Skip to content

Commit abc24c1

Browse files
committed
stmhal: Allow DAC.write_timed to take Timer object in place of freq.
This allows the DAC to use a user-specified Timer for the triggering (instead of the default Timer(6)), while still supporting original behaviour. Addresses issues adafruit#1129 and adafruit#1388.
1 parent 6f5e0fe commit abc24c1

File tree

4 files changed

+81
-10
lines changed

4 files changed

+81
-10
lines changed

docs/library/pyb.DAC.rst

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ Methods
6464
Initiates a burst of RAM to DAC using a DMA transfer.
6565
The input data is treated as an array of bytes (8 bit data).
6666

67+
``freq`` can be an integer specifying the frequency to write the DAC
68+
samples at, using Timer(6). Or it can be an already-initialised
69+
Timer object which is used to trigger the DAC sample. Valid timers
70+
are 2, 4, 5, 6, 7 and 8.
71+
6772
``mode`` can be ``DAC.NORMAL`` or ``DAC.CIRCULAR``.
68-
69-
TIM6 is used to control the frequency of the transfer.
73+
74+
Example using both DACs at the same time::
75+
76+
dac1 = DAC(1)
77+
dac2 = DAC(2)
78+
dac1.write_timed(buf1, pyb.Timer(6, freq=100), mode=DAC.CIRCULAR)
79+
dac2.write_timed(buf2, pyb.Timer(7, freq=200), mode=DAC.CIRCULAR)

stmhal/dac.c

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,51 @@ STATIC void TIM6_Config(uint freq) {
9393
}
9494
#endif
9595

96+
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+
102+
// TRGO selection to trigger DAC
103+
TIM_HandleTypeDef *tim = pyb_timer_get_handle(timer);
104+
TIM_MasterConfigTypeDef config;
105+
config.MasterOutputTrigger = TIM_TRGO_UPDATE;
106+
config.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
107+
HAL_TIMEx_MasterConfigSynchronization(tim, &config);
108+
109+
// work out the trigger channel (only certain ones are supported)
110+
if (tim->Instance == TIM2) {
111+
return DAC_TRIGGER_T2_TRGO;
112+
} else if (tim->Instance == TIM4) {
113+
return DAC_TRIGGER_T4_TRGO;
114+
} else if (tim->Instance == TIM5) {
115+
return DAC_TRIGGER_T5_TRGO;
116+
#if defined(TIM6)
117+
} else if (tim->Instance == TIM6) {
118+
return DAC_TRIGGER_T6_TRGO;
119+
#endif
120+
#if defined(TIM7)
121+
} else if (tim->Instance == TIM7) {
122+
return DAC_TRIGGER_T7_TRGO;
123+
#endif
124+
#if defined(TIM8)
125+
} else if (tim->Instance == TIM8) {
126+
return DAC_TRIGGER_T8_TRGO;
127+
#endif
128+
} else {
129+
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Timer does not support DAC triggering"));
130+
}
131+
}
132+
96133
/******************************************************************************/
97134
// Micro Python bindings
98135

99136
typedef enum {
100137
DAC_STATE_RESET,
101138
DAC_STATE_WRITE_SINGLE,
102139
DAC_STATE_BUILTIN_WAVEFORM,
103-
DAC_STATE_DMA_WAVEFORM,
140+
DAC_STATE_DMA_WAVEFORM, // should be last enum since we use space beyond it
104141
} pyb_dac_state_t;
105142

106143
typedef struct _pyb_dac_obj_t {
@@ -260,15 +297,25 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(pyb_dac_write_obj, pyb_dac_write);
260297
/// Initiates a burst of RAM to DAC using a DMA transfer.
261298
/// The input data is treated as an array of bytes (8 bit data).
262299
///
300+
/// `freq` can be an integer specifying the frequency to write the DAC
301+
/// samples at, using Timer(6). Or it can be an already-initialised
302+
/// Timer object which is used to trigger the DAC sample. Valid timers
303+
/// are 2, 4, 5, 6, 7 and 8.
304+
///
263305
/// `mode` can be `DAC.NORMAL` or `DAC.CIRCULAR`.
264306
///
265-
/// TIM6 is used to control the frequency of the transfer.
266307
// TODO add callback argument, to call when transfer is finished
267308
// TODO add double buffer argument
309+
//
310+
// TODO reconsider API, eg: write_trig(data, *, trig=None, loop=False)
311+
// Then trigger can be timer (preinitialised with desired freq) or pin (extint9),
312+
// and we can reuse the same timer for both DACs (and maybe also ADC) without
313+
// setting the freq twice.
314+
// Can still do 1-liner: dac.write_trig(buf, trig=Timer(6, freq=100), loop=True)
268315
mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
269316
static const mp_arg_t allowed_args[] = {
270317
{ MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
271-
{ MP_QSTR_freq, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
318+
{ MP_QSTR_freq, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
272319
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DMA_NORMAL} },
273320
};
274321

@@ -281,8 +328,15 @@ mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
281328
mp_buffer_info_t bufinfo;
282329
mp_get_buffer_raise(args[0].u_obj, &bufinfo, MP_BUFFER_READ);
283330

284-
// set TIM6 to trigger the DAC at the given frequency
285-
TIM6_Config(args[1].u_int);
331+
uint32_t dac_trigger;
332+
if (mp_obj_is_integer(args[1].u_obj)) {
333+
// set TIM6 to trigger the DAC at the given frequency
334+
TIM6_Config(mp_obj_get_int(args[1].u_obj));
335+
dac_trigger = DAC_TRIGGER_T6_TRGO;
336+
} else {
337+
// set the supplied timer to trigger the DAC (timer should be initialised)
338+
dac_trigger = TIMx_Config(args[1].u_obj);
339+
}
286340

287341
__DMA1_CLK_ENABLE();
288342

@@ -336,12 +390,12 @@ mp_obj_t pyb_dac_write_timed(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
336390
DAC_Handle.State = HAL_DAC_STATE_RESET;
337391
HAL_DAC_Init(&DAC_Handle);
338392

339-
if (self->state != DAC_STATE_DMA_WAVEFORM) {
393+
if (self->state != DAC_STATE_DMA_WAVEFORM + dac_trigger) {
340394
DAC_ChannelConfTypeDef config;
341-
config.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
395+
config.DAC_Trigger = dac_trigger;
342396
config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
343397
HAL_DAC_ConfigChannel(&DAC_Handle, &config, self->dac_channel);
344-
self->state = DAC_STATE_DMA_WAVEFORM;
398+
self->state = DAC_STATE_DMA_WAVEFORM + dac_trigger;
345399
}
346400

347401
HAL_DAC_Start_DMA(&DAC_Handle, self->dac_channel, (uint32_t*)bufinfo.buf, bufinfo.len, DAC_ALIGN_8B_R);

stmhal/timer.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,11 @@ STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks) {
470470
HAL_TIMEx_ConfigBreakDeadTime(&self->tim, &deadTimeConfig);
471471
}
472472

473+
TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer) {
474+
pyb_timer_obj_t *self = timer;
475+
return &self->tim;
476+
}
477+
473478
STATIC void pyb_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
474479
pyb_timer_obj_t *self = self_in;
475480

stmhal/timer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,5 @@ void timer_tim6_init(uint freq);
4343
void timer_deinit(void);
4444

4545
void timer_irq_handler(uint tim_id);
46+
47+
TIM_HandleTypeDef *pyb_timer_get_handle(mp_obj_t timer);

0 commit comments

Comments
 (0)