mimxrt: Implement Quadrature Encoder and Counter classes.

These classes are based on the Quadrature Encoder blocks of the i.MXRT
MCUs.  The i.MXRT 102x has two encoders, the other ones four.  The i.MXRT
101x does not support this function.  It is implemented as two classes,
Encoder and Counter.

The number of pins that can be uses as inputs is limited by the MCU
architecture and the board schematics.  The Encoder class supports:
- Defining the module.
- Defining the input pins.
- Defining a pin for an index signal.
- Defining a pin for a reset signal.
- Defining an output pin showing the compare match signal.
- Setting the number of cycles per revolution (min/max).
- Setting the initial value for the position.
- Setting the counting direction.
- Setting a glitch filter.
- Defining callbacks for getting to a specific position, overrun and
  underrun (starting the next revolution).  These callbacks can be hard
  interrupts to ensure short latency.

The encoder counts all phases of a cycle.  The span for the position is
2**32, for the revolution is 2**16.  The highest input frequency is
CPU-Clock/24.  Note that the "phases" argument is emulated at the API
level (the hardware will always count all phases).

The Counter mode counts single pulses on input A of the Encoder.  The
configuration supports:
- Defining the module.
- Defining the input pin.
- Defining the counting direction, either fixed or controlled by the level
  of an input pin.
- Defining a pin for an index signal.
- Defining an output pin showing the compare match signal.
- Setting the counter value.
- Setting the glitch filter.
- Defining a callback which is called at a certain value.
- Settings for MIMXRT1015. The MIMXRT1015 MCU has only one encoder/counter
  unit.

The counting range is 0 - 2**32-1 and a 16 bit overrun counter.  The
highest input frequency is CPU-Clock/12.

The implementation of the `.irq()` method uses the common code from
`shared/runtime/mpirq.c`, including the `irq().flags()` and
`irq().trigger()` methods.

Signed-off-by: robert-hh <robert@hammelrath.com>
This commit is contained in:
robert-hh
2021-09-24 21:47:31 +02:00
committed by Damien George
parent c3ca843493
commit 61bbd78eba
13 changed files with 921 additions and 14 deletions

View File

@@ -217,6 +217,10 @@ extern const mp_obj_type_t machine_timer_type;
extern const mp_obj_type_t machine_uart_type;
extern const mp_obj_type_t machine_usbd_type;
extern const mp_obj_type_t machine_wdt_type;
#if MICROPY_PY_MACHINE_QECNT
extern const mp_obj_type_t machine_encoder_type;
extern const mp_obj_type_t machine_counter_type;
#endif
#if MICROPY_PY_MACHINE_SOFTI2C
extern const mp_obj_type_t mp_machine_soft_i2c_type;

View File

@@ -190,9 +190,16 @@ endif
ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES), MIMXRT1015 MIMXRT1021 MIMXRT1052 MIMXRT1062 MIMXRT1064 MIMXRT1176))
SRC_HAL_IMX_C += \
$(MCUX_SDK_DIR)/drivers/qtmr_1/fsl_qtmr.c \
$(MCUX_SDK_DIR)/drivers/enc/fsl_enc.c \
$(MCUX_SDK_DIR)/drivers/xbara/fsl_xbara.c \
$(MCU_DIR)/drivers/fsl_romapi.c
INC_HAL_IMX += -I$(TOP)/$(MCUX_SDK_DIR)/drivers/qtmr_1
INC_HAL_IMX += \
-I$(TOP)/$(MCUX_SDK_DIR)/drivers/enc \
-I$(TOP)/$(MCUX_SDK_DIR)/drivers/xbara \
-I$(TOP)/$(MCUX_SDK_DIR)/drivers/qtmr_1
CFLAGS += -DMICROPY_PY_MACHINE_QECNT=1
endif
# If not empty, then it is 10xx.
@@ -256,6 +263,7 @@ SRC_C += \
machine_i2c.c \
machine_led.c \
machine_pin.c \
machine_encoder.c \
machine_rtc.c \
machine_sdcard.c \
machine_spi.c \

View File

@@ -82,3 +82,5 @@
I2S_GPIO(1, WS, TX, GPIO_07, IOMUXC_GPIO_07_SAI1_TX_SYNC), \
I2S_GPIO(1, SD, TX, GPIO_04, IOMUXC_GPIO_04_SAI1_TX_DATA00), \
}
#define XBARA1 XBARA

View File

