Skip to content

Commit 7693ef3

Browse files
committed
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 adafruit#1129.
1 parent 99a21dc commit 7693ef3

5 files changed

Lines changed: 79 additions & 36 deletions

File tree

docs/library/pyb.ADC.rst

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,32 @@ Methods
6363

6464
.. only:: port_pyboard
6565

66-
.. method:: adc.read_timed(buf, freq)
66+
.. method:: adc.read_timed(buf, timer)
6767

68-
Read analog values into the given buffer at the given frequency. Buffer
69-
can be bytearray or array.array for example. If a buffer with 8-bit elements
70-
is used, sample resolution will be reduced to 8 bits.
71-
72-
Example::
73-
68+
Read analog values into ``buf`` at a rate set by the ``timer`` object.
69+
70+
``buf`` can be bytearray or array.array for example. The ADC values have
71+
12-bit resolution and are stored directly into ``buf`` if its element size is
72+
16 bits or greater. If ``buf`` has only 8-bit elements (eg a bytearray) then
73+
the sample resolution will be reduced to 8 bits.
74+
75+
``timer`` should be a Timer object, and a sample is read each time the timer
76+
triggers. The timer must already be initialised and running at the desired
77+
sampling frequency.
78+
79+
To support previous behaviour of this function, ``timer`` can also be an
80+
integer which specifies the frequency (in Hz) to sample at. In this case
81+
Timer(6) will be automatically configured to run at the given frequency.
82+
83+
Example using a Timer object (preferred way)::
84+
85+
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
86+
tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz
87+
buf = bytearray(100) # creat a buffer to store the samples
88+
adc.read_timed(buf, tim) # sample 100 values, taking 10s
89+
90+
Example using an integer for the frequency::
91+
7492
adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
7593
buf = bytearray(100) # create a buffer of 100 bytes
7694
adc.read_timed(buf, 10) # read analog values into buf at 10Hz

stmhal/adc.c

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,31 @@ STATIC mp_obj_t adc_read(mp_obj_t self_in) {
198198
}
199199
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
200200

201-
/// \method read_timed(buf, freq)
202-
/// Read analog values into the given buffer at the given frequency. Buffer
203-
/// can be bytearray or array.array for example. If a buffer with 8-bit elements
204-
/// is used, sample resolution will be reduced to 8 bits.
201+
/// \method read_timed(buf, timer)
205202
///
206-
/// Example:
203+
/// Read analog values into `buf` at a rate set by the `timer` object.
204+
///
205+
/// `buf` can be bytearray or array.array for example. The ADC values have
206+
/// 12-bit resolution and are stored directly into `buf` if its element size is
207+
/// 16 bits or greater. If `buf` has only 8-bit elements (eg a bytearray) then
208+
/// the sample resolution will be reduced to 8 bits.
209+
///
210+
/// `timer` should be a Timer object, and a sample is read each time the timer
211+
/// triggers. The timer must already be initialised and running at the desired
212+
/// sampling frequency.
213+
///
214+
/// To support previous behaviour of this function, `timer` can also be an
215+
/// integer which specifies the frequency (in Hz) to sample at. In this case
216+
/// Timer(6) will be automatically configured to run at the given frequency.
217+
///
218+
/// Example using a Timer object (preferred way):
219+
///
220+
/// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
221+
/// tim = pyb.Timer(6, freq=10) # create a timer running at 10Hz
222+
/// buf = bytearray(100) # creat a buffer to store the samples
223+
/// adc.read_timed(buf, tim) # sample 100 values, taking 10s
224+
///
225+
/// Example using an integer for the frequency:
207226
///
208227
/// adc = pyb.ADC(pyb.Pin.board.X19) # create an ADC on pin X19
209228
/// buf = bytearray(100) # create a buffer of 100 bytes
@@ -213,19 +232,25 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, adc_read);
213232
/// print(val) # print the value out
214233
///
215234
/// This function does not allocate any memory.
216-
#if defined(TIM6)
217235
STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_in) {
218236
pyb_obj_adc_t *self = self_in;
219237

220238
mp_buffer_info_t bufinfo;
221239
mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE);
222240
size_t typesize = mp_binary_get_size('@', bufinfo.typecode, NULL);
223241

224-
// Init TIM6 at the required frequency (in Hz)
225-
timer_tim6_init(mp_obj_get_int(freq_in));
226-
227-
// Start timer
228-
HAL_TIM_Base_Start(&TIM6_Handle);
242+
TIM_HandleTypeDef *tim;
243+
#if defined(TIM6)
244+
if (mp_obj_is_integer(freq_in)) {
245+
// freq in Hz given so init TIM6 (legacy behaviour)
246+
tim = timer_tim6_init(mp_obj_get_int(freq_in));
247+
HAL_TIM_Base_Start(tim);
248+
} else
249+
#endif
250+
{
251+
// use the supplied timer object as the sampling time base
252+
tim = pyb_timer_get_handle(freq_in);
253+
}
229254

