From 6f418fc1b068c1a41113bb2b019a5803765e1deb Mon Sep 17 00:00:00 2001 From: Dave Hylands Date: Tue, 22 Jul 2014 07:57:36 -0700 Subject: [PATCH] Add support for selecting pin alternate functions from python. Converts generted pins to use qstrs instead of string pointers. This patch also adds the following functions: pyb.Pin.names() pyb.Pin.af_list() pyb.Pin.gpio() dir(pyb.Pin.board) and dir(pyb.Pin.cpu) also produce useful results. pyb.Pin now takes kw args. pyb.Pin.__str__ now prints more useful information about the pin configuration. I found the following functions in my boot.py to be useful: ```python def pins(): for pin_name in dir(pyb.Pin.board): pin = pyb.Pin(pin_name) print('{:10s} {:s}'.format(pin_name, str(pin))) def af(): for pin_name in dir(pyb.Pin.board): pin = pyb.Pin(pin_name) print('{:10s} {:s}'.format(pin_name, str(pin.af_list()))) ``` --- stmhal/Makefile | 9 +- stmhal/boards/make-pins.py | 66 ++++++++- stmhal/boards/stm32f4xx-prefix.c | 3 +- stmhal/mphal.h | 1 + stmhal/pin.c | 234 +++++++++++++++++++++++++++---- stmhal/pin.h | 17 ++- stmhal/pin_defs_stmhal.c | 37 +++++ stmhal/pin_named_pins.c | 69 ++++----- stmhal/qstrdefsport.h | 9 ++ teensy/Makefile | 9 +- teensy/hal_gpio.c | 15 +- teensy/main.c | 4 +- teensy/make-pins.py | 67 ++++++++- teensy/memzip_files/boot.py | 10 ++ teensy/mk20dx256-prefix.c | 3 +- teensy/pin_defs_teensy.c | 61 ++++++++ teensy/pin_defs_teensy.h | 1 - teensy/qstrdefsport.h | 8 ++ teensy/teensy_hal.h | 18 +++ 19 files changed, 551 insertions(+), 90 deletions(-) create mode 100644 stmhal/pin_defs_stmhal.c create mode 100644 teensy/pin_defs_teensy.c diff --git a/stmhal/Makefile b/stmhal/Makefile index 4daf665fa..d56125faf 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -11,7 +11,7 @@ BUILD ?= build-$(BOARD) include ../py/mkenv.mk # qstr definitions (must come before including py.mk) -QSTR_DEFS = qstrdefsport.h +QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h # include py core make definitions include ../py/py.mk @@ -74,6 +74,7 @@ SRC_C = \ timer.c \ led.c \ pin.c \ + pin_defs_stmhal.c \ pin_named_pins.c \ bufhelper.c \ i2c.c \ @@ -227,6 +228,8 @@ AF_FILE = boards/stm32f4xx-af.csv PREFIX_FILE = boards/stm32f4xx-prefix.c GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c GEN_PINS_HDR = $(HEADER_BUILD)/pins.h +GEN_PINS_QSTR = $(BUILD)/pins_qstr.h +GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins-af-const.h INSERT_USB_IDS = ../tools/insert-usb-ids.py FILE2H = ../tools/file2h.py @@ -247,9 +250,9 @@ $(BUILD)/main.o: $(GEN_CDCINF_HEADER) # Use a pattern rule here so that make will only call make-pins.py once to make # both pins_$(BOARD).c and pins.h -$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) +$(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%-af-const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) $(ECHO) "Create $@" - $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) > $(GEN_PINS_SRC) + $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) > $(GEN_PINS_SRC) $(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c $(call compile_c) diff --git a/stmhal/boards/make-pins.py b/stmhal/boards/make-pins.py index e3a3f583a..f3d1dee48 100755 --- a/stmhal/boards/make-pins.py +++ b/stmhal/boards/make-pins.py @@ -72,6 +72,9 @@ class AlternateFunction(object): return self.func return '{:s}{:d}'.format(self.func, self.fn_num) + def mux_name(self): + return 'AF{:d}_{:s}'.format(self.idx, self.ptr()) + def print(self): """Prints the C representation of this AF.""" if self.supported: @@ -84,6 +87,9 @@ class AlternateFunction(object): print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx, self.func, fn_num, self.pin_type, self.ptr(), self.af_str)) + def qstr_list(self): + return [self.mux_name()] + class Pin(object): """Holds the information associated with a pin.""" @@ -170,6 +176,14 @@ class Pin(object): hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. format(self.cpu_pin_name())) + def qstr_list(self): + result = [] + for alt_fn in self.alt_fn: + if alt_fn.is_supported(): + result += alt_fn.qstr_list() + return result + + class NamedPin(object): def __init__(self, name, pin): @@ -225,13 +239,13 @@ class Pins(object): self.board_pins.append(NamedPin(row[0], pin)) def print_named(self, label, named_pins): - print('const pin_named_pin_t pin_{:s}_pins[] = {{'.format(label)) + print('STATIC const mp_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) for named_pin in named_pins: pin = named_pin.pin() if pin.is_board_pin(): - print(' {{ "{:s}", &pin_{:s} }},'.format(named_pin.name(), pin.cpu_pin_name())) - print(' { NULL, NULL }') + print(' {{ MP_OBJ_NEW_QSTR(MP_QSTR_{:s}), (mp_obj_t)&pin_{:s} }},'.format(named_pin.name(), pin.cpu_pin_name())) print('};') + print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); def print(self): for named_pin in self.cpu_pins: @@ -269,6 +283,38 @@ class Pins(object): hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') + def print_qstr(self, qstr_filename): + with open(qstr_filename, 'wt') as qstr_file: + qstr_set = set([]) + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + qstr_set |= set(pin.qstr_list()) + qstr_set |= set([named_pin.name()]) + for named_pin in self.board_pins: + qstr_set |= set([named_pin.name()]) + for qstr in sorted(qstr_set): + print('Q({})'.format(qstr), file=qstr_file) + + def print_af_hdr(self, af_const_filename): + with open(af_const_filename, 'wt') as af_const_file: + af_hdr_set = set([]) + mux_name_width = 0 + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + for af in pin.alt_fn: + if af.is_supported(): + mux_name = af.mux_name() + af_hdr_set |= set([mux_name]) + if len(mux_name) > mux_name_width: + mux_name_width = len(mux_name) + for mux_name in sorted(af_hdr_set): + key = 'MP_OBJ_NEW_QSTR(MP_QSTR_{}),'.format(mux_name) + val = 'MP_OBJ_NEW_SMALL_INT(GPIO_{})'.format(mux_name) + print(' { %-*s %s },' % (mux_name_width + 26, key, val), + file=af_const_file) + def main(): parser = argparse.ArgumentParser( @@ -282,6 +328,12 @@ def main(): help="Specifies the alternate function file for the chip", default="stm32f4xx-af.csv" ) + parser.add_argument( + "--af-const", + dest="af_const_filename", + help="Specifies header file for alternate function constants.", + default="build/pins-af-const.h" + ) parser.add_argument( "-b", "--board", dest="board_filename", @@ -293,6 +345,12 @@ def main(): help="Specifies beginning portion of generated pins file", default="stm32f4xx-prefix.c" ) + parser.add_argument( + "-q", "--qstr", + dest="qstr_filename", + help="Specifies name of generated qstr header file", + default="build/pins-qstr.h" + ) parser.add_argument( "-r", "--hdr", dest="hdr_filename", @@ -323,6 +381,8 @@ def main(): pins.print_adc(2) pins.print_adc(3) pins.print_header(args.hdr_filename) + pins.print_qstr(args.qstr_filename) + pins.print_af_hdr(args.af_const_filename) if __name__ == "__main__": diff --git a/stmhal/boards/stm32f4xx-prefix.c b/stmhal/boards/stm32f4xx-prefix.c index 3bbb6bda0..45bcc0b65 100644 --- a/stmhal/boards/stm32f4xx-prefix.c +++ b/stmhal/boards/stm32f4xx-prefix.c @@ -14,6 +14,7 @@ #define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ { \ { &pin_af_type }, \ + .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \ .idx = (af_idx), \ .fn = AF_FN_ ## af_fn, \ .unit = (af_unit), \ @@ -24,7 +25,7 @@ #define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \ { \ { &pin_type }, \ - .name = #p_port #p_pin, \ + .name = MP_QSTR_ ## p_port ## p_pin, \ .port = PORT_ ## p_port, \ .pin = (p_pin), \ .num_af = (p_num_af), \ diff --git a/stmhal/mphal.h b/stmhal/mphal.h index 4e9a8b2bb..33407622c 100644 --- a/stmhal/mphal.h +++ b/stmhal/mphal.h @@ -5,3 +5,4 @@ #define GPIO_read_pin(gpio, pin) (((gpio)->IDR >> (pin)) & 1) #define GPIO_set_pin(gpio, pin_mask) (((gpio)->BSRRL) = (pin_mask)) #define GPIO_clear_pin(gpio, pin_mask) (((gpio)->BSRRH) = (pin_mask)) +#define GPIO_read_output_pin(gpio, pin) (((gpio)->ODR >> (pin)) & 1) diff --git a/stmhal/pin.c b/stmhal/pin.c index 0ef8b6950..5092d5e51 100644 --- a/stmhal/pin.c +++ b/stmhal/pin.c @@ -63,7 +63,8 @@ /// /// Users can add their own names: /// -/// pyb.Pin.dict["LeftMotorDir"] = pyb.Pin.cpu.C12 +/// MyMapperDict = { 'LeftMotorDir' : pyb.Pin.cpu.C12 } +/// pyb.Pin.dict(MyMapperDict) /// g = pyb.Pin("LeftMotorDir", pyb.Pin.OUT_OD) /// /// and can query mappings @@ -155,8 +156,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { } // See if the pin name matches a board pin - const char *pin_name = mp_obj_str_get_str(user_obj); - pin_obj = pin_find_named_pin(pin_board_pins, pin_name); + pin_obj = pin_find_named_pin(&pin_board_pins_locals_dict, user_obj); if (pin_obj) { if (pin_class_debug) { printf("Pin.board maps "); @@ -169,7 +169,7 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { } // See if the pin name matches a cpu pin - pin_obj = pin_find_named_pin(pin_cpu_pins, pin_name); + pin_obj = pin_find_named_pin(&pin_cpu_pins_locals_dict, user_obj); if (pin_obj) { if (pin_class_debug) { printf("Pin.cpu maps "); @@ -181,34 +181,69 @@ const pin_obj_t *pin_find(mp_obj_t user_obj) { return pin_obj; } - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", pin_name)); + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", mp_obj_str_get_str(user_obj))); } /// \method __str__() /// Return a string describing the pin object. STATIC void pin_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pin_obj_t *self = self_in; - print(env, "", self->name); + + // Need to query mode, pull, af + + print(env, "Pin(Pin.cpu.%s", qstr_str(self->name)); + uint32_t mode = pin_get_mode(self); + if (mode == GPIO_MODE_ANALOG) { + print(env, ", mode=Pin.ANALOG)", qstr_str(self->name)); + } else { + const char *pull_str = ""; + uint32_t pull = pin_get_pull(self); + if (pull == GPIO_PULLUP) { + pull_str = ", pull=Pin.PULL_UP"; + } else if (pull == GPIO_PULLDOWN) { + pull_str = ", pull=Pin.PULL_DOWN"; + } + if (mode == GPIO_MODE_INPUT) { + print(env, ", mode=Pin.IN%s)", pull_str); + } else if (mode == GPIO_MODE_OUTPUT_PP || mode == GPIO_MODE_OUTPUT_OD) { + if (mode == GPIO_MODE_OUTPUT_PP) { + print(env, ", mode=Pin.OUT_PP%s)", pull_str); + } else { + print(env, ", mode=Pin.OUT_OD%s)", pull_str); + } + } else { + if (mode == GPIO_MODE_AF_PP) { + print(env, ", mode=Pin.AF_PP"); + } else { + print(env, ", mode=Pin.AF_OD"); + } + mp_uint_t af_idx = pin_get_af(self); + const pin_af_obj_t *af = pin_find_af_by_index(self, af_idx); + if (af == NULL) { + print(env, ", af=%d%s)", af_idx, pull_str); + } else { + print(env, ", af=Pin.%s)", qstr_str(af->name), pull_str); + } + } + } } -STATIC mp_obj_t pin_obj_init(uint n_args, mp_obj_t *args); +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *pin, uint n_args, const mp_obj_t *args, mp_map_t *kw_args); /// \classmethod \constructor(id, ...) /// Create a new Pin object associated with the id. If additional arguments are given, /// they are used to initialise the pin. See `init`. STATIC mp_obj_t pin_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 1, 3, false); + mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true); // Run an argument through the mapper and return the result. const pin_obj_t *pin = pin_find(args[0]); - if (n_args >= 2) { + if (n_args > 1 || n_kw > 0) { // pin mode given, so configure this GPIO - mp_obj_t args2[3] = {(mp_obj_t)pin, args[1], MP_OBJ_NULL}; - if (n_args == 3) { - args2[2] = args[2]; - } - pin_obj_init(n_args, args2); + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args); } return (mp_obj_t)pin; @@ -238,6 +273,20 @@ STATIC mp_obj_t pin_map_dict(uint n_args, mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_dict_fun_obj, 1, 2, pin_map_dict); STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, (mp_obj_t)&pin_map_dict_fun_obj); +/// |classmethod af_list() +/// Returns an array of alternate functions available for this pin. +STATIC mp_obj_t pin_af_list(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_obj_t result = mp_obj_new_list(0, NULL); + + const pin_af_obj_t *af = self->af; + for (mp_uint_t i = 0; i < self->num_af; i++, af++) { + mp_obj_list_append(result, (mp_obj_t)af); + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_list_obj, pin_af_list); + /// \classmethod debug([state]) /// Get or set the debugging state (`True` or `False` for on or off). STATIC mp_obj_t pin_debug(uint n_args, mp_obj_t *args) { @@ -250,7 +299,7 @@ STATIC mp_obj_t pin_debug(uint n_args, mp_obj_t *args) { STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_debug_fun_obj, 1, 2, pin_debug); STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, (mp_obj_t)&pin_debug_fun_obj); -/// \method init(mode, pull=Pin.PULL_NONE) +/// \method init(mode, pull=Pin.PULL_NONE, af) /// Initialise the pin: /// /// - `mode` can be one of: @@ -264,26 +313,53 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, (mp_obj_t)&pin_debug_fun_o /// - `Pin.PULL_NONE` - no pull up or down resistors; /// - `Pin.PULL_UP` - enable the pull-up resistor; /// - `Pin.PULL_DOWN` - enable the pull-down resistor. +/// - when mode is Pin.AF_PP or Pin.AF_OD, then af can be the index or name +/// of one of the alternate functions associated with a pin. /// /// Returns: `None`. -// TODO allow keyword args -STATIC mp_obj_t pin_obj_init(uint n_args, mp_obj_t *args) { - pin_obj_t *self = args[0]; +STATIC const mp_arg_t pin_init_args[] = { + { MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pull, MP_ARG_INT, {.u_int = GPIO_NOPULL}}, + { MP_QSTR_af, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none}}, +}; +#define PIN_INIT_NUM_ARGS MP_ARRAY_SIZE(pin_init_args) + +STATIC mp_obj_t pin_obj_init_helper(const pin_obj_t *self, uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t vals[PIN_INIT_NUM_ARGS]; + mp_arg_parse_all(n_args, args, kw_args, PIN_INIT_NUM_ARGS, pin_init_args, vals); // get io mode - uint mode = mp_obj_get_int(args[1]); + uint mode = vals[0].u_int; if (!IS_GPIO_MODE(mode)) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin mode: %d", mode)); } // get pull mode - uint pull = GPIO_NOPULL; - if (n_args >= 3) { - pull = mp_obj_get_int(args[2]); - if (!IS_GPIO_PULL(pull)) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin pull: %d", pull)); + uint pull = vals[1].u_int; + if (!IS_GPIO_PULL(pull)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin pull: %d", pull)); + } + + // get af (alternate function) + mp_int_t af_idx = -1; + mp_obj_t af_obj = vals[2].u_obj; + if (af_obj != mp_const_none) { + if (MP_OBJ_IS_STR(af_obj)) { + const pin_af_obj_t *af; + const char *af_str = mp_obj_str_get_str(af_obj); + af = pin_find_af_by_name(self, af_str); + if (af == NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin af: %s", af_str)); + } + af_idx = af->idx; + } else { + af_idx = mp_obj_get_int(af_obj); } } + if ((mode == GPIO_MODE_AF_PP || mode == GPIO_MODE_AF_OD) && !IS_GPIO_AF(af_idx)) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin af: %d", af_idx)); + } // enable the peripheral clock for the port of this pin switch (self->port) { @@ -325,12 +401,15 @@ STATIC mp_obj_t pin_obj_init(uint n_args, mp_obj_t *args) { GPIO_InitStructure.Mode = mode; GPIO_InitStructure.Pull = pull; GPIO_InitStructure.Speed = GPIO_SPEED_FAST; - GPIO_InitStructure.Alternate = 0; + GPIO_InitStructure.Alternate = af_idx; HAL_GPIO_Init(self->gpio, &GPIO_InitStructure); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_init_obj, 2, 3, pin_obj_init); +STATIC mp_obj_t pin_obj_init(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { + return pin_obj_init_helper(args[0], n_args - 1, args + 1, kw_args); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pin_init_obj, 1, pin_obj_init); /// \method value([value]) /// Get or set the digital logic level of the pin: @@ -378,10 +457,29 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_high_obj, pin_high); /// Get the pin name. STATIC mp_obj_t pin_name(mp_obj_t self_in) { pin_obj_t *self = self_in; - return MP_OBJ_NEW_QSTR(qstr_from_str(self->name)); + return MP_OBJ_NEW_QSTR(self->name); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_name_obj, pin_name); +/// \method names() +/// Returns the cpu and board names for this pin. +STATIC mp_obj_t pin_names(mp_obj_t self_in) { + pin_obj_t *self = self_in; + mp_obj_t result = mp_obj_new_list(0, NULL); + mp_obj_list_append(result, MP_OBJ_NEW_QSTR(self->name)); + + mp_map_t *map = mp_obj_dict_get_map((mp_obj_t)&pin_board_pins_locals_dict); + mp_map_elem_t *elem = map->table; + + for (mp_uint_t i = 0; i < map->used; i++, elem++) { + if (elem->value == self) { + mp_obj_list_append(result, elem->key); + } + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_names_obj, pin_names); + /// \method port() /// Get the pin port. STATIC mp_obj_t pin_port(mp_obj_t self_in) { @@ -398,6 +496,14 @@ STATIC mp_obj_t pin_pin(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pin_obj, pin_pin); +/// \method gpio() +/// Returns the base address of the GPIO block associated with this pin. +STATIC mp_obj_t pin_gpio(mp_obj_t self_in) { + pin_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT((mp_int_t)self->gpio); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_gpio_obj, pin_gpio); + STATIC const mp_map_elem_t pin_locals_dict_table[] = { // instance methods { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pin_init_obj }, @@ -405,8 +511,11 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_low), (mp_obj_t)&pin_low_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_high), (mp_obj_t)&pin_high_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_name), (mp_obj_t)&pin_name_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_names), (mp_obj_t)&pin_names_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_af_list), (mp_obj_t)&pin_af_list_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_port), (mp_obj_t)&pin_port_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_pin), (mp_obj_t)&pin_pin_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_gpio), (mp_obj_t)&pin_gpio_obj }, // class methods { MP_OBJ_NEW_QSTR(MP_QSTR_mapper), (mp_obj_t)&pin_mapper_obj }, @@ -414,8 +523,8 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_debug), (mp_obj_t)&pin_debug_obj }, // class attributes - { MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&pin_board_pins_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_cpu), (mp_obj_t)&pin_cpu_pins_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&pin_board_pins_obj_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_cpu), (mp_obj_t)&pin_cpu_pins_obj_type }, // class constants /// \constant IN - initialise the pin to input mode @@ -433,6 +542,7 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_NONE), MP_OBJ_NEW_SMALL_INT(GPIO_NOPULL) }, { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(GPIO_PULLUP) }, { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PULLDOWN) }, +#include "genhdr/pins-af-const.h" }; STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table); @@ -445,14 +555,76 @@ const mp_obj_type_t pin_type = { .locals_dict = (mp_obj_t)&pin_locals_dict, }; +/// \moduleref pyb +/// \class PinAF - Pin Alternate Functions +/// +/// A Pin represents a physical pin on the microcprocessor. Each pin +/// can have a variety of functions (GPIO, I2C SDA, etc). Each PinAF +/// object represents a particular function for a pin. +/// +/// Usage Model: +/// +/// x3 = pyb.Pin.board.X3 +/// x3_af = x3.af_list() +/// +/// x3_af will now contain an array of PinAF objects which are availble on +/// pin X3. +/// +/// For the pyboard, x3_af would contain: +/// [Pin.AF1_TIM2, Pin.AF2_TIM5, Pin.AF3_TIM9, Pin.AF7_USART2] +/// +/// Normally, each peripheral would configure the af automatically, but sometimes +/// the same function is available on multiple pins, and having more control +/// is desired. +/// +/// To configure X3 to expose TIM2_CH3, you could use: +/// pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=pyb.Pin.AF1_TIM2) +/// or: +/// pin = pyb.Pin(pyb.Pin.board.X3, mode=pyb.Pin.AF_PP, af=1) + +/// \method __str__() +/// Return a string describing the alternate function. STATIC void pin_af_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pin_af_obj_t *self = self_in; - print(env, "", self->idx, self->fn, - self->unit, self->type); + print(env, "Pin.%s", qstr_str(self->name)); } +/// \method index() +/// Return the alternate function index. +STATIC mp_obj_t pin_af_index(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_SMALL_INT(af->idx); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_index_obj, pin_af_index); + +/// \method index() +/// Return the name of the alternate function. +STATIC mp_obj_t pin_af_name(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_QSTR(af->name); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_name_obj, pin_af_name); + +/// \method index() +/// Return the base register associated with the peripheral assigned to this +/// alternate function. For example, if the alternate function were TIM2_CH3 +/// this would return stm.TIM2 +STATIC mp_obj_t pin_af_reg(mp_obj_t self_in) { + pin_af_obj_t *af = self_in; + return MP_OBJ_NEW_SMALL_INT((mp_uint_t)af->reg); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_reg_obj, pin_af_reg); + +STATIC const mp_map_elem_t pin_af_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_index), (mp_obj_t)&pin_af_index_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_name), (mp_obj_t)&pin_af_name_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_reg), (mp_obj_t)&pin_af_reg_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(pin_af_locals_dict, pin_af_locals_dict_table); + const mp_obj_type_t pin_af_type = { { &mp_type_type }, .name = MP_QSTR_PinAF, .print = pin_af_obj_print, + .locals_dict = (mp_obj_t)&pin_af_locals_dict, }; diff --git a/stmhal/pin.h b/stmhal/pin.h index 51a434f1d..6ac73aabd 100644 --- a/stmhal/pin.h +++ b/stmhal/pin.h @@ -31,6 +31,7 @@ typedef struct { mp_obj_base_t base; + qstr name; uint8_t idx; uint8_t fn; uint8_t unit; @@ -45,7 +46,7 @@ typedef struct { typedef struct { mp_obj_base_t base; - const char *name; + qstr name; uint32_t port : 4; uint32_t pin : 5; // Some ARM processors use 32 bits/PORT uint32_t num_af : 4; @@ -75,10 +76,18 @@ typedef struct { const pin_named_pin_t *named_pins; } pin_named_pins_obj_t; -extern const pin_named_pins_obj_t pin_board_pins_obj; -extern const pin_named_pins_obj_t pin_cpu_pins_obj; +extern const mp_obj_type_t pin_board_pins_obj_type; +extern const mp_obj_type_t pin_cpu_pins_obj_type; + +extern const mp_obj_dict_t pin_cpu_pins_locals_dict; +extern const mp_obj_dict_t pin_board_pins_locals_dict; void pin_init0(void); +uint32_t pin_get_mode(const pin_obj_t *pin); +uint32_t pin_get_pull(const pin_obj_t *pin); +uint32_t pin_get_af(const pin_obj_t *pin); const pin_obj_t *pin_find(mp_obj_t user_obj); -const pin_obj_t *pin_find_named_pin(const pin_named_pin_t *pins, const char *name); +const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name); const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit, uint8_t pin_type); +const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx); +const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name); diff --git a/stmhal/pin_defs_stmhal.c b/stmhal/pin_defs_stmhal.c new file mode 100644 index 000000000..c2409dc6c --- /dev/null +++ b/stmhal/pin_defs_stmhal.c @@ -0,0 +1,37 @@ +#include "mpconfig.h" +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "runtime.h" +#include MICROPY_HAL_H +#include "pin.h" + +// Returns the pin mode. This value returned by this macro should be one of: +// GPIO_MODE_INPUT, GPIO_MODE_OUTPUT_PP, GPIO_MODE_OUTPUT_OD, +// GPIO_MODE_AF_PP, GPIO_MODE_AF_OD, or GPIO_MODE_ANALOG. + +uint32_t pin_get_mode(const pin_obj_t *pin) { + GPIO_TypeDef *gpio = pin->gpio; + uint32_t mode = (gpio->MODER >> (pin->pin * 2)) & 3; + if (mode != GPIO_MODE_ANALOG) { + if (gpio->OTYPER & pin->pin_mask) { + mode |= 1 << 4; + } + } + return mode; +} + +// Returns the pin pullup/pulldown. The value returned by this macro should +// be one of GPIO_NOPULL, GPIO_PULLUP, or GPIO_PULLDOWN. + +uint32_t pin_get_pull(const pin_obj_t *pin) { + return (pin->gpio->PUPDR >> (pin->pin * 2)) & 3; +} + +// Returns the af (alternate function) index currently set for a pin. + +uint32_t pin_get_af(const pin_obj_t *pin) { + return (pin->gpio->AFR[pin->pin >> 3] >> ((pin->pin & 7) * 4)) & 0xf; +} + diff --git a/stmhal/pin_named_pins.c b/stmhal/pin_named_pins.c index dbf03d1a0..c1ee4b8f3 100644 --- a/stmhal/pin_named_pins.c +++ b/stmhal/pin_named_pins.c @@ -41,52 +41,55 @@ STATIC void pin_named_pins_obj_print(void (*print)(void *env, const char *fmt, . print(env, "", qstr_str(self->name)); } -STATIC void pin_named_pins_obj_load_attr(mp_obj_t self_in, qstr attr_qstr, mp_obj_t *dest) { - pin_named_pins_obj_t *self = self_in; - const char *attr = qstr_str(attr_qstr); - const pin_obj_t *pin = pin_find_named_pin(self->named_pins, attr); - if (pin) { - dest[0] = (mp_obj_t)pin; - dest[1] = MP_OBJ_NULL; - } -} - -static const mp_obj_type_t pin_named_pins_obj_type = { +const mp_obj_type_t pin_cpu_pins_obj_type = { { &mp_type_type }, - .name = MP_QSTR_PinNamed, - .print = pin_named_pins_obj_print, - .load_attr = pin_named_pins_obj_load_attr, -}; - -const pin_named_pins_obj_t pin_board_pins_obj = { - { &pin_named_pins_obj_type }, - .name = MP_QSTR_board, - .named_pins = pin_board_pins, -}; - -const pin_named_pins_obj_t pin_cpu_pins_obj = { - { &pin_named_pins_obj_type }, .name = MP_QSTR_cpu, - .named_pins = pin_cpu_pins, + .print = pin_named_pins_obj_print, + .locals_dict = (mp_obj_t)&pin_cpu_pins_locals_dict, }; -const pin_obj_t *pin_find_named_pin(const pin_named_pin_t *named_pins, const char *name) { - const pin_named_pin_t *named_pin = named_pins; - while (named_pin->name) { - if (!strcmp(name, named_pin->name)) { - return named_pin->pin; - } - named_pin++; +const mp_obj_type_t pin_board_pins_obj_type = { + { &mp_type_type }, + .name = MP_QSTR_board, + .print = pin_named_pins_obj_print, + .locals_dict = (mp_obj_t)&pin_board_pins_locals_dict, +}; + +const pin_obj_t *pin_find_named_pin(const mp_obj_dict_t *named_pins, mp_obj_t name) { + mp_map_t *named_map = mp_obj_dict_get_map((mp_obj_t)named_pins); + mp_map_elem_t *named_elem = mp_map_lookup(named_map, name, MP_MAP_LOOKUP); + if (named_elem != NULL && named_elem->value != NULL) { + return named_elem->value; } return NULL; } const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit, uint8_t type) { const pin_af_obj_t *af = pin->af; - for (int i = 0; i < pin->num_af; i++, af++) { + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { if (af->fn == fn && af->unit == unit && af->type == type) { return af; } } return NULL; } + +const pin_af_obj_t *pin_find_af_by_index(const pin_obj_t *pin, mp_uint_t af_idx) { + const pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { + if (af->idx == af_idx) { + return af; + } + } + return NULL; +} + +const pin_af_obj_t *pin_find_af_by_name(const pin_obj_t *pin, const char *name) { + const pin_af_obj_t *af = pin->af; + for (mp_uint_t i = 0; i < pin->num_af; i++, af++) { + if (strcmp(name, qstr_str(af->name)) == 0) { + return af; + } + } + return NULL; +} diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 719a81d12..2505ca747 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -93,13 +93,22 @@ Q(value) Q(low) Q(high) Q(name) +Q(names) +Q(af) +Q(af_list) Q(port) Q(pin) +Q(gpio) Q(mapper) Q(dict) Q(debug) Q(board) Q(cpu) +Q(af) +Q(mode) +Q(pull) +Q(index) +Q(reg) Q(IN) Q(OUT_PP) Q(OUT_OD) diff --git a/teensy/Makefile b/teensy/Makefile index 54e6ef050..5b8e26621 100644 --- a/teensy/Makefile +++ b/teensy/Makefile @@ -1,7 +1,7 @@ include ../py/mkenv.mk # qstr definitions (must come before including py.mk) -QSTR_DEFS = qstrdefsport.h +QSTR_DEFS = qstrdefsport.h $(BUILD)/pins_qstr.h # include py core make definitions include ../py/py.mk @@ -53,6 +53,7 @@ SRC_C = \ lexermemzip.c \ memzip.c \ modpyb.c \ + pin_defs_teensy.c \ teensy_hal.c \ uart.c \ usb.c \ @@ -137,6 +138,8 @@ AF_FILE = mk20dx256-af.csv PREFIX_FILE = mk20dx256-prefix.c GEN_PINS_SRC = $(BUILD)/pins_gen.c GEN_PINS_HDR = $(HEADER_BUILD)/pins.h +GEN_PINS_QSTR = $(BUILD)/pins_qstr.h +GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins-af-const.h # Making OBJ use an order-only depenedency on the generated pins.h file # has the side effect of making the pins.h file before we actually compile @@ -147,9 +150,9 @@ $(OBJ): | $(HEADER_BUILD)/pins.h # Use a pattern rule here so that make will only call make-pins.py once to make # both pins_$(BOARD).c and pins.h -$(BUILD)/%_gen.c $(HEADER_BUILD)/%.h: teensy-%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) +$(BUILD)/%_gen.c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%-af-const.h $(BUILD)/%_qstr.h: teensy-%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD) $(ECHO) "Create $@" - $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) > $(GEN_PINS_SRC) + $(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) > $(GEN_PINS_SRC) $(BUILD)/pins_gen.o: $(BUILD)/pins_gen.c $(call compile_c) diff --git a/teensy/hal_gpio.c b/teensy/hal_gpio.c index 0811f76fd..218560e29 100644 --- a/teensy/hal_gpio.c +++ b/teensy/hal_gpio.c @@ -25,11 +25,17 @@ void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) if ((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)) { /* Check the Alternate function parameter */ assert_param(IS_GPIO_AF(GPIO_Init->Alternate)); - /* Configure Alternate function mapped with the current IO */ - - *port_pcr &= ~PORT_PCR_MUX_MASK; - *port_pcr |= PORT_PCR_MUX(GPIO_Init->Alternate); } + else if (GPIO_Init->Mode == GPIO_MODE_ANALOG) { + GPIO_Init->Alternate = 0; + } + else { + GPIO_Init->Alternate = 1; + } + + /* Configure Alternate function mapped with the current IO */ + *port_pcr &= ~PORT_PCR_MUX_MASK; + *port_pcr |= PORT_PCR_MUX(GPIO_Init->Alternate); /* Configure IO Direction mode (Input, Output, Alternate or Analog) */ if (GPIO_Init->Mode == GPIO_MODE_INPUT || GPIO_Init->Mode == GPIO_MODE_ANALOG) { @@ -112,4 +118,3 @@ void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) #endif } } - diff --git a/teensy/main.c b/teensy/main.c index 53f500d57..8de26f25e 100644 --- a/teensy/main.c +++ b/teensy/main.c @@ -24,7 +24,7 @@ #include "usb.h" #include "led.h" #include "uart.h" -//#include "pin.h" +#include "pin.h" #include "pybstdio.h" @@ -272,7 +272,7 @@ soft_reset: readline_init0(); - //pin_init(); + pin_init0(); #if 0 // add some functions to the python namespace diff --git a/teensy/make-pins.py b/teensy/make-pins.py index 1fd05ec20..6df1e4162 100755 --- a/teensy/make-pins.py +++ b/teensy/make-pins.py @@ -71,6 +71,9 @@ class AlternateFunction(object): return self.func return '{:s}{:d}'.format(self.func, self.fn_num) + def mux_name(self): + return 'AF{:d}_{:s}'.format(self.idx, self.ptr()) + def print(self): """Prints the C representation of this AF.""" if self.supported: @@ -83,6 +86,9 @@ class AlternateFunction(object): print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx, self.func, fn_num, self.pin_type, self.ptr(), self.af_str)) + def qstr_list(self): + return [self.mux_name()] + class Pin(object): """Holds the information associated with a pin.""" @@ -169,6 +175,14 @@ class Pin(object): hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'. format(self.cpu_pin_name())) + def qstr_list(self): + result = [] + for alt_fn in self.alt_fn: + if alt_fn.is_supported(): + result += alt_fn.qstr_list() + return result + + class NamedPin(object): def __init__(self, name, pin): @@ -222,13 +236,13 @@ class Pins(object): self.board_pins.append(NamedPin(row[0], pin)) def print_named(self, label, named_pins): - print('const pin_named_pin_t pin_{:s}_pins[] = {{'.format(label)) + print('STATIC const mp_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label)) for named_pin in named_pins: pin = named_pin.pin() if pin.is_board_pin(): - print(' {{ "{:s}", &pin_{:s} }},'.format(named_pin.name(), pin.cpu_pin_name())) - print(' { NULL, NULL }') + print(' {{ MP_OBJ_NEW_QSTR(MP_QSTR_{:s}), (mp_obj_t)&pin_{:s} }},'.format(named_pin.name(), pin.cpu_pin_name())) print('};') + print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label)); def print(self): for named_pin in self.cpu_pins: @@ -266,6 +280,39 @@ class Pins(object): hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n') hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n') + def print_qstr(self, qstr_filename): + with open(qstr_filename, 'wt') as qstr_file: + qstr_set = set([]) + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + qstr_set |= set(pin.qstr_list()) + qstr_set |= set([named_pin.name()]) + for named_pin in self.board_pins: + qstr_set |= set([named_pin.name()]) + for qstr in sorted(qstr_set): + print('Q({})'.format(qstr), file=qstr_file) + + + def print_af_hdr(self, af_const_filename): + with open(af_const_filename, 'wt') as af_const_file: + af_hdr_set = set([]) + mux_name_width = 0 + for named_pin in self.cpu_pins: + pin = named_pin.pin() + if pin.is_board_pin(): + for af in pin.alt_fn: + if af.is_supported(): + mux_name = af.mux_name() + af_hdr_set |= set([mux_name]) + if len(mux_name) > mux_name_width: + mux_name_width = len(mux_name) + for mux_name in sorted(af_hdr_set): + key = 'MP_OBJ_NEW_QSTR(MP_QSTR_{}),'.format(mux_name) + val = 'MP_OBJ_NEW_SMALL_INT(GPIO_{})'.format(mux_name) + print(' { %-*s %s },' % (mux_name_width + 26, key, val), + file=af_const_file) + def main(): parser = argparse.ArgumentParser( @@ -279,6 +326,12 @@ def main(): help="Specifies the alternate function file for the chip", default="stm32f4xx-af.csv" ) + parser.add_argument( + "--af-const", + dest="af_const_filename", + help="Specifies header file for alternate function constants.", + default="build/pins-af-const.h" + ) parser.add_argument( "-b", "--board", dest="board_filename", @@ -290,6 +343,12 @@ def main(): help="Specifies beginning portion of generated pins file", default="stm32f4xx-prefix.c" ) + parser.add_argument( + "-q", "--qstr", + dest="qstr_filename", + help="Specifies name of generated qstr header file", + default="build/pins-qstr.h" + ) parser.add_argument( "-r", "--hdr", dest="hdr_filename", @@ -320,6 +379,8 @@ def main(): pins.print_adc(2) pins.print_adc(3) pins.print_header(args.hdr_filename) + pins.print_qstr(args.qstr_filename) + pins.print_af_hdr(args.af_const_filename) if __name__ == "__main__": diff --git a/teensy/memzip_files/boot.py b/teensy/memzip_files/boot.py index 4702d7b5d..6dd5516a9 100644 --- a/teensy/memzip_files/boot.py +++ b/teensy/memzip_files/boot.py @@ -1,2 +1,12 @@ import pyb print("Executing boot.py") + +def pins(): + for pin_name in dir(pyb.Pin.board): + pin = pyb.Pin(pin_name) + print('{:10s} {:s}'.format(pin_name, str(pin))) + +def af(): + for pin_name in dir(pyb.Pin.board): + pin = pyb.Pin(pin_name) + print('{:10s} {:s}'.format(pin_name, str(pin.af_list()))) diff --git a/teensy/mk20dx256-prefix.c b/teensy/mk20dx256-prefix.c index 2485dc01a..048b64316 100644 --- a/teensy/mk20dx256-prefix.c +++ b/teensy/mk20dx256-prefix.c @@ -15,6 +15,7 @@ #define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \ { \ { &pin_af_type }, \ + .name = MP_QSTR_AF ## af_idx ## _ ## af_fn ## af_unit, \ .idx = (af_idx), \ .fn = AF_FN_ ## af_fn, \ .unit = (af_unit), \ @@ -25,7 +26,7 @@ #define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \ { \ { &pin_type }, \ - .name = #p_port #p_pin, \ + .name = MP_QSTR_ ## p_port ## p_pin, \ .port = PORT_ ## p_port, \ .pin = (p_pin), \ .num_af = (p_num_af), \ diff --git a/teensy/pin_defs_teensy.c b/teensy/pin_defs_teensy.c new file mode 100644 index 000000000..dd2f0dc21 --- /dev/null +++ b/teensy/pin_defs_teensy.c @@ -0,0 +1,61 @@ +#include +#include +#include "mpconfig.h" +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "runtime.h" +#include MICROPY_HAL_H +#include "pin.h" + +// Returns the pin mode. This value returned by this macro should be one of: +// GPIO_MODE_INPUT, GPIO_MODE_OUTPUT_PP, GPIO_MODE_OUTPUT_OD, +// GPIO_MODE_AF_PP, GPIO_MODE_AF_OD, or GPIO_MODE_ANALOG. + +uint32_t pin_get_mode(const pin_obj_t *pin) { + volatile uint32_t *port_pcr = GPIO_PIN_TO_PORT_PCR(pin->gpio, pin->pin); + uint32_t pcr = *port_pcr; + uint32_t af = (*port_pcr & PORT_PCR_MUX_MASK) >> 8;; + + if (af == 0) { + return GPIO_MODE_ANALOG; + } + if (af == 1) { + if (pin->gpio->PDDR & (1 << pin->pin)) { + if (pcr & PORT_PCR_ODE) { + return GPIO_MODE_OUTPUT_OD; + } + return GPIO_MODE_OUTPUT_PP; + } + return GPIO_MODE_INPUT; + } + + if (pcr & PORT_PCR_ODE) { + return GPIO_MODE_AF_OD; + } + return GPIO_MODE_AF_PP; +} + +// Returns the pin pullup/pulldown. The value returned by this macro should +// be one of GPIO_NOPULL, GPIO_PULLUP, or GPIO_PULLDOWN. + +uint32_t pin_get_pull(const pin_obj_t *pin) { + volatile uint32_t *port_pcr = GPIO_PIN_TO_PORT_PCR(pin->gpio, pin->pin); + + uint32_t pcr = *port_pcr; + if (pcr & PORT_PCR_PE) { + if (pcr & PORT_PCR_PS) { + return GPIO_PULLUP; + } + return GPIO_PULLDOWN; + } + return GPIO_NOPULL; +} + +// Returns the af (alternate function) index currently set for a pin. + +uint32_t pin_get_af(const pin_obj_t *pin) { + volatile uint32_t *port_pcr = GPIO_PIN_TO_PORT_PCR(pin->gpio, pin->pin); + return (*port_pcr & PORT_PCR_MUX_MASK) >> 8; +} diff --git a/teensy/pin_defs_teensy.h b/teensy/pin_defs_teensy.h index 66942c2ea..70fd47d8f 100644 --- a/teensy/pin_defs_teensy.h +++ b/teensy/pin_defs_teensy.h @@ -43,4 +43,3 @@ enum { SPI_TypeDef *SPI; typedef GPIO_TypeDef pin_gpio_t; - diff --git a/teensy/qstrdefsport.h b/teensy/qstrdefsport.h index 2fb70af7b..bdafd1428 100644 --- a/teensy/qstrdefsport.h +++ b/teensy/qstrdefsport.h @@ -62,13 +62,21 @@ Q(value) Q(low) Q(high) Q(name) +Q(names) +Q(af) +Q(af_list) Q(port) Q(pin) +Q(gpio) Q(mapper) Q(dict) Q(debug) Q(board) Q(cpu) +Q(mode) +Q(pull) +Q(index) +Q(reg) Q(IN) Q(OUT_PP) Q(OUT_OD) diff --git a/teensy/teensy_hal.h b/teensy/teensy_hal.h index ff16c98c5..9c9e62842 100644 --- a/teensy/teensy_hal.h +++ b/teensy/teensy_hal.h @@ -81,6 +81,7 @@ typedef struct { #define GPIO_SPEED_FAST ((uint32_t)2) #define GPIO_SPEED_HIGH ((uint32_t)3) +#define IS_GPIO_AF(af) ((af) >= 0 && (af) <= 7) typedef struct { uint32_t Pin; @@ -96,6 +97,22 @@ typedef struct { #define GPIO_PIN_TO_PORT_PCR(GPIOx, pin) \ (&PORTA_PCR0 + GPIO_PORT_TO_PORT_NUM(GPIOx) * 32 + (pin)) +#define GPIO_AF2_I2C0 2 +#define GPIO_AF2_I2C1 2 +#define GPIO_AF2_SPI0 2 +#define GPIO_AF3_FTM0 3 +#define GPIO_AF3_FTM1 3 +#define GPIO_AF3_FTM2 3 +#define GPIO_AF3_UART0 3 +#define GPIO_AF3_UART1 3 +#define GPIO_AF3_UART2 3 +#define GPIO_AF4_FTM0 4 +#define GPIO_AF6_FTM1 6 +#define GPIO_AF6_FTM2 6 +#define GPIO_AF6_I2C1 6 +#define GPIO_AF7_FTM1 7 + + __attribute__(( always_inline )) static inline void __WFI(void) { __asm volatile ("wfi"); @@ -109,3 +126,4 @@ void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *init); #define GPIO_read_pin(gpio, pin) (((gpio)->PDIR >> (pin)) & 1) #define GPIO_set_pin(gpio, pin_mask) (((gpio)->PSOR) = (pin_mask)) #define GPIO_clear_pin(gpio, pin_mask) (((gpio)->PCOR) = (pin_mask)) +#define GPIO_read_output_pin(gpio, pin) (((gpio)->PDOR >> (pin)) & 1)