@@ -20,14 +20,14 @@ GPIO_AD_03,LPSPI1_SDI,PIT_TRIGGER3,FLEXPWM1_PWM2_B,KPP_ROW2,GPT2_CLK,GPIO1_IO17,
GPIO_AD_04,LPSPI1_SDO,PIT_TRIGGER2,FLEXPWM1_PWM2_A,KPP_COL2,GPT2_COMPARE1,GPIO1_IO18,SNVS_VIO_5_CTL,,,,ADC1_IN4,,ALT5
GPIO_AD_05,LPSPI1_PCS0,PIT_TRIGGER1,FLEXPWM1_PWM3_B,KPP_ROW1,GPT2_CAPTURE1,GPIO1_IO19,,,,,ADC1_IN5,,ALT5
GPIO_AD_06,LPSPI1_SCK,PIT_TRIGGER0,FLEXPWM1_PWM3_A,KPP_COL1,GPT2_COMPARE2,GPIO1_IO20,LPI2C1_HREQ,,,,ADC1_IN6,,ALT5
GPIO_AD_07,LPI2C2_SDA,LPUART3_RXD,ARM_CM7_RXEV,LPUART2_RTS_B,GPT2_CAPTURE2,GPIO1_IO21,OCOTP_FUSE_LATCHED,XBAR1_INOUT03,,,ADC1_IN7,,ALT5
GPIO_AD_07,LPI2C2_SDA,LPUART3_RXD,ARM_CM7_RXEV,LPUART2_RTS_B,GPT2_CAPTURE2,GPIO1_IO21,OCOTP_FUSE_LATCHED,XBAR_INOUT03,,,ADC1_IN7,,ALT5
GPIO_AD_08,LPI2C2_SCL,LPUART3_TXD,ARM_CM7_TXEV,LPUART2_CTS_B,GPT2_COMPARE3,GPIO1_IO22,EWM_OUT_B,JTAG_TRSTB,,,ADC1_IN8,,ALT7
GPIO_AD_09,LPSPI2_SDI,FLEXPWM1_PWM3_X,KPP_ROW2,ARM_TRACE_SWO,FLEXIO1_IO21,GPIO1_IO23,REF_CLK_32K,JTAG_TDO,,,ADC1_IN9,,ALT7
GPIO_AD_10,LPSPI2_SDO,FLEXPWM1_PWM2_X,KPP_COL2,PIT_TRIGGER3,FLEXIO1_IO22,GPIO1_IO24,USB_OTG1_ID,JTAG_TDI,,,ADC1_IN10,,ALT7
GPIO_AD_11,LPSPI2_PCS0,FLEXPWM1_PWM1_X,KPP_ROW1,PIT_TRIGGER2,FLEXIO1_IO23,GPIO1_IO25,WDOG1_B,JTAG_MOD,,,ADC1_IN11,,ALT7
GPIO_AD_12,LPSPI2_SCK,FLEXPWM1_PWM0_X,KPP_COL1,PIT_TRIGGER1,FLEXIO1_IO24,GPIO1_IO26,USB_OTG1_PWR,JTAG_TCK,,,ADC1_IN12,,ALT7
GPIO_AD_13,LPI2C1_SDA,LPUART3_RTS_B,KPP_ROW0,LPUART4_RTS_B,FLEXIO1_IO25,GPIO1_IO27,ARM_NMI,JTAG_TMS,,,ADC1_IN13,,ALT7
GPIO_AD_14,LPI2C1_SCL,LPUART3_CTS_B,KPP_COL0,LPUART4_CTS_B,FLEXIO1_IO26,GPIO1_IO28,REF_CLK_24M,XBAR1_INOUT02,,,ADC1_IN14,,ALT5
GPIO_AD_14,LPI2C1_SCL,LPUART3_CTS_B,KPP_COL0,LPUART4_CTS_B,FLEXIO1_IO26,GPIO1_IO28,REF_CLK_24M,XBAR_INOUT02,,,ADC1_IN14,,ALT5
GPIO_SD_00,FLEXSPI_B_SS0_B,SAI3_TX_SYNC,ARM_CM7_RXEV,CCM_STOP,FLEXIO1_IO06,GPIO2_IO00,SRC_BT_CFG2,,,,,,ALT5
GPIO_SD_01,FLEXSPI_B_DATA1,SAI3_TX_BCLK,FLEXPWM1_PWM0_B,CCM_CLKO2,FLEXIO1_IO07,GPIO2_IO01,SRC_BT_CFG1,,,,,,ALT5
GPIO_SD_02,FLEXSPI_B_DATA2,SAI3_TX_DATA,FLEXPWM1_PWM0_A,CCM_CLKO1,FLEXIO1_IO08,GPIO2_IO02,SRC_BT_CFG0,,,,,,ALT5
1 Pad ALT0 ALT1 ALT2 ALT3 ALT4 ALT5 ALT6 ALT7 ALT8 ALT9 ADC ACMP Default
20 GPIO_AD_04 LPSPI1_SDO PIT_TRIGGER2 FLEXPWM1_PWM2_A KPP_COL2 GPT2_COMPARE1 GPIO1_IO18 SNVS_VIO_5_CTL ADC1_IN4 ALT5
21 GPIO_AD_05 LPSPI1_PCS0 PIT_TRIGGER1 FLEXPWM1_PWM3_B KPP_ROW1 GPT2_CAPTURE1 GPIO1_IO19 ADC1_IN5 ALT5
22 GPIO_AD_06 LPSPI1_SCK PIT_TRIGGER0 FLEXPWM1_PWM3_A KPP_COL1 GPT2_COMPARE2 GPIO1_IO20 LPI2C1_HREQ ADC1_IN6 ALT5
23 GPIO_AD_07 LPI2C2_SDA LPUART3_RXD ARM_CM7_RXEV LPUART2_RTS_B GPT2_CAPTURE2 GPIO1_IO21 OCOTP_FUSE_LATCHED XBAR1_INOUT03 XBAR_INOUT03 ADC1_IN7 ALT5
24 GPIO_AD_08 LPI2C2_SCL LPUART3_TXD ARM_CM7_TXEV LPUART2_CTS_B GPT2_COMPARE3 GPIO1_IO22 EWM_OUT_B JTAG_TRSTB ADC1_IN8 ALT7
25 GPIO_AD_09 LPSPI2_SDI FLEXPWM1_PWM3_X KPP_ROW2 ARM_TRACE_SWO FLEXIO1_IO21 GPIO1_IO23 REF_CLK_32K JTAG_TDO ADC1_IN9 ALT7
26 GPIO_AD_10 LPSPI2_SDO FLEXPWM1_PWM2_X KPP_COL2 PIT_TRIGGER3 FLEXIO1_IO22 GPIO1_IO24 USB_OTG1_ID JTAG_TDI ADC1_IN10 ALT7
27 GPIO_AD_11 LPSPI2_PCS0 FLEXPWM1_PWM1_X KPP_ROW1 PIT_TRIGGER2 FLEXIO1_IO23 GPIO1_IO25 WDOG1_B JTAG_MOD ADC1_IN11 ALT7
28 GPIO_AD_12 LPSPI2_SCK FLEXPWM1_PWM0_X KPP_COL1 PIT_TRIGGER1 FLEXIO1_IO24 GPIO1_IO26 USB_OTG1_PWR JTAG_TCK ADC1_IN12 ALT7
29 GPIO_AD_13 LPI2C1_SDA LPUART3_RTS_B KPP_ROW0 LPUART4_RTS_B FLEXIO1_IO25 GPIO1_IO27 ARM_NMI JTAG_TMS ADC1_IN13 ALT7
30 GPIO_AD_14 LPI2C1_SCL LPUART3_CTS_B KPP_COL0 LPUART4_CTS_B FLEXIO1_IO26 GPIO1_IO28 REF_CLK_24M XBAR1_INOUT02 XBAR_INOUT02 ADC1_IN14 ALT5
31 GPIO_SD_00 FLEXSPI_B_SS0_B SAI3_TX_SYNC ARM_CM7_RXEV CCM_STOP FLEXIO1_IO06 GPIO2_IO00 SRC_BT_CFG2 ALT5
32 GPIO_SD_01 FLEXSPI_B_DATA1 SAI3_TX_BCLK FLEXPWM1_PWM0_B CCM_CLKO2 FLEXIO1_IO07 GPIO2_IO01 SRC_BT_CFG1 ALT5
33 GPIO_SD_02 FLEXSPI_B_DATA2 SAI3_TX_DATA FLEXPWM1_PWM0_A CCM_CLKO1 FLEXIO1_IO08 GPIO2_IO02 SRC_BT_CFG0 ALT5