230255
// configure the ADC channel
231256
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_
236261
uint nelems = bufinfo.len / typesize;
237262
for (uint index = 0; index < nelems; index++) {
238263
// Wait for the timer to trigger so we sample at the correct frequency
239-
while (__HAL_TIM_GET_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE) == RESET) {
264+
while (__HAL_TIM_GET_FLAG(tim, TIM_FLAG_UPDATE) == RESET) {
240265
}
241-
__HAL_TIM_CLEAR_FLAG(&TIM6_Handle, TIM_FLAG_UPDATE);
266+
__HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
242267

243268
if (index == 0) {
244269
// 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_
270295
// turn the ADC off
271296
HAL_ADC_Stop(&self->handle);
272297

273-
// Stop timer
274-
HAL_TIM_Base_Stop(&TIM6_Handle);
298+
#if defined(TIM6)
299+
if (mp_obj_is_integer(freq_in)) {
300+
// stop timer if we initialised TIM6 in this function (legacy behaviour)
301+
HAL_TIM_Base_Stop(tim);
302+
}
303+
#endif
275304

276305
return mp_obj_new_int(bufinfo.len);
277306
}
278307
STATIC MP_DEFINE_CONST_FUN_OBJ_3(adc_read_timed_obj, adc_read_timed);
279-
#endif
280308

281309
STATIC const mp_map_elem_t adc_locals_dict_table[] = {
282310
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
283-
#if defined(TIM6)
284311
{ MP_OBJ_NEW_QSTR(MP_QSTR_read_timed), (mp_obj_t)&adc_read_timed_obj},
285-
#endif
286312
};
287313

288314
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);

stmhal/dac.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,25 +80,20 @@ void dac_init(void) {
8080
#if defined(TIM6)
8181
STATIC void TIM6_Config(uint freq) {
8282
// Init TIM6 at the required frequency (in Hz)
83-
timer_tim6_init(freq);
83+
TIM_HandleTypeDef *tim = timer_tim6_init(freq);
8484

8585
// TIM6 TRGO selection
8686
TIM_MasterConfigTypeDef config;
8787
config.MasterOutputTrigger = TIM_TRGO_UPDATE;
8888
config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
89-
HAL_TIMEx_MasterConfigSynchronization(&TIM6_Handle, &config);
89+
HAL_TIMEx_MasterConfigSynchronization(tim, &config);
9090

9191
// TIM6 start counter
92-
HAL_TIM_Base_Start(&TIM6_Handle);
92+
HAL_TIM_Base_Start(tim);
9393
}
9494
#endif
9595

9696
STATIC uint32_t TIMx_Config(mp_obj_t timer) {
97-
// make sure the given object is a timer
98-
if (mp_obj_get_type(timer) != &pyb_timer_type) {
99-
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a Timer object"));
100-
}
101-
10297
// TRGO selection to trigger DAC
10398
TIM_HandleTypeDef *tim = pyb_timer_get_handle(timer);
10499
TIM_MasterConfigTypeDef config;

stmhal/timer.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ void timer_tim5_init(void) {
227227
// Init TIM6 with a counter-overflow at the given frequency (given in Hz)
228228
// TIM6 is used by the DAC and ADC for auto sampling at a given frequency
229229
// This function inits but does not start the timer
230-
void timer_tim6_init(uint freq) {
230+
TIM_HandleTypeDef *timer_tim6_init(uint freq) {
231231
// TIM6 clock enable
232232
__TIM6_CLK_ENABLE();
233233

@@ -247,6 +247,8 @@ void timer_tim6_init(uint freq) {
247247
TIM6_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // unused for TIM6
248248
TIM6_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // unused for TIM6
249249
HAL_TIM_Base_Init(&TIM6_Handle);
250+
251+
return &TIM6_Handle;
250252
}
251253
#endif
252254

@@ -471,6 +473,9 @@ STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks) {
471473
}
472474

473475
TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer) {
476+
if (mp_obj_get_type(timer) != &pyb_timer_type) {
477+
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a Timer object"));
478+
}
474479
pyb_timer_obj_t *self = timer;
475480
return &self->tim;
476481
}

stmhal/timer.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,13 @@
3131

3232
extern TIM_HandleTypeDef TIM3_Handle;
3333
extern TIM_HandleTypeDef TIM5_Handle;
34-
extern TIM_HandleTypeDef TIM6_Handle;
3534

3635
extern const mp_obj_type_t pyb_timer_type;
3736

3837
void timer_init0(void);
3938
void timer_tim3_init(void);
4039
void timer_tim5_init(void);
41-
void timer_tim6_init(uint freq);
40+
TIM_HandleTypeDef *timer_tim6_init(uint freq);
4241

4342
void timer_deinit(void);
4443

0 commit comments

Comments
 (0)