Commit 7693ef3b authored by Damien George's avatar Damien George
Browse files

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.
parent 99a21dc0
...@@ -63,14 +63,32 @@ Methods ...@@ -63,14 +63,32 @@ Methods
.. only:: port_pyboard .. 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 Read analog values into ``buf`` at a rate set by the ``timer`` object.
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. ``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
Example:: 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 adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
buf = bytearray(100) # create a buffer of 100 bytes buf = bytearray(100) # create a buffer of 100 bytes
adc.read_timed(buf, 10) # read analog values into buf at 10Hz adc.read_timed(buf, 10) # read analog values into buf at 10Hz
......
...@@ -198,12 +198,31 @@ STATIC mp_obj_t adc_read(mp_obj_t self_in) { ...@@ -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); STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
/// \method read_timed(buf, freq) /// \method 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 /// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
/// buf = bytearray(100) # create a buffer of 100 bytes /// 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); ...@@ -213,7 +232,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
/// print(val) # print the value out /// print(val) # print the value out
/// ///
/// This function does not allocate any memory. /// 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) { 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; 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_ ...@@ -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); mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL); size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL);
// Init TIM6 at the required frequency (in Hz) TIM_HandleTypeDef *tim;
timer_tim6_init(mp_obj_get_int(freq_in)); #if defined(TIM6)
if (mp_obj_is_integer(freq_in)) {
// Start timer // freq in Hz given so init TIM6 (legacy behaviour)
HAL_TIM_Base_Start(&TIM6_Handle); 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 // configure the ADC channel
adc_config_channel(self); 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_ ...@@ -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; uint nelems = bufinfo.len / typesize;
for (uint index = 0; index < nelems; index++) { for (uint index = 0; index < nelems; index++) {
// Wait for the timer to trigger so we sample at the correct frequency // 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) { if (index == 0) {
// for the first sample we need to turn the ADC on // 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_ ...@@ -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 // turn the ADC off
HAL_ADC_Stop(&self->handle); HAL_ADC_Stop(&self->handle);
// Stop timer #if defined(TIM6)
HAL_TIM_Base_Stop(&TIM6_Handle); 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); return mp_obj_new_int(bufinfo.len);
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed); 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[] = { 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_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}, { 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); STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
......
...@@ -80,25 +80,20 @@ void dac_init(void) { ...@@ -80,25 +80,20 @@ void dac_init(void) {
#if defined(TIM6) #if defined(TIM6)
STATIC void TIM6_Config(uint freq) { STATIC void TIM6_Config(uint freq) {
// Init TIM6 at the required frequency (in Hz) // Init TIM6 at the required frequency (in Hz)
timer_tim6_init(freq); TIM_HandleTypeDef *tim = timer_tim6_init(freq);
// TIM6 TRGO selection // TIM6 TRGO selection
TIM_MasterConfigTypeDef config; TIM_MasterConfigTypeDef config;
config.MasterOutputTrigger = TIM_TRGO_UPDATE; config.MasterOutputTrigger = TIM_TRGO_UPDATE;
config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&TIM6_Handle, &config); HAL_TIMEx_MasterConfigSynchronization(tim, &config);
// TIM6 start counter // TIM6 start counter
HAL_TIM_Base_Start(&TIM6_Handle); HAL_TIM_Base_Start(tim);
} }
#endif #endif
STATIC uint32_t TIMx_Config(mp_obj_t timer) { 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 // TRGO selection to trigger DAC
TIM_HandleTypeDef *tim = pyb_timer_get_handle(timer); TIM_HandleTypeDef *tim = pyb_timer_get_handle(timer);
TIM_MasterConfigTypeDef config; TIM_MasterConfigTypeDef config;
......
...@@ -227,7 +227,7 @@ void timer_tim5_init(void) { ...@@ -227,7 +227,7 @@ void timer_tim5_init(void) {
// Init TIM6 with a counter-overflow at the given frequency (given in Hz) // 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 // TIM6 is used by the DAC and ADC for auto sampling at a given frequency
// This function inits but does not start the timer // 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 clock enable
__TIM6_CLK_ENABLE(); __TIM6_CLK_ENABLE();
...@@ -247,6 +247,8 @@ void timer_tim6_init(uint freq) { ...@@ -247,6 +247,8 @@ void timer_tim6_init(uint freq) {
TIM6_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // unused for TIM6 TIM6_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // unused for TIM6
TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6 TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
HAL_TIM_Base_Init(&TIM6_Handle); HAL_TIM_Base_Init(&TIM6_Handle);
return &TIM6_Handle;
} }
#endif #endif
...@@ -471,6 +473,9 @@ STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks) { ...@@ -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) { 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; pyb_timer_obj_t *self = timer;
return &self->tim; return &self->tim;
} }
......
...@@ -31,14 +31,13 @@ ...@@ -31,14 +31,13 @@
extern TIM_HandleTypeDef TIM3_Handle; extern TIM_HandleTypeDef TIM3_Handle;
extern TIM_HandleTypeDef TIM5_Handle; extern TIM_HandleTypeDef TIM5_Handle;
extern TIM_HandleTypeDef TIM6_Handle;
extern const mp_obj_type_t pyb_timer_type; extern const mp_obj_type_t pyb_timer_type;
void timer_init0(void); void timer_init0(void);
void timer_tim3_init(void); void timer_tim3_init(void);
void timer_tim5_init(void); void timer_tim5_init(void);
void timer_tim6_init(uint freq); TIM_HandleTypeDef *timer_tim6_init(uint freq);
void timer_deinit(void); void timer_deinit(void);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment