Skip to content

Commit 1ce916a

Browse files
committed
Merge pull request micropython#900 from dhylands/comp-deadtime
Add support for complimentary channel output and deadtime.
2 parents c36c75c + 1c79544 commit 1ce916a

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

stmhal/qstrdefsport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ Q(pulse_width_percent)
198198
Q(compare)
199199
Q(capture)
200200
Q(polarity)
201+
Q(deadtime)
201202

202203
// for ExtInt class
203204
Q(ExtInt)

stmhal/timer.c

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,59 @@ STATIC mp_obj_t compute_percent_from_pwm_value(uint32_t period, uint32_t cmp) {
414414
#endif
415415
}
416416

417+
// Computes the 8-bit value for the DTG field in the BDTR register.
418+
//
419+
// 1 tick = 1 count of the timer's clock (source_freq) divided by div.
420+
// 0-128 ticks in inrements of 1
421+
// 128-256 ticks in increments of 2
422+
// 256-512 ticks in increments of 8
423+
// 512-1008 ticks in increments of 16
424+
STATIC uint32_t compute_dtg_from_ticks(mp_int_t ticks) {
425+
if (ticks <= 0) {
426+
return 0;
427+
}
428+
if (ticks < 128) {
429+
return ticks;
430+
}
431+
if (ticks < 256) {
432+
return 0x80 | ((ticks - 128) / 2);
433+
}
434+
if (ticks < 512) {
435+
return 0xC0 | ((ticks - 256) / 8);
436+
}
437+
if (ticks < 1008) {
438+
return 0xE0 | ((ticks - 512) / 16);
439+
}
440+
return 0xFF;
441+
}
442+
443+
// Given the 8-bit value stored in the DTG field of the BDTR register, compute
444+
// the number of ticks.
445+
STATIC mp_int_t compute_ticks_from_dtg(uint32_t dtg) {
446+
if ((dtg & 0x80) == 0) {
447+
return dtg & 0x7F;
448+
}
449+
if ((dtg & 0xC0) == 0x80) {
450+
return 128 + ((dtg & 0x3F) * 2);
451+
}
452+
if ((dtg & 0xE0) == 0xC0) {
453+
return 256 + ((dtg & 0x1F) * 8);
454+
}
455+
return 512 + ((dtg & 0x1F) * 16);
456+
}
457+
458+
STATIC void config_deadtime(pyb_timer_obj_t *self, mp_int_t ticks) {
459+
TIM_BreakDeadTimeConfigTypeDef deadTimeConfig;
460+
deadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
461+
deadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
462+
deadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
463+
deadTimeConfig.DeadTime = compute_dtg_from_ticks(ticks);
464+
deadTimeConfig.BreakState = TIM_BREAK_DISABLE;
465+
deadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;
466+
deadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
467+
HAL_TIMEx_ConfigBreakDeadTime(&self->tim, &deadTimeConfig);
468+
}
469+
417470
STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
418471
pyb_timer_obj_t *self = self_in;
419472

@@ -424,7 +477,7 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
424477
uint32_t period = __HAL_TIM_GetAutoreload(&self->tim) & TIMER_CNT_MASK(self);
425478
// for efficiency, we compute and print freq as an int (not a float)
426479
uint32_t freq = timer_get_source_freq(self->tim_id) / ((prescaler + 1) * (period + 1));
427-
print(env, "Timer(%u, freq=%u, prescaler=%u, period=%u, mode=%s, div=%u)",
480+
print(env, "Timer(%u, freq=%u, prescaler=%u, period=%u, mode=%s, div=%u",
428481
self->tim_id,
429482
freq,
430483
prescaler,
@@ -433,6 +486,10 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
433486
self->tim.Init.CounterMode == TIM_COUNTERMODE_DOWN ? "DOWN" : "CENTER",
434487
self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV4 ? 4 :
435488
self->tim.Init.ClockDivision == TIM_CLOCKDIVISION_DIV2 ? 2 : 1);
489+
if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) {
490+
print(env, ", deadtime=%u", compute_ticks_from_dtg(self->tim.Instance->BDTR & TIM_BDTR_DTG));
491+
}
492+
print(env, ")");
436493
}
437494
}
438495