View File

@@ -87,3 +87,5 @@
I2S_GPIO(1, WS, TX, GPIO_EMC_27, IOMUXC_GPIO_EMC_27_SAI1_TX_SYNC), \
I2S_GPIO(1, SD, TX, GPIO_EMC_25, IOMUXC_GPIO_EMC_25_SAI1_TX_DATA00), \
}
#define XBARA1 XBARA

View File

@@ -22,6 +22,8 @@ A4,GPIO_AD_B1_15
A5,GPIO_AD_B1_14
RX,GPIO_EMC_33
TX,GPIO_EMC_32
ENC1,GPIO_EMC_06
ENC2,GPIO_EMC_07
SDA,GPIO_AD_B1_15
SCL,GPIO_AD_B1_14
SCK,GPIO_AD_B0_10
1 D0 GPIO_EMC_33
22 A5 GPIO_AD_B1_14
23 RX GPIO_EMC_33
24 TX GPIO_EMC_32
25 ENC1 GPIO_EMC_06
26 ENC2 GPIO_EMC_07
27 SDA GPIO_AD_B1_15
28 SCL GPIO_AD_B1_14
29 SCK GPIO_AD_B0_10

View File

@@ -181,3 +181,5 @@
{ IOMUXC_GPIO_AD_B0_15_ENET_TDATA01, 0, 0xB0E9u }, \
{ IOMUXC_GPIO_EMC_40_ENET_MDIO, 0, 0xB0E9u }, \
{ IOMUXC_GPIO_EMC_41_ENET_MDC, 0, 0xB0E9u },
#define XBARA1 XBARA

View File

@@ -88,3 +88,5 @@
I2S_GPIO(3, WS, TX, GPIO_SD_00, IOMUXC_GPIO_SD_00_SAI3_TX_SYNC), /* pin D9 */ \
I2S_GPIO(3, SD, TX, GPIO_SD_02, IOMUXC_GPIO_SD_02_SAI3_TX_DATA) /* pin D11 */ \
}
#define XBARA1 XBARA

870
ports/mimxrt/machine_encoder.c Executable file
View File

@@ -0,0 +1,870 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2020-2021 Damien P. George
* Copyright (c) 2026 Robert Hammelrath
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#if MICROPY_PY_MACHINE_QECNT
#include "py/runtime.h"
#include "py/mphal.h"
#include "py/objint.h"
#include "shared/runtime/mpirq.h"
#include "extmod/modmachine.h"
#include "modmachine.h"
#include "fsl_clock.h"
#include "fsl_enc.h"
#include "fsl_xbara.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
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;
uint8_t match_pin;
uint8_t phases_inv;
uint32_t max_count;
uint32_t min_count;
uint32_t filter;
mp_obj_t reset_pin;
uint16_t mp_irq_flags;
uint16_t mp_irq_trigger;
mp_irq_obj_t *mp_irq_obj;
enc_config_t enc_config;
} machine_encoder_obj_t;
typedef struct _encoder_xbar_signal_t {
xbar_output_signal_t enc_input_a;
xbar_output_signal_t enc_input_b;
xbar_output_signal_t enc_index;
xbar_output_signal_t enc_home;
xbar_output_signal_t enc_trigger;
xbar_input_signal_t enc_match;
} encoder_xbar_signal_t;
#define ENCODER_ALL_INTERRUPTS (0x7f)
#define XBAR_IN (1)
#define XBAR_OUT (0)
#define COUNTER_UP (-2)
#define COUNTER_DOWN (-3)
#define MODE_ENCODER (0)
#define MODE_COUNTER (1)
#define MP_ENCODER_ALLOWED_FLAGS (kENC_HOMETransitionFlag | kENC_INDEXPulseFlag | kENC_PositionCompareFlag | kENC_PositionRollUnderFlag | kENC_PositionRollOverFlag)
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,
kXBARA1_OutputEnc1Index,
kXBARA1_OutputEnc1Home,
kXBARA1_OutputEnc1Trigger,
kXBARA1_InputEnc1PosMatch },
#if FSL_FEATURE_SOC_ENC_COUNT > 1
{ kXBARA1_OutputEnc2PhaseAInput,
kXBARA1_OutputEnc2PhaseBInput,
kXBARA1_OutputEnc2Index,
kXBARA1_OutputEnc2Home,
kXBARA1_OutputEnc2Trigger,
kXBARA1_InputEnc2PosMatch },
#if FSL_FEATURE_SOC_ENC_COUNT > 2
{ kXBARA1_OutputEnc3PhaseAInput,
kXBARA1_OutputEnc3PhaseBInput,
kXBARA1_OutputEnc3Index,
kXBARA1_OutputEnc3Home,
kXBARA1_OutputEnc3Trigger,
kXBARA1_InputEnc3PosMatch },
{ kXBARA1_OutputEnc4PhaseAInput,
kXBARA1_OutputEnc4PhaseBInput,
kXBARA1_OutputEnc4Index,
kXBARA1_OutputEnc4Home,
kXBARA1_OutputEnc4Trigger,
kXBARA1_InputEnc4PosMatch },
#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;
static IRQn_Type enc_irqn[] = ENC_COMPARE_IRQS;
__attribute__((section(".ram_functions"))) void irq_callback(int irq_num) {
machine_encoder_obj_t *self = encoder_table[irq_num];
if (self != NULL) {
self->mp_irq_flags = ENC_GetStatusFlags(self->instance);
// In case of a position match event, disable that interrupt such that is is only handled
// once until enabled again. This is needed since otherwise the match interrupt will
// be triggered again as long as the match condition is true.
if (self->mp_irq_flags & kENC_PositionCompareFlag) {
ENC_DisableInterrupts(self->instance, kENC_PositionCompareInerruptEnable);
}
ENC_ClearStatusFlags(self->instance, self->mp_irq_flags);
__DSB();
mp_irq_handler(self->mp_irq_obj);
}
}
__attribute__((section(".ram_functions"))) void ENC1_IRQHandler(void) {
irq_callback(0);
}
#if FSL_FEATURE_SOC_ENC_COUNT > 1
__attribute__((section(".ram_functions"))) void ENC2_IRQHandler(void) {
irq_callback(1);
}
#if FSL_FEATURE_SOC_ENC_COUNT > 2
__attribute__((section(".ram_functions"))) void ENC3_IRQHandler(void) {
irq_callback(2);
}
__attribute__((section(".ram_functions"))) void ENC4_IRQHandler(void) {
irq_callback(3);
}
#endif
#endif
static void mp_machine_encoder_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
machine_encoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (self->mode == MODE_ENCODER) {
int32_t min = (int32_t)self->min_count;
if (min > 0) {
min += (self->phases_inv - 1);
}
int32_t max = (int32_t)self->max_count;
if (max > 0) {
max += (self->phases_inv - 1);
}
int32_t match = (int32_t)self->enc_config.positionCompareValue;
if (match > 0) {
match += (self->phases_inv - 1);
}
mp_printf(print, "Encoder(%d, phases=%d, max=%ld, min=%ld, match=%ld, filter_ns=%lu)",
self->id, 4 / self->phases_inv,
max / self->phases_inv, min / self->phases_inv,
match / self->phases_inv, self->filter);
} else {
mp_printf(print, "Counter(%d, max=%ld, min=%ld, match=%ld, filter_ns=%lu)",
self->id, self->max_count, self->min_count,
self->enc_config.positionCompareValue, self->filter);
}
}
// Utility functions
//
static void encoder_set_iomux(const machine_pin_obj_t *pin, const machine_pin_af_obj_t *af) {
IOMUXC_SetPinMux(pin->muxRegister, af->af_mode, af->input_register, af->input_daisy, pin->configRegister, 0U);
IOMUXC_SetPinConfig(pin->muxRegister, af->af_mode, af->input_register, af->input_daisy, pin->configRegister, 0x10B0U);
}
// decode the AF objects module and Port numer. Returns NULL if it is not a XBAR object
static const machine_pin_af_obj_t *af_name_decode_xbar(const machine_pin_af_obj_t *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
if (len < (xlen + 2) || strncmp(str, XBAR_STRING, xlen) != 0) {
return NULL;
}
// Get I/O number, e.g. XBAR_INOUT03
*io_number = (str[xlen] - '0') * 10 + (str[xlen + 1] - '0');
return af_obj;
}
static const machine_pin_af_obj_t *find_xbar_af(const machine_pin_obj_t *pin, xbar_input_signal_t *io_number) {
const machine_pin_af_obj_t *af = NULL;
for (int i = 0; i < pin->af_list_len; ++i) {
af = af_name_decode_xbar(&(pin->af_list[i]), io_number);
if (af != NULL) {
return af;
}
}
mp_raise_ValueError(MP_ERROR_TEXT("invalid input Pin"));
}
static uint8_t connect_pin_to_encoder(mp_obj_t desc, xbar_output_signal_t encoder_signal, uint8_t direction) {
xbar_input_signal_t xbar_pin;
const machine_pin_obj_t *pin = pin_find(desc);
const machine_pin_af_obj_t *af = find_xbar_af(pin, &xbar_pin);
encoder_set_iomux(pin, af);
if (direction == XBAR_IN) {
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;
}
static void clear_encoder_registers(machine_encoder_obj_t *self) {
// Create a High pulse on the Trigger input, clearing Position, Revolution and Hold registers.
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, xbar_signal_table[self->id].enc_home);
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicLow, xbar_signal_table[self->id].enc_home);
if (self->reset_pin) {
connect_pin_to_encoder(self->reset_pin, xbar_signal_table[self->id].enc_home, XBAR_IN);
}
}
//
// Functions for configuring the ENC Device
//
// Calculate the filter parameters based on a filter_ns value, telling the shortest
// pulse that will be detected.
//
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
*count = 0;
*period = 0;
} else {
uint16_t pmax = cycles / 10;
if (pmax > 255) {
pmax = 255;
}
if (pmax == 0) {
pmax = 1;
}
uint16_t cnt;
cnt = cycles / pmax;
if (cnt > 10) {
cnt = 10;
}
*count = cnt >= 3 ? cnt - 3 : 0;
*period = pmax;
}
return ((1000000000 / freq_khz) + 1) * (*count + 3) * *period / 1000;
}
// MicroPython API functions
//
static void mp_machine_encoder_init_helper_common(machine_encoder_obj_t *self,
mp_arg_val_t args[], enc_config_t *enc_config) {
enum { ARG_reset, ARG_match, ARG_match_pin, ARG_filter_ns, ARG_max, ARG_min, ARG_index };
// Check for a Home pin, resetting the counters
if (args[ARG_reset].u_obj != MP_ROM_INT(-1)) {
if (args[ARG_reset].u_obj != mp_const_none) {
self->reset_pin = args[ARG_reset].u_obj;
connect_pin_to_encoder(self->reset_pin, xbar_signal_table[self->id].enc_home, XBAR_IN);
self->enc_config.HOMETriggerMode = kENC_HOMETriggerOnRisingEdge;
} else {
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicLow, xbar_signal_table[self->id].enc_home);
self->reset_pin = NULL;
}
}
// Check for a Match pin for the compare match signal
if (args[ARG_match_pin].u_obj != MP_ROM_INT(-1)) {
if (args[ARG_match_pin].u_obj != mp_const_none) {
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
}
}
if (args[ARG_match].u_obj != mp_const_none) {
uint32_t compare = mp_obj_int_get_truncated(args[ARG_match].u_obj) * self->phases_inv;
self->enc_config.positionCompareValue = compare;
self->instance->LCOMP = (uint16_t)(compare) & 0xffff; // Lower 16 pos bits.
self->instance->UCOMP = (uint16_t)(compare >> 16U) & 0xffff; // Upper 16 pos bits.
} else {
// Set to the reset value
self->enc_config.positionCompareValue = 0xFFFFFFFFU;
self->instance->LCOMP = 0xffff;
self->instance->UCOMP = 0xffff;
// disable the interrupt to avoid false trigger
ENC_DisableInterrupts(self->instance, kENC_PositionCompareInerruptEnable);
}
if (args[ARG_filter_ns].u_int >= 0) {
self->filter = calc_filter(args[ARG_filter_ns].u_int,
&(enc_config->filterCount), &(enc_config->filterSamplePeriod));
}
if (args[ARG_max].u_obj != mp_const_none) {
self->max_count = mp_obj_int_get_truncated(args[ARG_max].u_obj) * self->phases_inv;
}
if (args[ARG_min].u_obj != mp_const_none) {
self->min_count = mp_obj_int_get_truncated(args[ARG_min].u_obj) * self->phases_inv;
}
enc_config->positionModulusValue =
self->max_count == 0 ? 0xffffffff : self->max_count + self->phases_inv - 1;
enc_config->positionInitialValue = self->min_count;
enc_config->enableModuloCountMode = true;
// Count cycles on RollOverModulus or index pulse
if (args[ARG_index].u_obj != MP_ROM_INT(-1)) {
if (args[ARG_index].u_obj != mp_const_none) {
connect_pin_to_encoder(args[ARG_index].u_obj, xbar_signal_table[self->id].enc_index, XBAR_IN);
enc_config->revolutionCountCondition = kENC_RevolutionCountOnINDEXPulse;
enc_config->INDEXTriggerMode = kENC_INDEXTriggerOnRisingEdge;
} else {
enc_config->revolutionCountCondition = kENC_RevolutionCountOnRollOverModulus;
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicLow, xbar_signal_table[self->id].enc_index);
}
}
// Initialize the ENC module and start
ENC_Init(self->instance, enc_config);
clear_encoder_registers(self);
// Set the position and clear the rev register
ENC_SetInitialPositionValue(self->instance, self->min_count);
ENC_DoSoftwareLoadInitialPositionValue(self->instance);
self->instance->REV = 0;
ENC_ClearStatusFlags(self->instance, 0xff); // Clear all status flags
self->active = true;
}
static void mp_machine_encoder_init_helper(machine_encoder_obj_t *self,
size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_phase_a, ARG_phase_b, ARG_phases, ARG_reset,
ARG_match, ARG_match_pin, ARG_filter_ns, ARG_max, ARG_min, ARG_index};
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_phase_a, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_phase_b, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_phases, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} },
{ MP_QSTR_match, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_match_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} },
{ MP_QSTR_filter_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_max, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_min, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args,
MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// Process the Encoder specific keyword arguments
// Get referred Pin object(s) and connect them to the encoder
if (args[ARG_phase_a].u_obj != mp_const_none) {
self->input_a = connect_pin_to_encoder(args[ARG_phase_a].u_obj, xbar_signal_table[self->id].enc_input_a, XBAR_IN);
}
if (args[ARG_phase_b].u_obj != mp_const_none) {
self->input_b = connect_pin_to_encoder(args[ARG_phase_b].u_obj, xbar_signal_table[self->id].enc_input_b, XBAR_IN);
}
// Check for valid input pins
if (self->input_a == 0 || self->input_b == 0 || self->input_a == self->input_b) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid or missing input pins"));
}
// Get the Phases argument
if (args[ARG_phases].u_int != -1) {
if ((args[ARG_phases].u_int != 1) && (args[ARG_phases].u_int != 2) && (args[ARG_phases].u_int != 4)) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid value for phases"));
}
self->phases_inv = 4 / args[ARG_phases].u_int;
}
// Set the common options
mp_machine_encoder_init_helper_common(self, args + ARG_reset, &self->enc_config);
ENC_DoSoftwareLoadInitialPositionValue(self->instance); /* Update the position counter with initial value. */
}
// Qencoder(id, input_a, input_b, [args])
static mp_obj_t mp_machine_encoder_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
// Check number of arguments
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
CLOCK_EnableClock(kCLOCK_Iomuxc); // just in case it was not set yet
XBARA_Init(XBARA1);
uint8_t id = mp_obj_get_int(args[0]);
if (id < 0 || id >= FSL_FEATURE_SOC_ENC_COUNT) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid encoder/counter id"));
}
// check, if the encoder is already in use, and if yes, deinit it
if (encoder_table[id] != NULL) {
encoder_deinit_single(encoder_table[id]);
}
// Connect the trigger input to low level
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicLow, xbar_signal_table[id].enc_trigger);
// Create and populate the Encoder object.
machine_encoder_obj_t *self = encoder_table[id];
if (self == NULL) {
self = mp_obj_malloc(machine_encoder_obj_t, &machine_encoder_type);
encoder_table[id] = self;
}
// Set defaults for ENC Config.
self->id = id;
self->input_a = 0;
self->input_b = 0;
self->instance = enc_instances[id + 1];
self->max_count = 0;
self->min_count = 0;
self->mp_irq_flags = 0;
self->mp_irq_trigger = 0;
self->mp_irq_obj = NULL;
self->match_pin = 0;
self->phases_inv = 4; // default: phases = 1
self->reset_pin = NULL;
self->mode = MODE_ENCODER;
// Set defaults for ENC Config
ENC_GetDefaultConfig(&self->enc_config);
self->enc_config.revolutionCountCondition = kENC_RevolutionCountOnRollOverModulus;
// Process the remaining parameters
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
mp_machine_encoder_init_helper(self, n_args - 1, args + 1, &kw_args);
return MP_OBJ_FROM_PTR(self);
}
static void encoder_deinit_single(machine_encoder_obj_t *self) {
if (self->active) {
if (self->mp_irq_obj && self->mp_irq_obj->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);
}
self->active = false;
}
// encoder_deinit_all()
void machine_encoder_deinit_all(void) {
for (int i = 0; i < ARRAY_SIZE(encoder_table); i++) {
if (encoder_table[i] != NULL) {
encoder_deinit_single(encoder_table[i]);
encoder_table[i] = NULL;
}
}
}
// encoder.deinit()
static mp_obj_t machine_encoder_deinit(mp_obj_t self_in) {
encoder_deinit_single(MP_OBJ_TO_PTR(self_in));
return mp_const_none;
}
static MP_DEFINE_CONST_FUN_OBJ_1(machine_encoder_deinit_obj, machine_encoder_deinit);
// 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) {
uint32_t value = mp_obj_int_get_truncated(args[1]) * self->phases_inv;
// Set the position register
ENC_SetInitialPositionValue(self->instance, value);
ENC_DoSoftwareLoadInitialPositionValue(self->instance);
// Reset the INIT Value, unlocking the counter.
ENC_SetInitialPositionValue(self->instance, 0);
}
// Get the position as signed 32 bit value.
int32_t value = (int32_t)actual_value;
if (value > 0) {
value += (self->phases_inv - 1);
}
return mp_obj_new_int(value / self->phases_inv);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_encoder_value_obj, 1, 2, machine_encoder_value);
// 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
self->instance->REV = mp_obj_get_int(args[1]);
}
return MP_OBJ_NEW_SMALL_INT(cycles);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_encoder_cycles_obj, 1, 2, machine_encoder_cycles);
// -------------------------------------- IRQ set-up --------------------------
static mp_uint_t encoder_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {
machine_encoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
self->mp_irq_trigger = new_trigger;
// Clear previous interrupts and enable the requested interrupts.
ENC_ClearStatusFlags(self->instance, ENCODER_ALL_INTERRUPTS);
ENC_DisableInterrupts(self->instance, ENCODER_ALL_INTERRUPTS);
ENC_EnableInterrupts(self->instance, new_trigger);
return 0;
}
static mp_uint_t encoder_irq_info(mp_obj_t self_in, mp_uint_t info_type) {
machine_encoder_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (info_type == MP_IRQ_INFO_FLAGS) {
return self->mp_irq_flags;
} else if (info_type == MP_IRQ_INFO_TRIGGERS) {
return self->mp_irq_trigger;
}
return 0;
}
static const mp_irq_methods_t encoder_irq_methods = {
.trigger = encoder_irq_trigger,
.info = encoder_irq_info,
};
// encoder.irq(trigger=ENCODER.IRQ_MATCH, handler=None, hard=False)
static mp_obj_t machine_encoder_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_val_t args[MP_IRQ_ARG_INIT_NUM_ARGS];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_IRQ_ARG_INIT_NUM_ARGS, mp_irq_init_args, args);
machine_encoder_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
bool any_args = n_args > 1 || kw_args->used != 0;
if (!self->active) {
mp_raise_ValueError(MP_ERROR_TEXT("device stopped"));
}
if (self->mp_irq_obj == NULL) {
self->mp_irq_obj = mp_irq_new(&encoder_irq_methods, MP_OBJ_FROM_PTR(self));
self->mp_irq_obj->ishard = false;
}
if (any_args) {
// Check the handler
mp_obj_t handler = args[MP_IRQ_ARG_INIT_handler].u_obj;
if (handler != mp_const_none && !mp_obj_is_callable(handler)) {
mp_raise_ValueError(MP_ERROR_TEXT("handler must be None or callable"));
}
// Check the trigger
mp_uint_t trigger = args[MP_IRQ_ARG_INIT_trigger].u_int;
mp_uint_t not_supported = trigger & ~MP_ENCODER_ALLOWED_FLAGS;
if (trigger != 0 && not_supported) {
mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("trigger 0x%04x unsupported"), not_supported);
}
self->mp_irq_obj->handler = handler;
self->mp_irq_obj->ishard = args[MP_IRQ_ARG_INIT_hard].u_bool;
self->mp_irq_trigger = trigger;
// Clear pending interrupt flags
ENC_ClearStatusFlags(self->instance, ENCODER_ALL_INTERRUPTS);
ENC_DisableInterrupts(self->instance, ENCODER_ALL_INTERRUPTS);
if (self->mp_irq_obj->handler != mp_const_none) {
ENC_EnableInterrupts(self->instance, trigger);
EnableIRQ(enc_irqn[self->id + 1]);
} else {
ENC_DisableInterrupts(self->instance, trigger);
DisableIRQ(enc_irqn[self->id + 1]);
}
}
return MP_OBJ_FROM_PTR(self->mp_irq_obj);
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_encoder_irq_obj, 1, machine_encoder_irq);
// encoder.init([kwargs])
static mp_obj_t machine_encoder_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
mp_machine_encoder_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_encoder_init_obj, 1, machine_encoder_init);
static const mp_rom_map_elem_t machine_encoder_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_encoder_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_encoder_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_encoder_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_encoder_value_obj) },
{ MP_ROM_QSTR(MP_QSTR_cycles), MP_ROM_PTR(&machine_encoder_cycles_obj) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_RESET), MP_ROM_INT(kENC_HOMETransitionFlag) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_INDEX), MP_ROM_INT(kENC_INDEXPulseFlag) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_MATCH), MP_ROM_INT(kENC_PositionCompareFlag) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_ROLL_UNDER), MP_ROM_INT(kENC_PositionRollUnderFlag) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_ROLL_OVER), MP_ROM_INT(kENC_PositionRollOverFlag) },
};
static MP_DEFINE_CONST_DICT(machine_encoder_locals_dict, machine_encoder_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
machine_encoder_type,
MP_QSTR_Encoder,
MP_TYPE_FLAG_NONE,
make_new, mp_machine_encoder_make_new,
print, mp_machine_encoder_print,
locals_dict, &machine_encoder_locals_dict
);
// --- Counter class code ----------
static void mp_machine_counter_init_helper(machine_encoder_obj_t *self,
size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_src, ARG_direction, ARG_reset, ARG_match, ARG_match_pin, ARG_filter_ns, ARG_max, ARG_min, ARG_index };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_src, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_direction, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} },
{ MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} },
{ MP_QSTR_match, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_match_pin, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} },
{ MP_QSTR_filter_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
{ MP_QSTR_max, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_min, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(-1)} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args,
MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if (args[ARG_src].u_obj != mp_const_none) {
self->input_a = connect_pin_to_encoder(args[ARG_src].u_obj, xbar_signal_table[self->id].enc_input_a, XBAR_IN);
}
if (self->input_a == 0) {
mp_raise_ValueError(MP_ERROR_TEXT("missing input pin"));
}
mp_obj_t direction = args[ARG_direction].u_obj;
if (direction != MP_ROM_INT(-1)) {
if (direction == MP_ROM_INT(COUNTER_UP)) {
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicLow, xbar_signal_table[self->id].enc_input_b);
} else if (direction == MP_ROM_INT(COUNTER_DOWN)) {
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicHigh, xbar_signal_table[self->id].enc_input_b);
} else {
connect_pin_to_encoder(direction, xbar_signal_table[self->id].enc_input_b, XBAR_IN);
}
}
// Set the common options and start
mp_machine_encoder_init_helper_common(self, args + ARG_reset, &self->enc_config);
}
// Counter(id, input, [args])
static mp_obj_t mp_machine_counter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
// Check number of arguments
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
CLOCK_EnableClock(kCLOCK_Iomuxc); // just in case it was not set yet
XBARA_Init(XBARA1);
uint8_t id = mp_obj_get_int(args[0]);
if (id < 0 || id >= FSL_FEATURE_SOC_ENC_COUNT) {
mp_raise_ValueError(MP_ERROR_TEXT("invalid encoder/counter id"));
}
// check, if the encoder is already in use, and if yes, deinit it
if (encoder_table[id] != NULL) {
encoder_deinit_single(encoder_table[id]);
}
// Connect input_b and the trigger input to a fixed level.
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicLow, xbar_signal_table[id].enc_input_b);
XBARA_SetSignalsConnection(XBARA1, kXBARA1_InputLogicLow, xbar_signal_table[id].enc_trigger);
// Create and populate the Qencoder object.
machine_encoder_obj_t *self = encoder_table[id];
if (self == NULL) {
self = mp_obj_malloc(machine_encoder_obj_t, &machine_counter_type);
encoder_table[id] = self;
}
self->id = id;
self->input_a = 0;
self->input_b = 0;
self->instance = enc_instances[id + 1];
self->max_count = 0;
self->min_count = 0;
self->mp_irq_flags = 0;
self->mp_irq_trigger = 0;
self->mp_irq_obj = NULL;
self->match_pin = 0;
self->phases_inv = 1;
self->reset_pin = NULL;
self->mode = MODE_COUNTER;
// Set defaults for ENC Config
ENC_GetDefaultConfig(&self->enc_config);
// Set the mode to a 32 bit counter
self->enc_config.decoderWorkMode = kENC_DecoderWorkAsSignalPhaseCountMode;
self->enc_config.revolutionCountCondition = kENC_RevolutionCountOnRollOverModulus;
// Process the remaining parameters
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
mp_machine_counter_init_helper(self, n_args - 1, args + 1, &kw_args);
return MP_OBJ_FROM_PTR(self);
}
// counter.init([kwargs])
static mp_obj_t machine_counter_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
mp_machine_counter_init_helper(args[0], n_args - 1, args + 1, kw_args);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(machine_counter_init_obj, 1, machine_counter_init);
static const mp_rom_map_elem_t machine_counter_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_counter_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_encoder_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_encoder_irq_obj) },
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_encoder_value_obj) },
{ MP_ROM_QSTR(MP_QSTR_cycles), MP_ROM_PTR(&machine_encoder_cycles_obj) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_RESET), MP_ROM_INT(kENC_HOMETransitionFlag) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_INDEX), MP_ROM_INT(kENC_INDEXPulseFlag) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_MATCH), MP_ROM_INT(kENC_PositionCompareFlag) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_ROLL_UNDER), MP_ROM_INT(kENC_PositionRollUnderFlag) },
{ MP_ROM_QSTR(MP_QSTR_IRQ_ROLL_OVER), MP_ROM_INT(kENC_PositionRollOverFlag) },
{ MP_ROM_QSTR(MP_QSTR_UP), MP_ROM_INT(COUNTER_UP) },
{ MP_ROM_QSTR(MP_QSTR_DOWN), MP_ROM_INT(COUNTER_DOWN) },
};
static MP_DEFINE_CONST_DICT(machine_counter_locals_dict, machine_counter_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
machine_counter_type,
MP_QSTR_Counter,
MP_TYPE_FLAG_NONE,
make_new, mp_machine_counter_make_new,
print, mp_machine_encoder_print,
locals_dict, &machine_counter_locals_dict
);
MP_REGISTER_ROOT_POINTER(struct _machine_encoder_obj_t *encoder_table[FSL_FEATURE_SOC_ENC_COUNT]);
#endif // MICROPY_PY_MACHINE_QECNT

