Skip to content

Commit

Permalink
mimxrt: Support Encoder/Counter for the MIMXRT117x family.
Browse files Browse the repository at this point in the history
Signed-off-by: robert-hh <robert@hammelrath.com>
  • Loading branch information
robert-hh committed Aug 31, 2023
1 parent f53a2bd commit 1365224
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 30 deletions.
22 changes: 11 additions & 11 deletions docs/mimxrt/quickref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -556,17 +556,17 @@ Example usage::

qe = Encoder(0, Pin(0), Pin(1)) # create Quadrature Encoder object
qe.value() # get current counter values
qe.value(0) # Set value and cycles to 0
qe.init(cpc=128) # Specify 128 counts/cycle
qe.init(index=Pin(3)) # Specify Pin 3 as Index pulse input
qe.value(0) # set value and cycles to 0
qe.init(cpc=128) # specify 128 counts/cycle
qe.init(index=Pin(3)) # specify Pin 3 as Index pulse input
qe.deinit() # turn off the Quadrature Encoder
qe.init(match=64) # Set a match event at count 64
qe.init(match=64) # set a match event at count 64
qe.irq(qe.IRQ_MATCH, value=100, handler=handler)
# Call the function handler at a match event
# call the function handler at a match event

qe # show the Encoder object properties

The Quadrature Encoder is hardware based. It available on all MIMXRT devices exept the ones
The Quadrature Encoder is hardware based. It is available at all MIMXRT devices except the ones
based on the i.MX RT 1010 MCU. For details about using the Encoder with a MIMXRT board
see :ref:`machine.Encoder <mimxrt_machine.Encoder>`:

Expand All @@ -585,15 +585,15 @@ Example usage::

counter = Counter(0, Pin(0)) # create Counter object
counter.value() # get current counter value
counter.value(0) # Set the counter to 0
counter.init(cpc=128) # Specify 128 counts/cycle
counter.value(0) # set the counter to 0
counter.init(cpc=128) # specify 128 counts/cycle
counter.deinit() # turn off the Counter
counter.init(match=1000) # Create a match event at count 1000
counter.irq(Counter.IRQ_MATCH, handler) # Call the function handler at a counter match
counter.init(match=1000) # create a match event at count 1000
counter.irq(Counter.IRQ_MATCH, handler) # call the function handler at a counter match

counter # show the Counter object properties

The Quadrature Encoder is hardware based. It available on all MIMXRT devices exept the ones
The Counter is hardware based. It is available at all MIMXRT devices except the ones
based on the i.MX RT 1010 MCU. For details about using the Counter with a MIMXRT board
see :ref:`machine.Counter <mimxrt_machine.Counter>`:

Expand Down
2 changes: 1 addition & 1 deletion ports/mimxrt/boards/make-pins.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ def module_instance_factory(pins, output_file, name):
if name == "FLEXPWM":
output_file.write(f"#define {k} {k[-4:]}\n")
if name == "XBAR":
output_file.write(f"#define {k} {k}A1\n")
output_file.write(f"#define {k} {k[:4]}A1\n")
for i in v:
output_file.write(i + "\n")

