From 22b4c28f854bb2066a0d7471b50f9e00e1363239 Mon Sep 17 00:00:00 2001 From: Daniel Campora Date: Mon, 14 Sep 2015 20:03:32 +0200 Subject: [PATCH] cc3200: New ADC API. --- cc3200/boards/make-pins.py | 18 ++- cc3200/mods/pybadc.c | 260 +++++++++++++++++++++++++++---------- cc3200/mods/pybpin.c | 10 ++ cc3200/mods/pybpin.h | 11 +- cc3200/qstrdefsport.h | 6 +- tests/wipy/adc.py | 116 +++++++++++++++++ tests/wipy/adc.py.exp | 28 ++++ 7 files changed, 371 insertions(+), 78 deletions(-) create mode 100644 tests/wipy/adc.py create mode 100644 tests/wipy/adc.py.exp diff --git a/cc3200/boards/make-pins.py b/cc3200/boards/make-pins.py index 884f72cf95..676896803a 100644 --- a/cc3200/boards/make-pins.py +++ b/cc3200/boards/make-pins.py @@ -35,6 +35,8 @@ class AF: def __init__(self, name, idx, fn, unit, type): self.name = name self.idx = idx + if self.idx > 15: + self.idx = -1 self.fn = fn self.unit = unit self.type = type @@ -57,12 +59,16 @@ class Pin: def print(self): print('// {}'.format(self.name)) - print('const pin_af_t pin_{}_af[] = {{'.format(self.name)) - for af in self.afs: - af.print() - print('};') - print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, pin_{}_af, {});\n'.format( - self.name, self.name, self.port, self.gpio_bit, self.pin_num, self.name, len(self.afs))) + if len(self.afs): + print('const pin_af_t pin_{}_af[] = {{'.format(self.name)) + for af in self.afs: + af.print() + print('};') + print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, pin_{}_af, {});\n'.format( + self.name, self.name, self.port, self.gpio_bit, self.pin_num, self.name, len(self.afs))) + else: + print('pin_obj_t pin_{:4s} = PIN({:6s}, {:1d}, {:3d}, {:2d}, NULL, 0);\n'.format( + self.name, self.name, self.port, self.gpio_bit, self.pin_num)) def print_header(self, hdr_file): hdr_file.write('extern pin_obj_t pin_{:s};\n'.format(self.name)) diff --git a/cc3200/mods/pybadc.c b/cc3200/mods/pybadc.c index d48763f660..877c40f9f6 100644 --- a/cc3200/mods/pybadc.c +++ b/cc3200/mods/pybadc.c @@ -52,17 +52,6 @@ #include "mpexception.h" -/// \moduleref pyb -/// \class ADC - analog to digital conversion: read analog values on a pin -/// -/// Usage: -/// -/// adc = pyb.ADC('GP5') # create an adc object on the given pin (GP2, GP3, GP4 o GP5) -/// adc.read() # read channel value -/// -/// The sample rate is fixed to 62.5KHz and the resolution to 12 bits. - - /****************************************************************************** DECLARE CONSTANTS ******************************************************************************/ @@ -71,32 +60,69 @@ /****************************************************************************** DEFINE TYPES ******************************************************************************/ +typedef struct { + mp_obj_base_t base; + bool enabled; +} pyb_adc_obj_t; + typedef struct { mp_obj_base_t base; pin_obj_t *pin; byte channel; byte id; -} pyb_adc_obj_t; + bool enabled; +} pyb_adc_channel_obj_t; + /****************************************************************************** DECLARE PRIVATE DATA ******************************************************************************/ -STATIC pyb_adc_obj_t pyb_adc_obj[PYB_ADC_NUM_CHANNELS] = { {.pin = &pin_GP2, .channel = ADC_CH_0, .id = 1}, {.pin = &pin_GP3, .channel = ADC_CH_1, .id = 2}, - {.pin = &pin_GP4, .channel = ADC_CH_2, .id = 2}, {.pin = &pin_GP5, .channel = ADC_CH_3, .id = 4} }; +STATIC pyb_adc_channel_obj_t pyb_adc_channel_obj[PYB_ADC_NUM_CHANNELS] = { {.pin = &pin_GP2, .channel = ADC_CH_0, .id = 0, .enabled = false}, + {.pin = &pin_GP3, .channel = ADC_CH_1, .id = 1, .enabled = false}, + {.pin = &pin_GP4, .channel = ADC_CH_2, .id = 2, .enabled = false}, + {.pin = &pin_GP5, .channel = ADC_CH_3, .id = 3, .enabled = false} }; +STATIC pyb_adc_obj_t pyb_adc_obj = {.enabled = false}; + +STATIC const mp_obj_type_t pyb_adc_channel_type; + +/****************************************************************************** + DECLARE PRIVATE FUNCTIONS + ******************************************************************************/ +STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in); /****************************************************************************** DEFINE PUBLIC FUNCTIONS ******************************************************************************/ -STATIC void pybadc_init (pyb_adc_obj_t *self) { - // configure the pin in analog mode - pin_config (self->pin, -1, PIN_TYPE_ANALOG, PIN_TYPE_STD, -1, PIN_STRENGTH_2MA); - // enable the ADC channel - MAP_ADCChannelEnable(ADC_BASE, self->channel); +STATIC void pyb_adc_init (pyb_adc_obj_t *self) { // enable and configure the timer MAP_ADCTimerConfig(ADC_BASE, (1 << 17) - 1); MAP_ADCTimerEnable(ADC_BASE); // enable the ADC peripheral MAP_ADCEnable(ADC_BASE); + self->enabled = true; +} + +STATIC void pyb_adc_check_init(void) { + // not initialized + if (!pyb_adc_obj.enabled) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + } +} + +STATIC void pyb_adc_channel_init (pyb_adc_channel_obj_t *self) { + // the ADC block must be enabled first + pyb_adc_check_init(); + // configure the pin in analog mode + pin_config (self->pin, -1, PIN_TYPE_ANALOG, PIN_TYPE_STD, -1, PIN_STRENGTH_2MA); + // enable the ADC channel + MAP_ADCChannelEnable(ADC_BASE, self->channel); + self->enabled = true; +} + +STATIC void pyb_adc_deinit_all_channels (void) { + for (int i = 0; i < PYB_ADC_NUM_CHANNELS; i++) { + adc_channel_deinit(&pyb_adc_channel_obj[i]); + } } /******************************************************************************/ @@ -104,73 +130,109 @@ STATIC void pybadc_init (pyb_adc_obj_t *self) { STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { pyb_adc_obj_t *self = self_in; - mp_printf(print, "", self->id, self->pin->name); -} - -/// \classmethod \constructor(pin) -/// Create an ADC object associated with the given pin. -/// This allows you to then read analog values on that pin. -STATIC mp_obj_t adc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { - // check number of arguments - mp_arg_check_num(n_args, n_kw, 1, 1, false); - - // the argument passed is the pin - const pin_obj_t *pin = (pin_obj_t *)pin_find(args[0]); - for (int32_t idx = 0; idx < PYB_ADC_NUM_CHANNELS; idx++) { - if (pin == pyb_adc_obj[idx].pin) { - pyb_adc_obj_t *self = &pyb_adc_obj[idx]; - self->base.type = &pyb_adc_type; - pybadc_init (self); - // register it with the sleep module - pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pybadc_init); - return self; - } + if (self->enabled) { + mp_printf(print, "ADC(0, bits=12)"); + } else { + mp_printf(print, "ADC(0)"); } - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } -/// \method read() -/// Read the value on the analog pin and return it. The returned value -/// will be between 0 and 4095. -STATIC mp_obj_t adc_read(mp_obj_t self_in) { - pyb_adc_obj_t *self = self_in; - uint32_t sample; +STATIC const mp_arg_t pyb_adc_init_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 12} }, +}; +STATIC mp_obj_t adc_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *all_args) { + // parse args + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, all_args + n_args); + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_init_args)]; + mp_arg_parse_all(n_args, all_args, &kw_args, MP_ARRAY_SIZE(args), pyb_adc_init_args, args); - // wait until a new value is available - while (!MAP_ADCFIFOLvlGet(ADC_BASE, self->channel)); - // read the sample - sample = MAP_ADCFIFORead(ADC_BASE, self->channel); - // the 12 bit sampled value is stored in bits [13:2] - return MP_OBJ_NEW_SMALL_INT((sample & 0x3FFF) >> 2); + // check the peripheral id + if (args[0].u_int != 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); + } + + // check the number of bits + if (args[1].u_int != 12) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + } + + // setup the object + pyb_adc_obj_t *self = &pyb_adc_obj; + self->base.type = &pyb_adc_type; + + // initialize and register with the sleep module + pyb_adc_init(self); + pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_init); + return self; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); -/// \method init() -/// Enable the adc channel -STATIC mp_obj_t adc_init(mp_obj_t self_in) { - pyb_adc_obj_t *self = self_in; - - pybadc_init(self); +STATIC mp_obj_t adc_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_init_args) - 1]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), &pyb_adc_init_args[1], args); + // check the number of bits + if (args[0].u_int != 12) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + } + pyb_adc_init(pos_args[0]); return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_init_obj, adc_init); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_init_obj, 1, adc_init); -/// \method deinit() -/// Disable the adc channel STATIC mp_obj_t adc_deinit(mp_obj_t self_in) { pyb_adc_obj_t *self = self_in; - - MAP_ADCChannelDisable(ADC_BASE, self->channel); + // first deinit all channels + pyb_adc_deinit_all_channels(); + MAP_ADCDisable(ADC_BASE); + self->enabled = false; // unregister it with the sleep module pybsleep_remove ((const mp_obj_t)self); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_deinit_obj, adc_deinit); +STATIC mp_obj_t adc_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + STATIC const mp_arg_t pyb_adc_channel_args[] = { + { MP_QSTR_id, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(pyb_adc_channel_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(args), pyb_adc_channel_args, args); + + uint ch_id; + if (args[0].u_obj != mp_const_none) { + ch_id = mp_obj_get_int(args[0].u_obj); + if (ch_id >= PYB_ADC_NUM_CHANNELS) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_os_resource_not_avaliable)); + } + else if (args[1].u_obj != mp_const_none) { + uint pin_ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0); + if (ch_id != pin_ch_id) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); + } + } + } else { + ch_id = pin_find_peripheral_type (args[1].u_obj, PIN_FN_ADC, 0); + } + + // setup the object + pyb_adc_channel_obj_t *self = &pyb_adc_channel_obj[ch_id]; + self->base.type = &pyb_adc_channel_type; + pyb_adc_channel_init (self); + // register it with the sleep module + pybsleep_add ((const mp_obj_t)self, (WakeUpCB_t)pyb_adc_channel_init); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adc_channel_obj, 1, adc_channel); + STATIC const mp_map_elem_t adc_locals_dict_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&adc_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&adc_deinit_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_channel), (mp_obj_t)&adc_channel_obj }, }; STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); @@ -183,3 +245,69 @@ const mp_obj_type_t pyb_adc_type = { .locals_dict = (mp_obj_t)&adc_locals_dict, }; +STATIC void adc_channel_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + pyb_adc_channel_obj_t *self = self_in; + if (self->enabled) { + mp_printf(print, "ADCChannel(%u, pin=%q)", self->id, self->pin->name); + } else { + mp_printf(print, "ADCChannel(%u)", self->id); + } +} + +STATIC mp_obj_t adc_channel_init(mp_obj_t self_in) { + pyb_adc_channel_obj_t *self = self_in; + // re-enable it + pyb_adc_channel_init(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_init_obj, adc_channel_init); + +STATIC mp_obj_t adc_channel_deinit(mp_obj_t self_in) { + pyb_adc_channel_obj_t *self = self_in; + + MAP_ADCChannelDisable(ADC_BASE, self->channel); + // unregister it with the sleep module + pybsleep_remove ((const mp_obj_t)self); + self->enabled = false; + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_deinit_obj, adc_channel_deinit); + +STATIC mp_obj_t adc_channel_value(mp_obj_t self_in) { + pyb_adc_channel_obj_t *self = self_in; + uint32_t value; + + // the channel must be enabled + if (!self->enabled) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_request_not_possible)); + } + + // wait until a new value is available + while (!MAP_ADCFIFOLvlGet(ADC_BASE, self->channel)); + // read the sample + value = MAP_ADCFIFORead(ADC_BASE, self->channel); + // the 12 bit sampled value is stored in bits [13:2] + return MP_OBJ_NEW_SMALL_INT((value & 0x3FFF) >> 2); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_channel_value_obj, adc_channel_value); + +STATIC mp_obj_t adc_channel_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 0, false); + return adc_channel_value (self_in); +} + +STATIC const mp_map_elem_t adc_channel_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&adc_channel_init_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_deinit), (mp_obj_t)&adc_channel_deinit_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_value), (mp_obj_t)&adc_channel_value_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(adc_channel_locals_dict, adc_channel_locals_dict_table); + +STATIC const mp_obj_type_t pyb_adc_channel_type = { + { &mp_type_type }, + .name = MP_QSTR_ADCChannel, + .print = adc_channel_print, + .call = adc_channel_call, + .locals_dict = (mp_obj_t)&adc_channel_locals_dict, +}; diff --git a/cc3200/mods/pybpin.c b/cc3200/mods/pybpin.c index de125a66d4..82143128e2 100644 --- a/cc3200/mods/pybpin.c +++ b/cc3200/mods/pybpin.c @@ -184,6 +184,16 @@ uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type) nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); } +uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit) { + pin_obj_t *pin_o = pin_find(pin); + for (int i = 0; i < pin_o->num_afs; i++) { + if (pin_o->af_list[i].fn == fn && pin_o->af_list[i].unit == unit) { + return pin_o->af_list[i].type; + } + } + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, mpexception_value_invalid_arguments)); +} + /****************************************************************************** DEFINE PRIVATE FUNCTIONS ******************************************************************************/ diff --git a/cc3200/mods/pybpin.h b/cc3200/mods/pybpin.h index 3d46a0b61e..72a90874c4 100644 --- a/cc3200/mods/pybpin.h +++ b/cc3200/mods/pybpin.h @@ -85,15 +85,15 @@ enum { }; enum { - PIN_TYPE_ADC_CH0 = -1, - PIN_TYPE_ADC_CH1 = -1, - PIN_TYPE_ADC_CH2 = -1, - PIN_TYPE_ADC_CH3 = -1, + PIN_TYPE_ADC_CH0 = 0, + PIN_TYPE_ADC_CH1, + PIN_TYPE_ADC_CH2, + PIN_TYPE_ADC_CH3, }; typedef struct { qstr name; - uint8_t idx; + int8_t idx; uint8_t fn; uint8_t unit; uint8_t type; @@ -136,5 +136,6 @@ void pin_config(pin_obj_t *self, int af, uint mode, uint type, int value, uint s pin_obj_t *pin_find(mp_obj_t user_obj); void pin_assign_pins_af (mp_obj_t *pins, uint32_t n_pins, uint32_t pull, uint32_t fn, uint32_t unit); uint8_t pin_find_peripheral_unit (const mp_obj_t pin, uint8_t fn, uint8_t type); +uint8_t pin_find_peripheral_type (const mp_obj_t pin, uint8_t fn, uint8_t unit); #endif // PYBPIN_H_ diff --git a/cc3200/qstrdefsport.h b/cc3200/qstrdefsport.h index 9d7e1ac643..c5fc53032b 100644 --- a/cc3200/qstrdefsport.h +++ b/cc3200/qstrdefsport.h @@ -177,9 +177,13 @@ Q(MASTER) // for ADC class Q(ADC) -Q(read) +Q(ADCChannel) +Q(value) Q(init) Q(deinit) +Q(channel) +Q(id) +Q(pin) #if MICROPY_HW_HAS_SDCARD // for SD class diff --git a/tests/wipy/adc.py b/tests/wipy/adc.py new file mode 100644 index 0000000000..50a2b3d722 --- /dev/null +++ b/tests/wipy/adc.py @@ -0,0 +1,116 @@ +''' +ADC test for the CC3200 based boards. +''' + +from pyb import ADC +from pyb import Pin +import os + +machine = os.uname().machine +if 'LaunchPad' in machine: + adc_pin = 'GP5' + adc_channel = 3 +elif 'WiPy' in machine: + adc_pin = 'GP3' + adc_channel = 1 +else: + raise Exception('Board not supported!') + +adc = ADC(0) +print(adc) +adc = ADC() +print(adc) +adc = ADC(0, bits=12) +print(adc) + +apin = adc.channel(adc_channel) +print(apin) +apin = adc.channel(id=adc_channel) +print(apin) +apin = adc.channel(adc_channel, pin=adc_pin) +print(apin) +apin = adc.channel(id=adc_channel, pin=adc_pin) +print(apin) + +print(apin.value() > 3000) +print(apin() > 3000) + +# de-init must work +apin.deinit() +print(apin) + +adc.deinit() +print(adc) +print(apin) +adc.init() +print(adc) +print(apin) +apin.init() +print(apin) +print(apin() > 3000) + +# check for memory leaks... +for i in range (0, 1000): + adc = ADC() + apin = adc.channel(adc_channel) + +# next ones should raise +try: + adc = ADC(bits=17) +except: + print('Exception') + +try: + adc = ADC(id=1) +except: + print('Exception') + +try: + adc = ADC(0, 16) +except: + print('Exception') + +adc = ADC() +try: + apin = adc.channel(4) +except: + print('Exception') + +try: + apin = adc.channel(-1) +except: + print('Exception') + +try: + apin = adc.channel(0, pin='GP3') +except: + print('Exception') + +apin = adc.channel(1) +apin.deinit() +try: + apin() +except: + print('Exception') + +try: + apin.value() +except: + print('Exception') + +adc.deinit() +try: + apin.value() +except: + print('Exception') + +try: + apin = adc.channel(1) +except: + print('Exception') + +# re-init must work +adc.init() +apin.init() +print(apin) +print(apin() > 3000) diff --git a/tests/wipy/adc.py.exp b/tests/wipy/adc.py.exp new file mode 100644 index 0000000000..a65cf4963b --- /dev/null +++ b/tests/wipy/adc.py.exp @@ -0,0 +1,28 @@ +ADC(0, bits=12) +ADC(0, bits=12) +ADC(0, bits=12) +ADCChannel(1, pin=GP3) +ADCChannel(1, pin=GP3) +ADCChannel(1, pin=GP3) +ADCChannel(1, pin=GP3) +True +True +ADCChannel(1) +ADC(0) +ADCChannel(1) +ADC(0, bits=12) +ADCChannel(1) +ADCChannel(1, pin=GP3) +True +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +Exception +ADCChannel(1, pin=GP3) +True