diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile index 7cda558bdc..eeab29ddc3 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 918513b230..7b2d2a8a63 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 64f4e537e0..1263cd336c 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 668b415f0b..3ce38eb0b9 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 e13b9c578f..441676adde 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 0000000000..cea6642120 --- /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 0000000000..cd4bdb1f8e --- /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 0000000000..a13af0d80f --- /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, "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, "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 fa6237ca07..4d603913fd 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 a05c81a40a..e7f0961344 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 b9949ab784..d18a227624 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 361b8bd089..967482dc77 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 a5ee102428..5ae6f7f13b 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 } }