@@ -472,6 +529,14 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
472529
///
473530
/// - `callback` - as per Timer.callback()
474531
///
532+
/// - `deadtime` - specifies the amount of "dead" or inactive time between
533+
/// transitions on complimentary channels (both channels will be inactive)
534+
/// for this time). `deadtime` may be an integer between 0 and 1008, with
535+
/// the following restrictions: 0-128 in steps of 1. 128-256 in steps of
536+
/// 2, 256-512 in steps of 8, and 512-1008 in steps of 16. `deadime`
537+
/// measures ticks of `source_freq` divided by `div` clock ticks.
538+
/// `deadtime` is only available on timers 1 and 8.
539+
///
475540
/// You must either specify freq or both of period and prescaler.
476541
STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
477542
static const mp_arg_t allowed_args[] = {
@@ -481,6 +546,7 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, c
481546
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = TIM_COUNTERMODE_UP} },
482547
{ MP_QSTR_div, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
483548
{ MP_QSTR_callback, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} },
549+
{ MP_QSTR_deadtime, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
484550
};
485551

486552
// parse args
@@ -537,6 +603,9 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, c
537603

538604
// init TIM
539605
HAL_TIM_Base_Init(&self->tim);
606+
if (IS_TIM_ADVANCED_INSTANCE(self->tim.Instance)) {
607+
config_deadtime(self, args[6].u_int);
608+
}
540609
if (args[5].u_obj == mp_const_none) {
541610
HAL_TIM_Base_Start(&self->tim);
542611
} else {
@@ -685,6 +754,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
685754
/// - `Timer.FALLING` - captures on falling edge.
686755
/// - `Timer.BOTH` - captures on both edges.
687756
///
757+
/// Note that capture only works on the primary channel, and not on the
758+
/// complimentary channels.
759+
///
688760
/// PWM Example:
689761
///
690762
/// timer = pyb.Timer(2, freq=1000)
@@ -808,6 +880,10 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
808880
} else {
809881
HAL_TIM_PWM_Start_IT(&self->tim, TIMER_CHANNEL(chan));
810882
}
883+
// Start the complimentary channel too (if its supported)
884+
if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) {
885+
HAL_TIMEx_PWMN_Start(&self->tim, TIMER_CHANNEL(chan));
886+
}
811887
break;
812888
}
813889

@@ -824,7 +900,11 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
824900
if (oc_config.OCPolarity == 0xffffffff) {
825901
oc_config.OCPolarity = TIM_OCPOLARITY_HIGH;
826902
}
827-
oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
903+
if (oc_config.OCPolarity == TIM_OCPOLARITY_HIGH) {
904+
oc_config.OCNPolarity = TIM_OCNPOLARITY_HIGH;
905+
} else {
906+
oc_config.OCNPolarity = TIM_OCNPOLARITY_LOW;
907+
}
828908
oc_config.OCFastMode = TIM_OCFAST_DISABLE;
829909
oc_config.OCIdleState = TIM_OCIDLESTATE_SET;
830910
oc_config.OCNIdleState = TIM_OCNIDLESTATE_SET;
@@ -838,6 +918,10 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
838918
} else {
839919
HAL_TIM_OC_Start_IT(&self->tim, TIMER_CHANNEL(chan));
840920
}
921+
// Start the complimentary channel too (if its supported)
922+
if (IS_TIM_CCXN_INSTANCE(self->tim.Instance, TIMER_CHANNEL(chan))) {
923+
HAL_TIMEx_OCN_Start(&self->tim, TIMER_CHANNEL(chan));
924+
}
841925
break;
842926
}
843927

0 commit comments

Comments
 (0)