@@ -133,7 +133,6 @@ typedef struct _pyb_timer_obj_t {
133133 TIM_HandleTypeDef tim ;
134134 IRQn_Type irqn ;
135135 pyb_timer_channel_obj_t * channel ;
136-
137136} pyb_timer_obj_t ;
138137
139138// The following yields TIM_IT_UPDATE when channel is zero and
@@ -153,6 +152,7 @@ STATIC uint32_t tim3_counter = 0;
153152STATIC pyb_timer_obj_t * pyb_timer_obj_all [14 ];
154153#define PYB_TIMER_OBJ_ALL_NUM MP_ARRAY_SIZE(pyb_timer_obj_all)
155154
155+ STATIC uint32_t timer_get_source_freq (uint32_t tim_id );
156156STATIC mp_obj_t pyb_timer_deinit (mp_obj_t self_in );
157157STATIC mp_obj_t pyb_timer_callback (mp_obj_t self_in , mp_obj_t callback );
158158STATIC mp_obj_t pyb_timer_channel_callback (mp_obj_t self_in , mp_obj_t callback );
@@ -181,7 +181,7 @@ void timer_tim3_init(void) {
181181
182182 TIM3_Handle .Instance = TIM3 ;
183183 TIM3_Handle .Init .Period = (USBD_CDC_POLLING_INTERVAL * 1000 ) - 1 ; // TIM3 fires every USBD_CDC_POLLING_INTERVAL ms
184- TIM3_Handle .Init .Prescaler = 2 * HAL_RCC_GetPCLK1Freq ( ) / 1000000 - 1 ; // TIM3 runs at 1MHz
184+ TIM3_Handle .Init .Prescaler = timer_get_source_freq ( 3 ) / 1000000 - 1 ; // TIM3 runs at 1MHz
185185 TIM3_Handle .Init .ClockDivision = TIM_CLOCKDIVISION_DIV1 ;
186186 TIM3_Handle .Init .CounterMode = TIM_COUNTERMODE_UP ;
187187 HAL_TIM_Base_Init (& TIM3_Handle );
@@ -215,7 +215,7 @@ void timer_tim5_init(void) {
215215 // PWM clock configuration
216216 TIM5_Handle .Instance = TIM5 ;
217217 TIM5_Handle .Init .Period = 2000 - 1 ; // timer cycles at 50Hz
218- TIM5_Handle .Init .Prescaler = (( SystemCoreClock / 2 ) / 100000 ) - 1 ; // timer runs at 100kHz
218+ TIM5_Handle .Init .Prescaler = (timer_get_source_freq ( 5 ) / 100000 ) - 1 ; // timer runs at 100kHz
219219 TIM5_Handle .Init .ClockDivision = TIM_CLOCKDIVISION_DIV1 ;
220220 TIM5_Handle .Init .CounterMode = TIM_COUNTERMODE_UP ;
221221
@@ -231,7 +231,7 @@ void timer_tim6_init(uint freq) {
231231
232232 // Timer runs at SystemCoreClock / 2
233233 // Compute the prescaler value so TIM6 triggers at freq-Hz
234- uint32_t period = MAX (1 , ( SystemCoreClock / 2 ) / freq );
234+ uint32_t period = MAX (1 , timer_get_source_freq ( 6 ) / freq );
235235 uint32_t prescaler = 1 ;
236236 while (period > 0xffff ) {
237237 period >>= 1 ;
@@ -263,6 +263,29 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
263263 }
264264}
265265
266+ // Get the frequency (in Hz) of the source clock for the given timer.
267+ // On STM32F405/407/415/417 there are 2 cases for how the clock freq is set.
268+ // If the APB prescaler is 1, then the timer clock is equal to its respective
269+ // APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its
270+ // respective APB clock. See DM00031020 Rev 4, page 115.
271+ STATIC uint32_t timer_get_source_freq (uint32_t tim_id ) {
272+ uint32_t source ;
273+ if (tim_id == 1 || (8 <= tim_id && tim_id <= 11 )) {
274+ // TIM{1,8,9,10,11} are on APB2
275+ source = HAL_RCC_GetPCLK2Freq ();
276+ if ((uint32_t )((RCC -> CFGR & RCC_CFGR_PPRE2 ) >> 3 ) != RCC_HCLK_DIV1 ) {
277+ source *= 2 ;
278+ }
279+ } else {
280+ // TIM{2,3,4,5,6,7,12,13,14} are on APB1
281+ source = HAL_RCC_GetPCLK1Freq ();
282+ if ((uint32_t )(RCC -> CFGR & RCC_CFGR_PPRE1 ) != RCC_HCLK_DIV1 ) {
283+ source *= 2 ;
284+ }
285+ }
286+ return source ;
287+ }
288+
266289/******************************************************************************/
267290/* Micro Python bindings */
268291
@@ -272,6 +295,37 @@ STATIC const mp_obj_type_t pyb_timer_channel_type;
272295// fit in a uint32_t.
273296#define MAX_PERIOD_DIV_100 42949672
274297
298+ // computes prescaler and period so TIM triggers at freq-Hz
299+ STATIC uint32_t compute_prescaler_period_from_freq (pyb_timer_obj_t * self , mp_obj_t freq_in , uint32_t * period_out ) {
300+ uint32_t source_freq = timer_get_source_freq (self -> tim_id );
301+ uint32_t prescaler = 1 ;
302+ uint32_t period ;
303+ if (0 ) {
304+ #if MICROPY_PY_BUILTINS_FLOAT
305+ } else if (MP_OBJ_IS_TYPE (freq_in , & mp_type_float )) {
306+ float freq = mp_obj_get_float (freq_in );
307+ if (freq <= 0 ) {
308+ goto bad_freq ;
309+ }
310+ period = MAX (1 , source_freq / freq );
311+ #endif
312+ } else {
313+ mp_int_t freq = mp_obj_get_int (freq_in );
314+ if (freq <= 0 ) {
315+ goto bad_freq ;
316+ bad_freq :
317+ nlr_raise (mp_obj_new_exception_msg (& mp_type_ValueError , "must have positive freq" ));
318+ }
319+ period = MAX (1 , source_freq / freq );
320+ }
321+ while (period > TIMER_CNT_MASK (self )) {
322+ prescaler <<= 1 ;
323+ period >>= 1 ;
324+ }
325+ * period_out = (period - 1 ) & TIMER_CNT_MASK (self );
326+ return (prescaler - 1 ) & 0xffff ;
327+ }
328+
275329// Helper function for determining the period used for calculating percent
276330STATIC uint32_t compute_period (pyb_timer_obj_t * self ) {
277331 // In center mode, compare == period corresponds to 100%
@@ -351,10 +405,15 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
351405 if (self -> tim .State == HAL_TIM_STATE_RESET ) {
352406 print (env , "Timer(%u)" , self -> tim_id );
353407 } else {
354- print (env , "Timer(%u, prescaler=%u, period=%u, mode=%s, div=%u)" ,
408+ uint32_t prescaler = self -> tim .Instance -> PSC & 0xffff ;
409+ uint32_t period = __HAL_TIM_GetAutoreload (& self -> tim ) & TIMER_CNT_MASK (self );
410+ // for efficiency, we compute and print freq as an int (not a float)
411+ uint32_t freq = timer_get_source_freq (self -> tim_id ) / ((prescaler + 1 ) * (period + 1 ));
412+ print (env , "Timer(%u, freq=%u, prescaler=%u, period=%u, mode=%s, div=%u)" ,
355413 self -> tim_id ,
356- self -> tim .Instance -> PSC & 0xffff ,
357- __HAL_TIM_GetAutoreload (& self -> tim ) & TIMER_CNT_MASK (self ),
414+ freq ,
415+ prescaler ,
416+ period ,
358417 self -> tim .Init .CounterMode == TIM_COUNTERMODE_UP ? "UP" :
359418 self -> tim .Init .CounterMode == TIM_COUNTERMODE_DOWN ? "DOWN" : "CENTER" ,
360419 self -> tim .Init .ClockDivision == TIM_CLOCKDIVISION_DIV4 ? 4 :
@@ -399,74 +458,46 @@ STATIC void pyb_timer_print(void (*print)(void *env, const char *fmt, ...), void
399458/// - `callback` - as per Timer.callback()
400459///
401460/// You must either specify freq or both of period and prescaler.
402- STATIC const mp_arg_t pyb_timer_init_args [] = {
403- { MP_QSTR_freq , MP_ARG_KW_ONLY | MP_ARG_INT , {. u_int = 0xffffffff } },
404- { MP_QSTR_prescaler , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0xffffffff } },
405- { MP_QSTR_period , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0xffffffff } },
406- { MP_QSTR_mode , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = TIM_COUNTERMODE_UP } },
407- { MP_QSTR_div , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 1 } },
408- { MP_QSTR_callback , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = mp_const_none } },
409- };
410- #define PYB_TIMER_INIT_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_init_args)
461+ 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 ) {
462+ static const mp_arg_t allowed_args [] = {
463+ { MP_QSTR_freq , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = mp_const_none } },
464+ { MP_QSTR_prescaler , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0xffffffff } },
465+ { MP_QSTR_period , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0xffffffff } },
466+ { MP_QSTR_mode , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = TIM_COUNTERMODE_UP } },
467+ { MP_QSTR_div , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 1 } },
468+ { MP_QSTR_callback , MP_ARG_KW_ONLY | MP_ARG_OBJ , {. u_obj = mp_const_none } },
469+ };
411470
412- STATIC mp_obj_t pyb_timer_init_helper (pyb_timer_obj_t * self , mp_uint_t n_args , const mp_obj_t * args , mp_map_t * kw_args ) {
413471 // parse args
414- mp_arg_val_t vals [ PYB_TIMER_INIT_NUM_ARGS ];
415- mp_arg_parse_all (n_args , args , kw_args , PYB_TIMER_INIT_NUM_ARGS , pyb_timer_init_args , vals );
472+ mp_arg_val_t args [ MP_ARRAY_SIZE ( allowed_args ) ];
473+ mp_arg_parse_all (n_args , pos_args , kw_args , MP_ARRAY_SIZE ( allowed_args ), allowed_args , args );
416474
417475 // set the TIM configuration values
418476 TIM_Base_InitTypeDef * init = & self -> tim .Init ;
419477
420- if (vals [0 ].u_int != 0xffffffff ) {
421- // set prescaler and period from frequency
422-
423- if (vals [0 ].u_int == 0 ) {
424- nlr_raise (mp_obj_new_exception_msg (& mp_type_ValueError , "can't have 0 frequency" ));
425- }
426-
427- // work out TIM's clock source
428- uint tim_clock ;
429- if (self -> tim_id == 1 || (8 <= self -> tim_id && self -> tim_id <= 11 )) {
430- // TIM{1,8,9,10,11} are on APB2
431- tim_clock = HAL_RCC_GetPCLK2Freq ();
432- } else {
433- // TIM{2,3,4,5,6,7,12,13,14} are on APB1
434- tim_clock = HAL_RCC_GetPCLK1Freq ();
435- }
436-
437- // Compute the prescaler value so TIM triggers at freq-Hz
438- // On STM32F405/407/415/417 there are 2 cases for how the clock freq is set.
439- // If the APB prescaler is 1, then the timer clock is equal to its respective
440- // APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its
441- // respective APB clock. See DM00031020 Rev 4, page 115.
442- uint32_t period = MAX (1 , 2 * tim_clock / vals [0 ].u_int );
443- uint32_t prescaler = 1 ;
444- while (period > TIMER_CNT_MASK (self )) {
445- period >>= 1 ;
446- prescaler <<= 1 ;
447- }
448- init -> Prescaler = prescaler - 1 ;
449- init -> Period = period - 1 ;
450- } else if (vals [1 ].u_int != 0xffffffff && vals [2 ].u_int != 0xffffffff ) {
478+ if (args [0 ].u_obj != mp_const_none ) {
479+ // set prescaler and period from desired frequency
480+ init -> Prescaler = compute_prescaler_period_from_freq (self , args [0 ].u_obj , & init -> Period );
481+ } else if (args [1 ].u_int != 0xffffffff && args [2 ].u_int != 0xffffffff ) {
451482 // set prescaler and period directly
452- init -> Prescaler = vals [1 ].u_int ;
453- init -> Period = vals [2 ].u_int ;
483+ init -> Prescaler = args [1 ].u_int ;
484+ init -> Period = args [2 ].u_int ;
454485 } else {
455486 nlr_raise (mp_obj_new_exception_msg (& mp_type_TypeError , "must specify either freq, or prescaler and period" ));
456487 }
457488
458- init -> CounterMode = vals [3 ].u_int ;
489+ init -> CounterMode = args [3 ].u_int ;
490+ if (!IS_TIM_COUNTER_MODE (init -> CounterMode )) {
491+ nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "invalid mode (%d)" , init -> CounterMode ));
492+ }
459493
460- init -> ClockDivision = vals [4 ].u_int == 2 ? TIM_CLOCKDIVISION_DIV2 :
461- vals [4 ].u_int == 4 ? TIM_CLOCKDIVISION_DIV4 :
494+ init -> ClockDivision = args [4 ].u_int == 2 ? TIM_CLOCKDIVISION_DIV2 :
495+ args [4 ].u_int == 4 ? TIM_CLOCKDIVISION_DIV4 :
462496 TIM_CLOCKDIVISION_DIV1 ;
463- init -> RepetitionCounter = 0 ;
464497
465- if (!IS_TIM_COUNTER_MODE (init -> CounterMode )) {
466- nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "Invalid counter_mode (%d)" , init -> CounterMode ));
467- }
498+ init -> RepetitionCounter = 0 ;
468499
469- // init the TIM peripheral
500+ // enable TIM clock
470501 switch (self -> tim_id ) {
471502 case 1 : __TIM1_CLK_ENABLE (); break ;
472503 case 2 : __TIM2_CLK_ENABLE (); break ;
@@ -483,16 +514,18 @@ STATIC mp_obj_t pyb_timer_init_helper(pyb_timer_obj_t *self, mp_uint_t n_args, c
483514 case 13 : __TIM13_CLK_ENABLE (); break ;
484515 case 14 : __TIM14_CLK_ENABLE (); break ;
485516 }
486- // set the priority (if not a special timer)
517+
518+ // set IRQ priority (if not a special timer)
487519 if (self -> tim_id != 3 && self -> tim_id != 5 ) {
488520 HAL_NVIC_SetPriority (self -> irqn , 0xe , 0xe ); // next-to lowest priority
489521 }
490522
523+ // init TIM
491524 HAL_TIM_Base_Init (& self -> tim );
492- if (vals [5 ].u_obj == mp_const_none ) {
525+ if (args [5 ].u_obj == mp_const_none ) {
493526 HAL_TIM_Base_Start (& self -> tim );
494527 } else {
495- pyb_timer_callback (self , vals [5 ].u_obj );
528+ pyb_timer_callback (self , args [5 ].u_obj );
496529 }
497530
498531 return mp_const_none ;
@@ -839,6 +872,41 @@ STATIC mp_obj_t pyb_timer_counter(mp_uint_t n_args, const mp_obj_t *args) {
839872}
840873STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_timer_counter_obj , 1 , 2 , pyb_timer_counter );
841874
875+ /// \method source_freq()
876+ /// Get the frequency of the source of the timer.
877+ STATIC mp_obj_t pyb_timer_source_freq (mp_obj_t self_in ) {
878+ pyb_timer_obj_t * self = self_in ;
879+ uint32_t source_freq = timer_get_source_freq (self -> tim_id );
880+ return mp_obj_new_int (source_freq );
881+ }
882+ STATIC MP_DEFINE_CONST_FUN_OBJ_1 (pyb_timer_source_freq_obj , pyb_timer_source_freq );
883+
884+ /// \method freq([value])
885+ /// Get or set the frequency for the timer (changes prescaler and period if set).
886+ STATIC mp_obj_t pyb_timer_freq (mp_uint_t n_args , const mp_obj_t * args ) {
887+ pyb_timer_obj_t * self = args [0 ];
888+ if (n_args == 1 ) {
889+ // get
890+ uint32_t prescaler = self -> tim .Instance -> PSC & 0xffff ;
891+ uint32_t period = __HAL_TIM_GetAutoreload (& self -> tim ) & TIMER_CNT_MASK (self );
892+ uint32_t source_freq = timer_get_source_freq (self -> tim_id );
893+ uint32_t divide = ((prescaler + 1 ) * (period + 1 ));
894+ if (source_freq % divide == 0 ) {
895+ return mp_obj_new_int (source_freq / divide );
896+ } else {
897+ return mp_obj_new_float ((float )source_freq / (float )divide );
898+ }
899+ } else {
900+ // set
901+ uint32_t period ;
902+ uint32_t prescaler = compute_prescaler_period_from_freq (self , args [1 ], & period );
903+ self -> tim .Instance -> PSC = prescaler ;
904+ __HAL_TIM_SetAutoreload (& self -> tim , period );
905+ return mp_const_none ;
906+ }
907+ }
908+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_timer_freq_obj , 1 , 2 , pyb_timer_freq );
909+
842910/// \method prescaler([value])
843911/// Get or set the prescaler for the timer.
844912STATIC mp_obj_t pyb_timer_prescaler (mp_uint_t n_args , const mp_obj_t * args ) {
@@ -848,7 +916,7 @@ STATIC mp_obj_t pyb_timer_prescaler(mp_uint_t n_args, const mp_obj_t *args) {
848916 return mp_obj_new_int (self -> tim .Instance -> PSC & 0xffff );
849917 } else {
850918 // set
851- self -> tim .Init . Prescaler = self -> tim . Instance -> PSC = mp_obj_get_int (args [1 ]) & 0xffff ;
919+ self -> tim .Instance -> PSC = mp_obj_get_int (args [1 ]) & 0xffff ;
852920 return mp_const_none ;
853921 }
854922}
@@ -897,6 +965,8 @@ STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
897965 { MP_OBJ_NEW_QSTR (MP_QSTR_deinit ), (mp_obj_t )& pyb_timer_deinit_obj },
898966 { MP_OBJ_NEW_QSTR (MP_QSTR_channel ), (mp_obj_t )& pyb_timer_channel_obj },
899967 { MP_OBJ_NEW_QSTR (MP_QSTR_counter ), (mp_obj_t )& pyb_timer_counter_obj },
968+ { MP_OBJ_NEW_QSTR (MP_QSTR_source_freq ), (mp_obj_t )& pyb_timer_source_freq_obj },
969+ { MP_OBJ_NEW_QSTR (MP_QSTR_freq ), (mp_obj_t )& pyb_timer_freq_obj },
900970 { MP_OBJ_NEW_QSTR (MP_QSTR_prescaler ), (mp_obj_t )& pyb_timer_prescaler_obj },
901971 { MP_OBJ_NEW_QSTR (MP_QSTR_period ), (mp_obj_t )& pyb_timer_period_obj },
902972 { MP_OBJ_NEW_QSTR (MP_QSTR_callback ), (mp_obj_t )& pyb_timer_callback_obj },
0 commit comments