@@ -104,7 +104,7 @@ typedef enum {
104104STATIC const struct {
105105 qstr name ;
106106 uint32_t oc_mode ;
107- } gChannelMode [ ] = {
107+ } channel_mode_info [ ] = {
108108 { MP_QSTR_PWM , TIM_OCMODE_PWM1 },
109109 { MP_QSTR_PWM_INVERTED , TIM_OCMODE_PWM2 },
110110 { MP_QSTR_OC_TIMING , TIM_OCMODE_TIMING },
@@ -147,7 +147,7 @@ TIM_HandleTypeDef TIM5_Handle;
147147TIM_HandleTypeDef TIM6_Handle ;
148148
149149// Used to divide down TIM3 and periodically call the flash storage IRQ
150- static uint32_t tim3_counter = 0 ;
150+ STATIC uint32_t tim3_counter = 0 ;
151151
152152// Used to do callbacks to Python code on interrupt
153153STATIC pyb_timer_obj_t * pyb_timer_obj_all [14 ];
@@ -266,6 +266,8 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
266266/******************************************************************************/
267267/* Micro Python bindings */
268268
269+ STATIC const mp_obj_type_t pyb_timer_channel_type ;
270+
269271STATIC void pyb_timer_print (void (* print )(void * env , const char * fmt , ...), void * env , mp_obj_t self_in , mp_print_kind_t kind ) {
270272 pyb_timer_obj_t * self = self_in ;
271273
@@ -507,8 +509,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
507509
508510/// \method channel(channel, mode, ...)
509511///
510- /// If only a channel nunber is passed, then a previously initialized channel
511- /// object is returned.
512+ /// If only a channel number is passed, then a previously initialized channel
513+ /// object is returned (or `None` if there is no previous channel) .
512514///
513515/// Othwerwise, a TimerChannel object is initialized and returned.
514516///
@@ -540,7 +542,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
540542///
541543/// Keyword arguments for Timer.PWM modes:
542544///
543- /// - 'pulse_width' - determines the initial pulse width to use.
545+ /// - `pulse_width` - determines the initial pulse width value to use.
546+ /// - `pulse_width_ratio` - determines the initial pulse width ratio to use.
544547///
545548/// Keyword arguments for Timer.OC modes:
546549///
@@ -563,17 +566,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
563566/// ch2 = timer.channel(2, pyb.Timer.PWM, pin=pyb.Pin.board.X2, pulse_width=210000)
564567/// ch3 = timer.channel(3, pyb.Timer.PWM, pin=pyb.Pin.board.X3, pulse_width=420000)
565568STATIC const mp_arg_t pyb_timer_channel_args [] = {
566- { MP_QSTR_callback , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = mp_const_none } },
567- { MP_QSTR_pin , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = mp_const_none } },
568- { MP_QSTR_pulse_width , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0 } },
569- { MP_QSTR_compare , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0 } },
570- { MP_QSTR_polarity , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0xffffffff } },
569+ { MP_QSTR_callback , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = mp_const_none } },
570+ { MP_QSTR_pin , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = mp_const_none } },
571+ { MP_QSTR_pulse_width , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0xffffffff } },
572+ { MP_QSTR_pulse_width_ratio , MP_ARG_KW_ONLY | MP_ARG_OBJ , {.u_obj = mp_const_none } },
573+ { MP_QSTR_compare , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0 } },
574+ { MP_QSTR_polarity , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0xffffffff } },
571575};
572576#define PYB_TIMER_CHANNEL_NUM_ARGS MP_ARRAY_SIZE(pyb_timer_channel_args)
573577
574578STATIC mp_obj_t pyb_timer_channel (mp_uint_t n_args , const mp_obj_t * args , mp_map_t * kw_args ) {
575- mp_arg_check_num (n_args , n_args - 3 , 3 , MP_OBJ_FUN_ARGS_MAX , true);
576-
577579 pyb_timer_obj_t * self = args [0 ];
578580 mp_int_t channel = mp_obj_get_int (args [1 ]);
579581
@@ -591,8 +593,10 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
591593 prev_chan = chan ;
592594 chan = chan -> next ;
593595 }
594- if (kw_args -> used == 0 ) {
595- // Return the previously allocated channel
596+
597+ // If only the channel number is given return the previously allocated
598+ // channel (or None if no previous channel).
599+ if (n_args == 2 ) {
596600 if (chan ) {
597601 return chan ;
598602 }
@@ -658,8 +662,24 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
658662 case CHANNEL_MODE_PWM_NORMAL :
659663 case CHANNEL_MODE_PWM_INVERTED : {
660664 TIM_OC_InitTypeDef oc_config ;
661- oc_config .OCMode = gChannelMode [chan -> mode ].oc_mode ;
662- oc_config .Pulse = vals [2 ].u_int ;
665+ oc_config .OCMode = channel_mode_info [chan -> mode ].oc_mode ;
666+ if (vals [2 ].u_int != 0xffffffff ) {
667+ // absolute pulse width value given
668+ oc_config .Pulse = vals [2 ].u_int ;
669+ } else if (vals [3 ].u_obj != mp_const_none ) {
670+ // pulse width ratio given
671+ uint32_t period = (__HAL_TIM_GetAutoreload (& self -> tim ) & TIMER_CNT_MASK (self )) + 1 ;
672+ uint32_t cmp = mp_obj_get_float (vals [3 ].u_obj ) * period ;
673+ if (cmp < 0 ) {
674+ cmp = 0 ;
675+ } else if (cmp > period ) {
676+ cmp = period ;
677+ }
678+ oc_config .Pulse = cmp ;
679+ } else {
680+ // nothing given, default to pulse width of 0
681+ oc_config .Pulse = 0 ;
682+ }
663683 oc_config .OCPolarity = TIM_OCPOLARITY_HIGH ;
664684 oc_config .OCNPolarity = TIM_OCNPOLARITY_HIGH ;
665685 oc_config .OCFastMode = TIM_OCFAST_DISABLE ;
@@ -682,9 +702,9 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
682702 case CHANNEL_MODE_OC_FORCED_ACTIVE :
683703 case CHANNEL_MODE_OC_FORCED_INACTIVE : {
684704 TIM_OC_InitTypeDef oc_config ;
685- oc_config .OCMode = gChannelMode [chan -> mode ].oc_mode ;
686- oc_config .Pulse = vals [3 ].u_int ;
687- oc_config .OCPolarity = vals [4 ].u_int ;
705+ oc_config .OCMode = channel_mode_info [chan -> mode ].oc_mode ;
706+ oc_config .Pulse = vals [4 ].u_int ;
707+ oc_config .OCPolarity = vals [5 ].u_int ;
688708 if (oc_config .OCPolarity == 0xffffffff ) {
689709 oc_config .OCPolarity = TIM_OCPOLARITY_HIGH ;
690710 }
@@ -708,7 +728,7 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
708728 case CHANNEL_MODE_IC : {
709729 TIM_IC_InitTypeDef ic_config ;
710730
711- ic_config .ICPolarity = vals [4 ].u_int ;
731+ ic_config .ICPolarity = vals [5 ].u_int ;
712732 if (ic_config .ICPolarity == 0xffffffff ) {
713733 ic_config .ICPolarity = TIM_ICPOLARITY_RISING ;
714734 }
@@ -734,11 +754,11 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *args, mp_map
734754
735755 return chan ;
736756}
737- STATIC MP_DEFINE_CONST_FUN_OBJ_KW (pyb_timer_channel_obj , 3 , pyb_timer_channel );
757+ STATIC MP_DEFINE_CONST_FUN_OBJ_KW (pyb_timer_channel_obj , 2 , pyb_timer_channel );
738758
739759/// \method counter([value])
740760/// Get or set the timer counter.
741- mp_obj_t pyb_timer_counter (mp_uint_t n_args , const mp_obj_t * args ) {
761+ STATIC mp_obj_t pyb_timer_counter (mp_uint_t n_args , const mp_obj_t * args ) {
742762 pyb_timer_obj_t * self = args [0 ];
743763 if (n_args == 1 ) {
744764 // get
@@ -753,7 +773,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_counter_obj, 1, 2, pyb_time
753773
754774/// \method prescaler([value])
755775/// Get or set the prescaler for the timer.
756- mp_obj_t pyb_timer_prescaler (mp_uint_t n_args , const mp_obj_t * args ) {
776+ STATIC mp_obj_t pyb_timer_prescaler (mp_uint_t n_args , const mp_obj_t * args ) {
757777 pyb_timer_obj_t * self = args [0 ];
758778 if (n_args == 1 ) {
759779 // get
@@ -768,7 +788,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_timer_prescaler_obj, 1, 2, pyb_ti
768788
769789/// \method period([value])
770790/// Get or set the period of the timer.
771- mp_obj_t pyb_timer_period (mp_uint_t n_args , const mp_obj_t * args ) {
791+ STATIC mp_obj_t pyb_timer_period (mp_uint_t n_args , const mp_obj_t * args ) {
772792 pyb_timer_obj_t * self = args [0 ];
773793 if (n_args == 1 ) {
774794 // get
@@ -852,7 +872,7 @@ STATIC void pyb_timer_channel_print(void (*print)(void *env, const char *fmt, ..
852872 print (env , "TimerChannel(timer=%u, channel=%u, mode=%s)" ,
853873 self -> timer -> tim_id ,
854874 self -> channel ,
855- qstr_str (gChannelMode [self -> mode ].name ));
875+ qstr_str (channel_mode_info [self -> mode ].name ));
856876}
857877
858878/// \method capture([value])
@@ -869,7 +889,7 @@ STATIC void pyb_timer_channel_print(void (*print)(void *env, const char *fmt, ..
869889/// Get or set the pulse width value associated with a channel.
870890/// capture, compare, and pulse_width are all aliases for the same function.
871891/// pulse_width is the logical name to use when the channel is in PWM mode.
872- STATIC mp_obj_t pyb_timer_channel_capture_compare (uint n_args , const mp_obj_t * args ) {
892+ STATIC mp_obj_t pyb_timer_channel_capture_compare (mp_uint_t n_args , const mp_obj_t * args ) {
873893 pyb_timer_channel_obj_t * self = args [0 ];
874894 if (self -> channel == 0 ) {
875895 nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "Timer %d no channel specified" , self -> timer -> tim_id ));
@@ -885,6 +905,35 @@ STATIC mp_obj_t pyb_timer_channel_capture_compare(uint n_args, const mp_obj_t *a
885905}
886906STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_timer_channel_capture_compare_obj , 1 , 2 , pyb_timer_channel_capture_compare );
887907
908+ /// \method pulse_width_ratio([value])
909+ /// Get or set the pulse width ratio associated with a channel. The value is
910+ /// a floating-point number between 0.0 and 1.0, and is relative to the period
911+ /// of the timer associated with this channel. For example, a ratio of 0.5
912+ /// would be a 50% duty cycle.
913+ STATIC mp_obj_t pyb_timer_channel_pulse_width_ratio (mp_uint_t n_args , const mp_obj_t * args ) {
914+ pyb_timer_channel_obj_t * self = args [0 ];
915+ if (self -> channel == 0 ) {
916+ nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "Timer %d no channel specified" , self -> timer -> tim_id ));
917+ }
918+ uint32_t period = (__HAL_TIM_GetAutoreload (& self -> timer -> tim ) & TIMER_CNT_MASK (self -> timer )) + 1 ;
919+ if (n_args == 1 ) {
920+ // get
921+ uint32_t cmp = __HAL_TIM_GetCompare (& self -> timer -> tim , TIMER_CHANNEL (self )) & TIMER_CNT_MASK (self -> timer );
922+ return mp_obj_new_float ((float )cmp / (float )period );
923+ } else {
924+ // set
925+ uint32_t cmp = mp_obj_get_float (args [1 ]) * period ;
926+ if (cmp < 0 ) {
927+ cmp = 0 ;
928+ } else if (cmp > period ) {
929+ cmp = period ;
930+ }
931+ __HAL_TIM_SetCompare (& self -> timer -> tim , TIMER_CHANNEL (self ), cmp & TIMER_CNT_MASK (self -> timer ));
932+ return mp_const_none ;
933+ }
934+ }
935+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_timer_channel_pulse_width_ratio_obj , 1 , 2 , pyb_timer_channel_pulse_width_ratio );
936+
888937/// \method callback(fun)
889938/// Set the function to be called when the timer channel triggers.
890939/// `fun` is passed 1 argument, the timer object.
@@ -927,19 +976,20 @@ STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table[] = {
927976 // instance methods
928977 { MP_OBJ_NEW_QSTR (MP_QSTR_callback ), (mp_obj_t )& pyb_timer_channel_callback_obj },
929978 { MP_OBJ_NEW_QSTR (MP_QSTR_pulse_width ), (mp_obj_t )& pyb_timer_channel_capture_compare_obj },
979+ { MP_OBJ_NEW_QSTR (MP_QSTR_pulse_width_ratio ), (mp_obj_t )& pyb_timer_channel_pulse_width_ratio_obj },
930980 { MP_OBJ_NEW_QSTR (MP_QSTR_capture ), (mp_obj_t )& pyb_timer_channel_capture_compare_obj },
931981 { MP_OBJ_NEW_QSTR (MP_QSTR_compare ), (mp_obj_t )& pyb_timer_channel_capture_compare_obj },
932982};
933983STATIC MP_DEFINE_CONST_DICT (pyb_timer_channel_locals_dict , pyb_timer_channel_locals_dict_table );
934984
935- const mp_obj_type_t pyb_timer_channel_type = {
985+ STATIC const mp_obj_type_t pyb_timer_channel_type = {
936986 { & mp_type_type },
937987 .name = MP_QSTR_TimerChannel ,
938988 .print = pyb_timer_channel_print ,
939989 .locals_dict = (mp_obj_t )& pyb_timer_channel_locals_dict ,
940990};
941991
942- void timer_handle_irq_channel (pyb_timer_obj_t * tim , uint8_t channel , mp_obj_t callback ) {
992+ STATIC void timer_handle_irq_channel (pyb_timer_obj_t * tim , uint8_t channel , mp_obj_t callback ) {
943993 uint32_t irq_mask = TIMER_IRQ_MASK (channel );
944994
945995 if (__HAL_TIM_GET_FLAG (& tim -> tim , irq_mask ) != RESET ) {
@@ -981,8 +1031,9 @@ void timer_irq_handler(uint tim_id) {
9811031 pyb_timer_obj_t * tim = pyb_timer_obj_all [tim_id - 1 ];
9821032
9831033 if (tim == NULL ) {
984- // timer object has not been set, so we can't do anything
985- printf ("No timer object for id=%d\n" , tim_id );
1034+ // Timer object has not been set, so we can't do anything.
1035+ // This can happen under normal circumstances for timers like
1036+ // 1 & 10 which use the same IRQ.
9861037 return ;
9871038 }
9881039
0 commit comments