Expand Down
133 changes: 115 additions & 18 deletions ports/mimxrt/machine_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ typedef struct _machine_encoder_obj_t {
mp_obj_base_t base;
ENC_Type *instance;
int8_t id;
bool active;
uint8_t input_a;
uint8_t input_b;
uint8_t mode;
Expand Down Expand Up @@ -69,13 +70,6 @@ typedef struct _encoder_xbar_signal_t {
#define ENCODER_TRIGGER_ROLL_UNDER (kENC_PositionRollUnderFlag)
#define ENCODER_ALL_INTERRUPTS (0x7f)

#if !defined(XBAR_ENC_DIR_OFFSET)
#define XBAR_ENC_DIR_OFFSET (12)
#define XBAR_ENC_DIR_REGISTER GPR6
#define XBAR_OUT_MIN (4)
#define XBAR_OUT_MAX (19)
#endif

#define XBAR_IN (1)
#define XBAR_OUT (0)

Expand All @@ -86,6 +80,58 @@ typedef struct _encoder_xbar_signal_t {

STATIC void encoder_deinit_single(machine_encoder_obj_t *self);

#if defined MIMXRT117x_SERIES

#define XBAR_ENC_DIR_OFFSET_1 (4)
#define XBAR_ENC_DIR_REGISTER_1 GPR20
#define XBAR_ENC_DIR_OFFSET_2 (32)
#define XBAR_ENC_DIR_REGISTER_2 GPR21
#define XBAR_OUT_MIN (4)
#define XBAR_OUT_MAX (42)
#define XBAR_STRING "XBAR1_INOUT"
#define XBAR_STRING_LEN strlen(XBAR_STRING)

static encoder_xbar_signal_t xbar_signal_table[FSL_FEATURE_SOC_ENC_COUNT] = {
{ kXBARA1_OutputDec1Phasea,
kXBARA1_OutputDec1Phaseb,
kXBARA1_OutputDec1Index,
kXBARA1_OutputDec1Home,
kXBARA1_OutputDec1Trigger,
kXBARA1_InputDec1PosMatch },

{ kXBARA1_OutputDec2Phasea,
kXBARA1_OutputDec2Phaseb,
kXBARA1_OutputDec2Index,
kXBARA1_OutputDec2Home,
kXBARA1_OutputDec2Trigger,
kXBARA1_InputDec2PosMatch },

{ kXBARA1_OutputDec3Phasea,
kXBARA1_OutputDec3Phaseb,
kXBARA1_OutputDec3Index,
kXBARA1_OutputDec3Home,
kXBARA1_OutputDec3Trigger,
kXBARA1_InputDec3PosMatch },

{ kXBARA1_OutputDec4Phasea,
kXBARA1_OutputDec4Phaseb,
kXBARA1_OutputDec4Index,
kXBARA1_OutputDec4Home,
kXBARA1_OutputDec4Trigger,
kXBARA1_InputDec4PosMatch },
};

#else // defined MIMXRT117x_SERIES

#if !defined(XBAR_ENC_DIR_OFFSET)
#define XBAR_ENC_DIR_OFFSET (12)
#define XBAR_ENC_DIR_REGISTER GPR6
#define XBAR_OUT_MIN (4)
#define XBAR_OUT_MAX (19)
#endif
#define XBAR_STRING "XBAR_INOUT"
#define XBAR_STRING_LEN strlen(XBAR_STRING)

static encoder_xbar_signal_t xbar_signal_table[FSL_FEATURE_SOC_ENC_COUNT] = {
{ kXBARA1_OutputEnc1PhaseAInput,
kXBARA1_OutputEnc1PhaseBInput,
Expand Down Expand Up @@ -122,6 +168,7 @@ static encoder_xbar_signal_t xbar_signal_table[FSL_FEATURE_SOC_ENC_COUNT] = {
#endif
#endif
};
#endif // defined MIMXRT117x_SERIES

static machine_encoder_obj_t *encoder_table[FSL_FEATURE_SOC_ENC_COUNT];
static ENC_Type *enc_instances[] = ENC_BASE_PTRS;
Expand Down Expand Up @@ -185,13 +232,14 @@ STATIC const machine_pin_af_obj_t *af_name_decode_xbar(const machine_pin_af_obj_
xbar_input_signal_t *io_number) {
const char *str;
size_t len;
size_t xlen = XBAR_STRING_LEN;
str = (char *)qstr_data(af_obj->name, &len);
// test for the name starting with XBAR_INOUT
if (len < 12 || strncmp(str, "XBAR_INOUT", 10) != 0) {
// test for the name starting with XBAR
if (len < (xlen + 2) || strncmp(str, XBAR_STRING, xlen) != 0) {
return NULL;
}
// Get I/O number, e.g. XBAR_INOUT03
*io_number = (str[10] - '0') * 10 + (str[11] - '0');
*io_number = (str[xlen] - '0') * 10 + (str[xlen + 1] - '0');
return af_obj;
}

Expand All @@ -215,12 +263,26 @@ STATIC uint8_t connect_pin_to_encoder(mp_obj_t desc, xbar_output_signal_t encode
XBARA_SetSignalsConnection(XBARA1, xbar_pin, encoder_signal);
} else {
// No API here, so do basic Register access.
#if defined MIMXRT117x_SERIES
if (xbar_pin >= XBAR_OUT_MIN && xbar_pin <= XBAR_OUT_MAX) {
if (xbar_pin < XBAR_ENC_DIR_OFFSET_2) {
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER_1 |= 1 << (xbar_pin - XBAR_ENC_DIR_OFFSET_1);
XBARA_SetSignalsConnection(XBARA1, encoder_signal, xbar_pin);
} else {
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER_2 |= 1 << (xbar_pin - XBAR_ENC_DIR_OFFSET_2);
XBARA_SetSignalsConnection(XBARA1, encoder_signal, xbar_pin);
}
} else {
mp_raise_ValueError(MP_ERROR_TEXT("invalid match Pin"));
}
#else
if (xbar_pin >= XBAR_OUT_MIN && xbar_pin <= XBAR_OUT_MAX) {
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER |= 1 << (xbar_pin + XBAR_ENC_DIR_OFFSET); // Compare the offset 12 with other MCU
XBARA_SetSignalsConnection(XBARA1, encoder_signal, xbar_pin);
} else {
mp_raise_ValueError(MP_ERROR_TEXT("invalid match Pin"));
}
#endif // defined MIMXRT117x_SERIES
}
return xbar_pin;
}
Expand All @@ -239,7 +301,12 @@ STATIC void clear_encoder_registers(machine_encoder_obj_t *self) {
//
STATIC uint32_t calc_filter(uint32_t filter_ns, uint16_t *count, uint16_t *period) {

#if defined MIMXRT117x_SERIES
uint32_t freq_khz = CLOCK_GetRootClockFreq(kCLOCK_Root_Bus) / 1000;
#else
uint32_t freq_khz = CLOCK_GetIpgFreq() / 1000;
#endif

uint32_t cycles = (filter_ns * (freq_khz / 1000)) / 1000;
if (cycles == 0) {
// Set filter off
Expand Down Expand Up @@ -277,7 +344,15 @@ STATIC void mp_machine_encoder_init_helper_common(machine_encoder_obj_t *self,
self->match_pin = connect_pin_to_encoder(args[ARG_match_pin].u_obj, xbar_signal_table[self->id].enc_match, XBAR_OUT);
} else {
// Disconnect the XBAR from the output by switching it to an input.
#if defined MIMXRT117x_SERIES
if (self->match_pin < XBAR_ENC_DIR_OFFSET_2) {
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER_1 &= ~(1 << (self->match_pin - XBAR_ENC_DIR_OFFSET_1));
} else {
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER_2 &= ~(1 << (self->match_pin - XBAR_ENC_DIR_OFFSET_2));
}
#else
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER &= ~(1 << (self->match_pin + XBAR_ENC_DIR_OFFSET));
#endif
}
}

Expand Down Expand Up @@ -321,6 +396,7 @@ STATIC void mp_machine_encoder_init_helper_common(machine_encoder_obj_t *self,
ENC_Init(self->instance, enc_config);
clear_encoder_registers(self);
ENC_ClearStatusFlags(self->instance, 0xff); // Clear all status flags
self->active = true;
}

STATIC void mp_machine_encoder_init_helper(machine_encoder_obj_t *self,
Expand Down Expand Up @@ -420,15 +496,26 @@ STATIC mp_obj_t mp_machine_encoder_make_new(const mp_obj_type_t *type, size_t n_
}

STATIC void encoder_deinit_single(machine_encoder_obj_t *self) {
if (self->irq->handler) {
DisableIRQ(enc_irqn[self->id + 1]);
ENC_DisableInterrupts(self->instance, ENCODER_ALL_INTERRUPTS);
}
if (self->match_pin != 0) {
// Disconnect the XBAR from the output by switching it to an input.
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER &= ~(1 << (self->match_pin + XBAR_ENC_DIR_OFFSET));
if (self->active) {
if (self->irq && self->irq->handler) {
DisableIRQ(enc_irqn[self->id + 1]);
ENC_DisableInterrupts(self->instance, ENCODER_ALL_INTERRUPTS);
}
if (self->match_pin != 0) {
// Disconnect the XBAR from the output by switching it to an input.
#if defined MIMXRT117x_SERIES
if (self->match_pin < XBAR_ENC_DIR_OFFSET_2) {
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER_1 &= ~(1 << (self->match_pin - XBAR_ENC_DIR_OFFSET_1));
} else {
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER_2 &= ~(1 << (self->match_pin - XBAR_ENC_DIR_OFFSET_2));
}
#else
IOMUXC_GPR->XBAR_ENC_DIR_REGISTER &= ~(1 << (self->match_pin + XBAR_ENC_DIR_OFFSET));
#endif
}
ENC_Deinit(self->instance);
}
ENC_Deinit(self->instance);
self->active = false;
}

// encoder_deinit_all()
Expand Down Expand Up @@ -458,6 +545,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_encoder_status_obj, machine_encoder_sta
// encoder.value([value])
STATIC mp_obj_t machine_encoder_value(size_t n_args, const mp_obj_t *args) {
machine_encoder_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (!self->active) {
mp_raise_ValueError(MP_ERROR_TEXT("device stopped"));
}
uint32_t actual_value = ENC_GetPositionValue(self->instance);
if (n_args > 1) {
// Set the encoder position value and clear the rev counter.
Expand All @@ -481,6 +571,10 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_encoder_value_obj, 1, 2, mach
// encoder.cycles([value])
STATIC mp_obj_t machine_encoder_cycles(size_t n_args, const mp_obj_t *args) {
machine_encoder_obj_t *self = MP_OBJ_TO_PTR(args[0]);
if (!self->active) {
mp_raise_ValueError(MP_ERROR_TEXT("device stopped"));
}

int16_t cycles = (int16_t)ENC_GetRevolutionValue(self->instance);
if (n_args > 1) {
// Set the revolution value
Expand All @@ -502,6 +596,9 @@ STATIC mp_obj_t machine_encoder_irq(size_t n_args, const mp_obj_t *pos_args, mp_
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
machine_encoder_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
if (!self->active) {
mp_raise_ValueError(MP_ERROR_TEXT("device stopped"));
}

if (self->irq == NULL) {
self->irq = m_new_obj(mp_irq_obj_t);
Expand Down

0 comments on commit 1365224

Please sign in to comment.