Commit b4c9a25e authored by Dave Hylands's avatar Dave Hylands Committed by Damien George
Browse files

stmhal: Add support for quadrature encoder mode to pyb.TimerChannel.

parent b57b56f2
......@@ -76,14 +76,17 @@ Methods
- ``Timer.OC_FORCED_ACTIVE`` --- the pin is forced active (compare match is ignored).
- ``Timer.OC_FORCED_INACTIVE`` --- the pin is forced inactive (compare match is ignored).
- ``Timer.IC`` --- configure the timer in Input Capture mode.
- ``Timer.ENC_A`` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
- ``Timer.ENC_B`` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
- ``Timer.ENC_AB`` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
- ``callback`` - as per TimerChannel.callback()
- ``pin`` None (the default) or a Pin object. If specified (and not None)
this will cause the alternate function of the the indicated pin
to be configured for this timer channel. An error will be raised if
the pin doesn't support any alternate functions for this timer channel.
Keyword arguments for Timer.PWM modes:
- ``pulse_width`` - determines the initial pulse width value to use.
......@@ -94,12 +97,14 @@ Methods
- ``compare`` - determines the initial value of the compare register.
- ``polarity`` can be one of:
- ``Timer.HIGH`` - output is active high
- ``Timer.LOW`` - output is acive low
Optional keyword arguments for Timer.IC modes:
- ``polarity`` can be one of:
- ``Timer.RISING`` - captures on rising edge.
- ``Timer.FALLING`` - captures on falling edge.
- ``Timer.BOTH`` - captures on both edges.
......@@ -107,6 +112,14 @@ Methods
Note that capture only works on the primary channel, and not on the
complimentary channels.
Notes for Timer.ENC modes:
- Requires 2 pins, so one or both pins will need to be configured to use
the appropriate timer AF using the Pin API.
- Read the encoder value using the timer.counter() method.
- Only works on CH1 and CH2 (and not on CH1N or CH2N)
- The channel number is ignored when setting the encoder mode.
PWM Example::
timer = pyb.Timer(2, freq=1000)
......
......@@ -247,6 +247,9 @@ Q(OC_INACTIVE)
Q(OC_TOGGLE)
Q(OC_FORCED_ACTIVE)
Q(OC_FORCED_INACTIVE)
Q(ENC_A)
Q(ENC_B)
Q(ENC_AB)
Q(HIGH)
Q(LOW)
Q(RISING)
......
......@@ -96,6 +96,9 @@ typedef enum {
CHANNEL_MODE_OC_FORCED_ACTIVE,
CHANNEL_MODE_OC_FORCED_INACTIVE,
CHANNEL_MODE_IC,
CHANNEL_MODE_ENC_A,
CHANNEL_MODE_ENC_B,
CHANNEL_MODE_ENC_AB,
} pyb_channel_mode;
STATIC const struct {
......@@ -111,6 +114,9 @@ STATIC const struct {
{ MP_QSTR_OC_FORCED_ACTIVE, TIM_OCMODE_FORCED_ACTIVE },
{ MP_QSTR_OC_FORCED_INACTIVE, TIM_OCMODE_FORCED_INACTIVE },
{ MP_QSTR_IC, 0 },
{ MP_QSTR_ENC_A, TIM_ENCODERMODE_TI1 },
{ MP_QSTR_ENC_B, TIM_ENCODERMODE_TI2 },
{ MP_QSTR_ENC_AB, TIM_ENCODERMODE_TI12 },
};
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);
/// - `Timer.OC_FORCED_ACTIVE` - the pin is forced active (compare match is ignored).
/// - `Timer.OC_FORCED_INACTIVE` - the pin is forced inactive (compare match is ignored).
/// - `Timer.IC` - configure the timer in Input Capture mode.
/// - `Timer.ENC_A` --- configure the timer in Encoder mode. The counter only changes when CH1 changes.
/// - `Timer.ENC_B` --- configure the timer in Encoder mode. The counter only changes when CH2 changes.
/// - `Timer.ENC_AB` --- configure the timer in Encoder mode. The counter changes when CH1 or CH2 changes.
///
/// - `callback` - as per TimerChannel.callback()
///
......@@ -750,6 +759,14 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_timer_deinit_obj, pyb_timer_deinit);
/// Note that capture only works on the primary channel, and not on the
/// complimentary channels.
///
/// Notes for Timer.ENC modes:
///
/// - Requires 2 pins, so one or both pins will need to be configured to use
/// the appropriate timer AF using the Pin API.
/// - Read the encoder value using the timer.counter() method.
/// - Only works on CH1 and CH2 (and not on CH1N or CH2N)
/// - The channel number is ignored when setting the encoder mode.
///
/// PWM Example:
///
/// 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
break;
}
case CHANNEL_MODE_ENC_A:
case CHANNEL_MODE_ENC_B:
case CHANNEL_MODE_ENC_AB: {
TIM_Encoder_InitTypeDef enc_config;
enc_config.EncoderMode = channel_mode_info[chan->mode].oc_mode;
enc_config.IC1Polarity = args[6].u_int;
if (enc_config.IC1Polarity == 0xffffffff) {
enc_config.IC1Polarity = TIM_ICPOLARITY_RISING;
}
enc_config.IC2Polarity = enc_config.IC1Polarity;
enc_config.IC1Selection = TIM_ICSELECTION_DIRECTTI;
enc_config.IC2Selection = TIM_ICSELECTION_DIRECTTI;
enc_config.IC1Prescaler = TIM_ICPSC_DIV1;
enc_config.IC2Prescaler = TIM_ICPSC_DIV1;
enc_config.IC1Filter = 0;
enc_config.IC2Filter = 0;
if (!IS_TIM_IC_POLARITY(enc_config.IC1Polarity)) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid polarity (%d)", enc_config.IC1Polarity));
}
// Only Timers 1, 2, 3, 4, 5, and 8 support encoder mode
if (self->tim.Instance != TIM1
&& self->tim.Instance != TIM2
&& self->tim.Instance != TIM3
&& self->tim.Instance != TIM4
&& self->tim.Instance != TIM5
&& self->tim.Instance != TIM8 ) {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "encoder not supported on timer %d", self->tim_id));
}
HAL_TIM_Encoder_Init(&self->tim, &enc_config);
__HAL_TIM_SetCounter(&self->tim, 0);
break;
}
default:
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid mode (%d)", chan->mode));
}
......@@ -1077,6 +1129,9 @@ STATIC const mp_map_elem_t pyb_timer_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_OC_FORCED_ACTIVE), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_OC_FORCED_ACTIVE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_OC_FORCED_INACTIVE), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_OC_FORCED_INACTIVE) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_IC), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_IC) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ENC_A), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_ENC_A) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ENC_B), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_ENC_B) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ENC_AB), MP_OBJ_NEW_SMALL_INT(CHANNEL_MODE_ENC_AB) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_HIGH), MP_OBJ_NEW_SMALL_INT(TIM_OCPOLARITY_HIGH) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_LOW), MP_OBJ_NEW_SMALL_INT(TIM_OCPOLARITY_LOW) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_RISING), MP_OBJ_NEW_SMALL_INT(TIM_ICPOLARITY_RISING) },
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment