@@ -96,6 +96,9 @@ typedef enum {
9696 CHANNEL_MODE_OC_FORCED_ACTIVE ,
9797 CHANNEL_MODE_OC_FORCED_INACTIVE ,
9898 CHANNEL_MODE_IC ,
99+ CHANNEL_MODE_ENC_A ,
100+ CHANNEL_MODE_ENC_B ,
101+ CHANNEL_MODE_ENC_AB ,
99102} pyb_channel_mode ;
100103
101104STATIC const struct {
@@ -111,6 +114,9 @@ STATIC const struct {
111114 { MP_QSTR_OC_FORCED_ACTIVE , TIM_OCMODE_FORCED_ACTIVE },
112115 { MP_QSTR_OC_FORCED_INACTIVE , TIM_OCMODE_FORCED_INACTIVE },
113116 { MP_QSTR_IC , 0 },
117+ { MP_QSTR_ENC_A , TIM_ENCODERMODE_TI1 },
118+ { MP_QSTR_ENC_B , TIM_ENCODERMODE_TI2 },
119+ { MP_QSTR_ENC_AB , TIM_ENCODERMODE_TI12 },
114120};
115121
116122typedef struct _pyb_timer_channel_obj_t {
@@ -719,6 +725,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
719725/// - `Timer.OC_FORCED_ACTIVE` - the pin is forced active (compare match is ignored).
720726/// - `Timer.OC_FORCED_INACTIVE` - the pin is forced inactive (compare match is ignored).
721727/// - `Timer.IC` - configure the timer in Input Capture mode.
728+ /// - `Timer.ENC_A` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
729+ /// - `Timer.ENC_B` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
730+ /// - `Timer.ENC_AB` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
722731///
723732/// - `callback` - as per TimerChannel.callback()
724733///
@@ -750,6 +759,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
750759/// Note that capture only works on the primary channel, and not on the
751760/// complimentary channels.
752761///
762+ /// Notes for Timer.ENC modes:
763+ ///
764+ /// - Requires 2 pins, so one or both pins will need to be configured to use
765+ /// the appropriate timer AF using the Pin API.
766+ /// - Read the encoder value using the timer.counter() method.
767+ /// - Only works on CH1 and CH2 (and not on CH1N or CH2N)
768+ /// - The channel number is ignored when setting the encoder mode.
769+ ///
753770/// PWM Example:
754771///
755772/// timer = pyb.Timer(2, freq=1000)
@@ -941,6 +958,41 @@ STATIC mp_obj_t pyb_timer_channel(mp_uint_t n_args, const mp_obj_t *pos_args, mp
941958 break ;
942959 }
943960
961+ case CHANNEL_MODE_ENC_A :
962+ case CHANNEL_MODE_ENC_B :
963+ case CHANNEL_MODE_ENC_AB : {
964+ TIM_Encoder_InitTypeDef enc_config ;
965+
966+ enc_config .EncoderMode = channel_mode_info [chan -> mode ].oc_mode ;
967+ enc_config .IC1Polarity = args [6 ].u_int ;
968+ if (enc_config .IC1Polarity == 0xffffffff ) {
969+ enc_config .IC1Polarity = TIM_ICPOLARITY_RISING ;
970+ }
971+ enc_config .IC2Polarity = enc_config .IC1Polarity ;
972+ enc_config .IC1Selection = TIM_ICSELECTION_DIRECTTI ;
973+ enc_config .IC2Selection = TIM_ICSELECTION_DIRECTTI ;
974+ enc_config .IC1Prescaler = TIM_ICPSC_DIV1 ;
975+ enc_config .IC2Prescaler = TIM_ICPSC_DIV1 ;
976+ enc_config .IC1Filter = 0 ;
977+ enc_config .IC2Filter = 0 ;
978+
979+ if (!IS_TIM_IC_POLARITY (enc_config .IC1Polarity )) {
980+ nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "invalid polarity (%d)" , enc_config .IC1Polarity ));
981+ }
982+ // Only Timers 1, 2, 3, 4, 5, and 8 support encoder mode
983+ if (self -> tim .Instance != TIM1
984+ && self -> tim .Instance != TIM2
985+ && self -> tim .Instance != TIM3
986+ && self -> tim .Instance != TIM4
987+ && self -> tim .Instance != TIM5
988+ && self -> tim .Instance != TIM8 ) {
989+ nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "encoder not supported on timer %d" , self -> tim_id ));
990+ }
991+ HAL_TIM_Encoder_Init (& self -> tim , & enc_config );
992+ __HAL_TIM_SetCounter (& self -> tim , 0 );
993+ break ;
994+ }
995+
944996 default :
945997 nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "invalid mode (%d)" , chan -> mode ));
946998 }
@@ -1077,6 +1129,9 @@ STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
10771129 { MP_OBJ_NEW_QSTR (MP_QSTR_OC_FORCED_ACTIVE ), MP_OBJ_NEW_SMALL_INT (CHANNEL_MODE_OC_FORCED_ACTIVE ) },
10781130 { MP_OBJ_NEW_QSTR (MP_QSTR_OC_FORCED_INACTIVE ), MP_OBJ_NEW_SMALL_INT (CHANNEL_MODE_OC_FORCED_INACTIVE ) },
10791131 { MP_OBJ_NEW_QSTR (MP_QSTR_IC ), MP_OBJ_NEW_SMALL_INT (CHANNEL_MODE_IC ) },
1132+ { MP_OBJ_NEW_QSTR (MP_QSTR_ENC_A ), MP_OBJ_NEW_SMALL_INT (CHANNEL_MODE_ENC_A ) },
1133+ { MP_OBJ_NEW_QSTR (MP_QSTR_ENC_B ), MP_OBJ_NEW_SMALL_INT (CHANNEL_MODE_ENC_B ) },
1134+ { MP_OBJ_NEW_QSTR (MP_QSTR_ENC_AB ), MP_OBJ_NEW_SMALL_INT (CHANNEL_MODE_ENC_AB ) },
10801135 { MP_OBJ_NEW_QSTR (MP_QSTR_HIGH ), MP_OBJ_NEW_SMALL_INT (TIM_OCPOLARITY_HIGH ) },
10811136 { MP_OBJ_NEW_QSTR (MP_QSTR_LOW ), MP_OBJ_NEW_SMALL_INT (TIM_OCPOLARITY_LOW ) },
10821137 { MP_OBJ_NEW_QSTR (MP_QSTR_RISING ), MP_OBJ_NEW_SMALL_INT (TIM_ICPOLARITY_RISING ) },
0 commit comments