diff options
| author | Daniel Campora | 2015-09-14 20:03:32 +0200 |
|---|---|---|
| committer | Daniel Campora | 2015-09-16 10:10:38 +0200 |
| commit | 22b4c28f854bb2066a0d7471b50f9e00e1363239 (patch) | |
| tree | eeedc24a49a3f8c5a3cfa8fe0eed83a7788c9584 /cc3200/mods/pybadc.c | |
| parent | 0e52d9860adc2d3d7328c649f3b6995ffc04fc63 (diff) | |
cc3200: New ADC API.
Diffstat (limited to 'cc3200/mods/pybadc.c')
| -rw-r--r-- | cc3200/mods/pybadc.c | 258 |
1 files changed, 193 insertions, 65 deletions
diff --git a/cc3200/mods/pybadc.c b/cc3200/mods/pybadc.c index d48763f66..877c40f9f 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 ******************************************************************************/ @@ -73,30 +62,67 @@ ******************************************************************************/ 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, "<ADC1 channel=%u on %q>", self->id, self->pin->name); + if (self->enabled) { + mp_printf(print, "ADC(0, bits=12)"); + } else { + mp_printf(print, "ADC(0)"); + } } -/// \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; - } +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); + + // 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)); } - 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; + // 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)); + } - // 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); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); + // setup the object + pyb_adc_obj_t *self = &pyb_adc_obj; + self->base.type = &pyb_adc_type; -/// \method init() -/// Enable the adc channel -STATIC mp_obj_t adc_init(mp_obj_t self_in) { - pyb_adc_obj_t *self = self_in; + // 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; +} - 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, +}; |
