Skip to content

Commit b4c9a25

Browse files
dhylandsdpgeorge
authored andcommitted
stmhal: Add support for quadrature encoder mode to pyb.TimerChannel.
1 parent b57b56f commit b4c9a25

3 files changed

Lines changed: 73 additions & 2 deletions

File tree

docs/library/pyb.Timer.rst

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,17 @@ Methods
7676
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
7777
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
7878
- ``Timer.IC`` --- configure the timer in Input Capture mode.
79-
79+
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
80+
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
81+
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
82+
8083
- ``callback`` - as per TimerChannel.callback()
8184

8285
- ``pin`` None (the default) or a Pin object. If specified (and not None)
8386
this will cause the alternate function of the the indicated pin
8487
to be configured for this timer channel. An error will be raised if
8588
the pin doesn't support any alternate functions for this timer channel.
86-
89+
8790
Keyword arguments for Timer.PWM modes:
8891

8992
- ``pulse_width`` - determines the initial pulse width value to use.
@@ -94,19 +97,29 @@ Methods
9497
- ``compare`` - determines the initial value of the compare register.
9598

9699
- ``polarity`` can be one of:
100+
97101
- ``Timer.HIGH`` - output is active high
98102
- ``Timer.LOW`` - output is acive low
99103

100104
Optional keyword arguments for Timer.IC modes:
101105

102106
- ``polarity`` can be one of:
107+
103108
- ``Timer.RISING`` - captures on rising edge.
104109
- ``Timer.FALLING`` - captures on falling edge.
105110
- ``Timer.BOTH`` - captures on both edges.
106111

107112
Note that capture only works on the primary channel, and not on the
108113
complimentary channels.
109114

115+
Notes for Timer.ENC modes:
116+
117+
- Requires 2 pins, so one or both pins will need to be configured to use
118+
the appropriate timer AF using the Pin API.
119+
- Read the encoder value using the timer.counter() method.
120+
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
121+
- The channel number is ignored when setting the encoder mode.
122+
110123
PWM Example::
111124
112125
timer = pyb.Timer(2, freq=1000)

stmhal/qstrdefsport.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ Q(OC_INACTIVE)
247247
Q(OC_TOGGLE)
248248
Q(OC_FORCED_ACTIVE)
249249
Q(OC_FORCED_INACTIVE)
250+
Q(ENC_A)
251+
Q(ENC_B)
252+
Q(ENC_AB)
250253
Q(HIGH)
251254
Q(LOW)
252255
Q(RISING)

stmhal/timer.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

101104
STATIC 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

116122
typedef 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

Comments
 (0)