summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/mimxrt/Makefile8
-rw-r--r--ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h9
-rw-r--r--ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h16
-rw-r--r--ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h12
-rw-r--r--ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h12
-rw-r--r--ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h12
-rw-r--r--ports/mimxrt/boards/TEENSY40/mpconfigboard.h18
-rw-r--r--ports/mimxrt/boards/TEENSY41/mpconfigboard.h18
-rw-r--r--ports/mimxrt/dma_channel.c51
-rw-r--r--ports/mimxrt/dma_channel.h34
-rw-r--r--ports/mimxrt/machine_spi.c334
-rw-r--r--ports/mimxrt/modmachine.c1
-rw-r--r--ports/mimxrt/modmachine.h1
13 files changed, 526 insertions, 0 deletions
diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 3b530a970..870248373 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -116,10 +116,15 @@ SRC_HAL_IMX_C += \
$(MCU_DIR)/xip/fsl_flexspi_nor_boot.c \
$(MCU_DIR)/project_template/clock_config.c \
$(MCU_DIR)/drivers/fsl_adc.c \
+ $(MCU_DIR)/drivers/fsl_cache.c \
$(MCU_DIR)/drivers/fsl_clock.c \
+ $(MCU_DIR)/drivers/fsl_dmamux.c \
+ $(MCU_DIR)/drivers/fsl_edma.c \
$(MCU_DIR)/drivers/fsl_gpio.c \
$(MCU_DIR)/drivers/fsl_gpt.c \
$(MCU_DIR)/drivers/fsl_common.c \
+ $(MCU_DIR)/drivers/fsl_lpspi.c \
+ $(MCU_DIR)/drivers/fsl_lpspi_edma.c \
$(MCU_DIR)/drivers/fsl_lpuart.c \
$(MCU_DIR)/drivers/fsl_flexram.c \
$(MCU_DIR)/drivers/fsl_flexspi.c \
@@ -134,11 +139,13 @@ SRC_C = \
ticks.c \
tusb_port.c \
board_init.c \
+ dma_channel.c \
$(BOARD_DIR)/flash_config.c \
machine_adc.c \
machine_led.c \
machine_pin.c \
machine_rtc.c \
+ machine_spi.c \
machine_timer.c \
machine_uart.c \
mimxrt_flash.c \
@@ -265,6 +272,7 @@ SRC_QSTR += \
machine_led.c \
machine_pin.c \
machine_rtc.c \
+ machine_spi.c \
machine_timer.c \
machine_uart.c \
mimxrt_flash.c \
diff --git a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
index fdaeac7ee..357670626 100644
--- a/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1010_EVK/mpconfigboard.h
@@ -24,3 +24,12 @@
{ 0 }, { 0 }, \
{ IOMUXC_GPIO_08_LPUART3_TXD }, { IOMUXC_GPIO_AD_07_LPUART3_RXD }, \
{ IOMUXC_GPIO_AD_02_LPUART4_TXD }, { IOMUXC_GPIO_AD_01_LPUART4_RXD },
+
+#define MICROPY_HW_SPI_INDEX { 1 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_AD_06_LPSPI1_SCK }, { IOMUXC_GPIO_AD_05_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_AD_04_LPSPI1_SDO }, { IOMUXC_GPIO_AD_03_LPSPI1_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx }
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx }
diff --git a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
index 8238762a0..55254d58f 100644
--- a/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1020_EVK/mpconfigboard.h
@@ -32,3 +32,19 @@
{ 0 }, { 0 }, \
{ 0 }, { 0 }, \
{ IOMUXC_GPIO_SD_B1_02_LPUART8_TX }, { IOMUXC_GPIO_SD_B1_03_LPUART8_RX },
+
+#define MICROPY_HW_SPI_INDEX { 1, 3 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_AD_B0_10_LPSPI1_SCK }, { IOMUXC_GPIO_AD_B0_11_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_AD_B0_12_LPSPI1_SDO }, { IOMUXC_GPIO_AD_B0_13_LPSPI1_SDI }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_12_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B1_13_LPSPI3_PCS0 }, \
+ { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_15_LPSPI3_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+ kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
diff --git a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
index 659c33263..db08b1064 100644
--- a/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1050_EVK/mpconfigboard.h
@@ -29,3 +29,15 @@
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
{ 0 }, { 0 }, \
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
+
+#define MICROPY_HW_SPI_INDEX { 1 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+ kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
diff --git a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
index 4fcc697e2..451d53daf 100644
--- a/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1060_EVK/mpconfigboard.h
@@ -29,3 +29,15 @@
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
{ 0 }, { 0 }, \
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
+
+#define MICROPY_HW_SPI_INDEX { 1 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+ kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
diff --git a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
index 754989951..e300efef3 100644
--- a/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
+++ b/ports/mimxrt/boards/MIMXRT1064_EVK/mpconfigboard.h
@@ -27,3 +27,15 @@
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
{ 0 }, { 0 }, \
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
+
+#define MICROPY_HW_SPI_INDEX { 1 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+ kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
diff --git a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
index 316116b2b..8b38d047f 100644
--- a/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY40/mpconfigboard.h
@@ -24,3 +24,21 @@
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
{ IOMUXC_GPIO_EMC_31_LPUART7_TX }, { IOMUXC_GPIO_EMC_32_LPUART7_RX }, \
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
+
+#define MICROPY_HW_SPI_INDEX { 4, 3}
+
+#define IOMUX_TABLE_SPI \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_15_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B0_03_LPSPI3_PCS0 }, \
+ { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B0_02_LPSPI3_SDI }, \
+ { IOMUXC_GPIO_B0_03_LPSPI4_SCK }, { IOMUXC_GPIO_B0_00_LPSPI4_PCS0 }, \
+ { IOMUXC_GPIO_B0_02_LPSPI4_SDO }, { IOMUXC_GPIO_B0_01_LPSPI4_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+ kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
diff --git a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
index 4bbb41f30..455bf8d69 100644
--- a/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
+++ b/ports/mimxrt/boards/TEENSY41/mpconfigboard.h
@@ -24,3 +24,21 @@
{ IOMUXC_GPIO_AD_B0_02_LPUART6_TX }, { IOMUXC_GPIO_AD_B0_03_LPUART6_RX }, \
{ IOMUXC_GPIO_EMC_31_LPUART7_TX }, { IOMUXC_GPIO_EMC_32_LPUART7_RX }, \
{ IOMUXC_GPIO_AD_B1_10_LPUART8_TX }, { IOMUXC_GPIO_AD_B1_11_LPUART8_RX },
+
+#define MICROPY_HW_SPI_INDEX { 4, 3, 1 }
+
+#define IOMUX_TABLE_SPI \
+ { IOMUXC_GPIO_SD_B0_00_LPSPI1_SCK }, { IOMUXC_GPIO_SD_B0_01_LPSPI1_PCS0 }, \
+ { IOMUXC_GPIO_SD_B0_02_LPSPI1_SDO }, { IOMUXC_GPIO_SD_B0_03_LPSPI1_SDI }, \
+ { 0 }, { 0 }, \
+ { 0 }, { 0 }, \
+ { IOMUXC_GPIO_AD_B1_15_LPSPI3_SCK }, { IOMUXC_GPIO_AD_B1_12_LPSPI3_PCS0 }, \
+ { IOMUXC_GPIO_AD_B1_14_LPSPI3_SDO }, { IOMUXC_GPIO_AD_B1_13_LPSPI3_SDI }, \
+ { IOMUXC_GPIO_B0_03_LPSPI4_SCK }, { IOMUXC_GPIO_B0_00_LPSPI4_PCS0 }, \
+ { IOMUXC_GPIO_B0_02_LPSPI4_SDO }, { IOMUXC_GPIO_B0_01_LPSPI4_SDI },
+
+#define DMA_REQ_SRC_RX { 0, kDmaRequestMuxLPSPI1Rx, kDmaRequestMuxLPSPI2Rx, \
+ kDmaRequestMuxLPSPI3Rx, kDmaRequestMuxLPSPI4Rx }
+
+#define DMA_REQ_SRC_TX { 0, kDmaRequestMuxLPSPI1Tx, kDmaRequestMuxLPSPI2Tx, \
+ kDmaRequestMuxLPSPI3Tx, kDmaRequestMuxLPSPI4Tx }
diff --git a/ports/mimxrt/dma_channel.c b/ports/mimxrt/dma_channel.c
new file mode 100644
index 000000000..3dd043a66
--- /dev/null
+++ b/ports/mimxrt/dma_channel.c
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * 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 "dma_channel.h"
+
+// List of channel flags: true: channel used, false: channel available
+static bool channel_list[32] = { true, true, true, true, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false };
+
+// allocate_channel(): retrieve an available channel. Return the number or -1
+int allocate_dma_channel(void) {
+ for (int i = 0; i < ARRAY_SIZE(channel_list); i++) {
+ if (channel_list[i] == false) { // Channel available
+ channel_list[i] = true;
+ return i;
+ }
+ }
+ return -1;
+}
+
+// free_channel(n): Declare channel as free
+void free_dma_channel(int n) {
+ if (n >= 0 && n <= ARRAY_SIZE(channel_list)) {
+ channel_list[n] = false;
+ }
+}
diff --git a/ports/mimxrt/dma_channel.h b/ports/mimxrt/dma_channel.h
new file mode 100644
index 000000000..3fe66a3db
--- /dev/null
+++ b/ports/mimxrt/dma_channel.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * 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.
+ */
+#ifndef MICROPY_INCLUDED_MIMXRT_DMACHANNEL_H
+#define MICROPY_INCLUDED_MIMXRT_DMACHANNEL_H
+
+#include "py/runtime.h"
+
+int allocate_dma_channel(void);
+void free_dma_channel(int n);
+
+#endif // MICROPY_INCLUDED_MIMXRT_DMACHANNEL_H
diff --git a/ports/mimxrt/machine_spi.c b/ports/mimxrt/machine_spi.c
new file mode 100644
index 000000000..41843b06d
--- /dev/null
+++ b/ports/mimxrt/machine_spi.c
@@ -0,0 +1,334 @@
+/*
+ * 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 "py/mperrno.h"
+#include "extmod/machine_spi.h"
+#include "modmachine.h"
+#include "dma_channel.h"
+
+#include "fsl_cache.h"
+#include "fsl_dmamux.h"
+#include "fsl_iomuxc.h"
+#include "fsl_lpspi.h"
+#include "fsl_lpspi_edma.h"
+
+#define DEFAULT_SPI_BAUDRATE (1000000)
+#define DEFAULT_SPI_POLARITY (0)
+#define DEFAULT_SPI_PHASE (0)
+#define DEFAULT_SPI_BITS (8)
+#define DEFAULT_SPI_FIRSTBIT (kLPSPI_MsbFirst)
+#define DEFAULT_SPI_DRIVE (6)
+
+#define CLOCK_DIVIDER (1)
+
+#define MICROPY_HW_SPI_NUM MP_ARRAY_SIZE(spi_index_table)
+
+#define SCK (iomux_table[index])
+#define CS0 (iomux_table[index + 1])
+#define SDO (iomux_table[index + 2])
+#define SDI (iomux_table[index + 3])
+
+typedef struct _machine_spi_obj_t {
+ mp_obj_base_t base;
+ uint8_t spi_id;
+ uint8_t mode;
+ uint8_t spi_hw_id;
+ bool transfer_busy;
+ LPSPI_Type *spi_inst;
+ lpspi_master_config_t *master_config;
+} machine_spi_obj_t;
+
+typedef struct _iomux_table_t {
+ uint32_t muxRegister;
+ uint32_t muxMode;
+ uint32_t inputRegister;
+ uint32_t inputDaisy;
+ uint32_t configRegister;
+} iomux_table_t;
+
+STATIC const uint8_t spi_index_table[] = MICROPY_HW_SPI_INDEX;
+STATIC LPSPI_Type *spi_base_ptr_table[] = LPSPI_BASE_PTRS;
+static const iomux_table_t iomux_table[] = {
+ IOMUX_TABLE_SPI
+};
+
+static uint16_t dma_req_src_rx[] = DMA_REQ_SRC_RX;
+static uint16_t dma_req_src_tx[] = DMA_REQ_SRC_TX;
+
+bool lpspi_set_iomux(int8_t spi, uint8_t drive) {
+ int index = (spi - 1) * 4;
+
+ if (SCK.muxRegister != 0) {
+ IOMUXC_SetPinMux(SCK.muxRegister, SCK.muxMode, SCK.inputRegister, SCK.inputDaisy, SCK.configRegister, 0U);
+ IOMUXC_SetPinConfig(SCK.muxRegister, SCK.muxMode, SCK.inputRegister, SCK.inputDaisy, SCK.configRegister,
+ 0x1080u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
+
+ IOMUXC_SetPinMux(CS0.muxRegister, CS0.muxMode, CS0.inputRegister, CS0.inputDaisy, CS0.configRegister, 0U);
+ IOMUXC_SetPinConfig(CS0.muxRegister, CS0.muxMode, CS0.inputRegister, CS0.inputDaisy, CS0.configRegister,
+ 0x1080u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
+
+ IOMUXC_SetPinMux(SDO.muxRegister, SDO.muxMode, SDO.inputRegister, SDO.inputDaisy, SDO.configRegister, 0U);
+ IOMUXC_SetPinConfig(SDO.muxRegister, SDO.muxMode, SDO.inputRegister, SDO.inputDaisy, SDO.configRegister,
+ 0x1080u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
+
+ IOMUXC_SetPinMux(SDI.muxRegister, SDI.muxMode, SDI.inputRegister, SDI.inputDaisy, SDI.configRegister, 0U);
+ IOMUXC_SetPinConfig(SDI.muxRegister, SDI.muxMode, SDI.inputRegister, SDI.inputDaisy, SDI.configRegister,
+ 0x1080u | drive << IOMUXC_SW_PAD_CTL_PAD_DSE_SHIFT);
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+STATIC void machine_spi_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ static const char *firstbit_str[] = {"MSB", "LSB"};
+ machine_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "SPI(%u, baudrate=%u, polarity=%u, phase=%u, bits=%u, firstbit=%s, gap_ns=%d)",
+ self->spi_id, self->master_config->baudRate, self->master_config->cpol,
+ self->master_config->cpha, self->master_config->bitsPerFrame,
+ firstbit_str[self->master_config->direction], self->master_config->betweenTransferDelayInNanoSec);
+}
+
+mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ enum { ARG_id, ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_gap_ns, ARG_drive };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_id, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = DEFAULT_SPI_BAUDRATE} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_POLARITY} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_PHASE} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_BITS} },
+ { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_FIRSTBIT} },
+ { MP_QSTR_gap_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_drive, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = DEFAULT_SPI_DRIVE} },
+ };
+
+ static bool clk_init = true;
+
+ // Parse the arguments.
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ // Get the SPI bus id.
+ int spi_id = mp_obj_get_int(args[ARG_id].u_obj);
+ if (spi_id < 0 || spi_id >= MP_ARRAY_SIZE(spi_index_table)) {
+ mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("SPI(%d) doesn't exist"), spi_id);
+ }
+
+ // Get peripheral object.
+ uint8_t spi_hw_id = spi_index_table[spi_id]; // the hw spi number 1..n
+ machine_spi_obj_t *self = m_new_obj(machine_spi_obj_t);
+ self->base.type = &machine_spi_type;
+ self->spi_id = spi_id;
+ self->spi_inst = spi_base_ptr_table[spi_hw_id];
+ self->spi_hw_id = spi_hw_id;
+
+ uint8_t drive = args[ARG_drive].u_int;
+ if (drive < 1 || drive > 7) {
+ drive = DEFAULT_SPI_DRIVE;
+ }
+
+ if (clk_init) {
+ clk_init = false;
+ /*Set clock source for LPSPI*/
+ CLOCK_SetMux(kCLOCK_LpspiMux, 1); // Clock source is kCLOCK_Usb1PllPfd1Clk
+ CLOCK_SetDiv(kCLOCK_LpspiDiv, CLOCK_DIVIDER);
+ }
+ lpspi_set_iomux(spi_index_table[spi_id], drive);
+ LPSPI_Reset(self->spi_inst);
+ LPSPI_Enable(self->spi_inst, false); // Disable first before new settings are applies
+
+ self->master_config = m_new_obj(lpspi_master_config_t);
+ LPSPI_MasterGetDefaultConfig(self->master_config);
+ // Initialise the SPI peripheral.
+ self->master_config->baudRate = args[ARG_baudrate].u_int;
+ self->master_config->betweenTransferDelayInNanoSec = 1000000000 / self->master_config->baudRate * 2;
+ self->master_config->cpol = args[ARG_polarity].u_int;
+ self->master_config->cpha = args[ARG_phase].u_int;
+ self->master_config->bitsPerFrame = args[ARG_bits].u_int;
+ self->master_config->direction = args[ARG_firstbit].u_int;
+ if (args[ARG_gap_ns].u_int != -1) {
+ self->master_config->betweenTransferDelayInNanoSec = args[ARG_gap_ns].u_int;
+ }
+ LPSPI_MasterInit(self->spi_inst, self->master_config, CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (CLOCK_DIVIDER + 1));
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+STATIC void machine_spi_init(mp_obj_base_t *self_in, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
+ enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits, ARG_firstbit, ARG_gap_ns };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_firstbit, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ { MP_QSTR_gap_ns, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
+ };
+
+ // Parse the arguments.
+ machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
+ 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);
+
+ // Reconfigure the baudrate if requested.
+ if (args[ARG_baudrate].u_int != -1) {
+ self->master_config->baudRate = args[ARG_baudrate].u_int;
+ self->master_config->betweenTransferDelayInNanoSec = 1000000000 / self->master_config->baudRate * 2;
+ }
+ // Reconfigure the format if requested.
+ if (args[ARG_polarity].u_int != -1) {
+ self->master_config->cpol = args[ARG_polarity].u_int;
+ }
+ if (args[ARG_phase].u_int != -1) {
+ self->master_config->cpha = args[ARG_phase].u_int;
+ }
+ if (args[ARG_bits].u_int != -1) {
+ self->master_config->bitsPerFrame = args[ARG_bits].u_int;
+ }
+ if (args[ARG_firstbit].u_int != -1) {
+ self->master_config->direction = args[ARG_firstbit].u_int;
+ }
+ if (args[ARG_gap_ns].u_int != -1) {
+ self->master_config->betweenTransferDelayInNanoSec = args[ARG_gap_ns].u_int;
+ }
+ LPSPI_Enable(self->spi_inst, false); // Disable first before new settings are applies
+ LPSPI_MasterInit(self->spi_inst, self->master_config, CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (CLOCK_DIVIDER + 1));
+}
+
+void LPSPI_EDMAMasterCallback(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, status_t status, void *self_in) {
+ machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
+ self->transfer_busy = false;
+}
+
+STATIC void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) {
+ machine_spi_obj_t *self = (machine_spi_obj_t *)self_in;
+ // Use DMA for large transfers if channels are available
+ const size_t dma_min_size_threshold = 16; // That's the FIFO size
+
+ int chan_tx = -1;
+ int chan_rx = -1;
+ if (len >= dma_min_size_threshold) {
+ // Use two DMA channels to service the two FIFOs
+ chan_rx = allocate_dma_channel();
+ chan_tx = allocate_dma_channel();
+ }
+ bool use_dma = chan_rx >= 0 && chan_tx >= 0;
+
+ if (use_dma) {
+ edma_config_t userConfig;
+
+ /* DMA MUX init*/
+ DMAMUX_Init(DMAMUX);
+
+ DMAMUX_SetSource(DMAMUX, chan_rx, dma_req_src_rx[self->spi_hw_id]); // ## SPIn source
+ DMAMUX_EnableChannel(DMAMUX, chan_rx);
+
+ DMAMUX_SetSource(DMAMUX, chan_tx, dma_req_src_tx[self->spi_hw_id]);
+ DMAMUX_EnableChannel(DMAMUX, chan_tx);
+
+ EDMA_GetDefaultConfig(&userConfig);
+ EDMA_Init(DMA0, &userConfig);
+
+ lpspi_master_edma_handle_t g_master_edma_handle;
+ edma_handle_t lpspiEdmaMasterRxRegToRxDataHandle;
+ edma_handle_t lpspiEdmaMasterTxDataToTxRegHandle;
+
+ // Set up lpspi EDMA master
+ EDMA_CreateHandle(&(lpspiEdmaMasterRxRegToRxDataHandle), DMA0, chan_rx);
+ EDMA_CreateHandle(&(lpspiEdmaMasterTxDataToTxRegHandle), DMA0, chan_tx);
+ LPSPI_MasterTransferCreateHandleEDMA(self->spi_inst, &g_master_edma_handle, LPSPI_EDMAMasterCallback, self,
+ &lpspiEdmaMasterRxRegToRxDataHandle,
+ &lpspiEdmaMasterTxDataToTxRegHandle);
+ // Start master transfer
+ lpspi_transfer_t masterXfer;
+ masterXfer.txData = (uint8_t *)src;
+ masterXfer.rxData = (uint8_t *)dest;
+ masterXfer.dataSize = len;
+ masterXfer.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
+
+ // Reconfigure the TCR, required after switch between DMA vs. non-DMA
+ LPSPI_Enable(self->spi_inst, false); // Disable first before new settings are applied
+ self->spi_inst->TCR = LPSPI_TCR_CPOL(self->master_config->cpol) | LPSPI_TCR_CPHA(self->master_config->cpha) |
+ LPSPI_TCR_LSBF(self->master_config->direction) | LPSPI_TCR_FRAMESZ(self->master_config->bitsPerFrame - 1) |
+ (self->spi_inst->TCR & LPSPI_TCR_PRESCALE_MASK) | LPSPI_TCR_PCS(self->master_config->whichPcs);
+ LPSPI_Enable(self->spi_inst, true);
+
+ self->transfer_busy = true;
+ if (dest) {
+ L1CACHE_DisableDCache();
+ } else if (src) {
+ DCACHE_CleanByRange((uint32_t)src, len);
+ }
+ LPSPI_MasterTransferEDMA(self->spi_inst, &g_master_edma_handle, &masterXfer);
+
+ while (self->transfer_busy) {
+ MICROPY_EVENT_POLL_HOOK
+ }
+ L1CACHE_EnableDCache();
+ }
+ // Release DMA channels, even if never allocated.
+ if (chan_rx >= 0) {
+ free_dma_channel(chan_rx);
+ }
+ if (chan_tx >= 0) {
+ free_dma_channel(chan_tx);
+ }
+
+ if (!use_dma) {
+ // Reconfigure the TCR, required after switch between DMA vs. non-DMA
+ LPSPI_Enable(self->spi_inst, false); // Disable first before new settings are applied
+ self->spi_inst->TCR = LPSPI_TCR_CPOL(self->master_config->cpol) | LPSPI_TCR_CPHA(self->master_config->cpha) |
+ LPSPI_TCR_LSBF(self->master_config->direction) | LPSPI_TCR_FRAMESZ(self->master_config->bitsPerFrame - 1) |
+ (self->spi_inst->TCR & LPSPI_TCR_PRESCALE_MASK) | LPSPI_TCR_PCS(self->master_config->whichPcs);
+ LPSPI_Enable(self->spi_inst, true);
+
+ lpspi_transfer_t masterXfer;
+ masterXfer.txData = (uint8_t *)src;
+ masterXfer.rxData = (uint8_t *)dest;
+ masterXfer.dataSize = len;
+ masterXfer.configFlags = kLPSPI_MasterPcs0 | kLPSPI_MasterPcsContinuous | kLPSPI_MasterByteSwap;
+
+ LPSPI_MasterTransferBlocking(self->spi_inst, &masterXfer);
+ }
+}
+
+STATIC const mp_machine_spi_p_t machine_spi_p = {
+ .init = machine_spi_init,
+ .transfer = machine_spi_transfer,
+};
+
+const mp_obj_type_t machine_spi_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_SPI,
+ .print = machine_spi_print,
+ .make_new = machine_spi_make_new,
+ .protocol = &machine_spi_p,
+ .locals_dict = (mp_obj_dict_t *)&mp_machine_spi_locals_dict,
+};
diff --git a/ports/mimxrt/modmachine.c b/ports/mimxrt/modmachine.c
index 09aa250c5..ed23510cf 100644
--- a/ports/mimxrt/modmachine.c
+++ b/ports/mimxrt/modmachine.c
@@ -65,6 +65,7 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
{ 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) },
+ { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&machine_spi_type) },
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&machine_uart_type) },
};
STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
diff --git a/ports/mimxrt/modmachine.h b/ports/mimxrt/modmachine.h
index 5ac865576..eba8e6db8 100644
--- a/ports/mimxrt/modmachine.h
+++ b/ports/mimxrt/modmachine.h
@@ -32,6 +32,7 @@
extern const mp_obj_type_t machine_adc_type;
extern const mp_obj_type_t machine_timer_type;
extern const mp_obj_type_t machine_rtc_type;
+extern const mp_obj_type_t machine_spi_type;
extern const mp_obj_type_t machine_uart_type;
void machine_adc_init(void);