Commit 6f418fc1 authored by Dave Hylands's avatar Dave Hylands
Browse files

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())))
```
parent 3ef91134
......@@ -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)
......
......@@ -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__":
......
......@@ -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), \
......
......@@ -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)
......@@ -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, "<Pin %s>", 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, "<Pin AF %d fn:%d unit:%d typ:%d>", 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,
};
......@@ -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);
#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) {