summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/mimxrt/Makefile8
-rw-r--r--ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h4
-rw-r--r--ports/mimxrt/boards/MIMXRT1021.ld4
-rw-r--r--ports/mimxrt/boards/MIMXRT1021_af.csv72
-rw-r--r--ports/mimxrt/boards/make-pins.py28
-rw-r--r--ports/mimxrt/hal/pwm_backport.c180
-rw-r--r--ports/mimxrt/hal/pwm_backport.h51
-rw-r--r--ports/mimxrt/machine_pwm.c618
-rw-r--r--ports/mimxrt/main.c1
-rw-r--r--ports/mimxrt/modmachine.c1
-rw-r--r--ports/mimxrt/modmachine.h2
-rw-r--r--ports/mimxrt/mpconfigport.h4
-rw-r--r--ports/mimxrt/ticks.c4
13 files changed, 922 insertions, 55 deletions
diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 7cda558bd..eeab29ddc 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -194,6 +194,7 @@ SRC_HAL_IMX_C += \
$(MCU_DIR)/drivers/fsl_lpuart.c \
$(MCU_DIR)/drivers/fsl_ocotp.c \
$(MCU_DIR)/drivers/fsl_pit.c \
+ $(MCU_DIR)/drivers/fsl_pwm.c \
$(MCU_DIR)/drivers/fsl_snvs_lp.c \
$(MCU_DIR)/drivers/fsl_trng.c \
$(MCU_DIR)/drivers/fsl_wdog.c \
@@ -209,6 +210,11 @@ ifeq ($(MICROPY_PY_MACHINE_SDCARD),1)
SRC_HAL_IMX_C += $(MCU_DIR)/drivers/fsl_usdhc.c
endif
+ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES), MIMXRT1015 MIMXRT1021 MIMXRT1052 MIMXRT1062 MIMXRT1064))
+SRC_HAL_IMX_C += \
+ $(MCU_DIR)/drivers/fsl_qtmr.c
+endif
+
SRC_C += \
board_init.c \
dma_channel.c \
@@ -220,6 +226,7 @@ SRC_C += \
extmod/modusocket.c \
extmod/uos_dupterm.c \
fatfs_port.c \
+ hal/pwm_backport.c \
led.c \
machine_adc.c \
machine_bitstream.c \
@@ -384,6 +391,7 @@ SRC_QSTR += \
machine_adc.c \
machine_led.c \
machine_pin.c \
+ machine_pwm.c \
machine_rtc.c \
machine_sdcard.c \
machine_spi.c \
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
index 918513b23..7b2d2a8a6 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
@@ -14,12 +14,12 @@
// LPUART4 on D6/D7 -> 2
#define MICROPY_HW_UART_NUM (sizeof(uart_index_table) / sizeof(uart_index_table)[0])
-#define MICROPY_HW_UART_INDEX { 0, 1, 4, 3 }
+#define MICROPY_HW_UART_INDEX { 0, 1, 4 }
#define IOMUX_TABLE_UART \
{ IOMUXC_GPIO_10_LPUART1_TXD }, { IOMUXC_GPIO_09_LPUART1_RXD }, \
{ 0 }, { 0 }, \
- { IOMUXC_GPIO_08_LPUART3_TXD }, { IOMUXC_GPIO_AD_07_LPUART3_RXD }, \
+ { 0 }, { 0 }, \
{ IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD },
#define MICROPY_HW_SPI_INDEX { 1 }
diff --git a/ports/mimxrt/boards/MIMXRT1021.ld b/ports/mimxrt/boards/MIMXRT1021.ld
index 64f4e537e..1263cd336 100644
--- a/ports/mimxrt/boards/MIMXRT1021.ld
+++ b/ports/mimxrt/boards/MIMXRT1021.ld
@@ -21,11 +21,11 @@ vfs_start = flash_start + 0x00100000;
text_size = ((vfs_start) - (text_start));
vfs_size = ((flash_end) - (vfs_start));
itcm_start = 0x00000000;
-itcm_size = 0x00008000;
+itcm_size = 0x00010000;
dtcm_start = 0x20000000;
dtcm_size = 0x00018000;
ocrm_start = 0x20200000;
-ocrm_size = 0x00020000;
+ocrm_size = 0x00018000;
#ifdef MICROPY_HW_SDRAM_AVAIL
sdram_start = 0x80000000;
diff --git a/ports/mimxrt/boards/MIMXRT1021_af.csv b/ports/mimxrt/boards/MIMXRT1021_af.csv
index 668b415f0..3ce38eb0b 100644
--- a/ports/mimxrt/boards/MIMXRT1021_af.csv
+++ b/ports/mimxrt/boards/MIMXRT1021_af.csv
@@ -5,30 +5,30 @@ GPIO_AD_B0_02,JTAG_MOD,,,,,GPIO1_IO02,USBPHY1_TSTI_TX_LS_MODE,GPT1_CAPTURE1,,,,,
GPIO_AD_B0_03,JTAG_TDI,USDHC2_CD_B,WDOG1_B,SAI1_MCLK,USDHC1_WP,GPIO1_IO03,USB_OTG1_OC,CCM_PMIC_RDY,,,,,ALT0
GPIO_AD_B0_04,JTAG_TDO,FLEXCAN1_TX,USDHC1_WP,TMR2_TIMER0,ENET_MDIO,GPIO1_IO04,USB_OTG1_PWR,EWM_OUT_B,,,,,ALT0
GPIO_AD_B0_05,JTAG_TRSTB,FLEXCAN1_RX,USDHC1_CD_B,TMR2_TIMER1,ENET_MDC,GPIO1_IO05,USB_OTG1_ID,ARM_NMI,,,,,ALT0
-GPIO_AD_B0_06,PIT_TRIGGER0,MQS_RIGHT,LPUART1_TXD,TMR2_TIMER2,FLEXPWM2_PWMA3,GPIO1_IO06,REF_32K_OUT,,,,,,ALT5
-GPIO_AD_B0_07,PIT_TRIGGER1,MQS_LEFT,LPUART1_RXD,TMR2_TIMER3,FLEXPWM2_PWMB3,GPIO1_IO07,REF_24M_OUT,,,,,,ALT5
+GPIO_AD_B0_06,PIT_TRIGGER0,MQS_RIGHT,LPUART1_TXD,TMR2_TIMER2,FLEXPWM2_PWM3_A,GPIO1_IO06,REF_32K_OUT,,,,,,ALT5
+GPIO_AD_B0_07,PIT_TRIGGER1,MQS_LEFT,LPUART1_RXD,TMR2_TIMER3,FLEXPWM2_PWM3_B,GPIO1_IO07,REF_24M_OUT,,,,,,ALT5
GPIO_AD_B0_08,ENET_TX_CLK,LPI2C3_SCL,LPUART1_CTS_B,KPP_COL0,ENET_REF_CLK,GPIO1_IO08,ARM_CM7_TXEV,,,,,ACMP1_IN4,ALT5
GPIO_AD_B0_09,ENET_RX_DATA1,LPI2C3_SDA,LPUART1_RTS_B,KPP_ROW0,,GPIO1_IO09,ARM_CM7_RXEV,,,,,ACMP2_IN4,ALT5
-GPIO_AD_B0_10,ENET_RX_DATA0,LPSPI1_SCK,LPUART5_TXD,KPP_COL1,FLEXPWM2_PWMA2,GPIO1_IO10,ARM_TRACE_CLK,,,,,ACMP3_IN4,ALT5
-GPIO_AD_B0_11,ENET_RX_EN,LPSPI1_PCS0,LPUART5_RXD,KPP_ROW1,FLEXPWM2_PWMB2,GPIO1_IO11,ARM_TRACE_SWO,,,,,ACMP4_IN4,ALT5
-GPIO_AD_B0_12,ENET_RX_ER,LPSPI1_SDO,LPUART3_CTS_B,KPP_COL2,FLEXPWM2_PWMA1,GPIO1_IO12,ARM_TRACE0,SNVS_VIO_5_CTL,,,ADC1_IN0,,ALT5
-GPIO_AD_B0_13,ENET_TX_EN,LPSPI1_SDI,LPUART3_RTS_B,KPP_ROW2,FLEXPWM2_PWMB1,GPIO1_IO13,,SNVS_VIO_5_B,,,ADC2_IN0,,ALT5
-GPIO_AD_B0_14,ENET_TX_DATA0,FLEXCAN2_TX,LPUART3_TXD,KPP_COL3,FLEXPWM2_PWMA0,GPIO1_IO14,,WDOG1_ANY,,,"ADC1_IN1,ADC2_IN1","ACMP1_IN0,ACMP2_IN0,ACMP3_IN0,ACMP4_IN0",ALT5
-GPIO_AD_B0_15,ENET_TX_DATA1,FLEXCAN2_RX,LPUART3_RXD,KPP_ROW3,FLEXPWM2_PWMB0,GPIO1_IO15,,,,,"ADC1_IN2,ADC2_IN2","ACMP1_IN1,ACMP2_IN1,ACMP3_IN1,ACMP4_IN1",ALT5
+GPIO_AD_B0_10,ENET_RX_DATA0,LPSPI1_SCK,LPUART5_TXD,KPP_COL1,FLEXPWM2_PWM2_A,GPIO1_IO10,ARM_TRACE_CLK,,,,,ACMP3_IN4,ALT5
+GPIO_AD_B0_11,ENET_RX_EN,LPSPI1_PCS0,LPUART5_RXD,KPP_ROW1,FLEXPWM2_PWM2_B,GPIO1_IO11,ARM_TRACE_SWO,,,,,ACMP4_IN4,ALT5
+GPIO_AD_B0_12,ENET_RX_ER,LPSPI1_SDO,LPUART3_CTS_B,KPP_COL2,FLEXPWM2_PWM1_A,GPIO1_IO12,ARM_TRACE0,SNVS_VIO_5_CTL,,,ADC1_IN0,,ALT5
+GPIO_AD_B0_13,ENET_TX_EN,LPSPI1_SDI,LPUART3_RTS_B,KPP_ROW2,FLEXPWM2_PWM1_B,GPIO1_IO13,,SNVS_VIO_5_B,,,ADC2_IN0,,ALT5
+GPIO_AD_B0_14,ENET_TX_DATA0,FLEXCAN2_TX,LPUART3_TXD,KPP_COL3,FLEXPWM2_PWM0_A,GPIO1_IO14,,WDOG1_ANY,,,"ADC1_IN1,ADC2_IN1","ACMP1_IN0,ACMP2_IN0,ACMP3_IN0,ACMP4_IN0",ALT5
+GPIO_AD_B0_15,ENET_TX_DATA1,FLEXCAN2_RX,LPUART3_RXD,KPP_ROW3,FLEXPWM2_PWM0_B,GPIO1_IO15,,,,,"ADC1_IN2,ADC2_IN2","ACMP1_IN1,ACMP2_IN1,ACMP3_IN1,ACMP4_IN1",ALT5
GPIO_AD_B1_00,SEMC_RDY,FLEXSPI_A_DATA3,FLEXCAN2_TX,SAI1_MCLK,FLEXIO1_D15,GPIO1_IO16,ENET_1588_EVENT2_OUT,KPP_COL4,,,,ACMP1_IN2,ALT5
GPIO_AD_B1_01,SEMC_CSX0,FLEXSPI_A_SCLK,FLEXCAN2_RX,SAI1_TX_BCLK,FLEXIO1_D14,GPIO1_IO17,ENET_1588_EVENT2_IN,KPP_ROW4,,,ADC1_IN3,ACMP2_IN2,ALT5
GPIO_AD_B1_02,SEMC_CSX1,FLEXSPI_A_DATA0,LPSPI4_SCK,SAI1_TX_SYNC,FLEXIO1_D13,GPIO1_IO18,ENET_1588_EVENT3_OUT,KPP_COL5,,,ADC2_IN3,ACMP3_IN2,ALT5
GPIO_AD_B1_03,SEMC_CSX2,FLEXSPI_A_DATA2,LPSPI4_PCS0,SAI1_TX_DATA0,FLEXIO1_D12,GPIO1_IO19,ENET_1588_EVENT3_IN,KPP_ROW5,,,ADC1_IN4,ACMP4_IN2,ALT5
GPIO_AD_B1_04,SEMC_CSX3,FLEXSPI_A_DATA1,LPSPI4_SDO,SAI1_RX_SYNC,FLEXIO1_D11,GPIO1_IO20,LPSPI1_PCS1,KPP_COL6,,,ADC2_IN4,ACMP1_IN3,ALT5
GPIO_AD_B1_05,USDHC1_WP,FLEXSPI_A_SS0_B,LPSPI4_SDI,SAI1_RX_DATA0,FLEXIO1_D10,GPIO1_IO21,LPSPI1_PCS2,KPP_ROW6,,,"ADC1_IN5,ADC2_IN5",ACMP2_IN3,ALT5
-GPIO_AD_B1_06,USDHC1_RESET_B,FLEXPWM1_PWMA0,LPUART2_CTS_B,SAI1_RX_BCLK,FLEXIO1_D09,GPIO1_IO22,LPSPI1_PCS3,KPP_COL7,,,"ADC1_IN6,ADC2_IN6",ACMP3_IN3,ALT5
-GPIO_AD_B1_07,USDHC1_VSELECT,FLEXPWM1_PWMB0,LPUART2_RTS_B,SAI1_TX_DATA1,FLEXIO1_D08,GPIO1_IO23,LPSPI3_PCS3,KPP_ROW7,,,"ADC1_IN7,ADC2_IN7",ACMP4_IN3,ALT5
-GPIO_AD_B1_08,LPI2C2_SCL,FLEXPWM1_PWMA1,LPUART2_TXD,SAI1_TX_DATA2,FLEXIO1_D07,GPIO1_IO24,LPSPI3_PCS2,XBAR_INOUT12,,,"ADC1_IN8,ADC2_IN8",ACMP1_IN5,ALT5
-GPIO_AD_B1_09,LPI2C2_SDA,FLEXPWM1_PWMB1,LPUART2_RXD,SAI1_TX_DATA3,FLEXIO1_D06,GPIO1_IO25,LPSPI3_PCS1,XBAR_INOUT13,,,"ADC1_IN9,ADC2_IN9",ACMP2_IN5,ALT5
-GPIO_AD_B1_10,USB_OTG1_PWR,FLEXPWM1_PWMA2,LPUART4_TXD,USDHC1_CD_B,FLEXIO1_D05,GPIO1_IO26,GPT2_CAPTURE1,,,,"ADC1_IN10,ADC2_IN10",ACMP3_IN5,ALT5
-GPIO_AD_B1_11,USB_OTG1_ID,FLEXPWM1_PWMB2,LPUART4_RXD,USDHC1_WP,FLEXIO1_D04,GPIO1_IO27,GPT2_COMPARE1,,,,"ADC1_IN11,ADC2_IN11",ACMP4_IN5,ALT5
-GPIO_AD_B1_12,USB_OTG1_OC,ACMP1_OUT,LPSPI3_SCK,USDHC2_CD_B,FLEXIO1_D03,GPIO1_IO28,FLEXPWM1_PWMA3,,,,"ADC1_IN12,ADC2_IN12","ACMP1_IN6,ACMP1_OUT",ALT5
-GPIO_AD_B1_13,LPI2C1_HREQ,ACMP2_OUT,LPSPI3_PCS0,USDHC2_WP,FLEXIO1_D02,GPIO1_IO29,FLEXPWM1_PWMB3,,,,"ADC1_IN13,ADC2_IN13","ACMP2_IN6,ACMP2_OUT",ALT5
+GPIO_AD_B1_06,USDHC1_RESET_B,FLEXPWM1_PWM0_A,LPUART2_CTS_B,SAI1_RX_BCLK,FLEXIO1_D09,GPIO1_IO22,LPSPI1_PCS3,KPP_COL7,,,"ADC1_IN6,ADC2_IN6",ACMP3_IN3,ALT5
+GPIO_AD_B1_07,USDHC1_VSELECT,FLEXPWM1_PWM0_B,LPUART2_RTS_B,SAI1_TX_DATA1,FLEXIO1_D08,GPIO1_IO23,LPSPI3_PCS3,KPP_ROW7,,,"ADC1_IN7,ADC2_IN7",ACMP4_IN3,ALT5
+GPIO_AD_B1_08,LPI2C2_SCL,FLEXPWM1_PWM1_A,LPUART2_TXD,SAI1_TX_DATA2,FLEXIO1_D07,GPIO1_IO24,LPSPI3_PCS2,XBAR_INOUT12,,,"ADC1_IN8,ADC2_IN8",ACMP1_IN5,ALT5
+GPIO_AD_B1_09,LPI2C2_SDA,FLEXPWM1_PWM1_B,LPUART2_RXD,SAI1_TX_DATA3,FLEXIO1_D06,GPIO1_IO25,LPSPI3_PCS1,XBAR_INOUT13,,,"ADC1_IN9,ADC2_IN9",ACMP2_IN5,ALT5
+GPIO_AD_B1_10,USB_OTG1_PWR,FLEXPWM1_PWM2_A,LPUART4_TXD,USDHC1_CD_B,FLEXIO1_D05,GPIO1_IO26,GPT2_CAPTURE1,,,,"ADC1_IN10,ADC2_IN10",ACMP3_IN5,ALT5
+GPIO_AD_B1_11,USB_OTG1_ID,FLEXPWM1_PWM2_B,LPUART4_RXD,USDHC1_WP,FLEXIO1_D04,GPIO1_IO27,GPT2_COMPARE1,,,,"ADC1_IN11,ADC2_IN11",ACMP4_IN5,ALT5
+GPIO_AD_B1_12,USB_OTG1_OC,ACMP1_OUT,LPSPI3_SCK,USDHC2_CD_B,FLEXIO1_D03,GPIO1_IO28,FLEXPWM1_PWM3_A,,,,"ADC1_IN12,ADC2_IN12","ACMP1_IN6,ACMP1_OUT",ALT5
+GPIO_AD_B1_13,LPI2C1_HREQ,ACMP2_OUT,LPSPI3_PCS0,USDHC2_WP,FLEXIO1_D02,GPIO1_IO29,FLEXPWM1_PWM3_B,,,,"ADC1_IN13,ADC2_IN13","ACMP2_IN6,ACMP2_OUT",ALT5
GPIO_AD_B1_14,LPI2C1_SCL,ACMP3_OUT,LPSPI3_SDO,ENET_1588_EVENT0_OUT,FLEXIO1_D01,GPIO1_IO30,,,,,"ADC1_IN14,ADC2_IN14","ACMP3_IN6,ACMP3_OUT",ALT5
GPIO_AD_B1_15,LPI2C1_SDA,ACMP4_OUT,LPSPI3_SDI,ENET_1588_EVENT0_IN,FLEXIO1_D00,GPIO1_IO31,,,,,"ADC1_IN15,ADC2_IN15","ACMP4_IN6,ACMP4_OUT",ALT5
GPIO_EMC_00,SEMC_DA00,TMR2_TIMER0,LPUART4_CTS_B,SPDIF_SR_CLK,LPSPI2_SCK,GPIO2_IO00,FLEXCAN1_TX,PIT_TRIGGER2,,,,,ALT5
@@ -41,36 +41,36 @@ GPIO_EMC_06,SEMC_DA06,XBAR_INOUT06,LPUART3_TXD,SAI2_TX_DATA,FLEXIO1_D18,GPIO2_IO
GPIO_EMC_07,SEMC_DA07,XBAR_INOUT07,LPUART3_RXD,SAI2_RX_SYNC,FLEXIO1_D19,GPIO2_IO07,USBPHY1_TSTO_RX_SQUELCH,,,,,,ALT5
GPIO_EMC_08,SEMC_DM0,XBAR_INOUT08,FLEXCAN2_TX,SAI2_RX_DATA,FLEXIO1_D20,GPIO2_IO08,USBPHY1_TSTO_RX_DISCON_DET,,,,,,ALT5
GPIO_EMC_09,SEMC_WE,XBAR_INOUT09,FLEXCAN2_RX,SAI2_RX_BCLK,FLEXIO1_D21,GPIO2_IO09,USBPHY1_TSTO_RX_HS_RXD,,,,,,ALT5
-GPIO_EMC_10,SEMC_CAS,XBAR_INOUT10,LPI2C4_SDA,SAI1_TX_SYNC,LPSPI2_SCK,GPIO2_IO10,FLEXPWM2_PWMX0,,,,,,ALT5
-GPIO_EMC_11,SEMC_RAS,XBAR_INOUT11,LPI2C4_SCL,SAI1_TX_BCLK,LPSPI2_PCS0,GPIO2_IO11,FLEXPWM2_PWMX1,,,,,,ALT5
-GPIO_EMC_12,SEMC_CS0,XBAR_INOUT12,LPUART6_TXD,SAI1_TX_DATA0,LPSPI2_SDO,GPIO2_IO12,FLEXPWM2_PWMX2,,,,,,ALT5
-GPIO_EMC_13,SEMC_BA0,XBAR_INOUT13,LPUART6_RXD,SAI1_RX_DATA0,LPSPI2_SDI,GPIO2_IO13,FLEXPWM2_PWMX3,CCM_PMIC_RDY,,,,,ALT5
+GPIO_EMC_10,SEMC_CAS,XBAR_INOUT10,LPI2C4_SDA,SAI1_TX_SYNC,LPSPI2_SCK,GPIO2_IO10,FLEXPWM2_PWM0_X,,,,,,ALT5
+GPIO_EMC_11,SEMC_RAS,XBAR_INOUT11,LPI2C4_SCL,SAI1_TX_BCLK,LPSPI2_PCS0,GPIO2_IO11,FLEXPWM2_PWM1_X,,,,,,ALT5
+GPIO_EMC_12,SEMC_CS0,XBAR_INOUT12,LPUART6_TXD,SAI1_TX_DATA0,LPSPI2_SDO,GPIO2_IO12,FLEXPWM2_PWM2_X,,,,,,ALT5
+GPIO_EMC_13,SEMC_BA0,XBAR_INOUT13,LPUART6_RXD,SAI1_RX_DATA0,LPSPI2_SDI,GPIO2_IO13,FLEXPWM2_PWM3_X,CCM_PMIC_RDY,,,,,ALT5
GPIO_EMC_14,SEMC_BA1,XBAR_INOUT14,LPUART6_CTS_B,SAI1_RX_BCLK,LPSPI2_PCS1,GPIO2_IO14,FLEXCAN1_TX,,,,,,ALT5
GPIO_EMC_15,SEMC_ADDR10,XBAR_INOUT15,LPUART6_RTS_B,SAI1_RX_SYNC,WDOG1_B,GPIO2_IO15,FLEXCAN1_RX,,,,,,ALT5
GPIO_EMC_16,SEMC_ADDR00,,MQS_RIGHT,SAI2_MCLK,,GPIO2_IO16,SRC_BOOT_MODE0,,,,,,ALT5
GPIO_EMC_17,SEMC_ADDR01,,MQS_LEFT,SAI3_MCLK,,GPIO2_IO17,SRC_BOOT_MODE1,,,,,,ALT5
GPIO_EMC_18,SEMC_ADDR02,XBAR_INOUT16,LPI2C2_SDA,SAI1_RX_SYNC,FLEXIO1_D22,GPIO2_IO18,SRC_BT_CFG0,,,,,,ALT5
GPIO_EMC_19,SEMC_ADDR03,XBAR_INOUT17,LPI2C2_SCL,SAI1_RX_BCLK,FLEXIO1_D23,GPIO2_IO19,SRC_BT_CFG1,,,,,,ALT5
-GPIO_EMC_20,SEMC_ADDR04,FLEXPWM1_PWMA3,LPUART2_CTS_B,SAI1_MCLK,FLEXIO1_D24,GPIO2_IO20,SRC_BT_CFG2,,,,,,ALT5
-GPIO_EMC_21,SEMC_ADDR05,FLEXPWM1_PWMB3,LPUART2_RTS_B,SAI1_RX_DATA0,FLEXIO1_D25,GPIO2_IO21,SRC_BT_CFG3,,,,,,ALT5
-GPIO_EMC_22,SEMC_ADDR06,FLEXPWM1_PWMA2,LPUART2_TXD,SAI1_TX_DATA3,FLEXIO1_D26,GPIO2_IO22,SRC_BT_CFG4,,,,,,ALT5
-GPIO_EMC_23,SEMC_ADDR07,FLEXPWM1_PWMB2,LPUART2_RXD,SAI1_TX_DATA2,FLEXIO1_D27,GPIO2_IO23,SRC_BT_CFG5,,,,,,ALT5
-GPIO_EMC_24,SEMC_ADDR08,FLEXPWM1_PWMA1,LPUART8_CTS_B,SAI1_TX_DATA1,FLEXIO1_D28,GPIO2_IO24,SRC_BT_CFG6,,,,,,ALT5
-GPIO_EMC_25,SEMC_ADDR09,FLEXPWM1_PWMB1,LPUART8_RTS_B,SAI1_TX_DATA0,FLEXIO1_D29,GPIO2_IO25,SRC_BT_CFG7,,,,,,ALT5
-GPIO_EMC_26,SEMC_ADDR11,FLEXPWM1_PWMA0,LPUART8_TXD,SAI1_TX_BCLK,FLEXIO1_D30,GPIO2_IO26,SRC_BT_CFG8,,,,,,ALT5
-GPIO_EMC_27,SEMC_ADDR12,FLEXPWM1_PWMB0,LPUART8_RXD,SAI1_TX_SYNC,FLEXIO1_D31,GPIO2_IO27,SRC_BT_CFG9,,,,,,ALT5
-GPIO_EMC_28,SEMC_DQS,FLEXPWM2_PWMA3,XBAR_INOUT18,SAI3_MCLK,EWM_OUT_B,GPIO2_IO28,GPT2_CAPTURE2,FLEXPWM1_PWMX0,,,,,ALT5
-GPIO_EMC_29,SEMC_CKE,FLEXPWM2_PWMB3,XBAR_INOUT19,SAI3_RX_BCLK,WDOG2_RST_B_DEB,GPIO2_IO29,GPT2_COMPARE2,FLEXPWM1_PWMX1,,,,,ALT5
-GPIO_EMC_30,SEMC_CLK,FLEXPWM2_PWMA2,LPUART4_CTS_B,SAI3_RX_SYNC,WDOG1_RST_B_DEB,GPIO2_IO30,GPT2_COMPARE3,FLEXPWM1_PWMX2,,,,,ALT5
-GPIO_EMC_31,SEMC_DM1,FLEXPWM2_PWMB2,LPUART4_RTS_B,SAI3_RX_DATA,WDOG2_B,GPIO2_IO31,GPT2_CLK,FLEXPWM1_PWMX3,,,,,ALT5
+GPIO_EMC_20,SEMC_ADDR04,FLEXPWM1_PWM3_A,LPUART2_CTS_B,SAI1_MCLK,FLEXIO1_D24,GPIO2_IO20,SRC_BT_CFG2,,,,,,ALT5
+GPIO_EMC_21,SEMC_ADDR05,FLEXPWM1_PWM3_B,LPUART2_RTS_B,SAI1_RX_DATA0,FLEXIO1_D25,GPIO2_IO21,SRC_BT_CFG3,,,,,,ALT5
+GPIO_EMC_22,SEMC_ADDR06,FLEXPWM1_PWM2_A,LPUART2_TXD,SAI1_TX_DATA3,FLEXIO1_D26,GPIO2_IO22,SRC_BT_CFG4,,,,,,ALT5
+GPIO_EMC_23,SEMC_ADDR07,FLEXPWM1_PWM2_B,LPUART2_RXD,SAI1_TX_DATA2,FLEXIO1_D27,GPIO2_IO23,SRC_BT_CFG5,,,,,,ALT5
+GPIO_EMC_24,SEMC_ADDR08,FLEXPWM1_PWM1_A,LPUART8_CTS_B,SAI1_TX_DATA1,FLEXIO1_D28,GPIO2_IO24,SRC_BT_CFG6,,,,,,ALT5
+GPIO_EMC_25,SEMC_ADDR09,FLEXPWM1_PWM1_B,LPUART8_RTS_B,SAI1_TX_DATA0,FLEXIO1_D29,GPIO2_IO25,SRC_BT_CFG7,,,,,,ALT5
+GPIO_EMC_26,SEMC_ADDR11,FLEXPWM1_PWM0_A,LPUART8_TXD,SAI1_TX_BCLK,FLEXIO1_D30,GPIO2_IO26,SRC_BT_CFG8,,,,,,ALT5
+GPIO_EMC_27,SEMC_ADDR12,FLEXPWM1_PWM0_B,LPUART8_RXD,SAI1_TX_SYNC,FLEXIO1_D31,GPIO2_IO27,SRC_BT_CFG9,,,,,,ALT5
+GPIO_EMC_28,SEMC_DQS,FLEXPWM2_PWM3_A,XBAR_INOUT18,SAI3_MCLK,EWM_OUT_B,GPIO2_IO28,GPT2_CAPTURE2,FLEXPWM1_PWM0_X,,,,,ALT5
+GPIO_EMC_29,SEMC_CKE,FLEXPWM2_PWM3_B,XBAR_INOUT19,SAI3_RX_BCLK,WDOG2_RST_B_DEB,GPIO2_IO29,GPT2_COMPARE2,FLEXPWM1_PWM1_X,,,,,ALT5
+GPIO_EMC_30,SEMC_CLK,FLEXPWM2_PWM2_A,LPUART4_CTS_B,SAI3_RX_SYNC,WDOG1_RST_B_DEB,GPIO2_IO30,GPT2_COMPARE3,FLEXPWM1_PWM2_X,,,,,ALT5
+GPIO_EMC_31,SEMC_DM1,FLEXPWM2_PWM2_B,LPUART4_RTS_B,SAI3_RX_DATA,WDOG2_B,GPIO2_IO31,GPT2_CLK,FLEXPWM1_PWM3_X,,,,,ALT5
GPIO_EMC_32,SEMC_DA08,TMR1_TIMER0,LPUART4_TXD,SAI3_TX_DATA,LPSPI4_SCK,GPIO3_IO00,USBPHY1_TSTO_RX_FS_RXD,REF_24M_OUT,,,,,ALT5
GPIO_EMC_33,SEMC_DA09,TMR1_TIMER1,LPUART4_RXD,SAI3_TX_BCLK,LPSPI4_PCS0,GPIO3_IO01,USBPHY1_TSTI_TX_DP,SRC_TESTER_ACK,,,,,ALT5
GPIO_EMC_34,SEMC_DA10,TMR1_TIMER2,LPUART7_TXD,SAI3_TX_SYNC,LPSPI4_SDO,GPIO3_IO02,ENET_CRS,,,,,,ALT5
GPIO_EMC_35,SEMC_DA11,TMR1_TIMER3,LPUART7_RXD,USDHC2_WP,LPSPI4_SDI,GPIO3_IO03,ENET_COL,,,,,,ALT5
-GPIO_EMC_36,SEMC_DA12,FLEXPWM2_PWMA1,LPUART5_CTS_B,CCM_PMIC_RDY,LPSPI4_PCS1,GPIO3_IO04,ENET_RX_CLK,USDHC1_WP,,,,,ALT5
-GPIO_EMC_37,SEMC_DA13,FLEXPWM2_PWMB1,LPUART5_RTS_B,MQS_RIGHT,LPSPI4_PCS2,GPIO3_IO05,ENET_RX_DATA3,USDHC1_VSELECT,,,,,ALT5
-GPIO_EMC_38,SEMC_DA14,FLEXPWM2_PWMA0,LPUART5_TXD,MQS_LEFT,LPSPI4_PCS3,GPIO3_IO06,ENET_RX_DATA2,USDHC1_CD_B,,,,,ALT5
-GPIO_EMC_39,SEMC_DA15,FLEXPWM2_PWMB0,LPUART5_RXD,USB_OTG1_OC,WDOG1_B,GPIO3_IO07,ENET_TX_ER,GPT1_CLK,,,,,ALT5
+GPIO_EMC_36,SEMC_DA12,FLEXPWM2_PWM1_A,LPUART5_CTS_B,CCM_PMIC_RDY,LPSPI4_PCS1,GPIO3_IO04,ENET_RX_CLK,USDHC1_WP,,,,,ALT5
+GPIO_EMC_37,SEMC_DA13,FLEXPWM2_PWM1_B,LPUART5_RTS_B,MQS_RIGHT,LPSPI4_PCS2,GPIO3_IO05,ENET_RX_DATA3,USDHC1_VSELECT,,,,,ALT5
+GPIO_EMC_38,SEMC_DA14,FLEXPWM2_PWM0_A,LPUART5_TXD,MQS_LEFT,LPSPI4_PCS3,GPIO3_IO06,ENET_RX_DATA2,USDHC1_CD_B,,,,,ALT5
+GPIO_EMC_39,SEMC_DA15,FLEXPWM2_PWM0_B,LPUART5_RXD,USB_OTG1_OC,WDOG1_B,GPIO3_IO07,ENET_TX_ER,GPT1_CLK,,,,,ALT5
GPIO_EMC_40,SEMC_CSX0,XBAR_INOUT18,SPDIF_OUT,USB_OTG1_ID,ENET_MDIO,GPIO3_IO08,ENET_TX_DATA3,GPT1_COMPARE3,,,,,ALT5
GPIO_EMC_41,SEMC_RDY,XBAR_INOUT19,SPDIF_IN,USB_OTG1_PWR,ENET_MDC,GPIO3_IO09,ENET_TX_DATA2,GPT1_COMPARE2,,,,,ALT5
GPIO_SD_B0_00,USDHC1_DATA2,TMR1_TIMER0,SAI1_MCLK,SAI2_MCLK,LPI2C3_SCL,GPIO3_IO13,FLEXSPI_A_SS1_B,XBAR_INOUT14,,,,,ALT5
diff --git a/ports/mimxrt/boards/make-pins.py b/ports/mimxrt/boards/make-pins.py
index e13b9c578..441676add 100644
--- a/ports/mimxrt/boards/make-pins.py
+++ b/ports/mimxrt/boards/make-pins.py
@@ -8,7 +8,7 @@ import sys
import csv
import re
-SUPPORTED_AFS = {"GPIO", "USDHC", "SEMC"}
+SUPPORTED_AFS = {"GPIO", "USDHC", "FLEXPWM", "TMR"}
MAX_AF = 10 # AF0 .. AF9
ADC_COL = 11
@@ -282,29 +282,33 @@ class Pins(object):
hdr_file.write("extern const mp_obj_dict_t machine_pin_board_pins_locals_dict;\n")
hdr_file.write("\n// Defines\n")
- usdhc_instance_factory(self.cpu_pins, hdr_file)
+ module_instance_factory(self.cpu_pins, hdr_file, "USDHC")
+ module_instance_factory(self.cpu_pins, hdr_file, "FLEXPWM")
+ module_instance_factory(self.cpu_pins, hdr_file, "TMR")
-def usdhc_instance_factory(pins, output_file):
- usdhc_pins = filter(lambda p: any([af for af in p.alt_fn if "USDHC" in af.af_str]), pins)
+def module_instance_factory(pins, output_file, name):
+ module_pin = filter(lambda p: any([af for af in p.alt_fn if name in af.af_str]), pins)
- usdhc_instances = dict()
- for pin in usdhc_pins:
+ module_instances = dict()
+ for pin in module_pin:
for idx, alt_fn in enumerate(pin.alt_fn):
- if "USDHC" in alt_fn.instance:
+ if name in alt_fn.instance:
format_string = "#define {0}_{1} &pin_{0}, {2}"
- if alt_fn.instance not in usdhc_instances:
- usdhc_instances[alt_fn.instance] = [
+ if alt_fn.instance not in module_instances:
+ module_instances[alt_fn.instance] = [
format_string.format(pin.name, alt_fn.af_str, idx)
]
else:
- usdhc_instances[alt_fn.instance].append(
+ module_instances[alt_fn.instance].append(
format_string.format(pin.name, alt_fn.af_str, idx)
)
- for k, v in usdhc_instances.items():
+ for k, v in module_instances.items():
output_file.write(f"// {k}\n")
output_file.write(f"#define {k}_AVAIL (1)\n")
+ if name == "FLEXPWM":
+ output_file.write(f"#define {k} {k[-4:]}\n")
for i in v:
output_file.write(i + "\n")
@@ -326,7 +330,7 @@ def main():
"-i",
"--iomux",
dest="iomux_filename",
- help="Specifies the fsl_iomux.h file for the chip",
+ help="Specifies the fsl_iomuxc.h file for the chip",
default="fsl_iomuxc.h",
)
parser.add_argument(
diff --git a/ports/mimxrt/hal/pwm_backport.c b/ports/mimxrt/hal/pwm_backport.c
new file mode 100644
index 000000000..cea664212
--- /dev/null
+++ b/ports/mimxrt/hal/pwm_backport.c
@@ -0,0 +1,180 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP *
+ * Copyright (c) 2021 Robert Hammelrath
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+// These are a few functions taken from the NXP-Lib
+// for PWM, for
+// - dealing with an u16 duty cycle setting,
+// - setting the pulse center position, and
+// - factoring out pure duty cycle change.
+
+#include "py/runtime.h"
+#include "hal/pwm_backport.h"
+
+void PWM_UpdatePwmDutycycle_u16(
+ PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, uint16_t dutyCycle, uint16_t Center_u16) {
+ assert((uint16_t)pwmSignal < 2U);
+ uint16_t pulseCnt = 0, pwmHighPulse = 0;
+ uint16_t center;
+
+ // check and confine bounds for Center_u16
+ if ((Center_u16 + dutyCycle / 2) >= PWM_FULL_SCALE) {
+ Center_u16 = PWM_FULL_SCALE - dutyCycle / 2 - 1;
+ } else if (Center_u16 < (dutyCycle / 2)) {
+ Center_u16 = dutyCycle / 2;
+ }
+ pulseCnt = base->SM[subModule].VAL1 + 1;
+ // Calculate pulse width and center position
+ pwmHighPulse = (pulseCnt * dutyCycle) / PWM_FULL_SCALE;
+ center = (pulseCnt * Center_u16) / PWM_FULL_SCALE;
+
+ // Setup the PWM dutycycle of channel A or B
+ if (pwmSignal == kPWM_PwmA) {
+ base->SM[subModule].VAL2 = center - pwmHighPulse / 2;
+ base->SM[subModule].VAL3 = base->SM[subModule].VAL2 + pwmHighPulse;
+ } else {
+ base->SM[subModule].VAL4 = center - pwmHighPulse / 2;
+ base->SM[subModule].VAL5 = base->SM[subModule].VAL4 + pwmHighPulse;
+ }
+}
+
+void PWM_SetupPwm_u16(PWM_Type *base, pwm_submodule_t subModule, pwm_signal_param_u16_t *chnlParams,
+ uint32_t pwmFreq_Hz, uint32_t srcClock_Hz, bool output_enable) {
+
+ uint32_t pwmClock;
+ uint16_t pulseCnt = 0;
+ uint8_t polarityShift = 0, outputEnableShift = 0;
+
+ // Divide the clock by the prescale value
+ pwmClock = (srcClock_Hz / (1U << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
+ pulseCnt = pwmClock / pwmFreq_Hz;
+ base->SM[subModule].INIT = 0;
+ base->SM[subModule].VAL1 = pulseCnt - 1;
+
+ // Set up the Registers VAL2..VAL5 controlling the duty cycle of channel A/B
+ PWM_UpdatePwmDutycycle_u16(base, subModule, chnlParams->pwmChannel,
+ chnlParams->dutyCycle_u16, chnlParams->Center_u16);
+
+ // Setup register shift values based on the channel being configured.
+ // Also setup the deadtime value
+ if (chnlParams->pwmChannel == kPWM_PwmA) {
+ polarityShift = PWM_OCTRL_POLA_SHIFT;
+ outputEnableShift = PWM_OUTEN_PWMA_EN_SHIFT;
+ base->SM[subModule].DTCNT0 = PWM_DTCNT0_DTCNT0(chnlParams->deadtimeValue);
+ } else {
+ polarityShift = PWM_OCTRL_POLB_SHIFT;
+ outputEnableShift = PWM_OUTEN_PWMB_EN_SHIFT;
+ base->SM[subModule].DTCNT1 = PWM_DTCNT1_DTCNT1(chnlParams->deadtimeValue);
+ }
+
+ // Setup signal active level
+ if (chnlParams->level == kPWM_HighTrue) {
+ base->SM[subModule].OCTRL &= ~(1U << polarityShift);
+ } else {
+ base->SM[subModule].OCTRL |= (1U << polarityShift);
+ }
+ // Enable PWM output
+ if (output_enable) {
+ base->OUTEN |= (1U << (outputEnableShift + subModule));
+ }
+}
+
+void PWM_SetupPwmx_u16(PWM_Type *base, pwm_submodule_t subModule,
+ uint32_t pwmFreq_Hz, uint16_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz) {
+
+ uint32_t pulseCnt;
+ uint32_t pwmClock;
+
+ // Divide the clock by the prescale value
+ pwmClock = (srcClock_Hz / (1U << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
+ pulseCnt = pwmClock / pwmFreq_Hz;
+ base->SM[subModule].INIT = 0;
+ base->SM[subModule].VAL0 = ((uint32_t)duty_cycle * pulseCnt) / PWM_FULL_SCALE;
+ base->SM[subModule].VAL1 = pulseCnt - 1;
+
+ base->SM[subModule].OCTRL = (base->SM[subModule].OCTRL & ~PWM_OCTRL_POLX_MASK) | PWM_OCTRL_POLX(!invert);
+
+ base->OUTEN |= (1U << subModule);
+}
+
+void PWM_SetupFaultDisableMap(PWM_Type *base, pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel, pwm_fault_channels_t pwm_fault_channels, uint16_t value) {
+ uint16_t reg = base->SM[subModule].DISMAP[pwm_fault_channels];
+ switch (pwmChannel) {
+ case kPWM_PwmA:
+ reg &= ~((uint16_t)PWM_DISMAP_DIS0A_MASK);
+ reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0A_SHIFT) & (uint16_t)PWM_DISMAP_DIS0A_MASK);
+ break;
+ case kPWM_PwmB:
+ reg &= ~((uint16_t)PWM_DISMAP_DIS0B_MASK);
+ reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0B_SHIFT) & (uint16_t)PWM_DISMAP_DIS0B_MASK);
+ break;
+ case kPWM_PwmX:
+ reg &= ~((uint16_t)PWM_DISMAP_DIS0X_MASK);
+ reg |= (((uint16_t)(value) << (uint16_t)PWM_DISMAP_DIS0X_SHIFT) & (uint16_t)PWM_DISMAP_DIS0X_MASK);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->SM[subModule].DISMAP[pwm_fault_channels] = reg;
+}
+
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz,
+ uint16_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init) {
+ uint32_t periodCount, highCount, lowCount, reg;
+
+ if (dutyCycleU16 >= PWM_FULL_SCALE) {
+ // Invalid dutycycle
+ return kStatus_Fail;
+ }
+
+ // Counter values to generate a PWM signal
+ periodCount = (srcClock_Hz / pwmFreqHz) - 1;
+ highCount = (periodCount * dutyCycleU16) / PWM_FULL_SCALE;
+ lowCount = periodCount - highCount;
+
+ // Setup the compare registers for PWM output
+ if (is_init == false) {
+ base->CHANNEL[channel].COMP1 = lowCount;
+ base->CHANNEL[channel].COMP2 = highCount;
+ }
+
+ // Setup the pre-load registers for PWM output
+ base->CHANNEL[channel].CMPLD1 = lowCount;
+ base->CHANNEL[channel].CMPLD2 = highCount;
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ // Setup the compare load control for COMP1 and COMP2.
+ // Load COMP1 when CSCTRL[TCF2] is asserted, load COMP2 when CSCTRL[TCF1] is asserted
+ reg &= ~(TMR_CSCTRL_CL1_MASK | TMR_CSCTRL_CL2_MASK);
+ reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1));
+ base->CHANNEL[channel].CSCTRL = reg;
+
+ // Set OFLAG pin for output mode
+ base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OEN_MASK;
+ if (outputPolarity) {
+ // Invert the polarity
+ base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OPS_MASK;
+ } else {
+ // True polarity, no inversion
+ base->CHANNEL[channel].SCTRL &= ~TMR_SCTRL_OPS_MASK;
+ }
+
+ reg = base->CHANNEL[channel].CTRL;
+ reg &= ~(TMR_CTRL_OUTMODE_MASK);
+ // Count until compare value is reached and re-initialize the counter, toggle OFLAG output
+ // using alternating compare register
+ reg |= (TMR_CTRL_LENGTH_MASK | TMR_CTRL_OUTMODE(kQTMR_ToggleOnAltCompareReg));
+ base->CHANNEL[channel].CTRL = reg;
+
+ return kStatus_Success;
+}
+#endif // FSL_FEATURE_SOC_TMR_COUNT
diff --git a/ports/mimxrt/hal/pwm_backport.h b/ports/mimxrt/hal/pwm_backport.h
new file mode 100644
index 000000000..cd4bdb1f8
--- /dev/null
+++ b/ports/mimxrt/hal/pwm_backport.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP *
+ * Copyright (c) 2021 Robert Hammelrath
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef PWM_BACKPORT_H
+#define PWM_BACKPORT_H
+#include "fsl_pwm.h"
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+#include "fsl_qtmr.h"
+#endif
+
+typedef struct _pwm_signal_param_u16
+{
+ pwm_channels_t pwmChannel; // PWM channel being configured; PWM A or PWM B
+ uint16_t dutyCycle_u16; // PWM pulse width, value should be between 0 to 65536
+ uint16_t Center_u16; // Center of the pulse, value should be between 0 to 65536
+ pwm_level_select_t level; // PWM output active level select */
+ uint16_t deadtimeValue; // The deadtime value; only used if channel pair is operating in complementary mode
+} pwm_signal_param_u16_t;
+
+typedef enum _pwm_fault_channels {
+ kPWM_faultchannel_0 = 0U,
+ kPWM_faultchannel_1
+} pwm_fault_channels_t;
+
+#define PWM_FULL_SCALE (65536UL)
+
+void PWM_UpdatePwmDutycycle_u16(PWM_Type *base, pwm_submodule_t subModule,
+ pwm_channels_t pwmSignal, uint16_t dutyCycle, uint16_t center);
+
+void PWM_SetupPwm_u16(PWM_Type *base, pwm_submodule_t subModule, pwm_signal_param_u16_t *chnlParams,
+ uint32_t pwmFreq_Hz, uint32_t srcClock_Hz, bool output_enable);
+
+void PWM_SetupPwmx_u16(PWM_Type *base, pwm_submodule_t subModule,
+ uint32_t pwmFreq_Hz, uint16_t duty_cycle, uint8_t invert, uint32_t srcClock_Hz);
+
+void PWM_SetupFaultDisableMap(PWM_Type *base, pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel, pwm_fault_channels_t pwm_fault_channels, uint16_t value);
+
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+status_t QTMR_SetupPwm_u16(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t pwmFreqHz,
+ uint16_t dutyCycleU16, bool outputPolarity, uint32_t srcClock_Hz, bool is_init);
+#endif // FSL_FEATURE_SOC_TMR_COUNT
+
+#endif // PWM_BACKPORT_H
diff --git a/ports/mimxrt/machine_pwm.c b/ports/mimxrt/machine_pwm.c
new file mode 100644
index 000000000..a13af0d80
--- /dev/null
+++ b/ports/mimxrt/machine_pwm.c
@@ -0,0 +1,618 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020-2021 Damien P. George
+ * Copyright (c) 2021 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.
+ */
+
+#include "py/runtime.h"
+#include "py/mphal.h"
+#include "modmachine.h"
+#include "pin.h"
+#include "fsl_clock.h"
+#include "fsl_iomuxc.h"
+#include "hal/pwm_backport.h"
+
+#define PWM_MIDDLE (0)
+#define PWM_BEGIN (1)
+#define PWM_END (2)
+
+#define PWM_CHANNEL1 (1)
+#define PWM_CHANNEL2 (2)
+
+typedef struct _machine_pwm_obj_t {
+ mp_obj_base_t base;
+ PWM_Type *instance;
+ bool is_flexpwm;
+ uint8_t complementary;
+ uint8_t module;
+ uint8_t submodule;
+ uint8_t channel1;
+ uint8_t channel2;
+ uint8_t invert;
+ bool sync;
+ uint32_t freq;
+ int16_t prescale;
+ uint16_t duty_u16;
+ uint32_t duty_ns;
+ uint16_t center;
+ uint32_t deadtime;
+ bool output_enable_1;
+ bool output_enable_2;
+ uint8_t xor;
+ bool is_init;
+} machine_pwm_obj_t;
+
+static char channel_char[] = {'B', 'A', 'X' };
+static char *ERRMSG_FREQ = "PWM frequency too low";
+static char *ERRMSG_INIT = "PWM set-up failed";
+static char *ERRMSG_VALUE = "value larger than period";
+
+STATIC void machine_pwm_start(machine_pwm_obj_t *self);
+
+STATIC void mp_machine_pwm_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ machine_pwm_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ if (self->is_flexpwm) {
+ mp_printf(print, "<FLEXPWM module=%u submodule=%u ", self->module, self->submodule);
+ if (self->complementary) {
+ mp_printf(print, "channel=%c/%c", channel_char[self->channel1], channel_char[self->channel2]);
+ } else {
+ mp_printf(print, "channel=%c", channel_char[self->channel1]);
+ }
+ if (self->duty_ns != 0) {
+ mp_printf(print, " duty_ns=%u", self->duty_ns);
+ } else {
+ mp_printf(print, " duty_u16=%u", self->duty_u16);
+ }
+ mp_printf(print, " freq=%u center=%u, deadtime=%u, sync=%u>",
+ self->freq, self->center, self->deadtime, self->sync);
+ #ifdef FSL_FEATURE_SOC_TMR_COUNT
+ } else {
+ mp_printf(print, "<QTMR_PWM module=%u channel=%u freq1=%u ",
+ self->module, self->channel1, self->freq);
+ if (self->duty_ns != 0) {
+ mp_printf(print, "duty_ns=%u>", self->duty_ns);
+ } else {
+ mp_printf(print, "duty_u16=%u>", self->duty_u16);
+ }
+ #endif
+ }
+}
+
+// Utility functions for decoding and convertings
+//
+STATIC uint32_t duty_ns_to_duty_u16(uint32_t freq, uint32_t duty_ns) {
+ uint64_t duty = (uint64_t)duty_ns * freq * PWM_FULL_SCALE / 1000000000ULL;
+ if (duty >= PWM_FULL_SCALE) {
+ mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
+ }
+ return (uint32_t)duty;
+}
+
+STATIC uint8_t module_decode(char channel) {
+ switch (channel) {
+ case '0':
+ return kPWM_Module_0;
+ case '1':
+ return kPWM_Module_1;
+ case '2':
+ return kPWM_Module_2;
+ case '3':
+ return kPWM_Module_3;
+ default:
+ return kPWM_Module_1;
+ }
+}
+
+STATIC uint8_t channel_decode(char channel) {
+ switch (channel) {
+ case 'A':
+ return kPWM_PwmA;
+ case 'B':
+ return kPWM_PwmB;
+ case 'X':
+ return kPWM_PwmX;
+ default:
+ return kPWM_PwmA;
+ }
+}
+
+// decode the AF objects module and Port numer. Returns NULL if it is not a FLEXPWM object
+STATIC const machine_pin_af_obj_t *af_name_decode_flexpwm(const machine_pin_af_obj_t *af_obj,
+ uint8_t *module, uint8_t *submodule, uint8_t *channel) {
+ const char *str;
+ size_t len;
+ str = (char *)qstr_data(af_obj->name, &len);
+ // test for the name starting with FLEXPWM
+ if (len < 15 || strncmp(str, "FLEXPWM", 7) != 0) {
+ return NULL;
+ }
+ // Get module, submodule and channel from the name, e.g. FLEXPWM1_PWM0_A
+ *module = str[7] - '0';
+ *submodule = module_decode(str[12]);
+ *channel = channel_decode(str[14]);
+
+ return af_obj;
+}
+
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+STATIC uint8_t qtmr_decode(char channel) {
+ switch (channel) {
+ case '0':
+ return kQTMR_Channel_0;
+ case '1':
+ return kQTMR_Channel_1;
+ case '2':
+ return kQTMR_Channel_2;
+ case '3':
+ return kQTMR_Channel_3;
+ default:
+ return kPWM_Module_1;
+ }
+}
+
+// decode the AF objects module and Port numer. Returns NULL if it is not a QTMR object
+STATIC const machine_pin_af_obj_t *af_name_decode_qtmr(const machine_pin_af_obj_t *af_obj, uint8_t *module, uint8_t *channel) {
+ const char *str;
+ size_t len;
+ str = (char *)qstr_data(af_obj->name, &len);
+ // test for the name starting with TMR
+ if (len < 11 || strncmp(str, "TMR", 3) != 0) {
+ return NULL;
+ }
+ // Get module, submodule and channel from the name, e.g. FLEXPWM1_PWM0_A
+ *module = str[3] - '0';
+ *channel = qtmr_decode(str[10]);
+
+ return af_obj;
+}
+#endif
+
+STATIC bool is_board_pin(const machine_pin_obj_t *pin) {
+ for (int i = 0; i < num_board_pins; i++) {
+ if (pin == machine_pin_board_pins[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Functions for configuring the PWM Device
+//
+STATIC int calc_prescaler(uint32_t clock, uint32_t freq) {
+ float temp = (float)clock / (float)PWM_FULL_SCALE / (float)freq;
+ for (int prescale = 0; prescale < 8; prescale++, temp /= 2) {
+ if (temp <= 1) {
+ return prescale;
+ }
+ }
+ // Frequency too low, cannot scale down.
+ return -1;
+}
+
+STATIC void configure_flexpwm(machine_pwm_obj_t *self) {
+ pwm_signal_param_u16_t pwmSignal;
+
+ // Initialize PWM module.
+ uint32_t pwmSourceClockInHz = CLOCK_GetFreq(kCLOCK_IpgClk);
+
+ int prescale = calc_prescaler(pwmSourceClockInHz, self->freq);
+ if (prescale < 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_FREQ));
+ }
+ if (self->prescale != prescale || self->is_init == false) {
+ pwm_config_t pwmConfig;
+ PWM_GetDefaultConfig(&pwmConfig);
+ self->prescale = prescale;
+ pwmConfig.prescale = prescale;
+ pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
+ if (self->complementary) {
+ pwmConfig.pairOperation = self->channel1 == kPWM_PwmA ? kPWM_ComplementaryPwmA : kPWM_ComplementaryPwmB;
+ } else {
+ pwmConfig.pairOperation = kPWM_Independent;
+ }
+ pwmConfig.clockSource = kPWM_BusClock;
+ pwmConfig.enableWait = false;
+ pwmConfig.initializationControl = self->sync ? kPWM_Initialize_MasterSync : kPWM_Initialize_LocalSync;
+
+ if (PWM_Init(self->instance, self->submodule, &pwmConfig) == kStatus_Fail) {
+ mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_INIT));
+ }
+ }
+
+ // Disable the fault detect function to avoid using the xbara
+ PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel1, kPWM_faultchannel_0, 0);
+ PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel1, kPWM_faultchannel_1, 0);
+ if (self->complementary) {
+ PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel2, kPWM_faultchannel_0, 0);
+ PWM_SetupFaultDisableMap(self->instance, self->submodule, self->channel2, kPWM_faultchannel_1, 0);
+ }
+
+ if (self->channel1 != kPWM_PwmX) { // Only for A/B channels
+ // Initialize the channel parameters
+ pwmSignal.pwmChannel = self->channel1;
+ pwmSignal.level = (self->invert & PWM_CHANNEL1) ? kPWM_LowTrue : kPWM_HighTrue;
+ pwmSignal.dutyCycle_u16 = self->duty_u16;
+ pwmSignal.Center_u16 = self->center;
+ pwmSignal.deadtimeValue = ((uint64_t)pwmSourceClockInHz * self->deadtime) / 1000000000ULL;
+ PWM_SetupPwm_u16(self->instance, self->submodule, &pwmSignal, self->freq,
+ pwmSourceClockInHz, self->output_enable_1);
+
+ if (self->complementary) {
+ // Initialize the second channel of the pair.
+ pwmSignal.pwmChannel = self->channel2;
+ pwmSignal.level = (self->invert & PWM_CHANNEL2) ? kPWM_LowTrue : kPWM_HighTrue;
+ PWM_SetupPwm_u16(self->instance, self->submodule, &pwmSignal, self->freq,
+ pwmSourceClockInHz, self->output_enable_2);
+ }
+ if (self->xor == 1) {
+ // Set the DBLEN bit for A, B = A ^ B
+ self->instance->SM[self->submodule].CTRL &= ~PWM_CTRL_SPLIT_MASK;
+ self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLEN_MASK;
+ } else if (self->xor == 2) {
+ // Set the DBLEN and SPLIT bits for A, B = A ^ B
+ self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLEN_MASK | PWM_CTRL_SPLIT_MASK;
+ } else {
+ self->instance->SM[self->submodule].CTRL &= ~(PWM_CTRL_DBLEN_MASK | PWM_CTRL_SPLIT_MASK);
+ }
+ } else {
+ PWM_SetupPwmx_u16(self->instance, self->submodule, self->freq, self->duty_u16,
+ self->invert, pwmSourceClockInHz);
+ if (self->xor) {
+ // Set the DBLX bit for X = A ^ B
+ self->instance->SM[self->submodule].CTRL |= PWM_CTRL_DBLX_MASK;
+ } else {
+ self->instance->SM[self->submodule].CTRL &= ~PWM_CTRL_DBLX_MASK;
+ }
+ }
+ // Set the load okay bit for the submodules
+ PWM_SetPwmLdok(self->instance, 1 << self->submodule, true);
+
+ // Start the PWM generation from the Submodules
+ PWM_StartTimer(self->instance, 1 << self->submodule);
+}
+
+#ifdef FSL_FEATURE_SOC_TMR_COUNT
+STATIC void configure_qtmr(machine_pwm_obj_t *self) {
+ qtmr_config_t qtmrConfig;
+ int prescale;
+
+ TMR_Type *instance = (TMR_Type *)self->instance;
+
+ prescale = calc_prescaler(CLOCK_GetFreq(kCLOCK_IpgClk), self->freq);
+ if (prescale < 0) {
+ mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_FREQ));
+ }
+ if (prescale != self->prescale) {
+ QTMR_GetDefaultConfig(&qtmrConfig);
+ qtmrConfig.primarySource = prescale + kQTMR_ClockDivide_1;
+ QTMR_Init(instance, self->channel1, &qtmrConfig);
+ self->prescale = prescale;
+ }
+ // Set up the PWM channel
+ if (QTMR_SetupPwm_u16(instance, self->channel1, self->freq, self->duty_u16,
+ self->invert, CLOCK_GetFreq(kCLOCK_IpgClk) / (1 << prescale), self->is_init) == kStatus_Fail) {
+ mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_INIT));
+ }
+ // Start the output
+ QTMR_StartTimer(instance, self->channel1, kQTMR_PriSrcRiseEdge);
+}
+#endif // FSL_FEATURE_SOC_TMR_COUNT
+
+STATIC void configure_pwm(machine_pwm_obj_t *self) {
+ // Set the clock frequencies
+ // Freq range is 15Hz to ~ 3 MHz.
+ static bool set_frequency = true;
+ // set the frequency only once
+ if (set_frequency) {
+ CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); // Set IPG PODF to 3, divide by 4
+ set_frequency = false;
+ }
+
+ if (self->duty_ns != 0) {
+ self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+ }
+ if (self->is_flexpwm) {
+ configure_flexpwm(self);
+ #ifdef FSL_FEATURE_SOC_TMR_COUNT
+ } else {
+ configure_qtmr(self);
+ #endif
+ }
+}
+
+// Micropython API functions
+//
+STATIC void mp_machine_pwm_init_helper(machine_pwm_obj_t *self,
+ size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_freq, ARG_duty_u16, ARG_duty_ns, ARG_center, ARG_align,
+ ARG_invert, ARG_sync, ARG_xor, ARG_deadtime };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_freq, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_duty_u16, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_duty_ns, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_center, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_align, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+ { MP_QSTR_invert, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+ { MP_QSTR_sync, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+ { MP_QSTR_xor, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1}},
+ { MP_QSTR_deadtime, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_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 ((n_args + kw_args->used) > 0 || self->is_init == false) {
+ // Maybe change PWM timer
+ if (args[ARG_freq].u_int > 0) {
+ self->freq = args[ARG_freq].u_int;
+ }
+
+ // Set duty_u16 cycle?
+ uint32_t duty = args[ARG_duty_u16].u_int;
+ if (duty != 0) {
+ if (duty >= PWM_FULL_SCALE) {
+ mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
+ }
+ self->duty_u16 = duty;
+ self->duty_ns = 0;
+ }
+ // Set duty_ns value?
+ duty = args[ARG_duty_ns].u_int;
+ if (duty != 0) {
+ self->duty_ns = duty;
+ self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+ }
+ // Set center value?
+ int32_t center = args[ARG_center].u_int;
+ if (center >= 0) {
+ if (center >= PWM_FULL_SCALE) {
+ mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
+ }
+ self->center = center;
+ } else { // Use alignment setting shortcut
+ if (args[ARG_align].u_int >= 0) {
+ uint8_t align = args[ARG_align].u_int & 3; // limit to 0..3
+ if (align == PWM_BEGIN) {
+ self->center = self->duty_u16 / 2;
+ } else if (align == PWM_END) {
+ self->center = PWM_FULL_SCALE - self->duty_u16 / 2;
+ } else {
+ self->center = 32768; // Default value: mid.
+ }
+ }
+ }
+
+ if (args[ARG_invert].u_int >= 0) {
+ self->invert = args[ARG_invert].u_int & (PWM_CHANNEL1 | PWM_CHANNEL2);
+ }
+
+ if (args[ARG_sync].u_int >= 0) {
+ self->sync = args[ARG_sync].u_int != false && self->submodule != 0;
+ }
+
+ if (args[ARG_xor].u_int >= 0) {
+ self->xor = args[ARG_xor].u_int & 0x03;
+ }
+
+ if (args[ARG_deadtime].u_int >= 0) {
+ self->deadtime = args[ARG_deadtime].u_int;
+ }
+ configure_pwm(self);
+ self->is_init = true;
+ } else {
+ machine_pwm_start(self);
+ }
+
+}
+
+// PWM(pin | pin-tuple, freq, [args])
+STATIC mp_obj_t mp_machine_pwm_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);
+
+ mp_obj_t *pins;
+ const machine_pin_obj_t *pin1;
+ const machine_pin_obj_t *pin2;
+
+ // Get referred Pin object(s)
+ if (mp_obj_is_type(args[0], &mp_type_tuple)) {
+ mp_obj_get_array_fixed_n(args[0], 2, &pins);
+ pin1 = pin_find(pins[0]);
+ pin2 = pin_find(pins[1]);
+ } else {
+ pin1 = pin_find(args[0]);
+ pin2 = NULL;
+ }
+
+ // Check whether it supports PWM and decode submodule & channel
+ const machine_pin_af_obj_t *af_obj1 = NULL;
+ uint8_t submodule1;
+ uint8_t channel1;
+ const machine_pin_af_obj_t *af_obj2 = NULL;
+ uint8_t submodule2;
+ uint8_t channel2;
+ uint8_t module;
+ bool is_flexpwm = false;
+
+ for (int i = 0; i < pin1->af_list_len; ++i) {
+ af_obj1 = af_name_decode_flexpwm(&(pin1->af_list[i]), &module, &submodule1, &channel1);
+ if (af_obj1 != NULL) {
+ break;
+ }
+ }
+ if (pin2 != NULL) {
+ for (int i = 0; i < pin1->af_list_len; ++i) {
+ af_obj2 = af_name_decode_flexpwm(&(pin2->af_list[i]), &module, &submodule2, &channel2);
+ if (af_obj2 != NULL) {
+ break;
+ }
+ }
+ }
+ if (af_obj1 == NULL) {
+ submodule1 = 0;
+ #ifdef FSL_FEATURE_SOC_TMR_COUNT
+ // Check for QTimer support
+ if (is_board_pin(pin1)) {
+ for (int i = 0; i < pin1->af_list_len; ++i) {
+ af_obj1 = af_name_decode_qtmr(&(pin1->af_list[i]), &module, &channel1);
+ if (af_obj1 != NULL) {
+ break;
+ }
+ }
+ }
+ #endif
+ if (af_obj1 == NULL) {
+ mp_raise_ValueError(MP_ERROR_TEXT("the requested Pin(s) does not support PWM"));
+ }
+ } else {
+ // is flexpwm, check for instance match
+ is_flexpwm = true;
+ if (pin2 != NULL && af_obj1->instance != af_obj2->instance && submodule1 != submodule2) {
+ mp_raise_ValueError(MP_ERROR_TEXT("the pins must be a A/B pair of a submodule"));
+ }
+ }
+
+ // Create and populate the PWM object.
+ machine_pwm_obj_t *self = m_new_obj(machine_pwm_obj_t);
+ self->base.type = &machine_pwm_type;
+ self->is_flexpwm = is_flexpwm;
+ self->instance = af_obj1->instance;
+ self->module = module;
+ self->submodule = submodule1;
+ self->channel1 = channel1;
+ self->invert = 0;
+ self->freq = 1000;
+ self->prescale = -1;
+ self->duty_u16 = 32768;
+ self->duty_ns = 0;
+ self->center = 32768;
+ self->output_enable_1 = is_board_pin(pin1);
+ self->sync = false;
+ self->deadtime = 0;
+ self->xor = 0;
+ self->is_init = false;
+
+ // Initialize the Pin(s).
+ CLOCK_EnableClock(kCLOCK_Iomuxc); // just in case it was not set yet
+ IOMUXC_SetPinMux(pin1->muxRegister, af_obj1->af_mode, af_obj1->input_register, af_obj1->input_daisy,
+ pin1->configRegister, 0U);
+ IOMUXC_SetPinConfig(pin1->muxRegister, af_obj1->af_mode, af_obj1->input_register, af_obj1->input_daisy,
+ pin1->configRegister, 0x10B0U);
+
+ // Settings for the second pin, if given.
+ if (pin2 != NULL && pin2 != pin1) {
+ self->complementary = 1;
+ self->channel2 = channel2;
+ self->output_enable_2 = is_board_pin(pin2);
+ // Initialize the Pin(s)
+ IOMUXC_SetPinMux(pin2->muxRegister, af_obj2->af_mode, af_obj2->input_register, af_obj2->input_daisy,
+ pin2->configRegister, 0U);
+ IOMUXC_SetPinConfig(pin2->muxRegister, af_obj2->af_mode, af_obj2->input_register, af_obj2->input_daisy,
+ pin2->configRegister, 0x10B0U);
+ } else {
+ self->complementary = 0;
+ }
+
+ // Process the remaining parameters.
+ mp_map_t kw_args;
+ mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
+ mp_machine_pwm_init_helper(self, n_args - 1, args + 1, &kw_args);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+// Disable all PWM devices. Called on soft reset
+void machine_pwm_deinit_all(void) {
+ static PWM_Type *const pwm_bases[] = PWM_BASE_PTRS;
+
+ for (int i = 1; i < ARRAY_SIZE(pwm_bases); i++) {
+ PWM_StopTimer(pwm_bases[i], 0x0f); // Stop all submodules
+ pwm_bases[i]->OUTEN = 0; // Disable ouput on all submodules, all channels
+ }
+
+ #ifdef FSL_FEATURE_SOC_TMR_COUNT
+ static TMR_Type *const tmr_bases[] = TMR_BASE_PTRS;
+ for (int i = 1; i < ARRAY_SIZE(tmr_bases); i++) {
+ for (int j = 0; j < 4; j++) {
+ QTMR_StopTimer(tmr_bases[i], j); // Stop all timers
+ }
+ }
+ #endif
+}
+
+STATIC void machine_pwm_start(machine_pwm_obj_t *self) {
+ if (self->is_flexpwm) {
+ PWM_StartTimer(self->instance, 1 << self->submodule);
+ #ifdef FSL_FEATURE_SOC_TMR_COUNT
+ } else {
+ QTMR_StartTimer((TMR_Type *)self->instance, self->channel1, kQTMR_PriSrcRiseEdge);
+ #endif
+ }
+}
+
+STATIC void mp_machine_pwm_deinit(machine_pwm_obj_t *self) {
+ if (self->is_flexpwm) {
+ PWM_StopTimer(self->instance, 1 << self->submodule);
+ #ifdef FSL_FEATURE_SOC_TMR_COUNT
+ } else {
+ QTMR_StopTimer((TMR_Type *)self->instance, self->channel1);
+ #endif
+ }
+}
+
+mp_obj_t mp_machine_pwm_freq_get(machine_pwm_obj_t *self) {
+ return MP_OBJ_NEW_SMALL_INT(self->freq);
+}
+
+void mp_machine_pwm_freq_set(machine_pwm_obj_t *self, mp_int_t freq) {
+ self->freq = freq;
+ configure_pwm(self);
+}
+
+mp_obj_t mp_machine_pwm_duty_get_u16(machine_pwm_obj_t *self) {
+ return MP_OBJ_NEW_SMALL_INT(self->duty_u16);
+}
+
+void mp_machine_pwm_duty_set_u16(machine_pwm_obj_t *self, mp_int_t duty) {
+ if (duty >= 0) {
+ if (duty >= PWM_FULL_SCALE) {
+ mp_raise_ValueError(MP_ERROR_TEXT(ERRMSG_VALUE));
+ }
+ self->duty_u16 = duty;
+ self->duty_ns = 0;
+ configure_pwm(self);
+ }
+}
+
+mp_obj_t mp_machine_pwm_duty_get_ns(machine_pwm_obj_t *self) {
+ return MP_OBJ_NEW_SMALL_INT(1000000000ULL / self->freq * self->duty_u16 / PWM_FULL_SCALE);
+}
+
+void mp_machine_pwm_duty_set_ns(machine_pwm_obj_t *self, mp_int_t duty) {
+ if (duty >= 0) {
+ self->duty_ns = duty;
+ self->duty_u16 = duty_ns_to_duty_u16(self->freq, self->duty_ns);
+ configure_pwm(self);
+ }
+}
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index fa6237ca0..4d603913f 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -119,6 +119,7 @@ int main(void) {
#if MICROPY_PY_NETWORK
mod_network_deinit();
#endif
+ machine_pwm_deinit_all();
gc_sweep_all();
mp_deinit();
}
diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index a05c81a40..e7f096134 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -129,6 +129,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
#if MICROPY_PY_MACHINE_SDCARD
{ MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&machine_sdcard_type) },
#endif
+ { MP_ROM_QSTR(MP_QSTR_PWM), MP_ROM_PTR(&machine_pwm_type) },
{ MP_ROM_QSTR(MP_QSTR_Signal), MP_ROM_PTR(&machine_signal_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftI2C), MP_ROM_PTR(&mp_machine_soft_i2c_type) },
{ MP_ROM_QSTR(MP_QSTR_SoftSPI), MP_ROM_PTR(&mp_machine_soft_spi_type) },
diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h
index b9949ab78..d18a22762 100644
--- a/ports/mimxrt/modmachine.h
+++ b/ports/mimxrt/modmachine.h
@@ -31,6 +31,7 @@
extern const mp_obj_type_t machine_adc_type;
extern const mp_obj_type_t machine_i2c_type;
+extern const mp_obj_type_t machine_pwm_type;
extern const mp_obj_type_t machine_rtc_type;
extern const mp_obj_type_t machine_sdcard_type;
extern const mp_obj_type_t machine_spi_type;
@@ -40,6 +41,7 @@ extern const mp_obj_type_t machine_wdt_type;
void machine_adc_init(void);
void machine_pin_irq_deinit(void);
+void machine_pwm_deinit_all(void);
void machine_timer_init_PIT(void);
void machine_sdcard_init0(void);
void mimxrt_sdram_init(void);
diff --git a/ports/mimxrt/mpconfigport.h b/ports/mimxrt/mpconfigport.h
index 361b8bd08..967482dc7 100644
--- a/ports/mimxrt/mpconfigport.h
+++ b/ports/mimxrt/mpconfigport.h
@@ -129,6 +129,10 @@ uint32_t trng_random_u32(void);
#define MICROPY_PY_MACHINE_PIN_MAKE_NEW mp_pin_make_new
#define MICROPY_PY_MACHINE_BITSTREAM (1)
#define MICROPY_PY_MACHINE_PULSE (1)
+#define MICROPY_PY_MACHINE_PWM (1)
+#define MICROPY_PY_MACHINE_PWM_INIT (1)
+#define MICROPY_PY_MACHINE_PWM_DUTY_U16_NS (1)
+#define MICROPY_PY_MACHINE_PWM_INCLUDEFILE "ports/mimxrt/machine_pwm.c"
#define MICROPY_PY_MACHINE_I2C (1)
#define MICROPY_PY_MACHINE_SOFTI2C (1)
#define MICROPY_PY_MACHINE_SPI (1)
diff --git a/ports/mimxrt/ticks.c b/ports/mimxrt/ticks.c
index a5ee10242..5ae6f7f13 100644
--- a/ports/mimxrt/ticks.c
+++ b/ports/mimxrt/ticks.c
@@ -129,9 +129,7 @@ void ticks_delay_us64(uint64_t us) {
dt = 0xffffffff;
}
ticks_wake_after_us32((uint32_t)dt);
- if (dt < 50) {
- __WFE();
- } else {
+ if (dt > 50) {
MICROPY_EVENT_POLL_HOOK
}
}