From 7693ef3bd6e4456105c86909174a00f535a19261 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 22 Jul 2015 19:37:21 +0100 Subject: [PATCH] stmhal: Allow ADC.read_timed to take Timer object in place of freq. This allows a user-specified Timer for the triggering of the ADC read, mirroring the new behaviour of DAC.write_timed. Addresses issue #1129. --- docs/library/pyb.ADC.rst | 32 ++++++++++++++++----- stmhal/adc.c | 62 ++++++++++++++++++++++++++++------------ stmhal/dac.c | 11 ++----- stmhal/timer.c | 7 ++++- stmhal/timer.h | 3 +- 5 files changed, 79 insertions(+), 36 deletions(-) diff --git a/docs/library/pyb.ADC.rst b/docs/library/pyb.ADC.rst index 64848d5779..36c376d375 100644 --- a/docs/library/pyb.ADC.rst +++ b/docs/library/pyb.ADC.rst @@ -63,14 +63,32 @@ Methods .. only:: port_pyboard - .. method:: adc.read_timed(buf, freq) + .. method:: adc.read_timed(buf, timer) - Read analog values into the given buffer at the given frequency. Buffer - can be bytearray or array.array for example. If a buffer with 8-bit elements - is used, sample resolution will be reduced to 8 bits. - - Example:: - + Read analog values into ``buf`` at a rate set by the ``timer`` object. + + ``buf`` can be bytearray or array.array for example. The ADC values have + 12-bit resolution and are stored directly into ``buf`` if its element size is + 16 bits or greater. If ``buf`` has only 8-bit elements (eg a bytearray) then + the sample resolution will be reduced to 8 bits. + + ``timer`` should be a Timer object, and a sample is read each time the timer + triggers. The timer must already be initialised and running at the desired + sampling frequency. + + To support previous behaviour of this function, ``timer`` can also be an + integer which specifies the frequency (in Hz) to sample at. In this case + Timer(6) will be automatically configured to run at the given frequency. + + Example using a Timer object (preferred way):: + + adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19 + tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz + buf = bytearray(100) # creat a buffer to store the samples + adc.read_timed(buf, tim) # sample 100 values, taking 10s + + Example using an integer for the frequency:: + adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19 buf = bytearray(100) # create a buffer of 100 bytes adc.read_timed(buf, 10) # read analog values into buf at 10Hz diff --git a/stmhal/adc.c b/stmhal/adc.c index 27cccda576..9ec8eac725 100644 --- a/stmhal/adc.c +++ b/stmhal/adc.c @@ -198,12 +198,31 @@ STATIC mp_obj_t adc_read(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); -/// \method read_timed(buf, freq) -/// Read analog values into the given buffer at the given frequency. Buffer -/// can be bytearray or array.array for example. If a buffer with 8-bit elements -/// is used, sample resolution will be reduced to 8 bits. +/// \method read_timed(buf, timer) /// -/// Example: +/// Read analog values into `buf` at a rate set by the `timer` object. +/// +/// `buf` can be bytearray or array.array for example. The ADC values have +/// 12-bit resolution and are stored directly into `buf` if its element size is +/// 16 bits or greater. If `buf` has only 8-bit elements (eg a bytearray) then +/// the sample resolution will be reduced to 8 bits. +/// +/// `timer` should be a Timer object, and a sample is read each time the timer +/// triggers. The timer must already be initialised and running at the desired +/// sampling frequency. +/// +/// To support previous behaviour of this function, `timer` can also be an +/// integer which specifies the frequency (in Hz) to sample at. In this case +/// Timer(6) will be automatically configured to run at the given frequency. +/// +/// Example using a Timer object (preferred way): +/// +/// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19 +/// tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz +/// buf = bytearray(100) # creat a buffer to store the samples +/// adc.read_timed(buf, tim) # sample 100 values, taking 10s +/// +/// Example using an integer for the frequency: /// /// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19 /// buf = bytearray(100) # create a buffer of 100 bytes @@ -213,7 +232,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read); /// print(val) # print the value out /// /// This function does not allocate any memory. -#if defined(TIM6) STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) { pyb_obj_adc_t *self = self_in; @@ -221,11 +239,18 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); - // Init TIM6 at the required frequency (in Hz) - timer_tim6_init(mp_obj_get_int(freq_in)); - - // Start timer - HAL_TIM_Base_Start(&TIM6_Handle); + TIM_HandleTypeDef *tim; + #if defined(TIM6) + if (mp_obj_is_integer(freq_in)) { + // freq in Hz given so init TIM6 (legacy behaviour) + tim = timer_tim6_init(mp_obj_get_int(freq_in)); + HAL_TIM_Base_Start(tim); + } else + #endif + { + // use the supplied timer object as the sampling time base + tim = pyb_timer_get_handle(freq_in); + } // configure the ADC channel adc_config_channel(self); @@ -236,9 +261,9 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ uint nelems = bufinfo.len / typesize; for (uint index = 0; index < nelems; index++) { // Wait for the timer to trigger so we sample at the correct frequency - while (__HAL_TIM_GET_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE) == RESET) { + while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) { } - __HAL_TIM_CLEAR_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE); + __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); if (index == 0) { // for the first sample we need to turn the ADC on @@ -270,19 +295,20 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_ // turn the ADC off HAL_ADC_Stop(&self->handle); - // Stop timer - HAL_TIM_Base_Stop(&TIM6_Handle); + #if defined(TIM6) + if (mp_obj_is_integer(freq_in)) { + // stop timer if we initialised TIM6 in this function (legacy behaviour) + HAL_TIM_Base_Stop(tim); + } + #endif return mp_obj_new_int(bufinfo.len); } STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed); -#endif STATIC const mp_map_elem_t adc_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj}, - #if defined(TIM6) { MP_OBJ_NEW_QSTR(MP_QSTR_read_timed), (mp_obj_t)&adc_read_timed_obj}, - #endif }; STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table); diff --git a/stmhal/dac.c b/stmhal/dac.c index d71543ff2e..b1e688442a 100644 --- a/stmhal/dac.c +++ b/stmhal/dac.c @@ -80,25 +80,20 @@ void dac_init(void) { #if defined(TIM6) STATIC void TIM6_Config(uint freq) { // Init TIM6 at the required frequency (in Hz) - timer_tim6_init(freq); + TIM_HandleTypeDef *tim = timer_tim6_init(freq); // TIM6 TRGO selection TIM_MasterConfigTypeDef config; config.MasterOutputTrigger = TIM_TRGO_UPDATE; config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - HAL_TIMEx_MasterConfigSynchronization(&TIM6_Handle, &config); + HAL_TIMEx_MasterConfigSynchronization(tim, &config); // TIM6 start counter - HAL_TIM_Base_Start(&TIM6_Handle); + HAL_TIM_Base_Start(tim); } #endif STATIC uint32_t TIMx_Config(mp_obj_t timer) { - // make sure the given object is a timer - if (mp_obj_get_type(timer) != &pyb_timer_type) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a Timer object")); - } - // TRGO selection to trigger DAC TIM_HandleTypeDef *tim = pyb_timer_get_handle(timer); TIM_MasterConfigTypeDef config; diff --git a/stmhal/timer.c b/stmhal/timer.c index 3519c3c150..002e6b4296 100644 --- a/stmhal/timer.c +++ b/stmhal/timer.c @@ -227,7 +227,7 @@ void timer_tim5_init(void) { // Init TIM6 with a counter-overflow at the given frequency (given in Hz) // TIM6 is used by the DAC and ADC for auto sampling at a given frequency // This function inits but does not start the timer -void timer_tim6_init(uint freq) { +TIM_HandleTypeDef *timer_tim6_init(uint freq) { // TIM6 clock enable __TIM6_CLK_ENABLE(); @@ -247,6 +247,8 @@ void timer_tim6_init(uint freq) { TIM6_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // unused for TIM6 TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6 HAL_TIM_Base_Init(&TIM6_Handle); + + return &TIM6_Handle; } #endif @@ -471,6 +473,9 @@ STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks) { } TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer) { + if (mp_obj_get_type(timer) != &pyb_timer_type) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a Timer object")); + } pyb_timer_obj_t *self = timer; return &self->tim; } diff --git a/stmhal/timer.h b/stmhal/timer.h index 879d7ae5d7..8988197c0f 100644 --- a/stmhal/timer.h +++ b/stmhal/timer.h @@ -31,14 +31,13 @@ extern TIM_HandleTypeDef TIM3_Handle; extern TIM_HandleTypeDef TIM5_Handle; -extern TIM_HandleTypeDef TIM6_Handle; extern const mp_obj_type_t pyb_timer_type; void timer_init0(void); void timer_tim3_init(void); void timer_tim5_init(void); -void timer_tim6_init(uint freq); +TIM_HandleTypeDef *timer_tim6_init(uint freq); void timer_deinit(void);