6969///
7070/// tim1 = pyb.Timer(2, mode=Timer.EVENT_COUNT) # initialize it capture mode
7171/// tim2 = pyb.Timer(1, mode=Timer.PWM) # initialize it in PWM mode
72- /// tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the PWM on channel B with a 50% duty cycle
73- /// tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the event counter with a frequency of 1Hz and triggered by positive edges
72+ /// tim_ch = tim1.channel(Timer.A, freq=1, polarity=Timer.POSITIVE) # start the event counter with a frequency of 1Hz and triggered by positive edges
73+ /// tim_ch = tim2.channel(Timer.B, freq=10000, duty_cycle=50) # start the PWM on channel B with a 50% duty cycle
7474/// tim_ch.time() # get the current time in usec (can also be set)
7575/// tim_ch.freq(20) # set the frequency (can also get)
7676/// tim_ch.duty_cycle(30) # set the duty cycle to 30% (can also get)
7777/// tim_ch.duty_cycle(30, Timer.NEGATIVE) # set the duty cycle to 30% and change the polarity to negative
7878/// tim_ch.event_count() # get the number of captured events
7979/// tim_ch.event_time() # get the the time of the last captured event
80+ /// tim_ch.period(2000000) # change the period to 2 seconds
8081///
8182
8283/******************************************************************************
@@ -104,6 +105,7 @@ typedef struct _pyb_timer_channel_obj_t {
104105 mp_obj_base_t base ;
105106 struct _pyb_timer_obj_t * timer ;
106107 uint32_t frequency ;
108+ uint32_t period ;
107109 uint16_t channel ;
108110 uint8_t polarity ;
109111 uint8_t duty_cycle ;
@@ -208,20 +210,23 @@ STATIC void timer_disable (pyb_timer_obj_t *tim) {
208210STATIC uint32_t compute_prescaler_period_and_match_value (pyb_timer_channel_obj_t * ch , uint32_t * period_out , uint32_t * match_out ) {
209211 uint32_t maxcount = (ch -> channel == (TIMER_A | TIMER_B )) ? 0xFFFFFFFF : 0xFFFF ;
210212 uint32_t prescaler ;
211- uint32_t period = PYBTIMER_SRC_FREQ_HZ / ch -> frequency ;
213+ uint32_t period_c = ( ch -> frequency > 0 ) ? PYBTIMER_SRC_FREQ_HZ / ch -> frequency : (( PYBTIMER_SRC_FREQ_HZ / 1000000 ) * ch -> period ) ;
212214
213- period = MAX (1 , period ) - 1 ;
214- prescaler = period >> 16 ;
215- * period_out = period ;
215+ period_c = MAX (1 , period_c ) - 1 ;
216+ if (period_c == 0 ) {
217+ goto error ;
218+ }
219+ prescaler = period_c >> 16 ;
220+ * period_out = period_c ;
216221 if (prescaler > 0xFF && maxcount == 0xFFFF ) {
217222 goto error ;
218223 }
219224 // check limit values for the duty cycle
220225 if (ch -> duty_cycle == 0 ) {
221- * match_out = period - 1 ;
226+ * match_out = period_c - 1 ;
222227 }
223228 else {
224- * match_out = period - ((period * ch -> duty_cycle ) / 100 );
229+ * match_out = period_c - ((period_c * ch -> duty_cycle ) / 100 );
225230 }
226231 if ((ch -> timer -> config & 0x0F ) == TIMER_CFG_A_PWM && (* match_out > 0xFFFF )) {
227232 goto error ;
@@ -240,15 +245,15 @@ STATIC void timer_init (pyb_timer_obj_t *tim) {
240245
241246STATIC void timer_channel_init (pyb_timer_channel_obj_t * ch ) {
242247 // calculate the period, the prescaler and the match value
243- uint32_t period ;
248+ uint32_t period_c ;
244249 uint32_t match ;
245- uint32_t prescaler = compute_prescaler_period_and_match_value (ch , & period , & match );
250+ uint32_t prescaler = compute_prescaler_period_and_match_value (ch , & period_c , & match );
246251
247252 // set the prescaler
248253 MAP_TimerPrescaleSet (ch -> timer -> timer , ch -> channel , (prescaler < 0xFF ) ? prescaler : 0 );
249254
250255 // set the load value
251- MAP_TimerLoadSet (ch -> timer -> timer , ch -> channel , period );
256+ MAP_TimerLoadSet (ch -> timer -> timer , ch -> channel , period_c );
252257
253258 // configure the pwm if we are in such mode
254259 if ((ch -> timer -> config & 0x0F ) == TIMER_CFG_A_PWM ) {
@@ -412,14 +417,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
412417///
413418/// Keyword arguments:
414419///
415- /// - `freq` - specifies the frequency in Hz
416- ///
417- /// - `polarity` - in PWM specifies the polarity of the pulse. In capture mode specifies the edge to capture.
418- /// in order to capture on both negative and positive edges, make it = Timer.POSITIVE | Timer.NEGATIVE.
420+ /// - `freq` - specifies the frequency in Hz.
421+ /// - `period` - specifies the period in microseconds.
422+ /// - `polarity` - in PWM specifies the polarity of the pulse. In capture mode specifies the edge to capture.
423+ /// in order to capture on both negative and positive edges, make it = Timer.POSITIVE | Timer.NEGATIVE.
424+ /// - `duty_cycle` - sets the duty cycle value
419425///
420426STATIC mp_obj_t pyb_timer_channel (mp_uint_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
421427 static const mp_arg_t allowed_args [] = {
422428 { MP_QSTR_freq , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0 } },
429+ { MP_QSTR_period , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0 } },
423430 { MP_QSTR_polarity , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = PYBTIMER_POLARITY_POS } },
424431 { MP_QSTR_duty_cycle , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0 } },
425432 };
@@ -454,12 +461,16 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
454461 mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
455462 mp_arg_parse_all (n_args - 2 , pos_args + 2 , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
456463
457- // check the frequency
458- if (args [0 ].u_int <= 0 ) {
464+ // throw an exception if both frequency and period are given
465+ if (args [0 ].u_int != 0 && args [1 ].u_int != 0 ) {
466+ goto error ;
467+ }
468+ // check that at least one of them has a valid value
469+ if (args [0 ].u_int <= 0 && args [1 ].u_int <= 0 ) {
459470 goto error ;
460471 }
461- // check that the polarity is not both in pwm mode
462- if ((tim -> config & TIMER_A ) == TIMER_CFG_A_PWM && args [1 ].u_int == (PYBTIMER_POLARITY_POS | PYBTIMER_POLARITY_NEG )) {
472+ // check that the polarity is not ' both' in pwm mode
473+ if ((tim -> config & TIMER_A ) == TIMER_CFG_A_PWM && args [2 ].u_int == (PYBTIMER_POLARITY_POS | PYBTIMER_POLARITY_NEG )) {
463474 goto error ;
464475 }
465476
@@ -471,8 +482,9 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
471482
472483 // get the frequency the polarity and the duty cycle
473484 ch -> frequency = args [0 ].u_int ;
474- ch -> polarity = args [1 ].u_int ;
475- ch -> duty_cycle = MIN (100 , MAX (0 , args [2 ].u_int ));
485+ ch -> period = args [1 ].u_int ;
486+ ch -> polarity = args [2 ].u_int ;
487+ ch -> duty_cycle = MIN (100 , MAX (0 , args [3 ].u_int ));
476488
477489 timer_channel_init (ch );
478490
@@ -611,39 +623,65 @@ STATIC mp_obj_t pyb_timer_channel_freq(mp_uint_t n_args, const mp_obj_t *args) {
611623 return mp_obj_new_int (ch -> frequency );
612624 } else {
613625 // set
614- ch -> frequency = mp_obj_get_int (args [1 ]);
626+ int32_t _frequency = mp_obj_get_int (args [1 ]);
627+ if (_frequency <= 0 ) {
628+ nlr_raise (mp_obj_new_exception_msg (& mp_type_ValueError , mpexception_value_invalid_arguments ));
629+ }
630+ ch -> frequency = _frequency ;
631+ ch -> period = 1000000 / _frequency ;
615632 timer_channel_init (ch );
616633 return mp_const_none ;
617634 }
618635}
619636STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_timer_channel_freq_obj , 1 , 2 , pyb_timer_channel_freq );
620637
638+ /// \method period([value])
639+ /// get or set the period of the timer channel in microseconds
640+ STATIC mp_obj_t pyb_timer_channel_period (mp_uint_t n_args , const mp_obj_t * args ) {
641+ pyb_timer_channel_obj_t * ch = args [0 ];
642+ if (n_args == 1 ) {
643+ // get
644+ return mp_obj_new_int (ch -> period );
645+ } else {
646+ // set
647+ int32_t _period = mp_obj_get_int (args [1 ]);
648+ if (_period <= 0 ) {
649+ nlr_raise (mp_obj_new_exception_msg (& mp_type_ValueError , mpexception_value_invalid_arguments ));
650+ }
651+ ch -> period = _period ;
652+ ch -> frequency = 1000000 / _period ;
653+ timer_channel_init (ch );
654+ return mp_const_none ;
655+ }
656+ }
657+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (pyb_timer_channel_period_obj , 1 , 2 , pyb_timer_channel_period );
658+
621659/// \method time([value])
622660/// get or set the value of the timer channel in microseconds
623661STATIC mp_obj_t pyb_timer_channel_time (mp_uint_t n_args , const mp_obj_t * args ) {
624662 pyb_timer_channel_obj_t * ch = args [0 ];
625663 uint32_t value ;
626664 // calculate the period, the prescaler and the match value
627- uint32_t period ;
665+ uint32_t period_c ;
628666 uint32_t match ;
629- (void )compute_prescaler_period_and_match_value (ch , & period , & match );
667+ (void )compute_prescaler_period_and_match_value (ch , & period_c , & match );
630668 if (n_args == 1 ) {
631669 // get
632670 value = (ch -> channel == TIMER_B ) ? HWREG (ch -> timer -> timer + TIMER_O_TBV ) : HWREG (ch -> timer -> timer + TIMER_O_TAV );
633671 // return the current timer value in microseconds
634672 // substract value to period since we are always operating in count-down mode
635- uint32_t time_t = (1000 * (period - value )) / period ;
673+ uint32_t time_t = (1000 * (period_c - value )) / period_c ;
636674 return mp_obj_new_int ((time_t * 1000 ) / ch -> frequency );
637675 }
638676 else {
639677 // set
640- value = (mp_obj_get_int (args [1 ]) * ((ch -> frequency * period ) / 1000 )) / 1000 ;
678+ value = (mp_obj_get_int (args [1 ]) * ((ch -> frequency * period_c ) / 1000 )) / 1000 ;
641679 if ((value > 0xFFFF ) && (ch -> timer -> config & TIMER_CFG_SPLIT_PAIR )) {
642680 // this exceeds the maximum value of a 16-bit timer
643681 nlr_raise (mp_obj_new_exception_msg (& mp_type_ValueError , mpexception_value_invalid_arguments ));
644682 }
645683 // write period minus value since we are always operating in count-down mode
646- TimerValueSet (ch -> timer -> timer , ch -> channel , (period - value ));
684+ TimerValueSet (ch -> timer -> timer , ch -> channel , (period_c - value ));
647685 return mp_const_none ;
648686 }
649687}
@@ -662,12 +700,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_channel_event_count_obj, pyb_timer_ch
662700STATIC mp_obj_t pyb_timer_channel_event_time (mp_obj_t self_in ) {
663701 pyb_timer_channel_obj_t * ch = self_in ;
664702 // calculate the period, the prescaler and the match value
665- uint32_t period ;
703+ uint32_t period_c ;
666704 uint32_t match ;
667- (void )compute_prescaler_period_and_match_value (ch , & period , & match );
705+ (void )compute_prescaler_period_and_match_value (ch , & period_c , & match );
668706 uint32_t value = MAP_TimerValueGet (ch -> timer -> timer , ch -> channel == (TIMER_A | TIMER_B ) ? TIMER_A : ch -> channel );
669707 // substract value to period since we are always operating in count-down mode
670- uint32_t time_t = (1000 * (period - value )) / period ;
708+ uint32_t time_t = (1000 * (period_c - value )) / period_c ;
671709 return mp_obj_new_int ((time_t * 1000 ) / ch -> frequency );
672710}
673711STATIC MP_DEFINE_CONST_FUN_OBJ_1 (pyb_timer_channel_event_time_obj , pyb_timer_channel_event_time );
@@ -683,10 +721,10 @@ STATIC mp_obj_t pyb_timer_channel_duty_cycle(mp_uint_t n_args, const mp_obj_t *a
683721 else {
684722 // duty cycle must be converted from percentage to ticks
685723 // calculate the period, the prescaler and the match value
686- uint32_t period ;
724+ uint32_t period_c ;
687725 uint32_t match ;
688726 ch -> duty_cycle = MIN (100 , MAX (0 , mp_obj_get_int (args [1 ])));
689- compute_prescaler_period_and_match_value (ch , & period , & match );
727+ compute_prescaler_period_and_match_value (ch , & period_c , & match );
690728 if (n_args == 3 ) {
691729 // set the new polarity if requested
692730 ch -> polarity = mp_obj_get_int (args [2 ]);
@@ -801,10 +839,10 @@ STATIC mp_obj_t pyb_timer_channel_callback (mp_uint_t n_args, const mp_obj_t *po
801839 ch -> duty_cycle = MIN (100 , c_value );
802840
803841 // reload the timer
804- uint32_t period ;
842+ uint32_t period_c ;
805843 uint32_t match ;
806- compute_prescaler_period_and_match_value (ch , & period , & match );
807- MAP_TimerLoadSet (ch -> timer -> timer , ch -> channel , period );
844+ compute_prescaler_period_and_match_value (ch , & period_c , & match );
845+ MAP_TimerLoadSet (ch -> timer -> timer , ch -> channel , period_c );
808846 // set the appropiate match value
809847 MAP_TimerMatchSet (ch -> timer -> timer , ch -> channel , (_config == TIMER_CFG_A_PWM ) ? match : c_value );
810848
@@ -821,6 +859,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_timer_channel_callback_obj, 1, pyb_timer_c
821859STATIC const mp_map_elem_t pyb_timer_channel_locals_dict_table [] = {
822860 // instance methods
823861 { MP_OBJ_NEW_QSTR (MP_QSTR_freq ), (mp_obj_t )& pyb_timer_channel_freq_obj },
862+ { MP_OBJ_NEW_QSTR (MP_QSTR_period ), (mp_obj_t )& pyb_timer_channel_period_obj },
824863 { MP_OBJ_NEW_QSTR (MP_QSTR_time ), (mp_obj_t )& pyb_timer_channel_time_obj },
825864 { MP_OBJ_NEW_QSTR (MP_QSTR_event_count ), (mp_obj_t )& pyb_timer_channel_event_count_obj },
826865 { MP_OBJ_NEW_QSTR (MP_QSTR_event_time ), (mp_obj_t )& pyb_timer_channel_event_time_obj },
0 commit comments