View File

@@ -93,7 +93,7 @@ int GPIO_get_instance(GPIO_Type *gpio) {
return 0;
}
void call_handler(GPIO_Type *gpio, int gpio_nr, int pin) {
__attribute__((section(".ram_functions"))) void call_handler(GPIO_Type *gpio, int gpio_nr, int pin) {
uint32_t mask = 1 << pin;
uint32_t isr = gpio->ISR & gpio->IMR;
for (int i = 0; i < 16; i++, pin++, mask <<= 1) {
@@ -122,43 +122,43 @@ void call_handler(GPIO_Type *gpio, int gpio_nr, int pin) {
// 10 GPIO IRQ handlers, each covering 16 bits.
void GPIO1_Combined_0_15_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO1_Combined_0_15_IRQHandler(void) {
call_handler(gpiobases[1], 1, 0);
}
void GPIO1_Combined_16_31_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO1_Combined_16_31_IRQHandler(void) {
call_handler(gpiobases[1], 1, 16);
}
void GPIO2_Combined_0_15_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO2_Combined_0_15_IRQHandler(void) {
call_handler(gpiobases[2], 2, 0);
}
void GPIO2_Combined_16_31_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO2_Combined_16_31_IRQHandler(void) {
call_handler(gpiobases[2], 2, 16);
}
void GPIO3_Combined_0_15_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO3_Combined_0_15_IRQHandler(void) {
call_handler(gpiobases[3], 3, 0);
}
void GPIO3_Combined_16_31_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO3_Combined_16_31_IRQHandler(void) {
call_handler(gpiobases[3], 3, 16);
}
void GPIO4_Combined_0_15_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO4_Combined_0_15_IRQHandler(void) {
call_handler(gpiobases[4], 4, 0);
}
void GPIO4_Combined_16_31_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO4_Combined_16_31_IRQHandler(void) {
call_handler(gpiobases[4], 4, 16);
}
void GPIO5_Combined_0_15_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO5_Combined_0_15_IRQHandler(void) {
call_handler(gpiobases[5], 5, 0);
}
void GPIO5_Combined_16_31_IRQHandler(void) {
__attribute__((section(".ram_functions"))) void GPIO5_Combined_16_31_IRQHandler(void) {
call_handler(gpiobases[5], 5, 16);
}

View File

@@ -60,6 +60,7 @@
#include "extmod/vfs.h"
extern uint8_t _sstack, _estack, _gc_heap_start, _gc_heap_end;
extern void machine_encoder_deinit_all(void);
void board_init(void);
@@ -195,6 +196,9 @@ int main(void) {
machine_pwm_deinit_all();
#endif
soft_timer_deinit();
#if MICROPY_PY_MACHINE_QECNT
machine_encoder_deinit_all();
#endif
gc_sweep_all();
mp_deinit();
}

View File

@@ -55,6 +55,13 @@
#else
#define MICROPY_PY_MACHINE_SDCARD_ENTRY
#endif
#if MICROPY_PY_MACHINE_QECNT
#define MICROPY_PY_MACHINE_ENCODER_ENTRY { MP_ROM_QSTR(MP_QSTR_Encoder), MP_ROM_PTR(&machine_encoder_type) },
#define MICROPY_PY_MACHINE_COUNTER_ENTRY { MP_ROM_QSTR(MP_QSTR_Counter), MP_ROM_PTR(&machine_counter_type) },
#else
#define MICROPY_PY_MACHINE_ENCODER_ENTRY
#define MICROPY_PY_MACHINE_COUNTER_ENTRY
#endif
#define MICROPY_PY_MACHINE_EXTRA_GLOBALS \
MICROPY_PY_MACHINE_LED_ENTRY \
@@ -62,6 +69,8 @@
{ MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, \
{ MP_ROM_QSTR(MP_QSTR_RTC), MP_ROM_PTR(&machine_rtc_type) }, \
MICROPY_PY_MACHINE_SDCARD_ENTRY \
MICROPY_PY_MACHINE_ENCODER_ENTRY \
MICROPY_PY_MACHINE_COUNTER_ENTRY \
\
/* Reset reasons */ \
{ MP_ROM_QSTR(MP_QSTR_PWRON_RESET), MP_ROM_INT(MP_PWRON_RESET) }, \

View File

@@ -57,6 +57,8 @@ uint32_t trng_random_u32(void);
// Optimisations
// Compiler configuration
// Python internal features
#define MICROPY_TRACKED_ALLOC (MICROPY_SSL_MBEDTLS)
#define MICROPY_READER_VFS (1)