summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/nxp
diff options
context:
space:
mode:
authorChristian Mauderer <christian.mauderer@embedded-brains.de>2020-10-12 13:40:30 +0200
committerChristian Mauderer <christian.mauderer@embedded-brains.de>2020-11-20 08:53:18 +0100
commit48f6a6c302a3e1a3f8915e2503d0fe618d1af285 (patch)
treeb5d570ddd5e432519c5a9d42b4cf6725d8161551 /bsps/arm/imxrt/nxp
parentcpu/armv7m: Add table based init for ARMV7M_MPU (diff)
downloadrtems-48f6a6c302a3e1a3f8915e2503d0fe618d1af285.tar.bz2
bsp/imxrt: Import files from MCUXpresso SDK V2.8.5
The following files have been imported: cp ${SDK}/boards/evkbimxrt1050/project_template/clock_config.c nxp/boards/evkbimxrt1050 cp ${SDK}/boards/evkbimxrt1050/project_template/clock_config.h include/fsl_clock_config.h cp ${SDK}/boards/evkbimxrt1050/project_template/dcd.c start/flash-dcd.c cp ${SDK}/boards/evkbimxrt1050/project_template/pin_mux.c nxp/boards/evkbimxrt1050 cp ${SDK}/boards/evkbimxrt1050/project_template/pin_mux.h include/fsl_pin_mux.h cp ${SDK}/boards/evkbimxrt1050/xip/evkbimxrt1050_flexspi_nor_config.h include/fsl_flexspi_nor_config.h cp ${SDK}/devices/MIMXRT1052/MIMXRT1052.h include cp ${SDK}/devices/MIMXRT1052/MIMXRT1052_features.h include cp ${SDK}/devices/MIMXRT1052/drivers/fsl_*.c nxp/devices/MIMXRT1052/drivers cp ${SDK}/devices/MIMXRT1052/drivers/fsl_*.h include cp ${SDK}/devices/MIMXRT1052/fsl_device_registers.h include cp ${SDK}/devices/MIMXRT1052/system_MIMXRT1052.h include/ cp ${SDK}/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.c nxp/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.c cp ${SDK}/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.h include Update #4180
Diffstat (limited to 'bsps/arm/imxrt/nxp')
-rw-r--r--bsps/arm/imxrt/nxp/boards/evkbimxrt1050/clock_config.c471
-rw-r--r--bsps/arm/imxrt/nxp/boards/evkbimxrt1050/pin_mux.c1094
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc.c395
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc_etc.c433
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aipstz.c51
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aoi.c214
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_bee.c303
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cache.c602
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_clock.c1250
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cmp.c371
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_common.c280
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_csi.c1395
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcdc.c534
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcp.c1461
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dmamux.c91
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_edma.c2849
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_elcdif.c386
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enc.c593
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enet.c3389
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ewm.c140
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexcan.c3564
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio.c424
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_camera.c215
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_camera_edma.c248
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2c_master.c1258
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2s.c903
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2s_edma.c447
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd.c1293
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c564
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_spi.c1326
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_spi_edma.c474
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_uart.c991
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_uart_edma.c407
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexram.c94
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexram_allocate.c157
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexspi.c1105
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpc.c103
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpio.c171
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpt.c127
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_kpp.c203
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c.c2315
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c518
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpspi.c2221
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpspi_edma.c1154
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpuart.c2051
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpuart_edma.c444
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ocotp.c263
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pit.c146
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pmu.c55
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pwm.c935
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pxp.c1050
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_qtmr.c612
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_rtwdog.c148
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_sai.c3764
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_sai_edma.c707
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_semc.c1148
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_snvs_hp.c573
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_snvs_lp.c809
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_spdif.c828
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_spdif_edma.c598
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_src.c49
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_tempmon.c195
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_trng.c1935
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_tsc.c260
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_usdhc.c2126
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_wdog.c214
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_xbara.c229
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_xbarb.c126
-rw-r--r--bsps/arm/imxrt/nxp/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.c51
69 files changed, 55900 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/clock_config.c b/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/clock_config.c
new file mode 100644
index 0000000000..2ed6638cbe
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/clock_config.c
@@ -0,0 +1,471 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * How to setup clock using clock driver functions:
+ *
+ * 1. Call CLOCK_InitXXXPLL() to configure corresponding PLL clock.
+ *
+ * 2. Call CLOCK_InitXXXpfd() to configure corresponding PLL pfd clock.
+ *
+ * 3. Call CLOCK_SetMux() to configure corresponding clock source for target clock out.
+ *
+ * 4. Call CLOCK_SetDiv() to configure corresponding clock divider for target clock out.
+ *
+ * 5. Call CLOCK_SetXtalFreq() to set XTAL frequency based on board settings.
+ *
+ */
+
+/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!GlobalInfo
+product: Clocks v5.0
+processor: MIMXRT1052xxxxB
+package_id: MIMXRT1052DVL6B
+mcu_data: ksdk2_0
+processor_version: 0.0.0
+board: IMXRT1050-EVKB
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
+
+#include "clock_config.h"
+#include "fsl_iomuxc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* System clock frequency. */
+extern uint32_t SystemCoreClock;
+
+/*******************************************************************************
+ ************************ BOARD_InitBootClocks function ************************
+ ******************************************************************************/
+void BOARD_InitBootClocks(void)
+{
+ BOARD_BootClockRUN();
+}
+
+/*******************************************************************************
+ ********************** Configuration BOARD_BootClockRUN ***********************
+ ******************************************************************************/
+/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!Configuration
+name: BOARD_BootClockRUN
+called_from_default_init: true
+outputs:
+- {id: AHB_CLK_ROOT.outFreq, value: 600 MHz}
+- {id: CAN_CLK_ROOT.outFreq, value: 40 MHz}
+- {id: CKIL_SYNC_CLK_ROOT.outFreq, value: 32.768 kHz}
+- {id: CLK_1M.outFreq, value: 1 MHz}
+- {id: CLK_24M.outFreq, value: 24 MHz}
+- {id: CSI_CLK_ROOT.outFreq, value: 12 MHz}
+- {id: ENET1_TX_CLK.outFreq, value: 2.4 MHz}
+- {id: ENET_125M_CLK.outFreq, value: 2.4 MHz}
+- {id: ENET_25M_REF_CLK.outFreq, value: 1.2 MHz}
+- {id: FLEXIO1_CLK_ROOT.outFreq, value: 30 MHz}
+- {id: FLEXIO2_CLK_ROOT.outFreq, value: 30 MHz}
+- {id: FLEXSPI_CLK_ROOT.outFreq, value: 160 MHz}
+- {id: GPT1_ipg_clk_highfreq.outFreq, value: 75 MHz}
+- {id: GPT2_ipg_clk_highfreq.outFreq, value: 75 MHz}
+- {id: IPG_CLK_ROOT.outFreq, value: 150 MHz}
+- {id: LCDIF_CLK_ROOT.outFreq, value: 67.5 MHz}
+- {id: LPI2C_CLK_ROOT.outFreq, value: 60 MHz}
+- {id: LPSPI_CLK_ROOT.outFreq, value: 105.6 MHz}
+- {id: LVDS1_CLK.outFreq, value: 1.2 GHz}
+- {id: MQS_MCLK.outFreq, value: 1080/17 MHz}
+- {id: PERCLK_CLK_ROOT.outFreq, value: 75 MHz}
+- {id: PLL7_MAIN_CLK.outFreq, value: 24 MHz}
+- {id: SAI1_CLK_ROOT.outFreq, value: 1080/17 MHz}
+- {id: SAI1_MCLK1.outFreq, value: 1080/17 MHz}
+- {id: SAI1_MCLK2.outFreq, value: 1080/17 MHz}
+- {id: SAI1_MCLK3.outFreq, value: 30 MHz}
+- {id: SAI2_CLK_ROOT.outFreq, value: 1080/17 MHz}
+- {id: SAI2_MCLK1.outFreq, value: 1080/17 MHz}
+- {id: SAI2_MCLK3.outFreq, value: 30 MHz}
+- {id: SAI3_CLK_ROOT.outFreq, value: 1080/17 MHz}
+- {id: SAI3_MCLK1.outFreq, value: 1080/17 MHz}
+- {id: SAI3_MCLK3.outFreq, value: 30 MHz}
+- {id: SEMC_CLK_ROOT.outFreq, value: 75 MHz}
+- {id: SPDIF0_CLK_ROOT.outFreq, value: 30 MHz}
+- {id: TRACE_CLK_ROOT.outFreq, value: 352/3 MHz}
+- {id: UART_CLK_ROOT.outFreq, value: 80 MHz}
+- {id: USDHC1_CLK_ROOT.outFreq, value: 198 MHz}
+- {id: USDHC2_CLK_ROOT.outFreq, value: 198 MHz}
+settings:
+- {id: CCM.AHB_PODF.scale, value: '1', locked: true}
+- {id: CCM.ARM_PODF.scale, value: '2', locked: true}
+- {id: CCM.FLEXSPI_PODF.scale, value: '3', locked: true}
+- {id: CCM.FLEXSPI_SEL.sel, value: CCM.PLL3_SW_CLK_SEL}
+- {id: CCM.LPSPI_PODF.scale, value: '5', locked: true}
+- {id: CCM.PERCLK_PODF.scale, value: '2', locked: true}
+- {id: CCM.SEMC_PODF.scale, value: '8'}
+- {id: CCM.TRACE_PODF.scale, value: '3', locked: true}
+- {id: CCM_ANALOG.PLL1_BYPASS.sel, value: CCM_ANALOG.PLL1}
+- {id: CCM_ANALOG.PLL1_PREDIV.scale, value: '1', locked: true}
+- {id: CCM_ANALOG.PLL1_VDIV.scale, value: '50', locked: true}
+- {id: CCM_ANALOG.PLL2.denom, value: '1', locked: true}
+- {id: CCM_ANALOG.PLL2.num, value: '0', locked: true}
+- {id: CCM_ANALOG.PLL2_BYPASS.sel, value: CCM_ANALOG.PLL2_OUT_CLK}
+- {id: CCM_ANALOG.PLL2_PFD0_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD0}
+- {id: CCM_ANALOG.PLL2_PFD1_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD1}
+- {id: CCM_ANALOG.PLL2_PFD2_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD2}
+- {id: CCM_ANALOG.PLL2_PFD3_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD3}
+- {id: CCM_ANALOG.PLL3_BYPASS.sel, value: CCM_ANALOG.PLL3}
+- {id: CCM_ANALOG.PLL3_PFD0_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD0}
+- {id: CCM_ANALOG.PLL3_PFD0_DIV.scale, value: '33', locked: true}
+- {id: CCM_ANALOG.PLL3_PFD0_MUL.scale, value: '18', locked: true}
+- {id: CCM_ANALOG.PLL3_PFD1_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD1}
+- {id: CCM_ANALOG.PLL3_PFD2_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD2}
+- {id: CCM_ANALOG.PLL3_PFD3_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD3}
+- {id: CCM_ANALOG.PLL4.denom, value: '50'}
+- {id: CCM_ANALOG.PLL4.div, value: '47'}
+- {id: CCM_ANALOG.PLL5.denom, value: '1'}
+- {id: CCM_ANALOG.PLL5.div, value: '40'}
+- {id: CCM_ANALOG.PLL5.num, value: '0'}
+- {id: CCM_ANALOG_PLL_ENET_POWERDOWN_CFG, value: 'Yes'}
+- {id: CCM_ANALOG_PLL_USB1_POWER_CFG, value: 'Yes'}
+sources:
+- {id: XTALOSC24M.OSC.outFreq, value: 24 MHz, enabled: true}
+- {id: XTALOSC24M.RTC_OSC.outFreq, value: 32.768 kHz, enabled: true}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
+
+/*******************************************************************************
+ * Variables for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN = {
+ .loopDivider = 100, /* PLL loop divider, Fout = Fin * 50 */
+ .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */
+};
+const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN = {
+ .loopDivider = 1, /* PLL loop divider, Fout = Fin * ( 20 + loopDivider*2 + numerator / denominator ) */
+ .numerator = 0, /* 30 bit numerator of fractional loop divider */
+ .denominator = 1, /* 30 bit denominator of fractional loop divider */
+ .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */
+};
+const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN = {
+ .loopDivider = 0, /* PLL loop divider, Fout = Fin * 20 */
+ .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */
+};
+/*******************************************************************************
+ * Code for BOARD_BootClockRUN configuration
+ ******************************************************************************/
+void BOARD_BootClockRUN(void)
+{
+ /* Init RTC OSC clock frequency. */
+ CLOCK_SetRtcXtalFreq(32768U);
+ /* Enable 1MHz clock output. */
+ XTALOSC24M->OSC_CONFIG2 |= XTALOSC24M_OSC_CONFIG2_ENABLE_1M_MASK;
+ /* Use free 1MHz clock output. */
+ XTALOSC24M->OSC_CONFIG2 &= ~XTALOSC24M_OSC_CONFIG2_MUX_1M_MASK;
+ /* Set XTAL 24MHz clock frequency. */
+ CLOCK_SetXtalFreq(24000000U);
+ /* Enable XTAL 24MHz clock source. */
+ CLOCK_InitExternalClk(0);
+ /* Enable internal RC. */
+ CLOCK_InitRcOsc24M();
+ /* Switch clock source to external OSC. */
+ CLOCK_SwitchOsc(kCLOCK_XtalOsc);
+ /* Set Oscillator ready counter value. */
+ CCM->CCR = (CCM->CCR & (~CCM_CCR_OSCNT_MASK)) | CCM_CCR_OSCNT(127);
+ /* Setting PeriphClk2Mux and PeriphMux to provide stable clock before PLLs are initialed */
+ CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 1); /* Set PERIPH_CLK2 MUX to OSC */
+ CLOCK_SetMux(kCLOCK_PeriphMux, 1); /* Set PERIPH_CLK MUX to PERIPH_CLK2 */
+ /* Setting the VDD_SOC to 1.275V. It is necessary to config AHB to 600Mhz. */
+ DCDC->REG3 = (DCDC->REG3 & (~DCDC_REG3_TRG_MASK)) | DCDC_REG3_TRG(0x13);
+ /* Waiting for DCDC_STS_DC_OK bit is asserted */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & DCDC->REG0))
+ {
+ }
+ /* Set AHB_PODF. */
+ CLOCK_SetDiv(kCLOCK_AhbDiv, 0);
+ /* Disable IPG clock gate. */
+ CLOCK_DisableClock(kCLOCK_Adc1);
+ CLOCK_DisableClock(kCLOCK_Adc2);
+ CLOCK_DisableClock(kCLOCK_Xbar1);
+ CLOCK_DisableClock(kCLOCK_Xbar2);
+ CLOCK_DisableClock(kCLOCK_Xbar3);
+ /* Set IPG_PODF. */
+ CLOCK_SetDiv(kCLOCK_IpgDiv, 3);
+ /* Set ARM_PODF. */
+ CLOCK_SetDiv(kCLOCK_ArmDiv, 1);
+ /* Set PERIPH_CLK2_PODF. */
+ CLOCK_SetDiv(kCLOCK_PeriphClk2Div, 0);
+ /* Disable PERCLK clock gate. */
+ CLOCK_DisableClock(kCLOCK_Gpt1);
+ CLOCK_DisableClock(kCLOCK_Gpt1S);
+ CLOCK_DisableClock(kCLOCK_Gpt2);
+ CLOCK_DisableClock(kCLOCK_Gpt2S);
+ CLOCK_DisableClock(kCLOCK_Pit);
+ /* Set PERCLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_PerclkDiv, 1);
+ /* Disable USDHC1 clock gate. */
+ CLOCK_DisableClock(kCLOCK_Usdhc1);
+ /* Set USDHC1_PODF. */
+ CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1);
+ /* Set Usdhc1 clock source. */
+ CLOCK_SetMux(kCLOCK_Usdhc1Mux, 0);
+ /* Disable USDHC2 clock gate. */
+ CLOCK_DisableClock(kCLOCK_Usdhc2);
+ /* Set USDHC2_PODF. */
+ CLOCK_SetDiv(kCLOCK_Usdhc2Div, 1);
+ /* Set Usdhc2 clock source. */
+ CLOCK_SetMux(kCLOCK_Usdhc2Mux, 0);
+/* In SDK projects, SDRAM (configured by SEMC) will be initialized in either debug script or dcd.
+ * With this macro SKIP_SYSCLK_INIT, system pll (selected to be SEMC source clock in SDK projects) will be left
+ * unchanged.
+ * Note: If another clock source is selected for SEMC, user may want to avoid changing that clock as well.*/
+#ifndef SKIP_SYSCLK_INIT
+ /* Disable Semc clock gate. */
+ CLOCK_DisableClock(kCLOCK_Semc);
+ /* Set SEMC_PODF. */
+ CLOCK_SetDiv(kCLOCK_SemcDiv, 7);
+ /* Set Semc alt clock source. */
+ CLOCK_SetMux(kCLOCK_SemcAltMux, 0);
+ /* Set Semc clock source. */
+ CLOCK_SetMux(kCLOCK_SemcMux, 0);
+#endif
+/* In SDK projects, external flash (configured by FLEXSPI) will be initialized by dcd.
+ * With this macro XIP_EXTERNAL_FLASH, usb1 pll (selected to be FLEXSPI clock source in SDK projects) will be left
+ * unchanged.
+ * Note: If another clock source is selected for FLEXSPI, user may want to avoid changing that clock as well.*/
+#if !(defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
+ /* Disable Flexspi clock gate. */
+ CLOCK_DisableClock(kCLOCK_FlexSpi);
+ /* Set FLEXSPI_PODF. */
+ CLOCK_SetDiv(kCLOCK_FlexspiDiv, 2);
+ /* Set Flexspi clock source. */
+ CLOCK_SetMux(kCLOCK_FlexspiMux, 1);
+#endif
+ /* Disable CSI clock gate. */
+ CLOCK_DisableClock(kCLOCK_Csi);
+ /* Set CSI_PODF. */
+ CLOCK_SetDiv(kCLOCK_CsiDiv, 1);
+ /* Set Csi clock source. */
+ CLOCK_SetMux(kCLOCK_CsiMux, 0);
+ /* Disable LPSPI clock gate. */
+ CLOCK_DisableClock(kCLOCK_Lpspi1);
+ CLOCK_DisableClock(kCLOCK_Lpspi2);
+ CLOCK_DisableClock(kCLOCK_Lpspi3);
+ CLOCK_DisableClock(kCLOCK_Lpspi4);
+ /* Set LPSPI_PODF. */
+ CLOCK_SetDiv(kCLOCK_LpspiDiv, 4);
+ /* Set Lpspi clock source. */
+ CLOCK_SetMux(kCLOCK_LpspiMux, 2);
+ /* Disable TRACE clock gate. */
+ CLOCK_DisableClock(kCLOCK_Trace);
+ /* Set TRACE_PODF. */
+ CLOCK_SetDiv(kCLOCK_TraceDiv, 2);
+ /* Set Trace clock source. */
+ CLOCK_SetMux(kCLOCK_TraceMux, 2);
+ /* Disable SAI1 clock gate. */
+ CLOCK_DisableClock(kCLOCK_Sai1);
+ /* Set SAI1_CLK_PRED. */
+ CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3);
+ /* Set SAI1_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_Sai1Div, 1);
+ /* Set Sai1 clock source. */
+ CLOCK_SetMux(kCLOCK_Sai1Mux, 0);
+ /* Disable SAI2 clock gate. */
+ CLOCK_DisableClock(kCLOCK_Sai2);
+ /* Set SAI2_CLK_PRED. */
+ CLOCK_SetDiv(kCLOCK_Sai2PreDiv, 3);
+ /* Set SAI2_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_Sai2Div, 1);
+ /* Set Sai2 clock source. */
+ CLOCK_SetMux(kCLOCK_Sai2Mux, 0);
+ /* Disable SAI3 clock gate. */
+ CLOCK_DisableClock(kCLOCK_Sai3);
+ /* Set SAI3_CLK_PRED. */
+ CLOCK_SetDiv(kCLOCK_Sai3PreDiv, 3);
+ /* Set SAI3_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_Sai3Div, 1);
+ /* Set Sai3 clock source. */
+ CLOCK_SetMux(kCLOCK_Sai3Mux, 0);
+ /* Disable Lpi2c clock gate. */
+ CLOCK_DisableClock(kCLOCK_Lpi2c1);
+ CLOCK_DisableClock(kCLOCK_Lpi2c2);
+ CLOCK_DisableClock(kCLOCK_Lpi2c3);
+ /* Set LPI2C_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 0);
+ /* Set Lpi2c clock source. */
+ CLOCK_SetMux(kCLOCK_Lpi2cMux, 0);
+ /* Disable CAN clock gate. */
+ CLOCK_DisableClock(kCLOCK_Can1);
+ CLOCK_DisableClock(kCLOCK_Can2);
+ CLOCK_DisableClock(kCLOCK_Can1S);
+ CLOCK_DisableClock(kCLOCK_Can2S);
+ /* Set CAN_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_CanDiv, 1);
+ /* Set Can clock source. */
+ CLOCK_SetMux(kCLOCK_CanMux, 2);
+ /* Disable UART clock gate. */
+ CLOCK_DisableClock(kCLOCK_Lpuart1);
+ CLOCK_DisableClock(kCLOCK_Lpuart2);
+ CLOCK_DisableClock(kCLOCK_Lpuart3);
+ CLOCK_DisableClock(kCLOCK_Lpuart4);
+ CLOCK_DisableClock(kCLOCK_Lpuart5);
+ CLOCK_DisableClock(kCLOCK_Lpuart6);
+ CLOCK_DisableClock(kCLOCK_Lpuart7);
+ CLOCK_DisableClock(kCLOCK_Lpuart8);
+ /* Set UART_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_UartDiv, 0);
+ /* Set Uart clock source. */
+ CLOCK_SetMux(kCLOCK_UartMux, 0);
+ /* Disable LCDIF clock gate. */
+ CLOCK_DisableClock(kCLOCK_LcdPixel);
+ /* Set LCDIF_PRED. */
+ CLOCK_SetDiv(kCLOCK_LcdifPreDiv, 1);
+ /* Set LCDIF_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_LcdifDiv, 3);
+ /* Set Lcdif pre clock source. */
+ CLOCK_SetMux(kCLOCK_LcdifPreMux, 5);
+ /* Disable SPDIF clock gate. */
+ CLOCK_DisableClock(kCLOCK_Spdif);
+ /* Set SPDIF0_CLK_PRED. */
+ CLOCK_SetDiv(kCLOCK_Spdif0PreDiv, 1);
+ /* Set SPDIF0_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_Spdif0Div, 7);
+ /* Set Spdif clock source. */
+ CLOCK_SetMux(kCLOCK_SpdifMux, 3);
+ /* Disable Flexio1 clock gate. */
+ CLOCK_DisableClock(kCLOCK_Flexio1);
+ /* Set FLEXIO1_CLK_PRED. */
+ CLOCK_SetDiv(kCLOCK_Flexio1PreDiv, 1);
+ /* Set FLEXIO1_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_Flexio1Div, 7);
+ /* Set Flexio1 clock source. */
+ CLOCK_SetMux(kCLOCK_Flexio1Mux, 3);
+ /* Disable Flexio2 clock gate. */
+ CLOCK_DisableClock(kCLOCK_Flexio2);
+ /* Set FLEXIO2_CLK_PRED. */
+ CLOCK_SetDiv(kCLOCK_Flexio2PreDiv, 1);
+ /* Set FLEXIO2_CLK_PODF. */
+ CLOCK_SetDiv(kCLOCK_Flexio2Div, 7);
+ /* Set Flexio2 clock source. */
+ CLOCK_SetMux(kCLOCK_Flexio2Mux, 3);
+ /* Set Pll3 sw clock source. */
+ CLOCK_SetMux(kCLOCK_Pll3SwMux, 0);
+ /* Init ARM PLL. */
+ CLOCK_InitArmPll(&armPllConfig_BOARD_BootClockRUN);
+ /* In SDK projects, SDRAM (configured by SEMC) will be initialized in either debug script or dcd.
+ * With this macro SKIP_SYSCLK_INIT, system pll (selected to be SEMC source clock in SDK projects) will be left
+ * unchanged. Note: If another clock source is selected for SEMC, user may want to avoid changing that clock as
+ * well.*/
+#ifndef SKIP_SYSCLK_INIT
+ /* Init System PLL. */
+ CLOCK_InitSysPll(&sysPllConfig_BOARD_BootClockRUN);
+ /* Init System pfd0. */
+ CLOCK_InitSysPfd(kCLOCK_Pfd0, 27);
+ /* Init System pfd1. */
+ CLOCK_InitSysPfd(kCLOCK_Pfd1, 16);
+ /* Init System pfd2. */
+ CLOCK_InitSysPfd(kCLOCK_Pfd2, 24);
+ /* Init System pfd3. */
+ CLOCK_InitSysPfd(kCLOCK_Pfd3, 16);
+ /* Disable pfd offset. */
+ CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_PFD_OFFSET_EN_MASK;
+#endif
+ /* In SDK projects, external flash (configured by FLEXSPI) will be initialized by dcd.
+ * With this macro XIP_EXTERNAL_FLASH, usb1 pll (selected to be FLEXSPI clock source in SDK projects) will be left
+ * unchanged. Note: If another clock source is selected for FLEXSPI, user may want to avoid changing that clock as
+ * well.*/
+#if !(defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
+ /* Init Usb1 PLL. */
+ CLOCK_InitUsb1Pll(&usb1PllConfig_BOARD_BootClockRUN);
+ /* Init Usb1 pfd0. */
+ CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 33);
+ /* Init Usb1 pfd1. */
+ CLOCK_InitUsb1Pfd(kCLOCK_Pfd1, 16);
+ /* Init Usb1 pfd2. */
+ CLOCK_InitUsb1Pfd(kCLOCK_Pfd2, 17);
+ /* Init Usb1 pfd3. */
+ CLOCK_InitUsb1Pfd(kCLOCK_Pfd3, 19);
+ /* Disable Usb1 PLL output for USBPHY1. */
+ CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
+#endif
+ /* DeInit Audio PLL. */
+ CLOCK_DeinitAudioPll();
+ /* Bypass Audio PLL. */
+ CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllAudio, 1);
+ /* Set divider for Audio PLL. */
+ CCM_ANALOG->MISC2 &= ~CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
+ CCM_ANALOG->MISC2 &= ~CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK;
+ /* Enable Audio PLL output. */
+ CCM_ANALOG->PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_ENABLE_MASK;
+ /* DeInit Video PLL. */
+ CLOCK_DeinitVideoPll();
+ /* Bypass Video PLL. */
+ CCM_ANALOG->PLL_VIDEO |= CCM_ANALOG_PLL_VIDEO_BYPASS_MASK;
+ /* Set divider for Video PLL. */
+ CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & (~CCM_ANALOG_MISC2_VIDEO_DIV_MASK)) | CCM_ANALOG_MISC2_VIDEO_DIV(0);
+ /* Enable Video PLL output. */
+ CCM_ANALOG->PLL_VIDEO |= CCM_ANALOG_PLL_VIDEO_ENABLE_MASK;
+ /* DeInit Enet PLL. */
+ CLOCK_DeinitEnetPll();
+ /* Bypass Enet PLL. */
+ CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllEnet, 1);
+ /* Set Enet output divider. */
+ CCM_ANALOG->PLL_ENET =
+ (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK)) | CCM_ANALOG_PLL_ENET_DIV_SELECT(1);
+ /* Enable Enet output. */
+ CCM_ANALOG->PLL_ENET |= CCM_ANALOG_PLL_ENET_ENABLE_MASK;
+ /* Enable Enet25M output. */
+ CCM_ANALOG->PLL_ENET |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK;
+ /* DeInit Usb2 PLL. */
+ CLOCK_DeinitUsb2Pll();
+ /* Bypass Usb2 PLL. */
+ CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllUsb2, 1);
+ /* Enable Usb2 PLL output. */
+ CCM_ANALOG->PLL_USB2 |= CCM_ANALOG_PLL_USB2_ENABLE_MASK;
+ /* Set preperiph clock source. */
+ CLOCK_SetMux(kCLOCK_PrePeriphMux, 3);
+ /* Set periph clock source. */
+ CLOCK_SetMux(kCLOCK_PeriphMux, 0);
+ /* Set periph clock2 clock source. */
+ CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 0);
+ /* Set per clock source. */
+ CLOCK_SetMux(kCLOCK_PerclkMux, 0);
+ /* Set lvds1 clock source. */
+ CCM_ANALOG->MISC1 =
+ (CCM_ANALOG->MISC1 & (~CCM_ANALOG_MISC1_LVDS1_CLK_SEL_MASK)) | CCM_ANALOG_MISC1_LVDS1_CLK_SEL(0);
+ /* Set clock out1 divider. */
+ CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO1_DIV_MASK)) | CCM_CCOSR_CLKO1_DIV(0);
+ /* Set clock out1 source. */
+ CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO1_SEL_MASK)) | CCM_CCOSR_CLKO1_SEL(1);
+ /* Set clock out2 divider. */
+ CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO2_DIV_MASK)) | CCM_CCOSR_CLKO2_DIV(0);
+ /* Set clock out2 source. */
+ CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO2_SEL_MASK)) | CCM_CCOSR_CLKO2_SEL(18);
+ /* Set clock out1 drives clock out1. */
+ CCM->CCOSR &= ~CCM_CCOSR_CLK_OUT_SEL_MASK;
+ /* Disable clock out1. */
+ CCM->CCOSR &= ~CCM_CCOSR_CLKO1_EN_MASK;
+ /* Disable clock out2. */
+ CCM->CCOSR &= ~CCM_CCOSR_CLKO2_EN_MASK;
+ /* Set SAI1 MCLK1 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk1Sel, 0);
+ /* Set SAI1 MCLK2 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk2Sel, 0);
+ /* Set SAI1 MCLK3 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk3Sel, 0);
+ /* Set SAI2 MCLK3 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI2MClk3Sel, 0);
+ /* Set SAI3 MCLK3 clock source. */
+ IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI3MClk3Sel, 0);
+ /* Set MQS configuration. */
+ IOMUXC_MQSConfig(IOMUXC_GPR, kIOMUXC_MqsPwmOverSampleRate32, 0);
+ /* Set ENET Tx clock source. */
+ IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false);
+ /* Set GPT1 High frequency reference clock source. */
+ IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT1_MASK;
+ /* Set GPT2 High frequency reference clock source. */
+ IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_MASK;
+ /* Set SystemCoreClock variable. */
+ SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK;
+}
diff --git a/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/pin_mux.c b/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/pin_mux.c
new file mode 100644
index 0000000000..8e3021afcb
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/boards/evkbimxrt1050/pin_mux.c
@@ -0,0 +1,1094 @@
+/*
+ * Copyright 2018 NXP.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/***********************************************************************************************************************
+ * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file
+ * will be overwritten if the respective MCUXpresso Config Tools is used to update this file.
+ **********************************************************************************************************************/
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+!!GlobalInfo
+product: Pins v4.1
+processor: MIMXRT1052xxxxB
+package_id: MIMXRT1052DVL6B
+mcu_data: ksdk2_0
+processor_version: 4.0.0
+board: IMXRT1050-EVKB
+pin_labels:
+- {pin_num: E3, pin_signal: GPIO_EMC_00, label: SEMC_D0, identifier: SEMC_D0}
+- {pin_num: F3, pin_signal: GPIO_EMC_01, label: SEMC_D1, identifier: SEMC_D1}
+- {pin_num: F4, pin_signal: GPIO_EMC_02, label: SEMC_D2, identifier: SEMC_D2}
+- {pin_num: F2, pin_signal: GPIO_EMC_04, label: SEMC_D4, identifier: SEMC_D4}
+- {pin_num: G4, pin_signal: GPIO_EMC_03, label: SEMC_D3, identifier: SEMC_D3}
+- {pin_num: G5, pin_signal: GPIO_EMC_05, label: SEMC_D5, identifier: SEMC_D5}
+- {pin_num: H5, pin_signal: GPIO_EMC_06, label: SEMC_D6, identifier: SEMC_D6}
+- {pin_num: H4, pin_signal: GPIO_EMC_07, label: SEMC_D7, identifier: SEMC_D7}
+- {pin_num: H3, pin_signal: GPIO_EMC_08, label: SEMC_DM0, identifier: SEMC_DM0}
+- {pin_num: C2, pin_signal: GPIO_EMC_09, label: SEMC_A0, identifier: SEMC_A0}
+- {pin_num: G1, pin_signal: GPIO_EMC_10, label: SEMC_A1, identifier: SEMC_A1}
+- {pin_num: G3, pin_signal: GPIO_EMC_11, label: SEMC_A2, identifier: SEMC_A2}
+- {pin_num: H1, pin_signal: GPIO_EMC_12, label: SEMC_A3, identifier: SEMC_A3}
+- {pin_num: A6, pin_signal: GPIO_EMC_13, label: SEMC_A4, identifier: SEMC_A4}
+- {pin_num: B6, pin_signal: GPIO_EMC_14, label: SEMC_A5, identifier: SEMC_A5}
+- {pin_num: B1, pin_signal: GPIO_EMC_15, label: SEMC_A6, identifier: SEMC_A6}
+- {pin_num: A5, pin_signal: GPIO_EMC_16, label: SEMC_A7, identifier: SEMC_A7}
+- {pin_num: A4, pin_signal: GPIO_EMC_17, label: SEMC_A8, identifier: SEMC_A8}
+- {pin_num: B2, pin_signal: GPIO_EMC_18, label: SEMC_A9, identifier: SEMC_A9}
+- {pin_num: B4, pin_signal: GPIO_EMC_19, label: SEMC_A11, identifier: SEMC_A11}
+- {pin_num: G2, pin_signal: GPIO_EMC_23, label: SEMC_A10, identifier: SEMC_A10}
+- {pin_num: A3, pin_signal: GPIO_EMC_20, label: SEMC_A12, identifier: SEMC_A12}
+- {pin_num: C1, pin_signal: GPIO_EMC_21, label: SEMC_BA0, identifier: SEMC_BA0}
+- {pin_num: F1, pin_signal: GPIO_EMC_22, label: SEMC_BA1, identifier: SEMC_BA1}
+- {pin_num: D3, pin_signal: GPIO_EMC_24, label: SEMC_CAS, identifier: SEMC_CAS}
+- {pin_num: D2, pin_signal: GPIO_EMC_25, label: SEMC_RAS, identifier: SEMC_RAS}
+- {pin_num: B3, pin_signal: GPIO_EMC_26, label: SEMC_CLK, identifier: SEMC_CLK}
+- {pin_num: A2, pin_signal: GPIO_EMC_27, label: SEMC_CKE, identifier: SEMC_CKE}
+- {pin_num: D1, pin_signal: GPIO_EMC_28, label: SEMC_WE, identifier: SEMC_WE}
+- {pin_num: E1, pin_signal: GPIO_EMC_29, label: SEMC_CS0, identifier: SEMC_CS0}
+- {pin_num: C6, pin_signal: GPIO_EMC_30, label: SEMC_D8, identifier: SEMC_D8}
+- {pin_num: C5, pin_signal: GPIO_EMC_31, label: SEMC_D9, identifier: SEMC_D9}
+- {pin_num: D5, pin_signal: GPIO_EMC_32, label: SEMC_D10, identifier: SEMC_D10}
+- {pin_num: C4, pin_signal: GPIO_EMC_33, label: SEMC_D11, identifier: SEMC_D11}
+- {pin_num: D4, pin_signal: GPIO_EMC_34, label: SEMC_D12, identifier: SEMC_D12}
+- {pin_num: E5, pin_signal: GPIO_EMC_35, label: SEMC_D13, identifier: SEMC_D13}
+- {pin_num: C3, pin_signal: GPIO_EMC_36, label: SEMC_D14, identifier: SEMC_D14}
+- {pin_num: E4, pin_signal: GPIO_EMC_37, label: SEMC_D15, identifier: SEMC_D15}
+- {pin_num: D6, pin_signal: GPIO_EMC_38, label: SEMC_DM1, identifier: SEMC_DM1}
+- {pin_num: B7, pin_signal: GPIO_EMC_39, label: SEMC_DQS, identifier: SEMC_DQS}
+- {pin_num: A7, pin_signal: GPIO_EMC_40, label: ENET_MDC, identifier: ENET_MDC}
+- {pin_num: C7, pin_signal: GPIO_EMC_41, label: ENET_MDIO, identifier: ENET_MDIO}
+- {pin_num: D7, pin_signal: GPIO_B0_00, label: LCDIF_CLK, identifier: LCDIF_CLK}
+- {pin_num: E7, pin_signal: GPIO_B0_01, label: LCDIF_ENABLE, identifier: LCDIF_ENABLE}
+- {pin_num: E8, pin_signal: GPIO_B0_02, label: LCDIF_HSYNC, identifier: LCDIF_HSYNC}
+- {pin_num: D8, pin_signal: GPIO_B0_03, label: LCDIF_VSYNC, identifier: LCDIF_VSYNC}
+- {pin_num: C8, pin_signal: GPIO_B0_04, label: 'LCDIF_D0/BT_CFG[0]', identifier: LCDIF_D0}
+- {pin_num: B8, pin_signal: GPIO_B0_05, label: 'LCDIF_D1/BT_CFG[1]', identifier: LCDIF_D1}
+- {pin_num: A8, pin_signal: GPIO_B0_06, label: 'LCDIF_D2/BT_CFG[2]', identifier: LCDIF_D2}
+- {pin_num: A9, pin_signal: GPIO_B0_07, label: 'LCDIF_D3/BT_CFG[3]', identifier: LCDIF_D3}
+- {pin_num: B9, pin_signal: GPIO_B0_08, label: 'LCDIF_D4/BT_CFG[4]', identifier: LCDIF_D4}
+- {pin_num: C9, pin_signal: GPIO_B0_09, label: 'LCDIF_D5/BT_CFG[5]', identifier: LCDIF_D5}
+- {pin_num: D9, pin_signal: GPIO_B0_10, label: 'LCDIF_D6/BT_CFG[6]', identifier: LCDIF_D6}
+- {pin_num: A10, pin_signal: GPIO_B0_11, label: 'LCDIF_D7/BT_CFG[7]', identifier: LCDIF_D7}
+- {pin_num: C10, pin_signal: GPIO_B0_12, label: 'LCDIF_D8/BT_CFG[8]', identifier: LCDIF_D8}
+- {pin_num: D10, pin_signal: GPIO_B0_13, label: 'LCDIF_D9/BT_CFG[9]', identifier: LCDIF_D9}
+- {pin_num: E10, pin_signal: GPIO_B0_14, label: 'LCDIF_D10/BT_CFG[10]', identifier: LCDIF_D10}
+- {pin_num: E11, pin_signal: GPIO_B0_15, label: 'LCDIF_D11/BT_CFG[11]', identifier: LCDIF_D11}
+- {pin_num: A11, pin_signal: GPIO_B1_00, label: LCDIF_D12, identifier: LCDIF_D12}
+- {pin_num: B11, pin_signal: GPIO_B1_01, label: LCDIF_D13, identifier: LCDIF_D13}
+- {pin_num: C11, pin_signal: GPIO_B1_02, label: LCDIF_D14, identifier: LCDIF_D14}
+- {pin_num: D11, pin_signal: GPIO_B1_03, label: LCDIF_D15, identifier: LCDIF_D15}
+- {pin_num: E12, pin_signal: GPIO_B1_04, label: ENET_RXD0, identifier: ENET_RXD0}
+- {pin_num: D12, pin_signal: GPIO_B1_05, label: ENET_RXD1, identifier: ENET_RXD1}
+- {pin_num: C12, pin_signal: GPIO_B1_06, label: ENET_CRS_DV, identifier: ENET_CRS_DV}
+- {pin_num: B12, pin_signal: GPIO_B1_07, label: ENET_TXD0, identifier: ENET_TXD0}
+- {pin_num: A12, pin_signal: GPIO_B1_08, label: ENET_TXD1, identifier: ENET_TXD1}
+- {pin_num: A13, pin_signal: GPIO_B1_09, label: ENET_TXEN, identifier: ENET_TXEN}
+- {pin_num: B13, pin_signal: GPIO_B1_10, label: ENET_TX_CLK, identifier: ENET_TX_CLK}
+- {pin_num: C13, pin_signal: GPIO_B1_11, label: ENET_RXER, identifier: ENET_RXER}
+- {pin_num: D13, pin_signal: GPIO_B1_12, label: SD_CD_SW, identifier: SD_CD_SW}
+- {pin_num: D14, pin_signal: GPIO_B1_13, label: WDOG_B, identifier: WDOG_B}
+- {pin_num: C14, pin_signal: GPIO_B1_14, label: SD0_VSELECT, identifier: SD0_VSELECT}
+- {pin_num: B14, pin_signal: GPIO_B1_15, label: USB_HOST_PWR/BACKLIGHT_CTL, identifier: BACKLIGHT_CTL}
+- {pin_num: E9, pin_signal: NVCC_GPIO0, label: DCDC_3V3/NVCC_GPIO_3V3}
+- {pin_num: F10, pin_signal: NVCC_GPIO1, label: DCDC_3V3/NVCC_GPIO_3V3}
+- {pin_num: J10, pin_signal: NVCC_GPIO2, label: DCDC_3V3/NVCC_GPIO_3V3}
+- {pin_num: M14, pin_signal: GPIO_AD_B0_00, label: 'USB_HOST_OC/J24[10]'}
+- {pin_num: H10, pin_signal: GPIO_AD_B0_01, label: 'USB_OTG1_ID/J24[9]'}
+- {pin_num: M11, pin_signal: GPIO_AD_B0_02, label: 'USB_OTG1_PWR/J24[2]'}
+- {pin_num: G11, pin_signal: GPIO_AD_B0_03, label: 'USB_OTG1_OC/J24[1]'}
+- {pin_num: F11, pin_signal: GPIO_AD_B0_04, label: 'CSI_PWDN/J35[17]/BOOT_MODE[0]', identifier: CSI_PWDN}
+- {pin_num: G14, pin_signal: GPIO_AD_B0_05, label: 'CAN_STBY/BOOT_MODE[1]/Flash_RST/U12[8]', identifier: CAN_STBY}
+- {pin_num: E14, pin_signal: GPIO_AD_B0_06, label: 'JTAG_TMS/J21[7]/SWD_DIO'}
+- {pin_num: F12, pin_signal: GPIO_AD_B0_07, label: 'JTAG_TCK/J21[9]/SWD_CLK'}
+- {pin_num: F13, pin_signal: GPIO_AD_B0_08, label: JTAG_MOD}
+- {pin_num: F14, pin_signal: GPIO_AD_B0_09, label: 'JTAG_TDI/J21[5]/ENET_RST/J22[5]'}
+- {pin_num: G13, pin_signal: GPIO_AD_B0_10, label: 'JTAG_TDO/J21[13]/INT1_COMBO/ENET_INT/J22[6]/U32[11]', identifier: INT1_COMBO}
+- {pin_num: G10, pin_signal: GPIO_AD_B0_11, label: 'JTAG_nTRST/J21[3]/INT2_COMBO/LCD_TOUCH_INT/J22[3]/U32[9]', identifier: INT2_COMBO}
+- {pin_num: K14, pin_signal: GPIO_AD_B0_12, label: UART1_TXD, identifier: UART1_TXD}
+- {pin_num: L14, pin_signal: GPIO_AD_B0_13, label: UART1_RXD, identifier: UART1_RXD}
+- {pin_num: H14, pin_signal: GPIO_AD_B0_14, label: 'CAN2_TX/U12[1]', identifier: CAN2_TX}
+- {pin_num: L10, pin_signal: GPIO_AD_B0_15, label: 'CAN2_RX/U12[4]', identifier: CAN2_RX}
+- {pin_num: J11, pin_signal: GPIO_AD_B1_00, label: 'I2C1_SCL/CSI_I2C_SCL/J35[20]/J23[6]/U13[17]/U32[4]', identifier: I2C_SCL_FXOS8700CQ;CSI_I2C_SCL}
+- {pin_num: K11, pin_signal: GPIO_AD_B1_01, label: 'I2C1_SDA/CSI_I2C_SDA/J35[22]/J23[5]/U13[18]/U32[6]', identifier: I2C_SDA_FXOS8700CQ;CSI_I2C_SDA}
+- {pin_num: L11, pin_signal: GPIO_AD_B1_02, label: 'SPDIF_OUT/J22[7]', identifier: SPDIF_OUT}
+- {pin_num: M12, pin_signal: GPIO_AD_B1_03, label: 'SPDIF_IN/J22[8]', identifier: SPDIF_IN}
+- {pin_num: H13, pin_signal: GPIO_AD_B1_08, label: 'AUD_INT/CSI_D9//J35[13]/J22[4]', identifier: CSI_D9}
+- {pin_num: M13, pin_signal: GPIO_AD_B1_09, label: 'SAI1_MCLK/CSI_D8/J35[11]', identifier: CSI_D8}
+- {pin_num: L13, pin_signal: GPIO_AD_B1_10, label: 'SAI1_RX_SYNC/CSI_D7/J35[9]/J23[1]', identifier: CSI_D7}
+- {pin_num: J13, pin_signal: GPIO_AD_B1_11, label: 'SAI1_RX_BCLK/CSI_D6/J35[7]/J23[2]', identifier: CSI_D6}
+- {pin_num: H12, pin_signal: GPIO_AD_B1_12, label: 'SAI1_RXD/CSI_D5/J35[5]/U13[16]', identifier: CSI_D5}
+- {pin_num: H11, pin_signal: GPIO_AD_B1_13, label: 'SAI1_TXD/CSI_D4/J35[3]/U13[14]', identifier: CSI_D4}
+- {pin_num: G12, pin_signal: GPIO_AD_B1_14, label: 'SAI1_TX_BCLK/CSI_D3/J35[4]/U13[12]', identifier: CSI_D3}
+- {pin_num: J14, pin_signal: GPIO_AD_B1_15, label: 'SAI1_TX_SYNC/CSI_D2/J35[6]/U13[13]', identifier: CSI_D2}
+- {pin_num: J4, pin_signal: GPIO_SD_B0_00, label: 'SD1_CMD/J24[6]', identifier: SD1_CMD}
+- {pin_num: J3, pin_signal: GPIO_SD_B0_01, label: 'SD1_CLK/J24[3]', identifier: SD1_CLK}
+- {pin_num: J1, pin_signal: GPIO_SD_B0_02, label: 'SD1_D0/J24[4]/SPI_MOSI/PWM', identifier: SD1_D0}
+- {pin_num: K1, pin_signal: GPIO_SD_B0_03, label: 'SD1_D1/J24[5]/SPI_MISO', identifier: SD1_D1}
+- {pin_num: H2, pin_signal: GPIO_SD_B0_04, label: SD1_D2, identifier: SD1_D2}
+- {pin_num: J2, pin_signal: GPIO_SD_B0_05, label: SD1_D3, identifier: SD1_D3}
+- {pin_num: L5, pin_signal: GPIO_SD_B1_00, label: FlexSPI_D3_B, identifier: FlexSPI_D3_B}
+- {pin_num: M5, pin_signal: GPIO_SD_B1_01, label: FlexSPI_D2_B, identifier: FlexSPI_D2_B}
+- {pin_num: M3, pin_signal: GPIO_SD_B1_02, label: FlexSPI_D1_B, identifier: FlexSPI_D1_B}
+- {pin_num: M4, pin_signal: GPIO_SD_B1_03, label: FlexSPI_D0_B, identifier: FlexSPI_D0_B}
+- {pin_num: P2, pin_signal: GPIO_SD_B1_04, label: FlexSPI_CLK_B, identifier: FlexSPI_CLK_B}
+- {pin_num: N3, pin_signal: GPIO_SD_B1_05, label: FlexSPI_DQS, identifier: FlexSPI_DQS}
+- {pin_num: L3, pin_signal: GPIO_SD_B1_06, label: FlexSPI_SS0, identifier: FlexSPI_SS0}
+- {pin_num: L4, pin_signal: GPIO_SD_B1_07, label: FlexSPI_CLK, identifier: FlexSPI_CLK}
+- {pin_num: P3, pin_signal: GPIO_SD_B1_08, label: FlexSPI_D0_A, identifier: FlexSPI_D0_A}
+- {pin_num: N4, pin_signal: GPIO_SD_B1_09, label: FlexSPI_D1_A, identifier: FlexSPI_D1_A}
+- {pin_num: P4, pin_signal: GPIO_SD_B1_10, label: FlexSPI_D2_A, identifier: FlexSPI_D2_A}
+- {pin_num: P5, pin_signal: GPIO_SD_B1_11, label: FlexSPI_D3_A, identifier: FlexSPI_D3_A}
+- {pin_num: M8, pin_signal: USB_OTG1_DN, label: OTG1_DN, identifier: OTG1_DN}
+- {pin_num: L8, pin_signal: USB_OTG1_DP, label: OTG1_DP, identifier: OTG1_DP}
+- {pin_num: N7, pin_signal: USB_OTG2_DN, label: OTG2_DN, identifier: OTG2_DN}
+- {pin_num: P7, pin_signal: USB_OTG2_DP, label: OTG2_DP, identifier: OTG2_DP}
+- {pin_num: K8, pin_signal: VDD_USB_CAP, label: VDD_USB_3V}
+- {pin_num: N6, pin_signal: USB_OTG1_VBUS, label: 5V_USB_OTG}
+- {pin_num: P6, pin_signal: USB_OTG2_VBUS, label: 5V_USB_HS}
+- {pin_num: L12, pin_signal: GPIO_AD_B1_04, label: 'CSI_PIXCLK/J35[8]/J23[3]', identifier: CSI_PIXCLK}
+- {pin_num: K12, pin_signal: GPIO_AD_B1_05, label: 'CSI_MCLK/J35[12]/J23[4]', identifier: CSI_MCLK}
+- {pin_num: J12, pin_signal: GPIO_AD_B1_06, label: 'CSI_VSYNC/J35[18]/J22[2]/UART_TX', identifier: CSI_VSYNC}
+- {pin_num: K10, pin_signal: GPIO_AD_B1_07, label: 'CSI_HSYNC/J35[16]/J22[1]/UART_RX', identifier: CSI_HSYNC}
+- {pin_num: M7, pin_signal: POR_B, label: 'RST_TGTMCU_B/POR_B/J21[15]', identifier: RST_TGTMCU_B;POR_B}
+- {pin_num: N14, pin_signal: VDDA_ADC_3P3, label: VDDA_ADC_3P3_MCU}
+- {pin_num: P12, pin_signal: VDD_HIGH_IN, label: VDD_HIGH_IN_MCU}
+- {pin_num: M9, pin_signal: VDD_SNVS_IN, label: VDD_SNVS_IN}
+- {pin_num: F6, pin_signal: VDD_SOC_IN0, label: VDD_SOC_IN}
+- {pin_num: H6, pin_signal: VDD_SOC_IN2, label: VDD_SOC_IN}
+- {pin_num: G6, pin_signal: VDD_SOC_IN1, label: VDD_SOC_IN}
+- {pin_num: F7, pin_signal: VDD_SOC_IN3, label: VDD_SOC_IN}
+- {pin_num: F8, pin_signal: VDD_SOC_IN4, label: VDD_SOC_IN}
+- {pin_num: F9, pin_signal: VDD_SOC_IN5, label: VDD_SOC_IN}
+- {pin_num: G9, pin_signal: VDD_SOC_IN6, label: VDD_SOC_IN}
+- {pin_num: H9, pin_signal: VDD_SOC_IN7, label: VDD_SOC_IN}
+- {pin_num: J9, pin_signal: VDD_SOC_IN8, label: VDD_SOC_IN}
+- {pin_num: P1, pin_signal: VSS1, label: GND}
+- {pin_num: E2, pin_signal: VSS2, label: GND}
+- {pin_num: K2, pin_signal: VSS3, label: GND}
+- {pin_num: B5, pin_signal: VSS4, label: GND}
+- {pin_num: N5, pin_signal: VSS5, label: GND}
+- {pin_num: G7, pin_signal: VSS6, label: GND}
+- {pin_num: H7, pin_signal: VSS7, label: GND}
+- {pin_num: J7, pin_signal: VSS8, label: GND}
+- {pin_num: G8, pin_signal: VSS9, label: GND}
+- {pin_num: H8, pin_signal: VSS10, label: GND}
+- {pin_num: J8, pin_signal: VSS11, label: GND}
+- {pin_num: N8, pin_signal: VSS12, label: GND}
+- {pin_num: L9, pin_signal: VSS13, label: GND}
+- {pin_num: B10, pin_signal: VSS14, label: GND}
+- {pin_num: E13, pin_signal: VSS15, label: GND}
+- {pin_num: K13, pin_signal: VSS16, label: GND}
+- {pin_num: A14, pin_signal: VSS17, label: GND}
+- {pin_num: P14, pin_signal: VSS18, label: GND}
+- {pin_num: A1, pin_signal: VSS0, label: GND}
+- {pin_num: J6, pin_signal: NVCC_SD0, label: NVCC_SD, identifier: NVCC_SD}
+- {pin_num: K5, pin_signal: NVCC_SD1, label: FLASH_VCC, identifier: FLASH_VCC}
+- {pin_num: F5, pin_signal: NVCC_EMC0, label: DCDC_3V3}
+- {pin_num: E6, pin_signal: NVCC_EMC1, label: DCDC_3V3}
+- {pin_num: L6, pin_signal: WAKEUP, label: SD_PWREN, identifier: SD_PWREN}
+- {pin_num: L1, pin_signal: DCDC_IN0, label: MCU_DCDC_IN_3V3}
+- {pin_num: L2, pin_signal: DCDC_IN1, label: MCU_DCDC_IN_3V3}
+- {pin_num: K4, pin_signal: DCDC_IN_Q, label: MCU_DCDC_IN_3V3}
+- {pin_num: M1, pin_signal: DCDC_LP0, label: VDD_SOC_IN}
+- {pin_num: M2, pin_signal: DCDC_LP1, label: VDD_SOC_IN}
+- {pin_num: P11, pin_signal: XTALI, label: XTALI, identifier: XTALI}
+- {pin_num: N11, pin_signal: XTALO, label: XTALO, identifier: XTALO}
+- {pin_num: N9, pin_signal: RTC_XTALI, label: RTC_XTALI, identifier: RTC_XTALI}
+- {pin_num: P9, pin_signal: RTC_XTALO, label: RTC_XTALO, identifier: RTC_XTALO}
+- {pin_num: N1, pin_signal: DCDC_GND0, label: GND}
+- {pin_num: N2, pin_signal: DCDC_GND1, label: GND}
+- {pin_num: J5, pin_signal: DCDC_SENSE, label: VDD_SOC_IN}
+- {pin_num: K3, pin_signal: DCDC_PSWITCH, label: MCU_DCDC_IN_3V3}
+- {pin_num: K7, pin_signal: PMIC_ON_REQ, label: PMIC_ON_REQ, identifier: PMIC_ON_REQ}
+- {pin_num: L7, pin_signal: PMIC_STBY_REQ, label: PERI_PWREN, identifier: PERI_PWREN}
+- {pin_num: M6, pin_signal: ONOFF, label: ONOFF, identifier: ONOFF}
+- {pin_num: K6, pin_signal: TEST_MODE, label: GND}
+- {pin_num: P10, pin_signal: NVCC_PLL, label: VDDA_1P1_CAP}
+- {pin_num: P8, pin_signal: VDD_HIGH_CAP, label: VDDA_2P5_CAP}
+- {pin_num: K9, pin_signal: NGND_KEL0, label: GND}
+- {pin_num: M10, pin_signal: VDD_SNVS_CAP, label: GND}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+#include "fsl_common.h"
+#include "fsl_iomuxc.h"
+#include "pin_mux.h"
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitBootPins
+ * Description : Calls initialization functions.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitBootPins(void) {
+ BOARD_InitPins();
+ BOARD_InitDEBUG_UARTPins();
+}
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitPins:
+- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'}
+- pin_list: []
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitPins(void) {
+}
+
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitDEBUG_UARTPins:
+- options: {callFromInitBoot: 'true', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: K14, peripheral: LPUART1, signal: TX, pin_signal: GPIO_AD_B0_12, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Down_100K_Ohm,
+ pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow}
+ - {pin_num: L14, peripheral: LPUART1, signal: RX, pin_signal: GPIO_AD_B0_13, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Down_100K_Ohm,
+ pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Disable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitDEBUG_UARTPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitDEBUG_UARTPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 is configured as LPUART1_TX */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 is configured as LPUART1_RX */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 PAD functional properties : */
+ 0x10B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Keeper
+ Pull Up / Down Config. Field: 100K Ohm Pull Down
+ Hyst. Enable Field: Hysteresis Disabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 PAD functional properties : */
+ 0x10B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Keeper
+ Pull Up / Down Config. Field: 100K Ohm Pull Down
+ Hyst. Enable Field: Hysteresis Disabled */
+}
+
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitSDRAMPins:
+- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: C2, peripheral: SEMC, signal: 'ADDR, 00', pin_signal: GPIO_EMC_09}
+ - {pin_num: G1, peripheral: SEMC, signal: 'ADDR, 01', pin_signal: GPIO_EMC_10}
+ - {pin_num: G3, peripheral: SEMC, signal: 'ADDR, 02', pin_signal: GPIO_EMC_11}
+ - {pin_num: H1, peripheral: SEMC, signal: 'ADDR, 03', pin_signal: GPIO_EMC_12}
+ - {pin_num: A6, peripheral: SEMC, signal: 'ADDR, 04', pin_signal: GPIO_EMC_13}
+ - {pin_num: B6, peripheral: SEMC, signal: 'ADDR, 05', pin_signal: GPIO_EMC_14}
+ - {pin_num: B1, peripheral: SEMC, signal: 'ADDR, 06', pin_signal: GPIO_EMC_15}
+ - {pin_num: A5, peripheral: SEMC, signal: 'ADDR, 07', pin_signal: GPIO_EMC_16}
+ - {pin_num: A4, peripheral: SEMC, signal: 'ADDR, 08', pin_signal: GPIO_EMC_17}
+ - {pin_num: B2, peripheral: SEMC, signal: 'ADDR, 09', pin_signal: GPIO_EMC_18}
+ - {pin_num: G2, peripheral: SEMC, signal: 'ADDR, 10', pin_signal: GPIO_EMC_23}
+ - {pin_num: B4, peripheral: SEMC, signal: 'ADDR, 11', pin_signal: GPIO_EMC_19}
+ - {pin_num: A3, peripheral: SEMC, signal: 'ADDR, 12', pin_signal: GPIO_EMC_20}
+ - {pin_num: C1, peripheral: SEMC, signal: 'BA, 0', pin_signal: GPIO_EMC_21}
+ - {pin_num: F1, peripheral: SEMC, signal: 'BA, 1', pin_signal: GPIO_EMC_22}
+ - {pin_num: D3, peripheral: SEMC, signal: semc_cas, pin_signal: GPIO_EMC_24}
+ - {pin_num: A2, peripheral: SEMC, signal: semc_cke, pin_signal: GPIO_EMC_27}
+ - {pin_num: B3, peripheral: SEMC, signal: semc_clk, pin_signal: GPIO_EMC_26}
+ - {pin_num: E3, peripheral: SEMC, signal: 'DATA, 00', pin_signal: GPIO_EMC_00}
+ - {pin_num: F3, peripheral: SEMC, signal: 'DATA, 01', pin_signal: GPIO_EMC_01}
+ - {pin_num: F4, peripheral: SEMC, signal: 'DATA, 02', pin_signal: GPIO_EMC_02}
+ - {pin_num: G4, peripheral: SEMC, signal: 'DATA, 03', pin_signal: GPIO_EMC_03}
+ - {pin_num: F2, peripheral: SEMC, signal: 'DATA, 04', pin_signal: GPIO_EMC_04}
+ - {pin_num: G5, peripheral: SEMC, signal: 'DATA, 05', pin_signal: GPIO_EMC_05}
+ - {pin_num: H5, peripheral: SEMC, signal: 'DATA, 06', pin_signal: GPIO_EMC_06}
+ - {pin_num: H4, peripheral: SEMC, signal: 'DATA, 07', pin_signal: GPIO_EMC_07}
+ - {pin_num: C6, peripheral: SEMC, signal: 'DATA, 08', pin_signal: GPIO_EMC_30}
+ - {pin_num: C5, peripheral: SEMC, signal: 'DATA, 09', pin_signal: GPIO_EMC_31}
+ - {pin_num: D5, peripheral: SEMC, signal: 'DATA, 10', pin_signal: GPIO_EMC_32}
+ - {pin_num: C4, peripheral: SEMC, signal: 'DATA, 11', pin_signal: GPIO_EMC_33}
+ - {pin_num: D4, peripheral: SEMC, signal: 'DATA, 12', pin_signal: GPIO_EMC_34}
+ - {pin_num: E5, peripheral: SEMC, signal: 'DATA, 13', pin_signal: GPIO_EMC_35}
+ - {pin_num: C3, peripheral: SEMC, signal: 'DATA, 14', pin_signal: GPIO_EMC_36}
+ - {pin_num: E4, peripheral: SEMC, signal: 'DATA, 15', pin_signal: GPIO_EMC_37}
+ - {pin_num: H3, peripheral: SEMC, signal: 'DM, 0', pin_signal: GPIO_EMC_08}
+ - {pin_num: D6, peripheral: SEMC, signal: 'DM, 1', pin_signal: GPIO_EMC_38}
+ - {pin_num: D2, peripheral: SEMC, signal: semc_ras, pin_signal: GPIO_EMC_25}
+ - {pin_num: D1, peripheral: SEMC, signal: semc_we, pin_signal: GPIO_EMC_28}
+ - {pin_num: C7, peripheral: SEMC, signal: 'CSX, 0', pin_signal: GPIO_EMC_41}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitSDRAMPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitSDRAMPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_00_SEMC_DATA00, /* GPIO_EMC_00 is configured as SEMC_DATA00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_01_SEMC_DATA01, /* GPIO_EMC_01 is configured as SEMC_DATA01 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_02_SEMC_DATA02, /* GPIO_EMC_02 is configured as SEMC_DATA02 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_03_SEMC_DATA03, /* GPIO_EMC_03 is configured as SEMC_DATA03 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_04_SEMC_DATA04, /* GPIO_EMC_04 is configured as SEMC_DATA04 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_05_SEMC_DATA05, /* GPIO_EMC_05 is configured as SEMC_DATA05 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_06_SEMC_DATA06, /* GPIO_EMC_06 is configured as SEMC_DATA06 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_07_SEMC_DATA07, /* GPIO_EMC_07 is configured as SEMC_DATA07 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_08_SEMC_DM00, /* GPIO_EMC_08 is configured as SEMC_DM00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_09_SEMC_ADDR00, /* GPIO_EMC_09 is configured as SEMC_ADDR00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_10_SEMC_ADDR01, /* GPIO_EMC_10 is configured as SEMC_ADDR01 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_11_SEMC_ADDR02, /* GPIO_EMC_11 is configured as SEMC_ADDR02 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_12_SEMC_ADDR03, /* GPIO_EMC_12 is configured as SEMC_ADDR03 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_13_SEMC_ADDR04, /* GPIO_EMC_13 is configured as SEMC_ADDR04 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_14_SEMC_ADDR05, /* GPIO_EMC_14 is configured as SEMC_ADDR05 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_15_SEMC_ADDR06, /* GPIO_EMC_15 is configured as SEMC_ADDR06 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_16_SEMC_ADDR07, /* GPIO_EMC_16 is configured as SEMC_ADDR07 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_17_SEMC_ADDR08, /* GPIO_EMC_17 is configured as SEMC_ADDR08 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_18_SEMC_ADDR09, /* GPIO_EMC_18 is configured as SEMC_ADDR09 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_19_SEMC_ADDR11, /* GPIO_EMC_19 is configured as SEMC_ADDR11 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_20_SEMC_ADDR12, /* GPIO_EMC_20 is configured as SEMC_ADDR12 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_21_SEMC_BA0, /* GPIO_EMC_21 is configured as SEMC_BA0 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_22_SEMC_BA1, /* GPIO_EMC_22 is configured as SEMC_BA1 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_23_SEMC_ADDR10, /* GPIO_EMC_23 is configured as SEMC_ADDR10 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_24_SEMC_CAS, /* GPIO_EMC_24 is configured as SEMC_CAS */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_25_SEMC_RAS, /* GPIO_EMC_25 is configured as SEMC_RAS */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_26_SEMC_CLK, /* GPIO_EMC_26 is configured as SEMC_CLK */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_27_SEMC_CKE, /* GPIO_EMC_27 is configured as SEMC_CKE */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_28_SEMC_WE, /* GPIO_EMC_28 is configured as SEMC_WE */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_30_SEMC_DATA08, /* GPIO_EMC_30 is configured as SEMC_DATA08 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_31_SEMC_DATA09, /* GPIO_EMC_31 is configured as SEMC_DATA09 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_32_SEMC_DATA10, /* GPIO_EMC_32 is configured as SEMC_DATA10 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_33_SEMC_DATA11, /* GPIO_EMC_33 is configured as SEMC_DATA11 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_34_SEMC_DATA12, /* GPIO_EMC_34 is configured as SEMC_DATA12 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_35_SEMC_DATA13, /* GPIO_EMC_35 is configured as SEMC_DATA13 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_36_SEMC_DATA14, /* GPIO_EMC_36 is configured as SEMC_DATA14 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_37_SEMC_DATA15, /* GPIO_EMC_37 is configured as SEMC_DATA15 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_38_SEMC_DM01, /* GPIO_EMC_38 is configured as SEMC_DM01 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_41_SEMC_CSX00, /* GPIO_EMC_41 is configured as SEMC_CSX00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+}
+
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitCSIPins:
+- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: H13, peripheral: CSI, signal: 'csi_data, 09', pin_signal: GPIO_AD_B1_08}
+ - {pin_num: M13, peripheral: CSI, signal: 'csi_data, 08', pin_signal: GPIO_AD_B1_09}
+ - {pin_num: L13, peripheral: CSI, signal: 'csi_data, 07', pin_signal: GPIO_AD_B1_10}
+ - {pin_num: J13, peripheral: CSI, signal: 'csi_data, 06', pin_signal: GPIO_AD_B1_11}
+ - {pin_num: H12, peripheral: CSI, signal: 'csi_data, 05', pin_signal: GPIO_AD_B1_12}
+ - {pin_num: H11, peripheral: CSI, signal: 'csi_data, 04', pin_signal: GPIO_AD_B1_13}
+ - {pin_num: J14, peripheral: CSI, signal: 'csi_data, 02', pin_signal: GPIO_AD_B1_15}
+ - {pin_num: G12, peripheral: CSI, signal: 'csi_data, 03', pin_signal: GPIO_AD_B1_14}
+ - {pin_num: L12, peripheral: CSI, signal: csi_pixclk, pin_signal: GPIO_AD_B1_04}
+ - {pin_num: K12, peripheral: CSI, signal: csi_mclk, pin_signal: GPIO_AD_B1_05}
+ - {pin_num: J12, peripheral: CSI, signal: csi_vsync, pin_signal: GPIO_AD_B1_06}
+ - {pin_num: K10, peripheral: CSI, signal: csi_hsync, pin_signal: GPIO_AD_B1_07}
+ - {pin_num: J11, peripheral: LPI2C1, signal: SCL, pin_signal: GPIO_AD_B1_00, identifier: CSI_I2C_SCL, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_22K_Ohm,
+ pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Enable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow}
+ - {pin_num: K11, peripheral: LPI2C1, signal: SDA, pin_signal: GPIO_AD_B1_01, identifier: CSI_I2C_SDA, software_input_on: Disable, hysteresis_enable: Disable, pull_up_down_config: Pull_Up_22K_Ohm,
+ pull_keeper_select: Keeper, pull_keeper_enable: Enable, open_drain: Enable, speed: MHZ_100, drive_strength: R0_6, slew_rate: Slow}
+ - {pin_num: F11, peripheral: GPIO1, signal: 'gpio_io, 04', pin_signal: GPIO_AD_B0_04}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitCSIPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitCSIPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B0_04_GPIO1_IO04, /* GPIO_AD_B0_04 is configured as GPIO1_IO04 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, /* GPIO_AD_B1_00 is configured as LPI2C1_SCL */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, /* GPIO_AD_B1_01 is configured as LPI2C1_SDA */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_04_CSI_PIXCLK, /* GPIO_AD_B1_04 is configured as CSI_PIXCLK */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_05_CSI_MCLK, /* GPIO_AD_B1_05 is configured as CSI_MCLK */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_06_CSI_VSYNC, /* GPIO_AD_B1_06 is configured as CSI_VSYNC */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_07_CSI_HSYNC, /* GPIO_AD_B1_07 is configured as CSI_HSYNC */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_08_CSI_DATA09, /* GPIO_AD_B1_08 is configured as CSI_DATA09 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_09_CSI_DATA08, /* GPIO_AD_B1_09 is configured as CSI_DATA08 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_10_CSI_DATA07, /* GPIO_AD_B1_10 is configured as CSI_DATA07 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_11_CSI_DATA06, /* GPIO_AD_B1_11 is configured as CSI_DATA06 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_12_CSI_DATA05, /* GPIO_AD_B1_12 is configured as CSI_DATA05 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_13_CSI_DATA04, /* GPIO_AD_B1_13 is configured as CSI_DATA04 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_14_CSI_DATA03, /* GPIO_AD_B1_14 is configured as CSI_DATA03 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B1_15_CSI_DATA02, /* GPIO_AD_B1_15 is configured as CSI_DATA02 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, /* GPIO_AD_B1_00 PAD functional properties : */
+ 0xD8B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Enabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Keeper
+ Pull Up / Down Config. Field: 22K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Disabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, /* GPIO_AD_B1_01 PAD functional properties : */
+ 0xD8B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Enabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Keeper
+ Pull Up / Down Config. Field: 22K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Disabled */
+}
+
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitLCDPins:
+- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: C8, peripheral: LCDIF, signal: 'lcdif_data, 00', pin_signal: GPIO_B0_04, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: B8, peripheral: LCDIF, signal: 'lcdif_data, 01', pin_signal: GPIO_B0_05, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: A8, peripheral: LCDIF, signal: 'lcdif_data, 02', pin_signal: GPIO_B0_06, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: D7, peripheral: LCDIF, signal: lcdif_clk, pin_signal: GPIO_B0_00, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: A9, peripheral: LCDIF, signal: 'lcdif_data, 03', pin_signal: GPIO_B0_07, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: B9, peripheral: LCDIF, signal: 'lcdif_data, 04', pin_signal: GPIO_B0_08, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: C9, peripheral: LCDIF, signal: 'lcdif_data, 05', pin_signal: GPIO_B0_09, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: D9, peripheral: LCDIF, signal: 'lcdif_data, 06', pin_signal: GPIO_B0_10, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: A10, peripheral: LCDIF, signal: 'lcdif_data, 07', pin_signal: GPIO_B0_11, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: C10, peripheral: LCDIF, signal: 'lcdif_data, 08', pin_signal: GPIO_B0_12, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: D10, peripheral: LCDIF, signal: 'lcdif_data, 09', pin_signal: GPIO_B0_13, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: E10, peripheral: LCDIF, signal: 'lcdif_data, 10', pin_signal: GPIO_B0_14, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: E11, peripheral: LCDIF, signal: 'lcdif_data, 11', pin_signal: GPIO_B0_15, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: A11, peripheral: LCDIF, signal: 'lcdif_data, 12', pin_signal: GPIO_B1_00, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: B11, peripheral: LCDIF, signal: 'lcdif_data, 13', pin_signal: GPIO_B1_01, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: C11, peripheral: LCDIF, signal: 'lcdif_data, 14', pin_signal: GPIO_B1_02, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: D11, peripheral: LCDIF, signal: 'lcdif_data, 15', pin_signal: GPIO_B1_03, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: E7, peripheral: LCDIF, signal: lcdif_enable, pin_signal: GPIO_B0_01, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: E8, peripheral: LCDIF, signal: lcdif_hsync, pin_signal: GPIO_B0_02, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: D8, peripheral: LCDIF, signal: lcdif_vsync, pin_signal: GPIO_B0_03, hysteresis_enable: Enable, pull_up_down_config: Pull_Up_100K_Ohm, pull_keeper_select: Pull}
+ - {pin_num: B14, peripheral: GPIO2, signal: 'gpio_io, 31', pin_signal: GPIO_B1_15, slew_rate: Slow}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitLCDPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitLCDPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_00_LCD_CLK, /* GPIO_B0_00 is configured as LCD_CLK */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_01_LCD_ENABLE, /* GPIO_B0_01 is configured as LCD_ENABLE */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_02_LCD_HSYNC, /* GPIO_B0_02 is configured as LCD_HSYNC */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_03_LCD_VSYNC, /* GPIO_B0_03 is configured as LCD_VSYNC */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_04_LCD_DATA00, /* GPIO_B0_04 is configured as LCD_DATA00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_05_LCD_DATA01, /* GPIO_B0_05 is configured as LCD_DATA01 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_06_LCD_DATA02, /* GPIO_B0_06 is configured as LCD_DATA02 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_07_LCD_DATA03, /* GPIO_B0_07 is configured as LCD_DATA03 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_08_LCD_DATA04, /* GPIO_B0_08 is configured as LCD_DATA04 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_09_LCD_DATA05, /* GPIO_B0_09 is configured as LCD_DATA05 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_10_LCD_DATA06, /* GPIO_B0_10 is configured as LCD_DATA06 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_11_LCD_DATA07, /* GPIO_B0_11 is configured as LCD_DATA07 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_12_LCD_DATA08, /* GPIO_B0_12 is configured as LCD_DATA08 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_13_LCD_DATA09, /* GPIO_B0_13 is configured as LCD_DATA09 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_14_LCD_DATA10, /* GPIO_B0_14 is configured as LCD_DATA10 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B0_15_LCD_DATA11, /* GPIO_B0_15 is configured as LCD_DATA11 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_00_LCD_DATA12, /* GPIO_B1_00 is configured as LCD_DATA12 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_01_LCD_DATA13, /* GPIO_B1_01 is configured as LCD_DATA13 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_02_LCD_DATA14, /* GPIO_B1_02 is configured as LCD_DATA14 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_03_LCD_DATA15, /* GPIO_B1_03 is configured as LCD_DATA15 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_15_GPIO2_IO31, /* GPIO_B1_15 is configured as GPIO2_IO31 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_00_LCD_CLK, /* GPIO_B0_00 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_01_LCD_ENABLE, /* GPIO_B0_01 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_02_LCD_HSYNC, /* GPIO_B0_02 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_03_LCD_VSYNC, /* GPIO_B0_03 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_04_LCD_DATA00, /* GPIO_B0_04 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_05_LCD_DATA01, /* GPIO_B0_05 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_06_LCD_DATA02, /* GPIO_B0_06 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_07_LCD_DATA03, /* GPIO_B0_07 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_08_LCD_DATA04, /* GPIO_B0_08 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_09_LCD_DATA05, /* GPIO_B0_09 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_10_LCD_DATA06, /* GPIO_B0_10 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_11_LCD_DATA07, /* GPIO_B0_11 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_12_LCD_DATA08, /* GPIO_B0_12 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_13_LCD_DATA09, /* GPIO_B0_13 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_14_LCD_DATA10, /* GPIO_B0_14 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B0_15_LCD_DATA11, /* GPIO_B0_15 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B1_00_LCD_DATA12, /* GPIO_B1_00 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B1_01_LCD_DATA13, /* GPIO_B1_01 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B1_02_LCD_DATA14, /* GPIO_B1_02 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B1_03_LCD_DATA15, /* GPIO_B1_03 PAD functional properties : */
+ 0x01B0B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Pull
+ Pull Up / Down Config. Field: 100K Ohm Pull Up
+ Hyst. Enable Field: Hysteresis Enabled */
+ IOMUXC_SetPinConfig(
+ IOMUXC_GPIO_B1_15_GPIO2_IO31, /* GPIO_B1_15 PAD functional properties : */
+ 0x10B0u); /* Slew Rate Field: Slow Slew Rate
+ Drive Strength Field: R0/6
+ Speed Field: medium(100MHz)
+ Open Drain Enable Field: Open Drain Disabled
+ Pull / Keep Enable Field: Pull/Keeper Enabled
+ Pull / Keep Select Field: Keeper
+ Pull Up / Down Config. Field: 100K Ohm Pull Down
+ Hyst. Enable Field: Hysteresis Disabled */
+}
+
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitCANPins:
+- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: H14, peripheral: CAN2, signal: TX, pin_signal: GPIO_AD_B0_14}
+ - {pin_num: L10, peripheral: CAN2, signal: RX, pin_signal: GPIO_AD_B0_15}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitCANPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitCANPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B0_14_FLEXCAN2_TX, /* GPIO_AD_B0_14 is configured as FLEXCAN2_TX */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_AD_B0_15_FLEXCAN2_RX, /* GPIO_AD_B0_15 is configured as FLEXCAN2_RX */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+}
+
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitENETPins:
+- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: A7, peripheral: ENET, signal: enet_mdc, pin_signal: GPIO_EMC_40}
+ - {pin_num: C7, peripheral: ENET, signal: enet_mdio, pin_signal: GPIO_EMC_41}
+ - {pin_num: B13, peripheral: ENET, signal: enet_ref_clk, pin_signal: GPIO_B1_10}
+ - {pin_num: E12, peripheral: ENET, signal: 'enet_rx_data, 0', pin_signal: GPIO_B1_04}
+ - {pin_num: D12, peripheral: ENET, signal: 'enet_rx_data, 1', pin_signal: GPIO_B1_05}
+ - {pin_num: C12, peripheral: ENET, signal: enet_rx_en, pin_signal: GPIO_B1_06}
+ - {pin_num: C13, peripheral: ENET, signal: enet_rx_er, pin_signal: GPIO_B1_11}
+ - {pin_num: B12, peripheral: ENET, signal: 'enet_tx_data, 0', pin_signal: GPIO_B1_07}
+ - {pin_num: A12, peripheral: ENET, signal: 'enet_tx_data, 1', pin_signal: GPIO_B1_08}
+ - {pin_num: A13, peripheral: ENET, signal: enet_tx_en, pin_signal: GPIO_B1_09}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitENETPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitENETPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_04_ENET_RX_DATA00, /* GPIO_B1_04 is configured as ENET_RX_DATA00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_05_ENET_RX_DATA01, /* GPIO_B1_05 is configured as ENET_RX_DATA01 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_06_ENET_RX_EN, /* GPIO_B1_06 is configured as ENET_RX_EN */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_07_ENET_TX_DATA00, /* GPIO_B1_07 is configured as ENET_TX_DATA00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_08_ENET_TX_DATA01, /* GPIO_B1_08 is configured as ENET_TX_DATA01 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_09_ENET_TX_EN, /* GPIO_B1_09 is configured as ENET_TX_EN */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_10_ENET_REF_CLK, /* GPIO_B1_10 is configured as ENET_REF_CLK */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_B1_11_ENET_RX_ER, /* GPIO_B1_11 is configured as ENET_RX_ER */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_40_ENET_MDC, /* GPIO_EMC_40 is configured as ENET_MDC */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_EMC_41_ENET_MDIO, /* GPIO_EMC_41 is configured as ENET_MDIO */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+}
+
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitUSDHCPins:
+- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: J2, peripheral: USDHC1, signal: 'usdhc_data, 3', pin_signal: GPIO_SD_B0_05}
+ - {pin_num: H2, peripheral: USDHC1, signal: 'usdhc_data, 2', pin_signal: GPIO_SD_B0_04}
+ - {pin_num: K1, peripheral: USDHC1, signal: 'usdhc_data, 1', pin_signal: GPIO_SD_B0_03}
+ - {pin_num: J1, peripheral: USDHC1, signal: 'usdhc_data, 0', pin_signal: GPIO_SD_B0_02}
+ - {pin_num: J4, peripheral: USDHC1, signal: usdhc_cmd, pin_signal: GPIO_SD_B0_00}
+ - {pin_num: J3, peripheral: USDHC1, signal: usdhc_clk, pin_signal: GPIO_SD_B0_01}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitUSDHCPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitUSDHCPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B0_00_USDHC1_CMD, /* GPIO_SD_B0_00 is configured as USDHC1_CMD */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B0_01_USDHC1_CLK, /* GPIO_SD_B0_01 is configured as USDHC1_CLK */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B0_02_USDHC1_DATA0, /* GPIO_SD_B0_02 is configured as USDHC1_DATA0 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B0_03_USDHC1_DATA1, /* GPIO_SD_B0_03 is configured as USDHC1_DATA1 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B0_04_USDHC1_DATA2, /* GPIO_SD_B0_04 is configured as USDHC1_DATA2 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B0_05_USDHC1_DATA3, /* GPIO_SD_B0_05 is configured as USDHC1_DATA3 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+}
+
+
+/*
+ * TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
+BOARD_InitHyperFlashPins:
+- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'}
+- pin_list:
+ - {pin_num: L4, peripheral: FLEXSPI, signal: FLEXSPI_A_SCLK, pin_signal: GPIO_SD_B1_07}
+ - {pin_num: P4, peripheral: FLEXSPI, signal: FLEXSPI_A_DATA2, pin_signal: GPIO_SD_B1_10}
+ - {pin_num: P3, peripheral: FLEXSPI, signal: FLEXSPI_A_DATA0, pin_signal: GPIO_SD_B1_08}
+ - {pin_num: N4, peripheral: FLEXSPI, signal: FLEXSPI_A_DATA1, pin_signal: GPIO_SD_B1_09}
+ - {pin_num: L5, peripheral: FLEXSPI, signal: FLEXSPI_B_DATA3, pin_signal: GPIO_SD_B1_00}
+ - {pin_num: M5, peripheral: FLEXSPI, signal: FLEXSPI_B_DATA2, pin_signal: GPIO_SD_B1_01}
+ - {pin_num: M3, peripheral: FLEXSPI, signal: FLEXSPI_B_DATA1, pin_signal: GPIO_SD_B1_02}
+ - {pin_num: M4, peripheral: FLEXSPI, signal: FLEXSPI_B_DATA0, pin_signal: GPIO_SD_B1_03}
+ - {pin_num: P2, peripheral: FLEXSPI, signal: FLEXSPI_B_SCLK, pin_signal: GPIO_SD_B1_04}
+ - {pin_num: L3, peripheral: FLEXSPI, signal: FLEXSPI_A_SS0_B, pin_signal: GPIO_SD_B1_06}
+ - {pin_num: P5, peripheral: FLEXSPI, signal: FLEXSPI_A_DATA3, pin_signal: GPIO_SD_B1_11}
+ - {pin_num: N3, peripheral: FLEXSPI, signal: FLEXSPI_A_DQS, pin_signal: GPIO_SD_B1_05}
+ * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS ***********
+ */
+
+/* FUNCTION ************************************************************************************************************
+ *
+ * Function Name : BOARD_InitHyperFlashPins
+ * Description : Configures pin routing and optionally pin electrical features.
+ *
+ * END ****************************************************************************************************************/
+void BOARD_InitHyperFlashPins(void) {
+ CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03u */
+
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_00_FLEXSPIB_DATA03, /* GPIO_SD_B1_00 is configured as FLEXSPIB_DATA03 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_01_FLEXSPIB_DATA02, /* GPIO_SD_B1_01 is configured as FLEXSPIB_DATA02 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_02_FLEXSPIB_DATA01, /* GPIO_SD_B1_02 is configured as FLEXSPIB_DATA01 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_03_FLEXSPIB_DATA00, /* GPIO_SD_B1_03 is configured as FLEXSPIB_DATA00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_04_FLEXSPIB_SCLK, /* GPIO_SD_B1_04 is configured as FLEXSPIB_SCLK */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_05_FLEXSPIA_DQS, /* GPIO_SD_B1_05 is configured as FLEXSPIA_DQS */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_06_FLEXSPIA_SS0_B, /* GPIO_SD_B1_06 is configured as FLEXSPIA_SS0_B */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_07_FLEXSPIA_SCLK, /* GPIO_SD_B1_07 is configured as FLEXSPIA_SCLK */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_08_FLEXSPIA_DATA00, /* GPIO_SD_B1_08 is configured as FLEXSPIA_DATA00 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_09_FLEXSPIA_DATA01, /* GPIO_SD_B1_09 is configured as FLEXSPIA_DATA01 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_10_FLEXSPIA_DATA02, /* GPIO_SD_B1_10 is configured as FLEXSPIA_DATA02 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+ IOMUXC_SetPinMux(
+ IOMUXC_GPIO_SD_B1_11_FLEXSPIA_DATA03, /* GPIO_SD_B1_11 is configured as FLEXSPIA_DATA03 */
+ 0U); /* Software Input On Field: Input Path is determined by functionality */
+}
+
+/***********************************************************************************************************************
+ * EOF
+ **********************************************************************************************************************/
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc.c
new file mode 100644
index 0000000000..d93de620c0
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_adc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.adc_12b1msps_sar"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for ADC module.
+ *
+ * @param base ADC peripheral base address
+ */
+static uint32_t ADC_GetInstance(ADC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to ADC bases for each instance. */
+static ADC_Type *const s_adcBases[] = ADC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to ADC clocks for each instance. */
+static const clock_ip_name_t s_adcClocks[] = ADC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t ADC_GetInstance(ADC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_adcBases); instance++)
+ {
+ if (s_adcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_adcBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initialize the ADC module.
+ *
+ * param base ADC peripheral base address.
+ * param config Pointer to "adc_config_t" structure.
+ */
+void ADC_Init(ADC_Type *base, const adc_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_adcClocks[ADC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /* ADCx_CFG */
+ tmp32 = base->CFG & (ADC_CFG_AVGS_MASK | ADC_CFG_ADTRG_MASK); /* Reserve AVGS and ADTRG bits. */
+ tmp32 |= ADC_CFG_REFSEL(config->referenceVoltageSource) | ADC_CFG_ADSTS(config->samplePeriodMode) |
+ ADC_CFG_ADICLK(config->clockSource) | ADC_CFG_ADIV(config->clockDriver) | ADC_CFG_MODE(config->resolution);
+ if (config->enableOverWrite)
+ {
+ tmp32 |= ADC_CFG_OVWREN_MASK;
+ }
+ if (config->enableLongSample)
+ {
+ tmp32 |= ADC_CFG_ADLSMP_MASK;
+ }
+ if (config->enableLowPower)
+ {
+ tmp32 |= ADC_CFG_ADLPC_MASK;
+ }
+ if (config->enableHighSpeed)
+ {
+ tmp32 |= ADC_CFG_ADHSC_MASK;
+ }
+ base->CFG = tmp32;
+
+ /* ADCx_GC */
+ tmp32 = base->GC & ~(ADC_GC_ADCO_MASK | ADC_GC_ADACKEN_MASK);
+ if (config->enableContinuousConversion)
+ {
+ tmp32 |= ADC_GC_ADCO_MASK;
+ }
+ if (config->enableAsynchronousClockOutput)
+ {
+ tmp32 |= ADC_GC_ADACKEN_MASK;
+ }
+ base->GC = tmp32;
+}
+
+/*!
+ * brief De-initializes the ADC module.
+ *
+ * param base ADC peripheral base address.
+ */
+void ADC_Deinit(ADC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_adcClocks[ADC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets an available pre-defined settings for the converter's configuration.
+ *
+ * This function initializes the converter configuration structure with available settings. The default values are:
+ * code
+ * config->enableAsynchronousClockOutput = true;
+ * config->enableOverWrite = false;
+ * config->enableContinuousConversion = false;
+ * config->enableHighSpeed = false;
+ * config->enableLowPower = false;
+ * config->enableLongSample = false;
+ * config->referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0;
+ * config->samplePeriodMode = kADC_SamplePeriod2or12Clocks;
+ * config->clockSource = kADC_ClockSourceAD;
+ * config->clockDriver = kADC_ClockDriver1;
+ * config->resolution = kADC_Resolution12Bit;
+ * endcode
+ * param base ADC peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void ADC_GetDefaultConfig(adc_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableAsynchronousClockOutput = true;
+ config->enableOverWrite = false;
+ config->enableContinuousConversion = false;
+ config->enableHighSpeed = false;
+ config->enableLowPower = false;
+ config->enableLongSample = false;
+ config->referenceVoltageSource = kADC_ReferenceVoltageSourceAlt0;
+ config->samplePeriodMode = kADC_SamplePeriod2or12Clocks;
+ config->clockSource = kADC_ClockSourceAD;
+ config->clockDriver = kADC_ClockDriver1;
+ config->resolution = kADC_Resolution12Bit;
+}
+
+/*!
+ * brief Configures the conversion channel.
+ *
+ * This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API
+ * configures the channel while the external trigger source helps to trigger the conversion.
+ *
+ * Note that the "Channel Group" has a detailed description.
+ * To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one
+ * group of status and control registers, one for each conversion. The channel group parameter indicates which group of
+ * registers are used, for example channel group 0 is for Group A registers and channel group 1 is for Group B
+ * registers. The
+ * channel groups are used in a "ping-pong" approach to control the ADC operation. At any point, only one of
+ * the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and
+ * hardware
+ * trigger modes. Channel groups 1 and greater indicate potentially multiple channel group registers for
+ * use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual
+ * about the
+ * number of SC1n registers (channel groups) specific to this device. None of the channel groups 1 or greater are used
+ * for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion.
+ * Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and
+ * vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a
+ * conversion aborts the current conversion.
+ *
+ * param base ADC peripheral base address.
+ * param channelGroup Channel group index.
+ * param config Pointer to the "adc_channel_config_t" structure for the conversion channel.
+ */
+void ADC_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc_channel_config_t *config)
+{
+ assert(NULL != config);
+ assert(channelGroup < FSL_FEATURE_ADC_CONVERSION_CONTROL_COUNT);
+
+ uint32_t tmp32;
+
+ tmp32 = ADC_HC_ADCH(config->channelNumber);
+ if (config->enableInterruptOnConversionCompleted)
+ {
+ tmp32 |= ADC_HC_AIEN_MASK;
+ }
+ base->HC[channelGroup] = tmp32;
+}
+
+/*
+ *To complete calibration, the user must follow the below procedure:
+ * 1. Configure ADC_CFG with actual operating values for maximum accuracy.
+ * 2. Configure the ADC_GC values along with CAL bit.
+ * 3. Check the status of CALF bit in ADC_GS and the CAL bit in ADC_GC.
+ * 4. When CAL bit becomes '0' then check the CALF status and COCO[0] bit status.
+ */
+/*!
+ * brief Automates the hardware calibration.
+ *
+ * This auto calibration helps to adjust the plus/minus side gain automatically.
+ * Execute the calibration before using the converter. Note that the software trigger should be used
+ * during calibration.
+ *
+ * param base ADC peripheral base address.
+ *
+ * return Execution status.
+ * retval kStatus_Success Calibration is done successfully.
+ * retval kStatus_Fail Calibration has failed.
+ */
+status_t ADC_DoAutoCalibration(ADC_Type *base)
+{
+ status_t status = kStatus_Success;
+#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
+ bool bHWTrigger = false;
+
+ /* The calibration would be failed when in hardwar mode.
+ * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/
+ if (0U != (ADC_CFG_ADTRG_MASK & base->CFG))
+ {
+ bHWTrigger = true;
+ ADC_EnableHardwareTrigger(base, false);
+ }
+#endif
+
+ /* Clear the CALF and launch the calibration. */
+ base->GS = ADC_GS_CALF_MASK; /* Clear the CALF. */
+ base->GC |= ADC_GC_CAL_MASK; /* Launch the calibration. */
+
+ /* Check the status of CALF bit in ADC_GS and the CAL bit in ADC_GC. */
+ while (0U != (base->GC & ADC_GC_CAL_MASK))
+ {
+ /* Check the CALF when the calibration is active. */
+ if (0U != (ADC_GetStatusFlags(base) & (uint32_t)kADC_CalibrationFailedFlag))
+ {
+ status = kStatus_Fail;
+ break;
+ }
+ }
+
+ /* When CAL bit becomes '0' then check the CALF status and COCO[0] bit status. */
+ if (0U == ADC_GetChannelStatusFlags(base, 0U)) /* Check the COCO[0] bit status. */
+ {
+ status = kStatus_Fail;
+ }
+ if (0U != (ADC_GetStatusFlags(base) & (uint32_t)kADC_CalibrationFailedFlag)) /* Check the CALF status. */
+ {
+ status = kStatus_Fail;
+ }
+
+ /* Clear conversion done flag. */
+ (void)ADC_GetChannelConversionValue(base, 0U);
+
+#if !(defined(FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE) && FSL_FEATURE_ADC_SUPPORT_HARDWARE_TRIGGER_REMOVE)
+ /* Restore original trigger mode. */
+ if (true == bHWTrigger)
+ {
+ ADC_EnableHardwareTrigger(base, true);
+ }
+#endif
+
+ return status;
+}
+
+/*!
+ * brief Set user defined offset.
+ *
+ * param base ADC peripheral base address.
+ * param config Pointer to "adc_offest_config_t" structure.
+ */
+void ADC_SetOffsetConfig(ADC_Type *base, const adc_offest_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+ tmp32 = ADC_OFS_OFS(config->offsetValue);
+ if (config->enableSigned)
+ {
+ tmp32 |= ADC_OFS_SIGN_MASK;
+ }
+ base->OFS = tmp32;
+}
+
+/*!
+ * brief Configures the hardware compare mode.
+ *
+ * The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the
+ * result
+ * in the compare range is available. To compare the range, see "adc_hardware_compare_mode_t" or the appopriate
+ * reference
+ * manual for more information.
+ *
+ * param base ADC peripheral base address.
+ * param Pointer to "adc_hardware_compare_config_t" structure.
+ *
+ */
+void ADC_SetHardwareCompareConfig(ADC_Type *base, const adc_hardware_compare_config_t *config)
+{
+ uint32_t tmp32;
+
+ tmp32 = base->GC & ~(ADC_GC_ACFE_MASK | ADC_GC_ACFGT_MASK | ADC_GC_ACREN_MASK);
+ if (NULL == config) /* Pass "NULL" to disable the feature. */
+ {
+ base->GC = tmp32;
+ return;
+ }
+ /* Enable the feature. */
+ tmp32 |= ADC_GC_ACFE_MASK;
+
+ /* Select the hardware compare working mode. */
+ switch (config->hardwareCompareMode)
+ {
+ case kADC_HardwareCompareMode0:
+ break;
+ case kADC_HardwareCompareMode1:
+ tmp32 |= ADC_GC_ACFGT_MASK;
+ break;
+ case kADC_HardwareCompareMode2:
+ tmp32 |= ADC_GC_ACREN_MASK;
+ break;
+ case kADC_HardwareCompareMode3:
+ tmp32 |= ADC_GC_ACFGT_MASK | ADC_GC_ACREN_MASK;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->GC = tmp32;
+
+ /* Load the compare values. */
+ tmp32 = ADC_CV_CV1(config->value1) | ADC_CV_CV2(config->value2);
+ base->CV = tmp32;
+}
+
+/*!
+ * brief Configures the hardware average mode.
+ *
+ * The hardware average mode provides a way to process the conversion result automatically by using hardware. The
+ * multiple
+ * conversion results are accumulated and averaged internally making them easier to read.
+ *
+ * param base ADC peripheral base address.
+ * param mode Setting the hardware average mode. See "adc_hardware_average_mode_t".
+ */
+void ADC_SetHardwareAverageConfig(ADC_Type *base, adc_hardware_average_mode_t mode)
+{
+ uint32_t tmp32;
+
+ if (mode == kADC_HardwareAverageDiasable)
+ {
+ base->GC &= ~ADC_GC_AVGE_MASK;
+ }
+ else
+ {
+ tmp32 = base->CFG & ~ADC_CFG_AVGS_MASK;
+ tmp32 |= ADC_CFG_AVGS(mode);
+ base->CFG = tmp32;
+ base->GC |= ADC_GC_AVGE_MASK; /* Enable the hardware compare. */
+ }
+}
+
+/*!
+ * brief Clears the converter's status falgs.
+ *
+ * param base ADC peripheral base address.
+ * param mask Mask value for the cleared flags. See "adc_status_flags_t".
+ */
+void ADC_ClearStatusFlags(ADC_Type *base, uint32_t mask)
+{
+ uint32_t tmp32 = 0;
+
+ if (0U != (mask & (uint32_t)kADC_CalibrationFailedFlag))
+ {
+ tmp32 |= ADC_GS_CALF_MASK;
+ }
+ if (0U != (mask & (uint32_t)kADC_ConversionActiveFlag))
+ {
+ tmp32 |= ADC_GS_ADACT_MASK;
+ }
+ base->GS = tmp32;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc_etc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc_etc.c
new file mode 100644
index 0000000000..d912b7045c
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_adc_etc.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_adc_etc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.adc_etc"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+#if defined(ADC_ETC_CLOCKS)
+/*!
+ * @brief Get instance number for ADC_ETC module.
+ *
+ * @param base ADC_ETC peripheral base address
+ */
+static uint32_t ADC_ETC_GetInstance(ADC_ETC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to ADC_ETC bases for each instance. */
+static ADC_ETC_Type *const s_adcetcBases[] = ADC_ETC_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to ADC_ETC clocks for each instance. */
+static const clock_ip_name_t s_adcetcClocks[] = ADC_ETC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t ADC_ETC_GetInstance(ADC_ETC_Type *base)
+{
+ uint32_t instance = 0U;
+ uint32_t adcetcArrayCount = (sizeof(s_adcetcBases) / sizeof(s_adcetcBases[0]));
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < adcetcArrayCount; instance++)
+ {
+ if (s_adcetcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ return instance;
+}
+#endif /* ADC_ETC_CLOCKS */
+
+/*!
+ * brief Initialize the ADC_ETC module.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param config Pointer to "adc_etc_config_t" structure.
+ */
+void ADC_ETC_Init(ADC_ETC_Type *base, const adc_etc_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32 = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(ADC_ETC_CLOCKS)
+ /* Open clock gate. */
+ CLOCK_EnableClock(s_adcetcClocks[ADC_ETC_GetInstance(base)]);
+#endif /* ADC_ETC_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Disable software reset. */
+ ADC_ETC_DoSoftwareReset(base, false);
+
+ /* Set ADC_ETC_CTRL register. */
+ tmp32 = ADC_ETC_CTRL_EXT0_TRIG_PRIORITY(config->TSC0triggerPriority) |
+ ADC_ETC_CTRL_EXT1_TRIG_PRIORITY(config->TSC1triggerPriority) |
+ ADC_ETC_CTRL_PRE_DIVIDER(config->clockPreDivider) | ADC_ETC_CTRL_TRIG_ENABLE(config->XBARtriggerMask)
+#if defined(FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL) && FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL
+ | ADC_ETC_CTRL_DMA_MODE_SEL(config->dmaMode)
+#endif /*FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL*/
+ ;
+ if (config->enableTSCBypass)
+ {
+ tmp32 |= ADC_ETC_CTRL_TSC_BYPASS_MASK;
+ }
+ if (config->enableTSC0Trigger)
+ {
+ tmp32 |= ADC_ETC_CTRL_EXT0_TRIG_ENABLE_MASK;
+ }
+ if (config->enableTSC1Trigger)
+ {
+ tmp32 |= ADC_ETC_CTRL_EXT1_TRIG_ENABLE_MASK;
+ }
+ base->CTRL = tmp32;
+}
+
+/*!
+ * brief De-Initialize the ADC_ETC module.
+ *
+ * param base ADC_ETC peripheral base address.
+ */
+void ADC_ETC_Deinit(ADC_ETC_Type *base)
+{
+ /* Do software reset to clear all logical. */
+ ADC_ETC_DoSoftwareReset(base, true);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(ADC_ETC_CLOCKS)
+ /* Close clock gate. */
+ CLOCK_DisableClock(s_adcetcClocks[ADC_ETC_GetInstance(base)]);
+#endif /* ADC_ETC_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets an available pre-defined settings for the ADC_ETC's configuration.
+ * This function initializes the ADC_ETC's configuration structure with available settings. The default values are:
+ * code
+ * config->enableTSCBypass = true;
+ * config->enableTSC0Trigger = false;
+ * config->enableTSC1Trigger = false;
+ * config->TSC0triggerPriority = 0U;
+ * config->TSC1triggerPriority = 0U;
+ * config->clockPreDivider = 0U;
+ * config->XBARtriggerMask = 0U;
+ * endCode
+ *
+ * param config Pointer to "adc_etc_config_t" structure.
+ */
+void ADC_ETC_GetDefaultConfig(adc_etc_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableTSCBypass = true;
+ config->enableTSC0Trigger = false;
+ config->enableTSC1Trigger = false;
+#if defined(FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL) && FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL
+ config->dmaMode = kADC_ETC_TrigDMAWithLatchedSignal;
+#endif /*FSL_FEATURE_ADC_ETC_HAS_CTRL_DMA_MODE_SEL*/
+ config->TSC0triggerPriority = 0U;
+ config->TSC1triggerPriority = 0U;
+ config->clockPreDivider = 0U;
+ config->XBARtriggerMask = 0U;
+}
+
+/*!
+ * brief Set the external XBAR trigger configuration.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param triggerGroup Trigger group index.
+ * param config Pointer to "adc_etc_trigger_config_t" structure.
+ */
+void ADC_ETC_SetTriggerConfig(ADC_ETC_Type *base, uint32_t triggerGroup, const adc_etc_trigger_config_t *config)
+{
+ assert(triggerGroup < ADC_ETC_TRIGn_CTRL_COUNT);
+ assert(ADC_ETC_TRIGn_COUNTER_COUNT > triggerGroup);
+
+ uint32_t tmp32 = 0U;
+
+ /* Set ADC_ETC_TRGn_CTRL register. */
+ tmp32 = ADC_ETC_TRIGn_CTRL_TRIG_CHAIN(config->triggerChainLength) |
+ ADC_ETC_TRIGn_CTRL_TRIG_PRIORITY(config->triggerPriority);
+ if (config->enableSyncMode)
+ {
+ tmp32 |= ADC_ETC_TRIGn_CTRL_SYNC_MODE_MASK;
+ }
+ if (config->enableSWTriggerMode)
+ {
+ tmp32 |= ADC_ETC_TRIGn_CTRL_TRIG_MODE_MASK;
+ }
+ base->TRIG[triggerGroup].TRIGn_CTRL = tmp32;
+
+ /* Set ADC_ETC_TRGn_COUNTER register. */
+ tmp32 = ADC_ETC_TRIGn_COUNTER_INIT_DELAY(config->initialDelay) |
+ ADC_ETC_TRIGn_COUNTER_SAMPLE_INTERVAL(config->sampleIntervalDelay);
+ base->TRIG[triggerGroup].TRIGn_COUNTER = tmp32;
+}
+
+/*!
+ * brief Set the external XBAR trigger chain configuration.
+ * For example, if triggerGroup is set to 0U and chainGroup is set to 1U, which means Trigger0 source's chain1 would be
+ * configurated.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param triggerGroup Trigger group index. Available number is 0~7.
+ * param chainGroup Trigger chain group index. Available number is 0~7.
+ * param config Pointer to "adc_etc_trigger_chain_config_t" structure.
+ */
+void ADC_ETC_SetTriggerChainConfig(ADC_ETC_Type *base,
+ uint32_t triggerGroup,
+ uint32_t chainGroup,
+ const adc_etc_trigger_chain_config_t *config)
+{
+ assert(triggerGroup < ADC_ETC_TRIGn_CTRL_COUNT);
+
+ uint32_t tmp32 = 0U;
+ uint32_t tmpReg = 0U;
+ uint8_t mRemainder = (uint8_t)(chainGroup % 2U);
+
+ /* Set ADC_ETC_TRIGn_CHAINm register. */
+ tmp32 = ADC_ETC_TRIGn_CHAIN_1_0_HWTS0(config->ADCHCRegisterSelect) |
+ ADC_ETC_TRIGn_CHAIN_1_0_CSEL0(config->ADCChannelSelect) |
+ ADC_ETC_TRIGn_CHAIN_1_0_IE0(config->InterruptEnable);
+ if (true == config->enableB2BMode)
+ {
+ tmp32 |= ADC_ETC_TRIGn_CHAIN_1_0_B2B0_MASK;
+ }
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ if (true == config->enableIrq)
+ {
+ tmp32 |= ADC_ETC_TRIGn_CHAIN_1_0_IE0_EN_MASK;
+ }
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+ switch (chainGroup / 2U)
+ {
+ case 0U: /* Configurate trigger chain0 and chain 1. */
+ tmpReg = base->TRIG[triggerGroup].TRIGn_CHAIN_1_0;
+ if (mRemainder == 0U) /* Chain 0. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_1_0_CSEL0_MASK | ADC_ETC_TRIGn_CHAIN_1_0_HWTS0_MASK |
+ ADC_ETC_TRIGn_CHAIN_1_0_B2B0_MASK | ADC_ETC_TRIGn_CHAIN_1_0_IE0_MASK);
+ tmpReg |= tmp32;
+ }
+ else /* Chain 1. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_1_0_CSEL1_MASK | ADC_ETC_TRIGn_CHAIN_1_0_HWTS1_MASK |
+ ADC_ETC_TRIGn_CHAIN_1_0_B2B1_MASK | ADC_ETC_TRIGn_CHAIN_1_0_IE1_MASK);
+ tmpReg |= (tmp32 << ADC_ETC_TRIGn_CHAIN_1_0_CSEL1_SHIFT);
+ }
+ base->TRIG[triggerGroup].TRIGn_CHAIN_1_0 = tmpReg;
+ break;
+ case 1U: /* Configurate trigger chain2 and chain 3. */
+ tmpReg = base->TRIG[triggerGroup].TRIGn_CHAIN_3_2;
+ if (mRemainder == 0U) /* Chain 2. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_3_2_CSEL2_MASK | ADC_ETC_TRIGn_CHAIN_3_2_HWTS2_MASK |
+ ADC_ETC_TRIGn_CHAIN_3_2_B2B2_MASK | ADC_ETC_TRIGn_CHAIN_3_2_IE2_MASK);
+ tmpReg |= tmp32;
+ }
+ else /* Chain 3. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_3_2_CSEL3_MASK | ADC_ETC_TRIGn_CHAIN_3_2_HWTS3_MASK |
+ ADC_ETC_TRIGn_CHAIN_3_2_B2B3_MASK | ADC_ETC_TRIGn_CHAIN_3_2_IE3_MASK);
+ tmpReg |= (tmp32 << ADC_ETC_TRIGn_CHAIN_3_2_CSEL3_SHIFT);
+ }
+ base->TRIG[triggerGroup].TRIGn_CHAIN_3_2 = tmpReg;
+ break;
+ case 2U: /* Configurate trigger chain4 and chain 5. */
+ tmpReg = base->TRIG[triggerGroup].TRIGn_CHAIN_5_4;
+ if (mRemainder == 0U) /* Chain 4. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_5_4_CSEL4_MASK | ADC_ETC_TRIGn_CHAIN_5_4_HWTS4_MASK |
+ ADC_ETC_TRIGn_CHAIN_5_4_B2B4_MASK | ADC_ETC_TRIGn_CHAIN_5_4_IE4_MASK);
+ tmpReg |= tmp32;
+ }
+ else /* Chain 5. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_5_4_CSEL5_MASK | ADC_ETC_TRIGn_CHAIN_5_4_HWTS5_MASK |
+ ADC_ETC_TRIGn_CHAIN_5_4_B2B5_MASK | ADC_ETC_TRIGn_CHAIN_5_4_IE5_MASK);
+ tmpReg |= (tmp32 << ADC_ETC_TRIGn_CHAIN_5_4_CSEL5_SHIFT);
+ }
+ base->TRIG[triggerGroup].TRIGn_CHAIN_5_4 = tmpReg;
+ break;
+ case 3U: /* Configurate trigger chain6 and chain 7. */
+ tmpReg = base->TRIG[triggerGroup].TRIGn_CHAIN_7_6;
+ if (mRemainder == 0U) /* Chain 6. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_7_6_CSEL6_MASK | ADC_ETC_TRIGn_CHAIN_7_6_HWTS6_MASK |
+ ADC_ETC_TRIGn_CHAIN_7_6_B2B6_MASK | ADC_ETC_TRIGn_CHAIN_7_6_IE6_MASK);
+ tmpReg |= tmp32;
+ }
+ else /* Chain 7. */
+ {
+ tmpReg &= ~(ADC_ETC_TRIGn_CHAIN_7_6_CSEL7_MASK | ADC_ETC_TRIGn_CHAIN_7_6_HWTS7_MASK |
+ ADC_ETC_TRIGn_CHAIN_7_6_B2B7_MASK | ADC_ETC_TRIGn_CHAIN_7_6_IE7_MASK);
+ tmpReg |= (tmp32 << ADC_ETC_TRIGn_CHAIN_7_6_CSEL7_SHIFT);
+ }
+ base->TRIG[triggerGroup].TRIGn_CHAIN_7_6 = tmpReg;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Gets the interrupt status flags of external XBAR and TSC triggers.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param sourceIndex trigger source index.
+ *
+ * return Status flags mask of trigger. Refer to "_adc_etc_status_flag_mask".
+ */
+uint32_t ADC_ETC_GetInterruptStatusFlags(ADC_ETC_Type *base, adc_etc_external_trigger_source_t sourceIndex)
+{
+ uint32_t tmp32 = 0U;
+
+ if (((base->DONE0_1_IRQ) & ((uint32_t)ADC_ETC_DONE0_1_IRQ_TRIG0_DONE0_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_Done0StatusFlagMask; /* Customized DONE0 status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+ if (((base->DONE0_1_IRQ) & ((uint32_t)ADC_ETC_DONE0_1_IRQ_TRIG0_DONE1_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_Done1StatusFlagMask; /* Customized DONE1 status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+ if (((base->DONE2_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_ERR_IRQ_TRIG0_DONE2_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_Done2StatusFlagMask; /* Customized DONE2 status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ if (((base->DONE2_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_ERR_IRQ_TRIG0_DONE3_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_Done3StatusFlagMask; /* Customized DONE3 status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+ if (((base->DONE2_ERR_IRQ) & ((uint32_t)ADC_ETC_DONE2_ERR_IRQ_TRIG0_ERR_MASK << (uint32_t)sourceIndex)) != 0U)
+ {
+ tmp32 |= (uint32_t)kADC_ETC_ErrorStatusFlagMask; /* Customized ERROR status flags mask, which is defined in
+ fsl_adc_etc.h file. */
+ }
+ return tmp32;
+}
+
+/*!
+ * brief Clears the ADC_ETC's interrupt status falgs.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param sourceIndex trigger source index.
+ * param mask Status flags mask of trigger. Refer to "_adc_etc_status_flag_mask".
+ */
+void ADC_ETC_ClearInterruptStatusFlags(ADC_ETC_Type *base, adc_etc_external_trigger_source_t sourceIndex, uint32_t mask)
+{
+ if (0U != (mask & (uint32_t)kADC_ETC_Done0StatusFlagMask)) /* Write 1 to clear DONE0 status flags. */
+ {
+ base->DONE0_1_IRQ = ((uint32_t)ADC_ETC_DONE0_1_IRQ_TRIG0_DONE0_MASK << (uint32_t)sourceIndex);
+ }
+ if (0U != (mask & (uint32_t)kADC_ETC_Done1StatusFlagMask)) /* Write 1 to clear DONE1 status flags. */
+ {
+ base->DONE0_1_IRQ = ((uint32_t)ADC_ETC_DONE0_1_IRQ_TRIG0_DONE1_MASK << (uint32_t)sourceIndex);
+ }
+ if (0U != (mask & (uint32_t)kADC_ETC_Done2StatusFlagMask)) /* Write 1 to clear DONE2 status flags. */
+ {
+ base->DONE2_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_ERR_IRQ_TRIG0_DONE2_MASK << (uint32_t)sourceIndex);
+ }
+#if defined(FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN) && FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN
+ if (0U != (mask & (uint32_t)kADC_ETC_Done3StatusFlagMask)) /* Write 1 to clear DONE3 status flags. */
+ {
+ base->DONE2_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_ERR_IRQ_TRIG0_DONE3_MASK << (uint32_t)sourceIndex);
+ }
+#endif /* FSL_FEATURE_ADC_ETC_HAS_TRIGm_CHAIN_a_b_IEn_EN */
+ if (0U != (mask & (uint32_t)kADC_ETC_ErrorStatusFlagMask)) /* Write 1 to clear ERROR status flags. */
+ {
+ base->DONE2_ERR_IRQ = ((uint32_t)ADC_ETC_DONE2_ERR_IRQ_TRIG0_ERR_MASK << (uint32_t)sourceIndex);
+ }
+}
+
+/*!
+ * brief Get ADC conversion result from external XBAR sources.
+ * For example, if triggerGroup is set to 0U and chainGroup is set to 1U, which means the API would
+ * return Trigger0 source's chain1 conversion result.
+ *
+ * param base ADC_ETC peripheral base address.
+ * param triggerGroup Trigger group index. Available number is 0~7.
+ * param chainGroup Trigger chain group index. Available number is 0~7.
+ * return ADC conversion result value.
+ */
+uint32_t ADC_ETC_GetADCConversionValue(ADC_ETC_Type *base, uint32_t triggerGroup, uint32_t chainGroup)
+{
+ assert(triggerGroup < ADC_ETC_TRIGn_RESULT_1_0_COUNT);
+
+ uint32_t mADCResult;
+ uint8_t mRemainder = (uint8_t)(chainGroup % 2U);
+
+ switch (chainGroup / 2U)
+ {
+ case 0U:
+ if (0U == mRemainder)
+ {
+ mADCResult = ADC_ETC_TRIGn_RESULT_1_0_DATA0_MASK & (base->TRIG[triggerGroup].TRIGn_RESULT_1_0);
+ }
+ else
+ {
+ mADCResult = (base->TRIG[triggerGroup].TRIGn_RESULT_1_0) >> ADC_ETC_TRIGn_RESULT_1_0_DATA1_SHIFT;
+ }
+ break;
+ case 1U:
+ if (0U == mRemainder)
+ {
+ mADCResult = ADC_ETC_TRIGn_RESULT_3_2_DATA2_MASK & (base->TRIG[triggerGroup].TRIGn_RESULT_3_2);
+ }
+ else
+ {
+ mADCResult = (base->TRIG[triggerGroup].TRIGn_RESULT_3_2) >> ADC_ETC_TRIGn_RESULT_3_2_DATA3_SHIFT;
+ }
+ break;
+ case 2U:
+ if (0U == mRemainder)
+ {
+ mADCResult = ADC_ETC_TRIGn_RESULT_5_4_DATA4_MASK & (base->TRIG[triggerGroup].TRIGn_RESULT_5_4);
+ }
+ else
+ {
+ mADCResult = (base->TRIG[triggerGroup].TRIGn_RESULT_5_4) >> ADC_ETC_TRIGn_RESULT_5_4_DATA5_SHIFT;
+ }
+ break;
+ case 3U:
+ if (0U == mRemainder)
+ {
+ mADCResult = ADC_ETC_TRIGn_RESULT_7_6_DATA6_MASK & (base->TRIG[triggerGroup].TRIGn_RESULT_7_6);
+ }
+ else
+ {
+ mADCResult = (base->TRIG[triggerGroup].TRIGn_RESULT_7_6) >> ADC_ETC_TRIGn_RESULT_7_6_DATA7_SHIFT;
+ }
+ break;
+ default:
+ mADCResult = 0U;
+ assert(false);
+ break;
+ }
+ return mADCResult;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aipstz.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aipstz.c
new file mode 100644
index 0000000000..077b4e01e2
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aipstz.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_aipstz.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.aipstz"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * brief Configure the privilege level for master.
+ *
+ * param base AIPSTZ peripheral base pointer
+ * param master Masters for AIPSTZ.
+ * param privilegeConfig Configuration is ORed from aipstz_master_privilege_level_t.
+ */
+void AIPSTZ_SetMasterPriviledgeLevel(AIPSTZ_Type *base, aipstz_master_t master, uint32_t privilegeConfig)
+{
+ uint32_t mask = ((uint32_t)master >> 8U) - 1U;
+ uint32_t shift = (uint32_t)master & 0xFFU;
+ base->MPR = (base->MPR & (~(mask << shift))) | (privilegeConfig << shift);
+}
+
+/*!
+ * brief Configure the access for peripheral.
+ *
+ * param base AIPSTZ peripheral base pointer
+ * param master Peripheral for AIPSTZ.
+ * param accessControl Configuration is ORed from aipstz_peripheral_access_control_t.
+ */
+void AIPSTZ_SetPeripheralAccessControl(AIPSTZ_Type *base, aipstz_peripheral_t peripheral, uint32_t accessControl)
+{
+ volatile uint32_t *reg = (uint32_t *)((uint32_t)base + ((uint32_t)peripheral >> 16U));
+ uint32_t mask = (((uint32_t)peripheral & 0xFF00U) >> 8U) - 1U;
+ uint32_t shift = (uint32_t)peripheral & 0xFFU;
+
+ *reg = (*reg & (~(mask << shift))) | ((accessControl & mask) << shift);
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aoi.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aoi.c
new file mode 100644
index 0000000000..a8f1f29ddb
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_aoi.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "fsl_aoi.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.aoi"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to aoi bases for each instance. */
+static AOI_Type *const s_aoiBases[] = AOI_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to aoi clocks for each instance. */
+static const clock_ip_name_t s_aoiClocks[] = AOI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for AOI module.
+ *
+ * @param base AOI peripheral base address
+ *
+ * @return The AOI instance
+ */
+static uint32_t AOI_GetInstance(AOI_Type *base);
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t AOI_GetInstance(AOI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_aoiBases); instance++)
+ {
+ if (s_aoiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_aoiBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes an AOI instance for operation.
+ *
+ * This function un-gates the AOI clock.
+ *
+ * param base AOI peripheral address.
+ */
+void AOI_Init(AOI_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock gate from clock manager. */
+ CLOCK_EnableClock(s_aoiClocks[AOI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Deinitializes an AOI instance for operation.
+ *
+ * This function shutdowns AOI module.
+ *
+ * param base AOI peripheral address.
+ */
+void AOI_Deinit(AOI_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock gate from clock manager */
+ CLOCK_DisableClock(s_aoiClocks[AOI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the Boolean evaluation associated.
+ *
+ * This function returns the Boolean evaluation associated.
+ *
+ * Example:
+ code
+ aoi_event_config_t demoEventLogicStruct;
+
+ AOI_GetEventLogicConfig(AOI, kAOI_Event0, &demoEventLogicStruct);
+ endcode
+ *
+ * param base AOI peripheral address.
+ * param event Index of the event which will be set of type aoi_event_t.
+ * param config Selected input configuration .
+ */
+void AOI_GetEventLogicConfig(AOI_Type *base, aoi_event_t event, aoi_event_config_t *config)
+{
+ assert((uint32_t)event < (uint32_t)FSL_FEATURE_AOI_EVENT_COUNT);
+ assert(config != NULL);
+
+ uint16_t value;
+ uint16_t temp;
+ /* Read BFCRT01 register at event index. */
+ value = base->BFCRT[event].BFCRT01;
+
+ temp = (value & AOI_BFCRT01_PT0_AC_MASK) >> AOI_BFCRT01_PT0_AC_SHIFT;
+ config->PT0AC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT0_BC_MASK) >> AOI_BFCRT01_PT0_BC_SHIFT;
+ config->PT0BC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT0_CC_MASK) >> AOI_BFCRT01_PT0_CC_SHIFT;
+ config->PT0CC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT0_DC_MASK) >> AOI_BFCRT01_PT0_DC_SHIFT;
+ config->PT0DC = (aoi_input_config_t)temp;
+
+ temp = (value & AOI_BFCRT01_PT1_AC_MASK) >> AOI_BFCRT01_PT1_AC_SHIFT;
+ config->PT1AC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT1_BC_MASK) >> AOI_BFCRT01_PT1_BC_SHIFT;
+ config->PT1BC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT1_CC_MASK) >> AOI_BFCRT01_PT1_CC_SHIFT;
+ config->PT1CC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT01_PT1_DC_MASK) >> AOI_BFCRT01_PT1_DC_SHIFT;
+ config->PT1DC = (aoi_input_config_t)temp;
+
+ /* Read BFCRT23 register at event index. */
+ value = base->BFCRT[event].BFCRT23;
+
+ temp = (value & AOI_BFCRT23_PT2_AC_MASK) >> AOI_BFCRT23_PT2_AC_SHIFT;
+ config->PT2AC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT2_BC_MASK) >> AOI_BFCRT23_PT2_BC_SHIFT;
+ config->PT2BC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT2_CC_MASK) >> AOI_BFCRT23_PT2_CC_SHIFT;
+ config->PT2CC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT2_DC_MASK) >> AOI_BFCRT23_PT2_DC_SHIFT;
+ config->PT2DC = (aoi_input_config_t)temp;
+
+ temp = (value & AOI_BFCRT23_PT3_AC_MASK) >> AOI_BFCRT23_PT3_AC_SHIFT;
+ config->PT3AC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT3_BC_MASK) >> AOI_BFCRT23_PT3_BC_SHIFT;
+ config->PT3BC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT3_CC_MASK) >> AOI_BFCRT23_PT3_CC_SHIFT;
+ config->PT3CC = (aoi_input_config_t)temp;
+ temp = (value & AOI_BFCRT23_PT3_DC_MASK) >> AOI_BFCRT23_PT3_DC_SHIFT;
+ config->PT3DC = (aoi_input_config_t)temp;
+}
+
+/*!
+ * brief Configures an AOI event.
+ *
+ * This function configures an AOI event according
+ * to the aoiEventConfig structure. This function configures all inputs (A, B, C, and D)
+ * of all product terms (0, 1, 2, and 3) of a desired event.
+ *
+ * Example:
+ code
+ aoi_event_config_t demoEventLogicStruct;
+
+ demoEventLogicStruct.PT0AC = kAOI_InvInputSignal;
+ demoEventLogicStruct.PT0BC = kAOI_InputSignal;
+ demoEventLogicStruct.PT0CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT0DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT1AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT1BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT1CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT1DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT2AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT2BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT2CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT2DC = kAOI_LogicOne;
+
+ demoEventLogicStruct.PT3AC = kAOI_LogicZero;
+ demoEventLogicStruct.PT3BC = kAOI_LogicOne;
+ demoEventLogicStruct.PT3CC = kAOI_LogicOne;
+ demoEventLogicStruct.PT3DC = kAOI_LogicOne;
+
+ AOI_SetEventLogicConfig(AOI, kAOI_Event0, demoEventLogicStruct);
+ endcode
+ *
+ * param base AOI peripheral address.
+ * param event Event which will be configured of type aoi_event_t.
+ * param eventConfig Pointer to type aoi_event_config_t structure. The user is responsible for
+ * filling out the members of this structure and passing the pointer to this function.
+ */
+void AOI_SetEventLogicConfig(AOI_Type *base, aoi_event_t event, const aoi_event_config_t *eventConfig)
+{
+ assert(eventConfig != NULL);
+ assert((uint32_t)event < (uint32_t)FSL_FEATURE_AOI_EVENT_COUNT);
+
+ uint16_t value;
+ /* Calculate value to configure product term 0, 1 */
+ value = AOI_BFCRT01_PT0_AC(eventConfig->PT0AC) | AOI_BFCRT01_PT0_BC(eventConfig->PT0BC) |
+ AOI_BFCRT01_PT0_CC(eventConfig->PT0CC) | AOI_BFCRT01_PT0_DC(eventConfig->PT0DC) |
+ AOI_BFCRT01_PT1_AC(eventConfig->PT1AC) | AOI_BFCRT01_PT1_BC(eventConfig->PT1BC) |
+ AOI_BFCRT01_PT1_CC(eventConfig->PT1CC) | AOI_BFCRT01_PT1_DC(eventConfig->PT1DC);
+ /* Write value to register */
+ base->BFCRT[event].BFCRT01 = value;
+
+ /* Reset and calculate value to configure product term 2, 3 */
+ value = AOI_BFCRT23_PT2_AC(eventConfig->PT2AC) | AOI_BFCRT23_PT2_BC(eventConfig->PT2BC) |
+ AOI_BFCRT23_PT2_CC(eventConfig->PT2CC) | AOI_BFCRT23_PT2_DC(eventConfig->PT2DC) |
+ AOI_BFCRT23_PT3_AC(eventConfig->PT3AC) | AOI_BFCRT23_PT3_BC(eventConfig->PT3BC) |
+ AOI_BFCRT23_PT3_CC(eventConfig->PT3CC) | AOI_BFCRT23_PT3_DC(eventConfig->PT3DC);
+ /* Write value to register */
+ base->BFCRT[event].BFCRT23 = value;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_bee.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_bee.c
new file mode 100644
index 0000000000..d4ffdacfb9
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_bee.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2017, 2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_bee.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.bee"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void aligned_memcpy(void *dst, const void *src, size_t size)
+{
+ register uint32_t *to32 = (uint32_t *)(uint32_t *)dst;
+ register const uint32_t *from32 = (const uint32_t *)(const uint32_t *)src;
+
+ while (size >= sizeof(uint32_t))
+ {
+ *to32 = *from32;
+ size -= sizeof(uint32_t);
+ to32++;
+ from32++;
+ }
+}
+
+/*!
+ * brief Resets BEE module to factory default values.
+ *
+ * This function performs hardware reset of BEE module. Attributes and keys from software for both regions are cleared.
+ *
+ * param base BEE peripheral address.
+ */
+void BEE_Init(BEE_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Bee);
+#endif
+
+ base->CTRL = BEE_CTRL_CTRL_SFTRST_N_MASK | BEE_CTRL_CTRL_CLK_EN_MASK;
+}
+
+/*!
+ * brief Resets BEE module, clears keys for both regions and disables clock to the BEE.
+ *
+ * This function performs hardware reset of BEE module and disables clocks. Attributes and keys from software for both
+ * regions are cleared.
+ *
+ * param base BEE peripheral address.
+ */
+void BEE_Deinit(BEE_Type *base)
+{
+ base->CTRL &=
+ ~(BEE_CTRL_BEE_ENABLE_MASK | BEE_CTRL_CTRL_SFTRST_N_MASK | BEE_CTRL_CTRL_CLK_EN_MASK | BEE_CTRL_KEY_VALID_MASK);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Bee);
+#endif
+}
+
+/*!
+ * brief Loads default values to the BEE region configuration structure.
+ *
+ * Loads default values to the BEE region configuration structure. The default values are as follows:
+ * code
+ * config->region0Mode = kBEE_AesCtrMode;
+ * config->region1Mode = kBEE_AesCtrMode;
+ * config->region0AddrOffset = 0U;
+ * config->region1AddrOffset = 0U;
+ * config->region0SecLevel = kBEE_SecurityLevel3;
+ * config->region1SecLevel = kBEE_SecurityLevel3;
+ * config->region1Bot = 0U;
+ * config->region1Top = 0U;
+ * config->accessPermission = kBEE_AccessProtDisabled;
+ * config->endianSwapEn = kBEE_EndianSwapEnabled;
+ * endcode
+ *
+ * param config Configuration structure for BEE peripheral.
+ */
+void BEE_GetDefaultConfig(bee_region_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->region0Mode = kBEE_AesCtrMode;
+ config->region1Mode = kBEE_AesCtrMode;
+ config->region0AddrOffset = 0U;
+ config->region1AddrOffset = 0U;
+ config->region0SecLevel = kBEE_SecurityLevel3;
+ config->region1SecLevel = kBEE_SecurityLevel3;
+ config->region1Bot = 0U;
+ config->region1Top = 0U;
+ config->accessPermission = kBEE_AccessProtDisabled;
+ config->endianSwapEn = kBEE_EndianSwapEnabled;
+}
+
+/*!
+ * brief Sets BEE configuration.
+ *
+ * This function sets BEE peripheral and BEE region settings accorging to given configuration structure.
+ *
+ * param base BEE peripheral address.
+ * param config Configuration structure for BEE.
+ */
+void BEE_SetConfig(BEE_Type *base, const bee_region_config_t *config)
+{
+ uint32_t beeCtrlVal;
+ bool reenable = false;
+
+ /* Wait until BEE is in idle state */
+ while (0U == (BEE_GetStatusFlags(base) & (uint32_t)kBEE_IdleFlag))
+ {
+ }
+
+ /* Disable BEE before region configuration in case it is enabled. */
+ if ((base->CTRL & BEE_CTRL_BEE_ENABLE_MASK) != 0U)
+ {
+ BEE_Disable(base);
+ reenable = true;
+ }
+
+ /* Preserve CTRL bit values that are not set by this function */
+ beeCtrlVal = base->CTRL & 0xFFFF0037U;
+
+ /* Set variable according to configuration */
+ beeCtrlVal |= BEE_CTRL_AC_PROT_EN(config->accessPermission) | BEE_CTRL_LITTLE_ENDIAN(config->endianSwapEn) |
+ BEE_CTRL_SECURITY_LEVEL_R0(config->region0SecLevel) | BEE_CTRL_CTRL_AES_MODE_R0(config->region0Mode) |
+ BEE_CTRL_SECURITY_LEVEL_R1(config->region1SecLevel) | BEE_CTRL_CTRL_AES_MODE_R1(config->region1Mode);
+
+ /* Load values to registers */
+ base->CTRL = beeCtrlVal;
+ base->ADDR_OFFSET0 = config->region0AddrOffset;
+ base->ADDR_OFFSET1 = config->region1AddrOffset;
+ base->REGION1_BOT = config->region1Bot;
+ base->REGION1_TOP = config->region1Top;
+
+ /* Reenable BEE if it was enabled before. */
+ if (reenable)
+ {
+ BEE_Enable(base);
+ }
+}
+
+/*!
+ * brief Loads the AES key for selected region into BEE key registers.
+ *
+ * This function loads given AES key to BEE register for the given region.
+ * The key must be 32-bit aligned and stored in little-endian format.
+ *
+ * Please note, that eFuse BEE_KEYx_SEL must be set accordingly to be able to load and use key loaded in BEE registers.
+ * Otherwise, key cannot loaded and BEE will use key from OTPMK or SW_GP2.
+ *
+ * param base BEE peripheral address.
+ * param region Selection of the BEE region to be configured.
+ * param key AES key (in little-endian format).
+ * param keySize Size of AES key.
+ */
+status_t BEE_SetRegionKey(BEE_Type *base, bee_region_t region, const uint8_t *key, size_t keySize)
+{
+ bool redisable = false;
+
+ /* Key must be 32-bit aligned */
+ if ((0U != ((uintptr_t)key & 0x3u)) || (keySize != 16U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Wait until BEE is in idle state */
+ while (0U == (BEE_GetStatusFlags(base) & (uint32_t)kBEE_IdleFlag))
+ {
+ }
+
+ /* Clear KEY_VALID bit before new key is loaded */
+ base->CTRL &= ~BEE_CTRL_KEY_VALID_MASK;
+
+ /* Write key registers, key is stored in little-endian format in memory */
+ aligned_memcpy((uint32_t *)(uint32_t)&base->AES_KEY0_W0, key, keySize);
+
+ /* Enable BEE before key configuration. */
+ if (0U == (base->CTRL & BEE_CTRL_BEE_ENABLE_MASK))
+ {
+ BEE_Enable(base);
+ redisable = true;
+ }
+
+ if (region == kBEE_Region0)
+ {
+ base->CTRL &= ~BEE_CTRL_KEY_REGION_SEL_MASK;
+ }
+
+ else if (region == kBEE_Region1)
+ {
+ base->CTRL |= BEE_CTRL_KEY_REGION_SEL_MASK;
+ }
+
+ else
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Set KEY_VALID bit to trigger key loading */
+ base->CTRL |= BEE_CTRL_KEY_VALID_MASK;
+ /* Wait until key is ready */
+ while (0U == (base->CTRL & BEE_CTRL_KEY_VALID_MASK))
+ {
+ }
+
+ /* Redisable BEE if it was disabled before this function call. */
+ if (redisable)
+ {
+ BEE_Disable(base);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Loads the nonce for selected region into BEE nonce registers.
+ *
+ * This function loads given nonce(only AES CTR mode) to BEE register for the given region.
+ * The nonce must be 32-bit aligned and stored in little-endian format.
+ *
+ * param base BEE peripheral address.
+ * param region Selection of the BEE region to be configured.
+ * param nonce AES nonce (in little-endian format).
+ * param nonceSize Size of AES nonce.
+ */
+status_t BEE_SetRegionNonce(BEE_Type *base, bee_region_t region, const uint8_t *nonce, size_t nonceSize)
+{
+ /* Nonce must be 32-bit aligned */
+ if ((0U != ((uintptr_t)nonce & 0x3u)) || (nonceSize != 16U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Wait until BEE is in idle state */
+ while (0U == (BEE_GetStatusFlags(base) & (uint32_t)kBEE_IdleFlag))
+ {
+ }
+
+ /* Write nonce registers, nonce is stored in little-endian format in memory */
+ if (region == kBEE_Region0)
+ {
+ aligned_memcpy((uint32_t *)(uint32_t)&base->CTR_NONCE0_W0, nonce, nonceSize);
+ }
+
+ else if (region == kBEE_Region1)
+ {
+ aligned_memcpy((uint32_t *)(uint32_t)&base->CTR_NONCE1_W0, nonce, nonceSize);
+ }
+
+ else
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the BEE status flags.
+ *
+ * This function returns status of BEE peripheral.
+ *
+ * param base BEE peripheral address.
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::bee_status_flags_t
+ */
+uint32_t BEE_GetStatusFlags(BEE_Type *base)
+{
+ return base->STATUS;
+}
+
+/*!
+ * brief Clears the BEE status flags.
+ *
+ * param base BEE peripheral base address.
+ * param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::bee_status_flags_t
+ */
+void BEE_ClearStatusFlags(BEE_Type *base, uint32_t mask)
+{
+ /* w1c */
+ base->STATUS |= mask;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cache.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cache.c
new file mode 100644
index 0000000000..31d6a2479c
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cache.c
@@ -0,0 +1,602 @@
+/*
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_cache.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.cache_armv7_m7"
+#endif
+
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#define L2CACHE_OPERATION_TIMEOUT 0xFFFFFU
+#define L2CACHE_8WAYS_MASK 0xFFU
+#define L2CACHE_16WAYS_MASK 0xFFFFU
+#define L2CACHE_SMALLWAYS_NUM 8U
+#define L2CACHE_1KBCOVERTOB 1024U
+#define L2CACHE_SAMLLWAYS_SIZE 16U
+#define L2CACHE_LOCKDOWN_REGNUM 8 /*!< Lock down register numbers.*/
+ /*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Set for all ways and waiting for the operation finished.
+ * This is provided for all the background operations.
+ *
+ * @param auxCtlReg The auxiliary control register.
+ * @param regAddr The register address to be operated.
+ */
+static void L2CACHE_SetAndWaitBackGroundOperate(uint32_t auxCtlReg, uint32_t regAddr);
+
+/*!
+ * @brief Invalidates the Level 2 cache line by physical address.
+ * This function invalidates a cache line by physcial address.
+ *
+ * @param address The physical addderss of the cache.
+ * The format of the address shall be :
+ * bit 31 ~ bit n+1 | bitn ~ bit5 | bit4 ~ bit0
+ * Tag | index | 0
+ * Note: the physical address shall be aligned to the line size - 32B (256 bit).
+ * so keep the last 5 bits (bit 4 ~ bit 0) of the physical address always be zero.
+ * If the input address is not aligned, it will be changed to 32-byte aligned address.
+ * The n is varies according to the index width.
+ * @return The actual 32-byte aligned physical address be operated.
+ */
+static uint32_t L2CACHE_InvalidateLineByAddr(uint32_t address);
+
+/*!
+ * @brief Cleans the Level 2 cache line based on the physical address.
+ * This function cleans a cache line based on a physcial address.
+ *
+ * @param address The physical addderss of the cache.
+ * The format of the address shall be :
+ * bit 31 ~ bit n+1 | bitn ~ bit5 | bit4 ~ bit0
+ * Tag | index | 0
+ * Note: the physical address shall be aligned to the line size - 32B (256 bit).
+ * so keep the last 5 bits (bit 4 ~ bit 0) of the physical address always be zero.
+ * If the input address is not aligned, it will be changed to 32-byte aligned address.
+ * The n is varies according to the index width.
+ * @return The actual 32-byte aligned physical address be operated.
+ */
+static uint32_t L2CACHE_CleanLineByAddr(uint32_t address);
+
+/*!
+ * @brief Cleans and invalidates the Level 2 cache line based on the physical address.
+ * This function cleans and invalidates a cache line based on a physcial address.
+ *
+ * @param address The physical addderss of the cache.
+ * The format of the address shall be :
+ * bit 31 ~ bit n+1 | bitn ~ bit5 | bit4 ~ bit0
+ * Tag | index | 0
+ * Note: the physical address shall be aligned to the line size - 32B (256 bit).
+ * so keep the last 5 bits (bit 4 ~ bit 0) of the physical address always be zero.
+ * If the input address is not aligned, it will be changed to 32-byte aligned address.
+ * The n is varies according to the index width.
+ * @return The actual 32-byte aligned physical address be operated.
+ */
+static uint32_t L2CACHE_CleanInvalidateLineByAddr(uint32_t address);
+
+/*!
+ * @brief Gets the number of the Level 2 cache and the way size.
+ * This function cleans and invalidates a cache line based on a physcial address.
+ *
+ * @param num_ways The number of the cache way.
+ * @param size_way The way size.
+ */
+static void L2CACHE_GetWayNumSize(uint32_t *num_ways, uint32_t *size_way);
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static void L2CACHE_SetAndWaitBackGroundOperate(uint32_t auxCtlReg, uint32_t regAddr)
+{
+ uint16_t mask = L2CACHE_8WAYS_MASK;
+ uint32_t timeout = L2CACHE_OPERATION_TIMEOUT;
+
+ /* Check the ways used at first. */
+ if (auxCtlReg & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK)
+ {
+ mask = L2CACHE_16WAYS_MASK;
+ }
+
+ /* Set the opeartion for all ways/entries of the cache. */
+ *(uint32_t *)regAddr = mask;
+ /* Waiting for until the operation is complete. */
+ while ((*(volatile uint32_t *)regAddr & mask) && timeout)
+ {
+ __ASM("nop");
+ timeout--;
+ }
+}
+
+static uint32_t L2CACHE_InvalidateLineByAddr(uint32_t address)
+{
+ /* Align the address first. */
+ address &= ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1);
+ /* Invalidate the cache line by physical address. */
+ L2CACHEC->REG7_INV_PA = address;
+
+ return address;
+}
+
+static uint32_t L2CACHE_CleanLineByAddr(uint32_t address)
+{
+ /* Align the address first. */
+ address &= ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1);
+ /* Invalidate the cache line by physical address. */
+ L2CACHEC->REG7_CLEAN_PA = address;
+
+ return address;
+}
+
+static uint32_t L2CACHE_CleanInvalidateLineByAddr(uint32_t address)
+{
+ /* Align the address first. */
+ address &= ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1);
+ /* Clean and invalidate the cache line by physical address. */
+ L2CACHEC->REG7_CLEAN_INV_PA = address;
+
+ return address;
+}
+
+static void L2CACHE_GetWayNumSize(uint32_t *num_ways, uint32_t *size_way)
+{
+ assert(num_ways);
+ assert(size_way);
+
+ uint32_t number = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_SHIFT;
+ uint32_t size = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_WAYSIZE_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_WAYSIZE_SHIFT;
+
+ *num_ways = (number + 1) * L2CACHE_SMALLWAYS_NUM;
+ if (!size)
+ {
+ /* 0 internally mapped to the same size as 1 - 16KB.*/
+ size += 1;
+ }
+ *size_way = (1 << (size - 1)) * L2CACHE_SAMLLWAYS_SIZE * L2CACHE_1KBCOVERTOB;
+}
+
+/*!
+ * brief Initializes the level 2 cache controller module.
+ *
+ * param config Pointer to configuration structure. See "l2cache_config_t".
+ */
+void L2CACHE_Init(l2cache_config_t *config)
+{
+ assert(config);
+
+ uint16_t waysNum = 0xFFU; /* Default use the 8-way mask. */
+ uint8_t count;
+ uint32_t auxReg = 0;
+
+ /*The aux register must be configured when the cachec is disabled
+ * So disable first if the cache controller is enabled.
+ */
+ if (L2CACHEC->REG1_CONTROL & L2CACHEC_REG1_CONTROL_CE_MASK)
+ {
+ L2CACHE_Disable();
+ }
+
+ /* Unlock all entries. */
+ if (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK)
+ {
+ waysNum = 0xFFFFU;
+ }
+
+ for (count = 0; count < L2CACHE_LOCKDOWN_REGNUM; count++)
+ {
+ L2CACHE_LockdownByWayEnable(count, waysNum, false);
+ }
+
+ /* Set the ways and way-size etc. */
+ auxReg = L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY(config->wayNum) |
+ L2CACHEC_REG1_AUX_CONTROL_WAYSIZE(config->waySize) | L2CACHEC_REG1_AUX_CONTROL_CRP(config->repacePolicy) |
+ L2CACHEC_REG1_AUX_CONTROL_IPE(config->istrPrefetchEnable) |
+ L2CACHEC_REG1_AUX_CONTROL_DPE(config->dataPrefetchEnable) |
+ L2CACHEC_REG1_AUX_CONTROL_NLE(config->nsLockdownEnable) |
+ L2CACHEC_REG1_AUX_CONTROL_FWA(config->writeAlloc) | L2CACHEC_REG1_AUX_CONTROL_HPSDRE(config->writeAlloc);
+ L2CACHEC->REG1_AUX_CONTROL = auxReg;
+
+ /* Set the tag/data ram latency. */
+ if (config->lateConfig)
+ {
+ uint32_t data = 0;
+ /* Tag latency. */
+ data = L2CACHEC_REG1_TAG_RAM_CONTROL_SL(config->lateConfig->tagSetupLate) |
+ L2CACHEC_REG1_TAG_RAM_CONTROL_SL(config->lateConfig->tagSetupLate) |
+ L2CACHEC_REG1_TAG_RAM_CONTROL_RAL(config->lateConfig->tagReadLate) |
+ L2CACHEC_REG1_TAG_RAM_CONTROL_WAL(config->lateConfig->dataWriteLate);
+ L2CACHEC->REG1_TAG_RAM_CONTROL = data;
+ /* Data latency. */
+ data = L2CACHEC_REG1_DATA_RAM_CONTROL_SL(config->lateConfig->dataSetupLate) |
+ L2CACHEC_REG1_DATA_RAM_CONTROL_SL(config->lateConfig->dataSetupLate) |
+ L2CACHEC_REG1_DATA_RAM_CONTROL_RAL(config->lateConfig->dataReadLate) |
+ L2CACHEC_REG1_DATA_RAM_CONTROL_WAL(config->lateConfig->dataWriteLate);
+ L2CACHEC->REG1_DATA_RAM_CONTROL = data;
+ }
+}
+
+/*!
+ * brief Gets an available default settings for the cache controller.
+ *
+ * This function initializes the cache controller configuration structure with default settings.
+ * The default values are:
+ * code
+ * config->waysNum = kL2CACHE_8ways;
+ * config->waySize = kL2CACHE_32KbSize;
+ * config->repacePolicy = kL2CACHE_Roundrobin;
+ * config->lateConfig = NULL;
+ * config->istrPrefetchEnable = false;
+ * config->dataPrefetchEnable = false;
+ * config->nsLockdownEnable = false;
+ * config->writeAlloc = kL2CACHE_UseAwcache;
+ * endcode
+ * param config Pointer to the configuration structure.
+ */
+void L2CACHE_GetDefaultConfig(l2cache_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ memset(config, 0, sizeof(*config));
+
+ uint32_t number = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_SHIFT;
+ uint32_t size = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_WAYSIZE_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_WAYSIZE_SHIFT;
+
+ /* Get the default value */
+ config->wayNum = (l2cache_way_num_t)number;
+ config->waySize = (l2cache_way_size)size;
+ config->repacePolicy = kL2CACHE_Roundrobin;
+ config->lateConfig = NULL;
+ config->istrPrefetchEnable = false;
+ config->dataPrefetchEnable = false;
+ config->nsLockdownEnable = false;
+ config->writeAlloc = kL2CACHE_UseAwcache;
+}
+
+/*!
+ * brief Enables the level 2 cache controller.
+ * This function enables the cache controller. Must be written using a secure access.
+ * If write with a Non-secure access will cause a DECERR response.
+ *
+ */
+void L2CACHE_Enable(void)
+{
+ /* Invalidate first. */
+ L2CACHE_Invalidate();
+ /* Enable the level 2 cache controller. */
+ L2CACHEC->REG1_CONTROL = L2CACHEC_REG1_CONTROL_CE_MASK;
+}
+
+/*!
+ * brief Disables the level 2 cache controller.
+ * This function disables the cache controller. Must be written using a secure access.
+ * If write with a Non-secure access will cause a DECERR response.
+ *
+ */
+void L2CACHE_Disable(void)
+{
+ /* First CleanInvalidate all enties in the cache. */
+ L2CACHE_CleanInvalidate();
+ /* Disable the level 2 cache controller. */
+ L2CACHEC->REG1_CONTROL &= ~L2CACHEC_REG1_CONTROL_CE_MASK;
+ /* DSB - data sync barrier.*/
+ __DSB();
+}
+
+/*!
+ * brief Invalidates the Level 2 cache.
+ * This function invalidates all entries in cache.
+ *
+ */
+void L2CACHE_Invalidate(void)
+{
+ /* Invalidate all entries in cache. */
+ L2CACHE_SetAndWaitBackGroundOperate(L2CACHEC->REG1_AUX_CONTROL, (uint32_t)&L2CACHEC->REG7_INV_WAY);
+ /* Cache sync. */
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Cleans the level 2 cache controller.
+ * This function cleans all entries in the level 2 cache controller.
+ *
+ */
+void L2CACHE_Clean(void)
+{
+ /* Clean all entries of the cache. */
+ L2CACHE_SetAndWaitBackGroundOperate(L2CACHEC->REG1_AUX_CONTROL, (uint32_t)&L2CACHEC->REG7_CLEAN_WAY);
+ /* Cache sync. */
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Cleans and invalidates the level 2 cache controller.
+ * This function cleans and invalidates all entries in the level 2 cache controller.
+ *
+ */
+void L2CACHE_CleanInvalidate(void)
+{
+ /* Clean all entries of the cache. */
+ L2CACHE_SetAndWaitBackGroundOperate(L2CACHEC->REG1_AUX_CONTROL, (uint32_t)&L2CACHEC->REG7_CLEAN_INV_WAY);
+ /* Cache sync. */
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Invalidates the Level 2 cache lines in the range of two physical addresses.
+ * This function invalidates all cache lines between two physical addresses.
+ *
+ * param address The start address of the memory to be invalidated.
+ * param size_byte The memory size.
+ * note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_InvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+ uint32_t endAddr = address + size_byte;
+
+ /* Invalidate addresses in the range. */
+ while (address < endAddr)
+ {
+ address = L2CACHE_InvalidateLineByAddr(address);
+ /* Update the size. */
+ address += FSL_FEATURE_L2CACHE_LINESIZE_BYTE;
+ }
+
+ /* Cache sync. */
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Cleans the Level 2 cache lines in the range of two physical addresses.
+ * This function cleans all cache lines between two physical addresses.
+ *
+ * param address The start address of the memory to be cleaned.
+ * param size_byte The memory size.
+ * note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_CleanByRange(uint32_t address, uint32_t size_byte)
+{
+ uint32_t num_ways = 0;
+ uint32_t size_way = 0;
+ uint32_t endAddr = address + size_byte;
+
+ /* Get the number and size of the cache way. */
+ L2CACHE_GetWayNumSize(&num_ways, &size_way);
+
+ /* Check if the clean size is over the cache size. */
+ if ((endAddr - address) > num_ways * size_way)
+ {
+ L2CACHE_Clean();
+ return;
+ }
+
+ /* Clean addresses in the range. */
+ while ((address & ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1)) < endAddr)
+ {
+ /* Clean the address in the range. */
+ address = L2CACHE_CleanLineByAddr(address);
+ address += FSL_FEATURE_L2CACHE_LINESIZE_BYTE;
+ }
+
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Cleans and invalidates the Level 2 cache lines in the range of two physical addresses.
+ * This function cleans and invalidates all cache lines between two physical addresses.
+ *
+ * param address The start address of the memory to be cleaned and invalidated.
+ * param size_byte The memory size.
+ * note The start address and size_byte should be 32-byte(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L2 line size if startAddr
+ * is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L2CACHE_CleanInvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+ uint32_t num_ways = 0;
+ uint32_t size_way = 0;
+ uint32_t endAddr = address + size_byte;
+
+ /* Get the number and size of the cache way. */
+ L2CACHE_GetWayNumSize(&num_ways, &size_way);
+
+ /* Check if the clean size is over the cache size. */
+ if ((endAddr - address) > num_ways * size_way)
+ {
+ L2CACHE_CleanInvalidate();
+ return;
+ }
+
+ /* Clean addresses in the range. */
+ while ((address & ~(uint32_t)(FSL_FEATURE_L2CACHE_LINESIZE_BYTE - 1)) < endAddr)
+ {
+ /* Clean the address in the range. */
+ address = L2CACHE_CleanInvalidateLineByAddr(address);
+ address += FSL_FEATURE_L2CACHE_LINESIZE_BYTE;
+ }
+
+ L2CACHEC->REG7_CACHE_SYNC = 0;
+}
+
+/*!
+ * brief Enables or disables to lock down the data and instruction by way.
+ * This function locks down the cached instruction/data by way and prevent the adresses from
+ * being allocated and prevent dara from being evicted out of the level 2 cache.
+ * But the normal cache maintenance operations that invalidate, clean or clean
+ * and validate cache contents affect the locked-down cache lines as normal.
+ *
+ * param masterId The master id, range from 0 ~ 7.
+ * param mask The ways to be enabled or disabled to lockdown.
+ * each bit in value is related to each way of the cache. for example:
+ * value: bit 0 ------ way 0.
+ * value: bit 1 ------ way 1.
+ * --------------------------
+ * value: bit 15 ------ way 15.
+ * Note: please make sure the value setting is align with your supported ways.
+ * param enable True enable the lockdown, false to disable the lockdown.
+ */
+void L2CACHE_LockdownByWayEnable(uint32_t masterId, uint32_t mask, bool enable)
+{
+ uint8_t num_ways = (L2CACHEC->REG1_AUX_CONTROL & L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_MASK) >>
+ L2CACHEC_REG1_AUX_CONTROL_ASSOCIATIVITY_SHIFT;
+ num_ways = (num_ways + 1) * L2CACHE_SMALLWAYS_NUM;
+
+ assert(mask < (1U << num_ways));
+ assert(masterId < L2CACHE_LOCKDOWN_REGNUM);
+
+ uint32_t dataReg = L2CACHEC->LOCKDOWN[masterId].REG9_D_LOCKDOWN;
+ uint32_t istrReg = L2CACHEC->LOCKDOWN[masterId].REG9_I_LOCKDOWN;
+
+ if (enable)
+ {
+ /* Data lockdown. */
+ L2CACHEC->LOCKDOWN[masterId].REG9_D_LOCKDOWN = dataReg | mask;
+ /* Instruction lockdown. */
+ L2CACHEC->LOCKDOWN[masterId].REG9_I_LOCKDOWN = istrReg | mask;
+ }
+ else
+ {
+ /* Data lockdown. */
+ L2CACHEC->LOCKDOWN[masterId].REG9_D_LOCKDOWN = dataReg & ~mask;
+ /* Instruction lockdown. */
+ L2CACHEC->LOCKDOWN[masterId].REG9_I_LOCKDOWN = istrReg & ~mask;
+ }
+}
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+
+/*!
+ * brief Invalidate cortex-m7 L1 instruction cache by range.
+ *
+ * param address The start address of the memory to be invalidated.
+ * param size_byte The memory size.
+ * note The start address and size_byte should be 32-byte(FSL_FEATURE_L1ICACHE_LINESIZE_BYTE) aligned.
+ * The startAddr here will be forced to align to L1 I-cache line size if
+ * startAddr is not aligned. For the size_byte, application should make sure the
+ * alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void L1CACHE_InvalidateICacheByRange(uint32_t address, uint32_t size_byte)
+{
+#if (__DCACHE_PRESENT == 1U)
+ uint32_t addr = address & ~((uint32_t)FSL_FEATURE_L1ICACHE_LINESIZE_BYTE - 1U);
+ uint32_t align_len = address - addr;
+ int32_t size = (int32_t)size_byte + (int32_t)align_len;
+
+ __DSB();
+ while (size > 0)
+ {
+ SCB->ICIMVAU = addr;
+ addr += (uint32_t)FSL_FEATURE_L1ICACHE_LINESIZE_BYTE;
+ size -= (int32_t)FSL_FEATURE_L1ICACHE_LINESIZE_BYTE;
+ }
+ __DSB();
+ __ISB();
+#endif
+}
+
+/*!
+ * brief Invalidates all instruction caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * param address The physical address.
+ * param size_byte size of the memory to be invalidated.
+ * note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void ICACHE_InvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#if defined(FSL_SDK_DISBLE_L2CACHE_PRESENT) && !FSL_SDK_DISBLE_L2CACHE_PRESENT
+ L2CACHE_InvalidateByRange(address, size_byte);
+#endif /* !FSL_SDK_DISBLE_L2CACHE_PRESENT */
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+
+ L1CACHE_InvalidateICacheByRange(address, size_byte);
+}
+
+/*!
+ * brief Invalidates all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * param address The physical address.
+ * param size_byte size of the memory to be invalidated.
+ * note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_InvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#if defined(FSL_SDK_DISBLE_L2CACHE_PRESENT) && !FSL_SDK_DISBLE_L2CACHE_PRESENT
+ L2CACHE_InvalidateByRange(address, size_byte);
+#endif /* !FSL_SDK_DISBLE_L2CACHE_PRESENT */
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+ L1CACHE_InvalidateDCacheByRange(address, size_byte);
+}
+
+/*!
+ * brief Cleans all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * param address The physical address.
+ * param size_byte size of the memory to be cleaned.
+ * note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_CleanByRange(uint32_t address, uint32_t size_byte)
+{
+ L1CACHE_CleanDCacheByRange(address, size_byte);
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#if defined(FSL_SDK_DISBLE_L2CACHE_PRESENT) && !FSL_SDK_DISBLE_L2CACHE_PRESENT
+ L2CACHE_CleanByRange(address, size_byte);
+#endif /* !FSL_SDK_DISBLE_L2CACHE_PRESENT */
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+}
+
+/*!
+ * brief Cleans and Invalidates all data caches by range.
+ *
+ * Both cortex-m7 L1 cache line and L2 PL310 cache line length is 32-byte.
+ *
+ * param address The physical address.
+ * param size_byte size of the memory to be cleaned and invalidated.
+ * note address and size should be aligned to cache line size
+ * 32-Byte due to the cache operation unit is one cache line. The startAddr here will be forced
+ * to align to the cache line size if startAddr is not aligned. For the size_byte, application should
+ * make sure the alignment or make sure the right operation order if the size_byte is not aligned.
+ */
+void DCACHE_CleanInvalidateByRange(uint32_t address, uint32_t size_byte)
+{
+ L1CACHE_CleanInvalidateDCacheByRange(address, size_byte);
+#if defined(FSL_FEATURE_SOC_L2CACHEC_COUNT) && FSL_FEATURE_SOC_L2CACHEC_COUNT
+#if defined(FSL_SDK_DISBLE_L2CACHE_PRESENT) && !FSL_SDK_DISBLE_L2CACHE_PRESENT
+ L2CACHE_CleanInvalidateByRange(address, size_byte);
+#endif /* !FSL_SDK_DISBLE_L2CACHE_PRESENT */
+#endif /* FSL_FEATURE_SOC_L2CACHEC_COUNT */
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_clock.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_clock.c
new file mode 100644
index 0000000000..cb5ca96dab
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_clock.c
@@ -0,0 +1,1250 @@
+/*
+ * Copyright 2017 - 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_clock.h"
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.clock"
+#endif
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/* To make full use of CM7 hardware FPU, use double instead of uint64_t in clock driver to
+achieve better performance, it is depend on the IDE Floating point settings, if double precision is selected
+in IDE, clock_64b_t will switch to double type automatically. only support IAR and MDK here */
+#if __FPU_USED
+
+#if (defined(__ICCARM__))
+
+#if (__ARMVFP__ >= __ARMFPV5__) && \
+ (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/
+typedef double clock_64b_t;
+#else
+typedef uint64_t clock_64b_t;
+#endif
+
+#elif (defined(__GNUC__))
+
+#if (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/
+typedef double clock_64b_t;
+#else
+typedef uint64_t clock_64b_t;
+#endif
+
+#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
+
+#if defined __TARGET_FPU_FPV5_D16
+typedef double clock_64b_t;
+#else
+typedef uint64_t clock_64b_t;
+#endif
+
+#else
+typedef uint64_t clock_64b_t;
+#endif
+
+#else
+typedef uint64_t clock_64b_t;
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* External XTAL (OSC) clock frequency. */
+volatile uint32_t g_xtalFreq;
+/* External RTC XTAL clock frequency. */
+volatile uint32_t g_rtcXtalFreq;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the periph clock frequency.
+ *
+ * @return Periph clock frequency in Hz.
+ */
+static uint32_t CLOCK_GetPeriphClkFreq(void);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t CLOCK_GetPeriphClkFreq(void)
+{
+ uint32_t freq;
+
+ /* Periph_clk2_clk ---> Periph_clk */
+ if ((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK_SEL_MASK) != 0U)
+ {
+ switch (CCM->CBCMR & CCM_CBCMR_PERIPH_CLK2_SEL_MASK)
+ {
+ /* Pll3_sw_clk ---> Periph_clk2_clk ---> Periph_clk */
+ case CCM_CBCMR_PERIPH_CLK2_SEL(0U):
+ freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
+ break;
+
+ /* Osc_clk ---> Periph_clk2_clk ---> Periph_clk */
+ case CCM_CBCMR_PERIPH_CLK2_SEL(1U):
+ freq = CLOCK_GetOscFreq();
+ break;
+
+ case CCM_CBCMR_PERIPH_CLK2_SEL(2U):
+ freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
+ break;
+
+ case CCM_CBCMR_PERIPH_CLK2_SEL(3U):
+ default:
+ freq = 0U;
+ break;
+ }
+
+ freq /= (((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK2_PODF_MASK) >> CCM_CBCDR_PERIPH_CLK2_PODF_SHIFT) + 1U);
+ }
+ /* Pre_Periph_clk ---> Periph_clk */
+ else
+ {
+ switch (CCM->CBCMR & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)
+ {
+ /* PLL2 ---> Pre_Periph_clk ---> Periph_clk */
+ case CCM_CBCMR_PRE_PERIPH_CLK_SEL(0U):
+ freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
+ break;
+
+ /* PLL2 PFD2 ---> Pre_Periph_clk ---> Periph_clk */
+ case CCM_CBCMR_PRE_PERIPH_CLK_SEL(1U):
+ freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
+ break;
+
+ /* PLL2 PFD0 ---> Pre_Periph_clk ---> Periph_clk */
+ case CCM_CBCMR_PRE_PERIPH_CLK_SEL(2U):
+ freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
+ break;
+
+ /* PLL1 divided(/2) ---> Pre_Periph_clk ---> Periph_clk */
+ case CCM_CBCMR_PRE_PERIPH_CLK_SEL(3U):
+ freq = CLOCK_GetPllFreq(kCLOCK_PllArm) /
+ (((CCM->CACRR & CCM_CACRR_ARM_PODF_MASK) >> CCM_CACRR_ARM_PODF_SHIFT) + 1U);
+ break;
+
+ default:
+ freq = 0U;
+ break;
+ }
+ }
+
+ return freq;
+}
+
+/*!
+ * brief Initialize the external 24MHz clock.
+ *
+ * This function supports two modes:
+ * 1. Use external crystal oscillator.
+ * 2. Bypass the external crystal oscillator, using input source clock directly.
+ *
+ * After this function, please call ref CLOCK_SetXtal0Freq to inform clock driver
+ * the external clock frequency.
+ *
+ * param bypassXtalOsc Pass in true to bypass the external crystal oscillator.
+ * note This device does not support bypass external crystal oscillator, so
+ * the input parameter should always be false.
+ */
+void CLOCK_InitExternalClk(bool bypassXtalOsc)
+{
+ /* This device does not support bypass XTAL OSC. */
+ assert(!bypassXtalOsc);
+
+ CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power up */
+ while ((XTALOSC24M->LOWPWR_CTRL & XTALOSC24M_LOWPWR_CTRL_XTALOSC_PWRUP_STAT_MASK) == 0U)
+ {
+ }
+ CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; /* detect freq */
+ while ((CCM_ANALOG->MISC0 & CCM_ANALOG_MISC0_OSC_XTALOK_MASK) == 0UL)
+ {
+ }
+ CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK;
+}
+
+/*!
+ * brief Deinitialize the external 24MHz clock.
+ *
+ * This function disables the external 24MHz clock.
+ *
+ * After this function, please call ref CLOCK_SetXtal0Freq to set external clock
+ * frequency to 0.
+ */
+void CLOCK_DeinitExternalClk(void)
+{
+ CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power down */
+}
+
+/*!
+ * brief Switch the OSC.
+ *
+ * This function switches the OSC source for SoC.
+ *
+ * param osc OSC source to switch to.
+ */
+void CLOCK_SwitchOsc(clock_osc_t osc)
+{
+ if (osc == kCLOCK_RcOsc)
+ {
+ XTALOSC24M->LOWPWR_CTRL_SET = XTALOSC24M_LOWPWR_CTRL_SET_OSC_SEL_MASK;
+ }
+ else
+ {
+ XTALOSC24M->LOWPWR_CTRL_CLR = XTALOSC24M_LOWPWR_CTRL_CLR_OSC_SEL_MASK;
+ }
+}
+
+/*!
+ * brief Initialize the RC oscillator 24MHz clock.
+ */
+void CLOCK_InitRcOsc24M(void)
+{
+ XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
+}
+
+/*!
+ * brief Power down the RCOSC 24M clock.
+ */
+void CLOCK_DeinitRcOsc24M(void)
+{
+ XTALOSC24M->LOWPWR_CTRL &= ~XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
+}
+
+/*!
+ * brief Gets the AHB clock frequency.
+ *
+ * return The AHB clock frequency value in hertz.
+ */
+uint32_t CLOCK_GetAhbFreq(void)
+{
+ return CLOCK_GetPeriphClkFreq() / (((CCM->CBCDR & CCM_CBCDR_AHB_PODF_MASK) >> CCM_CBCDR_AHB_PODF_SHIFT) + 1U);
+}
+
+/*!
+ * brief Gets the SEMC clock frequency.
+ *
+ * return The SEMC clock frequency value in hertz.
+ */
+uint32_t CLOCK_GetSemcFreq(void)
+{
+ uint32_t freq;
+
+ /* SEMC alternative clock ---> SEMC Clock */
+ if ((CCM->CBCDR & CCM_CBCDR_SEMC_CLK_SEL_MASK) != 0U)
+ {
+ /* PLL3 PFD1 ---> SEMC alternative clock ---> SEMC Clock */
+ if ((CCM->CBCDR & CCM_CBCDR_SEMC_ALT_CLK_SEL_MASK) != 0U)
+ {
+ freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
+ }
+ /* PLL2 PFD2 ---> SEMC alternative clock ---> SEMC Clock */
+ else
+ {
+ freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
+ }
+ }
+ /* Periph_clk ---> SEMC Clock */
+ else
+ {
+ freq = CLOCK_GetPeriphClkFreq();
+ }
+
+ freq /= (((CCM->CBCDR & CCM_CBCDR_SEMC_PODF_MASK) >> CCM_CBCDR_SEMC_PODF_SHIFT) + 1U);
+
+ return freq;
+}
+
+/*!
+ * brief Gets the IPG clock frequency.
+ *
+ * return The IPG clock frequency value in hertz.
+ */
+uint32_t CLOCK_GetIpgFreq(void)
+{
+ return CLOCK_GetAhbFreq() / (((CCM->CBCDR & CCM_CBCDR_IPG_PODF_MASK) >> CCM_CBCDR_IPG_PODF_SHIFT) + 1U);
+}
+
+/*!
+ * brief Gets the PER clock frequency.
+ *
+ * return The PER clock frequency value in hertz.
+ */
+uint32_t CLOCK_GetPerClkFreq(void)
+{
+ uint32_t freq;
+
+ /* Osc_clk ---> PER Clock*/
+ if ((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK) != 0U)
+ {
+ freq = CLOCK_GetOscFreq();
+ }
+ /* Periph_clk ---> AHB Clock ---> IPG Clock ---> PER Clock */
+ else
+ {
+ freq = CLOCK_GetIpgFreq();
+ }
+
+ freq /= (((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_PODF_MASK) >> CCM_CSCMR1_PERCLK_PODF_SHIFT) + 1U);
+
+ return freq;
+}
+
+/*!
+ * brief Gets the clock frequency for a specific clock name.
+ *
+ * This function checks the current clock configurations and then calculates
+ * the clock frequency for a specific clock name defined in clock_name_t.
+ *
+ * param clockName Clock names defined in clock_name_t
+ * return Clock frequency value in hertz
+ */
+uint32_t CLOCK_GetFreq(clock_name_t name)
+{
+ uint32_t freq;
+
+ switch (name)
+ {
+ case kCLOCK_CpuClk:
+ case kCLOCK_AhbClk:
+ freq = CLOCK_GetAhbFreq();
+ break;
+
+ case kCLOCK_SemcClk:
+ freq = CLOCK_GetSemcFreq();
+ break;
+
+ case kCLOCK_IpgClk:
+ freq = CLOCK_GetIpgFreq();
+ break;
+
+ case kCLOCK_PerClk:
+ freq = CLOCK_GetPerClkFreq();
+ break;
+
+ case kCLOCK_OscClk:
+ freq = CLOCK_GetOscFreq();
+ break;
+ case kCLOCK_RtcClk:
+ freq = CLOCK_GetRtcFreq();
+ break;
+ case kCLOCK_ArmPllClk:
+ freq = CLOCK_GetPllFreq(kCLOCK_PllArm);
+ break;
+ case kCLOCK_Usb1PllClk:
+ freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
+ break;
+ case kCLOCK_Usb1PllPfd0Clk:
+ freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd0);
+ break;
+ case kCLOCK_Usb1PllPfd1Clk:
+ freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
+ break;
+ case kCLOCK_Usb1PllPfd2Clk:
+ freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
+ break;
+ case kCLOCK_Usb1PllPfd3Clk:
+ freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd3);
+ break;
+ case kCLOCK_Usb2PllClk:
+ freq = CLOCK_GetPllFreq(kCLOCK_PllUsb2);
+ break;
+ case kCLOCK_SysPllClk:
+ freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
+ break;
+ case kCLOCK_SysPllPfd0Clk:
+ freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
+ break;
+ case kCLOCK_SysPllPfd1Clk:
+ freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd1);
+ break;
+ case kCLOCK_SysPllPfd2Clk:
+ freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
+ break;
+ case kCLOCK_SysPllPfd3Clk:
+ freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd3);
+ break;
+ case kCLOCK_EnetPll0Clk:
+ freq = CLOCK_GetPllFreq(kCLOCK_PllEnet);
+ break;
+ case kCLOCK_EnetPll1Clk:
+ freq = CLOCK_GetPllFreq(kCLOCK_PllEnet25M);
+ break;
+ case kCLOCK_AudioPllClk:
+ freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
+ break;
+ case kCLOCK_VideoPllClk:
+ freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);
+ break;
+ default:
+ freq = 0U;
+ break;
+ }
+
+ return freq;
+}
+
+/*! brief Enable USB HS clock.
+ *
+ * This function only enables the access to USB HS prepheral, upper layer
+ * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY
+ * clock to use USB HS.
+ *
+ * param src USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.
+ * param freq USB HS does not care about the clock source, so this parameter is ignored.
+ * retval true The clock is set successfully.
+ * retval false The clock source is invalid to get proper USB HS clock.
+ */
+bool CLOCK_EnableUsbhs0Clock(clock_usb_src_t src, uint32_t freq)
+{
+ uint32_t i;
+ CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;
+ USB1->USBCMD |= USBHS_USBCMD_RST_MASK;
+
+ /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/
+ for (i = 0; i < 400000U; i++)
+ {
+ __ASM("nop");
+ }
+ PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |
+ (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
+ return true;
+}
+
+/*! brief Enable USB HS clock.
+ *
+ * This function only enables the access to USB HS prepheral, upper layer
+ * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY
+ * clock to use USB HS.
+ *
+ * param src USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.
+ * param freq USB HS does not care about the clock source, so this parameter is ignored.
+ * retval true The clock is set successfully.
+ * retval false The clock source is invalid to get proper USB HS clock.
+ */
+bool CLOCK_EnableUsbhs1Clock(clock_usb_src_t src, uint32_t freq)
+{
+ uint32_t i = 0;
+ CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;
+ USB2->USBCMD |= USBHS_USBCMD_RST_MASK;
+
+ /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/
+ for (i = 0; i < 400000U; i++)
+ {
+ __ASM("nop");
+ }
+ PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |
+ (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
+ return true;
+}
+
+/*! brief Enable USB HS PHY PLL clock.
+ *
+ * This function enables the internal 480MHz USB PHY PLL clock.
+ *
+ * param src USB HS PHY PLL clock source.
+ * param freq The frequency specified by src.
+ * retval true The clock is set successfully.
+ * retval false The clock source is invalid to get proper USB HS clock.
+ */
+bool CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
+{
+ const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
+ if ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_ENABLE_MASK) != 0U)
+ {
+ CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
+ }
+ else
+ {
+ CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);
+ }
+ USBPHY1->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
+ USBPHY1->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
+
+ USBPHY1->PWD = 0;
+ USBPHY1->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
+ USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;
+ return true;
+}
+
+/*! brief Disable USB HS PHY PLL clock.
+ *
+ * This function disables USB HS PHY PLL clock.
+ */
+void CLOCK_DisableUsbhs0PhyPllClock(void)
+{
+ CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
+ USBPHY1->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
+}
+
+/*!
+ * brief Initialize the ARM PLL.
+ *
+ * This function initialize the ARM PLL with specific settings
+ *
+ * param config configuration to set to PLL.
+ */
+void CLOCK_InitArmPll(const clock_arm_pll_config_t *config)
+{
+ /* Bypass PLL first */
+ CCM_ANALOG->PLL_ARM = (CCM_ANALOG->PLL_ARM & (~CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_MASK)) |
+ CCM_ANALOG_PLL_ARM_BYPASS_MASK | CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC(config->src);
+
+ CCM_ANALOG->PLL_ARM =
+ (CCM_ANALOG->PLL_ARM & (~(CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK | CCM_ANALOG_PLL_ARM_POWERDOWN_MASK))) |
+ CCM_ANALOG_PLL_ARM_ENABLE_MASK | CCM_ANALOG_PLL_ARM_DIV_SELECT(config->loopDivider);
+
+ while ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_MASK) == 0UL)
+ {
+ }
+
+ /* Disable Bypass */
+ CCM_ANALOG->PLL_ARM &= ~CCM_ANALOG_PLL_ARM_BYPASS_MASK;
+}
+
+/*!
+ * brief De-initialize the ARM PLL.
+ */
+void CLOCK_DeinitArmPll(void)
+{
+ CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_MASK;
+}
+
+/*!
+ * brief Initialize the System PLL.
+ *
+ * This function initializes the System PLL with specific settings
+ *
+ * param config Configuration to set to PLL.
+ */
+void CLOCK_InitSysPll(const clock_sys_pll_config_t *config)
+{
+ /* Bypass PLL first */
+ CCM_ANALOG->PLL_SYS = (CCM_ANALOG->PLL_SYS & (~CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK)) |
+ CCM_ANALOG_PLL_SYS_BYPASS_MASK | CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC(config->src);
+
+ CCM_ANALOG->PLL_SYS =
+ (CCM_ANALOG->PLL_SYS & (~(CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK | CCM_ANALOG_PLL_SYS_POWERDOWN_MASK))) |
+ CCM_ANALOG_PLL_SYS_ENABLE_MASK | CCM_ANALOG_PLL_SYS_DIV_SELECT(config->loopDivider);
+
+ /* Initialize the fractional mode */
+ CCM_ANALOG->PLL_SYS_NUM = CCM_ANALOG_PLL_SYS_NUM_A(config->numerator);
+ CCM_ANALOG->PLL_SYS_DENOM = CCM_ANALOG_PLL_SYS_DENOM_B(config->denominator);
+
+ /* Initialize the spread spectrum mode */
+ CCM_ANALOG->PLL_SYS_SS = CCM_ANALOG_PLL_SYS_SS_STEP(config->ss_step) |
+ CCM_ANALOG_PLL_SYS_SS_ENABLE(config->ss_enable) |
+ CCM_ANALOG_PLL_SYS_SS_STOP(config->ss_stop);
+
+ while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0UL)
+ {
+ }
+
+ /* Disable Bypass */
+ CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_BYPASS_MASK;
+}
+
+/*!
+ * brief De-initialize the System PLL.
+ */
+void CLOCK_DeinitSysPll(void)
+{
+ CCM_ANALOG->PLL_SYS = CCM_ANALOG_PLL_SYS_POWERDOWN_MASK;
+}
+
+/*!
+ * brief Initialize the USB1 PLL.
+ *
+ * This function initializes the USB1 PLL with specific settings
+ *
+ * param config Configuration to set to PLL.
+ */
+void CLOCK_InitUsb1Pll(const clock_usb_pll_config_t *config)
+{
+ /* Bypass PLL first */
+ CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) |
+ CCM_ANALOG_PLL_USB1_BYPASS_MASK | CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC(config->src);
+
+ CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) |
+ CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK |
+ CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider);
+
+ while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL)
+ {
+ }
+
+ /* Disable Bypass */
+ CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK;
+}
+
+/*!
+ * brief Deinitialize the USB1 PLL.
+ */
+void CLOCK_DeinitUsb1Pll(void)
+{
+ CCM_ANALOG->PLL_USB1 = 0U;
+}
+
+/*!
+ * brief Initialize the USB2 PLL.
+ *
+ * This function initializes the USB2 PLL with specific settings
+ *
+ * param config Configuration to set to PLL.
+ */
+void CLOCK_InitUsb2Pll(const clock_usb_pll_config_t *config)
+{
+ /* Bypass PLL first */
+ CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_MASK)) |
+ CCM_ANALOG_PLL_USB2_BYPASS_MASK | CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC(config->src);
+
+ CCM_ANALOG->PLL_USB2 = (CCM_ANALOG->PLL_USB2 & (~CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK)) |
+ CCM_ANALOG_PLL_USB2_ENABLE_MASK | CCM_ANALOG_PLL_USB2_POWER_MASK |
+ CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB2_DIV_SELECT(config->loopDivider);
+
+ while ((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_LOCK_MASK) == 0UL)
+ {
+ }
+
+ /* Disable Bypass */
+ CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_BYPASS_MASK;
+}
+
+/*!
+ * brief Deinitialize the USB2 PLL.
+ */
+void CLOCK_DeinitUsb2Pll(void)
+{
+ CCM_ANALOG->PLL_USB2 = 0U;
+}
+
+/*!
+ * brief Initializes the Audio PLL.
+ *
+ * This function initializes the Audio PLL with specific settings
+ *
+ * param config Configuration to set to PLL.
+ */
+void CLOCK_InitAudioPll(const clock_audio_pll_config_t *config)
+{
+ uint32_t pllAudio;
+ uint32_t misc2 = 0;
+
+ /* Bypass PLL first */
+ CCM_ANALOG->PLL_AUDIO = (CCM_ANALOG->PLL_AUDIO & (~CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC_MASK)) |
+ CCM_ANALOG_PLL_AUDIO_BYPASS_MASK | CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC(config->src);
+
+ CCM_ANALOG->PLL_AUDIO_NUM = CCM_ANALOG_PLL_AUDIO_NUM_A(config->numerator);
+ CCM_ANALOG->PLL_AUDIO_DENOM = CCM_ANALOG_PLL_AUDIO_DENOM_B(config->denominator);
+
+ /*
+ * Set post divider:
+ *
+ * ------------------------------------------------------------------------
+ * | config->postDivider | PLL_AUDIO[POST_DIV_SELECT] | MISC2[AUDIO_DIV] |
+ * ------------------------------------------------------------------------
+ * | 1 | 2 | 0 |
+ * ------------------------------------------------------------------------
+ * | 2 | 1 | 0 |
+ * ------------------------------------------------------------------------
+ * | 4 | 2 | 3 |
+ * ------------------------------------------------------------------------
+ * | 8 | 1 | 3 |
+ * ------------------------------------------------------------------------
+ * | 16 | 0 | 3 |
+ * ------------------------------------------------------------------------
+ */
+ pllAudio =
+ (CCM_ANALOG->PLL_AUDIO & (~(CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK | CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK))) |
+ CCM_ANALOG_PLL_AUDIO_ENABLE_MASK | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(config->loopDivider);
+
+ switch (config->postDivider)
+ {
+ case 16:
+ pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0);
+ misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
+ break;
+
+ case 8:
+ pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
+ misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
+ break;
+
+ case 4:
+ pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
+ misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
+ break;
+
+ case 2:
+ pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
+ break;
+
+ default:
+ pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
+ break;
+ }
+
+ CCM_ANALOG->MISC2 =
+ (CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK)) | misc2;
+
+ CCM_ANALOG->PLL_AUDIO = pllAudio;
+
+ while ((CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK_MASK) == 0UL)
+ {
+ }
+
+ /* Disable Bypass */
+ CCM_ANALOG->PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS_MASK;
+}
+
+/*!
+ * brief De-initialize the Audio PLL.
+ */
+void CLOCK_DeinitAudioPll(void)
+{
+ CCM_ANALOG->PLL_AUDIO = (uint32_t)CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK;
+}
+
+/*!
+ * brief Initialize the video PLL.
+ *
+ * This function configures the Video PLL with specific settings
+ *
+ * param config configuration to set to PLL.
+ */
+void CLOCK_InitVideoPll(const clock_video_pll_config_t *config)
+{
+ uint32_t pllVideo;
+ uint32_t misc2 = 0;
+
+ /* Bypass PLL first */
+ CCM_ANALOG->PLL_VIDEO = (CCM_ANALOG->PLL_VIDEO & (~CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK)) |
+ CCM_ANALOG_PLL_VIDEO_BYPASS_MASK | CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC(config->src);
+
+ CCM_ANALOG->PLL_VIDEO_NUM = CCM_ANALOG_PLL_VIDEO_NUM_A(config->numerator);
+ CCM_ANALOG->PLL_VIDEO_DENOM = CCM_ANALOG_PLL_VIDEO_DENOM_B(config->denominator);
+
+ /*
+ * Set post divider:
+ *
+ * ------------------------------------------------------------------------
+ * | config->postDivider | PLL_VIDEO[POST_DIV_SELECT] | MISC2[VIDEO_DIV] |
+ * ------------------------------------------------------------------------
+ * | 1 | 2 | 0 |
+ * ------------------------------------------------------------------------
+ * | 2 | 1 | 0 |
+ * ------------------------------------------------------------------------
+ * | 4 | 2 | 3 |
+ * ------------------------------------------------------------------------
+ * | 8 | 1 | 3 |
+ * ------------------------------------------------------------------------
+ * | 16 | 0 | 3 |
+ * ------------------------------------------------------------------------
+ */
+ pllVideo =
+ (CCM_ANALOG->PLL_VIDEO & (~(CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK | CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK))) |
+ CCM_ANALOG_PLL_VIDEO_ENABLE_MASK | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(config->loopDivider);
+
+ switch (config->postDivider)
+ {
+ case 16:
+ pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0);
+ misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
+ break;
+
+ case 8:
+ pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
+ misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
+ break;
+
+ case 4:
+ pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);
+ misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
+ break;
+
+ case 2:
+ pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
+ break;
+
+ default:
+ pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);
+ break;
+ }
+
+ CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~CCM_ANALOG_MISC2_VIDEO_DIV_MASK) | misc2;
+
+ CCM_ANALOG->PLL_VIDEO = pllVideo;
+
+ while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0UL)
+ {
+ }
+
+ /* Disable Bypass */
+ CCM_ANALOG->PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_BYPASS_MASK;
+}
+
+/*!
+ * brief De-initialize the Video PLL.
+ */
+void CLOCK_DeinitVideoPll(void)
+{
+ CCM_ANALOG->PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK;
+}
+
+/*!
+ * brief Initialize the ENET PLL.
+ *
+ * This function initializes the ENET PLL with specific settings.
+ *
+ * param config Configuration to set to PLL.
+ */
+void CLOCK_InitEnetPll(const clock_enet_pll_config_t *config)
+{
+ uint32_t enet_pll = CCM_ANALOG_PLL_ENET_DIV_SELECT(config->loopDivider);
+
+ CCM_ANALOG->PLL_ENET = (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK)) |
+ CCM_ANALOG_PLL_ENET_BYPASS_MASK | CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(config->src);
+
+ if (config->enableClkOutput)
+ {
+ enet_pll |= CCM_ANALOG_PLL_ENET_ENABLE_MASK;
+ }
+
+ if (config->enableClkOutput25M)
+ {
+ enet_pll |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK;
+ }
+
+ CCM_ANALOG->PLL_ENET =
+ (CCM_ANALOG->PLL_ENET & (~(CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_POWERDOWN_MASK))) |
+ enet_pll;
+
+ /* Wait for stable */
+ while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0UL)
+ {
+ }
+
+ /* Disable Bypass */
+ CCM_ANALOG->PLL_ENET &= ~CCM_ANALOG_PLL_ENET_BYPASS_MASK;
+}
+
+/*!
+ * brief Deinitialize the ENET PLL.
+ *
+ * This function disables the ENET PLL.
+ */
+void CLOCK_DeinitEnetPll(void)
+{
+ CCM_ANALOG->PLL_ENET = CCM_ANALOG_PLL_ENET_POWERDOWN_MASK;
+}
+
+/*!
+ * brief Get current PLL output frequency.
+ *
+ * This function get current output frequency of specific PLL
+ *
+ * param pll pll name to get frequency.
+ * return The PLL output frequency in hertz.
+ */
+uint32_t CLOCK_GetPllFreq(clock_pll_t pll)
+{
+ uint32_t freq;
+ uint32_t divSelect;
+ clock_64b_t freqTmp;
+
+ const uint32_t enetRefClkFreq[] = {
+ 25000000U, /* 25M */
+ 50000000U, /* 50M */
+ 100000000U, /* 100M */
+ 125000000U /* 125M */
+ };
+
+ /* check if PLL is enabled */
+ if (!CLOCK_IsPllEnabled(CCM_ANALOG, pll))
+ {
+ return 0U;
+ }
+
+ /* get pll reference clock */
+ freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, pll);
+
+ /* check if pll is bypassed */
+ if (CLOCK_IsPllBypassed(CCM_ANALOG, pll))
+ {
+ return freq;
+ }
+
+ switch (pll)
+ {
+ case kCLOCK_PllArm:
+ freq = ((freq * ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK) >>
+ CCM_ANALOG_PLL_ARM_DIV_SELECT_SHIFT)) >>
+ 1U);
+ break;
+ case kCLOCK_PllSys:
+ /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
+ freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_SYS_NUM)));
+ freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_SYS_DENOM));
+
+ if ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK) != 0U)
+ {
+ freq *= 22U;
+ }
+ else
+ {
+ freq *= 20U;
+ }
+
+ freq += (uint32_t)freqTmp;
+ break;
+
+ case kCLOCK_PllUsb1:
+ freq = (freq * (((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0UL) ? 22U : 20U));
+ break;
+
+ case kCLOCK_PllAudio:
+ /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
+ divSelect =
+ (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_AUDIO_DIV_SELECT_SHIFT;
+
+ freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_NUM)));
+ freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_DENOM));
+
+ freq = freq * divSelect + (uint32_t)freqTmp;
+
+ /* AUDIO PLL output = PLL output frequency / POSTDIV. */
+
+ /*
+ * Post divider:
+ *
+ * PLL_AUDIO[POST_DIV_SELECT]:
+ * 0x00: 4
+ * 0x01: 2
+ * 0x02: 1
+ *
+ * MISC2[AUDO_DIV]:
+ * 0x00: 1
+ * 0x01: 2
+ * 0x02: 1
+ * 0x03: 4
+ */
+ switch (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT_MASK)
+ {
+ case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0U):
+ freq = freq >> 2U;
+ break;
+
+ case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1U):
+ freq = freq >> 1U;
+ break;
+
+ case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2U):
+ freq = freq >> 0U;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ switch (CCM_ANALOG->MISC2 & (CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK))
+ {
+ case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
+ freq >>= 2U;
+ break;
+
+ case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
+ freq >>= 1U;
+ break;
+
+ case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):
+ case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):
+ freq >>= 0U;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ break;
+
+ case kCLOCK_PllVideo:
+ /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
+ divSelect =
+ (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT;
+
+ freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_NUM)));
+ freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_VIDEO_DENOM));
+ freq = freq * divSelect + (uint32_t)freqTmp;
+
+ /* VIDEO PLL output = PLL output frequency / POSTDIV. */
+
+ /*
+ * Post divider:
+ *
+ * PLL_VIDEO[POST_DIV_SELECT]:
+ * 0x00: 4
+ * 0x01: 2
+ * 0x02: 1
+ *
+ * MISC2[VIDEO_DIV]:
+ * 0x00: 1
+ * 0x01: 2
+ * 0x02: 1
+ * 0x03: 4
+ */
+ switch (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK)
+ {
+ case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0U):
+ freq = freq >> 2U;
+ break;
+
+ case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1U):
+ freq = freq >> 1U;
+ break;
+
+ case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2U):
+ freq = freq >> 0U;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ switch (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV_MASK)
+ {
+ case CCM_ANALOG_MISC2_VIDEO_DIV(3U):
+ freq >>= 2U;
+ break;
+
+ case CCM_ANALOG_MISC2_VIDEO_DIV(1U):
+ freq >>= 1U;
+ break;
+
+ case CCM_ANALOG_MISC2_VIDEO_DIV(0U):
+ case CCM_ANALOG_MISC2_VIDEO_DIV(2U):
+ freq >>= 0U;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ break;
+ case kCLOCK_PllEnet:
+ divSelect =
+ (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_ENET_DIV_SELECT_SHIFT;
+ freq = enetRefClkFreq[divSelect];
+ break;
+
+ case kCLOCK_PllEnet25M:
+ /* ref_enetpll1 if fixed at 25MHz. */
+ freq = 25000000UL;
+ break;
+
+ case kCLOCK_PllUsb2:
+ freq = (freq * (((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK) != 0U) ? 22U : 20U));
+ break;
+ default:
+ freq = 0U;
+ break;
+ }
+
+ return freq;
+}
+
+/*!
+ * brief Initialize the System PLL PFD.
+ *
+ * This function initializes the System PLL PFD. During new value setting,
+ * the clock output is disabled to prevent glitch.
+ *
+ * param pfd Which PFD clock to enable.
+ * param pfdFrac The PFD FRAC value.
+ * note It is recommended that PFD settings are kept between 12-35.
+ */
+void CLOCK_InitSysPfd(clock_pfd_t pfd, uint8_t pfdFrac)
+{
+ uint32_t pfdIndex = (uint32_t)pfd;
+ uint32_t pfd528;
+
+ pfd528 = CCM_ANALOG->PFD_528 &
+ ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
+ << (8UL * pfdIndex)));
+
+ /* Disable the clock output first. */
+ CCM_ANALOG->PFD_528 = pfd528 | ((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * pfdIndex));
+
+ /* Set the new value and enable output. */
+ CCM_ANALOG->PFD_528 = pfd528 | (CCM_ANALOG_PFD_528_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex));
+}
+
+/*!
+ * brief De-initialize the System PLL PFD.
+ *
+ * This function disables the System PLL PFD.
+ *
+ * param pfd Which PFD clock to disable.
+ */
+void CLOCK_DeinitSysPfd(clock_pfd_t pfd)
+{
+ CCM_ANALOG->PFD_528 |= (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8U * (uint8_t)pfd);
+}
+
+/*!
+ * brief Initialize the USB1 PLL PFD.
+ *
+ * This function initializes the USB1 PLL PFD. During new value setting,
+ * the clock output is disabled to prevent glitch.
+ *
+ * param pfd Which PFD clock to enable.
+ * param pfdFrac The PFD FRAC value.
+ * note It is recommended that PFD settings are kept between 12-35.
+ */
+void CLOCK_InitUsb1Pfd(clock_pfd_t pfd, uint8_t pfdFrac)
+{
+ uint32_t pfdIndex = (uint32_t)pfd;
+ uint32_t pfd480;
+
+ pfd480 = CCM_ANALOG->PFD_480 &
+ ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD0_FRAC_MASK)
+ << (8UL * pfdIndex)));
+
+ /* Disable the clock output first. */
+ CCM_ANALOG->PFD_480 = pfd480 | ((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * pfdIndex));
+
+ /* Set the new value and enable output. */
+ CCM_ANALOG->PFD_480 = pfd480 | (CCM_ANALOG_PFD_480_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex));
+}
+
+/*!
+ * brief De-initialize the USB1 PLL PFD.
+ *
+ * This function disables the USB1 PLL PFD.
+ *
+ * param pfd Which PFD clock to disable.
+ */
+void CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd)
+{
+ CCM_ANALOG->PFD_480 |= (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint8_t)pfd);
+}
+
+/*!
+ * brief Get current System PLL PFD output frequency.
+ *
+ * This function get current output frequency of specific System PLL PFD
+ *
+ * param pfd pfd name to get frequency.
+ * return The PFD output frequency in hertz.
+ */
+uint32_t CLOCK_GetSysPfdFreq(clock_pfd_t pfd)
+{
+ uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
+
+ switch (pfd)
+ {
+ case kCLOCK_Pfd0:
+ freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD0_FRAC_SHIFT);
+ break;
+
+ case kCLOCK_Pfd1:
+ freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD1_FRAC_SHIFT);
+ break;
+
+ case kCLOCK_Pfd2:
+ freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD2_FRAC_SHIFT);
+ break;
+
+ case kCLOCK_Pfd3:
+ freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD3_FRAC_SHIFT);
+ break;
+
+ default:
+ freq = 0U;
+ break;
+ }
+ freq *= 18U;
+
+ return freq;
+}
+
+/*!
+ * brief Get current USB1 PLL PFD output frequency.
+ *
+ * This function get current output frequency of specific USB1 PLL PFD
+ *
+ * param pfd pfd name to get frequency.
+ * return The PFD output frequency in hertz.
+ */
+uint32_t CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd)
+{
+ uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
+
+ switch (pfd)
+ {
+ case kCLOCK_Pfd0:
+ freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT);
+ break;
+
+ case kCLOCK_Pfd1:
+ freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD1_FRAC_SHIFT);
+ break;
+
+ case kCLOCK_Pfd2:
+ freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD2_FRAC_SHIFT);
+ break;
+
+ case kCLOCK_Pfd3:
+ freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD3_FRAC_SHIFT);
+ break;
+
+ default:
+ freq = 0U;
+ break;
+ }
+ freq *= 18U;
+
+ return freq;
+}
+
+/*! brief Enable USB HS PHY PLL clock.
+ *
+ * This function enables the internal 480MHz USB PHY PLL clock.
+ *
+ * param src USB HS PHY PLL clock source.
+ * param freq The frequency specified by src.
+ * retval true The clock is set successfully.
+ * retval false The clock source is invalid to get proper USB HS clock.
+ */
+bool CLOCK_EnableUsbhs1PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
+{
+ const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
+ CLOCK_InitUsb2Pll(&g_ccmConfigUsbPll);
+ USBPHY2->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
+ USBPHY2->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
+
+ USBPHY2->PWD = 0;
+ USBPHY2->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
+ USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;
+
+ return true;
+}
+
+/*! brief Disable USB HS PHY PLL clock.
+ *
+ * This function disables USB HS PHY PLL clock.
+ */
+void CLOCK_DisableUsbhs1PhyPllClock(void)
+{
+ CCM_ANALOG->PLL_USB2 &= ~CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK;
+ USBPHY2->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cmp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cmp.c
new file mode 100644
index 0000000000..8f6bed69b4
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_cmp.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_cmp.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.cmp"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for CMP module.
+ *
+ * @param base CMP peripheral base address
+ */
+static uint32_t CMP_GetInstance(CMP_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to CMP bases for each instance. */
+static CMP_Type *const s_cmpBases[] = CMP_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to CMP clocks for each instance. */
+static const clock_ip_name_t s_cmpClocks[] = CMP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t CMP_GetInstance(CMP_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_cmpBases); instance++)
+ {
+ if (s_cmpBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_cmpBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the CMP.
+ *
+ * This function initializes the CMP module. The operations included are as follows.
+ * - Enabling the clock for CMP module.
+ * - Configuring the comparator.
+ * - Enabling the CMP module.
+ * Note that for some devices, multiple CMP instances share the same clock gate. In this case, to enable the clock for
+ * any instance enables all CMPs. See the appropriate MCU reference manual for the clock assignment of the CMP.
+ *
+ * param base CMP peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void CMP_Init(CMP_Type *base, const cmp_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t tmp8;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_cmpClocks[CMP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure. */
+ CMP_Enable(base, false); /* Disable the CMP module during configuring. */
+ /* CMPx_CR1. */
+ tmp8 = (uint8_t)(base->CR1 & ~(CMP_CR1_PMODE_MASK | CMP_CR1_INV_MASK | CMP_CR1_COS_MASK | CMP_CR1_OPE_MASK));
+ if (true == config->enableHighSpeed)
+ {
+ tmp8 |= CMP_CR1_PMODE_MASK;
+ }
+ if (true == config->enableInvertOutput)
+ {
+ tmp8 |= CMP_CR1_INV_MASK;
+ }
+ if (true == config->useUnfilteredOutput)
+ {
+ tmp8 |= CMP_CR1_COS_MASK;
+ }
+ if (true == config->enablePinOut)
+ {
+ tmp8 |= CMP_CR1_OPE_MASK;
+ }
+#if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
+ if (true == config->enableTriggerMode)
+ {
+ tmp8 |= CMP_CR1_TRIGM_MASK;
+ }
+ else
+ {
+ tmp8 &= ~(uint8_t)CMP_CR1_TRIGM_MASK;
+ }
+#endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
+ base->CR1 = tmp8;
+
+ /* CMPx_CR0. */
+ tmp8 = base->CR0 & ~(uint8_t)CMP_CR0_HYSTCTR_MASK;
+ tmp8 |= CMP_CR0_HYSTCTR(config->hysteresisMode);
+ base->CR0 = tmp8;
+
+ CMP_Enable(base, config->enableCmp); /* Enable the CMP module after configured or not. */
+}
+
+/*!
+ * brief De-initializes the CMP module.
+ *
+ * This function de-initializes the CMP module. The operations included are as follows.
+ * - Disabling the CMP module.
+ * - Disabling the clock for CMP module.
+ *
+ * This function disables the clock for the CMP.
+ * Note that for some devices, multiple CMP instances share the same clock gate. In this case, before disabling the
+ * clock for the CMP, ensure that all the CMP instances are not used.
+ *
+ * param base CMP peripheral base address.
+ */
+void CMP_Deinit(CMP_Type *base)
+{
+ /* Disable the CMP module. */
+ CMP_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_cmpClocks[CMP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Initializes the CMP user configuration structure.
+ *
+ * This function initializes the user configuration structure to these default values.
+ * code
+ * config->enableCmp = true;
+ * config->hysteresisMode = kCMP_HysteresisLevel0;
+ * config->enableHighSpeed = false;
+ * config->enableInvertOutput = false;
+ * config->useUnfilteredOutput = false;
+ * config->enablePinOut = false;
+ * config->enableTriggerMode = false;
+ * endcode
+ * param config Pointer to the configuration structure.
+ */
+void CMP_GetDefaultConfig(cmp_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableCmp = true; /* Enable the CMP module after initialization. */
+ config->hysteresisMode = kCMP_HysteresisLevel0;
+ config->enableHighSpeed = false;
+ config->enableInvertOutput = false;
+ config->useUnfilteredOutput = false;
+ config->enablePinOut = false;
+#if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
+ config->enableTriggerMode = false;
+#endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
+}
+
+/*!
+ * brief Sets the input channels for the comparator.
+ *
+ * This function sets the input channels for the comparator.
+ * Note that two input channels cannot be set the same way in the application. When the user selects the same input
+ * from the analog mux to the positive and negative port, the comparator is disabled automatically.
+ *
+ * param base CMP peripheral base address.
+ * param positiveChannel Positive side input channel number. Available range is 0-7.
+ * param negativeChannel Negative side input channel number. Available range is 0-7.
+ */
+void CMP_SetInputChannels(CMP_Type *base, uint8_t positiveChannel, uint8_t negativeChannel)
+{
+ uint8_t tmp8 = base->MUXCR;
+
+ tmp8 &= ~(uint8_t)(CMP_MUXCR_PSEL_MASK | CMP_MUXCR_MSEL_MASK);
+ tmp8 |= CMP_MUXCR_PSEL(positiveChannel) | CMP_MUXCR_MSEL(negativeChannel);
+ base->MUXCR = tmp8;
+}
+
+#if defined(FSL_FEATURE_CMP_HAS_DMA) && FSL_FEATURE_CMP_HAS_DMA
+/*!
+ * brief Enables/disables the DMA request for rising/falling events.
+ *
+ * This function enables/disables the DMA request for rising/falling events. Either event triggers the generation of
+ * the DMA request from CMP if the DMA feature is enabled. Both events are ignored for generating the DMA request from
+ * the CMP
+ * if the DMA is disabled.
+ *
+ * param base CMP peripheral base address.
+ * param enable Enables or disables the feature.
+ */
+void CMP_EnableDMA(CMP_Type *base, bool enable)
+{
+ uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
+
+ if (enable)
+ {
+ tmp8 |= CMP_SCR_DMAEN_MASK;
+ }
+ else
+ {
+ tmp8 &= ~(uint8_t)CMP_SCR_DMAEN_MASK;
+ }
+ base->SCR = tmp8;
+}
+#endif /* FSL_FEATURE_CMP_HAS_DMA */
+
+/*!
+ * brief Configures the filter.
+ *
+ * param base CMP peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void CMP_SetFilterConfig(CMP_Type *base, const cmp_filter_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t tmp8;
+
+#if defined(FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT) && FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT
+ /* Choose the clock source for sampling. */
+ if (config->enableSample)
+ {
+ base->CR1 |= CMP_CR1_SE_MASK; /* Choose the external SAMPLE clock. */
+ }
+ else
+ {
+ base->CR1 &= (uint8_t)(~CMP_CR1_SE_MASK); /* Choose the internal divided bus clock. */
+ }
+#endif /* FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT */
+ /* Set the filter count. */
+ tmp8 = (uint8_t)(base->CR0 & ~CMP_CR0_FILTER_CNT_MASK);
+ tmp8 |= CMP_CR0_FILTER_CNT(config->filterCount);
+ base->CR0 = tmp8;
+ /* Set the filter period. It is used as the divider to bus clock. */
+ base->FPR = CMP_FPR_FILT_PER(config->filterPeriod);
+}
+
+/*!
+ * brief Configures the internal DAC.
+ *
+ * param base CMP peripheral base address.
+ * param config Pointer to the configuration structure. "NULL" disables the feature.
+ */
+void CMP_SetDACConfig(CMP_Type *base, const cmp_dac_config_t *config)
+{
+ uint8_t tmp8 = 0U;
+
+ if (NULL == config)
+ {
+ /* Passing "NULL" as input parameter means no available configuration. So the DAC feature is disabled.*/
+ base->DACCR = 0U;
+ return;
+ }
+ /* CMPx_DACCR. */
+ tmp8 |= CMP_DACCR_DACEN_MASK; /* Enable the internal DAC. */
+ if (kCMP_VrefSourceVin2 == config->referenceVoltageSource)
+ {
+ tmp8 |= CMP_DACCR_VRSEL_MASK;
+ }
+ tmp8 |= CMP_DACCR_VOSEL(config->DACValue);
+
+ base->DACCR = tmp8;
+}
+
+/*!
+ * brief Enables the interrupts.
+ *
+ * param base CMP peripheral base address.
+ * param mask Mask value for interrupts. See "_cmp_interrupt_enable".
+ */
+void CMP_EnableInterrupts(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
+
+ if (0U != ((uint32_t)kCMP_OutputRisingInterruptEnable & mask))
+ {
+ tmp8 |= CMP_SCR_IER_MASK;
+ }
+ if (0U != ((uint32_t)kCMP_OutputFallingInterruptEnable & mask))
+ {
+ tmp8 |= CMP_SCR_IEF_MASK;
+ }
+ base->SCR = tmp8;
+}
+
+/*!
+ * brief Disables the interrupts.
+ *
+ * param base CMP peripheral base address.
+ * param mask Mask value for interrupts. See "_cmp_interrupt_enable".
+ */
+void CMP_DisableInterrupts(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
+
+ if (0U != ((uint32_t)kCMP_OutputRisingInterruptEnable & mask))
+ {
+ tmp8 &= ~(uint8_t)CMP_SCR_IER_MASK;
+ }
+ if (0U != ((uint32_t)kCMP_OutputFallingInterruptEnable & mask))
+ {
+ tmp8 &= ~(uint8_t)CMP_SCR_IEF_MASK;
+ }
+ base->SCR = tmp8;
+}
+
+/*!
+ * brief Gets the status flags.
+ *
+ * param base CMP peripheral base address.
+ *
+ * return Mask value for the asserted flags. See "_cmp_status_flags".
+ */
+uint32_t CMP_GetStatusFlags(CMP_Type *base)
+{
+ uint32_t ret32 = 0U;
+
+ if (0U != (CMP_SCR_CFR_MASK & base->SCR))
+ {
+ ret32 |= (uint32_t)kCMP_OutputRisingEventFlag;
+ }
+ if (0U != (CMP_SCR_CFF_MASK & base->SCR))
+ {
+ ret32 |= (uint32_t)kCMP_OutputFallingEventFlag;
+ }
+ if (0U != (CMP_SCR_COUT_MASK & base->SCR))
+ {
+ ret32 |= (uint32_t)kCMP_OutputAssertEventFlag;
+ }
+ return ret32;
+}
+
+/*!
+ * brief Clears the status flags.
+ *
+ * param base CMP peripheral base address.
+ * param mask Mask value for the flags. See "_cmp_status_flags".
+ */
+void CMP_ClearStatusFlags(CMP_Type *base, uint32_t mask)
+{
+ uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
+
+ if (0U != ((uint32_t)kCMP_OutputRisingEventFlag & mask))
+ {
+ tmp8 |= CMP_SCR_CFR_MASK;
+ }
+ if (0U != ((uint32_t)kCMP_OutputFallingEventFlag & mask))
+ {
+ tmp8 |= CMP_SCR_CFF_MASK;
+ }
+ base->SCR = tmp8;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_common.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_common.c
new file mode 100644
index 0000000000..fd96a955c3
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_common.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_common.h"
+#define SDK_MEM_MAGIC_NUMBER 12345U
+
+typedef struct _mem_align_control_block
+{
+ uint16_t identifier; /*!< Identifier for the memory control block. */
+ uint16_t offset; /*!< offset from aligned address to real address */
+} mem_align_cb_t;
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.common"
+#endif
+
+#ifndef __GIC_PRIO_BITS
+#if defined(ENABLE_RAM_VECTOR_TABLE)
+uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler)
+{
+/* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
+ extern uint32_t Image$$VECTOR_ROM$$Base[];
+ extern uint32_t Image$$VECTOR_RAM$$Base[];
+ extern uint32_t Image$$RW_m_data$$Base[];
+
+#define __VECTOR_TABLE Image$$VECTOR_ROM$$Base
+#define __VECTOR_RAM Image$$VECTOR_RAM$$Base
+#define __RAM_VECTOR_TABLE_SIZE (((uint32_t)Image$$RW_m_data$$Base - (uint32_t)Image$$VECTOR_RAM$$Base))
+#elif defined(__ICCARM__)
+ extern uint32_t __RAM_VECTOR_TABLE_SIZE[];
+ extern uint32_t __VECTOR_TABLE[];
+ extern uint32_t __VECTOR_RAM[];
+#elif defined(__GNUC__)
+ extern uint32_t __VECTOR_TABLE[];
+ extern uint32_t __VECTOR_RAM[];
+ extern uint32_t __RAM_VECTOR_TABLE_SIZE_BYTES[];
+ uint32_t __RAM_VECTOR_TABLE_SIZE = (uint32_t)(__RAM_VECTOR_TABLE_SIZE_BYTES);
+#endif /* defined(__CC_ARM) || defined(__ARMCC_VERSION) */
+ uint32_t n;
+ uint32_t ret;
+ uint32_t irqMaskValue;
+
+ irqMaskValue = DisableGlobalIRQ();
+ if (SCB->VTOR != (uint32_t)__VECTOR_RAM)
+ {
+ /* Copy the vector table from ROM to RAM */
+ for (n = 0; n < ((uint32_t)__RAM_VECTOR_TABLE_SIZE) / sizeof(uint32_t); n++)
+ {
+ __VECTOR_RAM[n] = __VECTOR_TABLE[n];
+ }
+ /* Point the VTOR to the position of vector table */
+ SCB->VTOR = (uint32_t)__VECTOR_RAM;
+ }
+
+ ret = __VECTOR_RAM[irq + 16];
+ /* make sure the __VECTOR_RAM is noncachable */
+ __VECTOR_RAM[irq + 16] = irqHandler;
+
+ EnableGlobalIRQ(irqMaskValue);
+ SDK_ISR_EXIT_BARRIER;
+
+ return ret;
+}
+#endif /* ENABLE_RAM_VECTOR_TABLE. */
+#endif /* __GIC_PRIO_BITS. */
+
+#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
+#if !(defined(FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS) && FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS)
+
+void EnableDeepSleepIRQ(IRQn_Type interrupt)
+{
+ uint32_t intNumber = (uint32_t)interrupt;
+
+ uint32_t index = 0;
+
+ while (intNumber >= 32u)
+ {
+ index++;
+ intNumber -= 32u;
+ }
+
+ SYSCON->STARTERSET[index] = 1u << intNumber;
+ EnableIRQ(interrupt); /* also enable interrupt at NVIC */
+}
+
+void DisableDeepSleepIRQ(IRQn_Type interrupt)
+{
+ uint32_t intNumber = (uint32_t)interrupt;
+
+ DisableIRQ(interrupt); /* also disable interrupt at NVIC */
+ uint32_t index = 0;
+
+ while (intNumber >= 32u)
+ {
+ index++;
+ intNumber -= 32u;
+ }
+
+ SYSCON->STARTERCLR[index] = 1u << intNumber;
+}
+#endif /* FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS */
+#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
+
+void *SDK_Malloc(size_t size, size_t alignbytes)
+{
+ mem_align_cb_t *p_cb = NULL;
+ uint32_t alignedsize = SDK_SIZEALIGN(size, alignbytes) + alignbytes + sizeof(mem_align_cb_t);
+ union
+ {
+ void *pointer_value;
+ uint32_t unsigned_value;
+ } p_align_addr, p_addr;
+
+ p_addr.pointer_value = malloc(alignedsize);
+
+ if (p_addr.pointer_value == NULL)
+ {
+ return NULL;
+ }
+
+ p_align_addr.unsigned_value = SDK_SIZEALIGN(p_addr.unsigned_value + sizeof(mem_align_cb_t), alignbytes);
+
+ p_cb = (mem_align_cb_t *)(p_align_addr.unsigned_value - 4U);
+ p_cb->identifier = SDK_MEM_MAGIC_NUMBER;
+ p_cb->offset = (uint16_t)(p_align_addr.unsigned_value - p_addr.unsigned_value);
+
+ return p_align_addr.pointer_value;
+}
+
+void SDK_Free(void *ptr)
+{
+ union
+ {
+ void *pointer_value;
+ uint32_t unsigned_value;
+ } p_free;
+ p_free.pointer_value = ptr;
+ mem_align_cb_t *p_cb = (mem_align_cb_t *)(p_free.unsigned_value - 4U);
+
+ if (p_cb->identifier != SDK_MEM_MAGIC_NUMBER)
+ {
+ return;
+ }
+
+ p_free.unsigned_value = p_free.unsigned_value - p_cb->offset;
+
+ free(p_free.pointer_value);
+}
+
+/*!
+ * @brief Delay function bases on while loop, every loop includes three instructions.
+ *
+ * @param count Counts of loop needed for dalay.
+ */
+#if defined(SDK_DELAY_USE_DWT) && defined(DWT)
+void enableCpuCycleCounter(void)
+{
+ /* Make sure the DWT trace fucntion is enabled. */
+ if (CoreDebug_DEMCR_TRCENA_Msk != (CoreDebug_DEMCR_TRCENA_Msk & CoreDebug->DEMCR))
+ {
+ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+ }
+
+ /* CYCCNT not supported on this device. */
+ assert(DWT_CTRL_NOCYCCNT_Msk != (DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk));
+
+ /* Read CYCCNT directly if CYCCENT has already been enabled, otherwise enable CYCCENT first. */
+ if (DWT_CTRL_CYCCNTENA_Msk != (DWT_CTRL_CYCCNTENA_Msk & DWT->CTRL))
+ {
+ DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+ }
+}
+
+uint32_t getCpuCycleCount(void)
+{
+ return DWT->CYCCNT;
+}
+#elif defined __XCC__
+extern uint32_t xthal_get_ccount(void);
+void enableCpuCycleCounter(void)
+{
+ /* do nothing */
+}
+
+uint32_t getCpuCycleCount(void)
+{
+ return xthal_get_ccount();
+}
+#endif
+
+#ifndef __XCC__
+#if (!defined(SDK_DELAY_USE_DWT)) || (!defined(DWT))
+#if defined(__CC_ARM) /* This macro is arm v5 specific */
+/* clang-format off */
+__ASM static void DelayLoop(uint32_t count)
+{
+loop
+ SUBS R0, R0, #1
+ CMP R0, #0
+ BNE loop
+ BX LR
+}
+/* clang-format on */
+#elif defined(__ARMCC_VERSION) || defined(__ICCARM__) || defined(__GNUC__)
+/* Cortex-M0 has a smaller instruction set, SUBS isn't supported in thumb-16 mode reported from __GNUC__ compiler,
+ * use SUB and CMP here for compatibility */
+static void DelayLoop(uint32_t count)
+{
+ __ASM volatile(" MOV R0, %0" : : "r"(count));
+ __ASM volatile(
+ "loop: \n"
+#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
+ " SUB R0, R0, #1 \n"
+#else
+ " SUBS R0, R0, #1 \n"
+#endif
+ " CMP R0, #0 \n"
+
+ " BNE loop \n");
+}
+#endif /* defined(__CC_ARM) */
+#endif /* (!defined(SDK_DELAY_USE_DWT)) || (!defined(DWT)) */
+#endif /* __XCC__ */
+/*!
+ * @brief Delay at least for some time.
+ * Please note that, if not uses DWT, this API will use while loop for delay, different run-time environments have
+ * effect on the delay time. If precise delay is needed, please enable DWT delay. The two parmeters delay_us and
+ * coreClock_Hz have limitation. For example, in the platform with 1GHz coreClock_Hz, the delay_us only supports
+ * up to 4294967 in current code. If long time delay is needed, please implement a new delay function.
+ *
+ * @param delay_us Delay time in unit of microsecond.
+ * @param coreClock_Hz Core clock frequency with Hz.
+ */
+void SDK_DelayAtLeastUs(uint32_t delay_us, uint32_t coreClock_Hz)
+{
+ assert(0U != delay_us);
+ uint64_t count = USEC_TO_COUNT(delay_us, coreClock_Hz);
+ assert(count <= UINT32_MAX);
+
+#if defined(SDK_DELAY_USE_DWT) && defined(DWT) || (defined __XCC__) /* Use DWT for better accuracy */
+
+ enableCpuCycleCounter();
+ /* Calculate the count ticks. */
+ count += getCpuCycleCount();
+
+ if (count > UINT32_MAX)
+ {
+ count -= UINT32_MAX;
+ /* Wait for cyccnt overflow. */
+ while (count < getCpuCycleCount())
+ {
+ }
+ }
+
+ /* Wait for cyccnt reach count value. */
+ while (count > getCpuCycleCount())
+ {
+ }
+#else
+ /* Divide value may be different in various environment to ensure delay is precise.
+ * Every loop count includes three instructions, due to Cortex-M7 sometimes executes
+ * two instructions in one period, through test here set divide 1.5. Other M cores use
+ * divide 4. By the way, divide 1.5 or 4 could let the count lose precision, but it does
+ * not matter because other instructions outside while loop is enough to fill the time.
+ */
+#if (__CORTEX_M == 7)
+ count = count / 3U * 2U;
+#else
+ count = count / 4U;
+#endif
+ DelayLoop((uint32_t)count);
+#endif /* defined(SDK_DELAY_USE_DWT) && defined(DWT) || (defined __XCC__) */
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_csi.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_csi.c
new file mode 100644
index 0000000000..2eea263e5f
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_csi.c
@@ -0,0 +1,1395 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_csi.h"
+#if CSI_DRIVER_FRAG_MODE
+#include "fsl_cache.h"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.csi"
+#endif
+
+/* Two frame buffer loaded to CSI register at most. */
+#define CSI_MAX_ACTIVE_FRAME_NUM 2U
+
+/* CSI driver only support RGB565 and YUV422 in fragment mode, 2 bytes per pixel. */
+#define CSI_FRAG_INPUT_BYTES_PER_PIXEL 2U
+
+/*!
+ * @brief Used for conversion between `void*` and `uint32_t`.
+ */
+typedef union pvoid_to_u32
+{
+ void *pvoid;
+ uint32_t u32;
+} pvoid_to_u32_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the instance from the base address
+ *
+ * @param base CSI peripheral base address
+ *
+ * @return The CSI module instance
+ */
+static uint32_t CSI_GetInstance(CSI_Type *base);
+
+#if !CSI_DRIVER_FRAG_MODE
+/*!
+ * @brief Get the delta value of two index in queue.
+ *
+ * @param startIdx Start index.
+ * @param endIdx End index.
+ *
+ * @return The delta between startIdx and endIdx in queue.
+ */
+static uint8_t CSI_TransferGetQueueDelta(uint8_t startIdx, uint8_t endIdx);
+
+/*!
+ * @brief Increase a index value in queue.
+ *
+ * This function increases the index value in the queue, if the index is out of
+ * the queue range, it is reset to 0.
+ *
+ * @param idx The index value to increase.
+ *
+ * @return The index value after increase.
+ */
+static uint8_t CSI_TransferIncreaseQueueIdx(uint8_t idx);
+
+/*!
+ * @brief Get the empty frame buffer count in queue.
+ *
+ * @param base CSI peripheral base address
+ * @param handle Pointer to CSI driver handle.
+ *
+ * @return Number of the empty frame buffer count in queue.
+ */
+static uint32_t CSI_TransferGetEmptyBufferCount(csi_handle_t *handle);
+
+/*!
+ * @brief Get the empty frame buffer.
+ *
+ * This function should only be called when frame buffer count larger than 0.
+ *
+ * @param handle Pointer to CSI driver handle.
+ *
+ * @return Empty buffer
+ */
+static uint32_t CSI_TransferGetEmptyBuffer(csi_handle_t *handle);
+
+/*!
+ * @brief Put the empty frame buffer.
+ *
+ * @param handle Pointer to CSI driver handle.
+ * @param buffer The empty buffer to put.
+ */
+static void CSI_TransferPutEmptyBuffer(csi_handle_t *handle, uint32_t buffer);
+
+/*!
+ * @brief Get the RX frame buffer address.
+ *
+ * @param base CSI peripheral base address.
+ * @param index Buffer index.
+ * @return Frame buffer address.
+ */
+static uint32_t CSI_GetRxBufferAddr(CSI_Type *base, uint8_t index);
+
+/* Typedef for interrupt handler. */
+typedef void (*csi_isr_t)(CSI_Type *base, csi_handle_t *handle);
+
+#else
+
+/* Typedef for interrupt handler to work in fragment mode. */
+typedef void (*csi_isr_t)(CSI_Type *base, csi_frag_handle_t *handle);
+#endif /* CSI_DRIVER_FRAG_MODE */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to CSI bases for each instance. */
+static CSI_Type *const s_csiBases[] = CSI_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to CSI clocks for each CSI submodule. */
+static const clock_ip_name_t s_csiClocks[] = CSI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* Array for the CSI driver handle. */
+#if !CSI_DRIVER_FRAG_MODE
+static csi_handle_t *s_csiHandle[ARRAY_SIZE(s_csiBases)];
+#else
+static csi_frag_handle_t *s_csiHandle[ARRAY_SIZE(s_csiBases)];
+#endif
+
+/* Array of CSI IRQ number. */
+static const IRQn_Type s_csiIRQ[] = CSI_IRQS;
+
+/* CSI ISR for transactional APIs. */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+static csi_isr_t s_csiIsr = (csi_isr_t)DefaultISR;
+#else
+static csi_isr_t s_csiIsr;
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t CSI_GetInstance(CSI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_csiBases); instance++)
+ {
+ if (s_csiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_csiBases));
+
+ return instance;
+}
+
+#if !CSI_DRIVER_FRAG_MODE
+static uint8_t CSI_TransferGetQueueDelta(uint8_t startIdx, uint8_t endIdx)
+{
+ uint8_t ret;
+
+ if (endIdx >= startIdx)
+ {
+ ret = endIdx - startIdx;
+ }
+ else
+ {
+ ret = (uint8_t)(endIdx + CSI_DRIVER_ACTUAL_QUEUE_SIZE - startIdx);
+ }
+
+ return ret;
+}
+
+static uint8_t CSI_TransferIncreaseQueueIdx(uint8_t idx)
+{
+ uint8_t ret;
+
+ /*
+ * Here not use the method:
+ * ret = (idx+1) % CSI_DRIVER_ACTUAL_QUEUE_SIZE;
+ *
+ * Because the mod function might be slow.
+ */
+
+ ret = idx + 1U;
+
+ if (ret >= CSI_DRIVER_ACTUAL_QUEUE_SIZE)
+ {
+ ret = 0U;
+ }
+
+ return ret;
+}
+
+static uint32_t CSI_TransferGetEmptyBufferCount(csi_handle_t *handle)
+{
+ return handle->emptyBufferCnt;
+}
+
+static uint32_t CSI_TransferGetEmptyBuffer(csi_handle_t *handle)
+{
+ pvoid_to_u32_t buf;
+
+ buf.pvoid = handle->emptyBuffer;
+ handle->emptyBufferCnt--;
+ handle->emptyBuffer = *(void **)(buf.pvoid);
+
+ return buf.u32;
+}
+
+static void CSI_TransferPutEmptyBuffer(csi_handle_t *handle, uint32_t buffer)
+{
+ pvoid_to_u32_t buf;
+ buf.u32 = buffer;
+
+ *(void **)(buf.pvoid) = handle->emptyBuffer;
+ handle->emptyBuffer = buf.pvoid;
+ handle->emptyBufferCnt++;
+}
+
+static uint32_t CSI_GetRxBufferAddr(CSI_Type *base, uint8_t index)
+{
+ uint32_t addr;
+
+ if (index != 0U)
+ {
+ addr = base->CSIDMASA_FB2;
+ }
+ else
+ {
+ addr = base->CSIDMASA_FB1;
+ }
+
+ return addr;
+}
+
+#endif /* CSI_DRIVER_FRAG_MODE */
+
+/*!
+ * brief Initialize the CSI.
+ *
+ * This function enables the CSI peripheral clock, and resets the CSI registers.
+ *
+ * param base CSI peripheral base address.
+ * param config Pointer to the configuration structure.
+ *
+ * retval kStatus_Success Initialize successfully.
+ * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_Init(CSI_Type *base, const csi_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t reg;
+ uint32_t imgWidth_Bytes;
+ uint8_t busCyclePerPixel;
+
+ imgWidth_Bytes = (uint32_t)config->width * (uint32_t)config->bytesPerPixel;
+
+ /* The image width and frame buffer pitch should be multiple of 8-bytes. */
+ if ((0U != (imgWidth_Bytes & 0x07U)) || (0U != ((uint32_t)config->linePitch_Bytes & 0x07U)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = CSI_GetInstance(base);
+ CLOCK_EnableClock(s_csiClocks[instance]);
+#endif
+
+ CSI_Reset(base);
+
+ /* Configure CSICR1. CSICR1 has been reset to the default value, so could write it directly. */
+ reg = ((uint32_t)config->workMode) | config->polarityFlags | CSI_CSICR1_FCC_MASK;
+
+ if (config->useExtVsync)
+ {
+ reg |= CSI_CSICR1_EXT_VSYNC_MASK;
+ }
+
+ base->CSICR1 = reg;
+
+ /*
+ * Generally, CSIIMAG_PARA[IMAGE_WIDTH] indicates how many data bus cycles per line.
+ * One special case is when receiving 24-bit pixels through 8-bit data bus.
+ * In this case, the CSIIMAG_PARA[IMAGE_WIDTH] should be set to the pixel number per line.
+ */
+ if ((kCSI_DataBus8Bit == config->dataBus) && (2U == config->bytesPerPixel))
+ {
+ busCyclePerPixel = 2U;
+ }
+ else
+ {
+ busCyclePerPixel = 1U;
+ }
+
+ if (4U == config->bytesPerPixel)
+ {
+ base->CSICR18 |= CSI_CSICR18_PARALLEL24_EN_MASK;
+ }
+
+ if (kCSI_DataBus16Bit == config->dataBus)
+ {
+ base->CSICR3 |= CSI_CSICR3_TWO_8BIT_SENSOR_MASK;
+ }
+
+ /* Image parameter. */
+ base->CSIIMAG_PARA =
+ (((uint32_t)config->width * (uint32_t)busCyclePerPixel) << CSI_CSIIMAG_PARA_IMAGE_WIDTH_SHIFT) |
+ ((uint32_t)(config->height) << CSI_CSIIMAG_PARA_IMAGE_HEIGHT_SHIFT);
+
+ /* The CSI frame buffer bus is 8-byte width. */
+ base->CSIFBUF_PARA = (uint32_t)((config->linePitch_Bytes - imgWidth_Bytes) / 8U)
+ << CSI_CSIFBUF_PARA_FBUF_STRIDE_SHIFT;
+
+ /* Enable auto ECC. */
+ base->CSICR3 |= CSI_CSICR3_ECC_AUTO_EN_MASK;
+
+ /*
+ * For better performance.
+ * The DMA burst size could be set to 16 * 8 byte, 8 * 8 byte, or 4 * 8 byte,
+ * choose the best burst size based on bytes per line.
+ */
+ if (0U == (imgWidth_Bytes % (8U * 16U)))
+ {
+ base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(3U);
+ base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((2U << CSI_CSICR3_RxFF_LEVEL_SHIFT));
+ }
+ else if (0U == (imgWidth_Bytes % (8U * 8U)))
+ {
+ base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(2U);
+ base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((1U << CSI_CSICR3_RxFF_LEVEL_SHIFT));
+ }
+ else
+ {
+ base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(1U);
+ base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((0U << CSI_CSICR3_RxFF_LEVEL_SHIFT));
+ }
+
+ CSI_ReflashFifoDma(base, kCSI_RxFifo);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief De-initialize the CSI.
+ *
+ * This function disables the CSI peripheral clock.
+ *
+ * param base CSI peripheral base address.
+ */
+void CSI_Deinit(CSI_Type *base)
+{
+ /* Disable transfer first. */
+ CSI_Stop(base);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = CSI_GetInstance(base);
+ CLOCK_DisableClock(s_csiClocks[instance]);
+#endif
+}
+
+/*!
+ * brief Reset the CSI.
+ *
+ * This function resets the CSI peripheral registers to default status.
+ *
+ * param base CSI peripheral base address.
+ */
+void CSI_Reset(CSI_Type *base)
+{
+ uint32_t csisr;
+
+ /* Disable transfer first. */
+ CSI_Stop(base);
+
+ /* Disable DMA request. */
+ base->CSICR3 = 0U;
+
+ /* Reset the fame count. */
+ base->CSICR3 |= CSI_CSICR3_FRMCNT_RST_MASK;
+ while (0U != (base->CSICR3 & CSI_CSICR3_FRMCNT_RST_MASK))
+ {
+ }
+
+ /* Clear the RX FIFO. */
+ CSI_ClearFifo(base, kCSI_AllFifo);
+
+ /* Reflash DMA. */
+ CSI_ReflashFifoDma(base, kCSI_AllFifo);
+
+ /* Clear the status. */
+ csisr = base->CSISR;
+ base->CSISR = csisr;
+
+ /* Set the control registers to default value. */
+ base->CSICR1 = CSI_CSICR1_HSYNC_POL_MASK | CSI_CSICR1_EXT_VSYNC_MASK;
+ base->CSICR2 = 0U;
+ base->CSICR3 = 0U;
+#if defined(CSI_CSICR18_CSI_LCDIF_BUFFER_LINES)
+ base->CSICR18 = CSI_CSICR18_AHB_HPROT(0x0DU) | CSI_CSICR18_CSI_LCDIF_BUFFER_LINES(0x02U);
+#else
+ base->CSICR18 = CSI_CSICR18_AHB_HPROT(0x0DU);
+#endif
+ base->CSIFBUF_PARA = 0U;
+ base->CSIIMAG_PARA = 0U;
+}
+
+/*!
+ * brief Get the default configuration for to initialize the CSI.
+ *
+ * The default configuration value is:
+ *
+ * code
+ config->width = 320U;
+ config->height = 240U;
+ config->polarityFlags = kCSI_HsyncActiveHigh | kCSI_DataLatchOnRisingEdge;
+ config->bytesPerPixel = 2U;
+ config->linePitch_Bytes = 320U * 2U;
+ config->workMode = kCSI_GatedClockMode;
+ config->dataBus = kCSI_DataBus8Bit;
+ config->useExtVsync = true;
+ endcode
+ *
+ * param config Pointer to the CSI configuration.
+ */
+void CSI_GetDefaultConfig(csi_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->width = 320U;
+ config->height = 240U;
+ config->polarityFlags = (uint32_t)kCSI_HsyncActiveHigh | (uint32_t)kCSI_DataLatchOnRisingEdge;
+ config->bytesPerPixel = 2U;
+ config->linePitch_Bytes = 320U * 2U;
+ config->workMode = kCSI_GatedClockMode;
+ config->dataBus = kCSI_DataBus8Bit;
+ config->useExtVsync = true;
+}
+
+/*!
+ * brief Set the RX frame buffer address.
+ *
+ * param base CSI peripheral base address.
+ * param index Buffer index.
+ * param addr Frame buffer address to set.
+ */
+void CSI_SetRxBufferAddr(CSI_Type *base, uint8_t index, uint32_t addr)
+{
+ if (0U != index)
+ {
+ base->CSIDMASA_FB2 = addr;
+ }
+ else
+ {
+ base->CSIDMASA_FB1 = addr;
+ }
+}
+
+/*!
+ * brief Clear the CSI FIFO.
+ *
+ * This function clears the CSI FIFO.
+ *
+ * param base CSI peripheral base address.
+ * param fifo The FIFO to clear.
+ */
+void CSI_ClearFifo(CSI_Type *base, csi_fifo_t fifo)
+{
+ uint32_t cr1;
+ uint32_t mask = 0U;
+
+ /* The FIFO could only be cleared when CSICR1[FCC] = 0, so first clear the FCC. */
+ cr1 = base->CSICR1;
+ base->CSICR1 = (cr1 & ~CSI_CSICR1_FCC_MASK);
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
+ {
+ mask |= CSI_CSICR1_CLR_RXFIFO_MASK;
+ }
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
+ {
+ mask |= CSI_CSICR1_CLR_STATFIFO_MASK;
+ }
+
+ base->CSICR1 = (cr1 & ~CSI_CSICR1_FCC_MASK) | mask;
+
+ /* Wait clear completed. */
+ while (0U != (base->CSICR1 & mask))
+ {
+ }
+
+ /* Recover the FCC. */
+ base->CSICR1 = cr1;
+}
+
+/*!
+ * brief Reflash the CSI FIFO DMA.
+ *
+ * This function reflashes the CSI FIFO DMA.
+ *
+ * For RXFIFO, there are two frame buffers. When the CSI module started, it saves
+ * the frames to frame buffer 0 then frame buffer 1, the two buffers will be
+ * written by turns. After reflash DMA using this function, the CSI is reset to
+ * save frame to buffer 0.
+ *
+ * param base CSI peripheral base address.
+ * param fifo The FIFO DMA to reflash.
+ */
+void CSI_ReflashFifoDma(CSI_Type *base, csi_fifo_t fifo)
+{
+ uint32_t cr3 = 0U;
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
+ {
+ cr3 |= CSI_CSICR3_DMA_REFLASH_RFF_MASK;
+ }
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
+ {
+ cr3 |= CSI_CSICR3_DMA_REFLASH_SFF_MASK;
+ }
+
+ base->CSICR3 |= cr3;
+
+ /* Wait clear completed. */
+ while (0U != (base->CSICR3 & cr3))
+ {
+ }
+}
+
+/*!
+ * brief Enable or disable the CSI FIFO DMA request.
+ *
+ * param base CSI peripheral base address.
+ * param fifo The FIFO DMA reques to enable or disable.
+ * param enable True to enable, false to disable.
+ */
+void CSI_EnableFifoDmaRequest(CSI_Type *base, csi_fifo_t fifo, bool enable)
+{
+ uint32_t cr3 = 0U;
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_RxFifo))
+ {
+ cr3 |= CSI_CSICR3_DMA_REQ_EN_RFF_MASK;
+ }
+
+ if (0U != ((uint32_t)fifo & (uint32_t)kCSI_StatFifo))
+ {
+ cr3 |= CSI_CSICR3_DMA_REQ_EN_SFF_MASK;
+ }
+
+ if (enable)
+ {
+ base->CSICR3 |= cr3;
+ }
+ else
+ {
+ base->CSICR3 &= ~cr3;
+ }
+}
+
+/*!
+ * brief Enables CSI interrupt requests.
+ *
+ * param base CSI peripheral base address.
+ * param mask The interrupts to enable, pass in as OR'ed value of ref _csi_interrupt_enable.
+ */
+void CSI_EnableInterrupts(CSI_Type *base, uint32_t mask)
+{
+ base->CSICR1 |= (mask & CSI_CSICR1_INT_EN_MASK);
+ base->CSICR3 |= (mask & CSI_CSICR3_INT_EN_MASK);
+ base->CSICR18 |= ((mask & CSI_CSICR18_INT_EN_MASK) >> 6U);
+}
+
+/*!
+ * brief Disable CSI interrupt requests.
+ *
+ * param base CSI peripheral base address.
+ * param mask The interrupts to disable, pass in as OR'ed value of ref _csi_interrupt_enable.
+ */
+void CSI_DisableInterrupts(CSI_Type *base, uint32_t mask)
+{
+ base->CSICR1 &= ~(mask & CSI_CSICR1_INT_EN_MASK);
+ base->CSICR3 &= ~(mask & CSI_CSICR3_INT_EN_MASK);
+ base->CSICR18 &= ~((mask & CSI_CSICR18_INT_EN_MASK) >> 6U);
+}
+
+#if !CSI_DRIVER_FRAG_MODE
+/*!
+ * brief Initializes the CSI handle.
+ *
+ * This function initializes CSI handle, it should be called before any other
+ * CSI transactional functions.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ * param callback Callback function for CSI transfer.
+ * param userData Callback function parameter.
+ *
+ * retval kStatus_Success Handle created successfully.
+ */
+status_t CSI_TransferCreateHandle(CSI_Type *base,
+ csi_handle_t *handle,
+ csi_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+ uint32_t instance;
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set the callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Get instance from peripheral base address. */
+ instance = CSI_GetInstance(base);
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_csiHandle[instance] = handle;
+
+ s_csiIsr = CSI_TransferHandleIRQ;
+
+ /* Enable interrupt. */
+ (void)EnableIRQ(s_csiIRQ[instance]);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Start the transfer using transactional functions.
+ *
+ * When the empty frame buffers have been submit to CSI driver using function
+ * ref CSI_TransferSubmitEmptyBuffer, user could call this function to start
+ * the transfer. The incoming frame will be saved to the empty frame buffer,
+ * and user could be optionally notified through callback function.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ *
+ * retval kStatus_Success Started successfully.
+ * retval kStatus_CSI_NoEmptyBuffer Could not start because no empty frame buffer in queue.
+ */
+status_t CSI_TransferStart(CSI_Type *base, csi_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ uint32_t emptyBufferCount;
+
+ emptyBufferCount = CSI_TransferGetEmptyBufferCount(handle);
+
+ if (emptyBufferCount < 2U)
+ {
+ return kStatus_CSI_NoEmptyBuffer;
+ }
+
+ /*
+ * Write to memory from first completed frame.
+ * DMA base addr switch at the edge of the first data of each frame, thus
+ * if one frame is broken, it could be reset at the next frame.
+ */
+ base->CSICR18 = (base->CSICR18 & ~CSI_CSICR18_MASK_OPTION_MASK) | CSI_CSICR18_MASK_OPTION(0) |
+ CSI_CSICR18_BASEADDR_SWITCH_SEL_MASK | CSI_CSICR18_BASEADDR_SWITCH_EN_MASK;
+
+ /* Load the frame buffer to CSI register, there are at least two empty buffers. */
+ base->CSIDMASA_FB1 = CSI_TransferGetEmptyBuffer(handle);
+ base->CSIDMASA_FB2 = CSI_TransferGetEmptyBuffer(handle);
+
+ handle->activeBufferNum = CSI_MAX_ACTIVE_FRAME_NUM;
+
+ /* After reflash DMA, the CSI saves frame to frame buffer 0. */
+ CSI_ReflashFifoDma(base, kCSI_RxFifo);
+
+ handle->transferStarted = true;
+
+ CSI_EnableInterrupts(
+ base, (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable | (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+
+ CSI_Start(base);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Stop the transfer using transactional functions.
+ *
+ * The driver does not clean the full frame buffers in queue. In other words, after
+ * calling this function, user still could get the full frame buffers in queue
+ * using function ref CSI_TransferGetFullBuffer.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ *
+ * retval kStatus_Success Stoped successfully.
+ */
+status_t CSI_TransferStop(CSI_Type *base, csi_handle_t *handle)
+{
+ assert(NULL != handle);
+ uint8_t activeBufferNum;
+ uint8_t bufIdx;
+
+ CSI_Stop(base);
+ CSI_DisableInterrupts(
+ base, (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable | (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+
+ activeBufferNum = handle->activeBufferNum;
+
+ handle->transferStarted = false;
+ handle->activeBufferNum = 0;
+
+ /*
+ * Put active buffers to empty queue.
+ *
+ * If there is only one active frame buffers, then FB0 and FB1 use the same address,
+ * put FB0 to empty buffer queue is OK.
+ */
+ for (bufIdx = 0; bufIdx < activeBufferNum; bufIdx++)
+ {
+ CSI_TransferPutEmptyBuffer(handle, CSI_GetRxBufferAddr(base, bufIdx));
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Submit empty frame buffer to queue.
+ *
+ * This function could be called before ref CSI_TransferStart or after ref
+ * CSI_TransferStart. If there is no room in queue to store the empty frame
+ * buffer, this function returns error.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ * param frameBuffer Empty frame buffer to submit.
+ *
+ * retval kStatus_Success Started successfully.
+ * retval kStatus_CSI_QueueFull Could not submit because there is no room in queue.
+ */
+status_t CSI_TransferSubmitEmptyBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t frameBuffer)
+{
+ uint32_t csicr1;
+
+ /* Disable the interrupt to protect the index information in handle. */
+ csicr1 = base->CSICR1;
+
+ base->CSICR1 = (csicr1 & ~(CSI_CSICR1_FB2_DMA_DONE_INTEN_MASK | CSI_CSICR1_FB1_DMA_DONE_INTEN_MASK));
+
+ /* Save the empty frame buffer address to queue. */
+ CSI_TransferPutEmptyBuffer(handle, frameBuffer);
+
+ base->CSICR1 = csicr1;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Get one full frame buffer from queue.
+ *
+ * After the transfer started using function ref CSI_TransferStart, the incoming
+ * frames will be saved to the empty frame buffers in queue. This function gets
+ * the full-filled frame buffer from the queue. If there is no full frame buffer
+ * in queue, this function returns error.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the handle structure.
+ * param frameBuffer Full frame buffer.
+ *
+ * retval kStatus_Success Started successfully.
+ * retval kStatus_CSI_NoFullBuffer There is no full frame buffer in queue.
+ */
+status_t CSI_TransferGetFullBuffer(CSI_Type *base, csi_handle_t *handle, uint32_t *frameBuffer)
+{
+ uint32_t csicr1;
+ status_t status;
+ uint8_t queueReadIdx;
+ uint8_t queueWriteIdx;
+
+ queueReadIdx = handle->queueReadIdx;
+ queueWriteIdx = handle->queueWriteIdx;
+
+ /* No full frame buffer. */
+ if (queueReadIdx == queueWriteIdx)
+ {
+ status = kStatus_CSI_NoFullBuffer;
+ }
+ else
+ {
+ /* Disable the interrupt to protect the index information in handle. */
+ csicr1 = base->CSICR1;
+
+ base->CSICR1 = (csicr1 & ~(CSI_CSICR1_FB2_DMA_DONE_INTEN_MASK | CSI_CSICR1_FB1_DMA_DONE_INTEN_MASK));
+
+ *frameBuffer = handle->frameBufferQueue[handle->queueReadIdx];
+
+ handle->queueReadIdx = CSI_TransferIncreaseQueueIdx(handle->queueReadIdx);
+
+ base->CSICR1 = csicr1;
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief CSI IRQ handle function.
+ *
+ * This function handles the CSI IRQ request to work with CSI driver transactional
+ * APIs.
+ *
+ * param base CSI peripheral base address.
+ * param handle CSI handle pointer.
+ */
+void CSI_TransferHandleIRQ(CSI_Type *base, csi_handle_t *handle)
+{
+ uint8_t queueWriteIdx;
+ uint8_t queueReadIdx;
+ uint8_t dmaDoneBufferIdx;
+ uint32_t frameBuffer;
+ uint32_t csisr = base->CSISR;
+
+ /* Clear the error flags. */
+ base->CSISR = csisr;
+
+ /*
+ * If both frame buffer 0 and frame buffer 1 flags assert, driver does not
+ * know which frame buffer ready just now, so skip them.
+ */
+ if ((csisr & (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)) ==
+ (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK))
+ {
+ ; /* Skip the frames. */
+ }
+ else if (0U != (csisr & (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)))
+ {
+ if (0U != (csisr & CSI_CSISR_DMA_TSF_DONE_FB2_MASK))
+ {
+ dmaDoneBufferIdx = 1;
+ }
+ else
+ {
+ dmaDoneBufferIdx = 0;
+ }
+
+ if (handle->activeBufferNum == CSI_MAX_ACTIVE_FRAME_NUM)
+ {
+ queueWriteIdx = handle->queueWriteIdx;
+ queueReadIdx = handle->queueReadIdx;
+
+ if (CSI_TransferGetQueueDelta(queueReadIdx, queueWriteIdx) < CSI_DRIVER_QUEUE_SIZE)
+ {
+ /* Put the full frame buffer to full buffer queue. */
+ frameBuffer = CSI_GetRxBufferAddr(base, dmaDoneBufferIdx);
+ handle->frameBufferQueue[queueWriteIdx] = frameBuffer;
+
+ handle->queueWriteIdx = CSI_TransferIncreaseQueueIdx(queueWriteIdx);
+
+ handle->activeBufferNum--;
+
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_CSI_FrameDone, handle->userData);
+ }
+ }
+ else
+ {
+ }
+ }
+
+ /*
+ * User may submit new frame buffer in callback, so recheck activeBufferNum here,
+ * if there is only one active buffer in CSI device, the two buffer registers
+ * are both set to the frame buffer address.
+ */
+ if (handle->activeBufferNum < CSI_MAX_ACTIVE_FRAME_NUM)
+ {
+ if (CSI_TransferGetEmptyBufferCount(handle) > 0U)
+ {
+ /* Get the empty frameBuffer, and submit to CSI device. */
+ CSI_SetRxBufferAddr(base, dmaDoneBufferIdx, CSI_TransferGetEmptyBuffer(handle));
+ handle->activeBufferNum++;
+ }
+ else
+ {
+ /* If there is only one active frame buffer, then the two CSI
+ * output buffer address are all set to this frame buffer.
+ */
+ frameBuffer = CSI_GetRxBufferAddr(base, dmaDoneBufferIdx ^ 1U);
+ CSI_SetRxBufferAddr(base, dmaDoneBufferIdx, frameBuffer);
+ }
+ }
+ }
+ else
+ {
+ }
+}
+
+#else /* CSI_DRIVER_FRAG_MODE */
+
+#if defined(__CC_ARM)
+__asm void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count)
+{
+ /* clang-format off */
+ push {r4-r7, lr}
+10
+ LDMIA R1!, {r3-r6}
+ bfi r7, r3, #0, #8 /* Y0 */
+ bfi ip, r5, #0, #8 /* Y4 */
+ lsr r3, r3, #16
+ lsr r5, r5, #16
+ bfi r7, r3, #8, #8 /* Y1 */
+ bfi ip, r5, #8, #8 /* Y5 */
+ bfi r7, r4, #16, #8 /* Y2 */
+ bfi ip, r6, #16, #8 /* Y6 */
+ lsr r4, r4, #16
+ lsr r6, r6, #16
+ bfi r7, r4, #24, #8 /* Y3 */
+ bfi ip, r6, #24, #8 /* Y7 */
+ STMIA r0!, {r7, ip}
+ subs r2, #8
+ bne %b10
+ pop {r4-r7, pc}
+ /* clang-format on */
+}
+
+__asm void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count)
+{
+ /* clang-format off */
+ push {r4-r7, lr}
+10
+ LDMIA R1!, {r3-r6}
+ lsr r3, r3, #8
+ lsr r5, r5, #8
+ bfi r7, r3, #0, #8 /* Y0 */
+ bfi ip, r5, #0, #8 /* Y4 */
+ lsr r3, r3, #16
+ lsr r5, r5, #16
+ bfi r7, r3, #8, #8 /* Y1 */
+ bfi ip, r5, #8, #8 /* Y5 */
+ lsr r4, r4, #8
+ lsr r6, r6, #8
+ bfi r7, r4, #16, #8 /* Y2 */
+ bfi ip, r6, #16, #8 /* Y6 */
+ lsr r4, r4, #16
+ lsr r6, r6, #16
+ bfi r7, r4, #24, #8 /* Y3 */
+ bfi ip, r6, #24, #8 /* Y7 */
+ STMIA r0!, {r7, ip}
+ subs r2, #8
+ bne %b10
+ pop {r4-r7, pc}
+ /* clang-format on */
+}
+
+#elif (defined(__GNUC__) || defined(__ICCARM__)) || defined(__ARMCC_VERSION)
+#if defined(__ICCARM__)
+#pragma diag_suppress = Pe940
+#endif
+__attribute__((naked)) void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count);
+void CSI_ExtractYFromYUYV(void *datBase, const void *dmaBase, size_t count)
+{
+ /* clang-format off */
+ __asm volatile(
+ " push {r1-r7, r12, lr} \n"
+ "loop0: \n"
+ " ldmia r1!, {r3-r6} \n"
+ " bfi r7, r3, #0, #8 \n" /* Y0 */
+ " bfi r12, r5, #0, #8 \n" /* Y4 */
+ " lsr r3, r3, #16 \n"
+ " lsr r5, r5, #16 \n"
+ " bfi r7, r3, #8, #8 \n" /* Y1 */
+ " bfi r12, r5, #8, #8 \n" /* Y5 */
+ " bfi r7, r4, #16, #8 \n" /* Y2 */
+ " bfi r12, r6, #16, #8 \n" /* Y6 */
+ " lsr r4, r4, #16 \n"
+ " lsr r6, r6, #16 \n"
+ " bfi r7, r4, #24, #8 \n" /* Y3 */
+ " bfi r12, r6, #24, #8 \n" /* Y7 */
+ " stmia r0!, {r7, r12} \n"
+ " subs r2, #8 \n"
+ " bne loop0 \n"
+ " pop {r1-r7, r12, pc} \n");
+ /* clang-format on */
+}
+
+__attribute__((naked)) void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count);
+void CSI_ExtractYFromUYVY(void *datBase, const void *dmaBase, size_t count)
+{
+ /* clang-format off */
+ __asm volatile(
+ " push {r1-r7, r12, lr} \n"
+ "loop1: \n"
+ " ldmia r1!, {r3-r6} \n"
+ " lsr r3, r3, #8 \n"
+ " lsr r5, r5, #8 \n"
+ " bfi r7, r3, #0, #8 \n" /* Y0 */
+ " bfi r12, r5, #0, #8 \n" /* Y4 */
+ " lsr r3, r3, #16 \n"
+ " lsr r5, r5, #16 \n"
+ " bfi r7, r3, #8, #8 \n" /* Y1 */
+ " bfi r12, r5, #8, #8 \n" /* Y5 */
+ " lsr r4, r4, #8 \n"
+ " lsr r6, r6, #8 \n"
+ " bfi r7, r4, #16, #8 \n" /* Y2 */
+ " bfi r12, r6, #16, #8 \n" /* Y6 */
+ " lsr r4, r4, #16 \n"
+ " lsr r6, r6, #16 \n"
+ " bfi r7, r4, #24, #8 \n" /* Y3 */
+ " bfi r12, r6, #24, #8 \n" /* Y7 */
+ " stmia r0!, {r7, r12} \n"
+ " subs r2, #8 \n"
+ " bne loop1 \n"
+ " pop {r1-r7, r12, pc} \n");
+ /* clang-format on */
+}
+#if defined(__ICCARM__)
+#pragma diag_default = Pe940
+#endif
+#else
+#error Toolchain not supported.
+#endif
+
+static void CSI_MemCopy(void *pDest, const void *pSrc, size_t cnt)
+{
+ (void)memcpy(pDest, pSrc, cnt);
+}
+
+/*!
+ * brief Initialize the CSI to work in fragment mode.
+ *
+ * This function enables the CSI peripheral clock, and resets the CSI registers.
+ *
+ * param base CSI peripheral base address.
+ */
+void CSI_FragModeInit(CSI_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = CSI_GetInstance(base);
+ CLOCK_EnableClock(s_csiClocks[instance]);
+#endif
+
+ CSI_Reset(base);
+}
+
+/*!
+ * brief De-initialize the CSI.
+ *
+ * This function disables the CSI peripheral clock.
+ *
+ * param base CSI peripheral base address.
+ */
+void CSI_FragModeDeinit(CSI_Type *base)
+{
+ CSI_Deinit(base);
+}
+
+/*!
+ * brief Create handle for CSI work in fragment mode.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the transactional handle.
+ * param config Pointer to the configuration structure.
+ * param callback Callback function for CSI transfer.
+ * param userData Callback function parameter.
+ *
+ * retval kStatus_Success Initialize successfully.
+ * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_FragModeCreateHandle(CSI_Type *base,
+ csi_frag_handle_t *handle,
+ const csi_frag_config_t *config,
+ csi_frag_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != config);
+ uint32_t reg;
+ uint32_t instance;
+ uint32_t imgWidth_Bytes;
+
+ if (config->dataBus != kCSI_DataBus8Bit)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ imgWidth_Bytes = (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
+
+ /* The image buffer line width should be multiple of 8-bytes. */
+ if ((imgWidth_Bytes & 0x07U) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Camera frame height must be dividable by DMA buffer line. */
+ if (config->height % config->dmaBufferLine != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ (void)memset(handle, 0, sizeof(*handle));
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->height = config->height;
+ handle->width = config->width;
+ handle->maxLinePerFrag = config->dmaBufferLine;
+ handle->dmaBytePerLine = config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
+ handle->isDmaBufferCachable = config->isDmaBufferCachable;
+
+ /* Get instance from peripheral base address. */
+ instance = CSI_GetInstance(base);
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_csiHandle[instance] = handle;
+
+ s_csiIsr = CSI_FragModeTransferHandleIRQ;
+
+ EnableIRQ(s_csiIRQ[instance]);
+
+ /* Configure CSICR1. CSICR1 has been reset to the default value, so could write it directly. */
+ reg = ((uint32_t)config->workMode) | config->polarityFlags | CSI_CSICR1_FCC_MASK;
+
+ if (config->useExtVsync)
+ {
+ reg |= CSI_CSICR1_EXT_VSYNC_MASK;
+ }
+
+ base->CSICR1 = reg;
+
+ /* No stride. */
+ base->CSIFBUF_PARA = 0;
+
+ /* Enable auto ECC. */
+ base->CSICR3 |= CSI_CSICR3_ECC_AUTO_EN_MASK;
+
+ /*
+ * For better performance.
+ * The DMA burst size could be set to 16 * 8 byte, 8 * 8 byte, or 4 * 8 byte,
+ * choose the best burst size based on bytes per line.
+ */
+ if (0U == (imgWidth_Bytes % (8U * 16U)))
+ {
+ base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(3U);
+ base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((2U << CSI_CSICR3_RxFF_LEVEL_SHIFT));
+ }
+ else if (0U == (imgWidth_Bytes % (8U * 8U)))
+ {
+ base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(2U);
+ base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((1U << CSI_CSICR3_RxFF_LEVEL_SHIFT));
+ }
+ else
+ {
+ base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(1U);
+ base->CSICR3 = (CSI->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | ((0U << CSI_CSICR3_RxFF_LEVEL_SHIFT));
+ }
+
+ base->CSIDMASA_FB1 = config->dmaBufferAddr0;
+ base->CSIDMASA_FB2 = config->dmaBufferAddr1;
+
+ if (handle->isDmaBufferCachable)
+ {
+ DCACHE_CleanInvalidateByRange(
+ config->dmaBufferAddr0,
+ (uint32_t)config->dmaBufferLine * (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
+ DCACHE_CleanInvalidateByRange(
+ config->dmaBufferAddr1,
+ (uint32_t)config->dmaBufferLine * (uint32_t)config->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Start to capture a image.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the transactional handle.
+ * param config Pointer to the capture configuration.
+ *
+ * retval kStatus_Success Initialize successfully.
+ * retval kStatus_InvalidArgument Initialize failed because of invalid argument.
+ */
+status_t CSI_FragModeTransferCaptureImage(CSI_Type *base,
+ csi_frag_handle_t *handle,
+ const csi_frag_capture_config_t *config)
+{
+ assert(NULL != config);
+
+ uint16_t windowWidth;
+
+ /*
+ * If no special window setting, capture full frame.
+ * If capture window, then capture 1 one each fragment.
+ */
+ if (config->window != NULL)
+ {
+ handle->windowULX = config->window->windowULX;
+ handle->windowULY = config->window->windowULY;
+ handle->windowLRX = config->window->windowLRX;
+ handle->windowLRY = config->window->windowLRY;
+ handle->linePerFrag = 1;
+ }
+ else
+ {
+ handle->windowULX = 0;
+ handle->windowULY = 0;
+ handle->windowLRX = handle->width - 1U;
+ handle->windowLRY = handle->height - 1U;
+ handle->linePerFrag = handle->maxLinePerFrag;
+ }
+
+ windowWidth = handle->windowLRX - handle->windowULX + 1U;
+
+ if (config->outputGrayScale)
+ {
+ /* When output format is gray, the window width must be multiple value of 8. */
+ if (windowWidth % 8U != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ handle->datBytePerLine = windowWidth;
+ if (handle->inputFormat == kCSI_FragInputYUYV)
+ {
+ handle->copyFunc = CSI_ExtractYFromYUYV;
+ }
+ else
+ {
+ handle->copyFunc = CSI_ExtractYFromUYVY;
+ }
+ }
+ else
+ {
+ handle->datBytePerLine = windowWidth * CSI_FRAG_INPUT_BYTES_PER_PIXEL;
+ handle->copyFunc = CSI_MemCopy;
+ }
+
+ handle->dmaCurLine = 0;
+ handle->outputBuffer = (uint32_t)config->buffer;
+ handle->datCurWriteAddr = (uint32_t)config->buffer;
+
+ /* Image parameter. */
+ base->CSIIMAG_PARA =
+ (((uint32_t)handle->width * CSI_FRAG_INPUT_BYTES_PER_PIXEL) << CSI_CSIIMAG_PARA_IMAGE_WIDTH_SHIFT) |
+ ((uint32_t)(handle->linePerFrag) << CSI_CSIIMAG_PARA_IMAGE_HEIGHT_SHIFT);
+
+ /*
+ * Write to memory from first completed frame.
+ * DMA base addr switch at dma transfer done.
+ */
+ base->CSICR18 = (base->CSICR18 & ~CSI_CSICR18_MASK_OPTION_MASK) | CSI_CSICR18_MASK_OPTION(0);
+
+ CSI_EnableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
+ (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
+ (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Abort image capture.
+ *
+ * Abort image capture initialized by ref CSI_FragModeTransferCaptureImage.
+ *
+ * param base CSI peripheral base address.
+ * param handle Pointer to the transactional handle.
+ */
+void CSI_FragModeTransferAbortCaptureImage(CSI_Type *base, csi_frag_handle_t *handle)
+{
+ CSI_Stop(base);
+ CSI_DisableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
+ (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
+ (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+}
+
+/*!
+ * brief CSI IRQ handle function.
+ *
+ * This function handles the CSI IRQ request to work with CSI driver fragment mode
+ * APIs.
+ *
+ * param base CSI peripheral base address.
+ * param handle CSI handle pointer.
+ */
+void CSI_FragModeTransferHandleIRQ(CSI_Type *base, csi_frag_handle_t *handle)
+{
+ uint32_t csisr = base->CSISR;
+ uint32_t dmaBufAddr;
+ uint16_t line;
+ pvoid_to_u32_t memSrc;
+ pvoid_to_u32_t memDest;
+
+ /* Clear the error flags. */
+ base->CSISR = csisr;
+
+ /* Start of frame, clear the FIFO and start receiving. */
+ if (0U != (csisr & (uint32_t)kCSI_StartOfFrameFlag))
+ {
+ /* Reflash the DMA and enable RX DMA request. */
+ base->CSICR3 |= (CSI_CSICR3_DMA_REFLASH_RFF_MASK | CSI_CSICR3_DMA_REQ_EN_RFF_MASK);
+ CSI_Start(base);
+ handle->dmaCurLine = 0;
+ handle->datCurWriteAddr = handle->outputBuffer;
+ }
+ else if ((csisr & (CSI_CSISR_DMA_TSF_DONE_FB2_MASK | CSI_CSISR_DMA_TSF_DONE_FB1_MASK)) != 0U)
+ {
+ if ((csisr & CSI_CSISR_DMA_TSF_DONE_FB1_MASK) == CSI_CSISR_DMA_TSF_DONE_FB1_MASK)
+ {
+ dmaBufAddr = base->CSIDMASA_FB1;
+ }
+ else
+ {
+ dmaBufAddr = base->CSIDMASA_FB2;
+ }
+
+ if (handle->isDmaBufferCachable)
+ {
+ DCACHE_InvalidateByRange(dmaBufAddr, (uint32_t)handle->dmaBytePerLine * (uint32_t)handle->linePerFrag);
+ }
+
+ /* Copy from DMA buffer to user data buffer. */
+ dmaBufAddr += ((uint32_t)handle->windowULX * CSI_FRAG_INPUT_BYTES_PER_PIXEL);
+
+ for (line = 0; line < handle->linePerFrag; line++)
+ {
+ if (handle->dmaCurLine + line > handle->windowLRY)
+ {
+ /* out of window range */
+ break;
+ }
+ else if (handle->dmaCurLine + line >= handle->windowULY)
+ {
+ memDest.u32 = handle->datCurWriteAddr;
+ memSrc.u32 = dmaBufAddr;
+
+ handle->copyFunc(memDest.pvoid, memSrc.pvoid, handle->datBytePerLine);
+ handle->datCurWriteAddr += handle->datBytePerLine;
+ dmaBufAddr += handle->dmaBytePerLine;
+ }
+ else
+ {
+ ; /* For MISRA C-2012 Rule 15.7 */
+ }
+ }
+
+ handle->dmaCurLine += handle->linePerFrag;
+
+ if (handle->dmaCurLine >= handle->height)
+ {
+ CSI_Stop(base);
+ CSI_DisableInterrupts(base, (uint32_t)kCSI_StartOfFrameInterruptEnable |
+ (uint32_t)kCSI_RxBuffer1DmaDoneInterruptEnable |
+ (uint32_t)kCSI_RxBuffer0DmaDoneInterruptEnable);
+
+ /* Image captured. Stop the CSI. */
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_CSI_FrameDone, handle->userData);
+ }
+ }
+ }
+ else
+ {
+ }
+}
+#endif /* CSI_DRIVER_FRAG_MODE */
+
+#if defined(CSI)
+void CSI_DriverIRQHandler(void)
+{
+ s_csiIsr(CSI, s_csiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CSI0)
+void CSI0_DriverIRQHandler(void)
+{
+ s_csiIsr(CSI, s_csiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcdc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcdc.c
new file mode 100644
index 0000000000..fa290939bd
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcdc.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2017-2019, NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dcdc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.dcdc_1"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for DCDC module.
+ *
+ * @param base DCDC peripheral base address
+ */
+static uint32_t DCDC_GetInstance(DCDC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to DCDC bases for each instance. */
+static DCDC_Type *const s_dcdcBases[] = DCDC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to DCDC clocks for each instance. */
+static const clock_ip_name_t s_dcdcClocks[] = DCDC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t DCDC_GetInstance(DCDC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dcdcBases); instance++)
+ {
+ if (s_dcdcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dcdcBases));
+
+ return instance;
+}
+
+/*!
+ * brief Enable the access to DCDC registers.
+ *
+ * param base DCDC peripheral base address.
+ */
+void DCDC_Init(DCDC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_dcdcClocks[DCDC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Disable the access to DCDC registers.
+ *
+ * param base DCDC peripheral base address.
+ */
+void DCDC_Deinit(DCDC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_dcdcClocks[DCDC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Configure the DCDC clock source.
+ *
+ * param base DCDC peripheral base address.
+ * param clockSource Clock source for DCDC. See to "dcdc_clock_source_t".
+ */
+void DCDC_SetClockSource(DCDC_Type *base, dcdc_clock_source_t clockSource)
+{
+ uint32_t tmp32;
+
+ /* Configure the DCDC_REG0 register. */
+ tmp32 = base->REG0 & ~(DCDC_REG0_XTAL_24M_OK_MASK | DCDC_REG0_DISABLE_AUTO_CLK_SWITCH_MASK |
+ DCDC_REG0_SEL_CLK_MASK | DCDC_REG0_PWD_OSC_INT_MASK);
+ switch (clockSource)
+ {
+ case kDCDC_ClockInternalOsc:
+ tmp32 |= DCDC_REG0_DISABLE_AUTO_CLK_SWITCH_MASK;
+ break;
+ case kDCDC_ClockExternalOsc:
+ /* Choose the external clock and disable the internal clock. */
+ tmp32 |= DCDC_REG0_DISABLE_AUTO_CLK_SWITCH_MASK | DCDC_REG0_SEL_CLK_MASK | DCDC_REG0_PWD_OSC_INT_MASK;
+ break;
+ case kDCDC_ClockAutoSwitch:
+ /* Set to switch from internal ring osc to xtal 24M if auto mode is enabled. */
+ tmp32 |= DCDC_REG0_XTAL_24M_OK_MASK;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->REG0 = tmp32;
+}
+
+/*!
+ * brief Get the default setting for detection configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * code
+ * config->enableXtalokDetection = false;
+ * config->powerDownOverVoltageDetection = true;
+ * config->powerDownLowVlotageDetection = false;
+ * config->powerDownOverCurrentDetection = true;
+ * config->powerDownPeakCurrentDetection = true;
+ * config->powerDownZeroCrossDetection = true;
+ * config->OverCurrentThreshold = kDCDC_OverCurrentThresholdAlt0;
+ * config->PeakCurrentThreshold = kDCDC_PeakCurrentThresholdAlt0;
+ * endcode
+ *
+ * param config Pointer to configuration structure. See to "dcdc_detection_config_t"
+ */
+void DCDC_GetDefaultDetectionConfig(dcdc_detection_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableXtalokDetection = false;
+ config->powerDownOverVoltageDetection = true;
+ config->powerDownLowVlotageDetection = false;
+ config->powerDownOverCurrentDetection = true;
+ config->powerDownPeakCurrentDetection = true;
+ config->powerDownZeroCrossDetection = true;
+ config->OverCurrentThreshold = kDCDC_OverCurrentThresholdAlt0;
+ config->PeakCurrentThreshold = kDCDC_PeakCurrentThresholdAlt0;
+}
+
+/*!
+ * breif Configure the DCDC detection.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_detection_config_t"
+ */
+void DCDC_SetDetectionConfig(DCDC_Type *base, const dcdc_detection_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+ /* Configure the DCDC_REG0 register. */
+ tmp32 = base->REG0 &
+ ~(DCDC_REG0_XTALOK_DISABLE_MASK | DCDC_REG0_PWD_HIGH_VOLT_DET_MASK | DCDC_REG0_PWD_CMP_BATT_DET_MASK |
+ DCDC_REG0_PWD_OVERCUR_DET_MASK | DCDC_REG0_PWD_CUR_SNS_CMP_MASK | DCDC_REG0_PWD_ZCD_MASK |
+ DCDC_REG0_CUR_SNS_THRSH_MASK | DCDC_REG0_OVERCUR_TRIG_ADJ_MASK);
+
+ tmp32 |= DCDC_REG0_CUR_SNS_THRSH(config->PeakCurrentThreshold) |
+ DCDC_REG0_OVERCUR_TRIG_ADJ(config->OverCurrentThreshold);
+ if (false == config->enableXtalokDetection)
+ {
+ tmp32 |= DCDC_REG0_XTALOK_DISABLE_MASK;
+ }
+ if (config->powerDownOverVoltageDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_HIGH_VOLT_DET_MASK;
+ }
+ if (config->powerDownLowVlotageDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_CMP_BATT_DET_MASK;
+ }
+ if (config->powerDownOverCurrentDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_OVERCUR_DET_MASK;
+ }
+ if (config->powerDownPeakCurrentDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_CUR_SNS_CMP_MASK;
+ }
+ if (config->powerDownZeroCrossDetection)
+ {
+ tmp32 |= DCDC_REG0_PWD_ZCD_MASK;
+ }
+ base->REG0 = tmp32;
+}
+
+/*!
+ * brief Get the default setting for low power configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * code
+ * config->enableOverloadDetection = true;
+ * config->enableAdjustHystereticValue = false;
+ * config->countChargingTimePeriod = kDCDC_CountChargingTimePeriod8Cycle;
+ * config->countChargingTimeThreshold = kDCDC_CountChargingTimeThreshold32;
+ * endcode
+ *
+ * param config Pointer to configuration structure. See to "dcdc_low_power_config_t"
+ */
+void DCDC_GetDefaultLowPowerConfig(dcdc_low_power_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableOverloadDetection = true;
+ config->enableAdjustHystereticValue = false;
+ config->countChargingTimePeriod = kDCDC_CountChargingTimePeriod8Cycle;
+ config->countChargingTimeThreshold = kDCDC_CountChargingTimeThreshold32;
+}
+
+/*!
+ * brief Configure the DCDC low power.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_low_power_config_t".
+ */
+void DCDC_SetLowPowerConfig(DCDC_Type *base, const dcdc_low_power_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+ /* Configure the DCDC_REG0 register. */
+ tmp32 = base->REG0 & ~(DCDC_REG0_EN_LP_OVERLOAD_SNS_MASK | DCDC_REG0_LP_HIGH_HYS_MASK |
+ DCDC_REG0_LP_OVERLOAD_FREQ_SEL_MASK | DCDC_REG0_LP_OVERLOAD_THRSH_MASK);
+ tmp32 |= DCDC_REG0_LP_OVERLOAD_FREQ_SEL(config->countChargingTimePeriod) |
+ DCDC_REG0_LP_OVERLOAD_THRSH(config->countChargingTimeThreshold);
+ if (config->enableOverloadDetection)
+ {
+ tmp32 |= DCDC_REG0_EN_LP_OVERLOAD_SNS_MASK;
+ }
+ if (config->enableAdjustHystereticValue)
+ {
+ tmp32 |= DCDC_REG0_LP_HIGH_HYS_MASK;
+ }
+ base->REG0 = tmp32;
+}
+
+/*!
+ * brief Get DCDC status flags.
+ *
+ * param base peripheral base address.
+ * return Mask of asserted status flags. See to "_dcdc_status_flags_t".
+ */
+uint32_t DCDC_GetstatusFlags(DCDC_Type *base)
+{
+ uint32_t tmp32 = 0U;
+
+ if (DCDC_REG0_STS_DC_OK_MASK == (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ tmp32 |= (uint32_t)kDCDC_LockedOKStatus;
+ }
+
+ return tmp32;
+}
+
+/*!
+ * brief Reset current alert signal. Alert signal is generate by peak current detection.
+ *
+ * param base DCDC peripheral base address.
+ * param enable Switcher to reset signal. True means reset signal. False means don't reset signal.
+ */
+void DCDC_ResetCurrentAlertSignal(DCDC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->REG0 |= DCDC_REG0_CURRENT_ALERT_RESET_MASK;
+ }
+ else
+ {
+ base->REG0 &= ~DCDC_REG0_CURRENT_ALERT_RESET_MASK;
+ }
+}
+
+/*!
+ * brief Get the default setting for loop control configuration.
+ *
+ * The default configuration are set according to responding registers' setting when powered on.
+ * They are:
+ * code
+ * config->enableCommonHysteresis = false;
+ * config->enableCommonThresholdDetection = false;
+ * config->enableInvertHysteresisSign = false;
+ * config->enableRCThresholdDetection = false;
+ * config->enableRCScaleCircuit = 0U;
+ * config->complementFeedForwardStep = 0U;
+ * config->controlParameterMagnitude = 2U;
+ * config->integralProportionalRatio = 2U;
+ * endcode
+ *
+ * param config Pointer to configuration structure. See to "dcdc_loop_control_config_t"
+ */
+void DCDC_GetDefaultLoopControlConfig(dcdc_loop_control_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableCommonHysteresis = false;
+ config->enableCommonThresholdDetection = false;
+ config->enableInvertHysteresisSign = false;
+ config->enableRCThresholdDetection = false;
+ config->enableRCScaleCircuit = 0U;
+ config->complementFeedForwardStep = 0U;
+ config->controlParameterMagnitude = 2U;
+ config->integralProportionalRatio = 2U;
+}
+
+/*!
+ * brief Configure the DCDC loop control.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_loop_control_config_t".
+ */
+void DCDC_SetLoopControlConfig(DCDC_Type *base, const dcdc_loop_control_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+ /* Configure the DCDC_REG1 register. */
+ tmp32 = base->REG1 & ~(DCDC_REG1_LOOPCTRL_EN_HYST_MASK | DCDC_REG1_LOOPCTRL_HST_THRESH_MASK);
+ if (config->enableCommonHysteresis)
+ {
+ tmp32 |= DCDC_REG1_LOOPCTRL_EN_HYST_MASK;
+ }
+ if (config->enableCommonThresholdDetection)
+ {
+ tmp32 |= DCDC_REG1_LOOPCTRL_HST_THRESH_MASK;
+ }
+ base->REG1 = tmp32;
+
+ /* configure the DCDC_REG2 register. */
+ tmp32 = base->REG2 & ~(DCDC_REG2_LOOPCTRL_HYST_SIGN_MASK | DCDC_REG2_LOOPCTRL_RCSCALE_THRSH_MASK |
+ DCDC_REG2_LOOPCTRL_EN_RCSCALE_MASK | DCDC_REG2_LOOPCTRL_DC_FF_MASK |
+ DCDC_REG2_LOOPCTRL_DC_R_MASK | DCDC_REG2_LOOPCTRL_DC_C_MASK);
+ tmp32 |= DCDC_REG2_LOOPCTRL_DC_FF(config->complementFeedForwardStep) |
+ DCDC_REG2_LOOPCTRL_DC_R(config->controlParameterMagnitude) |
+ DCDC_REG2_LOOPCTRL_DC_C(config->integralProportionalRatio) |
+ DCDC_REG2_LOOPCTRL_EN_RCSCALE(config->enableRCScaleCircuit);
+ if (config->enableInvertHysteresisSign)
+ {
+ tmp32 |= DCDC_REG2_LOOPCTRL_HYST_SIGN_MASK;
+ }
+ if (config->enableRCThresholdDetection)
+ {
+ tmp32 |= DCDC_REG2_LOOPCTRL_RCSCALE_THRSH_MASK;
+ }
+ base->REG2 = tmp32;
+}
+
+/*!
+ * brief Configure for the min power.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_min_power_config_t".
+ */
+void DCDC_SetMinPowerConfig(DCDC_Type *base, const dcdc_min_power_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+ tmp32 = base->REG3 & ~DCDC_REG3_MINPWR_DC_HALFCLK_MASK;
+ if (config->enableUseHalfFreqForContinuous)
+ {
+ tmp32 |= DCDC_REG3_MINPWR_DC_HALFCLK_MASK;
+ }
+ base->REG3 = tmp32;
+}
+
+/*!
+ * brief Adjust the target voltage of VDD_SOC in run mode and low power mode.
+ * @deprecated Do not use this function. It has been superceded by @ref DCDC_AdjustRunTargetVoltage
+ * and @ref DCDC_AdjustLowPowerTargetVoltage
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ * param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ */
+void DCDC_AdjustTargetVoltage(DCDC_Type *base, uint32_t VDDRun, uint32_t VDDStandby)
+{
+ uint32_t tmp32;
+
+ /* Unlock the step for the output. */
+ base->REG3 &= ~DCDC_REG3_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_REG3 register. */
+ tmp32 = base->REG3 & ~(DCDC_REG3_TARGET_LP_MASK | DCDC_REG3_TRG_MASK);
+
+ tmp32 |= DCDC_REG3_TARGET_LP(VDDStandby) | DCDC_REG3_TRG(VDDRun);
+ base->REG3 = tmp32;
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage settling to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+
+/*!
+ * brief Adjust the target voltage of VDD_SOC in run mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDRun Target value in run mode. 25 mV each step from 0x00 to 0x1F. 00 is for 0.8V, 0x1F is for 1.575V.
+ */
+void DCDC_AdjustRunTargetVoltage(DCDC_Type *base, uint32_t VDDRun)
+{
+ uint32_t tmp32;
+
+ /* Unlock the step for the output. */
+ base->REG3 &= ~DCDC_REG3_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_REG3 register. */
+ tmp32 = base->REG3 & ~DCDC_REG3_TRG_MASK;
+
+ tmp32 |= DCDC_REG3_TRG(VDDRun);
+ base->REG3 = tmp32;
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage settling to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+
+/*!
+ * brief Adjust the target voltage of VDD_SOC in low power mode.
+ *
+ * This function is to adjust the target voltage of DCDC output. Change them and finally wait until the output is
+ * stabled.
+ * Set the target value of run mode the same as low power mode before entering power save mode, because DCDC will switch
+ * back to run mode if it detects the current loading is larger than about 50 mA(typical value).
+ *
+ * param base DCDC peripheral base address.
+ * param VDDStandby Target value in low power mode. 25 mV each step from 0x00 to 0x4. 00 is for 0.9V, 0x4 is for 1.0V.
+ */
+void DCDC_AdjustLowPowerTargetVoltage(DCDC_Type *base, uint32_t VDDStandby)
+{
+ uint32_t tmp32;
+
+ /* Unlock the step for the output. */
+ base->REG3 &= ~DCDC_REG3_DISABLE_STEP_MASK;
+
+ /* Configure the DCDC_REG3 register. */
+ tmp32 = base->REG3 & ~DCDC_REG3_TARGET_LP_MASK;
+
+ tmp32 |= DCDC_REG3_TARGET_LP(VDDStandby);
+ base->REG3 = tmp32;
+
+ /* DCDC_STS_DC_OK bit will be de-asserted after target register changes. After output voltage settling to new
+ * target value, DCDC_STS_DC_OK will be asserted. */
+ while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & base->REG0))
+ {
+ }
+}
+
+/*!
+ * brief Configure the DCDC internal regulator.
+ *
+ * param base DCDC peripheral base address.
+ * param config Pointer to configuration structure. See to "dcdc_internal_regulator_config_t".
+ */
+void DCDC_SetInternalRegulatorConfig(DCDC_Type *base, const dcdc_internal_regulator_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t tmp32;
+
+ /* Configure the DCDC_REG1 register. */
+ tmp32 = base->REG1 & ~(DCDC_REG1_REG_FBK_SEL_MASK | DCDC_REG1_REG_RLOAD_SW_MASK);
+ tmp32 |= DCDC_REG1_REG_FBK_SEL(config->feedbackPoint);
+ if (config->enableLoadResistor)
+ {
+ tmp32 |= DCDC_REG1_REG_RLOAD_SW_MASK;
+ }
+ base->REG1 = tmp32;
+}
+
+/*!
+ * brief Boot DCDC into DCM(discontinous conduction mode).
+ *
+ * pwd_zcd=0x0;
+ * pwd_cmp_offset=0x0;
+ * dcdc_loopctrl_en_rcscale=0x3 or 0x5;
+ * DCM_set_ctrl=1'b1;
+ *
+ * param base DCDC peripheral base address.
+ */
+void DCDC_BootIntoDCM(DCDC_Type *base)
+{
+ base->REG0 &= ~(DCDC_REG0_PWD_ZCD_MASK | DCDC_REG0_PWD_CMP_OFFSET_MASK);
+ base->REG2 = (~DCDC_REG2_LOOPCTRL_EN_RCSCALE_MASK & base->REG2) | DCDC_REG2_LOOPCTRL_EN_RCSCALE(0x4U) |
+ DCDC_REG2_DCM_SET_CTRL_MASK;
+}
+
+/*!
+ * brief Boot DCDC into CCM(continous conduction mode).
+ *
+ * pwd_zcd=0x1;
+ * pwd_cmp_offset=0x0;
+ * dcdc_loopctrl_en_rcscale=0x3;
+ *
+ * param base DCDC peripheral base address.
+ */
+void DCDC_BootIntoCCM(DCDC_Type *base)
+{
+ base->REG0 = (~DCDC_REG0_PWD_CMP_OFFSET_MASK & base->REG0) | DCDC_REG0_PWD_ZCD_MASK;
+ base->REG2 = (~DCDC_REG2_LOOPCTRL_EN_RCSCALE_MASK & base->REG2) | DCDC_REG2_LOOPCTRL_EN_RCSCALE(0x3U);
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcp.c
new file mode 100644
index 0000000000..4477406a73
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dcp.c
@@ -0,0 +1,1461 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dcp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.dcp"
+#endif
+
+#ifndef DCP_USE_DCACHE
+#define DCP_USE_DCACHE 0
+#endif
+/* 1 - driver supports DCACHE, 0 - drivers does not support DCACHE */
+/* When enable (DCP_USE_DCACHE = 1) Input/output buffers and hash ctx should be in */
+/* non-cached memory or handled properly (Clean & Invalidate DCACHE) */
+
+/*! Compile time sizeof() check */
+#define BUILD_ASSURE(condition, msg) extern int msg[1 - 2 * (!(condition))] __attribute__((unused))
+
+#define dcp_memcpy memcpy
+
+/*! Internal states of the HASH creation process */
+typedef enum _dcp_hash_algo_state
+{
+ kDCP_StateHashInit = 1u, /*!< Init state. */
+ kDCP_StateHashUpdate, /*!< Update state. */
+} dcp_hash_algo_state_t;
+
+/*! multiple of 64-byte block represented as byte array of 32-bit words */
+typedef union _dcp_hash_block
+{
+ uint32_t w[DCP_HASH_BLOCK_SIZE / 4]; /*!< array of 32-bit words */
+ uint8_t b[DCP_HASH_BLOCK_SIZE]; /*!< byte array */
+} dcp_hash_block_t;
+
+/*! internal dcp_hash context structure */
+typedef struct _dcp_hash_ctx_internal
+{
+ dcp_hash_block_t blk; /*!< memory buffer. only full blocks are written to DCP during hash updates */
+ size_t blksz; /*!< number of valid bytes in memory buffer */
+ dcp_hash_algo_t algo; /*!< selected algorithm from the set of supported algorithms */
+ dcp_hash_algo_state_t state; /*!< finite machine state of the hash software process */
+ uint32_t fullMessageSize; /*!< track message size */
+ uint32_t ctrl0; /*!< HASH_INIT and HASH_TERM flags */
+ uint32_t runningHash[9]; /*!< running hash. up to SHA-256 plus size, that is 36 bytes. */
+ dcp_handle_t *handle;
+} dcp_hash_ctx_internal_t;
+
+/*!< SHA-1/SHA-2 digest length in bytes */
+enum _dcp_hash_digest_len
+{
+ kDCP_OutLenSha1 = 20u,
+ kDCP_OutLenSha256 = 32u,
+ kDCP_OutLenCrc32 = 4u,
+};
+
+enum _dcp_work_packet_bit_definitions
+{
+ kDCP_CONTROL0_DECR_SEMAPHOR = 1u << 1, /* DECR_SEMAPHOR */
+ kDCP_CONTROL0_ENABLE_HASH = 1u << 6, /* ENABLE_HASH */
+ kDCP_CONTROL0_HASH_INIT = 1u << 12, /* HASH_INIT */
+ kDCP_CONTROL0_HASH_TERM = 1u << 13, /* HASH_TERM */
+ kDCP_CONTROL1_HASH_SELECT_SHA256 = 2u << 16,
+ kDCP_CONTROL1_HASH_SELECT_SHA1 = 0u << 16,
+ kDCP_CONTROL1_HASH_SELECT_CRC32 = 1u << 16,
+};
+
+/*! 64-byte block represented as byte array of 16 32-bit words */
+typedef union _dcp_sha_block
+{
+ uint32_t w[64 / 4]; /*!< array of 32-bit words */
+ uint8_t b[64]; /*!< byte array */
+} dcp_sha_block_t;
+
+#if defined(DCP_HASH_CAVP_COMPATIBLE)
+/* result of sha1 hash for message with zero size */
+static uint8_t s_nullSha1[] = {0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
+ 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09};
+/* result of sha256 hash for message with zero size */
+static uint8_t s_nullSha256[] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
+ 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
+ 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
+#endif /* DCP_HASH_CAVP_COMPATIBLE */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+AT_NONCACHEABLE_SECTION_INIT(static dcp_context_t s_dcpContextSwitchingBuffer);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void dcp_reverse_and_copy(uint8_t *src, uint8_t *dest, size_t src_len)
+{
+ for (uint32_t i = 0; i < src_len; i++)
+ {
+ dest[i] = src[src_len - 1U - i];
+ }
+}
+
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+static uint32_t *DCP_FindCacheLine(uint8_t *dcpWorkExt)
+{
+ while ((uint32_t)dcpWorkExt & (FSL_FEATURE_L1DCACHE_LINESIZE_BYTE - 1))
+ dcpWorkExt++;
+ return (uint32_t *)dcpWorkExt;
+}
+#endif
+
+static status_t dcp_get_channel_status(DCP_Type *base, dcp_channel_t channel)
+{
+ uint32_t statReg = 0;
+ uint32_t semaReg = 0;
+ status_t status = kStatus_Fail;
+
+ switch (channel)
+ {
+ case kDCP_Channel0:
+ statReg = base->CH0STAT;
+ semaReg = base->CH0SEMA;
+ break;
+
+ case kDCP_Channel1:
+ statReg = base->CH1STAT;
+ semaReg = base->CH1SEMA;
+ break;
+
+ case kDCP_Channel2:
+ statReg = base->CH2STAT;
+ semaReg = base->CH2SEMA;
+ break;
+
+ case kDCP_Channel3:
+ statReg = base->CH3STAT;
+ semaReg = base->CH3SEMA;
+ break;
+
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+
+ if (!((0U != (semaReg & DCP_CH0SEMA_VALUE_MASK)) || (0U != (statReg & DCP_CH0STAT_ERROR_CODE_MASK))))
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+static void dcp_clear_status(DCP_Type *base)
+{
+ volatile uint32_t *dcpStatClrPtr = (volatile uint32_t *)&base->STAT + 2u;
+ *dcpStatClrPtr = 0xFFu;
+
+ while ((base->STAT & 0xffu) != 0U)
+ {
+ }
+}
+
+static void dcp_clear_channel_status(DCP_Type *base, uint32_t mask)
+{
+ volatile uint32_t *chStatClrPtr;
+
+ if (0U != (mask & (uint32_t)kDCP_Channel0))
+ {
+ chStatClrPtr = &base->CH0STAT_CLR;
+ *chStatClrPtr = 0xFFu;
+ }
+ if (0U != (mask & (uint32_t)kDCP_Channel1))
+ {
+ chStatClrPtr = &base->CH1STAT_CLR;
+ *chStatClrPtr = 0xFFu;
+ }
+ if (0U != (mask & (uint32_t)kDCP_Channel2))
+ {
+ chStatClrPtr = &base->CH2STAT_CLR;
+ *chStatClrPtr = 0xFFu;
+ }
+ if (0U != (mask & (uint32_t)kDCP_Channel3))
+ {
+ chStatClrPtr = &base->CH3STAT_CLR;
+ *chStatClrPtr = 0xFFu;
+ }
+}
+
+static status_t dcp_aes_set_sram_based_key(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key)
+{
+ base->KEY = DCP_KEY_INDEX(handle->keySlot) | DCP_KEY_SUBWORD(0);
+ /* move the key by 32-bit words */
+ int i = 0;
+ size_t keySize = 16u;
+ while (keySize != 0U)
+ {
+ keySize -= sizeof(uint32_t);
+ base->KEYDATA = ((uint32_t *)(uintptr_t)key)[i];
+ i++;
+ }
+ return kStatus_Success;
+}
+
+/* Disable optimizations for GCC to prevent instruction reordering */
+#if defined(__GNUC__)
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+#endif
+static status_t dcp_schedule_work(DCP_Type *base, dcp_handle_t *handle, dcp_work_packet_t *dcpPacket)
+{
+ status_t status;
+
+ /* check if our channel is active */
+ if ((base->STAT & (uint32_t)handle->channel) != (uint32_t)handle->channel)
+ {
+ /* disable global interrupt */
+ uint32_t currPriMask = DisableGlobalIRQ();
+
+ /* re-check if our channel is still available */
+ if ((base->STAT & (uint32_t)handle->channel) == 0U)
+ {
+ volatile uint32_t *cmdptr = NULL;
+ volatile uint32_t *chsema = NULL;
+
+ switch (handle->channel)
+ {
+ case kDCP_Channel0:
+ cmdptr = &base->CH0CMDPTR;
+ chsema = &base->CH0SEMA;
+ break;
+
+ case kDCP_Channel1:
+ cmdptr = &base->CH1CMDPTR;
+ chsema = &base->CH1SEMA;
+ break;
+
+ case kDCP_Channel2:
+ cmdptr = &base->CH2CMDPTR;
+ chsema = &base->CH2SEMA;
+ break;
+
+ case kDCP_Channel3:
+ cmdptr = &base->CH3CMDPTR;
+ chsema = &base->CH3SEMA;
+ break;
+
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+
+ if ((NULL != cmdptr) && (NULL != chsema))
+ {
+ /* set out packet to DCP CMDPTR */
+ *cmdptr = (uint32_t)dcpPacket;
+
+#if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ /* Clean DCACHE before sending DCP packet to engine */
+ SCB_CleanDCache_by_Addr((uint32_t *)dcpPacket, sizeof(dcp_work_packet_t));
+#endif
+ /* Make sure that all data memory accesses are completed before starting of the job */
+ __DSB();
+ __ISB();
+
+ /* set the channel semaphore to start the job */
+ *chsema = 1u;
+ }
+
+ status = kStatus_Success;
+ }
+
+ else
+ {
+ status = (int32_t)kStatus_DCP_Again;
+ }
+ /* global interrupt enable */
+ EnableGlobalIRQ(currPriMask);
+ }
+
+ else
+ {
+ return (int32_t)kStatus_DCP_Again;
+ }
+
+ return status;
+}
+#if defined(__GNUC__)
+#pragma GCC pop_options
+#endif
+
+/*!
+ * brief Set AES key to dcp_handle_t struct and optionally to DCP.
+ *
+ * Sets the AES key for encryption/decryption with the dcp_handle_t structure.
+ * The dcp_handle_t input argument specifies keySlot.
+ * If the keySlot is kDCP_OtpKey, the function will check the OTP_KEY_READY bit and will return it's ready to use
+ * status.
+ * For other keySlot selections, the function will copy and hold the key in dcp_handle_t struct.
+ * If the keySlot is one of the four DCP SRAM-based keys (one of kDCP_KeySlot0, kDCP_KeySlot1, kDCP_KeySlot2,
+ * kDCP_KeySlot3),
+ * this function will also load the supplied key to the specified keySlot in DCP.
+ *
+ * param base DCP peripheral base address.
+ * param handle Handle used for the request.
+ * param key 0-mod-4 aligned pointer to AES key.
+ * param keySize AES key size in bytes. Shall equal 16.
+ * return status from set key operation
+ */
+status_t DCP_AES_SetKey(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key, size_t keySize)
+{
+ status_t status = kStatus_Fail;
+
+ if ((kDCP_OtpKey == handle->keySlot) || (kDCP_OtpUniqueKey == handle->keySlot))
+ {
+ /* for AES OTP and unique key, check and return read from fuses status */
+ if ((base->STAT & DCP_STAT_OTP_KEY_READY_MASK) == DCP_STAT_OTP_KEY_READY_MASK)
+ {
+ status = kStatus_Success;
+ }
+ }
+ else
+ {
+ /* only work with aligned key[] */
+ if ((0x3U & (uintptr_t)key) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* keySize must be 16. */
+ if (keySize != 16U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* move the key by 32-bit words */
+ int i = 0;
+ while (keySize != 0U)
+ {
+ keySize -= sizeof(uint32_t);
+ handle->keyWord[i] = ((uint32_t *)(uintptr_t)key)[i];
+ i++;
+ }
+
+ if (kDCP_PayloadKey != handle->keySlot)
+ {
+ /* move the key by 32-bit words to DCP SRAM-based key storage */
+ status = dcp_aes_set_sram_based_key(base, handle, key);
+ }
+ else
+ {
+ /* for PAYLOAD_KEY, just return Ok status now */
+ status = kStatus_Success;
+ }
+ }
+
+ return status;
+}
+
+/*!
+ * brief Encrypts AES on one or multiple 128-bit block(s).
+ *
+ * Encrypts AES.
+ * The source plaintext and destination ciphertext can overlap in system memory.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param plaintext Input plain text to encrypt
+ * param[out] ciphertext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * return Status from encrypt operation
+ */
+status_t DCP_AES_EncryptEcb(
+ DCP_Type *base, dcp_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size)
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = DCP_AES_EncryptEcbNonBlocking(base, handle, dcpWork, plaintext, ciphertext, size);
+ } while (completionStatus == (int32_t)kStatus_DCP_Again);
+
+ if (completionStatus != kStatus_Success)
+ {
+ return completionStatus;
+ }
+
+ return DCP_WaitForChannelComplete(base, handle);
+}
+
+/*!
+ * brief Encrypts AES using the ECB block mode.
+ *
+ * Puts AES ECB encrypt work packet to DCP channel.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param[out] dcpPacket Memory for the DCP work packet.
+ * param plaintext Input plain text to encrypt.
+ * param[out] ciphertext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * return kStatus_Success The work packet has been scheduled at DCP channel.
+ * return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_EncryptEcbNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size)
+{
+ /* Size must be 16-byte multiple */
+ if ((size < 16u) || (0U != (size % 16u)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ dcpPacket->control0 =
+ 0x122u | (handle->swapConfig & 0xFC0000u); /* CIPHER_ENCRYPT | ENABLE_CIPHER | DECR_SEMAPHORE */
+ dcpPacket->sourceBufferAddress = (uint32_t)plaintext;
+ dcpPacket->destinationBufferAddress = (uint32_t)ciphertext;
+ dcpPacket->bufferSize = (uint32_t)size;
+
+ if (handle->keySlot == kDCP_OtpKey)
+ {
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 = ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
+ }
+ else if (handle->keySlot == kDCP_OtpUniqueKey)
+ {
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 = ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
+ }
+ else if (handle->keySlot == kDCP_PayloadKey)
+ {
+ /* ECB does not have IV, so we can point payload directly to keyWord[] stored in handle. */
+ dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
+ dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
+ }
+ else
+ {
+ dcpPacket->control1 = ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
+ }
+
+ return dcp_schedule_work(base, handle, dcpPacket);
+}
+
+/*!
+ * brief Decrypts AES on one or multiple 128-bit block(s).
+ *
+ * Decrypts AES.
+ * The source ciphertext and destination plaintext can overlap in system memory.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param ciphertext Input plain text to encrypt
+ * param[out] plaintext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * return Status from decrypt operation
+ */
+status_t DCP_AES_DecryptEcb(
+ DCP_Type *base, dcp_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size)
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = DCP_AES_DecryptEcbNonBlocking(base, handle, dcpWork, ciphertext, plaintext, size);
+ } while (completionStatus == (int32_t)(kStatus_DCP_Again));
+
+ if (completionStatus != kStatus_Success)
+ {
+ return completionStatus;
+ }
+
+ return DCP_WaitForChannelComplete(base, handle);
+}
+
+/*!
+ * brief Decrypts AES using ECB block mode.
+ *
+ * Puts AES ECB decrypt dcpPacket to DCP input job ring.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param[out] dcpPacket Memory for the DCP work packet.
+ * param ciphertext Input cipher text to decrypt
+ * param[out] plaintext Output plain text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * return kStatus_Success The work packet has been scheduled at DCP channel.
+ * return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_DecryptEcbNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size)
+{
+ /* Size must be 16-byte multiple */
+ if ((size < 16u) || (0U != (size % 16u)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ dcpPacket->control0 = 0x22u | (handle->swapConfig & 0xFC0000u); /* ENABLE_CIPHER | DECR_SEMAPHORE */
+ dcpPacket->sourceBufferAddress = (uint32_t)ciphertext;
+ dcpPacket->destinationBufferAddress = (uint32_t)plaintext;
+ dcpPacket->bufferSize = (uint32_t)size;
+
+ if (handle->keySlot == kDCP_OtpKey)
+ {
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 = ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
+ }
+ else if (handle->keySlot == kDCP_OtpUniqueKey)
+ {
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 = ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
+ }
+ else if (handle->keySlot == kDCP_PayloadKey)
+ {
+ /* ECB does not have IV, so we can point payload directly to keyWord[] stored in handle. */
+ dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
+ dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
+ }
+ else
+ {
+ dcpPacket->control1 = ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
+ }
+
+ return dcp_schedule_work(base, handle, dcpPacket);
+}
+
+/*!
+ * brief Encrypts AES using CBC block mode.
+ *
+ * Encrypts AES using CBC block mode.
+ * The source plaintext and destination ciphertext can overlap in system memory.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param plaintext Input plain text to encrypt
+ * param[out] ciphertext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * param iv Input initial vector to combine with the first input block.
+ * return Status from encrypt operation
+ */
+status_t DCP_AES_EncryptCbc(DCP_Type *base,
+ dcp_handle_t *handle,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size,
+ const uint8_t iv[16])
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = DCP_AES_EncryptCbcNonBlocking(base, handle, dcpWork, plaintext, ciphertext, size, iv);
+ } while (completionStatus == (int32_t)kStatus_DCP_Again);
+
+ if (completionStatus != kStatus_Success)
+ {
+ return completionStatus;
+ }
+
+ return DCP_WaitForChannelComplete(base, handle);
+}
+
+/*!
+ * brief Encrypts AES using CBC block mode.
+ *
+ * Puts AES CBC encrypt dcpPacket to DCP input job ring.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request. Specifies jobRing.
+ * param[out] dcpPacket Memory for the DCP work packet.
+ * param plaintext Input plain text to encrypt
+ * param[out] ciphertext Output cipher text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * param iv Input initial vector to combine with the first input block.
+ * return kStatus_Success The work packet has been scheduled at DCP channel.
+ * return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_EncryptCbcNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *plaintext,
+ uint8_t *ciphertext,
+ size_t size,
+ const uint8_t *iv)
+{
+ /* Size must be 16-byte multiple */
+ if ((size < 16u) || (0U != (size % 16u)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ dcpPacket->control0 =
+ 0x322u | (handle->swapConfig & 0xFC0000u); /* CIPHER_INIT | CIPHER_ENCRYPT | ENABLE_CIPHER | DECR_SEMAPHORE */
+ dcpPacket->control1 = 0x10u; /* CBC */
+ dcpPacket->sourceBufferAddress = (uint32_t)plaintext;
+ dcpPacket->destinationBufferAddress = (uint32_t)ciphertext;
+ dcpPacket->bufferSize = (uint32_t)size;
+
+ if (handle->keySlot == kDCP_OtpKey)
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 |= ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
+ }
+ else if (handle->keySlot == kDCP_OtpUniqueKey)
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 |= ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
+ }
+ else if (handle->keySlot == kDCP_PayloadKey)
+ {
+ /* In this case payload must contain key & iv in one array. */
+ /* Copy iv into handle right behind the keyWord[] so we can point payload to keyWord[]. */
+ (void)dcp_memcpy(handle->iv, (const uint32_t *)(uintptr_t)iv, 16);
+ dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
+ dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
+ }
+ else
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control1 |= ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
+ }
+
+ return dcp_schedule_work(base, handle, dcpPacket);
+}
+
+/*!
+ * brief Decrypts AES using CBC block mode.
+ *
+ * Decrypts AES using CBC block mode.
+ * The source ciphertext and destination plaintext can overlap in system memory.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request.
+ * param ciphertext Input cipher text to decrypt
+ * param[out] plaintext Output plain text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * param iv Input initial vector to combine with the first input block.
+ * return Status from decrypt operation
+ */
+status_t DCP_AES_DecryptCbc(DCP_Type *base,
+ dcp_handle_t *handle,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size,
+ const uint8_t iv[16])
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = DCP_AES_DecryptCbcNonBlocking(base, handle, dcpWork, ciphertext, plaintext, size, iv);
+ } while (completionStatus == (int32_t)kStatus_DCP_Again);
+
+ if (completionStatus != (int32_t)kStatus_Success)
+ {
+ return completionStatus;
+ }
+
+ return DCP_WaitForChannelComplete(base, handle);
+}
+
+/*!
+ * brief Decrypts AES using CBC block mode.
+ *
+ * Puts AES CBC decrypt dcpPacket to DCP input job ring.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for this request. Specifies jobRing.
+ * param[out] dcpPacket Memory for the DCP work packet.
+ * param ciphertext Input cipher text to decrypt
+ * param[out] plaintext Output plain text
+ * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
+ * param iv Input initial vector to combine with the first input block.
+ * return kStatus_Success The work packet has been scheduled at DCP channel.
+ * return kStatus_DCP_Again The DCP channel is busy processing previous request.
+ */
+status_t DCP_AES_DecryptCbcNonBlocking(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_work_packet_t *dcpPacket,
+ const uint8_t *ciphertext,
+ uint8_t *plaintext,
+ size_t size,
+ const uint8_t *iv)
+{
+ /* Size must be 16-byte multiple */
+ if ((size < 16u) || (0U != (size % 16u)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ dcpPacket->control0 = 0x222u | (handle->swapConfig & 0xFC0000u); /* CIPHER_INIT | ENABLE_CIPHER | DECR_SEMAPHORE */
+ dcpPacket->control1 = 0x10u; /* CBC */
+ dcpPacket->sourceBufferAddress = (uint32_t)ciphertext;
+ dcpPacket->destinationBufferAddress = (uint32_t)plaintext;
+ dcpPacket->bufferSize = (uint32_t)size;
+
+ if (handle->keySlot == kDCP_OtpKey)
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 |= ((uint32_t)0xFFu << 8); /* OTP_KEY */
+ }
+ else if (handle->keySlot == kDCP_OtpUniqueKey)
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control0 |= ((uint32_t)1u << 10); /* OTP_KEY */
+ dcpPacket->control1 |= ((uint32_t)0xFEu << 8); /* UNIQUE_KEY */
+ }
+ else if (handle->keySlot == kDCP_PayloadKey)
+ {
+ /* in this case payload must contain KEY + IV together */
+ /* copy iv into handle struct so we can point payload directly to keyWord[]. */
+ (void)dcp_memcpy(handle->iv, (const uint32_t *)(uintptr_t)iv, 16);
+ dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
+ dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
+ }
+ else
+ {
+ dcpPacket->payloadPointer = (uint32_t)iv;
+ dcpPacket->control1 |= ((uint32_t)handle->keySlot << 8); /* KEY_SELECT */
+ }
+
+ return dcp_schedule_work(base, handle, dcpPacket);
+}
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the DCP configuration structure to a default value. The default
+ * values are as follows.
+ * dcpConfig->gatherResidualWrites = true;
+ * dcpConfig->enableContextCaching = true;
+ * dcpConfig->enableContextSwitching = true;
+ * dcpConfig->enableChannnel = kDCP_chEnableAll;
+ * dcpConfig->enableChannelInterrupt = kDCP_chIntDisable;
+ *
+ * param[out] config Pointer to configuration structure.
+ */
+void DCP_GetDefaultConfig(dcp_config_t *config)
+{
+ /* ENABLE_CONTEXT_CACHING is disabled by default as the DCP Hash driver uses
+ * dcp_hash_save_running_hash() and dcp_hash_restore_running_hash() to support
+ * Hash context switch (different messages interleaved) on the same channel.
+ */
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ dcp_config_t userConfig = {
+ true, false, true, (uint8_t)kDCP_chEnableAll, (uint8_t)kDCP_chIntDisable,
+ };
+
+ *config = userConfig;
+}
+
+/*!
+ * brief Enables clock to and enables DCP
+ *
+ * Enable DCP clock and configure DCP.
+ *
+ * param base DCP base address
+ * param config Pointer to configuration structure.
+ */
+void DCP_Init(DCP_Type *base, const dcp_config_t *config)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Dcp);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ base->CTRL = 0xF0800000u; /* reset value */
+ base->CTRL = 0x30800000u; /* default value */
+
+ dcp_clear_status(base);
+ dcp_clear_channel_status(
+ base, (uint32_t)kDCP_Channel0 | (uint32_t)kDCP_Channel1 | (uint32_t)kDCP_Channel2 | (uint32_t)kDCP_Channel3);
+
+ base->CTRL = DCP_CTRL_GATHER_RESIDUAL_WRITES(config->gatherResidualWrites) |
+ DCP_CTRL_ENABLE_CONTEXT_CACHING(config->enableContextCaching) |
+ DCP_CTRL_ENABLE_CONTEXT_SWITCHING(config->enableContextSwitching) |
+ DCP_CTRL_CHANNEL_INTERRUPT_ENABLE(config->enableChannelInterrupt);
+
+ /* enable DCP channels */
+ base->CHANNELCTRL = DCP_CHANNELCTRL_ENABLE_CHANNEL(config->enableChannel);
+
+ /* use context switching buffer */
+ base->CONTEXT = (uint32_t)&s_dcpContextSwitchingBuffer;
+}
+
+/*!
+ * brief Disable DCP clock
+ *
+ * Reset DCP and Disable DCP clock.
+ *
+ * param base DCP base address
+ */
+void DCP_Deinit(DCP_Type *base)
+{
+ base->CTRL = 0xF0800000u; /* reset value */
+ (void)memset(&s_dcpContextSwitchingBuffer, 0, sizeof(s_dcpContextSwitchingBuffer));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Dcp);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Poll and wait on DCP channel.
+ *
+ * Polls the specified DCP channel until current it completes activity.
+ *
+ * param base DCP peripheral base address.
+ * param handle Specifies DCP channel.
+ * return kStatus_Success When data processing completes without error.
+ * return kStatus_Fail When error occurs.
+ */
+status_t DCP_WaitForChannelComplete(DCP_Type *base, dcp_handle_t *handle)
+{
+ /* wait if our channel is still active */
+ while ((base->STAT & (uint32_t)handle->channel) == (uint32_t)handle->channel)
+ {
+ }
+
+ if (dcp_get_channel_status(base, handle->channel) != kStatus_Success)
+ {
+ dcp_clear_status(base);
+ dcp_clear_channel_status(base, (uint32_t)handle->channel);
+ return kStatus_Fail;
+ }
+
+ dcp_clear_status(base);
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Check validity of algoritm.
+ *
+ * This function checks the validity of input argument.
+ *
+ * @param algo Tested algorithm value.
+ * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
+ */
+static status_t dcp_hash_check_input_alg(dcp_hash_algo_t algo)
+{
+ if ((algo != kDCP_Sha256) && (algo != kDCP_Sha1) && (algo != kDCP_Crc32))
+ {
+ return kStatus_InvalidArgument;
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Check validity of input arguments.
+ *
+ * This function checks the validity of input arguments.
+ *
+ * @param base DCP peripheral base address.
+ * @param ctx Memory buffer given by user application where the DCP_HASH_Init/DCP_HASH_Update/DCP_HASH_Finish store
+ * context.
+ * @param algo Tested algorithm value.
+ * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
+ */
+static status_t dcp_hash_check_input_args(DCP_Type *base, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo)
+{
+ /* Check validity of input algorithm */
+ if (kStatus_Success != dcp_hash_check_input_alg(algo))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((NULL == ctx) || (NULL == base))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Check validity of internal software context.
+ *
+ * This function checks if the internal context structure looks correct.
+ *
+ * @param ctxInternal Internal context.
+ * @param message Input message address.
+ * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
+ */
+static status_t dcp_hash_check_context(dcp_hash_ctx_internal_t *ctxInternal, const uint8_t *message)
+{
+ if ((NULL == message) || (NULL == ctxInternal) || (kStatus_Success != dcp_hash_check_input_alg(ctxInternal->algo)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ else if ((uint32_t)ctxInternal & (FSL_FEATURE_L1DCACHE_LINESIZE_BYTE - 1))
+ {
+ /* ctx must be cache line aligned when using DCACHE */
+ return kStatus_InvalidArgument;
+ }
+#endif
+
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Initialize the SHA engine for new hash.
+ *
+ * This function sets kDCP_CONTROL0_HASH_INIT for control0 in work packet to start a new hash.
+ *
+ * @param base SHA peripheral base address.
+ * @param ctxInternal Internal context.
+ */
+static status_t dcp_hash_engine_init(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal)
+{
+ status_t status;
+
+ status = kStatus_InvalidArgument;
+
+ if ((kDCP_Sha256 == ctxInternal->algo) || (kDCP_Sha1 == ctxInternal->algo) || (kDCP_Crc32 == ctxInternal->algo))
+ {
+ ctxInternal->ctrl0 = (uint32_t)kDCP_CONTROL0_HASH_INIT;
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+static status_t dcp_hash_update_non_blocking(
+ DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal, dcp_work_packet_t *dcpPacket, const uint8_t *msg, size_t size)
+{
+ dcpPacket->control0 = ctxInternal->ctrl0 | (ctxInternal->handle->swapConfig & 0xFC0000u) |
+ (uint32_t)kDCP_CONTROL0_ENABLE_HASH | (uint32_t)kDCP_CONTROL0_DECR_SEMAPHOR;
+ if (ctxInternal->algo == kDCP_Sha256)
+ {
+ dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_SHA256;
+ }
+ else if (ctxInternal->algo == kDCP_Sha1)
+ {
+ dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_SHA1;
+ }
+ else if (ctxInternal->algo == kDCP_Crc32)
+ {
+ /* In CRC-32 case if size is zero, do not schedule other computing */
+ if (size == 0U)
+ {
+#if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ /* Clear DCACHE memory before starting the engine */
+ SCB_CleanDCache_by_Addr((uint32_t *)ctxInternal, sizeof(dcp_hash_ctx_internal_t));
+#endif
+ /* Make sure that all data memory accesses are completed before starting of the job */
+ __DSB();
+ __ISB();
+ return kStatus_Success;
+ }
+ dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_CRC32;
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+ dcpPacket->sourceBufferAddress = (uint32_t)msg;
+ dcpPacket->destinationBufferAddress = 0;
+ dcpPacket->bufferSize = size;
+ dcpPacket->payloadPointer = (uint32_t)ctxInternal->runningHash;
+
+#if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ /* Clear DCACHE memory before starting the engine */
+ SCB_CleanDCache_by_Addr((uint32_t *)ctxInternal, sizeof(dcp_hash_ctx_internal_t));
+#endif
+ /* Make sure that all data memory accesses are completed before starting of the job */
+ __DSB();
+ __ISB();
+
+ return dcp_schedule_work(base, ctxInternal->handle, dcpPacket);
+}
+
+static status_t dcp_hash_update(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal, const uint8_t *msg, size_t size)
+{
+ status_t completionStatus = kStatus_Fail;
+
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_work_packet_t *dcpWork;
+ uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ dcpWork = (dcp_work_packet_t *)DCP_FindCacheLine(dcpWorkExt);
+#else
+ dcp_work_packet_t dcpWorkPacket = {0};
+ dcp_work_packet_t *dcpWork = &dcpWorkPacket;
+#endif
+
+ do
+ {
+ completionStatus = dcp_hash_update_non_blocking(base, ctxInternal, dcpWork, msg, size);
+ } while (completionStatus == (int32_t)kStatus_DCP_Again);
+
+ completionStatus = DCP_WaitForChannelComplete(base, ctxInternal->handle);
+
+ ctxInternal->ctrl0 = 0; /* clear kDCP_CONTROL0_HASH_INIT and kDCP_CONTROL0_HASH_TERM flags */
+ return (completionStatus);
+}
+
+/*!
+ * @brief Adds message to current hash.
+ *
+ * This function merges the message to fill the internal buffer, empties the internal buffer if
+ * it becomes full, then process all remaining message data.
+ *
+ *
+ * @param base DCP peripheral base address.
+ * @param ctxInternal Internal context.
+ * @param message Input message.
+ * @param messageSize Size of input message in bytes.
+ * @return kStatus_Success.
+ */
+static status_t dcp_hash_process_message_data(DCP_Type *base,
+ dcp_hash_ctx_internal_t *ctxInternal,
+ const uint8_t *message,
+ size_t messageSize)
+{
+ status_t status = kStatus_Fail;
+
+ /* if there is partially filled internal buffer, fill it to full block */
+ if (ctxInternal->blksz > 0U)
+ {
+ size_t toCopy = DCP_HASH_BLOCK_SIZE - ctxInternal->blksz;
+ (void)dcp_memcpy(&ctxInternal->blk.b[ctxInternal->blksz], message, toCopy);
+ message += toCopy;
+ messageSize -= toCopy;
+
+ /* process full internal block */
+ status = dcp_hash_update(base, ctxInternal, &ctxInternal->blk.b[0], DCP_HASH_BLOCK_SIZE);
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+ }
+
+ /* process all full blocks in message[] */
+ uint32_t fullBlocksSize = ((messageSize >> 6) << 6); /* (X / 64) * 64 */
+ if (fullBlocksSize > 0U)
+ {
+ status = dcp_hash_update(base, ctxInternal, message, fullBlocksSize);
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+ message += fullBlocksSize;
+ messageSize -= fullBlocksSize;
+ }
+
+ /* copy last incomplete message bytes into internal block */
+ (void)dcp_memcpy(&ctxInternal->blk.b[0], message, messageSize);
+ ctxInternal->blksz = messageSize;
+
+ return status;
+}
+
+/*!
+ * @brief Finalize the running hash to make digest.
+ *
+ * This function empties the internal buffer, adds padding bits, and generates final digest.
+ *
+ * @param base SHA peripheral base address.
+ * @param ctxInternal Internal context.
+ * @return kStatus_Success.
+ */
+static status_t dcp_hash_finalize(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal)
+{
+ status_t status;
+
+ ctxInternal->ctrl0 |= (uint32_t)kDCP_CONTROL0_HASH_TERM;
+ status = dcp_hash_update(base, ctxInternal, &ctxInternal->blk.b[0], ctxInternal->blksz);
+
+ return status;
+}
+
+static void dcp_hash_save_running_hash(dcp_hash_ctx_internal_t *ctxInternal)
+{
+ uint32_t *srcAddr = NULL;
+
+ switch (ctxInternal->handle->channel)
+ {
+ case kDCP_Channel0:
+ srcAddr = &s_dcpContextSwitchingBuffer.x[43];
+ break;
+
+ case kDCP_Channel1:
+ srcAddr = &s_dcpContextSwitchingBuffer.x[30];
+ break;
+
+ case kDCP_Channel2:
+ srcAddr = &s_dcpContextSwitchingBuffer.x[17];
+ break;
+
+ case kDCP_Channel3:
+ srcAddr = &s_dcpContextSwitchingBuffer.x[4];
+ break;
+
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+ if (srcAddr != NULL)
+ {
+ (void)dcp_memcpy(ctxInternal->runningHash, srcAddr, sizeof(ctxInternal->runningHash));
+ }
+}
+
+static void dcp_hash_restore_running_hash(dcp_hash_ctx_internal_t *ctxInternal)
+{
+ uint32_t *destAddr = NULL;
+
+ switch (ctxInternal->handle->channel)
+ {
+ case kDCP_Channel0:
+ destAddr = &s_dcpContextSwitchingBuffer.x[43];
+ break;
+
+ case kDCP_Channel1:
+ destAddr = &s_dcpContextSwitchingBuffer.x[30];
+ break;
+
+ case kDCP_Channel2:
+ destAddr = &s_dcpContextSwitchingBuffer.x[17];
+ break;
+
+ case kDCP_Channel3:
+ destAddr = &s_dcpContextSwitchingBuffer.x[4];
+ break;
+
+ default:
+ /* No valid channel */
+ break;
+ }
+ if (destAddr != NULL)
+ {
+ (void)dcp_memcpy(destAddr, ctxInternal->runningHash, sizeof(ctxInternal->runningHash));
+ }
+}
+
+/*!
+ * brief Initialize HASH context
+ *
+ * This function initializes the HASH.
+ *
+ * param base DCP peripheral base address
+ * param handle Specifies the DCP channel used for hashing.
+ * param[out] ctx Output hash context
+ * param algo Underlaying algorithm to use for hash computation.
+ * return Status of initialization
+ */
+status_t DCP_HASH_Init(DCP_Type *base, dcp_handle_t *handle, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo)
+{
+ status_t status;
+
+ dcp_hash_ctx_internal_t *ctxInternal;
+ /* compile time check for the correct structure size */
+ BUILD_ASSURE(sizeof(dcp_hash_ctx_t) >= sizeof(dcp_hash_ctx_internal_t), dcp_hash_ctx_t_size);
+ uint32_t i;
+
+ status = dcp_hash_check_input_args(base, ctx, algo);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+
+ /* set algorithm in context struct for later use */
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
+ ctxInternal->algo = algo;
+ ctxInternal->blksz = 0u;
+
+ const uint32_t j = sizeof(ctxInternal->blk.w) / sizeof(ctxInternal->blk.w[0]);
+ for (i = 0; i < j; i++)
+ {
+ ctxInternal->blk.w[i] = 0u;
+ }
+ ctxInternal->state = kDCP_StateHashInit;
+ ctxInternal->fullMessageSize = 0;
+ ctxInternal->handle = handle;
+ return status;
+}
+
+/*!
+ * brief Add data to current HASH
+ *
+ * Add data to current HASH. This can be called repeatedly with an arbitrary amount of data to be
+ * hashed. The functions blocks. If it returns kStatus_Success, the running hash
+ * has been updated (DCP has processed the input data), so the memory at ref input pointer
+ * can be released back to system. The DCP context buffer is updated with the running hash
+ * and with all necessary information to support possible context switch.
+ *
+ * param base DCP peripheral base address
+ * param[in,out] ctx HASH context
+ * param input Input data
+ * param inputSize Size of input data in bytes
+ * return Status of the hash update operation
+ */
+status_t DCP_HASH_Update(DCP_Type *base, dcp_hash_ctx_t *ctx, const uint8_t *input, size_t inputSize)
+{
+ bool isUpdateState;
+ status_t status;
+ dcp_hash_ctx_internal_t *ctxInternal;
+ size_t blockSize;
+
+ if (inputSize == 0U)
+ {
+ return kStatus_Success;
+ }
+
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
+ status = dcp_hash_check_context(ctxInternal, input);
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+
+ ctxInternal->fullMessageSize += inputSize;
+ blockSize = DCP_HASH_BLOCK_SIZE;
+ /* if we are still less than DCP_HASH_BLOCK_SIZE bytes, keep only in context */
+ if ((ctxInternal->blksz + inputSize) <= blockSize)
+ {
+ (void)dcp_memcpy((&ctxInternal->blk.b[0]) + ctxInternal->blksz, input, inputSize);
+ ctxInternal->blksz += inputSize;
+ return status;
+ }
+ else
+ {
+ isUpdateState = ctxInternal->state == kDCP_StateHashUpdate;
+ if (!isUpdateState)
+ {
+ /* start NEW hash */
+ status = dcp_hash_engine_init(base, ctxInternal);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+ ctxInternal->state = kDCP_StateHashUpdate;
+ }
+ else
+ {
+ dcp_hash_restore_running_hash(ctxInternal);
+ }
+ }
+
+ /* process input data */
+ status = dcp_hash_process_message_data(base, ctxInternal, input, inputSize);
+ dcp_hash_save_running_hash(ctxInternal);
+ return status;
+}
+
+/*!
+ * brief Finalize hashing
+ *
+ * Outputs the final hash (computed by DCP_HASH_Update()) and erases the context.
+ *
+ * param[in,out] ctx Input hash context
+ * param[out] output Output hash data
+ * param[in,out] outputSize Optional parameter (can be passed as NULL). On function entry, it specifies the size of
+ * output[] buffer. On function return, it stores the number of updated output bytes.
+ * return Status of the hash finish operation
+ */
+status_t DCP_HASH_Finish(DCP_Type *base, dcp_hash_ctx_t *ctx, uint8_t *output, size_t *outputSize)
+{
+ size_t algOutSize = 0;
+ status_t status;
+ dcp_hash_ctx_internal_t *ctxInternal;
+
+ ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
+ status = dcp_hash_check_context(ctxInternal, output);
+
+ if (kStatus_Success != status)
+ {
+ return status;
+ }
+
+ if (ctxInternal->state == kDCP_StateHashInit)
+ {
+ status = dcp_hash_engine_init(base, ctxInternal);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+ }
+ else
+ {
+ dcp_hash_restore_running_hash(ctxInternal);
+ }
+
+ size_t outSize = 0u;
+
+ /* compute algorithm output length */
+ switch (ctxInternal->algo)
+ {
+ case kDCP_Sha256:
+ outSize = (uint32_t)kDCP_OutLenSha256;
+ break;
+ case kDCP_Sha1:
+ outSize = (uint32_t)kDCP_OutLenSha1;
+ break;
+ case kDCP_Crc32:
+ outSize = (uint32_t)kDCP_OutLenCrc32;
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+ algOutSize = outSize;
+
+#if defined(DCP_HASH_CAVP_COMPATIBLE)
+ if (ctxInternal->fullMessageSize == 0U)
+ {
+ switch (ctxInternal->algo)
+ {
+ case kDCP_Sha256:
+ (void)dcp_memcpy(&output[0], &s_nullSha256, 32);
+ break;
+ case kDCP_Sha1:
+ (void)dcp_memcpy(&output[0], &s_nullSha1, 20);
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+
+ return kStatus_Success;
+ }
+#endif /* DCP_HASH_CAVP_COMPATIBLE */
+
+ /* flush message last incomplete block, if there is any, and add padding bits */
+ status = dcp_hash_finalize(base, ctxInternal);
+
+ if (outputSize != NULL)
+ {
+ if (algOutSize < *outputSize)
+ {
+ *outputSize = algOutSize;
+ }
+ else
+ {
+ algOutSize = *outputSize;
+ }
+ }
+
+#if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ SCB_InvalidateDCache_by_Addr(ctx, sizeof(dcp_hash_ctx_t));
+#endif
+ /* Reverse and copy result to output[] */
+ dcp_reverse_and_copy((uint8_t *)ctxInternal->runningHash, &output[0], algOutSize);
+
+ (void)memset(ctx, 0, sizeof(dcp_hash_ctx_t));
+ return status;
+}
+
+/*!
+ * brief Create HASH on given data
+ *
+ * Perform the full SHA or CRC32 in one function call. The function is blocking.
+ *
+ * param base DCP peripheral base address
+ * param handle Handle used for the request.
+ * param algo Underlaying algorithm to use for hash computation.
+ * param input Input data
+ * param inputSize Size of input data in bytes
+ * param[out] output Output hash data
+ * param[out] outputSize Output parameter storing the size of the output hash in bytes
+ * return Status of the one call hash operation.
+ */
+status_t DCP_HASH(DCP_Type *base,
+ dcp_handle_t *handle,
+ dcp_hash_algo_t algo,
+ const uint8_t *input,
+ size_t inputSize,
+ uint8_t *output,
+ size_t *outputSize)
+{
+ /* Use extended DCACHE line size aligned structure */
+#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
+ dcp_hash_ctx_t *hashCtx;
+ uint8_t hashCtxExt[sizeof(dcp_hash_ctx_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
+ hashCtx = (dcp_hash_ctx_t *)DCP_FindCacheLine(hashCtxExt);
+#else
+ dcp_hash_ctx_t hashCtxStruct = {0};
+ dcp_hash_ctx_t *hashCtx = &hashCtxStruct;
+#endif
+
+ status_t status;
+
+ status = DCP_HASH_Init(base, handle, hashCtx, algo);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+
+ status = DCP_HASH_Update(base, hashCtx, input, inputSize);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+
+ status = DCP_HASH_Finish(base, hashCtx, output, outputSize);
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dmamux.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dmamux.c
new file mode 100644
index 0000000000..8bfbe6c367
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_dmamux.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_dmamux.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.dmamux"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for DMAMUX.
+ *
+ * @param base DMAMUX peripheral base address.
+ */
+static uint32_t DMAMUX_GetInstance(DMAMUX_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map DMAMUX instance number to base pointer. */
+static DMAMUX_Type *const s_dmamuxBases[] = DMAMUX_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map DMAMUX instance number to clock name. */
+static const clock_ip_name_t s_dmamuxClockName[] = DMAMUX_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t DMAMUX_GetInstance(DMAMUX_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_dmamuxBases); instance++)
+ {
+ if (s_dmamuxBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_dmamuxBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the DMAMUX peripheral.
+ *
+ * This function ungates the DMAMUX clock.
+ *
+ * param base DMAMUX peripheral base address.
+ *
+ */
+void DMAMUX_Init(DMAMUX_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(s_dmamuxClockName[DMAMUX_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Deinitializes the DMAMUX peripheral.
+ *
+ * This function gates the DMAMUX clock.
+ *
+ * param base DMAMUX peripheral base address.
+ */
+void DMAMUX_Deinit(DMAMUX_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_dmamuxClockName[DMAMUX_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_edma.c
new file mode 100644
index 0000000000..e74334bc5a
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_edma.c
@@ -0,0 +1,2849 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.edma"
+#endif
+
+#define EDMA_TRANSFER_ENABLED_MASK 0x80U
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance offset.
+ *
+ * @param instance EDMA peripheral instance number.
+ */
+static uint32_t EDMA_GetInstanceOffset(uint32_t instance);
+
+/*!
+ * @brief Map transfer width.
+ *
+ * @param width transfer width.
+ */
+static edma_transfer_size_t EDMA_TransferWidthMapping(uint32_t width);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map EDMA instance number to base pointer. */
+static DMA_Type *const s_edmaBases[] = DMA_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map EDMA instance number to clock name. */
+static const clock_ip_name_t s_edmaClockName[] = EDMA_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Array to map EDMA instance number to IRQ number. */
+static const IRQn_Type s_edmaIRQNumber[][FSL_FEATURE_EDMA_MODULE_CHANNEL] = DMA_CHN_IRQS;
+
+/*! @brief Pointers to transfer handle for each EDMA channel. */
+static edma_handle_t *s_EDMAHandle[FSL_FEATURE_EDMA_MODULE_CHANNEL * FSL_FEATURE_SOC_EDMA_COUNT];
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t EDMA_GetInstance(DMA_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_edmaBases); instance++)
+ {
+ if (s_edmaBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_edmaBases));
+
+ return instance;
+}
+
+/*!
+ * brief Push content of TCD structure into hardware TCD register.
+ *
+ * param base EDMA peripheral base address.
+ * param channel EDMA channel number.
+ * param tcd Point to TCD structure.
+ */
+void EDMA_InstallTCD(DMA_Type *base, uint32_t channel, edma_tcd_t *tcd)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ /* Push tcd into hardware TCD register */
+ base->TCD[channel].SADDR = tcd->SADDR;
+ base->TCD[channel].SOFF = tcd->SOFF;
+ base->TCD[channel].ATTR = tcd->ATTR;
+ base->TCD[channel].NBYTES_MLNO = tcd->NBYTES;
+ base->TCD[channel].SLAST = tcd->SLAST;
+ base->TCD[channel].DADDR = tcd->DADDR;
+ base->TCD[channel].DOFF = tcd->DOFF;
+ base->TCD[channel].CITER_ELINKNO = tcd->CITER;
+ base->TCD[channel].DLAST_SGA = tcd->DLAST_SGA;
+ /* Clear DONE bit first, otherwise ESG cannot be set */
+ base->TCD[channel].CSR = 0;
+ base->TCD[channel].CSR = tcd->CSR;
+ base->TCD[channel].BITER_ELINKNO = tcd->BITER;
+}
+
+/*!
+ * brief Initializes the eDMA peripheral.
+ *
+ * This function ungates the eDMA clock and configures the eDMA peripheral according
+ * to the configuration structure.
+ *
+ * param base eDMA peripheral base address.
+ * param config A pointer to the configuration structure, see "edma_config_t".
+ * note This function enables the minor loop map feature.
+ */
+void EDMA_Init(DMA_Type *base, const edma_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t tmpreg;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate EDMA peripheral clock */
+ CLOCK_EnableClock(s_edmaClockName[EDMA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* clear all the enabled request, status to make sure EDMA status is in normal condition */
+ base->ERQ = 0U;
+ base->INT = 0xFFFFFFFFU;
+ base->ERR = 0xFFFFFFFFU;
+ /* Configure EDMA peripheral according to the configuration structure. */
+ tmpreg = base->CR;
+ tmpreg &= ~(DMA_CR_ERCA_MASK | DMA_CR_HOE_MASK | DMA_CR_CLM_MASK | DMA_CR_EDBG_MASK);
+ tmpreg |= (DMA_CR_ERCA(config->enableRoundRobinArbitration) | DMA_CR_HOE(config->enableHaltOnError) |
+ DMA_CR_CLM(config->enableContinuousLinkMode) | DMA_CR_EDBG(config->enableDebugMode) | DMA_CR_EMLM(1U));
+ base->CR = tmpreg;
+}
+
+/*!
+ * brief Deinitializes the eDMA peripheral.
+ *
+ * This function gates the eDMA clock.
+ *
+ * param base eDMA peripheral base address.
+ */
+void EDMA_Deinit(DMA_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate EDMA peripheral clock */
+ CLOCK_DisableClock(s_edmaClockName[EDMA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the eDMA default configuration structure.
+ *
+ * This function sets the configuration structure to default values.
+ * The default configuration is set to the following values.
+ * code
+ * config.enableContinuousLinkMode = false;
+ * config.enableHaltOnError = true;
+ * config.enableRoundRobinArbitration = false;
+ * config.enableDebugMode = false;
+ * endcode
+ *
+ * param config A pointer to the eDMA configuration structure.
+ */
+void EDMA_GetDefaultConfig(edma_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableRoundRobinArbitration = false;
+ config->enableHaltOnError = true;
+ config->enableContinuousLinkMode = false;
+ config->enableDebugMode = false;
+}
+
+/*!
+ * brief Sets all TCD registers to default values.
+ *
+ * This function sets TCD registers for this channel to default values.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * note This function must not be called while the channel transfer is ongoing
+ * or it causes unpredictable results.
+ * note This function enables the auto stop request feature.
+ */
+void EDMA_ResetChannel(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ EDMA_TcdReset((edma_tcd_t *)(uint32_t)&base->TCD[channel]);
+}
+
+/*!
+ * brief Configures the eDMA transfer attribute.
+ *
+ * This function configures the transfer attribute, including source address, destination address,
+ * transfer size, address offset, and so on. It also configures the scatter gather feature if the
+ * user supplies the TCD address.
+ * Example:
+ * code
+ * edma_transfer_t config;
+ * edma_tcd_t tcd;
+ * config.srcAddr = ..;
+ * config.destAddr = ..;
+ * ...
+ * EDMA_SetTransferConfig(DMA0, channel, &config, &stcd);
+ * endcode
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param config Pointer to eDMA transfer configuration structure.
+ * param nextTcd Point to TCD structure. It can be NULL if users
+ * do not want to enable scatter/gather feature.
+ * note If nextTcd is not NULL, it means scatter gather feature is enabled
+ * and DREQ bit is cleared in the previous transfer configuration, which
+ * is set in the eDMA_ResetChannel.
+ */
+void EDMA_SetTransferConfig(DMA_Type *base, uint32_t channel, const edma_transfer_config_t *config, edma_tcd_t *nextTcd)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(config != NULL);
+ assert(((uint32_t)nextTcd & 0x1FU) == 0U);
+
+ EDMA_TcdSetTransferConfig((edma_tcd_t *)(uint32_t)&base->TCD[channel], config, nextTcd);
+}
+
+/*!
+ * brief Configures the eDMA minor offset feature.
+ *
+ * The minor offset means that the signed-extended value is added to the source address or destination
+ * address after each minor loop.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param config A pointer to the minor offset configuration structure.
+ */
+void EDMA_SetMinorOffsetConfig(DMA_Type *base, uint32_t channel, const edma_minor_offset_config_t *config)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(config != NULL);
+
+ uint32_t tmpreg;
+
+ tmpreg = base->TCD[channel].NBYTES_MLOFFYES;
+ tmpreg &= ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
+ tmpreg |=
+ (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
+ DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
+ base->TCD[channel].NBYTES_MLOFFYES = tmpreg;
+}
+
+/*!
+ * brief Configures the eDMA channel preemption feature.
+ *
+ * This function configures the channel preemption attribute and the priority of the channel.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number
+ * param config A pointer to the channel preemption configuration structure.
+ */
+void EDMA_SetChannelPreemptionConfig(DMA_Type *base, uint32_t channel, const edma_channel_Preemption_config_t *config)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(config != NULL);
+
+ bool tmpEnablePreemptAbility = config->enablePreemptAbility;
+ bool tmpEnableChannelPreemption = config->enableChannelPreemption;
+ uint8_t tmpChannelPriority = config->channelPriority;
+ volatile uint8_t *tmpReg = &base->DCHPRI3;
+
+ ((volatile uint8_t *)tmpReg)[DMA_DCHPRI_INDEX(channel)] =
+ (DMA_DCHPRI0_DPA((true == tmpEnablePreemptAbility ? 0U : 1U)) |
+ DMA_DCHPRI0_ECP((true == tmpEnableChannelPreemption ? 1U : 0U)) | DMA_DCHPRI0_CHPRI(tmpChannelPriority));
+}
+
+/*!
+ * brief Sets the channel link for the eDMA transfer.
+ *
+ * This function configures either the minor link or the major link mode. The minor link means that the channel link is
+ * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
+ * exhausted.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param type A channel link type, which can be one of the following:
+ * arg kEDMA_LinkNone
+ * arg kEDMA_MinorLink
+ * arg kEDMA_MajorLink
+ * param linkedChannel The linked channel number.
+ * note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
+ */
+void EDMA_SetChannelLink(DMA_Type *base, uint32_t channel, edma_channel_link_type_t type, uint32_t linkedChannel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+ assert(linkedChannel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ EDMA_TcdSetChannelLink((edma_tcd_t *)(uint32_t)&base->TCD[channel], type, linkedChannel);
+}
+
+/*!
+ * brief Sets the bandwidth for the eDMA transfer.
+ *
+ * Because the eDMA processes the minor loop, it continuously generates read/write sequences
+ * until the minor count is exhausted. The bandwidth forces the eDMA to stall after the completion of
+ * each read/write access to control the bus request bandwidth seen by the crossbar switch.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param bandWidth A bandwidth setting, which can be one of the following:
+ * arg kEDMABandwidthStallNone
+ * arg kEDMABandwidthStall4Cycle
+ * arg kEDMABandwidthStall8Cycle
+ */
+void EDMA_SetBandWidth(DMA_Type *base, uint32_t channel, edma_bandwidth_t bandWidth)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ base->TCD[channel].CSR = (uint16_t)((base->TCD[channel].CSR & (~DMA_CSR_BWC_MASK)) | DMA_CSR_BWC(bandWidth));
+}
+
+/*!
+ * brief Sets the source modulo and the destination modulo for the eDMA transfer.
+ *
+ * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
+ * calculation is performed or the original register value. It provides the ability to implement a circular data
+ * queue easily.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param srcModulo A source modulo value.
+ * param destModulo A destination modulo value.
+ */
+void EDMA_SetModulo(DMA_Type *base, uint32_t channel, edma_modulo_t srcModulo, edma_modulo_t destModulo)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint16_t tmpreg;
+
+ tmpreg = base->TCD[channel].ATTR & (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
+ base->TCD[channel].ATTR = tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
+}
+
+/*!
+ * brief Enables the interrupt source for the eDMA transfer.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_EnableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Enable error interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_ErrorInterruptEnable))
+ {
+ base->EEI |= ((uint32_t)0x1U << channel);
+ }
+
+ /* Enable Major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
+ {
+ base->TCD[channel].CSR |= DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Enable Half major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
+ {
+ base->TCD[channel].CSR |= DMA_CSR_INTHALF_MASK;
+ }
+}
+
+/*!
+ * brief Disables the interrupt source for the eDMA transfer.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param mask The mask of the interrupt source to be set. Use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_DisableChannelInterrupts(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Disable error interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_ErrorInterruptEnable))
+ {
+ base->EEI &= (~((uint32_t)0x1U << channel));
+ }
+
+ /* Disable Major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
+ {
+ base->TCD[channel].CSR &= ~(uint16_t)DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Disable Half major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
+ {
+ base->TCD[channel].CSR &= ~(uint16_t)DMA_CSR_INTHALF_MASK;
+ }
+}
+
+/*!
+ * brief Sets all fields to default values for the TCD structure.
+ *
+ * This function sets all fields for this TCD structure to default value.
+ *
+ * param tcd Pointer to the TCD structure.
+ * note This function enables the auto stop request feature.
+ */
+void EDMA_TcdReset(edma_tcd_t *tcd)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ /* Reset channel TCD */
+ tcd->SADDR = 0U;
+ tcd->SOFF = 0U;
+ tcd->ATTR = 0U;
+ tcd->NBYTES = 0U;
+ tcd->SLAST = 0U;
+ tcd->DADDR = 0U;
+ tcd->DOFF = 0U;
+ tcd->CITER = 0U;
+ tcd->DLAST_SGA = 0U;
+ /* Enable auto disable request feature */
+ tcd->CSR = DMA_CSR_DREQ(true);
+ tcd->BITER = 0U;
+}
+
+/*!
+ * brief Configures the eDMA TCD transfer attribute.
+ *
+ * The TCD is a transfer control descriptor. The content of the TCD is the same as the hardware TCD registers.
+ * The STCD is used in the scatter-gather mode.
+ * This function configures the TCD transfer attribute, including source address, destination address,
+ * transfer size, address offset, and so on. It also configures the scatter gather feature if the
+ * user supplies the next TCD address.
+ * Example:
+ * code
+ * edma_transfer_t config = {
+ * ...
+ * }
+ * edma_tcd_t tcd __aligned(32);
+ * edma_tcd_t nextTcd __aligned(32);
+ * EDMA_TcdSetTransferConfig(&tcd, &config, &nextTcd);
+ * endcode
+ *
+ * param tcd Pointer to the TCD structure.
+ * param config Pointer to eDMA transfer configuration structure.
+ * param nextTcd Pointer to the next TCD structure. It can be NULL if users
+ * do not want to enable scatter/gather feature.
+ * note TCD address should be 32 bytes aligned or it causes an eDMA error.
+ * note If the nextTcd is not NULL, the scatter gather feature is enabled
+ * and DREQ bit is cleared in the previous transfer configuration, which
+ * is set in the EDMA_TcdReset.
+ */
+void EDMA_TcdSetTransferConfig(edma_tcd_t *tcd, const edma_transfer_config_t *config, edma_tcd_t *nextTcd)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+ assert(config != NULL);
+ assert(((uint32_t)nextTcd & 0x1FU) == 0U);
+ assert((config->srcAddr % (1UL << (uint32_t)config->srcTransferSize)) == 0U);
+ assert((config->destAddr % (1UL << (uint32_t)config->destTransferSize)) == 0U);
+
+ /* source address */
+ tcd->SADDR = config->srcAddr;
+ /* destination address */
+ tcd->DADDR = config->destAddr;
+ /* Source data and destination data transfer size */
+ tcd->ATTR = DMA_ATTR_SSIZE(config->srcTransferSize) | DMA_ATTR_DSIZE(config->destTransferSize);
+ /* Source address signed offset */
+ tcd->SOFF = (uint16_t)config->srcOffset;
+ /* Destination address signed offset */
+ tcd->DOFF = (uint16_t)config->destOffset;
+ /* Minor byte transfer count */
+ tcd->NBYTES = config->minorLoopBytes;
+ /* Current major iteration count */
+ tcd->CITER = (uint16_t)config->majorLoopCounts;
+ /* Starting major iteration count */
+ tcd->BITER = (uint16_t)config->majorLoopCounts;
+ /* Enable scatter/gather processing */
+ if (nextTcd != NULL)
+ {
+ tcd->DLAST_SGA = (uint32_t)nextTcd;
+ /*
+ Before call EDMA_TcdSetTransferConfig or EDMA_SetTransferConfig,
+ user must call EDMA_TcdReset or EDMA_ResetChannel which will set
+ DREQ, so must use "|" or "&" rather than "=".
+
+ Clear the DREQ bit because scatter gather has been enabled, so the
+ previous transfer is not the last transfer, and channel request should
+ be enabled at the next transfer(the next TCD).
+ */
+ tcd->CSR = (tcd->CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
+ }
+}
+
+/*!
+ * brief Configures the eDMA TCD minor offset feature.
+ *
+ * A minor offset is a signed-extended value added to the source address or a destination
+ * address after each minor loop.
+ *
+ * param tcd A point to the TCD structure.
+ * param config A pointer to the minor offset configuration structure.
+ */
+void EDMA_TcdSetMinorOffsetConfig(edma_tcd_t *tcd, const edma_minor_offset_config_t *config)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ uint32_t tmpreg;
+
+ tmpreg = tcd->NBYTES &
+ ~(DMA_NBYTES_MLOFFYES_SMLOE_MASK | DMA_NBYTES_MLOFFYES_DMLOE_MASK | DMA_NBYTES_MLOFFYES_MLOFF_MASK);
+ tmpreg |=
+ (DMA_NBYTES_MLOFFYES_SMLOE(config->enableSrcMinorOffset) |
+ DMA_NBYTES_MLOFFYES_DMLOE(config->enableDestMinorOffset) | DMA_NBYTES_MLOFFYES_MLOFF(config->minorOffset));
+ tcd->NBYTES = tmpreg;
+}
+
+/*!
+ * brief Sets the channel link for the eDMA TCD.
+ *
+ * This function configures either a minor link or a major link. The minor link means the channel link is
+ * triggered every time CITER decreases by 1. The major link means that the channel link is triggered when the CITER is
+ * exhausted.
+ *
+ * note Users should ensure that DONE flag is cleared before calling this interface, or the configuration is invalid.
+ * param tcd Point to the TCD structure.
+ * param type Channel link type, it can be one of:
+ * arg kEDMA_LinkNone
+ * arg kEDMA_MinorLink
+ * arg kEDMA_MajorLink
+ * param linkedChannel The linked channel number.
+ */
+void EDMA_TcdSetChannelLink(edma_tcd_t *tcd, edma_channel_link_type_t type, uint32_t linkedChannel)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+ assert(linkedChannel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ if (type == kEDMA_MinorLink) /* Minor link config */
+ {
+ uint16_t tmpreg;
+
+ /* Enable minor link */
+ tcd->CITER |= DMA_CITER_ELINKYES_ELINK_MASK;
+ tcd->BITER |= DMA_BITER_ELINKYES_ELINK_MASK;
+ /* Set linked channel */
+ tmpreg = tcd->CITER & (~(uint16_t)DMA_CITER_ELINKYES_LINKCH_MASK);
+ tmpreg |= DMA_CITER_ELINKYES_LINKCH(linkedChannel);
+ tcd->CITER = tmpreg;
+ tmpreg = tcd->BITER & (~(uint16_t)DMA_BITER_ELINKYES_LINKCH_MASK);
+ tmpreg |= DMA_BITER_ELINKYES_LINKCH(linkedChannel);
+ tcd->BITER = tmpreg;
+ }
+ else if (type == kEDMA_MajorLink) /* Major link config */
+ {
+ uint16_t tmpreg;
+
+ /* Enable major link */
+ tcd->CSR |= DMA_CSR_MAJORELINK_MASK;
+ /* Set major linked channel */
+ tmpreg = tcd->CSR & (~(uint16_t)DMA_CSR_MAJORLINKCH_MASK);
+ tcd->CSR = tmpreg | DMA_CSR_MAJORLINKCH(linkedChannel);
+ }
+ else /* Link none */
+ {
+ tcd->CITER &= ~(uint16_t)DMA_CITER_ELINKYES_ELINK_MASK;
+ tcd->BITER &= ~(uint16_t)DMA_BITER_ELINKYES_ELINK_MASK;
+ tcd->CSR &= ~(uint16_t)DMA_CSR_MAJORELINK_MASK;
+ }
+}
+
+/*!
+ * brief Sets the source modulo and the destination modulo for the eDMA TCD.
+ *
+ * This function defines a specific address range specified to be the value after (SADDR + SOFF)/(DADDR + DOFF)
+ * calculation is performed or the original register value. It provides the ability to implement a circular data
+ * queue easily.
+ *
+ * param tcd A pointer to the TCD structure.
+ * param srcModulo A source modulo value.
+ * param destModulo A destination modulo value.
+ */
+void EDMA_TcdSetModulo(edma_tcd_t *tcd, edma_modulo_t srcModulo, edma_modulo_t destModulo)
+{
+ assert(tcd != NULL);
+ assert(((uint32_t)tcd & 0x1FU) == 0U);
+
+ uint16_t tmpreg;
+
+ tmpreg = tcd->ATTR & (~(uint16_t)(DMA_ATTR_SMOD_MASK | DMA_ATTR_DMOD_MASK));
+ tcd->ATTR = tmpreg | DMA_ATTR_DMOD(destModulo) | DMA_ATTR_SMOD(srcModulo);
+}
+
+/*!
+ * brief Enables the interrupt source for the eDMA TCD.
+ *
+ * param tcd Point to the TCD structure.
+ * param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_TcdEnableInterrupts(edma_tcd_t *tcd, uint32_t mask)
+{
+ assert(tcd != NULL);
+
+ /* Enable Major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
+ {
+ tcd->CSR |= DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Enable Half major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
+ {
+ tcd->CSR |= DMA_CSR_INTHALF_MASK;
+ }
+}
+
+/*!
+ * brief Disables the interrupt source for the eDMA TCD.
+ *
+ * param tcd Point to the TCD structure.
+ * param mask The mask of interrupt source to be set. Users need to use
+ * the defined edma_interrupt_enable_t type.
+ */
+void EDMA_TcdDisableInterrupts(edma_tcd_t *tcd, uint32_t mask)
+{
+ assert(tcd != NULL);
+
+ /* Disable Major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_MajorInterruptEnable))
+ {
+ tcd->CSR &= ~(uint16_t)DMA_CSR_INTMAJOR_MASK;
+ }
+
+ /* Disable Half major interrupt */
+ if (0U != (mask & (uint32_t)kEDMA_HalfInterruptEnable))
+ {
+ tcd->CSR &= ~(uint16_t)DMA_CSR_INTHALF_MASK;
+ }
+}
+
+/*!
+ * brief Gets the remaining major loop count from the eDMA current channel TCD.
+ *
+ * This function checks the TCD (Task Control Descriptor) status for a specified
+ * eDMA channel and returns the number of major loop count that has not finished.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * return Major loop count which has not been transferred yet for the current TCD.
+ * note 1. This function can only be used to get unfinished major loop count of transfer without
+ * the next TCD, or it might be inaccuracy.
+ * 2. The unfinished/remaining transfer bytes cannot be obtained directly from registers while
+ * the channel is running.
+ * Because to calculate the remaining bytes, the initial NBYTES configured in DMA_TCDn_NBYTES_MLNO
+ * register is needed while the eDMA IP does not support getting it while a channel is active.
+ * In another word, the NBYTES value reading is always the actual (decrementing) NBYTES value the dma_engine
+ * is working with while a channel is running.
+ * Consequently, to get the remaining transfer bytes, a software-saved initial value of NBYTES (for example
+ * copied before enabling the channel) is needed. The formula to calculate it is shown below:
+ * RemainingBytes = RemainingMajorLoopCount * NBYTES(initially configured)
+ */
+uint32_t EDMA_GetRemainingMajorLoopCount(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t remainingCount = 0;
+
+ if (0U != (DMA_CSR_DONE_MASK & base->TCD[channel].CSR))
+ {
+ remainingCount = 0;
+ }
+ else
+ {
+ /* Calculate the unfinished bytes */
+ if (0U != (base->TCD[channel].CITER_ELINKNO & DMA_CITER_ELINKNO_ELINK_MASK))
+ {
+ remainingCount = (((uint32_t)base->TCD[channel].CITER_ELINKYES & DMA_CITER_ELINKYES_CITER_MASK) >>
+ DMA_CITER_ELINKYES_CITER_SHIFT);
+ }
+ else
+ {
+ remainingCount = (((uint32_t)base->TCD[channel].CITER_ELINKNO & DMA_CITER_ELINKNO_CITER_MASK) >>
+ DMA_CITER_ELINKNO_CITER_SHIFT);
+ }
+ }
+
+ return remainingCount;
+}
+
+/*!
+ * brief Gets the eDMA channel status flags.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * return The mask of channel status flags. Users need to use the
+ * _edma_channel_status_flags type to decode the return variables.
+ */
+uint32_t EDMA_GetChannelStatusFlags(DMA_Type *base, uint32_t channel)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t retval = 0;
+
+ /* Get DONE bit flag */
+ retval |= (((uint32_t)base->TCD[channel].CSR & DMA_CSR_DONE_MASK) >> DMA_CSR_DONE_SHIFT);
+ /* Get ERROR bit flag */
+ retval |= ((((uint32_t)base->ERR >> channel) & 0x1U) << 1U);
+ /* Get INT bit flag */
+ retval |= ((((uint32_t)base->INT >> channel) & 0x1U) << 2U);
+
+ return retval;
+}
+
+/*!
+ * brief Clears the eDMA channel status flags.
+ *
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ * param mask The mask of channel status to be cleared. Users need to use
+ * the defined _edma_channel_status_flags type.
+ */
+void EDMA_ClearChannelStatusFlags(DMA_Type *base, uint32_t channel, uint32_t mask)
+{
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ /* Clear DONE bit flag */
+ if (0U != (mask & (uint32_t)kEDMA_DoneFlag))
+ {
+ base->CDNE = (uint8_t)channel;
+ }
+ /* Clear ERROR bit flag */
+ if (0U != (mask & (uint32_t)kEDMA_ErrorFlag))
+ {
+ base->CERR = (uint8_t)channel;
+ }
+ /* Clear INT bit flag */
+ if (0U != (mask & (uint32_t)kEDMA_InterruptFlag))
+ {
+ base->CINT = (uint8_t)channel;
+ }
+}
+
+static uint32_t EDMA_GetInstanceOffset(uint32_t instance)
+{
+ static uint8_t startInstanceNum;
+
+#if defined(DMA0)
+ startInstanceNum = (uint8_t)EDMA_GetInstance(DMA0);
+#elif defined(DMA1)
+ startInstanceNum = (uint8_t)EDMA_GetInstance(DMA1);
+#elif defined(DMA2)
+ startInstanceNum = (uint8_t)EDMA_GetInstance(DMA2);
+#elif defined(DMA3)
+ startInstanceNum = (uint8_t)EDMA_GetInstance(DMA3);
+#endif
+
+ assert(startInstanceNum <= instance);
+
+ return instance - startInstanceNum;
+}
+
+/*!
+ * brief Creates the eDMA handle.
+ *
+ * This function is called if using the transactional API for eDMA. This function
+ * initializes the internal state of the eDMA handle.
+ *
+ * param handle eDMA handle pointer. The eDMA handle stores callback function and
+ * parameters.
+ * param base eDMA peripheral base address.
+ * param channel eDMA channel number.
+ */
+void EDMA_CreateHandle(edma_handle_t *handle, DMA_Type *base, uint32_t channel)
+{
+ assert(handle != NULL);
+ assert(channel < (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL);
+
+ uint32_t edmaInstance;
+ uint32_t channelIndex;
+ edma_tcd_t *tcdRegs;
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->base = base;
+ handle->channel = (uint8_t)channel;
+ /* Get the DMA instance number */
+ edmaInstance = EDMA_GetInstance(base);
+ channelIndex = (EDMA_GetInstanceOffset(edmaInstance) * (uint32_t)FSL_FEATURE_EDMA_MODULE_CHANNEL) + channel;
+ s_EDMAHandle[channelIndex] = handle;
+
+ /* Enable NVIC interrupt */
+ (void)EnableIRQ(s_edmaIRQNumber[edmaInstance][channel]);
+
+ /*
+ Reset TCD registers to zero. Unlike the EDMA_TcdReset(DREQ will be set),
+ CSR will be 0. Because in order to suit EDMA busy check mechanism in
+ EDMA_SubmitTransfer, CSR must be set 0.
+ */
+ tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
+ tcdRegs->SADDR = 0;
+ tcdRegs->SOFF = 0;
+ tcdRegs->ATTR = 0;
+ tcdRegs->NBYTES = 0;
+ tcdRegs->SLAST = 0;
+ tcdRegs->DADDR = 0;
+ tcdRegs->DOFF = 0;
+ tcdRegs->CITER = 0;
+ tcdRegs->DLAST_SGA = 0;
+ tcdRegs->CSR = 0;
+ tcdRegs->BITER = 0;
+}
+
+/*!
+ * brief Installs the TCDs memory pool into the eDMA handle.
+ *
+ * This function is called after the EDMA_CreateHandle to use scatter/gather feature. This function shall only be used
+ * while users need to use scatter gather mode. Scatter gather mode enables EDMA to load a new transfer control block
+ * (tcd) in hardware, and automatically reconfigure that DMA channel for a new transfer.
+ * Users need to prepare tcd memory and also configure tcds using interface EDMA_SubmitTransfer.
+ *
+ * param handle eDMA handle pointer.
+ * param tcdPool A memory pool to store TCDs. It must be 32 bytes aligned.
+ * param tcdSize The number of TCD slots.
+ */
+void EDMA_InstallTCDMemory(edma_handle_t *handle, edma_tcd_t *tcdPool, uint32_t tcdSize)
+{
+ assert(handle != NULL);
+ assert(((uint32_t)tcdPool & 0x1FU) == 0U);
+
+ /* Initialize tcd queue attribute. */
+ handle->header = 0;
+ handle->tail = 0;
+ handle->tcdUsed = 0;
+ handle->tcdSize = (int8_t)tcdSize;
+ handle->flags = 0;
+ handle->tcdPool = tcdPool;
+}
+
+/*!
+ * brief Installs a callback function for the eDMA transfer.
+ *
+ * This callback is called in the eDMA IRQ handler. Use the callback to do something after
+ * the current major loop transfer completes. This function will be called every time one tcd finished transfer.
+ *
+ * param handle eDMA handle pointer.
+ * param callback eDMA callback function pointer.
+ * param userData A parameter for the callback function.
+ */
+void EDMA_SetCallback(edma_handle_t *handle, edma_callback callback, void *userData)
+{
+ assert(handle != NULL);
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+static edma_transfer_size_t EDMA_TransferWidthMapping(uint32_t width)
+{
+ edma_transfer_size_t transferSize = kEDMA_TransferSize1Bytes;
+
+ /* map width to register value */
+ switch (width)
+ {
+ /* width 8bit */
+ case 1U:
+ transferSize = kEDMA_TransferSize1Bytes;
+ break;
+ /* width 16bit */
+ case 2U:
+ transferSize = kEDMA_TransferSize2Bytes;
+ break;
+ /* width 32bit */
+ case 4U:
+ transferSize = kEDMA_TransferSize4Bytes;
+ break;
+#if (defined(FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_8_BYTES_TRANSFER)
+ /* width 64bit */
+ case 8U:
+ transferSize = kEDMA_TransferSize8Bytes;
+ break;
+#endif
+#if (defined(FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER) && FSL_FEATURE_EDMA_SUPPORT_16_BYTES_TRANSFER)
+ /* width 128bit */
+ case 16U:
+ transferSize = kEDMA_TransferSize16Bytes;
+ break;
+#endif
+ /* width 256bit */
+ case 32U:
+ transferSize = kEDMA_TransferSize32Bytes;
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ assert(false);
+ break;
+ }
+
+ return transferSize;
+}
+
+/*!
+ * brief Prepares the eDMA transfer structure configurations.
+ *
+ * This function prepares the transfer configuration structure according to the user input.
+ *
+ * param config The user configuration structure of type edma_transfer_t.
+ * param srcAddr eDMA transfer source address.
+ * param srcWidth eDMA transfer source address width(bytes).
+ * param srcOffset source address offset.
+ * param destAddr eDMA transfer destination address.
+ * param destWidth eDMA transfer destination address width(bytes).
+ * param destOffset destination address offset.
+ * param bytesEachRequest eDMA transfer bytes per channel request.
+ * param transferBytes eDMA transfer bytes to be transferred.
+ * note The data address and the data width must be consistent. For example, if the SRC
+ * is 4 bytes, the source address must be 4 bytes aligned, or it results in
+ * source address error (SAE).
+ */
+void EDMA_PrepareTransferConfig(edma_transfer_config_t *config,
+ void *srcAddr,
+ uint32_t srcWidth,
+ int16_t srcOffset,
+ void *destAddr,
+ uint32_t destWidth,
+ int16_t destOffset,
+ uint32_t bytesEachRequest,
+ uint32_t transferBytes)
+{
+ assert(config != NULL);
+ assert(srcAddr != NULL);
+ assert(destAddr != NULL);
+ assert((srcWidth != 0U) && (srcWidth <= 32U) && ((srcWidth & (srcWidth - 1U)) == 0U));
+ assert((destWidth != 0U) && (destWidth <= 32U) && ((destWidth & (destWidth - 1U)) == 0U));
+ assert((transferBytes % bytesEachRequest) == 0U);
+ assert((((uint32_t)(uint32_t *)srcAddr) % srcWidth) == 0U);
+ assert((((uint32_t)(uint32_t *)destAddr) % destWidth) == 0U);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->destAddr = (uint32_t)(uint32_t *)destAddr;
+ config->srcAddr = (uint32_t)(uint32_t *)srcAddr;
+ config->minorLoopBytes = bytesEachRequest;
+ config->majorLoopCounts = transferBytes / bytesEachRequest;
+ config->srcTransferSize = EDMA_TransferWidthMapping(srcWidth);
+ config->destTransferSize = EDMA_TransferWidthMapping(destWidth);
+ config->destOffset = destOffset;
+ config->srcOffset = srcOffset;
+}
+
+/*!
+ * brief Prepares the eDMA transfer structure.
+ *
+ * This function prepares the transfer configuration structure according to the user input.
+ *
+ * param config The user configuration structure of type edma_transfer_t.
+ * param srcAddr eDMA transfer source address.
+ * param srcWidth eDMA transfer source address width(bytes).
+ * param destAddr eDMA transfer destination address.
+ * param destWidth eDMA transfer destination address width(bytes).
+ * param bytesEachRequest eDMA transfer bytes per channel request.
+ * param transferBytes eDMA transfer bytes to be transferred.
+ * param type eDMA transfer type.
+ * note The data address and the data width must be consistent. For example, if the SRC
+ * is 4 bytes, the source address must be 4 bytes aligned, or it results in
+ * source address error (SAE).
+ */
+void EDMA_PrepareTransfer(edma_transfer_config_t *config,
+ void *srcAddr,
+ uint32_t srcWidth,
+ void *destAddr,
+ uint32_t destWidth,
+ uint32_t bytesEachRequest,
+ uint32_t transferBytes,
+ edma_transfer_type_t type)
+{
+ assert(config != NULL);
+
+ int16_t srcOffset = 0, destOffset = 0;
+
+ switch (type)
+ {
+ case kEDMA_MemoryToMemory:
+ destOffset = (int16_t)destWidth;
+ srcOffset = (int16_t)srcWidth;
+ break;
+ case kEDMA_MemoryToPeripheral:
+ destOffset = 0;
+ srcOffset = (int16_t)srcWidth;
+ break;
+ case kEDMA_PeripheralToMemory:
+ destOffset = (int16_t)destWidth;
+ srcOffset = 0;
+ break;
+ case kEDMA_PeripheralToPeripheral:
+ destOffset = 0;
+ srcOffset = 0;
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ assert(false);
+ break;
+ }
+
+ EDMA_PrepareTransferConfig(config, srcAddr, srcWidth, srcOffset, destAddr, destWidth, destOffset, bytesEachRequest,
+ transferBytes);
+}
+
+/*!
+ * brief Submits the eDMA transfer request.
+ *
+ * This function submits the eDMA transfer request according to the transfer configuration structure.
+ * In scatter gather mode, call this function will add a configured tcd to the circular list of tcd pool.
+ * The tcd pools is setup by call function EDMA_InstallTCDMemory before.
+ *
+ * param handle eDMA handle pointer.
+ * param config Pointer to eDMA transfer configuration structure.
+ * retval kStatus_EDMA_Success It means submit transfer request succeed.
+ * retval kStatus_EDMA_QueueFull It means TCD queue is full. Submit transfer request is not allowed.
+ * retval kStatus_EDMA_Busy It means the given channel is busy, need to submit request later.
+ */
+status_t EDMA_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config)
+{
+ assert(handle != NULL);
+ assert(config != NULL);
+
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
+
+ if (handle->tcdPool == NULL)
+ {
+ /*
+ * Check if EDMA channel is busy:
+ * 1. if channel active bit is set, it implies that minor loop is executing, then channel is busy
+ * 2. if channel active bit is not set and BITER not equal to CITER, it implies that major loop is executing,
+ * then channel is busy
+ *
+ * There is one case can not be covered in below condition:
+ * When transfer request is submitted, but no request from peripheral, that is to say channel sevice doesn't
+ * begin, if application would like to submit another transfer , then the TCD will be overwritten, since the
+ * ACTIVE is 0 and BITER = CITER, for such case, it is a scatter gather(link TCD) case actually, so
+ * application should enabled TCD pool for dynamic scatter gather mode by calling EDMA_InstallTCDMemory.
+ */
+ if (((handle->base->TCD[handle->channel].CSR & DMA_CSR_ACTIVE_MASK) != 0U) ||
+ (((handle->base->TCD[handle->channel].CITER_ELINKNO & DMA_CITER_ELINKNO_CITER_MASK) !=
+ (handle->base->TCD[handle->channel].BITER_ELINKNO & DMA_BITER_ELINKNO_BITER_MASK))))
+ {
+ return kStatus_EDMA_Busy;
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->base, handle->channel, config, NULL);
+ /* Enable auto disable request feature */
+ handle->base->TCD[handle->channel].CSR |= DMA_CSR_DREQ_MASK;
+ /* Enable major interrupt */
+ handle->base->TCD[handle->channel].CSR |= DMA_CSR_INTMAJOR_MASK;
+
+ return kStatus_Success;
+ }
+ }
+ else /* Use the TCD queue. */
+ {
+ uint32_t primask;
+ uint16_t csr;
+ int8_t currentTcd;
+ int8_t previousTcd;
+ int8_t nextTcd;
+ int8_t tmpTcdUsed;
+ int8_t tmpTcdSize;
+
+ /* Check if tcd pool is full. */
+ primask = DisableGlobalIRQ();
+ tmpTcdUsed = handle->tcdUsed;
+ tmpTcdSize = handle->tcdSize;
+ if (tmpTcdUsed >= tmpTcdSize)
+ {
+ EnableGlobalIRQ(primask);
+
+ return kStatus_EDMA_QueueFull;
+ }
+ currentTcd = handle->tail;
+ handle->tcdUsed++;
+ /* Calculate index of next TCD */
+ nextTcd = currentTcd + 1;
+ if (nextTcd == handle->tcdSize)
+ {
+ nextTcd = 0;
+ }
+ /* Advance queue tail index */
+ handle->tail = nextTcd;
+ EnableGlobalIRQ(primask);
+ /* Calculate index of previous TCD */
+ previousTcd = currentTcd != 0 ? currentTcd - 1 : (handle->tcdSize - 1);
+ /* Configure current TCD block. */
+ EDMA_TcdReset(&handle->tcdPool[currentTcd]);
+ EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
+ /* Enable major interrupt */
+ handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
+ /* Link current TCD with next TCD for identification of current TCD */
+ handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
+ /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
+ if (currentTcd != previousTcd)
+ {
+ /* Enable scatter/gather feature in the previous TCD block. */
+ csr = handle->tcdPool[previousTcd].CSR | ((uint16_t)DMA_CSR_ESG_MASK);
+ csr &= ~((uint16_t)DMA_CSR_DREQ_MASK);
+ handle->tcdPool[previousTcd].CSR = csr;
+ /*
+ Check if the TCD block in the registers is the previous one (points to current TCD block). It
+ is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
+ link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
+ before link the previous TCD block.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
+ {
+ /* Clear the DREQ bits for the dynamic scatter gather */
+ tcdRegs->CSR |= DMA_CSR_DREQ_MASK;
+ /* Enable scatter/gather also in the TCD registers. */
+ csr = tcdRegs->CSR | DMA_CSR_ESG_MASK;
+ /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
+ tcdRegs->CSR = csr;
+ /*
+ It is very important to check the ESG bit!
+ Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
+ be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
+ and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
+ the current TCD block has been loaded into TCD registers), it means transfer finished
+ and TCD link operation fail, so must install TCD content into TCD registers and enable
+ transfer again. And if ESG is set, it means transfer has not finished, so TCD dynamic
+ link succeed.
+ */
+ if (0U != (tcdRegs->CSR & DMA_CSR_ESG_MASK))
+ {
+ tcdRegs->CSR &= ~(uint16_t)DMA_CSR_DREQ_MASK;
+ return kStatus_Success;
+ }
+ /*
+ Check whether the current TCD block is already loaded in the TCD registers. It is another
+ condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
+ TCD block has been loaded into TCD registers.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
+ {
+ return kStatus_Success;
+ }
+ /*
+ If go to this, means the previous transfer finished, and the DONE bit is set.
+ So shall configure TCD registers.
+ */
+ }
+ else if (tcdRegs->DLAST_SGA != 0UL)
+ {
+ /* The current TCD block has been linked successfully. */
+ return kStatus_Success;
+ }
+ else
+ {
+ /*
+ DLAST_SGA is 0 and it means the first submit transfer, so shall configure
+ TCD registers.
+ */
+ }
+ }
+ /* There is no live chain, TCD block need to be installed in TCD registers. */
+ EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
+ /* Enable channel request again. */
+ if (0U != (handle->flags & EDMA_TRANSFER_ENABLED_MASK))
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+
+ return kStatus_Success;
+ }
+}
+
+/*!
+ * brief eDMA starts transfer.
+ *
+ * This function enables the channel request. Users can call this function after submitting the transfer request
+ * or before submitting the transfer request.
+ *
+ * param handle eDMA handle pointer.
+ */
+void EDMA_StartTransfer(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+ uint32_t tmpCSR = 0;
+
+ if (handle->tcdPool == NULL)
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ else /* Use the TCD queue. */
+ {
+ uint32_t primask;
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)(uint32_t)&handle->base->TCD[handle->channel];
+
+ handle->flags |= EDMA_TRANSFER_ENABLED_MASK;
+
+ /* Check if there was at least one descriptor submitted since reset (TCD in registers is valid) */
+ if (tcdRegs->DLAST_SGA != 0U)
+ {
+ primask = DisableGlobalIRQ();
+ /* Check if channel request is actually disable. */
+ if ((handle->base->ERQ & ((uint32_t)1U << handle->channel)) == 0U)
+ {
+ /* Check if transfer is paused. */
+ tmpCSR = tcdRegs->CSR;
+ if ((0U == (tmpCSR & DMA_CSR_DONE_MASK)) || (0U != (tmpCSR & DMA_CSR_ESG_MASK)))
+ {
+ /*
+ Re-enable channel request must be as soon as possible, so must put it into
+ critical section to avoid task switching or interrupt service routine.
+ */
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ }
+ EnableGlobalIRQ(primask);
+ }
+ }
+}
+
+/*!
+ * brief eDMA stops transfer.
+ *
+ * This function disables the channel request to pause the transfer. Users can call EDMA_StartTransfer()
+ * again to resume the transfer.
+ *
+ * param handle eDMA handle pointer.
+ */
+void EDMA_StopTransfer(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ handle->flags &= (~(uint8_t)EDMA_TRANSFER_ENABLED_MASK);
+ handle->base->CERQ = DMA_CERQ_CERQ(handle->channel);
+}
+
+/*!
+ * brief eDMA aborts transfer.
+ *
+ * This function disables the channel request and clear transfer status bits.
+ * Users can submit another transfer after calling this API.
+ *
+ * param handle DMA handle pointer.
+ */
+void EDMA_AbortTransfer(edma_handle_t *handle)
+{
+ handle->base->CERQ = DMA_CERQ_CERQ(handle->channel);
+ /*
+ Clear CSR to release channel. Because if the given channel started transfer,
+ CSR will be not zero. Because if it is the last transfer, DREQ will be set.
+ If not, ESG will be set.
+ */
+ handle->base->TCD[handle->channel].CSR = 0;
+ /* Cancel all next TCD transfer. */
+ handle->base->TCD[handle->channel].DLAST_SGA = 0;
+
+ /* Handle the tcd */
+ if (handle->tcdPool != NULL)
+ {
+ handle->header = 0;
+ handle->tail = 0;
+ handle->tcdUsed = 0;
+ }
+}
+
+/*!
+ * brief eDMA IRQ handler for the current major loop transfer completion.
+ *
+ * This function clears the channel major interrupt flag and calls
+ * the callback function if it is not NULL.
+ *
+ * Note:
+ * For the case using TCD queue, when the major iteration count is exhausted, additional operations are performed.
+ * These include the final address adjustments and reloading of the BITER field into the CITER.
+ * Assertion of an optional interrupt request also occurs at this time, as does a possible fetch of a new TCD from
+ * memory using the scatter/gather address pointer included in the descriptor (if scatter/gather is enabled).
+ *
+ * For instance, when the time interrupt of TCD[0] happens, the TCD[1] has already been loaded into the eDMA engine.
+ * As sga and sga_index are calculated based on the DLAST_SGA bitfield lies in the TCD_CSR register, the sga_index
+ * in this case should be 2 (DLAST_SGA of TCD[1] stores the address of TCD[2]). Thus, the "tcdUsed" updated should be
+ * (tcdUsed - 2U) which indicates the number of TCDs can be loaded in the memory pool (because TCD[0] and TCD[1] have
+ * been loaded into the eDMA engine at this point already.).
+ *
+ * For the last two continuous ISRs in a scatter/gather process, they both load the last TCD (The last ISR does not
+ * load a new TCD) from the memory pool to the eDMA engine when major loop completes.
+ * Therefore, ensure that the header and tcdUsed updated are identical for them.
+ * tcdUsed are both 0 in this case as no TCD to be loaded.
+ *
+ * See the "eDMA basic data flow" in the eDMA Functional description section of the Reference Manual for
+ * further details.
+ *
+ * param handle eDMA handle pointer.
+ */
+void EDMA_HandleIRQ(edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ bool transfer_done;
+
+ /* Clear EDMA interrupt flag */
+ handle->base->CINT = handle->channel;
+ /* Check if transfer is already finished. */
+ transfer_done = ((handle->base->TCD[handle->channel].CSR & DMA_CSR_DONE_MASK) != 0U);
+
+ if (handle->tcdPool == NULL)
+ {
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(handle, handle->userData, transfer_done, 0);
+ }
+ }
+ else /* Use the TCD queue. Please refer to the API descriptions in the eDMA header file for detailed information. */
+ {
+ uint32_t sga = handle->base->TCD[handle->channel].DLAST_SGA;
+ uint32_t sga_index;
+ int32_t tcds_done;
+ uint8_t new_header;
+
+ /* Get the offset of the next transfer TCD blocks to be loaded into the eDMA engine. */
+ sga -= (uint32_t)handle->tcdPool;
+ /* Get the index of the next transfer TCD blocks to be loaded into the eDMA engine. */
+ sga_index = sga / sizeof(edma_tcd_t);
+ /* Adjust header positions. */
+ if (transfer_done)
+ {
+ /* New header shall point to the next TCD to be loaded (current one is already finished) */
+ new_header = (uint8_t)sga_index;
+ }
+ else
+ {
+ /* New header shall point to this descriptor currently loaded (not finished yet) */
+ new_header = sga_index != 0U ? (uint8_t)sga_index - 1U : (uint8_t)handle->tcdSize - 1U;
+ }
+ /* Calculate the number of finished TCDs */
+ if (new_header == (uint8_t)handle->header)
+ {
+ int8_t tmpTcdUsed = handle->tcdUsed;
+ int8_t tmpTcdSize = handle->tcdSize;
+
+ if (tmpTcdUsed == tmpTcdSize)
+ {
+ tcds_done = handle->tcdUsed;
+ }
+ else
+ {
+ /* No TCD in the memory are going to be loaded or internal error occurs. */
+ tcds_done = 0;
+ }
+ }
+ else
+ {
+ tcds_done = (int32_t)new_header - (int32_t)handle->header;
+ if (tcds_done < 0)
+ {
+ tcds_done += handle->tcdSize;
+ }
+ }
+ /* Advance header which points to the TCD to be loaded into the eDMA engine from memory. */
+ handle->header = (int8_t)new_header;
+ /* Release TCD blocks. tcdUsed is the TCD number which can be used/loaded in the memory pool. */
+ handle->tcdUsed -= (int8_t)tcds_done;
+ /* Invoke callback function. */
+ if (NULL != handle->callback)
+ {
+ (handle->callback)(handle, handle->userData, transfer_done, tcds_done);
+ }
+
+ /* clear the DONE bit here is meaningful for below cases:
+ *1.A new TCD has been loaded to EDMA already:
+ * need to clear the DONE bit in the IRQ handler to avoid TCD in EDMA been overwritten
+ * if peripheral request isn't coming before next transfer request.
+ *2.A new TCD has not been loaded to EDMA:
+ * for the case that transfer request occur in the privious edma callback, this is a case that doesn't
+ * need scatter gather, so keep DONE bit during the next transfer request will re-install the TCD.
+ */
+ if (transfer_done)
+ {
+ handle->base->CDNE = handle->channel;
+ }
+ }
+}
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 4)
+/* 8 channels (Shared): kl28 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL == 8U)
+
+#if defined(DMA0)
+void DMA0_04_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_37_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA1)
+
+#if defined(DMA0)
+void DMA1_04_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_37_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#else
+void DMA1_04_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_37_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#endif /* 8 channels (Shared) */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 8)
+/* 16 channels (Shared): K32H844P */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL == 16U)
+
+void DMA0_08_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_210_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_311_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_412_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_513_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_614_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_715_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#if defined(DMA1)
+void DMA1_08_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_210_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_311_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_412_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_513_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_614_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_715_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif /* 16 channels (Shared) */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 16)
+/* 32 channels (Shared): k80 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && FSL_FEATURE_EDMA_MODULE_CHANNEL == 32U
+#if defined(DMA0) && !(defined(DMA1))
+void DMA0_DMA16_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 16U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_DMA17_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 17U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA2_DMA18_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 18U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA3_DMA19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 19U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA4_DMA20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 20U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA5_DMA21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 21U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA6_DMA22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 22U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA7_DMA23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 23U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA8_DMA24_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 24U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA9_DMA25_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 25U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA10_DMA26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 26U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA11_DMA27_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 27U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA12_DMA28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 28U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA13_DMA29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 29U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA14_DMA30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 30U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA15_DMA31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 31U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#else
+void DMA0_0_16_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 16U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_1_17_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 17U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_2_18_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 18U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_3_19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 19U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_4_20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 20U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_5_21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 21U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_6_22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 22U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_7_23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 23U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_8_24_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 24U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_9_25_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 25U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_10_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 26U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_11_27_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 27U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_12_28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 28U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_13_29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 29U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_14_30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 30U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_15_31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 31U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_0_16_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[32]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 16U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[48]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_1_17_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[33]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 17U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[49]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_2_18_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[34]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 18U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[50]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_3_19_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[35]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 19U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[51]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_4_20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[36]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 20U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[52]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_5_21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[37]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 21U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[53]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_6_22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[38]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 22U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[54]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_7_23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[39]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 23U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[55]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_8_24_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[40]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 24U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[56]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_9_25_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[41]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 25U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[57]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_10_26_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[42]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 26U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[58]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_11_27_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[43]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 27U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[59]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_12_28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[44]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 28U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[60]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_13_29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[45]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 29U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[61]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_14_30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[46]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 30U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[62]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_15_31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA1, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[47]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA1, 31U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[63]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#endif
+#endif /* 32 channels (Shared) */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 4)
+/* 32 channels (Shared): MCIMX7U5_M4 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL == 32U)
+
+void DMA0_0_4_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 0U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 4U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_1_5_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 1U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 5U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_2_6_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 2U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 6U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_3_7_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 3U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 7U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_8_12_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 8U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 12U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_9_13_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 9U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 13U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_10_14_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 10U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 14U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_11_15_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 11U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 15U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_16_20_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 16U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 20U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_17_21_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 17U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 21U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_18_22_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 18U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 22U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_19_23_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 19U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 23U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_24_28_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 24U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 28U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_25_29_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 25U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 29U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_26_30_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 26U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 30U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA0_27_31_DriverIRQHandler(void)
+{
+ if ((EDMA_GetChannelStatusFlags(DMA0, 27U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ }
+ if ((EDMA_GetChannelStatusFlags(DMA0, 31U) & (uint32_t)kEDMA_InterruptFlag) != 0U)
+ {
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* 32 channels (Shared): MCIMX7U5 */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
+
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET) && \
+ (FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET == 0)
+/* 4 channels (No Shared): kv10 */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL > 0)
+
+void DMA0_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA1_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA2_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA3_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+/* 8 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL > 4U)
+
+void DMA4_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA5_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[5]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA6_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[6]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA7_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[7]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 8 */
+
+/* 16 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL > 8U)
+
+void DMA8_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[8]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA9_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[9]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA10_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[10]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA11_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[11]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA12_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[12]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA13_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[13]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA14_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[14]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA15_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[15]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 16 */
+
+/* 32 channels (No Shared) */
+#if defined(FSL_FEATURE_EDMA_MODULE_CHANNEL) && (FSL_FEATURE_EDMA_MODULE_CHANNEL > 16U)
+
+void DMA16_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[16]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA17_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[17]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA18_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[18]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA19_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[19]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA20_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[20]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA21_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[21]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA22_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[22]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA23_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[23]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA24_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[24]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA25_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[25]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA26_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[26]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA27_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[27]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA28_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[28]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA29_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[29]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA30_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[30]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void DMA31_DriverIRQHandler(void)
+{
+ EDMA_HandleIRQ(s_EDMAHandle[31]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL == 32 */
+
+#endif /* 4/8/16/32 channels (No Shared) */
+#endif /* FSL_FEATURE_EDMA_MODULE_CHANNEL_IRQ_ENTRY_SHARED_OFFSET */
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_elcdif.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_elcdif.c
new file mode 100644
index 0000000000..ab9f63f912
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_elcdif.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_elcdif.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.elcdif"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get instance number for ELCDIF module.
+ *
+ * @param base ELCDIF peripheral base address
+ */
+static uint32_t ELCDIF_GetInstance(LCDIF_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to ELCDIF bases for each instance. */
+static LCDIF_Type *const s_elcdifBases[] = LCDIF_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to eLCDIF apb_clk for each instance. */
+static const clock_ip_name_t s_elcdifApbClocks[] = LCDIF_CLOCKS;
+#if defined(LCDIF_PERIPH_CLOCKS)
+/*! @brief Pointers to eLCDIF pix_clk for each instance. */
+static const clock_ip_name_t s_elcdifPixClocks[] = LCDIF_PERIPH_CLOCKS;
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief The control register value to select different pixel format. */
+static const elcdif_pixel_format_reg_t s_pixelFormatReg[] = {
+ /* kELCDIF_PixelFormatRAW8 */
+ {/* Register CTRL. */
+ LCDIF_CTRL_WORD_LENGTH(1U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
+ /* kELCDIF_PixelFormatRGB565 */
+ {/* Register CTRL. */
+ LCDIF_CTRL_WORD_LENGTH(0U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
+ /* kELCDIF_PixelFormatRGB666 */
+ {/* Register CTRL. */
+ LCDIF_CTRL_WORD_LENGTH(3U) | LCDIF_CTRL_DATA_FORMAT_24_BIT(1U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)},
+ /* kELCDIF_PixelFormatXRGB8888 */
+ {/* Register CTRL. 24-bit. */
+ LCDIF_CTRL_WORD_LENGTH(3U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x07U)},
+ /* kELCDIF_PixelFormatRGB888 */
+ {/* Register CTRL. 24-bit. */
+ LCDIF_CTRL_WORD_LENGTH(3U),
+ /* Register CTRL1. */
+ LCDIF_CTRL1_BYTE_PACKING_FORMAT(0x0FU)},
+};
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+static uint32_t ELCDIF_GetInstance(LCDIF_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_elcdifBases); instance++)
+ {
+ if (s_elcdifBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_elcdifBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the eLCDIF to work in RGB mode (DOTCLK mode).
+ *
+ * This function ungates the eLCDIF clock and configures the eLCDIF peripheral according
+ * to the configuration structure.
+ *
+ * param base eLCDIF peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void ELCDIF_RgbModeInit(LCDIF_Type *base, const elcdif_rgb_mode_config_t *config)
+{
+ assert(NULL != config);
+ assert((uint32_t)config->pixelFormat < ARRAY_SIZE(s_pixelFormatReg));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = ELCDIF_GetInstance(base);
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_elcdifApbClocks[instance]);
+#if defined(LCDIF_PERIPH_CLOCKS)
+ CLOCK_EnableClock(s_elcdifPixClocks[instance]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset. */
+ ELCDIF_Reset(base);
+
+ base->CTRL = s_pixelFormatReg[(uint32_t)config->pixelFormat].regCtrl | (uint32_t)(config->dataBus) |
+ LCDIF_CTRL_DOTCLK_MODE_MASK | /* RGB mode. */
+ LCDIF_CTRL_BYPASS_COUNT_MASK | /* Keep RUN bit set. */
+ LCDIF_CTRL_MASTER_MASK;
+
+ base->CTRL1 = s_pixelFormatReg[(uint32_t)config->pixelFormat].regCtrl1;
+
+ base->TRANSFER_COUNT = ((uint32_t)config->panelHeight << LCDIF_TRANSFER_COUNT_V_COUNT_SHIFT) |
+ ((uint32_t)config->panelWidth << LCDIF_TRANSFER_COUNT_H_COUNT_SHIFT);
+
+ base->VDCTRL0 = LCDIF_VDCTRL0_ENABLE_PRESENT_MASK | /* Data enable signal. */
+ LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT_MASK | /* VSYNC period in the unit of display clock. */
+ LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT_MASK | /* VSYNC pulse width in the unit of display clock. */
+ (uint32_t)config->polarityFlags | (uint32_t)config->vsw;
+
+ base->VDCTRL1 =
+ (uint32_t)config->vsw + (uint32_t)config->panelHeight + (uint32_t)config->vfp + (uint32_t)config->vbp;
+ base->VDCTRL2 =
+ ((uint32_t)config->hsw << LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_SHIFT) |
+ (((uint32_t)config->hfp + (uint32_t)config->hbp + (uint32_t)config->panelWidth + (uint32_t)config->hsw))
+ << LCDIF_VDCTRL2_HSYNC_PERIOD_SHIFT;
+
+ base->VDCTRL3 = (((uint32_t)config->hbp + config->hsw) << LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_SHIFT) |
+ (((uint32_t)config->vbp + config->vsw) << LCDIF_VDCTRL3_VERTICAL_WAIT_CNT_SHIFT);
+
+ base->VDCTRL4 = LCDIF_VDCTRL4_SYNC_SIGNALS_ON_MASK |
+ ((uint32_t)config->panelWidth << LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT_SHIFT);
+
+ base->CUR_BUF = config->bufferAddr;
+ base->NEXT_BUF = config->bufferAddr;
+}
+
+/*!
+ * brief Gets the eLCDIF default configuration structure for RGB (DOTCLK) mode.
+ *
+ * This function sets the configuration structure to default values.
+ * The default configuration is set to the following values.
+ * code
+ config->panelWidth = 480U;
+ config->panelHeight = 272U;
+ config->hsw = 41;
+ config->hfp = 4;
+ config->hbp = 8;
+ config->vsw = 10;
+ config->vfp = 4;
+ config->vbp = 2;
+ config->polarityFlags = kELCDIF_VsyncActiveLow |
+ kELCDIF_HsyncActiveLow |
+ kELCDIF_DataEnableActiveLow |
+ kELCDIF_DriveDataOnFallingClkEdge;
+ config->bufferAddr = 0U;
+ config->pixelFormat = kELCDIF_PixelFormatRGB888;
+ config->dataBus = kELCDIF_DataBus24Bit;
+ code
+ *
+ * param config Pointer to the eLCDIF configuration structure.
+ */
+void ELCDIF_RgbModeGetDefaultConfig(elcdif_rgb_mode_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->panelWidth = 480U;
+ config->panelHeight = 272U;
+ config->hsw = 41;
+ config->hfp = 4;
+ config->hbp = 8;
+ config->vsw = 10;
+ config->vfp = 4;
+ config->vbp = 2;
+ config->polarityFlags = (uint32_t)kELCDIF_VsyncActiveLow | (uint32_t)kELCDIF_HsyncActiveLow |
+ (uint32_t)kELCDIF_DataEnableActiveLow | (uint32_t)kELCDIF_DriveDataOnFallingClkEdge;
+ config->bufferAddr = 0U;
+ config->pixelFormat = kELCDIF_PixelFormatRGB888;
+ config->dataBus = kELCDIF_DataBus24Bit;
+}
+
+/*!
+ * brief Set the pixel format in RGB (DOTCLK) mode.
+ *
+ * param base eLCDIF peripheral base address.
+ * param pixelFormat The pixel format.
+ */
+void ELCDIF_RgbModeSetPixelFormat(LCDIF_Type *base, elcdif_pixel_format_t pixelFormat)
+{
+ assert((uint32_t)pixelFormat < ARRAY_SIZE(s_pixelFormatReg));
+
+ base->CTRL = (base->CTRL & ~(LCDIF_CTRL_WORD_LENGTH_MASK | LCDIF_CTRL_DATA_FORMAT_24_BIT_MASK |
+ LCDIF_CTRL_DATA_FORMAT_18_BIT_MASK | LCDIF_CTRL_DATA_FORMAT_16_BIT_MASK)) |
+ s_pixelFormatReg[(uint32_t)pixelFormat].regCtrl;
+
+ base->CTRL1 = s_pixelFormatReg[(uint32_t)pixelFormat].regCtrl1;
+}
+
+/*!
+ * brief Deinitializes the eLCDIF peripheral.
+ *
+ * param base eLCDIF peripheral base address.
+ */
+void ELCDIF_Deinit(LCDIF_Type *base)
+{
+ ELCDIF_Reset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = ELCDIF_GetInstance(base);
+/* Disable the clock. */
+#if defined(LCDIF_PERIPH_CLOCKS)
+ CLOCK_DisableClock(s_elcdifPixClocks[instance]);
+#endif
+ CLOCK_DisableClock(s_elcdifApbClocks[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Stop display in RGB (DOTCLK) mode and wait until finished.
+ *
+ * param base eLCDIF peripheral base address.
+ */
+void ELCDIF_RgbModeStop(LCDIF_Type *base)
+{
+ base->CTRL_CLR = LCDIF_CTRL_DOTCLK_MODE_MASK;
+
+ /* Wait for data transfer finished. */
+ while (0U != (base->CTRL & LCDIF_CTRL_DOTCLK_MODE_MASK))
+ {
+ }
+}
+
+/*!
+ * brief Reset the eLCDIF peripheral.
+ *
+ * param base eLCDIF peripheral base address.
+ */
+void ELCDIF_Reset(LCDIF_Type *base)
+{
+ /*
+ * ELCDIF reset workflow:
+ *
+ * 1. Ungate clock.
+ * 2. Trigger the software reset.
+ * 3. The software reset finished when clk_gate bit is set.
+ * 4. Ungate the clock.
+ * 5. Release the reset.
+ */
+
+ /* Ungate clock. */
+ base->CTRL_CLR = LCDIF_CTRL_CLKGATE_MASK;
+
+ /*
+ * If already in reset state, release the reset.
+ * If not, trigger reset.
+ */
+ if (0U == (base->CTRL & LCDIF_CTRL_SFTRST_MASK))
+ {
+ /* Trigger reset. */
+ base->CTRL_SET = LCDIF_CTRL_SFTRST_MASK;
+
+ /* Reset is not finished until CLK_GATE is set. */
+ while (0U == (base->CTRL & LCDIF_CTRL_CLKGATE_MASK))
+ {
+ }
+
+ /* Ungate the clock. */
+ base->CTRL_CLR = LCDIF_CTRL_CLKGATE_MASK;
+ }
+
+ /* Release the reset. */
+ base->CTRL_CLR = LCDIF_CTRL_SFTRST_MASK;
+}
+
+#if !(defined(FSL_FEATURE_LCDIF_HAS_NO_AS) && FSL_FEATURE_LCDIF_HAS_NO_AS)
+/*!
+ * brief Set the configuration for alpha surface buffer.
+ *
+ * param base eLCDIF peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void ELCDIF_SetAlphaSurfaceBufferConfig(LCDIF_Type *base, const elcdif_as_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ base->AS_CTRL = (base->AS_CTRL & ~LCDIF_AS_CTRL_FORMAT_MASK) | LCDIF_AS_CTRL_FORMAT(config->pixelFormat);
+ base->AS_BUF = config->bufferAddr;
+ base->AS_NEXT_BUF = config->bufferAddr;
+}
+
+/*!
+ * brief Set the alpha surface blending configuration.
+ *
+ * param base eLCDIF peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void ELCDIF_SetAlphaSurfaceBlendConfig(LCDIF_Type *base, const elcdif_as_blend_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t reg;
+
+ reg = base->AS_CTRL;
+ reg &= ~(LCDIF_AS_CTRL_ALPHA_INVERT_MASK | LCDIF_AS_CTRL_ROP_MASK | LCDIF_AS_CTRL_ALPHA_MASK |
+ LCDIF_AS_CTRL_ALPHA_CTRL_MASK);
+ reg |= (LCDIF_AS_CTRL_ROP(config->ropMode) | LCDIF_AS_CTRL_ALPHA(config->alpha) |
+ LCDIF_AS_CTRL_ALPHA_CTRL(config->alphaMode));
+
+ if (config->invertAlpha)
+ {
+ reg |= LCDIF_AS_CTRL_ALPHA_INVERT_MASK;
+ }
+
+ base->AS_CTRL = reg;
+}
+#endif /* FSL_FEATURE_LCDIF_HAS_NO_AS */
+
+#if (defined(FSL_FEATURE_LCDIF_HAS_LUT) && FSL_FEATURE_LCDIF_HAS_LUT)
+/*!
+ * brief Load the LUT value.
+ *
+ * This function loads the LUT value to the specific LUT memory, user can
+ * specify the start entry index.
+ *
+ * param base eLCDIF peripheral base address.
+ * param lut Which LUT to load.
+ * param startIndex The start index of the LUT entry to update.
+ * param lutData The LUT data to load.
+ * param count Count of p lutData.
+ * retval kStatus_Success Initialization success.
+ * retval kStatus_InvalidArgument Wrong argument.
+ */
+status_t ELCDIF_UpdateLut(
+ LCDIF_Type *base, elcdif_lut_t lut, uint16_t startIndex, const uint32_t *lutData, uint16_t count)
+{
+ volatile uint32_t *regLutAddr;
+ volatile uint32_t *regLutData;
+ uint32_t i;
+ status_t status;
+
+ /* Only has 256 entries. */
+ if (startIndex + count > ELCDIF_LUT_ENTRY_NUM)
+ {
+ status = kStatus_InvalidArgument;
+ }
+ else
+ {
+ if (kELCDIF_Lut0 == lut)
+ {
+ regLutAddr = &(base->LUT0_ADDR);
+ regLutData = &(base->LUT0_DATA);
+ }
+ else
+ {
+ regLutAddr = &(base->LUT1_ADDR);
+ regLutData = &(base->LUT1_DATA);
+ }
+
+ *regLutAddr = startIndex;
+
+ for (i = 0; i < count; i++)
+ {
+ *regLutData = lutData[i];
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+#endif /* FSL_FEATURE_LCDIF_HAS_LUT */
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enc.c
new file mode 100644
index 0000000000..8117df1332
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enc.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_enc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.enc"
+#endif
+
+#define ENC_CTRL_W1C_FLAGS (ENC_CTRL_HIRQ_MASK | ENC_CTRL_XIRQ_MASK | ENC_CTRL_DIRQ_MASK | ENC_CTRL_CMPIRQ_MASK)
+#define ENC_CTRL2_W1C_FLAGS (ENC_CTRL2_SABIRQ_MASK | ENC_CTRL2_ROIRQ_MASK | ENC_CTRL2_RUIRQ_MASK)
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for ENC module.
+ *
+ * @param base ENC peripheral base address
+ */
+static uint32_t ENC_GetInstance(ENC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to ENC bases for each instance. */
+static ENC_Type *const s_encBases[] = ENC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to ENC clocks for each instance. */
+static const clock_ip_name_t s_encClocks[] = ENC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t ENC_GetInstance(ENC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_encBases); instance++)
+ {
+ if (s_encBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_encBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initialization for the ENC module.
+ *
+ * This function is to make the initialization for the ENC module. It should be called firstly before any operation to
+ * the ENC with the operations like:
+ * - Enable the clock for ENC module.
+ * - Configure the ENC's working attributes.
+ *
+ * param base ENC peripheral base address.
+ * param config Pointer to configuration structure. See to "enc_config_t".
+ */
+void ENC_Init(ENC_Type *base, const enc_config_t *config)
+{
+ assert(NULL != config);
+
+ uint16_t tmp16;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock. */
+ CLOCK_EnableClock(s_encClocks[ENC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* ENC_CTRL. */
+ tmp16 = base->CTRL & (uint16_t)(~(ENC_CTRL_W1C_FLAGS | ENC_CTRL_HIP_MASK | ENC_CTRL_HNE_MASK | ENC_CTRL_REV_MASK |
+ ENC_CTRL_PH1_MASK | ENC_CTRL_XIP_MASK | ENC_CTRL_XNE_MASK | ENC_CTRL_WDE_MASK));
+ /* For HOME trigger. */
+ if (kENC_HOMETriggerDisabled != config->HOMETriggerMode)
+ {
+ tmp16 |= ENC_CTRL_HIP_MASK;
+ if (kENC_HOMETriggerOnFallingEdge == config->HOMETriggerMode)
+ {
+ tmp16 |= ENC_CTRL_HNE_MASK;
+ }
+ }
+ /* For encoder work mode. */
+ if (config->enableReverseDirection)
+ {
+ tmp16 |= ENC_CTRL_REV_MASK;
+ }
+ if (kENC_DecoderWorkAsSignalPhaseCountMode == config->decoderWorkMode)
+ {
+ tmp16 |= ENC_CTRL_PH1_MASK;
+ }
+ /* For INDEX trigger. */
+ if (kENC_INDEXTriggerDisabled != config->INDEXTriggerMode)
+ {
+ tmp16 |= ENC_CTRL_XIP_MASK;
+ if (kENC_INDEXTriggerOnFallingEdge == config->INDEXTriggerMode)
+ {
+ tmp16 |= ENC_CTRL_XNE_MASK;
+ }
+ }
+ /* Watchdog. */
+ if (config->enableWatchdog)
+ {
+ tmp16 |= ENC_CTRL_WDE_MASK;
+ base->WTR = config->watchdogTimeoutValue; /* WDOG can be only available when the feature is enabled. */
+ }
+ base->CTRL = tmp16;
+
+ /* ENC_FILT. */
+ base->FILT = ENC_FILT_FILT_CNT(config->filterCount) | ENC_FILT_FILT_PER(config->filterSamplePeriod);
+
+ /* ENC_CTRL2. */
+ tmp16 = base->CTRL2 & (uint16_t)(~(ENC_CTRL2_W1C_FLAGS | ENC_CTRL2_OUTCTL_MASK | ENC_CTRL2_REVMOD_MASK |
+ ENC_CTRL2_MOD_MASK | ENC_CTRL2_UPDPOS_MASK | ENC_CTRL2_UPDHLD_MASK));
+ if (kENC_POSMATCHOnReadingAnyPositionCounter == config->positionMatchMode)
+ {
+ tmp16 |= ENC_CTRL2_OUTCTL_MASK;
+ }
+ if (kENC_RevolutionCountOnRollOverModulus == config->revolutionCountCondition)
+ {
+ tmp16 |= ENC_CTRL2_REVMOD_MASK;
+ }
+ if (config->enableModuloCountMode)
+ {
+ tmp16 |= ENC_CTRL2_MOD_MASK;
+ /* Set modulus value. */
+ base->UMOD = (uint16_t)(config->positionModulusValue >> 16U); /* Upper 16 bits. */
+ base->LMOD = (uint16_t)(config->positionModulusValue); /* Lower 16 bits. */
+ }
+ if (config->enableTRIGGERClearPositionCounter)
+ {
+ tmp16 |= ENC_CTRL2_UPDPOS_MASK;
+ }
+ if (config->enableTRIGGERClearHoldPositionCounter)
+ {
+ tmp16 |= ENC_CTRL2_UPDHLD_MASK;
+ }
+ base->CTRL2 = tmp16;
+
+ /* ENC_UCOMP & ENC_LCOMP. */
+ base->UCOMP = (uint16_t)(config->positionCompareValue >> 16U); /* Upper 16 bits. */
+ base->LCOMP = (uint16_t)(config->positionCompareValue); /* Lower 16 bits. */
+
+ /* ENC_UINIT & ENC_LINIT. */
+ base->UINIT = (uint16_t)(config->positionInitialValue >> 16U); /* Upper 16 bits. */
+ base->LINIT = (uint16_t)(config->positionInitialValue); /* Lower 16 bits. */
+}
+
+/*!
+ * brief De-initialization for the ENC module.
+ *
+ * This function is to make the de-initialization for the ENC module. It could be called when ENC is no longer used with
+ * the operations like:
+ * - Disable the clock for ENC module.
+ *
+ * param base ENC peripheral base address.
+ */
+void ENC_Deinit(ENC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the clock. */
+ CLOCK_DisableClock(s_encClocks[ENC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Get an available pre-defined settings for ENC's configuration.
+ *
+ * This function initializes the ENC configuration structure with an available settings, the default value are:
+ * code
+ * config->enableReverseDirection = false;
+ * config->decoderWorkMode = kENC_DecoderWorkAsNormalMode;
+ * config->HOMETriggerMode = kENC_HOMETriggerDisabled;
+ * config->INDEXTriggerMode = kENC_INDEXTriggerDisabled;
+ * config->enableTRIGGERClearPositionCounter = false;
+ * config->enableTRIGGERClearHoldPositionCounter = false;
+ * config->enableWatchdog = false;
+ * config->watchdogTimeoutValue = 0U;
+ * config->filterCount = 0U;
+ * config->filterSamplePeriod = 0U;
+ * config->positionMatchMode = kENC_POSMATCHOnPositionCounterEqualToComapreValue;
+ * config->positionCompareValue = 0xFFFFFFFFU;
+ * config->revolutionCountCondition = kENC_RevolutionCountOnINDEXPulse;
+ * config->enableModuloCountMode = false;
+ * config->positionModulusValue = 0U;
+ * config->positionInitialValue = 0U;
+ * endcode
+ * param config Pointer to a variable of configuration structure. See to "enc_config_t".
+ */
+void ENC_GetDefaultConfig(enc_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableReverseDirection = false;
+ config->decoderWorkMode = kENC_DecoderWorkAsNormalMode;
+ config->HOMETriggerMode = kENC_HOMETriggerDisabled;
+ config->INDEXTriggerMode = kENC_INDEXTriggerDisabled;
+ config->enableTRIGGERClearPositionCounter = false;
+ config->enableTRIGGERClearHoldPositionCounter = false;
+ config->enableWatchdog = false;
+ config->watchdogTimeoutValue = 0U;
+ config->filterCount = 0U;
+ config->filterSamplePeriod = 0U;
+ config->positionMatchMode = kENC_POSMATCHOnPositionCounterEqualToComapreValue;
+ config->positionCompareValue = 0xFFFFFFFFU;
+ config->revolutionCountCondition = kENC_RevolutionCountOnINDEXPulse;
+ config->enableModuloCountMode = false;
+ config->positionModulusValue = 0U;
+ config->positionInitialValue = 0U;
+}
+
+/*!
+ * brief Load the initial position value to position counter.
+ *
+ * This function is to transfer the initial position value (UINIT and LINIT) contents to position counter (UPOS and
+ * LPOS), so that to provide the consistent operation the position counter registers.
+ *
+ * param base ENC peripheral base address.
+ */
+void ENC_DoSoftwareLoadInitialPositionValue(ENC_Type *base)
+{
+ uint16_t tmp16 = base->CTRL & (uint16_t)(~ENC_CTRL_W1C_FLAGS);
+
+ tmp16 |= ENC_CTRL_SWIP_MASK; /* Write 1 to trigger the command for loading initial position value. */
+ base->CTRL = tmp16;
+}
+
+/*!
+ * brief Enable and configure the self test function.
+ *
+ * This function is to enable and configuration the self test function. It controls and sets the frequency of a
+ * quadrature signal generator. It provides a quadrature test signal to the inputs of the quadrature decoder module.
+ * It is a factory test feature; however, it may be useful to customers' software development and testing.
+ *
+ * param base ENC peripheral base address.
+ * param config Pointer to configuration structure. See to "enc_self_test_config_t". Pass "NULL" to disable.
+ */
+void ENC_SetSelfTestConfig(ENC_Type *base, const enc_self_test_config_t *config)
+{
+ uint16_t tmp16 = 0U;
+
+ if (NULL == config) /* Pass "NULL" to disable the feature. */
+ {
+ tmp16 = 0U;
+ }
+ else
+ {
+ tmp16 = ENC_TST_TEN_MASK | ENC_TST_TCE_MASK | ENC_TST_TEST_PERIOD(config->signalPeriod) |
+ ENC_TST_TEST_COUNT(config->signalCount);
+ if (kENC_SelfTestDirectionNegative == config->signalDirection)
+ {
+ tmp16 |= ENC_TST_QDN_MASK;
+ }
+ }
+
+ base->TST = tmp16;
+}
+
+/*!
+ * brief Enable watchdog for ENC module.
+ *
+ * param base ENC peripheral base address
+ * param enable Enables or disables the watchdog
+ */
+void ENC_EnableWatchdog(ENC_Type *base, bool enable)
+{
+ uint16_t tmp16 = base->CTRL & (uint16_t)(~(ENC_CTRL_W1C_FLAGS | ENC_CTRL_WDE_MASK));
+
+ if (enable)
+ {
+ tmp16 |= ENC_CTRL_WDE_MASK;
+ }
+ base->CTRL = tmp16;
+}
+
+/*!
+ * brief Get the status flags.
+ *
+ * param base ENC peripheral base address.
+ *
+ * return Mask value of status flags. For available mask, see to "_enc_status_flags".
+ */
+uint32_t ENC_GetStatusFlags(ENC_Type *base)
+{
+ uint32_t ret32 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != (ENC_CTRL_HIRQ_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_HOMETransitionFlag;
+ }
+ if (0U != (ENC_CTRL_XIRQ_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_INDEXPulseFlag;
+ }
+ if (0U != (ENC_CTRL_DIRQ_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_WatchdogTimeoutFlag;
+ }
+ if (0U != (ENC_CTRL_CMPIRQ_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_PositionCompareFlag;
+ }
+
+ /* ENC_CTRL2. */
+ if (0U != (ENC_CTRL2_SABIRQ_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_SimultBothPhaseChangeFlag;
+ }
+ if (0U != (ENC_CTRL2_ROIRQ_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_PositionRollOverFlag;
+ }
+ if (0U != (ENC_CTRL2_RUIRQ_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_PositionRollUnderFlag;
+ }
+ if (0U != (ENC_CTRL2_DIR_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_LastCountDirectionFlag;
+ }
+
+ return ret32;
+}
+
+/*!
+ * brief Clear the status flags.
+ *
+ * param base ENC peripheral base address.
+ * param mask Mask value of status flags to be cleared. For available mask, see to "_enc_status_flags".
+ */
+void ENC_ClearStatusFlags(ENC_Type *base, uint32_t mask)
+{
+ uint32_t tmp16 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != ((uint32_t)kENC_HOMETransitionFlag & mask))
+ {
+ tmp16 |= ENC_CTRL_HIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_INDEXPulseFlag & mask))
+ {
+ tmp16 |= ENC_CTRL_XIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_WatchdogTimeoutFlag & mask))
+ {
+ tmp16 |= ENC_CTRL_DIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionCompareFlag & mask))
+ {
+ tmp16 |= ENC_CTRL_CMPIRQ_MASK;
+ }
+ if (0U != tmp16)
+ {
+ base->CTRL = (uint16_t)(((uint32_t)base->CTRL & (~ENC_CTRL_W1C_FLAGS)) | tmp16);
+ }
+
+ /* ENC_CTRL2. */
+ tmp16 = 0U;
+ if (0U != ((uint32_t)kENC_SimultBothPhaseChangeFlag & mask))
+ {
+ tmp16 |= ENC_CTRL2_SABIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollOverFlag & mask))
+ {
+ tmp16 |= ENC_CTRL2_ROIRQ_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollUnderFlag & mask))
+ {
+ tmp16 |= ENC_CTRL2_RUIRQ_MASK;
+ }
+ if (0U != tmp16)
+ {
+ base->CTRL2 = (uint16_t)(((uint32_t)base->CTRL2 & (~ENC_CTRL2_W1C_FLAGS)) | tmp16);
+ }
+}
+
+/*!
+ * brief Enable the interrupts.
+ *
+ * param base ENC peripheral base address.
+ * param mask Mask value of interrupts to be enabled. For available mask, see to "_enc_interrupt_enable".
+ */
+void ENC_EnableInterrupts(ENC_Type *base, uint32_t mask)
+{
+ uint32_t tmp16 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != ((uint32_t)kENC_HOMETransitionInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_HIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_INDEXPulseInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_XIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_WatchdogTimeoutInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_DIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionCompareInerruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_CMPIE_MASK;
+ }
+ if (tmp16 != 0U)
+ {
+ base->CTRL = (uint16_t)(((uint32_t)base->CTRL & (~ENC_CTRL_W1C_FLAGS)) | tmp16);
+ }
+ /* ENC_CTRL2. */
+ tmp16 = 0U;
+ if (0U != ((uint32_t)kENC_SimultBothPhaseChangeInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_SABIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollOverInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_ROIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollUnderInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_RUIE_MASK;
+ }
+ if (tmp16 != 0U)
+ {
+ base->CTRL2 = (uint16_t)(((uint32_t)base->CTRL2 & (~ENC_CTRL2_W1C_FLAGS)) | tmp16);
+ }
+}
+
+/*!
+ * brief Disable the interrupts.
+ *
+ * param base ENC peripheral base address.
+ * param mask Mask value of interrupts to be disabled. For available mask, see to "_enc_interrupt_enable".
+ */
+void ENC_DisableInterrupts(ENC_Type *base, uint32_t mask)
+{
+ uint16_t tmp16 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != ((uint32_t)kENC_HOMETransitionInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_HIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_INDEXPulseInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_XIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_WatchdogTimeoutInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_DIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionCompareInerruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL_CMPIE_MASK;
+ }
+ if (0U != tmp16)
+ {
+ base->CTRL = (uint16_t)(base->CTRL & (uint16_t)(~ENC_CTRL_W1C_FLAGS)) & (uint16_t)(~tmp16);
+ }
+ /* ENC_CTRL2. */
+ tmp16 = 0U;
+ if (0U != ((uint32_t)kENC_SimultBothPhaseChangeInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_SABIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollOverInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_ROIE_MASK;
+ }
+ if (0U != ((uint32_t)kENC_PositionRollUnderInterruptEnable & mask))
+ {
+ tmp16 |= ENC_CTRL2_RUIE_MASK;
+ }
+ if (tmp16 != 0U)
+ {
+ base->CTRL2 = (uint16_t)(base->CTRL2 & (uint16_t)(~ENC_CTRL2_W1C_FLAGS)) & (uint16_t)(~tmp16);
+ }
+}
+
+/*!
+ * brief Get the enabled interrupts' flags.
+ *
+ * param base ENC peripheral base address.
+ *
+ * return Mask value of enabled interrupts.
+ */
+uint32_t ENC_GetEnabledInterrupts(ENC_Type *base)
+{
+ uint32_t ret32 = 0U;
+
+ /* ENC_CTRL. */
+ if (0U != (ENC_CTRL_HIE_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_HOMETransitionInterruptEnable;
+ }
+ if (0U != (ENC_CTRL_XIE_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_INDEXPulseInterruptEnable;
+ }
+ if (0U != (ENC_CTRL_DIE_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_WatchdogTimeoutInterruptEnable;
+ }
+ if (0U != (ENC_CTRL_CMPIE_MASK & base->CTRL))
+ {
+ ret32 |= (uint32_t)kENC_PositionCompareInerruptEnable;
+ }
+ /* ENC_CTRL2. */
+ if (0U != (ENC_CTRL2_SABIE_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_SimultBothPhaseChangeInterruptEnable;
+ }
+ if (0U != (ENC_CTRL2_ROIE_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_PositionRollOverInterruptEnable;
+ }
+ if (0U != (ENC_CTRL2_RUIE_MASK & base->CTRL2))
+ {
+ ret32 |= (uint32_t)kENC_PositionRollUnderInterruptEnable;
+ }
+ return ret32;
+}
+
+/*!
+ * brief Set initial position value for ENC module.
+ *
+ * param base ENC peripheral base address
+ * param value Positive initial value
+ */
+void ENC_SetInitialPositionValue(ENC_Type *base, uint32_t value)
+{
+ base->UINIT = (uint16_t)(value >> 16U); /* Set upper 16 bits. */
+ base->LINIT = (uint16_t)(value); /* Set lower 16 bits. */
+}
+
+/*!
+ * brief Get the current position counter's value.
+ *
+ * param base ENC peripheral base address.
+ *
+ * return Current position counter's value.
+ */
+uint32_t ENC_GetPositionValue(ENC_Type *base)
+{
+ uint32_t ret32;
+
+ ret32 = base->UPOS; /* Get upper 16 bits and make a snapshot. */
+ ret32 <<= 16U;
+ ret32 |= base->LPOSH; /* Get lower 16 bits from hold register. */
+
+ return ret32;
+}
+
+/*!
+ * brief Get the hold position counter's value.
+ *
+ * When any of the counter registers is read, the contents of each counter register is written to the corresponding hold
+ * register. Taking a snapshot of the counters' values provides a consistent view of a system position and a velocity to
+ * be attained.
+ *
+ * param base ENC peripheral base address.
+ *
+ * return Hold position counter's value.
+ */
+uint32_t ENC_GetHoldPositionValue(ENC_Type *base)
+{
+ uint32_t ret32;
+
+ ret32 = base->UPOSH; /* Get upper 16 bits and make a snapshot. */
+ ret32 <<= 16U;
+ ret32 |= base->LPOSH; /* Get lower 16 bits from hold register. */
+
+ return ret32;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enet.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enet.c
new file mode 100644
index 0000000000..2e9d229a18
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_enet.c
@@ -0,0 +1,3389 @@
+/*
+ * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_enet.h"
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+#include "fsl_cache.h"
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.enet"
+#endif
+
+/*! @brief Ethernet mac address length. */
+#define ENET_FRAME_MACLEN 6U
+/*! @brief Ethernet VLAN header length. */
+#define ENET_FRAME_VLAN_TAGLEN 4U
+/*! @brief MDC frequency. */
+#define ENET_MDC_FREQUENCY 2500000U
+/*! @brief NanoSecond in one second. */
+#define ENET_NANOSECOND_ONE_SECOND 1000000000U
+/*! @brief Define a common clock cycle delays used for time stamp capture. */
+#ifndef ENET_1588TIME_DELAY_COUNT
+#define ENET_1588TIME_DELAY_COUNT 10U
+#endif
+
+/*! @brief Define the ENET ring/class bumber . */
+enum
+{
+ kENET_Ring0 = 0U, /*!< ENET ring/class 0. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+ kENET_Ring1 = 1U, /*!< ENET ring/class 1. */
+ kENET_Ring2 = 2U /*!< ENET ring/class 2. */
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Pointers to enet clocks for each instance. */
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+const clock_ip_name_t s_enetClock[] = ENET_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to enet transmit IRQ number for each instance. */
+static const IRQn_Type s_enetTxIrqId[] = ENET_Transmit_IRQS;
+/*! @brief Pointers to enet receive IRQ number for each instance. */
+static const IRQn_Type s_enetRxIrqId[] = ENET_Receive_IRQS;
+#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*! @brief Pointers to enet timestamp IRQ number for each instance. */
+static const IRQn_Type s_enetTsIrqId[] = ENET_1588_Timer_IRQS;
+#if (FSL_FEATURE_ENET_QUEUE > 1) && defined(ENET_1G)
+/*! @brief Pointers to enet 1588 timestamp IRQ number for each instance. */
+static const IRQn_Type s_enet1588TimerIrqId[] = ENET_1588_Timer_IRQS;
+#endif
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+/*! @brief Pointers to enet error IRQ number for each instance. */
+static const IRQn_Type s_enetErrIrqId[] = ENET_Error_IRQS;
+
+/*! @brief Pointers to enet bases for each instance. */
+static ENET_Type *const s_enetBases[] = ENET_BASE_PTRS;
+
+/*! @brief Pointers to enet handles for each instance. */
+static enet_handle_t *s_ENETHandle[ARRAY_SIZE(s_enetBases)];
+
+/* ENET ISR for transactional APIs. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+static enet_isr_ring_t s_enetTxIsr[ARRAY_SIZE(s_enetBases)];
+static enet_isr_ring_t s_enetRxIsr[ARRAY_SIZE(s_enetBases)];
+#else
+static enet_isr_t s_enetTxIsr[ARRAY_SIZE(s_enetBases)];
+static enet_isr_t s_enetRxIsr[ARRAY_SIZE(s_enetBases)];
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+static enet_isr_t s_enetErrIsr[ARRAY_SIZE(s_enetBases)];
+static enet_isr_t s_enetTsIsr[ARRAY_SIZE(s_enetBases)];
+#if (FSL_FEATURE_ENET_QUEUE > 1) && defined(ENET_1G)
+static enet_isr_t s_enet1588TimerIsr[ARRAY_SIZE(s_enetBases)];
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Set ENET MAC controller with the configuration.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handle pointer.
+ * @param config ENET Mac configuration.
+ * @param bufferConfig ENET buffer configuration.
+ * @param macAddr ENET six-byte mac address.
+ * @param srcClock_Hz ENET module clock source, normally it's system clock.
+ */
+static void ENET_SetMacController(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Set ENET handler.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handle pointer.
+ * @param config ENET configuration stucture pointer.
+ * @param bufferConfig ENET buffer configuration.
+ */
+static void ENET_SetHandler(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig);
+
+/*!
+ * @brief Set ENET MAC transmit buffer descriptors.
+ *
+ * @param handle The ENET handle pointer.
+ * @param config The ENET configuration structure.
+ * @param bufferConfig The ENET buffer configuration.
+ */
+static void ENET_SetTxBufferDescriptors(enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig);
+
+/*!
+ * @brief Set ENET MAC receive buffer descriptors.
+ *
+ * @param handle The ENET handle pointer.
+ * @param config The ENET configuration structure.
+ * @param bufferConfig The ENET buffer configuration.
+ */
+static void ENET_SetRxBufferDescriptors(enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig);
+
+/*!
+ * @brief Updates the ENET read buffer descriptors.
+ *
+ * @param base ENET peripheral base address.
+ * @param handle The ENET handle pointer.
+ * @param ringId The descriptor ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1.
+ */
+static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint8_t ringId);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * @brief Get the ENET instance from peripheral base address.
+ *
+ * @param base ENET peripheral base address.
+ * @return ENET instance.
+ */
+uint32_t ENET_GetInstance(ENET_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_enetBases); instance++)
+ {
+ if (s_enetBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_enetBases));
+
+ return instance;
+}
+
+/*!
+ * brief Gets the ENET default configuration structure.
+ *
+ * The purpose of this API is to get the default ENET MAC controller
+ * configure structure for ENET_Init(). User may use the initialized
+ * structure unchanged in ENET_Init(), or modify some fields of the
+ * structure before calling ENET_Init().
+ * Example:
+ code
+ enet_config_t config;
+ ENET_GetDefaultConfig(&config);
+ endcode
+ * param config The ENET mac controller configuration structure pointer.
+ */
+void ENET_GetDefaultConfig(enet_config_t *config)
+{
+ /* Checks input parameter. */
+ assert(config != NULL);
+
+ /* Initializes the MAC configure structure to zero. */
+ (void)memset(config, 0, sizeof(enet_config_t));
+
+ /* Sets MII mode, full duplex, 100Mbps for MAC and PHY data interface. */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ config->miiMode = kENET_RgmiiMode;
+#else
+ config->miiMode = kENET_RmiiMode;
+#endif
+ config->miiSpeed = kENET_MiiSpeed100M;
+ config->miiDuplex = kENET_MiiFullDuplex;
+
+ config->ringNum = 1;
+
+ /* Sets the maximum receive frame length. */
+ config->rxMaxFrameLen = ENET_FRAME_MAX_FRAMELEN;
+}
+
+/*!
+ * brief Initializes the ENET module.
+ *
+ * This function initializes the module with the ENET configuration.
+ * note ENET has two buffer descriptors legacy buffer descriptors and
+ * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To
+ * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor
+ * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure()
+ * to configure the 1588 feature and related buffers after calling ENET_Up().
+ *
+ * param base ENET peripheral base address.
+ * param handle ENET handler pointer.
+ * param config ENET mac configuration structure pointer.
+ * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig
+ * can be used directly. It is also possible to verify the Mac configuration using other methods.
+ * param bufferConfig ENET buffer configuration structure pointer.
+ * The buffer configuration should be prepared for ENET Initialization.
+ * It is the start address of "ringNum" enet_buffer_config structures.
+ * To support added multi-ring features in some soc and compatible with the previous
+ * enet driver version. For single ring supported, this bufferConfig is a buffer
+ * configure structure pointer, for multi-ring supported and used case, this bufferConfig
+ * pointer should be a buffer configure structure array pointer.
+ * param macAddr ENET mac address of Ethernet device. This MAC address should be
+ * provided.
+ * param srcClock_Hz The internal module clock source for MII clock.
+ */
+void ENET_Up(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz)
+{
+ /* Checks input parameters. */
+ assert(handle != NULL);
+ assert(config != NULL);
+ assert(bufferConfig != NULL);
+ assert(macAddr != NULL);
+ assert(config->ringNum <= (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ /* Initializes the ENET transmit buffer descriptors. */
+ ENET_SetTxBufferDescriptors(handle, config, bufferConfig);
+
+ /* Initializes the ENET receive buffer descriptors. */
+ ENET_SetRxBufferDescriptors(handle, config, bufferConfig);
+
+ /* Initializes the ENET MAC controller with basic function. */
+ ENET_SetMacController(base, handle, config, bufferConfig, macAddr, srcClock_Hz);
+
+ /* Set all buffers or data in handler for data transmit/receive process. */
+ ENET_SetHandler(base, handle, config, bufferConfig);
+}
+
+/*!
+ * brief Initializes the ENET module.
+ *
+ * This function ungates the module clock and initializes it with the ENET configuration.
+ * note ENET has two buffer descriptors legacy buffer descriptors and
+ * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To
+ * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor
+ * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure()
+ * to configure the 1588 feature and related buffers after calling ENET_Init().
+ *
+ * param base ENET peripheral base address.
+ * param handle ENET handler pointer.
+ * param config ENET mac configuration structure pointer.
+ * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig
+ * can be used directly. It is also possible to verify the Mac configuration using other methods.
+ * param bufferConfig ENET buffer configuration structure pointer.
+ * The buffer configuration should be prepared for ENET Initialization.
+ * It is the start address of "ringNum" enet_buffer_config structures.
+ * To support added multi-ring features in some soc and compatible with the previous
+ * enet driver version. For single ring supported, this bufferConfig is a buffer
+ * configure structure pointer, for multi-ring supported and used case, this bufferConfig
+ * pointer should be a buffer configure structure array pointer.
+ * param macAddr ENET mac address of Ethernet device. This MAC address should be
+ * provided.
+ * param srcClock_Hz The internal module clock source for MII clock.
+ */
+void ENET_Init(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = ENET_GetInstance(base);
+
+ /* Ungate ENET clock. */
+ (void)CLOCK_EnableClock(s_enetClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /* Reset ENET module. */
+ ENET_Reset(base);
+
+ ENET_Up(base, handle, config, bufferConfig, macAddr, srcClock_Hz);
+}
+
+/*!
+ * brief Stops the ENET module.
+
+ * This function disables the ENET module.
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_Down(ENET_Type *base)
+{
+ /* Disable interrupt. */
+ base->EIMR = 0;
+
+ /* Disable ENET. */
+ base->ECR &= ~ENET_ECR_ETHEREN_MASK;
+}
+
+/*!
+ * brief Deinitializes the ENET module.
+
+ * This function gates the module clock, clears ENET interrupts, and disables the ENET module.
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_Deinit(ENET_Type *base)
+{
+ ENET_Down(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disables the clock source. */
+ (void)CLOCK_DisableClock(s_enetClock[ENET_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Sets the callback function.
+ * This API is provided for the application callback required case when ENET
+ * interrupt is enabled. This API should be called after calling ENET_Init.
+ *
+ * param handle ENET handler pointer. Should be provided by application.
+ * param callback The ENET callback function.
+ * param userData The callback function parameter.
+ */
+void ENET_SetCallback(enet_handle_t *handle, enet_callback_t callback, void *userData)
+{
+ assert(handle != NULL);
+
+ /* Set callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetRxIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetRxIrqId[instance]);
+}
+
+void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetTxIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetTxIrqId[instance]);
+}
+#else
+void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetRxIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetRxIrqId[instance]);
+}
+
+void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetTxIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetTxIrqId[instance]);
+}
+#endif
+
+void ENET_SetErrISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetErrIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetErrIrqId[instance]);
+}
+
+#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+void ENET_SetTsISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enetTsIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enetTsIrqId[instance]);
+}
+
+#if (FSL_FEATURE_ENET_QUEUE > 1) && defined(ENET_1G)
+void ENET_Set1588TimerISRHandler(ENET_Type *base, enet_isr_t ISRHandler)
+{
+ uint32_t instance = ENET_GetInstance(base);
+
+ s_enet1588TimerIsr[instance] = ISRHandler;
+ (void)EnableIRQ(s_enet1588TimerIrqId[instance]);
+}
+#endif
+#endif
+
+static void ENET_SetHandler(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig)
+{
+ uint8_t count;
+ uint32_t instance = ENET_GetInstance(base);
+ const enet_buffer_config_t *buffCfg = bufferConfig;
+
+ /* Store transfer parameters in handle pointer. */
+ (void)memset(handle, 0, sizeof(enet_handle_t));
+
+ handle->ringNum =
+ (config->ringNum > (uint8_t)FSL_FEATURE_ENET_QUEUE) ? (uint8_t)FSL_FEATURE_ENET_QUEUE : config->ringNum;
+ for (count = 0; count < handle->ringNum; count++)
+ {
+ assert(buffCfg->rxBuffSizeAlign * buffCfg->rxBdNumber > config->rxMaxFrameLen);
+
+ handle->rxBdRing[count].rxBdBase = buffCfg->rxBdStartAddrAlign;
+ handle->rxBuffSizeAlign[count] = buffCfg->rxBuffSizeAlign;
+ handle->rxBdRing[count].rxRingLen = buffCfg->rxBdNumber;
+ handle->rxMaintainEnable[count] = buffCfg->rxMaintainEnable;
+ handle->txBdRing[count].txBdBase = buffCfg->txBdStartAddrAlign;
+ handle->txBuffSizeAlign[count] = buffCfg->txBuffSizeAlign;
+ handle->txBdRing[count].txRingLen = buffCfg->txBdNumber;
+ handle->txMaintainEnable[count] = buffCfg->txMaintainEnable;
+ handle->txDirtyRing[count].txDirtyBase = buffCfg->txFrameInfo;
+ handle->txDirtyRing[count].txRingLen = buffCfg->txBdNumber;
+ buffCfg++;
+ }
+
+ /* Save the handle pointer in the global variables. */
+ s_ENETHandle[instance] = handle;
+
+ /* Set the IRQ handler when the interrupt is enabled. */
+ if (0U != (config->interrupt & (uint32_t)ENET_TX_INTERRUPT))
+ {
+ ENET_SetTxISRHandler(base, ENET_TransmitIRQHandler);
+ }
+ if (0U != (config->interrupt & (uint32_t)ENET_RX_INTERRUPT))
+ {
+ ENET_SetRxISRHandler(base, ENET_ReceiveIRQHandler);
+ }
+ if (0U != (config->interrupt & (uint32_t)ENET_ERR_INTERRUPT))
+ {
+ ENET_SetErrISRHandler(base, ENET_ErrorIRQHandler);
+ }
+}
+
+static void ENET_SetMacController(ENET_Type *base,
+ enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig,
+ uint8_t *macAddr,
+ uint32_t srcClock_Hz)
+{
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ /* Check the MII mode/speed/duplex setting. */
+ if (config->miiSpeed == kENET_MiiSpeed1000M)
+ {
+ /* Only RGMII mode has the 1000M bit/s. The 1000M only support full duplex. */
+ assert(config->miiMode == kENET_RgmiiMode);
+ assert(config->miiDuplex == kENET_MiiFullDuplex);
+ }
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+ uint32_t rcr = 0;
+ uint32_t tcr = 0;
+ uint32_t ecr = base->ECR;
+ uint32_t macSpecialConfig = config->macSpecialConfig;
+ uint32_t maxFrameLen = config->rxMaxFrameLen;
+ uint32_t configVal = 0;
+
+ /* Maximum frame length check. */
+ if ((0U != (macSpecialConfig & (uint32_t)kENET_ControlVLANTagEnable)) && (maxFrameLen <= ENET_FRAME_MAX_FRAMELEN))
+ {
+ maxFrameLen = (ENET_FRAME_MAX_FRAMELEN + ENET_FRAME_VLAN_TAGLEN);
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (0U != (macSpecialConfig & (uint32_t)kENET_ControlSVLANEnable))
+ {
+ /* Double vlan tag (SVLAN) supported. */
+ maxFrameLen += ENET_FRAME_VLAN_TAGLEN;
+ }
+ ecr |=
+ (uint32_t)(((macSpecialConfig & (uint32_t)kENET_ControlSVLANEnable) != 0U) ?
+ (ENET_ECR_SVLANEN_MASK | ENET_ECR_SVLANDBL_MASK) :
+ 0U) |
+ (uint32_t)(((macSpecialConfig & (uint32_t)kENET_ControlVLANUseSecondTag) != 0U) ? ENET_ECR_VLANUSE2ND_MASK :
+ 0U);
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+ }
+
+ /* Configures MAC receive controller with user configure structure. */
+ rcr = ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxPayloadCheckEnable)) ? ENET_RCR_NLC_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable)) ? ENET_RCR_CFEN_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable)) ? ENET_RCR_FCE_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxPadRemoveEnable)) ? ENET_RCR_PADEN_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxBroadCastRejectEnable)) ? ENET_RCR_BC_REJ_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlPromiscuousEnable)) ? ENET_RCR_PROM_MASK : 0U) |
+ ENET_RCR_MAX_FL(maxFrameLen) | ENET_RCR_CRCFWD_MASK;
+
+/* Set the RGMII or RMII, MII mode and control register. */
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (config->miiMode == kENET_RgmiiMode)
+ {
+ rcr |= ENET_RCR_RGMII_EN_MASK;
+ rcr &= ~ENET_RCR_MII_MODE_MASK;
+ }
+ else
+ {
+ rcr &= ~ENET_RCR_RGMII_EN_MASK;
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+ rcr |= ENET_RCR_MII_MODE_MASK;
+ if (config->miiMode == kENET_RmiiMode)
+ {
+ rcr |= ENET_RCR_RMII_MODE_MASK;
+ }
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ }
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+ /* Speed. */
+ if (config->miiSpeed == kENET_MiiSpeed10M)
+ {
+ rcr |= ENET_RCR_RMII_10T_MASK;
+ }
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ if (config->miiSpeed == kENET_MiiSpeed1000M)
+ {
+ ecr |= ENET_ECR_SPEED_MASK;
+ }
+ else
+ {
+ ecr &= ~ENET_ECR_SPEED_MASK;
+ }
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+ /* Receive setting for half duplex. */
+ if (config->miiDuplex == kENET_MiiHalfDuplex)
+ {
+ rcr |= ENET_RCR_DRT_MASK;
+ }
+ /* Sets internal loop only for MII mode. */
+ if ((0U != (config->macSpecialConfig & (uint32_t)kENET_ControlMIILoopEnable)) &&
+ (config->miiMode != kENET_RmiiMode))
+ {
+ rcr |= ENET_RCR_LOOP_MASK;
+ rcr &= ~ENET_RCR_DRT_MASK;
+ }
+ base->RCR = rcr;
+
+ /* Configures MAC transmit controller: duplex mode, mac address insertion. */
+ tcr = base->TCR & ~(ENET_TCR_FDEN_MASK | ENET_TCR_ADDINS_MASK);
+ tcr |= ((kENET_MiiHalfDuplex != config->miiDuplex) ? (uint32_t)ENET_TCR_FDEN_MASK : 0U) |
+ ((0U != (macSpecialConfig & (uint32_t)kENET_ControlMacAddrInsert)) ? (uint32_t)ENET_TCR_ADDINS_MASK : 0U);
+ base->TCR = tcr;
+
+ /* Configures receive and transmit accelerator. */
+ base->TACC = config->txAccelerConfig;
+ base->RACC = config->rxAccelerConfig;
+
+ /* Sets the pause duration and FIFO threshold for the flow control enabled case. */
+ if (0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable))
+ {
+ uint32_t reemReg;
+ base->OPD = config->pauseDuration;
+ reemReg = ENET_RSEM_RX_SECTION_EMPTY(config->rxFifoEmptyThreshold);
+#if defined(FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD) && FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD
+ reemReg |= ENET_RSEM_STAT_SECTION_EMPTY(config->rxFifoStatEmptyThreshold);
+#endif /* FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD */
+ base->RSEM = reemReg;
+ }
+
+ /* FIFO threshold setting for store and forward enable/disable case. */
+ if (0U != (macSpecialConfig & (uint32_t)kENET_ControlStoreAndFwdDisable))
+ {
+ /* Transmit fifo watermark settings. */
+ configVal = ((uint32_t)config->txFifoWatermark) & ENET_TFWR_TFWR_MASK;
+ base->TFWR = configVal;
+ /* Receive fifo full threshold settings. */
+ configVal = ((uint32_t)config->rxFifoFullThreshold) & ENET_RSFL_RX_SECTION_FULL_MASK;
+ base->RSFL = configVal;
+ }
+ else
+ {
+ /* Transmit fifo watermark settings. */
+ base->TFWR = ENET_TFWR_STRFWD_MASK;
+ base->RSFL = 0;
+ }
+
+ /* Enable store and forward when accelerator is enabled */
+ if (0U !=
+ (config->txAccelerConfig & ((uint32_t)kENET_TxAccelIpCheckEnabled | (uint32_t)kENET_TxAccelProtoCheckEnabled)))
+ {
+ base->TFWR = ENET_TFWR_STRFWD_MASK;
+ }
+ if (0U != ((config->rxAccelerConfig &
+ ((uint32_t)kENET_RxAccelIpCheckEnabled | (uint32_t)kENET_RxAccelProtoCheckEnabled))))
+ {
+ base->RSFL = 0;
+ }
+
+/* Initializes the ring 0. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ base->TDSR = MEMORY_ConvertMemoryMapAddress((uint32_t)bufferConfig->txBdStartAddrAlign, kMEMORY_Local2DMA);
+ base->RDSR = MEMORY_ConvertMemoryMapAddress((uint32_t)bufferConfig->rxBdStartAddrAlign, kMEMORY_Local2DMA);
+#else
+ base->TDSR = (uint32_t)bufferConfig->txBdStartAddrAlign;
+ base->RDSR = (uint32_t)bufferConfig->rxBdStartAddrAlign;
+#endif
+ base->MRBR = (uint32_t)bufferConfig->rxBuffSizeAlign;
+
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ const enet_buffer_config_t *buffCfg = bufferConfig;
+
+ if (config->ringNum > 1U)
+ {
+ /* Initializes the ring 1. */
+ buffCfg++;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ base->TDSR1 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBdStartAddrAlign, kMEMORY_Local2DMA);
+ base->RDSR1 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBdStartAddrAlign, kMEMORY_Local2DMA);
+#else
+ base->TDSR1 = (uint32_t)buffCfg->txBdStartAddrAlign;
+ base->RDSR1 = (uint32_t)buffCfg->rxBdStartAddrAlign;
+#endif
+ base->MRBR1 = (uint32_t)buffCfg->rxBuffSizeAlign;
+ /* Enable the DMAC for ring 1 and with no rx classification set. */
+ base->DMACFG[0] = ENET_DMACFG_DMA_CLASS_EN_MASK;
+ }
+ if (config->ringNum > 2U)
+ {
+ /* Initializes the ring 2. */
+ buffCfg++;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ base->TDSR2 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBdStartAddrAlign, kMEMORY_Local2DMA);
+ base->RDSR2 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBdStartAddrAlign, kMEMORY_Local2DMA);
+#else
+ base->TDSR2 = (uint32_t)buffCfg->txBdStartAddrAlign;
+ base->RDSR2 = (uint32_t)buffCfg->rxBdStartAddrAlign;
+#endif
+ base->MRBR2 = (uint32_t)buffCfg->rxBuffSizeAlign;
+ /* Enable the DMAC for ring 2 and with no rx classification set. */
+ base->DMACFG[1] = ENET_DMACFG_DMA_CLASS_EN_MASK;
+ }
+
+ /* Default the class/ring 1 and 2 are not enabled and the receive classification is disabled
+ * so we set the default transmit scheme with the round-robin mode. beacuse the legacy bd mode
+ * only support the round-robin mode. if the avb feature is required, just call the setup avb
+ * feature API. */
+ base->QOS |= ENET_QOS_TX_SCHEME(1);
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+ /* Configures the Mac address. */
+ ENET_SetMacAddr(base, macAddr);
+
+ /* Initialize the SMI if uninitialized. */
+ if (!ENET_GetSMI(base))
+ {
+ ENET_SetSMI(base, srcClock_Hz,
+ ((0U != (config->macSpecialConfig & (uint32_t)kENET_ControlSMIPreambleDisable)) ? true : false));
+ }
+
+/* Enables Ethernet interrupt, enables the interrupt coalsecing if it is required. */
+#if defined(FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE) && FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE
+ if (NULL != config->intCoalesceCfg)
+ {
+ uint32_t intMask = (ENET_EIMR_TXB_MASK | ENET_EIMR_RXB_MASK);
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+ uint8_t queue = 0;
+ intMask |= ENET_EIMR_TXB2_MASK | ENET_EIMR_RXB2_MASK | ENET_EIMR_TXB1_MASK | ENET_EIMR_RXB1_MASK;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+ /* Clear all buffer interrupts. */
+ base->EIMR &= ~intMask;
+
+/* Set the interrupt coalescence. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+ for (queue = 0; queue < (uint8_t)FSL_FEATURE_ENET_QUEUE; queue++)
+ {
+ base->TXIC[queue] = ENET_TXIC_ICFT(config->intCoalesceCfg->txCoalesceFrameCount[queue]) |
+ config->intCoalesceCfg->txCoalesceTimeCount[queue] | ENET_TXIC_ICCS_MASK |
+ ENET_TXIC_ICEN_MASK;
+ base->RXIC[queue] = ENET_RXIC_ICFT(config->intCoalesceCfg->rxCoalesceFrameCount[queue]) |
+ config->intCoalesceCfg->rxCoalesceTimeCount[queue] | ENET_RXIC_ICCS_MASK |
+ ENET_RXIC_ICEN_MASK;
+ }
+#else
+ base->TXIC = ENET_TXIC_ICFT(config->intCoalesceCfg->txCoalesceFrameCount[0]) |
+ config->intCoalesceCfg->txCoalesceTimeCount[0] | ENET_TXIC_ICCS_MASK | ENET_TXIC_ICEN_MASK;
+ base->RXIC = ENET_RXIC_ICFT(config->intCoalesceCfg->rxCoalesceFrameCount[0]) |
+ config->intCoalesceCfg->rxCoalesceTimeCount[0] | ENET_RXIC_ICCS_MASK | ENET_RXIC_ICEN_MASK;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+#endif /* FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE */
+ ENET_EnableInterrupts(base, config->interrupt);
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* Sets the 1588 enhanced feature. */
+ ecr |= ENET_ECR_EN1588_MASK;
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ /* Enables Ethernet module after all configuration except the buffer descriptor active. */
+ ecr |= ENET_ECR_ETHEREN_MASK | ENET_ECR_DBSWP_MASK;
+ base->ECR = ecr;
+}
+
+static void ENET_SetTxBufferDescriptors(enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig)
+{
+ assert(config != NULL);
+ assert(bufferConfig != NULL);
+
+ /* Default single ring is supported. */
+ uint8_t ringNum;
+ uint16_t count;
+ uint32_t txBuffSizeAlign;
+ uint8_t *txBuffer = NULL;
+ const enet_buffer_config_t *buffCfg = bufferConfig;
+
+ /* Check the input parameters. */
+ for (ringNum = 0; ringNum < config->ringNum; ringNum++)
+ {
+ if (buffCfg->txBdStartAddrAlign != NULL)
+ {
+ volatile enet_tx_bd_struct_t *curBuffDescrip = buffCfg->txBdStartAddrAlign;
+ txBuffSizeAlign = buffCfg->txBuffSizeAlign;
+
+ if (buffCfg->txBufferAlign != NULL)
+ {
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ txBuffer =
+ (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBufferAlign, kMEMORY_Local2DMA);
+#else
+ txBuffer = buffCfg->txBufferAlign;
+#endif
+ }
+
+ for (count = 0; count < buffCfg->txBdNumber; count++)
+ {
+ if (buffCfg->txBufferAlign != NULL)
+ {
+ /* Set data buffer address. */
+ curBuffDescrip->buffer = (uint8_t *)((uint32_t)&txBuffer[count * txBuffSizeAlign]);
+ }
+ /* Initializes data length. */
+ curBuffDescrip->length = 0;
+ /* Sets the crc. */
+ curBuffDescrip->control = ENET_BUFFDESCRIPTOR_TX_TRANMITCRC_MASK;
+ /* Sets the last buffer descriptor with the wrap flag. */
+ if (count == (buffCfg->txBdNumber - 1U))
+ {
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_WRAP_MASK;
+ }
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* Enable transmit interrupt for store the transmit timestamp. */
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK;
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ /* Set the type of the frame when the credit-based scheme is used. */
+ curBuffDescrip->controlExtend1 |= (uint16_t)(ENET_BD_FTYPE(ringNum));
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ /* Increase the index. */
+ curBuffDescrip++;
+ }
+ }
+ buffCfg++;
+ }
+}
+
+static void ENET_SetRxBufferDescriptors(enet_handle_t *handle,
+ const enet_config_t *config,
+ const enet_buffer_config_t *bufferConfig)
+{
+ assert(config != NULL);
+ assert(bufferConfig != NULL);
+
+ /* Default single ring is supported. */
+ uint8_t ringNum;
+ uint16_t count;
+ uint16_t rxBuffSizeAlign;
+ uint8_t *rxBuffer;
+ const enet_buffer_config_t *buffCfg = bufferConfig;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint32_t mask = ((uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt);
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Check the input parameters. */
+ for (ringNum = 0; ringNum < config->ringNum; ringNum++)
+ {
+ assert(buffCfg->rxBuffSizeAlign >= ENET_RX_MIN_BUFFERSIZE);
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+#if FSL_FEATURE_ENET_QUEUE > 1
+ if (ringNum == 1U)
+ {
+ mask = ((uint32_t)kENET_RxFrame1Interrupt | (uint32_t)kENET_RxBuffer1Interrupt);
+ }
+ else if (ringNum == 2U)
+ {
+ mask = ((uint32_t)kENET_RxFrame2Interrupt | (uint32_t)kENET_RxBuffer2Interrupt);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ if ((buffCfg->rxBdStartAddrAlign != NULL) && (buffCfg->rxBufferAlign != NULL))
+ {
+ volatile enet_rx_bd_struct_t *curBuffDescrip = buffCfg->rxBdStartAddrAlign;
+ rxBuffSizeAlign = buffCfg->rxBuffSizeAlign;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ rxBuffer = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBufferAlign, kMEMORY_Local2DMA);
+#else
+ rxBuffer = buffCfg->rxBufferAlign;
+#endif
+
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (buffCfg->rxMaintainEnable)
+ {
+ /* Invalidate rx buffers before DMA transfer data into them. */
+ DCACHE_InvalidateByRange((uint32_t)rxBuffer, ((uint32_t)buffCfg->rxBdNumber * rxBuffSizeAlign));
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+ for (count = 0; count < buffCfg->rxBdNumber; count++)
+ {
+ /* Set data buffer and the length. */
+ curBuffDescrip->buffer = (uint8_t *)((uint32_t)&rxBuffer[count * rxBuffSizeAlign]);
+ curBuffDescrip->length = 0;
+
+ /* Initializes the buffer descriptors with empty bit. */
+ curBuffDescrip->control = ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+ /* Sets the last buffer descriptor with the wrap flag. */
+ if (count == (buffCfg->rxBdNumber - 1U))
+ {
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ }
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ if (0U != (config->interrupt & mask))
+ {
+ /* Enable receive interrupt. */
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_RX_INTERRUPT_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 = 0;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ /* Increase the index. */
+ curBuffDescrip++;
+ }
+ }
+ buffCfg++;
+ }
+}
+
+/*!
+ * @brief Activates ENET send for multiple tx rings.
+ * @note This must be called after the MAC configuration and
+ * state are ready. It must be called after the ENET_Init() and
+ * this should be called when the ENET receive required.
+ *
+ * @param base ENET peripheral base address.
+ * @param ringId The descriptor ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1.
+ *
+ */
+static void ENET_ActiveSend(ENET_Type *base, uint8_t ringId)
+{
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ volatile uint32_t *txDesActive = NULL;
+
+ /* Ensure previous data update is completed with Data Synchronization Barrier before activing Tx BD. */
+ __DSB();
+
+ switch (ringId)
+ {
+ case kENET_Ring0:
+ txDesActive = &(base->TDAR);
+ break;
+#if FSL_FEATURE_ENET_QUEUE > 1
+ case kENET_Ring1:
+ txDesActive = &(base->TDAR1);
+ break;
+ case kENET_Ring2:
+ txDesActive = &(base->TDAR2);
+ break;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ default:
+ txDesActive = &(base->TDAR);
+ break;
+ }
+
+#if defined(FSL_FEATURE_ENET_HAS_ERRATA_007885) && FSL_FEATURE_ENET_HAS_ERRATA_007885
+ /* There is a TDAR race condition for mutliQ when the software sets TDAR
+ * and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles).
+ * This will cause the udma_tx and udma_tx_arbiter state machines to hang.
+ * Software workaround: introduces a delay by reading the relevant ENET_TDARn_TDAR 4 times
+ */
+ for (uint8_t i = 0; i < 4U; i++)
+ {
+ if (*txDesActive == 0U)
+ {
+ break;
+ }
+ }
+#endif
+
+ /* Write to active tx descriptor */
+ *txDesActive = 0;
+}
+
+/*!
+ * brief Sets the ENET MII speed and duplex.
+ *
+ * This API is provided to dynamically change the speed and dulpex for MAC.
+ *
+ * param base ENET peripheral base address.
+ * param speed The speed of the RMII mode.
+ * param duplex The duplex of the RMII mode.
+ */
+void ENET_SetMII(ENET_Type *base, enet_mii_speed_t speed, enet_mii_duplex_t duplex)
+{
+ uint32_t rcr = base->RCR;
+ uint32_t tcr = base->TCR;
+
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+ uint32_t ecr = base->ECR;
+
+ if (kENET_MiiSpeed1000M == speed)
+ {
+ assert(duplex == kENET_MiiFullDuplex);
+ ecr |= ENET_ECR_SPEED_MASK;
+ }
+ else
+ {
+ ecr &= ~ENET_ECR_SPEED_MASK;
+ }
+
+ base->ECR = ecr;
+#endif /* FSL_FEATURE_ENET_HAS_AVB */
+
+ /* Sets speed mode. */
+ if (kENET_MiiSpeed10M == speed)
+ {
+ rcr |= ENET_RCR_RMII_10T_MASK;
+ }
+ else
+ {
+ rcr &= ~ENET_RCR_RMII_10T_MASK;
+ }
+ /* Set duplex mode. */
+ if (duplex == kENET_MiiHalfDuplex)
+ {
+ rcr |= ENET_RCR_DRT_MASK;
+ tcr &= ~ENET_TCR_FDEN_MASK;
+ }
+ else
+ {
+ rcr &= ~ENET_RCR_DRT_MASK;
+ tcr |= ENET_TCR_FDEN_MASK;
+ }
+
+ base->RCR = rcr;
+ base->TCR = tcr;
+}
+
+/*!
+ * brief Sets the ENET module Mac address.
+ *
+ * param base ENET peripheral base address.
+ * param macAddr The six-byte Mac address pointer.
+ * The pointer is allocated by application and input into the API.
+ */
+void ENET_SetMacAddr(ENET_Type *base, uint8_t *macAddr)
+{
+ uint32_t address;
+
+ /* Set physical address lower register. */
+ address = (uint32_t)(((uint32_t)macAddr[0] << 24U) | ((uint32_t)macAddr[1] << 16U) | ((uint32_t)macAddr[2] << 8U) |
+ (uint32_t)macAddr[3]);
+ base->PALR = address;
+ /* Set physical address high register. */
+ address = (uint32_t)(((uint32_t)macAddr[4] << 8U) | ((uint32_t)macAddr[5]));
+ base->PAUR = address << ENET_PAUR_PADDR2_SHIFT;
+}
+
+/*!
+ * brief Gets the ENET module Mac address.
+ *
+ * param base ENET peripheral base address.
+ * param macAddr The six-byte Mac address pointer.
+ * The pointer is allocated by application and input into the API.
+ */
+void ENET_GetMacAddr(ENET_Type *base, uint8_t *macAddr)
+{
+ assert(macAddr != NULL);
+
+ uint32_t address;
+
+ /* Get from physical address lower register. */
+ address = base->PALR;
+ macAddr[0] = 0xFFU & (uint8_t)(address >> 24U);
+ macAddr[1] = 0xFFU & (uint8_t)(address >> 16U);
+ macAddr[2] = 0xFFU & (uint8_t)(address >> 8U);
+ macAddr[3] = 0xFFU & (uint8_t)address;
+
+ /* Get from physical address high register. */
+ address = (base->PAUR & ENET_PAUR_PADDR2_MASK) >> ENET_PAUR_PADDR2_SHIFT;
+ macAddr[4] = 0xFFU & (uint8_t)(address >> 8U);
+ macAddr[5] = 0xFFU & (uint8_t)address;
+}
+
+/*!
+ * brief Sets the ENET SMI(serial management interface)- MII management interface.
+ *
+ * param base ENET peripheral base address.
+ * param srcClock_Hz This is the ENET module clock frequency. Normally it's the system clock. See clock distribution.
+ * param isPreambleDisabled The preamble disable flag.
+ * - true Enables the preamble.
+ * - false Disables the preamble.
+ */
+void ENET_SetSMI(ENET_Type *base, uint32_t srcClock_Hz, bool isPreambleDisabled)
+{
+ assert((srcClock_Hz / (2U * ENET_MDC_FREQUENCY)) != 0U);
+
+ uint32_t clkCycle = 0;
+ uint32_t speed = 0;
+ uint32_t mscr = 0;
+
+ /* Calculate the MII speed which controls the frequency of the MDC. */
+ speed = srcClock_Hz / (2U * ENET_MDC_FREQUENCY) - 1U;
+ /* Calculate the hold time on the MDIO output. */
+ clkCycle = (10U + ENET_NANOSECOND_ONE_SECOND / srcClock_Hz - 1U) / (ENET_NANOSECOND_ONE_SECOND / srcClock_Hz) - 1U;
+ /* Build the configuration for MDC/MDIO control. */
+ mscr =
+ ENET_MSCR_MII_SPEED(speed) | ENET_MSCR_HOLDTIME(clkCycle) | (isPreambleDisabled ? ENET_MSCR_DIS_PRE_MASK : 0U);
+ base->MSCR = mscr;
+}
+
+/*!
+ * brief Starts an SMI write command.
+ *
+ * Used for standard IEEE802.3 MDIO Clause 22 format.
+ *
+ * param base ENET peripheral base address.
+ * param phyAddr The PHY address.
+ * param phyReg The PHY register. Range from 0 ~ 31.
+ * param operation The write operation.
+ * param data The data written to PHY.
+ */
+void ENET_StartSMIWrite(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, enet_mii_write_t operation, uint32_t data)
+{
+ uint32_t mmfr = 0;
+
+ /* Build MII write command. */
+ mmfr = ENET_MMFR_ST(1U) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(phyReg) |
+ ENET_MMFR_TA(2U) | (data & 0xFFFFU);
+ base->MMFR = mmfr;
+}
+
+/*!
+ * brief Starts an SMI (Serial Management Interface) read command.
+ *
+ * Used for standard IEEE802.3 MDIO Clause 22 format.
+ *
+ * param base ENET peripheral base address.
+ * param phyAddr The PHY address.
+ * param phyReg The PHY register. Range from 0 ~ 31.
+ * param operation The read operation.
+ */
+void ENET_StartSMIRead(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, enet_mii_read_t operation)
+{
+ uint32_t mmfr = 0;
+
+ /* Build MII read command. */
+ mmfr = ENET_MMFR_ST(1U) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(phyReg) | ENET_MMFR_TA(2U);
+ base->MMFR = mmfr;
+}
+
+#if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO
+/*!
+ * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write command.
+ * deprecated Do not use this function. It has been superceded by @ref ENET_StartExtC45SMIWriteReg and
+ * ENET_StartExtC45SMIWriteData.
+ *
+ * param base ENET peripheral base address.
+ * param phyAddr The PHY address.
+ * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45,
+ * the phyReg is a 21-bits combination of the devaddr (5 bits device address)
+ * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr.
+ * param data The data written to PHY.
+ */
+void ENET_StartExtC45SMIWrite(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
+{
+ uint32_t mmfr = 0;
+
+ /* Parse the address from the input register. */
+ uint16_t devAddr = (uint16_t)((phyReg >> ENET_MMFR_TA_SHIFT) & 0x1FU);
+ uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU);
+
+ /* Address write firstly. */
+ mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiAddrWrite_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) |
+ ENET_MMFR_TA(2) | ENET_MMFR_DATA(regAddr);
+ base->MMFR = mmfr;
+
+ /* Build MII write command. */
+ mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiWriteFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) |
+ ENET_MMFR_TA(2) | ENET_MMFR_DATA(data);
+ base->MMFR = mmfr;
+}
+
+/*!
+ * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI read command.
+ * deprecated Do not use this function. It has been superceded by @ref ENET_StartExtC45SMIWriteReg and
+ * ENET_StartExtC45SMIReadData.
+ *
+ * param base ENET peripheral base address.
+ * param phyAddr The PHY address.
+ * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45,
+ * the phyReg is a 21-bits combination of the devaddr (5 bits device address)
+ * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr.
+ */
+void ENET_StartExtC45SMIRead(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg)
+{
+ uint32_t mmfr = 0;
+
+ /* Parse the address from the input register. */
+ uint16_t devAddr = (uint16_t)((phyReg >> ENET_MMFR_TA_SHIFT) & 0x1FU);
+ uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU);
+
+ /* Address write firstly. */
+ mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiAddrWrite_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) |
+ ENET_MMFR_TA(2) | ENET_MMFR_DATA(regAddr);
+ base->MMFR = mmfr;
+
+ /* Build MII read command. */
+ mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiReadFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) |
+ ENET_MMFR_TA(2);
+ base->MMFR = mmfr;
+}
+
+/*!
+ * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write register command.
+ *
+ * param base ENET peripheral base address.
+ * param phyAddr The PHY address.
+ * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45,
+ * the phyReg is a 21-bits combination of the devaddr (5 bits device address)
+ * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr.
+ */
+void ENET_StartExtC45SMIWriteReg(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg)
+{
+ uint32_t mmfr = 0;
+
+ /* Parse the address from the input register. */
+ uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU);
+ uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU);
+
+ /* Address write. */
+ mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiAddrWrite_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) |
+ ENET_MMFR_TA(2) | ENET_MMFR_DATA(regAddr);
+ base->MMFR = mmfr;
+}
+
+/*!
+ * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write data command.
+ *
+ * After writing MMFR register, we need to check whether the transmission is over.
+ * This is an example for whole precedure of clause 45 MDIO write.
+ * code
+ * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ * ENET_StartExtC45SMIWriteReg(base, phyAddr, phyReg);
+ * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U)
+ * {
+ * }
+ * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ * ENET_StartExtC45SMIWriteData(base, phyAddr, phyReg, data);
+ * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U)
+ * {
+ * }
+ * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ * endcode
+ * param base ENET peripheral base address.
+ * param phyAddr The PHY address.
+ * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45,
+ * the phyReg is a 21-bits combination of the devaddr (5 bits device address)
+ * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr.
+ * param data The data written to PHY.
+ */
+void ENET_StartExtC45SMIWriteData(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data)
+{
+ uint32_t mmfr = 0;
+
+ /* Parse the address from the input register. */
+ uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU);
+
+ /* Build MII write command. */
+ mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiWriteFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) |
+ ENET_MMFR_TA(2) | ENET_MMFR_DATA(data);
+ base->MMFR = mmfr;
+}
+
+/*!
+ * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI read data command.
+ *
+ * After writing MMFR register, we need to check whether the transmission is over.
+ * This is an example for whole precedure of clause 45 MDIO read.
+ * code
+ * uint32_t data;
+ * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ * ENET_StartExtC45SMIWriteReg(base, phyAddr, phyReg);
+ * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U)
+ * {
+ * }
+ * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ * ENET_StartExtC45SMIReadData(base, phyAddr, phyReg);
+ * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U)
+ * {
+ * }
+ * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK);
+ * data = ENET_ReadSMIData(base);
+ * endcode
+ * param base ENET peripheral base address.
+ * param phyAddr The PHY address.
+ * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45,
+ * the phyReg is a 21-bits combination of the devaddr (5 bits device address)
+ * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr.
+ */
+void ENET_StartExtC45SMIReadData(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg)
+{
+ uint32_t mmfr = 0;
+
+ /* Parse the address from the input register. */
+ uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU);
+
+ /* Build MII read command. */
+ mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiReadFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) |
+ ENET_MMFR_TA(2);
+ base->MMFR = mmfr;
+}
+#endif /* FSL_FEATURE_ENET_HAS_EXTEND_MDIO */
+
+static uint16_t ENET_IncreaseIndex(uint16_t index, uint16_t max)
+{
+ /* Increase the index. */
+ index++;
+ if (index >= max)
+ {
+ index = 0;
+ }
+ return index;
+}
+
+static inline bool ENET_TxDirtyRingAvailable(enet_tx_dirty_ring_t *txDirtyRing)
+{
+ return !txDirtyRing->isFull;
+}
+
+/*!
+ * brief Gets the error statistics of a received frame for ENET specified ring.
+ *
+ * This API must be called after the ENET_GetRxFrameSize and before the ENET_ReadFrame().
+ * If the ENET_GetRxFrameSize returns kStatus_ENET_RxFrameError,
+ * the ENET_GetRxErrBeforeReadFrame can be used to get the exact error statistics.
+ * This is an example.
+ * code
+ * status = ENET_GetRxFrameSize(&g_handle, &length, 0);
+ * if (status == kStatus_ENET_RxFrameError)
+ * {
+ * ENET_GetRxErrBeforeReadFrame(&g_handle, &eErrStatic, 0);
+ * ENET_ReadFrame(EXAMPLE_ENET, &g_handle, NULL, 0);
+ * }
+ * endcode
+ * param handle The ENET handler structure pointer. This is the same handler pointer used in the ENET_Init.
+ * param eErrorStatic The error statistics structure pointer.
+ * param ringId The ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1.
+ */
+void ENET_GetRxErrBeforeReadFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(eErrorStatic != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ uint16_t control = 0;
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ volatile enet_rx_bd_struct_t *cmpBuffDescrip = curBuffDescrip;
+
+ do
+ {
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ control = curBuffDescrip->control;
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK))
+ {
+ /* The receive truncate error. */
+ eErrorStatic->statsRxTruncateErr++;
+ }
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK))
+ {
+ /* The receive over run error. */
+ eErrorStatic->statsRxOverRunErr++;
+ }
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK))
+ {
+ /* The receive length violation error. */
+ eErrorStatic->statsRxLenGreaterErr++;
+ }
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK))
+ {
+ /* The receive alignment error. */
+ eErrorStatic->statsRxAlignErr++;
+ }
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_CRC_MASK))
+ {
+ /* The receive CRC error. */
+ eErrorStatic->statsRxFcsErr++;
+ }
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ uint16_t controlExt = curBuffDescrip->controlExtend1;
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_MACERR_MASK))
+ {
+ /* The MAC error. */
+ eErrorStatic->statsRxMacErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK))
+ {
+ /* The PHY error. */
+ eErrorStatic->statsRxPhyErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK))
+ {
+ /* The receive collision error. */
+ eErrorStatic->statsRxCollisionErr++;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ break;
+ }
+
+ /* Increase the buffer descriptor, if it is the last one, increase to first one of the ring buffer. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ curBuffDescrip = rxBdRing->rxBdBase;
+ }
+ else
+ {
+ curBuffDescrip++;
+ }
+
+ } while (curBuffDescrip != cmpBuffDescrip);
+}
+
+/*!
+ * brief Gets the size of the read frame for specified ring.
+ *
+ * This function gets a received frame size from the ENET buffer descriptors.
+ * note The FCS of the frame is automatically removed by MAC and the size is the length without the FCS.
+ * After calling ENET_GetRxFrameSize, ENET_ReadFrame() should be called to update the
+ * receive buffers if the result is not "kStatus_ENET_RxFrameEmpty".
+ *
+ * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * param length The length of the valid frame received.
+ * param ringId The ring index or ring number.
+ * retval kStatus_ENET_RxFrameEmpty No frame received. Should not call ENET_ReadFrame to read frame.
+ * retval kStatus_ENET_RxFrameError Data error happens. ENET_ReadFrame should be called with NULL data
+ * and NULL length to update the receive buffers.
+ * retval kStatus_Success Receive a frame Successfully then the ENET_ReadFrame
+ * should be called with the right data buffer and the captured data length input.
+ */
+status_t ENET_GetRxFrameSize(enet_handle_t *handle, uint32_t *length, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(length != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ /* Reset the length to zero. */
+ *length = 0;
+
+ uint16_t validLastMask = ENET_BUFFDESCRIPTOR_RX_LAST_MASK | ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ uint16_t index = rxBdRing->rxGenIdx;
+ bool isReturn = false;
+ status_t result = kStatus_Success;
+
+ /* Check the current buffer descriptor's empty flag. If empty means there is no frame received. */
+ /* If this buffer descriptor is owned by application, return empty. Only need to check the first BD's owner if one
+ * frame in mutiple BDs. */
+ if (0U != (curBuffDescrip->control & (ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK | ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK)))
+ {
+ isReturn = true;
+ result = kStatus_ENET_RxFrameEmpty;
+ }
+ else
+ {
+ do
+ {
+ /* Add check for abnormal case. */
+ if (curBuffDescrip->length == 0U)
+ {
+ isReturn = true;
+ result = kStatus_ENET_RxFrameError;
+ break;
+ }
+
+ /* Find the last buffer descriptor. */
+ if ((curBuffDescrip->control & validLastMask) == ENET_BUFFDESCRIPTOR_RX_LAST_MASK)
+ {
+ isReturn = true;
+ /* The last buffer descriptor in the frame check the status of the received frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_ERR_MASK))
+ {
+ result = kStatus_ENET_RxFrameError;
+ break;
+ }
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ if (0U != (curBuffDescrip->controlExtend1 & ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK))
+ {
+ result = kStatus_ENET_RxFrameError;
+ break;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* FCS is removed by MAC. */
+ *length = curBuffDescrip->length;
+ break;
+ }
+ /* Increase the buffer descriptor, if it is the last one, increase to first one of the ring buffer. */
+ index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen);
+ curBuffDescrip = rxBdRing->rxBdBase + index;
+ } while (index != rxBdRing->rxGenIdx);
+ }
+
+ if (isReturn == false)
+ {
+ /* The frame is on processing - set to empty status to make application to receive it next time. */
+ result = kStatus_ENET_RxFrameEmpty;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Reads a frame from the ENET device.
+ * This function reads a frame (both the data and the length) from the ENET buffer descriptors.
+ * User can get timestamp through ts pointer if the ts is not NULL.
+ * Note that it doesn't store the timestamp in the receive timestamp queue.
+ * The ENET_GetRxFrameSize should be used to get the size of the prepared data buffer.
+ * This is an example:
+ * code
+ * uint32_t length;
+ * enet_handle_t g_handle;
+ * Comments: Get the received frame size firstly.
+ * status = ENET_GetRxFrameSize(&g_handle, &length, 0);
+ * if (length != 0)
+ * {
+ * Comments: Allocate memory here with the size of "length"
+ * uint8_t *data = memory allocate interface;
+ * if (!data)
+ * {
+ * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL);
+ * Comments: Add the console warning log.
+ * }
+ * else
+ * {
+ * status = ENET_ReadFrame(ENET, &g_handle, data, length, 0, NULL);
+ * Comments: Call stack input API to deliver the data to stack
+ * }
+ * }
+ * else if (status == kStatus_ENET_RxFrameError)
+ * {
+ * Comments: Update the received buffer when a error frame is received.
+ * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL);
+ * }
+ * endcode
+ * param base ENET peripheral base address.
+ * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * param data The data buffer provided by user to store the frame which memory size should be at least "length".
+ * param length The size of the data buffer which is still the length of the received frame.
+ * param ringId The ring index or ring number.
+ * param ts The timestamp address to store received timestamp.
+ * return The execute status, successful or failure.
+ */
+status_t ENET_ReadFrame(
+ ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length, uint8_t ringId, uint32_t *ts)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ uint32_t len = 0;
+ uint32_t offset = 0;
+ uint16_t control;
+ bool isLastBuff = false;
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ uint16_t index = rxBdRing->rxGenIdx;
+ status_t result = kStatus_Success;
+ uint32_t address;
+ uint32_t dest;
+
+ /* For data-NULL input, only update the buffer descriptor. */
+ if (data == NULL)
+ {
+ do
+ {
+ /* Update the control flag. */
+ control = curBuffDescrip->control;
+
+ /* Updates the receive buffer descriptors. */
+ ENET_UpdateReadBuffers(base, handle, ringId);
+
+ /* Find the last buffer descriptor for the frame. */
+ if (0U != (control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ break;
+ }
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ } while (index != rxBdRing->rxGenIdx);
+ }
+ else
+ {
+ while (!isLastBuff)
+ {
+/* A frame on one buffer or several receive buffers are both considered. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = (uint32_t)curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->rxMaintainEnable[ringId])
+ {
+ /* Add the cache invalidate maintain. */
+ DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+ dest = (uint32_t)data + offset;
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ /* This is a valid frame. */
+ isLastBuff = true;
+ if (length == curBuffDescrip->length)
+ {
+ /* Copy the frame to user's buffer without FCS. */
+ len = curBuffDescrip->length - offset;
+ (void)memcpy((uint32_t *)dest, (uint32_t *)address, len);
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* Get the timestamp if the ts isn't NULL. */
+ if (ts != NULL)
+ {
+ *ts = curBuffDescrip->timestamp;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Updates the receive buffer descriptors. */
+ ENET_UpdateReadBuffers(base, handle, ringId);
+ break;
+ }
+ else
+ {
+ /* Updates the receive buffer descriptors. */
+ ENET_UpdateReadBuffers(base, handle, ringId);
+ }
+ }
+ else
+ {
+ /* Store a frame on several buffer descriptors. */
+ isLastBuff = false;
+ /* Length check. */
+ if (offset >= length)
+ {
+ result = kStatus_ENET_RxFrameFail;
+ break;
+ }
+ (void)memcpy((uint32_t *)dest, (uint32_t *)address, handle->rxBuffSizeAlign[ringId]);
+ offset += handle->rxBuffSizeAlign[ringId];
+
+ /* Updates the receive buffer descriptors. */
+ ENET_UpdateReadBuffers(base, handle, ringId);
+ }
+
+ /* Get the current buffer descriptor. */
+ curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ }
+ }
+
+ return result;
+}
+
+static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ volatile enet_rx_bd_struct_t *curBuffDescrip =
+ handle->rxBdRing[ringId].rxBdBase + handle->rxBdRing[ringId].rxGenIdx;
+
+ /* Clears status. */
+ curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+
+ /* Increase current buffer descriptor to the next one. */
+ handle->rxBdRing[ringId].rxGenIdx =
+ ENET_IncreaseIndex(handle->rxBdRing[ringId].rxGenIdx, handle->rxBdRing[ringId].rxRingLen);
+
+ /* Ensure previous data update is completed with Data Synchronization Barrier before activing Rx BD. */
+ __DSB();
+
+ /* Actives the receive buffer descriptor. */
+ switch (ringId)
+ {
+ case kENET_Ring0:
+ base->RDAR = ENET_RDAR_RDAR_MASK;
+ break;
+#if FSL_FEATURE_ENET_QUEUE > 1
+ case kENET_Ring1:
+ base->RDAR1 = ENET_RDAR1_RDAR_MASK;
+ break;
+ case kENET_Ring2:
+ base->RDAR2 = ENET_RDAR2_RDAR_MASK;
+ break;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ default:
+ assert(false);
+ base->RDAR = ENET_RDAR_RDAR_MASK;
+ break;
+ }
+}
+
+/*!
+ * brief Transmits an ENET frame for specified ring.
+ * note The CRC is automatically appended to the data. Input the data
+ * to send without the CRC.
+ *
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param data The data buffer provided by user to send.
+ * param length The length of the data to send.
+ * param ringId The ring index or ring number.
+ * param tsFlag Timestamp enable flag.
+ * param context Used by user to handle some events after transmit over.
+ * retval kStatus_Success Send frame succeed.
+ * retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission.
+ * The transmit busy happens when the data send rate is over the MAC capacity.
+ * The waiting mechanism is recommended to be added after each call return with
+ * kStatus_ENET_TxFrameBusy.
+ */
+status_t ENET_SendFrame(ENET_Type *base,
+ enet_handle_t *handle,
+ const uint8_t *data,
+ uint32_t length,
+ uint8_t ringId,
+ bool tsFlag,
+ void *context)
+{
+ assert(handle != NULL);
+ assert(data != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ volatile enet_tx_bd_struct_t *curBuffDescrip;
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+ enet_frame_info_t *txDirty = NULL;
+ uint32_t len = 0;
+ uint32_t sizeleft = 0;
+ uint32_t address;
+ status_t result = kStatus_Success;
+ uint32_t src;
+ uint32_t configVal;
+ bool isReturn = false;
+
+ /* Check the frame length. */
+ if (length > ENET_FRAME_MAX_FRAMELEN)
+ {
+ result = kStatus_ENET_TxFrameOverLen;
+ }
+ else
+ {
+ /* Check if the transmit buffer is ready. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ /* Check txDirtyRing if need frameinfo in tx interrupt callback. */
+ else if ((handle->TxReclaimEnable[ringId]) && !ENET_TxDirtyRingAvailable(txDirtyRing))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ else
+ {
+ /* One transmit buffer is enough for one frame. */
+ if (handle->txBuffSizeAlign[ringId] >= length)
+ {
+ /* Copy data to the buffer for uDMA transfer. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = (uint32_t)curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ (void)memcpy((void *)(uint32_t *)address, (const void *)(uint32_t *)(uint32_t)data, length);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->txMaintainEnable[ringId])
+ {
+ DCACHE_CleanByRange(address, length);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+ /* Set data length. */
+ curBuffDescrip->length = (uint16_t)length;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if (tsFlag)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
+
+ /* Increase the buffer descriptor address. */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+ /* Add context to frame info ring */
+ if (handle->TxReclaimEnable[ringId])
+ {
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ txBdRing->txDescUsed++;
+ }
+
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSend(base, ringId);
+ }
+ else
+ {
+ /* One frame requires more than one transmit buffers. */
+ do
+ {
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if (tsFlag)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Update the size left to be transmit. */
+ sizeleft = length - len;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = (uint32_t)curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ src = (uint32_t)data + len;
+ if (sizeleft > handle->txBuffSizeAlign[ringId])
+ {
+ /* Data copy. */
+ (void)memcpy((uint32_t *)address, (uint32_t *)src, handle->txBuffSizeAlign[ringId]);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->txMaintainEnable[ringId])
+ {
+ /* Add the cache clean maintain. */
+ DCACHE_CleanByRange(address, handle->txBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+ /* Data length update. */
+ curBuffDescrip->length = handle->txBuffSizeAlign[ringId];
+ len += handle->txBuffSizeAlign[ringId];
+ /* Sets the control flag. */
+ configVal = (uint32_t)curBuffDescrip->control;
+ configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+ configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
+ curBuffDescrip->control = (uint16_t)configVal;
+
+ if (handle->TxReclaimEnable[ringId])
+ {
+ txBdRing->txDescUsed++;
+ }
+ /* Active the transmit buffer descriptor*/
+ ENET_ActiveSend(base, ringId);
+ }
+ else
+ {
+ (void)memcpy((uint32_t *)address, (uint32_t *)src, sizeleft);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->txMaintainEnable[ringId])
+ {
+ /* Add the cache clean maintain. */
+ DCACHE_CleanByRange(address, sizeleft);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+ curBuffDescrip->length = (uint16_t)sizeleft;
+ /* Set Last buffer wrap flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+
+ if (handle->TxReclaimEnable[ringId])
+ {
+ /* Add context to frame info ring */
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ txBdRing->txDescUsed++;
+ }
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSend(base, ringId);
+ isReturn = true;
+ break;
+ }
+ /* Increase and get the current buffer descriptor address. */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+
+ } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK));
+
+ if (isReturn == false)
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*!
+ * brief Enable or disable tx descriptors reclaim mechanism.
+ * note This function must be called when no pending send frame action.
+ * Set enable if you want to reclaim context or timestamp in interrupt.
+ *
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param isEnable Enable or disable flag.
+ * param ringId The ring index or ring number.
+ * retval kStatus_Success Succeed to enable/disable Tx reclaim.
+ * retval kStatus_Fail Fail to enable/disable Tx reclaim.
+ */
+status_t ENET_SetTxReclaim(enet_handle_t *handle, bool isEnable, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+
+ status_t result = kStatus_Success;
+
+ /* If tx dirty ring is empty, can set this flag and reset txConsumIdx */
+ if ((txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) && ENET_TxDirtyRingAvailable(txDirtyRing))
+ {
+ if (isEnable)
+ {
+ handle->TxReclaimEnable[ringId] = true;
+ txBdRing->txConsumIdx = txBdRing->txGenIdx;
+ }
+ else
+ {
+ handle->TxReclaimEnable[ringId] = false;
+ }
+ }
+ else
+ {
+ result = kStatus_Fail;
+ }
+ return result;
+}
+
+/*!
+ * brief Reclaim tx descriptors.
+ * This function is used to update the tx descriptor status and
+ * store the tx timestamp when the 1588 feature is enabled.
+ * This is called by the transmit interupt IRQ handler after the
+ * complete of a frame transmission.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param ringId The ring index or ring number.
+ */
+static void ENET_ReclaimTxDescriptor(ENET_Type *base, enet_handle_t *handle, uint8_t ringId)
+{
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ volatile enet_tx_bd_struct_t *curBuffDescrip = txBdRing->txBdBase + txBdRing->txConsumIdx;
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+ enet_frame_info_t *txDirty = NULL;
+
+ /* Need to update the first index for transmit buffer free. */
+ while ((0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) && (txBdRing->txDescUsed > 0U))
+ {
+ if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK) != 0U)
+ {
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txConsumIdx;
+ txDirtyRing->txConsumIdx = ENET_IncreaseIndex(txDirtyRing->txConsumIdx, txDirtyRing->txRingLen);
+ txDirtyRing->isFull = false;
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ if ((curBuffDescrip->controlExtend1 & ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK) != 0U)
+ {
+ enet_ptp_time_t *ts = &txDirty->timeStamp;
+ /* Get transmit time stamp second. */
+ txDirty->isTsAvail = true;
+ ts->second = handle->msTimerSecond;
+ ts->nanosecond = curBuffDescrip->timestamp;
+ }
+#endif
+ }
+
+ /* For tx buffer free or requeue for each descriptor.
+ * The tx interrupt callback should free/requeue the tx buffer. */
+ if (handle->callback != NULL)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, ringId, kENET_TxEvent, txDirty, handle->userData);
+#else
+ handle->callback(base, handle, kENET_TxEvent, txDirty, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+
+ /* Clean the txDirty pointer after used */
+ if (txDirty != NULL)
+ {
+ txDirty = NULL;
+ }
+ txBdRing->txDescUsed--;
+
+ /* Update the index. */
+ txBdRing->txConsumIdx = ENET_IncreaseIndex(txBdRing->txConsumIdx, txBdRing->txRingLen);
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txConsumIdx;
+ }
+}
+
+/*!
+ * brief Get a receive buffer pointer of the ENET device for specified ring.
+ *
+ * This function can get the data address which stores frame. Then can analyze these data directly without doing any
+ * memory copy. When the frame locates in multiple BD buffer, need to repeat calling this function until isLastBuff=true
+ * (need to store the temp buf pointer everytime call this function). After finishing the analysis of this frame,
+ * call ENET_ReleaseRxBuffer to release rxbuff memory to DMA.
+ * This is an example:
+ * code
+ * uint32_t length;
+ * uint8_t *buf = NULL;
+ * uint32_t data_len = 0;
+ * bool isLastBuff = false;
+ * enet_handle_t g_handle;
+ * status_t status;
+ * status = ENET_GetRxFrameSize(&g_handle, &length, 0);
+ * if (length != 0)
+ * {
+ * ENET_GetRxBuffer(EXAMPLE_ENET, &g_handle, &buf, &data_len, 0, &isLastBuff, NULL);
+ * ENET_ReleaseRxBuffer(EXAMPLE_ENET, &g_handle, buf, 0);
+ * }
+ * endcode
+ * param base ENET peripheral base address.
+ * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * param buffer The data buffer pointer to store the frame.
+ * param length The size of the data buffer. If isLastBuff=false, it represents data length of this buffer. If
+ * isLastBuff=true, it represents data length of total frame.
+ * param ringId The ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1.
+ * param isLastBuff The flag represents whether this buffer is the last buffer to store frame.
+ * param ts The 1588 timestamp value, vaild in last buffer.
+ * retval kStatus_Success Get receive buffer succeed.
+ * retval kStatus_ENET_RxFrameFail Get receive buffer fails, it's owned by application, should wait app to release this
+ * buffer.
+ */
+status_t ENET_GetRxBuffer(ENET_Type *base,
+ enet_handle_t *handle,
+ void **buffer,
+ uint32_t *length,
+ uint8_t ringId,
+ bool *isLastBuff,
+ uint32_t *ts)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+ assert(handle->rxBdRing[ringId].rxBdBase != NULL);
+
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ uint32_t address;
+
+ /* Check if current rx BD is under usage by certain application */
+ /* Buffer owner flag, 1: owned by application, 0: owned by driver */
+ if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK) == 0U)
+ {
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK;
+ }
+ else
+ {
+ return kStatus_ENET_RxFrameFail;
+ }
+
+/* A frame on one buffer or several receive buffers are both considered. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+ address = (uint32_t)curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->rxMaintainEnable[ringId])
+ {
+ /* Add the cache invalidate maintain. */
+ DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]);
+ }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+ *buffer = (void *)(uint32_t *)address;
+ *length = curBuffDescrip->length;
+
+ /* The last buffer descriptor of a frame. */
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK))
+ {
+ /* This is a valid frame. */
+ *isLastBuff = true;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ if (ts != NULL)
+ {
+ *ts = curBuffDescrip->timestamp;
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ }
+ else
+ {
+ *isLastBuff = false;
+ }
+
+ /* Increase current buffer descriptor to the next one. */
+ rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Release receive buffer descriptor to DMA.
+ *
+ * This function can release specified BD owned by application, meanwhile it may rearrange the BD to let the no-owned
+ * BDs always in back of the index of DMA transfer. So for the situation that releasing order is not same as the getting
+ * order, the rearrangement makes all ready BDs can be used by DMA.
+ * note This function can't be interrupted by ENET_GetRxBuffer, so in application must make sure ENET_GetRxBuffer is
+ * called before or after this function. And this function itself isn't thread safe due to BD content exchanging.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init.
+ * param buffer The buffer address to store frame, using it to find the correspond BD and release it.
+ * param ringId The ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1.
+ */
+void ENET_ReleaseRxBuffer(ENET_Type *base, enet_handle_t *handle, void *buffer, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId];
+ enet_rx_bd_struct_t *ownBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase;
+ enet_rx_bd_struct_t *blockBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase + rxBdRing->rxGenIdx;
+ enet_rx_bd_struct_t tempBuffDescrip;
+ uint16_t index = rxBdRing->rxGenIdx;
+ bool isReleaseBd = false;
+
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ buffer = (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)buffer, kMEMORY_Local2DMA);
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+
+ do
+ {
+ /* Find the BD for releasing, do nothing if it's not owned by application. */
+ if (buffer == ownBuffDescrip->buffer)
+ {
+ if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK))
+ {
+ isReleaseBd = true;
+ break;
+ }
+ }
+
+ if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ break;
+ }
+ ownBuffDescrip++;
+ } while (true);
+
+ if (isReleaseBd)
+ {
+ /* Find the first BD owned by application after rxBdCurrent, isReleaseBd is true so there's at least one BD is
+ * owned by application */
+ do
+ {
+ if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK))
+ {
+ break;
+ }
+ if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ blockBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase;
+ }
+ else
+ {
+ blockBuffDescrip++;
+ }
+ index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen);
+ } while (index != rxBdRing->rxGenIdx);
+
+ /* If the BD ready for releasing isn't the first BD owned by application after rxBdCurrent then exchange the two
+ * BDs */
+ if (blockBuffDescrip != ownBuffDescrip)
+ {
+ /* Exchange buffer descriptor content */
+ tempBuffDescrip = *ownBuffDescrip;
+ *ownBuffDescrip = *blockBuffDescrip;
+ *blockBuffDescrip = tempBuffDescrip;
+
+ /* Maintain the wrap flag */
+ if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ ownBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_RX_WRAP_MASK);
+ blockBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ }
+ else if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK))
+ {
+ blockBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_RX_WRAP_MASK);
+ ownBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ /* Clears status including the owner flag. */
+ blockBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ blockBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+ }
+ else
+ {
+ /* Clears status including the owner flag. */
+ ownBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
+ /* Sets the receive buffer descriptor with the empty flag. */
+ ownBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK;
+ }
+
+ /* Ensure previous data update is completed with Data Synchronization Barrier before activing Rx BD. */
+ __DSB();
+
+ /* Actives the receive buffer descriptor. */
+ base->RDAR = ENET_RDAR_RDAR_MASK;
+ }
+}
+
+/*!
+ * brief Transmits an ENET frame for specified ring with zero-copy.
+ * note The CRC is automatically appended to the data. Input the data
+ * to send without the CRC. The frame must store in continuous memeory
+ * and need to check the buffer start address alignment based on your
+ * device, otherwise it has issue or can't get highest DMA transmit speed.
+ *
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param data The data buffer provided by user to send.
+ * param length The length of the data to send.
+ * param ringId The ring index or ring number.
+ * param tsFlag Timestamp enable flag.
+ * param context Used by user to handle some events after transmit over.
+ * retval kStatus_Success Send frame succeed.
+ * retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission.
+ * The transmit busy happens when the data send rate is over the MAC capacity.
+ * The waiting mechanism is recommended to be added after each call return with
+ * kStatus_ENET_TxFrameBusy.
+ */
+status_t ENET_SendFrameZeroCopy(ENET_Type *base,
+ enet_handle_t *handle,
+ const uint8_t *data,
+ uint32_t length,
+ uint8_t ringId,
+ bool tsFlag,
+ void *context)
+{
+ assert(handle != NULL);
+ assert(data != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ volatile enet_tx_bd_struct_t *curBuffDescrip;
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+ enet_frame_info_t *txDirty = NULL;
+ uint32_t len = 0;
+ uint32_t sizeleft = 0;
+ status_t result = kStatus_Success;
+ uint8_t *data_temp;
+ uint32_t configVal;
+ bool isReturn = false;
+
+ /* Check the frame length. */
+ if (length > ENET_FRAME_MAX_FRAMELEN)
+ {
+ result = kStatus_ENET_TxFrameOverLen;
+ }
+ else
+ {
+ /* Check if the transmit buffer is ready. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ /* Check txDirtyRing if need frameinfo in tx interrupt callback. */
+ else if (handle->TxReclaimEnable[ringId] && !ENET_TxDirtyRingAvailable(txDirtyRing))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ else
+ {
+ /* One transmit buffer is enough for one frame. */
+ if (handle->txBuffSizeAlign[ringId] >= length)
+ {
+ /* Copy data to the buffer for uDMA transfer. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)data, kMEMORY_Local2DMA);
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ curBuffDescrip->buffer = (uint8_t *)(uint32_t)data;
+ /* Set data length. */
+ curBuffDescrip->length = (uint16_t)length;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if (tsFlag)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+ curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
+
+ /* Increase the buffer descriptor address. */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+ /* Add context to frame info ring */
+ if (handle->TxReclaimEnable[ringId])
+ {
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ txBdRing->txDescUsed++;
+ }
+
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSend(base, ringId);
+ }
+ else
+ {
+ /* One frame requires more than one transmit buffers. */
+ do
+ {
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if (tsFlag)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ /* Update the size left to be transmit. */
+ sizeleft = length - len;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)data, kMEMORY_Local2DMA);
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ data_temp = (uint8_t *)(uint32_t)data + len;
+ if (sizeleft > handle->txBuffSizeAlign[ringId])
+ {
+ /* Data copy. */
+ curBuffDescrip->buffer = data_temp;
+ /* Data length update. */
+ curBuffDescrip->length = handle->txBuffSizeAlign[ringId];
+ len += handle->txBuffSizeAlign[ringId];
+ /* Sets the control flag. */
+ configVal = (uint32_t)curBuffDescrip->control;
+ configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+ configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
+ curBuffDescrip->control = (uint16_t)configVal;
+
+ if (handle->TxReclaimEnable[ringId])
+ {
+ txBdRing->txDescUsed++;
+ }
+ /* Active the transmit buffer descriptor*/
+ ENET_ActiveSend(base, ringId);
+ }
+ else
+ {
+ curBuffDescrip->buffer = data_temp;
+ curBuffDescrip->length = (uint16_t)sizeleft;
+ /* Set Last buffer wrap flag. */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+
+ if (handle->TxReclaimEnable[ringId])
+ {
+ /* Add context to frame info ring */
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ txBdRing->txDescUsed++;
+ }
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSend(base, ringId);
+ isReturn = true;
+ break;
+ }
+ /* Increase and get the current buffer descriptor address. */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+
+ } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK));
+
+ if (isReturn == false)
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*!
+ * brief Set up ENET Tx buffer descriptor, preparing for one frame stores in scattered buffer.
+ * This function only set one Tx BD everytime calls, all ready data will be sent out with last flag sets or
+ * gets error. Send frame succeeds with last flag sets, then you can get context from frameInfo in callback.
+ * note The CRC is automatically appended to the data. Input the data to send without the CRC. And if doesn't
+ * succeed to call this function, user can't get context in frameInfo of callback.
+ *
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param data The data buffer provided by user to send.
+ * param length The length of the data to send.
+ * param ringId The ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1.
+ * param txFlag This function uses timestamp enable flag, last BD flag.
+ * param context Used by user to handle some events after transmit over.
+ * retval kStatus_Success Send frame succeed.
+ * retval kStatus_ENET_TxFrameOverLen Buffer length isn't enough to store data.
+ * retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission.
+ * The transmit busy happens when the data send rate is over the MAC capacity.
+ */
+status_t ENET_SetTxBuffer(ENET_Type *base,
+ enet_handle_t *handle,
+ const uint8_t *data,
+ uint32_t length,
+ uint8_t ringId,
+ uint8_t txFlag,
+ void *context)
+{
+ assert(handle != NULL);
+ assert(data != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+ enet_frame_info_t *txDirty = NULL;
+ volatile enet_tx_bd_struct_t *curBuffDescrip;
+ volatile enet_tx_bd_struct_t *tempBuffDescrip;
+ status_t result = kStatus_Success;
+ uint16_t index;
+
+ /* Check the data length. */
+ if (handle->txBuffSizeAlign[ringId] < length)
+ {
+ result = kStatus_ENET_TxFrameOverLen;
+ }
+ /* Check txDirtyRing if need frameinfo in tx interrupt callback. */
+ else if (handle->TxReclaimEnable[ringId] && !ENET_TxDirtyRingAvailable(txDirtyRing))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ else
+ {
+ /* Check if the transmit buffer is ready or ring with framinfo is full. */
+ curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ }
+ else
+ {
+ /* Prepare data address for uDMA transfer. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+ data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)data, kMEMORY_Local2DMA);
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+ curBuffDescrip->buffer = (uint8_t *)(uint32_t)data;
+
+ /* Set data length. */
+ curBuffDescrip->length = (uint16_t)length;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+ /* For enable the timestamp. */
+ if ((txFlag & ENET_TX_TIMESTAMP_FLAG) != 0U)
+ {
+ curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+ }
+ else
+ {
+ curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+ }
+
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+ if (handle->TxReclaimEnable[ringId])
+ {
+ txBdRing->txDescUsed++;
+ }
+ /* If BD is full or last flag sets, send out all data */
+ if ((txFlag & ENET_TX_LAST_BD_FLAG) != 0U)
+ {
+ /* Set all configurated BDs with own flag ready */
+ tempBuffDescrip = curBuffDescrip;
+ index = txBdRing->txGenIdx;
+ do
+ {
+ if ((tempBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK) != 0U)
+ {
+ tempBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK);
+ tempBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
+ }
+ index = ENET_IncreaseIndex(index, txBdRing->txRingLen);
+ tempBuffDescrip = txBdRing->txBdBase + index;
+ } while (tempBuffDescrip != curBuffDescrip);
+
+ /* Add context to frame info ring */
+ if (handle->TxReclaimEnable[ringId])
+ {
+ txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+ txDirty->context = context;
+ txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+ if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+ {
+ txDirtyRing->isFull = true;
+ }
+ }
+
+ curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
+
+ /* Active the transmit buffer descriptor. */
+ ENET_ActiveSend(base, 0);
+ }
+ else
+ {
+ curBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
+ /* Set owner flag, need to set Tx ready for all BDs with this flag after configurating last BD */
+ curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK;
+ }
+
+ /* Increase the buffer descriptor address. */
+ txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+ }
+ }
+
+ /* If fails to send whole frame success, need to send out all left ready data in BDs, make sure. */
+ if (result != kStatus_Success)
+ {
+ tempBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+ index = txBdRing->txGenIdx;
+ do
+ {
+ if ((tempBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK) != 0U)
+ {
+ tempBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK);
+ tempBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
+ }
+ index = ENET_IncreaseIndex(index, txBdRing->txRingLen);
+ tempBuffDescrip = txBdRing->txBdBase + index;
+ } while (index != txBdRing->txGenIdx);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Adds the ENET device to a multicast group.
+ *
+ * param base ENET peripheral base address.
+ * param address The six-byte multicast group address which is provided by application.
+ */
+void ENET_AddMulticastGroup(ENET_Type *base, uint8_t *address)
+{
+ assert(address != NULL);
+
+ uint32_t crc = 0xFFFFFFFFU;
+ uint32_t count1 = 0;
+ uint32_t count2 = 0;
+ uint32_t configVal = 0;
+
+ /* Calculates the CRC-32 polynomial on the multicast group address. */
+ for (count1 = 0; count1 < ENET_FRAME_MACLEN; count1++)
+ {
+ uint8_t c = address[count1];
+ for (count2 = 0; count2 < 0x08U; count2++)
+ {
+ if (0U != ((c ^ crc) & 1U))
+ {
+ crc >>= 1U;
+ c >>= 1U;
+ crc ^= 0xEDB88320U;
+ }
+ else
+ {
+ crc >>= 1U;
+ c >>= 1U;
+ }
+ }
+ }
+
+ /* Enable a multicast group address. */
+ configVal = 1U;
+ configVal = configVal << ((crc >> 0x1AU) & 0x1FU);
+
+ if (0U == ((crc >> 0x1FU) & 1U))
+ {
+ base->GALR |= configVal;
+ }
+ else
+ {
+ base->GAUR |= configVal;
+ }
+}
+
+/*!
+ * brief Moves the ENET device from a multicast group.
+ *
+ * param base ENET peripheral base address.
+ * param address The six-byte multicast group address which is provided by application.
+ */
+void ENET_LeaveMulticastGroup(ENET_Type *base, uint8_t *address)
+{
+ assert(address != NULL);
+
+ uint32_t crc = 0xFFFFFFFFU;
+ uint32_t count1 = 0;
+ uint32_t count2 = 0;
+ uint32_t configVal = 0;
+
+ /* Calculates the CRC-32 polynomial on the multicast group address. */
+ for (count1 = 0; count1 < ENET_FRAME_MACLEN; count1++)
+ {
+ uint8_t c = address[count1];
+ for (count2 = 0; count2 < 0x08U; count2++)
+ {
+ if (0U != ((c ^ crc) & 1U))
+ {
+ crc >>= 1U;
+ c >>= 1U;
+ crc ^= 0xEDB88320U;
+ }
+ else
+ {
+ crc >>= 1U;
+ c >>= 1U;
+ }
+ }
+ }
+
+ /* Set the hash table. */
+ configVal = 1U;
+ configVal = ~(configVal << ((crc >> 0x1AU) & 0x1FU));
+ if (0U == ((crc >> 0x1FU) & 1U))
+ {
+ base->GALR &= configVal;
+ }
+ else
+ {
+ base->GAUR &= configVal;
+ }
+}
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*!
+ * brief Gets the ENET transmit frame statistics after the data send for specified ring.
+ *
+ * This interface gets the error statistics of the transmit frame.
+ * Because the error information is reported by the uDMA after the data delivery, this interface
+ * should be called after the data transmit API. It is recommended to call this function on
+ * transmit interrupt handler. After calling the ENET_SendFrame, the
+ * transmit interrupt notifies the transmit completion.
+ *
+ * param handle The PTP handler pointer. This is the same handler pointer used in the ENET_Init.
+ * param eErrorStatic The error statistics structure pointer.
+ * param ringId The ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1.
+ * return The execute status.
+ */
+status_t ENET_GetTxErrAfterSendFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId)
+{
+ assert(handle != NULL);
+ assert(eErrorStatic != NULL);
+ assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE);
+
+ uint16_t control = 0;
+ uint16_t controlExt = 0;
+ status_t result = kStatus_Success;
+ bool isReturn = false;
+ enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+ volatile enet_tx_bd_struct_t *curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+
+ do
+ {
+ /* Get the current dirty transmit buffer descriptor. */
+ control = handle->txBdDirtyStatic[ringId]->control;
+ controlExt = handle->txBdDirtyStatic[ringId]->controlExtend0;
+
+ /* Get the control status data, If the buffer descriptor has not been processed break out. */
+ if (0U != (control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+ {
+ result = kStatus_ENET_TxFrameBusy;
+ isReturn = true;
+ break;
+ }
+
+ /* Increase the transmit dirty static pointer. */
+ if (0U != (handle->txBdDirtyStatic[ringId]->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK))
+ {
+ handle->txBdDirtyStatic[ringId] = txBdRing->txBdBase;
+ }
+ else
+ {
+ handle->txBdDirtyStatic[ringId]++;
+ }
+
+ /* If the transmit buffer descriptor is ready and the last buffer descriptor, store packet statistic. */
+ if (0U != (control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK))
+ {
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_ERR_MASK))
+ {
+ /* Transmit error. */
+ eErrorStatic->statsTxErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_EXCCOLLISIONERR_MASK))
+ {
+ /* Transmit excess collision error. */
+ eErrorStatic->statsTxExcessCollisionErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_LATECOLLISIONERR_MASK))
+ {
+ /* Transmit late collision error. */
+ eErrorStatic->statsTxLateCollisionErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_UNDERFLOWERR_MASK))
+ {
+ /* Transmit under flow error. */
+ eErrorStatic->statsTxUnderFlowErr++;
+ }
+ if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_OVERFLOWERR_MASK))
+ {
+ /* Transmit over flow error. */
+ eErrorStatic->statsTxOverFlowErr++;
+ }
+ isReturn = true;
+ break;
+ }
+
+ } while (handle->txBdDirtyStatic[ringId] != curBuffDescrip);
+
+ if (isReturn == false)
+ {
+ result = kStatus_ENET_TxFrameFail;
+ }
+ return result;
+}
+
+void ENET_Ptp1588ConfigureHandler(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig)
+{
+ assert(handle != NULL);
+ assert(ptpConfig != NULL);
+ uint8_t count;
+
+ uint32_t mask = (uint32_t)kENET_TxBufferInterrupt;
+#if FSL_FEATURE_ENET_QUEUE > 1
+ mask |= (uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxBuffer2Interrupt;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+ for (count = 0; count < handle->ringNum; count++)
+ {
+ handle->txBdDirtyStatic[count] = handle->txBdRing[count].txBdBase;
+ }
+
+ /* Setting the receive and transmit state for transaction. */
+ handle->msTimerSecond = 0;
+
+ /* Enables the time stamp interrupt and transmit frame interrupt to
+ * handle the time-stamp . */
+ ENET_EnableInterrupts(base, (ENET_TS_INTERRUPT | ENET_TX_INTERRUPT));
+ ENET_DisableInterrupts(base, mask);
+
+ /* Set the IRQ handler when the interrupt is enabled. */
+ ENET_SetTsISRHandler(base, ENET_TimeStampIRQHandler);
+ ENET_SetTxISRHandler(base, ENET_TransmitIRQHandler);
+}
+
+/*!
+ * brief Configures the ENET PTP IEEE 1588 feature with the basic configuration.
+ * The function sets the clock for PTP 1588 timer and enables
+ * time stamp interrupts and transmit interrupts for PTP 1588 features.
+ * This API should be called when the 1588 feature is enabled
+ * or the ENET_ENHANCEDBUFFERDESCRIPTOR_MODE is defined.
+ * ENET_Init should be called before calling this API.
+ *
+ * note The PTP 1588 time-stamp second increase though time-stamp interrupt handler
+ * and the transmit time-stamp store is done through transmit interrupt handler.
+ * As a result, the TS interrupt and TX interrupt are enabled when you call this API.
+ *
+ * param base ENET peripheral base address.
+ * param handle ENET handler pointer.
+ * param ptpConfig The ENET PTP1588 configuration.
+ */
+void ENET_Ptp1588Configure(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig)
+{
+ assert(handle != NULL);
+ assert(ptpConfig != NULL);
+
+ /* Start the 1588 timer. */
+ ENET_Ptp1588StartTimer(base, ptpConfig->ptp1588ClockSrc_Hz);
+
+ ENET_Ptp1588ConfigureHandler(base, handle, ptpConfig);
+}
+
+/*!
+ * brief Starts the ENET PTP 1588 Timer.
+ * This function is used to initialize the PTP timer. After the PTP starts,
+ * the PTP timer starts running.
+ *
+ * param base ENET peripheral base address.
+ * param ptpClkSrc The clock source of the PTP timer.
+ */
+void ENET_Ptp1588StartTimer(ENET_Type *base, uint32_t ptpClkSrc)
+{
+ /* Restart PTP 1588 timer, master clock. */
+ base->ATCR = ENET_ATCR_RESTART_MASK;
+
+ /* Initializes PTP 1588 timer. */
+ base->ATINC = ENET_ATINC_INC(ENET_NANOSECOND_ONE_SECOND / ptpClkSrc);
+ base->ATPER = ENET_NANOSECOND_ONE_SECOND;
+ /* Sets periodical event and the event signal output assertion and Actives PTP 1588 timer. */
+ base->ATCR = ENET_ATCR_PEREN_MASK | ENET_ATCR_PINPER_MASK | ENET_ATCR_EN_MASK;
+}
+
+/*!
+ * brief Gets the current ENET time from the PTP 1588 timer.
+ * Interrupts are not disabled.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * param ptpTime The PTP timer structure.
+ */
+void ENET_Ptp1588GetTimerNoIrqDisable(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime)
+{
+ uint16_t count = ENET_1588TIME_DELAY_COUNT;
+
+ /* Get the current PTP time. */
+ ptpTime->second = handle->msTimerSecond;
+ /* Get the nanosecond from the master timer. */
+ base->ATCR |= ENET_ATCR_CAPTURE_MASK;
+ /* Add at least six clock cycle delay to get accurate time.
+ It's the requirement when the 1588 clock source is slower
+ than the register clock.
+ */
+ while (0U != (count--))
+ {
+ __NOP();
+ }
+ /* Get the captured time. */
+ ptpTime->nanosecond = base->ATVR;
+}
+
+/*!
+ * brief Gets the current ENET time from the PTP 1588 timer.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * param ptpTime The PTP timer structure.
+ */
+void ENET_Ptp1588GetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime)
+{
+ assert(handle != NULL);
+ assert(ptpTime != NULL);
+ uint32_t primask;
+
+ /* Disables the interrupt. */
+ primask = DisableGlobalIRQ();
+
+ ENET_Ptp1588GetTimerNoIrqDisable(base, handle, ptpTime);
+
+ /* Get PTP timer wrap event. */
+ if (0U != (base->EIR & (uint32_t)kENET_TsTimerInterrupt))
+ {
+ ptpTime->second++;
+ }
+
+ /* Enables the interrupt. */
+ EnableGlobalIRQ(primask);
+}
+
+/*!
+ * brief Sets the ENET PTP 1588 timer to the assigned time.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ * param ptpTime The timer to be set to the PTP timer.
+ */
+void ENET_Ptp1588SetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime)
+{
+ assert(handle != NULL);
+ assert(ptpTime != NULL);
+
+ uint32_t primask;
+
+ /* Disables the interrupt. */
+ primask = DisableGlobalIRQ();
+
+ /* Sets PTP timer. */
+ handle->msTimerSecond = ptpTime->second;
+ base->ATVR = ptpTime->nanosecond;
+
+ /* Enables the interrupt. */
+ EnableGlobalIRQ(primask);
+}
+
+/*!
+ * brief Adjusts the ENET PTP 1588 timer.
+ *
+ * param base ENET peripheral base address.
+ * param corrIncrease The correction increment value. This value is added every time the correction
+ * timer expires. A value less than the PTP timer frequency(1/ptpClkSrc) slows down the timer,
+ * a value greater than the 1/ptpClkSrc speeds up the timer.
+ * param corrPeriod The PTP timer correction counter wrap-around value. This defines after how
+ * many timer clock the correction counter should be reset and trigger a correction
+ * increment on the timer. A value of 0 disables the correction counter and no correction occurs.
+ */
+void ENET_Ptp1588AdjustTimer(ENET_Type *base, uint32_t corrIncrease, uint32_t corrPeriod)
+{
+ /* Set correction for PTP timer increment. */
+ base->ATINC = (base->ATINC & ~ENET_ATINC_INC_CORR_MASK) | (corrIncrease << ENET_ATINC_INC_CORR_SHIFT);
+ /* Set correction for PTP timer period. */
+ base->ATCOR = (base->ATCOR & ~ENET_ATCOR_COR_MASK) | (corrPeriod << ENET_ATCOR_COR_SHIFT);
+}
+
+#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB
+/*!
+ * brief Sets the ENET AVB feature.
+ *
+ * ENET AVB feature configuration, set the Receive classification match and transmit
+ * bandwidth. This API is called when the AVB feature is required.
+ *
+ * Note: The AVB frames transmission scheme is credit-based tx scheme and it's only supported
+ * with the Enhanced buffer descriptors. so the AVB configuration should only done with
+ * Enhanced buffer descriptor. so when the AVB feature is required, please make sure the
+ * the "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" is defined.
+ *
+ * param base ENET peripheral base address.
+ * param handle ENET handler pointer.
+ * param config The ENET AVB feature configuration structure.
+ */
+void ENET_AVBConfigure(ENET_Type *base, enet_handle_t *handle, const enet_avb_config_t *config)
+{
+ assert(config != NULL);
+
+ uint8_t count = 0;
+
+ for (count = 0; count < (uint8_t)FSL_FEATURE_ENET_QUEUE - 1U; count++)
+ {
+ /* Set the AVB receive ring classification match when the match is not 0. */
+ if (0U != (config->rxClassifyMatch[count]))
+ {
+ base->RCMR[count] = ((uint32_t)config->rxClassifyMatch[count] & 0xFFFFU) | ENET_RCMR_MATCHEN_MASK;
+ }
+ /* Set the dma controller for the extended ring. */
+ base->DMACFG[count] |= ENET_DMACFG_IDLE_SLOPE(config->idleSlope[count]);
+ }
+
+ /* Shall use the credit-based scheme for avb. */
+ base->QOS &= ~ENET_QOS_TX_SCHEME_MASK;
+ base->QOS |= ENET_QOS_RX_FLUSH0_MASK;
+}
+#endif /* FSL_FETAURE_ENET_HAS_AVB */
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+/*!
+ * brief The transmit IRQ handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId)
+#else
+/*!
+ * brief The transmit IRQ handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle)
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+{
+ assert(handle != NULL);
+ uint32_t mask = (uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt;
+ uint32_t index = 0;
+ uint32_t irq;
+
+/* Check if the transmit interrupt happen. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+ switch (ringId)
+ {
+ case kENET_Ring1:
+ mask = ((uint32_t)kENET_TxFrame1Interrupt | (uint32_t)kENET_TxBuffer1Interrupt);
+ break;
+ case kENET_Ring2:
+ mask = ((uint32_t)kENET_TxFrame2Interrupt | (uint32_t)kENET_TxBuffer2Interrupt);
+ break;
+ default:
+ mask = (uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt;
+ break;
+ }
+ index = ringId;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+ while (0U != (mask & base->EIR))
+ {
+ irq = base->EIR;
+
+ /* Clear the transmit interrupt event. */
+ base->EIR = mask;
+
+ /* Callback Handler. */
+ if (handle->TxReclaimEnable[index] && (0U != (irq & (uint32_t)kENET_TxFrameInterrupt)))
+ {
+ ENET_ReclaimTxDescriptor(base, handle, (uint8_t)index);
+ }
+ else
+ {
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, index, kENET_TxEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_TxEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+ }
+}
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+/*!
+ * brief The receive IRQ handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId)
+#else
+/*!
+ * brief The receive IRQ handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle)
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+{
+ assert(handle != NULL);
+ uint32_t mask = (uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt;
+
+/* Check if the receive interrupt happen. */
+#if FSL_FEATURE_ENET_QUEUE > 1
+ switch (ringId)
+ {
+ case kENET_Ring1:
+ mask = ((uint32_t)kENET_RxFrame1Interrupt | (uint32_t)kENET_RxBuffer1Interrupt);
+ break;
+ case kENET_Ring2:
+ mask = ((uint32_t)kENET_RxFrame2Interrupt | (uint32_t)kENET_RxBuffer2Interrupt);
+ break;
+ default:
+ mask = (uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt;
+ break;
+ }
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+ while (0U != (mask & base->EIR))
+ {
+ /* Clear the transmit interrupt event. */
+ base->EIR = mask;
+
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, ringId, kENET_RxEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_RxEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+}
+
+/*!
+ * brief Some special IRQ handler including the error, mii, wakeup irq handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET handler pointer.
+ */
+void ENET_ErrorIRQHandler(ENET_Type *base, enet_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t errMask = (uint32_t)kENET_BabrInterrupt | (uint32_t)kENET_BabtInterrupt | (uint32_t)kENET_EBusERInterrupt |
+ (uint32_t)kENET_PayloadRxInterrupt | (uint32_t)kENET_LateCollisionInterrupt |
+ (uint32_t)kENET_RetryLimitInterrupt | (uint32_t)kENET_UnderrunInterrupt;
+
+ /* Check if the error interrupt happen. */
+ if (0U != ((uint32_t)kENET_WakeupInterrupt & base->EIR))
+ {
+ /* Clear the wakeup interrupt. */
+ base->EIR = (uint32_t)kENET_WakeupInterrupt;
+ /* wake up and enter the normal mode. */
+ ENET_EnableSleepMode(base, false);
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, 0, kENET_WakeUpEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_WakeUpEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+ else
+ {
+ /* Clear the error interrupt event status. */
+ errMask &= base->EIR;
+ base->EIR = errMask;
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, 0, kENET_ErrEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_ErrEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+/*!
+ * brief The IEEE 1588 PTP time stamp interrupt handler.
+ *
+ * param base ENET peripheral base address.
+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
+ */
+void ENET_TimeStampIRQHandler(ENET_Type *base, enet_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Check if the PTP time stamp interrupt happen. */
+ if (0U != ((uint32_t)kENET_TsTimerInterrupt & base->EIR))
+ {
+ /* Clear the time stamp interrupt. */
+ base->EIR = (uint32_t)kENET_TsTimerInterrupt;
+
+ /* Increase timer second counter. */
+ handle->msTimerSecond++;
+
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, 0, kENET_TimeStampEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_TimeStampEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+
+ if (0U != ((uint32_t)kENET_TsAvailInterrupt & base->EIR))
+ {
+ /* Clear the time stamp interrupt. */
+ base->EIR = (uint32_t)kENET_TsAvailInterrupt;
+ /* Callback function. */
+ if (NULL != handle->callback)
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ handle->callback(base, handle, 0, kENET_TimeStampAvailEvent, NULL, handle->userData);
+#else
+ handle->callback(base, handle, kENET_TimeStampAvailEvent, NULL, handle->userData);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+/*!
+ * brief the common IRQ handler for the tx/rx/error etc irq handler.
+ *
+ * This is used for the combined tx/rx/error interrupt for single/mutli-ring (frame 0).
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_CommonFrame0IRQHandler(ENET_Type *base)
+{
+ uint32_t event = base->EIR;
+ uint32_t instance = ENET_GetInstance(base);
+
+ if (0U != (event & ((uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt)))
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ s_enetTxIsr[instance](base, s_ENETHandle[instance], 0);
+#else
+ s_enetTxIsr[instance](base, s_ENETHandle[instance]);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+
+ if (0U != (event & ((uint32_t)kENET_RxBufferInterrupt | (uint32_t)kENET_RxFrameInterrupt)))
+ {
+#if FSL_FEATURE_ENET_QUEUE > 1
+ s_enetRxIsr[instance](base, s_ENETHandle[instance], 0);
+#else
+ s_enetRxIsr[instance](base, s_ENETHandle[instance]);
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+ }
+
+ if (0U != (event & ENET_TS_INTERRUPT) && (NULL != s_enetTsIsr[instance]))
+ {
+ s_enetTsIsr[instance](base, s_ENETHandle[instance]);
+ }
+ if (0U != (event & ENET_ERR_INTERRUPT) && (NULL != s_enetErrIsr[instance]))
+ {
+ s_enetErrIsr[instance](base, s_ENETHandle[instance]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#if FSL_FEATURE_ENET_QUEUE > 1
+/*!
+ * brief the common IRQ handler for the tx/rx irq handler.
+ *
+ * This is used for the combined tx/rx interrupt for multi-ring (frame 1).
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_CommonFrame1IRQHandler(ENET_Type *base)
+{
+ uint32_t event = base->EIR;
+ uint32_t instance = ENET_GetInstance(base);
+
+ if (0U != (event & ((uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxFrame1Interrupt)))
+ {
+ s_enetTxIsr[instance](base, s_ENETHandle[instance], 1);
+ }
+
+ if (0U != (event & ((uint32_t)kENET_RxBuffer1Interrupt | (uint32_t)kENET_RxFrame1Interrupt)))
+ {
+ s_enetRxIsr[instance](base, s_ENETHandle[instance], 1);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+/*!
+ * brief the common IRQ handler for the tx/rx irq handler.
+ *
+ * This is used for the combined tx/rx interrupt for multi-ring (frame 2).
+ *
+ * param base ENET peripheral base address.
+ */
+void ENET_CommonFrame2IRQHandler(ENET_Type *base)
+{
+ uint32_t event = base->EIR;
+ uint32_t instance = ENET_GetInstance(base);
+
+ if (0U != (event & ((uint32_t)kENET_TxBuffer2Interrupt | (uint32_t)kENET_TxFrame2Interrupt)))
+ {
+ s_enetTxIsr[instance](base, s_ENETHandle[instance], 2);
+ }
+
+ if (0U != (event & ((uint32_t)kENET_RxBuffer2Interrupt | (uint32_t)kENET_RxFrame2Interrupt)))
+ {
+ s_enetRxIsr[instance](base, s_ENETHandle[instance], 2);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+
+#if defined(ENET)
+void ENET_Transmit_IRQHandler(void)
+{
+ s_enetTxIsr[0](ENET, s_ENETHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET_Receive_IRQHandler(void)
+{
+ s_enetRxIsr[0](ENET, s_ENETHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET_Error_IRQHandler(void)
+{
+ s_enetErrIsr[0](ENET, s_ENETHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET_1588_Timer_IRQHandler(void)
+{
+ s_enetTsIsr[0](ENET, s_ENETHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void ENET_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(ENET);
+ SDK_ISR_EXIT_BARRIER;
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#endif
+
+#if defined(ENET1)
+void ENET1_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ENET2)
+void ENET2_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(ENET2);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CONNECTIVITY__ENET0)
+void CONNECTIVITY_ENET0_FRAME0_EVENT_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(CONNECTIVITY__ENET0);
+ SDK_ISR_EXIT_BARRIER;
+}
+#if FSL_FEATURE_ENET_QUEUE > 1
+void CONNECTIVITY_ENET0_FRAME1_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET0);
+ SDK_ISR_EXIT_BARRIER;
+}
+void CONNECTIVITY_ENET0_FRAME2_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET0);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#if defined(CONNECTIVITY__ENET1)
+void CONNECTIVITY_ENET1_FRAME0_EVENT_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(CONNECTIVITY__ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+#if FSL_FEATURE_ENET_QUEUE > 1
+void CONNECTIVITY_ENET1_FRAME1_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+void CONNECTIVITY_ENET1_FRAME2_INT_DriverIRQHandler(void)
+{
+ ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET1);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#if FSL_FEATURE_ENET_QUEUE > 1
+#if defined(ENET_1G)
+void ENET_1G_DriverIRQHandler(void)
+{
+ ENET_CommonFrame0IRQHandler(ENET_1G);
+/* Added for ARM errata 838869: storing immediate overlapping exception return operation
+ * might vector to incorrect interrupt, this affects Cortex-M4, Cortex-M4F. */
+#if defined __CORTEX_M && (__CORTEX_M == 4U)
+ __DSB();
+#endif
+}
+void ENET_MAC0_Tx_Rx_Done_0_DriverIRQHandler(void)
+{
+ ENET_CommonFrame1IRQHandler(ENET_1G);
+/* Added for ARM errata 838869: storing immediate overlapping exception return operation
+ * might vector to incorrect interrupt, this affects Cortex-M4, Cortex-M4F. */
+#if defined __CORTEX_M && (__CORTEX_M == 4U)
+ __DSB();
+#endif
+}
+void ENET_MAC0_Tx_Rx_Done_1_DriverIRQHandler(void)
+{
+ ENET_CommonFrame2IRQHandler(ENET_1G);
+/* Added for ARM errata 838869: storing immediate overlapping exception return operation
+ * might vector to incorrect interrupt, this affects Cortex-M4, Cortex-M4F. */
+#if defined __CORTEX_M && (__CORTEX_M == 4U)
+ __DSB();
+#endif
+}
+void ENET_1G_1588_Timer_DriverIRQHandler(void)
+{
+ s_enet1588TimerIsr(ENET_1G, s_ENETHandle[1]);
+/* Added for ARM errata 838869: storing immediate overlapping exception return operation
+ * might vector to incorrect interrupt, this affects Cortex-M4, Cortex-M4F. */
+#if defined __CORTEX_M && (__CORTEX_M == 4U)
+ __DSB();
+#endif
+}
+#endif
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ewm.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ewm.c
new file mode 100644
index 0000000000..593cf87a50
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ewm.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017, 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_ewm.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.ewm"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Initializes the EWM peripheral.
+ *
+ * This function is used to initialize the EWM. After calling, the EWM
+ * runs immediately according to the configuration.
+ * Note that, except for the interrupt enable control bit, other control bits and registers are write once after a
+ * CPU reset. Modifying them more than once generates a bus transfer error.
+ *
+ * This is an example.
+ * code
+ * ewm_config_t config;
+ * EWM_GetDefaultConfig(&config);
+ * config.compareHighValue = 0xAAU;
+ * EWM_Init(ewm_base,&config);
+ * endcode
+ *
+ * param base EWM peripheral base address
+ * param config The configuration of the EWM
+ */
+void EWM_Init(EWM_Type *base, const ewm_config_t *config)
+{
+ assert(NULL != config);
+
+ uint8_t value = 0U;
+
+#if !((defined(FSL_FEATURE_SOC_PCC_COUNT) && FSL_FEATURE_SOC_PCC_COUNT) && \
+ (defined(FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE) && FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE))
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(kCLOCK_Ewm0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+#endif
+ value = EWM_CTRL_EWMEN(config->enableEwm) | EWM_CTRL_ASSIN(config->setInputAssertLogic) |
+ EWM_CTRL_INEN(config->enableEwmInput) | EWM_CTRL_INTEN(config->enableInterrupt);
+#if defined(FSL_FEATURE_EWM_HAS_PRESCALER) && FSL_FEATURE_EWM_HAS_PRESCALER
+ base->CLKPRESCALER = config->prescaler;
+#endif /* FSL_FEATURE_EWM_HAS_PRESCALER */
+
+#if defined(FSL_FEATURE_EWM_HAS_CLOCK_SELECT) && FSL_FEATURE_EWM_HAS_CLOCK_SELECT
+ base->CLKCTRL = (uint8_t)config->clockSource;
+#endif /* FSL_FEATURE_EWM_HAS_CLOCK_SELECT*/
+
+ base->CMPL = config->compareLowValue;
+ base->CMPH = config->compareHighValue;
+ base->CTRL = value;
+}
+
+/*!
+ * brief Deinitializes the EWM peripheral.
+ *
+ * This function is used to shut down the EWM.
+ *
+ * param base EWM peripheral base address
+ */
+void EWM_Deinit(EWM_Type *base)
+{
+ EWM_DisableInterrupts(base, (uint32_t)kEWM_InterruptEnable);
+#if !((defined(FSL_FEATURE_SOC_PCC_COUNT) && FSL_FEATURE_SOC_PCC_COUNT) && \
+ (defined(FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE) && FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE))
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(kCLOCK_Ewm0);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+#endif /* FSL_FEATURE_PCC_SUPPORT_EWM_CLOCK_REMOVE */
+}
+
+/*!
+ * brief Initializes the EWM configuration structure.
+ *
+ * This function initializes the EWM configuration structure to default values. The default
+ * values are as follows.
+ * code
+ * ewmConfig->enableEwm = true;
+ * ewmConfig->enableEwmInput = false;
+ * ewmConfig->setInputAssertLogic = false;
+ * ewmConfig->enableInterrupt = false;
+ * ewmConfig->ewm_lpo_clock_source_t = kEWM_LpoClockSource0;
+ * ewmConfig->prescaler = 0;
+ * ewmConfig->compareLowValue = 0;
+ * ewmConfig->compareHighValue = 0xFEU;
+ * endcode
+ *
+ * param config Pointer to the EWM configuration structure.
+ * see ewm_config_t
+ */
+void EWM_GetDefaultConfig(ewm_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableEwm = true;
+ config->enableEwmInput = false;
+ config->setInputAssertLogic = false;
+ config->enableInterrupt = false;
+#if defined(FSL_FEATURE_EWM_HAS_CLOCK_SELECT) && FSL_FEATURE_EWM_HAS_CLOCK_SELECT
+ config->clockSource = kEWM_LpoClockSource0;
+#endif /* FSL_FEATURE_EWM_HAS_CLOCK_SELECT*/
+#if defined(FSL_FEATURE_EWM_HAS_PRESCALER) && FSL_FEATURE_EWM_HAS_PRESCALER
+ config->prescaler = 0U;
+#endif /* FSL_FEATURE_EWM_HAS_PRESCALER */
+ config->compareLowValue = 0U;
+ config->compareHighValue = 0xFEU;
+}
+
+/*!
+ * brief Services the EWM.
+ *
+ * This function resets the EWM counter to zero.
+ *
+ * param base EWM peripheral base address
+ */
+void EWM_Refresh(EWM_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupt to protect refresh sequence */
+ primaskValue = DisableGlobalIRQ();
+ base->SERV = (uint8_t)0xB4U;
+ base->SERV = (uint8_t)0x2CU;
+ EnableGlobalIRQ(primaskValue);
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexcan.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexcan.c
new file mode 100644
index 0000000000..682dae7492
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexcan.c
@@ -0,0 +1,3564 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexcan.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexcan"
+#endif
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032)
+#define RXINTERMISSION (CAN_DBG1_CFSM(0x2f))
+#define TXINTERMISSION (CAN_DBG1_CFSM(0x14))
+#define BUSIDLE (CAN_DBG1_CFSM(0x02))
+#define CBN_VALUE3 (CAN_DBG1_CBN(0x03))
+#define DELAY_BUSIDLE (200)
+#endif
+
+#define IDEAL_SP_LOW (750U)
+#define IDEAL_SP_MID (800U)
+#define IDEAL_SP_HIGH (875U)
+#define IDEAL_SP_FACTOR (1000U)
+
+#define MAX_PROPSEG (CAN_CTRL1_PROPSEG_MASK >> CAN_CTRL1_PROPSEG_SHIFT)
+#define MAX_PSEG1 (CAN_CTRL1_PSEG1_MASK >> CAN_CTRL1_PSEG1_SHIFT)
+#define MAX_PSEG2 (CAN_CTRL1_PSEG2_MASK >> CAN_CTRL1_PSEG2_SHIFT)
+#define MAX_RJW (CAN_CTRL1_RJW_MASK >> CAN_CTRL1_RJW_SHIFT)
+#define MAX_PRESDIV (CAN_CTRL1_PRESDIV_MASK >> CAN_CTRL1_PRESDIV_SHIFT)
+#define CTRL1_MAX_TIME_QUANTA (1U + MAX_PROPSEG + 1U + MAX_PSEG1 + 1U + MAX_PSEG2 + 1U)
+#define CTRL1_MIN_TIME_QUANTA (8U)
+
+#define MAX_EPROPSEG (CAN_CBT_EPROPSEG_MASK >> CAN_CBT_EPROPSEG_SHIFT)
+#define MAX_EPSEG1 (CAN_CBT_EPSEG1_MASK >> CAN_CBT_EPSEG1_SHIFT)
+#define MAX_EPSEG2 (CAN_CBT_EPSEG2_MASK >> CAN_CBT_EPSEG2_SHIFT)
+#define MAX_ERJW (CAN_CBT_ERJW_MASK >> CAN_CBT_ERJW_SHIFT)
+#define MAX_EPRESDIV (CAN_CBT_EPRESDIV_MASK >> CAN_CBT_EPRESDIV_SHIFT)
+#define CBT_MAX_TIME_QUANTA (1U + MAX_EPROPSEG + 1U + MAX_EPSEG1 + 1U + MAX_EPSEG2 + 1U)
+#define CBT_MIN_TIME_QUANTA (8U)
+
+#define MAX_FPROPSEG (CAN_FDCBT_FPROPSEG_MASK >> CAN_FDCBT_FPROPSEG_SHIFT)
+#define MAX_FPSEG1 (CAN_FDCBT_FPSEG1_MASK >> CAN_FDCBT_FPSEG1_SHIFT)
+#define MAX_FPSEG2 (CAN_FDCBT_FPSEG2_MASK >> CAN_FDCBT_FPSEG2_SHIFT)
+#define MAX_FRJW (CAN_FDCBT_FRJW_MASK >> CAN_FDCBT_FRJW_SHIFT)
+#define MAX_FPRESDIV (CAN_FDCBT_FPRESDIV_MASK >> CAN_FDCBT_FPRESDIV_SHIFT)
+#define FDCBT_MAX_TIME_QUANTA (1U + MAX_FPROPSEG + 0U + MAX_FPSEG1 + 1U + MAX_FPSEG2 + 1U)
+#define FDCBT_MIN_TIME_QUANTA (5U)
+
+#define MAX_CANFD_BAUDRATE (8000000U)
+#define MAX_CAN_BAUDRATE (1000000U)
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595)
+#define CAN_ESR1_FLTCONF_BUSOFF CAN_ESR1_FLTCONF(2U)
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#ifndef CAN_CLOCK_CHECK_NO_AFFECTS
+/* If no define such MACRO, it mean that the CAN in current device have no clock affect issue. */
+#define CAN_CLOCK_CHECK_NO_AFFECTS (true)
+#endif /* CAN_CLOCK_CHECK_NO_AFFECTS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief FlexCAN Internal State. */
+enum _flexcan_state
+{
+ kFLEXCAN_StateIdle = 0x0, /*!< MB/RxFIFO idle.*/
+ kFLEXCAN_StateRxData = 0x1, /*!< MB receiving.*/
+ kFLEXCAN_StateRxRemote = 0x2, /*!< MB receiving remote reply.*/
+ kFLEXCAN_StateTxData = 0x3, /*!< MB transmitting.*/
+ kFLEXCAN_StateTxRemote = 0x4, /*!< MB transmitting remote request.*/
+ kFLEXCAN_StateRxFifo = 0x5, /*!< RxFIFO receiving.*/
+};
+
+/*! @brief FlexCAN message buffer CODE for Rx buffers. */
+enum _flexcan_mb_code_rx
+{
+ kFLEXCAN_RxMbInactive = 0x0, /*!< MB is not active.*/
+ kFLEXCAN_RxMbFull = 0x2, /*!< MB is full.*/
+ kFLEXCAN_RxMbEmpty = 0x4, /*!< MB is active and empty.*/
+ kFLEXCAN_RxMbOverrun = 0x6, /*!< MB is overwritten into a full buffer.*/
+ kFLEXCAN_RxMbBusy = 0x8, /*!< FlexCAN is updating the contents of the MB.*/
+ /*! The CPU must not access the MB.*/
+ kFLEXCAN_RxMbRanswer = 0xA, /*!< A frame was configured to recognize a Remote Request Frame */
+ /*! and transmit a Response Frame in return.*/
+ kFLEXCAN_RxMbNotUsed = 0xF, /*!< Not used.*/
+};
+
+/*! @brief FlexCAN message buffer CODE FOR Tx buffers. */
+enum _flexcan_mb_code_tx
+{
+ kFLEXCAN_TxMbInactive = 0x8, /*!< MB is not active.*/
+ kFLEXCAN_TxMbAbort = 0x9, /*!< MB is aborted.*/
+ kFLEXCAN_TxMbDataOrRemote = 0xC, /*!< MB is a TX Data Frame(when MB RTR = 0) or */
+ /*!< MB is a TX Remote Request Frame (when MB RTR = 1).*/
+ kFLEXCAN_TxMbTanswer = 0xE, /*!< MB is a TX Response Request Frame from */
+ /*! an incoming Remote Request Frame.*/
+ kFLEXCAN_TxMbNotUsed = 0xF, /*!< Not used.*/
+};
+
+/* Typedef for interrupt handler. */
+typedef void (*flexcan_isr_t)(CAN_Type *base, flexcan_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+#if !defined(NDEBUG)
+/*!
+ * @brief Check if Message Buffer is occupied by Rx FIFO.
+ *
+ * This function check if Message Buffer is occupied by Rx FIFO.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ */
+static bool FLEXCAN_IsMbOccupied(CAN_Type *base, uint8_t mbIdx);
+#endif
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+/*!
+ * @brief Get the first valid Message buffer ID of give FlexCAN instance.
+ *
+ * This function is a helper function for Errata 5641 workaround.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return The first valid Message Buffer Number.
+ */
+static uint8_t FLEXCAN_GetFirstValidMb(CAN_Type *base);
+#endif
+
+/*!
+ * @brief Check if Message Buffer interrupt is enabled.
+ *
+ * This function check if Message Buffer interrupt is enabled.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx The FlexCAN Message Buffer index.
+ * @return TRUE if the index MB interrupt mask enabled, FALSE if the index MB interrupt mask disabled.
+ *
+ */
+static bool FLEXCAN_IsMbIntEnabled(CAN_Type *base, uint8_t mbIdx);
+
+/*!
+ * @brief Reset the FlexCAN Instance.
+ *
+ * Restores the FlexCAN module to reset state, notice that this function
+ * will set all the registers to reset state so the FlexCAN module can not work
+ * after calling this API.
+ *
+ * @param base FlexCAN peripheral base address.
+ */
+static void FLEXCAN_Reset(CAN_Type *base);
+
+/*!
+ * @brief Set Baud Rate of FlexCAN.
+ *
+ * This function set the baud rate of FlexCAN.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param sourceClock_Hz Source Clock in Hz.
+ * @param baudRate_Bps Baud Rate in Bps.
+ * @param timingConfig FlexCAN timingConfig.
+ */
+static void FLEXCAN_SetBaudRate(CAN_Type *base,
+ uint32_t sourceClock_Hz,
+ uint32_t baudRate_Bps,
+ flexcan_timing_config_t timingConfig);
+/*!
+ * @brief Calculates the segment values for a single bit time for classical CAN
+ *
+ * @param baudRate The data speed in bps
+ * @param tqNum Number of time quantas per bit
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if Calculates the segment success, FALSE if Calculates the segment success
+ */
+static bool FLEXCAN_GetSegments(uint32_t baudRate, uint32_t tqNum, flexcan_timing_config_t *pTimingConfig);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * @brief Set Baud Rate of FlexCAN FD frame.
+ *
+ * This function set the baud rate of FlexCAN FD frame.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param sourceClock_Hz Source Clock in Hz.
+ * @param baudRateFD_Bps FD frame Baud Rate in Bps.
+ * @param timingConfig FlexCAN timingConfig.
+ */
+static void FLEXCAN_SetFDBaudRate(CAN_Type *base,
+ uint32_t sourceClock_Hz,
+ uint32_t baudRateFD_Bps,
+ flexcan_timing_config_t timingConfig);
+
+/*!
+ * @brief Get Mailbox offset number by dword.
+ *
+ * This function gets the offset number of the specified mailbox.
+ * Mailbox is not consecutive between memory regions when payload is not 8 bytes
+ * so need to calculate the specified mailbox address.
+ * For example, in the first memory region, MB[0].CS address is 0x4002_4080. For 32 bytes
+ * payload frame, the second mailbox is ((1/12)*512 + 1%12*40)/4 = 10, meaning 10 dword
+ * after the 0x4002_4080, which is actually the address of mailbox MB[1].CS.
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param mbIdx Mailbox index.
+ */
+static uint32_t FLEXCAN_GetFDMailboxOffset(CAN_Type *base, uint8_t mbIdx);
+
+/*!
+ * @brief Calculates the segment values for a single bit time for CANFD bus control baud Rate
+ *
+ * @param baudRate The canfd bus control speed in bps
+ * @param tqNum Number of time quanta per bit
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if Calculates the segment success, FALSE if Calculates the segment success
+ */
+static bool FLEXCAN_FDGetSegments(uint32_t baudRate, uint32_t tqNum, flexcan_timing_config_t *pTimingConfig);
+
+/*!
+ * @brief Calculates the segment values for a single bit time for CANFD bus data baud Rate
+ *
+ * @param baudRatebrs The canfd bus data speed in bps
+ * @param tqNum Number of time quanta per bit
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if Calculates the segment success, FALSE if Calculates the segment success
+ */
+static bool FLEXCAN_FDGetSegmentswithBRS(uint32_t baudRatebrs, uint32_t tqNum, flexcan_timing_config_t *pTimingConfig);
+
+/*!
+ * @brief Calculates the improved timing values by specific baudrates for CAN by CBT register
+ *
+ * @param baudRate The classical CAN speed in bps defined by user
+ * @param sourceClock_Hz The Source clock data speed in bps. Zero to disable baudrate switching
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if timing configuration found, FALSE if failed to find configuration
+ */
+static bool FLEXCAN_CalculateImprovedTimingValuesByCBT(uint32_t baudRate,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig);
+#endif
+
+/*!
+ * @brief Check unhandle interrupt events
+ *
+ * @param base FlexCAN peripheral base address.
+ * @return TRUE if unhandled interrupt action exist, FALSE if no unhandlered interrupt action exist.
+ */
+static bool FLEXCAN_CheckUnhandleInterruptEvents(CAN_Type *base);
+
+/*!
+ * @brief Sub Handler Data Trasfered Events
+ *
+ * @param base FlexCAN peripheral base address.
+ * @param handle FlexCAN handle pointer.
+ * @param pResult Pointer to the Handle result.
+ * @return the status after handle each data transfered event.
+ */
+static status_t FLEXCAN_SubHandlerForDataTransfered(CAN_Type *base, flexcan_handle_t *handle, uint32_t *pResult);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of FlexCAN peripheral base address. */
+static CAN_Type *const s_flexcanBases[] = CAN_BASE_PTRS;
+
+/* Array of FlexCAN IRQ number. */
+static const IRQn_Type s_flexcanRxWarningIRQ[] = CAN_Rx_Warning_IRQS;
+static const IRQn_Type s_flexcanTxWarningIRQ[] = CAN_Tx_Warning_IRQS;
+static const IRQn_Type s_flexcanWakeUpIRQ[] = CAN_Wake_Up_IRQS;
+static const IRQn_Type s_flexcanErrorIRQ[] = CAN_Error_IRQS;
+static const IRQn_Type s_flexcanBusOffIRQ[] = CAN_Bus_Off_IRQS;
+static const IRQn_Type s_flexcanMbIRQ[] = CAN_ORed_Message_buffer_IRQS;
+
+/* Array of FlexCAN handle. */
+static flexcan_handle_t *s_flexcanHandle[ARRAY_SIZE(s_flexcanBases)];
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of FlexCAN clock name. */
+static const clock_ip_name_t s_flexcanClock[] = FLEXCAN_CLOCKS;
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+/* Array of FlexCAN serial clock name. */
+static const clock_ip_name_t s_flexcanPeriphClock[] = FLEXCAN_PERIPH_CLOCKS;
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* FlexCAN ISR for transactional APIs. */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+static flexcan_isr_t s_flexcanIsr = (flexcan_isr_t)DefaultISR;
+#else
+static flexcan_isr_t s_flexcanIsr;
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Get the FlexCAN instance from peripheral base address.
+ *
+ * param base FlexCAN peripheral base address.
+ * return FlexCAN instance.
+ */
+uint32_t FLEXCAN_GetInstance(CAN_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexcanBases); instance++)
+ {
+ if (s_flexcanBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexcanBases));
+
+ return instance;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595)
+void FLEXCAN_EnterFreezeMode(CAN_Type *base)
+{
+ uint32_t u32TimeoutCount = 0U;
+ uint32_t u32TempMCR = 0U;
+ uint32_t u32TempIMASK1 = 0U;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint32_t u32TempIMASK2 = 0U;
+#endif
+
+ /* Step1: set FRZ enable in MCR. */
+ base->MCR |= CAN_MCR_FRZ_MASK;
+
+ /* Step2: to check if MDIS bit set in MCR. if yes, clear it. */
+ if (0U != (base->MCR & CAN_MCR_MDIS_MASK))
+ {
+ base->MCR &= ~CAN_MCR_MDIS_MASK;
+ }
+
+ /* Step3: polling LPMACK. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT;
+ while ((0U == (base->MCR & CAN_MCR_LPMACK_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+
+ /* Step4: to check FLTCONF in ESR1 register */
+ if (0U == (base->ESR1 & CAN_ESR1_FLTCONF_BUSOFF))
+ {
+ /* Step5B: Set Halt bits. */
+ base->MCR |= CAN_MCR_HALT_MASK;
+
+ /* Step6B: Poll the MCR register until the Freeze Acknowledge (FRZACK) bit is set, timeout need more than 178
+ * CAN bit length, so 20 multiply timeout is enough. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT * 20U;
+ while ((0U == (base->MCR & CAN_MCR_FRZACK_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+ }
+ else
+ {
+ /* backup MCR and IMASK register. Errata document not descript it, but we need backup for step 8A and 9A. */
+ u32TempMCR = base->MCR;
+ u32TempIMASK1 = base->IMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ u32TempIMASK2 = base->IMASK2;
+#endif
+
+ /* Step5A: Set the Soft Reset bit ((SOFTRST) in the MCR.*/
+ base->MCR |= CAN_MCR_SOFTRST_MASK;
+
+ /* Step6A: Poll the MCR register until the Soft Reset (SOFTRST) bit is cleared. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT;
+ while ((CAN_MCR_SOFTRST_MASK == (base->MCR & CAN_MCR_SOFTRST_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+
+ /* Step7A: Poll the MCR register until the Freeze Acknowledge (FRZACK) bit is set. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT;
+ while ((0U == (base->MCR & CAN_MCR_FRZACK_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+
+ /* Step8A: reconfig MCR. */
+ base->MCR = u32TempMCR;
+
+ /* Step9A: reconfig IMASK. */
+ base->IMASK1 = u32TempIMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ base->IMASK2 = u32TempIMASK2;
+#endif
+ }
+}
+#elif (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_8341) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_8341)
+void FLEXCAN_EnterFreezeMode(CAN_Type *base)
+{
+ uint32_t u32TimeoutCount = 0U;
+ uint32_t u32TempMCR = 0U;
+ uint32_t u32TempIMASK1 = 0U;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint32_t u32TempIMASK2 = 0U;
+#endif
+
+ /* Step1: set FRZ and HALT bit enable in MCR. */
+ base->MCR |= CAN_MCR_FRZ_MASK;
+ base->MCR |= CAN_MCR_HALT_MASK;
+
+ /* Step2: to check if MDIS bit set in MCR. if yes, clear it. */
+ if (0U != (base->MCR & CAN_MCR_MDIS_MASK))
+ {
+ base->MCR &= ~CAN_MCR_MDIS_MASK;
+ }
+
+ /* Step3: Poll the MCR register until the Freeze Acknowledge (FRZACK) bit is set. */
+ u32TimeoutCount = (uint32_t)FLEXCAN_WAIT_TIMEOUT * 100U;
+ while ((0U == (base->MCR & CAN_MCR_FRZACK_MASK)) && (u32TimeoutCount > 0U))
+ {
+ u32TimeoutCount--;
+ }
+
+ /* Step4: check whether the timeout reached. if no skip step5 to step8. */
+ if (0U == u32TimeoutCount)
+ {
+ /* backup MCR and IMASK register. Errata document not descript it, but we need backup for step 8A and 9A. */
+ u32TempMCR = base->MCR;
+ u32TempIMASK1 = base->IMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ u32TempIMASK2 = base->IMASK2;
+#endif
+ /* Step5: Set the Soft Reset bit ((SOFTRST) in the MCR.*/
+ base->MCR |= CAN_MCR_SOFTRST_MASK;
+
+ /* Step6: Poll the MCR register until the Soft Reset (SOFTRST) bit is cleared. */
+ while (CAN_MCR_SOFTRST_MASK == (base->MCR & CAN_MCR_SOFTRST_MASK))
+ {
+ }
+
+ /* Step7: reconfig MCR. */
+ base->MCR = u32TempMCR;
+
+ /* Step8: reconfig IMASK. */
+ base->IMASK1 = u32TempIMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ base->IMASK2 = u32TempIMASK2;
+#endif
+ }
+}
+#else
+void FLEXCAN_EnterFreezeMode(CAN_Type *base)
+{
+ /* Set Freeze, Halt bits. */
+ base->MCR |= CAN_MCR_FRZ_MASK;
+ base->MCR |= CAN_MCR_HALT_MASK;
+ while (0U == (base->MCR & CAN_MCR_FRZACK_MASK))
+ {
+ }
+}
+#endif
+
+void FLEXCAN_ExitFreezeMode(CAN_Type *base)
+{
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Enable to update in MCER. */
+ base->CTRL2 |= CAN_CTRL2_ECRWRE_MASK;
+ base->MECR &= ~CAN_MECR_ECRWRDIS_MASK;
+#endif
+
+ /* Clear Freeze, Halt bits. */
+ base->MCR &= ~CAN_MCR_HALT_MASK;
+ base->MCR &= ~CAN_MCR_FRZ_MASK;
+
+ /* Wait until the FlexCAN Module exit freeze mode. */
+ while (0U != (base->MCR & CAN_MCR_FRZACK_MASK))
+ {
+ }
+}
+
+#if !defined(NDEBUG)
+static bool FLEXCAN_IsMbOccupied(CAN_Type *base, uint8_t mbIdx)
+{
+ uint8_t lastOccupiedMb;
+ bool fgRet;
+
+ /* Is Rx FIFO enabled? */
+ if (0U != (base->MCR & CAN_MCR_RFEN_MASK))
+ {
+ /* Get RFFN value. */
+ lastOccupiedMb = (uint8_t)((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
+ /* Calculate the number of last Message Buffer occupied by Rx FIFO. */
+ lastOccupiedMb = ((lastOccupiedMb + 1U) * 2U) + 5U;
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ /* the first valid MB should be occupied by ERRATA 5461 or 5829. */
+ lastOccupiedMb += 1U;
+#endif
+ fgRet = (mbIdx <= lastOccupiedMb);
+ }
+ else
+ {
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ if (0U == mbIdx)
+ {
+ fgRet = true;
+ }
+ else
+#endif
+ {
+ fgRet = false;
+ }
+ }
+
+ return fgRet;
+}
+#endif
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+static uint8_t FLEXCAN_GetFirstValidMb(CAN_Type *base)
+{
+ uint8_t firstValidMbNum;
+
+ if (0U != (base->MCR & CAN_MCR_RFEN_MASK))
+ {
+ firstValidMbNum = (uint8_t)((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
+ firstValidMbNum = ((firstValidMbNum + 1U) * 2U) + 6U;
+ }
+ else
+ {
+ firstValidMbNum = 0U;
+ }
+
+ return firstValidMbNum;
+}
+#endif
+
+static bool FLEXCAN_IsMbIntEnabled(CAN_Type *base, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(mbIdx < (uint8_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base));
+
+ uint32_t flag = 1U;
+ bool fgRet = false;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ if (mbIdx >= 32U)
+ {
+ fgRet = (0U != (base->IMASK2 & (flag << (mbIdx - 32U))));
+ }
+ else
+#endif
+ {
+ fgRet = (0U != (base->IMASK1 & (flag << mbIdx)));
+ }
+
+ return fgRet;
+}
+
+static void FLEXCAN_Reset(CAN_Type *base)
+{
+ /* The module must should be first exit from low power
+ * mode, and then soft reset can be applied.
+ */
+ assert(0U == (base->MCR & CAN_MCR_MDIS_MASK));
+
+ uint8_t i;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ if (0 != (FSL_FEATURE_FLEXCAN_INSTANCE_HAS_DOZE_MODE_SUPPORTn(base)))
+ {
+ /* De-assert DOZE Enable Bit. */
+ base->MCR &= ~CAN_MCR_DOZE_MASK;
+ }
+#endif
+
+ /* Wait until FlexCAN exit from any Low Power Mode. */
+ while (0U != (base->MCR & CAN_MCR_LPMACK_MASK))
+ {
+ }
+
+ /* Assert Soft Reset Signal. */
+ base->MCR |= CAN_MCR_SOFTRST_MASK;
+ /* Wait until FlexCAN reset completes. */
+ while (0U != (base->MCR & CAN_MCR_SOFTRST_MASK))
+ {
+ }
+
+/* Reset MCR register. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_GLITCH_FILTER) && FSL_FEATURE_FLEXCAN_HAS_GLITCH_FILTER)
+ base->MCR |= CAN_MCR_WRNEN_MASK | CAN_MCR_WAKSRC_MASK |
+ CAN_MCR_MAXMB((uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base) - 1U);
+#else
+ base->MCR |=
+ CAN_MCR_WRNEN_MASK | CAN_MCR_MAXMB((uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base) - 1U);
+#endif
+
+/* Reset CTRL1 and CTRL2 register. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ /* SMP bit cannot be asserted when CAN FD is enabled */
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+ base->CTRL1 = 0x0;
+ }
+ else
+ {
+ base->CTRL1 = CAN_CTRL1_SMP_MASK;
+ }
+#else
+ base->CTRL1 = CAN_CTRL1_SMP_MASK;
+#endif
+ base->CTRL2 = CAN_CTRL2_TASD(0x16) | CAN_CTRL2_RRS_MASK | CAN_CTRL2_EACEN_MASK;
+
+ /* Clean all individual Rx Mask of Message Buffers. */
+ for (i = 0; i < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base); i++)
+ {
+ base->RXIMR[i] = 0x3FFFFFFF;
+ }
+
+ /* Clean Global Mask of Message Buffers. */
+ base->RXMGMASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Message Buffer 14. */
+ base->RX14MASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Message Buffer 15. */
+ base->RX15MASK = 0x3FFFFFFF;
+ /* Clean Global Mask of Rx FIFO. */
+ base->RXFGMASK = 0x3FFFFFFF;
+
+ /* Clean all Message Buffer CS fields. */
+ for (i = 0; i < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base); i++)
+ {
+ base->MB[i].CS = 0x0;
+ }
+}
+
+static void FLEXCAN_SetBaudRate(CAN_Type *base,
+ uint32_t sourceClock_Hz,
+ uint32_t baudRate_Bps,
+ flexcan_timing_config_t timingConfig)
+{
+ /* FlexCAN timing setting formula:
+ * quantum = 1 + (PSEG1 + 1) + (PSEG2 + 1) + (PROPSEG + 1);
+ */
+ uint32_t quantum = (1U + ((uint32_t)timingConfig.phaseSeg1 + 1U) + ((uint32_t)timingConfig.phaseSeg2 + 1U) +
+ ((uint32_t)timingConfig.propSeg + 1U));
+ uint32_t priDiv = baudRate_Bps * quantum;
+
+ /* Assertion: Desired baud rate is too high. */
+ assert(baudRate_Bps <= 1000000U);
+ /* Assertion: Source clock should greater than baud rate * quantum. */
+ assert(priDiv <= sourceClock_Hz);
+
+ if (0U == priDiv)
+ {
+ priDiv = 1;
+ }
+
+ priDiv = (sourceClock_Hz / priDiv) - 1U;
+
+ /* Desired baud rate is too low. */
+ if (priDiv > 0xFFU)
+ {
+ priDiv = 0xFF;
+ }
+
+ timingConfig.preDivider = (uint16_t)priDiv;
+
+ /* Update actual timing characteristic. */
+ FLEXCAN_SetTimingConfig(base, (const flexcan_timing_config_t *)(uint32_t)&timingConfig);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+static void FLEXCAN_SetFDBaudRate(CAN_Type *base,
+ uint32_t sourceClock_Hz,
+ uint32_t baudRateFD_Bps,
+ flexcan_timing_config_t timingConfig)
+{
+ /* FlexCAN FD timing setting formula:
+ * quantum = 1 + (FPSEG1 + 1) + (FPSEG2 + 1) + FPROPSEG;
+ */
+ uint32_t quantum = (1U + ((uint32_t)timingConfig.fphaseSeg1 + 1U) + ((uint32_t)timingConfig.fphaseSeg2 + 1U) +
+ (uint32_t)timingConfig.fpropSeg);
+ uint32_t priDiv = baudRateFD_Bps * quantum;
+
+ /* Assertion: Desired baud rate is too high. */
+ assert(baudRateFD_Bps <= 8000000U);
+ /* Assertion: Source clock should greater than baud rate * FLEXCAN_TIME_QUANTA_NUM. */
+ assert(priDiv <= sourceClock_Hz);
+
+ if (0U == priDiv)
+ {
+ priDiv = 1;
+ }
+
+ priDiv = (sourceClock_Hz / priDiv) - 1U;
+
+ /* Desired baud rate is too low. */
+ if (priDiv > 0xFFU)
+ {
+ priDiv = 0xFF;
+ }
+
+ timingConfig.fpreDivider = (uint16_t)priDiv;
+
+ /* Update actual timing characteristic. */
+ FLEXCAN_SetFDTimingConfig(base, (const flexcan_timing_config_t *)(uint32_t)&timingConfig);
+}
+#endif
+
+/*!
+ * brief Initializes a FlexCAN instance.
+ *
+ * This function initializes the FlexCAN module with user-defined settings.
+ * This example shows how to set up the flexcan_config_t parameters and how
+ * to call the FLEXCAN_Init function by passing in these parameters.
+ * code
+ * flexcan_config_t flexcanConfig;
+ * flexcanConfig.clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig.baudRate = 1000000U;
+ * flexcanConfig.maxMbNum = 16;
+ * flexcanConfig.enableLoopBack = false;
+ * flexcanConfig.enableSelfWakeup = false;
+ * flexcanConfig.enableIndividMask = false;
+ * flexcanConfig.disableSelfReception = false;
+ * flexcanConfig.enableListenOnlyMode = false;
+ * flexcanConfig.enableDoze = false;
+ * flexcanConfig.timingConfig = timingConfig;
+ * FLEXCAN_Init(CAN0, &flexcanConfig, 8000000UL);
+ * endcode
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the user-defined configuration structure.
+ * param sourceClock_Hz FlexCAN Protocol Engine clock source frequency in Hz.
+ */
+void FLEXCAN_Init(CAN_Type *base, const flexcan_config_t *pConfig, uint32_t sourceClock_Hz)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+ assert((pConfig->maxMbNum > 0U) &&
+ (pConfig->maxMbNum <= (uint8_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base)));
+
+ uint32_t mcrTemp;
+ uint32_t ctrl1Temp;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance;
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ instance = FLEXCAN_GetInstance(base);
+ /* Enable FlexCAN clock. */
+ (void)CLOCK_EnableClock(s_flexcanClock[instance]);
+ /*
+ * Check the CAN clock in this device whether affected by Other clock gate
+ * If it affected, we'd better to change other clock source,
+ * If user insist on using that clock source, user need open these gate at same time,
+ * In this scene, User need to care the power consumption.
+ */
+ assert(CAN_CLOCK_CHECK_NO_AFFECTS);
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+ /* Enable FlexCAN serial clock. */
+ (void)CLOCK_EnableClock(s_flexcanPeriphClock[instance]);
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(CAN_CTRL1_CLKSRC_MASK)
+#if (defined(FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE) && FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE)
+ if (0 == FSL_FEATURE_FLEXCAN_INSTANCE_SUPPORT_ENGINE_CLK_SEL_REMOVEn(base))
+#endif /* FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE */
+ {
+ /* Disable FlexCAN Module. */
+ FLEXCAN_Enable(base, false);
+
+ /* Protocol-Engine clock source selection, This bit must be set
+ * when FlexCAN Module in Disable Mode.
+ */
+ base->CTRL1 = (kFLEXCAN_ClkSrc0 == pConfig->clkSrc) ? (base->CTRL1 & ~CAN_CTRL1_CLKSRC_MASK) :
+ (base->CTRL1 | CAN_CTRL1_CLKSRC_MASK);
+ }
+#endif /* CAN_CTRL1_CLKSRC_MASK */
+
+ /* Enable FlexCAN Module for configuration. */
+ FLEXCAN_Enable(base, true);
+
+ /* Reset to known status. */
+ FLEXCAN_Reset(base);
+
+ /* Save current CTRL1 value and enable to enter Freeze mode(enabled by default). */
+ ctrl1Temp = base->CTRL1;
+
+ /* Save current MCR value and enable to enter Freeze mode(enabled by default). */
+ mcrTemp = base->MCR;
+
+ /* Enable Loop Back Mode? */
+ ctrl1Temp = (pConfig->enableLoopBack) ? (ctrl1Temp | CAN_CTRL1_LPB_MASK) : (ctrl1Temp & ~CAN_CTRL1_LPB_MASK);
+
+ /* Enable Timer Sync? */
+ ctrl1Temp = (pConfig->enableTimerSync) ? (ctrl1Temp | CAN_CTRL1_TSYN_MASK) : (ctrl1Temp & ~CAN_CTRL1_TSYN_MASK);
+
+ /* Enable Listen Only Mode? */
+ ctrl1Temp = (pConfig->enableListenOnlyMode) ? ctrl1Temp | CAN_CTRL1_LOM_MASK : ctrl1Temp & ~CAN_CTRL1_LOM_MASK;
+
+ /* Set the maximum number of Message Buffers */
+ mcrTemp = (mcrTemp & ~CAN_MCR_MAXMB_MASK) | CAN_MCR_MAXMB((uint32_t)pConfig->maxMbNum - 1U);
+
+ /* Enable Self Wake Up Mode and configure the wake up source. */
+ mcrTemp = (pConfig->enableSelfWakeup) ? (mcrTemp | CAN_MCR_SLFWAK_MASK) : (mcrTemp & ~CAN_MCR_SLFWAK_MASK);
+ mcrTemp = (kFLEXCAN_WakeupSrcFiltered == pConfig->wakeupSrc) ? (mcrTemp | CAN_MCR_WAKSRC_MASK) :
+ (mcrTemp & ~CAN_MCR_WAKSRC_MASK);
+
+ /* Enable Individual Rx Masking? */
+ mcrTemp = (pConfig->enableIndividMask) ? (mcrTemp | CAN_MCR_IRMQ_MASK) : (mcrTemp & ~CAN_MCR_IRMQ_MASK);
+
+ /* Disable Self Reception? */
+ mcrTemp = (pConfig->disableSelfReception) ? mcrTemp | CAN_MCR_SRXDIS_MASK : mcrTemp & ~CAN_MCR_SRXDIS_MASK;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_DOZE_MODE_SUPPORTn(base))
+ {
+ /* Enable Doze Mode? */
+ mcrTemp = (pConfig->enableDoze) ? (mcrTemp | CAN_MCR_DOZE_MASK) : (mcrTemp & ~CAN_MCR_DOZE_MASK);
+ }
+#endif
+
+ /* Write back CTRL1 Configuration to register. */
+ base->CTRL1 = ctrl1Temp;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL) && FSL_FEATURE_FLEXCAN_HAS_MEMORY_ERROR_CONTROL)
+ /* Enable to update in MCER. */
+ base->CTRL2 |= CAN_CTRL2_ECRWRE_MASK;
+ base->MECR &= ~CAN_MECR_ECRWRDIS_MASK;
+#endif
+
+ /* Write back MCR Configuration to register. */
+ base->MCR = mcrTemp;
+
+ /* Baud Rate Configuration.*/
+ FLEXCAN_SetBaudRate(base, sourceClock_Hz, pConfig->baudRate, pConfig->timingConfig);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Initializes a FlexCAN instance.
+ *
+ * This function initializes the FlexCAN module with user-defined settings.
+ * This example shows how to set up the flexcan_config_t parameters and how
+ * to call the FLEXCAN_FDInit function by passing in these parameters.
+ * code
+ * flexcan_config_t flexcanConfig;
+ * flexcanConfig.clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig.baudRate = 1000000U;
+ * flexcanConfig.baudRateFD = 2000000U;
+ * flexcanConfig.maxMbNum = 16;
+ * flexcanConfig.enableLoopBack = false;
+ * flexcanConfig.enableSelfWakeup = false;
+ * flexcanConfig.enableIndividMask = false;
+ * flexcanConfig.disableSelfReception = false;
+ * flexcanConfig.enableListenOnlyMode = false;
+ * flexcanConfig.enableDoze = false;
+ * flexcanConfig.timingConfig = timingConfig;
+ * FLEXCAN_FDInit(CAN0, &flexcanConfig, 8000000UL, kFLEXCAN_16BperMB, false);
+ * endcode
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the user-defined configuration structure.
+ * param sourceClock_Hz FlexCAN Protocol Engine clock source frequency in Hz.
+ * param dataSize FlexCAN FD frame payload size.
+ * param brs If bitrate switch is enabled in FD mode.
+ */
+void FLEXCAN_FDInit(
+ CAN_Type *base, const flexcan_config_t *pConfig, uint32_t sourceClock_Hz, flexcan_mb_size_t dataSize, bool brs)
+{
+ assert((uint32_t)dataSize <= 3U);
+
+ uint32_t fdctrl = 0U;
+
+ /* Initialization of classical CAN. */
+ FLEXCAN_Init(base, pConfig, sourceClock_Hz);
+
+ /* Extra bitrate setting for CANFD. */
+ FLEXCAN_SetFDBaudRate(base, sourceClock_Hz, pConfig->baudRateFD, pConfig->timingConfig);
+
+ /* read FDCTRL register. */
+ fdctrl = base->FDCTRL;
+
+ /* Enable FD operation and set bitrate switch. */
+ if (brs)
+ {
+ fdctrl |= CAN_FDCTRL_FDRATE_MASK;
+ }
+ else
+ {
+ fdctrl &= ~CAN_FDCTRL_FDRATE_MASK;
+ }
+
+ if (brs && !(pConfig->enableLoopBack))
+ {
+ /* Before use "|=" operation for multi-bits field, CPU should Clean previous Setting. */
+ fdctrl = (fdctrl & ~CAN_FDCTRL_TDCOFF_MASK) | CAN_FDCTRL_TDCOFF(0x2U);
+ }
+
+ /* Before use "|=" operation for multi-bits field, CPU should clean previous Setting. */
+ fdctrl = (fdctrl & ~CAN_FDCTRL_MBDSR0_MASK) | CAN_FDCTRL_MBDSR0(dataSize);
+#if defined(CAN_FDCTRL_MBDSR1_MASK)
+ fdctrl = (fdctrl & ~CAN_FDCTRL_MBDSR1_MASK) | CAN_FDCTRL_MBDSR1(dataSize);
+#endif
+#if defined(CAN_FDCTRL_MBDSR2_MASK)
+ fdctrl = (fdctrl & ~CAN_FDCTRL_MBDSR2_MASK) | CAN_FDCTRL_MBDSR2(dataSize);
+#endif
+#if defined(CAN_FDCTRL_MBDSR3_MASK)
+ fdctrl = (fdctrl & ~CAN_FDCTRL_MBDSR3_MASK) | CAN_FDCTRL_MBDSR3(dataSize);
+#endif
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ base->MCR |= CAN_MCR_FDEN_MASK;
+
+ /* update the FDCTL register. */
+ base->FDCTRL = fdctrl;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+#endif
+
+/*!
+ * brief De-initializes a FlexCAN instance.
+ *
+ * This function disables the FlexCAN module clock and sets all register values
+ * to the reset value.
+ *
+ * param base FlexCAN peripheral base address.
+ */
+void FLEXCAN_Deinit(CAN_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance;
+#endif
+ /* Reset all Register Contents. */
+ FLEXCAN_Reset(base);
+
+ /* Disable FlexCAN module. */
+ FLEXCAN_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ instance = FLEXCAN_GetInstance(base);
+#if defined(FLEXCAN_PERIPH_CLOCKS)
+ /* Disable FlexCAN serial clock. */
+ (void)CLOCK_DisableClock(s_flexcanPeriphClock[instance]);
+#endif /* FLEXCAN_PERIPH_CLOCKS */
+ /* Disable FlexCAN clock. */
+ (void)CLOCK_DisableClock(s_flexcanClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the FlexCAN configuration structure to default values. The default
+ * values are as follows.
+ * flexcanConfig->clkSrc = kFLEXCAN_ClkSrc0;
+ * flexcanConfig->baudRate = 1000000U;
+ * flexcanConfig->baudRateFD = 2000000U;
+ * flexcanConfig->maxMbNum = 16;
+ * flexcanConfig->enableLoopBack = false;
+ * flexcanConfig->enableSelfWakeup = false;
+ * flexcanConfig->enableIndividMask = false;
+ * flexcanConfig->disableSelfReception = false;
+ * flexcanConfig->enableListenOnlyMode = false;
+ * flexcanConfig->enableDoze = false;
+ * flexcanConfig.timingConfig = timingConfig;
+ *
+ * param pConfig Pointer to the FlexCAN configuration structure.
+ */
+void FLEXCAN_GetDefaultConfig(flexcan_config_t *pConfig)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(pConfig, 0, sizeof(*pConfig));
+
+ /* Initialize FlexCAN Module config struct with default value. */
+ pConfig->clkSrc = kFLEXCAN_ClkSrc0;
+ pConfig->baudRate = 1000000U;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ pConfig->baudRateFD = 2000000U;
+#endif
+ pConfig->maxMbNum = 16;
+ pConfig->enableLoopBack = false;
+ pConfig->enableTimerSync = true;
+ pConfig->enableSelfWakeup = false;
+ pConfig->wakeupSrc = kFLEXCAN_WakeupSrcUnfiltered;
+ pConfig->enableIndividMask = false;
+ pConfig->disableSelfReception = false;
+ pConfig->enableListenOnlyMode = false;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT) && FSL_FEATURE_FLEXCAN_HAS_DOZE_MODE_SUPPORT)
+ pConfig->enableDoze = false;
+#endif
+ /* Default protocol timing configuration, time quantum is 10. */
+ pConfig->timingConfig.phaseSeg1 = 3;
+ pConfig->timingConfig.phaseSeg2 = 2;
+ pConfig->timingConfig.propSeg = 1;
+ pConfig->timingConfig.rJumpwidth = 1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ pConfig->timingConfig.fphaseSeg1 = 3;
+ pConfig->timingConfig.fphaseSeg2 = 3;
+ pConfig->timingConfig.fpropSeg = 1;
+ pConfig->timingConfig.frJumpwidth = 1;
+#endif
+}
+
+/*!
+ * brief Sets the FlexCAN protocol timing characteristic.
+ *
+ * This function gives user settings to CAN bus timing characteristic.
+ * The function is for an experienced user. For less experienced users, call
+ * the FLEXCAN_Init() and fill the baud rate field with a desired value.
+ * This provides the default timing characteristics to the module.
+ *
+ * Note that calling FLEXCAN_SetTimingConfig() overrides the baud rate set
+ * in FLEXCAN_Init().
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the timing configuration structure.
+ */
+void FLEXCAN_SetTimingConfig(CAN_Type *base, const flexcan_timing_config_t *pConfig)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0 != FSL_FEATURE_FLEXCAN_INSTANCE_HAS_FLEXIBLE_DATA_RATEn(base))
+ {
+ /* Cleaning previous Timing Setting. */
+ base->CBT &= ~(CAN_CBT_EPRESDIV_MASK | CAN_CBT_ERJW_MASK | CAN_CBT_EPSEG1_MASK | CAN_CBT_EPSEG2_MASK |
+ CAN_CBT_EPROPSEG_MASK);
+
+ /* Updating Timing Setting according to configuration structure. */
+ base->CBT |= (CAN_CBT_EPRESDIV(pConfig->preDivider) | CAN_CBT_ERJW(pConfig->rJumpwidth) |
+ CAN_CBT_EPSEG1(pConfig->phaseSeg1) | CAN_CBT_EPSEG2(pConfig->phaseSeg2) |
+ CAN_CBT_EPROPSEG(pConfig->propSeg));
+ }
+ else
+ {
+ /* Cleaning previous Timing Setting. */
+ base->CTRL1 &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_RJW_MASK | CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK |
+ CAN_CTRL1_PROPSEG_MASK);
+
+ /* Updating Timing Setting according to configuration structure. */
+ base->CTRL1 |= (CAN_CTRL1_PRESDIV(pConfig->preDivider) | CAN_CTRL1_RJW(pConfig->rJumpwidth) |
+ CAN_CTRL1_PSEG1(pConfig->phaseSeg1) | CAN_CTRL1_PSEG2(pConfig->phaseSeg2) |
+ CAN_CTRL1_PROPSEG(pConfig->propSeg));
+ }
+#else
+ /* Cleaning previous Timing Setting. */
+ base->CTRL1 &= ~(CAN_CTRL1_PRESDIV_MASK | CAN_CTRL1_RJW_MASK | CAN_CTRL1_PSEG1_MASK | CAN_CTRL1_PSEG2_MASK |
+ CAN_CTRL1_PROPSEG_MASK);
+
+ /* Updating Timing Setting according to configuration structure. */
+ base->CTRL1 |= (CAN_CTRL1_PRESDIV(pConfig->preDivider) | CAN_CTRL1_RJW(pConfig->rJumpwidth) |
+ CAN_CTRL1_PSEG1(pConfig->phaseSeg1) | CAN_CTRL1_PSEG2(pConfig->phaseSeg2) |
+ CAN_CTRL1_PROPSEG(pConfig->propSeg));
+#endif
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Sets the FlexCAN FD protocol timing characteristic.
+ *
+ * This function gives user settings to CAN bus timing characteristic.
+ * The function is for an experienced user. For less experienced users, call
+ * the FLEXCAN_Init() and fill the baud rate field with a desired value.
+ * This provides the default timing characteristics to the module.
+ *
+ * Note that calling FLEXCAN_SetFDTimingConfig() overrides the baud rate set
+ * in FLEXCAN_Init().
+ *
+ * param base FlexCAN peripheral base address.
+ * param pConfig Pointer to the timing configuration structure.
+ */
+void FLEXCAN_SetFDTimingConfig(CAN_Type *base, const flexcan_timing_config_t *pConfig)
+{
+ /* Assertion. */
+ assert(NULL != pConfig);
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ base->CBT |= CAN_CBT_BTF(1);
+ /* Cleaning previous Timing Setting. */
+ base->FDCBT &= ~(CAN_FDCBT_FPRESDIV_MASK | CAN_FDCBT_FRJW_MASK | CAN_FDCBT_FPSEG1_MASK | CAN_FDCBT_FPSEG2_MASK |
+ CAN_FDCBT_FPROPSEG_MASK);
+
+ /* Updating Timing Setting according to configuration structure. */
+ base->FDCBT |= (CAN_FDCBT_FPRESDIV(pConfig->fpreDivider) | CAN_FDCBT_FRJW(pConfig->frJumpwidth) |
+ CAN_FDCBT_FPSEG1(pConfig->fphaseSeg1) | CAN_FDCBT_FPSEG2(pConfig->fphaseSeg2) |
+ CAN_FDCBT_FPROPSEG(pConfig->fpropSeg));
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+#endif
+
+/*!
+ * brief Sets the FlexCAN receive message buffer global mask.
+ *
+ * This function sets the global mask for the FlexCAN message buffer in a matching process.
+ * The configuration is only effective when the Rx individual mask is disabled in the FLEXCAN_Init().
+ *
+ * param base FlexCAN peripheral base address.
+ * param mask Rx Message Buffer Global Mask value.
+ */
+void FLEXCAN_SetRxMbGlobalMask(CAN_Type *base, uint32_t mask)
+{
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx Message Buffer Global Mask value. */
+ base->RXMGMASK = mask;
+ base->RX14MASK = mask;
+ base->RX15MASK = mask;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+/*!
+ * brief Sets the FlexCAN receive FIFO global mask.
+ *
+ * This function sets the global mask for FlexCAN FIFO in a matching process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mask Rx Fifo Global Mask value.
+ */
+void FLEXCAN_SetRxFifoGlobalMask(CAN_Type *base, uint32_t mask)
+{
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx FIFO Global Mask value. */
+ base->RXFGMASK = mask;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+/*!
+ * brief Sets the FlexCAN receive individual mask.
+ *
+ * This function sets the individual mask for the FlexCAN matching process.
+ * The configuration is only effective when the Rx individual mask is enabled in the FLEXCAN_Init().
+ * If the Rx FIFO is disabled, the individual mask is applied to the corresponding Message Buffer.
+ * If the Rx FIFO is enabled, the individual mask for Rx FIFO occupied Message Buffer is applied to
+ * the Rx Filter with the same index. Note that only the first 32
+ * individual masks can be used as the Rx FIFO filter mask.
+ *
+ * param base FlexCAN peripheral base address.
+ * param maskIdx The Index of individual Mask.
+ * param mask Rx Individual Mask value.
+ */
+void FLEXCAN_SetRxIndividualMask(CAN_Type *base, uint8_t maskIdx, uint32_t mask)
+{
+ assert(maskIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Setting Rx Individual Mask value. */
+ base->RXIMR[maskIdx] = mask;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+/*!
+ * brief Configures a FlexCAN transmit message buffer.
+ *
+ * This function aborts the previous transmission, cleans the Message Buffer, and
+ * configures it as a Transmit Message Buffer.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The Message Buffer index.
+ * param enable Enable/disable Tx Message Buffer.
+ * - true: Enable Tx Message Buffer.
+ * - false: Disable Tx Message Buffer.
+ */
+void FLEXCAN_SetTxMbConfig(CAN_Type *base, uint8_t mbIdx, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ /* Inactivate Message Buffer. */
+ if (enable)
+ {
+ base->MB[mbIdx].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ }
+ else
+ {
+ base->MB[mbIdx].CS = 0;
+ }
+
+ /* Clean Message Buffer content. */
+ base->MB[mbIdx].ID = 0x0;
+ base->MB[mbIdx].WORD0 = 0x0;
+ base->MB[mbIdx].WORD1 = 0x0;
+}
+
+/*!
+ * @brief Calculates the segment values for a single bit time for classical CAN
+ *
+ * @param baudRate The data speed in bps
+ * @param tqNum Number of time quantas per bit
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if Calculates the segment success, FALSE if Calculates the segment success
+ */
+static bool FLEXCAN_GetSegments(uint32_t baudRate, uint32_t tqNum, flexcan_timing_config_t *pTimingConfig)
+{
+ uint32_t ideal_sp;
+ uint32_t p1;
+ bool fgRet = false;
+
+ /* Get ideal sample point. For the Bit field in CTRL1 register can't calculate higher ideal SP, we set it as the
+ * lowest one(75%).*/
+ ideal_sp = IDEAL_SP_LOW;
+
+ /* distribute time quanta. */
+ p1 = tqNum * (uint32_t)ideal_sp;
+ pTimingConfig->propSeg = (uint8_t)(p1 / (uint32_t)IDEAL_SP_FACTOR - 2U);
+ if (pTimingConfig->propSeg <= (MAX_PSEG1 + MAX_PROPSEG))
+ {
+ if (pTimingConfig->propSeg > MAX_PROPSEG)
+ {
+ pTimingConfig->phaseSeg1 = pTimingConfig->propSeg - MAX_PROPSEG;
+ pTimingConfig->propSeg = MAX_PROPSEG;
+ }
+ else
+ {
+ pTimingConfig->phaseSeg1 = 0;
+ }
+
+ /* The value of prog Seg should be not larger than tqNum -4U. */
+ if ((pTimingConfig->propSeg + pTimingConfig->phaseSeg1) < ((uint8_t)tqNum - 4U))
+ {
+ pTimingConfig->phaseSeg2 = (uint8_t)tqNum - (pTimingConfig->phaseSeg1 + pTimingConfig->propSeg + 4U);
+
+ if (pTimingConfig->phaseSeg2 <= MAX_PSEG1)
+ {
+ if ((pTimingConfig->phaseSeg1 < pTimingConfig->phaseSeg2) &&
+ (pTimingConfig->propSeg > (pTimingConfig->phaseSeg2 - pTimingConfig->phaseSeg1)))
+ {
+ pTimingConfig->propSeg -= (pTimingConfig->phaseSeg2 - pTimingConfig->phaseSeg1);
+ pTimingConfig->phaseSeg1 = pTimingConfig->phaseSeg2;
+ }
+
+ /* subtract one TQ for sync seg. */
+ /* sjw is 20% of total TQ, rounded to nearest int. */
+ pTimingConfig->rJumpwidth = ((uint8_t)tqNum + 4U) / 5U - 1U;
+ /* The max tqNum for CBT will reach to 129, ERJW would not be larger than 26. */
+ /* Considering that max ERJW is 31, rJumpwidth will always be smaller than MAX_ERJW. */
+ if (pTimingConfig->rJumpwidth > MAX_RJW)
+ {
+ pTimingConfig->rJumpwidth = MAX_RJW;
+ }
+
+ fgRet = true;
+ }
+ }
+ }
+
+ return fgRet;
+}
+
+/*!
+ * @brief Calculates the improved timing values by specific baudrates for classical CAN
+ *
+ * @param baudRate The classical CAN speed in bps defined by user
+ * @param sourceClock_Hz The Source clock data speed in bps. Zero to disable baudrate switching
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if timing configuration found, FALSE if failed to find configuration
+ */
+bool FLEXCAN_CalculateImprovedTimingValues(uint32_t baudRate,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig)
+{
+ /* observe baud rate maximums. */
+ assert(baudRate <= MAX_CAN_BAUDRATE);
+
+ uint32_t clk; /* the clock is tqNumb x baudRateFD. */
+ uint32_t tqNum; /* Numbers of TQ. */
+ bool fgRet = false;
+
+ /* Auto Improved Protocal timing for CTRL1. */
+ tqNum = CTRL1_MAX_TIME_QUANTA;
+ do
+ {
+ clk = baudRate * tqNum;
+ if (clk > sourceClock_Hz)
+ {
+ continue; /* tqNum too large, clk has been exceed sourceClock_Hz. */
+ }
+
+ if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
+ {
+ continue; /* Non-supporting: the frequency of clock source is not divisible by target baud rate, the user
+ should change a divisible baud rate. */
+ }
+
+ pTimingConfig->preDivider = (uint16_t)(sourceClock_Hz / clk) - 1U;
+ if (pTimingConfig->preDivider > MAX_PRESDIV)
+ {
+ break; /* The frequency of source clock is too large or the baud rate is too small, the pre-divider could
+ not handle it. */
+ }
+
+ /* Try to get the best timing configuration. */
+ if (FLEXCAN_GetSegments(baudRate, tqNum, pTimingConfig))
+ {
+ fgRet = true;
+ break;
+ }
+ } while (--tqNum >= CTRL1_MIN_TIME_QUANTA);
+
+ return fgRet;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+static uint32_t FLEXCAN_GetFDMailboxOffset(CAN_Type *base, uint8_t mbIdx)
+{
+ uint32_t offset = 0;
+ uint32_t dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+ switch (dataSize)
+ {
+ case (uint32_t)kFLEXCAN_8BperMB:
+ offset = (((uint32_t)mbIdx / 32U) * 512U + ((uint32_t)mbIdx % 32U) * 16U);
+ break;
+ case (uint32_t)kFLEXCAN_16BperMB:
+ offset = (((uint32_t)mbIdx / 21U) * 512U + ((uint32_t)mbIdx % 21U) * 24U);
+ break;
+ case (uint32_t)kFLEXCAN_32BperMB:
+ offset = (((uint32_t)mbIdx / 12U) * 512U + ((uint32_t)mbIdx % 12U) * 40U);
+ break;
+ case (uint32_t)kFLEXCAN_64BperMB:
+ offset = (((uint32_t)mbIdx / 7U) * 512U + ((uint32_t)mbIdx % 7U) * 72U);
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ assert(false);
+ break;
+ }
+ /* To get the dword aligned offset, need to divide by 4. */
+ offset = offset / 4U;
+ return offset;
+}
+
+/*!
+ * @brief Calculates the segment values for a single bit time for CANFD bus control baud Rate
+ *
+ * @param baudRate The canfd bus control speed in bps
+ * @param tqNum Number of time quanta per bit
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if Calculates the segment success, FALSE if Calculates the segment success
+ */
+static bool FLEXCAN_FDGetSegments(uint32_t baudRate, uint32_t tqNum, flexcan_timing_config_t *pTimingConfig)
+{
+ uint32_t ideal_sp;
+ uint32_t p1;
+ bool fgRet = false;
+
+ /* Get ideal sample point. */
+ if (baudRate >= 1000000U)
+ {
+ ideal_sp = IDEAL_SP_LOW;
+ }
+ else if (baudRate >= 800000U)
+ {
+ ideal_sp = IDEAL_SP_MID;
+ }
+ else
+ {
+ ideal_sp = IDEAL_SP_HIGH;
+ }
+
+ /* distribute time quanta. */
+ p1 = tqNum * (uint32_t)ideal_sp;
+ pTimingConfig->propSeg = (uint8_t)(p1 / (uint32_t)IDEAL_SP_FACTOR - 2U);
+ if (pTimingConfig->propSeg <= (MAX_EPSEG1 + MAX_EPROPSEG))
+ {
+ if (pTimingConfig->propSeg > MAX_EPROPSEG)
+ {
+ pTimingConfig->phaseSeg1 = pTimingConfig->propSeg - MAX_EPROPSEG;
+ pTimingConfig->propSeg = MAX_EPROPSEG;
+ }
+ else
+ {
+ pTimingConfig->phaseSeg1 = 0;
+ }
+
+ /* The value of prog Seg should be not larger than tqNum -4U. */
+ if ((pTimingConfig->propSeg + pTimingConfig->phaseSeg1) < ((uint8_t)tqNum - 4U))
+ {
+ pTimingConfig->phaseSeg2 = (uint8_t)tqNum - (pTimingConfig->phaseSeg1 + pTimingConfig->propSeg + 4U);
+
+ if (pTimingConfig->phaseSeg2 <= MAX_EPSEG2)
+ {
+ if ((pTimingConfig->phaseSeg1 < pTimingConfig->phaseSeg2) &&
+ (pTimingConfig->propSeg > (pTimingConfig->phaseSeg2 - pTimingConfig->phaseSeg1)))
+ {
+ pTimingConfig->propSeg -= (pTimingConfig->phaseSeg2 - pTimingConfig->phaseSeg1);
+ pTimingConfig->phaseSeg1 = pTimingConfig->phaseSeg2;
+ }
+
+ /* subtract one TQ for sync seg. */
+ /* sjw is 20% of total TQ, rounded to nearest int. */
+ pTimingConfig->rJumpwidth = ((uint8_t)tqNum + 4U) / 5U - 1U;
+ /* The max tqNum for CBT will reach to 129, ERJW would not be larger than 26. */
+ /* Considering that max ERJW is 31, rJumpwidth will always be smaller than MAX_ERJW. */
+ if (pTimingConfig->rJumpwidth > MAX_ERJW)
+ {
+ pTimingConfig->rJumpwidth = MAX_ERJW;
+ }
+
+ fgRet = true;
+ }
+ }
+ }
+
+ return fgRet;
+}
+
+/*!
+ * @brief Calculates the segment values for a single bit time for CANFD bus data baud Rate
+ *
+ * @param baudRatebrs The canfd bus data speed in bps
+ * @param tqNum Number of time quanta per bit
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if Calculates the segment success, FALSE if Calculates the segment success
+ */
+static bool FLEXCAN_FDGetSegmentswithBRS(uint32_t baudRatebrs, uint32_t tqNum, flexcan_timing_config_t *pTimingConfig)
+{
+ uint32_t ideal_sp;
+ uint32_t p1;
+ bool fgRet = false;
+
+ /* get ideal sample point. */
+ if (baudRatebrs >= 1000000U)
+ {
+ ideal_sp = IDEAL_SP_LOW;
+ }
+ else if (baudRatebrs >= 800000U)
+ {
+ ideal_sp = IDEAL_SP_MID;
+ }
+ else
+ {
+ ideal_sp = IDEAL_SP_HIGH;
+ }
+
+ /* distribute time quanta. */
+ p1 = tqNum * (uint32_t)ideal_sp;
+ pTimingConfig->fpropSeg = (uint8_t)(p1 / (uint32_t)IDEAL_SP_FACTOR - 1U);
+ if (pTimingConfig->fpropSeg <= (MAX_FPSEG1 + MAX_FPROPSEG))
+ {
+ if (pTimingConfig->fpropSeg > MAX_FPROPSEG)
+ {
+ pTimingConfig->fphaseSeg1 = pTimingConfig->fpropSeg - MAX_FPROPSEG;
+ pTimingConfig->fpropSeg = MAX_FPROPSEG;
+ }
+ else
+ {
+ pTimingConfig->fphaseSeg1 = 0;
+ }
+
+ /* The value of prog Seg should be not larger than tqNum -3U. */
+ if ((pTimingConfig->fpropSeg + pTimingConfig->fphaseSeg1) < ((uint8_t)tqNum - 3U))
+ {
+ pTimingConfig->fphaseSeg2 = (uint8_t)tqNum - (pTimingConfig->fphaseSeg1 + pTimingConfig->fpropSeg + 3U);
+
+ if ((pTimingConfig->fphaseSeg1 < pTimingConfig->fphaseSeg2) &&
+ (pTimingConfig->fpropSeg > (pTimingConfig->fphaseSeg2 - pTimingConfig->fphaseSeg1)))
+ {
+ pTimingConfig->fpropSeg -= (pTimingConfig->fphaseSeg2 - pTimingConfig->fphaseSeg1);
+ pTimingConfig->fphaseSeg1 = pTimingConfig->fphaseSeg2;
+ }
+
+ /* subtract one TQ for sync seg. */
+ /* sjw is 20% of total TQ, rounded to nearest int. */
+ pTimingConfig->frJumpwidth = ((uint8_t)tqNum + 4U) / 5U - 1U;
+
+ if (pTimingConfig->frJumpwidth > MAX_FRJW)
+ {
+ pTimingConfig->frJumpwidth = MAX_FRJW;
+ }
+ fgRet = true;
+ }
+ }
+
+ return fgRet;
+}
+
+/*!
+ * @brief Calculates the improved timing values by specific baudrates for CAN by CBT register
+ *
+ * @param baudRate The classical CAN speed in bps defined by user
+ * @param sourceClock_Hz The Source clock data speed in bps. Zero to disable baudrate switching
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if timing configuration found, FALSE if failed to find configuration
+ */
+static bool FLEXCAN_CalculateImprovedTimingValuesByCBT(uint32_t baudRate,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig)
+{
+ /* observe baud rate maximums. */
+ assert(baudRate <= MAX_CAN_BAUDRATE);
+
+ uint32_t clk; /* the clock is tqNumb x baudRateFD. */
+ uint32_t tqNum; /* Numbers of TQ. */
+ bool fgRet = false;
+
+ tqNum = CBT_MAX_TIME_QUANTA;
+ /* Auto Improved Protocal timing. */
+ do
+ {
+ clk = baudRate * tqNum;
+ if (clk > sourceClock_Hz)
+ {
+ continue; /* tqNum too large, clk has been exceed sourceClock_Hz. */
+ }
+
+ if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
+ {
+ continue; /* Non-supporting: the frequency of clock source is not divisible by target baud rate, the user
+ should change a divisible baud rate. */
+ }
+
+ pTimingConfig->preDivider = (uint16_t)(sourceClock_Hz / clk) - 1U;
+ if (pTimingConfig->preDivider > MAX_EPRESDIV)
+ {
+ break; /* The frequency of source clock is too large or the baud rate is too small, the pre-divider could
+ not handle it. */
+ }
+
+ /* Try to get the best timing configuration. */
+ if (FLEXCAN_FDGetSegments(baudRate, tqNum, pTimingConfig))
+ {
+ fgRet = true;
+ break;
+ }
+ } while (--tqNum >= CBT_MIN_TIME_QUANTA);
+
+ return fgRet;
+}
+
+/*!
+ * @brief Calculates the improved timing values by specific baudrates for CANFD
+ *
+ * @param baudRate The CANFD bus control speed in bps defined by user
+ * @param baudRateFD The CANFD bus data speed in bps defined by user
+ * @param sourceClock_Hz The Source clock data speed in bps. Zero to disable baudrate switching
+ * @param pTimingConfig Pointer to the FlexCAN timing configuration structure.
+ *
+ * @return TRUE if timing configuration found, FALSE if failed to find configuration
+ */
+bool FLEXCAN_FDCalculateImprovedTimingValues(uint32_t baudRate,
+ uint32_t baudRateFD,
+ uint32_t sourceClock_Hz,
+ flexcan_timing_config_t *pTimingConfig)
+{
+ /* observe baud rate maximums */
+ assert(baudRate <= MAX_CAN_BAUDRATE);
+ assert(baudRateFD <= MAX_CANFD_BAUDRATE);
+
+ uint32_t clk;
+ uint32_t tqNum; /* Numbers of TQ. */
+ bool fgRet = false;
+
+ if (FLEXCAN_CalculateImprovedTimingValuesByCBT(baudRate, sourceClock_Hz, pTimingConfig))
+ {
+ if (0U != baudRateFD)
+ {
+ /* Auto Improved Protocal timing for CBT. */
+ tqNum = FDCBT_MAX_TIME_QUANTA;
+ do
+ {
+ clk = baudRateFD * tqNum;
+ if (clk > sourceClock_Hz)
+ {
+ continue; /* tqNum too large, clk x tqNum has been exceed sourceClock_Hz. */
+ }
+
+ if ((sourceClock_Hz / clk * clk) != sourceClock_Hz)
+ {
+ continue; /* Non-supporting: the frequency of clock source is not divisible by target baud rate,
+ the user should change a divisible baud rate. */
+ }
+
+ pTimingConfig->fpreDivider = (uint16_t)(sourceClock_Hz / clk - 1U);
+ if (pTimingConfig->fpreDivider > MAX_FPRESDIV)
+ {
+ break; /* The frequency of source clock is too large or the baud rate is too small, the pre-divider
+ could not handle it. */
+ }
+
+ /* Get the best CANFD data bus timing configuration. */
+ if (FLEXCAN_FDGetSegmentswithBRS(baudRateFD, tqNum, pTimingConfig))
+ {
+ fgRet = true;
+ break;
+ }
+ } while (--tqNum >= FDCBT_MIN_TIME_QUANTA);
+ }
+ else
+ {
+ fgRet = true; /* User don't use Brs feature. */
+ }
+ }
+ return fgRet;
+}
+
+/*!
+ * brief Configures a FlexCAN transmit message buffer.
+ *
+ * This function aborts the previous transmission, cleans the Message Buffer, and
+ * configures it as a Transmit Message Buffer.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The Message Buffer index.
+ * param enable Enable/disable Tx Message Buffer.
+ * - true: Enable Tx Message Buffer.
+ * - false: Disable Tx Message Buffer.
+ */
+void FLEXCAN_SetFDTxMbConfig(CAN_Type *base, uint8_t mbIdx, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint8_t cnt = 0;
+ uint8_t payload_dword = 1;
+ uint32_t dataSize;
+ dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ uint32_t availoffset = FLEXCAN_GetFDMailboxOffset(base, FLEXCAN_GetFirstValidMb(base));
+#endif
+
+ /* Inactivate Message Buffer. */
+ if (enable)
+ {
+ /* Inactivate by writing CS. */
+ mbAddr[offset] = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ }
+ else
+ {
+ mbAddr[offset] = 0x0;
+ }
+
+ /* Calculate the DWORD number, dataSize 0/1/2/3 corresponds to 8/16/32/64
+ Bytes payload. */
+ for (cnt = 0; cnt < (dataSize + 1U); cnt++)
+ {
+ payload_dword *= 2U;
+ }
+
+ /* Clean ID. */
+ mbAddr[offset + 1U] = 0x0U;
+ /* Clean Message Buffer content, DWORD by DWORD. */
+ for (cnt = 0; cnt < payload_dword; cnt++)
+ {
+ mbAddr[offset + 2U + cnt] = 0x0U;
+ }
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ mbAddr[availoffset] = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+#endif
+}
+#endif /* FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE */
+
+/*!
+ * brief Configures a FlexCAN Receive Message Buffer.
+ *
+ * This function cleans a FlexCAN build-in Message Buffer and configures it
+ * as a Receive Message Buffer.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The Message Buffer index.
+ * param pRxMbConfig Pointer to the FlexCAN Message Buffer configuration structure.
+ * param enable Enable/disable Rx Message Buffer.
+ * - true: Enable Rx Message Buffer.
+ * - false: Disable Rx Message Buffer.
+ */
+void FLEXCAN_SetRxMbConfig(CAN_Type *base, uint8_t mbIdx, const flexcan_rx_mb_config_t *pRxMbConfig, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(((NULL != pRxMbConfig) || (false == enable)));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint32_t cs_temp = 0;
+
+ /* Inactivate Message Buffer. */
+ base->MB[mbIdx].CS = 0;
+
+ /* Clean Message Buffer content. */
+ base->MB[mbIdx].ID = 0x0;
+ base->MB[mbIdx].WORD0 = 0x0;
+ base->MB[mbIdx].WORD1 = 0x0;
+
+ if (enable)
+ {
+ /* Setup Message Buffer ID. */
+ base->MB[mbIdx].ID = pRxMbConfig->id;
+
+ /* Setup Message Buffer format. */
+ if (kFLEXCAN_FrameFormatExtend == pRxMbConfig->format)
+ {
+ cs_temp |= CAN_CS_IDE_MASK;
+ }
+
+ /* Setup Message Buffer type. */
+ if (kFLEXCAN_FrameTypeRemote == pRxMbConfig->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ /* Activate Rx Message Buffer. */
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_RxMbEmpty);
+ base->MB[mbIdx].CS = cs_temp;
+ }
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Configures a FlexCAN Receive Message Buffer.
+ *
+ * This function cleans a FlexCAN build-in Message Buffer and configures it
+ * as a Receive Message Buffer.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The Message Buffer index.
+ * param pRxMbConfig Pointer to the FlexCAN Message Buffer configuration structure.
+ * param enable Enable/disable Rx Message Buffer.
+ * - true: Enable Rx Message Buffer.
+ * - false: Disable Rx Message Buffer.
+ */
+void FLEXCAN_SetFDRxMbConfig(CAN_Type *base, uint8_t mbIdx, const flexcan_rx_mb_config_t *pRxMbConfig, bool enable)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(((NULL != pRxMbConfig) || (false == enable)));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint32_t cs_temp = 0;
+ uint8_t cnt = 0;
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+ uint8_t payload_dword;
+ uint32_t dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+
+ /* Inactivate Message Buffer. */
+ mbAddr[offset] = 0U;
+
+ /* Clean Message Buffer content. */
+ mbAddr[offset + 1U] = 0U;
+ /* Calculate the DWORD number, dataSize 0/1/2/3 corresponds to 8/16/32/64
+ Bytes payload. */
+ payload_dword = (2U << dataSize);
+ for (cnt = 0; cnt < payload_dword; cnt++)
+ {
+ mbAddr[offset + 2U + cnt] = 0x0;
+ }
+
+ if (enable)
+ {
+ /* Setup Message Buffer ID. */
+ mbAddr[offset + 1U] = pRxMbConfig->id;
+
+ /* Setup Message Buffer format. */
+ if (kFLEXCAN_FrameFormatExtend == pRxMbConfig->format)
+ {
+ cs_temp |= CAN_CS_IDE_MASK;
+ }
+
+ /* Setup Message Buffer type. */
+ if (kFLEXCAN_FrameTypeRemote == pRxMbConfig->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ /* Activate Rx Message Buffer. */
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_RxMbEmpty);
+ mbAddr[offset] = cs_temp;
+ }
+}
+#endif
+
+/*!
+ * brief Configures the FlexCAN Rx FIFO.
+ *
+ * This function configures the Rx FIFO with given Rx FIFO configuration.
+ *
+ * param base FlexCAN peripheral base address.
+ * param pRxFifoConfig Pointer to the FlexCAN Rx FIFO configuration structure.
+ * param enable Enable/disable Rx FIFO.
+ * - true: Enable Rx FIFO.
+ * - false: Disable Rx FIFO.
+ */
+void FLEXCAN_SetRxFifoConfig(CAN_Type *base, const flexcan_rx_fifo_config_t *pRxFifoConfig, bool enable)
+{
+ /* Assertion. */
+ assert((NULL != pRxFifoConfig) || (false == enable));
+
+ volatile uint32_t *mbAddr;
+ uint8_t i, j, k, rffn = 0, numMbOccupy;
+ uint32_t setup_mb = 0;
+
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ if (enable)
+ {
+ assert(pRxFifoConfig->idFilterNum <= 128U);
+
+ /* Get the setup_mb value. */
+ setup_mb = (uint8_t)((base->MCR & CAN_MCR_MAXMB_MASK) >> CAN_MCR_MAXMB_SHIFT);
+ setup_mb = (setup_mb < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base)) ?
+ setup_mb :
+ (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base);
+
+ /* Determine RFFN value. */
+ for (i = 0; i <= 0xFU; i++)
+ {
+ if ((8U * (i + 1U)) >= pRxFifoConfig->idFilterNum)
+ {
+ rffn = i;
+ assert(((setup_mb - 8U) - (2U * rffn)) > 0U);
+
+ base->CTRL2 = (base->CTRL2 & ~CAN_CTRL2_RFFN_MASK) | CAN_CTRL2_RFFN(rffn);
+ break;
+ }
+ }
+
+ /* caculate the Number of Mailboxes occupied by RX Legacy FIFO and the filter. */
+ numMbOccupy = 6U + (rffn + 1U) * 2U;
+
+ /* Copy ID filter table to Message Buffer Region (Fix MISRA_C-2012 Rule 18.1). */
+ j = 0U;
+ for (i = 6U; i < numMbOccupy; i++)
+ {
+ /* Get address for current mail box. */
+ mbAddr = &(base->MB[i].CS);
+
+ /* One Mail box contain 4U DWORD registers. */
+ for (k = 0; k < 4U; k++)
+ {
+ /* Fill all valid filter in the mail box occupied by filter.
+ * Disable unused Rx FIFO Filter, the other rest of register in the last Mail box occupied by fiter set
+ * as 0xffffffff.
+ */
+ mbAddr[k] = (j < pRxFifoConfig->idFilterNum) ? (pRxFifoConfig->idFilterTable[j]) : 0xFFFFFFFFU;
+
+ /* Try to fill next filter in current Mail Box. */
+ j++;
+ }
+ }
+
+ /* Setup ID Fitlter Type. */
+ switch (pRxFifoConfig->idFilterType)
+ {
+ case kFLEXCAN_RxFifoFilterTypeA:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x0);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeB:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x1);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeC:
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x2);
+ break;
+ case kFLEXCAN_RxFifoFilterTypeD:
+ /* All frames rejected. */
+ base->MCR = (base->MCR & ~CAN_MCR_IDAM_MASK) | CAN_MCR_IDAM(0x3);
+ break;
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ assert(false);
+ break;
+ }
+
+ /* Setting Message Reception Priority. */
+ base->CTRL2 = (pRxFifoConfig->priority == kFLEXCAN_RxFifoPrioHigh) ? (base->CTRL2 & ~CAN_CTRL2_MRP_MASK) :
+ (base->CTRL2 | CAN_CTRL2_MRP_MASK);
+
+ /* Enable Rx Message FIFO. */
+ base->MCR |= CAN_MCR_RFEN_MASK;
+ }
+ else
+ {
+ rffn = (uint8_t)((base->CTRL2 & CAN_CTRL2_RFFN_MASK) >> CAN_CTRL2_RFFN_SHIFT);
+ /* caculate the Number of Mailboxes occupied by RX Legacy FIFO and the filter. */
+ numMbOccupy = 6U + (rffn + 1U) * 2U;
+
+ /* Disable Rx Message FIFO. */
+ base->MCR &= ~CAN_MCR_RFEN_MASK;
+
+ /* Clean MB0 ~ MB5 and all MB occupied by ID filters (Fix MISRA_C-2012 Rule 18.1). */
+
+ for (i = 0; i < numMbOccupy; i++)
+ {
+ FLEXCAN_SetRxMbConfig(base, i, NULL, false);
+ }
+ }
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA) && FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA)
+/*!
+ * brief Enables or disables the FlexCAN Rx FIFO DMA request.
+ *
+ * This function enables or disables the DMA feature of FlexCAN build-in Rx FIFO.
+ *
+ * param base FlexCAN peripheral base address.
+ * param enable true to enable, false to disable.
+ */
+void FLEXCAN_EnableRxFifoDMA(CAN_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Enable FlexCAN DMA. */
+ base->MCR |= CAN_MCR_DMA_MASK;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+ }
+ else
+ {
+ /* Enter Freeze Mode. */
+ FLEXCAN_EnterFreezeMode(base);
+
+ /* Disable FlexCAN DMA. */
+ base->MCR &= ~CAN_MCR_DMA_MASK;
+
+ /* Exit Freeze Mode. */
+ FLEXCAN_ExitFreezeMode(base);
+ }
+}
+#endif /* FSL_FEATURE_FLEXCAN_HAS_RX_FIFO_DMA */
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032)
+/*!
+ * FlexCAN: A frame with wrong ID or payload is transmitted into
+ * the CAN bus when the Message Buffer under transmission is
+ * either aborted or deactivated while the CAN bus is in the Bus Idle state
+ *
+ * This function to do workaround for ERR006032
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN Message Buffer index.
+ */
+static void FLEXCAN_ERRATA_6032(CAN_Type *base, volatile uint32_t *mbCSAddr)
+{
+ uint32_t dbg_temp = 0U;
+ uint32_t u32TempCS = 0U;
+ uint32_t u32Timeout = DELAY_BUSIDLE;
+ uint32_t u32TempIMASK1 = base->IMASK1;
+/*after backup all interruption, disable ALL interruption*/
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint32_t u32TempIMASK2 = base->IMASK2;
+ base->IMASK2 = 0;
+#endif
+ base->IMASK1 = 0;
+ dbg_temp = (uint32_t)(base->DBG1);
+ switch (dbg_temp & CAN_DBG1_CFSM_MASK)
+ {
+ case RXINTERMISSION:
+ if (CBN_VALUE3 == (dbg_temp & CAN_DBG1_CBN_MASK))
+ {
+ /*wait until CFSM is different from RXINTERMISSION */
+ while (RXINTERMISSION == (base->DBG1 & CAN_DBG1_CFSM_MASK))
+ {
+ __NOP();
+ }
+ }
+ break;
+ case TXINTERMISSION:
+ if (CBN_VALUE3 == (dbg_temp & CAN_DBG1_CBN_MASK))
+ {
+ /*wait until CFSM is different from TXINTERMISSION*/
+ while (TXINTERMISSION == (base->DBG1 & CAN_DBG1_CFSM_MASK))
+ {
+ __NOP();
+ }
+ }
+ break;
+ default:
+ /* To avoid MISRA-C 2012 rule 16.4 issue. */
+ break;
+ }
+ /*Anyway, BUSIDLE need to delay*/
+ if (BUSIDLE == (base->DBG1 & CAN_DBG1_CFSM_MASK))
+ {
+ while (u32Timeout-- > 0U)
+ {
+ __NOP();
+ }
+
+ /*Write 0x0 into Code field of CS word.*/
+ u32TempCS = (uint32_t)(*mbCSAddr);
+ u32TempCS &= ~CAN_CS_CODE_MASK;
+ *mbCSAddr = u32TempCS;
+ }
+ /*restore interruption*/
+ base->IMASK1 = u32TempIMASK1;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ base->IMASK2 = u32TempIMASK2;
+#endif
+}
+#endif
+
+/*!
+ * brief Writes a FlexCAN Message to the Transmit Message Buffer.
+ *
+ * This function writes a CAN Message to the specified Transmit Message Buffer
+ * and changes the Message Buffer state to start CAN Message transmit. After
+ * that the function returns immediately.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * param pTxFrame Pointer to CAN message frame to be sent.
+ * retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_WriteTxMb(CAN_Type *base, uint8_t mbIdx, const flexcan_frame_t *pTxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(NULL != pTxFrame);
+ assert(pTxFrame->length <= 8U);
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint32_t cs_temp = 0;
+ status_t status;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032)
+ FLEXCAN_ERRATA_6032(base, &(base->MB[mbIdx].CS));
+#endif
+ /* Check if Message Buffer is available. */
+ if (CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) != (base->MB[mbIdx].CS & CAN_CS_CODE_MASK))
+ {
+ /* Inactive Tx Message Buffer. */
+ base->MB[mbIdx].CS = (base->MB[mbIdx].CS & ~CAN_CS_CODE_MASK) | CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+
+ /* Fill Message ID field. */
+ base->MB[mbIdx].ID = pTxFrame->id;
+
+ /* Fill Message Format field. */
+ if ((uint32_t)kFLEXCAN_FrameFormatExtend == pTxFrame->format)
+ {
+ cs_temp |= CAN_CS_SRR_MASK | CAN_CS_IDE_MASK;
+ }
+
+ /* Fill Message Type field. */
+ if ((uint32_t)kFLEXCAN_FrameTypeRemote == pTxFrame->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) | CAN_CS_DLC(pTxFrame->length);
+
+ /* Load Message Payload. */
+ base->MB[mbIdx].WORD0 = pTxFrame->dataWord0;
+ base->MB[mbIdx].WORD1 = pTxFrame->dataWord1;
+
+ /* Activate Tx Message Buffer. */
+ base->MB[mbIdx].CS = cs_temp;
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ base->MB[FLEXCAN_GetFirstValidMb(base)].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ base->MB[FLEXCAN_GetFirstValidMb(base)].CS = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ /* Tx Message Buffer is activated, return immediately. */
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Writes a FlexCAN FD Message to the Transmit Message Buffer.
+ *
+ * This function writes a CAN FD Message to the specified Transmit Message Buffer
+ * and changes the Message Buffer state to start CAN FD Message transmit. After
+ * that the function returns immediately.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * param pTxFrame Pointer to CAN FD message frame to be sent.
+ * retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_WriteFDTxMb(CAN_Type *base, uint8_t mbIdx, const flexcan_fd_frame_t *pTxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(NULL != pTxFrame);
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ status_t status;
+ uint32_t cs_temp = 0;
+ uint8_t cnt = 0;
+ uint32_t can_cs = 0;
+ uint8_t payload_dword = 1;
+ uint32_t dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ uint32_t availoffset = FLEXCAN_GetFDMailboxOffset(base, FLEXCAN_GetFirstValidMb(base));
+#endif
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_6032)
+ FLEXCAN_ERRATA_6032(base, &(mbAddr[offset]));
+#endif
+
+ can_cs = mbAddr[offset];
+ /* Check if Message Buffer is available. */
+ if (CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) != (can_cs & CAN_CS_CODE_MASK))
+ {
+ /* Inactive Tx Message Buffer and Fill Message ID field. */
+ mbAddr[offset] = (can_cs & ~CAN_CS_CODE_MASK) | CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ mbAddr[offset + 1U] = pTxFrame->id;
+
+ /* Fill Message Format field. */
+ if ((uint32_t)kFLEXCAN_FrameFormatExtend == pTxFrame->format)
+ {
+ cs_temp |= CAN_CS_SRR_MASK | CAN_CS_IDE_MASK;
+ }
+
+ /* Fill Message Type field. */
+ if ((uint32_t)kFLEXCAN_FrameTypeRemote == pTxFrame->type)
+ {
+ cs_temp |= CAN_CS_RTR_MASK;
+ }
+
+ cs_temp |= CAN_CS_CODE(kFLEXCAN_TxMbDataOrRemote) | CAN_CS_DLC(pTxFrame->length) | CAN_CS_EDL(1) |
+ CAN_CS_BRS(pTxFrame->brs);
+
+ /* Calculate the DWORD number, dataSize 0/1/2/3 corresponds to 8/16/32/64
+ Bytes payload. */
+ for (cnt = 0; cnt < (dataSize + 1U); cnt++)
+ {
+ payload_dword *= 2U;
+ }
+
+ /* Load Message Payload and Activate Tx Message Buffer. */
+ for (cnt = 0; cnt < payload_dword; cnt++)
+ {
+ mbAddr[offset + 2U + cnt] = pTxFrame->dataWord[cnt];
+ }
+ mbAddr[offset] = cs_temp;
+
+#if ((defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5641) || \
+ (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829) && FSL_FEATURE_FLEXCAN_HAS_ERRATA_5829))
+ mbAddr[availoffset] = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+ mbAddr[availoffset] = CAN_CS_CODE(kFLEXCAN_TxMbInactive);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ /* Tx Message Buffer is activated, return immediately. */
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Reads a FlexCAN Message from Receive Message Buffer.
+ *
+ * This function reads a CAN message from a specified Receive Message Buffer.
+ * The function fills a receive CAN message frame structure with
+ * just received data and activates the Message Buffer again.
+ * The function returns immediately.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_ReadRxMb(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pRxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(NULL != pRxFrame);
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ uint32_t cs_temp;
+ uint32_t rx_code;
+ status_t status;
+
+ /* Read CS field of Rx Message Buffer to lock Message Buffer. */
+ cs_temp = base->MB[mbIdx].CS;
+ /* Get Rx Message Buffer Code field. */
+ rx_code = (cs_temp & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT;
+
+ /* Check to see if Rx Message Buffer is full. */
+ if (((uint32_t)kFLEXCAN_RxMbFull == rx_code) || ((uint32_t)kFLEXCAN_RxMbOverrun == rx_code))
+ {
+ /* Store Message ID. */
+ pRxFrame->id = base->MB[mbIdx].ID & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ pRxFrame->format = (cs_temp & CAN_CS_IDE_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameFormatExtend :
+ (uint8_t)kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ pRxFrame->type =
+ (cs_temp & CAN_CS_RTR_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameTypeRemote : (uint8_t)kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ pRxFrame->length = (uint8_t)((cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
+
+ /* Get the time stamp. */
+ pRxFrame->timestamp = (uint16_t)((cs_temp & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ /* Store Message Payload. */
+ pRxFrame->dataWord0 = base->MB[mbIdx].WORD0;
+ pRxFrame->dataWord1 = base->MB[mbIdx].WORD1;
+
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ if ((uint32_t)kFLEXCAN_RxMbFull == rx_code)
+ {
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxOverflow;
+ }
+ }
+ else
+ {
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Reads a FlexCAN FD Message from Receive Message Buffer.
+ *
+ * This function reads a CAN FD message from a specified Receive Message Buffer.
+ * The function fills a receive CAN FD message frame structure with
+ * just received data and activates the Message Buffer again.
+ * The function returns immediately.
+ *
+ * param base FlexCAN peripheral base address.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_ReadFDRxMb(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pRxFrame)
+{
+ /* Assertion. */
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+ assert(NULL != pRxFrame);
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+ status_t status;
+ uint32_t cs_temp;
+ uint8_t rx_code;
+ uint8_t cnt = 0;
+ uint32_t can_id = 0;
+ uint32_t dataSize;
+ dataSize = (base->FDCTRL & CAN_FDCTRL_MBDSR0_MASK) >> CAN_FDCTRL_MBDSR0_SHIFT;
+ uint8_t payload_dword = 1;
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+
+ /* Read CS field of Rx Message Buffer to lock Message Buffer. */
+ cs_temp = mbAddr[offset];
+ can_id = mbAddr[offset + 1U];
+
+ /* Get Rx Message Buffer Code field. */
+ rx_code = (uint8_t)((cs_temp & CAN_CS_CODE_MASK) >> CAN_CS_CODE_SHIFT);
+
+ /* Check to see if Rx Message Buffer is full. */
+ if (((uint8_t)kFLEXCAN_RxMbFull == rx_code) || ((uint8_t)kFLEXCAN_RxMbOverrun == rx_code))
+ {
+ /* Store Message ID. */
+ pRxFrame->id = can_id & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ pRxFrame->format = (cs_temp & CAN_CS_IDE_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameFormatExtend :
+ (uint8_t)kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ pRxFrame->type =
+ (cs_temp & CAN_CS_RTR_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameTypeRemote : (uint8_t)kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ pRxFrame->length = (uint8_t)((cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
+
+ /* Get the time stamp. */
+ pRxFrame->timestamp = (uint16_t)((cs_temp & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ /* Calculate the DWORD number, dataSize 0/1/2/3 corresponds to 8/16/32/64
+ Bytes payload. */
+ for (cnt = 0; cnt < (dataSize + 1U); cnt++)
+ {
+ payload_dword *= 2U;
+ }
+
+ /* Store Message Payload. */
+ for (cnt = 0; cnt < payload_dword; cnt++)
+ {
+ pRxFrame->dataWord[cnt] = mbAddr[offset + 2U + cnt];
+ }
+
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ if ((uint32_t)kFLEXCAN_RxMbFull == rx_code)
+ {
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxOverflow;
+ }
+ }
+ else
+ {
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Reads a FlexCAN Message from Rx FIFO.
+ *
+ * This function reads a CAN message from the FlexCAN build-in Rx FIFO.
+ *
+ * param base FlexCAN peripheral base address.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_ReadRxFifo(CAN_Type *base, flexcan_frame_t *pRxFrame)
+{
+ /* Assertion. */
+ assert(NULL != pRxFrame);
+
+ uint32_t cs_temp;
+ status_t status;
+
+ /* Check if Rx FIFO is Enabled. */
+ if (0U != (base->MCR & CAN_MCR_RFEN_MASK))
+ {
+ /* Read CS field of Rx Message Buffer to lock Message Buffer. */
+ cs_temp = base->MB[0].CS;
+
+ /* Read data from Rx FIFO output port. */
+ /* Store Message ID. */
+ pRxFrame->id = base->MB[0].ID & (CAN_ID_EXT_MASK | CAN_ID_STD_MASK);
+
+ /* Get the message ID and format. */
+ pRxFrame->format = (cs_temp & CAN_CS_IDE_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameFormatExtend :
+ (uint8_t)kFLEXCAN_FrameFormatStandard;
+
+ /* Get the message type. */
+ pRxFrame->type =
+ (cs_temp & CAN_CS_RTR_MASK) != 0U ? (uint8_t)kFLEXCAN_FrameTypeRemote : (uint8_t)kFLEXCAN_FrameTypeData;
+
+ /* Get the message length. */
+ pRxFrame->length = (uint8_t)((cs_temp & CAN_CS_DLC_MASK) >> CAN_CS_DLC_SHIFT);
+
+ /* Get the time stamp. */
+ pRxFrame->timestamp = (uint16_t)((cs_temp & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ /* Store Message Payload. */
+ pRxFrame->dataWord0 = base->MB[0].WORD0;
+ pRxFrame->dataWord1 = base->MB[0].WORD1;
+
+ /* Store ID Filter Hit Index. */
+ pRxFrame->idhit = (uint16_t)(base->RXFIR & CAN_RXFIR_IDHIT_MASK);
+
+ /* Read free-running timer to unlock Rx Message Buffer. */
+ (void)base->TIMER;
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Performs a polling send transaction on the CAN bus.
+ *
+ * Note that a transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * param pTxFrame Pointer to CAN message frame to be sent.
+ * retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_TransferSendBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pTxFrame)
+{
+ status_t status;
+
+ /* Write Tx Message Buffer to initiate a data sending. */
+ if (kStatus_Success == FLEXCAN_WriteTxMb(base, mbIdx, (const flexcan_frame_t *)(uint32_t)pTxFrame))
+ {
+/* Wait until CAN Message send out. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u64flag << mbIdx))
+#else
+ uint32_t u32flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u32flag << mbIdx))
+#endif
+ {
+ }
+
+/* Clean Tx Message Buffer Flag. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << mbIdx);
+#else
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << mbIdx);
+#endif
+ /*After TX MB tranfered success, update the Timestamp from MB[mbIdx].CS register*/
+ pTxFrame->timestamp = (uint16_t)((base->MB[mbIdx].CS & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Performs a polling receive transaction on the CAN bus.
+ *
+ * Note that a transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param mbIdx The FlexCAN Message Buffer index.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_TransferReceiveBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_frame_t *pRxFrame)
+{
+/* Wait until Rx Message Buffer non-empty. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u64flag << mbIdx))
+#else
+ uint32_t u32flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u32flag << mbIdx))
+#endif
+ {
+ }
+
+/* Clean Rx Message Buffer Flag. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << mbIdx);
+#else
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << mbIdx);
+#endif
+
+ /* Read Received CAN Message. */
+ return FLEXCAN_ReadRxMb(base, mbIdx, pRxFrame);
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Performs a polling send transaction on the CAN bus.
+ *
+ * Note that a transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * param pTxFrame Pointer to CAN FD message frame to be sent.
+ * retval kStatus_Success - Write Tx Message Buffer Successfully.
+ * retval kStatus_Fail - Tx Message Buffer is currently in use.
+ */
+status_t FLEXCAN_TransferFDSendBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pTxFrame)
+{
+ status_t status;
+
+ /* Write Tx Message Buffer to initiate a data sending. */
+ if (kStatus_Success == FLEXCAN_WriteFDTxMb(base, mbIdx, (const flexcan_fd_frame_t *)(uint32_t)pTxFrame))
+ {
+/* Wait until CAN Message send out. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u64flag << mbIdx))
+#else
+ uint32_t u32flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u32flag << mbIdx))
+#endif
+ {
+ }
+
+/* Clean Tx Message Buffer Flag. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << mbIdx);
+#else
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << mbIdx);
+#endif
+ /*After TX MB tranfered success, update the Timestamp from base->MB[offset for CANFD].CS register*/
+ volatile uint32_t *mbAddr = &(base->MB[0].CS);
+ uint32_t offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+ pTxFrame->timestamp = (uint16_t)((mbAddr[offset] & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Performs a polling receive transaction on the CAN bus.
+ *
+ * Note that a transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * param pRxFrame Pointer to CAN FD message frame structure for reception.
+ * retval kStatus_Success - Rx Message Buffer is full and has been read successfully.
+ * retval kStatus_FLEXCAN_RxOverflow - Rx Message Buffer is already overflowed and has been read successfully.
+ * retval kStatus_Fail - Rx Message Buffer is empty.
+ */
+status_t FLEXCAN_TransferFDReceiveBlocking(CAN_Type *base, uint8_t mbIdx, flexcan_fd_frame_t *pRxFrame)
+{
+/* Wait until Rx Message Buffer non-empty. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u64flag << mbIdx))
+#else
+ uint32_t u32flag = 1;
+ while (0U == FLEXCAN_GetMbStatusFlags(base, u32flag << mbIdx))
+#endif
+ {
+ }
+
+/* Clean Rx Message Buffer Flag. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << mbIdx);
+#else
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << mbIdx);
+#endif
+
+ /* Read Received CAN Message. */
+ return FLEXCAN_ReadFDRxMb(base, mbIdx, pRxFrame);
+}
+#endif
+
+/*!
+ * brief Performs a polling receive transaction from Rx FIFO on the CAN bus.
+ *
+ * Note that a transfer handle does not need to be created before calling this API.
+ *
+ * param base FlexCAN peripheral base pointer.
+ * param pRxFrame Pointer to CAN message frame structure for reception.
+ * retval kStatus_Success - Read Message from Rx FIFO successfully.
+ * retval kStatus_Fail - Rx FIFO is not enabled.
+ */
+status_t FLEXCAN_TransferReceiveFifoBlocking(CAN_Type *base, flexcan_frame_t *pRxFrame)
+{
+ status_t rxFifoStatus;
+
+ /* Wait until Rx FIFO non-empty. */
+ while (0U == FLEXCAN_GetMbStatusFlags(base, (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag))
+ {
+ }
+
+ /* */
+ rxFifoStatus = FLEXCAN_ReadRxFifo(base, pRxFrame);
+
+ /* Clean Rx Fifo available flag. */
+ FLEXCAN_ClearMbStatusFlags(base, (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag);
+
+ return rxFifoStatus;
+}
+
+/*!
+ * brief Initializes the FlexCAN handle.
+ *
+ * This function initializes the FlexCAN handle, which can be used for other FlexCAN
+ * transactional APIs. Usually, for a specified FlexCAN instance,
+ * call this API once to get the initialized handle.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ */
+void FLEXCAN_TransferCreateHandle(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ uint8_t instance;
+
+ /* Clean FlexCAN transfer handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Get instance from peripheral base address. */
+ instance = (uint8_t)FLEXCAN_GetInstance(base);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ s_flexcanHandle[instance] = handle;
+
+ /* Register Callback function. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ s_flexcanIsr = FLEXCAN_TransferHandleIRQ;
+
+ /* We Enable Error & Status interrupt here, because this interrupt just
+ * report current status of FlexCAN module through Callback function.
+ * It is insignificance without a available callback function.
+ */
+ if (handle->callback != NULL)
+ {
+ FLEXCAN_EnableInterrupts(
+ base, (uint32_t)kFLEXCAN_BusOffInterruptEnable | (uint32_t)kFLEXCAN_ErrorInterruptEnable |
+ (uint32_t)kFLEXCAN_RxWarningInterruptEnable | (uint32_t)kFLEXCAN_TxWarningInterruptEnable |
+ (uint32_t)kFLEXCAN_WakeUpInterruptEnable);
+ }
+ else
+ {
+ FLEXCAN_DisableInterrupts(
+ base, (uint32_t)kFLEXCAN_BusOffInterruptEnable | (uint32_t)kFLEXCAN_ErrorInterruptEnable |
+ (uint32_t)kFLEXCAN_RxWarningInterruptEnable | (uint32_t)kFLEXCAN_TxWarningInterruptEnable |
+ (uint32_t)kFLEXCAN_WakeUpInterruptEnable);
+ }
+
+ /* Enable interrupts in NVIC. */
+ (void)EnableIRQ((IRQn_Type)(s_flexcanRxWarningIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanTxWarningIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanWakeUpIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanErrorIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanBusOffIRQ[instance]));
+ (void)EnableIRQ((IRQn_Type)(s_flexcanMbIRQ[instance]));
+}
+
+/*!
+ * brief Sends a message using IRQ.
+ *
+ * This function sends a message using IRQ. This is a non-blocking function, which returns
+ * right away. When messages have been sent out, the send callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pMbXfer FlexCAN Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * retval kStatus_Success Start Tx Message Buffer sending process successfully.
+ * retval kStatus_Fail Write Tx Message Buffer failed.
+ * retval kStatus_FLEXCAN_TxBusy Tx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferSendNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pMbXfer);
+ assert(pMbXfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, pMbXfer->mbIdx));
+#endif
+
+ status_t status;
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->mbState[pMbXfer->mbIdx])
+ {
+ /* Distinguish transmit type. */
+ if ((uint32_t)kFLEXCAN_FrameTypeRemote == pMbXfer->frame->type)
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateTxRemote;
+ }
+ else
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateTxData;
+ }
+
+ if (kStatus_Success ==
+ FLEXCAN_WriteTxMb(base, pMbXfer->mbIdx, (const flexcan_frame_t *)(uint32_t)pMbXfer->frame))
+ {
+/* Enable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u64mask << pMbXfer->mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u32mask << pMbXfer->mbIdx);
+#endif
+ status = kStatus_Success;
+ }
+ else
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+ status = kStatus_Fail;
+ }
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_TxBusy;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives a message using IRQ.
+ *
+ * This function receives a message using IRQ. This is non-blocking function, which returns
+ * right away. When the message has been received, the receive callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pMbXfer FlexCAN Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * retval kStatus_Success - Start Rx Message Buffer receiving process successfully.
+ * retval kStatus_FLEXCAN_RxBusy - Rx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferReceiveNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer)
+{
+ status_t status;
+
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pMbXfer);
+ assert(pMbXfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, pMbXfer->mbIdx));
+#endif
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->mbState[pMbXfer->mbIdx])
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateRxData;
+
+ /* Register Message Buffer. */
+ handle->mbFrameBuf[pMbXfer->mbIdx] = pMbXfer->frame;
+
+/* Enable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u64mask << pMbXfer->mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u32mask << pMbXfer->mbIdx);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxBusy;
+ }
+
+ return status;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Sends a message using IRQ.
+ *
+ * This function sends a message using IRQ. This is a non-blocking function, which returns
+ * right away. When messages have been sent out, the send callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pMbXfer FlexCAN FD Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * retval kStatus_Success Start Tx Message Buffer sending process successfully.
+ * retval kStatus_Fail Write Tx Message Buffer failed.
+ * retval kStatus_FLEXCAN_TxBusy Tx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferFDSendNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pMbXfer);
+ assert(pMbXfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, pMbXfer->mbIdx));
+#endif
+
+ status_t status;
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->mbState[pMbXfer->mbIdx])
+ {
+ /* Distinguish transmit type. */
+ if ((uint32_t)kFLEXCAN_FrameTypeRemote == pMbXfer->framefd->type)
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateTxRemote;
+ }
+ else
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateTxData;
+ }
+
+ if (kStatus_Success ==
+ FLEXCAN_WriteFDTxMb(base, pMbXfer->mbIdx, (const flexcan_fd_frame_t *)(uint32_t)pMbXfer->framefd))
+ {
+/* Enable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u64mask << pMbXfer->mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u32mask << pMbXfer->mbIdx);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+ status = kStatus_Fail;
+ }
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_TxBusy;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives a message using IRQ.
+ *
+ * This function receives a message using IRQ. This is non-blocking function, which returns
+ * right away. When the message has been received, the receive callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pMbXfer FlexCAN FD Message Buffer transfer structure. See the #flexcan_mb_transfer_t.
+ * retval kStatus_Success - Start Rx Message Buffer receiving process successfully.
+ * retval kStatus_FLEXCAN_RxBusy - Rx Message Buffer is in use.
+ */
+status_t FLEXCAN_TransferFDReceiveNonBlocking(CAN_Type *base, flexcan_handle_t *handle, flexcan_mb_transfer_t *pMbXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pMbXfer);
+ assert(pMbXfer->mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, pMbXfer->mbIdx));
+#endif
+
+ status_t status;
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->mbState[pMbXfer->mbIdx])
+ {
+ handle->mbState[pMbXfer->mbIdx] = (uint8_t)kFLEXCAN_StateRxData;
+
+ /* Register Message Buffer. */
+ handle->mbFDFrameBuf[pMbXfer->mbIdx] = pMbXfer->framefd;
+
+/* Enable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u64mask << pMbXfer->mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_EnableMbInterrupts(base, u32mask << pMbXfer->mbIdx);
+#endif
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxBusy;
+ }
+
+ return status;
+}
+#endif
+
+/*!
+ * brief Receives a message from Rx FIFO using IRQ.
+ *
+ * This function receives a message using IRQ. This is a non-blocking function, which returns
+ * right away. When all messages have been received, the receive callback function is called.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param pFifoXfer FlexCAN Rx FIFO transfer structure. See the ref flexcan_fifo_transfer_t.
+ * retval kStatus_Success - Start Rx FIFO receiving process successfully.
+ * retval kStatus_FLEXCAN_RxFifoBusy - Rx FIFO is currently in use.
+ */
+status_t FLEXCAN_TransferReceiveFifoNonBlocking(CAN_Type *base,
+ flexcan_handle_t *handle,
+ flexcan_fifo_transfer_t *pFifoXfer)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(NULL != pFifoXfer);
+
+ status_t status;
+
+ /* Check if Message Buffer is idle. */
+ if ((uint8_t)kFLEXCAN_StateIdle == handle->rxFifoState)
+ {
+ handle->rxFifoState = (uint8_t)kFLEXCAN_StateRxFifo;
+
+ /* Register Message Buffer. */
+ handle->rxFifoFrameBuf = pFifoXfer->frame;
+
+ /* Enable Message Buffer Interrupt. */
+ FLEXCAN_EnableMbInterrupts(base, (uint32_t)kFLEXCAN_RxFifoOverflowFlag | (uint32_t)kFLEXCAN_RxFifoWarningFlag |
+ (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag);
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_FLEXCAN_RxFifoBusy;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the interrupt driven message send process.
+ *
+ * This function aborts the interrupt driven message send process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN Message Buffer index.
+ */
+void FLEXCAN_TransferAbortSend(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ uint16_t timestamp;
+
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+/* Disable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u64mask << mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u32mask << mbIdx);
+#endif
+
+ /* Update the TX frame 's time stamp by MB[mbIdx].cs. */
+ timestamp = (uint16_t)((base->MB[mbIdx].CS & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+ handle->timestamp[mbIdx] = timestamp;
+
+ /* Clean Message Buffer. */
+ FLEXCAN_SetTxMbConfig(base, mbIdx, true);
+
+ handle->mbState[mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+}
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+/*!
+ * brief Aborts the interrupt driven message send process.
+ *
+ * This function aborts the interrupt driven message send process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ */
+void FLEXCAN_TransferFDAbortSend(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ volatile uint32_t *mbAddr;
+ uint32_t offset;
+ uint16_t timestamp;
+
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+/* Disable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u64mask << mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u32mask << mbIdx);
+#endif
+
+ /* Update the TX frame 's time stamp by base->MB[offset for CANFD].CS. */
+ mbAddr = &(base->MB[0].CS);
+ offset = FLEXCAN_GetFDMailboxOffset(base, mbIdx);
+ timestamp = (uint16_t)((mbAddr[offset] & CAN_CS_TIME_STAMP_MASK) >> CAN_CS_TIME_STAMP_SHIFT);
+ handle->timestamp[mbIdx] = timestamp;
+
+ /* Clean Message Buffer. */
+ FLEXCAN_SetFDTxMbConfig(base, mbIdx, true);
+
+ handle->mbState[mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+}
+
+/*!
+ * brief Aborts the interrupt driven message receive process.
+ *
+ * This function aborts the interrupt driven message receive process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ */
+void FLEXCAN_TransferFDAbortReceive(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+/* Disable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u64mask << mbIdx);
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, u32mask << mbIdx);
+#endif
+
+ /* Un-register handle. */
+ handle->mbFDFrameBuf[mbIdx] = NULL;
+ handle->mbState[mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+}
+#endif
+
+/*!
+ * brief Aborts the interrupt driven message receive process.
+ *
+ * This function aborts the interrupt driven message receive process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN Message Buffer index.
+ */
+void FLEXCAN_TransferAbortReceive(CAN_Type *base, flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+ assert(mbIdx <= (base->MCR & CAN_MCR_MAXMB_MASK));
+#if !defined(NDEBUG)
+ assert(!FLEXCAN_IsMbOccupied(base, mbIdx));
+#endif
+
+/* Disable Message Buffer Interrupt. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, (u64mask << mbIdx));
+#else
+ uint32_t u32mask = 1;
+ FLEXCAN_DisableMbInterrupts(base, (u32mask << mbIdx));
+#endif
+
+ /* Un-register handle. */
+ handle->mbFrameBuf[mbIdx] = NULL;
+ handle->mbState[mbIdx] = (uint8_t)kFLEXCAN_StateIdle;
+}
+
+/*!
+ * brief Aborts the interrupt driven message receive from Rx FIFO process.
+ *
+ * This function aborts the interrupt driven message receive from Rx FIFO process.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ */
+void FLEXCAN_TransferAbortReceiveFifo(CAN_Type *base, flexcan_handle_t *handle)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+
+ /* Check if Rx FIFO is enabled. */
+ if (0U != (base->MCR & CAN_MCR_RFEN_MASK))
+ {
+ /* Disable Rx Message FIFO Interrupts. */
+ FLEXCAN_DisableMbInterrupts(base, (uint32_t)kFLEXCAN_RxFifoOverflowFlag | (uint32_t)kFLEXCAN_RxFifoWarningFlag |
+ (uint32_t)kFLEXCAN_RxFifoFrameAvlFlag);
+
+ /* Un-register handle. */
+ handle->rxFifoFrameBuf = NULL;
+ }
+
+ handle->rxFifoState = (uint8_t)kFLEXCAN_StateIdle;
+}
+
+/*!
+ * brief Gets the detail index of Mailbox's Timestamp by handle.
+ *
+ * Then function can only be used when calling non-blocking Data transfer (TX/RX) API,
+ * After TX/RX data transfer done (User can get the status by handler's callback function),
+ * we can get the detail index of Mailbox's timestamp by handle,
+ * Detail non-blocking data transfer API (TX/RX) contain.
+ * -FLEXCAN_TransferSendNonBlocking
+ * -FLEXCAN_TransferFDSendNonBlocking
+ * -FLEXCAN_TransferReceiveNonBlocking
+ * -FLEXCAN_TransferFDReceiveNonBlocking
+ * -FLEXCAN_TransferReceiveFifoNonBlocking
+ *
+ * param handle FlexCAN handle pointer.
+ * param mbIdx The FlexCAN FD Message Buffer index.
+ * return the index of mailbox 's timestamp stored in the handle.
+ *
+ */
+uint32_t FLEXCAN_GetTimeStamp(flexcan_handle_t *handle, uint8_t mbIdx)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+
+ return (uint32_t)(handle->timestamp[mbIdx]);
+}
+
+static bool FLEXCAN_CheckUnhandleInterruptEvents(CAN_Type *base)
+{
+ uint64_t tempmask;
+ uint64_t tempflag;
+ bool fgRet = false;
+
+ /* Checking exist error flag. */
+ if (0U == (FLEXCAN_GetStatusFlags(base) &
+ ((uint32_t)kFLEXCAN_TxWarningIntFlag | (uint32_t)kFLEXCAN_RxWarningIntFlag |
+ (uint32_t)kFLEXCAN_BusOffIntFlag | (uint32_t)kFLEXCAN_ErrorIntFlag | (uint32_t)kFLEXCAN_WakeUpIntFlag)))
+ {
+ tempmask = (uint64_t)base->IMASK1;
+ tempflag = (uint64_t)base->IFLAG1;
+
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ /* Checking whether exist MB interrupt status and legacy RX FIFO interrupt status. */
+ tempmask |= ((uint64_t)base->IMASK2) << 32;
+ tempflag |= ((uint64_t)base->IFLAG2) << 32;
+#endif
+ fgRet = (0U != (tempmask & tempflag));
+ }
+ else
+ {
+ fgRet = true;
+ }
+
+ return fgRet;
+}
+
+static status_t FLEXCAN_SubHandlerForDataTransfered(CAN_Type *base, flexcan_handle_t *handle, uint32_t *pResult)
+{
+ status_t status = kStatus_FLEXCAN_UnHandled;
+ uint32_t result = 0xFFU;
+
+ /* For this implementation, we solve the Message with lowest MB index first. */
+ for (result = 0U; result < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base); result++)
+ {
+ /* Get the lowest unhandled Message Buffer */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ if (0U != FLEXCAN_GetMbStatusFlags(base, u64flag << result))
+#else
+ uint32_t u32flag = 1;
+ if (0U != FLEXCAN_GetMbStatusFlags(base, u32flag << result))
+#endif
+ {
+ if (FLEXCAN_IsMbIntEnabled(base, (uint8_t)result))
+ {
+ break;
+ }
+ }
+ }
+
+ /* find Message to deal with. */
+ if (result < (uint32_t)FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(base))
+ {
+ /* Solve Legacy Rx FIFO interrupt. */
+ if (((uint8_t)kFLEXCAN_StateIdle != handle->rxFifoState) && (result <= (uint32_t)CAN_IFLAG1_BUF7I_SHIFT))
+ {
+ uint32_t u32mask = 1;
+ switch (u32mask << result)
+ {
+ case kFLEXCAN_RxFifoOverflowFlag:
+ status = kStatus_FLEXCAN_RxFifoOverflow;
+ break;
+
+ case kFLEXCAN_RxFifoWarningFlag:
+ status = kStatus_FLEXCAN_RxFifoWarning;
+ break;
+
+ case kFLEXCAN_RxFifoFrameAvlFlag:
+ status = FLEXCAN_ReadRxFifo(base, handle->rxFifoFrameBuf);
+ if (kStatus_Success == status)
+ {
+ /* Align the current (index 0) rxfifo timestamp to the timestamp array by handle. */
+ handle->timestamp[0] = handle->rxFifoFrameBuf->timestamp;
+ status = kStatus_FLEXCAN_RxFifoIdle;
+ }
+ FLEXCAN_TransferAbortReceiveFifo(base, handle);
+ break;
+
+ default:
+ status = kStatus_FLEXCAN_UnHandled;
+ break;
+ }
+ }
+ else
+ {
+ /* Get current State of Message Buffer. */
+ switch (handle->mbState[result])
+ {
+ /* Solve Rx Data Frame. */
+ case (uint8_t)kFLEXCAN_StateRxData:
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0U != (base->MCR & CAN_MCR_FDEN_MASK))
+ {
+ status = FLEXCAN_ReadFDRxMb(base, (uint8_t)result, handle->mbFDFrameBuf[result]);
+ if (kStatus_Success == status)
+ {
+ /* Align the current index of RX MB timestamp to the timestamp array by handle. */
+ handle->timestamp[result] = handle->mbFDFrameBuf[result]->timestamp;
+ status = kStatus_FLEXCAN_RxIdle;
+ }
+ }
+ else
+#endif
+ {
+ status = FLEXCAN_ReadRxMb(base, (uint8_t)result, handle->mbFrameBuf[result]);
+ if (kStatus_Success == status)
+ {
+ /* Align the current index of RX MB timestamp to the timestamp array by handle. */
+ handle->timestamp[result] = handle->mbFrameBuf[result]->timestamp;
+ status = kStatus_FLEXCAN_RxIdle;
+ }
+ }
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0U != (base->MCR & CAN_MCR_FDEN_MASK))
+ {
+ FLEXCAN_TransferFDAbortReceive(base, handle, (uint8_t)result);
+ }
+ else
+#endif
+ {
+ FLEXCAN_TransferAbortReceive(base, handle, (uint8_t)result);
+ }
+ break;
+
+ /* Sove Rx Remote Frame. User need to Read the frame in Mail box in time by Read from MB API. */
+ case (uint8_t)kFLEXCAN_StateRxRemote:
+ status = kStatus_FLEXCAN_RxRemote;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0U != (base->MCR & CAN_MCR_FDEN_MASK))
+ {
+ FLEXCAN_TransferFDAbortReceive(base, handle, (uint8_t)result);
+ }
+ else
+#endif
+ {
+ FLEXCAN_TransferAbortReceive(base, handle, (uint8_t)result);
+ }
+ break;
+
+ /* Solve Tx Data Frame. */
+ case (uint8_t)kFLEXCAN_StateTxData:
+ status = kStatus_FLEXCAN_TxIdle;
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
+ if (0U != (base->MCR & CAN_MCR_FDEN_MASK))
+ {
+ FLEXCAN_TransferFDAbortSend(base, handle, (uint8_t)result);
+ }
+ else
+#endif
+ {
+ FLEXCAN_TransferAbortSend(base, handle, (uint8_t)result);
+ }
+ break;
+
+ /* Solve Tx Remote Frame. */
+ case (uint8_t)kFLEXCAN_StateTxRemote:
+ handle->mbState[result] = (uint8_t)kFLEXCAN_StateRxRemote;
+ status = kStatus_FLEXCAN_TxSwitchToRx;
+ break;
+
+ default:
+ status = kStatus_FLEXCAN_UnHandled;
+ break;
+ }
+ }
+
+ /* Clear resolved Message Buffer IRQ. */
+#if (defined(FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER)) && (FSL_FEATURE_FLEXCAN_HAS_EXTENDED_FLAG_REGISTER > 0)
+ uint64_t u64flag = 1;
+ FLEXCAN_ClearMbStatusFlags(base, u64flag << result);
+#else
+ uint32_t u32flag = 1;
+ FLEXCAN_ClearMbStatusFlags(base, u32flag << result);
+#endif
+ }
+
+ *pResult = result;
+
+ return status;
+}
+
+/*!
+ * brief FlexCAN IRQ handle function.
+ *
+ * This function handles the FlexCAN Error, the Message Buffer, and the Rx FIFO IRQ request.
+ *
+ * param base FlexCAN peripheral base address.
+ * param handle FlexCAN handle pointer.
+ */
+void FLEXCAN_TransferHandleIRQ(CAN_Type *base, flexcan_handle_t *handle)
+{
+ /* Assertion. */
+ assert(NULL != handle);
+
+ status_t status;
+ uint32_t result = 0xFFU;
+ uint32_t EsrStatus = 0U;
+
+ do
+ {
+ /* Get Current FlexCAN Module Error and Status. */
+ EsrStatus = FLEXCAN_GetStatusFlags(base);
+
+ /* To handle FlexCAN Error and Status Interrupt first. */
+ if (0U != (EsrStatus & ((uint32_t)kFLEXCAN_TxWarningIntFlag | (uint32_t)kFLEXCAN_RxWarningIntFlag |
+ (uint32_t)kFLEXCAN_BusOffIntFlag | (uint32_t)kFLEXCAN_ErrorIntFlag)))
+ {
+ status = kStatus_FLEXCAN_ErrorStatus;
+ /* Clear FlexCAN Error and Status Interrupt. */
+ FLEXCAN_ClearStatusFlags(base, (uint32_t)kFLEXCAN_TxWarningIntFlag | (uint32_t)kFLEXCAN_RxWarningIntFlag |
+ (uint32_t)kFLEXCAN_BusOffIntFlag | (uint32_t)kFLEXCAN_ErrorIntFlag);
+ result = EsrStatus;
+ }
+ else if (0U != (EsrStatus & (uint32_t)kFLEXCAN_WakeUpIntFlag))
+ {
+ status = kStatus_FLEXCAN_WakeUp;
+ FLEXCAN_ClearStatusFlags(base, (uint32_t)kFLEXCAN_WakeUpIntFlag);
+ }
+ else
+ {
+ /* to handle real data transfer. */
+ status = FLEXCAN_SubHandlerForDataTransfered(base, handle, &result);
+ }
+
+ /* Calling Callback Function if has one. */
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, status, result, handle->userData);
+ }
+ } while (FLEXCAN_CheckUnhandleInterruptEvents(base));
+}
+
+#if defined(CAN0)
+void CAN0_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[0]);
+
+ s_flexcanIsr(CAN0, s_flexcanHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CAN1)
+void CAN1_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[1]);
+
+ s_flexcanIsr(CAN1, s_flexcanHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CAN2)
+void CAN2_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[2]);
+
+ s_flexcanIsr(CAN2, s_flexcanHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CAN3)
+void CAN3_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[3]);
+
+ s_flexcanIsr(CAN3, s_flexcanHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CAN4)
+void CAN4_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[4]);
+
+ s_flexcanIsr(CAN4, s_flexcanHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__CAN0)
+void DMA_FLEXCAN0_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN0)]);
+
+ s_flexcanIsr(DMA__CAN0, s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN0)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__CAN1)
+void DMA_FLEXCAN1_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN1)]);
+
+ s_flexcanIsr(DMA__CAN1, s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN1)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__CAN2)
+void DMA_FLEXCAN2_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN2)]);
+
+ s_flexcanIsr(DMA__CAN2, s_flexcanHandle[FLEXCAN_GetInstance(DMA__CAN2)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__CAN0)
+void ADMA_FLEXCAN0_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN0)]);
+
+ s_flexcanIsr(ADMA__CAN0, s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN0)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__CAN1)
+void ADMA_FLEXCAN1_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN1)]);
+
+ s_flexcanIsr(ADMA__CAN1, s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN1)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__CAN2)
+void ADMA_FLEXCAN2_INT_DriverIRQHandler(void)
+{
+ assert(NULL != s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN2)]);
+
+ s_flexcanIsr(ADMA__CAN2, s_flexcanHandle[FLEXCAN_GetInstance(ADMA__CAN2)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio.c
new file mode 100644
index 0000000000..af14b5e28f
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio"
+#endif
+
+/*< @brief user configurable flexio handle count. */
+#define FLEXIO_HANDLE_COUNT 2
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to flexio bases for each instance. */
+FLEXIO_Type *const s_flexioBases[] = FLEXIO_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to flexio clocks for each instance. */
+const clock_ip_name_t s_flexioClocks[] = FLEXIO_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*< @brief pointer to array of FLEXIO handle. */
+static void *s_flexioHandle[FLEXIO_HANDLE_COUNT];
+
+/*< @brief pointer to array of FLEXIO IP types. */
+static void *s_flexioType[FLEXIO_HANDLE_COUNT];
+
+/*< @brief pointer to array of FLEXIO Isr. */
+static flexio_isr_t s_flexioIsr[FLEXIO_HANDLE_COUNT];
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+/*!
+ * brief Get instance number for FLEXIO module.
+ *
+ * param base FLEXIO peripheral base address.
+ */
+uint32_t FLEXIO_GetInstance(FLEXIO_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexioBases); instance++)
+ {
+ if (s_flexioBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexioBases));
+
+ return instance;
+}
+
+/*!
+ * brief Configures the FlexIO with a FlexIO configuration. The configuration structure
+ * can be filled by the user or be set with default values by FLEXIO_GetDefaultConfig().
+ *
+ * Example
+ code
+ flexio_config_t config = {
+ .enableFlexio = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false
+ };
+ FLEXIO_Configure(base, &config);
+ endcode
+ *
+ * param base FlexIO peripheral base address
+ * param userConfig pointer to flexio_config_t structure
+*/
+void FLEXIO_Init(FLEXIO_Type *base, const flexio_config_t *userConfig)
+{
+ uint32_t ctrlReg = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ FLEXIO_Reset(base);
+
+ ctrlReg = base->CTRL;
+ ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ ctrlReg |= (FLEXIO_CTRL_DBGE(userConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(userConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(userConfig->enableFlexio));
+ if (!userConfig->enableInDoze)
+ {
+ ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->CTRL = ctrlReg;
+}
+
+/*!
+ * brief Gates the FlexIO clock. Call this API to stop the FlexIO clock.
+ *
+ * note After calling this API, call the FLEXO_Init to use the FlexIO module.
+ *
+ * param base FlexIO peripheral base address
+ */
+void FLEXIO_Deinit(FLEXIO_Type *base)
+{
+ FLEXIO_Enable(base, false);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_flexioClocks[FLEXIO_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO module. The configuration
+ * can used directly to call the FLEXIO_Configure().
+ *
+ * Example:
+ code
+ flexio_config_t config;
+ FLEXIO_GetDefaultConfig(&config);
+ endcode
+ *
+ * param userConfig pointer to flexio_config_t structure
+*/
+void FLEXIO_GetDefaultConfig(flexio_config_t *userConfig)
+{
+ assert(userConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(userConfig, 0, sizeof(*userConfig));
+
+ userConfig->enableFlexio = true;
+ userConfig->enableInDoze = false;
+ userConfig->enableInDebug = true;
+ userConfig->enableFastAccess = false;
+}
+
+/*!
+ * brief Resets the FlexIO module.
+ *
+ * param base FlexIO peripheral base address
+ */
+void FLEXIO_Reset(FLEXIO_Type *base)
+{
+ /*do software reset, software reset operation affect all other FLEXIO registers except CTRL*/
+ base->CTRL |= FLEXIO_CTRL_SWRST_MASK;
+ base->CTRL = 0;
+}
+
+/*!
+ * brief Gets the shifter buffer address for the DMA transfer usage.
+ *
+ * param base FlexIO peripheral base address
+ * param type Shifter type of flexio_shifter_buffer_type_t
+ * param index Shifter index
+ * return Corresponding shifter buffer index
+ */
+uint32_t FLEXIO_GetShifterBufferAddress(FLEXIO_Type *base, flexio_shifter_buffer_type_t type, uint8_t index)
+{
+ assert(index < FLEXIO_SHIFTBUF_COUNT);
+
+ uint32_t address = 0;
+
+ switch (type)
+ {
+ case kFLEXIO_ShifterBuffer:
+ address = (uint32_t) & (base->SHIFTBUF[index]);
+ break;
+
+ case kFLEXIO_ShifterBufferBitSwapped:
+ address = (uint32_t) & (base->SHIFTBUFBIS[index]);
+ break;
+
+ case kFLEXIO_ShifterBufferByteSwapped:
+ address = (uint32_t) & (base->SHIFTBUFBYS[index]);
+ break;
+
+ case kFLEXIO_ShifterBufferBitByteSwapped:
+ address = (uint32_t) & (base->SHIFTBUFBBS[index]);
+ break;
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_BYTE_SWAP
+ case kFLEXIO_ShifterBufferNibbleByteSwapped:
+ address = (uint32_t) & (base->SHIFTBUFNBS[index]);
+ break;
+
+#endif
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_HALF_WORD_SWAP
+ case kFLEXIO_ShifterBufferHalfWordSwapped:
+ address = (uint32_t) & (base->SHIFTBUFHWS[index]);
+ break;
+
+#endif
+#if defined(FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP) && FSL_FEATURE_FLEXIO_HAS_SHFT_BUFFER_NIBBLE_SWAP
+ case kFLEXIO_ShifterBufferNibbleSwapped:
+ address = (uint32_t) & (base->SHIFTBUFNIS[index]);
+ break;
+
+#endif
+ default:
+ address = (uint32_t) & (base->SHIFTBUF[index]);
+ break;
+ }
+ return address;
+}
+
+/*!
+ * brief Configures the shifter with the shifter configuration. The configuration structure
+ * covers both the SHIFTCTL and SHIFTCFG registers. To configure the shifter to the proper
+ * mode, select which timer controls the shifter to shift, whether to generate start bit/stop
+ * bit, and the polarity of start bit and stop bit.
+ *
+ * Example
+ code
+ flexio_shifter_config_t config = {
+ .timerSelect = 0,
+ .timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive,
+ .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection,
+ .pinPolarity = kFLEXIO_PinActiveLow,
+ .shifterMode = kFLEXIO_ShifterModeTransmit,
+ .inputSource = kFLEXIO_ShifterInputFromPin,
+ .shifterStop = kFLEXIO_ShifterStopBitHigh,
+ .shifterStart = kFLEXIO_ShifterStartBitLow
+ };
+ FLEXIO_SetShifterConfig(base, &config);
+ endcode
+ *
+ * param base FlexIO peripheral base address
+ * param index Shifter index
+ * param shifterConfig Pointer to flexio_shifter_config_t structure
+*/
+void FLEXIO_SetShifterConfig(FLEXIO_Type *base, uint8_t index, const flexio_shifter_config_t *shifterConfig)
+{
+ base->SHIFTCFG[index] = FLEXIO_SHIFTCFG_INSRC(shifterConfig->inputSource)
+#if FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH
+ | FLEXIO_SHIFTCFG_PWIDTH(shifterConfig->parallelWidth)
+#endif /* FSL_FEATURE_FLEXIO_HAS_PARALLEL_WIDTH */
+ | FLEXIO_SHIFTCFG_SSTOP(shifterConfig->shifterStop) |
+ FLEXIO_SHIFTCFG_SSTART(shifterConfig->shifterStart);
+
+ base->SHIFTCTL[index] =
+ FLEXIO_SHIFTCTL_TIMSEL(shifterConfig->timerSelect) | FLEXIO_SHIFTCTL_TIMPOL(shifterConfig->timerPolarity) |
+ FLEXIO_SHIFTCTL_PINCFG(shifterConfig->pinConfig) | FLEXIO_SHIFTCTL_PINSEL(shifterConfig->pinSelect) |
+ FLEXIO_SHIFTCTL_PINPOL(shifterConfig->pinPolarity) | FLEXIO_SHIFTCTL_SMOD(shifterConfig->shifterMode);
+}
+
+/*!
+ * brief Configures the timer with the timer configuration. The configuration structure
+ * covers both the TIMCTL and TIMCFG registers. To configure the timer to the proper
+ * mode, select trigger source for timer and the timer pin output and the timing for timer.
+ *
+ * Example
+ code
+ flexio_timer_config_t config = {
+ .triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(0),
+ .triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow,
+ .triggerSource = kFLEXIO_TimerTriggerSourceInternal,
+ .pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection,
+ .pinSelect = 0,
+ .pinPolarity = kFLEXIO_PinActiveHigh,
+ .timerMode = kFLEXIO_TimerModeDual8BitBaudBit,
+ .timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset,
+ .timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput,
+ .timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput,
+ .timerDisable = kFLEXIO_TimerDisableOnTimerCompare,
+ .timerEnable = kFLEXIO_TimerEnableOnTriggerHigh,
+ .timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable,
+ .timerStart = kFLEXIO_TimerStartBitEnabled
+ };
+ FLEXIO_SetTimerConfig(base, &config);
+ endcode
+ *
+ * param base FlexIO peripheral base address
+ * param index Timer index
+ * param timerConfig Pointer to the flexio_timer_config_t structure
+*/
+void FLEXIO_SetTimerConfig(FLEXIO_Type *base, uint8_t index, const flexio_timer_config_t *timerConfig)
+{
+ base->TIMCFG[index] =
+ FLEXIO_TIMCFG_TIMOUT(timerConfig->timerOutput) | FLEXIO_TIMCFG_TIMDEC(timerConfig->timerDecrement) |
+ FLEXIO_TIMCFG_TIMRST(timerConfig->timerReset) | FLEXIO_TIMCFG_TIMDIS(timerConfig->timerDisable) |
+ FLEXIO_TIMCFG_TIMENA(timerConfig->timerEnable) | FLEXIO_TIMCFG_TSTOP(timerConfig->timerStop) |
+ FLEXIO_TIMCFG_TSTART(timerConfig->timerStart);
+
+ base->TIMCMP[index] = FLEXIO_TIMCMP_CMP(timerConfig->timerCompare);
+
+ base->TIMCTL[index] = FLEXIO_TIMCTL_TRGSEL(timerConfig->triggerSelect) |
+ FLEXIO_TIMCTL_TRGPOL(timerConfig->triggerPolarity) |
+ FLEXIO_TIMCTL_TRGSRC(timerConfig->triggerSource) |
+ FLEXIO_TIMCTL_PINCFG(timerConfig->pinConfig) | FLEXIO_TIMCTL_PINSEL(timerConfig->pinSelect) |
+ FLEXIO_TIMCTL_PINPOL(timerConfig->pinPolarity) | FLEXIO_TIMCTL_TIMOD(timerConfig->timerMode);
+}
+
+/*!
+ * brief Registers the handle and the interrupt handler for the FlexIO-simulated peripheral.
+ *
+ * param base Pointer to the FlexIO simulated peripheral type.
+ * param handle Pointer to the handler for FlexIO simulated peripheral.
+ * param isr FlexIO simulated peripheral interrupt handler.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_RegisterHandleIRQ(void *base, void *handle, flexio_isr_t isr)
+{
+ assert(base != NULL);
+ assert(handle != NULL);
+ assert(isr != NULL);
+
+ uint8_t index;
+
+ /* Find the an empty handle pointer to store the handle. */
+ for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
+ {
+ if (s_flexioHandle[index] == NULL)
+ {
+ /* Register FLEXIO simulated driver base, handle and isr. */
+ s_flexioType[index] = base;
+ s_flexioHandle[index] = handle;
+ s_flexioIsr[index] = isr;
+ break;
+ }
+ }
+
+ if (index == (uint8_t)FLEXIO_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+ else
+ {
+ return kStatus_Success;
+ }
+}
+
+/*!
+ * brief Unregisters the handle and the interrupt handler for the FlexIO-simulated peripheral.
+ *
+ * param base Pointer to the FlexIO simulated peripheral type.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_UnregisterHandleIRQ(void *base)
+{
+ assert(base != NULL);
+
+ uint8_t index;
+
+ /* Find the index from base address mappings. */
+ for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
+ {
+ if (s_flexioType[index] == base)
+ {
+ /* Unregister FLEXIO simulated driver handle and isr. */
+ s_flexioType[index] = NULL;
+ s_flexioHandle[index] = NULL;
+ s_flexioIsr[index] = NULL;
+ break;
+ }
+ }
+
+ if (index == (uint8_t)FLEXIO_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+ else
+ {
+ return kStatus_Success;
+ }
+}
+
+void FLEXIO_CommonIRQHandler(void)
+{
+ uint8_t index;
+
+ for (index = 0U; index < (uint8_t)FLEXIO_HANDLE_COUNT; index++)
+ {
+ if (s_flexioHandle[index] != NULL)
+ {
+ s_flexioIsr[index](s_flexioType[index], s_flexioHandle[index]);
+ }
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void FLEXIO_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void FLEXIO0_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void FLEXIO1_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void UART2_FLEXIO_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void FLEXIO2_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
+
+void FLEXIO3_DriverIRQHandler(void)
+{
+ FLEXIO_CommonIRQHandler();
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_camera.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_camera.c
new file mode 100644
index 0000000000..3f5fb2ffd3
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_camera.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_camera.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_camera"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static uint32_t FLEXIO_CAMERA_GetInstance(FLEXIO_CAMERA_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO Camera. The configuration
+ * can be used directly for calling the FLEXIO_CAMERA_Init().
+ * Example:
+ code
+ flexio_camera_config_t config;
+ FLEXIO_CAMERA_GetDefaultConfig(&userConfig);
+ endcode
+ * param config Pointer to the flexio_camera_config_t structure
+*/
+void FLEXIO_CAMERA_GetDefaultConfig(flexio_camera_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enablecamera = false;
+ config->enableInDoze = false;
+ config->enableInDebug = false;
+ config->enableFastAccess = false;
+}
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, and configures the FlexIO Camera.
+ *
+ * param base Pointer to FLEXIO_CAMERA_Type structure
+ * param config Pointer to flexio_camera_config_t structure
+ */
+void FLEXIO_CAMERA_Init(FLEXIO_CAMERA_Type *base, const flexio_camera_config_t *config)
+{
+ assert((base != NULL) && (config != NULL));
+ assert(base->shifterCount > 0U);
+
+ uint32_t i = 0U;
+ volatile uint32_t controlVal = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_CAMERA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+
+ /* Clear the shifterConfig & timerConfig struct. */
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+ /* Configure flexio camera */
+ controlVal = base->flexioBase->CTRL;
+ controlVal &=
+ ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ controlVal |= (FLEXIO_CTRL_DBGE(config->enableInDebug) | FLEXIO_CTRL_FASTACC(config->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(config->enablecamera));
+ if (!config->enableInDoze)
+ {
+ controlVal |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+ base->flexioBase->CTRL = controlVal;
+
+ /* FLEXIO_CAMERA shifter config */
+ shifterConfig.timerSelect = base->timerIdx;
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->datPinStartIdx;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.parallelWidth = FLEXIO_CAMERA_PARALLEL_DATA_WIDTH - 1U;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromNextShifterOutput;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ /* Configure the shifters as FIFO buffer. */
+ for (i = base->shifterStartIdx; i < (base->shifterStartIdx + base->shifterCount - 1U); i++)
+ {
+ FLEXIO_SetShifterConfig(base->flexioBase, (uint8_t)i, &shifterConfig);
+ }
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ FLEXIO_SetShifterConfig(base->flexioBase, (uint8_t)i, &shifterConfig);
+
+ /* FLEXIO_CAMERA timer config, the PCLK's clk is source of timer to drive the shifter, the HREF is the selecting
+ * signal for available data. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->hrefPinIdx);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->pclkPinIdx;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetOnTimerTriggerRisingEdge;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTriggerFallingEdge;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerRisingEdge;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ timerConfig.timerCompare = 8U * base->shifterCount - 1U;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, (uint8_t)base->timerIdx, &timerConfig);
+ /* Clear flags. */
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, (((1UL << (base->shifterCount)) - 1U) << (base->shifterStartIdx)));
+ FLEXIO_ClearTimerStatusFlags(base->flexioBase, 1UL << (base->timerIdx));
+}
+
+/*!
+ * brief Resets the FLEXIO_CAMERA shifer and timer config.
+ *
+ * note After calling this API, call FLEXO_CAMERA_Init to use the FlexIO Camera module.
+ *
+ * param base Pointer to FLEXIO_CAMERA_Type structure
+ */
+void FLEXIO_CAMERA_Deinit(FLEXIO_CAMERA_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->shifterStartIdx] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterStartIdx] = 0;
+ base->flexioBase->TIMCFG[base->timerIdx] = 0;
+ base->flexioBase->TIMCMP[base->timerIdx] = 0;
+ base->flexioBase->TIMCTL[base->timerIdx] = 0;
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterStartIdx);
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIdx);
+}
+
+/*!
+ * brief Gets the FlexIO Camera status flags.
+ *
+ * param base Pointer to FLEXIO_CAMERA_Type structure
+ * return FlexIO shifter status flags
+ * arg FLEXIO_SHIFTSTAT_SSF_MASK
+ * arg 0
+ */
+uint32_t FLEXIO_CAMERA_GetStatusFlags(FLEXIO_CAMERA_Type *base)
+{
+ uint32_t status = 0;
+ status = ((FLEXIO_GetShifterStatusFlags(base->flexioBase) >> (base->shifterStartIdx)) &
+ ((1U << (base->shifterCount)) - 1U));
+ return status;
+}
+
+/*!
+ * brief Clears the receive buffer full flag manually.
+ *
+ * param base Pointer to the device.
+ * param mask status flag
+ * The parameter can be any combination of the following values:
+ * arg kFLEXIO_CAMERA_RxDataRegFullFlag
+ * arg kFLEXIO_CAMERA_RxErrorFlag
+ */
+void FLEXIO_CAMERA_ClearStatusFlags(FLEXIO_CAMERA_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_CAMERA_RxDataRegFullFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, ((1UL << (base->shifterCount)) - 1U)
+ << (base->shifterStartIdx));
+ }
+ if ((mask & (uint32_t)kFLEXIO_CAMERA_RxErrorFlag) != 0U)
+ { /* Clear error flags if they are asserted to make sure the buffer would be available. */
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, ((1UL << (base->shifterCount)) - 1U)
+ << (base->shifterStartIdx));
+ }
+}
+
+/*!
+ * brief Switches on the interrupt for receive buffer full event.
+ *
+ * param base Pointer to the device.
+ */
+void FLEXIO_CAMERA_EnableInterrupt(FLEXIO_CAMERA_Type *base)
+{
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << (base->shifterStartIdx));
+}
+
+/*!
+ * brief Switches off the interrupt for receive buffer full event.
+ *
+ * param base Pointer to the device.
+ *
+ */
+void FLEXIO_CAMERA_DisableInterrupt(FLEXIO_CAMERA_Type *base)
+{
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << (base->shifterStartIdx));
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_camera_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_camera_edma.c
new file mode 100644
index 0000000000..12bb77b020
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_camera_edma.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_camera_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_camera_edma"
+#endif
+
+/*<! Structure definition for camera_edma_private_handle_t. The structure is private. */
+typedef struct _flexio_camera_edma_private_handle
+{
+ FLEXIO_CAMERA_Type *base;
+ flexio_camera_edma_handle_t *handle;
+} flexio_camera_edma_private_handle_t;
+
+/* CAMERA EDMA transfer handle. */
+enum _flexio_camera_edma_tansfer_states
+{
+ kFLEXIO_CAMERA_RxIdle, /* RX idle. */
+ kFLEXIO_CAMERA_RxBusy /* RX busy. */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*< @brief user configurable flexio camera handle count. */
+#define FLEXIO_CAMERA_HANDLE_COUNT 1
+
+/*<! Private handle only used for internally. */
+static flexio_camera_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_CAMERA_HANDLE_COUNT];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief FLEXIO CAMERA EDMA receive finished callback function.
+ *
+ * This function is called when FLEXIO CAMERA EDMA receive finished. It disables the CAMERA
+ * RX EDMA request and sends @ref kStatus_FLEXIO_CAMERA_RxIdle to CAMERA callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_CAMERA_TransferReceiveEDMACallback(edma_handle_t *handle,
+ void *param,
+ bool transferDone,
+ uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void FLEXIO_CAMERA_TransferReceiveEDMACallback(edma_handle_t *handle,
+ void *param,
+ bool transferDone,
+ uint32_t tcds)
+{
+ flexio_camera_edma_private_handle_t *cameraPrivateHandle = (flexio_camera_edma_private_handle_t *)param;
+
+ /* Avoid the warning for unused variables. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ FLEXIO_CAMERA_TransferAbortReceiveEDMA(cameraPrivateHandle->base, cameraPrivateHandle->handle);
+
+ if (cameraPrivateHandle->handle->callback != NULL)
+ {
+ cameraPrivateHandle->handle->callback(cameraPrivateHandle->base, cameraPrivateHandle->handle,
+ kStatus_FLEXIO_CAMERA_RxIdle, cameraPrivateHandle->handle->userData);
+ }
+ }
+}
+/*!
+ * brief Initializes the Camera handle, which is used in transactional functions.
+ *
+ * param base Pointer to the FLEXIO_CAMERA_Type.
+ * param handle Pointer to flexio_camera_edma_handle_t structure.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * param rxEdmaHandle User requested DMA handle for RX DMA transfer.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO Camera eDMA type/handle table out of range.
+ */
+status_t FLEXIO_CAMERA_TransferCreateHandleEDMA(FLEXIO_CAMERA_Type *base,
+ flexio_camera_edma_handle_t *handle,
+ flexio_camera_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *rxEdmaHandle)
+{
+ assert(handle != NULL);
+
+ uint8_t index;
+
+ /* Find the an empty handle pointer to store the handle. */
+ for (index = 0U; index < (uint8_t)FLEXIO_CAMERA_HANDLE_COUNT; index++)
+ {
+ if (s_edmaPrivateHandle[index].base == NULL)
+ {
+ s_edmaPrivateHandle[index].base = base;
+ s_edmaPrivateHandle[index].handle = handle;
+ break;
+ }
+ }
+
+ if (index == (uint8_t)FLEXIO_CAMERA_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ s_edmaPrivateHandle[index].base = base;
+ s_edmaPrivateHandle[index].handle = handle;
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->rxState = (uint8_t)kFLEXIO_CAMERA_RxIdle;
+ handle->rxEdmaHandle = rxEdmaHandle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Configure RX. */
+ if (rxEdmaHandle != NULL)
+ {
+ EDMA_SetCallback(handle->rxEdmaHandle, FLEXIO_CAMERA_TransferReceiveEDMACallback, &s_edmaPrivateHandle);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives data using eDMA.
+ *
+ * This function receives data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * param base Pointer to the FLEXIO_CAMERA_Type.
+ * param handle Pointer to the flexio_camera_edma_handle_t structure.
+ * param xfer Camera eDMA transfer structure, see #flexio_camera_transfer_t.
+ * retval kStatus_Success if succeeded, others failed.
+ * retval kStatus_CAMERA_RxBusy Previous transfer on going.
+ */
+status_t FLEXIO_CAMERA_TransferReceiveEDMA(FLEXIO_CAMERA_Type *base,
+ flexio_camera_edma_handle_t *handle,
+ flexio_camera_transfer_t *xfer)
+{
+ assert(handle->rxEdmaHandle != NULL);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* If previous RX not finished. */
+ if ((uint8_t)kFLEXIO_CAMERA_RxBusy == handle->rxState)
+ {
+ status = kStatus_FLEXIO_CAMERA_RxBusy;
+ }
+ else
+ {
+ handle->rxState = (uint8_t)kFLEXIO_CAMERA_RxBusy;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, (uint32_t *)FLEXIO_CAMERA_GetRxBufferAddress(base), 32,
+ (uint32_t *)xfer->dataAddress, 32, 32, xfer->dataNum, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO CAMERA handle */
+ handle->nbytes = 32;
+
+ /* Submit transfer. */
+ (void)EDMA_SubmitTransfer(handle->rxEdmaHandle, &xferConfig);
+ EDMA_StartTransfer(handle->rxEdmaHandle);
+ /* Enable CAMERA RX EDMA. */
+ FLEXIO_CAMERA_EnableRxDMA(base, true);
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the receive data which used the eDMA.
+ *
+ * This function aborts the receive data which used the eDMA.
+ *
+ * param base Pointer to the FLEXIO_CAMERA_Type.
+ * param handle Pointer to the flexio_camera_edma_handle_t structure.
+ */
+void FLEXIO_CAMERA_TransferAbortReceiveEDMA(FLEXIO_CAMERA_Type *base, flexio_camera_edma_handle_t *handle)
+{
+ assert(handle->rxEdmaHandle != NULL);
+
+ /* Disable CAMERA RX EDMA. */
+ FLEXIO_CAMERA_EnableRxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_StopTransfer(handle->rxEdmaHandle);
+
+ handle->rxState = (uint8_t)kFLEXIO_CAMERA_RxIdle;
+}
+
+/*!
+ * brief Gets the remaining bytes to be received.
+ *
+ * This function gets the number of bytes still not received.
+ *
+ * param base Pointer to the FLEXIO_CAMERA_Type.
+ * param handle Pointer to the flexio_camera_edma_handle_t structure.
+ * param count Number of bytes sent so far by the non-blocking transaction.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_InvalidArgument The count parameter is invalid.
+ */
+status_t FLEXIO_CAMERA_TransferGetReceiveCountEDMA(FLEXIO_CAMERA_Type *base,
+ flexio_camera_edma_handle_t *handle,
+ size_t *count)
+{
+ assert(handle->rxEdmaHandle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((uint8_t)kFLEXIO_CAMERA_RxBusy == handle->rxState)
+ {
+ *count = (handle->rxSize -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel));
+ }
+ else
+ {
+ *count = handle->rxSize;
+ }
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2c_master.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2c_master.c
new file mode 100644
index 0000000000..43b5bc1b88
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2c_master.c
@@ -0,0 +1,1258 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_i2c_master.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_i2c_master"
+#endif
+
+/*! @brief FLEXIO I2C transfer state */
+enum _flexio_i2c_master_transfer_states
+{
+ kFLEXIO_I2C_Idle = 0x0U, /*!< I2C bus idle */
+ kFLEXIO_I2C_Start = 0x1U, /*!< I2C start phase */
+ kFLEXIO_I2C_SendCommand = 0x2U, /*!< Send command byte phase */
+ kFLEXIO_I2C_SendData = 0x3U, /*!< Send data transfer phase*/
+ kFLEXIO_I2C_ReceiveDataBegin = 0x4U, /*!< Receive data begin transfer phase*/
+ kFLEXIO_I2C_ReceiveData = 0x5U, /*!< Receive data transfer phase*/
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Set up master transfer, send slave address and decide the initial
+ * transfer state.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param transfer pointer to flexio_i2c_master_transfer_t structure
+ */
+static status_t FLEXIO_I2C_MasterTransferInitStateMachine(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_t *xfer);
+
+/*!
+ * @brief Master run transfer state machine to perform a byte of transfer.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param statusFlags flexio i2c hardware status
+ * @retval kStatus_Success Successfully run state machine
+ * @retval kStatus_FLEXIO_I2C_Nak Receive Nak during transfer
+ */
+static status_t FLEXIO_I2C_MasterTransferRunStateMachine(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags);
+
+/*!
+ * @brief Complete transfer, disable interrupt and call callback.
+ *
+ * @param base pointer to FLEXIO_I2C_Type structure
+ * @param handle pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * @param status flexio transfer status
+ */
+static void FLEXIO_I2C_MasterTransferComplete(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ status_t status);
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static uint32_t FLEXIO_I2C_GetInstance(FLEXIO_I2C_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+static status_t FLEXIO_I2C_MasterTransferInitStateMachine(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_t *xfer)
+{
+ bool needRestart;
+ uint32_t byteCount;
+
+ /* Init the handle member. */
+ handle->transfer.slaveAddress = xfer->slaveAddress;
+ handle->transfer.direction = xfer->direction;
+ handle->transfer.subaddress = xfer->subaddress;
+ handle->transfer.subaddressSize = xfer->subaddressSize;
+ handle->transfer.data = xfer->data;
+ handle->transfer.dataSize = xfer->dataSize;
+ handle->transfer.flags = xfer->flags;
+ handle->transferSize = xfer->dataSize;
+
+ /* Initial state, i2c start state. */
+ handle->state = (uint8_t)kFLEXIO_I2C_Start;
+
+ /* Clear all status before transfer. */
+ FLEXIO_I2C_MasterClearStatusFlags(base, (uint32_t)kFLEXIO_I2C_ReceiveNakFlag);
+
+ /* Calculate whether need to send re-start. */
+ needRestart = (handle->transfer.subaddressSize != 0U) && (handle->transfer.direction == kFLEXIO_I2C_Read);
+ handle->needRestart = needRestart;
+
+ /* Calculate total byte count in a frame. */
+ byteCount = 1U;
+
+ if (!needRestart)
+ {
+ byteCount += handle->transfer.dataSize;
+ }
+
+ if (handle->transfer.subaddressSize != 0U)
+ {
+ byteCount += handle->transfer.subaddressSize;
+ }
+
+ /* Configure data count. */
+ if (FLEXIO_I2C_MasterSetTransferCount(base, (uint16_t)byteCount) != kStatus_Success)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Configure timer1 disable condition. */
+ uint32_t tmpConfig = base->flexioBase->TIMCFG[base->timerIndex[1]];
+ tmpConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK;
+ tmpConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnPreTimerDisable);
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = tmpConfig;
+
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+ {
+ }
+#endif
+
+ return kStatus_Success;
+}
+
+static status_t FLEXIO_I2C_MasterTransferRunStateMachine(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ uint32_t statusFlags)
+{
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_ReceiveNakFlag) != 0U)
+ {
+ /* Clear receive nak flag. */
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+
+ if ((!((handle->state == (uint8_t)kFLEXIO_I2C_SendData) && (handle->transfer.dataSize == 0U))) &&
+ (!(((handle->state == (uint8_t)kFLEXIO_I2C_ReceiveData) ||
+ (handle->state == (uint8_t)kFLEXIO_I2C_ReceiveDataBegin)) &&
+ (handle->transfer.dataSize == 1U))))
+ {
+ (void)FLEXIO_I2C_MasterReadByte(base);
+
+ FLEXIO_I2C_MasterAbortStop(base);
+
+ /* Delay one clk cycle to ensure the bus is idle. */
+ SDK_DelayAtLeastUs(1000000UL / base->baudrate, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
+
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+
+ return kStatus_FLEXIO_I2C_Nak;
+ }
+ }
+
+ if (((statusFlags & (uint8_t)kFLEXIO_I2C_RxFullFlag) != 0U) && (handle->state != (uint8_t)kFLEXIO_I2C_ReceiveData))
+ {
+ (void)FLEXIO_I2C_MasterReadByte(base);
+ }
+
+ switch (handle->state)
+ {
+ /* Initial state, i2c start state. */
+ case (uint8_t)kFLEXIO_I2C_Start:
+ /* Send address byte first. */
+ if (handle->needRestart)
+ {
+ FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, kFLEXIO_I2C_Write);
+ }
+ else
+ {
+ FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, handle->transfer.direction);
+ }
+ if (handle->transfer.subaddressSize == 0U)
+ {
+ if (handle->transfer.direction == kFLEXIO_I2C_Write)
+ {
+ /* Next state, send data. */
+ handle->state = (uint8_t)kFLEXIO_I2C_SendData;
+ }
+ else
+ {
+ /* Next state, receive data begin. */
+ handle->state = (uint8_t)kFLEXIO_I2C_ReceiveDataBegin;
+ }
+ }
+ else
+ {
+ /* Next state, send command byte. */
+ handle->state = (uint8_t)kFLEXIO_I2C_SendCommand;
+ }
+ break;
+
+ /* Check address only needed for transfer with subaddress */
+ case (uint8_t)kFLEXIO_I2C_SendCommand:
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ if (handle->transfer.subaddressSize > 0U)
+ {
+ handle->transfer.subaddressSize--;
+ FLEXIO_I2C_MasterWriteByte(
+ base, ((handle->transfer.subaddress) >> (8U * handle->transfer.subaddressSize)));
+
+ if (handle->transfer.subaddressSize == 0U)
+ {
+ /* Load re-start in advance. */
+ if (handle->transfer.direction == kFLEXIO_I2C_Read)
+ {
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) &
+ (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U ==
+ (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+ {
+ }
+#endif
+ FLEXIO_I2C_MasterRepeatedStart(base);
+ }
+ }
+ }
+ else
+ {
+ if (handle->transfer.direction == kFLEXIO_I2C_Write)
+ {
+ /* Send first byte of data. */
+ if (handle->transfer.dataSize > 0U)
+ {
+ /* Next state, send data. */
+ handle->state = (uint8_t)kFLEXIO_I2C_SendData;
+
+ FLEXIO_I2C_MasterWriteByte(base, *handle->transfer.data);
+ handle->transfer.data++;
+ handle->transfer.dataSize--;
+ }
+ else
+ {
+ FLEXIO_I2C_MasterStop(base);
+
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag)) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag))
+ {
+ }
+#endif
+ (void)FLEXIO_I2C_MasterReadByte(base);
+
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+ }
+ }
+ else
+ {
+ (void)FLEXIO_I2C_MasterSetTransferCount(base, (uint16_t)(handle->transfer.dataSize + 1U));
+ FLEXIO_I2C_MasterStart(base, handle->transfer.slaveAddress, kFLEXIO_I2C_Read);
+
+ /* Next state, receive data begin. */
+ handle->state = (uint8_t)kFLEXIO_I2C_ReceiveDataBegin;
+ }
+ }
+ }
+ break;
+
+ /* Send command byte. */
+ case (uint8_t)kFLEXIO_I2C_SendData:
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ /* Send one byte of data. */
+ if (handle->transfer.dataSize > 0U)
+ {
+ FLEXIO_I2C_MasterWriteByte(base, *handle->transfer.data);
+
+ handle->transfer.data++;
+ handle->transfer.dataSize--;
+ }
+ else
+ {
+ FLEXIO_I2C_MasterStop(base);
+
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag)) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag))
+ {
+ }
+#endif
+ (void)FLEXIO_I2C_MasterReadByte(base);
+
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+ }
+ }
+ break;
+
+ case (uint8_t)kFLEXIO_I2C_ReceiveDataBegin:
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_RxFullFlag) != 0U)
+ {
+ handle->state = (uint8_t)kFLEXIO_I2C_ReceiveData;
+ /* Send nak at the last receive byte. */
+ if (handle->transfer.dataSize == 1U)
+ {
+ FLEXIO_I2C_MasterEnableAck(base, false);
+#if I2C_RETRY_TIMES
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+ {
+ }
+#endif
+ FLEXIO_I2C_MasterStop(base);
+ }
+ else
+ {
+ FLEXIO_I2C_MasterEnableAck(base, true);
+ }
+ }
+ else if ((statusFlags & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ /* Read one byte of data. */
+ FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU);
+ }
+ else
+ {
+ ; /* Avoid MISRA 2012 rule 15.7 */
+ }
+ break;
+
+ case (uint8_t)kFLEXIO_I2C_ReceiveData:
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_RxFullFlag) != 0U)
+ {
+ *handle->transfer.data = FLEXIO_I2C_MasterReadByte(base);
+ handle->transfer.data++;
+ if (0U != handle->transfer.dataSize--)
+ {
+ if (handle->transfer.dataSize == 0U)
+ {
+ FLEXIO_I2C_MasterDisableInterrupts(base, (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+ /* Return nak if ReceiveNakFlag is not set */
+ if ((statusFlags & (uint32_t)kFLEXIO_I2C_ReceiveNakFlag) == 0U)
+ {
+ return kStatus_FLEXIO_I2C_Nak;
+ }
+ }
+
+ /* Send nak at the last receive byte. */
+ if (handle->transfer.dataSize == 1U)
+ {
+ FLEXIO_I2C_MasterEnableAck(base, false);
+#if I2C_RETRY_TIMES
+ while (
+ (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+ {
+ }
+#endif
+ FLEXIO_I2C_MasterStop(base);
+ }
+ }
+ }
+ else if ((statusFlags & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ if (handle->transfer.dataSize > 1U)
+ {
+ FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU);
+ }
+ }
+ else
+ {
+ ; /* Avoid MISRA 2012 rule 15.7 */
+ }
+ break;
+
+ default:
+ /* Add comment to avoid MISRA violation */
+ break;
+ }
+
+ return kStatus_Success;
+}
+
+static void FLEXIO_I2C_MasterTransferComplete(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ status_t status)
+{
+ FLEXIO_I2C_MasterDisableInterrupts(
+ base, (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable | (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(base, handle, status, handle->userData);
+ }
+}
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS
+/*!
+ * brief Make sure the bus isn't already pulled down.
+ *
+ * Check the FLEXIO pin status to see whether either of SDA and SCL pin is pulled down.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure..
+ * retval kStatus_Success
+ * retval kStatus_FLEXIO_I2C_Busy
+ */
+status_t FLEXIO_I2C_CheckForBusyBus(FLEXIO_I2C_Type *base)
+{
+ uint32_t mask;
+ /* If in certain loops the SDA/SCL is continuously pulled down, then return bus busy status. */
+ /* The loop count is determined by maximum CPU clock frequency */
+ for (uint32_t i = 0U; i < SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY / 600000U; ++i)
+ {
+ mask = 1UL << base->SDAPinIndex | 1UL << base->SCLPinIndex;
+ if ((FLEXIO_ReadPinInput(base->flexioBase) & mask) == mask)
+ {
+ return kStatus_Success;
+ }
+ }
+ return kStatus_FLEXIO_I2C_Busy;
+}
+#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, and configures the FlexIO I2C
+ * hardware configuration.
+ *
+ * Example
+ code
+ FLEXIO_I2C_Type base = {
+ .flexioBase = FLEXIO,
+ .SDAPinIndex = 0,
+ .SCLPinIndex = 1,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_i2c_master_config_t config = {
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 100000
+ };
+ FLEXIO_I2C_MasterInit(base, &config, srcClock_Hz);
+ endcode
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param masterConfig Pointer to flexio_i2c_master_config_t structure.
+ * param srcClock_Hz FlexIO source clock in Hz.
+ * retval kStatus_Success Initialization successful
+ * retval kStatus_InvalidArgument The source clock exceed upper range limitation
+*/
+status_t FLEXIO_I2C_MasterInit(FLEXIO_I2C_Type *base, flexio_i2c_master_config_t *masterConfig, uint32_t srcClock_Hz)
+{
+ assert((base != NULL) && (masterConfig != NULL));
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+ uint32_t controlVal = 0;
+ uint16_t timerDiv = 0;
+ status_t result = kStatus_Success;
+
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_I2C_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Do hardware configuration. */
+ /* 1. Configure the shifter 0 for tx. */
+ shifterConfig.timerSelect = base->timerIndex[2];
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection;
+ shifterConfig.pinSelect = base->SDAPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveLow;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitHigh;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitLow;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
+
+ /* 2. Configure the shifter 1 for rx. */
+ shifterConfig.timerSelect = base->timerIndex[2];
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->SDAPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitLow;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
+
+ /*3. Configure the timer 0 and timer 1 for generating bit clock. */
+ /* timer 1 is used to config baudrate */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOpenDrainOrBidirection;
+ timerConfig.pinSelect = base->SCLPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetOnTimerPinEqualToTimerOutput;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnPreTimerDisable;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+
+ /* Set TIMCMP = (baud rate divider / 2) - 1. */
+ timerDiv = (uint16_t)(srcClock_Hz / masterConfig->baudRate_Bps) / 2U - 1U;
+ /* Calculate and assign the actual baudrate. */
+ base->baudrate = srcClock_Hz / (2U * ((uint32_t)timerDiv + 1U));
+
+ timerConfig.timerCompare = timerDiv;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[1], &timerConfig);
+
+ /* timer 0 is used to config total shift clock edges */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->SCLPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+
+ /* Set TIMCMP when confinguring transfer bytes. */
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
+
+ /* 4. Configure the timer 2 for controlling shifters. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->SCLPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveLow;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnPreTimerDisable;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerCompare;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+
+ /* Set TIMCMP[15:0] = (number of bits x 2) - 1. */
+ timerConfig.timerCompare = 8U * 2U - 1U;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[2], &timerConfig);
+
+ /* Configure FLEXIO I2C Master. */
+ controlVal = base->flexioBase->CTRL;
+ controlVal &=
+ ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ controlVal |= (FLEXIO_CTRL_DBGE(masterConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(masterConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(masterConfig->enableMaster));
+ if (!masterConfig->enableInDoze)
+ {
+ controlVal |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->flexioBase->CTRL = controlVal;
+ /* Disable internal IRQs. */
+ FLEXIO_I2C_MasterDisableInterrupts(
+ base, (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable | (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+ return result;
+}
+
+/*!
+ * brief De-initializes the FlexIO I2C master peripheral. Calling this API Resets the FlexIO I2C master
+ * shifer and timer config, module can't work unless the FLEXIO_I2C_MasterInit is called.
+ *
+ * param base pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterDeinit(FLEXIO_I2C_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCFG[base->shifterIndex[1]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[1]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[2]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[2]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[2]] = 0;
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[0]);
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[1]);
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[0]);
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[1]);
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[2]);
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO module. The configuration
+ * can be used directly for calling the FLEXIO_I2C_MasterInit().
+ *
+ * Example:
+ code
+ flexio_i2c_master_config_t config;
+ FLEXIO_I2C_MasterGetDefaultConfig(&config);
+ endcode
+ * param masterConfig Pointer to flexio_i2c_master_config_t structure.
+*/
+void FLEXIO_I2C_MasterGetDefaultConfig(flexio_i2c_master_config_t *masterConfig)
+{
+ assert(masterConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->enableMaster = true;
+ masterConfig->enableInDoze = false;
+ masterConfig->enableInDebug = true;
+ masterConfig->enableFastAccess = false;
+
+ /* Default baud rate at 100kbps. */
+ masterConfig->baudRate_Bps = 100000U;
+}
+
+/*!
+ * brief Gets the FlexIO I2C master status flags.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure
+ * return Status flag, use status flag to AND #_flexio_i2c_master_status_flags can get the related status.
+ */
+
+uint32_t FLEXIO_I2C_MasterGetStatusFlags(FLEXIO_I2C_Type *base)
+{
+ uint32_t status = 0;
+
+ status =
+ ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])) >> base->shifterIndex[0]);
+ status |=
+ (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
+ << 1U);
+ status |=
+ (((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
+ << 2U);
+
+ return status;
+}
+
+/*!
+ * brief Clears the FlexIO I2C master status flags.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param mask Status flag.
+ * The parameter can be any combination of the following values:
+ * arg kFLEXIO_I2C_RxFullFlag
+ * arg kFLEXIO_I2C_ReceiveNakFlag
+ */
+
+void FLEXIO_I2C_MasterClearStatusFlags(FLEXIO_I2C_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2C_TxEmptyFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+
+ if ((mask & (uint32_t)kFLEXIO_I2C_RxFullFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+
+ if ((mask & (uint32_t)kFLEXIO_I2C_ReceiveNakFlag) != 0U)
+ {
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Enables the FlexIO i2c master interrupt requests.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param mask Interrupt source.
+ * Currently only one interrupt request source:
+ * arg kFLEXIO_I2C_TransferCompleteInterruptEnable
+ */
+void FLEXIO_I2C_MasterEnableInterrupts(FLEXIO_I2C_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Disables the FlexIO I2C master interrupt requests.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param mask Interrupt source.
+ */
+void FLEXIO_I2C_MasterDisableInterrupts(FLEXIO_I2C_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Sets the FlexIO I2C master transfer baudrate.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure
+ * param baudRate_Bps the baud rate value in HZ
+ * param srcClock_Hz source clock in HZ
+ */
+void FLEXIO_I2C_MasterSetBaudRate(FLEXIO_I2C_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
+{
+ uint16_t timerDiv = 0;
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ /* Set TIMCMP = (baud rate divider / 2) - 1.*/
+ timerDiv = (uint16_t)((srcClock_Hz / baudRate_Bps) / 2U - 1U);
+
+ flexioBase->TIMCMP[base->timerIndex[1]] = timerDiv;
+
+ /* Calculate and assign the actual baudrate. */
+ base->baudrate = srcClock_Hz / (2U * ((uint32_t)timerDiv + 1U));
+}
+
+/*!
+ * brief Sets the number of bytes to be transferred from a start signal to a stop signal.
+ *
+ * note Call this API before a transfer begins because the timer generates a number of clocks according
+ * to the number of bytes that need to be transferred.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param count Number of bytes need to be transferred from a start signal to a re-start/stop signal
+ * retval kStatus_Success Successfully configured the count.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ */
+status_t FLEXIO_I2C_MasterSetTransferCount(FLEXIO_I2C_Type *base, uint16_t count)
+{
+ /* Calculate whether the transfer count is larger than the max value compare register can achieve */
+ if (count > ((0xFFFFUL - 1UL) / (16UL + 1UL + 1UL)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ uint32_t timerConfig = 0U;
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ flexioBase->TIMCMP[base->timerIndex[0]] = (uint32_t)count * 18U + 1U;
+ timerConfig = flexioBase->TIMCFG[base->timerIndex[0]];
+ timerConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK;
+ timerConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare);
+ flexioBase->TIMCFG[base->timerIndex[0]] = timerConfig;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sends START + 7-bit address to the bus.
+ *
+ * note This API should be called when the transfer configuration is ready to send a START signal
+ * and 7-bit address to the bus. This is a non-blocking API, which returns directly after the address
+ * is put into the data register but the address transfer is not finished on the bus. Ensure that
+ * the kFLEXIO_I2C_RxFullFlag status is asserted before calling this API.
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param address 7-bit address.
+ * param direction transfer direction.
+ * This parameter is one of the values in flexio_i2c_direction_t:
+ * arg kFLEXIO_I2C_Write: Transmit
+ * arg kFLEXIO_I2C_Read: Receive
+ */
+
+void FLEXIO_I2C_MasterStart(FLEXIO_I2C_Type *base, uint8_t address, flexio_i2c_direction_t direction)
+{
+ uint32_t data;
+
+ data = ((uint32_t)address) << 1U | ((direction == kFLEXIO_I2C_Read) ? 1U : 0U);
+
+ FLEXIO_I2C_MasterWriteByte(base, data);
+}
+
+/*!
+ * brief Sends the repeated start signal on the bus.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterRepeatedStart(FLEXIO_I2C_Type *base)
+{
+ /* Prepare for RESTART condition, no stop.*/
+ FLEXIO_I2C_MasterWriteByte(base, 0xFFFFFFFFU);
+}
+
+/*!
+ * brief Sends the stop signal on the bus.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterStop(FLEXIO_I2C_Type *base)
+{
+ /* Prepare normal stop. */
+ (void)FLEXIO_I2C_MasterSetTransferCount(base, 0x0U);
+ FLEXIO_I2C_MasterWriteByte(base, 0x0U);
+}
+
+/*!
+ * brief Sends the stop signal when transfer is still on-going.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ */
+void FLEXIO_I2C_MasterAbortStop(FLEXIO_I2C_Type *base)
+{
+ uint32_t tmpConfig;
+
+ /* Prepare abort stop. */
+ /* Disable timer 0. */
+ tmpConfig = base->flexioBase->TIMCFG[base->timerIndex[0]];
+ tmpConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK;
+ tmpConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnPinBothEdge);
+ base->flexioBase->TIMCFG[base->timerIndex[0]] = tmpConfig;
+
+ /* Disable timer 1. */
+ tmpConfig = base->flexioBase->TIMCFG[base->timerIndex[1]];
+ tmpConfig &= ~FLEXIO_TIMCFG_TIMDIS_MASK;
+ tmpConfig |= FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnPinBothEdge);
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = tmpConfig;
+}
+
+/*!
+ * brief Configures the sent ACK/NAK for the following byte.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param enable True to configure send ACK, false configure to send NAK.
+ */
+void FLEXIO_I2C_MasterEnableAck(FLEXIO_I2C_Type *base, bool enable)
+{
+ uint32_t tmpConfig = 0;
+
+ tmpConfig = base->flexioBase->SHIFTCFG[base->shifterIndex[0]];
+ tmpConfig &= ~FLEXIO_SHIFTCFG_SSTOP_MASK;
+ if (enable)
+ {
+ tmpConfig |= FLEXIO_SHIFTCFG_SSTOP(kFLEXIO_ShifterStopBitLow);
+ }
+ else
+ {
+ tmpConfig |= FLEXIO_SHIFTCFG_SSTOP(kFLEXIO_ShifterStopBitHigh);
+ }
+ base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = tmpConfig;
+}
+
+/*!
+ * brief Sends a buffer of data in bytes.
+ *
+ * note This function blocks via polling until all bytes have been sent.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param txBuff The data bytes to send.
+ * param txSize The number of data bytes to send.
+ * retval kStatus_Success Successfully write data.
+ * retval kStatus_FLEXIO_I2C_Nak Receive NAK during writing data.
+ * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2C_MasterWriteBlocking(FLEXIO_I2C_Type *base, const uint8_t *txBuff, uint8_t txSize)
+{
+ assert(txBuff != NULL);
+ assert(txSize != 0U);
+
+ uint32_t status;
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ while (0U != txSize--)
+ {
+ FLEXIO_I2C_MasterWriteByte(base, *txBuff++);
+
+ /* Wait until data transfer complete. */
+#if I2C_RETRY_TIMES
+ waitTimes = I2C_RETRY_TIMES;
+ while ((0U == ((status = FLEXIO_I2C_MasterGetStatusFlags(base)) & (uint32_t)kFLEXIO_I2C_RxFullFlag)) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == ((status = FLEXIO_I2C_MasterGetStatusFlags(base)) & (uint32_t)kFLEXIO_I2C_RxFullFlag))
+ {
+ }
+#endif
+
+ if ((status & (uint32_t)kFLEXIO_I2C_ReceiveNakFlag) != 0U)
+ {
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ return kStatus_FLEXIO_I2C_Nak;
+ }
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of bytes.
+ *
+ * note This function blocks via polling until all bytes have been received.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param rxBuff The buffer to store the received bytes.
+ * param rxSize The number of data bytes to be received.
+ * retval kStatus_Success Successfully read data.
+ * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2C_MasterReadBlocking(FLEXIO_I2C_Type *base, uint8_t *rxBuff, uint8_t rxSize)
+{
+ assert(rxBuff != NULL);
+ assert(rxSize != 0U);
+
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ while (0U != rxSize--)
+ {
+ /* Wait until data transfer complete. */
+#if I2C_RETRY_TIMES
+ waitTimes = I2C_RETRY_TIMES;
+ while ((0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag)) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == (FLEXIO_I2C_MasterGetStatusFlags(base) & (uint32_t)kFLEXIO_I2C_RxFullFlag))
+ {
+ }
+#endif
+ *rxBuff++ = FLEXIO_I2C_MasterReadByte(base);
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a master polling transfer on the I2C bus.
+ *
+ * note The API does not return until the transfer succeeds or fails due
+ * to receiving NAK.
+ *
+ * param base pointer to FLEXIO_I2C_Type structure.
+ * param xfer pointer to flexio_i2c_master_transfer_t structure.
+ * return status of status_t.
+ */
+status_t FLEXIO_I2C_MasterTransferBlocking(FLEXIO_I2C_Type *base, flexio_i2c_master_transfer_t *xfer)
+{
+ assert(xfer != NULL);
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS
+ /* Return an error if the bus is already in use not by us.*/
+ status_t status = FLEXIO_I2C_CheckForBusyBus(base);
+ if (status != kStatus_Success)
+ {
+ return status;
+ }
+#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/
+
+ flexio_i2c_master_handle_t tmpHandle;
+ uint32_t statusFlags;
+ status_t result = kStatus_Success;
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ /* Zero the handle. */
+ (void)memset(&tmpHandle, 0, sizeof(tmpHandle));
+
+ /* Set up transfer machine. */
+ result = FLEXIO_I2C_MasterTransferInitStateMachine(base, &tmpHandle, xfer);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ do
+ {
+ /* Wait either tx empty or rx full flag is asserted. */
+#if I2C_RETRY_TIMES
+ waitTimes = I2C_RETRY_TIMES;
+ while ((0U == ((statusFlags = FLEXIO_I2C_MasterGetStatusFlags(base)) &
+ ((uint32_t)kFLEXIO_I2C_TxEmptyFlag | (uint32_t)kFLEXIO_I2C_RxFullFlag))) &&
+ (0U != --waitTimes))
+ {
+ }
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_I2C_Timeout;
+ }
+#else
+ while (0U == ((statusFlags = FLEXIO_I2C_MasterGetStatusFlags(base)) &
+ ((uint32_t)kFLEXIO_I2C_TxEmptyFlag | (uint32_t)kFLEXIO_I2C_RxFullFlag)))
+ {
+ }
+#endif
+ FLEXIO_ClearTimerStatusFlags(base->flexioBase, ((1UL << base->timerIndex[0]) | (1UL << base->timerIndex[1])));
+ result = FLEXIO_I2C_MasterTransferRunStateMachine(base, &tmpHandle, statusFlags);
+
+ } while ((tmpHandle.state != (uint8_t)kFLEXIO_I2C_Idle) && (result == kStatus_Success));
+
+ /* Timer disable on timer compare, wait until bit clock TSF set, which means timer disable and stop has been sent.
+ */
+ while (0U == (FLEXIO_GetTimerStatusFlags(base->flexioBase) & (1UL << base->timerIndex[1])))
+ {
+ }
+
+ return result;
+}
+
+/*!
+ * brief Initializes the I2C handle which is used in transactional functions.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param handle Pointer to flexio_i2c_master_handle_t structure to store the transfer state.
+ * param callback Pointer to user callback function.
+ * param userData User param passed to the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/isr table out of range.
+ */
+status_t FLEXIO_I2C_MasterTransferCreateHandle(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Register callback and userData. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ /* Clear pending NVIC IRQ before enable NVIC IRQ. */
+ NVIC_ClearPendingIRQ(flexio_irqs[FLEXIO_I2C_GetInstance(base)]);
+ (void)EnableIRQ(flexio_irqs[FLEXIO_I2C_GetInstance(base)]);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2C_MasterTransferHandleIRQ);
+}
+
+/*!
+ * brief Performs a master interrupt non-blocking transfer on the I2C bus.
+ *
+ * note The API returns immediately after the transfer initiates.
+ * Call FLEXIO_I2C_MasterTransferGetCount to poll the transfer status to check whether
+ * the transfer is finished. If the return status is not kStatus_FLEXIO_I2C_Busy, the transfer
+ * is finished.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure
+ * param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ * param xfer pointer to flexio_i2c_master_transfer_t structure
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_FLEXIO_I2C_Busy FlexIO I2C is not idle, is running another transfer.
+ */
+status_t FLEXIO_I2C_MasterTransferNonBlocking(FLEXIO_I2C_Type *base,
+ flexio_i2c_master_handle_t *handle,
+ flexio_i2c_master_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ status_t result = kStatus_Success;
+
+#if defined(FSL_FEATURE_FLEXIO_HAS_PIN_STATUS) && FSL_FEATURE_FLEXIO_HAS_PIN_STATUS
+ /* Return an error if the bus is already in use not by us.*/
+ result = FLEXIO_I2C_CheckForBusyBus(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+#endif /*FSL_FEATURE_FLEXIO_HAS_PIN_STATUS*/
+
+ if (handle->state != (uint8_t)kFLEXIO_I2C_Idle)
+ {
+ return kStatus_FLEXIO_I2C_Busy;
+ }
+ else
+ {
+ /* Set up transfer machine. */
+ result = FLEXIO_I2C_MasterTransferInitStateMachine(base, handle, xfer);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ /* Enable both tx empty and rxfull interrupt. */
+ FLEXIO_I2C_MasterEnableInterrupts(
+ base, (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable | (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+
+ return kStatus_Success;
+ }
+}
+
+/*!
+ * brief Aborts an interrupt non-blocking transfer early.
+ *
+ * note This API can be called at any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure
+ * param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2C_MasterTransferAbort(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable interrupts. */
+ FLEXIO_I2C_MasterDisableInterrupts(
+ base, (uint32_t)kFLEXIO_I2C_TxEmptyInterruptEnable | (uint32_t)kFLEXIO_I2C_RxFullInterruptEnable);
+
+ /* Reset to idle state. */
+ handle->state = (uint8_t)kFLEXIO_I2C_Idle;
+}
+
+/*!
+ * brief Gets the master transfer status during a interrupt non-blocking transfer.
+ *
+ * param base Pointer to FLEXIO_I2C_Type structure.
+ * param handle Pointer to flexio_i2c_master_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * retval kStatus_InvalidArgument count is Invalid.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_I2C_MasterTransferGetCount(FLEXIO_I2C_Type *base, flexio_i2c_master_handle_t *handle, size_t *count)
+{
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state == (uint8_t)kFLEXIO_I2C_Idle)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->transferSize - handle->transfer.dataSize;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Master interrupt handler.
+ *
+ * param i2cType Pointer to FLEXIO_I2C_Type structure
+ * param i2cHandle Pointer to flexio_i2c_master_transfer_t structure
+ */
+void FLEXIO_I2C_MasterTransferHandleIRQ(void *i2cType, void *i2cHandle)
+{
+ FLEXIO_I2C_Type *base = (FLEXIO_I2C_Type *)i2cType;
+ flexio_i2c_master_handle_t *handle = (flexio_i2c_master_handle_t *)i2cHandle;
+ uint32_t statusFlags;
+ status_t result;
+
+ statusFlags = FLEXIO_I2C_MasterGetStatusFlags(base);
+
+ result = FLEXIO_I2C_MasterTransferRunStateMachine(base, handle, statusFlags);
+
+ if (handle->state == (uint8_t)kFLEXIO_I2C_Idle)
+ {
+ FLEXIO_I2C_MasterTransferComplete(base, handle, result);
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2s.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2s.c
new file mode 100644
index 0000000000..087e0d691d
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2s.c
@@ -0,0 +1,903 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_i2s.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_i2s"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*!@brief _sai_transfer_state*/
+enum
+{
+ kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO_I2S is busy */
+ kFLEXIO_I2S_Idle, /*!< Transfer is done. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Receive a piece of data in non-blocking way.
+ *
+ * @param base FLEXIO I2S base pointer
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+static void FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size);
+
+/*!
+ * @brief sends a piece of data in non-blocking way.
+ *
+ * @param base FLEXIO I2S base pointer
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+static void FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t FLEXIO_I2S_GetInstance(FLEXIO_I2S_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+static void FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size)
+{
+ uint32_t i = 0;
+ uint8_t j = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+ uint32_t temp = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ for (j = 0; j < bytesPerWord; j++)
+ {
+ temp = (uint32_t)(*txData);
+ data |= (temp << (8U * j));
+ txData++;
+ }
+ base->flexioBase->SHIFTBUFBIS[base->txShifterIndex] = data << (32U - bitWidth);
+ data = 0;
+ }
+}
+
+static void FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size)
+{
+ uint32_t i = 0;
+ uint8_t j = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ data = (base->flexioBase->SHIFTBUFBIS[base->rxShifterIndex]);
+ for (j = 0; j < bytesPerWord; j++)
+ {
+ *rxData = (uint8_t)((data >> (8U * j)) & 0xFFU);
+ rxData++;
+ }
+ }
+}
+
+/*!
+ * brief Initializes the FlexIO I2S.
+ *
+ * This API configures FlexIO pins and shifter to I2S and configures the FlexIO I2S with a configuration structure.
+ * The configuration structure can be filled by the user, or be set with default values by
+ * FLEXIO_I2S_GetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the FlexIO I2S driver. Otherwise, any access to the FlexIO I2S module can cause hard fault
+ * because the clock is not enabled.
+ *
+ * param base FlexIO I2S base pointer
+ * param config FlexIO I2S configure structure.
+ */
+void FLEXIO_I2S_Init(FLEXIO_I2S_Type *base, const flexio_i2s_config_t *config)
+{
+ assert((base != NULL) && (config != NULL));
+
+ flexio_shifter_config_t shifterConfig = {0};
+ flexio_timer_config_t timerConfig = {0};
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_I2S_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* reset Flexio */
+ FLEXIO_Reset(base->flexioBase);
+
+ /* Set shifter for I2S Tx data */
+ shifterConfig.timerSelect = base->bclkTimerIndex;
+ shifterConfig.pinSelect = base->txPinIndex;
+ shifterConfig.timerPolarity = config->txTimerPolarity;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ shifterConfig.pinPolarity = config->txPinPolarity;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ if (config->masterSlave == kFLEXIO_I2S_Master)
+ {
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
+ }
+ else
+ {
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->txShifterIndex, &shifterConfig);
+
+ /* Set shifter for I2S Rx Data */
+ shifterConfig.timerSelect = base->bclkTimerIndex;
+ shifterConfig.pinSelect = base->rxPinIndex;
+ shifterConfig.timerPolarity = config->rxTimerPolarity;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinPolarity = config->rxPinPolarity;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->rxShifterIndex, &shifterConfig);
+
+ /* Set Timer to I2S frame sync */
+ if (config->masterSlave == kFLEXIO_I2S_Master)
+ {
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->txPinIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceExternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ timerConfig.pinSelect = base->fsPinIndex;
+ timerConfig.pinPolarity = config->fsPinPolarity;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableNever;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ }
+ else
+ {
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->bclkPinIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->fsPinIndex;
+ timerConfig.pinPolarity = config->fsPinPolarity;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnTriggerInputShiftTriggerInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPinRisingEdge;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ }
+ FLEXIO_SetTimerConfig(base->flexioBase, base->fsTimerIndex, &timerConfig);
+
+ /* Set Timer to I2S bit clock */
+ if (config->masterSlave == kFLEXIO_I2S_Master)
+ {
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinSelect = base->bclkPinIndex;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ timerConfig.pinPolarity = config->bclkPinPolarity;
+ timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableNever;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ }
+ else
+ {
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_TIMn(base->fsTimerIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinSelect = base->bclkPinIndex;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinPolarity = config->bclkPinPolarity;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompareTriggerLow;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPinRisingEdgeTriggerHigh;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ }
+ FLEXIO_SetTimerConfig(base->flexioBase, base->bclkTimerIndex, &timerConfig);
+
+ /* If enable flexio I2S */
+ if (config->enableI2S)
+ {
+ base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
+ }
+ else
+ {
+ base->flexioBase->CTRL &= ~FLEXIO_CTRL_FLEXEN_MASK;
+ }
+}
+
+/*!
+ * brief Sets the FlexIO I2S configuration structure to default values.
+ *
+ * The purpose of this API is to get the configuration structure initialized for use in FLEXIO_I2S_Init().
+ * Users may use the initialized structure unchanged in FLEXIO_I2S_Init() or modify
+ * some fields of the structure before calling FLEXIO_I2S_Init().
+ *
+ * param config pointer to master configuration structure
+ */
+void FLEXIO_I2S_GetDefaultConfig(flexio_i2s_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->masterSlave = kFLEXIO_I2S_Master;
+ config->enableI2S = true;
+ config->txPinPolarity = kFLEXIO_PinActiveHigh;
+ config->rxPinPolarity = kFLEXIO_PinActiveHigh;
+ config->bclkPinPolarity = kFLEXIO_PinActiveHigh;
+ config->fsPinPolarity = kFLEXIO_PinActiveLow;
+ config->txTimerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ config->rxTimerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+}
+
+/*!
+ * brief De-initializes the FlexIO I2S.
+ *
+ * Calling this API resets the FlexIO I2S shifter and timer config. After calling this API,
+ * call the FLEXO_I2S_Init to use the FlexIO I2S module.
+ *
+ * param base FlexIO I2S base pointer
+ */
+void FLEXIO_I2S_Deinit(FLEXIO_I2S_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->txShifterIndex] = 0;
+ base->flexioBase->SHIFTCTL[base->txShifterIndex] = 0;
+ base->flexioBase->SHIFTCFG[base->rxShifterIndex] = 0;
+ base->flexioBase->SHIFTCTL[base->rxShifterIndex] = 0;
+ base->flexioBase->TIMCFG[base->fsTimerIndex] = 0;
+ base->flexioBase->TIMCMP[base->fsTimerIndex] = 0;
+ base->flexioBase->TIMCTL[base->fsTimerIndex] = 0;
+ base->flexioBase->TIMCFG[base->bclkTimerIndex] = 0;
+ base->flexioBase->TIMCMP[base->bclkTimerIndex] = 0;
+ base->flexioBase->TIMCTL[base->bclkTimerIndex] = 0;
+}
+
+/*!
+ * brief Enables the FlexIO I2S interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * param mask interrupt source
+ */
+void FLEXIO_I2S_EnableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyInterruptEnable) != 0UL)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->txShifterIndex);
+ }
+ if ((mask & (uint32_t)kFLEXIO_I2S_RxDataRegFullInterruptEnable) != 0UL)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->rxShifterIndex);
+ }
+}
+
+/*!
+ * brief Gets the FlexIO I2S status flags.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * return Status flag, which are ORed by the enumerators in the _flexio_i2s_status_flags.
+ */
+uint32_t FLEXIO_I2S_GetStatusFlags(FLEXIO_I2S_Type *base)
+{
+ uint32_t status = 0;
+ status = ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->txShifterIndex)) >> base->txShifterIndex);
+ status |=
+ (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) >> (base->rxShifterIndex))
+ << 1U);
+ return status;
+}
+
+/*!
+ * brief Disables the FlexIO I2S interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * param base pointer to FLEXIO_I2S_Type structure
+ * param mask interrupt source
+ */
+void FLEXIO_I2S_DisableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyInterruptEnable) != 0UL)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->txShifterIndex);
+ }
+ if ((mask & (uint32_t)kFLEXIO_I2S_RxDataRegFullInterruptEnable) != 0UL)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->rxShifterIndex);
+ }
+}
+
+/*!
+ * brief Configures the FlexIO I2S audio format in master mode.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * param format Pointer to FlexIO I2S audio data format structure.
+ * param srcClock_Hz I2S master clock source frequency in Hz.
+ */
+void FLEXIO_I2S_MasterSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format, uint32_t srcClock_Hz)
+{
+ uint32_t timDiv = srcClock_Hz / (format->sampleRate_Hz * format->bitWidth * 2U);
+ uint32_t bclkDiv = 0;
+
+ /* Shall keep bclk and fs div an integer */
+ if ((timDiv % 2UL) != 0UL)
+ {
+ timDiv += 1U;
+ }
+ /* Set Frame sync timer cmp */
+ base->flexioBase->TIMCMP[base->fsTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * timDiv - 1U);
+
+ /* Set bit clock timer cmp */
+ bclkDiv = ((timDiv / 2U - 1U) | ((format->bitWidth * 2UL - 1UL) << 8U));
+ base->flexioBase->TIMCMP[base->bclkTimerIndex] = FLEXIO_TIMCMP_CMP(bclkDiv);
+}
+
+/*!
+ * brief Configures the FlexIO I2S audio format in slave mode.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * param format Pointer to FlexIO I2S audio data format structure.
+ */
+void FLEXIO_I2S_SlaveSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format)
+{
+ /* Set Frame sync timer cmp */
+ base->flexioBase->TIMCMP[base->fsTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * 4UL - 3UL);
+
+ /* Set bit clock timer cmp */
+ base->flexioBase->TIMCMP[base->bclkTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * 2UL - 1UL);
+}
+
+/*!
+ * brief Sends data using a blocking method.
+ *
+ * note This function blocks via polling until data is ready to be sent.
+ *
+ * param base FlexIO I2S base pointer.
+ * param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * param txData Pointer to the data to be written.
+ * param size Bytes to be written.
+ * retval kStatus_Success Successfully write data.
+ * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2S_WriteBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size)
+{
+ uint32_t i = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+#if I2S_RETRY_TIMES
+ uint32_t waitTimes = I2S_RETRY_TIMES;
+#endif
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ /* Wait until it can write data */
+#if I2S_RETRY_TIMES
+ waitTimes = I2S_RETRY_TIMES;
+ while (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL) &&
+ (--waitTimes != 0U))
+ {
+ }
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_I2S_Timeout;
+ }
+#else
+ while ((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL)
+ {
+ }
+#endif
+
+ FLEXIO_I2S_WriteNonBlocking(base, bitWidth, txData, bytesPerWord);
+ txData = (uint8_t *)((uint32_t)txData + bytesPerWord);
+ }
+
+ /* Wait until the last data is sent */
+#if I2S_RETRY_TIMES
+ waitTimes = I2S_RETRY_TIMES;
+ while (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL) && (--waitTimes != 0U))
+ {
+ }
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_I2S_Timeout;
+ }
+#else
+ while ((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL)
+ {
+ }
+#endif
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a piece of data using a blocking method.
+ *
+ * note This function blocks via polling until data is ready to be sent.
+ *
+ * param base FlexIO I2S base pointer
+ * param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * param rxData Pointer to the data to be read.
+ * param size Bytes to be read.
+ * retval kStatus_Success Successfully read data.
+ * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
+ */
+status_t FLEXIO_I2S_ReadBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size)
+{
+ uint32_t i = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+#if I2S_RETRY_TIMES
+ uint32_t waitTimes = I2S_RETRY_TIMES;
+#endif
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ /* Wait until data is received */
+#if I2S_RETRY_TIMES
+ waitTimes = I2S_RETRY_TIMES;
+ while ((!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) != 0UL)) &&
+ (--waitTimes != 0U))
+ {
+ }
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_I2S_Timeout;
+ }
+#else
+ while (!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) != 0UL))
+ {
+ }
+#endif
+
+ FLEXIO_I2S_ReadNonBlocking(base, bitWidth, rxData, bytesPerWord);
+ rxData = (uint8_t *)((uint32_t)rxData + bytesPerWord);
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the FlexIO I2S handle.
+ *
+ * This function initializes the FlexIO I2S handle which can be used for other
+ * FlexIO I2S transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure
+ * param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
+ * param callback FlexIO I2S callback function, which is called while finished a block.
+ * param userData User parameter for the FlexIO I2S callback.
+ */
+void FLEXIO_I2S_TransferTxCreateHandle(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Store callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ (void)FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2S_TransferTxHandleIRQ);
+
+ /* Set the TX/RX state. */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_I2S_GetInstance(base)]);
+}
+
+/*!
+ * brief Initializes the FlexIO I2S receive handle.
+ *
+ * This function initializes the FlexIO I2S handle which can be used for other
+ * FlexIO I2S transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
+ * param callback FlexIO I2S callback function, which is called while finished a block.
+ * param userData User parameter for the FlexIO I2S callback.
+ */
+void FLEXIO_I2S_TransferRxCreateHandle(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Store callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ (void)FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2S_TransferRxHandleIRQ);
+
+ /* Set the TX/RX state. */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_I2S_GetInstance(base)]);
+}
+
+/*!
+ * brief Configures the FlexIO I2S audio format.
+ *
+ * Audio format can be changed at run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle FlexIO I2S handle pointer.
+ * param format Pointer to audio data format structure.
+ * param srcClock_Hz FlexIO I2S bit clock source frequency in Hz. This parameter should be 0 while in slave mode.
+ */
+void FLEXIO_I2S_TransferSetFormat(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_format_t *format,
+ uint32_t srcClock_Hz)
+{
+ assert((handle != NULL) && (format != NULL));
+
+ /* Set the bitWidth to handle */
+ handle->bitWidth = format->bitWidth;
+
+ /* Set sample rate */
+ if (srcClock_Hz != 0UL)
+ {
+ /* It is master */
+ FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
+ }
+ else
+ {
+ FLEXIO_I2S_SlaveSetFormat(base, format);
+ }
+}
+
+/*!
+ * brief Performs an interrupt non-blocking send transfer on FlexIO I2S.
+ *
+ * note The API returns immediately after transfer initiates.
+ * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status and check whether
+ * the transfer is finished. If the return status is 0, the transfer is finished.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * param xfer Pointer to flexio_i2s_transfer_t structure
+ * retval kStatus_Success Successfully start the data transmission.
+ * retval kStatus_FLEXIO_I2S_TxBusy Previous transmission still not finished, data not all written to TX register yet.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t FLEXIO_I2S_TransferSendNonBlocking(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->queue[handle->queueUser].data != NULL)
+ {
+ return kStatus_FLEXIO_I2S_QueueFull;
+ }
+ if ((xfer->dataSize == 0U) || (xfer->data == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Add into queue */
+ handle->queue[handle->queueUser].data = xfer->data;
+ handle->queue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+
+ /* Set the state to busy */
+ handle->state = (uint32_t)kFLEXIO_I2S_Busy;
+
+ FLEXIO_I2S_EnableInterrupts(base, kFLEXIO_I2S_TxDataRegEmptyInterruptEnable);
+
+ /* Enable Tx transfer */
+ FLEXIO_I2S_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on FlexIO I2S.
+ *
+ * note The API returns immediately after transfer initiates.
+ * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status to check whether
+ * the transfer is finished. If the return status is 0, the transfer is finished.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * param xfer Pointer to flexio_i2s_transfer_t structure
+ * retval kStatus_Success Successfully start the data receive.
+ * retval kStatus_FLEXIO_I2S_RxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t FLEXIO_I2S_TransferReceiveNonBlocking(FLEXIO_I2S_Type *base,
+ flexio_i2s_handle_t *handle,
+ flexio_i2s_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->queue[handle->queueUser].data != NULL)
+ {
+ return kStatus_FLEXIO_I2S_QueueFull;
+ }
+
+ if ((xfer->dataSize == 0U) || (xfer->data == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Add into queue */
+ handle->queue[handle->queueUser].data = xfer->data;
+ handle->queue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = (uint32_t)kFLEXIO_I2S_Busy;
+
+ /* Enable interrupt */
+ FLEXIO_I2S_EnableInterrupts(base, kFLEXIO_I2S_RxDataRegFullInterruptEnable);
+
+ /* Enable Rx transfer */
+ FLEXIO_I2S_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts the current send.
+ *
+ * note This API can be called at any time when interrupt non-blocking transfer initiates
+ * to abort the transfer in a early time.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2S_TransferAbortSend(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Stop Tx transfer and disable interrupt */
+ FLEXIO_I2S_DisableInterrupts(base, kFLEXIO_I2S_TxDataRegEmptyInterruptEnable);
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->queue, 0, sizeof(flexio_i2s_transfer_t) * FLEXIO_I2S_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Aborts the current receive.
+ *
+ * note This API can be called at any time when interrupt non-blocking transfer initiates
+ * to abort the transfer in a early time.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ */
+void FLEXIO_I2S_TransferAbortReceive(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Stop rx transfer and disable interrupt */
+ FLEXIO_I2S_DisableInterrupts(base, kFLEXIO_I2S_RxDataRegFullInterruptEnable);
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->queue, 0, sizeof(flexio_i2s_transfer_t) * FLEXIO_I2S_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Gets the remaining bytes to be sent.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * param count Bytes sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetSendCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->queue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets the remaining bytes to be received.
+ *
+ * param base Pointer to FLEXIO_I2S_Type structure.
+ * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
+ * return count Bytes received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetReceiveCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->queue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param i2sBase Pointer to FLEXIO_I2S_Type structure.
+ * param i2sHandle Pointer to flexio_i2s_handle_t structure
+ */
+void FLEXIO_I2S_TransferTxHandleIRQ(void *i2sBase, void *i2sHandle)
+{
+ assert(i2sHandle != NULL);
+
+ flexio_i2s_handle_t *handle = (flexio_i2s_handle_t *)i2sHandle;
+ FLEXIO_I2S_Type *base = (FLEXIO_I2S_Type *)i2sBase;
+ uint8_t *buffer = handle->queue[handle->queueDriver].data;
+ uint8_t dataSize = handle->bitWidth / 8U;
+
+ /* Handle error */
+ if ((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->txShifterIndex)) != 0UL)
+ {
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, (1UL << base->txShifterIndex));
+ }
+ /* Handle transfer */
+ if (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) != 0UL) &&
+ (handle->queue[handle->queueDriver].data != NULL))
+ {
+ FLEXIO_I2S_WriteNonBlocking(base, handle->bitWidth, buffer, dataSize);
+
+ /* Update internal counter */
+ handle->queue[handle->queueDriver].dataSize -= dataSize;
+ handle->queue[handle->queueDriver].data =
+ (uint8_t *)((uint32_t)handle->queue[handle->queueDriver].data + dataSize);
+ }
+
+ /* If finished a block, call the callback function */
+ if ((handle->queue[handle->queueDriver].dataSize == 0U) && (handle->queue[handle->queueDriver].data != NULL))
+ {
+ (void)memset(&handle->queue[handle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_Success, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->queue[handle->queueDriver].data == NULL)
+ {
+ FLEXIO_I2S_TransferAbortSend(base, handle);
+ }
+}
+
+/*!
+ * brief Rx interrupt handler.
+ *
+ * param i2sBase Pointer to FLEXIO_I2S_Type structure.
+ * param i2sHandle Pointer to flexio_i2s_handle_t structure.
+ */
+void FLEXIO_I2S_TransferRxHandleIRQ(void *i2sBase, void *i2sHandle)
+{
+ assert(i2sHandle != NULL);
+
+ flexio_i2s_handle_t *handle = (flexio_i2s_handle_t *)i2sHandle;
+ FLEXIO_I2S_Type *base = (FLEXIO_I2S_Type *)i2sBase;
+ uint8_t *buffer = handle->queue[handle->queueDriver].data;
+ uint8_t dataSize = handle->bitWidth / 8U;
+
+ /* Handle transfer */
+ if (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_RxDataRegFullFlag) != 0UL) &&
+ (handle->queue[handle->queueDriver].data != NULL))
+ {
+ FLEXIO_I2S_ReadNonBlocking(base, handle->bitWidth, buffer, dataSize);
+
+ /* Update internal state */
+ handle->queue[handle->queueDriver].dataSize -= dataSize;
+ handle->queue[handle->queueDriver].data =
+ (uint8_t *)((uint32_t)handle->queue[handle->queueDriver].data + dataSize);
+ }
+
+ /* If finished a block, call the callback function */
+ if ((handle->queue[handle->queueDriver].dataSize == 0U) && (handle->queue[handle->queueDriver].data != NULL))
+ {
+ (void)memset(&handle->queue[handle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_Success, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->queue[handle->queueDriver].data == NULL)
+ {
+ FLEXIO_I2S_TransferAbortReceive(base, handle);
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2s_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2s_edma.c
new file mode 100644
index 0000000000..21e3a6ff51
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_i2s_edma.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_i2s_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_i2s_edma"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
+
+/*<! Structure definition for flexio_i2s_edma_private_handle_t. The structure is private. */
+typedef struct _flexio_i2s_edma_private_handle
+{
+ FLEXIO_I2S_Type *base;
+ flexio_i2s_edma_handle_t *handle;
+} flexio_i2s_edma_private_handle_t;
+
+/*!@brief _flexio_i2s_edma_transfer_state */
+enum
+{
+ kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO I2S is busy */
+ kFLEXIO_I2S_Idle, /*!< Transfer is done. */
+};
+
+/*<! Private handle only used for internally. */
+static flexio_i2s_edma_private_handle_t s_edmaPrivateHandle[2];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief FLEXIO I2S EDMA callback for send.
+ *
+ * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief FLEXIO I2S EDMA callback for receive.
+ *
+ * @param handle pointer to flexio_i2s_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static void FLEXIO_I2S_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
+ flexio_i2s_edma_handle_t *flexio_i2sHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
+ flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+ if (flexio_i2sHandle->callback != NULL)
+ {
+ (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
+ {
+ FLEXIO_I2S_TransferAbortSendEDMA(privHandle->base, flexio_i2sHandle);
+ }
+}
+
+static void FLEXIO_I2S_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ flexio_i2s_edma_private_handle_t *privHandle = (flexio_i2s_edma_private_handle_t *)userData;
+ flexio_i2s_edma_handle_t *flexio_i2sHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
+ flexio_i2sHandle->queueDriver = (flexio_i2sHandle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+ if (flexio_i2sHandle->callback != NULL)
+ {
+ (flexio_i2sHandle->callback)(privHandle->base, flexio_i2sHandle, kStatus_Success, flexio_i2sHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (flexio_i2sHandle->queue[flexio_i2sHandle->queueDriver].data == NULL)
+ {
+ FLEXIO_I2S_TransferAbortReceiveEDMA(privHandle->base, flexio_i2sHandle);
+ }
+}
+
+/*!
+ * brief Initializes the FlexIO I2S eDMA handle.
+ *
+ * This function initializes the FlexIO I2S master DMA handle which can be used for other FlexIO I2S master
+ * transactional APIs.
+ * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S eDMA handle pointer.
+ * param callback FlexIO I2S eDMA callback function called while finished a block.
+ * param userData User parameter for callback.
+ * param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
+ */
+void FLEXIO_I2S_TransferTxCreateHandleEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaHandle)
+{
+ assert((handle != NULL) && (dmaHandle != NULL));
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set flexio_i2s base to handle */
+ handle->dmaHandle = dmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set FLEXIO I2S state to idle */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ s_edmaPrivateHandle[0].base = base;
+ s_edmaPrivateHandle[0].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaHandle, FLEXIO_I2S_TxEDMACallback, &s_edmaPrivateHandle[0]);
+}
+
+/*!
+ * brief Initializes the FlexIO I2S Rx eDMA handle.
+ *
+ * This function initializes the FlexIO I2S slave DMA handle which can be used for other FlexIO I2S master transactional
+ * APIs.
+ * Usually, for a specified FlexIO I2S instance, call this API once to get the initialized handle.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S eDMA handle pointer.
+ * param callback FlexIO I2S eDMA callback function called while finished a block.
+ * param userData User parameter for callback.
+ * param dmaHandle eDMA handle for FlexIO I2S. This handle is a static value allocated by users.
+ */
+void FLEXIO_I2S_TransferRxCreateHandleEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaHandle)
+{
+ assert((handle != NULL) && (dmaHandle != NULL));
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set flexio_i2s base to handle */
+ handle->dmaHandle = dmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set FLEXIO I2S state to idle */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+
+ s_edmaPrivateHandle[1].base = base;
+ s_edmaPrivateHandle[1].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaHandle, STCD_ADDR(handle->tcd), FLEXIO_I2S_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaHandle, FLEXIO_I2S_RxEDMACallback, &s_edmaPrivateHandle[1]);
+}
+
+/*!
+ * brief Configures the FlexIO I2S Tx audio format.
+ *
+ * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to format.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S eDMA handle pointer
+ * param format Pointer to FlexIO I2S audio data format structure.
+ * param srcClock_Hz FlexIO I2S clock source frequency in Hz, it should be 0 while in slave mode.
+ * retval kStatus_Success Audio format set successfully.
+ * retval kStatus_InvalidArgument The input arguments is invalid.
+ */
+void FLEXIO_I2S_TransferSetFormatEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_format_t *format,
+ uint32_t srcClock_Hz)
+{
+ assert((handle != NULL) && (format != NULL));
+
+ /* Configure the audio format to FLEXIO I2S registers */
+ if (srcClock_Hz != 0UL)
+ {
+ /* It is master */
+ FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
+ }
+ else
+ {
+ FLEXIO_I2S_SlaveSetFormat(base, format);
+ }
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ handle->bytesPerFrame = format->bitWidth / 8U;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO I2S transfer using DMA.
+ *
+ * note This interface returned immediately after transfer initiates. Users should call
+ * FLEXIO_I2S_GetTransferStatus to poll the transfer status and check whether the FlexIO I2S transfer is finished.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a FlexIO I2S eDMA send successfully.
+ * retval kStatus_InvalidArgument The input arguments is invalid.
+ * retval kStatus_TxBusy FlexIO I2S is busy sending data.
+ */
+status_t FLEXIO_I2S_TransferSendEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t destAddr = FLEXIO_I2S_TxGetDataRegisterAddress(base) + (4UL - handle->bytesPerFrame);
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->queue[handle->queueUser].data != NULL)
+ {
+ return kStatus_FLEXIO_I2S_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kFLEXIO_I2S_Busy;
+
+ /* Update the queue state */
+ handle->queue[handle->queueUser].data = xfer->data;
+ handle->queue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, xfer->data, handle->bytesPerFrame, (uint32_t *)destAddr, handle->bytesPerFrame,
+ handle->bytesPerFrame, xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
+ handle->nbytes = handle->bytesPerFrame;
+
+ (void)EDMA_SubmitTransfer(handle->dmaHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ FLEXIO_I2S_TxEnableDMA(base, true);
+
+ /* Enable FLEXIO I2S Tx clock */
+ FLEXIO_I2S_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO I2S receive using eDMA.
+ *
+ * note This interface returned immediately after transfer initiates. Users should call
+ * FLEXIO_I2S_GetReceiveRemainingBytes to poll the transfer status and check whether the FlexIO I2S transfer is
+ * finished.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a FlexIO I2S eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input arguments is invalid.
+ * retval kStatus_RxBusy FlexIO I2S is busy receiving data.
+ */
+status_t FLEXIO_I2S_TransferReceiveEDMA(FLEXIO_I2S_Type *base,
+ flexio_i2s_edma_handle_t *handle,
+ flexio_i2s_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t srcAddr = FLEXIO_I2S_RxGetDataRegisterAddress(base);
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->queue[handle->queueUser].data != NULL)
+ {
+ return kStatus_FLEXIO_I2S_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kFLEXIO_I2S_Busy;
+
+ /* Update queue state */
+ handle->queue[handle->queueUser].data = xfer->data;
+ handle->queue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, (uint32_t *)srcAddr, handle->bytesPerFrame, xfer->data, handle->bytesPerFrame,
+ handle->bytesPerFrame, xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO I2S handle */
+ handle->nbytes = handle->bytesPerFrame;
+
+ (void)EDMA_SubmitTransfer(handle->dmaHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ FLEXIO_I2S_RxEnableDMA(base, true);
+
+ /* Enable FLEXIO I2S Rx clock */
+ FLEXIO_I2S_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a FlexIO I2S transfer using eDMA.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ */
+void FLEXIO_I2S_TransferAbortSendEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable DMA enable bit */
+ FLEXIO_I2S_TxEnableDMA(base, false);
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+}
+
+/*!
+ * brief Aborts a FlexIO I2S receive using eDMA.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ */
+void FLEXIO_I2S_TransferAbortReceiveEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable DMA enable bit */
+ FLEXIO_I2S_RxEnableDMA(base, false);
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kFLEXIO_I2S_Idle;
+}
+
+/*!
+ * brief Gets the remaining bytes to be sent.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ * param count Bytes sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetSendCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Get the remaining bytes to be received.
+ *
+ * param base FlexIO I2S peripheral base address.
+ * param handle FlexIO I2S DMA handle pointer.
+ * param count Bytes received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t FLEXIO_I2S_TransferGetReceiveCountEDMA(FLEXIO_I2S_Type *base, flexio_i2s_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel);
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd.c
new file mode 100644
index 0000000000..f9f890a627
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd.c
@@ -0,0 +1,1293 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_mculcd.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_mculcd"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+
+enum _mculcd_transfer_state
+{
+ kFLEXIO_MCULCD_StateIdle, /*!< No transfer in progress. */
+ kFLEXIO_MCULCD_StateReadArray, /*!< Reading array in progress. */
+ kFLEXIO_MCULCD_StateWriteArray, /*!< Writing array in progress. */
+ kFLEXIO_MCULCD_StateWriteSameValue, /*!< Writing the same value in progress. */
+};
+
+/* The TIMCFG[0:7] is used for baud rate divider in dual 8-bit counters baud/bit mode. */
+#define FLEXIO_BAUDRATE_DIV_MASK 0xFFU
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, configures the
+ * FlexIO MCULCD hardware, and configures the FlexIO MCULCD with FlexIO MCULCD
+ * configuration.
+ * The configuration structure can be filled by the user, or be set with default
+ * values
+ * by the ref FLEXIO_MCULCD_GetDefaultConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param config Pointer to the flexio_mculcd_config_t structure.
+ * param srcClock_Hz FlexIO source clock in Hz.
+ * retval kStatus_Success Initialization success.
+ * retval kStatus_InvalidArgument Initialization failed because of invalid
+ * argument.
+ */
+status_t FLEXIO_MCULCD_Init(FLEXIO_MCULCD_Type *base, flexio_mculcd_config_t *config, uint32_t srcClock_Hz)
+{
+ assert(NULL != config);
+
+ flexio_config_t flexioConfig = {config->enable, config->enableInDoze, config->enableInDebug,
+ config->enableFastAccess};
+
+ FLEXIO_Init(base->flexioBase, &flexioConfig);
+
+ if (kStatus_Success != FLEXIO_MCULCD_SetBaudRate(base, config->baudRate_Bps, srcClock_Hz))
+ {
+ return kStatus_Success;
+ }
+
+ base->setCSPin(true);
+ base->setRSPin(true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Resets the FLEXIO_MCULCD timer and shifter configuration.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ */
+void FLEXIO_MCULCD_Deinit(FLEXIO_MCULCD_Type *base)
+{
+ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
+ FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO MCULCD.
+ *
+ * The default configuration value is:
+ * code
+ * config->enable = true;
+ * config->enableInDoze = false;
+ * config->enableInDebug = true;
+ * config->enableFastAccess = true;
+ * config->baudRate_Bps = 96000000U;
+ * endcode
+ * param Config Pointer to the flexio_mculcd_config_t structure.
+ */
+void FLEXIO_MCULCD_GetDefaultConfig(flexio_mculcd_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enable = true;
+ config->enableInDoze = false;
+ config->enableInDebug = true;
+ config->enableFastAccess = true;
+ config->baudRate_Bps = 96000000U;
+}
+
+/*!
+ * brief Set desired baud rate.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param baudRate_Bps Desired baud rate.
+ * param srcClock_Hz FLEXIO clock frequency in Hz.
+ * retval kStatus_Success Set successfully.
+ * retval kStatus_InvalidArgument Could not set the baud rate.
+ */
+status_t FLEXIO_MCULCD_SetBaudRate(FLEXIO_MCULCD_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
+{
+ uint32_t baudRateDiv;
+ uint32_t baudRatePerDataLine;
+ uint32_t timerCompare;
+ status_t status;
+
+ baudRatePerDataLine = baudRate_Bps / FLEXIO_MCULCD_DATA_BUS_WIDTH;
+
+ baudRateDiv = (srcClock_Hz + baudRatePerDataLine) / (baudRatePerDataLine * 2U);
+
+ if ((0U == baudRateDiv) || (baudRateDiv > (FLEXIO_BAUDRATE_DIV_MASK + 1U)))
+ {
+ status = kStatus_InvalidArgument;
+ }
+ else
+ {
+ baudRateDiv--;
+
+ timerCompare = base->flexioBase->TIMCMP[base->timerIndex];
+
+ timerCompare = (timerCompare & ~FLEXIO_BAUDRATE_DIV_MASK) | baudRateDiv;
+
+ base->flexioBase->TIMCMP[base->timerIndex] = timerCompare;
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets FlexIO MCULCD status flags.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * return status flag; OR'ed value or the ref _flexio_mculcd_status_flags.
+ *
+ * note Don't use this function with DMA APIs.
+ */
+uint32_t FLEXIO_MCULCD_GetStatusFlags(FLEXIO_MCULCD_Type *base)
+{
+ uint32_t ret = 0U;
+ uint32_t flags;
+
+ /* Get shifter status. */
+ flags = FLEXIO_GetShifterStatusFlags(base->flexioBase);
+
+ if (0U != (flags & (1UL << base->rxShifterEndIndex)))
+ {
+ ret |= (uint32_t)kFLEXIO_MCULCD_RxFullFlag;
+ }
+
+ if (0U != (flags & (1UL << base->txShifterStartIndex)))
+ {
+ ret |= (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag;
+ }
+
+ return ret;
+}
+
+/*!
+ * brief Clears FlexIO MCULCD status flags.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param mask Status to clear, it is the OR'ed value of ref
+ * _flexio_mculcd_status_flags.
+ *
+ * note Don't use this function with DMA APIs.
+ */
+void FLEXIO_MCULCD_ClearStatusFlags(FLEXIO_MCULCD_Type *base, uint32_t mask)
+{
+ uint32_t flags = 0U;
+
+ /* Clear the shifter flags. */
+ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
+ {
+ flags |= (1UL << base->rxShifterEndIndex);
+ }
+
+ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
+ {
+ flags |= (1UL << base->txShifterStartIndex);
+ }
+
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, flags);
+}
+
+/*!
+ * brief Enables the FlexIO MCULCD interrupt.
+ *
+ * This function enables the FlexIO MCULCD interrupt.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param mask Interrupts to enable, it is the OR'ed value of ref
+ * _flexio_mculcd_interrupt_enable.
+ */
+void FLEXIO_MCULCD_EnableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask)
+{
+ uint32_t interrupts = 0U;
+
+ /* Enable shifter interrupts. */
+ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
+ {
+ interrupts |= (1UL << base->rxShifterEndIndex);
+ }
+
+ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
+ {
+ interrupts |= (1UL << base->txShifterStartIndex);
+ }
+
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, interrupts);
+}
+
+/*!
+ * brief Disables the FlexIO MCULCD interrupt.
+ *
+ * This function disables the FlexIO MCULCD interrupt.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param mask Interrupts to disable, it is the OR'ed value of ref
+ * _flexio_mculcd_interrupt_enable.
+ */
+void FLEXIO_MCULCD_DisableInterrupts(FLEXIO_MCULCD_Type *base, uint32_t mask)
+{
+ uint32_t interrupts = 0U;
+
+ /* Disable shifter interrupts. */
+ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_RxFullFlag))
+ {
+ interrupts |= (1UL << base->rxShifterEndIndex);
+ }
+
+ if (0U != (mask & (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag))
+ {
+ interrupts |= (1UL << base->txShifterStartIndex);
+ }
+
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, interrupts);
+}
+
+/*!
+ * brief Read data from the FLEXIO MCULCD RX shifter buffer.
+ *
+ * Read data from the RX shift buffer directly, it does no check whether the
+ * buffer is empty or not.
+ *
+ * If the data bus width is 8-bit:
+ * code
+ * uint8_t value;
+ * value = (uint8_t)FLEXIO_MCULCD_ReadData(base);
+ * endcode
+ *
+ * If the data bus width is 16-bit:
+ * code
+ * uint16_t value;
+ * value = (uint16_t)FLEXIO_MCULCD_ReadData(base);
+ * endcode
+ *
+ * note This function returns the RX shifter buffer value (32-bit) directly.
+ * The return value should be converted according to data bus width.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * return The data read out.
+ *
+ * note Don't use this function with DMA APIs.
+ */
+uint32_t FLEXIO_MCULCD_ReadData(FLEXIO_MCULCD_Type *base)
+{
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ return base->flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
+#else
+ return base->flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
+#endif
+}
+
+/*!
+ * brief Configures the FLEXIO MCULCD to multiple beats write mode.
+ *
+ * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to
+ * multiple beats write mode using this function. After write operation, the configuration
+ * is cleared by ref FLEXIO_MCULCD_ClearSingleBeatWriteConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_SetSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base)
+{
+ /*
+ * This function will be called at the beginning of every data writing. For
+ * performance consideration, it access the FlexIO registers directly, but not
+ * call FlexIO driver APIs.
+ */
+
+ uint32_t timerCompare;
+
+ /* Enable the TX Shifter output. */
+ base->flexioBase->SHIFTCFG[base->txShifterStartIndex] =
+ FLEXIO_SHIFTCFG_PWIDTH(FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
+ FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
+
+ base->flexioBase->SHIFTCTL[base->txShifterStartIndex] =
+ FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
+ FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
+ FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
+
+ timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
+
+ /*
+ * TIMCMP[15:8] = (number of beats x 2) - 1. Because the number of beat is 1,
+ * so the TIMCMP[15:8] is 1.
+ */
+ base->flexioBase->TIMCMP[base->timerIndex] = (1UL << 8U) | timerCompare;
+
+ /* Use TX shifter flag as the inverted timer trigger. Timer output to WR/EN pin. */
+ base->flexioBase->TIMCFG[base->timerIndex] =
+ FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
+ FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
+ FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
+ FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled) |
+ FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
+
+ base->flexioBase->TIMCTL[base->timerIndex] =
+ FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterStartIndex)) |
+ FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
+ FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
+ FLEXIO_TIMCTL_PINSEL(base->ENWRPinIndex) | FLEXIO_TIMCTL_PINPOL(kFLEXIO_PinActiveLow) |
+ FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
+}
+
+/*!
+ * brief Clear the FLEXIO MCULCD multiple beats write mode configuration.
+ *
+ * Clear the write configuration set by ref FLEXIO_MCULCD_SetSingleBeatWriteConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_ClearSingleBeatWriteConfig(FLEXIO_MCULCD_Type *base)
+{
+ /* Disable the timer. */
+ base->flexioBase->TIMCTL[base->timerIndex] = 0U;
+ base->flexioBase->TIMCFG[base->timerIndex] = 0U;
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
+ /* Stop the TX shifter. */
+ base->flexioBase->SHIFTCTL[base->txShifterStartIndex] = 0U;
+ base->flexioBase->SHIFTCFG[base->txShifterStartIndex] = 0U;
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = (1UL << base->txShifterStartIndex);
+}
+
+/*!
+ * brief Configures the FLEXIO MCULCD to multiple beats read mode.
+ *
+ * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured
+ * to multiple beats read mode using this function. After read operation, the configuration
+ * is cleared by ref FLEXIO_MCULCD_ClearSingleBeatReadConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_SetSingleBeatReadConfig(FLEXIO_MCULCD_Type *base)
+{
+ /*
+ * This function will be called at the beginning of every data reading. For
+ * performance consideration, it access the FlexIO registers directly, but not
+ * call FlexIO driver APIs.
+ */
+
+ uint8_t timerPin;
+ uint32_t timerCompare;
+ flexio_pin_polarity_t timerPinPolarity;
+
+ /* Timer output to RD pin (8080 mode), to WR/EN pin in 6800 mode. */
+ if (kFLEXIO_MCULCD_8080 == base->busType)
+ {
+ timerPin = base->RDPinIndex;
+ timerPinPolarity = kFLEXIO_PinActiveLow;
+ }
+ else
+ {
+ timerPin = base->ENWRPinIndex;
+ timerPinPolarity = kFLEXIO_PinActiveHigh;
+ }
+
+ /* Enable the RX Shifter input. */
+ base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] = FLEXIO_SHIFTCFG_PWIDTH(FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U);
+
+ base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] =
+ FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
+ FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
+ FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
+
+ /* Use RX shifter flag as the inverted timer trigger. */
+ base->flexioBase->TIMCFG[base->timerIndex] =
+ FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
+ FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
+ FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
+ FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) |
+ FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable) |
+ FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
+
+ timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
+
+ /*
+ * TIMCMP[15:8] = (number of beats x 2) - 1. Because the number of beat is 1,
+ * so the TIMCMP[15:8] is 1.
+ */
+ base->flexioBase->TIMCMP[base->timerIndex] = (1UL << 8U) | timerCompare;
+
+ base->flexioBase->TIMCTL[base->timerIndex] |=
+ FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->rxShifterEndIndex)) |
+ FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
+ FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
+ FLEXIO_TIMCTL_PINSEL(timerPin) | FLEXIO_TIMCTL_PINPOL(timerPinPolarity) |
+ FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
+}
+
+/*!
+ * brief Clear the FLEXIO MCULCD multiple beats read mode configuration.
+ *
+ * Clear the read configuration set by ref FLEXIO_MCULCD_SetSingleBeatReadConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_ClearSingleBeatReadConfig(FLEXIO_MCULCD_Type *base)
+{
+ /* Disable the timer. */
+ base->flexioBase->TIMCTL[base->timerIndex] = 0U;
+ base->flexioBase->TIMCFG[base->timerIndex] = 0U;
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
+ /* Stop the RX shifter. */
+ base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] = 0U;
+ base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] = 0U;
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = (1UL << base->rxShifterEndIndex);
+}
+
+/*!
+ * brief Configures the FLEXIO MCULCD to multiple beats write mode.
+ *
+ * At the begining multiple beats write operation, the FLEXIO MCULCD is configured to
+ * multiple beats write mode using this function. After write operation, the configuration
+ * is cleared by ref FLEXIO_MCULCD_ClearMultBeatsWriteConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_SetMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base)
+{
+ /*
+ * This function will be called at the beginning of every data writing. For
+ * performance consideration, it access the FlexIO registers directly, but not
+ * call FlexIO driver APIs.
+ */
+
+ uint32_t timerCompare;
+ uint8_t beats;
+ uint8_t i;
+
+ /* Enable the TX Shifter output. */
+ base->flexioBase->SHIFTCFG[base->txShifterStartIndex] =
+ FLEXIO_SHIFTCFG_PWIDTH(FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
+ FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
+
+ base->flexioBase->SHIFTCTL[base->txShifterStartIndex] =
+ FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
+ FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutput) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
+ FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
+
+ for (i = base->txShifterStartIndex + 1U; i <= base->txShifterEndIndex; i++)
+ {
+ base->flexioBase->SHIFTCFG[i] = FLEXIO_SHIFTCFG_PWIDTH(FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
+ FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
+
+ base->flexioBase->SHIFTCTL[i] =
+ FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnPositive) |
+ FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(0) |
+ FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeTransmit);
+ }
+
+ timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
+
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ beats = 4U * (base->txShifterEndIndex - base->txShifterStartIndex + 1U);
+#else
+ beats = 2U * (base->txShifterEndIndex - base->txShifterStartIndex + 1U);
+#endif
+
+ /*
+ * TIMCMP[15:8] = (number of beats x 2) - 1.
+ */
+ base->flexioBase->TIMCMP[base->timerIndex] = ((beats * 2UL - 1UL) << 8U) | timerCompare;
+
+ /* Use TX shifter flag as the inverted timer trigger. Timer output to WR/EN pin. */
+ base->flexioBase->TIMCFG[base->timerIndex] =
+ FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
+ FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
+ FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
+ FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) | FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitDisabled) |
+ FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
+
+ base->flexioBase->TIMCTL[base->timerIndex] =
+ FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterEndIndex)) |
+ FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
+ FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
+ FLEXIO_TIMCTL_PINSEL(base->ENWRPinIndex) | FLEXIO_TIMCTL_PINPOL(kFLEXIO_PinActiveLow) |
+ FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
+}
+
+/*!
+ * brief Clear the FLEXIO MCULCD multiple beats write mode configuration.
+ *
+ * Clear the write configuration set by ref FLEXIO_MCULCD_SetMultBeatsWriteConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(FLEXIO_MCULCD_Type *base)
+{
+ uint8_t i;
+ uint32_t statusFlags = 0U;
+
+ /* Disable the timer. */
+ base->flexioBase->TIMCTL[base->timerIndex] = 0U;
+ base->flexioBase->TIMCFG[base->timerIndex] = 0U;
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
+
+ /* Stop the TX shifter. */
+ for (i = base->txShifterStartIndex; i <= base->txShifterEndIndex; i++)
+ {
+ base->flexioBase->SHIFTCFG[i] = 0U;
+ base->flexioBase->SHIFTCTL[i] = 0U;
+ statusFlags |= (1UL << i);
+ }
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = statusFlags;
+}
+
+/*!
+ * brief Configures the FLEXIO MCULCD to multiple beats read mode.
+ *
+ * At the begining or multiple beats read operation, the FLEXIO MCULCD is configured
+ * to multiple beats read mode using this function. After read operation, the configuration
+ * is cleared by ref FLEXIO_MCULCD_ClearMultBeatsReadConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_SetMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base)
+{
+ /*
+ * This function will be called at the beginning of every data reading. For
+ * performance consideration, it access the FlexIO registers directly, but not
+ * call FlexIO driver APIs.
+ */
+
+ uint8_t timerPin;
+ uint8_t beats;
+ uint8_t i;
+ uint32_t timerCompare;
+ flexio_pin_polarity_t timerPinPolarity;
+
+ /* Timer output to RD pin (8080 mode), to WR/EN pin in 6800 mode. */
+ if (kFLEXIO_MCULCD_8080 == base->busType)
+ {
+ timerPin = base->RDPinIndex;
+ timerPinPolarity = kFLEXIO_PinActiveLow;
+ }
+ else
+ {
+ timerPin = base->ENWRPinIndex;
+ timerPinPolarity = kFLEXIO_PinActiveHigh;
+ }
+
+ /* Enable the RX Shifter input. */
+ for (i = base->rxShifterStartIndex; i < base->rxShifterEndIndex; i++)
+ {
+ base->flexioBase->SHIFTCFG[i] = FLEXIO_SHIFTCFG_PWIDTH(FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U) |
+ FLEXIO_SHIFTCFG_INSRC(kFLEXIO_ShifterInputFromNextShifterOutput);
+
+ base->flexioBase->SHIFTCTL[i] =
+ FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
+ FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
+ FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
+ }
+
+ base->flexioBase->SHIFTCFG[base->rxShifterEndIndex] = FLEXIO_SHIFTCFG_PWIDTH(FLEXIO_MCULCD_DATA_BUS_WIDTH - 1U);
+ base->flexioBase->SHIFTCTL[base->rxShifterEndIndex] =
+ FLEXIO_SHIFTCTL_TIMSEL(base->timerIndex) | FLEXIO_SHIFTCTL_TIMPOL(kFLEXIO_ShifterTimerPolarityOnNegitive) |
+ FLEXIO_SHIFTCTL_PINCFG(kFLEXIO_PinConfigOutputDisabled) | FLEXIO_SHIFTCTL_PINSEL(base->dataPinStartIndex) |
+ FLEXIO_SHIFTCTL_PINPOL(kFLEXIO_PinActiveHigh) | FLEXIO_SHIFTCTL_SMOD(kFLEXIO_ShifterModeReceive);
+
+ timerCompare = base->flexioBase->TIMCMP[base->timerIndex] & 0xFFU;
+
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ beats = 4U * (base->rxShifterEndIndex - base->rxShifterStartIndex + 1U);
+#else
+ beats = 2U * (base->rxShifterEndIndex - base->rxShifterStartIndex + 1U);
+#endif
+
+ /*
+ * TIMCMP[15:8] = (number of beats x 2) - 1.
+ */
+ base->flexioBase->TIMCMP[base->timerIndex] = ((beats * 2UL - 1UL) << 8U) | timerCompare;
+
+ /* Use RX shifter flag as the inverted timer trigger. */
+ base->flexioBase->TIMCFG[base->timerIndex] =
+ FLEXIO_TIMCFG_TIMOUT(kFLEXIO_TimerOutputOneNotAffectedByReset) |
+ FLEXIO_TIMCFG_TIMDEC(kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput) |
+ FLEXIO_TIMCFG_TIMRST(kFLEXIO_TimerResetNever) | FLEXIO_TIMCFG_TIMDIS(kFLEXIO_TimerDisableOnTimerCompare) |
+ FLEXIO_TIMCFG_TIMENA(kFLEXIO_TimerEnableOnTriggerHigh) |
+ FLEXIO_TIMCFG_TSTOP(kFLEXIO_TimerStopBitEnableOnTimerDisable) |
+ FLEXIO_TIMCFG_TSTART(kFLEXIO_TimerStartBitDisabled);
+
+ base->flexioBase->TIMCTL[base->timerIndex] |=
+ FLEXIO_TIMCTL_TRGSEL(FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->rxShifterEndIndex)) |
+ FLEXIO_TIMCTL_TRGPOL(kFLEXIO_TimerTriggerPolarityActiveLow) |
+ FLEXIO_TIMCTL_TRGSRC(kFLEXIO_TimerTriggerSourceInternal) | FLEXIO_TIMCTL_PINCFG(kFLEXIO_PinConfigOutput) |
+ FLEXIO_TIMCTL_PINSEL(timerPin) | FLEXIO_TIMCTL_PINPOL(timerPinPolarity) |
+ FLEXIO_TIMCTL_TIMOD(kFLEXIO_TimerModeDual8BitBaudBit);
+}
+
+/*!
+ * brief Clear the FLEXIO MCULCD multiple beats read mode configuration.
+ *
+ * Clear the read configuration set by ref FLEXIO_MCULCD_SetMultBeatsReadConfig.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type.
+ *
+ * note This is an internal used function, upper layer should not use.
+ */
+void FLEXIO_MCULCD_ClearMultiBeatsReadConfig(FLEXIO_MCULCD_Type *base)
+{
+ uint8_t i;
+ uint32_t statusFlags = 0U;
+
+ /* Disable the timer. */
+ base->flexioBase->TIMCTL[base->timerIndex] = 0U;
+ base->flexioBase->TIMCFG[base->timerIndex] = 0U;
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex);
+ /* Stop the RX shifter. */
+ for (i = base->rxShifterStartIndex; i <= base->rxShifterEndIndex; i++)
+ {
+ base->flexioBase->SHIFTCTL[i] = 0U;
+ base->flexioBase->SHIFTCFG[i] = 0U;
+ statusFlags |= (1UL << i);
+ }
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = statusFlags;
+}
+
+/*!
+ * brief Wait for transmit data send out finished.
+ *
+ * Currently there is no effective method to wait for the data send out
+ * from the shiter, so here use a while loop to wait.
+ *
+ * note This is an internal used function.
+ */
+void FLEXIO_MCULCD_WaitTransmitComplete(void)
+{
+ uint32_t i = FLEXIO_MCULCD_WAIT_COMPLETE_TIME;
+
+ while (0U != (i--))
+ {
+ __NOP();
+ }
+}
+
+/*!
+ * brief Send command in blocking way.
+ *
+ * This function sends the command and returns when the command has been sent
+ * out.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param command The command to send.
+ */
+void FLEXIO_MCULCD_WriteCommandBlocking(FLEXIO_MCULCD_Type *base, uint32_t command)
+{
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ /* De-assert the RS pin. */
+ base->setRSPin(false);
+
+ /* For 6800, de-assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(false);
+ }
+
+ /* Configure the timer and TX shifter. */
+ FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
+
+ /* Write command to shifter buffer. */
+ flexioBase->SHIFTBUF[base->txShifterStartIndex] = command;
+
+ /* Wait for command send out. */
+ while (0U == ((1UL << base->timerIndex) & FLEXIO_GetTimerStatusFlags(flexioBase)))
+ {
+ }
+
+ /* Stop the timer and TX shifter. */
+ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
+
+ /* Assert the RS pin. */
+ base->setRSPin(true);
+ /* For 6800, assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(true);
+ }
+}
+
+/*!
+ * brief Send data array in blocking way.
+ *
+ * This function sends the data array and returns when the data sent out.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param data The data array to send.
+ * param size How many bytes to write.
+ */
+void FLEXIO_MCULCD_WriteDataArrayBlocking(FLEXIO_MCULCD_Type *base, void *data, size_t size)
+{
+ assert(size > 0U);
+
+ uint32_t i;
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ uint8_t *data8Bit;
+#else
+ uint16_t *data16Bit;
+#endif
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ /* Assert the RS pin. */
+ base->setRSPin(true);
+ /* For 6800, de-assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(false);
+ }
+
+ /* Configure the timer and TX shifter. */
+ FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
+
+/* If data bus width is 8. */
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ data8Bit = (uint8_t *)data;
+
+ for (i = 0; i < size; i++)
+ {
+ flexioBase->SHIFTBUF[base->txShifterStartIndex] = data8Bit[i];
+
+ /* Wait for the data send out. */
+ while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
+ {
+ }
+
+ /* Clear the timer stat. */
+ flexioBase->TIMSTAT = 1UL << base->timerIndex;
+ }
+#else
+ data16Bit = (uint16_t *)data;
+ size /= 2U;
+
+ for (i = 0; i < size; i++)
+ {
+ flexioBase->SHIFTBUF[base->txShifterStartIndex] = data16Bit[i];
+
+ /* Wait for the data send out. */
+ while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
+ {
+ }
+
+ /* Clear the timer stat. */
+ flexioBase->TIMSTAT = 1UL << base->timerIndex;
+ }
+#endif
+
+ /* Stop the timer and TX shifter. */
+ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
+}
+
+/*!
+ * brief Read data into array in blocking way.
+ *
+ * This function reads the data into array and returns when the data read
+ * finished.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param data The array to save the data.
+ * param size How many bytes to read.
+ */
+void FLEXIO_MCULCD_ReadDataArrayBlocking(FLEXIO_MCULCD_Type *base, void *data, size_t size)
+{
+ assert(size > 0U);
+
+ uint32_t i;
+
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ uint8_t *data8Bit = (uint8_t *)data;
+#else
+ uint16_t *data16Bit = (uint16_t *)data;
+#endif
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ /* Assert the RS pin. */
+ base->setRSPin(true);
+ /* For 6800, de-assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(false);
+ }
+
+ /* Enable the timer and RX shifter. */
+ FLEXIO_MCULCD_SetSingleBeatReadConfig(base);
+
+/* If data bus width is 8. */
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ for (i = 0; i < (size - 1U); i++)
+ {
+ /* Wait for shifter buffer full. */
+ while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
+ {
+ }
+
+ data8Bit[i] = (uint8_t)flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
+ }
+#else
+ /* Data bus width is 16. */
+ size /= 2U;
+
+ for (i = 0; i < (size - 1U); i++)
+ {
+ /* Wait for shifter buffer full. */
+ while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
+ {
+ }
+
+ data16Bit[i] = (uint16_t)flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
+ }
+#endif
+
+ /* Wait for shifter buffer full. */
+ while (0U == ((1UL << base->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
+ {
+ }
+
+ /* Stop the timer and disable the RX shifter. */
+ FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
+
+/* Read out the last data. */
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ data8Bit[i] = (uint8_t)flexioBase->SHIFTBUFBYS[base->rxShifterEndIndex];
+#else
+ data16Bit[i] = (uint16_t)flexioBase->SHIFTBUFHWS[base->rxShifterEndIndex];
+#endif
+}
+
+/*!
+ * brief Send the same value many times in blocking way.
+ *
+ * This function sends the same value many times. It could be used to clear the
+ * LCD screen. If the data bus width is 8, this function will send LSB 8 bits of
+ * p sameValue for p size times. If the data bus is 16, this function will send
+ * LSB 16 bits of p sameValue for p size / 2 times.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param sameValue The same value to send.
+ * param size How many bytes to send.
+ */
+void FLEXIO_MCULCD_WriteSameValueBlocking(FLEXIO_MCULCD_Type *base, uint32_t sameValue, size_t size)
+{
+ assert(size > 0U);
+
+ uint32_t i;
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+#if (16 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ size /= 2U;
+#endif
+
+ /* Assert the RS pin. */
+ base->setRSPin(true);
+ /* For 6800, de-assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(false);
+ }
+
+ /* Configure the timer and TX shifter. */
+ FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
+
+ for (i = 0; i < size; i++)
+ {
+ flexioBase->SHIFTBUF[base->txShifterStartIndex] = sameValue;
+
+ /* Wait for the data send out. */
+ while (0U == ((1UL << base->timerIndex) & flexioBase->TIMSTAT))
+ {
+ }
+
+ /* Clear the timer stat. */
+ flexioBase->TIMSTAT = 1UL << base->timerIndex;
+ }
+
+ /* Stop the timer and TX shifter. */
+ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
+}
+
+/*!
+ * brief Performs a polling transfer.
+ *
+ * note The API does not return until the transfer finished.
+ *
+ * param base pointer to FLEXIO_MCULCD_Type structure.
+ * param xfer pointer to flexio_mculcd_transfer_t structure.
+ */
+void FLEXIO_MCULCD_TransferBlocking(FLEXIO_MCULCD_Type *base, flexio_mculcd_transfer_t *xfer)
+{
+ FLEXIO_MCULCD_StartTransfer(base);
+
+ FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command);
+
+ if (xfer->dataSize > 0U)
+ {
+ if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
+ {
+ FLEXIO_MCULCD_ReadDataArrayBlocking(base, (uint8_t *)(xfer->dataAddrOrSameValue), xfer->dataSize);
+ }
+ else if (kFLEXIO_MCULCD_WriteArray == xfer->mode)
+ {
+ FLEXIO_MCULCD_WriteDataArrayBlocking(base, (uint8_t *)(xfer->dataAddrOrSameValue), xfer->dataSize);
+ }
+ else
+ {
+ FLEXIO_MCULCD_WriteSameValueBlocking(base, xfer->dataAddrOrSameValue, xfer->dataSize);
+ }
+ }
+
+ FLEXIO_MCULCD_StopTransfer(base);
+}
+
+/*!
+ * brief Initializes the FlexIO MCULCD handle, which is used in transactional
+ * functions.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_MCULCD_TransferCreateHandle(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_handle_t *handle,
+ flexio_mculcd_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+
+ /* Register callback and userData. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_GetInstance(base->flexioBase)]);
+
+ /* Save the context in global variables to support the double weak mechanism.
+ */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_MCULCD_TransferHandleIRQ);
+}
+
+/*!
+ * brief Transfer data using IRQ.
+ *
+ * This function sends data using IRQ. This is a non-blocking function, which
+ * returns right away. When all data is sent out/received, the callback
+ * function is called.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ * param xfer FlexIO MCULCD transfer structure. See #flexio_mculcd_transfer_t.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_MCULCD_Busy MCULCD is busy with another transfer.
+ */
+status_t FLEXIO_MCULCD_TransferNonBlocking(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_handle_t *handle,
+ flexio_mculcd_transfer_t *xfer)
+{
+ /* If previous transfer is in progress. */
+ if ((uint32_t)kFLEXIO_MCULCD_StateIdle != handle->state)
+ {
+ return kStatus_FLEXIO_MCULCD_Busy;
+ }
+
+ /* Set the state in handle. */
+ if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
+ {
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateReadArray;
+ }
+ else if (kFLEXIO_MCULCD_WriteArray == xfer->mode)
+ {
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteArray;
+ }
+ else
+ {
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteSameValue;
+ }
+
+ /* Assert the nCS. */
+ FLEXIO_MCULCD_StartTransfer(base);
+
+ /* Send the command. */
+ FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command);
+
+ /* If transfer count is 0 (only to send command), return directly. */
+ if (0U == xfer->dataSize)
+ {
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+
+ /* De-assert the nCS. */
+ FLEXIO_MCULCD_StopTransfer(base);
+
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, kStatus_FLEXIO_MCULCD_Idle, handle->userData);
+ }
+ }
+ else
+ {
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ handle->dataCount = xfer->dataSize;
+#else
+ handle->dataCount = xfer->dataSize / 2U;
+#endif
+
+ handle->remainingCount = handle->dataCount;
+
+ handle->dataAddrOrSameValue = xfer->dataAddrOrSameValue;
+
+ /* Enable interrupt. */
+ if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
+ {
+ /* For 6800, assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(true);
+ }
+ FLEXIO_MCULCD_SetSingleBeatReadConfig(base);
+ FLEXIO_MCULCD_EnableInterrupts(base, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable);
+ }
+ else
+ {
+ /* For 6800, de-assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(false);
+ }
+ FLEXIO_MCULCD_SetSingleBeatWriteConfig(base);
+ FLEXIO_MCULCD_EnableInterrupts(base, (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts the data transfer, which used IRQ.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ */
+void FLEXIO_MCULCD_TransferAbort(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle)
+{
+ /* If no transfer in process, return directly. */
+ if ((uint32_t)kFLEXIO_MCULCD_StateIdle == handle->state)
+ {
+ return;
+ }
+
+ /* Disable the interrupt. */
+ FLEXIO_MCULCD_DisableInterrupts(
+ base, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable | (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
+
+ if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == handle->state)
+ {
+ /* Stop the timer and disable the RX shifter. */
+ FLEXIO_MCULCD_ClearSingleBeatReadConfig(base);
+ }
+ else
+ {
+ /* Stop the timer and disable the TX shifter. */
+ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(base);
+ }
+
+ /* Clean the flags. */
+ FLEXIO_MCULCD_ClearStatusFlags(base, (uint32_t)kFLEXIO_MCULCD_TxEmptyFlag | (uint32_t)kFLEXIO_MCULCD_RxFullFlag);
+
+ /* De-assert the nCS. */
+ FLEXIO_MCULCD_StopTransfer(base);
+
+ handle->dataCount = 0;
+ handle->remainingCount = 0;
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+}
+
+/*!
+ * brief Gets the data transfer status which used IRQ.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ * param count How many bytes transferred so far by the non-blocking transaction.
+ * retval kStatus_Success Get the transferred count Successfully.
+ * retval kStatus_NoTransferInProgress No transfer in process.
+ */
+status_t FLEXIO_MCULCD_TransferGetCount(FLEXIO_MCULCD_Type *base, flexio_mculcd_handle_t *handle, size_t *count)
+{
+ assert(NULL != count);
+
+ if ((uint32_t)kFLEXIO_MCULCD_StateIdle == handle->state)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->dataCount - handle->remainingCount;
+
+#if (16 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ *count *= 2U;
+#endif
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief FlexIO MCULCD IRQ handler function.
+ *
+ * param base Pointer to the FLEXIO_MCULCD_Type structure.
+ * param handle Pointer to the flexio_mculcd_handle_t structure to store the
+ * transfer state.
+ */
+void FLEXIO_MCULCD_TransferHandleIRQ(void *base, void *handle)
+{
+ FLEXIO_MCULCD_Type *flexioLcdMcuBase = (FLEXIO_MCULCD_Type *)base;
+ flexio_mculcd_handle_t *flexioLcdMcuHandle = (flexio_mculcd_handle_t *)handle;
+ uint32_t statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
+ uint32_t data;
+
+ if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == flexioLcdMcuHandle->state)
+ {
+ /* Handle the reading process. */
+ while ((0U != ((uint32_t)kFLEXIO_MCULCD_RxFullFlag & statusFlags)) && (flexioLcdMcuHandle->remainingCount > 0U))
+ {
+ if (1U == flexioLcdMcuHandle->remainingCount)
+ {
+ /* If this is the last data, stop the RX shifter and timer. */
+ FLEXIO_MCULCD_DisableInterrupts(flexioLcdMcuBase, (uint32_t)kFLEXIO_MCULCD_RxFullInterruptEnable);
+ FLEXIO_MCULCD_ClearSingleBeatReadConfig(flexioLcdMcuBase);
+ FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
+ }
+
+ /* Read out the data. */
+ data = FLEXIO_MCULCD_ReadData(flexioLcdMcuBase);
+
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ *(uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue) = (uint8_t)data;
+ flexioLcdMcuHandle->dataAddrOrSameValue++;
+#else
+ *(uint16_t *)(flexioLcdMcuHandle->dataAddrOrSameValue) = (uint16_t)data;
+ flexioLcdMcuHandle->dataAddrOrSameValue += 2U;
+#endif
+
+ flexioLcdMcuHandle->remainingCount--;
+
+ /* Transfer finished, call the callback. */
+ if (0U == flexioLcdMcuHandle->remainingCount)
+ {
+ flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+
+ if (NULL != flexioLcdMcuHandle->completionCallback)
+ {
+ flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle,
+ kStatus_FLEXIO_MCULCD_Idle, flexioLcdMcuHandle->userData);
+ }
+ }
+
+ /* Is the shifter buffer ready to send the next data? */
+ statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
+ }
+ }
+ else
+ {
+ /* Handle the writing process. */
+ while ((0U != ((uint32_t)kFLEXIO_MCULCD_TxEmptyFlag & statusFlags)) &&
+ (flexioLcdMcuHandle->remainingCount > 0U))
+ {
+ /* Send the data. */
+ if ((uint32_t)kFLEXIO_MCULCD_StateWriteSameValue == flexioLcdMcuHandle->state)
+ {
+ data = flexioLcdMcuHandle->dataAddrOrSameValue;
+ }
+ else
+ {
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ data = *(uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue);
+ flexioLcdMcuHandle->dataAddrOrSameValue++;
+#else
+ data = *(uint16_t *)(flexioLcdMcuHandle->dataAddrOrSameValue);
+ flexioLcdMcuHandle->dataAddrOrSameValue += 2U;
+#endif
+ }
+
+ /* If this is the last data to send, delay to wait for the data shift out. */
+ if (1U == flexioLcdMcuHandle->remainingCount)
+ {
+ FLEXIO_MCULCD_DisableInterrupts(flexioLcdMcuBase, (uint32_t)kFLEXIO_MCULCD_TxEmptyInterruptEnable);
+
+ /* Write the last data. */
+ FLEXIO_MCULCD_WriteData(flexioLcdMcuBase, data);
+
+ /* Wait for the last data send finished. */
+ FLEXIO_MCULCD_WaitTransmitComplete();
+ flexioLcdMcuHandle->remainingCount = 0;
+
+ FLEXIO_MCULCD_ClearSingleBeatWriteConfig(flexioLcdMcuBase);
+ FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
+ flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+
+ if (NULL != flexioLcdMcuHandle->completionCallback)
+ {
+ flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle,
+ kStatus_FLEXIO_MCULCD_Idle, flexioLcdMcuHandle->userData);
+ }
+ }
+ else
+ {
+ FLEXIO_MCULCD_WriteData(flexioLcdMcuBase, data);
+ flexioLcdMcuHandle->remainingCount--;
+ }
+ /* Is the shifter buffer ready to send the next data? */
+ statusFlags = FLEXIO_MCULCD_GetStatusFlags(flexioLcdMcuBase);
+ }
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c
new file mode 100644
index 0000000000..458ad8e72b
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_mculcd_edma.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_mculcd_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_mculcd_edma"
+#endif
+
+#define EDMA_MAX_MAJOR_COUNT (DMA_CITER_ELINKNO_CITER_MASK >> DMA_CITER_ELINKNO_CITER_SHIFT)
+
+enum
+{
+ kFLEXIO_MCULCD_StateIdle, /*!< No transfer in progress. */
+ kFLEXIO_MCULCD_StateReadArray, /*!< Reading array in progress. */
+ kFLEXIO_MCULCD_StateWriteArray, /*!< Writing array in progress. */
+ kFLEXIO_MCULCD_StateWriteSameValue, /*!< Writing the same value in progress.
+ */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief EDMA callback function for FLEXIO MCULCD TX.
+ *
+ * For details, see @ref edma_callback.
+ */
+static void FLEXIO_MCULCD_TxEDMACallback(edma_handle_t *DmaHandle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief EDMA callback function for FLEXIO MCULCD RX.
+ *
+ * For details, see @ref edma_callback.
+ */
+static void FLEXIO_MCULCD_RxEDMACallback(edma_handle_t *DmaHandle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief Set EDMA config for FLEXIO MCULCD transfer.
+ *
+ * @param base pointer to FLEXIO_MCULCD_Type structure.
+ * @param handle pointer to flexio_mculcd_edma_handle_t structure to store the
+ * transfer state.
+ */
+static void FLEXIO_MCULCD_EDMAConfig(FLEXIO_MCULCD_Type *base, flexio_mculcd_edma_handle_t *handle);
+
+/*!
+ * @brief Convert the FlexIO shifter number to eDMA modulo.
+ *
+ * @param shifterNum The FlexIO shifter number.
+ * @param modulo The modulo number.
+ * @retval Get the modulo successfully.
+ * @retval Could not get the modulo for the shifter number.
+ */
+static bool FLEXIO_MCULCD_GetEDMAModulo(uint8_t shifterNum, edma_modulo_t *modulo);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void FLEXIO_MCULCD_TxEDMACallback(edma_handle_t *DmaHandle, void *param, bool transferDone, uint32_t tcds)
+{
+ tcds = tcds;
+ flexio_mculcd_edma_handle_t *flexioLcdMcuHandle = (flexio_mculcd_edma_handle_t *)param;
+ FLEXIO_MCULCD_Type *flexioLcdMcuBase = flexioLcdMcuHandle->base;
+
+ if (transferDone)
+ {
+ if (flexioLcdMcuHandle->remainingCount >= flexioLcdMcuHandle->minorLoopBytes)
+ {
+ FLEXIO_MCULCD_EDMAConfig(flexioLcdMcuBase, flexioLcdMcuHandle);
+ EDMA_StartTransfer(flexioLcdMcuHandle->txDmaHandle);
+ }
+ else
+ {
+ FLEXIO_MCULCD_EnableTxDMA(flexioLcdMcuBase, false);
+
+ /* Now the data are in shifter, wait for the data send out from the shifter. */
+ FLEXIO_MCULCD_WaitTransmitComplete();
+
+ /* Disable the TX shifter and the timer. */
+ FLEXIO_MCULCD_ClearMultiBeatsWriteConfig(flexioLcdMcuBase);
+
+ /* Send the remaining data. */
+ if (0U != flexioLcdMcuHandle->remainingCount)
+ {
+ if ((uint32_t)kFLEXIO_MCULCD_StateWriteSameValue == flexioLcdMcuHandle->state)
+ {
+ FLEXIO_MCULCD_WriteSameValueBlocking(flexioLcdMcuBase, flexioLcdMcuHandle->dataAddrOrSameValue,
+ flexioLcdMcuHandle->remainingCount);
+ }
+ else
+ {
+ FLEXIO_MCULCD_WriteDataArrayBlocking(flexioLcdMcuBase,
+ (uint8_t *)flexioLcdMcuHandle->dataAddrOrSameValue,
+ flexioLcdMcuHandle->remainingCount);
+ }
+ }
+
+ /* De-assert nCS. */
+ FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
+
+ /* Change the state. */
+ flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+ flexioLcdMcuHandle->dataCount = 0;
+ flexioLcdMcuHandle->remainingCount = 0;
+
+ /* Callback to inform upper layer. */
+ if (NULL != flexioLcdMcuHandle->completionCallback)
+ {
+ flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle, kStatus_FLEXIO_MCULCD_Idle,
+ flexioLcdMcuHandle->userData);
+ }
+ }
+ }
+}
+
+static void FLEXIO_MCULCD_RxEDMACallback(edma_handle_t *DmaHandle, void *param, bool transferDone, uint32_t tcds)
+{
+ tcds = tcds;
+ uint32_t i;
+ uint32_t rxBufAddr;
+ flexio_mculcd_edma_handle_t *flexioLcdMcuHandle = (flexio_mculcd_edma_handle_t *)param;
+ FLEXIO_MCULCD_Type *flexioLcdMcuBase = flexioLcdMcuHandle->base;
+ FLEXIO_Type *flexioBase = flexioLcdMcuBase->flexioBase;
+
+ if (transferDone)
+ {
+ if (flexioLcdMcuHandle->remainingCount >= (2U * flexioLcdMcuHandle->minorLoopBytes))
+ {
+ FLEXIO_MCULCD_EDMAConfig(flexioLcdMcuBase, flexioLcdMcuHandle);
+ EDMA_StartTransfer(flexioLcdMcuHandle->rxDmaHandle);
+ }
+ else
+ {
+ FLEXIO_MCULCD_EnableRxDMA(flexioLcdMcuBase, false);
+
+ /* Wait the data saved to the shifter buffer. */
+ while (0U == ((1UL << flexioLcdMcuBase->rxShifterEndIndex) & FLEXIO_GetShifterStatusFlags(flexioBase)))
+ {
+ }
+
+ /* Disable the RX shifter and the timer. */
+ FLEXIO_MCULCD_ClearMultiBeatsReadConfig(flexioLcdMcuBase);
+
+ rxBufAddr = FLEXIO_MCULCD_GetRxDataRegisterAddress(flexioLcdMcuBase);
+
+/* Read out the data. */
+#if (defined(__CORTEX_M) && (__CORTEX_M == 0))
+ /* Cortex M0 and M0+ only support aligned access. */
+ for (i = 0; i < flexioLcdMcuHandle->rxShifterNum * 4; i++)
+ {
+ ((uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue))[i] = ((volatile uint8_t *)rxBufAddr)[i];
+ }
+#else
+ for (i = 0; i < flexioLcdMcuHandle->rxShifterNum; i++)
+ {
+ ((uint32_t *)(flexioLcdMcuHandle->dataAddrOrSameValue))[i] = ((volatile uint32_t *)rxBufAddr)[i];
+ }
+#endif
+ flexioLcdMcuHandle->remainingCount -= flexioLcdMcuHandle->minorLoopBytes;
+
+ if (0U != flexioLcdMcuHandle->remainingCount)
+ {
+ FLEXIO_MCULCD_ReadDataArrayBlocking(
+ flexioLcdMcuBase,
+ (uint8_t *)(flexioLcdMcuHandle->dataAddrOrSameValue + flexioLcdMcuHandle->minorLoopBytes),
+ flexioLcdMcuHandle->remainingCount);
+ }
+
+ /* De-assert nCS. */
+ FLEXIO_MCULCD_StopTransfer(flexioLcdMcuBase);
+
+ /* Change the state. */
+ flexioLcdMcuHandle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+ flexioLcdMcuHandle->dataCount = 0;
+ flexioLcdMcuHandle->remainingCount = 0;
+
+ /* Callback to inform upper layer. */
+ if (NULL != flexioLcdMcuHandle->completionCallback)
+ {
+ flexioLcdMcuHandle->completionCallback(flexioLcdMcuBase, flexioLcdMcuHandle, kStatus_FLEXIO_MCULCD_Idle,
+ flexioLcdMcuHandle->userData);
+ }
+ }
+ }
+}
+
+static void FLEXIO_MCULCD_EDMAConfig(FLEXIO_MCULCD_Type *base, flexio_mculcd_edma_handle_t *handle)
+{
+ edma_transfer_config_t xferConfig = {0};
+ edma_transfer_size_t transferSize = kEDMA_TransferSize1Bytes;
+ int16_t offset;
+ uint32_t majorLoopCounts;
+ uint32_t transferCount;
+
+#if (8 == FLEXIO_MCULCD_DATA_BUS_WIDTH)
+ transferSize = kEDMA_TransferSize1Bytes;
+ offset = 1;
+#else
+ transferSize = kEDMA_TransferSize2Bytes;
+ offset = 2;
+#endif
+
+ majorLoopCounts = handle->remainingCount / handle->minorLoopBytes;
+
+ /* For reading, the last minor loop data is not tranfered by DMA. */
+ if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == handle->state)
+ {
+ majorLoopCounts--;
+ }
+
+ if (majorLoopCounts > EDMA_MAX_MAJOR_COUNT)
+ {
+ majorLoopCounts = EDMA_MAX_MAJOR_COUNT;
+ }
+
+ transferCount = majorLoopCounts * handle->minorLoopBytes;
+
+ if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == handle->state)
+ {
+ xferConfig.srcAddr = FLEXIO_MCULCD_GetRxDataRegisterAddress(base);
+ xferConfig.destAddr = handle->dataAddrOrSameValue;
+ xferConfig.srcTransferSize = kEDMA_TransferSize4Bytes;
+ xferConfig.destTransferSize = transferSize;
+ xferConfig.srcOffset = 4;
+ xferConfig.destOffset = offset;
+ xferConfig.minorLoopBytes = handle->minorLoopBytes;
+ xferConfig.majorLoopCounts = majorLoopCounts;
+ handle->remainingCount -= transferCount;
+ handle->dataAddrOrSameValue += transferCount;
+ (void)EDMA_SubmitTransfer(handle->rxDmaHandle, &xferConfig);
+ EDMA_SetModulo(handle->rxDmaHandle->base, handle->rxDmaHandle->channel, handle->rxEdmaModulo,
+ kEDMA_ModuloDisable);
+ }
+ else
+ {
+ if ((uint32_t)kFLEXIO_MCULCD_StateWriteArray == handle->state)
+ {
+ xferConfig.srcAddr = handle->dataAddrOrSameValue;
+ xferConfig.srcOffset = offset;
+ handle->dataAddrOrSameValue += transferCount;
+ }
+ else
+ {
+ xferConfig.srcAddr = (uint32_t)(&(handle->dataAddrOrSameValue));
+ xferConfig.srcOffset = 0;
+ }
+ xferConfig.destAddr = FLEXIO_MCULCD_GetTxDataRegisterAddress(base);
+ xferConfig.srcTransferSize = transferSize;
+ xferConfig.destTransferSize = kEDMA_TransferSize4Bytes;
+ xferConfig.destOffset = 4;
+ xferConfig.minorLoopBytes = handle->minorLoopBytes;
+ xferConfig.majorLoopCounts = majorLoopCounts;
+ handle->remainingCount -= transferCount;
+ (void)EDMA_SubmitTransfer(handle->txDmaHandle, &xferConfig);
+ EDMA_SetModulo(handle->txDmaHandle->base, handle->txDmaHandle->channel, kEDMA_ModuloDisable,
+ handle->txEdmaModulo);
+ }
+}
+
+static bool FLEXIO_MCULCD_GetEDMAModulo(uint8_t shifterNum, edma_modulo_t *modulo)
+{
+ bool ret = true;
+
+ switch (shifterNum)
+ {
+ case 1U:
+ *modulo = kEDMA_Modulo4bytes;
+ break;
+ case 2U:
+ *modulo = kEDMA_Modulo8bytes;
+ break;
+ case 4U:
+ *modulo = kEDMA_Modulo16bytes;
+ break;
+ case 8U:
+ *modulo = kEDMA_Modulo32bytes;
+ break;
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * brief Initializes the FLEXO MCULCD master eDMA handle.
+ *
+ * This function initializes the FLEXO MCULCD master eDMA handle which can be
+ * used for other FLEXO MCULCD transactional APIs. For a specified FLEXO MCULCD
+ * instance, call this API once to get the initialized handle.
+ *
+ * param base Pointer to FLEXIO_MCULCD_Type structure.
+ * param handle Pointer to flexio_mculcd_edma_handle_t structure to store the
+ * transfer state.
+ * param callback MCULCD transfer complete callback, NULL means no callback.
+ * param userData callback function parameter.
+ * param txDmaHandle User requested eDMA handle for FlexIO MCULCD eDMA TX,
+ * the DMA request source of this handle should be the first of TX shifters.
+ * param rxDmaHandle User requested eDMA handle for FlexIO MCULCD eDMA RX,
+ * the DMA request source of this handle should be the last of RX shifters.
+ * retval kStatus_Success Successfully create the handle.
+ */
+status_t FLEXIO_MCULCD_TransferCreateHandleEDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_edma_handle_t *handle,
+ flexio_mculcd_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txDmaHandle,
+ edma_handle_t *rxDmaHandle)
+{
+ assert(NULL != handle);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Initialize the state. */
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+
+ /* Register callback and userData. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ handle->base = base;
+ handle->txShifterNum = base->txShifterEndIndex - base->txShifterStartIndex + 1U;
+ handle->rxShifterNum = base->rxShifterEndIndex - base->rxShifterStartIndex + 1U;
+
+ if (NULL != rxDmaHandle)
+ {
+ if (!FLEXIO_MCULCD_GetEDMAModulo(handle->rxShifterNum, &handle->rxEdmaModulo))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ handle->rxDmaHandle = rxDmaHandle;
+ EDMA_SetCallback(rxDmaHandle, FLEXIO_MCULCD_RxEDMACallback, handle);
+ }
+
+ if (NULL != txDmaHandle)
+ {
+ if (!FLEXIO_MCULCD_GetEDMAModulo(handle->txShifterNum, &handle->txEdmaModulo))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ handle->txDmaHandle = txDmaHandle;
+ EDMA_SetCallback(txDmaHandle, FLEXIO_MCULCD_TxEDMACallback, handle);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO MCULCD transfer using eDMA.
+ *
+ * This function returns immediately after transfer initiates. To check whether
+ * the transfer is completed, user could:
+ * 1. Use the transfer completed callback;
+ * 2. Polling function ref FLEXIO_MCULCD_GetTransferCountEDMA
+ *
+ * param base pointer to FLEXIO_MCULCD_Type structure.
+ * param handle pointer to flexio_mculcd_edma_handle_t structure to store the
+ * transfer state.
+ * param xfer Pointer to FlexIO MCULCD transfer structure.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_MCULCD_Busy FlexIO MCULCD is not idle, it is running another
+ * transfer.
+ */
+status_t FLEXIO_MCULCD_TransferEDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_edma_handle_t *handle,
+ flexio_mculcd_transfer_t *xfer)
+{
+ assert(NULL != handle);
+ assert(NULL != xfer);
+
+ /*
+ * The data transfer mechanism:
+ *
+ * Read:
+ * Assume the data length is Lr = (n1 * minorLoopBytes + n2), where
+ * n2 < minorLoopBytes.
+ * If (n1 <= 1), then all data are sent using blocking method.
+ * If (n1 > 1), then the beginning ((n1-1) * minorLoopBytes) are read
+ * using DMA, the left (minorLoopBytes + n2) are read using blocking method.
+ *
+ * Write:
+ * Assume the data length is Lw = (n1 * minorLoopBytes + n2), where
+ * n2 < minorLoopBytes.
+ * If (n1 = 0), then all data are sent using blocking method.
+ * If (n1 >= 1), then the beginning (n1 * minorLoopBytes) are sent
+ * using DMA, the left n2 are sent using blocking method.
+ */
+
+ /* Check if the device is busy. */
+ if ((uint32_t)kFLEXIO_MCULCD_StateIdle != handle->state)
+ {
+ return kStatus_FLEXIO_MCULCD_Busy;
+ }
+
+ /* Set the state in handle. */
+ if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
+ {
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateReadArray;
+ handle->minorLoopBytes = handle->rxShifterNum * 4UL;
+ }
+ else
+ {
+ handle->minorLoopBytes = handle->txShifterNum * 4UL;
+
+ if (kFLEXIO_MCULCD_WriteArray == xfer->mode)
+ {
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteArray;
+ }
+ else
+ {
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateWriteSameValue;
+ }
+ }
+
+ /*
+ * For TX, if data is less than one minor loop, then use polling method.
+ * For RX, if data is less than two minor loop, then use polling method.
+ */
+ if ((xfer->dataSize < handle->minorLoopBytes) ||
+ ((kFLEXIO_MCULCD_ReadArray == xfer->mode) && (xfer->dataSize < 2U * (handle->minorLoopBytes))))
+ {
+ FLEXIO_MCULCD_TransferBlocking(base, xfer);
+
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+
+ /* Callback to inform upper layer. */
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, kStatus_FLEXIO_MCULCD_Idle, handle->userData);
+ }
+ }
+ else
+ {
+ handle->dataCount = xfer->dataSize;
+ handle->remainingCount = xfer->dataSize;
+ handle->dataAddrOrSameValue = xfer->dataAddrOrSameValue;
+
+ /* Setup DMA to transfer data. */
+ /* Assert the nCS. */
+ FLEXIO_MCULCD_StartTransfer(base);
+ /* Send the command. */
+ FLEXIO_MCULCD_WriteCommandBlocking(base, xfer->command);
+
+ /* Setup the DMA configuration. */
+ FLEXIO_MCULCD_EDMAConfig(base, handle);
+
+ /* Start the transfer. */
+ if (kFLEXIO_MCULCD_ReadArray == xfer->mode)
+ {
+ /* For 6800, assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(true);
+ }
+ FLEXIO_MCULCD_SetMultiBeatsReadConfig(base);
+ FLEXIO_MCULCD_EnableRxDMA(base, true);
+ EDMA_StartTransfer(handle->rxDmaHandle);
+ }
+ else
+ {
+ /* For 6800, de-assert the RDWR pin. */
+ if (kFLEXIO_MCULCD_6800 == base->busType)
+ {
+ base->setRDWRPin(false);
+ }
+ FLEXIO_MCULCD_SetMultiBeatsWriteConfig(base);
+ FLEXIO_MCULCD_EnableTxDMA(base, true);
+ EDMA_StartTransfer(handle->txDmaHandle);
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a FlexIO MCULCD transfer using eDMA.
+ *
+ * param base pointer to FLEXIO_MCULCD_Type structure.
+ * param handle FlexIO MCULCD eDMA handle pointer.
+ */
+void FLEXIO_MCULCD_TransferAbortEDMA(FLEXIO_MCULCD_Type *base, flexio_mculcd_edma_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ /* Disable dma. */
+ if (NULL != handle->txDmaHandle)
+ {
+ EDMA_AbortTransfer(handle->txDmaHandle);
+ }
+ if (NULL != handle->rxDmaHandle)
+ {
+ EDMA_AbortTransfer(handle->rxDmaHandle);
+ }
+
+ /* Disable DMA enable bit. */
+ FLEXIO_MCULCD_EnableTxDMA(handle->base, false);
+ FLEXIO_MCULCD_EnableRxDMA(handle->base, false);
+
+ /* Set the handle state. */
+ handle->state = (uint32_t)kFLEXIO_MCULCD_StateIdle;
+ handle->dataCount = 0;
+}
+
+/*!
+ * brief Gets the remaining bytes for FlexIO MCULCD eDMA transfer.
+ *
+ * param base pointer to FLEXIO_MCULCD_Type structure.
+ * param handle FlexIO MCULCD eDMA handle pointer.
+ * param count Number of count transferred so far by the eDMA transaction.
+ * retval kStatus_Success Get the transferred count Successfully.
+ * retval kStatus_NoTransferInProgress No transfer in process.
+ */
+status_t FLEXIO_MCULCD_TransferGetCountEDMA(FLEXIO_MCULCD_Type *base,
+ flexio_mculcd_edma_handle_t *handle,
+ size_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != count);
+ uint32_t state = handle->state;
+
+ if ((uint32_t)kFLEXIO_MCULCD_StateIdle == state)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->dataCount - handle->remainingCount;
+
+ if ((uint32_t)kFLEXIO_MCULCD_StateReadArray == state)
+ {
+ *count -= handle->minorLoopBytes *
+ EDMA_GetRemainingMajorLoopCount(handle->rxDmaHandle->base, handle->rxDmaHandle->channel);
+ }
+ else
+ {
+ *count -= handle->minorLoopBytes *
+ EDMA_GetRemainingMajorLoopCount(handle->txDmaHandle->base, handle->txDmaHandle->channel);
+ }
+ }
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_spi.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_spi.c
new file mode 100644
index 0000000000..3c7db5d552
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_spi.c
@@ -0,0 +1,1326 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_spi.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_spi"
+#endif
+
+/*! @brief FLEXIO SPI transfer state, which is used for SPI transactiaonl APIs' internal state. */
+enum _flexio_spi_transfer_states
+{
+ kFLEXIO_SPI_Idle = 0x0U, /*!< Nothing in the transmitter/receiver's queue. */
+ kFLEXIO_SPI_Busy, /*!< Transmiter/Receive's queue is not finished. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Send a piece of data for SPI.
+ *
+ * This function computes the number of data to be written into D register or Tx FIFO,
+ * and write the data into it. At the same time, this function updates the values in
+ * master handle structure.
+ *
+ * @param base pointer to FLEXIO_SPI_Type structure
+ * @param handle Pointer to SPI master handle structure.
+ */
+static void FLEXIO_SPI_TransferSendTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle);
+
+/*!
+ * @brief Receive a piece of data for SPI master.
+ *
+ * This function computes the number of data to receive from D register or Rx FIFO,
+ * and write the data to destination address. At the same time, this function updates
+ * the values in master handle structure.
+ *
+ * @param base pointer to FLEXIO_SPI_Type structure
+ * @param handle Pointer to SPI master handle structure.
+ */
+static void FLEXIO_SPI_TransferReceiveTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static uint32_t FLEXIO_SPI_GetInstance(FLEXIO_SPI_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+static void FLEXIO_SPI_TransferSendTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle)
+{
+ uint16_t tmpData = FLEXIO_SPI_DUMMYDATA;
+
+ if (handle->txData != NULL)
+ {
+ /* Transmit data and update tx size/buff. */
+ if (handle->bytePerFrame == 1U)
+ {
+ tmpData = *(handle->txData);
+ handle->txData++;
+ }
+ else
+ {
+ if (handle->direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint16_t)(handle->txData[0]) << 8U;
+ tmpData += handle->txData[1];
+ }
+ else
+ {
+ tmpData = (uint16_t)(handle->txData[1]) << 8U;
+ tmpData += handle->txData[0];
+ }
+ handle->txData += 2U;
+ }
+ }
+ else
+ {
+ tmpData = FLEXIO_SPI_DUMMYDATA;
+ }
+
+ handle->txRemainingBytes -= handle->bytePerFrame;
+
+ FLEXIO_SPI_WriteData(base, handle->direction, tmpData);
+
+ if (0U == handle->txRemainingBytes)
+ {
+ FLEXIO_SPI_DisableInterrupts(base, (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable);
+ }
+}
+
+static void FLEXIO_SPI_TransferReceiveTransaction(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle)
+{
+ uint16_t tmpData;
+
+ tmpData = FLEXIO_SPI_ReadData(base, handle->direction);
+
+ if (handle->rxData != NULL)
+ {
+ if (handle->bytePerFrame == 1U)
+ {
+ *handle->rxData = (uint8_t)tmpData;
+ handle->rxData++;
+ }
+ else
+ {
+ if (handle->direction == kFLEXIO_SPI_MsbFirst)
+ {
+ *handle->rxData = (uint8_t)(tmpData >> 8);
+ handle->rxData++;
+ *handle->rxData = (uint8_t)tmpData;
+ }
+ else
+ {
+ *handle->rxData = (uint8_t)tmpData;
+ handle->rxData++;
+ *handle->rxData = (uint8_t)(tmpData >> 8);
+ }
+ handle->rxData++;
+ }
+ }
+ handle->rxRemainingBytes -= handle->bytePerFrame;
+}
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, configures the FlexIO SPI master hardware,
+ * and configures the FlexIO SPI with FlexIO SPI master configuration. The
+ * configuration structure can be filled by the user, or be set with default values
+ * by the FLEXIO_SPI_MasterGetDefaultConfig().
+ *
+ * note 1.FlexIO SPI master only support CPOL = 0, which means clock inactive low.
+ * 2.For FlexIO SPI master, the input valid time is 1.5 clock cycles, for slave the output valid time
+ * is 2.5 clock cycles. So if FlexIO SPI master communicates with other spi IPs, the maximum baud
+ * rate is FlexIO clock frequency divided by 2*2=4. If FlexIO SPI master communicates with FlexIO
+ * SPI slave, the maximum baud rate is FlexIO clock frequency divided by (1.5+2.5)*2=8.
+ *
+ * Example
+ code
+ FLEXIO_SPI_Type spiDev = {
+ .flexioBase = FLEXIO,
+ .SDOPinIndex = 0,
+ .SDIPinIndex = 1,
+ .SCKPinIndex = 2,
+ .CSnPinIndex = 3,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_spi_master_config_t config = {
+ .enableMaster = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 500000,
+ .phase = kFLEXIO_SPI_ClockPhaseFirstEdge,
+ .direction = kFLEXIO_SPI_MsbFirst,
+ .dataMode = kFLEXIO_SPI_8BitMode
+ };
+ FLEXIO_SPI_MasterInit(&spiDev, &config, srcClock_Hz);
+ endcode
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param masterConfig Pointer to the flexio_spi_master_config_t structure.
+ * param srcClock_Hz FlexIO source clock in Hz.
+*/
+void FLEXIO_SPI_MasterInit(FLEXIO_SPI_Type *base, flexio_spi_master_config_t *masterConfig, uint32_t srcClock_Hz)
+{
+ assert(base != NULL);
+ assert(masterConfig != NULL);
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+ uint32_t ctrlReg = 0;
+ uint16_t timerDiv = 0;
+ uint16_t timerCmp = 0;
+
+ /* Clear the shifterConfig & timerConfig struct. */
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_SPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure FLEXIO SPI Master */
+ ctrlReg = base->flexioBase->CTRL;
+ ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ ctrlReg |= (FLEXIO_CTRL_DBGE(masterConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(masterConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(masterConfig->enableMaster));
+ if (!masterConfig->enableInDoze)
+ {
+ ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->flexioBase->CTRL = ctrlReg;
+
+ /* Do hardware configuration. */
+ /* 1. Configure the shifter 0 for tx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ shifterConfig.pinSelect = base->SDOPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ if (masterConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ }
+ else
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitLow;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
+
+ /* 2. Configure the shifter 1 for rx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->SDIPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ if (masterConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ }
+ else
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
+
+ /*3. Configure the timer 0 for SCK. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ timerConfig.pinSelect = base->SCKPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+
+ timerDiv = (uint16_t)(srcClock_Hz / masterConfig->baudRate_Bps);
+ timerDiv = timerDiv / 2U - 1U;
+
+ timerCmp = ((uint16_t)masterConfig->dataMode * 2U - 1U) << 8U;
+ timerCmp |= timerDiv;
+
+ timerConfig.timerCompare = timerCmp;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
+
+ /* 4. Configure the timer 1 for CSn. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_TIMn(base->timerIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ timerConfig.pinSelect = base->CSnPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveLow;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnPreTimerDisable;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPrevTimerEnable;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+
+ timerConfig.timerCompare = 0xFFFFU;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[1], &timerConfig);
+}
+
+/*!
+ * brief Resets the FlexIO SPI timer and shifter config.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type.
+ */
+void FLEXIO_SPI_MasterDeinit(FLEXIO_SPI_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCFG[base->shifterIndex[1]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[1]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[1]] = 0;
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO SPI master. The configuration
+ * can be used directly by calling the FLEXIO_SPI_MasterConfigure().
+ * Example:
+ code
+ flexio_spi_master_config_t masterConfig;
+ FLEXIO_SPI_MasterGetDefaultConfig(&masterConfig);
+ endcode
+ * param masterConfig Pointer to the flexio_spi_master_config_t structure.
+*/
+void FLEXIO_SPI_MasterGetDefaultConfig(flexio_spi_master_config_t *masterConfig)
+{
+ assert(masterConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->enableMaster = true;
+ masterConfig->enableInDoze = false;
+ masterConfig->enableInDebug = true;
+ masterConfig->enableFastAccess = false;
+ /* Default baud rate 500kbps. */
+ masterConfig->baudRate_Bps = 500000U;
+ /* Default CPHA = 0. */
+ masterConfig->phase = kFLEXIO_SPI_ClockPhaseFirstEdge;
+ /* Default bit count at 8. */
+ masterConfig->dataMode = kFLEXIO_SPI_8BitMode;
+}
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, configures the FlexIO SPI slave hardware
+ * configuration, and configures the FlexIO SPI with FlexIO SPI slave configuration. The
+ * configuration structure can be filled by the user, or be set with default values
+ * by the FLEXIO_SPI_SlaveGetDefaultConfig().
+ *
+ * note 1.Only one timer is needed in the FlexIO SPI slave. As a result, the second timer index is ignored.
+ * 2.FlexIO SPI slave only support CPOL = 0, which means clock inactive low.
+ * 3.For FlexIO SPI master, the input valid time is 1.5 clock cycles, for slave the output valid time
+ * is 2.5 clock cycles. So if FlexIO SPI slave communicates with other spi IPs, the maximum baud
+ * rate is FlexIO clock frequency divided by 3*2=6. If FlexIO SPI slave communicates with FlexIO
+ * SPI master, the maximum baud rate is FlexIO clock frequency divided by (1.5+2.5)*2=8.
+ * Example
+ code
+ FLEXIO_SPI_Type spiDev = {
+ .flexioBase = FLEXIO,
+ .SDOPinIndex = 0,
+ .SDIPinIndex = 1,
+ .SCKPinIndex = 2,
+ .CSnPinIndex = 3,
+ .shifterIndex = {0,1},
+ .timerIndex = {0}
+ };
+ flexio_spi_slave_config_t config = {
+ .enableSlave = true,
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .phase = kFLEXIO_SPI_ClockPhaseFirstEdge,
+ .direction = kFLEXIO_SPI_MsbFirst,
+ .dataMode = kFLEXIO_SPI_8BitMode
+ };
+ FLEXIO_SPI_SlaveInit(&spiDev, &config);
+ endcode
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param slaveConfig Pointer to the flexio_spi_slave_config_t structure.
+*/
+void FLEXIO_SPI_SlaveInit(FLEXIO_SPI_Type *base, flexio_spi_slave_config_t *slaveConfig)
+{
+ assert((base != NULL) && (slaveConfig != NULL));
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+ uint32_t ctrlReg = 0;
+
+ /* Clear the shifterConfig & timerConfig struct. */
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_SPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure FLEXIO SPI Slave */
+ ctrlReg = base->flexioBase->CTRL;
+ ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ ctrlReg |= (FLEXIO_CTRL_DBGE(slaveConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(slaveConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(slaveConfig->enableSlave));
+ if (!slaveConfig->enableInDoze)
+ {
+ ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->flexioBase->CTRL = ctrlReg;
+
+ /* Do hardware configuration. */
+ /* 1. Configure the shifter 0 for tx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ shifterConfig.pinSelect = base->SDOPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ if (slaveConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ }
+ else
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
+
+ /* 2. Configure the shifter 1 for rx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->SDIPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitDisable;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
+ if (slaveConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ }
+ else
+ {
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ }
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
+
+ /*3. Configure the timer 0 for shift clock. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->CSnPinIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->SCKPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeSingle16Bit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputZeroNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerRisingEdge;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitDisabled;
+ if (slaveConfig->phase == kFLEXIO_SPI_ClockPhaseFirstEdge)
+ {
+ /* The configuration kFLEXIO_TimerDisableOnTimerCompare only support continuous
+ PCS access, change to kFLEXIO_TimerDisableNever to enable discontinuous PCS access. */
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitDisabled;
+ }
+ else
+ {
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTriggerFallingEdge;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+ }
+
+ timerConfig.timerCompare = (uint32_t)slaveConfig->dataMode * 2U - 1U;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
+}
+
+/*!
+ * brief Gates the FlexIO clock.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type.
+ */
+void FLEXIO_SPI_SlaveDeinit(FLEXIO_SPI_Type *base)
+{
+ FLEXIO_SPI_MasterDeinit(base);
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO SPI slave. The configuration
+ * can be used directly for calling the FLEXIO_SPI_SlaveConfigure().
+ * Example:
+ code
+ flexio_spi_slave_config_t slaveConfig;
+ FLEXIO_SPI_SlaveGetDefaultConfig(&slaveConfig);
+ endcode
+ * param slaveConfig Pointer to the flexio_spi_slave_config_t structure.
+*/
+void FLEXIO_SPI_SlaveGetDefaultConfig(flexio_spi_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(slaveConfig, 0, sizeof(*slaveConfig));
+
+ slaveConfig->enableSlave = true;
+ slaveConfig->enableInDoze = false;
+ slaveConfig->enableInDebug = true;
+ slaveConfig->enableFastAccess = false;
+ /* Default CPHA = 0. */
+ slaveConfig->phase = kFLEXIO_SPI_ClockPhaseFirstEdge;
+ /* Default bit count at 8. */
+ slaveConfig->dataMode = kFLEXIO_SPI_8BitMode;
+}
+
+/*!
+ * brief Enables the FlexIO SPI interrupt.
+ *
+ * This function enables the FlexIO SPI interrupt.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param mask interrupt source. The parameter can be any combination of the following values:
+ * arg kFLEXIO_SPI_RxFullInterruptEnable
+ * arg kFLEXIO_SPI_TxEmptyInterruptEnable
+ */
+void FLEXIO_SPI_EnableInterrupts(FLEXIO_SPI_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Disables the FlexIO SPI interrupt.
+ *
+ * This function disables the FlexIO SPI interrupt.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param mask interrupt source The parameter can be any combination of the following values:
+ * arg kFLEXIO_SPI_RxFullInterruptEnable
+ * arg kFLEXIO_SPI_TxEmptyInterruptEnable
+ */
+void FLEXIO_SPI_DisableInterrupts(FLEXIO_SPI_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Enables/disables the FlexIO SPI transmit DMA. This function enables/disables the FlexIO SPI Tx DMA,
+ * which means that asserting the kFLEXIO_SPI_TxEmptyFlag does/doesn't trigger the DMA request.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param mask SPI DMA source.
+ * param enable True means enable DMA, false means disable DMA.
+ */
+void FLEXIO_SPI_EnableDMA(FLEXIO_SPI_Type *base, uint32_t mask, bool enable)
+{
+ if ((mask & (uint32_t)kFLEXIO_SPI_TxDmaEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->shifterIndex[0], enable);
+ }
+
+ if ((mask & (uint32_t)kFLEXIO_SPI_RxDmaEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusDMA(base->flexioBase, 1UL << base->shifterIndex[1], enable);
+ }
+}
+
+/*!
+ * brief Gets FlexIO SPI status flags.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * return status flag; Use the status flag to AND the following flag mask and get the status.
+ * arg kFLEXIO_SPI_TxEmptyFlag
+ * arg kFLEXIO_SPI_RxEmptyFlag
+ */
+
+uint32_t FLEXIO_SPI_GetStatusFlags(FLEXIO_SPI_Type *base)
+{
+ uint32_t shifterStatus = FLEXIO_GetShifterStatusFlags(base->flexioBase);
+ uint32_t status = 0;
+
+ status = ((shifterStatus & (1UL << base->shifterIndex[0])) >> base->shifterIndex[0]);
+ status |= (((shifterStatus & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1])) << 1U);
+
+ return status;
+}
+
+/*!
+ * brief Clears FlexIO SPI status flags.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param mask status flag
+ * The parameter can be any combination of the following values:
+ * arg kFLEXIO_SPI_TxEmptyFlag
+ * arg kFLEXIO_SPI_RxEmptyFlag
+ */
+
+void FLEXIO_SPI_ClearStatusFlags(FLEXIO_SPI_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Sets baud rate for the FlexIO SPI transfer, which is only used for the master.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param baudRate_Bps Baud Rate needed in Hz.
+ * param srcClockHz SPI source clock frequency in Hz.
+ */
+void FLEXIO_SPI_MasterSetBaudRate(FLEXIO_SPI_Type *base, uint32_t baudRate_Bps, uint32_t srcClockHz)
+{
+ uint16_t timerDiv = 0;
+ uint16_t timerCmp = 0;
+ FLEXIO_Type *flexioBase = base->flexioBase;
+
+ /* Set TIMCMP[7:0] = (baud rate divider / 2) - 1.*/
+ timerDiv = (uint16_t)(srcClockHz / baudRate_Bps);
+ timerDiv = timerDiv / 2U - 1U;
+
+ timerCmp = (uint16_t)(flexioBase->TIMCMP[base->timerIndex[0]]);
+ timerCmp &= 0xFF00U;
+ timerCmp |= timerDiv;
+
+ flexioBase->TIMCMP[base->timerIndex[0]] = timerCmp;
+}
+
+/*!
+ * brief Sends a buffer of data bytes.
+ *
+ * note This function blocks using the polling method until all bytes have been sent.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param direction Shift direction of MSB first or LSB first.
+ * param buffer The data bytes to send.
+ * param size The number of data bytes to send.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_WriteBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_shift_direction_t direction,
+ const uint8_t *buffer,
+ size_t size)
+{
+ assert(buffer != NULL);
+ assert(size != 0U);
+
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != size--)
+ {
+ /* Wait until data transfer complete. */
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_SPI_Timeout;
+ }
+#endif
+ FLEXIO_SPI_WriteData(base, direction, *buffer++);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of bytes.
+ *
+ * note This function blocks using the polling method until all bytes have been received.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param direction Shift direction of MSB first or LSB first.
+ * param buffer The buffer to store the received bytes.
+ * param size The number of data bytes to be received.
+ * param direction Shift direction of MSB first or LSB first.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_ReadBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_shift_direction_t direction,
+ uint8_t *buffer,
+ size_t size)
+{
+ assert(buffer != NULL);
+ assert(size != 0U);
+
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != size--)
+ {
+ /* Wait until data transfer complete. */
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_SPI_Timeout;
+ }
+#endif
+ *buffer++ = (uint8_t)FLEXIO_SPI_ReadData(base, direction);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of bytes.
+ *
+ * note This function blocks via polling until all bytes have been received.
+ *
+ * param base pointer to FLEXIO_SPI_Type structure
+ * param xfer FlexIO SPI transfer structure, see #flexio_spi_transfer_t.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_FLEXIO_SPI_Timeout The transfer timed out and was aborted.
+ */
+status_t FLEXIO_SPI_MasterTransferBlocking(FLEXIO_SPI_Type *base, flexio_spi_transfer_t *xfer)
+{
+ flexio_spi_shift_direction_t direction;
+ uint8_t bytesPerFrame;
+ uint32_t dataMode = 0;
+ uint16_t timerCmp = (uint16_t)(base->flexioBase->TIMCMP[base->timerIndex[0]]);
+ uint16_t tmpData = FLEXIO_SPI_DUMMYDATA;
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ timerCmp &= 0x00FFU;
+ /* Configure the values in handle. */
+ switch (xfer->flags)
+ {
+ case (uint8_t)kFLEXIO_SPI_8bitMsb:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+
+ case (uint8_t)kFLEXIO_SPI_8bitLsb:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+
+ case (uint8_t)kFLEXIO_SPI_16bitMsb:
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 2U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+
+ case (uint8_t)kFLEXIO_SPI_16bitLsb:
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 2U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+
+ default:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ assert(true);
+ break;
+ }
+
+ dataMode |= timerCmp;
+
+ /* Configure transfer size. */
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ while (xfer->dataSize != 0U)
+ {
+ /* Wait until data transfer complete. */
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_SPI_Timeout;
+ }
+#endif
+ if (xfer->txData != NULL)
+ {
+ /* Transmit data and update tx size/buff. */
+ if (bytesPerFrame == 1U)
+ {
+ tmpData = *(xfer->txData);
+ xfer->txData++;
+ }
+ else
+ {
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint16_t)(xfer->txData[0]) << 8U;
+ tmpData += xfer->txData[1];
+ }
+ else
+ {
+ tmpData = (uint16_t)(xfer->txData[1]) << 8U;
+ tmpData += xfer->txData[0];
+ }
+ xfer->txData += 2U;
+ }
+ }
+ else
+ {
+ tmpData = FLEXIO_SPI_DUMMYDATA;
+ }
+
+ xfer->dataSize -= bytesPerFrame;
+
+ FLEXIO_SPI_WriteData(base, direction, tmpData);
+
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_SPI_GetStatusFlags(base) & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_FLEXIO_SPI_Timeout;
+ }
+#endif
+ tmpData = FLEXIO_SPI_ReadData(base, direction);
+
+ if (xfer->rxData != NULL)
+ {
+ if (bytesPerFrame == 1U)
+ {
+ *xfer->rxData = (uint8_t)tmpData;
+ xfer->rxData++;
+ }
+ else
+ {
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ *xfer->rxData = (uint8_t)(tmpData >> 8);
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)tmpData;
+ }
+ else
+ {
+ *xfer->rxData = (uint8_t)tmpData;
+ xfer->rxData++;
+ *xfer->rxData = (uint8_t)(tmpData >> 8);
+ }
+ xfer->rxData++;
+ }
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the FlexIO SPI Master handle, which is used in transactional functions.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_SPI_MasterTransferCreateHandle(FLEXIO_SPI_Type *base,
+ flexio_spi_master_handle_t *handle,
+ flexio_spi_master_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Register callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_SPI_GetInstance(base)]);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_SPI_MasterTransferHandleIRQ);
+}
+
+/*!
+ * brief Master transfer data using IRQ.
+ *
+ * This function sends data using IRQ. This is a non-blocking function, which returns
+ * right away. When all data is sent out/received, the callback function is called.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * param xfer FlexIO SPI transfer structure. See #flexio_spi_transfer_t.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_SPI_Busy SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_MasterTransferNonBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_master_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ uint32_t dataMode = 0;
+ uint16_t timerCmp = (uint16_t)base->flexioBase->TIMCMP[base->timerIndex[0]];
+ uint16_t tmpData = FLEXIO_SPI_DUMMYDATA;
+
+ timerCmp &= 0x00FFU;
+
+ /* Check if SPI is busy. */
+ if (handle->state == (uint32_t)kFLEXIO_SPI_Busy)
+ {
+ return kStatus_FLEXIO_SPI_Busy;
+ }
+
+ /* Check if the argument is legal. */
+ if ((xfer->txData == NULL) && (xfer->rxData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Configure the values in handle */
+ switch (xfer->flags)
+ {
+ case (uint8_t)kFLEXIO_SPI_8bitMsb:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_8bitLsb:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitMsb:
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 2U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitLsb:
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 2U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ default:
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ assert(true);
+ break;
+ }
+
+ dataMode |= timerCmp;
+
+ /* Configure transfer size. */
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ handle->state = (uint32_t)kFLEXIO_SPI_Busy;
+ handle->txData = xfer->txData;
+ handle->rxData = xfer->rxData;
+ handle->rxRemainingBytes = xfer->dataSize;
+
+ /* Save total transfer size. */
+ handle->transferSize = xfer->dataSize;
+
+ /* Send first byte of data to trigger the rx interrupt. */
+ if (handle->txData != NULL)
+ {
+ /* Transmit data and update tx size/buff. */
+ if (handle->bytePerFrame == 1U)
+ {
+ tmpData = *(handle->txData);
+ handle->txData++;
+ }
+ else
+ {
+ if (handle->direction == kFLEXIO_SPI_MsbFirst)
+ {
+ tmpData = (uint16_t)(handle->txData[0]) << 8U;
+ tmpData += handle->txData[1];
+ }
+ else
+ {
+ tmpData = (uint16_t)(handle->txData[1]) << 8U;
+ tmpData += handle->txData[0];
+ }
+ handle->txData += 2U;
+ }
+ }
+ else
+ {
+ tmpData = FLEXIO_SPI_DUMMYDATA;
+ }
+
+ handle->txRemainingBytes = xfer->dataSize - handle->bytePerFrame;
+
+ FLEXIO_SPI_WriteData(base, handle->direction, tmpData);
+
+ /* Enable transmit and receive interrupt to handle rx. */
+ FLEXIO_SPI_EnableInterrupts(base, (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the data transfer status which used IRQ.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * retval kStatus_InvalidArgument count is Invalid.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_SPI_MasterTransferGetCount(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Return remaing bytes in different cases. */
+ if (handle->rxData != NULL)
+ {
+ *count = handle->transferSize - handle->rxRemainingBytes;
+ }
+ else
+ {
+ *count = handle->transferSize - handle->txRemainingBytes;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts the master data transfer, which used IRQ.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_MasterTransferAbort(FLEXIO_SPI_Type *base, flexio_spi_master_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ FLEXIO_SPI_DisableInterrupts(base, (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable);
+ FLEXIO_SPI_DisableInterrupts(base, (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable);
+
+ /* Transfer finished, set the state to idle. */
+ handle->state = (uint32_t)kFLEXIO_SPI_Idle;
+
+ /* Clear the internal state. */
+ handle->rxRemainingBytes = 0;
+ handle->txRemainingBytes = 0;
+}
+
+/*!
+ * brief FlexIO SPI master IRQ handler function.
+ *
+ * param spiType Pointer to the FLEXIO_SPI_Type structure.
+ * param spiHandle Pointer to the flexio_spi_master_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_MasterTransferHandleIRQ(void *spiType, void *spiHandle)
+{
+ assert(spiHandle != NULL);
+
+ flexio_spi_master_handle_t *handle = (flexio_spi_master_handle_t *)spiHandle;
+ FLEXIO_SPI_Type *base;
+ uint32_t status;
+
+ if (handle->state == (uint32_t)kFLEXIO_SPI_Idle)
+ {
+ return;
+ }
+
+ base = (FLEXIO_SPI_Type *)spiType;
+ status = FLEXIO_SPI_GetStatusFlags(base);
+
+ /* Handle rx. */
+ if (((status & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag) != 0U) && (handle->rxRemainingBytes != 0U))
+ {
+ FLEXIO_SPI_TransferReceiveTransaction(base, handle);
+ }
+
+ /* Handle tx. */
+ if (((status & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag) != 0U) && (handle->txRemainingBytes != 0U))
+ {
+ FLEXIO_SPI_TransferSendTransaction(base, handle);
+ }
+
+ /* All the transfer finished. */
+ if ((handle->txRemainingBytes == 0U) && (handle->rxRemainingBytes == 0U))
+ {
+ FLEXIO_SPI_MasterTransferAbort(base, handle);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_FLEXIO_SPI_Idle, handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Initializes the FlexIO SPI Slave handle, which is used in transactional functions.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param handle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_SPI_SlaveTransferCreateHandle(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_handle_t *handle,
+ flexio_spi_slave_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Register callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_SPI_GetInstance(base)]);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_SPI_SlaveTransferHandleIRQ);
+}
+
+/*!
+ * brief Slave transfer data using IRQ.
+ *
+ * This function sends data using IRQ. This is a non-blocking function, which returns
+ * right away. When all data is sent out/received, the callback function is called.
+ * param handle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ *
+ * param base Pointer to the FLEXIO_SPI_Type structure.
+ * param xfer FlexIO SPI transfer structure. See #flexio_spi_transfer_t.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_SPI_Busy SPI is not idle; it is running another transfer.
+ */
+status_t FLEXIO_SPI_SlaveTransferNonBlocking(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ uint32_t dataMode = 0;
+
+ /* Check if SPI is busy. */
+ if (handle->state == (uint32_t)kFLEXIO_SPI_Busy)
+ {
+ return kStatus_FLEXIO_SPI_Busy;
+ }
+
+ /* Check if the argument is legal. */
+ if ((xfer->txData == NULL) && (xfer->rxData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Configure the values in handle */
+ switch (xfer->flags)
+ {
+ case (uint8_t)kFLEXIO_SPI_8bitMsb:
+ dataMode = 8U * 2U - 1U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_8bitLsb:
+ dataMode = 8U * 2U - 1U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitMsb:
+ dataMode = 16U * 2U - 1U;
+ handle->bytePerFrame = 2U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitLsb:
+ dataMode = 16U * 2U - 1U;
+ handle->bytePerFrame = 2U;
+ handle->direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ default:
+ dataMode = 8U * 2U - 1U;
+ handle->bytePerFrame = 1U;
+ handle->direction = kFLEXIO_SPI_MsbFirst;
+ assert(true);
+ break;
+ }
+
+ /* Configure transfer size. */
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ handle->state = (uint32_t)kFLEXIO_SPI_Busy;
+ handle->txData = xfer->txData;
+ handle->rxData = xfer->rxData;
+ handle->txRemainingBytes = xfer->dataSize;
+ handle->rxRemainingBytes = xfer->dataSize;
+
+ /* Save total transfer size. */
+ handle->transferSize = xfer->dataSize;
+
+ /* Enable transmit and receive interrupt to handle tx and rx. */
+ FLEXIO_SPI_EnableInterrupts(base, (uint32_t)kFLEXIO_SPI_TxEmptyInterruptEnable);
+ FLEXIO_SPI_EnableInterrupts(base, (uint32_t)kFLEXIO_SPI_RxFullInterruptEnable);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief FlexIO SPI slave IRQ handler function.
+ *
+ * param spiType Pointer to the FLEXIO_SPI_Type structure.
+ * param spiHandle Pointer to the flexio_spi_slave_handle_t structure to store the transfer state.
+ */
+void FLEXIO_SPI_SlaveTransferHandleIRQ(void *spiType, void *spiHandle)
+{
+ assert(spiHandle != NULL);
+
+ flexio_spi_master_handle_t *handle = (flexio_spi_master_handle_t *)spiHandle;
+ FLEXIO_SPI_Type *base;
+ uint32_t status;
+
+ if (handle->state == (uint32_t)kFLEXIO_SPI_Idle)
+ {
+ return;
+ }
+
+ base = (FLEXIO_SPI_Type *)spiType;
+ status = FLEXIO_SPI_GetStatusFlags(base);
+
+ /* Handle tx. */
+ if (((status & (uint32_t)kFLEXIO_SPI_TxBufferEmptyFlag) != 0U) && (handle->txRemainingBytes != 0U))
+ {
+ FLEXIO_SPI_TransferSendTransaction(base, handle);
+ }
+
+ /* Handle rx. */
+ if (((status & (uint32_t)kFLEXIO_SPI_RxBufferFullFlag) != 0U) && (handle->rxRemainingBytes != 0U))
+ {
+ FLEXIO_SPI_TransferReceiveTransaction(base, handle);
+ }
+
+ /* All the transfer finished. */
+ if ((handle->txRemainingBytes == 0U) && (handle->rxRemainingBytes == 0U))
+ {
+ FLEXIO_SPI_SlaveTransferAbort(base, handle);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_FLEXIO_SPI_Idle, handle->userData);
+ }
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_spi_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_spi_edma.c
new file mode 100644
index 0000000000..3adf92d4df
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_spi_edma.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_spi_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_spi_edma"
+#endif
+
+/*<! Structure definition for spi_edma_private_handle_t. The structure is private. */
+typedef struct _flexio_spi_master_edma_private_handle
+{
+ FLEXIO_SPI_Type *base;
+ flexio_spi_master_edma_handle_t *handle;
+} flexio_spi_master_edma_private_handle_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief EDMA callback function for FLEXIO SPI send transfer.
+ *
+ * @param handle EDMA handle pointer.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief EDMA callback function for FLEXIO SPI receive transfer.
+ *
+ * @param handle EDMA handle pointer.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief EDMA config for FLEXIO SPI transfer.
+ *
+ * @param base pointer to FLEXIO_SPI_Type structure.
+ * @param handle pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
+ * @param xfer Pointer to flexio spi transfer structure.
+ */
+static void FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Dummy data used to send */
+static const uint16_t s_dummyData = FLEXIO_SPI_DUMMYDATA;
+
+/*< @brief user configurable flexio spi handle count. */
+#define FLEXIO_SPI_HANDLE_COUNT 2
+
+/*<! Private handle only used for internally. */
+static flexio_spi_master_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_SPI_HANDLE_COUNT];
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void FLEXIO_SPI_TxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ tcds = tcds;
+ flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
+
+ /* Disable Tx DMA */
+ if (transferDone)
+ {
+ FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, (uint32_t)kFLEXIO_SPI_TxDmaEnable, false);
+
+ /* change the state */
+ spiPrivateHandle->handle->txInProgress = false;
+
+ /* All finished, call the callback */
+ if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
+ {
+ if (spiPrivateHandle->handle->callback != NULL)
+ {
+ (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
+ spiPrivateHandle->handle->userData);
+ }
+ }
+ }
+}
+
+static void FLEXIO_SPI_RxEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ tcds = tcds;
+ flexio_spi_master_edma_private_handle_t *spiPrivateHandle = (flexio_spi_master_edma_private_handle_t *)param;
+
+ if (transferDone)
+ {
+ /* Disable Rx dma */
+ FLEXIO_SPI_EnableDMA(spiPrivateHandle->base, (uint32_t)kFLEXIO_SPI_RxDmaEnable, false);
+
+ /* change the state */
+ spiPrivateHandle->handle->rxInProgress = false;
+
+ /* All finished, call the callback */
+ if ((spiPrivateHandle->handle->txInProgress == false) && (spiPrivateHandle->handle->rxInProgress == false))
+ {
+ if (spiPrivateHandle->handle->callback != NULL)
+ {
+ (spiPrivateHandle->handle->callback)(spiPrivateHandle->base, spiPrivateHandle->handle, kStatus_Success,
+ spiPrivateHandle->handle->userData);
+ }
+ }
+ }
+}
+
+static void FLEXIO_SPI_EDMAConfig(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ edma_transfer_config_t xferConfig = {0};
+ flexio_spi_shift_direction_t direction = kFLEXIO_SPI_MsbFirst;
+ uint8_t bytesPerFrame;
+
+ /* Configure the values in handle. */
+ switch (xfer->flags)
+ {
+ case (uint8_t)kFLEXIO_SPI_8bitMsb:
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_8bitLsb:
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitMsb:
+ bytesPerFrame = 2U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ break;
+ case (uint8_t)kFLEXIO_SPI_16bitLsb:
+ bytesPerFrame = 2U;
+ direction = kFLEXIO_SPI_LsbFirst;
+ break;
+ default:
+ bytesPerFrame = 1U;
+ direction = kFLEXIO_SPI_MsbFirst;
+ assert(true);
+ break;
+ }
+
+ /* Save total transfer size. */
+ handle->transferSize = xfer->dataSize;
+
+ /* Configure tx transfer EDMA. */
+ xferConfig.destAddr = FLEXIO_SPI_GetTxDataRegisterAddress(base, direction);
+ xferConfig.destOffset = 0;
+ if (bytesPerFrame == 1U)
+ {
+ xferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ xferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ xferConfig.minorLoopBytes = 1U;
+ }
+ else
+ {
+ if (direction == kFLEXIO_SPI_MsbFirst)
+ {
+ xferConfig.destAddr -= 1U;
+ }
+ xferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
+ xferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
+ xferConfig.minorLoopBytes = 2U;
+ }
+
+ /* Configure DMA channel. */
+ if (xfer->txData != NULL)
+ {
+ xferConfig.srcOffset = (int16_t)bytesPerFrame;
+ xferConfig.srcAddr = (uint32_t)(xfer->txData);
+ }
+ else
+ {
+ /* Disable the source increasement and source set to dummyData. */
+ xferConfig.srcOffset = 0;
+ xferConfig.srcAddr = (uint32_t)(&s_dummyData);
+ }
+
+ xferConfig.majorLoopCounts = (xfer->dataSize / xferConfig.minorLoopBytes);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO SPI handle */
+ handle->nbytes = (uint8_t)xferConfig.minorLoopBytes;
+
+ if (handle->txHandle != NULL)
+ {
+ (void)EDMA_SubmitTransfer(handle->txHandle, &xferConfig);
+ }
+
+ /* Configure rx transfer EDMA. */
+ if (xfer->rxData != NULL)
+ {
+ xferConfig.srcAddr = FLEXIO_SPI_GetRxDataRegisterAddress(base, direction);
+ if (bytesPerFrame == 2U)
+ {
+ if (direction == kFLEXIO_SPI_LsbFirst)
+ {
+ xferConfig.srcAddr -= 1U;
+ }
+ }
+ xferConfig.srcOffset = 0;
+ xferConfig.destAddr = (uint32_t)(xfer->rxData);
+ xferConfig.destOffset = (int16_t)bytesPerFrame;
+ (void)EDMA_SubmitTransfer(handle->rxHandle, &xferConfig);
+ handle->rxInProgress = true;
+ FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_RxDmaEnable, true);
+ EDMA_StartTransfer(handle->rxHandle);
+ }
+
+ /* Always start tx transfer. */
+ if (handle->txHandle != NULL)
+ {
+ handle->txInProgress = true;
+ FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_TxDmaEnable, true);
+ EDMA_StartTransfer(handle->txHandle);
+ }
+}
+
+/*!
+ * brief Initializes the FlexIO SPI master eDMA handle.
+ *
+ * This function initializes the FlexIO SPI master eDMA handle which can be used for other FlexIO SPI master
+ * transactional
+ * APIs.
+ * For a specified FlexIO SPI instance, call this API once to get the initialized handle.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle Pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
+ * param callback SPI callback, NULL means no callback.
+ * param userData callback function parameter.
+ * param txHandle User requested eDMA handle for FlexIO SPI RX eDMA transfer.
+ * param rxHandle User requested eDMA handle for FlexIO SPI TX eDMA transfer.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO SPI eDMA type/handle table out of range.
+ */
+status_t FLEXIO_SPI_MasterTransferCreateHandleEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_master_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txHandle,
+ edma_handle_t *rxHandle)
+{
+ assert(handle != NULL);
+
+ uint8_t index = 0;
+
+ /* Find the an empty handle pointer to store the handle. */
+ for (index = 0U; index < (uint8_t)FLEXIO_SPI_HANDLE_COUNT; index++)
+ {
+ if (s_edmaPrivateHandle[index].base == NULL)
+ {
+ s_edmaPrivateHandle[index].base = base;
+ s_edmaPrivateHandle[index].handle = handle;
+ break;
+ }
+ }
+
+ if (index == (uint16_t)FLEXIO_SPI_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ /* Set spi base to handle. */
+ handle->txHandle = txHandle;
+ handle->rxHandle = rxHandle;
+
+ /* Register callback and userData. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set SPI state to idle. */
+ handle->txInProgress = false;
+ handle->rxInProgress = false;
+
+ /* Install callback for Tx/Rx dma channel. */
+ if (handle->txHandle != NULL)
+ {
+ EDMA_SetCallback(handle->txHandle, FLEXIO_SPI_TxEDMACallback, &s_edmaPrivateHandle[index]);
+ }
+ if (handle->rxHandle != NULL)
+ {
+ EDMA_SetCallback(handle->rxHandle, FLEXIO_SPI_RxEDMACallback, &s_edmaPrivateHandle[index]);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO SPI transfer using eDMA.
+ *
+ * note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_SPI_MasterGetTransferCountEDMA to poll the transfer status and check
+ * whether the FlexIO SPI transfer is finished.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle Pointer to flexio_spi_master_edma_handle_t structure to store the transfer state.
+ * param xfer Pointer to FlexIO SPI transfer structure.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_MasterTransferEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ uint32_t dataMode = 0;
+ uint16_t timerCmp = (uint16_t)base->flexioBase->TIMCMP[base->timerIndex[0]];
+
+ timerCmp &= 0x00FFU;
+
+ /* Check if the device is busy. */
+ if ((handle->txInProgress) || (handle->rxInProgress))
+ {
+ return kStatus_FLEXIO_SPI_Busy;
+ }
+
+ /* Check if input parameter invalid. */
+ if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* configure data mode. */
+ if ((xfer->flags == (uint8_t)kFLEXIO_SPI_8bitMsb) || (xfer->flags == (uint8_t)kFLEXIO_SPI_8bitLsb))
+ {
+ dataMode = (8UL * 2UL - 1UL) << 8U;
+ }
+ else if ((xfer->flags == (uint8_t)kFLEXIO_SPI_16bitMsb) || (xfer->flags == (uint8_t)kFLEXIO_SPI_16bitLsb))
+ {
+ dataMode = (16UL * 2UL - 1UL) << 8U;
+ }
+ else
+ {
+ dataMode = 8UL * 2UL - 1UL;
+ }
+
+ dataMode |= timerCmp;
+
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ FLEXIO_SPI_EDMAConfig(base, handle, xfer);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the remaining bytes for FlexIO SPI eDMA transfer.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle FlexIO SPI eDMA handle pointer.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ */
+status_t FLEXIO_SPI_MasterTransferGetCountEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_master_edma_handle_t *handle,
+ size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->rxInProgress)
+ {
+ *count =
+ (handle->transferSize - (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(
+ handle->rxHandle->base, handle->rxHandle->channel));
+ }
+ else
+ {
+ *count =
+ (handle->transferSize - (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(
+ handle->txHandle->base, handle->txHandle->channel));
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a FlexIO SPI transfer using eDMA.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle FlexIO SPI eDMA handle pointer.
+ */
+void FLEXIO_SPI_MasterTransferAbortEDMA(FLEXIO_SPI_Type *base, flexio_spi_master_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma. */
+ EDMA_StopTransfer(handle->txHandle);
+ EDMA_StopTransfer(handle->rxHandle);
+
+ /* Disable DMA enable bit. */
+ FLEXIO_SPI_EnableDMA(base, (uint32_t)kFLEXIO_SPI_DmaAllEnable, false);
+
+ /* Set the handle state. */
+ handle->txInProgress = false;
+ handle->rxInProgress = false;
+}
+
+/*!
+ * brief Performs a non-blocking FlexIO SPI transfer using eDMA.
+ *
+ * note This interface returns immediately after transfer initiates. Call
+ * FLEXIO_SPI_SlaveGetTransferCountEDMA to poll the transfer status and
+ * check whether the FlexIO SPI transfer is finished.
+ *
+ * param base Pointer to FLEXIO_SPI_Type structure.
+ * param handle Pointer to flexio_spi_slave_edma_handle_t structure to store the transfer state.
+ * param xfer Pointer to FlexIO SPI transfer structure.
+ * retval kStatus_Success Successfully start a transfer.
+ * retval kStatus_InvalidArgument Input argument is invalid.
+ * retval kStatus_FLEXIO_SPI_Busy FlexIO SPI is not idle, is running another transfer.
+ */
+status_t FLEXIO_SPI_SlaveTransferEDMA(FLEXIO_SPI_Type *base,
+ flexio_spi_slave_edma_handle_t *handle,
+ flexio_spi_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ uint32_t dataMode = 0U;
+
+ /* Check if the device is busy. */
+ if ((handle->txInProgress) || (handle->rxInProgress))
+ {
+ return kStatus_FLEXIO_SPI_Busy;
+ }
+
+ /* Check if input parameter invalid. */
+ if (((xfer->txData == NULL) && (xfer->rxData == NULL)) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* configure data mode. */
+ if ((xfer->flags == (uint8_t)kFLEXIO_SPI_8bitMsb) || (xfer->flags == (uint8_t)kFLEXIO_SPI_8bitLsb))
+ {
+ dataMode = 8U * 2U - 1U;
+ }
+ else if ((xfer->flags == (uint8_t)kFLEXIO_SPI_16bitMsb) || (xfer->flags == (uint8_t)kFLEXIO_SPI_16bitLsb))
+ {
+ dataMode = 16U * 2U - 1U;
+ }
+ else
+ {
+ dataMode = 8U * 2U - 1U;
+ }
+
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = dataMode;
+
+ FLEXIO_SPI_EDMAConfig(base, handle, xfer);
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_uart.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_uart.c
new file mode 100644
index 0000000000..6e524470b8
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_uart.c
@@ -0,0 +1,991 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_uart.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_uart"
+#endif
+
+/*<! @brief uart transfer state. */
+enum _flexio_uart_transfer_states
+{
+ kFLEXIO_UART_TxIdle, /* TX idle. */
+ kFLEXIO_UART_TxBusy, /* TX busy. */
+ kFLEXIO_UART_RxIdle, /* RX idle. */
+ kFLEXIO_UART_RxBusy /* RX busy. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the length of received data in RX ring buffer.
+ *
+ * @param handle FLEXIO UART handle pointer.
+ * @return Length of received data in RX ring buffer.
+ */
+static size_t FLEXIO_UART_TransferGetRxRingBufferLength(flexio_uart_handle_t *handle);
+
+/*!
+ * @brief Check whether the RX ring buffer is full.
+ *
+ * @param handle FLEXIO UART handle pointer.
+ * @retval true RX ring buffer is full.
+ * @retval false RX ring buffer is not full.
+ */
+static bool FLEXIO_UART_TransferIsRxRingBufferFull(flexio_uart_handle_t *handle);
+
+/*******************************************************************************
+ * Codes
+ ******************************************************************************/
+
+static uint32_t FLEXIO_UART_GetInstance(FLEXIO_UART_Type *base)
+{
+ return FLEXIO_GetInstance(base->flexioBase);
+}
+
+static size_t FLEXIO_UART_TransferGetRxRingBufferLength(flexio_uart_handle_t *handle)
+{
+ size_t size;
+ uint16_t rxRingBufferHead = handle->rxRingBufferHead;
+ uint16_t rxRingBufferTail = handle->rxRingBufferTail;
+
+ if (rxRingBufferTail > rxRingBufferHead)
+ {
+ size = (size_t)rxRingBufferHead + handle->rxRingBufferSize - (size_t)rxRingBufferTail;
+ }
+ else
+ {
+ size = (size_t)rxRingBufferHead - (size_t)rxRingBufferTail;
+ }
+
+ return size;
+}
+
+static bool FLEXIO_UART_TransferIsRxRingBufferFull(flexio_uart_handle_t *handle)
+{
+ bool full;
+
+ if (FLEXIO_UART_TransferGetRxRingBufferLength(handle) == (handle->rxRingBufferSize - 1U))
+ {
+ full = true;
+ }
+ else
+ {
+ full = false;
+ }
+
+ return full;
+}
+
+/*!
+ * brief Ungates the FlexIO clock, resets the FlexIO module, configures FlexIO UART
+ * hardware, and configures the FlexIO UART with FlexIO UART configuration.
+ * The configuration structure can be filled by the user or be set with
+ * default values by FLEXIO_UART_GetDefaultConfig().
+ *
+ * Example
+ code
+ FLEXIO_UART_Type base = {
+ .flexioBase = FLEXIO,
+ .TxPinIndex = 0,
+ .RxPinIndex = 1,
+ .shifterIndex = {0,1},
+ .timerIndex = {0,1}
+ };
+ flexio_uart_config_t config = {
+ .enableInDoze = false,
+ .enableInDebug = true,
+ .enableFastAccess = false,
+ .baudRate_Bps = 115200U,
+ .bitCountPerChar = 8
+ };
+ FLEXIO_UART_Init(base, &config, srcClock_Hz);
+ endcode
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param userConfig Pointer to the flexio_uart_config_t structure.
+ * param srcClock_Hz FlexIO source clock in Hz.
+ * retval kStatus_Success Configuration success
+ * retval kStatus_InvalidArgument Buadrate configuration out of range
+*/
+status_t FLEXIO_UART_Init(FLEXIO_UART_Type *base, const flexio_uart_config_t *userConfig, uint32_t srcClock_Hz)
+{
+ assert((base != NULL) && (userConfig != NULL));
+
+ flexio_shifter_config_t shifterConfig;
+ flexio_timer_config_t timerConfig;
+ uint32_t ctrlReg = 0;
+ uint16_t timerDiv = 0;
+ uint16_t timerCmp = 0;
+ status_t result = kStatus_Success;
+
+ /* Clear the shifterConfig & timerConfig struct. */
+ (void)memset(&shifterConfig, 0, sizeof(shifterConfig));
+ (void)memset(&timerConfig, 0, sizeof(timerConfig));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate flexio clock. */
+ CLOCK_EnableClock(s_flexioClocks[FLEXIO_UART_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Configure FLEXIO UART */
+ ctrlReg = base->flexioBase->CTRL;
+ ctrlReg &= ~(FLEXIO_CTRL_DOZEN_MASK | FLEXIO_CTRL_DBGE_MASK | FLEXIO_CTRL_FASTACC_MASK | FLEXIO_CTRL_FLEXEN_MASK);
+ ctrlReg |= (FLEXIO_CTRL_DBGE(userConfig->enableInDebug) | FLEXIO_CTRL_FASTACC(userConfig->enableFastAccess) |
+ FLEXIO_CTRL_FLEXEN(userConfig->enableUart));
+ if (!userConfig->enableInDoze)
+ {
+ ctrlReg |= FLEXIO_CTRL_DOZEN_MASK;
+ }
+
+ base->flexioBase->CTRL = ctrlReg;
+
+ /* Do hardware configuration. */
+ /* 1. Configure the shifter 0 for tx. */
+ shifterConfig.timerSelect = base->timerIndex[0];
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutput;
+ shifterConfig.pinSelect = base->TxPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeTransmit;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitHigh;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitLow;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[0], &shifterConfig);
+
+ /*2. Configure the timer 0 for tx. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->shifterIndex[0]);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceInternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->TxPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneNotAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetNever;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnTriggerHigh;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+
+ timerDiv = (uint16_t)(srcClock_Hz / userConfig->baudRate_Bps);
+ timerDiv = timerDiv / 2U - 1U;
+
+ if (timerDiv > 0xFFU)
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ timerCmp = ((uint16_t)userConfig->bitCountPerChar * 2U - 1U) << 8U;
+ timerCmp |= timerDiv;
+
+ timerConfig.timerCompare = timerCmp;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[0], &timerConfig);
+
+ /* 3. Configure the shifter 1 for rx. */
+ shifterConfig.timerSelect = base->timerIndex[1];
+ shifterConfig.timerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
+ shifterConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ shifterConfig.pinSelect = base->RxPinIndex;
+ shifterConfig.pinPolarity = kFLEXIO_PinActiveHigh;
+ shifterConfig.shifterMode = kFLEXIO_ShifterModeReceive;
+ shifterConfig.inputSource = kFLEXIO_ShifterInputFromPin;
+ shifterConfig.shifterStop = kFLEXIO_ShifterStopBitHigh;
+ shifterConfig.shifterStart = kFLEXIO_ShifterStartBitLow;
+
+ FLEXIO_SetShifterConfig(base->flexioBase, base->shifterIndex[1], &shifterConfig);
+
+ /* 4. Configure the timer 1 for rx. */
+ timerConfig.triggerSelect = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->RxPinIndex);
+ timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
+ timerConfig.triggerSource = kFLEXIO_TimerTriggerSourceExternal;
+ timerConfig.pinConfig = kFLEXIO_PinConfigOutputDisabled;
+ timerConfig.pinSelect = base->RxPinIndex;
+ timerConfig.pinPolarity = kFLEXIO_PinActiveLow;
+ timerConfig.timerMode = kFLEXIO_TimerModeDual8BitBaudBit;
+ timerConfig.timerOutput = kFLEXIO_TimerOutputOneAffectedByReset;
+ timerConfig.timerDecrement = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
+ timerConfig.timerReset = kFLEXIO_TimerResetOnTimerPinRisingEdge;
+ timerConfig.timerDisable = kFLEXIO_TimerDisableOnTimerCompare;
+ timerConfig.timerEnable = kFLEXIO_TimerEnableOnPinRisingEdge;
+ timerConfig.timerStop = kFLEXIO_TimerStopBitEnableOnTimerDisable;
+ timerConfig.timerStart = kFLEXIO_TimerStartBitEnabled;
+
+ timerConfig.timerCompare = timerCmp;
+
+ FLEXIO_SetTimerConfig(base->flexioBase, base->timerIndex[1], &timerConfig);
+
+ return result;
+}
+
+/*!
+ * brief Resets the FlexIO UART shifter and timer config.
+ *
+ * note After calling this API, call the FLEXO_UART_Init to use the FlexIO UART module.
+ *
+ * param base Pointer to FLEXIO_UART_Type structure
+ */
+void FLEXIO_UART_Deinit(FLEXIO_UART_Type *base)
+{
+ base->flexioBase->SHIFTCFG[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[0]] = 0;
+ base->flexioBase->SHIFTCFG[base->shifterIndex[1]] = 0;
+ base->flexioBase->SHIFTCTL[base->shifterIndex[1]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[0]] = 0;
+ base->flexioBase->TIMCFG[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCMP[base->timerIndex[1]] = 0;
+ base->flexioBase->TIMCTL[base->timerIndex[1]] = 0;
+ /* Clear the shifter flag. */
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[0]);
+ base->flexioBase->SHIFTSTAT = (1UL << base->shifterIndex[1]);
+ /* Clear the timer flag. */
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[0]);
+ base->flexioBase->TIMSTAT = (1UL << base->timerIndex[1]);
+}
+
+/*!
+ * brief Gets the default configuration to configure the FlexIO UART. The configuration
+ * can be used directly for calling the FLEXIO_UART_Init().
+ * Example:
+ code
+ flexio_uart_config_t config;
+ FLEXIO_UART_GetDefaultConfig(&userConfig);
+ endcode
+ * param userConfig Pointer to the flexio_uart_config_t structure.
+*/
+void FLEXIO_UART_GetDefaultConfig(flexio_uart_config_t *userConfig)
+{
+ assert(userConfig != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(userConfig, 0, sizeof(*userConfig));
+
+ userConfig->enableUart = true;
+ userConfig->enableInDoze = false;
+ userConfig->enableInDebug = true;
+ userConfig->enableFastAccess = false;
+ /* Default baud rate 115200. */
+ userConfig->baudRate_Bps = 115200U;
+ /* Default bit count at 8. */
+ userConfig->bitCountPerChar = kFLEXIO_UART_8BitsPerChar;
+}
+
+/*!
+ * brief Enables the FlexIO UART interrupt.
+ *
+ * This function enables the FlexIO UART interrupt.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param mask Interrupt source.
+ */
+void FLEXIO_UART_EnableInterrupts(FLEXIO_UART_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable) != 0U)
+ {
+ FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Disables the FlexIO UART interrupt.
+ *
+ * This function disables the FlexIO UART interrupt.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param mask Interrupt source.
+ */
+void FLEXIO_UART_DisableInterrupts(FLEXIO_UART_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable) != 0U)
+ {
+ FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Gets the FlexIO UART status flags.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * return FlexIO UART status flags.
+ */
+
+uint32_t FLEXIO_UART_GetStatusFlags(FLEXIO_UART_Type *base)
+{
+ uint32_t status = 0U;
+ status =
+ ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])) >> base->shifterIndex[0]);
+ status |=
+ (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
+ << 1U);
+ status |=
+ (((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->shifterIndex[1])) >> (base->shifterIndex[1]))
+ << 2U);
+ return status;
+}
+
+/*!
+ * brief Gets the FlexIO UART status flags.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param mask Status flag.
+ * The parameter can be any combination of the following values:
+ * arg kFLEXIO_UART_TxDataRegEmptyFlag
+ * arg kFLEXIO_UART_RxEmptyFlag
+ * arg kFLEXIO_UART_RxOverRunFlag
+ */
+
+void FLEXIO_UART_ClearStatusFlags(FLEXIO_UART_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kFLEXIO_UART_TxDataRegEmptyFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[0]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag) != 0U)
+ {
+ FLEXIO_ClearShifterStatusFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+ if ((mask & (uint32_t)kFLEXIO_UART_RxOverRunFlag) != 0U)
+ {
+ FLEXIO_ClearShifterErrorFlags(base->flexioBase, 1UL << base->shifterIndex[1]);
+ }
+}
+
+/*!
+ * brief Sends a buffer of data bytes.
+ *
+ * note This function blocks using the polling method until all bytes have been sent.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param txData The data bytes to send.
+ * param txSize The number of data bytes to send.
+ * retval kStatus_FLEXIO_UART_Timeout Transmission timed out and was aborted.
+ * retval kStatus_Success Successfully wrote all data.
+ */
+status_t FLEXIO_UART_WriteBlocking(FLEXIO_UART_Type *base, const uint8_t *txData, size_t txSize)
+{
+ assert(txData != NULL);
+ assert(txSize != 0U);
+#if UART_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != txSize--)
+ {
+ /* Wait until data transfer complete. */
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+ while ((0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0]))) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->shifterIndex[0])))
+#endif
+ {
+ }
+#if UART_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_UART_Timeout;
+ }
+#endif
+
+ base->flexioBase->SHIFTBUF[base->shifterIndex[0]] = *txData++;
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of bytes.
+ *
+ * note This function blocks using the polling method until all bytes have been received.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param rxData The buffer to store the received bytes.
+ * param rxSize The number of data bytes to be received.
+ * retval kStatus_FLEXIO_UART_Timeout Transmission timed out and was aborted.
+ * retval kStatus_Success Successfully received all data.
+ */
+status_t FLEXIO_UART_ReadBlocking(FLEXIO_UART_Type *base, uint8_t *rxData, size_t rxSize)
+{
+ assert(rxData != NULL);
+ assert(rxSize != 0U);
+#if UART_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != rxSize--)
+ {
+ /* Wait until data transfer complete. */
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+ while ((0U == (FLEXIO_UART_GetStatusFlags(base) & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag)) &&
+ (0U != --waitTimes))
+#else
+ while (0U == (FLEXIO_UART_GetStatusFlags(base) & (uint32_t)kFLEXIO_UART_RxDataRegFullFlag))
+#endif
+ {
+ }
+#if UART_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_FLEXIO_UART_Timeout;
+ }
+#endif
+
+ *rxData++ = (uint8_t)(base->flexioBase->SHIFTBUFBYS[base->shifterIndex[1]]);
+ }
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the UART handle.
+ *
+ * This function initializes the FlexIO UART handle, which can be used for other FlexIO
+ * UART transactional APIs. Call this API once to get the
+ * initialized handle.
+ *
+ * The UART driver supports the "background" receiving, which means that users can set up
+ * a RX ring buffer optionally. Data received is stored into the ring buffer even when
+ * the user doesn't call the FLEXIO_UART_TransferReceiveNonBlocking() API. If there is already data
+ * received in the ring buffer, users can get the received data from the ring buffer
+ * directly. The ring buffer is disabled if passing NULL as p ringBuffer.
+ *
+ * param base to FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO type/handle/ISR table out of range.
+ */
+status_t FLEXIO_UART_TransferCreateHandle(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set the TX/RX state. */
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+
+ /* Set the callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Enable interrupt in NVIC. */
+ (void)EnableIRQ(flexio_irqs[FLEXIO_UART_GetInstance(base)]);
+
+ /* Save the context in global variables to support the double weak mechanism. */
+ return FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_UART_TransferHandleIRQ);
+}
+
+/*!
+ * brief Sets up the RX ring buffer.
+ *
+ * This function sets up the RX ring buffer to a specific UART handle.
+ *
+ * When the RX ring buffer is used, data received is stored into the ring buffer even when
+ * the user doesn't call the UART_ReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, users can get the received data from the ring buffer directly.
+ *
+ * note When using the RX ring buffer, one byte is reserved for internal use. In other
+ * words, if p ringBufferSize is 32, only 31 bytes are used for saving data.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param ringBuffer Start address of ring buffer for background receiving. Pass NULL to disable the ring buffer.
+ * param ringBufferSize Size of the ring buffer.
+ */
+void FLEXIO_UART_TransferStartRingBuffer(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ uint8_t *ringBuffer,
+ size_t ringBufferSize)
+{
+ assert(handle != NULL);
+
+ /* Setup the ringbuffer address */
+ if (ringBuffer != NULL)
+ {
+ handle->rxRingBuffer = ringBuffer;
+ handle->rxRingBufferSize = ringBufferSize;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+
+ /* Enable the interrupt to accept the data when user need the ring buffer. */
+ FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+}
+
+/*!
+ * brief Aborts the background transfer and uninstalls the ring buffer.
+ *
+ * This function aborts the background transfer and uninstalls the ring buffer.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferStopRingBuffer(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ if (handle->rxState == (uint8_t)kFLEXIO_UART_RxIdle)
+ {
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+
+ handle->rxRingBuffer = NULL;
+ handle->rxRingBufferSize = 0U;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+}
+
+/*!
+ * brief Transmits a buffer of data using the interrupt method.
+ *
+ * This function sends data using an interrupt method. This is a non-blocking function,
+ * which returns directly without waiting for all data to be written to the TX register. When
+ * all data is written to the TX register in ISR, the FlexIO UART driver calls the callback
+ * function and passes the ref kStatus_FLEXIO_UART_TxIdle as status parameter.
+ *
+ * note The kStatus_FLEXIO_UART_TxIdle is passed to the upper layer when all data is written
+ * to the TX register. However, it does not ensure that all data is sent out.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param xfer FlexIO UART transfer structure. See #flexio_uart_transfer_t.
+ * retval kStatus_Success Successfully starts the data transmission.
+ * retval kStatus_UART_TxBusy Previous transmission still not finished, data not written to the TX register.
+ */
+status_t FLEXIO_UART_TransferSendNonBlocking(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_t *xfer)
+{
+ status_t status;
+
+ /* Return error if xfer invalid. */
+ if ((0U == xfer->dataSize) || (NULL == xfer->data))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Return error if current TX busy. */
+ if ((uint8_t)kFLEXIO_UART_TxBusy == handle->txState)
+ {
+ status = kStatus_FLEXIO_UART_TxBusy;
+ }
+ else
+ {
+ handle->txData = xfer->data;
+ handle->txDataSize = xfer->dataSize;
+ handle->txDataSizeAll = xfer->dataSize;
+ handle->txState = (uint8_t)kFLEXIO_UART_TxBusy;
+
+ /* Enable transmiter interrupt. */
+ FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the interrupt-driven data transmit.
+ *
+ * This function aborts the interrupt-driven data sending. Get the remainBytes to find out
+ * how many bytes are still not sent out.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferAbortSend(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
+{
+ /* Disable the transmitter and disable the interrupt. */
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
+
+ handle->txDataSize = 0U;
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes sent.
+ *
+ * This function gets the number of bytes sent driven by interrupt.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param count Number of bytes sent so far by the non-blocking transaction.
+ * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetSendCount(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+ assert(count != NULL);
+
+ if ((uint8_t)kFLEXIO_UART_TxIdle == handle->txState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->txDataSizeAll - handle->txDataSize;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Receives a buffer of data using the interrupt method.
+ *
+ * This function receives data using the interrupt method. This is a non-blocking function,
+ * which returns without waiting for all data to be received.
+ * If the RX ring buffer is used and not empty, the data in ring buffer is copied and
+ * the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
+ * After copying, if the data in ring buffer is not enough to read, the receive
+ * request is saved by the UART driver. When new data arrives, the receive request
+ * is serviced first. When all data is received, the UART driver notifies the upper layer
+ * through a callback function and passes the status parameter ref kStatus_UART_RxIdle.
+ * For example, if the upper layer needs 10 bytes but there are only 5 bytes in the ring buffer,
+ * the 5 bytes are copied to xfer->data. This function returns with the
+ * parameter p receivedBytes set to 5. For the last 5 bytes, newly arrived data is
+ * saved from the xfer->data[5]. When 5 bytes are received, the UART driver notifies upper layer.
+ * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
+ * to receive data to xfer->data. When all data is received, the upper layer is notified.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param xfer UART transfer structure. See #flexio_uart_transfer_t.
+ * param receivedBytes Bytes received from the ring buffer directly.
+ * retval kStatus_Success Successfully queue the transfer into the transmit queue.
+ * retval kStatus_FLEXIO_UART_RxBusy Previous receive request is not finished.
+ */
+status_t FLEXIO_UART_TransferReceiveNonBlocking(FLEXIO_UART_Type *base,
+ flexio_uart_handle_t *handle,
+ flexio_uart_transfer_t *xfer,
+ size_t *receivedBytes)
+{
+ uint32_t i;
+ status_t status;
+ /* How many bytes to copy from ring buffer to user memory. */
+ size_t bytesToCopy = 0U;
+ /* How many bytes to receive. */
+ size_t bytesToReceive;
+ /* How many bytes currently have received. */
+ size_t bytesCurrentReceived;
+
+ /* Return error if xfer invalid. */
+ if ((0U == xfer->dataSize) || (NULL == xfer->data))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* How to get data:
+ 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
+ to uart handle, enable interrupt to store received data to xfer->data. When
+ all data received, trigger callback.
+ 2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
+ If there are enough data in ring buffer, copy them to xfer->data and return.
+ If there are not enough data in ring buffer, copy all of them to xfer->data,
+ save the xfer->data remained empty space to uart handle, receive data
+ to this empty space and trigger callback when finished. */
+
+ if ((uint8_t)kFLEXIO_UART_RxBusy == handle->rxState)
+ {
+ status = kStatus_FLEXIO_UART_RxBusy;
+ }
+ else
+ {
+ bytesToReceive = xfer->dataSize;
+ bytesCurrentReceived = 0U;
+
+ /* If RX ring buffer is used. */
+ if (handle->rxRingBuffer != NULL)
+ {
+ /* Disable FLEXIO_UART RX IRQ, protect ring buffer. */
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+
+ /* How many bytes in RX ring buffer currently. */
+ bytesToCopy = FLEXIO_UART_TransferGetRxRingBufferLength(handle);
+
+ if (bytesToCopy != 0U)
+ {
+ bytesToCopy = MIN(bytesToReceive, bytesToCopy);
+
+ bytesToReceive -= bytesToCopy;
+
+ /* Copy data from ring buffer to user memory. */
+ for (i = 0U; i < bytesToCopy; i++)
+ {
+ xfer->data[bytesCurrentReceived++] = handle->rxRingBuffer[handle->rxRingBufferTail];
+
+ /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
+ if ((uint32_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+ }
+
+ /* If ring buffer does not have enough data, still need to read more data. */
+ if (bytesToReceive != 0U)
+ {
+ /* No data in ring buffer, save the request to UART handle. */
+ handle->rxData = xfer->data + bytesCurrentReceived;
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = bytesToReceive;
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxBusy;
+ }
+
+ /* Enable FLEXIO_UART RX IRQ if previously enabled. */
+ FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+
+ /* Call user callback since all data are received. */
+ if (0U == bytesToReceive)
+ {
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_RxIdle, handle->userData);
+ }
+ }
+ }
+ /* Ring buffer not used. */
+ else
+ {
+ handle->rxData = xfer->data + bytesCurrentReceived;
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = bytesToReceive;
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxBusy;
+
+ /* Enable RX interrupt. */
+ FLEXIO_UART_EnableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+
+ /* Return the how many bytes have read. */
+ if (receivedBytes != NULL)
+ {
+ *receivedBytes = bytesCurrentReceived;
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the receive data which was using IRQ.
+ *
+ * This function aborts the receive data which was using IRQ.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferAbortReceive(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle)
+{
+ /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
+ if (NULL == handle->rxRingBuffer)
+ {
+ /* Disable RX interrupt. */
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+
+ handle->rxDataSize = 0U;
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes received.
+ *
+ * This function gets the number of bytes received driven by interrupt.
+ *
+ * param base Pointer to the FLEXIO_UART_Type structure.
+ * param handle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ * param count Number of bytes received so far by the non-blocking transaction.
+ * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetReceiveCount(FLEXIO_UART_Type *base, flexio_uart_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+ assert(count != NULL);
+
+ if ((uint8_t)kFLEXIO_UART_RxIdle == handle->rxState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->rxDataSizeAll - handle->rxDataSize;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief FlexIO UART IRQ handler function.
+ *
+ * This function processes the FlexIO UART transmit and receives the IRQ request.
+ *
+ * param uartType Pointer to the FLEXIO_UART_Type structure.
+ * param uartHandle Pointer to the flexio_uart_handle_t structure to store the transfer state.
+ */
+void FLEXIO_UART_TransferHandleIRQ(void *uartType, void *uartHandle)
+{
+ uint8_t count = 1;
+ FLEXIO_UART_Type *base = (FLEXIO_UART_Type *)uartType;
+ flexio_uart_handle_t *handle = (flexio_uart_handle_t *)uartHandle;
+ uint16_t rxRingBufferHead;
+
+ /* Read the status back. */
+ uint32_t status = FLEXIO_UART_GetStatusFlags(base);
+
+ /* If RX overrun. */
+ if (((uint32_t)kFLEXIO_UART_RxOverRunFlag & status) != 0U)
+ {
+ /* Clear Overrun flag. */
+ FLEXIO_UART_ClearStatusFlags(base, (uint32_t)kFLEXIO_UART_RxOverRunFlag);
+
+ /* Trigger callback. */
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_RxHardwareOverrun, handle->userData);
+ }
+ }
+
+ /* Receive data register full */
+ if ((((uint32_t)kFLEXIO_UART_RxDataRegFullFlag & status) != 0U) &&
+ ((base->flexioBase->SHIFTSIEN & (1UL << base->shifterIndex[1])) != 0U))
+ {
+ /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
+ if (handle->rxDataSize != 0U)
+ {
+ /* Using non block API to read the data from the registers. */
+ FLEXIO_UART_ReadByte(base, handle->rxData);
+ handle->rxDataSize--;
+ handle->rxData++;
+ count--;
+
+ /* If all the data required for upper layer is ready, trigger callback. */
+ if (0U == handle->rxDataSize)
+ {
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_RxIdle, handle->userData);
+ }
+ }
+ }
+
+ if (handle->rxRingBuffer != NULL)
+ {
+ if (count != 0U)
+ {
+ /* If RX ring buffer is full, trigger callback to notify over run. */
+ if (FLEXIO_UART_TransferIsRxRingBufferFull(handle))
+ {
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_RxRingBufferOverrun, handle->userData);
+ }
+ }
+
+ /* If ring buffer is still full after callback function, the oldest data is overridden. */
+ if (FLEXIO_UART_TransferIsRxRingBufferFull(handle))
+ {
+ /* Increase handle->rxRingBufferTail to make room for new data. */
+ if ((uint32_t)handle->rxRingBufferTail + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+
+ /* Read data. */
+ rxRingBufferHead = handle->rxRingBufferHead;
+ handle->rxRingBuffer[rxRingBufferHead] =
+ (uint8_t)(base->flexioBase->SHIFTBUFBYS[base->shifterIndex[1]]);
+
+ /* Increase handle->rxRingBufferHead. */
+ if ((uint32_t)handle->rxRingBufferHead + 1U == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferHead = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferHead++;
+ }
+ }
+ }
+ /* If no receive requst pending, stop RX interrupt. */
+ else if (0U == handle->rxDataSize)
+ {
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_RxDataRegFullInterruptEnable);
+ }
+ else
+ {
+ }
+ }
+
+ /* Send data register empty and the interrupt is enabled. */
+ if ((((uint32_t)kFLEXIO_UART_TxDataRegEmptyFlag & status) != 0U) &&
+ ((base->flexioBase->SHIFTSIEN & (1UL << base->shifterIndex[0])) != 0U))
+ {
+ if (handle->txDataSize != 0U)
+ {
+ /* Using non block API to write the data to the registers. */
+ FLEXIO_UART_WriteByte(base, handle->txData);
+ handle->txData++;
+ handle->txDataSize--;
+
+ /* If all the data are written to data register, TX finished. */
+ if (0U == handle->txDataSize)
+ {
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+
+ /* Disable TX register empty interrupt. */
+ FLEXIO_UART_DisableInterrupts(base, (uint32_t)kFLEXIO_UART_TxDataRegEmptyInterruptEnable);
+
+ /* Trigger callback. */
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_FLEXIO_UART_TxIdle, handle->userData);
+ }
+ }
+ }
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_uart_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_uart_edma.c
new file mode 100644
index 0000000000..522cbe83c9
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexio_uart_edma.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexio_uart_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexio_uart_edma"
+#endif
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct _flexio_uart_edma_private_handle
+{
+ FLEXIO_UART_Type *base;
+ flexio_uart_edma_handle_t *handle;
+} flexio_uart_edma_private_handle_t;
+
+/* UART EDMA transfer handle. */
+enum _flexio_uart_edma_tansfer_states
+{
+ kFLEXIO_UART_TxIdle, /* TX idle. */
+ kFLEXIO_UART_TxBusy, /* TX busy. */
+ kFLEXIO_UART_RxIdle, /* RX idle. */
+ kFLEXIO_UART_RxBusy /* RX busy. */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*< @brief user configurable flexio uart handle count. */
+#define FLEXIO_UART_HANDLE_COUNT 2
+
+/*<! Private handle only used for internally. */
+static flexio_uart_edma_private_handle_t s_edmaPrivateHandle[FLEXIO_UART_HANDLE_COUNT];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief FLEXIO UART EDMA send finished callback function.
+ *
+ * This function is called when FLEXIO UART EDMA send finished. It disables the UART
+ * TX EDMA request and sends @ref kStatus_FLEXIO_UART_TxIdle to FLEXIO UART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief FLEXIO UART EDMA receive finished callback function.
+ *
+ * This function is called when FLEXIO UART EDMA receive finished. It disables the UART
+ * RX EDMA request and sends @ref kStatus_FLEXIO_UART_RxIdle to UART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
+ void *param,
+ bool transferDone,
+ uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void FLEXIO_UART_TransferSendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
+
+ assert(uartPrivateHandle->handle != NULL);
+
+ /* Avoid the warning for unused variables. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ FLEXIO_UART_TransferAbortSendEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
+
+ if (uartPrivateHandle->handle->callback != NULL)
+ {
+ uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
+ kStatus_FLEXIO_UART_TxIdle, uartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+static void FLEXIO_UART_TransferReceiveEDMACallback(edma_handle_t *handle,
+ void *param,
+ bool transferDone,
+ uint32_t tcds)
+{
+ flexio_uart_edma_private_handle_t *uartPrivateHandle = (flexio_uart_edma_private_handle_t *)param;
+
+ assert(uartPrivateHandle->handle != NULL);
+
+ /* Avoid the warning for unused variables. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ /* Disable transfer. */
+ FLEXIO_UART_TransferAbortReceiveEDMA(uartPrivateHandle->base, uartPrivateHandle->handle);
+
+ if (uartPrivateHandle->handle->callback != NULL)
+ {
+ uartPrivateHandle->handle->callback(uartPrivateHandle->base, uartPrivateHandle->handle,
+ kStatus_FLEXIO_UART_RxIdle, uartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Initializes the UART handle which is used in transactional functions.
+ *
+ * param base Pointer to FLEXIO_UART_Type.
+ * param handle Pointer to flexio_uart_edma_handle_t structure.
+ * param callback The callback function.
+ * param userData The parameter of the callback function.
+ * param rxEdmaHandle User requested DMA handle for RX DMA transfer.
+ * param txEdmaHandle User requested DMA handle for TX DMA transfer.
+ * retval kStatus_Success Successfully create the handle.
+ * retval kStatus_OutOfRange The FlexIO SPI eDMA type/handle table out of range.
+ */
+status_t FLEXIO_UART_TransferCreateHandleEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txEdmaHandle,
+ edma_handle_t *rxEdmaHandle)
+{
+ assert(handle != NULL);
+
+ uint8_t index = 0U;
+
+ /* Find the an empty handle pointer to store the handle. */
+ for (index = 0U; index < (uint8_t)FLEXIO_UART_HANDLE_COUNT; index++)
+ {
+ if (s_edmaPrivateHandle[index].base == NULL)
+ {
+ s_edmaPrivateHandle[index].base = base;
+ s_edmaPrivateHandle[index].handle = handle;
+ break;
+ }
+ }
+
+ if (index == (uint8_t)FLEXIO_UART_HANDLE_COUNT)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+
+ handle->rxEdmaHandle = rxEdmaHandle;
+ handle->txEdmaHandle = txEdmaHandle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Configure TX. */
+ if (txEdmaHandle != NULL)
+ {
+ EDMA_SetCallback(handle->txEdmaHandle, FLEXIO_UART_TransferSendEDMACallback, &s_edmaPrivateHandle);
+ }
+
+ /* Configure RX. */
+ if (rxEdmaHandle != NULL)
+ {
+ EDMA_SetCallback(handle->rxEdmaHandle, FLEXIO_UART_TransferReceiveEDMACallback, &s_edmaPrivateHandle);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sends data using eDMA.
+ *
+ * This function sends data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is sent out, the send callback function is called.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle UART handle pointer.
+ * param xfer UART eDMA transfer structure, see #flexio_uart_transfer_t.
+ * retval kStatus_Success if succeed, others failed.
+ * retval kStatus_FLEXIO_UART_TxBusy Previous transfer on going.
+ */
+status_t FLEXIO_UART_TransferSendEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_transfer_t *xfer)
+{
+ assert(handle->txEdmaHandle != NULL);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* Return error if xfer invalid. */
+ if ((0U == xfer->dataSize) || (NULL == xfer->data))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* If previous TX not finished. */
+ if ((uint8_t)kFLEXIO_UART_TxBusy == handle->txState)
+ {
+ status = kStatus_FLEXIO_UART_TxBusy;
+ }
+ else
+ {
+ handle->txState = (uint8_t)kFLEXIO_UART_TxBusy;
+ handle->txDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t),
+ (uint32_t *)FLEXIO_UART_GetTxDataRegisterAddress(base), sizeof(uint8_t), sizeof(uint8_t),
+ xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
+ handle->nbytes = sizeof(uint8_t);
+
+ /* Submit transfer. */
+ (void)EDMA_SubmitTransfer(handle->txEdmaHandle, &xferConfig);
+ EDMA_StartTransfer(handle->txEdmaHandle);
+
+ /* Enable UART TX EDMA. */
+ FLEXIO_UART_EnableTxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives data using eDMA.
+ *
+ * This function receives data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ * param xfer UART eDMA transfer structure, see #flexio_uart_transfer_t.
+ * retval kStatus_Success if succeed, others failed.
+ * retval kStatus_UART_RxBusy Previous transfer on going.
+ */
+status_t FLEXIO_UART_TransferReceiveEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ flexio_uart_transfer_t *xfer)
+{
+ assert(handle->rxEdmaHandle != NULL);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* Return error if xfer invalid. */
+ if ((0U == xfer->dataSize) || (NULL == xfer->data))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* If previous RX not finished. */
+ if ((uint8_t)kFLEXIO_UART_RxBusy == handle->rxState)
+ {
+ status = kStatus_FLEXIO_UART_RxBusy;
+ }
+ else
+ {
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxBusy;
+ handle->rxDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, (uint32_t *)FLEXIO_UART_GetRxDataRegisterAddress(base), sizeof(uint8_t),
+ xfer->data, sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the FLEXIO UART handle */
+ handle->nbytes = sizeof(uint8_t);
+
+ /* Submit transfer. */
+ (void)EDMA_SubmitTransfer(handle->rxEdmaHandle, &xferConfig);
+ EDMA_StartTransfer(handle->rxEdmaHandle);
+
+ /* Enable UART RX EDMA. */
+ FLEXIO_UART_EnableRxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the sent data which using eDMA.
+ *
+ * This function aborts sent data which using eDMA.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ */
+void FLEXIO_UART_TransferAbortSendEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
+{
+ assert(handle->txEdmaHandle != NULL);
+
+ /* Disable UART TX EDMA. */
+ FLEXIO_UART_EnableTxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_StopTransfer(handle->txEdmaHandle);
+
+ handle->txState = (uint8_t)kFLEXIO_UART_TxIdle;
+}
+
+/*!
+ * brief Aborts the receive data which using eDMA.
+ *
+ * This function aborts the receive data which using eDMA.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ */
+void FLEXIO_UART_TransferAbortReceiveEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle)
+{
+ assert(handle->rxEdmaHandle != NULL);
+
+ /* Disable UART RX EDMA. */
+ FLEXIO_UART_EnableRxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_StopTransfer(handle->rxEdmaHandle);
+
+ handle->rxState = (uint8_t)kFLEXIO_UART_RxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes received.
+ *
+ * This function gets the number of bytes received.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ * param count Number of bytes received so far by the non-blocking transaction.
+ * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetReceiveCountEDMA(FLEXIO_UART_Type *base,
+ flexio_uart_edma_handle_t *handle,
+ size_t *count)
+{
+ assert(handle != NULL);
+ assert(handle->rxEdmaHandle != NULL);
+ assert(count != NULL);
+
+ if ((uint8_t)kFLEXIO_UART_RxIdle == handle->rxState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->rxDataSizeAll -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the number of bytes sent out.
+ *
+ * This function gets the number of bytes sent out.
+ *
+ * param base Pointer to FLEXIO_UART_Type
+ * param handle Pointer to flexio_uart_edma_handle_t structure
+ * param count Number of bytes sent so far by the non-blocking transaction.
+ * retval kStatus_NoTransferInProgress transfer has finished or no transfer in progress.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXIO_UART_TransferGetSendCountEDMA(FLEXIO_UART_Type *base, flexio_uart_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+ assert(handle->txEdmaHandle != NULL);
+ assert(count != NULL);
+
+ if ((uint8_t)kFLEXIO_UART_TxIdle == handle->txState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->txDataSizeAll -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel);
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexram.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexram.c
new file mode 100644
index 0000000000..898c0d897c
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexram.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexram.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexram"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base FLEXRAM base address
+ *
+ * @return The FLEXRAM instance
+ */
+static uint32_t FLEXRAM_GetInstance(FLEXRAM_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to FLEXRAM bases for each instance. */
+static FLEXRAM_Type *const s_flexramBases[] = FLEXRAM_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to FLEXRAM clocks for each instance. */
+static const clock_ip_name_t s_flexramClocks[] = FLEXRAM_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t FLEXRAM_GetInstance(FLEXRAM_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexramBases); instance++)
+ {
+ if (s_flexramBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexramBases));
+
+ return instance;
+}
+
+/*!
+ * brief FLEXRAM module initialization function.
+ *
+ * param base FLEXRAM base address.
+ */
+void FLEXRAM_Init(FLEXRAM_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate ENET clock. */
+ CLOCK_EnableClock(s_flexramClocks[FLEXRAM_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* enable all the interrupt status */
+ base->INT_STAT_EN |= (uint32_t)kFLEXRAM_InterruptStatusAll;
+ /* clear all the interrupt status */
+ base->INT_STATUS |= (uint32_t)kFLEXRAM_InterruptStatusAll;
+ /* disable all the interrpt */
+ base->INT_SIG_EN = 0U;
+}
+
+/*!
+ * brief Deinitializes the FLEXRAM.
+ *
+ */
+void FLEXRAN_Deinit(FLEXRAM_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate ENET clock. */
+ CLOCK_DisableClock(s_flexramClocks[FLEXRAM_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexram_allocate.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexram_allocate.c
new file mode 100644
index 0000000000..cf1b3bfaf1
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexram_allocate.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexram_allocate.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexram"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief FLEXRAM map TCM size to register value
+ *
+ * @param tcmBankNum tcm banknumber
+ * @retval register value correspond to the tcm size
+ */
+static uint8_t FLEXRAM_MapTcmSizeToRegister(uint8_t tcmBankNum);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint8_t FLEXRAM_MapTcmSizeToRegister(uint8_t tcmBankNum)
+{
+ uint8_t tcmSizeConfig = 0U;
+ uint32_t totalTcmSize = 0U;
+
+ /* if bank number is a odd value, use a new bank number which bigger than target */
+ do
+ {
+ if ((tcmBankNum & (tcmBankNum - 1U)) == 0U)
+ {
+ break;
+ }
+ } while (++tcmBankNum < (uint8_t)FSL_FEATURE_FLEXRAM_INTERNAL_RAM_TOTAL_BANK_NUMBERS);
+
+ totalTcmSize = (uint32_t)tcmBankNum * ((uint32_t)FSL_FEATURE_FLEXRAM_INTERNAL_RAM_BANK_SIZE >> 10U);
+ /* get bit '1' position */
+ while (totalTcmSize != 0x00U)
+ {
+ if ((totalTcmSize & 1U) == 0U)
+ {
+ tcmSizeConfig++;
+ }
+ else
+ {
+ break;
+ }
+ totalTcmSize >>= 1U;
+ }
+
+ return tcmSizeConfig + 1U;
+}
+
+void FLEXRAM_SetTCMSize(uint8_t itcmBankNum, uint8_t dtcmBankNum)
+{
+ assert(itcmBankNum <= FSL_FEATURE_FLEXRAM_INTERNAL_RAM_TOTAL_BANK_NUMBERS);
+ assert(dtcmBankNum <= FSL_FEATURE_FLEXRAM_INTERNAL_RAM_TOTAL_BANK_NUMBERS);
+
+ /* dtcm configuration */
+ if (dtcmBankNum != 0U)
+ {
+ IOMUXC_GPR->GPR14 &= ~IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ_MASK;
+ IOMUXC_GPR->GPR14 |= IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ(FLEXRAM_MapTcmSizeToRegister(dtcmBankNum));
+ IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_INIT_DTCM_EN_MASK;
+ }
+ else
+ {
+ IOMUXC_GPR->GPR16 &= ~IOMUXC_GPR_GPR16_INIT_DTCM_EN_MASK;
+ }
+
+ /* itcm configuration */
+ if (itcmBankNum != 0U)
+ {
+ IOMUXC_GPR->GPR14 &= ~IOMUXC_GPR_GPR14_CM7_CFGITCMSZ_MASK;
+ IOMUXC_GPR->GPR14 |= IOMUXC_GPR_GPR14_CM7_CFGITCMSZ(FLEXRAM_MapTcmSizeToRegister(itcmBankNum));
+ IOMUXC_GPR->GPR16 |= IOMUXC_GPR_GPR16_INIT_ITCM_EN_MASK;
+ }
+ else
+ {
+ IOMUXC_GPR->GPR16 &= ~IOMUXC_GPR_GPR16_INIT_ITCM_EN_MASK;
+ }
+}
+
+/*!
+ * brief FLEXRAM allocate on-chip ram for OCRAM,ITCM,DTCM
+ * This function is independent of FLEXRAM_Init, it can be called directly if ram re-allocate
+ * is needed.
+ * param config allocate configuration.
+ * retval kStatus_InvalidArgument the argument is invalid
+ * kStatus_Success allocate success
+ */
+status_t FLEXRAM_AllocateRam(flexram_allocate_ram_t *config)
+{
+ assert(config != NULL);
+
+ uint8_t dtcmBankNum = config->dtcmBankNum;
+ uint8_t itcmBankNum = config->itcmBankNum;
+ uint8_t ocramBankNum = config->ocramBankNum;
+ uint8_t i = 0U;
+ uint32_t bankCfg = 0U;
+ status_t status = kStatus_Success;
+
+ /* check the arguments */
+ if ((uint8_t)FSL_FEATURE_FLEXRAM_INTERNAL_RAM_TOTAL_BANK_NUMBERS < (dtcmBankNum + itcmBankNum + ocramBankNum))
+ {
+ status = kStatus_InvalidArgument;
+ }
+ else
+ {
+ /* flexram bank config value */
+ for (i = 0U; i < (uint8_t)FSL_FEATURE_FLEXRAM_INTERNAL_RAM_TOTAL_BANK_NUMBERS; i++)
+ {
+ if (i < ocramBankNum)
+ {
+ bankCfg |= ((uint32_t)kFLEXRAM_BankOCRAM) << (i * 2U);
+ continue;
+ }
+
+ if (i < (dtcmBankNum + ocramBankNum))
+ {
+ bankCfg |= ((uint32_t)kFLEXRAM_BankDTCM) << (i * 2U);
+ continue;
+ }
+
+ if (i < (dtcmBankNum + ocramBankNum + itcmBankNum))
+ {
+ bankCfg |= ((uint32_t)kFLEXRAM_BankITCM) << (i * 2U);
+ continue;
+ }
+ }
+
+ IOMUXC_GPR->GPR17 = bankCfg;
+
+ /* set TCM size */
+ FLEXRAM_SetTCMSize(itcmBankNum, dtcmBankNum);
+ /* select ram allocate source from FLEXRAM_BANK_CFG */
+ FLEXRAM_SetAllocateRamSrc(kFLEXRAM_BankAllocateThroughBankCfg);
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexspi.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexspi.c
new file mode 100644
index 0000000000..0fdadefabe
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_flexspi.c
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexspi.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.flexspi"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+#define FREQ_1MHz (1000000UL)
+#define FLEXSPI_DLLCR_DEFAULT (0x100UL)
+#define FLEXSPI_LUT_KEY_VAL (0x5AF05AF0UL)
+
+enum
+{
+ kFLEXSPI_DelayCellUnitMin = 75, /* 75ps. */
+ kFLEXSPI_DelayCellUnitMax = 225, /* 225ps. */
+};
+
+enum
+{
+ kFLEXSPI_FlashASampleClockSlaveDelayLocked =
+ FLEXSPI_STS2_ASLVLOCK_MASK, /* Flash A sample clock slave delay line locked. */
+ kFLEXSPI_FlashASampleClockRefDelayLocked =
+ FLEXSPI_STS2_AREFLOCK_MASK, /* Flash A sample clock reference delay line locked. */
+ kFLEXSPI_FlashBSampleClockSlaveDelayLocked =
+ FLEXSPI_STS2_BSLVLOCK_MASK, /* Flash B sample clock slave delay line locked. */
+ kFLEXSPI_FlashBSampleClockRefDelayLocked =
+ FLEXSPI_STS2_BREFLOCK_MASK, /* Flash B sample clock reference delay line locked. */
+};
+
+/*! @brief Common sets of flags used by the driver. */
+enum _flexspi_flag_constants
+{
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kIrqFlags = kFLEXSPI_IpTxFifoWatermarkEmptyFlag | kFLEXSPI_IpRxFifoWatermarkAvailableFlag |
+ kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag |
+ kFLEXSPI_IpCommandGrantTimeoutFlag | kFLEXSPI_IpCommandExecutionDoneFlag,
+
+ /*! Errors to check for. */
+ kErrorFlags = kFLEXSPI_SequenceExecutionTimeoutFlag | kFLEXSPI_IpCommandSequenceErrorFlag |
+ kFLEXSPI_IpCommandGrantTimeoutFlag,
+};
+
+enum _flexspi_transfer_state
+{
+ kFLEXSPI_Idle = 0x0U, /*!< Transfer is done. */
+ kFLEXSPI_BusyWrite = 0x1U, /*!< FLEXSPI is busy write transfer. */
+ kFLEXSPI_BusyRead = 0x2U, /*!< FLEXSPI is busy write transfer. */
+};
+
+/*! @brief Typedef for interrupt handler. */
+typedef void (*flexspi_isr_t)(FLEXSPI_Type *base, flexspi_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance number for FLEXSPI.
+ *
+ * @param base FLEXSPI base pointer.
+ */
+uint32_t FLEXSPI_GetInstance(FLEXSPI_Type *base);
+
+/*!
+ * @brief Configure flash A/B sample clock DLL.
+ *
+ * @param base FLEXSPI base pointer.
+ * @param config Flash configuration parameters.
+ */
+static uint32_t FLEXSPI_ConfigureDll(FLEXSPI_Type *base, flexspi_device_config_t *config);
+
+/*!
+ * @brief Check and clear IP command execution errors.
+ *
+ * @param base FLEXSPI base pointer.
+ * @param status interrupt status.
+ */
+status_t FLEXSPI_CheckAndClearError(FLEXSPI_Type *base, uint32_t status);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to flexspi bases for each instance. */
+static FLEXSPI_Type *const s_flexspiBases[] = FLEXSPI_BASE_PTRS;
+
+/*! @brief Pointers to flexspi IRQ number for each instance. */
+static const IRQn_Type s_flexspiIrqs[] = FLEXSPI_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_flexspiClock[] = FLEXSPI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+/*! @brief Pointers to flexspi handles for each instance. */
+static flexspi_handle_t *s_flexspiHandle[ARRAY_SIZE(s_flexspiBases)];
+#endif
+
+#if defined(FSL_FEATURE_FLEXSPI_HAS_RESET) && FSL_FEATURE_FLEXSPI_HAS_RESET
+/*! @brief Pointers to FLEXSPI resets for each instance. */
+static const reset_ip_name_t s_flexspiResets[] = FLEXSPI_RSTS;
+#endif
+
+#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+/*! @brief Pointer to flexspi IRQ handler. */
+static flexspi_isr_t s_flexspiIsr;
+#endif
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+uint32_t FLEXSPI_GetInstance(FLEXSPI_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_flexspiBases); instance++)
+ {
+ if (s_flexspiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_flexspiBases));
+
+ return instance;
+}
+
+static uint32_t FLEXSPI_ConfigureDll(FLEXSPI_Type *base, flexspi_device_config_t *config)
+{
+ bool isUnifiedConfig = true;
+ uint32_t flexspiDllValue;
+ uint32_t dllValue;
+ uint32_t temp;
+
+ uint32_t rxSampleClock = (base->MCR0 & FLEXSPI_MCR0_RXCLKSRC_MASK) >> FLEXSPI_MCR0_RXCLKSRC_SHIFT;
+ switch (rxSampleClock)
+ {
+ case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackInternally:
+ case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackFromDqsPad:
+ case (uint32_t)kFLEXSPI_ReadSampleClkLoopbackFromSckPad:
+ isUnifiedConfig = true;
+ break;
+ case (uint32_t)kFLEXSPI_ReadSampleClkExternalInputFromDqsPad:
+ if (config->isSck2Enabled)
+ {
+ isUnifiedConfig = true;
+ }
+ else
+ {
+ isUnifiedConfig = false;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ if (isUnifiedConfig)
+ {
+ flexspiDllValue = FLEXSPI_DLLCR_DEFAULT; /* 1 fixed delay cells in DLL delay chain) */
+ }
+ else
+ {
+ if (config->flexspiRootClk >= 100U * FREQ_1MHz)
+ {
+ /* DLLEN = 1, SLVDLYTARGET = 0xF, */
+ flexspiDllValue = FLEXSPI_DLLCR_DLLEN(1) | FLEXSPI_DLLCR_SLVDLYTARGET(0x0F);
+ }
+ else
+ {
+ temp = (uint32_t)config->dataValidTime * 1000U; /* Convert data valid time in ns to ps. */
+ dllValue = temp / (uint32_t)kFLEXSPI_DelayCellUnitMin;
+ if (dllValue * (uint32_t)kFLEXSPI_DelayCellUnitMin < temp)
+ {
+ dllValue++;
+ }
+ flexspiDllValue = FLEXSPI_DLLCR_OVRDEN(1) | FLEXSPI_DLLCR_OVRDVAL(dllValue);
+ }
+ }
+ return flexspiDllValue;
+}
+
+status_t FLEXSPI_CheckAndClearError(FLEXSPI_Type *base, uint32_t status)
+{
+ status_t result = kStatus_Success;
+
+ /* Check for error. */
+ status &= (uint32_t)kErrorFlags;
+ if (0U != status)
+ {
+ /* Select the correct error code.. */
+ if (0U != (status & (uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag))
+ {
+ result = kStatus_FLEXSPI_SequenceExecutionTimeout;
+ }
+ else if (0U != (status & (uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag))
+ {
+ result = kStatus_FLEXSPI_IpCommandSequenceError;
+ }
+ else if (0U != (status & (uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag))
+ {
+ result = kStatus_FLEXSPI_IpCommandGrantTimeout;
+ }
+ else
+ {
+ assert(false);
+ }
+
+ /* Clear the flags. */
+ FLEXSPI_ClearInterruptStatusFlags(base, status);
+
+ /* Reset fifos. These flags clear automatically. */
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Initializes the FLEXSPI module and internal state.
+ *
+ * This function enables the clock for FLEXSPI and also configures the FLEXSPI with the
+ * input configure parameters. Users should call this function before any FLEXSPI operations.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param config FLEXSPI configure structure.
+ */
+void FLEXSPI_Init(FLEXSPI_Type *base, const flexspi_config_t *config)
+{
+ uint32_t configValue = 0;
+ uint8_t i = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the flexspi clock */
+ (void)CLOCK_EnableClock(s_flexspiClock[FLEXSPI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_FLEXSPI_HAS_RESET) && FSL_FEATURE_FLEXSPI_HAS_RESET
+ /* Reset the FLEXSPI module */
+ RESET_PeripheralReset(s_flexspiResets[FLEXSPI_GetInstance(base)]);
+#endif
+
+ /* Reset peripheral before configuring it. */
+ base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
+ FLEXSPI_SoftwareReset(base);
+
+ /* Configure MCR0 configuration items. */
+ configValue = FLEXSPI_MCR0_RXCLKSRC(config->rxSampleClock) | FLEXSPI_MCR0_DOZEEN(config->enableDoze) |
+ FLEXSPI_MCR0_IPGRANTWAIT(config->ipGrantTimeoutCycle) |
+ FLEXSPI_MCR0_AHBGRANTWAIT(config->ahbConfig.ahbGrantTimeoutCycle) |
+ FLEXSPI_MCR0_SCKFREERUNEN(config->enableSckFreeRunning) |
+ FLEXSPI_MCR0_HSEN(config->enableHalfSpeedAccess) |
+ FLEXSPI_MCR0_COMBINATIONEN(config->enableCombination) |
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN)
+ FLEXSPI_MCR0_ATDFEN(config->ahbConfig.enableAHBWriteIpTxFifo) |
+#endif
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN)
+ FLEXSPI_MCR0_ARDFEN(config->ahbConfig.enableAHBWriteIpRxFifo) |
+#endif
+ FLEXSPI_MCR0_MDIS_MASK;
+ base->MCR0 = configValue;
+
+ /* Configure MCR1 configurations. */
+ configValue =
+ FLEXSPI_MCR1_SEQWAIT(config->seqTimeoutCycle) | FLEXSPI_MCR1_AHBBUSWAIT(config->ahbConfig.ahbBusTimeoutCycle);
+ base->MCR1 = configValue;
+
+ /* Configure MCR2 configurations. */
+ configValue = base->MCR2;
+ configValue &= ~(FLEXSPI_MCR2_RESUMEWAIT_MASK | FLEXSPI_MCR2_SCKBDIFFOPT_MASK | FLEXSPI_MCR2_SAMEDEVICEEN_MASK |
+ FLEXSPI_MCR2_CLRAHBBUFOPT_MASK);
+ configValue |= FLEXSPI_MCR2_RESUMEWAIT(config->ahbConfig.resumeWaitCycle) |
+ FLEXSPI_MCR2_SCKBDIFFOPT(config->enableSckBDiffOpt) |
+ FLEXSPI_MCR2_SAMEDEVICEEN(config->enableSameConfigForAll) |
+ FLEXSPI_MCR2_CLRAHBBUFOPT(config->ahbConfig.enableClearAHBBufferOpt);
+
+ base->MCR2 = configValue;
+
+ /* Configure AHB control items. */
+ configValue = base->AHBCR;
+ configValue &= ~(FLEXSPI_AHBCR_READADDROPT_MASK | FLEXSPI_AHBCR_PREFETCHEN_MASK | FLEXSPI_AHBCR_BUFFERABLEEN_MASK |
+ FLEXSPI_AHBCR_CACHABLEEN_MASK);
+ configValue |= FLEXSPI_AHBCR_READADDROPT(config->ahbConfig.enableReadAddressOpt) |
+ FLEXSPI_AHBCR_PREFETCHEN(config->ahbConfig.enableAHBPrefetch) |
+ FLEXSPI_AHBCR_BUFFERABLEEN(config->ahbConfig.enableAHBBufferable) |
+ FLEXSPI_AHBCR_CACHABLEEN(config->ahbConfig.enableAHBCachable);
+ base->AHBCR = configValue;
+
+ /* Configure AHB rx buffers. */
+ for (i = 0; i < (uint32_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT; i++)
+ {
+ configValue = base->AHBRXBUFCR0[i];
+
+ configValue &= ~(FLEXSPI_AHBRXBUFCR0_PREFETCHEN_MASK | FLEXSPI_AHBRXBUFCR0_PRIORITY_MASK |
+ FLEXSPI_AHBRXBUFCR0_MSTRID_MASK | FLEXSPI_AHBRXBUFCR0_BUFSZ_MASK);
+ configValue |= FLEXSPI_AHBRXBUFCR0_PREFETCHEN(config->ahbConfig.buffer[i].enablePrefetch) |
+ FLEXSPI_AHBRXBUFCR0_PRIORITY(config->ahbConfig.buffer[i].priority) |
+ FLEXSPI_AHBRXBUFCR0_MSTRID(config->ahbConfig.buffer[i].masterIndex) |
+ FLEXSPI_AHBRXBUFCR0_BUFSZ((uint32_t)config->ahbConfig.buffer[i].bufferSize / 8U);
+ base->AHBRXBUFCR0[i] = configValue;
+ }
+
+ /* Configure IP Fifo watermarks. */
+ base->IPRXFCR &= ~FLEXSPI_IPRXFCR_RXWMRK_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_RXWMRK((uint32_t)config->rxWatermark / 8U - 1U);
+ base->IPTXFCR &= ~FLEXSPI_IPTXFCR_TXWMRK_MASK;
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_TXWMRK((uint32_t)config->txWatermark / 8U - 1U);
+
+ /* Reset flash size on all ports */
+ for (i = 0; i < (uint32_t)kFLEXSPI_PortCount; i++)
+ {
+ base->FLSHCR0[i] = 0;
+ }
+}
+
+/*!
+ * brief Gets default settings for FLEXSPI.
+ *
+ * param config FLEXSPI configuration structure.
+ */
+void FLEXSPI_GetDefaultConfig(flexspi_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->rxSampleClock = kFLEXSPI_ReadSampleClkLoopbackInternally;
+ config->enableSckFreeRunning = false;
+ config->enableCombination = false;
+ config->enableDoze = true;
+ config->enableHalfSpeedAccess = false;
+ config->enableSckBDiffOpt = false;
+ config->enableSameConfigForAll = false;
+ config->seqTimeoutCycle = 0xFFFFU;
+ config->ipGrantTimeoutCycle = 0xFFU;
+ config->txWatermark = 8;
+ config->rxWatermark = 8;
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ATDFEN)
+ config->ahbConfig.enableAHBWriteIpTxFifo = false;
+#endif
+#if !(defined(FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN) && FSL_FEATURE_FLEXSPI_HAS_NO_MCR0_ARDFEN)
+ config->ahbConfig.enableAHBWriteIpRxFifo = false;
+#endif
+ config->ahbConfig.ahbGrantTimeoutCycle = 0xFFU;
+ config->ahbConfig.ahbBusTimeoutCycle = 0xFFFFU;
+ config->ahbConfig.resumeWaitCycle = 0x20U;
+ (void)memset(config->ahbConfig.buffer, 0, sizeof(config->ahbConfig.buffer));
+ /* Use invalid master ID 0xF and buffer size 0 for the first several buffers. */
+ for (uint8_t i = 0; i < ((uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 2U); i++)
+ {
+ config->ahbConfig.buffer[i].enablePrefetch = true; /* Default enable AHB prefetch. */
+ config->ahbConfig.buffer[i].masterIndex = 0xFU; /* Invalid master index which is not used, so will never hit. */
+ config->ahbConfig.buffer[i].bufferSize =
+ 0; /* Default buffer size 0 for buffer0 to buffer(FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 3U)*/
+ }
+
+ for (uint8_t i = ((uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT - 2U);
+ i < (uint8_t)FSL_FEATURE_FLEXSPI_AHB_BUFFER_COUNT; i++)
+ {
+ config->ahbConfig.buffer[i].enablePrefetch = true; /* Default enable AHB prefetch. */
+ config->ahbConfig.buffer[i].bufferSize = 256U; /* Default buffer size 256 bytes. */
+ }
+ config->ahbConfig.enableClearAHBBufferOpt = false;
+ config->ahbConfig.enableReadAddressOpt = false;
+ config->ahbConfig.enableAHBPrefetch = false;
+ config->ahbConfig.enableAHBBufferable = false;
+ config->ahbConfig.enableAHBCachable = false;
+}
+
+/*!
+ * brief Deinitializes the FLEXSPI module.
+ *
+ * Clears the FLEXSPI state and FLEXSPI module registers.
+ * param base FLEXSPI peripheral base address.
+ */
+void FLEXSPI_Deinit(FLEXSPI_Type *base)
+{
+ /* Reset peripheral. */
+ FLEXSPI_SoftwareReset(base);
+}
+
+/*!
+ * brief Configures the connected device parameter.
+ *
+ * This function configures the connected device relevant parameters, such as the size, command, and so on.
+ * The flash configuration value cannot have a default value. The user needs to configure it according to the
+ * connected device.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param config Flash configuration parameters.
+ * param port FLEXSPI Operation port.
+ */
+void FLEXSPI_SetFlashConfig(FLEXSPI_Type *base, flexspi_device_config_t *config, flexspi_port_t port)
+{
+ uint32_t configValue = 0;
+ uint32_t statusValue = 0;
+ uint8_t index = (uint8_t)port >> 1U; /* PortA with index 0, PortB with index 1. */
+
+ /* Wait for bus idle before change flash configuration. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ /* Configure flash size. */
+ base->FLSHCR0[port] = config->flashSize;
+
+ /* Configure flash parameters. */
+ base->FLSHCR1[port] = FLEXSPI_FLSHCR1_CSINTERVAL(config->CSInterval) |
+ FLEXSPI_FLSHCR1_CSINTERVALUNIT(config->CSIntervalUnit) |
+ FLEXSPI_FLSHCR1_TCSH(config->CSHoldTime) | FLEXSPI_FLSHCR1_TCSS(config->CSSetupTime) |
+ FLEXSPI_FLSHCR1_CAS(config->columnspace) | FLEXSPI_FLSHCR1_WA(config->enableWordAddress);
+
+ /* Configure AHB operation items. */
+ configValue = base->FLSHCR2[port];
+
+ configValue &= ~(FLEXSPI_FLSHCR2_AWRWAITUNIT_MASK | FLEXSPI_FLSHCR2_AWRWAIT_MASK | FLEXSPI_FLSHCR2_AWRSEQNUM_MASK |
+ FLEXSPI_FLSHCR2_AWRSEQID_MASK | FLEXSPI_FLSHCR2_ARDSEQNUM_MASK | FLEXSPI_FLSHCR2_ARDSEQID_MASK);
+
+ configValue |=
+ FLEXSPI_FLSHCR2_AWRWAITUNIT(config->AHBWriteWaitUnit) | FLEXSPI_FLSHCR2_AWRWAIT(config->AHBWriteWaitInterval);
+
+ if (config->AWRSeqNumber > 0U)
+ {
+ configValue |= FLEXSPI_FLSHCR2_AWRSEQID((uint32_t)config->AWRSeqIndex) |
+ FLEXSPI_FLSHCR2_AWRSEQNUM((uint32_t)config->AWRSeqNumber - 1U);
+ }
+
+ if (config->ARDSeqNumber > 0U)
+ {
+ configValue |= FLEXSPI_FLSHCR2_ARDSEQID((uint32_t)config->ARDSeqIndex) |
+ FLEXSPI_FLSHCR2_ARDSEQNUM((uint32_t)config->ARDSeqNumber - 1U);
+ }
+
+ base->FLSHCR2[port] = configValue;
+
+ /* Configure DLL. */
+ configValue = FLEXSPI_ConfigureDll(base, config);
+ base->DLLCR[index] = configValue;
+
+ /* Configure write mask. */
+ if (config->enableWriteMask)
+ {
+ base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMOPT1_MASK;
+ }
+ else
+ {
+ base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMOPT1_MASK;
+ }
+
+ if (index == 0U) /*PortA*/
+ {
+ base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENA_MASK;
+ base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENA(config->enableWriteMask);
+ }
+ else
+ {
+ base->FLSHCR4 &= ~FLEXSPI_FLSHCR4_WMENB_MASK;
+ base->FLSHCR4 |= FLEXSPI_FLSHCR4_WMENB(config->enableWriteMask);
+ }
+
+ /* Exit stop mode. */
+ base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
+
+ /* According to ERR011377, need to delay at least 100 NOPs to ensure the DLL is locked. */
+ statusValue =
+ (index == 0U) ?
+ ((uint32_t)kFLEXSPI_FlashASampleClockSlaveDelayLocked |
+ (uint32_t)kFLEXSPI_FlashASampleClockRefDelayLocked) :
+ ((uint32_t)kFLEXSPI_FlashBSampleClockSlaveDelayLocked | (uint32_t)kFLEXSPI_FlashBSampleClockRefDelayLocked);
+
+ if (0U != (configValue & FLEXSPI_DLLCR_DLLEN_MASK))
+ {
+ /* Wait slave delay line locked and slave reference delay line locked. */
+ while ((base->STS2 & statusValue) != statusValue)
+ {
+ }
+
+ /* Wait at least 100 NOPs*/
+ for (uint8_t delay = 100U; delay > 0U; delay--)
+ {
+ __NOP();
+ }
+ }
+}
+
+/*! brief Updates the LUT table.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param index From which index start to update. It could be any index of the LUT table, which
+ * also allows user to update command content inside a command. Each command consists of up to
+ * 8 instructions and occupy 4*32-bit memory.
+ * param cmd Command sequence array.
+ * param count Number of sequences.
+ */
+void FLEXSPI_UpdateLUT(FLEXSPI_Type *base, uint32_t index, const uint32_t *cmd, uint32_t count)
+{
+ assert(index < 64U);
+
+ uint32_t i = 0;
+ volatile uint32_t *lutBase;
+
+ /* Wait for bus idle before change flash configuration. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ /* Unlock LUT for update. */
+ base->LUTKEY = FLEXSPI_LUT_KEY_VAL;
+ base->LUTCR = 0x02;
+
+ lutBase = &base->LUT[index];
+ for (i = 0; i < count; i++)
+ {
+ *lutBase++ = *cmd++;
+ }
+
+ /* Lock LUT. */
+ base->LUTKEY = FLEXSPI_LUT_KEY_VAL;
+ base->LUTCR = 0x01;
+}
+
+/*! brief Update read sample clock source
+ *
+ * param base FLEXSPI peripheral base address.
+ * param clockSource clockSource of type #flexspi_read_sample_clock_t
+ */
+void FLEXSPI_UpdateRxSampleClock(FLEXSPI_Type *base, flexspi_read_sample_clock_t clockSource)
+{
+ uint32_t mcr0Val;
+
+ /* Wait for bus idle before change flash configuration. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ mcr0Val = base->MCR0;
+ mcr0Val &= ~FLEXSPI_MCR0_RXCLKSRC_MASK;
+ mcr0Val |= FLEXSPI_MCR0_RXCLKSRC(clockSource);
+ base->MCR0 = mcr0Val;
+
+ /* Reset peripheral. */
+ FLEXSPI_SoftwareReset(base);
+}
+
+/*!
+ * brief Sends a buffer of data bytes using blocking method.
+ * note This function blocks via polling until all bytes have been sent.
+ * param base FLEXSPI peripheral base address
+ * param buffer The data bytes to send
+ * param size The number of data bytes to send
+ * retval kStatus_Success write success without error
+ * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected
+ * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_WriteBlocking(FLEXSPI_Type *base, uint32_t *buffer, size_t size)
+{
+ uint32_t txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;
+ uint32_t status;
+ status_t result = kStatus_Success;
+ uint32_t i = 0;
+
+ /* Send data buffer */
+ while (0U != size)
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ while (0U == ((status = base->INTR) & (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag))
+ {
+ }
+
+ result = FLEXSPI_CheckAndClearError(base, status);
+
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Write watermark level data into tx fifo . */
+ if (size >= 8U * txWatermark)
+ {
+ for (i = 0U; i < 2U * txWatermark; i++)
+ {
+ base->TFDR[i] = *buffer++;
+ }
+
+ size = size - 8U * txWatermark;
+ }
+ else
+ {
+ for (i = 0U; i < (size / 4U + 1U); i++)
+ {
+ base->TFDR[i] = *buffer++;
+ }
+ size = 0U;
+ }
+
+ /* Push a watermark level data into IP TX FIFO. */
+ base->INTR |= (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Receives a buffer of data bytes using a blocking method.
+ * note This function blocks via polling until all bytes have been sent.
+ * param base FLEXSPI peripheral base address
+ * param buffer The data bytes to send
+ * param size The number of data bytes to receive
+ * retval kStatus_Success read success without error
+ * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected
+ * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_ReadBlocking(FLEXSPI_Type *base, uint32_t *buffer, size_t size)
+{
+ uint32_t rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;
+ uint32_t status;
+ status_t result = kStatus_Success;
+ uint32_t i = 0;
+ bool isReturn = false;
+
+ /* Send data buffer */
+ while (0U != size)
+ {
+ if (size >= 8U * rxWatermark)
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ while (0U == ((status = base->INTR) & (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag))
+ {
+ result = FLEXSPI_CheckAndClearError(base, status);
+
+ if (kStatus_Success != result)
+ {
+ isReturn = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* Wait fill level. This also checks for errors. */
+ while (size > ((((base->IPRXFSTS) & FLEXSPI_IPRXFSTS_FILL_MASK) >> FLEXSPI_IPRXFSTS_FILL_SHIFT) * 8U))
+ {
+ result = FLEXSPI_CheckAndClearError(base, base->INTR);
+
+ if (kStatus_Success != result)
+ {
+ isReturn = true;
+ break;
+ }
+ }
+ }
+
+ if (isReturn)
+ {
+ break;
+ }
+
+ result = FLEXSPI_CheckAndClearError(base, base->INTR);
+
+ if (kStatus_Success != result)
+ {
+ break;
+ }
+
+ /* Read watermark level data from rx fifo . */
+ if (size >= 8U * rxWatermark)
+ {
+ for (i = 0U; i < 2U * rxWatermark; i++)
+ {
+ *buffer++ = base->RFDR[i];
+ }
+
+ size = size - 8U * rxWatermark;
+ }
+ else
+ {
+ for (i = 0U; i < ((size + 3U) / 4U); i++)
+ {
+ *buffer++ = base->RFDR[i];
+ }
+ size = 0;
+ }
+
+ /* Pop out a watermark level datas from IP RX FIFO. */
+ base->INTR |= (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Execute command to transfer a buffer data bytes using a blocking method.
+ * param base FLEXSPI peripheral base address
+ * param xfer pointer to the transfer structure.
+ * retval kStatus_Success command transfer success without error
+ * retval kStatus_FLEXSPI_SequenceExecutionTimeout sequence execution timeout
+ * retval kStatus_FLEXSPI_IpCommandSequenceError IP command sequence error detected
+ * retval kStatus_FLEXSPI_IpCommandGrantTimeout IP command grant timeout detected
+ */
+status_t FLEXSPI_TransferBlocking(FLEXSPI_Type *base, flexspi_transfer_t *xfer)
+{
+ uint32_t configValue = 0;
+ status_t result = kStatus_Success;
+
+ /* Clear sequence pointer before sending data to external devices. */
+ base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
+
+ /* Clear former pending status before start this transfer. */
+ base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
+ FLEXSPI_INTR_IPCMDGE_MASK;
+
+ /* Configure base address. */
+ base->IPCR0 = xfer->deviceAddress;
+
+ /* Reset fifos. */
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
+
+ /* Configure data size. */
+ if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
+ {
+ configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
+ }
+
+ /* Configure sequence ID. */
+ configValue |=
+ FLEXSPI_IPCR1_ISEQID((uint32_t)xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
+ base->IPCR1 = configValue;
+
+ /* Start Transfer. */
+ base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
+
+ if ((xfer->cmdType == kFLEXSPI_Write) || (xfer->cmdType == kFLEXSPI_Config))
+ {
+ result = FLEXSPI_WriteBlocking(base, xfer->data, xfer->dataSize);
+ }
+ else if (xfer->cmdType == kFLEXSPI_Read)
+ {
+ result = FLEXSPI_ReadBlocking(base, xfer->data, xfer->dataSize);
+ }
+ else
+ {
+ /* Empty else. */
+ }
+
+ /* Wait for bus idle. */
+ while (!FLEXSPI_GetBusIdleStatus(base))
+ {
+ }
+
+ if (xfer->cmdType == kFLEXSPI_Command)
+ {
+ result = FLEXSPI_CheckAndClearError(base, base->INTR);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Initializes the FLEXSPI handle which is used in transactional functions.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure to store the transfer state.
+ * param callback pointer to user callback function.
+ * param userData user parameter passed to the callback function.
+ */
+void FLEXSPI_TransferCreateHandle(FLEXSPI_Type *base,
+ flexspi_handle_t *handle,
+ flexspi_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ uint32_t instance = FLEXSPI_GetInstance(base);
+
+ /* Zero handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set callback and userData. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+ /* Save the context in global variables to support the double weak mechanism. */
+ s_flexspiHandle[instance] = handle;
+ s_flexspiIsr = FLEXSPI_TransferHandleIRQ;
+#endif
+
+ /* Enable NVIC interrupt. */
+ (void)EnableIRQ(s_flexspiIrqs[instance]);
+}
+
+/*!
+ * brief Performs a interrupt non-blocking transfer on the FLEXSPI bus.
+ *
+ * note Calling the API returns immediately after transfer initiates. The user needs
+ * to call FLEXSPI_GetTransferCount to poll the transfer status to check whether
+ * the transfer is finished. If the return status is not kStatus_FLEXSPI_Busy, the transfer
+ * is finished. For FLEXSPI_Read, the dataSize should be multiple of rx watermark level, or
+ * FLEXSPI could not read data properly.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure which stores the transfer state.
+ * param xfer pointer to flexspi_transfer_t structure.
+ * retval kStatus_Success Successfully start the data transmission.
+ * retval kStatus_FLEXSPI_Busy Previous transmission still not finished.
+ */
+status_t FLEXSPI_TransferNonBlocking(FLEXSPI_Type *base, flexspi_handle_t *handle, flexspi_transfer_t *xfer)
+{
+ uint32_t configValue = 0;
+ status_t result = kStatus_Success;
+
+ assert(NULL != handle);
+ assert(NULL != xfer);
+
+ /* Check if the I2C bus is idle - if not return busy status. */
+ if (handle->state != (uint32_t)kFLEXSPI_Idle)
+ {
+ result = kStatus_FLEXSPI_Busy;
+ }
+ else
+ {
+ handle->data = xfer->data;
+ handle->dataSize = xfer->dataSize;
+ handle->transferTotalSize = xfer->dataSize;
+ handle->state = (xfer->cmdType == kFLEXSPI_Read) ? (uint32_t)kFLEXSPI_BusyRead : (uint32_t)kFLEXSPI_BusyWrite;
+
+ /* Clear sequence pointer before sending data to external devices. */
+ base->FLSHCR2[xfer->port] |= FLEXSPI_FLSHCR2_CLRINSTRPTR_MASK;
+
+ /* Clear former pending status before start this transfer. */
+ base->INTR |= FLEXSPI_INTR_AHBCMDERR_MASK | FLEXSPI_INTR_IPCMDERR_MASK | FLEXSPI_INTR_AHBCMDGE_MASK |
+ FLEXSPI_INTR_IPCMDGE_MASK;
+
+ /* Configure base address. */
+ base->IPCR0 = xfer->deviceAddress;
+
+ /* Reset fifos. */
+ base->IPTXFCR |= FLEXSPI_IPTXFCR_CLRIPTXF_MASK;
+ base->IPRXFCR |= FLEXSPI_IPRXFCR_CLRIPRXF_MASK;
+
+ /* Configure data size. */
+ if ((xfer->cmdType == kFLEXSPI_Read) || (xfer->cmdType == kFLEXSPI_Write))
+ {
+ configValue = FLEXSPI_IPCR1_IDATSZ(xfer->dataSize);
+ }
+
+ /* Configure sequence ID. */
+ configValue |=
+ FLEXSPI_IPCR1_ISEQID((uint32_t)xfer->seqIndex) | FLEXSPI_IPCR1_ISEQNUM((uint32_t)xfer->SeqNumber - 1U);
+ base->IPCR1 = configValue;
+
+ /* Start Transfer. */
+ base->IPCMD |= FLEXSPI_IPCMD_TRG_MASK;
+
+ if (handle->state == (uint32_t)kFLEXSPI_BusyRead)
+ {
+ FLEXSPI_EnableInterrupts(base, (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag |
+ (uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag |
+ (uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag |
+ (uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag |
+ (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag);
+ }
+ else
+ {
+ FLEXSPI_EnableInterrupts(
+ base, (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag | (uint32_t)kFLEXSPI_SequenceExecutionTimeoutFlag |
+ (uint32_t)kFLEXSPI_IpCommandSequenceErrorFlag | (uint32_t)kFLEXSPI_IpCommandGrantTimeoutFlag |
+ (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag);
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief Gets the master transfer status during a interrupt non-blocking transfer.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * retval kStatus_InvalidArgument count is Invalid.
+ * retval kStatus_Success Successfully return the count.
+ */
+status_t FLEXSPI_TransferGetCount(FLEXSPI_Type *base, flexspi_handle_t *handle, size_t *count)
+{
+ assert(NULL != handle);
+
+ status_t result = kStatus_Success;
+
+ if (handle->state == (uint32_t)kFLEXSPI_Idle)
+ {
+ result = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->transferTotalSize - handle->dataSize;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Aborts an interrupt non-blocking transfer early.
+ *
+ * note This API can be called at any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure which stores the transfer state
+ */
+void FLEXSPI_TransferAbort(FLEXSPI_Type *base, flexspi_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ FLEXSPI_DisableInterrupts(base, (uint32_t)kIrqFlags);
+ handle->state = (uint32_t)kFLEXSPI_Idle;
+}
+
+/*!
+ * brief Master interrupt handler.
+ *
+ * param base FLEXSPI peripheral base address.
+ * param handle pointer to flexspi_handle_t structure.
+ */
+void FLEXSPI_TransferHandleIRQ(FLEXSPI_Type *base, flexspi_handle_t *handle)
+{
+ uint32_t status;
+ status_t result;
+ uint32_t intEnableStatus;
+ uint32_t txWatermark;
+ uint32_t rxWatermark;
+ uint8_t i = 0;
+
+ status = base->INTR;
+ intEnableStatus = base->INTEN;
+
+ /* Check if interrupt is enabled and status is alerted. */
+ if ((status & intEnableStatus) != 0U)
+ {
+ result = FLEXSPI_CheckAndClearError(base, status);
+
+ if ((result != kStatus_Success) && (handle->completionCallback != NULL))
+ {
+ FLEXSPI_TransferAbort(base, handle);
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+ }
+ else
+ {
+ if ((0U != (status & (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag)) &&
+ (handle->state == (uint32_t)kFLEXSPI_BusyRead))
+ {
+ rxWatermark = ((base->IPRXFCR & FLEXSPI_IPRXFCR_RXWMRK_MASK) >> FLEXSPI_IPRXFCR_RXWMRK_SHIFT) + 1U;
+
+ /* Read watermark level data from rx fifo . */
+ if (handle->dataSize >= 8U * rxWatermark)
+ {
+ /* Read watermark level data from rx fifo . */
+ for (i = 0U; i < 2U * rxWatermark; i++)
+ {
+ *handle->data++ = base->RFDR[i];
+ }
+
+ handle->dataSize = handle->dataSize - 8U * rxWatermark;
+ }
+ else
+ {
+ for (i = 0; i < (handle->dataSize + 3U) / 4U; i++)
+ {
+ *handle->data++ = base->RFDR[i];
+ }
+ handle->dataSize = 0;
+ }
+ /* Pop out a watermark level data from IP RX FIFO. */
+ base->INTR |= (uint32_t)kFLEXSPI_IpRxFifoWatermarkAvailableFlag;
+ }
+
+ if (0U != (status & (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag))
+ {
+ base->INTR |= (uint32_t)kFLEXSPI_IpCommandExecutionDoneFlag;
+
+ FLEXSPI_TransferAbort(base, handle);
+
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, kStatus_Success, handle->userData);
+ }
+ }
+
+ /* TX FIFO empty interrupt, push watermark level data into tx FIFO. */
+ if ((0U != (status & (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag)) &&
+ (handle->state == (uint32_t)kFLEXSPI_BusyWrite))
+ {
+ if (0U != handle->dataSize)
+ {
+ txWatermark = ((base->IPTXFCR & FLEXSPI_IPTXFCR_TXWMRK_MASK) >> FLEXSPI_IPTXFCR_TXWMRK_SHIFT) + 1U;
+ /* Write watermark level data into tx fifo . */
+ if (handle->dataSize >= 8U * txWatermark)
+ {
+ for (i = 0; i < 2U * txWatermark; i++)
+ {
+ base->TFDR[i] = *handle->data++;
+ }
+
+ handle->dataSize = handle->dataSize - 8U * txWatermark;
+ }
+ else
+ {
+ for (i = 0; i < (handle->dataSize / 4U + 1U); i++)
+ {
+ base->TFDR[i] = *handle->data++;
+ }
+ handle->dataSize = 0;
+ }
+
+ /* Push a watermark level data into IP TX FIFO. */
+ base->INTR |= (uint32_t)kFLEXSPI_IpTxFifoWatermarkEmptyFlag;
+ }
+ }
+ else
+ {
+ /* Empty else */
+ }
+ }
+ }
+ else
+ {
+ /* Empty else */
+ }
+}
+
+#if defined(FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ) && FSL_DRIVER_TRANSFER_DOUBLE_WEAK_IRQ
+#if defined(FLEXSPI)
+void FLEXSPI_DriverIRQHandler(void)
+{
+ s_flexspiIsr(FLEXSPI, s_flexspiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(FLEXSPI0)
+void FLEXSPI0_DriverIRQHandler(void)
+{
+ s_flexspiIsr(FLEXSPI0, s_flexspiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#if defined(FLEXSPI1)
+void FLEXSPI1_DriverIRQHandler(void)
+{
+ s_flexspiIsr(FLEXSPI1, s_flexspiHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(LSIO__FLEXSPI0)
+void LSIO_OCTASPI0_INT_DriverIRQHandler(void)
+{
+ s_flexspiIsr(LSIO__FLEXSPI0, s_flexspiHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#if defined(LSIO__FLEXSPI1)
+void LSIO_OCTASPI1_INT_DriverIRQHandler(void)
+{
+ s_flexspiIsr(LSIO__FLEXSPI1, s_flexspiHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(FSL_FEATURE_FLEXSPI_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_FLEXSPI_HAS_SHARED_IRQ0_IRQ1
+
+void FLEXSPI0_FLEXSPI1_DriverIRQHandler(void)
+{
+ /* If handle is registered, treat the transfer function is enabled. */
+ if (NULL != s_flexspiHandle[0])
+ {
+ s_flexspiIsr(FLEXSPI0, s_flexspiHandle[0]);
+ }
+ if (NULL != s_flexspiHandle[1])
+ {
+ s_flexspiIsr(FLEXSPI1, s_flexspiHandle[1]);
+ }
+}
+#endif
+
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpc.c
new file mode 100644
index 0000000000..e5cef48d1b
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpc.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_gpc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.gpc_1"
+#endif
+
+/*!
+ * brief Enable the IRQ.
+ *
+ * param base GPC peripheral base address.
+ * param irqId ID number of IRQ to be enabled, available range is 32-159. 0-31 is available in some platforms.
+ */
+void GPC_EnableIRQ(GPC_Type *base, uint32_t irqId)
+{
+ uint32_t irqRegNum = irqId / 32U;
+ uint32_t irqRegShiftNum = irqId % 32U;
+
+ assert(irqRegNum <= GPC_IMR_COUNT);
+
+#if ((defined FSL_FEATURE_GPC_HAS_IRQ_0_31) && FSL_FEATURE_GPC_HAS_IRQ_0_31)
+ if (irqRegNum == GPC_IMR_COUNT)
+ {
+ base->IMR5 &= ~(1UL << irqRegShiftNum);
+ }
+ else
+ {
+ base->IMR[irqRegNum] &= ~(1UL << irqRegShiftNum);
+ }
+#else
+ assert(irqRegNum > 0U);
+ base->IMR[irqRegNum - 1UL] &= ~(1UL << irqRegShiftNum);
+#endif /* FSL_FEATURE_GPC_HAS_IRQ_0_31 */
+}
+
+/*!
+ * brief Disable the IRQ.
+ *
+ * param base GPC peripheral base address.
+ * param irqId ID number of IRQ to be disabled, available range is 32-159. 0-31 is available in some platforms.
+ */
+void GPC_DisableIRQ(GPC_Type *base, uint32_t irqId)
+{
+ uint32_t irqRegNum = irqId / 32U;
+ uint32_t irqRegShiftNum = irqId % 32U;
+
+ assert(irqRegNum <= GPC_IMR_COUNT);
+
+#if ((defined FSL_FEATURE_GPC_HAS_IRQ_0_31) && FSL_FEATURE_GPC_HAS_IRQ_0_31)
+ if (irqRegNum == GPC_IMR_COUNT)
+ {
+ base->IMR5 |= (1UL << irqRegShiftNum);
+ }
+ else
+ {
+ base->IMR[irqRegNum] |= (1UL << irqRegShiftNum);
+ }
+#else
+ assert(irqRegNum > 0U);
+ base->IMR[irqRegNum - 1UL] |= (1UL << irqRegShiftNum);
+#endif /* FSL_FEATURE_GPC_HAS_IRQ_0_31 */
+}
+
+/*!
+ * brief Get the IRQ/Event flag.
+ *
+ * param base GPC peripheral base address.
+ * param irqId ID number of IRQ to be enabled, available range is 32-159. 0-31 is available in some platforms.
+ * return Indicated IRQ/Event is asserted or not.
+ */
+bool GPC_GetIRQStatusFlag(GPC_Type *base, uint32_t irqId)
+{
+ uint32_t irqRegNum = irqId / 32U;
+ uint32_t irqRegShiftNum = irqId % 32U;
+ uint32_t ret;
+
+ assert(irqRegNum <= GPC_IMR_COUNT);
+
+#if ((defined FSL_FEATURE_GPC_HAS_IRQ_0_31) && FSL_FEATURE_GPC_HAS_IRQ_0_31)
+ if (irqRegNum == GPC_IMR_COUNT)
+ {
+ ret = base->ISR5 & (1UL << irqRegShiftNum);
+ }
+ else
+ {
+ ret = base->ISR[irqRegNum] & (1UL << irqRegShiftNum);
+ }
+#else
+ assert(irqRegNum > 0U);
+ ret = base->ISR[irqRegNum - 1UL] & (1UL << irqRegShiftNum);
+#endif /* FSL_FEATURE_GPC_HAS_IRQ_0_31 */
+
+ return (1UL << irqRegShiftNum) == ret;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpio.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpio.c
new file mode 100644
index 0000000000..a3f864defc
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpio.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_gpio.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.igpio"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of GPIO peripheral base address. */
+static GPIO_Type *const s_gpioBases[] = GPIO_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of GPIO clock name. */
+static const clock_ip_name_t s_gpioClock[] = GPIO_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Gets the GPIO instance according to the GPIO base
+ *
+ * @param base GPIO peripheral base pointer(PTA, PTB, PTC, etc.)
+ * @retval GPIO instance
+ */
+static uint32_t GPIO_GetInstance(GPIO_Type *base);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t GPIO_GetInstance(GPIO_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0U; instance < ARRAY_SIZE(s_gpioBases); instance++)
+ {
+ if (s_gpioBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_gpioBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the GPIO peripheral according to the specified
+ * parameters in the initConfig.
+ *
+ * param base GPIO base pointer.
+ * param pin Specifies the pin number
+ * param initConfig pointer to a ref gpio_pin_config_t structure that
+ * contains the configuration information.
+ */
+void GPIO_PinInit(GPIO_Type *base, uint32_t pin, const gpio_pin_config_t *Config)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable GPIO clock. */
+ uint32_t instance = GPIO_GetInstance(base);
+
+ /* If The clock IP is valid, enable the clock gate. */
+ if ((instance < ARRAY_SIZE(s_gpioClock)) && (kCLOCK_IpInvalid != s_gpioClock[instance]))
+ {
+ CLOCK_EnableClock(s_gpioClock[instance]);
+ }
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Register reset to default value */
+ base->IMR &= ~(1UL << pin);
+
+ /* Configure GPIO pin direction */
+ if (Config->direction == kGPIO_DigitalInput)
+ {
+ base->GDIR &= ~(1UL << pin);
+ }
+ else
+ {
+ GPIO_PinWrite(base, pin, Config->outputLogic);
+ base->GDIR |= (1UL << pin);
+ }
+
+ /* Configure GPIO pin interrupt mode */
+ GPIO_SetPinInterruptConfig(base, pin, Config->interruptMode);
+}
+
+/*!
+ * brief Sets the output level of the individual GPIO pin to logic 1 or 0.
+ *
+ * param base GPIO base pointer.
+ * param pin GPIO port pin number.
+ * param output GPIOpin output logic level.
+ * - 0: corresponding pin output low-logic level.
+ * - 1: corresponding pin output high-logic level.
+ */
+void GPIO_PinWrite(GPIO_Type *base, uint32_t pin, uint8_t output)
+{
+ assert(pin < 32U);
+ if (output == 0U)
+ {
+ base->DR &= ~(1UL << pin); /* Set pin output to low level.*/
+ }
+ else
+ {
+ base->DR |= (1UL << pin); /* Set pin output to high level.*/
+ }
+}
+
+/*!
+ * brief Sets the current pin interrupt mode.
+ *
+ * param base GPIO base pointer.
+ * param pin GPIO port pin number.
+ * param pininterruptMode pointer to a ref gpio_interrupt_mode_t structure
+ * that contains the interrupt mode information.
+ */
+void GPIO_PinSetInterruptConfig(GPIO_Type *base, uint32_t pin, gpio_interrupt_mode_t pinInterruptMode)
+{
+ volatile uint32_t *icr;
+ uint32_t icrShift;
+
+ icrShift = pin;
+
+ /* Register reset to default value */
+ base->EDGE_SEL &= ~(1UL << pin);
+
+ if (pin < 16U)
+ {
+ icr = &(base->ICR1);
+ }
+ else
+ {
+ icr = &(base->ICR2);
+ icrShift -= 16U;
+ }
+ switch (pinInterruptMode)
+ {
+ case (kGPIO_IntLowLevel):
+ *icr &= ~(3UL << (2UL * icrShift));
+ break;
+ case (kGPIO_IntHighLevel):
+ *icr = (*icr & (~(3UL << (2UL * icrShift)))) | (1UL << (2UL * icrShift));
+ break;
+ case (kGPIO_IntRisingEdge):
+ *icr = (*icr & (~(3UL << (2UL * icrShift)))) | (2UL << (2UL * icrShift));
+ break;
+ case (kGPIO_IntFallingEdge):
+ *icr |= (3UL << (2UL * icrShift));
+ break;
+ case (kGPIO_IntRisingOrFallingEdge):
+ base->EDGE_SEL |= (1UL << pin);
+ break;
+ default:; /* Intentional empty default */
+ break;
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpt.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpt.c
new file mode 100644
index 0000000000..050ebf1f5c
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_gpt.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_gpt.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.gpt"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to GPT bases for each instance. */
+static GPT_Type *const s_gptBases[] = GPT_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to GPT clocks for each instance. */
+static const clock_ip_name_t s_gptClocks[] = GPT_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t GPT_GetInstance(GPT_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0U; instance < ARRAY_SIZE(s_gptBases); instance++)
+ {
+ if (s_gptBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_gptBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initialize GPT to reset state and initialize running mode.
+ *
+ * param base GPT peripheral base address.
+ * param initConfig GPT mode setting configuration.
+ */
+void GPT_Init(GPT_Type *base, const gpt_config_t *initConfig)
+{
+ assert(NULL != initConfig);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate the GPT clock*/
+ (void)CLOCK_EnableClock(s_gptClocks[GPT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ base->CR = 0U;
+
+ GPT_SoftwareReset(base);
+
+ base->CR =
+ (initConfig->enableFreeRun ? GPT_CR_FRR_MASK : 0UL) | (initConfig->enableRunInWait ? GPT_CR_WAITEN_MASK : 0UL) |
+ (initConfig->enableRunInStop ? GPT_CR_STOPEN_MASK : 0UL) |
+ (initConfig->enableRunInDoze ? GPT_CR_DOZEEN_MASK : 0UL) |
+ (initConfig->enableRunInDbg ? GPT_CR_DBGEN_MASK : 0UL) | (initConfig->enableMode ? GPT_CR_ENMOD_MASK : 0UL);
+
+ GPT_SetClockSource(base, initConfig->clockSource);
+ GPT_SetClockDivider(base, initConfig->divider);
+}
+
+/*!
+ * brief Disables the module and gates the GPT clock.
+ *
+ * param base GPT peripheral base address.
+ */
+void GPT_Deinit(GPT_Type *base)
+{
+ /* Disable GPT timers */
+ base->CR = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the GPT clock*/
+ (void)CLOCK_DisableClock(s_gptClocks[GPT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Fills in the GPT configuration structure with default settings.
+ *
+ * The default values are:
+ * code
+ * config->clockSource = kGPT_ClockSource_Periph;
+ * config->divider = 1U;
+ * config->enableRunInStop = true;
+ * config->enableRunInWait = true;
+ * config->enableRunInDoze = false;
+ * config->enableRunInDbg = false;
+ * config->enableFreeRun = false;
+ * config->enableMode = true;
+ * endcode
+ * param config Pointer to the user configuration structure.
+ */
+void GPT_GetDefaultConfig(gpt_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->clockSource = kGPT_ClockSource_Periph;
+ config->divider = 1U;
+ config->enableRunInStop = true;
+ config->enableRunInWait = true;
+ config->enableRunInDoze = false;
+ config->enableRunInDbg = false;
+ config->enableFreeRun = false;
+ config->enableMode = true;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_kpp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_kpp.c
new file mode 100644
index 0000000000..8c0b1958be
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_kpp.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2017, 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_kpp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.kpp"
+#endif
+
+#define KPP_KEYPAD_SCAN_TIMES (3U)
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to SEMC clocks for each instance. */
+static const clock_ip_name_t s_kppClock[FSL_FEATURE_SOC_KPP_COUNT] = KPP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to SEMC bases for each instance. */
+static KPP_Type *const s_kppBases[] = KPP_BASE_PTRS;
+
+/*! @brief Pointers to KPP IRQ number for each instance. */
+static const IRQn_Type s_kppIrqs[] = KPP_IRQS;
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t KPP_GetInstance(KPP_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_kppBases); instance++)
+ {
+ if (s_kppBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_kppBases));
+
+ return instance;
+}
+static void KPP_Mdelay(uint64_t tickets)
+{
+ while ((tickets--) != 0UL)
+ {
+ __NOP();
+ }
+}
+
+/*!
+ * brief KPP initialize.
+ * This function ungates the KPP clock and initializes KPP.
+ * This function must be called before calling any other KPP driver functions.
+ *
+ * param base KPP peripheral base address.
+ * param configure The KPP configuration structure pointer.
+ */
+void KPP_Init(KPP_Type *base, kpp_config_t *configure)
+{
+ assert(configure);
+
+ uint32_t instance = KPP_GetInstance(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Un-gate sdram controller clock. */
+ CLOCK_EnableClock(s_kppClock[KPP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Clear all. */
+ base->KPSR &= (uint16_t)(~(KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK));
+
+ /* Enable the keypad row and set the column strobe output to open drain. */
+ base->KPCR = KPP_KPCR_KRE(configure->activeRow);
+ base->KPDR = KPP_KPDR_KCD((uint8_t) ~(configure->activeColumn));
+ base->KPCR |= KPP_KPCR_KCO(configure->activeColumn);
+
+ /* Set the input direction for row and output direction for column. */
+ base->KDDR = KPP_KDDR_KCDD(configure->activeColumn) | KPP_KDDR_KRDD((uint8_t) ~(configure->activeRow));
+
+ /* Clear the status flag and enable the interrupt. */
+ base->KPSR = KPP_KPSR_KPKR_MASK | KPP_KPSR_KPKD_MASK | KPP_KPSR_KDSC_MASK | configure->interrupt;
+
+ if ((configure->interrupt) != 0U)
+ {
+ /* Enable at the Interrupt */
+ (void)EnableIRQ(s_kppIrqs[instance]);
+ }
+}
+
+/*!
+ * brief Deinitializes the KPP module and gates the clock.
+ * This function gates the KPP clock. As a result, the KPP
+ * module doesn't work after calling this function.
+ *
+ * param base KPP peripheral base address.
+ */
+void KPP_Deinit(KPP_Type *base)
+{
+ /* Disable interrupts and disable all rows. */
+ base->KPSR &= (uint16_t)(~(KPP_KPSR_KRIE_MASK | KPP_KPSR_KDIE_MASK));
+ base->KPCR = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable KPP clock. */
+ CLOCK_DisableClock(s_kppClock[KPP_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Keypad press scanning.
+ *
+ * This function will scanning all columns and rows. so
+ * all scanning data will be stored in the data pointer.
+ *
+ * param base KPP peripheral base address.
+ * param data KPP key press scanning data. The data buffer should be prepared with
+ * length at least equal to KPP_KEYPAD_COLUMNNUM_MAX * KPP_KEYPAD_ROWNUM_MAX.
+ * the data pointer is recommended to be a array like uint8_t data[KPP_KEYPAD_COLUMNNUM_MAX].
+ * for example the data[2] = 4, that means in column 1 row 2 has a key press event.
+ * param clockSrc_Hz Source clock.
+ */
+void KPP_keyPressScanning(KPP_Type *base, uint8_t *data, uint32_t clockSrc_Hz)
+{
+ assert(data);
+
+ uint16_t kppKCO = base->KPCR & KPP_KPCR_KCO_MASK;
+ uint8_t columIndex = 0;
+ uint8_t activeColumn = (uint8_t)((base->KPCR & KPP_KPCR_KCO_MASK) >> KPP_KPCR_KCO_SHIFT);
+ uint8_t times;
+ uint8_t rowData[KPP_KEYPAD_SCAN_TIMES][KPP_KEYPAD_COLUMNNUM_MAX];
+ bool press = false;
+ uint8_t column;
+
+ /* Initialize row data to zero. */
+ (void)memset(&rowData[0][0], 0, sizeof(rowData));
+
+ /* Scanning. */
+ /* Configure the column data to 1 according to column numbers. */
+ base->KPDR = KPP_KPDR_KCD_MASK;
+ /* Configure column to totem pole for quick discharge of keypad capacitance. */
+ base->KPCR &= (uint16_t)(((uint16_t)~kppKCO) | KPP_KPCR_KRE_MASK);
+ /* Recover. */
+ base->KPCR |= kppKCO;
+ /* Three times scanning. */
+ for (times = 0; times < KPP_KEYPAD_SCAN_TIMES; times++)
+ {
+ for (columIndex = 0; columIndex < KPP_KEYPAD_COLUMNNUM_MAX; columIndex++)
+ {
+ column = activeColumn & (1U << columIndex);
+ if (column != 0U)
+ {
+ /* Set the single column line to 0. */
+ base->KPDR = KPP_KPDR_KCD(~(uint16_t)column);
+ /* Take 100us delays. */
+ KPP_Mdelay(((uint64_t)clockSrc_Hz / 10000000UL));
+ /* Read row data. */
+ rowData[times][columIndex] = (uint8_t)(~(base->KPDR & KPP_KPDR_KRD_MASK));
+ }
+ else
+ {
+ /* Read row data. */
+ rowData[times][columIndex] = 0;
+ }
+ }
+ }
+
+ /* Return all columns to 0 in preparation for standby mode. */
+ base->KPDR &= (uint16_t)(~KPP_KPDR_KCD_MASK);
+
+ /* Check if three time scan data is the same. */
+ for (columIndex = 0; columIndex < KPP_KEYPAD_COLUMNNUM_MAX; columIndex++)
+ {
+ if (((uint8_t)(rowData[0][columIndex] & rowData[1][columIndex]) & rowData[2][columIndex]) != 0U)
+ {
+ press = true;
+ }
+ }
+
+ if (press)
+ {
+ (void)memcpy(data, &rowData[0][0], sizeof(rowData[0]));
+ }
+ else
+ {
+ (void)memset(data, 0, sizeof(rowData[0]));
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c.c
new file mode 100644
index 0000000000..f8d6f55e95
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c.c
@@ -0,0 +1,2315 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpi2c.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpi2c"
+#endif
+
+/*! @brief Common sets of flags used by the driver. */
+enum
+{
+ /*! All flags which are cleared by the driver upon starting a transfer. */
+ kMasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag |
+ kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag |
+ kLPI2C_MasterDataMatchFlag,
+
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kMasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag |
+ kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag |
+ kLPI2C_MasterFifoErrFlag,
+
+ /*! Errors to check for. */
+ kMasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag |
+ kLPI2C_MasterPinLowTimeoutFlag,
+
+ /*! All flags which are cleared by the driver upon starting a transfer. */
+ kSlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag |
+ kLPI2C_SlaveFifoErrFlag,
+
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kSlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag |
+ kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag |
+ kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag,
+
+ /*! Errors to check for. */
+ kSlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag,
+};
+
+/* ! @brief LPI2C master fifo commands. */
+enum
+{
+ kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
+ kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
+ kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
+ kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
+};
+
+/*!
+ * @brief Default watermark values.
+ *
+ * The default watermarks are set to zero.
+ */
+enum
+{
+ kDefaultTxWatermark = 0,
+ kDefaultRxWatermark = 0,
+};
+
+/*! @brief States for the state machine used by transactional APIs. */
+enum
+{
+ kIdleState = 0,
+ kSendCommandState,
+ kIssueReadCommandState,
+ kTransferDataState,
+ kStopState,
+ kWaitForCompletionState,
+};
+
+/*! @brief Typedef for master interrupt handler. */
+typedef void (*lpi2c_master_isr_t)(LPI2C_Type *base, lpi2c_master_handle_t *handle);
+
+/*! @brief Typedef for slave interrupt handler. */
+typedef void (*lpi2c_slave_isr_t)(LPI2C_Type *base, lpi2c_slave_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+uint32_t LPI2C_GetInstance(LPI2C_Type *base);
+
+static uint32_t LPI2C_GetCyclesForWidth(uint32_t sourceClock_Hz,
+ uint32_t width_ns,
+ uint32_t maxCycles,
+ uint32_t prescaler);
+
+static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base);
+
+static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone);
+
+static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle);
+
+static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags);
+
+static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief Array to map LPI2C instance number to base pointer. */
+static LPI2C_Type *const kLpi2cBases[] = LPI2C_BASE_PTRS;
+
+/*! @brief Array to map LPI2C instance number to IRQ number. */
+static IRQn_Type const kLpi2cIrqs[] = LPI2C_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Array to map LPI2C instance number to clock gate enum. */
+static clock_ip_name_t const kLpi2cClocks[] = LPI2C_CLOCKS;
+
+#if defined(LPI2C_PERIPH_CLOCKS)
+/*! @brief Array to map LPI2C instance number to pheripheral clock gate enum. */
+static const clock_ip_name_t kLpi2cPeriphClocks[] = LPI2C_PERIPH_CLOCKS;
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointer to master IRQ handler for each instance. */
+static lpi2c_master_isr_t s_lpi2cMasterIsr;
+
+/*! @brief Pointers to master handles for each instance. */
+static lpi2c_master_handle_t *s_lpi2cMasterHandle[ARRAY_SIZE(kLpi2cBases)];
+
+/*! @brief Pointer to slave IRQ handler for each instance. */
+static lpi2c_slave_isr_t s_lpi2cSlaveIsr;
+
+/*! @brief Pointers to slave handles for each instance. */
+static lpi2c_slave_handle_t *s_lpi2cSlaveHandle[ARRAY_SIZE(kLpi2cBases)];
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * @brief Returns an instance number given a base address.
+ *
+ * If an invalid base address is passed, debug builds will assert. Release builds will just return
+ * instance number 0.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @return LPI2C instance number starting from 0.
+ */
+uint32_t LPI2C_GetInstance(LPI2C_Type *base)
+{
+ uint32_t instance;
+ for (instance = 0U; instance < ARRAY_SIZE(kLpi2cBases); ++instance)
+ {
+ if (kLpi2cBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(kLpi2cBases));
+ return instance;
+}
+
+/*!
+ * @brief Computes a cycle count for a given time in nanoseconds.
+ * @param sourceClock_Hz LPI2C functional clock frequency in Hertz.
+ * @param width_ns Desired with in nanoseconds.
+ * @param maxCycles Maximum cycle count, determined by the number of bits wide the cycle count field is.
+ * @param prescaler LPI2C prescaler setting. Pass 1 if the prescaler should not be used, as for slave glitch widths.
+ */
+static uint32_t LPI2C_GetCyclesForWidth(uint32_t sourceClock_Hz,
+ uint32_t width_ns,
+ uint32_t maxCycles,
+ uint32_t prescaler)
+{
+ assert(sourceClock_Hz > 0U);
+ assert(prescaler > 0U);
+
+ uint32_t busCycle_ns = 1000000U / (sourceClock_Hz / prescaler / 1000U);
+ uint32_t cycles = 0U;
+
+ /* Search for the cycle count just below the desired glitch width. */
+ while ((((cycles + 1U) * busCycle_ns) < width_ns) && (cycles + 1U < maxCycles))
+ {
+ ++cycles;
+ }
+
+ /* If we end up with zero cycles, then set the filter to a single cycle unless the */
+ /* bus clock is greater than 10x the desired glitch width. */
+ if ((cycles == 0U) && (busCycle_ns <= (width_ns * 10U)))
+ {
+ cycles = 1U;
+ }
+
+ return cycles;
+}
+
+/*!
+ * @brief Convert provided flags to status code, and clear any errors if present.
+ * @param base The LPI2C peripheral base address.
+ * @param status Current status flags value that will be checked.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_MasterCheckAndClearError(LPI2C_Type *base, uint32_t status)
+{
+ status_t result = kStatus_Success;
+
+ /* Check for error. These errors cause a stop to automatically be sent. We must */
+ /* clear the errors before a new transfer can start. */
+ status &= (uint32_t)kMasterErrorFlags;
+ if (0U != status)
+ {
+ /* Select the correct error code. Ordered by severity, with bus issues first. */
+ if (0U != (status & (uint32_t)kLPI2C_MasterPinLowTimeoutFlag))
+ {
+ result = kStatus_LPI2C_PinLowTimeout;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterArbitrationLostFlag))
+ {
+ result = kStatus_LPI2C_ArbitrationLost;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterNackDetectFlag))
+ {
+ result = kStatus_LPI2C_Nak;
+ }
+ else if (0U != (status & (uint32_t)kLPI2C_MasterFifoErrFlag))
+ {
+ result = kStatus_LPI2C_FifoError;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Clear the flags. */
+ LPI2C_MasterClearStatusFlags(base, status);
+
+ /* Reset fifos. These flags clear automatically. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return result;
+}
+
+/*!
+ * @brief Wait until there is room in the tx fifo.
+ * @param base The LPI2C peripheral base address.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_MasterWaitForTxReady(LPI2C_Type *base)
+{
+ uint32_t status;
+ size_t txCount;
+ size_t txFifoSize = (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base);
+
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+ do
+ {
+ status_t result;
+
+ /* Get the number of words in the tx fifo and compute empty slots. */
+ LPI2C_MasterGetFifoCounts(base, NULL, &txCount);
+ txCount = txFifoSize - txCount;
+
+ /* Check for error flags. */
+ status = LPI2C_MasterGetStatusFlags(base);
+ result = LPI2C_MasterCheckAndClearError(base, status);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+#if I2C_RETRY_TIMES
+ } while ((0U == txCount) && (0U != --waitTimes));
+
+ if (0U == waitTimes)
+ {
+ return kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == txCount);
+#endif
+
+ return kStatus_Success;
+}
+
+/*!
+ * @brief Make sure the bus isn't already busy.
+ *
+ * A busy bus is allowed if we are the one driving it.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_Busy
+ */
+/* Not static so it can be used from fsl_lpi2c_edma.c. */
+status_t LPI2C_CheckForBusyBus(LPI2C_Type *base)
+{
+ status_t ret = kStatus_Success;
+
+ uint32_t status = LPI2C_MasterGetStatusFlags(base);
+ if ((0U != (status & (uint32_t)kLPI2C_MasterBusBusyFlag)) && (0U == (status & (uint32_t)kLPI2C_MasterBusyFlag)))
+ {
+ ret = kStatus_LPI2C_Busy;
+ }
+
+ return ret;
+}
+
+/*!
+ * brief Provides a default configuration for the LPI2C master peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C master peripheral:
+ * code
+ * masterConfig->enableMaster = true;
+ * masterConfig->debugEnable = false;
+ * masterConfig->ignoreAck = false;
+ * masterConfig->pinConfig = kLPI2C_2PinOpenDrain;
+ * masterConfig->baudRate_Hz = 100000U;
+ * masterConfig->busIdleTimeout_ns = 0U;
+ * masterConfig->pinLowTimeout_ns = 0U;
+ * masterConfig->sdaGlitchFilterWidth_ns = 0U;
+ * masterConfig->sclGlitchFilterWidth_ns = 0U;
+ * masterConfig->hostRequest.enable = false;
+ * masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin;
+ * masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
+ * endcode
+ *
+ * After calling this function, you can override any settings in order to customize the configuration,
+ * prior to initializing the master driver with LPI2C_MasterInit().
+ *
+ * param[out] masterConfig User provided configuration structure for default values. Refer to #lpi2c_master_config_t.
+ */
+void LPI2C_MasterGetDefaultConfig(lpi2c_master_config_t *masterConfig)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->enableMaster = true;
+ masterConfig->debugEnable = false;
+ masterConfig->enableDoze = true;
+ masterConfig->ignoreAck = false;
+ masterConfig->pinConfig = kLPI2C_2PinOpenDrain;
+ masterConfig->baudRate_Hz = 100000U;
+ masterConfig->busIdleTimeout_ns = 0U;
+ masterConfig->pinLowTimeout_ns = 0U;
+ masterConfig->sdaGlitchFilterWidth_ns = 0U;
+ masterConfig->sclGlitchFilterWidth_ns = 0U;
+ masterConfig->hostRequest.enable = false;
+ masterConfig->hostRequest.source = kLPI2C_HostRequestExternalPin;
+ masterConfig->hostRequest.polarity = kLPI2C_HostRequestPinActiveHigh;
+}
+
+/*!
+ * brief Initializes the LPI2C master peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C master peripheral as described by the user
+ * provided configuration. A software reset is performed prior to configuration.
+ *
+ * param base The LPI2C peripheral base address.
+ * param masterConfig User provided peripheral configuration. Use LPI2C_MasterGetDefaultConfig() to get a set of
+ * defaults
+ * that you can override.
+ * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the baud rate divisors,
+ * filter widths, and timeout periods.
+ */
+void LPI2C_MasterInit(LPI2C_Type *base, const lpi2c_master_config_t *masterConfig, uint32_t sourceClock_Hz)
+{
+ uint32_t prescaler;
+ uint32_t cycles;
+ uint32_t cfgr2;
+ uint32_t value;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Ungate the clock. */
+ CLOCK_EnableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Ungate the functional clock in initialize function. */
+ CLOCK_EnableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset peripheral before configuring it. */
+ LPI2C_MasterReset(base);
+
+ /* Doze bit: 0 is enable, 1 is disable */
+ base->MCR = LPI2C_MCR_DBGEN(masterConfig->debugEnable) | LPI2C_MCR_DOZEN(!(masterConfig->enableDoze));
+
+ /* host request */
+ value = base->MCFGR0;
+ value &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK | LPI2C_MCFGR0_HRSEL_MASK));
+ value |= LPI2C_MCFGR0_HREN(masterConfig->hostRequest.enable) |
+ LPI2C_MCFGR0_HRPOL(masterConfig->hostRequest.polarity) |
+ LPI2C_MCFGR0_HRSEL(masterConfig->hostRequest.source);
+ base->MCFGR0 = value;
+
+ /* pin config and ignore ack */
+ value = base->MCFGR1;
+ value &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK);
+ value |= LPI2C_MCFGR1_PINCFG(masterConfig->pinConfig);
+ value |= LPI2C_MCFGR1_IGNACK(masterConfig->ignoreAck);
+ base->MCFGR1 = value;
+
+ LPI2C_MasterSetWatermarks(base, (size_t)kDefaultTxWatermark, (size_t)kDefaultRxWatermark);
+
+ LPI2C_MasterSetBaudRate(base, sourceClock_Hz, masterConfig->baudRate_Hz);
+
+ /* Configure glitch filters and bus idle and pin low timeouts. */
+ prescaler = (base->MCFGR1 & LPI2C_MCFGR1_PRESCALE_MASK) >> LPI2C_MCFGR1_PRESCALE_SHIFT;
+ cfgr2 = base->MCFGR2;
+ if (0U != (masterConfig->busIdleTimeout_ns))
+ {
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->busIdleTimeout_ns,
+ (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler);
+ cfgr2 &= ~LPI2C_MCFGR2_BUSIDLE_MASK;
+ cfgr2 |= LPI2C_MCFGR2_BUSIDLE(cycles);
+ }
+ if (0U != (masterConfig->sdaGlitchFilterWidth_ns))
+ {
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sdaGlitchFilterWidth_ns,
+ (LPI2C_MCFGR2_FILTSDA_MASK >> LPI2C_MCFGR2_FILTSDA_SHIFT), 1U);
+ cfgr2 &= ~LPI2C_MCFGR2_FILTSDA_MASK;
+ cfgr2 |= LPI2C_MCFGR2_FILTSDA(cycles);
+ }
+ if (0U != masterConfig->sclGlitchFilterWidth_ns)
+ {
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->sclGlitchFilterWidth_ns,
+ (LPI2C_MCFGR2_FILTSCL_MASK >> LPI2C_MCFGR2_FILTSCL_SHIFT), 1U);
+ cfgr2 &= ~LPI2C_MCFGR2_FILTSCL_MASK;
+ cfgr2 |= LPI2C_MCFGR2_FILTSCL(cycles);
+ }
+ base->MCFGR2 = cfgr2;
+ if (0U != masterConfig->pinLowTimeout_ns)
+ {
+ cycles = LPI2C_GetCyclesForWidth(sourceClock_Hz, masterConfig->pinLowTimeout_ns / 256U,
+ (LPI2C_MCFGR2_BUSIDLE_MASK >> LPI2C_MCFGR2_BUSIDLE_SHIFT), prescaler);
+ base->MCFGR3 = (base->MCFGR3 & ~LPI2C_MCFGR3_PINLOW_MASK) | LPI2C_MCFGR3_PINLOW(cycles);
+ }
+
+ LPI2C_MasterEnable(base, masterConfig->enableMaster);
+}
+
+/*!
+ * brief Deinitializes the LPI2C master peripheral.
+ *
+ * This function disables the LPI2C master peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * param base The LPI2C peripheral base address.
+ */
+void LPI2C_MasterDeinit(LPI2C_Type *base)
+{
+ /* Restore to reset state. */
+ LPI2C_MasterReset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Gate clock. */
+ CLOCK_DisableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Gate the functional clock. */
+ CLOCK_DisableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Configures LPI2C master data match feature.
+ *
+ * param base The LPI2C peripheral base address.
+ * param config Settings for the data match feature.
+ */
+void LPI2C_MasterConfigureDataMatch(LPI2C_Type *base, const lpi2c_data_match_config_t *config)
+{
+ /* Disable master mode. */
+ bool wasEnabled = (0U != ((base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT));
+ LPI2C_MasterEnable(base, false);
+
+ base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_MATCFG_MASK) | LPI2C_MCFGR1_MATCFG(config->matchMode);
+ base->MCFGR0 = (base->MCFGR0 & ~LPI2C_MCFGR0_RDMO_MASK) | LPI2C_MCFGR0_RDMO(config->rxDataMatchOnly);
+ base->MDMR = LPI2C_MDMR_MATCH0(config->match0) | LPI2C_MDMR_MATCH1(config->match1);
+
+ /* Restore master mode. */
+ if (wasEnabled)
+ {
+ LPI2C_MasterEnable(base, true);
+ }
+}
+
+/*!
+ * brief Sets the I2C bus frequency for master transactions.
+ *
+ * The LPI2C master is automatically disabled and re-enabled as necessary to configure the baud
+ * rate. Do not call this function during a transfer, or the transfer is aborted.
+ *
+ * note Please note that the second parameter is the clock frequency of LPI2C module, the third
+ * parameter means user configured bus baudrate, this implementation is different from other I2C drivers
+ * which use baudrate configuration as second parameter and source clock frequency as third parameter.
+ *
+ * param base The LPI2C peripheral base address.
+ * param sourceClock_Hz LPI2C functional clock frequency in Hertz.
+ * param baudRate_Hz Requested bus frequency in Hertz.
+ */
+void LPI2C_MasterSetBaudRate(LPI2C_Type *base, uint32_t sourceClock_Hz, uint32_t baudRate_Hz)
+{
+ uint32_t prescale = 0U;
+ uint32_t bestPre = 0U;
+ uint32_t bestClkHi = 0U;
+ uint32_t absError = 0U;
+ uint32_t bestError = 0xffffffffu;
+ uint32_t value;
+ uint32_t clkHiCycle;
+ uint32_t computedRate;
+ uint32_t i;
+ bool wasEnabled;
+
+ /* Disable master mode. */
+ wasEnabled = (0U != ((base->MCR & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT));
+ LPI2C_MasterEnable(base, false);
+
+ /* Baud rate = (sourceClock_Hz/2^prescale)/(CLKLO+1+CLKHI+1 + ROUNDDOWN((2+FILTSCL)/2^prescale) */
+ /* Assume CLKLO = 2*CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2. */
+ for (prescale = 1U; prescale <= 128U; prescale = 2U * prescale)
+ {
+ if (bestError == 0U)
+ {
+ break;
+ }
+
+ for (clkHiCycle = 1U; clkHiCycle < 32U; clkHiCycle++)
+ {
+ if (clkHiCycle == 1U)
+ {
+ computedRate = (sourceClock_Hz / prescale) / (1U + 3U + 2U + 2U / prescale);
+ }
+ else
+ {
+ computedRate = (sourceClock_Hz / prescale) / (3U * clkHiCycle + 2U + 2U / prescale);
+ }
+
+ absError = baudRate_Hz > computedRate ? baudRate_Hz - computedRate : computedRate - baudRate_Hz;
+
+ if (absError < bestError)
+ {
+ bestPre = prescale;
+ bestClkHi = clkHiCycle;
+ bestError = absError;
+
+ /* If the error is 0, then we can stop searching because we won't find a better match. */
+ if (absError == 0U)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ /* Standard, fast, fast mode plus and ultra-fast transfers. */
+ value = LPI2C_MCCR0_CLKHI(bestClkHi);
+
+ if (bestClkHi < 2U)
+ {
+ value |= (uint32_t)(LPI2C_MCCR0_CLKLO(3UL) | LPI2C_MCCR0_SETHOLD(2UL) | LPI2C_MCCR0_DATAVD(1UL));
+ }
+ else
+ {
+ value |=
+ LPI2C_MCCR0_CLKLO(2UL * bestClkHi) | LPI2C_MCCR0_SETHOLD(bestClkHi) | LPI2C_MCCR0_DATAVD(bestClkHi / 2UL);
+ }
+
+ base->MCCR0 = value;
+
+ for (i = 0U; i < 8U; i++)
+ {
+ if (bestPre == (1UL << i))
+ {
+ bestPre = i;
+ break;
+ }
+ }
+ base->MCFGR1 = (base->MCFGR1 & ~LPI2C_MCFGR1_PRESCALE_MASK) | LPI2C_MCFGR1_PRESCALE(bestPre);
+
+ /* Restore master mode. */
+ if (wasEnabled)
+ {
+ LPI2C_MasterEnable(base, true);
+ }
+}
+
+/*!
+ * brief Sends a START signal and slave address on the I2C bus.
+ *
+ * This function is used to initiate a new master mode transfer. First, the bus state is checked to ensure
+ * that another master is not occupying the bus. Then a START signal is transmitted, followed by the
+ * 7-bit address specified in the a address parameter. Note that this function does not actually wait
+ * until the START and address are successfully sent on the bus before returning.
+ *
+ * param base The LPI2C peripheral base address.
+ * param address 7-bit slave device address, in bits [6:0].
+ * param dir Master transfer direction, either #kLPI2C_Read or #kLPI2C_Write. This parameter is used to set
+ * the R/w bit (bit 0) in the transmitted slave address.
+ * retval #kStatus_Success START signal and address were successfully enqueued in the transmit FIFO.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ */
+status_t LPI2C_MasterStart(LPI2C_Type *base, uint8_t address, lpi2c_direction_t dir)
+{
+ /* Return an error if the bus is already in use not by us. */
+ status_t result = LPI2C_CheckForBusyBus(base);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ /* Wait until there is room in the fifo. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Issue start command. */
+ base->MTDR = (uint32_t)kStartCmd | (((uint32_t)address << 1U) | (uint32_t)dir);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sends a STOP signal on the I2C bus.
+ *
+ * This function does not return until the STOP signal is seen on the bus, or an error occurs.
+ *
+ * param base The LPI2C peripheral base address.
+ * retval #kStatus_Success The STOP signal was successfully sent on the bus and the transaction terminated.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterStop(LPI2C_Type *base)
+{
+ /* Wait until there is room in the fifo. */
+ status_t result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Send the STOP signal */
+ base->MTDR = (uint32_t)kStopCmd;
+
+/* Wait for the stop detected flag to set, indicating the transfer has completed on the bus. */
+/* Also check for errors while waiting. */
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+#if I2C_RETRY_TIMES
+ while ((result == kStatus_Success) && (0U != --waitTimes))
+#else
+ while (result == kStatus_Success)
+#endif
+ {
+ uint32_t status = LPI2C_MasterGetStatusFlags(base);
+
+ /* Check for error flags. */
+ result = LPI2C_MasterCheckAndClearError(base, status);
+
+ /* Check if the stop was sent successfully. */
+ if ((0U != (status & (uint32_t)kLPI2C_MasterStopDetectFlag)) &&
+ (0U != (status & (uint32_t)kLPI2C_MasterTxReadyFlag)))
+ {
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kLPI2C_MasterStopDetectFlag);
+ break;
+ }
+ }
+
+#if I2C_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_LPI2C_Timeout;
+ }
+#endif
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling receive transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param rxBuff The pointer to the data to be transferred.
+ * param rxSize The length in bytes of the data to be transferred.
+ * retval #kStatus_Success Data was received successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize)
+{
+ status_t result;
+ uint8_t *buf;
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ assert(NULL != rxBuff);
+
+ /* Handle empty read. */
+ if (rxSize == 0U)
+ {
+ return kStatus_Success;
+ }
+
+ /* Wait until there is room in the command fifo. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Issue command to receive data. */
+ base->MTDR = ((uint32_t)kRxDataCmd) | LPI2C_MTDR_DATA(rxSize - 1U);
+
+ /* Receive data */
+ buf = (uint8_t *)rxBuff;
+ while (0U != (rxSize--))
+ {
+#if I2C_RETRY_TIMES
+ waitTimes = I2C_RETRY_TIMES;
+#endif
+ /* Read LPI2C receive fifo register. The register includes a flag to indicate whether */
+ /* the FIFO is empty, so we can both get the data and check if we need to keep reading */
+ /* using a single register read. */
+ uint32_t value;
+ do
+ {
+ /* Check for errors. */
+ result = LPI2C_MasterCheckAndClearError(base, LPI2C_MasterGetStatusFlags(base));
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ value = base->MRDR;
+#if I2C_RETRY_TIMES
+ } while ((0U != (value & LPI2C_MRDR_RXEMPTY_MASK)) && (0U != --waitTimes));
+ if (0U == waitTimes)
+ {
+ return kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U != (value & LPI2C_MRDR_RXEMPTY_MASK));
+#endif
+
+ *buf++ = (uint8_t)(value & LPI2C_MRDR_DATA_MASK);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a polling send transfer on the I2C bus.
+ *
+ * Sends up to a txSize number of bytes to the previously addressed slave device. The slave may
+ * reply with a NAK to any byte in order to terminate the transfer early. If this happens, this
+ * function returns #kStatus_LPI2C_Nak.
+ *
+ * param base The LPI2C peripheral base address.
+ * param txBuff The pointer to the data to be transferred.
+ * param txSize The length in bytes of the data to be transferred.
+ * retval #kStatus_Success Data was sent successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or over run.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterSend(LPI2C_Type *base, void *txBuff, size_t txSize)
+{
+ uint8_t *buf = (uint8_t *)txBuff;
+
+ assert(NULL != txBuff);
+
+ /* Send data buffer */
+ while (0U != (txSize--))
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ status_t result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Write byte into LPI2C master data register. */
+ base->MTDR = *buf++;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a master polling transfer on the I2C bus.
+ *
+ * note The API does not return until the transfer succeeds or fails due
+ * to error happens during transfer.
+ *
+ * param base The LPI2C peripheral base address.
+ * param transfer Pointer to the transfer structure.
+ * retval #kStatus_Success Data was received successfully.
+ * retval #kStatus_LPI2C_Busy Another master is currently utilizing the bus.
+ * retval #kStatus_LPI2C_Nak The slave device sent a NAK in response to a byte.
+ * retval #kStatus_LPI2C_FifoError FIFO under run or overrun.
+ * retval #kStatus_LPI2C_ArbitrationLost Arbitration lost error.
+ * retval #kStatus_LPI2C_PinLowTimeout SCL or SDA were held low longer than the timeout.
+ */
+status_t LPI2C_MasterTransferBlocking(LPI2C_Type *base, lpi2c_master_transfer_t *transfer)
+{
+ status_t result = kStatus_Success;
+ uint16_t commandBuffer[7];
+ uint32_t cmdCount = 0U;
+
+ assert(NULL != transfer);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ /* Return an error if the bus is already in use not by us. */
+ result = LPI2C_CheckForBusyBus(base);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ lpi2c_direction_t direction = (0U != transfer->subaddressSize) ? kLPI2C_Write : transfer->direction;
+ if (0U == (transfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag))
+ {
+ commandBuffer[cmdCount++] =
+ (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)direction);
+ }
+
+ /* Subaddress, MSB first. */
+ if (0U != transfer->subaddressSize)
+ {
+ uint32_t subaddressRemaining = transfer->subaddressSize;
+ while (0U != subaddressRemaining--)
+ {
+ uint8_t subaddressByte = (uint8_t)((transfer->subaddress >> (8U * subaddressRemaining)) & 0xffU);
+ commandBuffer[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling. */
+ if ((0U != transfer->dataSize) && (transfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ commandBuffer[cmdCount++] =
+ (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)transfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+ }
+
+ /* Send command buffer */
+ uint32_t index = 0U;
+ while (0U != cmdCount--)
+ {
+ /* Wait until there is room in the fifo. This also checks for errors. */
+ result = LPI2C_MasterWaitForTxReady(base);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Write byte into LPI2C master data register. */
+ base->MTDR = commandBuffer[index];
+ index++;
+ }
+
+ /* Transmit data. */
+ if ((transfer->direction == kLPI2C_Write) && (transfer->dataSize > 0U))
+ {
+ /* Send Data. */
+ result = LPI2C_MasterSend(base, transfer->data, transfer->dataSize);
+ }
+
+ /* Receive Data. */
+ if ((transfer->direction == kLPI2C_Read) && (transfer->dataSize > 0U))
+ {
+ result = LPI2C_MasterReceive(base, transfer->data, transfer->dataSize);
+ }
+
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ if ((transfer->flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U)
+ {
+ result = LPI2C_MasterStop(base);
+ }
+
+ return result;
+}
+
+/*!
+ * brief Creates a new handle for the LPI2C master non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbort() API shall be called.
+ *
+ *
+ * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+ *
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C master driver handle.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_callback_t callback,
+ void *userData)
+{
+ uint32_t instance;
+
+ assert(NULL != handle);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Look up instance number */
+ instance = LPI2C_GetInstance(base);
+
+ /* Save base and instance. */
+ handle->completionCallback = callback;
+ handle->userData = userData;
+
+ /* Save this handle for IRQ use. */
+ s_lpi2cMasterHandle[instance] = handle;
+
+ /* Set irq handler. */
+ s_lpi2cMasterIsr = LPI2C_MasterTransferHandleIRQ;
+
+ /* Clear internal IRQ enables and enable NVIC IRQ. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
+
+ /* Enable NVIC IRQ, this only enables the IRQ directly connected to the NVIC.
+ In some cases the LPI2C IRQ is configured through INTMUX, user needs to enable
+ INTMUX IRQ in application code. */
+ (void)EnableIRQ(kLpi2cIrqs[instance]);
+}
+
+/*!
+ * @brief Execute states until FIFOs are exhausted.
+ * @param handle Master nonblocking driver handle.
+ * @param[out] isDone Set to true if the transfer has completed.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_PinLowTimeout
+ * @retval #kStatus_LPI2C_ArbitrationLost
+ * @retval #kStatus_LPI2C_Nak
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_RunTransferStateMachine(LPI2C_Type *base, lpi2c_master_handle_t *handle, bool *isDone)
+{
+ uint32_t status;
+ status_t result = kStatus_Success;
+ lpi2c_master_transfer_t *xfer;
+ size_t txCount;
+ size_t rxCount;
+ size_t txFifoSize = (size_t)FSL_FEATURE_LPI2C_FIFO_SIZEn(base);
+ bool state_complete = false;
+ uint16_t sendval;
+
+ /* Set default isDone return value. */
+ *isDone = false;
+
+ /* Check for errors. */
+ status = LPI2C_MasterGetStatusFlags(base);
+ /* For the last byte, nack flag is expected.
+ Do not check and clear kLPI2C_MasterNackDetectFlag for the last byte,
+ in case FIFO is emptied when stop command has not been sent. */
+ if (handle->remainingBytes == 0U)
+ {
+ status &= ~(uint32_t)kLPI2C_MasterNackDetectFlag;
+ }
+ result = LPI2C_MasterCheckAndClearError(base, status);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Get pointer to private data. */
+ xfer = &handle->transfer;
+
+ /* Get fifo counts and compute room in tx fifo. */
+ LPI2C_MasterGetFifoCounts(base, &rxCount, &txCount);
+ txCount = txFifoSize - txCount;
+
+ while (!state_complete)
+ {
+ /* Execute the state. */
+ switch (handle->state)
+ {
+ case (uint8_t)kSendCommandState:
+ /* Make sure there is room in the tx fifo for the next command. */
+ if (0U == txCount--)
+ {
+ state_complete = true;
+ break;
+ }
+
+ /* Issue command. buf is a uint8_t* pointing at the uint16 command array. */
+ sendval = ((uint16_t)(*handle->buf)) | ((uint16_t)(*(handle->buf + 1U)) << 8U);
+ base->MTDR = sendval;
+ handle->buf++;
+ handle->buf++;
+
+ /* Count down until all commands are sent. */
+ if (--handle->remainingBytes == 0U)
+ {
+ /* Choose next state and set up buffer pointer and count. */
+ if (0U != xfer->dataSize)
+ {
+ /* Either a send or receive transfer is next. */
+ handle->state = (uint8_t)kTransferDataState;
+ handle->buf = (uint8_t *)xfer->data;
+ handle->remainingBytes = (uint16_t)xfer->dataSize;
+ if (xfer->direction == kLPI2C_Read)
+ {
+ /* Disable TX interrupt */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterTxReadyFlag);
+ }
+ }
+ else
+ {
+ /* No transfer, so move to stop state. */
+ handle->state = (uint8_t)kStopState;
+ }
+ }
+ break;
+
+ case (uint8_t)kIssueReadCommandState:
+ /* Make sure there is room in the tx fifo for the read command. */
+ if (0U == txCount--)
+ {
+ state_complete = true;
+ break;
+ }
+
+ base->MTDR = (uint32_t)kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1U);
+
+ /* Move to transfer state. */
+ handle->state = (uint8_t)kTransferDataState;
+ if (xfer->direction == kLPI2C_Read)
+ {
+ /* Disable TX interrupt */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kLPI2C_MasterTxReadyFlag);
+ }
+ break;
+
+ case (uint8_t)kTransferDataState:
+ if (xfer->direction == kLPI2C_Write)
+ {
+ /* Make sure there is room in the tx fifo. */
+ if (0U == txCount--)
+ {
+ state_complete = true;
+ break;
+ }
+
+ /* Put byte to send in fifo. */
+ base->MTDR = *(handle->buf)++;
+ }
+ else
+ {
+ /* XXX handle receive sizes > 256, use kIssueReadCommandState */
+ /* Make sure there is data in the rx fifo. */
+ if (0U == rxCount--)
+ {
+ state_complete = true;
+ break;
+ }
+
+ /* Read byte from fifo. */
+ *(handle->buf)++ = (uint8_t)(base->MRDR & LPI2C_MRDR_DATA_MASK);
+ }
+
+ /* Move to stop when the transfer is done. */
+ if (--handle->remainingBytes == 0U)
+ {
+ if (xfer->direction == kLPI2C_Write)
+ {
+ state_complete = true;
+ }
+ handle->state = (uint8_t)kStopState;
+ }
+ break;
+
+ case (uint8_t)kStopState:
+ /* Only issue a stop transition if the caller requested it. */
+ if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStopFlag) == 0U)
+ {
+ /* Make sure there is room in the tx fifo for the stop command. */
+ if (0U == txCount--)
+ {
+ state_complete = true;
+ break;
+ }
+
+ base->MTDR = (uint32_t)kStopCmd;
+ }
+ else
+ {
+ /* Caller doesn't want to send a stop, so we're done now. */
+ *isDone = true;
+ state_complete = true;
+ break;
+ }
+ handle->state = (uint8_t)kWaitForCompletionState;
+ break;
+
+ case (uint8_t)kWaitForCompletionState:
+ /* We stay in this state until the stop state is detected. */
+ if (0U != (status & (uint32_t)kLPI2C_MasterStopDetectFlag))
+ {
+ *isDone = true;
+ }
+ state_complete = true;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ return result;
+}
+
+/*!
+ * @brief Prepares the transfer state machine and fills in the command buffer.
+ * @param handle Master nonblocking driver handle.
+ */
+static void LPI2C_InitTransferStateMachine(lpi2c_master_handle_t *handle)
+{
+ lpi2c_master_transfer_t *xfer = &handle->transfer;
+
+ /* Handle no start option. */
+ if (0U != (xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag))
+ {
+ if (xfer->direction == kLPI2C_Read)
+ {
+ /* Need to issue read command first. */
+ handle->state = (uint8_t)kIssueReadCommandState;
+ }
+ else
+ {
+ /* Start immediately in the data transfer state. */
+ handle->state = (uint8_t)kTransferDataState;
+ }
+
+ handle->buf = (uint8_t *)xfer->data;
+ handle->remainingBytes = (uint16_t)xfer->dataSize;
+ }
+ else
+ {
+ uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
+ uint32_t cmdCount = 0U;
+
+ /* Initial direction depends on whether a subaddress was provided, and of course the actual */
+ /* data transfer direction. */
+ lpi2c_direction_t direction = (0U != xfer->subaddressSize) ? kLPI2C_Write : xfer->direction;
+
+ /* Start command. */
+ cmd[cmdCount++] =
+ (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
+
+ /* Subaddress, MSB first. */
+ if (0U != xfer->subaddressSize)
+ {
+ uint32_t subaddressRemaining = xfer->subaddressSize;
+ while (0U != (subaddressRemaining--))
+ {
+ uint8_t subaddressByte = (uint8_t)((xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU);
+ cmd[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling. */
+ if ((0U != xfer->dataSize) && (xfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ cmd[cmdCount++] = (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+
+ /* Read command. */
+ cmd[cmdCount++] = (uint16_t)((uint32_t)kRxDataCmd | LPI2C_MTDR_DATA(xfer->dataSize - 1U));
+ }
+
+ /* Set up state machine for transferring the commands. */
+ handle->state = (uint8_t)kSendCommandState;
+ handle->remainingBytes = (uint16_t)cmdCount;
+ handle->buf = (uint8_t *)&handle->commandBuffer;
+ }
+}
+
+/*!
+ * brief Performs a non-blocking transaction on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param transfer The pointer to the transfer descriptor.
+ * retval #kStatus_Success The transaction was started successfully.
+ * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or a non-blocking
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferNonBlocking(LPI2C_Type *base,
+ lpi2c_master_handle_t *handle,
+ lpi2c_master_transfer_t *transfer)
+{
+ status_t result;
+
+ assert(NULL != handle);
+ assert(NULL != transfer);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->state != (uint8_t)kIdleState)
+ {
+ return kStatus_LPI2C_Busy;
+ }
+
+ /* Return an error if the bus is already in use not by us. */
+ result = LPI2C_CheckForBusyBus(base);
+ if (kStatus_Success != result)
+ {
+ return result;
+ }
+
+ /* Disable LPI2C IRQ sources while we configure stuff. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
+
+ /* Reset FIFO in case there are data. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* Save transfer into handle. */
+ handle->transfer = *transfer;
+
+ /* Generate commands to send. */
+ LPI2C_InitTransferStateMachine(handle);
+
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
+
+ /* Turn off auto-stop option. */
+ base->MCFGR1 &= ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+
+ /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
+ LPI2C_MasterEnableInterrupts(base, (uint32_t)kMasterIrqFlags);
+
+ return result;
+}
+
+/*!
+ * brief Returns number of bytes transferred so far.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCount(LPI2C_Type *base, lpi2c_master_handle_t *handle, size_t *count)
+{
+ assert(NULL != handle);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state == (uint8_t)kIdleState)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ uint8_t state;
+ uint16_t remainingBytes;
+ uint32_t dataSize;
+
+ /* Cache some fields with IRQs disabled. This ensures all field values */
+ /* are synchronized with each other during an ongoing transfer. */
+ uint32_t irqs = LPI2C_MasterGetEnabledInterrupts(base);
+ LPI2C_MasterDisableInterrupts(base, irqs);
+ state = handle->state;
+ remainingBytes = handle->remainingBytes;
+ dataSize = handle->transfer.dataSize;
+ LPI2C_MasterEnableInterrupts(base, irqs);
+
+ /* Get transfer count based on current transfer state. */
+ switch (state)
+ {
+ case (uint8_t)kIdleState:
+ case (uint8_t)kSendCommandState:
+ case (
+ uint8_t)kIssueReadCommandState: /* XXX return correct value for this state when >256 reads are supported */
+ *count = 0;
+ break;
+
+ case (uint8_t)kTransferDataState:
+ *count = dataSize - remainingBytes;
+ break;
+
+ case (uint8_t)kStopState:
+ case (uint8_t)kWaitForCompletionState:
+ default:
+ *count = dataSize;
+ break;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * LPI2C peripheral's IRQ priority.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * retval #kStatus_Success A transaction was successfully aborted.
+ * retval #kStatus_LPI2C_Idle There is not a non-blocking transaction currently in progress.
+ */
+void LPI2C_MasterTransferAbort(LPI2C_Type *base, lpi2c_master_handle_t *handle)
+{
+ if (handle->state != (uint8_t)kIdleState)
+ {
+ /* Disable internal IRQ enables. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
+
+ /* Reset fifos. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* Send a stop command to finalize the transfer. */
+ base->MTDR = (uint32_t)kStopCmd;
+
+ /* Reset handle. */
+ handle->state = (uint8_t)kIdleState;
+ }
+}
+
+/*!
+ * brief Reusable routine to handle master interrupts.
+ * note This function does not need to be called unless you are reimplementing the
+ * nonblocking API's interrupt handler routines to add special functionality.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ */
+void LPI2C_MasterTransferHandleIRQ(LPI2C_Type *base, lpi2c_master_handle_t *handle)
+{
+ bool isDone = false;
+ status_t result;
+ size_t txCount;
+
+ /* Don't do anything if we don't have a valid handle. */
+ if (NULL == handle)
+ {
+ return;
+ }
+
+ if (handle->state == (uint8_t)kIdleState)
+ {
+ return;
+ }
+
+ result = LPI2C_RunTransferStateMachine(base, handle, &isDone);
+
+ if ((result != kStatus_Success) || isDone)
+ {
+ /* Handle error, terminate xfer */
+ if (result != kStatus_Success)
+ {
+ LPI2C_MasterTransferAbort(base, handle);
+ }
+ /* Check whether there is data in tx FIFO not sent out, is there is then the last transfer was NACKed by slave
+ */
+ LPI2C_MasterGetFifoCounts(base, NULL, &txCount);
+ if (txCount != 0U)
+ {
+ result = kStatus_LPI2C_Nak;
+ /* Reset fifos. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+ /* Send a stop command to finalize the transfer. */
+ base->MTDR = (uint32_t)kStopCmd;
+ }
+ /* Disable internal IRQ enables. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
+
+ /* Set handle to idle state. */
+ handle->state = (uint8_t)kIdleState;
+
+ /* Invoke callback. */
+ if (NULL != handle->completionCallback)
+ {
+ handle->completionCallback(base, handle, result, handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Provides a default configuration for the LPI2C slave peripheral.
+ *
+ * This function provides the following default configuration for the LPI2C slave peripheral:
+ * code
+ * slaveConfig->enableSlave = true;
+ * slaveConfig->address0 = 0U;
+ * slaveConfig->address1 = 0U;
+ * slaveConfig->addressMatchMode = kLPI2C_MatchAddress0;
+ * slaveConfig->filterDozeEnable = true;
+ * slaveConfig->filterEnable = true;
+ * slaveConfig->enableGeneralCall = false;
+ * slaveConfig->sclStall.enableAck = false;
+ * slaveConfig->sclStall.enableTx = true;
+ * slaveConfig->sclStall.enableRx = true;
+ * slaveConfig->sclStall.enableAddress = true;
+ * slaveConfig->ignoreAck = false;
+ * slaveConfig->enableReceivedAddressRead = false;
+ * slaveConfig->sdaGlitchFilterWidth_ns = 0;
+ * slaveConfig->sclGlitchFilterWidth_ns = 0;
+ * slaveConfig->dataValidDelay_ns = 0;
+ * slaveConfig->clockHoldTime_ns = 0;
+ * endcode
+ *
+ * After calling this function, override any settings to customize the configuration,
+ * prior to initializing the master driver with LPI2C_SlaveInit(). Be sure to override at least the a
+ * address0 member of the configuration structure with the desired slave address.
+ *
+ * param[out] slaveConfig User provided configuration structure that is set to default values. Refer to
+ * #lpi2c_slave_config_t.
+ */
+void LPI2C_SlaveGetDefaultConfig(lpi2c_slave_config_t *slaveConfig)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(slaveConfig, 0, sizeof(*slaveConfig));
+
+ slaveConfig->enableSlave = true;
+ slaveConfig->address0 = 0U;
+ slaveConfig->address1 = 0U;
+ slaveConfig->addressMatchMode = kLPI2C_MatchAddress0;
+ slaveConfig->filterDozeEnable = true;
+ slaveConfig->filterEnable = true;
+ slaveConfig->enableGeneralCall = false;
+ slaveConfig->sclStall.enableAck = false;
+ slaveConfig->sclStall.enableTx = true;
+ slaveConfig->sclStall.enableRx = true;
+ slaveConfig->sclStall.enableAddress = false;
+ slaveConfig->ignoreAck = false;
+ slaveConfig->enableReceivedAddressRead = false;
+ slaveConfig->sdaGlitchFilterWidth_ns = 0U; /* TODO determine default width values */
+ slaveConfig->sclGlitchFilterWidth_ns = 0U;
+ slaveConfig->dataValidDelay_ns = 0U;
+ slaveConfig->clockHoldTime_ns = 0U;
+}
+
+/*!
+ * brief Initializes the LPI2C slave peripheral.
+ *
+ * This function enables the peripheral clock and initializes the LPI2C slave peripheral as described by the user
+ * provided configuration.
+ *
+ * param base The LPI2C peripheral base address.
+ * param slaveConfig User provided peripheral configuration. Use LPI2C_SlaveGetDefaultConfig() to get a set of defaults
+ * that you can override.
+ * param sourceClock_Hz Frequency in Hertz of the LPI2C functional clock. Used to calculate the filter widths,
+ * data valid delay, and clock hold time.
+ */
+void LPI2C_SlaveInit(LPI2C_Type *base, const lpi2c_slave_config_t *slaveConfig, uint32_t sourceClock_Hz)
+{
+ uint32_t tmpCycle;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Ungate the clock. */
+ CLOCK_EnableClock(kLpi2cClocks[instance]);
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Ungate the functional clock in initialize function. */
+ CLOCK_EnableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Restore to reset conditions. */
+ LPI2C_SlaveReset(base);
+
+ /* Configure peripheral. */
+ base->SAMR = LPI2C_SAMR_ADDR0(slaveConfig->address0) | LPI2C_SAMR_ADDR1(slaveConfig->address1);
+
+ base->SCFGR1 =
+ LPI2C_SCFGR1_ADDRCFG(slaveConfig->addressMatchMode) | LPI2C_SCFGR1_IGNACK(slaveConfig->ignoreAck) |
+ LPI2C_SCFGR1_RXCFG(slaveConfig->enableReceivedAddressRead) | LPI2C_SCFGR1_GCEN(slaveConfig->enableGeneralCall) |
+ LPI2C_SCFGR1_ACKSTALL(slaveConfig->sclStall.enableAck) | LPI2C_SCFGR1_TXDSTALL(slaveConfig->sclStall.enableTx) |
+ LPI2C_SCFGR1_RXSTALL(slaveConfig->sclStall.enableRx) |
+ LPI2C_SCFGR1_ADRSTALL(slaveConfig->sclStall.enableAddress);
+
+ tmpCycle =
+ LPI2C_SCFGR2_FILTSDA(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sdaGlitchFilterWidth_ns,
+ (LPI2C_SCFGR2_FILTSDA_MASK >> LPI2C_SCFGR2_FILTSDA_SHIFT), 1U));
+ tmpCycle |=
+ LPI2C_SCFGR2_FILTSCL(LPI2C_GetCyclesForWidth(sourceClock_Hz, slaveConfig->sclGlitchFilterWidth_ns,
+ (LPI2C_SCFGR2_FILTSCL_MASK >> LPI2C_SCFGR2_FILTSCL_SHIFT), 1U));
+ tmpCycle |= LPI2C_SCFGR2_DATAVD(LPI2C_GetCyclesForWidth(
+ sourceClock_Hz, slaveConfig->dataValidDelay_ns, (LPI2C_SCFGR2_DATAVD_MASK >> LPI2C_SCFGR2_DATAVD_SHIFT), 1U));
+
+ base->SCFGR2 = tmpCycle | LPI2C_SCFGR2_CLKHOLD(LPI2C_GetCyclesForWidth(
+ sourceClock_Hz, slaveConfig->clockHoldTime_ns,
+ (LPI2C_SCFGR2_CLKHOLD_MASK >> LPI2C_SCFGR2_CLKHOLD_SHIFT), 1U));
+
+ /* Save SCR to last so we don't enable slave until it is configured */
+ base->SCR = LPI2C_SCR_FILTDZ(slaveConfig->filterDozeEnable) | LPI2C_SCR_FILTEN(slaveConfig->filterEnable) |
+ LPI2C_SCR_SEN(slaveConfig->enableSlave);
+}
+
+/*!
+ * brief Deinitializes the LPI2C slave peripheral.
+ *
+ * This function disables the LPI2C slave peripheral and gates the clock. It also performs a software
+ * reset to restore the peripheral to reset conditions.
+ *
+ * param base The LPI2C peripheral base address.
+ */
+void LPI2C_SlaveDeinit(LPI2C_Type *base)
+{
+ LPI2C_SlaveReset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPI2C_GetInstance(base);
+
+ /* Gate the clock. */
+ CLOCK_DisableClock(kLpi2cClocks[instance]);
+
+#if defined(LPI2C_PERIPH_CLOCKS)
+ /* Gate the functional clock. */
+ CLOCK_DisableClock(kLpi2cPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * @brief Convert provided flags to status code, and clear any errors if present.
+ * @param base The LPI2C peripheral base address.
+ * @param status Current status flags value that will be checked.
+ * @retval #kStatus_Success
+ * @retval #kStatus_LPI2C_BitError
+ * @retval #kStatus_LPI2C_FifoError
+ */
+static status_t LPI2C_SlaveCheckAndClearError(LPI2C_Type *base, uint32_t flags)
+{
+ status_t result = kStatus_Success;
+
+ flags &= (uint32_t)kSlaveErrorFlags;
+ if (0U != flags)
+ {
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveBitErrFlag))
+ {
+ result = kStatus_LPI2C_BitError;
+ }
+ else if (0U != (flags & (uint32_t)kLPI2C_SlaveFifoErrFlag))
+ {
+ result = kStatus_LPI2C_FifoError;
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ /* Clear the errors. */
+ LPI2C_SlaveClearStatusFlags(base, flags);
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return result;
+}
+
+/*!
+ * brief Performs a polling send transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param txBuff The pointer to the data to be transferred.
+ * param txSize The length in bytes of the data to be transferred.
+ * param[out] actualTxSize
+ * return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveSend(LPI2C_Type *base, void *txBuff, size_t txSize, size_t *actualTxSize)
+{
+ uint8_t *buf = (uint8_t *)txBuff;
+ size_t remaining = txSize;
+
+ assert(NULL != txBuff);
+
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ /* Clear stop flag. */
+ LPI2C_SlaveClearStatusFlags(base,
+ (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+
+ while (0U != remaining)
+ {
+ uint32_t flags;
+ status_t result;
+
+ /* Wait until we can transmit. */
+ do
+ {
+ /* Check for errors */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+ result = LPI2C_SlaveCheckAndClearError(base, flags);
+ if (kStatus_Success != result)
+ {
+ if (NULL != actualTxSize)
+ {
+ *actualTxSize = txSize - remaining;
+ }
+ return result;
+ }
+#if I2C_RETRY_TIMES
+ } while ((0U == (flags & ((uint32_t)kLPI2C_SlaveTxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (0U != --waitTimes));
+ if (0U == waitTimes)
+ {
+ return kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == (flags & ((uint32_t)kLPI2C_SlaveTxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)));
+#endif
+
+ /* Send a byte. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTxReadyFlag))
+ {
+ base->STDR = *buf++;
+ --remaining;
+ }
+
+ /* Exit loop if we see a stop or restart in transfer*/
+ if ((0U != (flags & ((uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (remaining != 0U))
+ {
+ LPI2C_SlaveClearStatusFlags(
+ base, (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+ break;
+ }
+ }
+
+ if (NULL != actualTxSize)
+ {
+ *actualTxSize = txSize - remaining;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a polling receive transfer on the I2C bus.
+ *
+ * param base The LPI2C peripheral base address.
+ * param rxBuff The pointer to the data to be transferred.
+ * param rxSize The length in bytes of the data to be transferred.
+ * param[out] actualRxSize
+ * return Error or success status returned by API.
+ */
+status_t LPI2C_SlaveReceive(LPI2C_Type *base, void *rxBuff, size_t rxSize, size_t *actualRxSize)
+{
+ uint8_t *buf = (uint8_t *)rxBuff;
+ size_t remaining = rxSize;
+
+ assert(NULL != rxBuff);
+
+#if I2C_RETRY_TIMES
+ uint32_t waitTimes = I2C_RETRY_TIMES;
+#endif
+
+ /* Clear stop flag. */
+ LPI2C_SlaveClearStatusFlags(base,
+ (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+
+ while (0U != remaining)
+ {
+ uint32_t flags;
+ status_t result;
+
+ /* Wait until we can receive. */
+ do
+ {
+ /* Check for errors */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+ result = LPI2C_SlaveCheckAndClearError(base, flags);
+ if (kStatus_Success != result)
+ {
+ if (NULL != actualRxSize)
+ {
+ *actualRxSize = rxSize - remaining;
+ }
+ return result;
+ }
+#if I2C_RETRY_TIMES
+ } while ((0U == (flags & ((uint32_t)kLPI2C_SlaveRxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (0U != --waitTimes));
+ if (0U == waitTimes)
+ {
+ return kStatus_LPI2C_Timeout;
+ }
+#else
+ } while (0U == (flags & ((uint32_t)kLPI2C_SlaveRxReadyFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag |
+ (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)));
+#endif
+
+ /* Receive a byte. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveRxReadyFlag))
+ {
+ *buf++ = (uint8_t)(base->SRDR & LPI2C_SRDR_DATA_MASK);
+ --remaining;
+ }
+
+ /* Exit loop if we see a stop or restart */
+ if ((0U != (flags & ((uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag))) &&
+ (remaining != 0U))
+ {
+ LPI2C_SlaveClearStatusFlags(
+ base, (uint32_t)kLPI2C_SlaveStopDetectFlag | (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag);
+ break;
+ }
+ }
+
+ if (NULL != actualRxSize)
+ {
+ *actualRxSize = rxSize - remaining;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Creates a new handle for the LPI2C slave non-blocking APIs.
+ *
+ * The creation of a handle is for use with the non-blocking APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_SlaveTransferAbort() API shall be called.
+ *
+ * note The function also enables the NVIC IRQ for the input LPI2C. Need to notice
+ * that on some SoCs the LPI2C IRQ is connected to INTMUX, in this case user needs to
+ * enable the associated INTMUX IRQ in application.
+
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C slave driver handle.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_SlaveTransferCreateHandle(LPI2C_Type *base,
+ lpi2c_slave_handle_t *handle,
+ lpi2c_slave_transfer_callback_t callback,
+ void *userData)
+{
+ uint32_t instance;
+
+ assert(NULL != handle);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Look up instance number */
+ instance = LPI2C_GetInstance(base);
+
+ /* Save base and instance. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Save this handle for IRQ use. */
+ s_lpi2cSlaveHandle[instance] = handle;
+
+ /* Set irq handler. */
+ s_lpi2cSlaveIsr = LPI2C_SlaveTransferHandleIRQ;
+
+ /* Clear internal IRQ enables and enable NVIC IRQ. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags);
+ (void)EnableIRQ(kLpi2cIrqs[instance]);
+
+ /* Nack by default. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+}
+
+/*!
+ * brief Starts accepting slave transfers.
+ *
+ * Call this API after calling I2C_SlaveInit() and LPI2C_SlaveTransferCreateHandle() to start processing
+ * transactions driven by an I2C master. The slave monitors the I2C bus and pass events to the
+ * callback that was passed into the call to LPI2C_SlaveTransferCreateHandle(). The callback is always invoked
+ * from the interrupt context.
+ *
+ * The set of events received by the callback is customizable. To do so, set the a eventMask parameter to
+ * the OR'd combination of #lpi2c_slave_transfer_event_t enumerators for the events you wish to receive.
+ * The #kLPI2C_SlaveTransmitEvent and #kLPI2C_SlaveReceiveEvent events are always enabled and do not need
+ * to be included in the mask. Alternatively, you can pass 0 to get a default set of only the transmit and
+ * receive events that are always enabled. In addition, the #kLPI2C_SlaveAllEvents constant is provided as
+ * a convenient way to enable all events.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ * param eventMask Bit mask formed by OR'ing together #lpi2c_slave_transfer_event_t enumerators to specify
+ * which events to send to the callback. Other accepted values are 0 to get a default set of
+ * only the transmit and receive events, and #kLPI2C_SlaveAllEvents to enable all events.
+ *
+ * retval #kStatus_Success Slave transfers were successfully started.
+ * retval #kStatus_LPI2C_Busy Slave transfers have already been started on this handle.
+ */
+status_t LPI2C_SlaveTransferNonBlocking(LPI2C_Type *base, lpi2c_slave_handle_t *handle, uint32_t eventMask)
+{
+ uint32_t status;
+
+ assert(NULL != handle);
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->isBusy)
+ {
+ return kStatus_LPI2C_Busy;
+ }
+
+ /* Return an error if the bus is already in use not by us. */
+ status = LPI2C_SlaveGetStatusFlags(base);
+ if ((0U != (status & (uint32_t)kLPI2C_SlaveBusBusyFlag)) && (0U == (status & (uint32_t)kLPI2C_SlaveBusyFlag)))
+ {
+ return kStatus_LPI2C_Busy;
+ }
+
+ /* Disable LPI2C IRQ sources while we configure stuff. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags);
+
+ /* Clear transfer in handle. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+
+ /* Record that we're busy. */
+ handle->isBusy = true;
+
+ /* Set up event mask. tx and rx are always enabled. */
+ handle->eventMask = eventMask | (uint32_t)kLPI2C_SlaveTransmitEvent | (uint32_t)kLPI2C_SlaveReceiveEvent;
+
+ /* Ack by default. */
+ base->STAR = 0U;
+
+ /* Clear all flags. */
+ LPI2C_SlaveClearStatusFlags(base, (uint32_t)kSlaveClearFlags);
+
+ /* Enable LPI2C internal IRQ sources. NVIC IRQ was enabled in CreateHandle() */
+ LPI2C_SlaveEnableInterrupts(base, (uint32_t)kSlaveIrqFlags);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the slave transfer status during a non-blocking transfer.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to i2c_slave_handle_t structure.
+ * param[out] count Pointer to a value to hold the number of bytes transferred. May be NULL if the count is not
+ * required.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress
+ */
+status_t LPI2C_SlaveTransferGetCount(LPI2C_Type *base, lpi2c_slave_handle_t *handle, size_t *count)
+{
+ assert(NULL != handle);
+
+ if (count == NULL)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (!handle->isBusy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ /* For an active transfer, just return the count from the handle. */
+ *count = handle->transferredCount;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts the slave non-blocking transfers.
+ * note This API could be called at any time to stop slave for handling the bus events.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ * retval #kStatus_Success
+ * retval #kStatus_LPI2C_Idle
+ */
+void LPI2C_SlaveTransferAbort(LPI2C_Type *base, lpi2c_slave_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ /* Return idle if no transaction is in progress. */
+ if (handle->isBusy)
+ {
+ /* Disable LPI2C IRQ sources. */
+ LPI2C_SlaveDisableInterrupts(base, (uint32_t)kSlaveIrqFlags);
+
+ /* Nack by default. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+
+ /* Reset transfer info. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+
+ /* We're no longer busy. */
+ handle->isBusy = false;
+ }
+}
+
+/*!
+ * brief Reusable routine to handle slave interrupts.
+ * note This function does not need to be called unless you are reimplementing the
+ * non blocking API's interrupt handler routines to add special functionality.
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to #lpi2c_slave_handle_t structure which stores the transfer state.
+ */
+void LPI2C_SlaveTransferHandleIRQ(LPI2C_Type *base, lpi2c_slave_handle_t *handle)
+{
+ uint32_t flags;
+ lpi2c_slave_transfer_t *xfer;
+
+ /* Check for a valid handle in case of a spurious interrupt. */
+ if (NULL == handle)
+ {
+ return;
+ }
+
+ xfer = &handle->transfer;
+
+ /* Get status flags. */
+ flags = LPI2C_SlaveGetStatusFlags(base);
+
+ if (0U != (flags & ((uint32_t)kLPI2C_SlaveBitErrFlag | (uint32_t)kLPI2C_SlaveFifoErrFlag)))
+ {
+ xfer->event = kLPI2C_SlaveCompletionEvent;
+ xfer->completionStatus = LPI2C_SlaveCheckAndClearError(base, flags);
+
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveCompletionEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ return;
+ }
+ if (0U != (flags & (((uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag) | ((uint32_t)kLPI2C_SlaveStopDetectFlag))))
+ {
+ xfer->event = (0U != (flags & (uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag)) ? kLPI2C_SlaveRepeatedStartEvent :
+ kLPI2C_SlaveCompletionEvent;
+ xfer->receivedAddress = 0U;
+ xfer->completionStatus = kStatus_Success;
+ xfer->transferredCount = handle->transferredCount;
+
+ if (xfer->event == kLPI2C_SlaveCompletionEvent)
+ {
+ handle->isBusy = false;
+ }
+
+ if (handle->wasTransmit)
+ {
+ /* Subtract one from the transmit count to offset the fact that LPI2C asserts the */
+ /* tx flag before it sees the nack from the master-receiver, thus causing one more */
+ /* count that the master actually receives. */
+ --xfer->transferredCount;
+ handle->wasTransmit = false;
+ }
+
+ /* Clear the flag. */
+ LPI2C_SlaveClearStatusFlags(
+ base, flags & ((uint32_t)kLPI2C_SlaveRepeatedStartDetectFlag | (uint32_t)kLPI2C_SlaveStopDetectFlag));
+
+ /* Revert to sending an Ack by default, in case we sent a Nack for receive. */
+ base->STAR = 0U;
+
+ if ((0U != (handle->eventMask & (uint32_t)xfer->event)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clean up transfer info on completion, after the callback has been invoked. */
+ (void)memset(&handle->transfer, 0, sizeof(handle->transfer));
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveAddressValidFlag))
+ {
+ xfer->event = kLPI2C_SlaveAddressMatchEvent;
+ xfer->receivedAddress = (uint8_t)(base->SASR & LPI2C_SASR_RADDR_MASK);
+
+ /* Update handle status to busy because slave is addressed. */
+ handle->isBusy = true;
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveAddressMatchEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTransmitAckFlag))
+ {
+ xfer->event = kLPI2C_SlaveTransmitAckEvent;
+
+ if ((0U != (handle->eventMask & (uint32_t)kLPI2C_SlaveTransmitAckEvent)) && (NULL != handle->callback))
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+ }
+
+ /* Handle transmit and receive. */
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveTxReadyFlag))
+ {
+ handle->wasTransmit = true;
+
+ /* If we're out of data, invoke callback to get more. */
+ if ((NULL == xfer->data) || (0U == xfer->dataSize))
+ {
+ xfer->event = kLPI2C_SlaveTransmitEvent;
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clear the transferred count now that we have a new buffer. */
+ handle->transferredCount = 0U;
+ }
+
+ /* Transmit a byte. */
+ if ((NULL != xfer->data) && (0U != xfer->dataSize))
+ {
+ base->STDR = *xfer->data++;
+ --xfer->dataSize;
+ ++handle->transferredCount;
+ }
+ }
+ if (0U != (flags & (uint32_t)kLPI2C_SlaveRxReadyFlag))
+ {
+ /* If we're out of room in the buffer, invoke callback to get another. */
+ if ((NULL == xfer->data) || (0U == xfer->dataSize))
+ {
+ xfer->event = kLPI2C_SlaveReceiveEvent;
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, xfer, handle->userData);
+ }
+
+ /* Clear the transferred count now that we have a new buffer. */
+ handle->transferredCount = 0U;
+ }
+
+ /* Receive a byte. */
+ if ((NULL != xfer->data) && (0U != xfer->dataSize))
+ {
+ *xfer->data++ = (uint8_t)base->SRDR;
+ --xfer->dataSize;
+ ++handle->transferredCount;
+ }
+ else
+ {
+ /* We don't have any room to receive more data, so send a nack. */
+ base->STAR = LPI2C_STAR_TXNACK_MASK;
+ }
+ }
+}
+
+#if !(defined(FSL_FEATURE_I2C_HAS_NO_IRQ) && FSL_FEATURE_I2C_HAS_NO_IRQ)
+/*!
+ * @brief Shared IRQ handler that can call both master and slave ISRs.
+ *
+ * The master and slave ISRs are called through function pointers in order to decouple
+ * this code from the ISR functions. Without this, the linker would always pull in both
+ * ISRs and every function they call, even if only the functional API was used.
+ *
+ * @param base The LPI2C peripheral base address.
+ * @param instance The LPI2C peripheral instance number.
+ */
+static void LPI2C_CommonIRQHandler(LPI2C_Type *base, uint32_t instance)
+{
+ /* Check for master IRQ. */
+ if ((0U != (base->MCR & LPI2C_MCR_MEN_MASK)) && (NULL != s_lpi2cMasterIsr))
+ {
+ /* Master mode. */
+ s_lpi2cMasterIsr(base, s_lpi2cMasterHandle[instance]);
+ }
+
+ /* Check for slave IRQ. */
+ if ((0U != (base->SCR & LPI2C_SCR_SEN_MASK)) && (NULL != s_lpi2cSlaveIsr))
+ {
+ /* Slave mode. */
+ s_lpi2cSlaveIsr(base, s_lpi2cSlaveHandle[instance]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(LPI2C0)
+/* Implementation of LPI2C0 handler named in startup code. */
+void LPI2C0_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C0, 0U);
+}
+#endif
+
+#if defined(LPI2C1)
+/* Implementation of LPI2C1 handler named in startup code. */
+void LPI2C1_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C1, 1U);
+}
+#endif
+
+#if defined(LPI2C2)
+/* Implementation of LPI2C2 handler named in startup code. */
+void LPI2C2_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C2, 2U);
+}
+#endif
+
+#if defined(LPI2C3)
+/* Implementation of LPI2C3 handler named in startup code. */
+void LPI2C3_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C3, 3U);
+}
+#endif
+
+#if defined(LPI2C4)
+/* Implementation of LPI2C4 handler named in startup code. */
+void LPI2C4_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C4, 4U);
+}
+#endif
+
+#if defined(LPI2C5)
+/* Implementation of LPI2C5 handler named in startup code. */
+void LPI2C5_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C5, 5U);
+}
+#endif
+
+#if defined(LPI2C6)
+/* Implementation of LPI2C6 handler named in startup code. */
+void LPI2C6_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(LPI2C6, 6U);
+}
+#endif
+
+#if defined(CM4_0__LPI2C)
+/* Implementation of CM4_0__LPI2C handler named in startup code. */
+void M4_0_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4_0__LPI2C, LPI2C_GetInstance(CM4_0__LPI2C));
+}
+#endif
+
+#if defined(CM4__LPI2C)
+/* Implementation of CM4__LPI2C handler named in startup code. */
+void M4_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4__LPI2C, LPI2C_GetInstance(CM4__LPI2C));
+}
+#endif
+
+#if defined(CM4_1__LPI2C)
+/* Implementation of CM4_1__LPI2C handler named in startup code. */
+void M4_1_LPI2C_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(CM4_1__LPI2C, LPI2C_GetInstance(CM4_1__LPI2C));
+}
+#endif
+
+#if defined(DMA__LPI2C0)
+/* Implementation of DMA__LPI2C0 handler named in startup code. */
+void DMA_I2C0_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C0, LPI2C_GetInstance(DMA__LPI2C0));
+}
+#endif
+
+#if defined(DMA__LPI2C1)
+/* Implementation of DMA__LPI2C1 handler named in startup code. */
+void DMA_I2C1_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C1, LPI2C_GetInstance(DMA__LPI2C1));
+}
+#endif
+
+#if defined(DMA__LPI2C2)
+/* Implementation of DMA__LPI2C2 handler named in startup code. */
+void DMA_I2C2_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C2, LPI2C_GetInstance(DMA__LPI2C2));
+}
+#endif
+
+#if defined(DMA__LPI2C3)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void DMA_I2C3_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C3, LPI2C_GetInstance(DMA__LPI2C3));
+}
+#endif
+
+#if defined(DMA__LPI2C4)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void DMA_I2C4_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(DMA__LPI2C4, LPI2C_GetInstance(DMA__LPI2C4));
+}
+#endif
+
+#if defined(ADMA__LPI2C0)
+/* Implementation of DMA__LPI2C0 handler named in startup code. */
+void ADMA_I2C0_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C0, LPI2C_GetInstance(ADMA__LPI2C0));
+}
+#endif
+
+#if defined(ADMA__LPI2C1)
+/* Implementation of DMA__LPI2C1 handler named in startup code. */
+void ADMA_I2C1_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C1, LPI2C_GetInstance(ADMA__LPI2C1));
+}
+#endif
+
+#if defined(ADMA__LPI2C2)
+/* Implementation of DMA__LPI2C2 handler named in startup code. */
+void ADMA_I2C2_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C2, LPI2C_GetInstance(ADMA__LPI2C2));
+}
+#endif
+
+#if defined(ADMA__LPI2C3)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void ADMA_I2C3_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C3, LPI2C_GetInstance(ADMA__LPI2C3));
+}
+#endif
+
+#if defined(ADMA__LPI2C4)
+/* Implementation of DMA__LPI2C3 handler named in startup code. */
+void ADMA_I2C4_INT_DriverIRQHandler(void)
+{
+ LPI2C_CommonIRQHandler(ADMA__LPI2C4, LPI2C_GetInstance(ADMA__LPI2C4));
+}
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c
new file mode 100644
index 0000000000..c325405bf9
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpi2c_edma.c
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpi2c_edma.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpi2c_edma"
+#endif
+
+/* @brief Mask to align an address to 32 bytes. */
+#define ALIGN_32_MASK (0x1fU)
+
+/*! @brief Common sets of flags used by the driver. */
+enum _lpi2c_flag_constants
+{
+ /*! All flags which are cleared by the driver upon starting a transfer. */
+ kMasterClearFlags = kLPI2C_MasterEndOfPacketFlag | kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag |
+ kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag | kLPI2C_MasterPinLowTimeoutFlag |
+ kLPI2C_MasterDataMatchFlag,
+
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kMasterIrqFlags = kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterTxReadyFlag | kLPI2C_MasterRxReadyFlag |
+ kLPI2C_MasterStopDetectFlag | kLPI2C_MasterNackDetectFlag | kLPI2C_MasterPinLowTimeoutFlag |
+ kLPI2C_MasterFifoErrFlag,
+
+ /*! Errors to check for. */
+ kMasterErrorFlags = kLPI2C_MasterNackDetectFlag | kLPI2C_MasterArbitrationLostFlag | kLPI2C_MasterFifoErrFlag |
+ kLPI2C_MasterPinLowTimeoutFlag,
+
+ /*! All flags which are cleared by the driver upon starting a transfer. */
+ kSlaveClearFlags = kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveStopDetectFlag | kLPI2C_SlaveBitErrFlag |
+ kLPI2C_SlaveFifoErrFlag,
+
+ /*! IRQ sources enabled by the non-blocking transactional API. */
+ kSlaveIrqFlags = kLPI2C_SlaveTxReadyFlag | kLPI2C_SlaveRxReadyFlag | kLPI2C_SlaveStopDetectFlag |
+ kLPI2C_SlaveRepeatedStartDetectFlag | kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag |
+ kLPI2C_SlaveTransmitAckFlag | kLPI2C_SlaveAddressValidFlag,
+
+ /*! Errors to check for. */
+ kSlaveErrorFlags = kLPI2C_SlaveFifoErrFlag | kLPI2C_SlaveBitErrFlag,
+};
+
+/* ! @brief LPI2C master fifo commands. */
+enum _lpi2c_master_fifo_cmd
+{
+ kTxDataCmd = LPI2C_MTDR_CMD(0x0U), /*!< Transmit DATA[7:0] */
+ kRxDataCmd = LPI2C_MTDR_CMD(0X1U), /*!< Receive (DATA[7:0] + 1) bytes */
+ kStopCmd = LPI2C_MTDR_CMD(0x2U), /*!< Generate STOP condition */
+ kStartCmd = LPI2C_MTDR_CMD(0x4U), /*!< Generate(repeated) START and transmit address in DATA[[7:0] */
+};
+
+/*! @brief States for the state machine used by transactional APIs. */
+enum _lpi2c_transfer_states
+{
+ kIdleState = 0,
+ kSendCommandState,
+ kIssueReadCommandState,
+ kTransferDataState,
+ kStopState,
+ kWaitForCompletionState,
+};
+
+/*! @brief Typedef for interrupt handler. */
+typedef void (*lpi2c_isr_t)(LPI2C_Type *base, void *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle);
+
+static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+static uint32_t lpi2c_edma_RecSetting = 0x02;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Create a new handle for the LPI2C master DMA APIs.
+ *
+ * The creation of a handle is for use with the DMA APIs. Once a handle
+ * is created, there is not a corresponding destroy handle. If the user wants to
+ * terminate a transfer, the LPI2C_MasterTransferAbortEDMA() API shall be called.
+ *
+ * For devices where the LPI2C send and receive DMA requests are OR'd together, the a txDmaHandle
+ * parameter is ignored and may be set to NULL.
+ *
+ * param base The LPI2C peripheral base address.
+ * param[out] handle Pointer to the LPI2C master driver handle.
+ * param rxDmaHandle Handle for the eDMA receive channel. Created by the user prior to calling this function.
+ * param txDmaHandle Handle for the eDMA transmit channel. Created by the user prior to calling this function.
+ * param callback User provided pointer to the asynchronous callback function.
+ * param userData User provided pointer to the application callback data.
+ */
+void LPI2C_MasterCreateEDMAHandle(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ edma_handle_t *rxDmaHandle,
+ edma_handle_t *txDmaHandle,
+ lpi2c_master_edma_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+ assert(rxDmaHandle);
+ assert(txDmaHandle);
+
+ /* Clear out the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set up the handle. For combined rx/tx DMA requests, the tx channel handle is set to the rx handle */
+ /* in order to make the transfer API code simpler. */
+ handle->base = base;
+ handle->completionCallback = callback;
+ handle->userData = userData;
+ handle->rx = rxDmaHandle;
+ handle->tx = (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) > 0) ? txDmaHandle : rxDmaHandle;
+
+ /* Set DMA channel completion callbacks. */
+ EDMA_SetCallback(handle->rx, LPI2C_MasterEDMACallback, handle);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_SetCallback(handle->tx, LPI2C_MasterEDMACallback, handle);
+ }
+}
+
+/*!
+ * @brief Prepares the command buffer with the sequence of commands needed to send the requested transaction.
+ * @param handle Master DMA driver handle.
+ * @return Number of command words.
+ */
+static uint32_t LPI2C_GenerateCommands(lpi2c_master_edma_handle_t *handle)
+{
+ lpi2c_master_transfer_t *xfer = &handle->transfer;
+ uint16_t *cmd = (uint16_t *)&handle->commandBuffer;
+ uint32_t cmdCount = 0;
+
+ /* Handle no start option. */
+ if ((xfer->flags & (uint32_t)kLPI2C_TransferNoStartFlag) != 0U)
+ {
+ if (xfer->direction == kLPI2C_Read)
+ {
+ /* Need to issue read command first. */
+ cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
+ }
+ }
+ else
+ {
+ /*
+ * Initial direction depends on whether a subaddress was provided, and of course the actual
+ * data transfer direction.
+ */
+ lpi2c_direction_t direction = (xfer->subaddressSize != 0U) ? kLPI2C_Write : xfer->direction;
+
+ /* Start command. */
+ cmd[cmdCount++] =
+ (uint16_t)kStartCmd | (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)direction);
+
+ /* Subaddress, MSB first. */
+ if (xfer->subaddressSize != 0U)
+ {
+ uint32_t subaddressRemaining = xfer->subaddressSize;
+ while (0U != subaddressRemaining--)
+ {
+ uint8_t subaddressByte = (uint8_t)(xfer->subaddress >> (8U * subaddressRemaining)) & 0xffU;
+ cmd[cmdCount++] = subaddressByte;
+ }
+ }
+
+ /* Reads need special handling because we have to issue a read command and maybe a repeated start. */
+ if ((xfer->dataSize != 0U) && (xfer->direction == kLPI2C_Read))
+ {
+ /* Need to send repeated start if switching directions to read. */
+ if (direction == kLPI2C_Write)
+ {
+ cmd[cmdCount++] = (uint16_t)kStartCmd |
+ (uint16_t)((uint16_t)((uint16_t)xfer->slaveAddress << 1U) | (uint16_t)kLPI2C_Read);
+ }
+
+ /* Read command. */
+ cmd[cmdCount++] = (uint16_t)kRxDataCmd | (uint16_t)LPI2C_MTDR_DATA(xfer->dataSize - 1U);
+ }
+ }
+
+ return cmdCount;
+}
+
+/*!
+ * brief Performs a non-blocking DMA-based transaction on the I2C bus.
+ *
+ * The callback specified when the a handle was created is invoked when the transaction has
+ * completed.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param transfer The pointer to the transfer descriptor.
+ * retval #kStatus_Success The transaction was started successfully.
+ * retval #kStatus_LPI2C_Busy Either another master is currently utilizing the bus, or another DMA
+ * transaction is already in progress.
+ */
+status_t LPI2C_MasterTransferEDMA(LPI2C_Type *base,
+ lpi2c_master_edma_handle_t *handle,
+ lpi2c_master_transfer_t *transfer)
+{
+ status_t result;
+
+ assert(handle);
+ assert(transfer);
+ assert(transfer->subaddressSize <= sizeof(transfer->subaddress));
+
+ /* Return busy if another transaction is in progress. */
+ if (handle->isBusy)
+ {
+ return kStatus_LPI2C_Busy;
+ }
+
+ /* Return an error if the bus is already in use not by us. */
+ result = LPI2C_CheckForBusyBus(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ /* We're now busy. */
+ handle->isBusy = true;
+
+ /* Disable LPI2C IRQ and DMA sources while we configure stuff. */
+ LPI2C_MasterDisableInterrupts(base, (uint32_t)kMasterIrqFlags);
+ LPI2C_MasterEnableDMA(base, false, false);
+
+ /* Clear all flags. */
+ LPI2C_MasterClearStatusFlags(base, (uint32_t)kMasterClearFlags);
+
+ /* Save transfer into handle. */
+ handle->transfer = *transfer;
+
+ /* Generate commands to send. */
+ uint32_t commandCount = LPI2C_GenerateCommands(handle);
+
+ /* If the user is transmitting no data with no start or stop, then just go ahead and invoke the callback. */
+ if ((0U == commandCount) && (transfer->dataSize == 0U))
+ {
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(base, handle, kStatus_Success, handle->userData);
+ }
+ return kStatus_Success;
+ }
+
+ /* Reset DMA channels. */
+ EDMA_ResetChannel(handle->rx->base, handle->rx->channel);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_ResetChannel(handle->tx->base, handle->tx->channel);
+ }
+
+ /* Get a 32-byte aligned TCD pointer. */
+ edma_tcd_t *tcd = (edma_tcd_t *)((uint32_t)(&handle->tcds[1]) & (~ALIGN_32_MASK));
+
+ bool hasSendData = (transfer->direction == kLPI2C_Write) && (transfer->dataSize != 0U);
+ bool hasReceiveData = (transfer->direction == kLPI2C_Read) && (transfer->dataSize != 0U);
+
+ edma_transfer_config_t transferConfig;
+ edma_tcd_t *linkTcd = NULL;
+
+ /* Set up data transmit. */
+ if (hasSendData)
+ {
+ uint32_t *srcAddr = (uint32_t *)transfer->data;
+ transferConfig.srcAddr = (uint32_t)srcAddr;
+ transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.destOffset = 0;
+ transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to fill fifo */
+ transferConfig.majorLoopCounts = transfer->dataSize;
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
+ handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
+
+ if (commandCount != 0U)
+ {
+ /* Create a software TCD, which will be chained after the commands. */
+ EDMA_TcdReset(tcd);
+ EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
+ EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
+ linkTcd = tcd;
+ }
+ else
+ {
+ /* User is only transmitting data with no required commands, so this transfer can stand alone. */
+ EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, NULL);
+ EDMA_EnableChannelInterrupts(handle->tx->base, handle->tx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+ }
+ else if (hasReceiveData)
+ {
+ uint32_t *srcAddr = (uint32_t *)transfer->data;
+ /* Set up data receive. */
+ transferConfig.srcAddr = (uint32_t)LPI2C_MasterGetRxFifoAddress(base);
+ transferConfig.destAddr = (uint32_t)srcAddr;
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = 0;
+ transferConfig.destOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.minorLoopBytes = sizeof(uint8_t); /* TODO optimize to empty fifo */
+ transferConfig.majorLoopCounts = transfer->dataSize;
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPI2C handle */
+ handle->nbytes = (uint8_t)transferConfig.minorLoopBytes;
+
+ if ((FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0) || (0U == commandCount))
+ {
+ /* We can put this receive transfer on its own DMA channel. */
+ EDMA_SetTransferConfig(handle->rx->base, handle->rx->channel, &transferConfig, NULL);
+ EDMA_EnableChannelInterrupts(handle->rx->base, handle->rx->channel, (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+ else
+ {
+ /* For shared rx/tx DMA requests, when there are commands, create a software TCD of
+ enabling rx dma and disabling tx dma, which will be chained onto the commands transfer,
+ and create another software TCD of transfering data and chain it onto the last TCD.
+ Notice that in this situation assume tx/rx uses same channel */
+ EDMA_TcdReset(tcd);
+ EDMA_TcdSetTransferConfig(tcd, &transferConfig, NULL);
+ EDMA_TcdEnableInterrupts(tcd, (uint32_t)kEDMA_MajorInterruptEnable);
+
+ transferConfig.srcAddr = (uint32_t)&lpi2c_edma_RecSetting;
+ transferConfig.destAddr = (uint32_t) & (base->MDER);
+ transferConfig.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfig.srcOffset = 0;
+ transferConfig.destOffset = (int16_t)sizeof(uint8_t);
+ transferConfig.minorLoopBytes = sizeof(uint8_t);
+ transferConfig.majorLoopCounts = 1;
+
+ edma_tcd_t *tcdSetRxClearTxDMA = (edma_tcd_t *)((uint32_t)(&handle->tcds[2]) & (~ALIGN_32_MASK));
+
+ EDMA_TcdReset(tcdSetRxClearTxDMA);
+ EDMA_TcdSetTransferConfig(tcdSetRxClearTxDMA, &transferConfig, tcd);
+ linkTcd = tcdSetRxClearTxDMA;
+ }
+ }
+ else
+ {
+ /* No data to send */
+ }
+
+ /* Set up commands transfer. */
+ if (commandCount != 0U)
+ {
+ transferConfig.srcAddr = (uint32_t)handle->commandBuffer;
+ transferConfig.destAddr = (uint32_t)LPI2C_MasterGetTxFifoAddress(base);
+ transferConfig.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfig.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfig.srcOffset = (int16_t)sizeof(uint16_t);
+ transferConfig.destOffset = 0;
+ transferConfig.minorLoopBytes = sizeof(uint16_t); /* TODO optimize to fill fifo */
+ transferConfig.majorLoopCounts = commandCount;
+
+ EDMA_SetTransferConfig(handle->tx->base, handle->tx->channel, &transferConfig, linkTcd);
+ }
+
+ /* Start DMA transfer. */
+ if (hasReceiveData || (0 == FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base)))
+ {
+ EDMA_StartTransfer(handle->rx);
+ }
+
+ if ((hasSendData || (commandCount != 0U)) && (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0))
+ {
+ EDMA_StartTransfer(handle->tx);
+ }
+
+ /* Enable DMA in both directions. This actually kicks of the transfer. */
+ LPI2C_MasterEnableDMA(base, true, true);
+
+ return result;
+}
+
+/*!
+ * brief Returns number of bytes transferred so far.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * param[out] count Number of bytes transferred so far by the non-blocking transaction.
+ * retval #kStatus_Success
+ * retval #kStatus_NoTransferInProgress There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferGetCountEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (!handle->isBusy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ uint32_t remaining = handle->transfer.dataSize;
+
+ /* If the DMA is still on a commands transfer that chains to the actual data transfer, */
+ /* we do nothing and return the number of transferred bytes as zero. */
+ if (EDMA_GetNextTCDAddress(handle->tx) == 0U)
+ {
+ if (handle->transfer.direction == kLPI2C_Write)
+ {
+ remaining =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->tx->base, handle->tx->channel);
+ }
+ else
+ {
+ remaining =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->rx->base, handle->rx->channel);
+ }
+ }
+
+ *count = handle->transfer.dataSize - remaining;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Terminates a non-blocking LPI2C master transmission early.
+ *
+ * note It is not safe to call this function from an IRQ handler that has a higher priority than the
+ * eDMA peripheral's IRQ priority.
+ *
+ * param base The LPI2C peripheral base address.
+ * param handle Pointer to the LPI2C master driver handle.
+ * retval #kStatus_Success A transaction was successfully aborted.
+ * retval #kStatus_LPI2C_Idle There is not a DMA transaction currently in progress.
+ */
+status_t LPI2C_MasterTransferAbortEDMA(LPI2C_Type *base, lpi2c_master_edma_handle_t *handle)
+{
+ /* Catch when there is not an active transfer. */
+ if (!handle->isBusy)
+ {
+ return kStatus_LPI2C_Idle;
+ }
+
+ /* Terminate DMA transfers. */
+ EDMA_AbortTransfer(handle->rx);
+ if (FSL_FEATURE_LPI2C_HAS_SEPARATE_DMA_RX_TX_REQn(base) != 0)
+ {
+ EDMA_AbortTransfer(handle->tx);
+ }
+
+ /* Reset fifos. */
+ base->MCR |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+
+ /* Send a stop command to finalize the transfer. */
+ base->MTDR = (uint32_t)kStopCmd;
+
+ /* Reset handle. */
+ handle->isBusy = false;
+
+ return kStatus_Success;
+}
+
+/*!
+ * @brief DMA completion callback.
+ * @param dmaHandle DMA channel handle for the channel that completed.
+ * @param userData User data associated with the channel handle. For this callback, the user data is the
+ * LPI2C DMA driver handle.
+ * @param isTransferDone Whether the DMA transfer has completed.
+ * @param tcds Number of TCDs that completed.
+ */
+static void LPI2C_MasterEDMACallback(edma_handle_t *dmaHandle, void *userData, bool isTransferDone, uint32_t tcds)
+{
+ lpi2c_master_edma_handle_t *handle = (lpi2c_master_edma_handle_t *)userData;
+
+ if (NULL == handle)
+ {
+ return;
+ }
+
+ /* Check for errors. */
+ status_t result = LPI2C_MasterCheckAndClearError(handle->base, LPI2C_MasterGetStatusFlags(handle->base));
+
+ /* Done with this transaction. */
+ handle->isBusy = false;
+
+ if (0U == (handle->transfer.flags & (uint32_t)kLPI2C_TransferNoStopFlag))
+ {
+ /* Send a stop command to finalize the transfer. */
+ handle->base->MTDR = (uint32_t)kStopCmd;
+ }
+
+ /* Invoke callback. */
+ if (handle->completionCallback != NULL)
+ {
+ handle->completionCallback(handle->base, handle, result, handle->userData);
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpspi.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpspi.c
new file mode 100644
index 0000000000..4917a01c9e
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpspi.c
@@ -0,0 +1,2221 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpspi.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpspi"
+#endif
+
+/*!
+ * @brief Default watermark values.
+ *
+ * The default watermarks are set to zero.
+ */
+enum _lpspi_default_watermarks
+{
+ kLpspiDefaultTxWatermark = 0,
+ kLpspiDefaultRxWatermark = 0,
+};
+
+/*! @brief Typedef for master interrupt handler. */
+typedef void (*lpspi_master_isr_t)(LPSPI_Type *base, lpspi_master_handle_t *handle);
+
+/*! @brief Typedef for slave interrupt handler. */
+typedef void (*lpspi_slave_isr_t)(LPSPI_Type *base, lpspi_slave_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Configures the LPSPI peripheral chip select polarity.
+ *
+ * This function takes in the desired peripheral chip select (Pcs) and it's corresponding desired polarity and
+ * configures the Pcs signal to operate with the desired characteristic.
+ *
+ * @param base LPSPI peripheral address.
+ * @param pcs The particular peripheral chip select (parameter value is of type lpspi_which_pcs_t) for which we wish to
+ * apply the active high or active low characteristic.
+ * @param activeLowOrHigh The setting for either "active high, inactive low (0)" or "active low, inactive high(1)" of
+ * type lpspi_pcs_polarity_config_t.
+ */
+static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base,
+ lpspi_which_pcs_t pcs,
+ lpspi_pcs_polarity_config_t activeLowOrHigh);
+
+/*!
+ * @brief Combine the write data for 1 byte to 4 bytes.
+ * This is not a public API.
+ */
+static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint8_t bytesEachWrite, bool isByteSwap);
+
+/*!
+ * @brief Separate the read data for 1 byte to 4 bytes.
+ * This is not a public API.
+ */
+static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint8_t bytesEachRead, bool isByteSwap);
+
+/*!
+ * @brief Master fill up the TX FIFO with data.
+ * This is not a public API.
+ */
+static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle);
+
+/*!
+ * @brief Master finish up a transfer.
+ * It would call back if there is callback function and set the state to idle.
+ * This is not a public API.
+ */
+static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle);
+
+/*!
+ * @brief Slave fill up the TX FIFO with data.
+ * This is not a public API.
+ */
+static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle);
+
+/*!
+ * @brief Slave finish up a transfer.
+ * It would call back if there is callback function and set the state to idle.
+ * This is not a public API.
+ */
+static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle);
+
+/*!
+ * @brief LPSPI common interrupt handler.
+ *
+ * @param handle pointer to s_lpspiHandle which stores the transfer state.
+ */
+static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Defines constant value arrays for the baud rate pre-scalar and scalar divider values.*/
+static const uint8_t s_baudratePrescaler[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+/*! @brief Pointers to lpspi bases for each instance. */
+static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS;
+
+/*! @brief Pointers to lpspi IRQ number for each instance. */
+static const IRQn_Type s_lpspiIRQ[] = LPSPI_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to lpspi clocks for each instance. */
+static const clock_ip_name_t s_lpspiClocks[] = LPSPI_CLOCKS;
+
+#if defined(LPSPI_PERIPH_CLOCKS)
+static const clock_ip_name_t s_LpspiPeriphClocks[] = LPSPI_PERIPH_CLOCKS;
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to lpspi handles for each instance. */
+static void *s_lpspiHandle[ARRAY_SIZE(s_lpspiBases)];
+
+/*! @brief Pointer to master IRQ handler for each instance. */
+static lpspi_master_isr_t s_lpspiMasterIsr;
+/*! @brief Pointer to slave IRQ handler for each instance. */
+static lpspi_slave_isr_t s_lpspiSlaveIsr;
+/* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/
+volatile uint8_t g_lpspiDummyData[ARRAY_SIZE(s_lpspiBases)] = {0};
+
+/**********************************************************************************************************************
+ * Code
+ *********************************************************************************************************************/
+
+/*!
+ * brief Get the LPSPI instance from peripheral base address.
+ *
+ * param base LPSPI peripheral base address.
+ * return LPSPI instance.
+ */
+uint32_t LPSPI_GetInstance(LPSPI_Type *base)
+{
+ uint8_t instance = 0;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_lpspiBases); instance++)
+ {
+ if (s_lpspiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_lpspiBases));
+
+ return instance;
+}
+
+/*!
+ * brief Set up the dummy data.
+ *
+ * param base LPSPI peripheral address.
+ * param dummyData Data to be transferred when tx buffer is NULL.
+ * Note:
+ * This API has no effect when LPSPI in slave interrupt mode, because driver
+ * will set the TXMSK bit to 1 if txData is NULL, no data is loaded from transmit
+ * FIFO and output pin is tristated.
+ */
+void LPSPI_SetDummyData(LPSPI_Type *base, uint8_t dummyData)
+{
+ uint32_t instance = LPSPI_GetInstance(base);
+ g_lpspiDummyData[instance] = dummyData;
+}
+
+/*!
+ * brief Initializes the LPSPI master.
+ *
+ * param base LPSPI peripheral address.
+ * param masterConfig Pointer to structure lpspi_master_config_t.
+ * param srcClock_Hz Module source input clock in Hertz
+ */
+void LPSPI_MasterInit(LPSPI_Type *base, const lpspi_master_config_t *masterConfig, uint32_t srcClock_Hz)
+{
+ assert(masterConfig);
+
+ uint32_t tcrPrescaleValue = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPSPI_GetInstance(base);
+ /* Enable LPSPI clock */
+ (void)CLOCK_EnableClock(s_lpspiClocks[instance]);
+
+#if defined(LPSPI_PERIPH_CLOCKS)
+ (void)CLOCK_EnableClock(s_LpspiPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Set LPSPI to master */
+ LPSPI_SetMasterSlaveMode(base, kLPSPI_Master);
+
+ /* Set specific PCS to active high or low */
+ LPSPI_SetOnePcsPolarity(base, masterConfig->whichPcs, masterConfig->pcsActiveHighOrLow);
+
+ /* Set Configuration Register 1 related setting.*/
+ base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK | LPSPI_CFGR1_NOSTALL_MASK)) |
+ LPSPI_CFGR1_OUTCFG(masterConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(masterConfig->pinCfg) |
+ LPSPI_CFGR1_NOSTALL(0);
+
+ /* Set baudrate and delay times*/
+ (void)LPSPI_MasterSetBaudRate(base, masterConfig->baudRate, srcClock_Hz, &tcrPrescaleValue);
+
+ /* Set default watermarks */
+ LPSPI_SetFifoWatermarks(base, (uint32_t)kLpspiDefaultTxWatermark, (uint32_t)kLpspiDefaultRxWatermark);
+
+ /* Set Transmit Command Register*/
+ base->TCR = LPSPI_TCR_CPOL(masterConfig->cpol) | LPSPI_TCR_CPHA(masterConfig->cpha) |
+ LPSPI_TCR_LSBF(masterConfig->direction) | LPSPI_TCR_FRAMESZ(masterConfig->bitsPerFrame - 1U) |
+ LPSPI_TCR_PRESCALE(tcrPrescaleValue) | LPSPI_TCR_PCS(masterConfig->whichPcs);
+
+ LPSPI_Enable(base, true);
+
+ (void)LPSPI_MasterSetDelayTimes(base, masterConfig->pcsToSckDelayInNanoSec, kLPSPI_PcsToSck, srcClock_Hz);
+ (void)LPSPI_MasterSetDelayTimes(base, masterConfig->lastSckToPcsDelayInNanoSec, kLPSPI_LastSckToPcs, srcClock_Hz);
+ (void)LPSPI_MasterSetDelayTimes(base, masterConfig->betweenTransferDelayInNanoSec, kLPSPI_BetweenTransfer,
+ srcClock_Hz);
+
+ LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA);
+}
+
+/*!
+ * brief Sets the lpspi_master_config_t structure to default values.
+ *
+ * This API initializes the configuration structure for LPSPI_MasterInit().
+ * The initialized structure can remain unchanged in LPSPI_MasterInit(), or can be modified
+ * before calling the LPSPI_MasterInit().
+ * Example:
+ * code
+ * lpspi_master_config_t masterConfig;
+ * LPSPI_MasterGetDefaultConfig(&masterConfig);
+ * endcode
+ * param masterConfig pointer to lpspi_master_config_t structure
+ */
+void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig)
+{
+ assert(masterConfig);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(masterConfig, 0, sizeof(*masterConfig));
+
+ masterConfig->baudRate = 500000;
+ masterConfig->bitsPerFrame = 8;
+ masterConfig->cpol = kLPSPI_ClockPolarityActiveHigh;
+ masterConfig->cpha = kLPSPI_ClockPhaseFirstEdge;
+ masterConfig->direction = kLPSPI_MsbFirst;
+
+ masterConfig->pcsToSckDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U;
+ masterConfig->lastSckToPcsDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U;
+ masterConfig->betweenTransferDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U;
+
+ masterConfig->whichPcs = kLPSPI_Pcs0;
+ masterConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow;
+
+ masterConfig->pinCfg = kLPSPI_SdiInSdoOut;
+ masterConfig->dataOutConfig = kLpspiDataOutRetained;
+}
+
+/*!
+ * brief LPSPI slave configuration.
+ *
+ * param base LPSPI peripheral address.
+ * param slaveConfig Pointer to a structure lpspi_slave_config_t.
+ */
+void LPSPI_SlaveInit(LPSPI_Type *base, const lpspi_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPSPI_GetInstance(base);
+ /* Enable LPSPI clock */
+ (void)CLOCK_EnableClock(s_lpspiClocks[instance]);
+
+#if defined(LPSPI_PERIPH_CLOCKS)
+ (void)CLOCK_EnableClock(s_LpspiPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ LPSPI_SetMasterSlaveMode(base, kLPSPI_Slave);
+
+ LPSPI_SetOnePcsPolarity(base, slaveConfig->whichPcs, slaveConfig->pcsActiveHighOrLow);
+
+ base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK)) |
+ LPSPI_CFGR1_OUTCFG(slaveConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(slaveConfig->pinCfg);
+
+ LPSPI_SetFifoWatermarks(base, (uint32_t)kLpspiDefaultTxWatermark, (uint32_t)kLpspiDefaultRxWatermark);
+
+ base->TCR = LPSPI_TCR_CPOL(slaveConfig->cpol) | LPSPI_TCR_CPHA(slaveConfig->cpha) |
+ LPSPI_TCR_LSBF(slaveConfig->direction) | LPSPI_TCR_FRAMESZ(slaveConfig->bitsPerFrame - 1U);
+
+ /* This operation will set the dummy data for edma transfer, no effect in interrupt way. */
+ LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA);
+
+ LPSPI_Enable(base, true);
+}
+
+/*!
+ * brief Sets the lpspi_slave_config_t structure to default values.
+ *
+ * This API initializes the configuration structure for LPSPI_SlaveInit().
+ * The initialized structure can remain unchanged in LPSPI_SlaveInit() or can be modified
+ * before calling the LPSPI_SlaveInit().
+ * Example:
+ * code
+ * lpspi_slave_config_t slaveConfig;
+ * LPSPI_SlaveGetDefaultConfig(&slaveConfig);
+ * endcode
+ * param slaveConfig pointer to lpspi_slave_config_t structure.
+ */
+void LPSPI_SlaveGetDefaultConfig(lpspi_slave_config_t *slaveConfig)
+{
+ assert(slaveConfig);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(slaveConfig, 0, sizeof(*slaveConfig));
+
+ slaveConfig->bitsPerFrame = 8; /*!< Bits per frame, minimum 8, maximum 4096.*/
+ slaveConfig->cpol = kLPSPI_ClockPolarityActiveHigh; /*!< Clock polarity. */
+ slaveConfig->cpha = kLPSPI_ClockPhaseFirstEdge; /*!< Clock phase. */
+ slaveConfig->direction = kLPSPI_MsbFirst; /*!< MSB or LSB data shift direction. */
+
+ slaveConfig->whichPcs = kLPSPI_Pcs0; /*!< Desired Peripheral Chip Select (pcs) */
+ slaveConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow; /*!< Desired PCS active high or low */
+
+ slaveConfig->pinCfg = kLPSPI_SdiInSdoOut;
+ slaveConfig->dataOutConfig = kLpspiDataOutRetained;
+}
+
+/*!
+ * brief Restores the LPSPI peripheral to reset state. Note that this function
+ * sets all registers to reset state. As a result, the LPSPI module can't work after calling
+ * this API.
+ * param base LPSPI peripheral address.
+ */
+void LPSPI_Reset(LPSPI_Type *base)
+{
+ /* Reset all internal logic and registers, except the Control Register. Remains set until cleared by software.*/
+ base->CR |= LPSPI_CR_RST_MASK;
+
+ /* Software reset doesn't reset the CR, so manual reset the FIFOs */
+ base->CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK;
+
+ /* Master logic is not reset and module is disabled.*/
+ base->CR = 0x00U;
+}
+
+/*!
+ * brief De-initializes the LPSPI peripheral. Call this API to disable the LPSPI clock.
+ * param base LPSPI peripheral address.
+ */
+void LPSPI_Deinit(LPSPI_Type *base)
+{
+ /* Reset to default value */
+ LPSPI_Reset(base);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPSPI_GetInstance(base);
+ /* Enable LPSPI clock */
+ (void)CLOCK_DisableClock(s_lpspiClocks[instance]);
+
+#if defined(LPSPI_PERIPH_CLOCKS)
+ (void)CLOCK_DisableClock(s_LpspiPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base,
+ lpspi_which_pcs_t pcs,
+ lpspi_pcs_polarity_config_t activeLowOrHigh)
+{
+ uint32_t cfgr1Value = 0;
+ /* Clear the PCS polarity bit */
+ cfgr1Value = base->CFGR1 & ~(1UL << (LPSPI_CFGR1_PCSPOL_SHIFT + (uint32_t)pcs));
+
+ /* Configure the PCS polarity bit according to the activeLowOrHigh setting */
+ base->CFGR1 = cfgr1Value | ((uint32_t)activeLowOrHigh << (LPSPI_CFGR1_PCSPOL_SHIFT + (uint32_t)pcs));
+}
+
+/*!
+ * brief Sets the LPSPI baud rate in bits per second.
+ *
+ * This function takes in the desired bitsPerSec (baud rate) and calculates the nearest
+ * possible baud rate without exceeding the desired baud rate and returns the
+ * calculated baud rate in bits-per-second. It requires the caller to provide
+ * the frequency of the module source clock (in Hertz). Note that the baud rate
+ * does not go into effect until the Transmit Control Register (TCR) is programmed
+ * with the prescale value. Hence, this function returns the prescale tcrPrescaleValue
+ * parameter for later programming in the TCR. The higher level
+ * peripheral driver should alert the user of an out of range baud rate input.
+ *
+ * Note that the LPSPI module must first be disabled before configuring this.
+ * Note that the LPSPI module must be configured for master mode before configuring this.
+ *
+ * param base LPSPI peripheral address.
+ * param baudRate_Bps The desired baud rate in bits per second.
+ * param srcClock_Hz Module source input clock in Hertz.
+ * param tcrPrescaleValue The TCR prescale value needed to program the TCR.
+ * return The actual calculated baud rate. This function may also return a "0" if the
+ * LPSPI is not configured for master mode or if the LPSPI module is not disabled.
+ */
+
+uint32_t LPSPI_MasterSetBaudRate(LPSPI_Type *base,
+ uint32_t baudRate_Bps,
+ uint32_t srcClock_Hz,
+ uint32_t *tcrPrescaleValue)
+{
+ assert(tcrPrescaleValue);
+
+ /* For master mode configuration only, if slave mode detected, return 0.
+ * Also, the LPSPI module needs to be disabled first, if enabled, return 0
+ */
+ if ((!LPSPI_IsMaster(base)) || ((base->CR & LPSPI_CR_MEN_MASK) != 0U))
+ {
+ return 0U;
+ }
+
+ uint32_t prescaler, bestPrescaler;
+ uint32_t scaler, bestScaler;
+ uint32_t realBaudrate, bestBaudrate;
+ uint32_t diff, min_diff;
+ uint32_t desiredBaudrate = baudRate_Bps;
+
+ /* find combination of prescaler and scaler resulting in baudrate closest to the
+ * requested value
+ */
+ min_diff = 0xFFFFFFFFU;
+
+ /* Set to maximum divisor value bit settings so that if baud rate passed in is less
+ * than the minimum possible baud rate, then the SPI will be configured to the lowest
+ * possible baud rate
+ */
+ bestPrescaler = 7;
+ bestScaler = 255;
+
+ bestBaudrate = 0; /* required to avoid compilation warning */
+
+ /* In all for loops, if min_diff = 0, the exit for loop*/
+ for (prescaler = 0U; prescaler < 8U; prescaler++)
+ {
+ if (min_diff == 0U)
+ {
+ break;
+ }
+ for (scaler = 0U; scaler < 256U; scaler++)
+ {
+ if (min_diff == 0U)
+ {
+ break;
+ }
+ realBaudrate = (srcClock_Hz / (s_baudratePrescaler[prescaler] * (scaler + 2U)));
+
+ /* calculate the baud rate difference based on the conditional statement
+ * that states that the calculated baud rate must not exceed the desired baud rate
+ */
+ if (desiredBaudrate >= realBaudrate)
+ {
+ diff = desiredBaudrate - realBaudrate;
+ if (min_diff > diff)
+ {
+ /* a better match found */
+ min_diff = diff;
+ bestPrescaler = prescaler;
+ bestScaler = scaler;
+ bestBaudrate = realBaudrate;
+ }
+ }
+ }
+ }
+
+ /* Write the best baud rate scalar to the CCR.
+ * Note, no need to check for error since we've already checked to make sure the module is
+ * disabled and in master mode. Also, there is a limit on the maximum divider so we will not
+ * exceed this.
+ */
+ base->CCR = (base->CCR & ~LPSPI_CCR_SCKDIV_MASK) | LPSPI_CCR_SCKDIV(bestScaler);
+
+ /* return the best prescaler value for user to use later */
+ *tcrPrescaleValue = bestPrescaler;
+
+ /* return the actual calculated baud rate */
+ return bestBaudrate;
+}
+
+/*!
+ * brief Manually configures a specific LPSPI delay parameter (module must be disabled to
+ * change the delay values).
+ *
+ * This function configures the following:
+ * SCK to PCS delay, or
+ * PCS to SCK delay, or
+ * The configurations must occur between the transfer delay.
+ *
+ * The delay names are available in type lpspi_delay_type_t.
+ *
+ * The user passes the desired delay along with the delay value.
+ * This allows the user to directly set the delay values if they have
+ * pre-calculated them or if they simply wish to manually increment the value.
+ *
+ * Note that the LPSPI module must first be disabled before configuring this.
+ * Note that the LPSPI module must be configured for master mode before configuring this.
+ *
+ * param base LPSPI peripheral address.
+ * param scaler The 8-bit delay value 0x00 to 0xFF (255).
+ * param whichDelay The desired delay to configure, must be of type lpspi_delay_type_t.
+ */
+void LPSPI_MasterSetDelayScaler(LPSPI_Type *base, uint32_t scaler, lpspi_delay_type_t whichDelay)
+{
+ /*These settings are only relevant in master mode */
+ switch (whichDelay)
+ {
+ case kLPSPI_PcsToSck:
+ base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler);
+
+ break;
+ case kLPSPI_LastSckToPcs:
+ base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler);
+
+ break;
+ case kLPSPI_BetweenTransfer:
+ base->CCR = (base->CCR & (~LPSPI_CCR_DBT_MASK)) | LPSPI_CCR_DBT(scaler);
+
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Calculates the delay based on the desired delay input in nanoseconds (module must be
+ * disabled to change the delay values).
+ *
+ * This function calculates the values for the following:
+ * SCK to PCS delay, or
+ * PCS to SCK delay, or
+ * The configurations must occur between the transfer delay.
+ *
+ * The delay names are available in type lpspi_delay_type_t.
+ *
+ * The user passes the desired delay and the desired delay value in
+ * nano-seconds. The function calculates the value needed for the desired delay parameter
+ * and returns the actual calculated delay because an exact delay match may not be possible. In this
+ * case, the closest match is calculated without going below the desired delay value input.
+ * It is possible to input a very large delay value that exceeds the capability of the part, in
+ * which case the maximum supported delay is returned. It is up to the higher level
+ * peripheral driver to alert the user of an out of range delay input.
+ *
+ * Note that the LPSPI module must be configured for master mode before configuring this. And note that
+ * the delayTime = LPSPI_clockSource / (PRESCALE * Delay_scaler).
+ *
+ * param base LPSPI peripheral address.
+ * param delayTimeInNanoSec The desired delay value in nano-seconds.
+ * param whichDelay The desired delay to configuration, which must be of type lpspi_delay_type_t.
+ * param srcClock_Hz Module source input clock in Hertz.
+ * return actual Calculated delay value in nano-seconds.
+ */
+uint32_t LPSPI_MasterSetDelayTimes(LPSPI_Type *base,
+ uint32_t delayTimeInNanoSec,
+ lpspi_delay_type_t whichDelay,
+ uint32_t srcClock_Hz)
+{
+ uint64_t realDelay, bestDelay;
+ uint32_t scaler, bestScaler;
+ uint32_t diff, min_diff;
+ uint64_t initialDelayNanoSec;
+ uint32_t clockDividedPrescaler;
+
+ /* For delay between transfer, an additional scaler value is needed */
+ uint32_t additionalScaler = 0;
+
+ /*As the RM note, the LPSPI baud rate clock is itself divided by the PRESCALE setting, which can vary between
+ * transfers.*/
+ clockDividedPrescaler =
+ srcClock_Hz / s_baudratePrescaler[(base->TCR & LPSPI_TCR_PRESCALE_MASK) >> LPSPI_TCR_PRESCALE_SHIFT];
+
+ /* Find combination of prescaler and scaler resulting in the delay closest to the requested value.*/
+ min_diff = 0xFFFFFFFFU;
+
+ /* Initialize scaler to max value to generate the max delay */
+ bestScaler = 0xFFU;
+
+ /* Calculate the initial (min) delay and maximum possible delay based on the specific delay as
+ * the delay divisors are slightly different based on which delay we are configuring.
+ */
+ if (whichDelay == kLPSPI_BetweenTransfer)
+ {
+ /* First calculate the initial, default delay, note min delay is 2 clock cycles. Due to large size of
+ calculated values (uint64_t), we need to break up the calculation into several steps to ensure
+ accurate calculated results
+ */
+ initialDelayNanoSec = 1000000000U;
+ initialDelayNanoSec *= 2U;
+ initialDelayNanoSec /= clockDividedPrescaler;
+
+ /* Calculate the maximum delay */
+ bestDelay = 1000000000U;
+ bestDelay *= 257U; /* based on DBT+2, or 255 + 2 */
+ bestDelay /= clockDividedPrescaler;
+
+ additionalScaler = 1U;
+ }
+ else
+ {
+ /* First calculate the initial, default delay, min delay is 1 clock cycle. Due to large size of calculated
+ values (uint64_t), we need to break up the calculation into several steps to ensure accurate calculated
+ results.
+ */
+ initialDelayNanoSec = 1000000000U;
+ initialDelayNanoSec /= clockDividedPrescaler;
+
+ /* Calculate the maximum delay */
+ bestDelay = 1000000000U;
+ bestDelay *= 256U; /* based on SCKPCS+1 or PCSSCK+1, or 255 + 1 */
+ bestDelay /= clockDividedPrescaler;
+
+ additionalScaler = 0U;
+ }
+
+ /* If the initial, default delay is already greater than the desired delay, then
+ * set the delay to their initial value (0) and return the delay. In other words,
+ * there is no way to decrease the delay value further.
+ */
+ if (initialDelayNanoSec >= delayTimeInNanoSec)
+ {
+ LPSPI_MasterSetDelayScaler(base, 0, whichDelay);
+ return (uint32_t)initialDelayNanoSec;
+ }
+
+ /* If min_diff = 0, the exit for loop */
+ for (scaler = 0U; scaler < 256U; scaler++)
+ {
+ if (min_diff == 0U)
+ {
+ break;
+ }
+ /* Calculate the real delay value as we cycle through the scaler values.
+ Due to large size of calculated values (uint64_t), we need to break up the
+ calculation into several steps to ensure accurate calculated results
+ */
+ realDelay = 1000000000U;
+ realDelay *= ((uint64_t)scaler + 1UL + (uint64_t)additionalScaler);
+ realDelay /= clockDividedPrescaler;
+
+ /* calculate the delay difference based on the conditional statement
+ * that states that the calculated delay must not be less then the desired delay
+ */
+ if (realDelay >= delayTimeInNanoSec)
+ {
+ diff = (uint32_t)(realDelay - (uint64_t)delayTimeInNanoSec);
+ if (min_diff > diff)
+ {
+ /* a better match found */
+ min_diff = diff;
+ bestScaler = scaler;
+ bestDelay = realDelay;
+ }
+ }
+ }
+
+ /* write the best scaler value for the delay */
+ LPSPI_MasterSetDelayScaler(base, bestScaler, whichDelay);
+
+ /* return the actual calculated delay value (in ns) */
+ return (uint32_t)bestDelay;
+}
+
+/*Transactional APIs -- Master*/
+
+/*!
+ * brief Initializes the LPSPI master handle.
+ *
+ * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+
+ * param base LPSPI peripheral address.
+ * param handle LPSPI handle pointer to lpspi_master_handle_t.
+ * param callback DSPI callback.
+ * param userData callback function parameter.
+ */
+void LPSPI_MasterTransferCreateHandle(LPSPI_Type *base,
+ lpspi_master_handle_t *handle,
+ lpspi_master_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_lpspiHandle[LPSPI_GetInstance(base)] = handle;
+
+ /* Set irq handler. */
+ s_lpspiMasterIsr = LPSPI_MasterTransferHandleIRQ;
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+/*!
+ * brief Check the argument for transfer .
+ *
+ * param transfer the transfer struct to be used.
+ * param bitPerFrame The bit size of one frame.
+ * param bytePerFrame The byte size of one frame.
+ * return Return true for right and false for wrong.
+ */
+bool LPSPI_CheckTransferArgument(lpspi_transfer_t *transfer, uint32_t bitsPerFrame, uint32_t bytesPerFrame)
+{
+ assert(transfer);
+
+ /* If the transfer count is zero, then return immediately.*/
+ if (transfer->dataSize == 0U)
+ {
+ return false;
+ }
+
+ /* If both send buffer and receive buffer is null */
+ if ((NULL == (transfer->txData)) && (NULL == (transfer->rxData)))
+ {
+ return false;
+ }
+
+ /*The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4 .
+ *For bytesPerFrame greater than 4 situation:
+ *the transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4 ,
+ *otherwise , the transfer data size can be integer multiples of bytesPerFrame.
+ */
+ if (bytesPerFrame <= 4U)
+ {
+ if ((transfer->dataSize % bytesPerFrame) != 0U)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ((bytesPerFrame % 4U) != 0U)
+ {
+ if (transfer->dataSize != bytesPerFrame)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ((transfer->dataSize % bytesPerFrame) != 0U)
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+/*!
+ * brief LPSPI master transfer data using a polling method.
+ *
+ * This function transfers data using a polling method. This is a blocking function, which does not return until all
+ * transfers have been
+ * completed.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral address.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferBlocking(LPSPI_Type *base, lpspi_transfer_t *transfer)
+{
+ assert(transfer);
+
+ uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U;
+ uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U;
+ uint32_t temp = 0U;
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+
+ if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that LPSPI is not busy.*/
+ if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ModuleBusyFlag) != 0U)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+
+ uint8_t *txData = transfer->txData;
+ uint8_t *rxData = transfer->rxData;
+ uint32_t txRemainingByteCount = transfer->dataSize;
+ uint32_t rxRemainingByteCount = transfer->dataSize;
+
+ uint8_t bytesEachWrite;
+ uint8_t bytesEachRead;
+
+ uint32_t readData = 0U;
+ uint32_t wordToSend =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+
+ /*The TX and RX FIFO sizes are always the same*/
+ uint32_t fifoSize = LPSPI_GetRxFifoSize(base);
+ uint32_t rxFifoMaxBytes = MIN(bytesPerFrame, 4U) * fifoSize;
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+
+ bool isPcsContinuous = ((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U);
+ bool isRxMask = false;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+
+ if (NULL == rxData)
+ {
+ isRxMask = true;
+ }
+
+ LPSPI_Enable(base, false);
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+ /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
+ temp = base->CFGR1;
+ temp &= LPSPI_CFGR1_PINCFG_MASK;
+ if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
+ {
+ if (NULL == txData)
+ {
+ base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
+ }
+ /* The 3-wire mode can't send and receive data at the same time. */
+ if ((txData != NULL) && (rxData != NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+ }
+ LPSPI_Enable(base, true);
+
+ base->TCR =
+ (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
+ LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_PCS(whichPcs);
+
+ if (bytesPerFrame <= 4U)
+ {
+ bytesEachWrite = (uint8_t)bytesPerFrame;
+ bytesEachRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ bytesEachWrite = 4U;
+ bytesEachRead = 4U;
+ }
+
+ /*Write the TX data until txRemainingByteCount is equal to 0 */
+ while (txRemainingByteCount > 0U)
+ {
+ if (txRemainingByteCount < bytesEachWrite)
+ {
+ bytesEachWrite = (uint8_t)txRemainingByteCount;
+ }
+
+ /*Wait until TX FIFO is not full*/
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetTxFifoCount(base) == fifoSize) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetTxFifoCount(base) == fifoSize)
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_SPI_Timeout;
+ }
+#endif
+
+ /* To prevent rxfifo overflow, ensure transmitting and receiving are executed in parallel */
+ if (((NULL == rxData) || (rxRemainingByteCount - txRemainingByteCount) < rxFifoMaxBytes))
+ {
+ if (txData != NULL)
+ {
+ wordToSend = LPSPI_CombineWriteData(txData, bytesEachWrite, isByteSwap);
+ txData += bytesEachWrite;
+ }
+
+ LPSPI_WriteData(base, wordToSend);
+ txRemainingByteCount -= bytesEachWrite;
+ }
+
+ /*Check whether there is RX data in RX FIFO . Read out the RX data so that the RX FIFO would not overrun.*/
+ if (rxData != NULL)
+ {
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetRxFifoCount(base) != 0U)
+#endif
+ {
+ readData = LPSPI_ReadData(base);
+ if (rxRemainingByteCount < bytesEachRead)
+ {
+ bytesEachRead = (uint8_t)rxRemainingByteCount;
+ }
+
+ LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap);
+ rxData += bytesEachRead;
+
+ rxRemainingByteCount -= bytesEachRead;
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_SPI_Timeout;
+ }
+#endif
+ }
+ }
+
+ /* After write all the data in TX FIFO , should write the TCR_CONTC to 0 to de-assert the PCS. Note that TCR
+ * register also use the TX FIFO.
+ */
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetTxFifoCount(base) == fifoSize) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetTxFifoCount(base) == fifoSize)
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_SPI_Timeout;
+ }
+#endif
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK));
+
+ /*Read out the RX data in FIFO*/
+ if (rxData != NULL)
+ {
+ while (rxRemainingByteCount > 0U)
+ {
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetRxFifoCount(base) != 0U)
+#endif
+ {
+ readData = LPSPI_ReadData(base);
+
+ if (rxRemainingByteCount < bytesEachRead)
+ {
+ bytesEachRead = (uint8_t)rxRemainingByteCount;
+ }
+
+ LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap);
+ rxData += bytesEachRead;
+
+ rxRemainingByteCount -= bytesEachRead;
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_SPI_Timeout;
+ }
+#endif
+ }
+ }
+ else
+ {
+ /* If no RX buffer, then transfer is not complete until transfer complete flag sets */
+#if SPI_RETRY_TIMES
+ waitTimes = SPI_RETRY_TIMES;
+ while (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U) && (--waitTimes != 0U))
+#else
+ while ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U)
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_SPI_Timeout;
+ }
+#endif
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief LPSPI master transfer data using an interrupt method.
+ *
+ * This function transfers data using an interrupt method. This is a non-blocking function, which returns right away.
+ * When all data
+ * is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferNonBlocking(LPSPI_Type *base, lpspi_master_handle_t *handle, lpspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U;
+ uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U;
+ uint32_t temp = 0U;
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+ bool isPcsContinuous;
+ uint32_t tmpTimes;
+
+ if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+
+ handle->state = (uint8_t)kLPSPI_Busy;
+
+ bool isRxMask = false;
+
+ uint8_t txWatermark;
+
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+
+ handle->writeTcrInIsr = false;
+
+ handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
+ handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
+
+ handle->txBuffIfNull =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+
+ /*The TX and RX FIFO sizes are always the same*/
+ handle->fifoSize = LPSPI_GetRxFifoSize(base);
+
+ handle->isPcsContinuous = ((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U);
+ isPcsContinuous = handle->isPcsContinuous;
+ handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+
+ /*Set the RX and TX watermarks to reduce the ISR times.*/
+ if (handle->fifoSize > 1U)
+ {
+ txWatermark = 1U;
+ handle->rxWatermark = handle->fifoSize - 2U;
+ }
+ else
+ {
+ txWatermark = 0U;
+ handle->rxWatermark = 0U;
+ }
+
+ LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark);
+
+ LPSPI_Enable(base, false);
+ /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+ /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
+ temp = base->CFGR1;
+ temp &= LPSPI_CFGR1_PINCFG_MASK;
+ if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
+ {
+ if (NULL == handle->txData)
+ {
+ base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
+ }
+ /* The 3-wire mode can't send and receive data at the same time. */
+ if ((NULL != handle->txData) && (NULL != handle->rxData))
+ {
+ return kStatus_InvalidArgument;
+ }
+ }
+ LPSPI_Enable(base, true);
+
+ /*Flush FIFO , clear status , disable all the inerrupts.*/
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ /* If there is not rxData , can mask the receive data (receive data is not stored in receive FIFO).
+ * For master transfer , we'd better not masked the transmit data in TCR since the transfer flow is hard to
+ * controlled by software.*/
+ if (handle->rxData == NULL)
+ {
+ isRxMask = true;
+ handle->rxRemainingByteCount = 0;
+ }
+
+ base->TCR =
+ (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
+ LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_PCS(whichPcs);
+
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+ }
+
+ /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX ,
+ * and you should also enable the INTMUX interupt in your application.
+ */
+ (void)EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]);
+
+ /*TCR is also shared the FIFO , so wait for TCR written.*/
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetTxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetTxFifoCount(base) != 0U)
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_SPI_Timeout;
+ }
+#endif
+
+ /*Fill up the TX data in FIFO */
+ LPSPI_MasterTransferFillUpTxFifo(base, handle);
+
+ /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data.
+ * The IRQ handler will get the status of RX and TX interrupt flags.
+ */
+ if (handle->rxData != NULL)
+ {
+ /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
+ *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
+ */
+ tmpTimes = handle->readRegRemainingTimes;
+ if (tmpTimes <= handle->rxWatermark)
+ {
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(tmpTimes - 1U);
+ }
+
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ else
+ {
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable);
+ }
+
+ return kStatus_Success;
+}
+
+static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle)
+{
+ assert(handle);
+
+ uint32_t wordToSend = 0;
+ uint8_t fifoSize = handle->fifoSize;
+ uint32_t writeRegRemainingTimes = handle->writeRegRemainingTimes;
+ uint32_t readRegRemainingTimes = handle->readRegRemainingTimes;
+ size_t txRemainingByteCount = handle->txRemainingByteCount;
+ uint8_t bytesEachWrite = handle->bytesEachWrite;
+ bool isByteSwap = handle->isByteSwap;
+
+ /* Make sure the difference in remaining TX and RX byte counts does not exceed FIFO depth
+ * and that the number of TX FIFO entries does not exceed the FIFO depth.
+ * But no need to make the protection if there is no rxData.
+ */
+ while ((LPSPI_GetTxFifoCount(base) < fifoSize) &&
+ (((readRegRemainingTimes - writeRegRemainingTimes) < (uint32_t)fifoSize) || (handle->rxData == NULL)))
+ {
+ if (txRemainingByteCount < (size_t)bytesEachWrite)
+ {
+ handle->bytesEachWrite = (uint8_t)txRemainingByteCount;
+ bytesEachWrite = handle->bytesEachWrite;
+ }
+
+ if (handle->txData != NULL)
+ {
+ wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap);
+ handle->txData += bytesEachWrite;
+ }
+ else
+ {
+ wordToSend = handle->txBuffIfNull;
+ }
+
+ /*Write the word to TX register*/
+ LPSPI_WriteData(base, wordToSend);
+
+ /*Decrease the write TX register times.*/
+ --handle->writeRegRemainingTimes;
+ writeRegRemainingTimes = handle->writeRegRemainingTimes;
+
+ /*Decrease the remaining TX byte count.*/
+ handle->txRemainingByteCount -= (size_t)bytesEachWrite;
+ txRemainingByteCount = handle->txRemainingByteCount;
+
+ if (handle->txRemainingByteCount == 0U)
+ {
+ /* If PCS is continuous, update TCR to de-assert PCS */
+ if (handle->isPcsContinuous)
+ {
+ /* Only write to the TCR if the FIFO has room */
+ if (LPSPI_GetTxFifoCount(base) < fifoSize)
+ {
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK));
+ handle->writeTcrInIsr = false;
+ }
+ /* Else, set a global flag to tell the ISR to do write to the TCR */
+ else
+ {
+ handle->writeTcrInIsr = true;
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle)
+{
+ assert(handle);
+
+ /* Disable interrupt requests*/
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, kStatus_Success, handle->userData);
+ }
+}
+
+/*!
+ * brief Gets the master transfer remaining bytes.
+ *
+ * This function gets the master transfer remaining bytes.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferGetCount(LPSPI_Type *base, lpspi_master_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != (uint8_t)kLPSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t remainingByte;
+
+ if (handle->rxData != NULL)
+ {
+ remainingByte = handle->rxRemainingByteCount;
+ }
+ else
+ {
+ remainingByte = handle->txRemainingByteCount;
+ }
+
+ *count = handle->totalByteCount - remainingByte;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief LPSPI master abort transfer which uses an interrupt method.
+ *
+ * This function aborts a transfer which uses an interrupt method.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferAbort(LPSPI_Type *base, lpspi_master_handle_t *handle)
+{
+ assert(handle);
+
+ /* Disable interrupt requests*/
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ LPSPI_Reset(base);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+ handle->txRemainingByteCount = 0;
+ handle->rxRemainingByteCount = 0;
+}
+
+/*!
+ * brief LPSPI Master IRQ handler function.
+ *
+ * This function processes the LPSPI transmit and receive IRQ.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_master_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferHandleIRQ(LPSPI_Type *base, lpspi_master_handle_t *handle)
+{
+ assert(handle);
+
+ uint32_t readData;
+ uint8_t bytesEachRead = handle->bytesEachRead;
+ bool isByteSwap = handle->isByteSwap;
+ uint32_t readRegRemainingTimes = handle->readRegRemainingTimes;
+
+ if (handle->rxData != NULL)
+ {
+ if (handle->rxRemainingByteCount != 0U)
+ {
+ /* First, disable the interrupts to avoid potentially triggering another interrupt
+ * while reading out the RX FIFO as more data may be coming into the RX FIFO. We'll
+ * re-enable the interrupts based on the LPSPI state after reading out the FIFO.
+ */
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
+
+ while ((LPSPI_GetRxFifoCount(base) != 0U) && (handle->rxRemainingByteCount != 0U))
+ {
+ /*Read out the data*/
+ readData = LPSPI_ReadData(base);
+
+ /*Decrease the read RX register times.*/
+ --handle->readRegRemainingTimes;
+ readRegRemainingTimes = handle->readRegRemainingTimes;
+
+ if (handle->rxRemainingByteCount < (size_t)bytesEachRead)
+ {
+ handle->bytesEachRead = (uint8_t)(handle->rxRemainingByteCount);
+ bytesEachRead = handle->bytesEachRead;
+ }
+
+ LPSPI_SeparateReadData(handle->rxData, readData, bytesEachRead, isByteSwap);
+ handle->rxData += bytesEachRead;
+
+ /*Decrease the remaining RX byte count.*/
+ handle->rxRemainingByteCount -= (size_t)bytesEachRead;
+ }
+
+ /* Re-enable the interrupts only if rxCount indicates there is more data to receive,
+ * else we may get a spurious interrupt.
+ * */
+ if (handle->rxRemainingByteCount != 0U)
+ {
+ /* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ }
+
+ /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
+ *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
+ */
+ if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark)
+ {
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) |
+ LPSPI_FCR_RXWATER((readRegRemainingTimes > 1U) ? (readRegRemainingTimes - 1U) : (0U));
+ }
+ }
+
+ if (handle->txRemainingByteCount != 0U)
+ {
+ LPSPI_MasterTransferFillUpTxFifo(base, handle);
+ }
+ else
+ {
+ if ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize)))
+ {
+ if ((handle->isPcsContinuous) && (handle->writeTcrInIsr))
+ {
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK));
+ handle->writeTcrInIsr = false;
+ }
+ }
+ }
+
+ if ((handle->txRemainingByteCount == 0U) && (handle->rxRemainingByteCount == 0U) && (!handle->writeTcrInIsr))
+ {
+ /* If no RX buffer, then transfer is not complete until transfer complete flag sets */
+ if (handle->rxData == NULL)
+ {
+ if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) != 0U)
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_TransferCompleteFlag);
+ /* Complete the transfer and disable the interrupts */
+ LPSPI_MasterTransferComplete(base, handle);
+ }
+ else
+ {
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TransferCompleteInterruptEnable);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ }
+ else
+ {
+ /* Complete the transfer and disable the interrupts */
+ LPSPI_MasterTransferComplete(base, handle);
+ }
+ }
+}
+
+/*Transactional APIs -- Slave*/
+/*!
+ * brief Initializes the LPSPI slave handle.
+ *
+ * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * param base LPSPI peripheral address.
+ * param handle LPSPI handle pointer to lpspi_slave_handle_t.
+ * param callback DSPI callback.
+ * param userData callback function parameter.
+ */
+void LPSPI_SlaveTransferCreateHandle(LPSPI_Type *base,
+ lpspi_slave_handle_t *handle,
+ lpspi_slave_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_lpspiHandle[LPSPI_GetInstance(base)] = handle;
+
+ /* Set irq handler. */
+ s_lpspiSlaveIsr = LPSPI_SlaveTransferHandleIRQ;
+
+ handle->callback = callback;
+ handle->userData = userData;
+}
+
+/*!
+ * brief LPSPI slave transfer data using an interrupt method.
+ *
+ * This function transfer data using an interrupt method. This is a non-blocking function, which returns right away.
+ * When all data
+ * is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_SlaveTransferNonBlocking(LPSPI_Type *base, lpspi_slave_handle_t *handle, lpspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U;
+ uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U;
+ uint32_t temp = 0U;
+ uint32_t readRegRemainingTimes;
+
+ if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+ handle->state = (uint8_t)kLPSPI_Busy;
+
+ bool isRxMask = false;
+ bool isTxMask = false;
+
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_SLAVE_PCS_MASK) >> LPSPI_SLAVE_PCS_SHIFT;
+
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+
+ handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
+ handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
+
+ /*The TX and RX FIFO sizes are always the same*/
+ handle->fifoSize = LPSPI_GetRxFifoSize(base);
+
+ handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_SlaveByteSwap) != 0U);
+
+ /*Set the RX and TX watermarks to reduce the ISR times.*/
+ uint8_t txWatermark;
+ if (handle->fifoSize > 1U)
+ {
+ txWatermark = 1U;
+ handle->rxWatermark = handle->fifoSize - 2U;
+ }
+ else
+ {
+ txWatermark = 0U;
+ handle->rxWatermark = 0U;
+ }
+ LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark);
+
+ /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
+ temp = base->CFGR1;
+ temp &= LPSPI_CFGR1_PINCFG_MASK;
+ if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
+ {
+ if (NULL == handle->txData)
+ {
+ LPSPI_Enable(base, false);
+ base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
+ LPSPI_Enable(base, true);
+ }
+ /* The 3-wire mode can't send and receive data at the same time. */
+ if ((handle->txData != NULL) && (handle->rxData != NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+ }
+
+ /*Flush FIFO , clear status , disable all the inerrupts.*/
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ /*If there is not rxData , can mask the receive data (receive data is not stored in receive FIFO).*/
+ if (handle->rxData == NULL)
+ {
+ isRxMask = true;
+ handle->rxRemainingByteCount = 0U;
+ }
+
+ /*If there is not txData , can mask the transmit data (no data is loaded from transmit FIFO and output pin
+ * is tristated).
+ */
+ if (handle->txData == NULL)
+ {
+ isTxMask = true;
+ handle->txRemainingByteCount = 0U;
+ }
+
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK |
+ LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) |
+ LPSPI_TCR_CONT(0) | LPSPI_TCR_CONTC(0) | LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_TXMSK(isTxMask) |
+ LPSPI_TCR_PCS(whichPcs);
+
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+ }
+
+ /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX ,
+ * and you should also enable the INTMUX interupt in your application.
+ */
+ (void)EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]);
+
+ /*TCR is also shared the FIFO , so wait for TCR written.*/
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetTxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetTxFifoCount(base) != 0U)
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return kStatus_SPI_Timeout;
+ }
+#endif
+
+ /*Fill up the TX data in FIFO */
+ if (handle->txData != NULL)
+ {
+ LPSPI_SlaveTransferFillUpTxFifo(base, handle);
+ }
+
+ /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data.
+ * The IRQ handler will get the status of RX and TX interrupt flags.
+ */
+ if (handle->rxData != NULL)
+ {
+ /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
+ *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
+ */
+ readRegRemainingTimes = handle->readRegRemainingTimes;
+ if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark)
+ {
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(readRegRemainingTimes - 1U);
+ }
+
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ else
+ {
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable);
+ }
+
+ if (handle->rxData != NULL)
+ {
+ /* RX FIFO overflow request enable */
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_ReceiveErrorInterruptEnable);
+ }
+ if (handle->txData != NULL)
+ {
+ /* TX FIFO underflow request enable */
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TransmitErrorInterruptEnable);
+ }
+
+ return kStatus_Success;
+}
+
+static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle)
+{
+ assert(handle);
+
+ uint32_t wordToSend = 0U;
+ uint8_t bytesEachWrite = handle->bytesEachWrite;
+ bool isByteSwap = handle->isByteSwap;
+
+ while (LPSPI_GetTxFifoCount(base) < (handle->fifoSize))
+ {
+ if (handle->txRemainingByteCount < (size_t)bytesEachWrite)
+ {
+ handle->bytesEachWrite = (uint8_t)handle->txRemainingByteCount;
+ bytesEachWrite = handle->bytesEachWrite;
+ }
+
+ wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap);
+ handle->txData += bytesEachWrite;
+
+ /*Decrease the remaining TX byte count.*/
+ handle->txRemainingByteCount -= (size_t)bytesEachWrite;
+
+ /*Write the word to TX register*/
+ LPSPI_WriteData(base, wordToSend);
+
+ if (handle->txRemainingByteCount == 0U)
+ {
+ break;
+ }
+ }
+}
+
+static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle)
+{
+ assert(handle);
+
+ status_t status = kStatus_Success;
+
+ /* Disable interrupt requests*/
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ if (handle->state == (uint8_t)kLPSPI_Error)
+ {
+ status = kStatus_LPSPI_Error;
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+
+ if (handle->callback != NULL)
+ {
+ handle->callback(base, handle, status, handle->userData);
+ }
+}
+
+/*!
+ * brief Gets the slave transfer remaining bytes.
+ *
+ * This function gets the slave transfer remaining bytes.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the non-blocking transaction.
+ * return status of status_t.
+ */
+status_t LPSPI_SlaveTransferGetCount(LPSPI_Type *base, lpspi_slave_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != (uint8_t)kLPSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t remainingByte;
+
+ if (handle->rxData != NULL)
+ {
+ remainingByte = handle->rxRemainingByteCount;
+ }
+ else
+ {
+ remainingByte = handle->txRemainingByteCount;
+ }
+
+ *count = handle->totalByteCount - remainingByte;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief LPSPI slave aborts a transfer which uses an interrupt method.
+ *
+ * This function aborts a transfer which uses an interrupt method.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferAbort(LPSPI_Type *base, lpspi_slave_handle_t *handle)
+{
+ assert(handle);
+
+ /* Disable interrupt requests*/
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable);
+
+ LPSPI_Reset(base);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+ handle->txRemainingByteCount = 0U;
+ handle->rxRemainingByteCount = 0U;
+}
+
+/*!
+ * brief LPSPI Slave IRQ handler function.
+ *
+ * This function processes the LPSPI transmit and receives an IRQ.
+ *
+ * param base LPSPI peripheral address.
+ * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferHandleIRQ(LPSPI_Type *base, lpspi_slave_handle_t *handle)
+{
+ assert(handle);
+
+ uint32_t readData; /* variable to store word read from RX FIFO */
+ uint32_t wordToSend; /* variable to store word to write to TX FIFO */
+ uint8_t bytesEachRead = handle->bytesEachRead;
+ uint8_t bytesEachWrite = handle->bytesEachWrite;
+ bool isByteSwap = handle->isByteSwap;
+ uint32_t readRegRemainingTimes;
+
+ if (handle->rxData != NULL)
+ {
+ if (handle->rxRemainingByteCount > 0U)
+ {
+ while (LPSPI_GetRxFifoCount(base) != 0U)
+ {
+ /*Read out the data*/
+ readData = LPSPI_ReadData(base);
+
+ /*Decrease the read RX register times.*/
+ --handle->readRegRemainingTimes;
+
+ if (handle->rxRemainingByteCount < (size_t)bytesEachRead)
+ {
+ handle->bytesEachRead = (uint8_t)handle->rxRemainingByteCount;
+ bytesEachRead = handle->bytesEachRead;
+ }
+
+ LPSPI_SeparateReadData(handle->rxData, readData, bytesEachRead, isByteSwap);
+ handle->rxData += bytesEachRead;
+
+ /*Decrease the remaining RX byte count.*/
+ handle->rxRemainingByteCount -= (size_t)bytesEachRead;
+
+ if ((handle->txRemainingByteCount > 0U) && (handle->txData != NULL))
+ {
+ if (handle->txRemainingByteCount < (size_t)bytesEachWrite)
+ {
+ handle->bytesEachWrite = (uint8_t)handle->txRemainingByteCount;
+ bytesEachWrite = handle->bytesEachWrite;
+ }
+
+ wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap);
+ handle->txData += bytesEachWrite;
+
+ /*Decrease the remaining TX byte count.*/
+ handle->txRemainingByteCount -= (size_t)bytesEachWrite;
+
+ /*Write the word to TX register*/
+ LPSPI_WriteData(base, wordToSend);
+ }
+
+ if (handle->rxRemainingByteCount == 0U)
+ {
+ break;
+ }
+ }
+ }
+
+ /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there
+ *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark.
+ */
+ readRegRemainingTimes = handle->readRegRemainingTimes;
+ if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark)
+ {
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) |
+ LPSPI_FCR_RXWATER((readRegRemainingTimes > 1U) ? (readRegRemainingTimes - 1U) : (0U));
+ }
+ }
+ if ((handle->rxData == NULL) && (handle->txRemainingByteCount != 0U) && (handle->txData != NULL))
+ {
+ LPSPI_SlaveTransferFillUpTxFifo(base, handle);
+ }
+
+ if ((handle->txRemainingByteCount == 0U) && (handle->rxRemainingByteCount == 0U))
+ {
+ /* If no RX buffer, then transfer is not complete until transfer complete flag sets and the TX FIFO empty*/
+ if (handle->rxData == NULL)
+ {
+ if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_FrameCompleteFlag) != 0U) &&
+ (LPSPI_GetTxFifoCount(base) == 0U))
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_FrameCompleteFlag);
+ /* Complete the transfer and disable the interrupts */
+ LPSPI_SlaveTransferComplete(base, handle);
+ }
+ else
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_FrameCompleteFlag);
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_FrameCompleteInterruptEnable);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable);
+ }
+ }
+ else
+ {
+ /* Complete the transfer and disable the interrupts */
+ LPSPI_SlaveTransferComplete(base, handle);
+ }
+ }
+
+ /* Catch tx fifo underflow conditions, service only if tx under flow interrupt enabled */
+ if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransmitErrorFlag) != 0U) &&
+ ((base->IER & LPSPI_IER_TEIE_MASK) != 0U))
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_TransmitErrorFlag);
+ /* Change state to error and clear flag */
+ if (handle->txData != NULL)
+ {
+ handle->state = (uint8_t)kLPSPI_Error;
+ }
+ handle->errorCount++;
+ }
+ /* Catch rx fifo overflow conditions, service only if rx over flow interrupt enabled */
+ if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ReceiveErrorFlag) != 0U) &&
+ ((base->IER & LPSPI_IER_REIE_MASK) != 0U))
+ {
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_ReceiveErrorFlag);
+ /* Change state to error and clear flag */
+ if (handle->txData != NULL)
+ {
+ handle->state = (uint8_t)kLPSPI_Error;
+ }
+ handle->errorCount++;
+ }
+}
+
+static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint8_t bytesEachWrite, bool isByteSwap)
+{
+ assert(txData != NULL);
+
+ uint32_t wordToSend = 0U;
+
+ switch (bytesEachWrite)
+ {
+ case 1:
+ wordToSend = *txData;
+ ++txData;
+ break;
+
+ case 2:
+ if (!isByteSwap)
+ {
+ wordToSend = *txData;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ }
+ else
+ {
+ wordToSend = (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= *txData;
+ ++txData;
+ }
+
+ break;
+
+ case 3:
+ if (!isByteSwap)
+ {
+ wordToSend = *txData;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 16U;
+ ++txData;
+ }
+ else
+ {
+ wordToSend = (unsigned)(*txData) << 16U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= *txData;
+ ++txData;
+ }
+ break;
+
+ case 4:
+ if (!isByteSwap)
+ {
+ wordToSend = *txData;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 16U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 24U;
+ ++txData;
+ }
+ else
+ {
+ wordToSend = (unsigned)(*txData) << 24U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 16U;
+ ++txData;
+ wordToSend |= (unsigned)(*txData) << 8U;
+ ++txData;
+ wordToSend |= *txData;
+ ++txData;
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ return wordToSend;
+}
+
+static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint8_t bytesEachRead, bool isByteSwap)
+{
+ assert(rxData);
+
+ switch (bytesEachRead)
+ {
+ case 1:
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ break;
+
+ case 2:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ }
+ break;
+
+ case 3:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ }
+ break;
+
+ case 4:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param)
+{
+ if (LPSPI_IsMaster(base))
+ {
+ s_lpspiMasterIsr(base, (lpspi_master_handle_t *)param);
+ }
+ else
+ {
+ s_lpspiSlaveIsr(base, (lpspi_slave_handle_t *)param);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#if defined(LPSPI0)
+void LPSPI0_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[0]);
+ LPSPI_CommonIRQHandler(LPSPI0, s_lpspiHandle[0]);
+}
+#endif
+
+#if defined(LPSPI1)
+void LPSPI1_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[1]);
+ LPSPI_CommonIRQHandler(LPSPI1, s_lpspiHandle[1]);
+}
+#endif
+
+#if defined(LPSPI2)
+void LPSPI2_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[2]);
+ LPSPI_CommonIRQHandler(LPSPI2, s_lpspiHandle[2]);
+}
+#endif
+
+#if defined(LPSPI3)
+void LPSPI3_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[3]);
+ LPSPI_CommonIRQHandler(LPSPI3, s_lpspiHandle[3]);
+}
+#endif
+
+#if defined(LPSPI4)
+void LPSPI4_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[4]);
+ LPSPI_CommonIRQHandler(LPSPI4, s_lpspiHandle[4]);
+}
+#endif
+
+#if defined(LPSPI5)
+void LPSPI5_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[5]);
+ LPSPI_CommonIRQHandler(LPSPI5, s_lpspiHandle[5]);
+}
+#endif
+
+#if defined(DMA__LPSPI0)
+void DMA_SPI0_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]);
+ LPSPI_CommonIRQHandler(DMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]);
+}
+#endif
+
+#if defined(DMA__LPSPI1)
+void DMA_SPI1_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]);
+ LPSPI_CommonIRQHandler(DMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]);
+}
+#endif
+#if defined(DMA__LPSPI2)
+void DMA_SPI2_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]);
+ LPSPI_CommonIRQHandler(DMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]);
+}
+#endif
+
+#if defined(DMA__LPSPI3)
+void DMA_SPI3_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]);
+ LPSPI_CommonIRQHandler(DMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI0)
+void ADMA_SPI0_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI1)
+void ADMA_SPI1_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]);
+}
+#endif
+#if defined(ADMA__LPSPI2)
+void ADMA_SPI2_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI3)
+void ADMA_SPI3_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]);
+}
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpspi_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpspi_edma.c
new file mode 100644
index 0000000000..5a19ca0092
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpspi_edma.c
@@ -0,0 +1,1154 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpspi_edma.h"
+
+/***********************************************************************************************************************
+ * Definitions
+ ***********************************************************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpspi_edma"
+#endif
+
+/*!
+ * @brief Structure definition for dspi_master_edma_private_handle_t. The structure is private.
+ */
+typedef struct _lpspi_master_edma_private_handle
+{
+ LPSPI_Type *base; /*!< LPSPI peripheral base address. */
+ lpspi_master_edma_handle_t *handle; /*!< lpspi_master_edma_handle_t handle */
+} lpspi_master_edma_private_handle_t;
+
+/*!
+ * @brief Structure definition for dspi_slave_edma_private_handle_t. The structure is private.
+ */
+typedef struct _lpspi_slave_edma_private_handle
+{
+ LPSPI_Type *base; /*!< LPSPI peripheral base address. */
+ lpspi_slave_edma_handle_t *handle; /*!< lpspi_slave_edma_handle_t handle */
+} lpspi_slave_edma_private_handle_t;
+
+/***********************************************************************************************************************
+ * Prototypes
+ ***********************************************************************************************************************/
+
+/*!
+ * @brief EDMA_LpspiMasterCallback after the LPSPI master transfer completed by using EDMA.
+ * This is not a public API.
+ */
+static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds);
+
+/*!
+ * @brief EDMA_LpspiSlaveCallback after the LPSPI slave transfer completed by using EDMA.
+ * This is not a public API.
+ */
+static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds);
+
+static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap);
+
+/***********************************************************************************************************************
+ * Variables
+ ***********************************************************************************************************************/
+/*! @brief Pointers to lpspi bases for each instance. */
+static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS;
+
+/*! @brief Pointers to lpspi edma handles for each instance. */
+static lpspi_master_edma_private_handle_t s_lpspiMasterEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
+static lpspi_slave_edma_private_handle_t s_lpspiSlaveEdmaPrivateHandle[ARRAY_SIZE(s_lpspiBases)];
+
+/***********************************************************************************************************************
+ * Code
+ ***********************************************************************************************************************/
+static void LPSPI_SeparateEdmaReadData(uint8_t *rxData, uint32_t readData, uint32_t bytesEachRead, bool isByteSwap)
+{
+ assert(rxData);
+
+ switch (bytesEachRead)
+ {
+ case 1:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+ }
+ break;
+
+ case 2:
+ if (!isByteSwap)
+ {
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ }
+ else
+ {
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+ }
+ break;
+
+ case 4:
+
+ *rxData = (uint8_t)readData;
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 8);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 16);
+ ++rxData;
+ *rxData = (uint8_t)(readData >> 24);
+ ++rxData;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Initializes the LPSPI master eDMA handle.
+ *
+ * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * Note that the LPSPI eDMA has a separated (Rx and Rx as two sources) or shared (Rx and Tx are the same source) DMA
+ * request source.
+ * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
+ * Tx DMAMUX source for edmaIntermediaryToTxRegHandle.
+ * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle LPSPI handle pointer to lpspi_master_edma_handle_t.
+ * param callback LPSPI callback.
+ * param userData callback function parameter.
+ * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
+ * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
+ */
+void LPSPI_MasterTransferCreateHandleEDMA(LPSPI_Type *base,
+ lpspi_master_edma_handle_t *handle,
+ lpspi_master_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaRxRegToRxDataHandle,
+ edma_handle_t *edmaTxDataToTxRegHandle)
+{
+ assert(handle);
+ assert(edmaRxRegToRxDataHandle);
+ assert(edmaTxDataToTxRegHandle);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ uint32_t instance = LPSPI_GetInstance(base);
+
+ s_lpspiMasterEdmaPrivateHandle[instance].base = base;
+ s_lpspiMasterEdmaPrivateHandle[instance].handle = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
+ handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
+}
+
+/*!
+ * brief LPSPI master transfer data using eDMA.
+ *
+ * This function transfers data using eDMA. This is a non-blocking function, which returns right away. When all data
+ * is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, lpspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U;
+ uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U;
+ uint32_t temp = 0U;
+ bool isByteSwap;
+ bool isPcsContinuous;
+
+ if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /*And since the dma transfer can not support 3 bytes .*/
+ if ((bytesPerFrame % 4U) == 3U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+
+ handle->state = (uint8_t)kLPSPI_Busy;
+
+ uint32_t instance = LPSPI_GetInstance(base);
+ uint32_t rxAddr = LPSPI_GetRxRegisterAddress(base);
+ uint32_t txAddr = LPSPI_GetTxRegisterAddress(base);
+
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+
+ /*Because DMA is fast enough , so set the RX and TX watermarks to 0 .*/
+ uint8_t txWatermark = 0;
+ uint8_t rxWatermark = 0;
+
+ /*Used for byte swap*/
+ uint32_t dif = 0;
+
+ uint8_t bytesLastWrite = 0;
+
+ bool isThereExtraTxBytes = false;
+
+ uint8_t dummyData = g_lpspiDummyData[instance];
+
+ edma_transfer_config_t transferConfigRx;
+ edma_transfer_config_t transferConfigTx;
+
+ edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
+ edma_tcd_t *softwareTCD_pcsContinuous = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[2]) & (~0x1FU));
+
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+
+ handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
+ handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
+
+ handle->txBuffIfNull =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+
+ /*The TX and RX FIFO sizes are always the same*/
+ handle->fifoSize = LPSPI_GetRxFifoSize(base);
+
+ handle->isPcsContinuous = (bool)(transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous);
+ handle->isByteSwap = (bool)(transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap);
+ isPcsContinuous = handle->isPcsContinuous;
+ isByteSwap = handle->isByteSwap;
+
+ LPSPI_SetFifoWatermarks(base, txWatermark, rxWatermark);
+
+ /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ LPSPI_Enable(base, false);
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+ /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
+ temp = base->CFGR1;
+ temp &= LPSPI_CFGR1_PINCFG_MASK;
+ if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
+ {
+ if (NULL == handle->txData)
+ {
+ base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
+ }
+ /* The 3-wire mode can't send and receive data at the same time. */
+ if ((handle->txData != NULL) && (handle->rxData != NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+ }
+
+ LPSPI_Enable(base, true);
+
+ /*Flush FIFO , clear status , disable all the inerrupts.*/
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ /* For DMA transfer , we'd better not masked the transmit data and receive data in TCR since the transfer flow is
+ * hard to controlled by software.
+ */
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_PCS_MASK)) |
+ LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(0U) | LPSPI_TCR_BYSW(isByteSwap) |
+ LPSPI_TCR_PCS(whichPcs);
+
+ isThereExtraTxBytes = false;
+ handle->isThereExtraRxBytes = false;
+
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)bytesPerFrame;
+
+ handle->bytesLastRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+
+ handle->bytesLastRead = 4U;
+
+ if ((transfer->dataSize % 4U) != 0U)
+ {
+ bytesLastWrite = (uint8_t)(transfer->dataSize % 4U);
+ handle->bytesLastRead = bytesLastWrite;
+
+ isThereExtraTxBytes = true;
+
+ --handle->writeRegRemainingTimes;
+
+ --handle->readRegRemainingTimes;
+ handle->isThereExtraRxBytes = true;
+ }
+ }
+
+ LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiMasterCallback,
+ &s_lpspiMasterEdmaPrivateHandle[instance]);
+
+ /*Rx*/
+ EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
+
+ if (handle->rxData != NULL)
+ {
+ transferConfigRx.destAddr = (uint32_t) & (handle->rxData[0]);
+ transferConfigRx.destOffset = 1;
+ }
+ else
+ {
+ transferConfigRx.destAddr = (uint32_t) & (handle->rxBuffIfNull);
+ transferConfigRx.destOffset = 0;
+ }
+ transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
+
+ dif = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ dif = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigRx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ dif = 2;
+ }
+ break;
+
+ case (4U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigRx.minorLoopBytes = 4;
+ break;
+
+ default:
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigRx.srcAddr = (uint32_t)rxAddr + dif;
+ transferConfigRx.srcOffset = 0;
+
+ transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPSPI handle */
+ handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
+
+ EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &transferConfigRx, NULL);
+ EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ (uint32_t)kEDMA_MajorInterruptEnable);
+
+ /*Tx*/
+ EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
+
+ if (isThereExtraTxBytes)
+ {
+ if (handle->txData != NULL)
+ {
+ transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
+ transferConfigTx.srcOffset = 1;
+ }
+ else
+ {
+ transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull);
+ transferConfigTx.srcOffset = 0;
+ }
+
+ transferConfigTx.destOffset = 0;
+
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+
+ dif = 0;
+ switch (bytesLastWrite)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ dif = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ dif = 2;
+ }
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + dif;
+ transferConfigTx.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD_extraBytes);
+
+ if (handle->isPcsContinuous)
+ {
+ EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, softwareTCD_pcsContinuous);
+ }
+ else
+ {
+ EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
+ }
+ }
+
+ if (handle->isPcsContinuous)
+ {
+ handle->transmitCommand = base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK);
+
+ transferConfigTx.srcAddr = (uint32_t) & (handle->transmitCommand);
+ transferConfigTx.srcOffset = 0;
+
+ transferConfigTx.destAddr = (uint32_t) & (base->TCR);
+ transferConfigTx.destOffset = 0;
+
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigTx.minorLoopBytes = 4;
+ transferConfigTx.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD_pcsContinuous);
+ EDMA_TcdSetTransferConfig(softwareTCD_pcsContinuous, &transferConfigTx, NULL);
+ }
+
+ if (handle->txData != NULL)
+ {
+ transferConfigTx.srcAddr = (uint32_t)(handle->txData);
+ transferConfigTx.srcOffset = 1;
+ }
+ else
+ {
+ transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull);
+ transferConfigTx.srcOffset = 0;
+ }
+
+ transferConfigTx.destOffset = 0;
+
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+
+ dif = 0U;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ dif = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+
+ if (handle->isByteSwap)
+ {
+ dif = 2;
+ }
+ break;
+
+ case (4U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigTx.minorLoopBytes = 4;
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + dif;
+
+ transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
+
+ if (isThereExtraTxBytes)
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, softwareTCD_extraBytes);
+ }
+ else if (handle->isPcsContinuous)
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, softwareTCD_pcsContinuous);
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, NULL);
+ }
+
+ EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
+ EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
+
+ LPSPI_EnableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ return kStatus_Success;
+}
+
+static void EDMA_LpspiMasterCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds)
+{
+ assert(edmaHandle);
+ assert(g_lpspiEdmaPrivateHandle);
+
+ uint32_t readData;
+
+ lpspi_master_edma_private_handle_t *lpspiEdmaPrivateHandle;
+
+ lpspiEdmaPrivateHandle = (lpspi_master_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
+
+ size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
+ uint8_t bytesLastRead = lpspiEdmaPrivateHandle->handle->bytesLastRead;
+ bool isByteSwap = lpspiEdmaPrivateHandle->handle->isByteSwap;
+
+ LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
+
+ if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
+ {
+ while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
+ {
+ }
+ readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
+
+ if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
+ {
+ LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
+ readData, bytesLastRead, isByteSwap);
+ }
+ }
+
+ lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
+
+ if (lpspiEdmaPrivateHandle->handle->callback != NULL)
+ {
+ lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
+ kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
+ }
+}
+
+/*!
+ * brief LPSPI master aborts a transfer which is using eDMA.
+ *
+ * This function aborts a transfer which is using eDMA.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ */
+void LPSPI_MasterTransferAbortEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle)
+{
+ assert(handle);
+
+ LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
+ EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+}
+
+/*!
+ * brief Gets the master eDMA transfer remaining bytes.
+ *
+ * This function gets the master eDMA transfer remaining bytes.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_master_edma_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the EDMA transaction.
+ * return status of status_t.
+ */
+status_t LPSPI_MasterTransferGetCountEDMA(LPSPI_Type *base, lpspi_master_edma_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != (uint8_t)kLPSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t remainingByte;
+
+ remainingByte =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
+ handle->edmaRxRegToRxDataHandle->channel);
+
+ *count = handle->totalByteCount - remainingByte;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the LPSPI slave eDMA handle.
+ *
+ * This function initializes the LPSPI eDMA handle which can be used for other LPSPI transactional APIs. Usually, for a
+ * specified LPSPI instance, call this API once to get the initialized handle.
+ *
+ * Note that LPSPI eDMA has a separated (Rx and Tx as two sources) or shared (Rx and Tx as the same source) DMA request
+ * source.
+ *
+ * (1) For a separated DMA request source, enable and set the Rx DMAMUX source for edmaRxRegToRxDataHandle and
+ * Tx DMAMUX source for edmaTxDataToTxRegHandle.
+ * (2) For a shared DMA request source, enable and set the Rx/Rx DMAMUX source for edmaRxRegToRxDataHandle .
+ *
+ * param base LPSPI peripheral base address.
+ * param handle LPSPI handle pointer to lpspi_slave_edma_handle_t.
+ * param callback LPSPI callback.
+ * param userData callback function parameter.
+ * param edmaRxRegToRxDataHandle edmaRxRegToRxDataHandle pointer to edma_handle_t.
+ * param edmaTxDataToTxRegHandle edmaTxDataToTxRegHandle pointer to edma_handle_t.
+ */
+void LPSPI_SlaveTransferCreateHandleEDMA(LPSPI_Type *base,
+ lpspi_slave_edma_handle_t *handle,
+ lpspi_slave_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *edmaRxRegToRxDataHandle,
+ edma_handle_t *edmaTxDataToTxRegHandle)
+{
+ assert(handle);
+ assert(edmaRxRegToRxDataHandle);
+ assert(edmaTxDataToTxRegHandle);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ uint32_t instance = LPSPI_GetInstance(base);
+
+ s_lpspiSlaveEdmaPrivateHandle[instance].base = base;
+ s_lpspiSlaveEdmaPrivateHandle[instance].handle = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+ handle->edmaRxRegToRxDataHandle = edmaRxRegToRxDataHandle;
+ handle->edmaTxDataToTxRegHandle = edmaTxDataToTxRegHandle;
+}
+
+/*!
+ * brief LPSPI slave transfers data using eDMA.
+ *
+ * This function transfers data using eDMA. This is a non-blocking function, which return right away. When all data
+ * is transferred, the callback function is called.
+ *
+ * Note:
+ * The transfer data size should be an integer multiple of bytesPerFrame if bytesPerFrame is less than or equal to 4.
+ * For bytesPerFrame greater than 4:
+ * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4.
+ * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ * param transfer pointer to lpspi_transfer_t structure.
+ * return status of status_t.
+ */
+status_t LPSPI_SlaveTransferEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, lpspi_transfer_t *transfer)
+{
+ assert(handle);
+ assert(transfer);
+
+ uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U;
+ uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U;
+ uint32_t temp = 0U;
+ bool isByteSwap;
+
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+
+ if (!LPSPI_CheckTransferArgument(transfer, bitsPerFrame, bytesPerFrame))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /*And since the dma transfer can not support 3 bytes .*/
+ if ((bytesPerFrame % 4U) == 3U)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+
+ handle->state = (uint8_t)kLPSPI_Busy;
+
+ uint32_t rxAddr = LPSPI_GetRxRegisterAddress(base);
+ uint32_t txAddr = LPSPI_GetTxRegisterAddress(base);
+
+ edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
+
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+
+ /*Because DMA is fast enough , so set the RX and TX watermarks to 0 .*/
+ uint8_t txWatermark = 0;
+ uint8_t rxWatermark = 0;
+
+ /*Used for byte swap*/
+ uint32_t dif = 0;
+
+ uint8_t bytesLastWrite = 0;
+
+ uint32_t instance = LPSPI_GetInstance(base);
+
+ edma_transfer_config_t transferConfigRx;
+ edma_transfer_config_t transferConfigTx;
+
+ bool isThereExtraTxBytes = false;
+
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+
+ handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U);
+ handle->readRegRemainingTimes = handle->writeRegRemainingTimes;
+
+ handle->txBuffIfNull =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+
+ /*The TX and RX FIFO sizes are always the same*/
+ handle->fifoSize = LPSPI_GetRxFifoSize(base);
+
+ handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ isByteSwap = handle->isByteSwap;
+
+ LPSPI_SetFifoWatermarks(base, txWatermark, rxWatermark);
+
+ /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ LPSPI_Enable(base, false);
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+ /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
+ temp = base->CFGR1;
+ temp &= LPSPI_CFGR1_PINCFG_MASK;
+ if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
+ {
+ if (NULL == handle->txData)
+ {
+ base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
+ }
+ /* The 3-wire mode can't send and receive data at the same time. */
+ if ((handle->txData != NULL) && (handle->rxData != NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+ }
+
+ LPSPI_Enable(base, true);
+
+ /*Flush FIFO , clear status , disable all the inerrupts.*/
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ /* For DMA transfer , we'd better not masked the transmit data and receive data in TCR since the transfer flow is
+ * hard to controlled by software.
+ */
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK)) |
+ LPSPI_TCR_CONTC(0U) | LPSPI_TCR_BYSW(isByteSwap) | LPSPI_TCR_PCS(whichPcs);
+
+ isThereExtraTxBytes = false;
+ handle->isThereExtraRxBytes = false;
+
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)bytesPerFrame;
+
+ handle->bytesLastRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+
+ handle->bytesLastRead = 4U;
+
+ if ((transfer->dataSize % 4U) != 0U)
+ {
+ bytesLastWrite = (uint8_t)(transfer->dataSize % 4U);
+ handle->bytesLastRead = bytesLastWrite;
+
+ isThereExtraTxBytes = true;
+ --handle->writeRegRemainingTimes;
+
+ handle->isThereExtraRxBytes = true;
+ --handle->readRegRemainingTimes;
+ }
+ }
+
+ LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiSlaveCallback,
+ &s_lpspiSlaveEdmaPrivateHandle[instance]);
+
+ /*Rx*/
+ if (handle->readRegRemainingTimes > 0U)
+ {
+ EDMA_ResetChannel(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel);
+
+ if (handle->rxData != NULL)
+ {
+ transferConfigRx.destAddr = (uint32_t) & (handle->rxData[0]);
+ transferConfigRx.destOffset = 1;
+ }
+ else
+ {
+ transferConfigRx.destAddr = (uint32_t) & (handle->rxBuffIfNull);
+ transferConfigRx.destOffset = 0;
+ }
+ transferConfigRx.destTransferSize = kEDMA_TransferSize1Bytes;
+
+ dif = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ dif = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigRx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ dif = 2;
+ }
+ break;
+
+ case (4U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigRx.minorLoopBytes = 4;
+ break;
+
+ default:
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigRx.srcAddr = (uint32_t)rxAddr + dif;
+ transferConfigRx.srcOffset = 0;
+
+ transferConfigRx.majorLoopCounts = handle->readRegRemainingTimes;
+
+ /* Store the initially configured eDMA minor byte transfer count into the DSPI handle */
+ handle->nbytes = (uint8_t)transferConfigRx.minorLoopBytes;
+
+ EDMA_SetTransferConfig(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ &transferConfigRx, NULL);
+ EDMA_EnableChannelInterrupts(handle->edmaRxRegToRxDataHandle->base, handle->edmaRxRegToRxDataHandle->channel,
+ (uint32_t)kEDMA_MajorInterruptEnable);
+ }
+
+ /*Tx*/
+ EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
+
+ if (isThereExtraTxBytes)
+ {
+ if (handle->txData != NULL)
+ {
+ transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
+ transferConfigTx.srcOffset = 1;
+ }
+ else
+ {
+ transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull);
+ transferConfigTx.srcOffset = 0;
+ }
+
+ transferConfigTx.destOffset = 0;
+
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+
+ dif = 0;
+ switch (bytesLastWrite)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ dif = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ dif = 2;
+ }
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + dif;
+ transferConfigTx.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD_extraBytes);
+
+ EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
+ }
+
+ if (handle->txData != NULL)
+ {
+ transferConfigTx.srcAddr = (uint32_t)(handle->txData);
+ transferConfigTx.srcOffset = 1;
+ }
+ else
+ {
+ transferConfigTx.srcAddr = (uint32_t)(&handle->txBuffIfNull);
+ transferConfigTx.srcOffset = 0;
+ }
+
+ transferConfigTx.destOffset = 0;
+
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+
+ dif = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ dif = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+
+ if (handle->isByteSwap)
+ {
+ dif = 2;
+ }
+ break;
+
+ case (4U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize4Bytes;
+ transferConfigTx.minorLoopBytes = 4;
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + dif;
+
+ transferConfigTx.majorLoopCounts = handle->writeRegRemainingTimes;
+
+ if (isThereExtraTxBytes)
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, softwareTCD_extraBytes);
+ }
+ else
+ {
+ EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
+ &transferConfigTx, NULL);
+ }
+
+ EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
+ EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
+
+ LPSPI_EnableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ return kStatus_Success;
+}
+
+static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds)
+{
+ assert(edmaHandle);
+ assert(g_lpspiEdmaPrivateHandle);
+
+ uint32_t readData;
+
+ lpspi_slave_edma_private_handle_t *lpspiEdmaPrivateHandle;
+
+ lpspiEdmaPrivateHandle = (lpspi_slave_edma_private_handle_t *)g_lpspiEdmaPrivateHandle;
+
+ size_t rxRemainingByteCount = lpspiEdmaPrivateHandle->handle->rxRemainingByteCount;
+ uint8_t bytesLastRead = lpspiEdmaPrivateHandle->handle->bytesLastRead;
+ bool isByteSwap = lpspiEdmaPrivateHandle->handle->isByteSwap;
+
+ LPSPI_DisableDMA(lpspiEdmaPrivateHandle->base, (uint32_t)kLPSPI_TxDmaEnable | (uint32_t)kLPSPI_RxDmaEnable);
+
+ if (lpspiEdmaPrivateHandle->handle->isThereExtraRxBytes)
+ {
+ while (LPSPI_GetRxFifoCount(lpspiEdmaPrivateHandle->base) == 0U)
+ {
+ }
+ readData = LPSPI_ReadData(lpspiEdmaPrivateHandle->base);
+
+ if (lpspiEdmaPrivateHandle->handle->rxData != NULL)
+ {
+ LPSPI_SeparateEdmaReadData(&(lpspiEdmaPrivateHandle->handle->rxData[rxRemainingByteCount - bytesLastRead]),
+ readData, bytesLastRead, isByteSwap);
+ }
+ }
+
+ lpspiEdmaPrivateHandle->handle->state = (uint8_t)kLPSPI_Idle;
+
+ if (lpspiEdmaPrivateHandle->handle->callback != NULL)
+ {
+ lpspiEdmaPrivateHandle->handle->callback(lpspiEdmaPrivateHandle->base, lpspiEdmaPrivateHandle->handle,
+ kStatus_Success, lpspiEdmaPrivateHandle->handle->userData);
+ }
+}
+
+/*!
+ * brief LPSPI slave aborts a transfer which is using eDMA.
+ *
+ * This function aborts a transfer which is using eDMA.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ */
+void LPSPI_SlaveTransferAbortEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle)
+{
+ assert(handle);
+
+ LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+
+ EDMA_AbortTransfer(handle->edmaRxRegToRxDataHandle);
+ EDMA_AbortTransfer(handle->edmaTxDataToTxRegHandle);
+
+ handle->state = (uint8_t)kLPSPI_Idle;
+}
+
+/*!
+ * brief Gets the slave eDMA transfer remaining bytes.
+ *
+ * This function gets the slave eDMA transfer remaining bytes.
+ *
+ * param base LPSPI peripheral base address.
+ * param handle pointer to lpspi_slave_edma_handle_t structure which stores the transfer state.
+ * param count Number of bytes transferred so far by the eDMA transaction.
+ * return status of status_t.
+ */
+status_t LPSPI_SlaveTransferGetCountEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, size_t *count)
+{
+ assert(handle);
+
+ if (NULL == count)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Catch when there is not an active transfer. */
+ if (handle->state != (uint8_t)kLPSPI_Busy)
+ {
+ *count = 0;
+ return kStatus_NoTransferInProgress;
+ }
+
+ size_t remainingByte;
+
+ remainingByte =
+ (uint32_t)handle->nbytes * EDMA_GetRemainingMajorLoopCount(handle->edmaRxRegToRxDataHandle->base,
+ handle->edmaRxRegToRxDataHandle->channel);
+
+ *count = handle->totalByteCount - remainingByte;
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpuart.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpuart.c
new file mode 100644
index 0000000000..379fd8aec0
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpuart.c
@@ -0,0 +1,2051 @@
+/*
+ * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpuart.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpuart"
+#endif
+
+/* LPUART transfer state. */
+enum
+{
+ kLPUART_TxIdle, /*!< TX idle. */
+ kLPUART_TxBusy, /*!< TX busy. */
+ kLPUART_RxIdle, /*!< RX idle. */
+ kLPUART_RxBusy /*!< RX busy. */
+};
+
+/* Typedef for interrupt handler. */
+typedef void (*lpuart_isr_t)(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Check whether the RX ring buffer is full.
+ *
+ * @userData handle LPUART handle pointer.
+ * @retval true RX ring buffer is full.
+ * @retval false RX ring buffer is not full.
+ */
+static bool LPUART_TransferIsRxRingBufferFull(LPUART_Type *base, lpuart_handle_t *handle);
+
+/*!
+ * @brief Write to TX register using non-blocking method.
+ *
+ * This function writes data to the TX register directly, upper layer must make
+ * sure the TX register is empty or TX FIFO has empty room before calling this function.
+ *
+ * @note This function does not check whether all the data has been sent out to bus,
+ * so before disable TX, check kLPUART_TransmissionCompleteFlag to ensure the TX is
+ * finished.
+ *
+ * @param base LPUART peripheral base address.
+ * @param data Start address of the data to write.
+ * @param length Size of the buffer to be sent.
+ */
+static void LPUART_WriteNonBlocking(LPUART_Type *base, const uint8_t *data, size_t length);
+
+/*!
+ * @brief Read RX register using non-blocking method.
+ *
+ * This function reads data from the TX register directly, upper layer must make
+ * sure the RX register is full or TX FIFO has data before calling this function.
+ *
+ * @param base LPUART peripheral base address.
+ * @param data Start address of the buffer to store the received data.
+ * @param length Size of the buffer.
+ */
+static void LPUART_ReadNonBlocking(LPUART_Type *base, uint8_t *data, size_t length);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Array of LPUART peripheral base address. */
+static LPUART_Type *const s_lpuartBases[] = LPUART_BASE_PTRS;
+/* Array of LPUART handle. */
+static lpuart_handle_t *s_lpuartHandle[ARRAY_SIZE(s_lpuartBases)];
+/* Array of LPUART IRQ number. */
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+static const IRQn_Type s_lpuartRxIRQ[] = LPUART_RX_IRQS;
+static const IRQn_Type s_lpuartTxIRQ[] = LPUART_TX_IRQS;
+#else
+static const IRQn_Type s_lpuartIRQ[] = LPUART_RX_TX_IRQS;
+#endif
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of LPUART clock name. */
+static const clock_ip_name_t s_lpuartClock[] = LPUART_CLOCKS;
+
+#if defined(LPUART_PERIPH_CLOCKS)
+/* Array of LPUART functional clock name. */
+static const clock_ip_name_t s_lpuartPeriphClocks[] = LPUART_PERIPH_CLOCKS;
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/* LPUART ISR for transactional APIs. */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+static lpuart_isr_t s_lpuartIsr = (lpuart_isr_t)DefaultISR;
+#else
+static lpuart_isr_t s_lpuartIsr;
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief Get the LPUART instance from peripheral base address.
+ *
+ * param base LPUART peripheral base address.
+ * return LPUART instance.
+ */
+uint32_t LPUART_GetInstance(LPUART_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0U; instance < ARRAY_SIZE(s_lpuartBases); instance++)
+ {
+ if (s_lpuartBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_lpuartBases));
+
+ return instance;
+}
+
+/*!
+ * brief Get the length of received data in RX ring buffer.
+ *
+ * userData handle LPUART handle pointer.
+ * return Length of received data in RX ring buffer.
+ */
+size_t LPUART_TransferGetRxRingBufferLength(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ size_t size;
+ size_t tmpRxRingBufferSize = handle->rxRingBufferSize;
+ uint16_t tmpRxRingBufferTail = handle->rxRingBufferTail;
+ uint16_t tmpRxRingBufferHead = handle->rxRingBufferHead;
+
+ if (tmpRxRingBufferTail > tmpRxRingBufferHead)
+ {
+ size = ((size_t)tmpRxRingBufferHead + tmpRxRingBufferSize - (size_t)tmpRxRingBufferTail);
+ }
+ else
+ {
+ size = ((size_t)tmpRxRingBufferHead - (size_t)tmpRxRingBufferTail);
+ }
+
+ return size;
+}
+
+static bool LPUART_TransferIsRxRingBufferFull(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ bool full;
+
+ if (LPUART_TransferGetRxRingBufferLength(base, handle) == (handle->rxRingBufferSize - 1U))
+ {
+ full = true;
+ }
+ else
+ {
+ full = false;
+ }
+ return full;
+}
+
+static void LPUART_WriteNonBlocking(LPUART_Type *base, const uint8_t *data, size_t length)
+{
+ assert(NULL != data);
+
+ size_t i;
+
+ /* The Non Blocking write data API assume user have ensured there is enough space in
+ peripheral to write. */
+ for (i = 0; i < length; i++)
+ {
+ base->DATA = data[i];
+ }
+}
+
+static void LPUART_ReadNonBlocking(LPUART_Type *base, uint8_t *data, size_t length)
+{
+ assert(NULL != data);
+
+ size_t i;
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ uint32_t ctrl = base->CTRL;
+ bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) ||
+ (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U)));
+#endif
+
+ /* The Non Blocking read data API assume user have ensured there is enough space in
+ peripheral to write. */
+ for (i = 0; i < length; i++)
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ if (isSevenDataBits)
+ {
+ data[i] = (uint8_t)(base->DATA & 0x7FU);
+ }
+ else
+ {
+ data[i] = (uint8_t)base->DATA;
+ }
+#else
+ data[i] = (uint8_t)(base->DATA);
+#endif
+ }
+}
+
+/*!
+ * brief Initializes an LPUART instance with the user configuration structure and the peripheral clock.
+ *
+ * This function configures the LPUART module with user-defined settings. Call the LPUART_GetDefaultConfig() function
+ * to configure the configuration structure and get the default configuration.
+ * The example below shows how to use this API to configure the LPUART.
+ * code
+ * lpuart_config_t lpuartConfig;
+ * lpuartConfig.baudRate_Bps = 115200U;
+ * lpuartConfig.parityMode = kLPUART_ParityDisabled;
+ * lpuartConfig.dataBitsCount = kLPUART_EightDataBits;
+ * lpuartConfig.isMsb = false;
+ * lpuartConfig.stopBitCount = kLPUART_OneStopBit;
+ * lpuartConfig.txFifoWatermark = 0;
+ * lpuartConfig.rxFifoWatermark = 1;
+ * LPUART_Init(LPUART1, &lpuartConfig, 20000000U);
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * param config Pointer to a user-defined configuration structure.
+ * param srcClock_Hz LPUART clock source frequency in HZ.
+ * retval kStatus_LPUART_BaudrateNotSupport Baudrate is not support in current clock source.
+ * retval kStatus_Success LPUART initialize succeed
+ */
+status_t LPUART_Init(LPUART_Type *base, const lpuart_config_t *config, uint32_t srcClock_Hz)
+{
+ assert(NULL != config);
+ assert(0U < config->baudRate_Bps);
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ assert((uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) >= config->txFifoWatermark);
+ assert((uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) >= config->rxFifoWatermark);
+#endif
+
+ status_t status = kStatus_Success;
+ uint32_t temp;
+ uint16_t sbr, sbrTemp;
+ uint8_t osr, osrTemp;
+ uint32_t tempDiff, calculatedBaud, baudDiff;
+
+ /* This LPUART instantiation uses a slightly different baud rate calculation
+ * The idea is to use the best OSR (over-sampling rate) possible
+ * Note, OSR is typically hard-set to 16 in other LPUART instantiations
+ * loop to find the best OSR value possible, one that generates minimum baudDiff
+ * iterate through the rest of the supported values of OSR */
+
+ baudDiff = config->baudRate_Bps;
+ osr = 0U;
+ sbr = 0U;
+ for (osrTemp = 4U; osrTemp <= 32U; osrTemp++)
+ {
+ /* calculate the temporary sbr value */
+ sbrTemp = (uint16_t)((srcClock_Hz * 10U / (config->baudRate_Bps * (uint32_t)osrTemp) + 5U) / 10U);
+ /*set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate*/
+ if (sbrTemp == 0U)
+ {
+ sbrTemp = 1U;
+ }
+ /* Calculate the baud rate based on the temporary OSR and SBR values */
+ calculatedBaud = (srcClock_Hz / ((uint32_t)osrTemp * (uint32_t)sbrTemp));
+ tempDiff = calculatedBaud > config->baudRate_Bps ? (calculatedBaud - config->baudRate_Bps) :
+ (config->baudRate_Bps - calculatedBaud);
+
+ if (tempDiff <= baudDiff)
+ {
+ baudDiff = tempDiff;
+ osr = osrTemp; /* update and store the best OSR value calculated */
+ sbr = sbrTemp; /* update store the best SBR value calculated */
+ }
+ }
+
+ /* Check to see if actual baud rate is within 3% of desired baud rate
+ * based on the best calculate OSR value */
+ if (baudDiff > ((config->baudRate_Bps / 100U) * 3U))
+ {
+ /* Unacceptable baud rate difference of more than 3%*/
+ status = kStatus_LPUART_BaudrateNotSupport;
+ }
+ else
+ {
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+
+ uint32_t instance = LPUART_GetInstance(base);
+
+ /* Enable lpuart clock */
+ CLOCK_EnableClock(s_lpuartClock[instance]);
+#if defined(LPUART_PERIPH_CLOCKS)
+ CLOCK_EnableClock(s_lpuartPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_LPUART_HAS_GLOBAL) && FSL_FEATURE_LPUART_HAS_GLOBAL
+ /*Reset all internal logic and registers, except the Global Register */
+ LPUART_SoftwareReset(base);
+#else
+ /* Disable LPUART TX RX before setting. */
+ base->CTRL &= ~(LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK);
+#endif
+
+ temp = base->BAUD;
+
+ /* Acceptable baud rate, check if OSR is between 4x and 7x oversampling.
+ * If so, then "BOTHEDGE" sampling must be turned on */
+ if ((osr > 3U) && (osr < 8U))
+ {
+ temp |= LPUART_BAUD_BOTHEDGE_MASK;
+ }
+
+ /* program the osr value (bit value is one less than actual value) */
+ temp &= ~LPUART_BAUD_OSR_MASK;
+ temp |= LPUART_BAUD_OSR((uint32_t)osr - 1UL);
+
+ /* write the sbr value to the BAUD registers */
+ temp &= ~LPUART_BAUD_SBR_MASK;
+ base->BAUD = temp | LPUART_BAUD_SBR(sbr);
+
+ /* Set bit count and parity mode. */
+ base->BAUD &= ~LPUART_BAUD_M10_MASK;
+
+ temp = base->CTRL & ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK | LPUART_CTRL_ILT_MASK |
+ LPUART_CTRL_IDLECFG_MASK);
+
+ temp |= (uint8_t)config->parityMode | LPUART_CTRL_IDLECFG(config->rxIdleConfig) |
+ LPUART_CTRL_ILT(config->rxIdleType);
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ if (kLPUART_SevenDataBits == config->dataBitsCount)
+ {
+ if (kLPUART_ParityDisabled != config->parityMode)
+ {
+ temp &= ~LPUART_CTRL_M7_MASK; /* Seven data bits and one parity bit */
+ }
+ else
+ {
+ temp |= LPUART_CTRL_M7_MASK;
+ }
+ }
+ else
+#endif
+ {
+ if (kLPUART_ParityDisabled != config->parityMode)
+ {
+ temp |= LPUART_CTRL_M_MASK; /* Eight data bits and one parity bit */
+ }
+ }
+
+ base->CTRL = temp;
+
+#if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
+ /* set stop bit per char */
+ temp = base->BAUD & ~LPUART_BAUD_SBNS_MASK;
+ base->BAUD = temp | LPUART_BAUD_SBNS((uint8_t)config->stopBitCount);
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Set tx/rx WATER watermark
+ Note:
+ Take care of the RX FIFO, RX interrupt request only assert when received bytes
+ equal or more than RX water mark, there is potential issue if RX water
+ mark larger than 1.
+ For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
+ 5 bytes are received. the last byte will be saved in FIFO but not trigger
+ RX interrupt because the water mark is 2.
+ */
+ base->WATER = (((uint32_t)(config->rxFifoWatermark) << 16U) | config->txFifoWatermark);
+
+ /* Enable tx/rx FIFO */
+ base->FIFO |= (LPUART_FIFO_TXFE_MASK | LPUART_FIFO_RXFE_MASK);
+
+ /* Flush FIFO */
+ base->FIFO |= (LPUART_FIFO_TXFLUSH_MASK | LPUART_FIFO_RXFLUSH_MASK);
+#endif
+
+ /* Clear all status flags */
+ temp = (LPUART_STAT_RXEDGIF_MASK | LPUART_STAT_IDLE_MASK | LPUART_STAT_OR_MASK | LPUART_STAT_NF_MASK |
+ LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK);
+
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ temp |= LPUART_STAT_LBKDIF_MASK;
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ temp |= (LPUART_STAT_MA1F_MASK | LPUART_STAT_MA2F_MASK);
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
+ /* Set the CTS configuration/TX CTS source. */
+ base->MODIR |= LPUART_MODIR_TXCTSC(config->txCtsConfig) | LPUART_MODIR_TXCTSSRC(config->txCtsSource);
+ if (true == config->enableRxRTS)
+ {
+ /* Enable the receiver RTS(request-to-send) function. */
+ base->MODIR |= LPUART_MODIR_RXRTSE_MASK;
+ }
+ if (true == config->enableTxCTS)
+ {
+ /* Enable the CTS(clear-to-send) function. */
+ base->MODIR |= LPUART_MODIR_TXCTSE_MASK;
+ }
+#endif
+
+ /* Set data bits order. */
+ if (true == config->isMsb)
+ {
+ temp |= LPUART_STAT_MSBF_MASK;
+ }
+ else
+ {
+ temp &= ~LPUART_STAT_MSBF_MASK;
+ }
+
+ base->STAT |= temp;
+
+ /* Enable TX/RX base on configure structure. */
+ temp = base->CTRL;
+ if (true == config->enableTx)
+ {
+ temp |= LPUART_CTRL_TE_MASK;
+ }
+
+ if (true == config->enableRx)
+ {
+ temp |= LPUART_CTRL_RE_MASK;
+ }
+
+ base->CTRL = temp;
+ }
+
+ return status;
+}
+/*!
+ * brief Deinitializes a LPUART instance.
+ *
+ * This function waits for transmit to complete, disables TX and RX, and disables the LPUART clock.
+ *
+ * param base LPUART peripheral base address.
+ */
+void LPUART_Deinit(LPUART_Type *base)
+{
+ uint32_t temp;
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Wait tx FIFO send out*/
+ while (0U != ((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXWATER_SHIFT))
+ {
+ }
+#endif
+ /* Wait last char shift out */
+ while (0U == (base->STAT & LPUART_STAT_TC_MASK))
+ {
+ }
+
+ /* Clear all status flags */
+ temp = (LPUART_STAT_RXEDGIF_MASK | LPUART_STAT_IDLE_MASK | LPUART_STAT_OR_MASK | LPUART_STAT_NF_MASK |
+ LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK);
+
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ temp |= LPUART_STAT_LBKDIF_MASK;
+#endif
+
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ temp |= (LPUART_STAT_MA1F_MASK | LPUART_STAT_MA2F_MASK);
+#endif
+
+ base->STAT |= temp;
+
+ /* Disable the module. */
+ base->CTRL = 0U;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = LPUART_GetInstance(base);
+
+ /* Disable lpuart clock */
+ CLOCK_DisableClock(s_lpuartClock[instance]);
+
+#if defined(LPUART_PERIPH_CLOCKS)
+ CLOCK_DisableClock(s_lpuartPeriphClocks[instance]);
+#endif
+
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the LPUART configuration structure to a default value. The default
+ * values are:
+ * lpuartConfig->baudRate_Bps = 115200U;
+ * lpuartConfig->parityMode = kLPUART_ParityDisabled;
+ * lpuartConfig->dataBitsCount = kLPUART_EightDataBits;
+ * lpuartConfig->isMsb = false;
+ * lpuartConfig->stopBitCount = kLPUART_OneStopBit;
+ * lpuartConfig->txFifoWatermark = 0;
+ * lpuartConfig->rxFifoWatermark = 1;
+ * lpuartConfig->rxIdleType = kLPUART_IdleTypeStartBit;
+ * lpuartConfig->rxIdleConfig = kLPUART_IdleCharacter1;
+ * lpuartConfig->enableTx = false;
+ * lpuartConfig->enableRx = false;
+ *
+ * param config Pointer to a configuration structure.
+ */
+void LPUART_GetDefaultConfig(lpuart_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->baudRate_Bps = 115200U;
+ config->parityMode = kLPUART_ParityDisabled;
+ config->dataBitsCount = kLPUART_EightDataBits;
+ config->isMsb = false;
+#if defined(FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT) && FSL_FEATURE_LPUART_HAS_STOP_BIT_CONFIG_SUPPORT
+ config->stopBitCount = kLPUART_OneStopBit;
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ config->txFifoWatermark = 0U;
+ config->rxFifoWatermark = 0U;
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT) && FSL_FEATURE_LPUART_HAS_MODEM_SUPPORT
+ config->enableRxRTS = false;
+ config->enableTxCTS = false;
+ config->txCtsConfig = kLPUART_CtsSampleAtStart;
+ config->txCtsSource = kLPUART_CtsSourcePin;
+#endif
+ config->rxIdleType = kLPUART_IdleTypeStartBit;
+ config->rxIdleConfig = kLPUART_IdleCharacter1;
+ config->enableTx = false;
+ config->enableRx = false;
+}
+
+/*!
+ * brief Sets the LPUART instance baudrate.
+ *
+ * This function configures the LPUART module baudrate. This function is used to update
+ * the LPUART module baudrate after the LPUART module is initialized by the LPUART_Init.
+ * code
+ * LPUART_SetBaudRate(LPUART1, 115200U, 20000000U);
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * param baudRate_Bps LPUART baudrate to be set.
+ * param srcClock_Hz LPUART clock source frequency in HZ.
+ * retval kStatus_LPUART_BaudrateNotSupport Baudrate is not supported in the current clock source.
+ * retval kStatus_Success Set baudrate succeeded.
+ */
+status_t LPUART_SetBaudRate(LPUART_Type *base, uint32_t baudRate_Bps, uint32_t srcClock_Hz)
+{
+ assert(0U < baudRate_Bps);
+
+ status_t status = kStatus_Success;
+ uint32_t temp, oldCtrl;
+ uint16_t sbr, sbrTemp;
+ uint8_t osr, osrTemp;
+ uint32_t tempDiff, calculatedBaud, baudDiff;
+
+ /* This LPUART instantiation uses a slightly different baud rate calculation
+ * The idea is to use the best OSR (over-sampling rate) possible
+ * Note, OSR is typically hard-set to 16 in other LPUART instantiations
+ * loop to find the best OSR value possible, one that generates minimum baudDiff
+ * iterate through the rest of the supported values of OSR */
+
+ baudDiff = baudRate_Bps;
+ osr = 0U;
+ sbr = 0U;
+ for (osrTemp = 4U; osrTemp <= 32U; osrTemp++)
+ {
+ /* calculate the temporary sbr value */
+ sbrTemp = (uint16_t)((srcClock_Hz * 10U / (baudRate_Bps * (uint32_t)osrTemp) + 5U) / 10U);
+ /*set sbrTemp to 1 if the sourceClockInHz can not satisfy the desired baud rate*/
+ if (sbrTemp == 0U)
+ {
+ sbrTemp = 1U;
+ }
+ /* Calculate the baud rate based on the temporary OSR and SBR values */
+ calculatedBaud = srcClock_Hz / ((uint32_t)osrTemp * (uint32_t)sbrTemp);
+
+ tempDiff = calculatedBaud > baudRate_Bps ? (calculatedBaud - baudRate_Bps) : (baudRate_Bps - calculatedBaud);
+
+ if (tempDiff <= baudDiff)
+ {
+ baudDiff = tempDiff;
+ osr = osrTemp; /* update and store the best OSR value calculated */
+ sbr = sbrTemp; /* update store the best SBR value calculated */
+ }
+ }
+
+ /* Check to see if actual baud rate is within 3% of desired baud rate
+ * based on the best calculate OSR value */
+ if (baudDiff < (uint32_t)((baudRate_Bps / 100U) * 3U))
+ {
+ /* Store CTRL before disable Tx and Rx */
+ oldCtrl = base->CTRL;
+
+ /* Disable LPUART TX RX before setting. */
+ base->CTRL &= ~(LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK);
+
+ temp = base->BAUD;
+
+ /* Acceptable baud rate, check if OSR is between 4x and 7x oversampling.
+ * If so, then "BOTHEDGE" sampling must be turned on */
+ if ((osr > 3U) && (osr < 8U))
+ {
+ temp |= LPUART_BAUD_BOTHEDGE_MASK;
+ }
+
+ /* program the osr value (bit value is one less than actual value) */
+ temp &= ~LPUART_BAUD_OSR_MASK;
+ temp |= LPUART_BAUD_OSR((uint32_t)osr - 1UL);
+
+ /* write the sbr value to the BAUD registers */
+ temp &= ~LPUART_BAUD_SBR_MASK;
+ base->BAUD = temp | LPUART_BAUD_SBR(sbr);
+
+ /* Restore CTRL. */
+ base->CTRL = oldCtrl;
+ }
+ else
+ {
+ /* Unacceptable baud rate difference of more than 3%*/
+ status = kStatus_LPUART_BaudrateNotSupport;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Enables LPUART interrupts according to a provided mask.
+ *
+ * This function enables the LPUART interrupts according to a provided mask. The mask
+ * is a logical OR of enumeration members. See the ref _lpuart_interrupt_enable.
+ * This examples shows how to enable TX empty interrupt and RX full interrupt:
+ * code
+ * LPUART_EnableInterrupts(LPUART1,kLPUART_TxDataRegEmptyInterruptEnable | kLPUART_RxDataRegFullInterruptEnable);
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * param mask The interrupts to enable. Logical OR of ref _uart_interrupt_enable.
+ */
+void LPUART_EnableInterrupts(LPUART_Type *base, uint32_t mask)
+{
+ base->BAUD |= ((mask << 8U) & (LPUART_BAUD_LBKDIE_MASK | LPUART_BAUD_RXEDGIE_MASK));
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ base->FIFO = (base->FIFO & ~(LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) |
+ ((mask << 8U) & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK));
+#endif
+ mask &= 0xFFFFFF00U;
+ base->CTRL |= mask;
+}
+
+/*!
+ * brief Disables LPUART interrupts according to a provided mask.
+ *
+ * This function disables the LPUART interrupts according to a provided mask. The mask
+ * is a logical OR of enumeration members. See ref _lpuart_interrupt_enable.
+ * This example shows how to disable the TX empty interrupt and RX full interrupt:
+ * code
+ * LPUART_DisableInterrupts(LPUART1,kLPUART_TxDataRegEmptyInterruptEnable | kLPUART_RxDataRegFullInterruptEnable);
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * param mask The interrupts to disable. Logical OR of ref _lpuart_interrupt_enable.
+ */
+void LPUART_DisableInterrupts(LPUART_Type *base, uint32_t mask)
+{
+ base->BAUD &= ~((mask << 8U) & (LPUART_BAUD_LBKDIE_MASK | LPUART_BAUD_RXEDGIE_MASK));
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ base->FIFO = (base->FIFO & ~(LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) &
+ ~((mask << 8U) & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK));
+#endif
+ mask &= 0xFFFFFF00U;
+ base->CTRL &= ~mask;
+}
+
+/*!
+ * brief Gets enabled LPUART interrupts.
+ *
+ * This function gets the enabled LPUART interrupts. The enabled interrupts are returned
+ * as the logical OR value of the enumerators ref _lpuart_interrupt_enable. To check
+ * a specific interrupt enable status, compare the return value with enumerators
+ * in ref _lpuart_interrupt_enable.
+ * For example, to check whether the TX empty interrupt is enabled:
+ * code
+ * uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(LPUART1);
+ *
+ * if (kLPUART_TxDataRegEmptyInterruptEnable & enabledInterrupts)
+ * {
+ * ...
+ * }
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * return LPUART interrupt flags which are logical OR of the enumerators in ref _lpuart_interrupt_enable.
+ */
+uint32_t LPUART_GetEnabledInterrupts(LPUART_Type *base)
+{
+ uint32_t temp;
+ temp = (base->BAUD & (LPUART_BAUD_LBKDIE_MASK | LPUART_BAUD_RXEDGIE_MASK)) >> 8U;
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ temp |= (base->FIFO & (LPUART_FIFO_TXOFE_MASK | LPUART_FIFO_RXUFE_MASK)) >> 8U;
+#endif
+ temp |= (uint32_t)(base->CTRL & 0xFF0C000u);
+
+ return temp;
+}
+
+/*!
+ * brief Gets LPUART status flags.
+ *
+ * This function gets all LPUART status flags. The flags are returned as the logical
+ * OR value of the enumerators ref _lpuart_flags. To check for a specific status,
+ * compare the return value with enumerators in the ref _lpuart_flags.
+ * For example, to check whether the TX is empty:
+ * code
+ * if (kLPUART_TxDataRegEmptyFlag & LPUART_GetStatusFlags(LPUART1))
+ * {
+ * ...
+ * }
+ * endcode
+ *
+ * param base LPUART peripheral base address.
+ * return LPUART status flags which are ORed by the enumerators in the _lpuart_flags.
+ */
+uint32_t LPUART_GetStatusFlags(LPUART_Type *base)
+{
+ uint32_t temp;
+ temp = base->STAT;
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ temp |= (base->FIFO &
+ (LPUART_FIFO_TXEMPT_MASK | LPUART_FIFO_RXEMPT_MASK | LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK)) >>
+ 16U;
+#endif
+ return temp;
+}
+
+/*!
+ * brief Clears status flags with a provided mask.
+ *
+ * This function clears LPUART status flags with a provided mask. Automatically cleared flags
+ * can't be cleared by this function.
+ * Flags that can only cleared or set by hardware are:
+ * kLPUART_TxDataRegEmptyFlag, kLPUART_TransmissionCompleteFlag, kLPUART_RxDataRegFullFlag,
+ * kLPUART_RxActiveFlag, kLPUART_NoiseErrorInRxDataRegFlag, kLPUART_ParityErrorInRxDataRegFlag,
+ * kLPUART_TxFifoEmptyFlag,kLPUART_RxFifoEmptyFlag
+ * Note: This API should be called when the Tx/Rx is idle, otherwise it takes no effects.
+ *
+ * param base LPUART peripheral base address.
+ * param mask the status flags to be cleared. The user can use the enumerators in the
+ * _lpuart_status_flag_t to do the OR operation and get the mask.
+ * return 0 succeed, others failed.
+ * retval kStatus_LPUART_FlagCannotClearManually The flag can't be cleared by this function but
+ * it is cleared automatically by hardware.
+ * retval kStatus_Success Status in the mask are cleared.
+ */
+status_t LPUART_ClearStatusFlags(LPUART_Type *base, uint32_t mask)
+{
+ uint32_t temp;
+ status_t status;
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ temp = (uint32_t)base->FIFO;
+ temp &= (uint32_t)(~(LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK));
+ temp |= (mask << 16U) & (LPUART_FIFO_TXOF_MASK | LPUART_FIFO_RXUF_MASK);
+ base->FIFO = temp;
+#endif
+ temp = (uint32_t)base->STAT;
+#if defined(FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT) && FSL_FEATURE_LPUART_HAS_LIN_BREAK_DETECT
+ temp &= (uint32_t)(~(LPUART_STAT_LBKDIF_MASK));
+ temp |= mask & LPUART_STAT_LBKDIF_MASK;
+#endif
+ temp &= (uint32_t)(~(LPUART_STAT_RXEDGIF_MASK | LPUART_STAT_IDLE_MASK | LPUART_STAT_OR_MASK | LPUART_STAT_NF_MASK |
+ LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK));
+ temp |= mask & (LPUART_STAT_RXEDGIF_MASK | LPUART_STAT_IDLE_MASK | LPUART_STAT_OR_MASK | LPUART_STAT_NF_MASK |
+ LPUART_STAT_FE_MASK | LPUART_STAT_PF_MASK);
+#if defined(FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING) && FSL_FEATURE_LPUART_HAS_ADDRESS_MATCHING
+ temp &= (uint32_t)(~(LPUART_STAT_MA2F_MASK | LPUART_STAT_MA1F_MASK));
+ temp |= mask & (LPUART_STAT_MA2F_MASK | LPUART_STAT_MA1F_MASK);
+#endif
+ base->STAT = temp;
+ /* If some flags still pending. */
+ if (0U != (mask & LPUART_GetStatusFlags(base)))
+ {
+ /* Some flags can only clear or set by the hardware itself, these flags are: kLPUART_TxDataRegEmptyFlag,
+ kLPUART_TransmissionCompleteFlag, kLPUART_RxDataRegFullFlag, kLPUART_RxActiveFlag,
+ kLPUART_NoiseErrorInRxDataRegFlag, kLPUART_ParityErrorInRxDataRegFlag,
+ kLPUART_TxFifoEmptyFlag, kLPUART_RxFifoEmptyFlag. */
+ status = kStatus_LPUART_FlagCannotClearManually; /* flags can not clear manually */
+ }
+ else
+ {
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Writes to the transmitter register using a blocking method.
+ *
+ * This function polls the transmitter register, first waits for the register to be empty or TX FIFO to have room,
+ * and writes data to the transmitter buffer, then waits for the data to be sent out to bus.
+ *
+ * param base LPUART peripheral base address.
+ * param data Start address of the data to write.
+ * param length Size of the data to write.
+ * retval kStatus_LPUART_Timeout Transmission timed out and was aborted.
+ * retval kStatus_Success Successfully wrote all data.
+ */
+status_t LPUART_WriteBlocking(LPUART_Type *base, const uint8_t *data, size_t length)
+{
+ assert(NULL != data);
+
+ const uint8_t *dataAddress = data;
+ size_t transferSize = length;
+
+#if UART_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != transferSize)
+ {
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+ while ((0U == (base->STAT & LPUART_STAT_TDRE_MASK)) && (0U != --waitTimes))
+#else
+ while (0U == (base->STAT & LPUART_STAT_TDRE_MASK))
+#endif
+ {
+ }
+#if UART_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_LPUART_Timeout;
+ }
+#endif
+ base->DATA = *(dataAddress);
+ dataAddress++;
+ transferSize--;
+ }
+ /* Ensure all the data in the transmit buffer are sent out to bus. */
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+ while ((0U == (base->STAT & LPUART_STAT_TC_MASK)) && (0U != --waitTimes))
+#else
+ while (0U == (base->STAT & LPUART_STAT_TC_MASK))
+#endif
+ {
+ }
+#if UART_RETRY_TIMES
+ if (0U == waitTimes)
+ {
+ return kStatus_LPUART_Timeout;
+ }
+#endif
+ return kStatus_Success;
+}
+
+/*!
+ * brief Reads the receiver data register using a blocking method.
+ *
+ * This function polls the receiver register, waits for the receiver register full or receiver FIFO
+ * has data, and reads data from the TX register.
+ *
+ * param base LPUART peripheral base address.
+ * param data Start address of the buffer to store the received data.
+ * param length Size of the buffer.
+ * retval kStatus_LPUART_RxHardwareOverrun Receiver overrun happened while receiving data.
+ * retval kStatus_LPUART_NoiseError Noise error happened while receiving data.
+ * retval kStatus_LPUART_FramingError Framing error happened while receiving data.
+ * retval kStatus_LPUART_ParityError Parity error happened while receiving data.
+ * retval kStatus_LPUART_Timeout Transmission timed out and was aborted.
+ * retval kStatus_Success Successfully received all data.
+ */
+status_t LPUART_ReadBlocking(LPUART_Type *base, uint8_t *data, size_t length)
+{
+ assert(NULL != data);
+
+ status_t status = kStatus_Success;
+ uint32_t statusFlag;
+ uint8_t *dataAddress = data;
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ uint32_t ctrl = base->CTRL;
+ bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) ||
+ (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U)));
+#endif
+
+#if UART_RETRY_TIMES
+ uint32_t waitTimes;
+#endif
+
+ while (0U != (length--))
+ {
+#if UART_RETRY_TIMES
+ waitTimes = UART_RETRY_TIMES;
+#endif
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ while (0U == ((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT))
+#else
+ while (0U == (base->STAT & LPUART_STAT_RDRF_MASK))
+#endif
+ {
+#if UART_RETRY_TIMES
+ if (0U == --waitTimes)
+ {
+ status = kStatus_LPUART_Timeout;
+ break;
+ }
+#endif
+ statusFlag = LPUART_GetStatusFlags(base);
+
+ if (0U != (statusFlag & (uint32_t)kLPUART_RxOverrunFlag))
+ {
+ status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_RxOverrunFlag)) ?
+ (kStatus_LPUART_RxHardwareOverrun) :
+ (kStatus_LPUART_FlagCannotClearManually));
+ /* Other error flags(FE, NF, and PF) are prevented from setting once OR is set, no need to check other
+ * error flags*/
+ break;
+ }
+
+ if (0U != (statusFlag & (uint32_t)kLPUART_ParityErrorFlag))
+ {
+ status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_ParityErrorFlag)) ?
+ (kStatus_LPUART_ParityError) :
+ (kStatus_LPUART_FlagCannotClearManually));
+ }
+
+ if (0U != (statusFlag & (uint32_t)kLPUART_FramingErrorFlag))
+ {
+ status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_FramingErrorFlag)) ?
+ (kStatus_LPUART_FramingError) :
+ (kStatus_LPUART_FlagCannotClearManually));
+ }
+
+ if (0U != (statusFlag & (uint32_t)kLPUART_NoiseErrorFlag))
+ {
+ status = ((kStatus_Success == LPUART_ClearStatusFlags(base, (uint32_t)kLPUART_NoiseErrorFlag)) ?
+ (kStatus_LPUART_NoiseError) :
+ (kStatus_LPUART_FlagCannotClearManually));
+ }
+ if (kStatus_Success != status)
+ {
+ break;
+ }
+ }
+
+ if (kStatus_Success == status)
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ if (isSevenDataBits)
+ {
+ *(dataAddress) = (uint8_t)(base->DATA & 0x7FU);
+ dataAddress++;
+ }
+ else
+ {
+ *(dataAddress) = (uint8_t)base->DATA;
+ dataAddress++;
+ }
+#else
+ *(dataAddress) = (uint8_t)base->DATA;
+ dataAddress++;
+#endif
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*!
+ * brief Initializes the LPUART handle.
+ *
+ * This function initializes the LPUART handle, which can be used for other LPUART
+ * transactional APIs. Usually, for a specified LPUART instance,
+ * call this API once to get the initialized handle.
+ *
+ * The LPUART driver supports the "background" receiving, which means that user can set up
+ * an RX ring buffer optionally. Data received is stored into the ring buffer even when the
+ * user doesn't call the LPUART_TransferReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, the user can get the received data from the ring buffer directly.
+ * The ring buffer is disabled if passing NULL as p ringBuffer.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param callback Callback function.
+ * param userData User data.
+ */
+void LPUART_TransferCreateHandle(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ lpuart_transfer_callback_t callback,
+ void *userData)
+{
+ assert(NULL != handle);
+
+ uint32_t instance;
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ uint32_t ctrl = base->CTRL;
+ bool isSevenDataBits = (((ctrl & LPUART_CTRL_M7_MASK) != 0U) ||
+ (((ctrl & LPUART_CTRL_M_MASK) == 0U) && ((ctrl & LPUART_CTRL_PE_MASK) != 0U)));
+#endif
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(lpuart_handle_t));
+
+ /* Set the TX/RX state. */
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+
+ /* Set the callback and user data. */
+ handle->callback = callback;
+ handle->userData = userData;
+
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ /* Initial seven data bits flag */
+ handle->isSevenDataBits = isSevenDataBits;
+#endif
+
+ /* Get instance from peripheral base address. */
+ instance = LPUART_GetInstance(base);
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_lpuartHandle[instance] = handle;
+
+ s_lpuartIsr = LPUART_TransferHandleIRQ;
+
+/* Enable interrupt in NVIC. */
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+ (void)EnableIRQ(s_lpuartRxIRQ[instance]);
+ (void)EnableIRQ(s_lpuartTxIRQ[instance]);
+#else
+ (void)EnableIRQ(s_lpuartIRQ[instance]);
+#endif
+}
+
+/*!
+ * brief Sets up the RX ring buffer.
+ *
+ * This function sets up the RX ring buffer to a specific UART handle.
+ *
+ * When the RX ring buffer is used, data received is stored into the ring buffer even when
+ * the user doesn't call the UART_TransferReceiveNonBlocking() API. If there is already data received
+ * in the ring buffer, the user can get the received data from the ring buffer directly.
+ *
+ * note When using RX ring buffer, one byte is reserved for internal use. In other
+ * words, if p ringBufferSize is 32, then only 31 bytes are used for saving data.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param ringBuffer Start address of ring buffer for background receiving. Pass NULL to disable the ring buffer.
+ * param ringBufferSize size of the ring buffer.
+ */
+void LPUART_TransferStartRingBuffer(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ uint8_t *ringBuffer,
+ size_t ringBufferSize)
+{
+ assert(NULL != handle);
+ assert(NULL != ringBuffer);
+
+ /* Setup the ring buffer address */
+ handle->rxRingBuffer = ringBuffer;
+ handle->rxRingBufferSize = ringBufferSize;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+
+ /* Enable the interrupt to accept the data when user need the ring buffer. */
+ LPUART_EnableInterrupts(
+ base, (uint32_t)kLPUART_RxDataRegFullInterruptEnable | (uint32_t)kLPUART_RxOverrunInterruptEnable);
+}
+
+/*!
+ * brief Aborts the background transfer and uninstalls the ring buffer.
+ *
+ * This function aborts the background transfer and uninstalls the ring buffer.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ */
+void LPUART_TransferStopRingBuffer(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ if (handle->rxState == (uint8_t)kLPUART_RxIdle)
+ {
+ LPUART_DisableInterrupts(
+ base, (uint32_t)kLPUART_RxDataRegFullInterruptEnable | (uint32_t)kLPUART_RxOverrunInterruptEnable);
+ }
+
+ handle->rxRingBuffer = NULL;
+ handle->rxRingBufferSize = 0U;
+ handle->rxRingBufferHead = 0U;
+ handle->rxRingBufferTail = 0U;
+}
+
+/*!
+ * brief Transmits a buffer of data using the interrupt method.
+ *
+ * This function send data using an interrupt method. This is a non-blocking function, which
+ * returns directly without waiting for all data written to the transmitter register. When
+ * all data is written to the TX register in the ISR, the LPUART driver calls the callback
+ * function and passes the ref kStatus_LPUART_TxIdle as status parameter.
+ *
+ * note The kStatus_LPUART_TxIdle is passed to the upper layer when all data are written
+ * to the TX register. However, there is no check to ensure that all the data sent out. Before disabling the TX,
+ * check the kLPUART_TransmissionCompleteFlag to ensure that the transmit is finished.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param xfer LPUART transfer structure, see #lpuart_transfer_t.
+ * retval kStatus_Success Successfully start the data transmission.
+ * retval kStatus_LPUART_TxBusy Previous transmission still not finished, data not all written to the TX register.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_TransferSendNonBlocking(LPUART_Type *base, lpuart_handle_t *handle, lpuart_transfer_t *xfer)
+{
+ assert(NULL != handle);
+ assert(NULL != xfer);
+ assert(NULL != xfer->data);
+ assert(0U != xfer->dataSize);
+
+ status_t status;
+
+ /* Return error if current TX busy. */
+ if ((uint8_t)kLPUART_TxBusy == handle->txState)
+ {
+ status = kStatus_LPUART_TxBusy;
+ }
+ else
+ {
+ handle->txData = xfer->data;
+ handle->txDataSize = xfer->dataSize;
+ handle->txDataSizeAll = xfer->dataSize;
+ handle->txState = (uint8_t)kLPUART_TxBusy;
+
+ /* Enable transmitter interrupt. */
+ LPUART_EnableInterrupts(base, (uint32_t)kLPUART_TxDataRegEmptyInterruptEnable);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the interrupt-driven data transmit.
+ *
+ * This function aborts the interrupt driven data sending. The user can get the remainBtyes to find out
+ * how many bytes are not sent out.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ */
+void LPUART_TransferAbortSend(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ LPUART_DisableInterrupts(
+ base, (uint32_t)kLPUART_TxDataRegEmptyInterruptEnable | (uint32_t)kLPUART_TransmissionCompleteInterruptEnable);
+
+ handle->txDataSize = 0;
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes that have been sent out to bus.
+ *
+ * This function gets the number of bytes that have been sent out to bus by an interrupt method.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param count Send bytes count.
+ * retval kStatus_NoTransferInProgress No send in progress.
+ * retval kStatus_InvalidArgument Parameter is invalid.
+ * retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetSendCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != count);
+
+ status_t status = kStatus_Success;
+ size_t tmptxDataSize = handle->txDataSize;
+
+ if ((uint8_t)kLPUART_TxIdle == handle->txState)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ *count = handle->txDataSizeAll - tmptxDataSize -
+ ((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXCOUNT_SHIFT);
+#else
+ if ((base->STAT & (uint32_t)kLPUART_TxDataRegEmptyFlag) != 0U)
+ {
+ *count = handle->txDataSizeAll - tmptxDataSize;
+ }
+ else
+ {
+ *count = handle->txDataSizeAll - tmptxDataSize - 1U;
+ }
+#endif
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives a buffer of data using the interrupt method.
+ *
+ * This function receives data using an interrupt method. This is a non-blocking function
+ * which returns without waiting to ensure that all data are received.
+ * If the RX ring buffer is used and not empty, the data in the ring buffer is copied and
+ * the parameter p receivedBytes shows how many bytes are copied from the ring buffer.
+ * After copying, if the data in the ring buffer is not enough for read, the receive
+ * request is saved by the LPUART driver. When the new data arrives, the receive request
+ * is serviced first. When all data is received, the LPUART driver notifies the upper layer
+ * through a callback function and passes a status parameter ref kStatus_UART_RxIdle.
+ * For example, the upper layer needs 10 bytes but there are only 5 bytes in ring buffer.
+ * The 5 bytes are copied to xfer->data, which returns with the
+ * parameter p receivedBytes set to 5. For the remaining 5 bytes, the newly arrived data is
+ * saved from xfer->data[5]. When 5 bytes are received, the LPUART driver notifies the upper layer.
+ * If the RX ring buffer is not enabled, this function enables the RX and RX interrupt
+ * to receive data to xfer->data. When all data is received, the upper layer is notified.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param xfer LPUART transfer structure, see #uart_transfer_t.
+ * param receivedBytes Bytes received from the ring buffer directly.
+ * retval kStatus_Success Successfully queue the transfer into the transmit queue.
+ * retval kStatus_LPUART_RxBusy Previous receive request is not finished.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_TransferReceiveNonBlocking(LPUART_Type *base,
+ lpuart_handle_t *handle,
+ lpuart_transfer_t *xfer,
+ size_t *receivedBytes)
+{
+ assert(NULL != handle);
+ assert(NULL != xfer);
+ assert(NULL != xfer->data);
+ assert(0U != xfer->dataSize);
+
+ uint32_t i;
+ status_t status;
+ /* How many bytes to copy from ring buffer to user memory. */
+ size_t bytesToCopy = 0U;
+ /* How many bytes to receive. */
+ size_t bytesToReceive;
+ /* How many bytes currently have received. */
+ size_t bytesCurrentReceived;
+
+ /* How to get data:
+ 1. If RX ring buffer is not enabled, then save xfer->data and xfer->dataSize
+ to lpuart handle, enable interrupt to store received data to xfer->data. When
+ all data received, trigger callback.
+ 2. If RX ring buffer is enabled and not empty, get data from ring buffer first.
+ If there are enough data in ring buffer, copy them to xfer->data and return.
+ If there are not enough data in ring buffer, copy all of them to xfer->data,
+ save the xfer->data remained empty space to lpuart handle, receive data
+ to this empty space and trigger callback when finished. */
+
+ if ((uint8_t)kLPUART_RxBusy == handle->rxState)
+ {
+ status = kStatus_LPUART_RxBusy;
+ }
+ else
+ {
+ bytesToReceive = xfer->dataSize;
+ bytesCurrentReceived = 0;
+
+ /* If RX ring buffer is used. */
+ if (NULL != handle->rxRingBuffer)
+ {
+ /* Disable LPUART RX IRQ, protect ring buffer. */
+ LPUART_DisableInterrupts(base, (uint32_t)kLPUART_RxDataRegFullInterruptEnable);
+
+ /* How many bytes in RX ring buffer currently. */
+ bytesToCopy = LPUART_TransferGetRxRingBufferLength(base, handle);
+
+ if (0U != bytesToCopy)
+ {
+ bytesToCopy = MIN(bytesToReceive, bytesToCopy);
+
+ bytesToReceive -= bytesToCopy;
+
+ /* Copy data from ring buffer to user memory. */
+ for (i = 0U; i < bytesToCopy; i++)
+ {
+ xfer->data[bytesCurrentReceived] = handle->rxRingBuffer[handle->rxRingBufferTail];
+ bytesCurrentReceived++;
+
+ /* Wrap to 0. Not use modulo (%) because it might be large and slow. */
+ if (((uint32_t)handle->rxRingBufferTail + 1U) == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+ }
+
+ /* If ring buffer does not have enough data, still need to read more data. */
+ if (0U != bytesToReceive)
+ {
+ /* No data in ring buffer, save the request to LPUART handle. */
+ handle->rxData = xfer->data + bytesCurrentReceived;
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = bytesToReceive;
+ handle->rxState = (uint8_t)kLPUART_RxBusy;
+ }
+ /* Enable LPUART RX IRQ if previously enabled. */
+ LPUART_EnableInterrupts(base, (uint32_t)kLPUART_RxDataRegFullInterruptEnable);
+
+ /* Call user callback since all data are received. */
+ if (0U == bytesToReceive)
+ {
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxIdle, handle->userData);
+ }
+ }
+ }
+ /* Ring buffer not used. */
+ else
+ {
+ handle->rxData = xfer->data + bytesCurrentReceived;
+ handle->rxDataSize = bytesToReceive;
+ handle->rxDataSizeAll = bytesToReceive;
+ handle->rxState = (uint8_t)kLPUART_RxBusy;
+
+ /* Enable RX interrupt. */
+ LPUART_EnableInterrupts(base, (uint32_t)kLPUART_RxDataRegFullInterruptEnable |
+ (uint32_t)kLPUART_RxOverrunInterruptEnable |
+ (uint32_t)kLPUART_IdleLineInterruptEnable);
+ }
+
+ /* Return the how many bytes have read. */
+ if (NULL != receivedBytes)
+ {
+ *receivedBytes = bytesCurrentReceived;
+ }
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the interrupt-driven data receiving.
+ *
+ * This function aborts the interrupt-driven data receiving. The user can get the remainBytes to find out
+ * how many bytes not received yet.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ */
+void LPUART_TransferAbortReceive(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ /* Only abort the receive to handle->rxData, the RX ring buffer is still working. */
+ if (NULL == handle->rxRingBuffer)
+ {
+ /* Disable RX interrupt. */
+ LPUART_DisableInterrupts(base, (uint32_t)kLPUART_RxDataRegFullInterruptEnable |
+ (uint32_t)kLPUART_RxOverrunInterruptEnable |
+ (uint32_t)kLPUART_IdleLineInterruptEnable);
+ }
+
+ handle->rxDataSize = 0U;
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+}
+
+/*!
+ * brief Gets the number of bytes that have been received.
+ *
+ * This function gets the number of bytes that have been received.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param count Receive bytes count.
+ * retval kStatus_NoTransferInProgress No receive in progress.
+ * retval kStatus_InvalidArgument Parameter is invalid.
+ * retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetReceiveCount(LPUART_Type *base, lpuart_handle_t *handle, uint32_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != count);
+
+ status_t status = kStatus_Success;
+ size_t tmprxDataSize = handle->rxDataSize;
+
+ if ((uint8_t)kLPUART_RxIdle == handle->rxState)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = handle->rxDataSizeAll - tmprxDataSize;
+ }
+
+ return status;
+}
+
+/*!
+ * brief LPUART IRQ handle function.
+ *
+ * This function handles the LPUART transmit and receive IRQ request.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ */
+void LPUART_TransferHandleIRQ(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ assert(NULL != handle);
+
+ uint8_t count;
+ uint8_t tempCount;
+ uint32_t status = LPUART_GetStatusFlags(base);
+ uint32_t enabledInterrupts = LPUART_GetEnabledInterrupts(base);
+ uint16_t tpmRxRingBufferHead;
+ uint32_t tpmData;
+
+ /* If RX overrun. */
+ if ((uint32_t)kLPUART_RxOverrunFlag == ((uint32_t)kLPUART_RxOverrunFlag & status))
+ {
+ /* Clear overrun flag, otherwise the RX does not work. */
+ base->STAT = ((base->STAT & 0x3FE00000U) | LPUART_STAT_OR_MASK);
+
+ /* Trigger callback. */
+ if (NULL != (handle->callback))
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxHardwareOverrun, handle->userData);
+ }
+ }
+
+ /* If IDLE flag is set and the IDLE interrupt is enabled. */
+ if ((0U != ((uint32_t)kLPUART_IdleLineFlag & status)) &&
+ (0U != ((uint32_t)kLPUART_IdleLineInterruptEnable & enabledInterrupts)))
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ count = ((uint8_t)((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT));
+
+ while ((0U != handle->rxDataSize) && (0U != count))
+ {
+ tempCount = (uint8_t)MIN(handle->rxDataSize, count);
+
+ /* Using non block API to read the data from the registers. */
+ LPUART_ReadNonBlocking(base, handle->rxData, tempCount);
+ handle->rxData += tempCount;
+ handle->rxDataSize -= tempCount;
+ count -= tempCount;
+
+ /* If rxDataSize is 0, disable idle line interrupt.*/
+ if (0U == (handle->rxDataSize))
+ {
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+
+ LPUART_DisableInterrupts(
+ base, (uint32_t)kLPUART_RxDataRegFullInterruptEnable | (uint32_t)kLPUART_RxOverrunInterruptEnable);
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxIdle, handle->userData);
+ }
+ }
+ }
+#endif
+ /* Clear IDLE flag.*/
+ base->STAT |= LPUART_STAT_IDLE_MASK;
+
+ /* If rxDataSize is 0, disable idle line interrupt.*/
+ if (0U != (handle->rxDataSize))
+ {
+ LPUART_DisableInterrupts(base, (uint32_t)kLPUART_IdleLineInterruptEnable);
+ }
+ /* If callback is not NULL and rxDataSize is not 0. */
+ if ((0U != handle->rxDataSize) && (NULL != handle->callback))
+ {
+ handle->callback(base, handle, kStatus_LPUART_IdleLineDetected, handle->userData);
+ }
+ }
+ /* Receive data register full */
+ if ((0U != ((uint32_t)kLPUART_RxDataRegFullFlag & status)) &&
+ (0U != ((uint32_t)kLPUART_RxDataRegFullInterruptEnable & enabledInterrupts)))
+ {
+/* Get the size that can be stored into buffer for this interrupt. */
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ count = ((uint8_t)((base->WATER & LPUART_WATER_RXCOUNT_MASK) >> LPUART_WATER_RXCOUNT_SHIFT));
+#else
+ count = 1;
+#endif
+
+ /* If handle->rxDataSize is not 0, first save data to handle->rxData. */
+ while ((0U != handle->rxDataSize) && (0U != count))
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ tempCount = (uint8_t)MIN(handle->rxDataSize, count);
+#else
+ tempCount = 1;
+#endif
+
+ /* Using non block API to read the data from the registers. */
+ LPUART_ReadNonBlocking(base, handle->rxData, tempCount);
+ handle->rxData += tempCount;
+ handle->rxDataSize -= tempCount;
+ count -= tempCount;
+
+ /* If all the data required for upper layer is ready, trigger callback. */
+ if (0U == handle->rxDataSize)
+ {
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxIdle, handle->userData);
+ }
+ }
+ }
+
+ /* If use RX ring buffer, receive data to ring buffer. */
+ if (NULL != handle->rxRingBuffer)
+ {
+ while (0U != count--)
+ {
+ /* If RX ring buffer is full, trigger callback to notify over run. */
+ if (LPUART_TransferIsRxRingBufferFull(base, handle))
+ {
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_RxRingBufferOverrun, handle->userData);
+ }
+ }
+
+ /* If ring buffer is still full after callback function, the oldest data is overridden. */
+ if (LPUART_TransferIsRxRingBufferFull(base, handle))
+ {
+ /* Increase handle->rxRingBufferTail to make room for new data. */
+ if (((uint32_t)handle->rxRingBufferTail + 1U) == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferTail = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferTail++;
+ }
+ }
+
+ /* Read data. */
+ tpmRxRingBufferHead = handle->rxRingBufferHead;
+ tpmData = base->DATA;
+#if defined(FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT) && FSL_FEATURE_LPUART_HAS_7BIT_DATA_SUPPORT
+ if (handle->isSevenDataBits)
+ {
+ handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)(tpmData & 0x7FU);
+ }
+ else
+ {
+ handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)tpmData;
+ }
+#else
+ handle->rxRingBuffer[tpmRxRingBufferHead] = (uint8_t)tpmData;
+#endif
+
+ /* Increase handle->rxRingBufferHead. */
+ if (((uint32_t)handle->rxRingBufferHead + 1U) == handle->rxRingBufferSize)
+ {
+ handle->rxRingBufferHead = 0U;
+ }
+ else
+ {
+ handle->rxRingBufferHead++;
+ }
+ }
+ }
+ /* If no receive requst pending, stop RX interrupt. */
+ else if (0U == handle->rxDataSize)
+ {
+ LPUART_DisableInterrupts(
+ base, (uint32_t)kLPUART_RxDataRegFullInterruptEnable | (uint32_t)kLPUART_RxOverrunInterruptEnable);
+ }
+ else
+ {
+ }
+ }
+
+ /* Send data register empty and the interrupt is enabled. */
+ if ((0U != ((uint32_t)kLPUART_TxDataRegEmptyFlag & status)) &&
+ (0U != ((uint32_t)kLPUART_TxDataRegEmptyInterruptEnable & enabledInterrupts)))
+ {
+/* Get the bytes that available at this moment. */
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ count = (uint8_t)FSL_FEATURE_LPUART_FIFO_SIZEn(base) -
+ (uint8_t)((base->WATER & LPUART_WATER_TXCOUNT_MASK) >> LPUART_WATER_TXCOUNT_SHIFT);
+#else
+ count = 1;
+#endif
+
+ while ((0U != handle->txDataSize) && (0U != count))
+ {
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ tempCount = (uint8_t)MIN(handle->txDataSize, count);
+#else
+ tempCount = 1;
+#endif
+
+ /* Using non block API to write the data to the registers. */
+ LPUART_WriteNonBlocking(base, handle->txData, tempCount);
+ handle->txData += tempCount;
+ handle->txDataSize -= tempCount;
+ count -= tempCount;
+
+ /* If all the data are written to data register, notify user with the callback, then TX finished. */
+ if (0U == handle->txDataSize)
+ {
+ /* Disable TX register empty interrupt. */
+ base->CTRL = (base->CTRL & ~LPUART_CTRL_TIE_MASK);
+ /* Enable transmission complete interrupt. */
+ LPUART_EnableInterrupts(base, (uint32_t)kLPUART_TransmissionCompleteInterruptEnable);
+ }
+ }
+ }
+
+ /* Transmission complete and the interrupt is enabled. */
+ if ((0U != ((uint32_t)kLPUART_TransmissionCompleteFlag & status)) &&
+ (0U != ((uint32_t)kLPUART_TransmissionCompleteInterruptEnable & enabledInterrupts)))
+ {
+ /* Set txState to idle only when all data has been sent out to bus. */
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+ /* Disable transmission complete interrupt. */
+ LPUART_DisableInterrupts(base, (uint32_t)kLPUART_TransmissionCompleteInterruptEnable);
+
+ /* Trigger callback. */
+ if (NULL != handle->callback)
+ {
+ handle->callback(base, handle, kStatus_LPUART_TxIdle, handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief LPUART Error IRQ handle function.
+ *
+ * This function handles the LPUART error IRQ request.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ */
+void LPUART_TransferHandleErrorIRQ(LPUART_Type *base, lpuart_handle_t *handle)
+{
+ /* To be implemented by User. */
+}
+#if defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART0_LPUART1_RX_DriverIRQHandler(void)
+{
+ uint32_t stat = 0U;
+ uint32_t ctrl = 0U;
+
+ if (CLOCK_isEnabledClock(s_lpuartClock[0]))
+ {
+ stat = LPUART0->STAT;
+ ctrl = LPUART0->CTRL;
+ if ((LPUART_STAT_OR_MASK & stat) || ((LPUART_STAT_RDRF_MASK & stat) && (LPUART_CTRL_RIE_MASK & ctrl)))
+ {
+ s_lpuartIsr(LPUART0, s_lpuartHandle[0]);
+ }
+ }
+ if (CLOCK_isEnabledClock(s_lpuartClock[1]))
+ {
+ stat = LPUART1->STAT;
+ ctrl = LPUART1->CTRL;
+ if ((LPUART_STAT_OR_MASK & stat) || ((LPUART_STAT_RDRF_MASK & stat) && (LPUART_CTRL_RIE_MASK & ctrl)))
+ {
+ s_lpuartIsr(LPUART1, s_lpuartHandle[1]);
+ }
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART0_LPUART1_TX_DriverIRQHandler(void)
+{
+ uint32_t stat = 0U;
+ uint32_t ctrl = 0U;
+
+ if (CLOCK_isEnabledClock(s_lpuartClock[0]))
+ {
+ stat = LPUART0->STAT;
+ ctrl = LPUART0->CTRL;
+ if ((LPUART_STAT_OR_MASK & stat) || ((stat & LPUART_STAT_TDRE_MASK) && (ctrl & LPUART_CTRL_TIE_MASK)))
+ {
+ s_lpuartIsr(LPUART0, s_lpuartHandle[0]);
+ }
+ }
+ if (CLOCK_isEnabledClock(s_lpuartClock[1]))
+ {
+ stat = LPUART1->STAT;
+ ctrl = LPUART1->CTRL;
+ if ((LPUART_STAT_OR_MASK & stat) || ((stat & LPUART_STAT_TDRE_MASK) && (ctrl & LPUART_CTRL_TIE_MASK)))
+ {
+ s_lpuartIsr(LPUART1, s_lpuartHandle[1]);
+ }
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART0_LPUART1_DriverIRQHandler(void)
+{
+ uint32_t stat = 0U;
+ uint32_t ctrl = 0U;
+
+ if (CLOCK_isEnabledClock(s_lpuartClock[0]))
+ {
+ stat = LPUART0->STAT;
+ ctrl = LPUART0->CTRL;
+ if ((0U != (LPUART_STAT_OR_MASK & stat)) ||
+ ((0U != (LPUART_STAT_RDRF_MASK & stat)) && (0U != (LPUART_CTRL_RIE_MASK & ctrl))) ||
+ ((0U != (stat & LPUART_STAT_TDRE_MASK)) && (0U != (ctrl & LPUART_CTRL_TIE_MASK))))
+ {
+ s_lpuartIsr(LPUART0, s_lpuartHandle[0]);
+ }
+ }
+ if (CLOCK_isEnabledClock(s_lpuartClock[1]))
+ {
+ stat = LPUART1->STAT;
+ ctrl = LPUART1->CTRL;
+ if ((0U != (LPUART_STAT_OR_MASK & stat)) ||
+ ((0U != (LPUART_STAT_RDRF_MASK & stat)) && (0U != (LPUART_CTRL_RIE_MASK & ctrl))) ||
+ ((0U != (stat & LPUART_STAT_TDRE_MASK)) && (0U != (ctrl & LPUART_CTRL_TIE_MASK))))
+ {
+ s_lpuartIsr(LPUART1, s_lpuartHandle[1]);
+ }
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART0)
+#if !(defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART0_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART0, s_lpuartHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART0_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART0, s_lpuartHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART0_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART0, s_lpuartHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#endif
+
+#if defined(LPUART1)
+#if !(defined(FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1) && FSL_FEATURE_LPUART_HAS_SHARED_IRQ0_IRQ1)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART1_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART1, s_lpuartHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART1_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART1, s_lpuartHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART1_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART1, s_lpuartHandle[1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#endif
+
+#if defined(LPUART2)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART2_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART2, s_lpuartHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART2_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART2, s_lpuartHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART2_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART2, s_lpuartHandle[2]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART3)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART3_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART3, s_lpuartHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART3_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART3, s_lpuartHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART3_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART3, s_lpuartHandle[3]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART4)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART4_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART4, s_lpuartHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART4_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART4, s_lpuartHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART4_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART4, s_lpuartHandle[4]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART5)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART5_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART5, s_lpuartHandle[5]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART5_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART5, s_lpuartHandle[5]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART5_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART5, s_lpuartHandle[5]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART6)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART6_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART6, s_lpuartHandle[6]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART6_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART6, s_lpuartHandle[6]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART6_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART6, s_lpuartHandle[6]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART7)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART7_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART7, s_lpuartHandle[7]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART7_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART7, s_lpuartHandle[7]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART7_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART7, s_lpuartHandle[7]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(LPUART8)
+#if defined(FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ) && FSL_FEATURE_LPUART_HAS_SEPARATE_RX_TX_IRQ
+void LPUART8_TX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART8, s_lpuartHandle[8]);
+ SDK_ISR_EXIT_BARRIER;
+}
+void LPUART8_RX_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART8, s_lpuartHandle[8]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#else
+void LPUART8_DriverIRQHandler(void)
+{
+ s_lpuartIsr(LPUART8, s_lpuartHandle[8]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(CM4_0__LPUART)
+void M4_0_LPUART_DriverIRQHandler(void)
+{
+ s_lpuartIsr(CM4_0__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4_0__LPUART)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CM4_1__LPUART)
+void M4_1_LPUART_DriverIRQHandler(void)
+{
+ s_lpuartIsr(CM4_1__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4_1__LPUART)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(CM4__LPUART)
+void M4_LPUART_DriverIRQHandler(void)
+{
+ s_lpuartIsr(CM4__LPUART, s_lpuartHandle[LPUART_GetInstance(CM4__LPUART)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART0)
+void DMA_UART0_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(DMA__LPUART0, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART0)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART1)
+void DMA_UART1_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(DMA__LPUART1, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART1)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART2)
+void DMA_UART2_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(DMA__LPUART2, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART2)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART3)
+void DMA_UART3_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(DMA__LPUART3, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART3)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(DMA__LPUART4)
+void DMA_UART4_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(DMA__LPUART4, s_lpuartHandle[LPUART_GetInstance(DMA__LPUART4)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__LPUART0)
+void ADMA_UART0_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(ADMA__LPUART0, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART0)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__LPUART1)
+void ADMA_UART1_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(ADMA__LPUART1, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART1)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__LPUART2)
+void ADMA_UART2_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(ADMA__LPUART2, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART2)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(ADMA__LPUART3)
+void ADMA_UART3_INT_DriverIRQHandler(void)
+{
+ s_lpuartIsr(ADMA__LPUART3, s_lpuartHandle[LPUART_GetInstance(ADMA__LPUART3)]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpuart_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpuart_edma.c
new file mode 100644
index 0000000000..c165539ada
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_lpuart_edma.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_lpuart_edma.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.lpuart_edma"
+#endif
+
+/*<! Structure definition for lpuart_edma_private_handle_t. The structure is private. */
+typedef struct _lpuart_edma_private_handle
+{
+ LPUART_Type *base;
+ lpuart_edma_handle_t *handle;
+} lpuart_edma_private_handle_t;
+
+/* LPUART EDMA transfer handle. */
+enum
+{
+ kLPUART_TxIdle, /* TX idle. */
+ kLPUART_TxBusy, /* TX busy. */
+ kLPUART_RxIdle, /* RX idle. */
+ kLPUART_RxBusy /* RX busy. */
+};
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of LPUART handle. */
+#if (defined(LPUART8))
+#define LPUART_HANDLE_ARRAY_SIZE 9
+#else /* LPUART8 */
+#if (defined(LPUART7))
+#define LPUART_HANDLE_ARRAY_SIZE 8
+#else /* LPUART7 */
+#if (defined(LPUART6))
+#define LPUART_HANDLE_ARRAY_SIZE 7
+#else /* LPUART6 */
+#if (defined(LPUART5))
+#define LPUART_HANDLE_ARRAY_SIZE 6
+#else /* LPUART5 */
+#if (defined(LPUART4))
+#define LPUART_HANDLE_ARRAY_SIZE 5
+#else /* LPUART4 */
+#if (defined(LPUART3))
+#define LPUART_HANDLE_ARRAY_SIZE 4
+#else /* LPUART3 */
+#if (defined(LPUART2))
+#define LPUART_HANDLE_ARRAY_SIZE 3
+#else /* LPUART2 */
+#if (defined(LPUART1))
+#define LPUART_HANDLE_ARRAY_SIZE 2
+#else /* LPUART1 */
+#if (defined(LPUART0))
+#define LPUART_HANDLE_ARRAY_SIZE 1
+#else /* LPUART0 */
+#define LPUART_HANDLE_ARRAY_SIZE FSL_FEATURE_SOC_LPUART_COUNT
+#endif /* LPUART 0 */
+#endif /* LPUART 1 */
+#endif /* LPUART 2 */
+#endif /* LPUART 3 */
+#endif /* LPUART 4 */
+#endif /* LPUART 5 */
+#endif /* LPUART 6 */
+#endif /* LPUART 7 */
+#endif /* LPUART 8 */
+
+/*<! Private handle only used for internally. */
+static lpuart_edma_private_handle_t s_lpuartEdmaPrivateHandle[LPUART_HANDLE_ARRAY_SIZE];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief LPUART EDMA send finished callback function.
+ *
+ * This function is called when LPUART EDMA send finished. It disables the LPUART
+ * TX EDMA request and sends @ref kStatus_LPUART_TxIdle to LPUART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void LPUART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*!
+ * @brief LPUART EDMA receive finished callback function.
+ *
+ * This function is called when LPUART EDMA receive finished. It disables the LPUART
+ * RX EDMA request and sends @ref kStatus_LPUART_RxIdle to LPUART callback.
+ *
+ * @param handle The EDMA handle.
+ * @param param Callback function parameter.
+ */
+static void LPUART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static void LPUART_SendEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ assert(NULL != param);
+
+ lpuart_edma_private_handle_t *lpuartPrivateHandle = (lpuart_edma_private_handle_t *)param;
+
+ /* Avoid the warning for unused variables. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ LPUART_TransferAbortSendEDMA(lpuartPrivateHandle->base, lpuartPrivateHandle->handle);
+
+ /* Ensure all the data in the transmit buffer are sent out to bus. */
+ while (0U == (lpuartPrivateHandle->base->STAT & LPUART_STAT_TC_MASK))
+ {
+ }
+
+ if (NULL != lpuartPrivateHandle->handle->callback)
+ {
+ lpuartPrivateHandle->handle->callback(lpuartPrivateHandle->base, lpuartPrivateHandle->handle,
+ kStatus_LPUART_TxIdle, lpuartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+static void LPUART_ReceiveEDMACallback(edma_handle_t *handle, void *param, bool transferDone, uint32_t tcds)
+{
+ assert(NULL != param);
+
+ lpuart_edma_private_handle_t *lpuartPrivateHandle = (lpuart_edma_private_handle_t *)param;
+
+ /* Avoid warning for unused parameters. */
+ handle = handle;
+ tcds = tcds;
+
+ if (transferDone)
+ {
+ /* Disable transfer. */
+ LPUART_TransferAbortReceiveEDMA(lpuartPrivateHandle->base, lpuartPrivateHandle->handle);
+
+ if (NULL != lpuartPrivateHandle->handle->callback)
+ {
+ lpuartPrivateHandle->handle->callback(lpuartPrivateHandle->base, lpuartPrivateHandle->handle,
+ kStatus_LPUART_RxIdle, lpuartPrivateHandle->handle->userData);
+ }
+ }
+}
+
+/*!
+ * brief Initializes the LPUART handle which is used in transactional functions.
+ * param base LPUART peripheral base address.
+ * param handle Pointer to lpuart_edma_handle_t structure.
+ * param callback Callback function.
+ * param userData User data.
+ * param txEdmaHandle User requested DMA handle for TX DMA transfer.
+ * param rxEdmaHandle User requested DMA handle for RX DMA transfer.
+ */
+void LPUART_TransferCreateHandleEDMA(LPUART_Type *base,
+ lpuart_edma_handle_t *handle,
+ lpuart_edma_transfer_callback_t callback,
+ void *userData,
+ edma_handle_t *txEdmaHandle,
+ edma_handle_t *rxEdmaHandle)
+{
+ assert(NULL != handle);
+
+ uint32_t instance = LPUART_GetInstance(base);
+
+ s_lpuartEdmaPrivateHandle[instance].base = base;
+ s_lpuartEdmaPrivateHandle[instance].handle = handle;
+
+ (void)memset(handle, 0, sizeof(*handle));
+
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+
+ handle->rxEdmaHandle = rxEdmaHandle;
+ handle->txEdmaHandle = txEdmaHandle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+
+#if defined(FSL_FEATURE_LPUART_HAS_FIFO) && FSL_FEATURE_LPUART_HAS_FIFO
+ /* Note:
+ Take care of the RX FIFO, EDMA request only assert when received bytes
+ equal or more than RX water mark, there is potential issue if RX water
+ mark larger than 1.
+ For example, if RX FIFO water mark is 2, upper layer needs 5 bytes and
+ 5 bytes are received. the last byte will be saved in FIFO but not trigger
+ EDMA transfer because the water mark is 2.
+ */
+ if (NULL != rxEdmaHandle)
+ {
+ base->WATER &= (~LPUART_WATER_RXWATER_MASK);
+ }
+#endif
+
+ /* Configure TX. */
+ if (NULL != txEdmaHandle)
+ {
+ EDMA_SetCallback(handle->txEdmaHandle, LPUART_SendEDMACallback, &s_lpuartEdmaPrivateHandle[instance]);
+ }
+
+ /* Configure RX. */
+ if (NULL != rxEdmaHandle)
+ {
+ EDMA_SetCallback(handle->rxEdmaHandle, LPUART_ReceiveEDMACallback, &s_lpuartEdmaPrivateHandle[instance]);
+ }
+}
+
+/*!
+ * brief Sends data using eDMA.
+ *
+ * This function sends data using eDMA. This is a non-blocking function, which returns
+ * right away. When all data is sent, the send callback function is called.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param xfer LPUART eDMA transfer structure. See #lpuart_transfer_t.
+ * retval kStatus_Success if succeed, others failed.
+ * retval kStatus_LPUART_TxBusy Previous transfer on going.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_SendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->txEdmaHandle);
+ assert(NULL != xfer);
+ assert(NULL != xfer->data);
+ assert(0U != xfer->dataSize);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* If previous TX not finished. */
+ if ((uint8_t)kLPUART_TxBusy == handle->txState)
+ {
+ status = kStatus_LPUART_TxBusy;
+ }
+ else
+ {
+ handle->txState = (uint8_t)kLPUART_TxBusy;
+ handle->txDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, xfer->data, sizeof(uint8_t),
+ (void *)(uint32_t *)LPUART_GetDataRegisterAddress(base), sizeof(uint8_t), sizeof(uint8_t),
+ xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPUART handle */
+ handle->nbytes = (uint8_t)sizeof(uint8_t);
+
+ /* Submit transfer. */
+ if (kStatus_Success !=
+ EDMA_SubmitTransfer(handle->txEdmaHandle, (const edma_transfer_config_t *)(uint32_t)&xferConfig))
+ {
+ return kStatus_Fail;
+ }
+ EDMA_StartTransfer(handle->txEdmaHandle);
+
+ /* Enable LPUART TX EDMA. */
+ LPUART_EnableTxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Receives data using eDMA.
+ *
+ * This function receives data using eDMA. This is non-blocking function, which returns
+ * right away. When all data is received, the receive callback function is called.
+ *
+ * param base LPUART peripheral base address.
+ * param handle Pointer to lpuart_edma_handle_t structure.
+ * param xfer LPUART eDMA transfer structure, see #lpuart_transfer_t.
+ * retval kStatus_Success if succeed, others fail.
+ * retval kStatus_LPUART_RxBusy Previous transfer ongoing.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t LPUART_ReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, lpuart_transfer_t *xfer)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->rxEdmaHandle);
+ assert(NULL != xfer);
+ assert(NULL != xfer->data);
+ assert(0U != xfer->dataSize);
+
+ edma_transfer_config_t xferConfig;
+ status_t status;
+
+ /* If previous RX not finished. */
+ if ((uint8_t)kLPUART_RxBusy == handle->rxState)
+ {
+ status = kStatus_LPUART_RxBusy;
+ }
+ else
+ {
+ handle->rxState = (uint8_t)kLPUART_RxBusy;
+ handle->rxDataSizeAll = xfer->dataSize;
+
+ /* Prepare transfer. */
+ EDMA_PrepareTransfer(&xferConfig, (void *)(uint32_t *)LPUART_GetDataRegisterAddress(base), sizeof(uint8_t),
+ xfer->data, sizeof(uint8_t), sizeof(uint8_t), xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the LPUART handle */
+ handle->nbytes = (uint8_t)sizeof(uint8_t);
+
+ /* Submit transfer. */
+ if (kStatus_Success !=
+ EDMA_SubmitTransfer(handle->rxEdmaHandle, (const edma_transfer_config_t *)(uint32_t)&xferConfig))
+ {
+ return kStatus_Fail;
+ }
+ EDMA_StartTransfer(handle->rxEdmaHandle);
+
+ /* Enable LPUART RX EDMA. */
+ LPUART_EnableRxDMA(base, true);
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the sent data using eDMA.
+ *
+ * This function aborts the sent data using eDMA.
+ *
+ * param base LPUART peripheral base address.
+ * param handle Pointer to lpuart_edma_handle_t structure.
+ */
+void LPUART_TransferAbortSendEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->txEdmaHandle);
+
+ /* Disable LPUART TX EDMA. */
+ LPUART_EnableTxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_AbortTransfer(handle->txEdmaHandle);
+
+ handle->txState = (uint8_t)kLPUART_TxIdle;
+}
+
+/*!
+ * brief Aborts the received data using eDMA.
+ *
+ * This function aborts the received data using eDMA.
+ *
+ * param base LPUART peripheral base address.
+ * param handle Pointer to lpuart_edma_handle_t structure.
+ */
+void LPUART_TransferAbortReceiveEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->rxEdmaHandle);
+
+ /* Disable LPUART RX EDMA. */
+ LPUART_EnableRxDMA(base, false);
+
+ /* Stop transfer. */
+ EDMA_AbortTransfer(handle->rxEdmaHandle);
+
+ handle->rxState = (uint8_t)kLPUART_RxIdle;
+}
+
+/*!
+ * brief Gets the number of received bytes.
+ *
+ * This function gets the number of received bytes.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param count Receive bytes count.
+ * retval kStatus_NoTransferInProgress No receive in progress.
+ * retval kStatus_InvalidArgument Parameter is invalid.
+ * retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetReceiveCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->rxEdmaHandle);
+ assert(NULL != count);
+
+ if ((uint8_t)kLPUART_RxIdle == handle->rxState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->rxDataSizeAll -
+ ((uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->rxEdmaHandle->base, handle->rxEdmaHandle->channel));
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the number of bytes written to the LPUART TX register.
+ *
+ * This function gets the number of bytes written to the LPUART TX
+ * register by DMA.
+ *
+ * param base LPUART peripheral base address.
+ * param handle LPUART handle pointer.
+ * param count Send bytes count.
+ * retval kStatus_NoTransferInProgress No send in progress.
+ * retval kStatus_InvalidArgument Parameter is invalid.
+ * retval kStatus_Success Get successfully through the parameter \p count;
+ */
+status_t LPUART_TransferGetSendCountEDMA(LPUART_Type *base, lpuart_edma_handle_t *handle, uint32_t *count)
+{
+ assert(NULL != handle);
+ assert(NULL != handle->txEdmaHandle);
+ assert(NULL != count);
+
+ if ((uint8_t)kLPUART_TxIdle == handle->txState)
+ {
+ return kStatus_NoTransferInProgress;
+ }
+
+ *count = handle->txDataSizeAll -
+ ((uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->txEdmaHandle->base, handle->txEdmaHandle->channel));
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ocotp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ocotp.c
new file mode 100644
index 0000000000..e37daf059c
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_ocotp.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_ocotp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.ocotp"
+#endif
+
+/* Wait time should be not less than 150ns . */
+#define OCOTP_TIMING_WAIT_NS (uint64_t)150
+/* Relex time should be not less than 100ns . */
+#define OCOTP_TIMING_RELEX_NS (uint64_t)100
+/* Program time should be rang from 9000ns~11000ns. */
+#define OCOTP_TIMING_PROGRAM_NS (uint64_t)10000
+/* Read time should be less than 40ns. */
+#define OCOTP_TIMING_READ_NS (uint64_t)40
+
+/* Unlock key is 0x3E77. */
+#define OCOTP_WRITE_UNLOCK_KEY (0x3E77)
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Set read timing configuration.
+ *
+ * @param base OCOTP peripheral base addess.
+ * @param timingConfig configuration of timing.
+ */
+static void OCOTP_SetReadTiming(OCOTP_Type *base, ocotp_timing_t timingConfig);
+
+/*!
+ * @brief Set write timing configuration.
+ *
+ * @param base OCOTP peripheral base addess.
+ * @param timingConfig configuration of timing.
+ */
+static void OCOTP_SetWriteTiming(OCOTP_Type *base, ocotp_timing_t timingConfig);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Timing configuration for OCOTP controller. */
+ocotp_timing_t s_timingConfig;
+
+/*******************************************************************************
+ * Code
+ *******************************************************************************/
+/* Reload the shadow register. */
+void OCOTP_ReloadShadowRegister(OCOTP_Type *base)
+{
+ assert(NULL != base);
+
+ /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Clear access error status bit. */
+ OCOTP_ClearErrorStatus(base);
+
+ /* Set the read timing. */
+ OCOTP_SetReadTiming(base, s_timingConfig);
+
+ /* Wait for the OCOTP controller not busy. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Set reload bit. */
+ base->CTRL_SET = OCOTP_CTRL_RELOAD_SHADOWS(1);
+
+ /* Wait for the OCOTP controller not busy. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+ /* Wait for shadow register reload complete. this bit will be auto clear by OCOTP once operation is complete. */
+ while (OCOTP_CTRL_RELOAD_SHADOWS_MASK == (base->CTRL & OCOTP_CTRL_RELOAD_SHADOWS_MASK))
+ {
+ }
+}
+
+static void OCOTP_SetReadTiming(OCOTP_Type *base, ocotp_timing_t timingConfig)
+{
+ uint32_t timingValue = base->TIMING;
+
+ timingValue &= ~(OCOTP_TIMING_RELAX_MASK | OCOTP_TIMING_STROBE_READ_MASK | OCOTP_TIMING_WAIT_MASK);
+ timingValue |= OCOTP_TIMING_RELAX(timingConfig.relax) | OCOTP_TIMING_STROBE_READ(timingConfig.strobe_read) |
+ OCOTP_TIMING_WAIT(timingConfig.wait);
+ base->TIMING = timingValue;
+}
+
+static void OCOTP_SetWriteTiming(OCOTP_Type *base, ocotp_timing_t timingConfig)
+{
+ uint32_t timingValue = base->TIMING;
+
+ timingValue &= ~(OCOTP_TIMING_RELAX_MASK | OCOTP_TIMING_STROBE_PROG_MASK | OCOTP_TIMING_WAIT_MASK);
+ timingValue |= OCOTP_TIMING_RELAX(timingConfig.relax) | OCOTP_TIMING_STROBE_PROG(timingConfig.strobe_prog) |
+ OCOTP_TIMING_WAIT(timingConfig.wait);
+
+ base->TIMING = timingValue;
+}
+
+/* Initializes OCOTP controller. */
+void OCOTP_Init(OCOTP_Type *base, uint32_t srcClock_Hz)
+{
+ assert(NULL != base);
+ assert(0UL != srcClock_Hz);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable OCOTP clock */
+ CLOCK_EnableClock(kCLOCK_Ocotp);
+#endif
+
+ /* tWait time shoule be higher than OCOTP_TIMING_WAIT_NS. */
+ s_timingConfig.wait = (OCOTP_TIMING_WAIT_NS * srcClock_Hz + 1000000000) / 1000000000 - 1;
+
+ /* tRelax time shoule be higher than OCOTP_TIMING_RELEX_NS. */
+ s_timingConfig.relax = (OCOTP_TIMING_RELEX_NS * srcClock_Hz + 1000000000) / 1000000000 - 1;
+
+ /* tStrobe_prog time should be close to OCOTP_TIMING_PROGRAM_NS, only add half of 1000000000. */
+ s_timingConfig.strobe_prog =
+ (OCOTP_TIMING_PROGRAM_NS * srcClock_Hz + 500000000) / 1000000000 + 2 * (s_timingConfig.relax + 1) - 1;
+
+ /* tStrobe_read time should be higher than OCOTP_TIMING_READ_NS. */
+ s_timingConfig.strobe_read =
+ (OCOTP_TIMING_READ_NS * srcClock_Hz + 1000000000) / 1000000000 + 2 * (s_timingConfig.relax + 1) - 1;
+}
+
+/* De-init OCOTP controller. */
+void OCOTP_Deinit(OCOTP_Type *base)
+{
+ assert(NULL != base);
+
+ s_timingConfig.wait = 0UL;
+ s_timingConfig.relax = 0UL;
+ s_timingConfig.strobe_prog = 0UL;
+ s_timingConfig.strobe_read = 0UL;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable OCOTP clock */
+ CLOCK_DisableClock(kCLOCK_Ocotp);
+#endif
+}
+
+/* Read the fuse shadow register. */
+uint32_t OCOTP_ReadFuseShadowRegister(OCOTP_Type *base, uint32_t address)
+{
+ assert(NULL != base);
+
+ /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* If ERROR bit was set, clear access error status bit. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ OCOTP_ClearErrorStatus(base);
+ }
+
+ /* Set the read timing. */
+ OCOTP_SetReadTiming(base, s_timingConfig);
+
+ /* Wait for busy bit is cleared. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Clear access error status bit. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ OCOTP_ClearErrorStatus(base);
+ }
+
+ /* Write requested address to register. */
+ base->CTRL_CLR = OCOTP_CTRL_CLR_ADDR_MASK;
+ base->CTRL_SET = OCOTP_CTRL_SET_ADDR(address);
+
+ /* Set OCOTP auto read enable. */
+ base->READ_CTRL = OCOTP_READ_CTRL_READ_FUSE_MASK;
+
+ /* Wait for busy bit is cleared, and no error occurred on controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* If ERROR bit was set, this may be mean that the accsee to the register was wrong. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ /* Clear access error status bit. */
+ OCOTP_ClearErrorStatus(base);
+ }
+
+ /* Read the fuse data. */
+ return (base->READ_FUSE_DATA);
+}
+
+/* Write the fuse shadow register. */
+status_t OCOTP_WriteFuseShadowRegister(OCOTP_Type *base, uint32_t address, uint32_t data)
+{
+ assert(NULL != base);
+
+ /* Make sure the OCOTP is ready, Overlapped accesses are not supported by the controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Clear access error status bit. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ OCOTP_ClearErrorStatus(base);
+ }
+
+ /* Set write timing for OCOTP controller. */
+ OCOTP_SetWriteTiming(base, s_timingConfig);
+
+ /* Wait for busy bit is cleared. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* Clear access error status bit. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ OCOTP_ClearErrorStatus(base);
+ }
+
+ /* Write requested address and unlock key to register. */
+ base->CTRL_CLR = OCOTP_CTRL_CLR_ADDR_MASK | OCOTP_CTRL_WR_UNLOCK_MASK;
+ base->CTRL_SET = OCOTP_CTRL_SET_ADDR(address) | OCOTP_CTRL_WR_UNLOCK(OCOTP_WRITE_UNLOCK_KEY);
+
+ /* Write data to register. */
+ base->DATA = data;
+
+ /* Wait for busy bit is cleared, and no error occurred on controller. */
+ while (OCOTP_CheckBusyStatus(base))
+ {
+ }
+
+ /* If ERROR bit was set, this may be mean that the accsee to the register was wrong. */
+ if (OCOTP_CheckErrorStatus(base))
+ {
+ /* Clear access error status bit. */
+ OCOTP_ClearErrorStatus(base);
+
+ return kStatus_OCOTP_AccessError;
+ }
+
+ /* Reload the fuse register. */
+ OCOTP_ReloadShadowRegister(base);
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pit.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pit.c
new file mode 100644
index 0000000000..659de24999
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pit.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pit.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pit"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base PIT peripheral base address
+ *
+ * @return The PIT instance
+ */
+static uint32_t PIT_GetInstance(PIT_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to PIT bases for each instance. */
+static PIT_Type *const s_pitBases[] = PIT_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to PIT clocks for each instance. */
+static const clock_ip_name_t s_pitClocks[] = PIT_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t PIT_GetInstance(PIT_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pitBases); instance++)
+ {
+ if (s_pitBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pitBases));
+
+ return instance;
+}
+
+/*!
+ * brief Ungates the PIT clock, enables the PIT module, and configures the peripheral for basic operations.
+ *
+ * note This API should be called at the beginning of the application using the PIT driver.
+ *
+ * param base PIT peripheral base address
+ * param config Pointer to the user's PIT config structure
+ */
+void PIT_Init(PIT_Type *base, const pit_config_t *config)
+{
+ assert(NULL != config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate the PIT clock*/
+ CLOCK_EnableClock(s_pitClocks[PIT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_PIT_HAS_MDIS) && FSL_FEATURE_PIT_HAS_MDIS
+ /* Enable PIT timers */
+ base->MCR &= ~PIT_MCR_MDIS_MASK;
+#endif
+
+#if defined(FSL_FEATURE_PIT_TIMER_COUNT) && (FSL_FEATURE_PIT_TIMER_COUNT)
+ /* Clear all status bits for all channels to make sure the status of all TCTRL registers is clean. */
+ for (uint8_t i = 0U; i < (uint32_t)FSL_FEATURE_PIT_TIMER_COUNT; i++)
+ {
+ base->CHANNEL[i].TCTRL &= ~(PIT_TCTRL_TEN_MASK | PIT_TCTRL_TIE_MASK | PIT_TCTRL_CHN_MASK);
+ }
+#endif /* FSL_FEATURE_PIT_TIMER_COUNT */
+
+ /* Config timer operation when in debug mode */
+ if (true == config->enableRunInDebug)
+ {
+ base->MCR &= ~PIT_MCR_FRZ_MASK;
+ }
+ else
+ {
+ base->MCR |= PIT_MCR_FRZ_MASK;
+ }
+}
+
+/*!
+ * brief Gates the PIT clock and disables the PIT module.
+ *
+ * param base PIT peripheral base address
+ */
+void PIT_Deinit(PIT_Type *base)
+{
+#if defined(FSL_FEATURE_PIT_HAS_MDIS) && FSL_FEATURE_PIT_HAS_MDIS
+ /* Disable PIT timers */
+ base->MCR |= PIT_MCR_MDIS_MASK;
+#endif
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the PIT clock*/
+ CLOCK_DisableClock(s_pitClocks[PIT_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+#if defined(FSL_FEATURE_PIT_HAS_LIFETIME_TIMER) && FSL_FEATURE_PIT_HAS_LIFETIME_TIMER
+
+/*!
+ * brief Reads the current lifetime counter value.
+ *
+ * The lifetime timer is a 64-bit timer which chains timer 0 and timer 1 together.
+ * Timer 0 and 1 are chained by calling the PIT_SetTimerChainMode before using this timer.
+ * The period of lifetime timer is equal to the "period of timer 0 * period of timer 1".
+ * For the 64-bit value, the higher 32-bit has the value of timer 1, and the lower 32-bit
+ * has the value of timer 0.
+ *
+ * param base PIT peripheral base address
+ *
+ * return Current lifetime timer value
+ */
+uint64_t PIT_GetLifetimeTimerCount(PIT_Type *base)
+{
+ uint32_t valueH = 0U;
+ uint32_t valueL = 0U;
+
+ /* LTMR64H should be read before LTMR64L */
+ valueH = base->LTMR64H;
+ valueL = base->LTMR64L;
+
+ return (((uint64_t)valueH << 32U) + (uint64_t)(valueL));
+}
+
+#endif /* FSL_FEATURE_PIT_HAS_LIFETIME_TIMER */
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pmu.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pmu.c
new file mode 100644
index 0000000000..8e8b0473bf
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pmu.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "fsl_pmu.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pmu"
+#endif
+
+/*!
+ * name Status.
+ * {
+ */
+
+uint32_t PMU_GetStatusFlags(PMU_Type *base)
+{
+ uint32_t ret = 0U;
+
+ /* For 1P1. */
+ if (PMU_REG_1P1_OK_VDD1P1_MASK == (PMU_REG_1P1_OK_VDD1P1_MASK & base->REG_1P1))
+ {
+ ret |= (uint32_t)kPMU_1P1RegulatorOutputOK;
+ }
+ if (PMU_REG_1P1_BO_VDD1P1_MASK == (PMU_REG_1P1_BO_VDD1P1_MASK & base->REG_1P1))
+ {
+ ret |= (uint32_t)kPMU_1P1BrownoutOnOutput;
+ }
+
+ /* For 3P0. */
+ if (PMU_REG_3P0_OK_VDD3P0_MASK == (PMU_REG_3P0_OK_VDD3P0_MASK & base->REG_3P0))
+ {
+ ret |= (uint32_t)kPMU_3P0RegulatorOutputOK;
+ }
+ if (PMU_REG_3P0_BO_VDD3P0_MASK == (PMU_REG_3P0_BO_VDD3P0_MASK & base->REG_3P0))
+ {
+ ret |= (uint32_t)kPMU_3P0BrownoutOnOutput;
+ }
+
+ /* For 2P5. */
+ if (PMU_REG_2P5_OK_VDD2P5_MASK == (PMU_REG_2P5_OK_VDD2P5_MASK & base->REG_2P5))
+ {
+ ret |= (uint32_t)kPMU_2P5RegulatorOutputOK;
+ }
+ if (PMU_REG_2P5_BO_VDD2P5_MASK == (PMU_REG_2P5_BO_VDD2P5_MASK & base->REG_2P5))
+ {
+ ret |= (uint32_t)kPMU_2P5BrownoutOnOutput;
+ }
+
+ return ret;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pwm.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pwm.c
new file mode 100644
index 0000000000..d16fe3a139
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pwm.c
@@ -0,0 +1,935 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pwm.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pwm"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance from the base address
+ *
+ * @param base PWM peripheral base address
+ *
+ * @return The PWM module instance
+ */
+static uint32_t PWM_GetInstance(PWM_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to PWM bases for each instance. */
+static PWM_Type *const s_pwmBases[] = PWM_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to PWM clocks for each PWM submodule. */
+static const clock_ip_name_t s_pwmClocks[][FSL_FEATURE_PWM_SUBMODULE_COUNT] = PWM_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Complement the variable of type uint16_t as needed
+ *
+ * This function can complement the variable of type uint16_t as needed.For example,
+ * need to ask for the opposite of a positive integer.
+ *
+ * param value Parameters of type uint16_t
+ */
+static inline uint16_t PWM_GetComplementU16(uint16_t value)
+{
+ return (~value + 1U);
+}
+
+static inline uint16_t dutyCycleToReloadValue(uint8_t dutyCyclePercent)
+{
+ /* Rounding calculations to improve the accuracy of reloadValue */
+ return ((65535U * dutyCyclePercent) + 50U) / 100U;
+}
+
+static uint32_t PWM_GetInstance(PWM_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pwmBases); instance++)
+ {
+ if (s_pwmBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pwmBases));
+
+ return instance;
+}
+
+/*!
+ * brief Ungates the PWM submodule clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the PWM driver.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param config Pointer to user's PWM config structure.
+ *
+ * return kStatus_Success means success; else failed.
+ */
+status_t PWM_Init(PWM_Type *base, pwm_submodule_t subModule, const pwm_config_t *config)
+{
+ assert(config);
+
+ uint16_t reg;
+
+ /* Source clock for submodule 0 cannot be itself */
+ if ((config->clockSource == kPWM_Submodule0Clock) && (subModule == kPWM_Module_0))
+ {
+ return kStatus_Fail;
+ }
+
+ /* Reload source select clock for submodule 0 cannot be master reload */
+ if ((config->reloadSelect == kPWM_MasterReload) && (subModule == kPWM_Module_0))
+ {
+ return kStatus_Fail;
+ }
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Ungate the PWM submodule clock*/
+ CLOCK_EnableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Clear the fault status flags */
+ base->FSTS |= PWM_FSTS_FFLAG_MASK;
+
+ reg = base->SM[subModule].CTRL2;
+
+ /* Setup the submodule clock-source, control source of the INIT signal,
+ * source of the force output signal, operation in debug & wait modes and reload source select
+ */
+ reg &= ~(uint16_t)(PWM_CTRL2_CLK_SEL_MASK | PWM_CTRL2_FORCE_SEL_MASK | PWM_CTRL2_INIT_SEL_MASK |
+ PWM_CTRL2_INDEP_MASK | PWM_CTRL2_WAITEN_MASK | PWM_CTRL2_DBGEN_MASK | PWM_CTRL2_RELOAD_SEL_MASK);
+ reg |= (PWM_CTRL2_CLK_SEL(config->clockSource) | PWM_CTRL2_FORCE_SEL(config->forceTrigger) |
+ PWM_CTRL2_INIT_SEL(config->initializationControl) | PWM_CTRL2_DBGEN(config->enableDebugMode) |
+ PWM_CTRL2_WAITEN(config->enableWait) | PWM_CTRL2_RELOAD_SEL(config->reloadSelect));
+
+ /* Setup PWM A & B to be independent or a complementary-pair */
+ switch (config->pairOperation)
+ {
+ case kPWM_Independent:
+ reg |= PWM_CTRL2_INDEP_MASK;
+ break;
+ case kPWM_ComplementaryPwmA:
+ base->MCTRL &= ~((uint16_t)1U << (PWM_MCTRL_IPOL_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_ComplementaryPwmB:
+ base->MCTRL |= ((uint16_t)1U << (PWM_MCTRL_IPOL_SHIFT + (uint16_t)subModule));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->SM[subModule].CTRL2 = reg;
+
+ reg = base->SM[subModule].CTRL;
+
+ /* Setup the clock prescale, load mode and frequency */
+ reg &= ~(uint16_t)(PWM_CTRL_PRSC_MASK | PWM_CTRL_LDFQ_MASK | PWM_CTRL_LDMOD_MASK);
+ reg |= (PWM_CTRL_PRSC(config->prescale) | PWM_CTRL_LDFQ(config->reloadFrequency));
+
+ /* Setup register reload logic */
+ switch (config->reloadLogic)
+ {
+ case kPWM_ReloadImmediate:
+ reg |= PWM_CTRL_LDMOD_MASK;
+ break;
+ case kPWM_ReloadPwmHalfCycle:
+ reg |= PWM_CTRL_HALF_MASK;
+ reg &= (uint16_t)(~PWM_CTRL_FULL_MASK);
+ break;
+ case kPWM_ReloadPwmFullCycle:
+ reg &= (uint16_t)(~PWM_CTRL_HALF_MASK);
+ reg |= PWM_CTRL_FULL_MASK;
+ break;
+ case kPWM_ReloadPwmHalfAndFullCycle:
+ reg |= PWM_CTRL_HALF_MASK;
+ reg |= PWM_CTRL_FULL_MASK;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->SM[subModule].CTRL = reg;
+
+ /* Issue a Force trigger event when configured to trigger locally */
+ if (config->forceTrigger == kPWM_Force_Local)
+ {
+ base->SM[subModule].CTRL2 |= PWM_CTRL2_FORCE(1U);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gate the PWM submodule clock
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to deinitialize
+ */
+void PWM_Deinit(PWM_Type *base, pwm_submodule_t subModule)
+{
+ /* Stop the submodule */
+ base->MCTRL &= ~((uint16_t)1U << (PWM_MCTRL_RUN_SHIFT + (uint16_t)subModule));
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Gate the PWM submodule clock*/
+ CLOCK_DisableClock(s_pwmClocks[PWM_GetInstance(base)][subModule]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Fill in the PWM config struct with the default settings
+ *
+ * The default values are:
+ * code
+ * config->enableDebugMode = false;
+ * config->enableWait = false;
+ * config->reloadSelect = kPWM_LocalReload;
+ * config->clockSource = kPWM_BusClock;
+ * config->prescale = kPWM_Prescale_Divide_1;
+ * config->initializationControl = kPWM_Initialize_LocalSync;
+ * config->forceTrigger = kPWM_Force_Local;
+ * config->reloadFrequency = kPWM_LoadEveryOportunity;
+ * config->reloadLogic = kPWM_ReloadImmediate;
+ * config->pairOperation = kPWM_Independent;
+ * endcode
+ * param config Pointer to user's PWM config structure.
+ */
+void PWM_GetDefaultConfig(pwm_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* PWM is paused in debug mode */
+ config->enableDebugMode = false;
+ /* PWM is paused in wait mode */
+ config->enableWait = false;
+ /* PWM module uses the local reload signal to reload registers */
+ config->reloadSelect = kPWM_LocalReload;
+ /* Use the IP Bus clock as source clock for the PWM submodule */
+ config->clockSource = kPWM_BusClock;
+ /* Clock source prescale is set to divide by 1*/
+ config->prescale = kPWM_Prescale_Divide_1;
+ /* Local sync causes initialization */
+ config->initializationControl = kPWM_Initialize_LocalSync;
+ /* The local force signal, CTRL2[FORCE], from the submodule is used to force updates */
+ config->forceTrigger = kPWM_Force_Local;
+ /* PWM reload frequency, reload opportunity is PWM half cycle or full cycle.
+ * This field is not used in Immediate reload mode
+ */
+ config->reloadFrequency = kPWM_LoadEveryOportunity;
+ /* Buffered-registers get loaded with new values as soon as LDOK bit is set */
+ config->reloadLogic = kPWM_ReloadImmediate;
+ /* PWM A & PWM B operate as 2 independent channels */
+ config->pairOperation = kPWM_Independent;
+}
+
+/*!
+ * brief Sets up the PWM signals for a PWM submodule.
+ *
+ * The function initializes the submodule according to the parameters passed in by the user. The function
+ * also sets up the value compare registers to match the PWM signal requirements.
+ * If the dead time insertion logic is enabled, the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param chnlParams Array of PWM channel parameters to configure the channel(s)
+ * param numOfChnls Number of channels to configure, this should be the size of the array passed in.
+ * Array size should not be more than 2 as each submodule has 2 pins to output PWM
+ * param mode PWM operation mode, options available in enumeration ::pwm_mode_t
+ * param pwmFreq_Hz PWM signal frequency in Hz
+ * param srcClock_Hz PWM main counter clock in Hz.
+ *
+ * return Returns kStatusFail if there was error setting up the signal; kStatusSuccess otherwise
+ */
+status_t PWM_SetupPwm(PWM_Type *base,
+ pwm_submodule_t subModule,
+ const pwm_signal_param_t *chnlParams,
+ uint8_t numOfChnls,
+ pwm_mode_t mode,
+ uint32_t pwmFreq_Hz,
+ uint32_t srcClock_Hz)
+{
+ assert(chnlParams);
+ assert(pwmFreq_Hz);
+ assert(numOfChnls);
+ assert(srcClock_Hz);
+
+ uint32_t pwmClock;
+ uint16_t pulseCnt = 0, pwmHighPulse = 0;
+ uint16_t modulo = 0;
+ uint8_t i, polarityShift = 0, outputEnableShift = 0;
+
+ if (numOfChnls > 2U)
+ {
+ /* Each submodule has 2 signals; PWM A & PWM B */
+ return kStatus_Fail;
+ }
+
+ /* Divide the clock by the prescale value */
+ pwmClock = (srcClock_Hz / (1UL << ((base->SM[subModule].CTRL & PWM_CTRL_PRSC_MASK) >> PWM_CTRL_PRSC_SHIFT)));
+ pulseCnt = (uint16_t)(pwmClock / pwmFreq_Hz);
+
+ /* Setup each PWM channel */
+ for (i = 0; i < numOfChnls; i++)
+ {
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * chnlParams->dutyCyclePercent) / 100U;
+
+ /* Setup the different match registers to generate the PWM signal */
+ switch (mode)
+ {
+ case kPWM_SignedCenterAligned:
+ /* Setup the PWM period for a signed center aligned signal */
+ if (i == 0U)
+ {
+ modulo = (pulseCnt >> 1U);
+ /* Indicates the start of the PWM period */
+ base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = 0;
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = modulo - 1U;
+ }
+
+ /* Setup the PWM dutycycle */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
+ base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
+ base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
+ }
+ break;
+ case kPWM_CenterAligned:
+ /* Setup the PWM period for an unsigned center aligned signal */
+ /* Indicates the start of the PWM period */
+ if (i == 0U)
+ {
+ base->SM[subModule].INIT = 0;
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = (pulseCnt / 2U);
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = pulseCnt - 1U;
+ }
+
+ /* Setup the PWM dutycycle */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
+ base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
+ base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
+ }
+ break;
+ case kPWM_SignedEdgeAligned:
+ /* Setup the PWM period for a signed edge aligned signal */
+ if (i == 0U)
+ {
+ modulo = (pulseCnt >> 1U);
+ /* Indicates the start of the PWM period */
+ base->SM[subModule].INIT = PWM_GetComplementU16(modulo);
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = 0;
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = modulo - 1U;
+ }
+
+ /* Setup the PWM dutycycle */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
+ base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
+ base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
+ }
+ break;
+ case kPWM_EdgeAligned:
+ /* Setup the PWM period for a unsigned edge aligned signal */
+ /* Indicates the start of the PWM period */
+ if (i == 0U)
+ {
+ base->SM[subModule].INIT = 0;
+ /* Indicates the center value */
+ base->SM[subModule].VAL0 = (pulseCnt / 2U);
+ /* Indicates the end of the PWM period */
+ /* The change during the end to start of the PWM period requires a count time */
+ base->SM[subModule].VAL1 = pulseCnt - 1U;
+ }
+
+ /* Setup the PWM dutycycle */
+ if (chnlParams->pwmChannel == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = 0;
+ base->SM[subModule].VAL3 = pwmHighPulse;
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = 0;
+ base->SM[subModule].VAL5 = pwmHighPulse;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ /* 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);
+ }
+
+ /* Set PWM output fault status */
+ switch (chnlParams->pwmChannel)
+ {
+ case kPWM_PwmA:
+ base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMAFS_MASK);
+ base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMAFS_SHIFT) &
+ (uint16_t)PWM_OCTRL_PWMAFS_MASK);
+ break;
+ case kPWM_PwmB:
+ base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMBFS_MASK);
+ base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMBFS_SHIFT) &
+ (uint16_t)PWM_OCTRL_PWMBFS_MASK);
+ break;
+ case kPWM_PwmX:
+ base->SM[subModule].OCTRL &= ~((uint16_t)PWM_OCTRL_PWMXFS_MASK);
+ base->SM[subModule].OCTRL |= (((uint16_t)(chnlParams->faultState) << (uint16_t)PWM_OCTRL_PWMXFS_SHIFT) &
+ (uint16_t)PWM_OCTRL_PWMXFS_MASK);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ /* Setup signal active level */
+ if ((bool)chnlParams->level == kPWM_HighTrue)
+ {
+ base->SM[subModule].OCTRL &= ~((uint16_t)1U << (uint16_t)polarityShift);
+ }
+ else
+ {
+ base->SM[subModule].OCTRL |= ((uint16_t)1U << (uint16_t)polarityShift);
+ }
+ /* Enable PWM output */
+ base->OUTEN |= ((uint16_t)1U << ((uint16_t)outputEnableShift + (uint16_t)subModule));
+
+ /* Get the next channel parameters */
+ chnlParams++;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Updates the PWM signal's dutycycle.
+ *
+ * The function updates the PWM dutycyle to the new value that is passed in.
+ * If the dead time insertion logic is enabled then the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmSignal Signal (PWM A or PWM B) to update
+ * param currPwmMode The current PWM mode set during PWM setup
+ * param dutyCyclePercent New PWM pulse width, value should be between 0 to 100
+ * 0=inactive signal(0% duty cycle)...
+ * 100=active signal (100% duty cycle)
+ */
+void PWM_UpdatePwmDutycycle(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmSignal,
+ pwm_mode_t currPwmMode,
+ uint8_t dutyCyclePercent)
+{
+ assert(dutyCyclePercent <= 100U);
+ assert((uint16_t)pwmSignal < 2U);
+ uint16_t reloadValue = dutyCycleToReloadValue(dutyCyclePercent);
+
+ PWM_UpdatePwmDutycycleHighAccuracy(base, subModule, pwmSignal, currPwmMode, reloadValue);
+}
+
+/*!
+ * brief Updates the PWM signal's dutycycle with 16-bit accuracy.
+ *
+ * The function updates the PWM dutycyle to the new value that is passed in.
+ * If the dead time insertion logic is enabled then the pulse period is reduced by the
+ * dead time period specified by the user.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmSignal Signal (PWM A or PWM B) to update
+ * param currPwmMode The current PWM mode set during PWM setup
+ * param dutyCycle New PWM pulse width, value should be between 0 to 65535
+ * 0=inactive signal(0% duty cycle)...
+ * 65535=active signal (100% duty cycle)
+ */
+void PWM_UpdatePwmDutycycleHighAccuracy(
+ PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmSignal, pwm_mode_t currPwmMode, uint16_t dutyCycle)
+{
+ assert((uint16_t)pwmSignal < 2U);
+ uint16_t pulseCnt = 0, pwmHighPulse = 0;
+ uint16_t modulo = 0;
+
+ switch (currPwmMode)
+ {
+ case kPWM_SignedCenterAligned:
+ modulo = base->SM[subModule].VAL1 + 1U;
+ pulseCnt = modulo * 2U;
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
+
+ /* Setup the PWM dutycycle */
+ if (pwmSignal == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(pwmHighPulse / 2U);
+ base->SM[subModule].VAL3 = (pwmHighPulse / 2U);
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(pwmHighPulse / 2U);
+ base->SM[subModule].VAL5 = (pwmHighPulse / 2U);
+ }
+ break;
+ case kPWM_CenterAligned:
+ pulseCnt = base->SM[subModule].VAL1 + 1U;
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
+
+ /* Setup the PWM dutycycle */
+ if (pwmSignal == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = ((pulseCnt - pwmHighPulse) / 2U);
+ base->SM[subModule].VAL3 = ((pulseCnt + pwmHighPulse) / 2U);
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = ((pulseCnt - pwmHighPulse) / 2U);
+ base->SM[subModule].VAL5 = ((pulseCnt + pwmHighPulse) / 2U);
+ }
+ break;
+ case kPWM_SignedEdgeAligned:
+ modulo = base->SM[subModule].VAL1 + 1U;
+ pulseCnt = modulo * 2U;
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
+
+ /* Setup the PWM dutycycle */
+ if (pwmSignal == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = PWM_GetComplementU16(modulo);
+ base->SM[subModule].VAL3 = PWM_GetComplementU16(modulo) + pwmHighPulse;
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = PWM_GetComplementU16(modulo);
+ base->SM[subModule].VAL5 = PWM_GetComplementU16(modulo) + pwmHighPulse;
+ }
+ break;
+ case kPWM_EdgeAligned:
+ pulseCnt = base->SM[subModule].VAL1 + 1U;
+ /* Calculate pulse width */
+ pwmHighPulse = (pulseCnt * dutyCycle) / 65535U;
+
+ /* Setup the PWM dutycycle */
+ if (pwmSignal == kPWM_PwmA)
+ {
+ base->SM[subModule].VAL2 = 0;
+ base->SM[subModule].VAL3 = pwmHighPulse;
+ }
+ else
+ {
+ base->SM[subModule].VAL4 = 0;
+ base->SM[subModule].VAL5 = pwmHighPulse;
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * brief Sets up the PWM input capture
+ *
+ * Each PWM submodule has 3 pins that can be configured for use as input capture pins. This function
+ * sets up the capture parameters for each pin and enables the pin for input capture operation.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmChannel Channel in the submodule to setup
+ * param inputCaptureParams Parameters passed in to set up the input pin
+ */
+void PWM_SetupInputCapture(PWM_Type *base,
+ pwm_submodule_t subModule,
+ pwm_channels_t pwmChannel,
+ const pwm_input_capture_param_t *inputCaptureParams)
+{
+ uint16_t reg = 0;
+ switch (pwmChannel)
+ {
+ case kPWM_PwmA:
+ /* Setup the capture paramters for PWM A pin */
+ reg = (PWM_CAPTCTRLA_INP_SELA(inputCaptureParams->captureInputSel) |
+ PWM_CAPTCTRLA_EDGA0(inputCaptureParams->edge0) | PWM_CAPTCTRLA_EDGA1(inputCaptureParams->edge1) |
+ PWM_CAPTCTRLA_ONESHOTA(inputCaptureParams->enableOneShotCapture) |
+ PWM_CAPTCTRLA_CFAWM(inputCaptureParams->fifoWatermark));
+ /* Enable the edge counter if using the output edge counter */
+ if (inputCaptureParams->captureInputSel)
+ {
+ reg |= PWM_CAPTCTRLA_EDGCNTA_EN_MASK;
+ }
+ /* Enable input capture operation */
+ reg |= PWM_CAPTCTRLA_ARMA_MASK;
+
+ base->SM[subModule].CAPTCTRLA = reg;
+
+ /* Setup the compare value when using the edge counter as source */
+ base->SM[subModule].CAPTCOMPA = PWM_CAPTCOMPA_EDGCMPA(inputCaptureParams->edgeCompareValue);
+ /* Setup PWM A pin for input capture */
+ base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMA_EN_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_PwmB:
+ /* Setup the capture paramters for PWM B pin */
+ reg = (PWM_CAPTCTRLB_INP_SELB(inputCaptureParams->captureInputSel) |
+ PWM_CAPTCTRLB_EDGB0(inputCaptureParams->edge0) | PWM_CAPTCTRLB_EDGB1(inputCaptureParams->edge1) |
+ PWM_CAPTCTRLB_ONESHOTB(inputCaptureParams->enableOneShotCapture) |
+ PWM_CAPTCTRLB_CFBWM(inputCaptureParams->fifoWatermark));
+ /* Enable the edge counter if using the output edge counter */
+ if (inputCaptureParams->captureInputSel)
+ {
+ reg |= PWM_CAPTCTRLB_EDGCNTB_EN_MASK;
+ }
+ /* Enable input capture operation */
+ reg |= PWM_CAPTCTRLB_ARMB_MASK;
+
+ base->SM[subModule].CAPTCTRLB = reg;
+
+ /* Setup the compare value when using the edge counter as source */
+ base->SM[subModule].CAPTCOMPB = PWM_CAPTCOMPB_EDGCMPB(inputCaptureParams->edgeCompareValue);
+ /* Setup PWM B pin for input capture */
+ base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMB_EN_SHIFT + (uint16_t)subModule));
+ break;
+ case kPWM_PwmX:
+ reg = (PWM_CAPTCTRLX_INP_SELX(inputCaptureParams->captureInputSel) |
+ PWM_CAPTCTRLX_EDGX0(inputCaptureParams->edge0) | PWM_CAPTCTRLX_EDGX1(inputCaptureParams->edge1) |
+ PWM_CAPTCTRLX_ONESHOTX(inputCaptureParams->enableOneShotCapture) |
+ PWM_CAPTCTRLX_CFXWM(inputCaptureParams->fifoWatermark));
+ /* Enable the edge counter if using the output edge counter */
+ if (inputCaptureParams->captureInputSel)
+ {
+ reg |= PWM_CAPTCTRLX_EDGCNTX_EN_MASK;
+ }
+ /* Enable input capture operation */
+ reg |= PWM_CAPTCTRLX_ARMX_MASK;
+
+ base->SM[subModule].CAPTCTRLX = reg;
+
+ /* Setup the compare value when using the edge counter as source */
+ base->SM[subModule].CAPTCOMPX = PWM_CAPTCOMPX_EDGCMPX(inputCaptureParams->edgeCompareValue);
+ /* Setup PWM X pin for input capture */
+ base->OUTEN &= ~((uint16_t)1U << (PWM_OUTEN_PWMX_EN_SHIFT + (uint16_t)subModule));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+/*!
+ * @brief Sets up the PWM fault input filter.
+ *
+ * @param base PWM peripheral base address
+ * @param faultInputFilterParams Parameters passed in to set up the fault input filter.
+ */
+void PWM_SetupFaultInputFilter(PWM_Type *base, const pwm_fault_input_filter_param_t *faultInputFilterParams)
+{
+ assert(NULL != faultInputFilterParams);
+
+ /* When changing values for fault period from a non-zero value, first write a value of 0 to clear the filter. */
+ if (0U != (base->FFILT & PWM_FFILT_FILT_PER_MASK))
+ {
+ base->FFILT &= ~(uint16_t)(PWM_FFILT_FILT_PER_MASK);
+ }
+
+ base->FFILT = (uint16_t)(PWM_FFILT_FILT_PER(faultInputFilterParams->faultFilterPeriod) |
+ PWM_FFILT_FILT_CNT(faultInputFilterParams->faultFilterCount) |
+ PWM_FFILT_GSTR(faultInputFilterParams->faultGlitchStretch ? 1U : 0U));
+}
+
+/*!
+ * brief Sets up the PWM fault protection.
+ *
+ * PWM has 4 fault inputs.
+ *
+ * param base PWM peripheral base address
+ * param faultNum PWM fault to configure.
+ * param faultParams Pointer to the PWM fault config structure
+ */
+void PWM_SetupFaults(PWM_Type *base, pwm_fault_input_t faultNum, const pwm_fault_param_t *faultParams)
+{
+ assert(faultParams);
+ uint16_t reg;
+
+ reg = base->FCTRL;
+ /* Set the faults level-settting */
+ if (faultParams->faultLevel)
+ {
+ reg |= ((uint16_t)1U << (PWM_FCTRL_FLVL_SHIFT + (uint16_t)faultNum));
+ }
+ else
+ {
+ reg &= ~((uint16_t)1U << (PWM_FCTRL_FLVL_SHIFT + (uint16_t)faultNum));
+ }
+ /* Set the fault clearing mode */
+ if ((uint16_t)faultParams->faultClearingMode != 0U)
+ {
+ /* Use manual fault clearing */
+ reg &= ~((uint16_t)1U << (PWM_FCTRL_FAUTO_SHIFT + (uint16_t)faultNum));
+ if (faultParams->faultClearingMode == kPWM_ManualSafety)
+ {
+ /* Use manual fault clearing with safety mode enabled */
+ reg |= ((uint16_t)1U << (PWM_FCTRL_FSAFE_SHIFT + (uint16_t)faultNum));
+ }
+ else
+ {
+ /* Use manual fault clearing with safety mode disabled */
+ reg &= ~((uint16_t)1U << (PWM_FCTRL_FSAFE_SHIFT + (uint16_t)faultNum));
+ }
+ }
+ else
+ {
+ /* Use automatic fault clearing */
+ reg |= ((uint16_t)1U << (PWM_FCTRL_FAUTO_SHIFT + (uint16_t)faultNum));
+ }
+ base->FCTRL = reg;
+
+ /* Set the combinational path option */
+ if (faultParams->enableCombinationalPath)
+ {
+ /* Combinational path from the fault input to the PWM output is available */
+ base->FCTRL2 &= ~((uint16_t)1U << (uint16_t)faultNum);
+ }
+ else
+ {
+ /* No combinational path available, only fault filter & latch signal can disable PWM output */
+ base->FCTRL2 |= ((uint16_t)1U << (uint16_t)faultNum);
+ }
+
+ /* Initially clear both recovery modes */
+ reg = base->FSTS;
+ reg &= ~(((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum)) |
+ ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum)));
+ /* Setup fault recovery */
+ switch (faultParams->recoverMode)
+ {
+ case kPWM_NoRecovery:
+ break;
+ case kPWM_RecoverHalfCycle:
+ reg |= ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum));
+ break;
+ case kPWM_RecoverFullCycle:
+ reg |= ((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum));
+ break;
+ case kPWM_RecoverHalfAndFullCycle:
+ reg |= ((uint16_t)1U << (PWM_FSTS_FHALF_SHIFT + (uint16_t)faultNum));
+ reg |= ((uint16_t)1U << (PWM_FSTS_FFULL_SHIFT + (uint16_t)faultNum));
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->FSTS = reg;
+}
+
+/*!
+ * brief Fill in the PWM fault config struct with the default settings
+ *
+ * The default values are:
+ * code
+ * config->faultClearingMode = kPWM_Automatic;
+ * config->faultLevel = false;
+ * config->enableCombinationalPath = true;
+ * config->recoverMode = kPWM_NoRecovery;
+ * endcode
+ * param config Pointer to user's PWM fault config structure.
+ */
+void PWM_FaultDefaultConfig(pwm_fault_param_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* PWM uses automatic fault clear mode */
+ config->faultClearingMode = kPWM_Automatic;
+ /* PWM fault level is set to logic 0 */
+ config->faultLevel = false;
+ /* Combinational Path from fault input is enabled */
+ config->enableCombinationalPath = true;
+ /* PWM output will stay inactive when recovering from a fault */
+ config->recoverMode = kPWM_NoRecovery;
+}
+
+/*!
+ * brief Selects the signal to output on a PWM pin when a FORCE_OUT signal is asserted.
+ *
+ * The user specifies which channel to configure by supplying the submodule number and whether
+ * to modify PWM A or PWM B within that submodule.
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param pwmChannel Channel to configure
+ * param mode Signal to output when a FORCE_OUT is triggered
+ */
+void PWM_SetupForceSignal(PWM_Type *base, pwm_submodule_t subModule, pwm_channels_t pwmChannel, pwm_force_signal_t mode)
+
+{
+ uint16_t shift;
+ uint16_t reg;
+
+ /* DTSRCSEL register has 4 bits per submodule; 2 bits for PWM A and 2 bits for PWM B */
+ shift = ((uint16_t)subModule * 4U) + ((uint16_t)pwmChannel * 2U);
+
+ /* Setup the signal to be passed upon occurrence of a FORCE_OUT signal */
+ reg = base->DTSRCSEL;
+ reg &= ~((uint16_t)0x3U << shift);
+ reg |= (uint16_t)((uint16_t)mode << shift);
+ base->DTSRCSEL = reg;
+}
+
+/*!
+ * brief Enables the selected PWM interrupts
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+void PWM_EnableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
+{
+ /* Upper 16 bits are for related to the submodule */
+ base->SM[subModule].INTEN |= ((uint16_t)mask & 0xFFFFU);
+ /* Fault related interrupts */
+ base->FCTRL |= ((uint16_t)(mask >> 16U) & PWM_FCTRL_FIE_MASK);
+}
+
+/*!
+ * brief Disables the selected PWM interrupts
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+void PWM_DisableInterrupts(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
+{
+ base->SM[subModule].INTEN &= ~((uint16_t)mask & 0xFFFFU);
+ base->FCTRL &= ~((uint16_t)(mask >> 16U) & PWM_FCTRL_FIE_MASK);
+}
+
+/*!
+ * brief Gets the enabled PWM interrupts
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ *
+ * return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::pwm_interrupt_enable_t
+ */
+uint32_t PWM_GetEnabledInterrupts(PWM_Type *base, pwm_submodule_t subModule)
+{
+ uint32_t enabledInterrupts;
+
+ enabledInterrupts = base->SM[subModule].INTEN;
+ enabledInterrupts |= (((uint32_t)base->FCTRL & PWM_FCTRL_FIE_MASK) << 16UL);
+ return enabledInterrupts;
+}
+
+/*!
+ * brief Gets the PWM status flags
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::pwm_status_flags_t
+ */
+uint32_t PWM_GetStatusFlags(PWM_Type *base, pwm_submodule_t subModule)
+{
+ uint32_t statusFlags;
+
+ statusFlags = base->SM[subModule].STS;
+ statusFlags |= (((uint32_t)base->FSTS & PWM_FSTS_FFLAG_MASK) << 16UL);
+
+ return statusFlags;
+}
+
+/*!
+ * brief Clears the PWM status flags
+ *
+ * param base PWM peripheral base address
+ * param subModule PWM submodule to configure
+ * param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::pwm_status_flags_t
+ */
+void PWM_ClearStatusFlags(PWM_Type *base, pwm_submodule_t subModule, uint32_t mask)
+{
+ uint16_t reg;
+
+ base->SM[subModule].STS = ((uint16_t)mask & 0xFFFFU);
+ reg = base->FSTS;
+ /* Clear the fault flags and set only the ones we wish to clear as the fault flags are cleared
+ * by writing a login one
+ */
+ reg &= ~(uint16_t)(PWM_FSTS_FFLAG_MASK);
+ reg |= (uint16_t)((mask >> 16U) & PWM_FSTS_FFLAG_MASK);
+ base->FSTS = reg;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pxp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pxp.c
new file mode 100644
index 0000000000..2d9740ff54
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_pxp.c
@@ -0,0 +1,1050 @@
+/*
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pxp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pxp"
+#endif
+
+/* The CSC2 coefficient is ###.####_#### */
+#define PXP_CSC2_COEF_INT_WIDTH 2
+#define PXP_CSC2_COEF_FRAC_WIDTH 8
+
+/* Compatibility map macro. */
+#if defined(PXP_PS_CLRKEYLOW_0_PIXEL_MASK) && (!defined(PXP_PS_CLRKEYLOW_PIXEL_MASK))
+#define PS_CLRKEYLOW PS_CLRKEYLOW_0
+#define PS_CLRKEYHIGH PS_CLRKEYHIGH_0
+#endif
+#if defined(PXP_AS_CLRKEYLOW_0_PIXEL_MASK) && (!defined(PXP_AS_CLRKEYLOW_PIXEL_MASK))
+#define AS_CLRKEYLOW AS_CLRKEYLOW_0
+#define AS_CLRKEYHIGH AS_CLRKEYHIGH_0
+#endif
+
+#define PXP_MAX_HEIGHT ((PXP_OUT_LRC_Y_MASK >> PXP_OUT_LRC_Y_SHIFT) + 1U)
+
+typedef union _u32_f32
+{
+ float f32;
+ uint32_t u32;
+} u32_f32_t;
+
+typedef union _pxp_pvoid_u32
+{
+ void *pvoid;
+ uint32_t u32;
+} pxp_pvoid_u32_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance from the base address
+ *
+ * @param base PXP peripheral base address
+ *
+ * @return The PXP module instance
+ */
+static uint32_t PXP_GetInstance(PXP_Type *base);
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
+/*!
+ * @brief Convert IEEE 754 float value to the value could be written to registers.
+ *
+ * This function converts the float value to integer value to set the scaler
+ * and CSC parameters.
+ *
+ * This function is an alternative implemention of the following code with no
+ * MISRA 2004 rule 10.4 error:
+ *
+ * @code
+ return (uint32_t)(floatValue * (float)(1 << fracBits));
+ @endcode
+ *
+ * @param floatValue The float value to convert.
+ * @param intBits Bits number of integer part in result.
+ * @param fracBits Bits number of fractional part in result.
+ * @return The value to set to register.
+ */
+static uint32_t PXP_ConvertFloat(float floatValue, uint8_t intBits, uint8_t fracBits);
+#endif
+
+/*!
+ * @brief Convert the desired scale fact to DEC and PS_SCALE.
+ *
+ * @param inputDimension Input dimension.
+ * @param outputDimension Output dimension.
+ * @param dec The decimation filter contr0l value.
+ * @param scale The scale value set to register PS_SCALE.
+ */
+static void PXP_GetScalerParam(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale);
+
+/*!
+ * @brief Reset the PXP to initialized state.
+ *
+ * @param base PXP peripheral base address.
+ */
+static void PXP_ResetToInit(PXP_Type *base);
+
+/*!
+ * @brief Copy rectangle.
+ *
+ * @param base PXP peripheral base address.
+ * @param srcAddr Start address of the soruce rectangle.
+ * @param srcPitchBytes Pitch of source buffer.
+ * @param destAddr Start address of the destination rectangle.
+ * @param destPitchBytes Pitch of destination buffer.
+ * @param width How many pixels one line to copy.
+ * @param height How many lines to copy.
+ * @param pixelFormat Pixel format.
+ */
+static void PXP_StartRectCopy(PXP_Type *base,
+ uint32_t srcAddr,
+ uint16_t srcPitchBytes,
+ uint32_t destAddr,
+ uint16_t destPitchBytes,
+ uint16_t width,
+ uint16_t height,
+ pxp_as_pixel_format_t pixelFormat);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to PXP bases for each instance. */
+static PXP_Type *const s_pxpBases[] = PXP_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to PXP clocks for each PXP submodule. */
+static const clock_ip_name_t s_pxpClocks[] = PXP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t PXP_GetInstance(PXP_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pxpBases); instance++)
+ {
+ if (s_pxpBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pxpBases));
+
+ return instance;
+}
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
+static uint32_t PXP_ConvertFloat(float floatValue, uint8_t intBits, uint8_t fracBits)
+{
+ /* One bit reserved for sign bit. */
+ assert(intBits + fracBits < 32);
+
+ u32_f32_t u32_f32;
+ uint32_t ret;
+
+ u32_f32.f32 = floatValue;
+ uint32_t floatBits = u32_f32.u32;
+ int32_t expValue = (int32_t)((floatBits & 0x7F800000U) >> 23U) - 127;
+
+ ret = (floatBits & 0x007FFFFFU) | 0x00800000U;
+ expValue += fracBits;
+
+ if (expValue < 0)
+ {
+ return 0U;
+ }
+ else if (expValue > 23)
+ {
+ /* should not exceed 31-bit when left shift. */
+ assert((expValue - 23) <= 7);
+ ret <<= (expValue - 23);
+ }
+ else
+ {
+ ret >>= (23 - expValue);
+ }
+
+ /* Set the sign bit. */
+ if (floatBits & 0x80000000U)
+ {
+ ret = ((~ret) + 1U) & ~(((uint32_t)-1) << (intBits + fracBits + 1));
+ }
+
+ return ret;
+}
+#endif
+
+static void PXP_GetScalerParam(uint16_t inputDimension, uint16_t outputDimension, uint8_t *dec, uint32_t *scale)
+{
+ uint32_t scaleFact = ((uint32_t)inputDimension << 12U) / outputDimension;
+
+ if (scaleFact >= (16UL << 12U))
+ {
+ /* Desired fact is two large, use the largest support value. */
+ *dec = 3U;
+ *scale = 0x2000U;
+ }
+ else
+ {
+ if (scaleFact > (8UL << 12U))
+ {
+ *dec = 3U;
+ }
+ else if (scaleFact > (4UL << 12U))
+ {
+ *dec = 2U;
+ }
+ else if (scaleFact > (2UL << 12U))
+ {
+ *dec = 1U;
+ }
+ else
+ {
+ *dec = 0U;
+ }
+
+ *scale = scaleFact >> (*dec);
+
+ if (0U == *scale)
+ {
+ *scale = 1U;
+ }
+ }
+}
+
+static void PXP_ResetToInit(PXP_Type *base)
+{
+ uint32_t ctrl = 0U;
+
+ PXP_Reset(base);
+
+/* Enable the process engine in primary processing flow. */
+#if defined(PXP_CTRL_ENABLE_ROTATE0_MASK)
+ ctrl |= PXP_CTRL_ENABLE_ROTATE0_MASK;
+#endif
+#if defined(PXP_CTRL_ENABLE_ROTATE1_MASK)
+ ctrl |= PXP_CTRL_ENABLE_ROTATE1_MASK;
+#endif
+#if defined(PXP_CTRL_ENABLE_CSC2_MASK)
+ ctrl |= PXP_CTRL_ENABLE_CSC2_MASK;
+#endif
+#if defined(PXP_CTRL_ENABLE_LUT_MASK)
+ ctrl |= PXP_CTRL_ENABLE_LUT_MASK;
+#endif
+#if defined(PXP_CTRL_ENABLE_PS_AS_OUT_MASK)
+ ctrl |= PXP_CTRL_ENABLE_PS_AS_OUT_MASK;
+#endif
+
+ base->CTRL = ctrl;
+}
+
+/*!
+ * brief Initialize the PXP.
+ *
+ * This function enables the PXP peripheral clock, and resets the PXP registers
+ * to default status.
+ *
+ * param base PXP peripheral base address.
+ */
+void PXP_Init(PXP_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = PXP_GetInstance(base);
+ CLOCK_EnableClock(s_pxpClocks[instance]);
+#endif
+
+ PXP_ResetToInit(base);
+}
+
+/*!
+ * brief De-initialize the PXP.
+ *
+ * This function disables the PXP peripheral clock.
+ *
+ * param base PXP peripheral base address.
+ */
+void PXP_Deinit(PXP_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ uint32_t instance = PXP_GetInstance(base);
+ CLOCK_DisableClock(s_pxpClocks[instance]);
+#endif
+}
+
+/*!
+ * brief Reset the PXP.
+ *
+ * This function resets the PXP peripheral registers to default status.
+ *
+ * param base PXP peripheral base address.
+ */
+void PXP_Reset(PXP_Type *base)
+{
+ base->CTRL_SET = PXP_CTRL_SFTRST_MASK;
+ base->CTRL_CLR = (PXP_CTRL_SFTRST_MASK | PXP_CTRL_CLKGATE_MASK);
+}
+
+/*!
+ * brief Set the alpha surface input buffer configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetAlphaSurfaceBufferConfig(PXP_Type *base, const pxp_as_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ base->AS_CTRL = (base->AS_CTRL & ~PXP_AS_CTRL_FORMAT_MASK) | PXP_AS_CTRL_FORMAT(config->pixelFormat);
+
+ base->AS_BUF = config->bufferAddr;
+ base->AS_PITCH = config->pitchBytes;
+}
+
+/*!
+ * brief Set the alpha surface blending configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration structure.
+ */
+void PXP_SetAlphaSurfaceBlendConfig(PXP_Type *base, const pxp_as_blend_config_t *config)
+{
+ assert(NULL != config);
+ uint32_t reg;
+
+ reg = base->AS_CTRL;
+ reg &=
+ ~(PXP_AS_CTRL_ALPHA0_INVERT_MASK | PXP_AS_CTRL_ROP_MASK | PXP_AS_CTRL_ALPHA_MASK | PXP_AS_CTRL_ALPHA_CTRL_MASK);
+ reg |= (PXP_AS_CTRL_ROP(config->ropMode) | PXP_AS_CTRL_ALPHA(config->alpha) |
+ PXP_AS_CTRL_ALPHA_CTRL(config->alphaMode));
+
+ if (config->invertAlpha)
+ {
+ reg |= PXP_AS_CTRL_ALPHA0_INVERT_MASK;
+ }
+
+ base->AS_CTRL = reg;
+}
+
+/*!
+ * brief Set the alpha surface position in output buffer.
+ *
+ * param base PXP peripheral base address.
+ * param upperLeftX X of the upper left corner.
+ * param upperLeftY Y of the upper left corner.
+ * param lowerRightX X of the lower right corner.
+ * param lowerRightY Y of the lower right corner.
+ */
+void PXP_SetAlphaSurfacePosition(
+ PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY)
+{
+ base->OUT_AS_ULC = PXP_OUT_AS_ULC_Y(upperLeftY) | PXP_OUT_AS_ULC_X(upperLeftX);
+ base->OUT_AS_LRC = PXP_OUT_AS_LRC_Y(lowerRightY) | PXP_OUT_AS_LRC_X(lowerRightX);
+}
+
+/*!
+ * brief Set the alpha surface overlay color key.
+ *
+ * If a pixel in the current overlay image with a color that falls in the range
+ * from the p colorKeyLow to p colorKeyHigh range, it will use the process surface
+ * pixel value for that location. If no PS image is present or if the PS image also
+ * matches its colorkey range, the PS background color is used.
+ *
+ * param base PXP peripheral base address.
+ * param colorKeyLow Color key low range.
+ * param colorKeyHigh Color key high range.
+ *
+ * note Colorkey operations are higher priority than alpha or ROP operations
+ */
+void PXP_SetAlphaSurfaceOverlayColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
+{
+ base->AS_CLRKEYLOW = colorKeyLow;
+ base->AS_CLRKEYHIGH = colorKeyHigh;
+}
+
+/*!
+ * brief Set the process surface input buffer configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetProcessSurfaceBufferConfig(PXP_Type *base, const pxp_ps_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ base->PS_CTRL = ((base->PS_CTRL & ~(PXP_PS_CTRL_FORMAT_MASK | PXP_PS_CTRL_WB_SWAP_MASK)) |
+ PXP_PS_CTRL_FORMAT(config->pixelFormat) | PXP_PS_CTRL_WB_SWAP(config->swapByte));
+
+ base->PS_BUF = config->bufferAddr;
+ base->PS_UBUF = config->bufferAddrU;
+ base->PS_VBUF = config->bufferAddrV;
+ base->PS_PITCH = config->pitchBytes;
+}
+
+/*!
+ * brief Set the process surface scaler configuration.
+ *
+ * The valid down scale fact is 1/(2^12) ~ 16.
+ *
+ * param base PXP peripheral base address.
+ * param inputWidth Input image width.
+ * param inputHeight Input image height.
+ * param outputWidth Output image width.
+ * param outputHeight Output image height.
+ */
+void PXP_SetProcessSurfaceScaler(
+ PXP_Type *base, uint16_t inputWidth, uint16_t inputHeight, uint16_t outputWidth, uint16_t outputHeight)
+{
+ uint8_t decX, decY;
+ uint32_t scaleX, scaleY;
+
+ PXP_GetScalerParam(inputWidth, outputWidth, &decX, &scaleX);
+ PXP_GetScalerParam(inputHeight, outputHeight, &decY, &scaleY);
+
+ base->PS_CTRL = (base->PS_CTRL & ~(PXP_PS_CTRL_DECX_MASK | PXP_PS_CTRL_DECY_MASK)) | PXP_PS_CTRL_DECX(decX) |
+ PXP_PS_CTRL_DECY(decY);
+
+ base->PS_SCALE = PXP_PS_SCALE_XSCALE(scaleX) | PXP_PS_SCALE_YSCALE(scaleY);
+}
+
+/*!
+ * brief Set the process surface position in output buffer.
+ *
+ * param base PXP peripheral base address.
+ * param upperLeftX X of the upper left corner.
+ * param upperLeftY Y of the upper left corner.
+ * param lowerRightX X of the lower right corner.
+ * param lowerRightY Y of the lower right corner.
+ */
+void PXP_SetProcessSurfacePosition(
+ PXP_Type *base, uint16_t upperLeftX, uint16_t upperLeftY, uint16_t lowerRightX, uint16_t lowerRightY)
+{
+ base->OUT_PS_ULC = PXP_OUT_PS_ULC_Y(upperLeftY) | PXP_OUT_PS_ULC_X(upperLeftX);
+ base->OUT_PS_LRC = PXP_OUT_PS_LRC_Y(lowerRightY) | PXP_OUT_PS_LRC_X(lowerRightX);
+}
+
+/*!
+ * brief Set the process surface color key.
+ *
+ * If the PS image matches colorkey range, the PS background color is output. Set
+ * p colorKeyLow to 0xFFFFFFFF and p colorKeyHigh to 0 will disable the colorkeying.
+ *
+ * param base PXP peripheral base address.
+ * param colorKeyLow Color key low range.
+ * param colorKeyHigh Color key high range.
+ */
+void PXP_SetProcessSurfaceColorKey(PXP_Type *base, uint32_t colorKeyLow, uint32_t colorKeyHigh)
+{
+ base->PS_CLRKEYLOW = colorKeyLow;
+ base->PS_CLRKEYHIGH = colorKeyHigh;
+}
+
+/*!
+ * brief Set the PXP outpt buffer configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetOutputBufferConfig(PXP_Type *base, const pxp_output_buffer_config_t *config)
+{
+ assert(NULL != config);
+
+ base->OUT_CTRL = (base->OUT_CTRL & ~(PXP_OUT_CTRL_FORMAT_MASK | PXP_OUT_CTRL_INTERLACED_OUTPUT_MASK)) |
+ PXP_OUT_CTRL_FORMAT(config->pixelFormat) | PXP_OUT_CTRL_INTERLACED_OUTPUT(config->interlacedMode);
+
+ base->OUT_BUF = config->buffer0Addr;
+ base->OUT_BUF2 = config->buffer1Addr;
+
+ base->OUT_PITCH = config->pitchBytes;
+ base->OUT_LRC = PXP_OUT_LRC_Y((uint32_t)config->height - 1U) | PXP_OUT_LRC_X((uint32_t)config->width - 1U);
+
+/*
+ * The dither store size must be set to the same with the output buffer size,
+ * otherwise the dither engine could not work.
+ */
+#if defined(PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH_MASK)
+ base->DITHER_STORE_SIZE_CH0 = PXP_DITHER_STORE_SIZE_CH0_OUT_WIDTH(config->width - 1U) |
+ PXP_DITHER_STORE_SIZE_CH0_OUT_HEIGHT(config->height - 1U);
+#endif
+}
+
+/*!
+ * brief Set the next command.
+ *
+ * The PXP supports a primitive ability to queue up one operation while the current
+ * operation is running. Workflow:
+ *
+ * 1. Prepare the PXP register values except STAT, CSCCOEFn, NEXT in the memory
+ * in the order they appear in the register map.
+ * 2. Call this function sets the new operation to PXP.
+ * 3. There are two methods to check whether the PXP has loaded the new operation.
+ * The first method is using ref PXP_IsNextCommandPending. If there is new operation
+ * not loaded by the PXP, this function returns true. The second method is checking
+ * the flag ref kPXP_CommandLoadFlag, if command loaded, this flag asserts. User
+ * could enable interrupt ref kPXP_CommandLoadInterruptEnable to get the loaded
+ * signal in interrupt way.
+ * 4. When command loaded by PXP, a new command could be set using this function.
+ *
+ * param base PXP peripheral base address.
+ * param commandAddr Address of the new command.
+ */
+void PXP_SetNextCommand(PXP_Type *base, void *commandAddr)
+{
+ pxp_pvoid_u32_t addr;
+
+ /* Make sure commands have been saved to memory. */
+ __DSB();
+
+ addr.pvoid = commandAddr;
+
+ base->NEXT = addr.u32 & PXP_NEXT_POINTER_MASK;
+}
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_CSC2) && FSL_FEATURE_PXP_HAS_NO_CSC2)
+/*!
+ * brief Set the CSC2 configuration.
+ *
+ * The CSC2 module receives pixels in any color space and can convert the pixels
+ * into any of RGB, YUV, or YCbCr color spaces. The output pixels are passed
+ * onto the LUT and rotation engine for further processing
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetCsc2Config(PXP_Type *base, const pxp_csc2_config_t *config)
+{
+ assert(NULL != config);
+
+ base->CSC2_CTRL = (base->CSC2_CTRL & ~PXP_CSC2_CTRL_CSC_MODE_MASK) | PXP_CSC2_CTRL_CSC_MODE(config->mode);
+
+ base->CSC2_COEF0 =
+ (PXP_ConvertFloat(config->A1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF0_A1_SHIFT) |
+ (PXP_ConvertFloat(config->A2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF0_A2_SHIFT);
+
+ base->CSC2_COEF1 =
+ (PXP_ConvertFloat(config->A3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF1_A3_SHIFT) |
+ (PXP_ConvertFloat(config->B1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF1_B1_SHIFT);
+
+ base->CSC2_COEF2 =
+ (PXP_ConvertFloat(config->B2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF2_B2_SHIFT) |
+ (PXP_ConvertFloat(config->B3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF2_B3_SHIFT);
+
+ base->CSC2_COEF3 =
+ (PXP_ConvertFloat(config->C1, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF3_C1_SHIFT) |
+ (PXP_ConvertFloat(config->C2, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF3_C2_SHIFT);
+
+ base->CSC2_COEF4 =
+ (PXP_ConvertFloat(config->C3, PXP_CSC2_COEF_INT_WIDTH, PXP_CSC2_COEF_FRAC_WIDTH) << PXP_CSC2_COEF4_C3_SHIFT) |
+ PXP_CSC2_COEF4_D1(config->D1);
+
+ base->CSC2_COEF5 = PXP_CSC2_COEF5_D2(config->D2) | PXP_CSC2_COEF5_D3(config->D3);
+}
+#endif
+
+/*!
+ * brief Set the CSC1 mode.
+ *
+ * The CSC1 module receives scaled YUV/YCbCr444 pixels from the scale engine and
+ * converts the pixels to the RGB888 color space. It could only be used by process
+ * surface.
+ *
+ * param base PXP peripheral base address.
+ * param mode The conversion mode.
+ */
+void PXP_SetCsc1Mode(PXP_Type *base, pxp_csc1_mode_t mode)
+{
+ /*
+ * The equations used for Colorspace conversion are:
+ *
+ * R = C0*(Y+Y_OFFSET) + C1(V+UV_OFFSET)
+ * G = C0*(Y+Y_OFFSET) + C3(U+UV_OFFSET) + C2(V+UV_OFFSET)
+ * B = C0*(Y+Y_OFFSET) + C4(U+UV_OFFSET)
+ */
+
+ if (kPXP_Csc1YUV2RGB == mode)
+ {
+ base->CSC1_COEF0 = (base->CSC1_COEF0 & ~(PXP_CSC1_COEF0_C0_MASK | PXP_CSC1_COEF0_Y_OFFSET_MASK |
+ PXP_CSC1_COEF0_UV_OFFSET_MASK | PXP_CSC1_COEF0_YCBCR_MODE_MASK)) |
+ PXP_CSC1_COEF0_C0(0x100U) /* 1.00. */
+ | PXP_CSC1_COEF0_Y_OFFSET(0x0U) /* 0. */
+ | PXP_CSC1_COEF0_UV_OFFSET(0x0U); /* 0. */
+ base->CSC1_COEF1 = PXP_CSC1_COEF1_C1(0x0123U) /* 1.140. */
+ | PXP_CSC1_COEF1_C4(0x0208U); /* 2.032. */
+ base->CSC1_COEF2 = PXP_CSC1_COEF2_C2(0x076BU) /* -0.851. */
+ | PXP_CSC1_COEF2_C3(0x079BU); /* -0.394. */
+ }
+ else
+ {
+ base->CSC1_COEF0 = (base->CSC1_COEF0 &
+ ~(PXP_CSC1_COEF0_C0_MASK | PXP_CSC1_COEF0_Y_OFFSET_MASK | PXP_CSC1_COEF0_UV_OFFSET_MASK)) |
+ PXP_CSC1_COEF0_YCBCR_MODE_MASK | PXP_CSC1_COEF0_C0(0x12AU) /* 1.164. */
+ | PXP_CSC1_COEF0_Y_OFFSET(0x1F0U) /* -16. */
+ | PXP_CSC1_COEF0_UV_OFFSET(0x180U); /* -128. */
+ base->CSC1_COEF1 = PXP_CSC1_COEF1_C1(0x0198U) /* 1.596. */
+ | PXP_CSC1_COEF1_C4(0x0204U); /* 2.017. */
+ base->CSC1_COEF2 = PXP_CSC1_COEF2_C2(0x0730U) /* -0.813. */
+ | PXP_CSC1_COEF2_C3(0x079CU); /* -0.392. */
+ }
+}
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
+/*!
+ * brief Set the LUT configuration.
+ *
+ * The lookup table (LUT) is used to modify pixels in a manner that is not linear
+ * and that cannot be achieved by the color space conversion modules. To setup
+ * the LUT, the complete workflow is:
+ * 1. Use ref PXP_SetLutConfig to set the configuration, such as the lookup mode.
+ * 2. Use ref PXP_LoadLutTable to load the lookup table to PXP.
+ * 3. Use ref PXP_EnableLut to enable the function.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetLutConfig(PXP_Type *base, const pxp_lut_config_t *config)
+{
+ base->LUT_CTRL = (base->LUT_CTRL & ~(PXP_LUT_CTRL_OUT_MODE_MASK | PXP_LUT_CTRL_LOOKUP_MODE_MASK)) |
+ PXP_LUT_CTRL_LRU_UPD_MASK | /* Use Least Recently Used Policy Update Control. */
+ PXP_LUT_CTRL_OUT_MODE(config->outMode) | PXP_LUT_CTRL_LOOKUP_MODE(config->lookupMode);
+
+ if (kPXP_LutOutRGBW4444CFA == config->outMode)
+ {
+ base->CFA = config->cfaValue;
+ }
+}
+
+/*!
+ * brief Set the look up table to PXP.
+ *
+ * If lookup mode is DIRECT mode, this function loads p bytesNum of values
+ * from the address p memAddr into PXP LUT address p lutStartAddr. So this
+ * function allows only update part of the PXP LUT.
+ *
+ * If lookup mode is CACHE mode, this function sets the new address to p memAddr
+ * and invalid the PXP LUT cache.
+ *
+ * param base PXP peripheral base address.
+ * param lookupMode Which lookup mode is used. Note that this parameter is only
+ * used to distinguish DIRECT mode and CACHE mode, it does not change the register
+ * value PXP_LUT_CTRL[LOOKUP_MODE]. To change that value, use function ref PXP_SetLutConfig.
+ * param bytesNum How many bytes to set. This value must be divisable by 8.
+ * param memAddr Address of look up table to set.
+ * param lutStartAddr The LUT value will be loaded to LUT from index lutAddr. It should
+ * be 8 bytes aligned.
+ *
+ * retval kStatus_Success Load successfully.
+ * retval kStatus_InvalidArgument Failed because of invalid argument.
+ */
+status_t PXP_LoadLutTable(
+ PXP_Type *base, pxp_lut_lookup_mode_t lookupMode, uint32_t bytesNum, uint32_t memAddr, uint16_t lutStartAddr)
+{
+ if (kPXP_LutCacheRGB565 == lookupMode)
+ {
+ /* Make sure the previous memory write is finished, especially the LUT data memory. */
+ __DSB();
+
+ base->LUT_EXTMEM = memAddr;
+ /* Invalid cache. */
+ base->LUT_CTRL |= PXP_LUT_CTRL_INVALID_MASK;
+ }
+ else
+ {
+ /* Number of bytes must be divisable by 8. */
+ if ((bytesNum & 0x07U) || (bytesNum < 8U) || (lutStartAddr & 0x07U) ||
+ (bytesNum + lutStartAddr > PXP_LUT_TABLE_BYTE))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ base->LUT_EXTMEM = memAddr;
+ base->LUT_ADDR = PXP_LUT_ADDR_ADDR(lutStartAddr) | PXP_LUT_ADDR_NUM_BYTES(bytesNum);
+
+ base->STAT_CLR = PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK;
+
+ /* Start DMA transfer. */
+ base->LUT_CTRL |= PXP_LUT_CTRL_DMA_START_MASK;
+
+ __DSB();
+
+ /* Wait for transfer completed. */
+ while (!(base->STAT & PXP_STAT_LUT_DMA_LOAD_DONE_IRQ_MASK))
+ {
+ }
+ }
+
+ return kStatus_Success;
+}
+#endif /* FSL_FEATURE_PXP_HAS_NO_LUT */
+
+#if (defined(FSL_FEATURE_PXP_HAS_DITHER) && FSL_FEATURE_PXP_HAS_DITHER)
+/*!
+ * brief Write data to the PXP internal memory.
+ *
+ * param base PXP peripheral base address.
+ * param ram Which internal memory to write.
+ * param bytesNum How many bytes to write.
+ * param data Pointer to the data to write.
+ * param memStartAddr The start address in the internal memory to write the data.
+ */
+void PXP_SetInternalRamData(PXP_Type *base, pxp_ram_t ram, uint32_t bytesNum, uint8_t *data, uint16_t memStartAddr)
+{
+ assert((memStartAddr + bytesNum) <= PXP_INTERNAL_RAM_LUT_BYTE);
+
+ base->INIT_MEM_CTRL =
+ PXP_INIT_MEM_CTRL_ADDR(memStartAddr) | PXP_INIT_MEM_CTRL_SELECT(ram) | PXP_INIT_MEM_CTRL_START_MASK;
+
+ while (bytesNum--)
+ {
+ base->INIT_MEM_DATA = (uint32_t)(*data);
+ data++;
+ }
+
+ base->INIT_MEM_CTRL = 0U;
+}
+
+/*!
+ * brief Set the dither final LUT data.
+ *
+ * The dither final LUT is only applicble to dither engine 0. It takes the bits[7:4]
+ * of the output pixel and looks up and 8 bit value from the 16 value LUT to generate
+ * the final output pixel to the next process module.
+ *
+ * param base PXP peripheral base address.
+ * param data Pointer to the LUT data to set.
+ */
+void PXP_SetDitherFinalLutData(PXP_Type *base, const pxp_dither_final_lut_data_t *data)
+{
+ base->DITHER_FINAL_LUT_DATA0 = data->data_3_0;
+ base->DITHER_FINAL_LUT_DATA1 = data->data_7_4;
+ base->DITHER_FINAL_LUT_DATA2 = data->data_11_8;
+ base->DITHER_FINAL_LUT_DATA3 = data->data_15_12;
+}
+
+/*!
+ * brief Enable or disable dither engine in the PXP process path.
+ *
+ * After the initialize function ref PXP_Init, the dither engine is disabled and not
+ * use in the PXP processing path. This function enables the dither engine and
+ * routes the dither engine output to the output buffer. When the dither engine
+ * is enabled using this function, ref PXP_SetDitherConfig must be called to
+ * configure dither engine correctly, otherwise there is not output to the output
+ * buffer.
+ *
+ * param base PXP peripheral base address.
+ * param enable Pass in true to enable, false to disable.
+ */
+void PXP_EnableDither(PXP_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_SET = PXP_CTRL_ENABLE_DITHER_MASK;
+ /* Route dither output to output buffer. */
+ base->DATA_PATH_CTRL0 &= ~PXP_DATA_PATH_CTRL0_MUX14_SEL_MASK;
+ }
+ else
+ {
+ base->CTRL_CLR = PXP_CTRL_ENABLE_DITHER_MASK;
+ /* Route MUX 12 output to output buffer. */
+ base->DATA_PATH_CTRL0 |= PXP_DATA_PATH_CTRL0_MUX14_SEL(1U);
+ }
+}
+#endif /* FSL_FEATURE_PXP_HAS_DITHER */
+
+/*!
+ * brief Set the Porter Duff configuration.
+ *
+ * param base PXP peripheral base address.
+ * param config Pointer to the configuration.
+ */
+void PXP_SetPorterDuffConfig(PXP_Type *base, const pxp_porter_duff_config_t *config)
+{
+ assert(NULL != config);
+
+ union
+ {
+ pxp_porter_duff_config_t pdConfigStruct;
+ uint32_t u32;
+ } pdConfig;
+
+ pdConfig.pdConfigStruct = *config;
+
+ base->PORTER_DUFF_CTRL = pdConfig.u32;
+}
+
+/*!
+ * brief Get the Porter Duff configuration by blend mode.
+ *
+ * param mode The blend mode.
+ * param config Pointer to the configuration.
+ * retval kStatus_Success Successfully get the configuratoin.
+ * retval kStatus_InvalidArgument The blend mode not supported.
+ */
+status_t PXP_GetPorterDuffConfig(pxp_porter_duff_blend_mode_t mode, pxp_porter_duff_config_t *config)
+{
+ status_t status;
+
+ union
+ {
+ pxp_porter_duff_config_t pdConfigStruct;
+ uint32_t u32;
+ } pdConfig;
+
+ static const uint32_t pdCtrl[] = {
+ /* kPXP_PorterDuffSrc */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorOne) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
+
+ /* kPXP_PorterDuffAtop */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorStraight) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
+
+ /* kPXP_PorterDuffOver */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorOne) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
+
+ /* kPXP_PorterDuffIn */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorStraight) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
+
+ /* kPXP_PorterDuffOut */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
+
+ /* kPXP_PorterDuffDst */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorOne),
+
+ /* kPXP_PorterDuffDstAtop */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorStraight),
+
+ /* kPXP_PorterDuffDstOver */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorOne),
+
+ /* kPXP_PorterDuffDstIn */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorStraight),
+
+ /* kPXP_PorterDuffDstOut */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
+
+ /* kPXP_PorterDuffXor */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorInversed) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorInversed),
+
+ /* kPXP_PorterDuffClear */
+ PXP_PORTER_DUFF_CTRL_POTER_DUFF_ENABLE_MASK |
+ PXP_PORTER_DUFF_CTRL_S0_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S1_GLOBAL_ALPHA_MODE(kPXP_PorterDuffLocalAlpha) |
+ PXP_PORTER_DUFF_CTRL_S0_S1_FACTOR_MODE(kPXP_PorterDuffFactorZero) |
+ PXP_PORTER_DUFF_CTRL_S1_S0_FACTOR_MODE(kPXP_PorterDuffFactorZero),
+ };
+
+ if (mode >= kPXP_PorterDuffMax)
+ {
+ status = kStatus_InvalidArgument;
+ }
+ else
+ {
+ pdConfig.u32 = pdCtrl[(uint32_t)mode];
+
+ *config = pdConfig.pdConfigStruct;
+
+ status = kStatus_Success;
+ }
+
+ return status;
+}
+
+static void PXP_StartRectCopy(PXP_Type *base,
+ uint32_t srcAddr,
+ uint16_t srcPitchBytes,
+ uint32_t destAddr,
+ uint16_t destPitchBytes,
+ uint16_t width,
+ uint16_t height,
+ pxp_as_pixel_format_t pixelFormat)
+{
+ pxp_output_buffer_config_t outputBufferConfig;
+ pxp_as_buffer_config_t asBufferConfig;
+ uint32_t intMask;
+
+#if !(defined(FSL_FEATURE_PXP_HAS_NO_LUT) && FSL_FEATURE_PXP_HAS_NO_LUT)
+ intMask =
+ base->CTRL & (PXP_CTRL_NEXT_IRQ_ENABLE_MASK | PXP_CTRL_IRQ_ENABLE_MASK | PXP_CTRL_LUT_DMA_IRQ_ENABLE_MASK);
+#else
+ intMask = base->CTRL & (PXP_CTRL_NEXT_IRQ_ENABLE_MASK | PXP_CTRL_IRQ_ENABLE_MASK);
+#endif
+
+ PXP_ResetToInit(base);
+
+ /* Restore previous interrupt configuration. */
+ PXP_EnableInterrupts(base, intMask);
+
+ /* Disable PS */
+ PXP_SetProcessSurfacePosition(base, 0xFFFFU, 0xFFFFU, 0U, 0U);
+
+ /* Input buffer. */
+ asBufferConfig.pixelFormat = pixelFormat;
+ asBufferConfig.bufferAddr = srcAddr;
+ asBufferConfig.pitchBytes = srcPitchBytes;
+
+ PXP_SetAlphaSurfaceBufferConfig(base, &asBufferConfig);
+ PXP_SetAlphaSurfacePosition(base, 0U, 0U, width - 1U, height - 1U);
+
+ /* Alpha mode set to ROP, AS OR PS*/
+ const pxp_as_blend_config_t asBlendConfig = {
+ .alpha = 0U, .invertAlpha = false, .alphaMode = kPXP_AlphaRop, .ropMode = kPXP_RopMergeAs};
+
+ PXP_SetAlphaSurfaceBlendConfig(base, &asBlendConfig);
+
+ /* Output buffer. */
+ outputBufferConfig.pixelFormat = (pxp_output_pixel_format_t)pixelFormat;
+ outputBufferConfig.interlacedMode = kPXP_OutputProgressive;
+ outputBufferConfig.buffer0Addr = destAddr;
+ outputBufferConfig.buffer1Addr = 0U;
+ outputBufferConfig.pitchBytes = destPitchBytes;
+ outputBufferConfig.width = width;
+ outputBufferConfig.height = height;
+
+ PXP_SetOutputBufferConfig(base, &outputBufferConfig);
+
+ PXP_ClearStatusFlags(base, (uint32_t)kPXP_CompleteFlag);
+
+ PXP_Start(base);
+}
+
+/*!
+ * brief Copy picture from one buffer to another buffer.
+ *
+ * This function copies a rectangle from one buffer to another buffer.
+ *
+ * param base PXP peripheral base address.
+ * retval kStatus_Success Successfully started the copy process.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_StartPictureCopy(PXP_Type *base, const pxp_pic_copy_config_t *config)
+{
+ uint8_t bytePerPixel;
+ uint32_t copyFromAddr;
+ uint32_t copyToAddr;
+
+ if ((0U == config->height) || (0U == config->width))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((config->pixelFormat == kPXP_AsPixelFormatARGB8888) || (config->pixelFormat == kPXP_AsPixelFormatRGB888))
+ {
+ bytePerPixel = 4U;
+ }
+ else
+ {
+ bytePerPixel = 2U;
+ }
+
+ copyFromAddr = config->srcPicBaseAddr + ((uint32_t)config->srcOffsetY * (uint32_t)config->srcPitchBytes) +
+ bytePerPixel * config->srcOffsetX;
+ copyToAddr = config->destPicBaseAddr + ((uint32_t)config->destOffsetY * (uint32_t)config->destPitchBytes) +
+ bytePerPixel * config->destOffsetX;
+
+ PXP_StartRectCopy(base, copyFromAddr, config->srcPitchBytes, copyToAddr, config->destPitchBytes, config->width,
+ config->height, config->pixelFormat);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Copy continous memory.
+ *
+ * The copy size should be 512 byte aligned.
+ *
+ * param base PXP peripheral base address.
+ * retval kStatus_Success Successfully started the copy process.
+ * retval kStatus_InvalidArgument Invalid argument.
+ */
+status_t PXP_StartMemCopy(PXP_Type *base, uint32_t srcAddr, uint32_t destAddr, uint32_t size)
+{
+ uint16_t pitchBytes;
+ uint32_t height;
+
+ if ((0U == size) || ((size % 512U) != 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /*
+ * By default, PXP process block is 8x8. For better performance, choose
+ * width and height dividable by block size.
+ */
+ if (size < 8U * 512U)
+ {
+ height = 8U;
+ pitchBytes = (uint16_t)(size / height);
+ }
+ else
+ {
+ pitchBytes = 512U;
+ height = size / pitchBytes;
+ }
+
+ if (height > PXP_MAX_HEIGHT)
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ PXP_StartRectCopy(base, srcAddr, pitchBytes, destAddr, pitchBytes, pitchBytes / 4U, (uint16_t)height,
+ kPXP_AsPixelFormatARGB8888);
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_qtmr.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_qtmr.c
new file mode 100644
index 0000000000..44b7867441
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_qtmr.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2017-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_qtmr.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.qtmr"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Gets the instance from the base address to be used to gate or ungate the module clock
+ *
+ * @param base Quad Timer peripheral base address
+ *
+ * @return The Quad Timer instance
+ */
+static uint32_t QTMR_GetInstance(TMR_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to Quad Timer bases for each instance. */
+static TMR_Type *const s_qtmrBases[] = TMR_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to Quad Timer clocks for each instance. */
+static const clock_ip_name_t s_qtmrClocks[] = TMR_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t QTMR_GetInstance(TMR_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_qtmrBases); instance++)
+ {
+ if (s_qtmrBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_qtmrBases));
+
+ return instance;
+}
+
+/*!
+ * brief Ungates the Quad Timer clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the Quad Timer driver.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param config Pointer to user's Quad Timer config structure
+ */
+void QTMR_Init(TMR_Type *base, qtmr_channel_selection_t channel, const qtmr_config_t *config)
+{
+ assert(NULL != config);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the module clock */
+ CLOCK_EnableClock(s_qtmrClocks[QTMR_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Setup the counter sources */
+ base->CHANNEL[channel].CTRL = (TMR_CTRL_PCS(config->primarySource) | TMR_CTRL_SCS(config->secondarySource));
+
+ /* Setup the master mode operation */
+ base->CHANNEL[channel].SCTRL =
+ (TMR_SCTRL_EEOF(config->enableExternalForce) | TMR_SCTRL_MSTR(config->enableMasterMode));
+
+ /* Setup debug mode */
+ base->CHANNEL[channel].CSCTRL = TMR_CSCTRL_DBG_EN(config->debugMode);
+
+ base->CHANNEL[channel].FILT &= (uint16_t)(~(TMR_FILT_FILT_CNT_MASK | TMR_FILT_FILT_PER_MASK));
+ /* Setup input filter */
+ base->CHANNEL[channel].FILT =
+ (TMR_FILT_FILT_CNT(config->faultFilterCount) | TMR_FILT_FILT_PER(config->faultFilterPeriod));
+}
+
+/*!
+ * brief Stops the counter and gates the Quad Timer clock
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ */
+void QTMR_Deinit(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ /* Stop the counter */
+ base->CHANNEL[channel].CTRL &= (uint16_t)(~TMR_CTRL_CM_MASK);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the module clock */
+ CLOCK_DisableClock(s_qtmrClocks[QTMR_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Fill in the Quad Timer config struct with the default settings
+ *
+ * The default values are:
+ * code
+ * config->debugMode = kQTMR_RunNormalInDebug;
+ * config->enableExternalForce = false;
+ * config->enableMasterMode = false;
+ * config->faultFilterCount = 0;
+ * config->faultFilterPeriod = 0;
+ * config->primarySource = kQTMR_ClockDivide_2;
+ * config->secondarySource = kQTMR_Counter0InputPin;
+ * endcode
+ * param config Pointer to user's Quad Timer config structure.
+ */
+void QTMR_GetDefaultConfig(qtmr_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* Halt counter during debug mode */
+ config->debugMode = kQTMR_RunNormalInDebug;
+ /* Another counter cannot force state of OFLAG signal */
+ config->enableExternalForce = false;
+ /* Compare function's output from this counter is not broadcast to other counters */
+ config->enableMasterMode = false;
+ /* Fault filter count is set to 0 */
+ config->faultFilterCount = 0;
+ /* Fault filter period is set to 0 which disables the fault filter */
+ config->faultFilterPeriod = 0;
+ /* Primary count source is IP bus clock divide by 2 */
+ config->primarySource = kQTMR_ClockDivide_2;
+ /* Secondary count source is counter 0 input pin */
+ config->secondarySource = kQTMR_Counter0InputPin;
+}
+
+/*!
+ * brief Sets up Quad timer module for PWM signal output.
+ *
+ * The function initializes the timer module according to the parameters passed in by the user. The
+ * function also sets up the value compare registers to match the PWM signal requirements.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param pwmFreqHz PWM signal frequency in Hz
+ * param dutyCyclePercent PWM pulse width, value should be between 0 to 100
+ * 0=inactive signal(0% duty cycle)...
+ * 100=active signal (100% duty cycle)
+ * param outputPolarity true: invert polarity of the output signal, false: no inversion
+ * param srcClock_Hz Main counter clock in Hz.
+ *
+ * return Returns an error if there was error setting up the signal.
+ */
+status_t QTMR_SetupPwm(TMR_Type *base,
+ qtmr_channel_selection_t channel,
+ uint32_t pwmFreqHz,
+ uint8_t dutyCyclePercent,
+ bool outputPolarity,
+ uint32_t srcClock_Hz)
+{
+ uint32_t periodCount, highCount, lowCount;
+ uint16_t reg;
+ status_t status;
+
+ if (dutyCyclePercent <= 100U)
+ {
+ /* Set OFLAG pin for output mode and force out a low on the pin */
+ base->CHANNEL[channel].SCTRL |= (TMR_SCTRL_FORCE_MASK | TMR_SCTRL_OEN_MASK);
+
+ /* Counter values to generate a PWM signal */
+ periodCount = srcClock_Hz / pwmFreqHz;
+ highCount = periodCount * dutyCyclePercent / 100U;
+ lowCount = periodCount - highCount;
+
+ if (highCount > 0U)
+ {
+ highCount -= 1U;
+ }
+ if (lowCount > 0U)
+ {
+ lowCount -= 1U;
+ }
+
+ /* This should not be a 16-bit overflow value. If it is, change to a larger divider for clock source. */
+ assert(highCount <= 0xFFFFU);
+ assert(lowCount <= 0xFFFFU);
+
+ /* Setup the compare registers for PWM output */
+ base->CHANNEL[channel].COMP1 = (uint16_t)lowCount;
+ base->CHANNEL[channel].COMP2 = (uint16_t)highCount;
+
+ /* Setup the pre-load registers for PWM output */
+ base->CHANNEL[channel].CMPLD1 = (uint16_t)lowCount;
+ base->CHANNEL[channel].CMPLD2 = (uint16_t)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 &= (uint16_t)(~(TMR_CSCTRL_CL1_MASK | TMR_CSCTRL_CL2_MASK));
+ reg |= (TMR_CSCTRL_CL1(kQTMR_LoadOnComp2) | TMR_CSCTRL_CL2(kQTMR_LoadOnComp1));
+ base->CHANNEL[channel].CSCTRL = reg;
+
+ if (outputPolarity)
+ {
+ /* Invert the polarity */
+ base->CHANNEL[channel].SCTRL |= TMR_SCTRL_OPS_MASK;
+ }
+ else
+ {
+ /* True polarity, no inversion */
+ base->CHANNEL[channel].SCTRL &= ~(uint16_t)TMR_SCTRL_OPS_MASK;
+ }
+
+ reg = base->CHANNEL[channel].CTRL;
+ reg &= ~(uint16_t)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;
+
+ status = kStatus_Success;
+ }
+ else
+ {
+ /* Invalid dutycycle */
+ status = kStatus_Fail;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Allows the user to count the source clock cycles until a capture event arrives.
+ *
+ * The count is stored in the capture register.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param capturePin Pin through which we receive the input signal to trigger the capture
+ * param inputPolarity true: invert polarity of the input signal, false: no inversion
+ * param reloadOnCapture true: reload the counter when an input capture occurs, false: no reload
+ * param captureMode Specifies which edge of the input signal triggers a capture
+ */
+void QTMR_SetupInputCapture(TMR_Type *base,
+ qtmr_channel_selection_t channel,
+ qtmr_input_source_t capturePin,
+ bool inputPolarity,
+ bool reloadOnCapture,
+ qtmr_input_capture_edge_t captureMode)
+{
+ uint16_t reg;
+
+ /* Clear the prior value for the input source for capture */
+ reg = base->CHANNEL[channel].CTRL & (uint16_t)(~TMR_CTRL_SCS_MASK);
+
+ /* Set the new input source */
+ reg |= TMR_CTRL_SCS(capturePin);
+ base->CHANNEL[channel].CTRL = reg;
+
+ /* Clear the prior values for input polarity, capture mode. Set the external pin as input */
+ reg = base->CHANNEL[channel].SCTRL &
+ (uint16_t)(~(TMR_SCTRL_IPS_MASK | TMR_SCTRL_CAPTURE_MODE_MASK | TMR_SCTRL_OEN_MASK));
+ /* Set the new values */
+ reg |= (TMR_SCTRL_IPS(inputPolarity) | TMR_SCTRL_CAPTURE_MODE(captureMode));
+ base->CHANNEL[channel].SCTRL = reg;
+
+ /* Setup if counter should reload when a capture occurs */
+ if (reloadOnCapture)
+ {
+ base->CHANNEL[channel].CSCTRL |= TMR_CSCTRL_ROC_MASK;
+ }
+ else
+ {
+ base->CHANNEL[channel].CSCTRL &= (uint16_t)(~TMR_CSCTRL_ROC_MASK);
+ }
+}
+
+/*!
+ * brief Enables the selected Quad Timer interrupts
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+void QTMR_EnableInterrupts(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Compare interrupt */
+ if ((mask & (uint16_t)kQTMR_CompareInterruptEnable) != 0UL)
+ {
+ reg |= TMR_SCTRL_TCFIE_MASK;
+ }
+ /* Overflow interrupt */
+ if ((mask & (uint16_t)kQTMR_OverflowInterruptEnable) != 0UL)
+ {
+ reg |= TMR_SCTRL_TOFIE_MASK;
+ }
+ /* Input edge interrupt */
+ if ((mask & (uint16_t)kQTMR_EdgeInterruptEnable) != 0UL)
+ {
+ /* Restriction: Do not set both SCTRL[IEFIE] and DMA[IEFDE] */
+ base->CHANNEL[channel].DMA &= ~(uint16_t)TMR_DMA_IEFDE_MASK;
+ reg |= TMR_SCTRL_IEFIE_MASK;
+ }
+ base->CHANNEL[channel].SCTRL = reg;
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 interrupt */
+ if ((mask & (uint16_t)kQTMR_Compare1InterruptEnable) != 0UL)
+ {
+ reg |= TMR_CSCTRL_TCF1EN_MASK;
+ }
+ /* Compare 2 interrupt */
+ if ((mask & (uint16_t)kQTMR_Compare2InterruptEnable) != 0UL)
+ {
+ reg |= TMR_CSCTRL_TCF2EN_MASK;
+ }
+ base->CHANNEL[channel].CSCTRL = reg;
+}
+
+/*!
+ * brief Disables the selected Quad Timer interrupts
+ *
+ * param base Quad Timer peripheral base addres
+ * param channel Quad Timer channel number
+ * param mask The interrupts to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+void QTMR_DisableInterrupts(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Compare interrupt */
+ if ((mask & (uint16_t)kQTMR_CompareInterruptEnable) != 0UL)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_TCFIE_MASK);
+ }
+ /* Overflow interrupt */
+ if ((mask & (uint16_t)kQTMR_OverflowInterruptEnable) != 0UL)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_TOFIE_MASK);
+ }
+ /* Input edge interrupt */
+ if ((mask & (uint16_t)kQTMR_EdgeInterruptEnable) != 0UL)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_IEFIE_MASK);
+ }
+ base->CHANNEL[channel].SCTRL = reg;
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 interrupt */
+ if ((mask & (uint16_t)kQTMR_Compare1InterruptEnable) != 0UL)
+ {
+ reg &= ~(uint16_t)TMR_CSCTRL_TCF1EN_MASK;
+ }
+ /* Compare 2 interrupt */
+ if ((mask & (uint16_t)kQTMR_Compare2InterruptEnable) != 0UL)
+ {
+ reg &= ~(uint16_t)TMR_CSCTRL_TCF2EN_MASK;
+ }
+ base->CHANNEL[channel].CSCTRL = reg;
+}
+
+/*!
+ * brief Gets the enabled Quad Timer interrupts
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ *
+ * return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::qtmr_interrupt_enable_t
+ */
+uint32_t QTMR_GetEnabledInterrupts(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ uint32_t enabledInterrupts = 0;
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Compare interrupt */
+ if ((reg & TMR_SCTRL_TCFIE_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_CompareFlag;
+ }
+ /* Overflow interrupt */
+ if ((reg & TMR_SCTRL_TOFIE_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_OverflowInterruptEnable;
+ }
+ /* Input edge interrupt */
+ if ((reg & TMR_SCTRL_IEFIE_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_EdgeInterruptEnable;
+ }
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 interrupt */
+ if ((reg & TMR_CSCTRL_TCF1EN_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_Compare1InterruptEnable;
+ }
+ /* Compare 2 interrupt */
+ if ((reg & TMR_CSCTRL_TCF2EN_MASK) != 0U)
+ {
+ enabledInterrupts |= (uint32_t)kQTMR_Compare2InterruptEnable;
+ }
+
+ return enabledInterrupts;
+}
+
+/*!
+ * brief Gets the Quad Timer status flags
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::qtmr_status_flags_t
+ */
+uint32_t QTMR_GetStatus(TMR_Type *base, qtmr_channel_selection_t channel)
+{
+ uint32_t statusFlags = 0;
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Timer compare flag */
+ if ((reg & TMR_SCTRL_TCF_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_CompareFlag;
+ }
+ /* Timer overflow flag */
+ if ((reg & TMR_SCTRL_TOF_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_OverflowFlag;
+ }
+ /* Input edge flag */
+ if ((reg & TMR_SCTRL_IEF_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_EdgeFlag;
+ }
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 flag */
+ if ((reg & TMR_CSCTRL_TCF1_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_Compare1Flag;
+ }
+ /* Compare 2 flag */
+ if ((reg & TMR_CSCTRL_TCF2_MASK) != 0U)
+ {
+ statusFlags |= (uint32_t)kQTMR_Compare2Flag;
+ }
+
+ return statusFlags;
+}
+
+/*!
+ * brief Clears the Quad Timer status flags.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param mask The status flags to clear. This is a logical OR of members of the
+ * enumeration ::qtmr_status_flags_t
+ */
+void QTMR_ClearStatusFlags(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].SCTRL;
+ /* Timer compare flag */
+ if ((mask & (uint32_t)kQTMR_CompareFlag) != 0U)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_TCF_MASK);
+ }
+ /* Timer overflow flag */
+ if ((mask & (uint32_t)kQTMR_OverflowFlag) != 0U)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_TOF_MASK);
+ }
+ /* Input edge flag */
+ if ((mask & (uint32_t)kQTMR_EdgeFlag) != 0U)
+ {
+ reg &= (uint16_t)(~TMR_SCTRL_IEF_MASK);
+ }
+ base->CHANNEL[channel].SCTRL = reg;
+
+ reg = base->CHANNEL[channel].CSCTRL;
+ /* Compare 1 flag */
+ if ((mask & (uint32_t)kQTMR_Compare1Flag) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_CSCTRL_TCF1_MASK;
+ }
+ /* Compare 2 flag */
+ if ((mask & (uint32_t)kQTMR_Compare2Flag) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_CSCTRL_TCF2_MASK;
+ }
+ base->CHANNEL[channel].CSCTRL = reg;
+}
+
+/*!
+ * brief Sets the timer period in ticks.
+ *
+ * Timers counts from initial value till it equals the count value set here. The counter
+ * will then reinitialize to the value specified in the Load register.
+ *
+ * note
+ * 1. This function will write the time period in ticks to COMP1 or COMP2 register
+ * depending on the count direction
+ * 2. User can call the utility macros provided in fsl_common.h to convert to ticks
+ * 3. This function supports cases, providing only primary source clock without secondary source clock.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param ticks Timer period in units of ticks
+ */
+void QTMR_SetTimerPeriod(TMR_Type *base, qtmr_channel_selection_t channel, uint16_t ticks)
+{
+ /* Set the length bit to reinitialize the counters on a match */
+ base->CHANNEL[channel].CTRL |= TMR_CTRL_LENGTH_MASK;
+
+ if ((base->CHANNEL[channel].CTRL & TMR_CTRL_DIR_MASK) != 0U)
+ {
+ /* Counting down */
+ base->CHANNEL[channel].COMP2 = ticks;
+ }
+ else
+ {
+ /* Counting up */
+ base->CHANNEL[channel].COMP1 = ticks;
+ }
+}
+
+/*!
+ * brief Enable the Quad Timer DMA.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param mask The DMA to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_dma_enable_t
+ */
+void QTMR_EnableDma(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].DMA;
+ /* Input Edge Flag DMA Enable */
+ if ((mask & (uint32_t)kQTMR_InputEdgeFlagDmaEnable) != 0U)
+ {
+ /* Restriction: Do not set both DMA[IEFDE] and SCTRL[IEFIE] */
+ base->CHANNEL[channel].SCTRL &= (uint16_t)(~TMR_SCTRL_IEFIE_MASK);
+ reg |= TMR_DMA_IEFDE_MASK;
+ }
+ /* Comparator Preload Register 1 DMA Enable */
+ if ((mask & (uint32_t)kQTMR_ComparatorPreload1DmaEnable) != 0U)
+ {
+ reg |= TMR_DMA_CMPLD1DE_MASK;
+ }
+ /* Comparator Preload Register 2 DMA Enable */
+ if ((mask & (uint32_t)kQTMR_ComparatorPreload2DmaEnable) != 0U)
+ {
+ reg |= TMR_DMA_CMPLD2DE_MASK;
+ }
+ base->CHANNEL[channel].DMA = reg;
+}
+
+/*!
+ * brief Disable the Quad Timer DMA.
+ *
+ * param base Quad Timer peripheral base address
+ * param channel Quad Timer channel number
+ * param mask The DMA to enable. This is a logical OR of members of the
+ * enumeration ::qtmr_dma_enable_t
+ */
+void QTMR_DisableDma(TMR_Type *base, qtmr_channel_selection_t channel, uint32_t mask)
+{
+ uint16_t reg;
+
+ reg = base->CHANNEL[channel].DMA;
+ /* Input Edge Flag DMA Enable */
+ if ((mask & (uint32_t)kQTMR_InputEdgeFlagDmaEnable) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_DMA_IEFDE_MASK;
+ }
+ /* Comparator Preload Register 1 DMA Enable */
+ if ((mask & (uint32_t)kQTMR_ComparatorPreload1DmaEnable) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_DMA_CMPLD1DE_MASK;
+ }
+ /* Comparator Preload Register 2 DMA Enable */
+ if ((mask & (uint32_t)kQTMR_ComparatorPreload2DmaEnable) != 0U)
+ {
+ reg &= ~(uint16_t)TMR_DMA_CMPLD2DE_MASK;
+ }
+ base->CHANNEL[channel].DMA = reg;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_rtwdog.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_rtwdog.c
new file mode 100644
index 0000000000..4b49280bf8
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_rtwdog.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_rtwdog.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.rtwdog"
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Clears the RTWDOG flag.
+ *
+ * This function clears the RTWDOG status flag.
+ *
+ * Example to clear an interrupt flag:
+ * code
+ * RTWDOG_ClearStatusFlags(wdog_base,kRTWDOG_InterruptFlag);
+ * endcode
+ * param base RTWDOG peripheral base address.
+ * param mask The status flags to clear.
+ * The parameter can be any combination of the following values:
+ * arg kRTWDOG_InterruptFlag
+ */
+void RTWDOG_ClearStatusFlags(RTWDOG_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kRTWDOG_InterruptFlag) != 0U)
+ {
+ base->CS |= RTWDOG_CS_FLG_MASK;
+ }
+}
+
+/*!
+ * brief Initializes the RTWDOG configuration structure.
+ *
+ * This function initializes the RTWDOG configuration structure to default values. The default
+ * values are:
+ * code
+ * rtwdogConfig->enableRtwdog = true;
+ * rtwdogConfig->clockSource = kRTWDOG_ClockSource1;
+ * rtwdogConfig->prescaler = kRTWDOG_ClockPrescalerDivide1;
+ * rtwdogConfig->workMode.enableWait = true;
+ * rtwdogConfig->workMode.enableStop = false;
+ * rtwdogConfig->workMode.enableDebug = false;
+ * rtwdogConfig->testMode = kRTWDOG_TestModeDisabled;
+ * rtwdogConfig->enableUpdate = true;
+ * rtwdogConfig->enableInterrupt = false;
+ * rtwdogConfig->enableWindowMode = false;
+ * rtwdogConfig->windowValue = 0U;
+ * rtwdogConfig->timeoutValue = 0xFFFFU;
+ * endcode
+ *
+ * param config Pointer to the RTWDOG configuration structure.
+ * see rtwdog_config_t
+ */
+void RTWDOG_GetDefaultConfig(rtwdog_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableRtwdog = true;
+ config->clockSource = kRTWDOG_ClockSource1;
+ config->prescaler = kRTWDOG_ClockPrescalerDivide1;
+ config->workMode.enableWait = true;
+ config->workMode.enableStop = false;
+ config->workMode.enableDebug = false;
+ config->testMode = kRTWDOG_TestModeDisabled;
+ config->enableUpdate = true;
+ config->enableInterrupt = false;
+ config->enableWindowMode = false;
+ config->windowValue = 0U;
+ config->timeoutValue = 0xFFFFU;
+}
+
+/*!
+ * brief Initializes the RTWDOG module.
+ *
+ * This function initializes the RTWDOG.
+ * To reconfigure the RTWDOG without forcing a reset first, enableUpdate must be set to true
+ * in the configuration.
+ *
+ * Example:
+ * code
+ * rtwdog_config_t config;
+ * RTWDOG_GetDefaultConfig(&config);
+ * config.timeoutValue = 0x7ffU;
+ * config.enableUpdate = true;
+ * RTWDOG_Init(wdog_base,&config);
+ * endcode
+ *
+ * param base RTWDOG peripheral base address.
+ * param config The configuration of the RTWDOG.
+ */
+void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t value = 0U;
+ uint32_t primaskValue = 0U;
+
+ value = RTWDOG_CS_EN(config->enableRtwdog) | RTWDOG_CS_CLK(config->clockSource) |
+ RTWDOG_CS_INT(config->enableInterrupt) | RTWDOG_CS_WIN(config->enableWindowMode) |
+ RTWDOG_CS_UPDATE(config->enableUpdate) | RTWDOG_CS_DBG(config->workMode.enableDebug) |
+ RTWDOG_CS_STOP(config->workMode.enableStop) | RTWDOG_CS_WAIT(config->workMode.enableWait) |
+ RTWDOG_CS_PRES(config->prescaler) | RTWDOG_CS_CMD32EN(1U) | RTWDOG_CS_TST(config->testMode);
+
+ /* Disable the global interrupts. Otherwise, an interrupt could effectively invalidate the unlock sequence
+ * and the WCT may expire. After the configuration finishes, re-enable the global interrupts. */
+ primaskValue = DisableGlobalIRQ();
+ RTWDOG_Unlock(base);
+ base->WIN = config->windowValue;
+ base->TOVAL = config->timeoutValue;
+ base->CS = value;
+ while ((base->CS & RTWDOG_CS_RCS_MASK) == 0U)
+ {
+ }
+ EnableGlobalIRQ(primaskValue);
+}
+
+/*!
+ * brief De-initializes the RTWDOG module.
+ *
+ * This function shuts down the RTWDOG.
+ * Ensure that the WDOG_CS.UPDATE is 1, which means that the register update is enabled.
+ *
+ * param base RTWDOG peripheral base address.
+ */
+void RTWDOG_Deinit(RTWDOG_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupts */
+ primaskValue = DisableGlobalIRQ();
+ RTWDOG_Unlock(base);
+ RTWDOG_Disable(base);
+ EnableGlobalIRQ(primaskValue);
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_sai.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_sai.c
new file mode 100644
index 0000000000..af69595996
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_sai.c
@@ -0,0 +1,3764 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_sai.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.sai"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*! @brief _sai_transfer_state sai transfer state.*/
+enum
+{
+ kSAI_Busy = 0x0U, /*!< SAI is busy */
+ kSAI_Idle, /*!< Transfer is done. */
+ kSAI_Error /*!< Transfer error occurred. */
+};
+
+/*! @brief Typedef for sai tx interrupt handler. */
+typedef void (*sai_tx_isr_t)(I2S_Type *base, sai_handle_t *saiHandle);
+
+/*! @brief Typedef for sai rx interrupt handler. */
+typedef void (*sai_rx_isr_t)(I2S_Type *base, sai_handle_t *saiHandle);
+
+/*! @brief check flag avalibility */
+#define IS_SAI_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL)
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief sai get rx enabled interrupt status.
+ *
+ *
+ * @param base SAI base pointer.
+ * @param enableFlag enable flag to check.
+ * @param statusFlag status flag to check.
+ */
+static bool SAI_RxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag);
+
+/*!
+ * @brief sai get tx enabled interrupt status.
+ *
+ *
+ * @param base SAI base pointer.
+ * @param enableFlag enable flag to check.
+ * @param statusFlag status flag to check.
+ */
+static bool SAI_TxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag);
+
+/*!
+ * @brief Set the master clock divider.
+ *
+ * This API will compute the master clock divider according to master clock frequency and master
+ * clock source clock source frequency.
+ *
+ * @param base SAI base pointer.
+ * @param mclk_Hz Mater clock frequency in Hz.
+ * @param mclkSrcClock_Hz Master clock source frequency in Hz.
+ */
+static bool SAI_TxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag);
+
+#if ((defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV) && (FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV)))
+
+/*!
+ * @brief Set the master clock divider.
+ *
+ * This API will compute the master clock divider according to master clock frequency and master
+ * clock source clock source frequency.
+ *
+ * @param base SAI base pointer.
+ * @param mclk_Hz Mater clock frequency in Hz.
+ * @param mclkSrcClock_Hz Master clock source frequency in Hz.
+ */
+static void SAI_SetMasterClockDivider(I2S_Type *base, uint32_t mclk_Hz, uint32_t mclkSrcClock_Hz);
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+/*!
+ * @brief Get the instance number for SAI.
+ *
+ * @param base SAI base pointer.
+ */
+static uint32_t SAI_GetInstance(I2S_Type *base);
+
+/*!
+ * @brief sends a piece of data in non-blocking way.
+ *
+ * @param base SAI base pointer
+ * @param channel start channel number.
+ * @param channelMask enabled channels mask.
+ * @param endChannel end channel numbers.
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be written.
+ * @param size Bytes to be written.
+ */
+static void SAI_WriteNonBlocking(I2S_Type *base,
+ uint32_t channel,
+ uint32_t channelMask,
+ uint32_t endChannel,
+ uint8_t bitWidth,
+ uint8_t *buffer,
+ uint32_t size);
+
+/*!
+ * @brief Receive a piece of data in non-blocking way.
+ *
+ * @param base SAI base pointer
+ * @param channel start channel number.
+ * @param channelMask enabled channels mask.
+ * @param endChannel end channel numbers.
+ * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
+ * @param buffer Pointer to the data to be read.
+ * @param size Bytes to be read.
+ */
+static void SAI_ReadNonBlocking(I2S_Type *base,
+ uint32_t channel,
+ uint32_t channelMask,
+ uint32_t endChannel,
+ uint8_t bitWidth,
+ uint8_t *buffer,
+ uint32_t size);
+
+/*!
+ * @brief Get classic I2S mode configurations.
+ *
+ * @param config transceiver configurations
+ * @param bitWidth audio data bitWidth.
+ * @param mode audio data channel
+ * @param saiChannelMask channel mask value to enable
+ */
+static void SAI_GetCommonConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Base pointer array */
+static I2S_Type *const s_saiBases[] = I2S_BASE_PTRS;
+/*!@brief SAI handle pointer */
+static sai_handle_t *s_saiHandle[ARRAY_SIZE(s_saiBases)][2];
+/* IRQ number array */
+static const IRQn_Type s_saiTxIRQ[] = I2S_TX_IRQS;
+static const IRQn_Type s_saiRxIRQ[] = I2S_RX_IRQS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_saiClock[] = SAI_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/*! @brief Pointer to tx IRQ handler for each instance. */
+static sai_tx_isr_t s_saiTxIsr;
+/*! @brief Pointer to tx IRQ handler for each instance. */
+static sai_rx_isr_t s_saiRxIsr;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static bool SAI_RxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag)
+{
+ uint32_t rcsr = base->RCSR;
+
+ return IS_SAI_FLAG_SET(rcsr, enableFlag) && IS_SAI_FLAG_SET(rcsr, statusFlag);
+}
+
+static bool SAI_TxGetEnabledInterruptStatus(I2S_Type *base, uint32_t enableFlag, uint32_t statusFlag)
+{
+ uint32_t tcsr = base->TCSR;
+
+ return IS_SAI_FLAG_SET(tcsr, enableFlag) && IS_SAI_FLAG_SET(tcsr, statusFlag);
+}
+
+#if ((defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV) && (FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV)))
+static void SAI_SetMasterClockDivider(I2S_Type *base, uint32_t mclk_Hz, uint32_t mclkSrcClock_Hz)
+{
+ assert(mclk_Hz <= mclkSrcClock_Hz);
+
+ uint32_t sourceFreq = mclkSrcClock_Hz / 100U; /*In order to prevent overflow */
+ uint32_t targetFreq = mclk_Hz / 100U; /*In order to prevent overflow */
+
+#if FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV
+ uint32_t postDivider = sourceFreq / targetFreq;
+
+ /* if source equal to target, then disable divider */
+ if (postDivider == 1U)
+ {
+ base->MCR &= ~I2S_MCR_DIVEN_MASK;
+ }
+ else
+ {
+ base->MCR = (base->MCR & (~I2S_MCR_DIV_MASK)) | I2S_MCR_DIV(postDivider / 2U - 1U) | I2S_MCR_DIVEN_MASK;
+ }
+#endif
+#if FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER
+ uint16_t fract, divide;
+ uint32_t remaind = 0;
+ uint32_t current_remainder = 0xFFFFFFFFU;
+ uint16_t current_fract = 0;
+ uint16_t current_divide = 0;
+ uint32_t mul_freq = 0;
+ uint32_t max_fract = 256;
+
+ /* Compute the max fract number */
+ max_fract = targetFreq * 4096U / sourceFreq + 1U;
+ if (max_fract > 256U)
+ {
+ max_fract = 256U;
+ }
+
+ /* Looking for the closet frequency */
+ for (fract = 1; fract < max_fract; fract++)
+ {
+ mul_freq = sourceFreq * fract;
+ remaind = mul_freq % targetFreq;
+ divide = (uint16_t)(mul_freq / targetFreq);
+
+ /* Find the exactly frequency */
+ if (remaind == 0U)
+ {
+ current_fract = fract;
+ current_divide = (uint16_t)(mul_freq / targetFreq);
+ break;
+ }
+
+ /* Closer to next one, set the closest to next data */
+ if (remaind > mclk_Hz / 2U)
+ {
+ remaind = targetFreq - remaind;
+ divide += 1U;
+ }
+
+ /* Update the closest div and fract */
+ if (remaind < current_remainder)
+ {
+ current_fract = fract;
+ current_divide = divide;
+ current_remainder = remaind;
+ }
+ }
+
+ /* Fill the computed fract and divider to registers */
+ base->MDR = I2S_MDR_DIVIDE(current_divide - 1UL) | I2S_MDR_FRACT(current_fract - 1UL);
+
+ /* Waiting for the divider updated */
+ while ((base->MCR & I2S_MCR_DUF_MASK) != 0UL)
+ {
+ }
+#endif
+}
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+static uint32_t SAI_GetInstance(I2S_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_saiBases); instance++)
+ {
+ if (s_saiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_saiBases));
+
+ return instance;
+}
+
+static void SAI_WriteNonBlocking(I2S_Type *base,
+ uint32_t channel,
+ uint32_t channelMask,
+ uint32_t endChannel,
+ uint8_t bitWidth,
+ uint8_t *buffer,
+ uint32_t size)
+{
+ uint32_t i = 0, j = 0U;
+ uint8_t m = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+ uint32_t temp = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ for (j = channel; j <= endChannel; j++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << j), channelMask))
+ {
+ for (m = 0; m < bytesPerWord; m++)
+ {
+ temp = (uint32_t)(*buffer);
+ data |= (temp << (8U * m));
+ buffer++;
+ }
+ base->TDR[j] = data;
+ data = 0;
+ }
+ }
+ }
+}
+
+static void SAI_ReadNonBlocking(I2S_Type *base,
+ uint32_t channel,
+ uint32_t channelMask,
+ uint32_t endChannel,
+ uint8_t bitWidth,
+ uint8_t *buffer,
+ uint32_t size)
+{
+ uint32_t i = 0, j = 0;
+ uint8_t m = 0;
+ uint8_t bytesPerWord = bitWidth / 8U;
+ uint32_t data = 0;
+
+ for (i = 0; i < size / bytesPerWord; i++)
+ {
+ for (j = channel; j <= endChannel; j++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << j), channelMask))
+ {
+ data = base->RDR[j];
+ for (m = 0; m < bytesPerWord; m++)
+ {
+ *buffer = (uint8_t)(data >> (8U * m)) & 0xFFU;
+ buffer++;
+ }
+ }
+ }
+ }
+}
+
+static void SAI_GetCommonConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+
+ (void)memset(config, 0, sizeof(sai_transceiver_t));
+
+ config->channelMask = (uint8_t)saiChannelMask;
+ /* sync mode default configurations */
+ config->syncMode = kSAI_ModeAsync;
+
+ /* master mode default */
+ config->masterSlave = kSAI_Master;
+
+ /* bit default configurations */
+ config->bitClock.bclkSrcSwap = false;
+ config->bitClock.bclkInputDelay = false;
+ config->bitClock.bclkPolarity = kSAI_SampleOnRisingEdge;
+ config->bitClock.bclkSource = kSAI_BclkSourceMclkDiv;
+
+ /* frame sync default configurations */
+ config->frameSync.frameSyncWidth = (uint8_t)bitWidth;
+ config->frameSync.frameSyncEarly = true;
+#if defined(FSL_FEATURE_SAI_HAS_FRAME_SYNC_ON_DEMAND) && FSL_FEATURE_SAI_HAS_FRAME_SYNC_ON_DEMAND
+ config->frameSync.frameSyncGenerateOnDemand = false;
+#endif
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveLow;
+
+ /* serial data default configurations */
+#if defined(FSL_FEATURE_SAI_HAS_CHANNEL_MODE) && FSL_FEATURE_SAI_HAS_CHANNEL_MODE
+ config->serialData.dataMode = kSAI_DataPinStateOutputZero;
+#endif
+ config->serialData.dataOrder = kSAI_DataMSB;
+ config->serialData.dataWord0Length = (uint8_t)bitWidth;
+ config->serialData.dataWordLength = (uint8_t)bitWidth;
+ config->serialData.dataWordNLength = (uint8_t)bitWidth;
+ config->serialData.dataFirstBitShifted = (uint8_t)bitWidth;
+ config->serialData.dataWordNum = 2U;
+ config->serialData.dataMaskedWord = (uint32_t)mode;
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* fifo configurations */
+ config->fifo.fifoWatermark = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNT / 2U);
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ config->fifo.fifoContinueOneError = true;
+#endif
+}
+
+/*!
+ * brief Initializes the SAI Tx peripheral.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_Init
+ *
+ * Ungates the SAI clock, resets the module, and configures SAI Tx with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SAI_TxGetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the SAI driver. Otherwise, accessing the SAIM module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base SAI base pointer
+ * param config SAI configuration structure.
+ */
+void SAI_TxInit(I2S_Type *base, const sai_config_t *config)
+{
+ uint32_t val = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the SAI clock */
+ (void)CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ /* Master clock source setting */
+ val = (base->MCR & ~I2S_MCR_MICS_MASK);
+ base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
+#endif
+
+ /* Configure Master clock output enable */
+ val = (base->MCR & ~I2S_MCR_MOE_MASK);
+ base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+
+ SAI_TxReset(base);
+
+ /* Configure audio protocol */
+ if (config->protocol == kSAI_BusLeftJustified)
+ {
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusRightJustified)
+ {
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusI2S)
+ {
+ base->TCR2 |= I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(31U) | I2S_TCR4_FSE(1U) | I2S_TCR4_FSP(1U) | I2S_TCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusPCMA)
+ {
+ base->TCR2 &= ~I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(0U) | I2S_TCR4_FSE(1U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ }
+ else
+ {
+ base->TCR2 &= ~I2S_TCR2_BCP_MASK;
+ base->TCR3 &= ~I2S_TCR3_WDFL_MASK;
+ base->TCR4 = I2S_TCR4_MF(1U) | I2S_TCR4_SYWD(0U) | I2S_TCR4_FSE(0U) | I2S_TCR4_FSP(0U) | I2S_TCR4_FRSZ(1U);
+ }
+
+ /* Set master or slave */
+ if (config->masterSlave == kSAI_Master)
+ {
+ base->TCR2 |= I2S_TCR2_BCD_MASK;
+ base->TCR4 |= I2S_TCR4_FSD_MASK;
+
+ /* Bit clock source setting */
+ val = base->TCR2 & (~I2S_TCR2_MSEL_MASK);
+ base->TCR2 = (val | I2S_TCR2_MSEL(config->bclkSource));
+ }
+ else
+ {
+ base->TCR2 &= ~I2S_TCR2_BCD_MASK;
+ base->TCR4 &= ~I2S_TCR4_FSD_MASK;
+ }
+
+ /* Set Sync mode */
+ if (config->syncMode == kSAI_ModeAsync)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ }
+ if (config->syncMode == kSAI_ModeSync)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(1U));
+ /* If sync with Rx, should set Rx to async mode */
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ }
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ if (config->syncMode == kSAI_ModeSyncWithOtherTx)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(2U));
+ }
+ if (config->syncMode == kSAI_ModeSyncWithOtherRx)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(3U));
+ }
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ SAI_TxSetFIFOErrorContinue(base, true);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR */
+}
+
+/*!
+ * brief Initializes the SAI Rx peripheral.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_Init
+ *
+ * Ungates the SAI clock, resets the module, and configures the SAI Rx with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SAI_RxGetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the SAI driver. Otherwise, accessing the SAI module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base SAI base pointer
+ * param config SAI configuration structure.
+ */
+void SAI_RxInit(I2S_Type *base, const sai_config_t *config)
+{
+ uint32_t val = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable SAI clock first. */
+ (void)CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ /* Master clock source setting */
+ val = (base->MCR & ~I2S_MCR_MICS_MASK);
+ base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
+#endif
+
+ /* Configure Master clock output enable */
+ val = (base->MCR & ~I2S_MCR_MOE_MASK);
+ base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+
+ SAI_RxReset(base);
+
+ /* Configure audio protocol */
+ if (config->protocol == kSAI_BusLeftJustified)
+ {
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusRightJustified)
+ {
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusI2S)
+ {
+ base->RCR2 |= I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(31U) | I2S_RCR4_FSE(1U) | I2S_RCR4_FSP(1U) | I2S_RCR4_FRSZ(1U);
+ }
+ else if (config->protocol == kSAI_BusPCMA)
+ {
+ base->RCR2 &= ~I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(0U) | I2S_RCR4_FSE(1U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ }
+ else
+ {
+ base->RCR2 &= ~I2S_RCR2_BCP_MASK;
+ base->RCR3 &= ~I2S_RCR3_WDFL_MASK;
+ base->RCR4 = I2S_RCR4_MF(1U) | I2S_RCR4_SYWD(0U) | I2S_RCR4_FSE(0U) | I2S_RCR4_FSP(0U) | I2S_RCR4_FRSZ(1U);
+ }
+
+ /* Set master or slave */
+ if (config->masterSlave == kSAI_Master)
+ {
+ base->RCR2 |= I2S_RCR2_BCD_MASK;
+ base->RCR4 |= I2S_RCR4_FSD_MASK;
+
+ /* Bit clock source setting */
+ val = base->RCR2 & (~I2S_RCR2_MSEL_MASK);
+ base->RCR2 = (val | I2S_RCR2_MSEL(config->bclkSource));
+ }
+ else
+ {
+ base->RCR2 &= ~I2S_RCR2_BCD_MASK;
+ base->RCR4 &= ~I2S_RCR4_FSD_MASK;
+ }
+
+ /* Set Sync mode */
+ if (config->syncMode == kSAI_ModeAsync)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ }
+ if (config->syncMode == kSAI_ModeSync)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(1U));
+ /* If sync with Tx, should set Tx to async mode */
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ }
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ if (config->syncMode == kSAI_ModeSyncWithOtherTx)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(2U));
+ }
+ if (config->syncMode == kSAI_ModeSyncWithOtherRx)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(3U));
+ }
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ SAI_RxSetFIFOErrorContinue(base, true);
+#endif /* FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR */
+}
+
+/*!
+ * brief Initializes the SAI peripheral.
+ *
+ * This API gates the SAI clock. The SAI module can't operate unless SAI_Init is called to enable the clock.
+ *
+ * param base SAI base pointer
+ */
+void SAI_Init(I2S_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the SAI clock */
+ (void)CLOCK_EnableClock(s_saiClock[SAI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* disable interrupt and DMA request*/
+ base->TCSR &=
+ ~(I2S_TCSR_FRIE_MASK | I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK | I2S_TCSR_FRDE_MASK | I2S_TCSR_FWDE_MASK);
+ base->RCSR &=
+ ~(I2S_RCSR_FRIE_MASK | I2S_RCSR_FWIE_MASK | I2S_RCSR_FEIE_MASK | I2S_RCSR_FRDE_MASK | I2S_RCSR_FWDE_MASK);
+#else
+ /* disable interrupt and DMA request*/
+ base->TCSR &= ~(I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK | I2S_TCSR_FWDE_MASK);
+ base->RCSR &= ~(I2S_RCSR_FWIE_MASK | I2S_RCSR_FEIE_MASK | I2S_RCSR_FWDE_MASK);
+#endif
+}
+
+/*!
+ * brief De-initializes the SAI peripheral.
+ *
+ * This API gates the SAI clock. The SAI module can't operate unless SAI_TxInit
+ * or SAI_RxInit is called to enable the clock.
+ *
+ * param base SAI base pointer
+ */
+void SAI_Deinit(I2S_Type *base)
+{
+ SAI_TxEnable(base, false);
+ SAI_RxEnable(base, false);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ (void)CLOCK_DisableClock(s_saiClock[SAI_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Sets the SAI Tx configuration structure to default values.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref
+ * SAI_GetClassicI2SConfig, SAI_GetLeftJustifiedConfig,SAI_GetRightJustifiedConfig, SAI_GetDSPConfig,SAI_GetTDMConfig
+ *
+ * This API initializes the configuration structure for use in SAI_TxConfig().
+ * The initialized structure can remain unchanged in SAI_TxConfig(), or it can be modified
+ * before calling SAI_TxConfig().
+ * This is an example.
+ code
+ sai_config_t config;
+ SAI_TxGetDefaultConfig(&config);
+ endcode
+ *
+ * param config pointer to master configuration structure
+ */
+void SAI_TxGetDefaultConfig(sai_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->bclkSource = kSAI_BclkSourceMclkDiv;
+ config->masterSlave = kSAI_Master;
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ config->mclkOutputEnable = true;
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ config->mclkSource = kSAI_MclkSourceSysclk;
+#endif
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+ config->protocol = kSAI_BusI2S;
+ config->syncMode = kSAI_ModeAsync;
+}
+
+/*!
+ * brief Sets the SAI Rx configuration structure to default values.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref
+ * SAI_GetClassicI2SConfig,SAI_GetLeftJustifiedConfig,SAI_GetRightJustifiedConfig,SAI_GetDSPConfig,SAI_GetTDMConfig
+ *
+ * This API initializes the configuration structure for use in SAI_RxConfig().
+ * The initialized structure can remain unchanged in SAI_RxConfig() or it can be modified
+ * before calling SAI_RxConfig().
+ * This is an example.
+ code
+ sai_config_t config;
+ SAI_RxGetDefaultConfig(&config);
+ endcode
+ *
+ * param config pointer to master configuration structure
+ */
+void SAI_RxGetDefaultConfig(sai_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->bclkSource = kSAI_BclkSourceMclkDiv;
+ config->masterSlave = kSAI_Master;
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ config->mclkOutputEnable = true;
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ config->mclkSource = kSAI_MclkSourceSysclk;
+#endif
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+ config->protocol = kSAI_BusI2S;
+ config->syncMode = kSAI_ModeSync;
+}
+
+/*!
+ * brief Resets the SAI Tx.
+ *
+ * This function enables the software reset and FIFO reset of SAI Tx. After reset, clear the reset bit.
+ *
+ * param base SAI base pointer
+ */
+void SAI_TxReset(I2S_Type *base)
+{
+ /* Set the software reset and FIFO reset to clear internal state */
+ base->TCSR = I2S_TCSR_SR_MASK | I2S_TCSR_FR_MASK;
+
+ /* Clear software reset bit, this should be done by software */
+ base->TCSR &= ~I2S_TCSR_SR_MASK;
+
+ /* Reset all Tx register values */
+ base->TCR2 = 0;
+ base->TCR3 = 0;
+ base->TCR4 = 0;
+ base->TCR5 = 0;
+ base->TMR = 0;
+}
+
+/*!
+ * brief Resets the SAI Rx.
+ *
+ * This function enables the software reset and FIFO reset of SAI Rx. After reset, clear the reset bit.
+ *
+ * param base SAI base pointer
+ */
+void SAI_RxReset(I2S_Type *base)
+{
+ /* Set the software reset and FIFO reset to clear internal state */
+ base->RCSR = I2S_RCSR_SR_MASK | I2S_RCSR_FR_MASK;
+
+ /* Clear software reset bit, this should be done by software */
+ base->RCSR &= ~I2S_RCSR_SR_MASK;
+
+ /* Reset all Rx register values */
+ base->RCR2 = 0;
+ base->RCR3 = 0;
+ base->RCR4 = 0;
+ base->RCR5 = 0;
+ base->RMR = 0;
+}
+
+/*!
+ * brief Enables/disables the SAI Tx.
+ *
+ * param base SAI base pointer
+ * param enable True means enable SAI Tx, false means disable.
+ */
+void SAI_TxEnable(I2S_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* If clock is sync with Rx, should enable RE bit. */
+ if (((base->TCR2 & I2S_TCR2_SYNC_MASK) >> I2S_TCR2_SYNC_SHIFT) == 0x1U)
+ {
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK);
+ }
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK);
+ /* Also need to clear the FIFO error flag before start */
+ SAI_TxClearStatusFlags(base, kSAI_FIFOErrorFlag);
+ }
+ else
+ {
+ /* If Rx not in sync with Tx, then disable Tx, otherwise, shall not disable Tx */
+ if (((base->RCR2 & I2S_RCR2_SYNC_MASK) >> I2S_RCR2_SYNC_SHIFT) != 0x1U)
+ {
+ /* Disable TE bit */
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK));
+ }
+ }
+}
+
+/*!
+ * brief Enables/disables the SAI Rx.
+ *
+ * param base SAI base pointer
+ * param enable True means enable SAI Rx, false means disable.
+ */
+void SAI_RxEnable(I2S_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* If clock is sync with Tx, should enable TE bit. */
+ if (((base->RCR2 & I2S_RCR2_SYNC_MASK) >> I2S_RCR2_SYNC_SHIFT) == 0x1U)
+ {
+ base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK);
+ }
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK);
+ /* Also need to clear the FIFO error flag before start */
+ SAI_RxClearStatusFlags(base, kSAI_FIFOErrorFlag);
+ }
+ else
+ {
+ /* If Tx not in sync with Rx, then disable Rx, otherwise, shall not disable Rx */
+ if (((base->TCR2 & I2S_TCR2_SYNC_MASK) >> I2S_TCR2_SYNC_SHIFT) != 0x1U)
+ {
+ /* Disable RE bit */
+ base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK));
+ }
+ }
+}
+
+/*!
+ * brief Do software reset or FIFO reset .
+ *
+ * FIFO reset means clear all the data in the FIFO, and make the FIFO pointer both to 0.
+ * Software reset means clear the Tx internal logic, including the bit clock, frame count etc. But software
+ * reset will not clear any configuration registers like TCR1~TCR5.
+ * This function will also clear all the error flags such as FIFO error, sync error etc.
+ *
+ * param base SAI base pointer
+ * param type Reset type, FIFO reset or software reset
+ */
+void SAI_TxSoftwareReset(I2S_Type *base, sai_reset_type_t type)
+{
+ base->TCSR |= (uint32_t)type;
+
+ /* Clear the software reset */
+ base->TCSR &= ~I2S_TCSR_SR_MASK;
+}
+
+/*!
+ * brief Do software reset or FIFO reset .
+ *
+ * FIFO reset means clear all the data in the FIFO, and make the FIFO pointer both to 0.
+ * Software reset means clear the Rx internal logic, including the bit clock, frame count etc. But software
+ * reset will not clear any configuration registers like RCR1~RCR5.
+ * This function will also clear all the error flags such as FIFO error, sync error etc.
+ *
+ * param base SAI base pointer
+ * param type Reset type, FIFO reset or software reset
+ */
+void SAI_RxSoftwareReset(I2S_Type *base, sai_reset_type_t type)
+{
+ base->RCSR |= (uint32_t)type;
+
+ /* Clear the software reset */
+ base->RCSR &= ~I2S_RCSR_SR_MASK;
+}
+
+/*!
+ * brief Set the Tx channel FIFO enable mask.
+ *
+ * param base SAI base pointer
+ * param mask Channel enable mask, 0 means all channel FIFO disabled, 1 means channel 0 enabled,
+ * 3 means both channel 0 and channel 1 enabled.
+ */
+void SAI_TxSetChannelFIFOMask(I2S_Type *base, uint8_t mask)
+{
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+ base->TCR3 |= I2S_TCR3_TCE(mask);
+}
+
+/*!
+ * brief Set the Rx channel FIFO enable mask.
+ *
+ * param base SAI base pointer
+ * param mask Channel enable mask, 0 means all channel FIFO disabled, 1 means channel 0 enabled,
+ * 3 means both channel 0 and channel 1 enabled.
+ */
+void SAI_RxSetChannelFIFOMask(I2S_Type *base, uint8_t mask)
+{
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+ base->RCR3 |= I2S_RCR3_RCE(mask);
+}
+
+/*!
+ * brief Set the Tx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_TxSetDataOrder(I2S_Type *base, sai_data_order_t order)
+{
+ uint32_t val = (base->TCR4) & (~I2S_TCR4_MF_MASK);
+
+ val |= I2S_TCR4_MF(order);
+ base->TCR4 = val;
+}
+
+/*!
+ * brief Set the Rx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_RxSetDataOrder(I2S_Type *base, sai_data_order_t order)
+{
+ uint32_t val = (base->RCR4) & (~I2S_RCR4_MF_MASK);
+
+ val |= I2S_RCR4_MF(order);
+ base->RCR4 = val;
+}
+
+/*!
+ * brief Set the Tx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_TxSetBitClockPolarity(I2S_Type *base, sai_clock_polarity_t polarity)
+{
+ uint32_t val = (base->TCR2) & (~I2S_TCR2_BCP_MASK);
+
+ val |= I2S_TCR2_BCP(polarity);
+ base->TCR2 = val;
+}
+
+/*!
+ * brief Set the Rx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_RxSetBitClockPolarity(I2S_Type *base, sai_clock_polarity_t polarity)
+{
+ uint32_t val = (base->RCR2) & (~I2S_RCR2_BCP_MASK);
+
+ val |= I2S_RCR2_BCP(polarity);
+ base->RCR2 = val;
+}
+
+/*!
+ * brief Set the Tx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_TxSetFrameSyncPolarity(I2S_Type *base, sai_clock_polarity_t polarity)
+{
+ uint32_t val = (base->TCR4) & (~I2S_TCR4_FSP_MASK);
+
+ val |= I2S_TCR4_FSP(polarity);
+ base->TCR4 = val;
+}
+
+/*!
+ * brief Set the Rx data order.
+ *
+ * param base SAI base pointer
+ * param order Data order MSB or LSB
+ */
+void SAI_RxSetFrameSyncPolarity(I2S_Type *base, sai_clock_polarity_t polarity)
+{
+ uint32_t val = (base->RCR4) & (~I2S_RCR4_FSP_MASK);
+
+ val |= I2S_RCR4_FSP(polarity);
+ base->RCR4 = val;
+}
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+/*!
+ * brief Set Tx FIFO packing feature.
+ *
+ * param base SAI base pointer.
+ * param pack FIFO pack type. It is element of sai_fifo_packing_t.
+ */
+void SAI_TxSetFIFOPacking(I2S_Type *base, sai_fifo_packing_t pack)
+{
+ uint32_t val = base->TCR4;
+
+ val &= ~I2S_TCR4_FPACK_MASK;
+ val |= I2S_TCR4_FPACK(pack);
+ base->TCR4 = val;
+}
+
+/*!
+ * brief Set Rx FIFO packing feature.
+ *
+ * param base SAI base pointer.
+ * param pack FIFO pack type. It is element of sai_fifo_packing_t.
+ */
+void SAI_RxSetFIFOPacking(I2S_Type *base, sai_fifo_packing_t pack)
+{
+ uint32_t val = base->RCR4;
+
+ val &= ~I2S_RCR4_FPACK_MASK;
+ val |= I2S_RCR4_FPACK(pack);
+ base->RCR4 = val;
+}
+#endif /* FSL_FEATURE_SAI_HAS_FIFO_PACKING */
+
+/*!
+ * brief Transmitter bit clock rate configurations.
+ *
+ * param base SAI base pointer.
+ * param sourceClockHz, bit clock source frequency.
+ * param sampleRate audio data sample rate.
+ * param bitWidth, audio data bitWidth.
+ * param channelNumbers, audio channel numbers.
+ */
+void SAI_TxSetBitClockRate(
+ I2S_Type *base, uint32_t sourceClockHz, uint32_t sampleRate, uint32_t bitWidth, uint32_t channelNumbers)
+{
+ uint32_t tcr2 = base->TCR2;
+ uint32_t bitClockDiv = 0;
+ uint32_t bitClockFreq = sampleRate * bitWidth * channelNumbers;
+
+ assert(sourceClockHz >= bitClockFreq);
+
+ tcr2 &= ~I2S_TCR2_DIV_MASK;
+ /* need to check the divided bclk, if bigger than target, then divider need to re-calculate. */
+ bitClockDiv = sourceClockHz / bitClockFreq;
+ /* for the condition where the source clock is smaller than target bclk */
+ if (bitClockDiv == 0U)
+ {
+ bitClockDiv++;
+ }
+ /* recheck the divider if properly or not, to make sure output blck not bigger than target*/
+ if ((sourceClockHz / bitClockDiv) > bitClockFreq)
+ {
+ bitClockDiv++;
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_BCLK_BYPASS) && (FSL_FEATURE_SAI_HAS_BCLK_BYPASS)
+ /* if bclk same with MCLK, bypass the divider */
+ if (bitClockDiv == 1U)
+ {
+ tcr2 |= I2S_TCR2_BYP_MASK;
+ }
+ else
+#endif
+ {
+ tcr2 |= I2S_TCR2_DIV(bitClockDiv / 2U - 1UL);
+ }
+
+ base->TCR2 = tcr2;
+}
+
+/*!
+ * brief Receiver bit clock rate configurations.
+ *
+ * param base SAI base pointer.
+ * param sourceClockHz, bit clock source frequency.
+ * param sampleRate audio data sample rate.
+ * param bitWidth, audio data bitWidth.
+ * param channelNumbers, audio channel numbers.
+ */
+void SAI_RxSetBitClockRate(
+ I2S_Type *base, uint32_t sourceClockHz, uint32_t sampleRate, uint32_t bitWidth, uint32_t channelNumbers)
+{
+ uint32_t rcr2 = base->RCR2;
+ uint32_t bitClockDiv = 0;
+ uint32_t bitClockFreq = sampleRate * bitWidth * channelNumbers;
+
+ assert(sourceClockHz >= bitClockFreq);
+
+ rcr2 &= ~I2S_RCR2_DIV_MASK;
+ /* need to check the divided bclk, if bigger than target, then divider need to re-calculate. */
+ bitClockDiv = sourceClockHz / bitClockFreq;
+ /* for the condition where the source clock is smaller than target bclk */
+ if (bitClockDiv == 0U)
+ {
+ bitClockDiv++;
+ }
+ /* recheck the divider if properly or not, to make sure output blck not bigger than target*/
+ if ((sourceClockHz / bitClockDiv) > bitClockFreq)
+ {
+ bitClockDiv++;
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_BCLK_BYPASS) && (FSL_FEATURE_SAI_HAS_BCLK_BYPASS)
+ /* if bclk same with MCLK, bypass the divider */
+ if (bitClockDiv == 1U)
+ {
+ rcr2 |= I2S_RCR2_BYP_MASK;
+ }
+ else
+#endif
+ {
+ rcr2 |= I2S_RCR2_DIV(bitClockDiv / 2U - 1UL);
+ }
+
+ base->RCR2 = rcr2;
+}
+
+/*!
+ * brief Transmitter Bit clock configurations.
+ *
+ * param base SAI base pointer.
+ * param masterSlave master or slave.
+ * param config bit clock other configurations, can be NULL in slave mode.
+ */
+void SAI_TxSetBitclockConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_bit_clock_t *config)
+{
+ uint32_t tcr2 = base->TCR2;
+
+ if ((masterSlave == kSAI_Master) || (masterSlave == kSAI_Bclk_Master_FrameSync_Slave))
+ {
+ assert(config != NULL);
+
+ tcr2 &= ~(I2S_TCR2_BCD_MASK | I2S_TCR2_BCP_MASK | I2S_TCR2_BCI_MASK | I2S_TCR2_BCS_MASK | I2S_TCR2_MSEL_MASK);
+ tcr2 |= I2S_TCR2_BCD(1U) | I2S_TCR2_BCP(config->bclkPolarity) | I2S_TCR2_BCI(config->bclkInputDelay) |
+ I2S_TCR2_BCS(config->bclkSrcSwap) | I2S_TCR2_MSEL(config->bclkSource);
+ }
+ else
+ {
+ tcr2 &= ~(I2S_TCR2_BCD_MASK);
+ }
+
+ base->TCR2 = tcr2;
+}
+
+/*!
+ * brief Receiver Bit clock configurations.
+ *
+ * param base SAI base pointer.
+ * param masterSlave master or slave.
+ * param config bit clock other configurations, can be NULL in slave mode.
+ */
+void SAI_RxSetBitclockConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_bit_clock_t *config)
+{
+ uint32_t rcr2 = base->RCR2;
+
+ if ((masterSlave == kSAI_Master) || (masterSlave == kSAI_Bclk_Master_FrameSync_Slave))
+ {
+ assert(config != NULL);
+
+ rcr2 &= ~(I2S_RCR2_BCD_MASK | I2S_RCR2_BCP_MASK | I2S_RCR2_BCI_MASK | I2S_RCR2_BCS_MASK | I2S_RCR2_MSEL_MASK);
+ rcr2 |= I2S_RCR2_BCD(1U) | I2S_RCR2_BCP(config->bclkPolarity) | I2S_RCR2_BCI(config->bclkInputDelay) |
+ I2S_RCR2_BCS(config->bclkSrcSwap) | I2S_RCR2_MSEL(config->bclkSource);
+ }
+ else
+ {
+ rcr2 &= ~(I2S_RCR2_BCD_MASK);
+ }
+
+ base->RCR2 = rcr2;
+}
+
+#if (defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER))
+/*!
+ * brief Master clock configurations.
+ *
+ * param base SAI base pointer.
+ * param config master clock configurations.
+ */
+void SAI_SetMasterClockConfig(I2S_Type *base, sai_master_clock_t *config)
+{
+ assert(config != NULL);
+
+#if defined(FSL_FEATURE_SAI_HAS_MCR) && (FSL_FEATURE_SAI_HAS_MCR)
+ uint32_t val = 0;
+#if !(defined(FSL_FEATURE_SAI_HAS_NO_MCR_MICS) && (FSL_FEATURE_SAI_HAS_NO_MCR_MICS))
+ /* Master clock source setting */
+ val = (base->MCR & ~I2S_MCR_MICS_MASK);
+ base->MCR = (val | I2S_MCR_MICS(config->mclkSource));
+#endif
+
+ /* Configure Master clock output enable */
+ val = (base->MCR & ~I2S_MCR_MOE_MASK);
+ base->MCR = (val | I2S_MCR_MOE(config->mclkOutputEnable));
+#endif /* FSL_FEATURE_SAI_HAS_MCR */
+
+#if ((defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)) || \
+ (defined(FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV) && (FSL_FEATURE_SAI_HAS_MCR_MCLK_POST_DIV)))
+ /* Check if master clock divider enabled, then set master clock divider */
+ if (config->mclkOutputEnable)
+ {
+ SAI_SetMasterClockDivider(base, config->mclkHz, config->mclkSourceClkHz);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+}
+#endif
+
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+/*!
+ * brief SAI transmitter fifo configurations.
+ *
+ * param base SAI base pointer.
+ * param config fifo configurations.
+ */
+void SAI_TxSetFifoConfig(I2S_Type *base, sai_fifo_t *config)
+{
+ assert(config != NULL);
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ assert(config->fifoWatermark <= (I2S_TCR1_TFW_MASK >> I2S_TCR1_TFW_SHIFT));
+#endif
+
+ uint32_t tcr4 = base->TCR4;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_COMBINE) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_COMBINE
+ tcr4 &= ~I2S_TCR4_FCOMB_MASK;
+ tcr4 |= I2S_TCR4_FCOMB(config->fifoCombine);
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ tcr4 &= ~I2S_TCR4_FCONT_MASK;
+ /* ERR05144: not set FCONT = 1 when TMR > 0, the transmit shift register may not load correctly that will cause TX
+ * not work */
+ if (base->TMR == 0U)
+ {
+ tcr4 |= I2S_TCR4_FCONT(config->fifoContinueOneError);
+ }
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+ tcr4 &= ~I2S_TCR4_FPACK_MASK;
+ tcr4 |= I2S_TCR4_FPACK(config->fifoPacking);
+#endif
+
+ base->TCR4 = tcr4;
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ base->TCR1 = (base->TCR1 & (~I2S_TCR1_TFW_MASK)) | I2S_TCR1_TFW(config->fifoWatermark);
+#endif
+}
+
+/*!
+ * brief SAI receiver fifo configurations.
+ *
+ * param base SAI base pointer.
+ * param config fifo configurations.
+ */
+void SAI_RxSetFifoConfig(I2S_Type *base, sai_fifo_t *config)
+{
+ assert(config != NULL);
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ assert(config->fifoWatermark <= (I2S_TCR1_TFW_MASK >> I2S_TCR1_TFW_SHIFT));
+#endif
+ uint32_t rcr4 = base->RCR4;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_COMBINE) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_COMBINE
+ rcr4 &= ~I2S_RCR4_FCOMB_MASK;
+ rcr4 |= I2S_RCR4_FCOMB(config->fifoCombine);
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ rcr4 &= ~I2S_RCR4_FCONT_MASK;
+ rcr4 |= I2S_RCR4_FCONT(config->fifoContinueOneError);
+#endif
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_PACKING) && FSL_FEATURE_SAI_HAS_FIFO_PACKING
+ rcr4 &= ~I2S_RCR4_FPACK_MASK;
+ rcr4 |= I2S_RCR4_FPACK(config->fifoPacking);
+#endif
+
+ base->RCR4 = rcr4;
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ base->RCR1 = (base->RCR1 & (~I2S_RCR1_RFW_MASK)) | I2S_RCR1_RFW(config->fifoWatermark);
+#endif
+}
+#endif
+
+/*!
+ * brief SAI transmitter Frame sync configurations.
+ *
+ * param base SAI base pointer.
+ * param masterSlave master or slave.
+ * param config frame sync configurations, can be NULL in slave mode.
+ */
+void SAI_TxSetFrameSyncConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_frame_sync_t *config)
+{
+ uint32_t tcr4 = base->TCR4;
+
+ if ((masterSlave == kSAI_Master) || (masterSlave == kSAI_Bclk_Slave_FrameSync_Master))
+ {
+ assert(config != NULL);
+ assert((config->frameSyncWidth - 1UL) <= (I2S_TCR4_SYWD_MASK >> I2S_TCR4_SYWD_SHIFT));
+
+ tcr4 &= ~(I2S_TCR4_FSE_MASK | I2S_TCR4_FSP_MASK | I2S_TCR4_FSD_MASK | I2S_TCR4_SYWD_MASK);
+
+#if defined(FSL_FEATURE_SAI_HAS_FRAME_SYNC_ON_DEMAND) && FSL_FEATURE_SAI_HAS_FRAME_SYNC_ON_DEMAND
+ tcr4 &= ~I2S_TCR4_ONDEM_MASK;
+ tcr4 |= I2S_TCR4_ONDEM(config->frameSyncGenerateOnDemand);
+#endif
+
+ tcr4 |= I2S_TCR4_FSE(config->frameSyncEarly) | I2S_TCR4_FSP(config->frameSyncPolarity) | I2S_TCR4_FSD(1UL) |
+ I2S_TCR4_SYWD(config->frameSyncWidth - 1UL);
+ }
+ else
+ {
+ tcr4 &= ~I2S_TCR4_FSD_MASK;
+ }
+
+ base->TCR4 = tcr4;
+}
+
+/*!
+ * brief SAI receiver Frame sync configurations.
+ *
+ * param base SAI base pointer.
+ * param masterSlave master or slave.
+ * param config frame sync configurations, can be NULL in slave mode.
+ */
+void SAI_RxSetFrameSyncConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai_frame_sync_t *config)
+{
+ uint32_t rcr4 = base->RCR4;
+
+ if ((masterSlave == kSAI_Master) || (masterSlave == kSAI_Bclk_Slave_FrameSync_Master))
+ {
+ assert(config != NULL);
+ assert((config->frameSyncWidth - 1UL) <= (I2S_RCR4_SYWD_MASK >> I2S_RCR4_SYWD_SHIFT));
+
+ rcr4 &= ~(I2S_RCR4_FSE_MASK | I2S_RCR4_FSP_MASK | I2S_RCR4_FSD_MASK | I2S_RCR4_SYWD_MASK);
+
+#if defined(FSL_FEATURE_SAI_HAS_FRAME_SYNC_ON_DEMAND) && FSL_FEATURE_SAI_HAS_FRAME_SYNC_ON_DEMAND
+ rcr4 &= ~I2S_RCR4_ONDEM_MASK;
+ rcr4 |= I2S_RCR4_ONDEM(config->frameSyncGenerateOnDemand);
+#endif
+
+ rcr4 |= I2S_RCR4_FSE(config->frameSyncEarly) | I2S_RCR4_FSP(config->frameSyncPolarity) | I2S_RCR4_FSD(1UL) |
+ I2S_RCR4_SYWD(config->frameSyncWidth - 1UL);
+ }
+ else
+ {
+ rcr4 &= ~I2S_RCR4_FSD_MASK;
+ }
+
+ base->RCR4 = rcr4;
+}
+
+/*!
+ * brief SAI transmitter Serial data configurations.
+ *
+ * param base SAI base pointer.
+ * param config serial data configurations.
+ */
+void SAI_TxSetSerialDataConfig(I2S_Type *base, sai_serial_data_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t tcr4 = base->TCR4;
+
+ base->TCR5 = I2S_TCR5_WNW(config->dataWordNLength - 1UL) | I2S_TCR5_W0W(config->dataWord0Length - 1UL) |
+ I2S_TCR5_FBT(config->dataFirstBitShifted - 1UL);
+ base->TMR = config->dataMaskedWord;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR) && FSL_FEATURE_SAI_HAS_FIFO_FUNCTION_AFTER_ERROR
+ /* ERR05144: not set FCONT = 1 when TMR > 0, the transmit shift register may not load correctly that will cause TX
+ * not work */
+ if (config->dataMaskedWord > 0U)
+ {
+ tcr4 &= ~I2S_TCR4_FCONT_MASK;
+ }
+#endif
+ tcr4 &= ~(I2S_TCR4_FRSZ_MASK | I2S_TCR4_MF_MASK);
+ tcr4 |= I2S_TCR4_FRSZ(config->dataWordNum - 1UL) | I2S_TCR4_MF(config->dataOrder);
+
+#if defined(FSL_FEATURE_SAI_HAS_CHANNEL_MODE) && FSL_FEATURE_SAI_HAS_CHANNEL_MODE
+ tcr4 &= ~I2S_TCR4_CHMOD_MASK;
+ tcr4 |= I2S_TCR4_CHMOD(config->dataMode);
+#endif
+
+ base->TCR4 = tcr4;
+}
+
+/*!
+ * @brief SAI receiver Serial data configurations.
+ *
+ * @param base SAI base pointer.
+ * @param config serial data configurations.
+ */
+void SAI_RxSetSerialDataConfig(I2S_Type *base, sai_serial_data_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t rcr4 = base->RCR4;
+
+ base->RCR5 = I2S_RCR5_WNW(config->dataWordNLength - 1UL) | I2S_RCR5_W0W(config->dataWord0Length - 1UL) |
+ I2S_RCR5_FBT(config->dataFirstBitShifted - 1UL);
+ base->RMR = config->dataMaskedWord;
+
+ rcr4 &= ~(I2S_RCR4_FRSZ_MASK | I2S_RCR4_MF_MASK);
+ rcr4 |= I2S_RCR4_FRSZ(config->dataWordNum - 1uL) | I2S_RCR4_MF(config->dataOrder);
+
+ base->RCR4 = rcr4;
+}
+
+/*!
+ * brief SAI transmitter configurations.
+ *
+ * param base SAI base pointer.
+ * param config transmitter configurations.
+ */
+void SAI_TxSetConfig(I2S_Type *base, sai_transceiver_t *config)
+{
+ assert(config != NULL);
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint8_t i = 0U;
+ uint32_t val = 0U;
+ uint8_t channelNums = 0U;
+
+ /* reset transmitter */
+ SAI_TxReset(base);
+
+ /* if channel mask is not set, then format->channel must be set,
+ use it to get channel mask value */
+ if (config->channelMask == 0U)
+ {
+ config->channelMask = 1U << config->startChannel;
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET(1UL << i, config->channelMask))
+ {
+ channelNums++;
+ config->endChannel = i;
+ }
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), config->channelMask))
+ {
+ config->startChannel = i;
+ break;
+ }
+ }
+
+ config->channelNums = channelNums;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && (FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ /* make sure combine mode disabled while multipe channel is used */
+ if (config->channelNums > 1U)
+ {
+ base->TCR4 &= ~I2S_TCR4_FCOMB_MASK;
+ }
+#endif
+
+ /* Set data channel */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+ base->TCR3 |= I2S_TCR3_TCE(config->channelMask);
+
+ if (config->syncMode == kSAI_ModeAsync)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ }
+ if (config->syncMode == kSAI_ModeSync)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(1U));
+ /* If sync with Rx, should set Rx to async mode */
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ }
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ if (config->syncMode == kSAI_ModeSyncWithOtherTx)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(2U));
+ }
+ if (config->syncMode == kSAI_ModeSyncWithOtherRx)
+ {
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(3U));
+ }
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+
+ /* bit clock configurations */
+ SAI_TxSetBitclockConfig(base, config->masterSlave, &config->bitClock);
+ /* serial data configurations */
+ SAI_TxSetSerialDataConfig(base, &config->serialData);
+ /* frame sync configurations */
+ SAI_TxSetFrameSyncConfig(base, config->masterSlave, &config->frameSync);
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+ /* fifo configurations */
+ SAI_TxSetFifoConfig(base, &config->fifo);
+#endif
+}
+
+/*!
+ * brief SAI transmitter transfer configurations.
+ *
+ * This function initializes the TX, include bit clock, frame sync, master clock, serial data and fifo configurations.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param config tranmitter configurations.
+ */
+void SAI_TransferTxSetConfig(I2S_Type *base, sai_handle_t *handle, sai_transceiver_t *config)
+{
+ assert(handle != NULL);
+ assert(config != NULL);
+ assert(config->channelNums <= (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base));
+
+ handle->bitWidth = config->frameSync.frameSyncWidth;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->watermark = config->fifo.fifoWatermark;
+#endif
+
+ /* transmitter configurations */
+ SAI_TxSetConfig(base, config);
+
+ handle->channel = config->startChannel;
+ /* used for multi channel */
+ handle->channelMask = config->channelMask;
+ handle->channelNums = config->channelNums;
+ handle->endChannel = config->endChannel;
+}
+
+/*!
+ * brief SAI receiver configurations.
+ *
+ * param base SAI base pointer.
+ * param config transmitter configurations.
+ */
+void SAI_RxSetConfig(I2S_Type *base, sai_transceiver_t *config)
+{
+ assert(config != NULL);
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint8_t i = 0U;
+ uint32_t val = 0U;
+ uint8_t channelNums = 0U;
+
+ /* reset receiver */
+ SAI_RxReset(base);
+
+ /* if channel mask is not set, then format->channel must be set,
+ use it to get channel mask value */
+ if (config->channelMask == 0U)
+ {
+ config->channelMask = 1U << config->startChannel;
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), config->channelMask))
+ {
+ channelNums++;
+ config->endChannel = i;
+ }
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), config->channelMask))
+ {
+ config->startChannel = i;
+ break;
+ }
+ }
+
+ config->channelNums = channelNums;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && (FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ /* make sure combine mode disabled while multipe channel is used */
+ if (config->channelNums > 1U)
+ {
+ base->RCR4 &= ~I2S_RCR4_FCOMB_MASK;
+ }
+#endif
+
+ /* Set data channel */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+ base->RCR3 |= I2S_RCR3_RCE(config->channelMask);
+
+ /* Set Sync mode */
+ if (config->syncMode == kSAI_ModeAsync)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(0U));
+ }
+ if (config->syncMode == kSAI_ModeSync)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(1U));
+ /* If sync with Tx, should set Tx to async mode */
+ val = base->TCR2;
+ val &= ~I2S_TCR2_SYNC_MASK;
+ base->TCR2 = (val | I2S_TCR2_SYNC(0U));
+ }
+#if defined(FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI) && (FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI)
+ if (config->syncMode == kSAI_ModeSyncWithOtherTx)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(2U));
+ }
+ if (config->syncMode == kSAI_ModeSyncWithOtherRx)
+ {
+ val = base->RCR2;
+ val &= ~I2S_RCR2_SYNC_MASK;
+ base->RCR2 = (val | I2S_RCR2_SYNC(3U));
+ }
+#endif /* FSL_FEATURE_SAI_HAS_SYNC_WITH_ANOTHER_SAI */
+
+ /* bit clock configurations */
+ SAI_RxSetBitclockConfig(base, config->masterSlave, &config->bitClock);
+ /* serial data configurations */
+ SAI_RxSetSerialDataConfig(base, &config->serialData);
+ /* frame sync configurations */
+ SAI_RxSetFrameSyncConfig(base, config->masterSlave, &config->frameSync);
+#if FSL_SAI_HAS_FIFO_EXTEND_FEATURE
+ /* fifo configurations */
+ SAI_RxSetFifoConfig(base, &config->fifo);
+#endif
+}
+
+/*!
+ * brief SAI receiver transfer configurations.
+ *
+ * This function initializes the TX, include bit clock, frame sync, master clock, serial data and fifo configurations.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param config tranmitter configurations.
+ */
+void SAI_TransferRxSetConfig(I2S_Type *base, sai_handle_t *handle, sai_transceiver_t *config)
+{
+ assert(handle != NULL);
+ assert(config != NULL);
+
+ handle->bitWidth = config->frameSync.frameSyncWidth;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->watermark = config->fifo.fifoWatermark;
+#endif
+
+ /* receiver configurations */
+ SAI_RxSetConfig(base, config);
+
+ handle->channel = config->startChannel;
+ /* used for multi channel */
+ handle->channelMask = config->channelMask;
+ handle->channelNums = config->channelNums;
+ handle->endChannel = config->endChannel;
+}
+
+/*!
+ * brief Get classic I2S mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetClassicI2SConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ SAI_GetCommonConfig(config, bitWidth, mode, saiChannelMask);
+}
+
+/*!
+ * brief Get left justified mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetLeftJustifiedConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+
+ SAI_GetCommonConfig(config, bitWidth, mode, saiChannelMask);
+
+ config->frameSync.frameSyncEarly = false;
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveHigh;
+}
+
+/*!
+ * brief Get right justified mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetRightJustifiedConfig(sai_transceiver_t *config,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+
+ SAI_GetCommonConfig(config, bitWidth, mode, saiChannelMask);
+
+ config->frameSync.frameSyncEarly = false;
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveHigh;
+}
+
+/*!
+ * brief Get DSP mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetDSPConfig(sai_transceiver_t *config,
+ sai_frame_sync_len_t frameSyncWidth,
+ sai_word_width_t bitWidth,
+ sai_mono_stereo_t mode,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+
+ SAI_GetCommonConfig(config, bitWidth, mode, saiChannelMask);
+
+ /* frame sync default configurations */
+ switch (frameSyncWidth)
+ {
+ case kSAI_FrameSyncLenOneBitClk:
+ config->frameSync.frameSyncWidth = 1U;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ config->frameSync.frameSyncEarly = false;
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveHigh;
+}
+
+/*!
+ * brief Get TDM mode configurations.
+ *
+ * param config transceiver configurations.
+ * param bitWidth audio data bitWidth.
+ * param mode audio data channel.
+ * param saiChannelMask channel mask value to enable.
+ */
+void SAI_GetTDMConfig(sai_transceiver_t *config,
+ sai_frame_sync_len_t frameSyncWidth,
+ sai_word_width_t bitWidth,
+ uint32_t dataWordNum,
+ uint32_t saiChannelMask)
+{
+ assert(NULL != config);
+ assert(saiChannelMask != 0U);
+ assert(dataWordNum <= 32U);
+
+ SAI_GetCommonConfig(config, bitWidth, kSAI_Stereo, saiChannelMask);
+
+ /* frame sync default configurations */
+ switch (frameSyncWidth)
+ {
+ case kSAI_FrameSyncLenOneBitClk:
+ config->frameSync.frameSyncWidth = 1U;
+ break;
+ case kSAI_FrameSyncLenPerWordWidth:
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ config->frameSync.frameSyncEarly = false;
+ config->frameSync.frameSyncPolarity = kSAI_PolarityActiveHigh;
+ config->serialData.dataWordNum = (uint8_t)dataWordNum;
+}
+
+/*!
+ * brief Configures the SAI Tx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_TxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SAI base pointer.
+ * param format Pointer to the SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If the bit clock source is a master
+ * clock, this value should equal the masterClockHz.
+ */
+void SAI_TxSetFormat(I2S_Type *base,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint32_t bclk = 0;
+ uint32_t val = 0;
+ uint8_t i = 0U, channelNums = 0U;
+ uint32_t divider = 0U;
+
+ if (format->isFrameSyncCompact)
+ {
+ bclk = format->sampleRate_Hz * format->bitWidth * (format->stereo == kSAI_Stereo ? 2U : 1U);
+ val = (base->TCR4 & (~I2S_TCR4_SYWD_MASK));
+ val |= I2S_TCR4_SYWD(format->bitWidth - 1U);
+ base->TCR4 = val;
+ }
+ else
+ {
+ bclk = format->sampleRate_Hz * 32U * 2U;
+ }
+
+/* Compute the mclk */
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ /* Check if master clock divider enabled, then set master clock divider */
+ if (IS_SAI_FLAG_SET(base->MCR, I2S_MCR_MOE_MASK))
+ {
+ SAI_SetMasterClockDivider(base, format->masterClockHz, mclkSourceClockHz);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+ /* Set bclk if needed */
+ if (IS_SAI_FLAG_SET(base->TCR2, I2S_TCR2_BCD_MASK))
+ {
+ base->TCR2 &= ~I2S_TCR2_DIV_MASK;
+ /* need to check the divided bclk, if bigger than target, then divider need to re-calculate. */
+ divider = bclkSourceClockHz / bclk;
+ /* for the condition where the source clock is smaller than target bclk */
+ if (divider == 0U)
+ {
+ divider++;
+ }
+ /* recheck the divider if properly or not, to make sure output blck not bigger than target*/
+ if ((bclkSourceClockHz / divider) > bclk)
+ {
+ divider++;
+ }
+
+#if defined(FSL_FEATURE_SAI_HAS_BCLK_BYPASS) && (FSL_FEATURE_SAI_HAS_BCLK_BYPASS)
+ /* if bclk same with MCLK, bypass the divider */
+ if (divider == 1U)
+ {
+ base->TCR2 |= I2S_TCR2_BYP_MASK;
+ }
+ else
+#endif
+ {
+ base->TCR2 |= I2S_TCR2_DIV(divider / 2U - 1U);
+ }
+ }
+
+ /* Set bitWidth */
+ val = (format->isFrameSyncCompact) ? (format->bitWidth - 1U) : 31U;
+ if (format->protocol == kSAI_BusRightJustified)
+ {
+ base->TCR5 = I2S_TCR5_WNW(val) | I2S_TCR5_W0W(val) | I2S_TCR5_FBT(val);
+ }
+ else
+ {
+ if (IS_SAI_FLAG_SET(base->TCR4, I2S_TCR4_MF_MASK))
+ {
+ base->TCR5 = I2S_TCR5_WNW(val) | I2S_TCR5_W0W(val) | I2S_TCR5_FBT(format->bitWidth - 1UL);
+ }
+ else
+ {
+ base->TCR5 = I2S_TCR5_WNW(val) | I2S_TCR5_W0W(val) | I2S_TCR5_FBT(0);
+ }
+ }
+
+ /* Set mono or stereo */
+ base->TMR = (uint32_t)format->stereo;
+
+ /* if channel mask is not set, then format->channel must be set,
+ use it to get channel mask value */
+ if (format->channelMask == 0U)
+ {
+ format->channelMask = 1U << format->channel;
+ }
+
+ /* if channel nums is not set, calculate it here according to channelMask*/
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), format->channelMask))
+ {
+ channelNums++;
+ format->endChannel = i;
+ }
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), format->channelMask))
+ {
+ format->channel = i;
+ break;
+ }
+ }
+
+ format->channelNums = channelNums;
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && (FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ /* make sure combine mode disabled while multipe channel is used */
+ if (format->channelNums > 1U)
+ {
+ base->TCR4 &= ~I2S_TCR4_FCOMB_MASK;
+ }
+#endif
+
+ /* Set data channel */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+ base->TCR3 |= I2S_TCR3_TCE(format->channelMask);
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Set watermark */
+ base->TCR1 = format->watermark;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+/*!
+ * brief Configures the SAI Rx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_RxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SAI base pointer.
+ * param format Pointer to the SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If the bit clock source is a master
+ * clock, this value should equal the masterClockHz.
+ */
+void SAI_RxSetFormat(I2S_Type *base,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint32_t bclk = 0;
+ uint32_t val = 0;
+ uint8_t i = 0U, channelNums = 0U;
+ uint32_t divider = 0U;
+
+ if (format->isFrameSyncCompact)
+ {
+ bclk = format->sampleRate_Hz * format->bitWidth * (format->stereo == kSAI_Stereo ? 2U : 1U);
+ val = (base->RCR4 & (~I2S_RCR4_SYWD_MASK));
+ val |= I2S_RCR4_SYWD(format->bitWidth - 1U);
+ base->RCR4 = val;
+ }
+ else
+ {
+ bclk = format->sampleRate_Hz * 32U * 2U;
+ }
+
+/* Compute the mclk */
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ /* Check if master clock divider enabled */
+ if (IS_SAI_FLAG_SET(base->MCR, I2S_MCR_MOE_MASK))
+ {
+ SAI_SetMasterClockDivider(base, format->masterClockHz, mclkSourceClockHz);
+ }
+#endif /* FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER */
+
+ /* Set bclk if needed */
+ if (IS_SAI_FLAG_SET(base->RCR2, I2S_RCR2_BCD_MASK))
+ {
+ base->RCR2 &= ~I2S_RCR2_DIV_MASK;
+ /* need to check the divided bclk, if bigger than target, then divider need to re-calculate. */
+ divider = bclkSourceClockHz / bclk;
+ /* for the condition where the source clock is smaller than target bclk */
+ if (divider == 0U)
+ {
+ divider++;
+ }
+ /* recheck the divider if properly or not, to make sure output blck not bigger than target*/
+ if ((bclkSourceClockHz / divider) > bclk)
+ {
+ divider++;
+ }
+#if defined(FSL_FEATURE_SAI_HAS_BCLK_BYPASS) && (FSL_FEATURE_SAI_HAS_BCLK_BYPASS)
+ /* if bclk same with MCLK, bypass the divider */
+ if (divider == 1U)
+ {
+ base->RCR2 |= I2S_RCR2_BYP_MASK;
+ }
+ else
+#endif
+ {
+ base->RCR2 |= I2S_RCR2_DIV(divider / 2U - 1U);
+ }
+ }
+
+ /* Set bitWidth */
+ val = (format->isFrameSyncCompact) ? (format->bitWidth - 1U) : 31U;
+ if (format->protocol == kSAI_BusRightJustified)
+ {
+ base->RCR5 = I2S_RCR5_WNW(val) | I2S_RCR5_W0W(val) | I2S_RCR5_FBT(val);
+ }
+ else
+ {
+ if (IS_SAI_FLAG_SET(base->RCR4, I2S_RCR4_MF_MASK))
+ {
+ base->RCR5 = I2S_RCR5_WNW(val) | I2S_RCR5_W0W(val) | I2S_RCR5_FBT(format->bitWidth - 1UL);
+ }
+ else
+ {
+ base->RCR5 = I2S_RCR5_WNW(val) | I2S_RCR5_W0W(val) | I2S_RCR5_FBT(0UL);
+ }
+ }
+
+ /* Set mono or stereo */
+ base->RMR = (uint32_t)format->stereo;
+
+ /* if channel mask is not set, then format->channel must be set,
+ use it to get channel mask value */
+ if (format->channelMask == 0U)
+ {
+ format->channelMask = 1U << format->channel;
+ }
+
+ /* if channel nums is not set, calculate it here according to channelMask*/
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), format->channelMask))
+ {
+ channelNums++;
+ format->endChannel = i;
+ }
+ }
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), format->channelMask))
+ {
+ format->channel = i;
+ break;
+ }
+ }
+
+ format->channelNums = channelNums;
+
+#if defined(FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE) && (FSL_FEATURE_SAI_HAS_FIFO_COMBINE_MODE)
+ /* make sure combine mode disabled while multipe channel is used */
+ if (format->channelNums > 1U)
+ {
+ base->RCR4 &= ~I2S_RCR4_FCOMB_MASK;
+ }
+#endif
+
+ /* Set data channel */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+ /* enable all the channel */
+ base->RCR3 |= I2S_RCR3_RCE(format->channelMask);
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Set watermark */
+ base->RCR1 = format->watermark;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+/*!
+ * brief Sends data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SAI base pointer.
+ * param channel Data channel used.
+ * param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * param buffer Pointer to the data to be written.
+ * param size Bytes to be written.
+ */
+void SAI_WriteBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ uint32_t i = 0;
+ uint32_t bytesPerWord = bitWidth / 8U;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ bytesPerWord = (((uint32_t)FSL_FEATURE_SAI_FIFO_COUNT - base->TCR1) * bytesPerWord);
+#endif
+
+ while (i < size)
+ {
+ /* Wait until it can write data */
+ while (!(IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK)))
+ {
+ }
+
+ SAI_WriteNonBlocking(base, channel, 1UL << channel, channel, (uint8_t)bitWidth, buffer, bytesPerWord);
+ buffer += bytesPerWord;
+ i += bytesPerWord;
+ }
+
+ /* Wait until the last data is sent */
+ while (!(IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK)))
+ {
+ }
+}
+
+/*!
+ * brief Sends data to multi channel using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SAI base pointer.
+ * param channel Data channel used.
+ * param channelMask channel mask.
+ * param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * param buffer Pointer to the data to be written.
+ * param size Bytes to be written.
+ */
+void SAI_WriteMultiChannelBlocking(
+ I2S_Type *base, uint32_t channel, uint32_t channelMask, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint32_t i = 0, j = 0;
+ uint32_t bytesPerWord = bitWidth / 8U;
+ uint32_t channelNums = 0U, endChannel = 0U;
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ bytesPerWord = (((uint32_t)FSL_FEATURE_SAI_FIFO_COUNT - base->TCR1) * bytesPerWord);
+#endif
+
+ for (i = 0U; (i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base)); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), channelMask))
+ {
+ channelNums++;
+ endChannel = i;
+ }
+ }
+
+ bytesPerWord *= channelNums;
+
+ while (j < size)
+ {
+ /* Wait until it can write data */
+ while (!(IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK)))
+ {
+ }
+
+ SAI_WriteNonBlocking(base, channel, channelMask, endChannel, (uint8_t)bitWidth, buffer, bytesPerWord);
+ buffer += bytesPerWord;
+ j += bytesPerWord;
+ }
+
+ /* Wait until the last data is sent */
+ while (!(IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK)))
+ {
+ }
+}
+
+/*!
+ * brief Receives multi channel data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SAI base pointer.
+ * param channel Data channel used.
+ * param channelMask channel mask.
+ * param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * param buffer Pointer to the data to be read.
+ * param size Bytes to be read.
+ */
+void SAI_ReadMultiChannelBlocking(
+ I2S_Type *base, uint32_t channel, uint32_t channelMask, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ assert(FSL_FEATURE_SAI_CHANNEL_COUNTn(base) != -1);
+
+ uint32_t i = 0, j = 0;
+ uint32_t bytesPerWord = bitWidth / 8U;
+ uint32_t channelNums = 0U, endChannel = 0U;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ bytesPerWord = base->RCR1 * bytesPerWord;
+#endif
+ for (i = 0U; (i < (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base)); i++)
+ {
+ if (IS_SAI_FLAG_SET((1UL << i), channelMask))
+ {
+ channelNums++;
+ endChannel = i;
+ }
+ }
+
+ bytesPerWord *= channelNums;
+
+ while (j < size)
+ {
+ /* Wait until data is received */
+ while (!(IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FWF_MASK)))
+ {
+ }
+
+ SAI_ReadNonBlocking(base, channel, channelMask, endChannel, (uint8_t)bitWidth, buffer, bytesPerWord);
+ buffer += bytesPerWord;
+ j += bytesPerWord;
+ }
+}
+
+/*!
+ * brief Receives data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SAI base pointer.
+ * param channel Data channel used.
+ * param bitWidth How many bits in an audio word; usually 8/16/24/32 bits.
+ * param buffer Pointer to the data to be read.
+ * param size Bytes to be read.
+ */
+void SAI_ReadBlocking(I2S_Type *base, uint32_t channel, uint32_t bitWidth, uint8_t *buffer, uint32_t size)
+{
+ uint32_t i = 0;
+ uint32_t bytesPerWord = bitWidth / 8U;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ bytesPerWord = base->RCR1 * bytesPerWord;
+#endif
+
+ while (i < size)
+ {
+ /* Wait until data is received */
+ while (!(IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FWF_MASK)))
+ {
+ }
+
+ SAI_ReadNonBlocking(base, channel, 1UL << channel, channel, (uint8_t)bitWidth, buffer, bytesPerWord);
+ buffer += bytesPerWord;
+ i += bytesPerWord;
+ }
+}
+
+/*!
+ * brief Initializes the SAI Tx handle.
+ *
+ * This function initializes the Tx handle for the SAI Tx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SAI base pointer
+ * param handle SAI handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function
+ */
+void SAI_TransferTxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_saiHandle[SAI_GetInstance(base)][0] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->base = base;
+
+ /* Set the isr pointer */
+ s_saiTxIsr = SAI_TransferTxHandleIRQ;
+
+ /* Enable Tx irq */
+ (void)EnableIRQ(s_saiTxIRQ[SAI_GetInstance(base)]);
+}
+
+/*!
+ * brief Initializes the SAI Rx handle.
+ *
+ * This function initializes the Rx handle for the SAI Rx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function.
+ */
+void SAI_TransferRxCreateHandle(I2S_Type *base, sai_handle_t *handle, sai_transfer_callback_t callback, void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_saiHandle[SAI_GetInstance(base)][1] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->base = base;
+
+ /* Set the isr pointer */
+ s_saiRxIsr = SAI_TransferRxHandleIRQ;
+
+ /* Enable Rx irq */
+ (void)EnableIRQ(s_saiRxIRQ[SAI_GetInstance(base)]);
+}
+
+/*!
+ * brief Configures the SAI Tx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_TransferTxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param format Pointer to the SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is a master
+ * clock, this value should equal the masterClockHz in format.
+ * return Status of this function. Return value is the status_t.
+ */
+status_t SAI_TransferTxSetFormat(I2S_Type *base,
+ sai_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(handle != NULL);
+
+ if ((bclkSourceClockHz < format->sampleRate_Hz)
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ || (mclkSourceClockHz < format->sampleRate_Hz)
+#endif
+ )
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Copy format to handle */
+ handle->bitWidth = (uint8_t)format->bitWidth;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->watermark = format->watermark;
+#endif
+
+ SAI_TxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ handle->channel = format->channel;
+ /* used for multi channel */
+ handle->channelMask = format->channelMask;
+ handle->channelNums = format->channelNums;
+ handle->endChannel = format->endChannel;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures the SAI Rx audio format.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref SAI_TransferRxSetConfig
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SAI base pointer.
+ * param handle SAI handle pointer.
+ * param format Pointer to the SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is a master
+ * clock, this value should equal the masterClockHz in format.
+ * return Status of this function. Return value is one of status_t.
+ */
+status_t SAI_TransferRxSetFormat(I2S_Type *base,
+ sai_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert(handle != NULL);
+
+ if ((bclkSourceClockHz < format->sampleRate_Hz)
+#if defined(FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER) && (FSL_FEATURE_SAI_HAS_MCLKDIV_REGISTER)
+ || (mclkSourceClockHz < format->sampleRate_Hz)
+#endif
+ )
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Copy format to handle */
+ handle->bitWidth = (uint8_t)format->bitWidth;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->watermark = format->watermark;
+#endif
+
+ SAI_RxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ handle->channel = format->channel;
+ /* used for multi channel */
+ handle->channelMask = format->channelMask;
+ handle->channelNums = format->channelNums;
+ handle->endChannel = format->endChannel;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking send transfer on SAI.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SAI_TxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SAI_Busy, the transfer
+ * is finished.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the sai_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SAI_TxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SAI_TransferSendNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(handle->channelNums <= (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base));
+
+ /* Check if the queue is full */
+ if (handle->saiQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % SAI_XFER_QUEUE_SIZE;
+
+ /* Set the state to busy */
+ handle->state = (uint32_t)kSAI_Busy;
+
+ /* Enable interrupt */
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Use FIFO request interrupt and fifo error*/
+ SAI_TxEnableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FRIE_MASK);
+#else
+ SAI_TxEnableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FWIE_MASK);
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ /* Enable Tx transfer */
+ SAI_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on SAI.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SAI_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SAI_Busy, the transfer
+ * is finished.
+ *
+ * param base SAI base pointer
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the sai_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SAI_RxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SAI_TransferReceiveNonBlocking(I2S_Type *base, sai_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(handle->channelNums <= (uint32_t)FSL_FEATURE_SAI_CHANNEL_COUNTn(base));
+
+ /* Check if the queue is full */
+ if (handle->saiQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % SAI_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = (uint32_t)kSAI_Busy;
+
+/* Enable interrupt */
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Use FIFO request interrupt and fifo error*/
+ SAI_RxEnableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FRIE_MASK);
+#else
+ SAI_RxEnableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FWIE_MASK);
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ /* Enable Rx transfer */
+ SAI_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets a set byte count.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * param count Bytes count sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SAI_TransferGetSendCount(I2S_Type *base, sai_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint32_t queueDriverIndex = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriverIndex] - handle->saiQueue[queueDriverIndex].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets a received byte count.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ * param count Bytes count received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SAI_TransferGetReceiveCount(I2S_Type *base, sai_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint32_t queueDriverIndex = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriverIndex] - handle->saiQueue[queueDriverIndex].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the current send.
+ *
+ * note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ */
+void SAI_TransferAbortSend(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Stop Tx transfer and disable interrupt */
+ SAI_TxEnable(base, false);
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Use FIFO request interrupt and fifo error */
+ SAI_TxDisableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FRIE_MASK);
+#else
+ SAI_TxDisableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FWIE_MASK);
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ handle->state = (uint32_t)kSAI_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->saiQueue, 0, sizeof(sai_transfer_t) * SAI_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Aborts the current IRQ receive.
+ *
+ * note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SAI base pointer
+ * param handle Pointer to the sai_handle_t structure which stores the transfer state.
+ */
+void SAI_TransferAbortReceive(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Stop Tx transfer and disable interrupt */
+ SAI_RxEnable(base, false);
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ /* Use FIFO request interrupt and fifo error */
+ SAI_RxDisableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FRIE_MASK);
+#else
+ SAI_RxDisableInterrupts(base, I2S_TCSR_FEIE_MASK | I2S_TCSR_FWIE_MASK);
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ handle->state = (uint32_t)kSAI_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->saiQueue, 0, sizeof(sai_transfer_t) * SAI_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Terminate all SAI send.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortSend.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateSend(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ SAI_TransferAbortSend(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+}
+
+/*!
+ * brief Terminate all SAI receive.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortReceive.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateReceive(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ SAI_TransferAbortReceive(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure.
+ */
+void SAI_TransferTxHandleIRQ(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = handle->saiQueue[handle->queueDriver].data;
+ uint32_t dataSize = (handle->bitWidth / 8UL) * handle->channelNums;
+
+ /* Handle Error */
+ if (IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FEF_MASK))
+ {
+ /* Clear FIFO error flag to continue transfer */
+ SAI_TxClearStatusFlags(base, I2S_TCSR_FEF_MASK);
+
+ /* Reset FIFO for safety */
+ SAI_TxSoftwareReset(base, kSAI_ResetTypeFIFO);
+
+ /* Call the callback */
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_TxError, handle->userData);
+ }
+ }
+
+/* Handle transfer */
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if (IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FRF_MASK))
+ {
+ /* Judge if the data need to transmit is less than space */
+ size_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize),
+ (size_t)(((uint32_t)FSL_FEATURE_SAI_FIFO_COUNT - handle->watermark) * dataSize));
+
+ /* Copy the data from sai buffer to FIFO */
+ SAI_WriteNonBlocking(base, handle->channel, handle->channelMask, handle->endChannel, handle->bitWidth, buffer,
+ size);
+
+ /* Update the internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data = (uint8_t *)((uint32_t)buffer + size);
+ }
+#else
+ if (IS_SAI_FLAG_SET(base->TCSR, I2S_TCSR_FWF_MASK))
+ {
+ size_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), dataSize);
+
+ SAI_WriteNonBlocking(base, handle->channel, handle->channelMask, handle->endChannel, handle->bitWidth, buffer,
+ size);
+
+ /* Update internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data = (uint8_t *)((uint32_t)buffer + size);
+ }
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ /* If finished a block, call the callback function */
+ if (handle->saiQueue[handle->queueDriver].dataSize == 0U)
+ {
+ (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % SAI_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_TxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->saiQueue[handle->queueDriver].data == NULL)
+ {
+ SAI_TransferAbortSend(base, handle);
+ }
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SAI base pointer.
+ * param handle Pointer to the sai_handle_t structure.
+ */
+void SAI_TransferRxHandleIRQ(I2S_Type *base, sai_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = handle->saiQueue[handle->queueDriver].data;
+ uint32_t dataSize = (handle->bitWidth / 8UL) * handle->channelNums;
+
+ /* Handle Error */
+ if (IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FEF_MASK))
+ {
+ /* Clear FIFO error flag to continue transfer */
+ SAI_RxClearStatusFlags(base, I2S_TCSR_FEF_MASK);
+
+ /* Reset FIFO for safety */
+ SAI_RxSoftwareReset(base, kSAI_ResetTypeFIFO);
+
+ /* Call the callback */
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_RxError, handle->userData);
+ }
+ }
+
+/* Handle transfer */
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if (IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FRF_MASK))
+ {
+ /* Judge if the data need to transmit is less than space */
+ size_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), handle->watermark * dataSize);
+
+ /* Copy the data from sai buffer to FIFO */
+ SAI_ReadNonBlocking(base, handle->channel, handle->channelMask, handle->endChannel, handle->bitWidth, buffer,
+ size);
+
+ /* Update the internal counter */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data = (uint8_t *)((uint32_t)buffer + size);
+ }
+#else
+ if (IS_SAI_FLAG_SET(base->RCSR, I2S_RCSR_FWF_MASK))
+ {
+ size_t size = MIN((handle->saiQueue[handle->queueDriver].dataSize), dataSize);
+
+ SAI_ReadNonBlocking(base, handle->channel, handle->channelMask, handle->endChannel, handle->bitWidth, buffer,
+ size);
+
+ /* Update internal state */
+ handle->saiQueue[handle->queueDriver].dataSize -= size;
+ handle->saiQueue[handle->queueDriver].data = (uint8_t *)((uint32_t)buffer + size);
+ }
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+
+ /* If finished a block, call the callback function */
+ if (handle->saiQueue[handle->queueDriver].dataSize == 0U)
+ {
+ (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % SAI_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SAI_RxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->saiQueue[handle->queueDriver].data == NULL)
+ {
+ SAI_TransferAbortReceive(base, handle);
+ }
+}
+
+#if defined(I2S0)
+void I2S0_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[0][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S0, s_saiHandle[0][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[0][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S0, s_saiHandle[0][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S0_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[0][0] != NULL);
+ s_saiTxIsr(I2S0, s_saiHandle[0][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S0_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[0][1] != NULL);
+ s_saiRxIsr(I2S0, s_saiHandle[0][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* I2S0*/
+
+#if defined(I2S1)
+void I2S1_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S1, s_saiHandle[1][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S1, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S1_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[1][0] != NULL);
+ s_saiTxIsr(I2S1, s_saiHandle[1][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S1_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[1][1] != NULL);
+ s_saiRxIsr(I2S1, s_saiHandle[1][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* I2S1*/
+
+#if defined(I2S2)
+void I2S2_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[2][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S2, s_saiHandle[2][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[2][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S2, s_saiHandle[2][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S2_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[2][0] != NULL);
+ s_saiTxIsr(I2S2, s_saiHandle[2][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S2_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[2][1] != NULL);
+ s_saiRxIsr(I2S2, s_saiHandle[2][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* I2S2*/
+
+#if defined(I2S3)
+void I2S3_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[3][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S3, s_saiHandle[3][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[3][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S3, s_saiHandle[3][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S3_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[3][0] != NULL);
+ s_saiTxIsr(I2S3, s_saiHandle[3][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S3_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[3][1] != NULL);
+ s_saiRxIsr(I2S3, s_saiHandle[3][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* I2S3*/
+
+#if defined(I2S4)
+void I2S4_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[4][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[4][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S4, s_saiHandle[4][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[4][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[4][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S4, s_saiHandle[4][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S4_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[4][0] != NULL);
+ s_saiTxIsr(I2S4, s_saiHandle[4][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S4_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[4][1] != NULL);
+ s_saiRxIsr(I2S4, s_saiHandle[4][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(FSL_FEATURE_SAI_SAI5_SAI6_SHARE_IRQ) && (FSL_FEATURE_SAI_SAI5_SAI6_SHARE_IRQ) && defined(I2S5) && \
+ defined(I2S6)
+void I2S56_DriverIRQHandler(void)
+{
+ /* use index 5 to get handle when I2S5 & I2S6 share IRQ NUMBER */
+ I2S_Type *base = s_saiHandle[5][1]->base;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(base, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(base, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(base, s_saiHandle[5][1]);
+ }
+
+ base = s_saiHandle[5][0]->base;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(base, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(base, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(base, s_saiHandle[5][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S56_Tx_DriverIRQHandler(void)
+{
+ /* use index 5 to get handle when I2S5 & I2S6 share IRQ NUMBER */
+ assert(s_saiHandle[5][0] != NULL);
+ s_saiTxIsr(s_saiHandle[5][0]->base, s_saiHandle[5][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S56_Rx_DriverIRQHandler(void)
+{
+ /* use index 5 to get handle when I2S5 & I2S6 share IRQ NUMBER */
+ assert(s_saiHandle[5][1] != NULL);
+ s_saiRxIsr(s_saiHandle[5][1]->base, s_saiHandle[5][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#else
+
+#if defined(I2S5)
+void I2S5_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S5, s_saiHandle[5][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S5, s_saiHandle[5][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S5_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[5][0] != NULL);
+ s_saiTxIsr(I2S5, s_saiHandle[5][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S5_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[5][1] != NULL);
+ s_saiRxIsr(I2S5, s_saiHandle[5][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(I2S6)
+void I2S6_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[6][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][1] != NULL) && SAI_RxGetEnabledInterruptStatus(I2S6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(I2S6, s_saiHandle[6][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[6][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][0] != NULL) && SAI_TxGetEnabledInterruptStatus(I2S6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(I2S6, s_saiHandle[6][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S6_Tx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[6][0] != NULL);
+ s_saiTxIsr(I2S6, s_saiHandle[6][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void I2S6_Rx_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[6][1] != NULL);
+ s_saiRxIsr(I2S6, s_saiHandle[6][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+
+#if defined(AUDIO__SAI0)
+void AUDIO_SAI0_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[0][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI0, s_saiHandle[0][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[0][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI0, s_saiHandle[0][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI0 */
+
+#if defined(AUDIO__SAI1)
+void AUDIO_SAI1_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI1, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI1, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI1 */
+
+#if defined(AUDIO__SAI2)
+void AUDIO_SAI2_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[2][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI2, s_saiHandle[2][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[2][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI2, s_saiHandle[2][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI2 */
+
+#if defined(AUDIO__SAI3)
+void AUDIO_SAI3_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[3][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI3, s_saiHandle[3][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[3][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI3, s_saiHandle[3][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#if defined(AUDIO__SAI6)
+void AUDIO_SAI6_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[6][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI6, s_saiHandle[6][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[6][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI6, s_saiHandle[6][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI6 */
+
+#if defined(AUDIO__SAI7)
+void AUDIO_SAI7_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[7][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI7, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[7][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(AUDIO__SAI7, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(AUDIO__SAI7, s_saiHandle[7][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[7][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI7, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[7][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(AUDIO__SAI7, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(AUDIO__SAI7, s_saiHandle[7][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* AUDIO__SAI7 */
+
+#if defined(ADMA__SAI0)
+void ADMA_SAI0_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI0, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI0, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI0 */
+
+#if defined(ADMA__SAI1)
+void ADMA_SAI1_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI1, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI1, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI1 */
+
+#if defined(ADMA__SAI2)
+void ADMA_SAI2_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI2, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI2, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI2 */
+
+#if defined(ADMA__SAI3)
+void ADMA_SAI3_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI3, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI3, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI3 */
+
+#if defined(ADMA__SAI4)
+void ADMA_SAI4_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI4, s_saiHandle[1][1]);
+ }
+
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI4, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI4 */
+
+#if defined(ADMA__SAI5)
+void ADMA_SAI5_INT_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) &&
+ SAI_RxGetEnabledInterruptStatus(ADMA__SAI5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(ADMA__SAI5, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) &&
+ SAI_TxGetEnabledInterruptStatus(ADMA__SAI5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(ADMA__SAI5, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* ADMA__SAI5 */
+
+#if defined(SAI0)
+void SAI0_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[0][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI0, s_saiHandle[0][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[0][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI0, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[0][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI0, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI0, s_saiHandle[0][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI0 */
+
+#if defined(SAI1)
+void SAI1_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI1, s_saiHandle[1][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[1][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI1, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[1][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI1, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI1, s_saiHandle[1][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI1 */
+
+#if defined(SAI2)
+void SAI2_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[2][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI2, s_saiHandle[2][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[2][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI2, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[2][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI2, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI2, s_saiHandle[2][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI2 */
+
+#if defined(SAI3)
+void SAI3_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[3][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI3, s_saiHandle[3][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[3][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI3, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[3][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI3, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI3, s_saiHandle[3][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void SAI3_TX_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[3][0] != NULL);
+ s_saiTxIsr(SAI3, s_saiHandle[3][0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+void SAI3_RX_DriverIRQHandler(void)
+{
+ assert(s_saiHandle[3][1] != NULL);
+ s_saiRxIsr(SAI3, s_saiHandle[3][1]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI3 */
+
+#if defined(SAI4)
+void SAI4_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[4][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[4][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI4, s_saiHandle[4][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[4][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI4, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[4][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI4, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI4, s_saiHandle[4][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI4 */
+
+#if defined(SAI5)
+void SAI5_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI5, s_saiHandle[5][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI5, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[5][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI5, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI5, s_saiHandle[5][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI5 */
+
+#if defined(SAI6)
+void SAI6_DriverIRQHandler(void)
+{
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[6][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][1] != NULL) && SAI_RxGetEnabledInterruptStatus(SAI6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiRxIsr(SAI6, s_saiHandle[6][1]);
+ }
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ if ((s_saiHandle[6][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI6, (I2S_TCSR_FRIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FRF_MASK | I2S_TCSR_FEF_MASK)))
+#else
+ if ((s_saiHandle[6][0] != NULL) && SAI_TxGetEnabledInterruptStatus(SAI6, (I2S_TCSR_FWIE_MASK | I2S_TCSR_FEIE_MASK),
+ (I2S_TCSR_FWF_MASK | I2S_TCSR_FEF_MASK)))
+#endif
+ {
+ s_saiTxIsr(SAI6, s_saiHandle[6][0]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif /* SAI6 */
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_sai_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_sai_edma.c
new file mode 100644
index 0000000000..edaff64ef0
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_sai_edma.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_sai_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.sai_edma"
+#endif
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32UL) & ~0x1FU)
+
+static I2S_Type *const s_saiBases[] = I2S_BASE_PTRS;
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct sai_edma_private_handle
+{
+ I2S_Type *base;
+ sai_edma_handle_t *handle;
+} sai_edma_private_handle_t;
+
+/*! @brief sai_edma_transfer_state, sai edma transfer state.*/
+enum
+{
+ kSAI_Busy = 0x0U, /*!< SAI is busy */
+ kSAI_Idle, /*!< Transfer is done. */
+};
+
+/*<! Private handle only used for internally. */
+static sai_edma_private_handle_t s_edmaPrivateHandle[ARRAY_SIZE(s_saiBases)][2];
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance number for SAI.
+ *
+ * @param base SAI base pointer.
+ */
+static uint32_t SAI_GetInstance(I2S_Type *base);
+
+/*!
+ * @brief SAI EDMA callback for send.
+ *
+ * @param handle pointer to sai_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief SAI EDMA callback for receive.
+ *
+ * @param handle pointer to sai_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SAI_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t SAI_GetInstance(I2S_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_saiBases); instance++)
+ {
+ if (s_saiBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_saiBases));
+
+ return instance;
+}
+
+static void SAI_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ sai_edma_private_handle_t *privHandle = (sai_edma_private_handle_t *)userData;
+ sai_edma_handle_t *saiHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
+ saiHandle->queueDriver = (saiHandle->queueDriver + 1U) % SAI_XFER_QUEUE_SIZE;
+ if (saiHandle->callback != NULL)
+ {
+ (saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_TxIdle, saiHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
+ {
+ /* Disable DMA enable bit */
+ SAI_TxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
+ EDMA_AbortTransfer(handle);
+ }
+}
+
+static void SAI_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ sai_edma_private_handle_t *privHandle = (sai_edma_private_handle_t *)userData;
+ sai_edma_handle_t *saiHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&saiHandle->saiQueue[saiHandle->queueDriver], 0, sizeof(sai_transfer_t));
+ saiHandle->queueDriver = (saiHandle->queueDriver + 1U) % SAI_XFER_QUEUE_SIZE;
+ if (saiHandle->callback != NULL)
+ {
+ (saiHandle->callback)(privHandle->base, saiHandle, kStatus_SAI_RxIdle, saiHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (saiHandle->saiQueue[saiHandle->queueDriver].data == NULL)
+ {
+ /* Disable DMA enable bit */
+ SAI_RxEnableDMA(privHandle->base, kSAI_FIFORequestDMAEnable, false);
+ EDMA_AbortTransfer(handle);
+ }
+}
+
+/*!
+ * brief Initializes the SAI eDMA handle.
+ *
+ * This function initializes the SAI master DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param base SAI peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void SAI_TransferTxCreateHandleEDMA(
+ I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *txDmaHandle)
+{
+ assert((handle != NULL) && (txDmaHandle != NULL));
+
+ uint32_t instance = SAI_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set sai base to handle */
+ handle->dmaHandle = txDmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set SAI state to idle */
+ handle->state = (uint32_t)kSAI_Idle;
+
+ s_edmaPrivateHandle[instance][0].base = base;
+ s_edmaPrivateHandle[instance][0].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(txDmaHandle, (edma_tcd_t *)(STCD_ADDR(handle->tcd)), SAI_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(txDmaHandle, SAI_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
+}
+
+/*!
+ * brief Initializes the SAI Rx eDMA handle.
+ *
+ * This function initializes the SAI slave DMA handle, which can be used for other SAI master transactional APIs.
+ * Usually, for a specified SAI instance, call this API once to get the initialized handle.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param base SAI peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void SAI_TransferRxCreateHandleEDMA(
+ I2S_Type *base, sai_edma_handle_t *handle, sai_edma_callback_t callback, void *userData, edma_handle_t *rxDmaHandle)
+{
+ assert((handle != NULL) && (rxDmaHandle != NULL));
+
+ uint32_t instance = SAI_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set sai base to handle */
+ handle->dmaHandle = rxDmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set SAI state to idle */
+ handle->state = (uint32_t)kSAI_Idle;
+
+ s_edmaPrivateHandle[instance][1].base = base;
+ s_edmaPrivateHandle[instance][1].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(rxDmaHandle, STCD_ADDR(handle->tcd), SAI_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(rxDmaHandle, SAI_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
+}
+
+/*!
+ * brief Configures the SAI Tx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to formatting requirements.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param format Pointer to SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If bit clock source is master
+ * clock, this value should equals to masterClockHz in format.
+ * retval kStatus_Success Audio format set successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ */
+void SAI_TransferTxSetFormatEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert((handle != NULL) && (format != NULL));
+
+ /* Configure the audio format to SAI registers */
+ SAI_TxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ if (format->bitWidth == 24U)
+ {
+ handle->bytesPerFrame = 4U;
+ }
+ else
+ {
+ handle->bytesPerFrame = (uint8_t)(format->bitWidth / 8U);
+ }
+
+ /* Update the data channel SAI used */
+ handle->channel = format->channel;
+
+ /* Clear the channel enable bits until do a send/receive */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->count = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNT - format->watermark);
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+/*!
+ * @brief Configures the SAI Tx.
+ *
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param saiConfig sai configurations.
+ */
+void SAI_TransferTxSetConfigEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transceiver_t *saiConfig)
+{
+ assert((handle != NULL) && (saiConfig != NULL));
+
+ /* Configure the audio format to SAI registers */
+ SAI_TxSetConfig(base, saiConfig);
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ if (saiConfig->serialData.dataWordLength == 24U)
+ {
+ handle->bytesPerFrame = 4U;
+ }
+ else
+ {
+ handle->bytesPerFrame = saiConfig->serialData.dataWordLength / 8U;
+ }
+ /* Update the data channel SAI used */
+ handle->channel = saiConfig->startChannel;
+
+ /* Clear the channel enable bits until do a send/receive */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->count = (uint8_t)((uint32_t)FSL_FEATURE_SAI_FIFO_COUNT - saiConfig->fifo.fifoWatermark);
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+/*!
+ * brief Configures the SAI Rx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred. This function also sets the eDMA parameter according to formatting requirements.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param format Pointer to SAI audio data format structure.
+ * param mclkSourceClockHz SAI master clock source frequency in Hz.
+ * param bclkSourceClockHz SAI bit clock source frequency in Hz. If a bit clock source is the master
+ * clock, this value should equal to masterClockHz in format.
+ * retval kStatus_Success Audio format set successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ */
+void SAI_TransferRxSetFormatEDMA(I2S_Type *base,
+ sai_edma_handle_t *handle,
+ sai_transfer_format_t *format,
+ uint32_t mclkSourceClockHz,
+ uint32_t bclkSourceClockHz)
+{
+ assert((handle != NULL) && (format != NULL));
+
+ /* Configure the audio format to SAI registers */
+ SAI_RxSetFormat(base, format, mclkSourceClockHz, bclkSourceClockHz);
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ if (format->bitWidth == 24U)
+ {
+ handle->bytesPerFrame = 4U;
+ }
+ else
+ {
+ handle->bytesPerFrame = (uint8_t)(format->bitWidth / 8U);
+ }
+
+ /* Update the data channel SAI used */
+ handle->channel = format->channel;
+
+ /* Clear the channel enable bits until do a send/receive */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->count = format->watermark;
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+/*!
+ * @brief Configures the SAI Rx.
+ *
+ *
+ * @param base SAI base pointer.
+ * @param handle SAI eDMA handle pointer.
+ * @param saiConfig sai configurations.
+ */
+void SAI_TransferRxSetConfigEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transceiver_t *saiConfig)
+{
+ assert((handle != NULL) && (saiConfig != NULL));
+
+ /* Configure the audio format to SAI registers */
+ SAI_RxSetConfig(base, saiConfig);
+
+ /* Get the transfer size from format, this should be used in EDMA configuration */
+ if (saiConfig->serialData.dataWordLength == 24U)
+ {
+ handle->bytesPerFrame = 4U;
+ }
+ else
+ {
+ handle->bytesPerFrame = saiConfig->serialData.dataWordLength / 8U;
+ }
+
+ /* Update the data channel SAI used */
+ handle->channel = saiConfig->startChannel;
+
+ /* Clear the channel enable bits until do a send/receive */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+#if defined(FSL_FEATURE_SAI_FIFO_COUNT) && (FSL_FEATURE_SAI_FIFO_COUNT > 1)
+ handle->count = saiConfig->fifo.fifoWatermark;
+#else
+ handle->count = 1U;
+#endif /* FSL_FEATURE_SAI_FIFO_COUNT */
+}
+
+/*!
+ * brief Performs a non-blocking SAI transfer using DMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * SAI_GetTransferStatus to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param xfer Pointer to the DMA transfer structure.
+ * retval kStatus_Success Start a SAI eDMA send successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_TxBusy SAI is busy sending data.
+ */
+status_t SAI_TransferSendEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t destAddr = SAI_TxGetDataRegisterAddress(base, handle->channel);
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->saiQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kSAI_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % SAI_XFER_QUEUE_SIZE;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, xfer->data, handle->bytesPerFrame, (uint32_t *)destAddr, handle->bytesPerFrame,
+ (uint32_t)handle->count * handle->bytesPerFrame, xfer->dataSize, kEDMA_MemoryToPeripheral);
+
+ /* Store the initially configured eDMA minor byte transfer count into the SAI handle */
+ handle->nbytes = handle->count * handle->bytesPerFrame;
+
+ if (EDMA_SubmitTransfer(handle->dmaHandle, &config) != kStatus_Success)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
+
+ /* Enable SAI Tx clock */
+ SAI_TxEnable(base, true);
+
+ /* Enable the channel FIFO */
+ base->TCR3 |= I2S_TCR3_TCE(1UL << handle->channel);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking SAI receive using eDMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * the SAI_GetReceiveRemainingBytes to poll the transfer status and check whether the SAI transfer is finished.
+ *
+ * param base SAI base pointer
+ * param handle SAI eDMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a SAI eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_RxBusy SAI is busy receiving data.
+ */
+status_t SAI_TransferReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle, sai_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t srcAddr = SAI_RxGetDataRegisterAddress(base, handle->channel);
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if (handle->saiQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = (uint32_t)kSAI_Busy;
+
+ /* Update queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->saiQueue[handle->queueUser].data = xfer->data;
+ handle->saiQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % SAI_XFER_QUEUE_SIZE;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, (uint32_t *)srcAddr, handle->bytesPerFrame, xfer->data, handle->bytesPerFrame,
+ (uint32_t)handle->count * handle->bytesPerFrame, xfer->dataSize, kEDMA_PeripheralToMemory);
+
+ /* Store the initially configured eDMA minor byte transfer count into the SAI handle */
+ handle->nbytes = handle->count * handle->bytesPerFrame;
+
+ if (EDMA_SubmitTransfer(handle->dmaHandle, &config) != kStatus_Success)
+ {
+ return kStatus_SAI_QueueFull;
+ }
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, true);
+
+ /* Enable the channel FIFO */
+ base->RCR3 |= I2S_RCR3_RCE(1UL << handle->channel);
+
+ /* Enable SAI Rx clock */
+ SAI_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a SAI transfer using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call SAI_TransferTerminateSendEDMA.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferAbortSendEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable the channel FIFO */
+ base->TCR3 &= ~I2S_TCR3_TCE_MASK;
+
+ /* Disable DMA enable bit */
+ SAI_TxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
+
+ /* Disable Tx */
+ SAI_TxEnable(base, false);
+
+ /* If Tx is disabled, reset the FIFO pointer and clear error flags */
+ if ((base->TCSR & I2S_TCSR_TE_MASK) == 0UL)
+ {
+ base->TCSR |= (I2S_TCSR_FR_MASK | I2S_TCSR_SR_MASK);
+ base->TCSR &= ~I2S_TCSR_SR_MASK;
+ }
+
+ /* Handle the queue index */
+ (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % SAI_XFER_QUEUE_SIZE;
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kSAI_Idle;
+}
+
+/*!
+ * brief Aborts a SAI receive using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call SAI_TransferTerminateReceiveEDMA.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferAbortReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable the channel FIFO */
+ base->RCR3 &= ~I2S_RCR3_RCE_MASK;
+
+ /* Disable DMA enable bit */
+ SAI_RxEnableDMA(base, kSAI_FIFORequestDMAEnable, false);
+
+ /* Disable Rx */
+ SAI_RxEnable(base, false);
+
+ /* If Rx is disabled, reset the FIFO pointer and clear error flags */
+ if ((base->RCSR & I2S_RCSR_RE_MASK) == 0UL)
+ {
+ base->RCSR |= (I2S_RCSR_FR_MASK | I2S_RCSR_SR_MASK);
+ base->RCSR &= ~I2S_RCSR_SR_MASK;
+ }
+
+ /* Handle the queue index */
+ (void)memset(&handle->saiQueue[handle->queueDriver], 0, sizeof(sai_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 1U) % SAI_XFER_QUEUE_SIZE;
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kSAI_Idle;
+}
+
+/*!
+ * brief Terminate all SAI send.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortSendEDMA.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateSendEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ SAI_TransferAbortSendEDMA(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->tcd, 0, sizeof(handle->tcd));
+ (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+}
+
+/*!
+ * brief Terminate all SAI receive.
+ *
+ * This function will clear all transfer slots buffered in the sai queue. If users only want to abort the
+ * current transfer slot, please call SAI_TransferAbortReceiveEDMA.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ */
+void SAI_TransferTerminateReceiveEDMA(I2S_Type *base, sai_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ SAI_TransferAbortReceiveEDMA(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->tcd, 0, sizeof(handle->tcd));
+ (void)memset(handle->saiQueue, 0, sizeof(handle->saiQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+}
+
+/*!
+ * brief Gets byte count sent by SAI.
+ *
+ * param base SAI base pointer.
+ * param handle SAI eDMA handle pointer.
+ * param count Bytes count sent by SAI.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SAI_TransferGetSendCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets byte count received by SAI.
+ *
+ * param base SAI base pointer
+ * param handle SAI eDMA handle pointer.
+ * param count Bytes count received by SAI.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SAI_TransferGetReceiveCountEDMA(I2S_Type *base, sai_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSAI_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaHandle->base, handle->dmaHandle->channel));
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_semc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_semc.c
new file mode 100644
index 0000000000..49b22fba43
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_semc.c
@@ -0,0 +1,1148 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_semc.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.semc"
+#endif
+
+/*! @brief Define macros for SEMC driver. */
+#define SEMC_IPCOMMANDDATASIZEBYTEMAX (4U)
+#define SEMC_IPCOMMANDMAGICKEY (0xA55A)
+#define SEMC_IOCR_PINMUXBITWIDTH (0x3U)
+#define SEMC_IOCR_NAND_CE (4U)
+#define SEMC_IOCR_NOR_CE (5U)
+#define SEMC_IOCR_NOR_CE_A8 (2U)
+#define SEMC_IOCR_PSRAM_CE (6U)
+#define SEMC_IOCR_PSRAM_CE_A8 (3U)
+#define SEMC_IOCR_DBI_CSX (7U)
+#define SEMC_IOCR_DBI_CSX_A8 (4U)
+#define SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE (24U)
+#define SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX (28U)
+#define SEMC_BMCR0_TYPICAL_WQOS (5U)
+#define SEMC_BMCR0_TYPICAL_WAGE (8U)
+#define SEMC_BMCR0_TYPICAL_WSH (0x40U)
+#define SEMC_BMCR0_TYPICAL_WRWS (0x10U)
+#define SEMC_BMCR1_TYPICAL_WQOS (5U)
+#define SEMC_BMCR1_TYPICAL_WAGE (8U)
+#define SEMC_BMCR1_TYPICAL_WPH (0x60U)
+#define SEMC_BMCR1_TYPICAL_WBR (0x40U)
+#define SEMC_BMCR1_TYPICAL_WRWS (0x24U)
+#define SEMC_STARTADDRESS (0x80000000U)
+#define SEMC_ENDADDRESS (0xDFFFFFFFU)
+#define SEMC_BR_MEMSIZE_MIN (4U)
+#define SEMC_BR_MEMSIZE_OFFSET (2U)
+#define SEMC_BR_MEMSIZE_MAX (4U * 1024U * 1024U)
+#define SEMC_SDRAM_MODESETCAL_OFFSET (4U)
+#define SEMC_BR_REG_NUM (9U)
+#define SEMC_BYTE_NUMBIT (8U)
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for SEMC module.
+ *
+ * @param base SEMC peripheral base address
+ */
+static uint32_t SEMC_GetInstance(SEMC_Type *base);
+
+/*!
+ * @brief Covert the input memory size to internal register set value.
+ *
+ * @param base SEMC peripheral base address
+ * @param size_kbytes SEMC memory size in unit of kbytes.
+ * @param sizeConverted SEMC converted memory size to 0 ~ 0x1F.
+ * @return Execution status.
+ */
+static status_t SEMC_CovertMemorySize(SEMC_Type *base, uint32_t size_kbytes, uint8_t *sizeConverted);
+
+/*!
+ * @brief Covert the external timing nanosecond to internal clock cycle.
+ *
+ * @param time_ns SEMC external time interval in unit of nanosecond.
+ * @param clkSrc_Hz SEMC clock source frequency.
+ * @return The changed internal clock cycle.
+ */
+static uint8_t SEMC_ConvertTiming(uint32_t time_ns, uint32_t clkSrc_Hz);
+
+/*!
+ * @brief Configure IP command.
+ *
+ * @param base SEMC peripheral base address.
+ * @param size_bytes SEMC IP command data size.
+ * @return Execution status.
+ */
+static status_t SEMC_ConfigureIPCommand(SEMC_Type *base, uint8_t size_bytes);
+
+/*!
+ * @brief Check if the IP command has finished.
+ *
+ * @param base SEMC peripheral base address.
+ * @return Execution status.
+ */
+static status_t SEMC_IsIPCommandDone(SEMC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to SEMC clocks for each instance. */
+static const clock_ip_name_t s_semcClock[FSL_FEATURE_SOC_SEMC_COUNT] = SEMC_CLOCKS;
+static const clock_ip_name_t s_semcExtClock[FSL_FEATURE_SOC_SEMC_COUNT] = SEMC_EXSC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointers to SEMC bases for each instance. */
+static SEMC_Type *const s_semcBases[] = SEMC_BASE_PTRS;
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t SEMC_GetInstance(SEMC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_semcBases); instance++)
+ {
+ if (s_semcBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_semcBases));
+
+ return instance;
+}
+
+static status_t SEMC_CovertMemorySize(SEMC_Type *base, uint32_t size_kbytes, uint8_t *sizeConverted)
+{
+ assert(sizeConverted != NULL);
+ uint32_t memsize;
+ status_t status = kStatus_Success;
+
+ if ((size_kbytes < SEMC_BR_MEMSIZE_MIN) || (size_kbytes > SEMC_BR_MEMSIZE_MAX))
+ {
+ status = kStatus_SEMC_InvalidMemorySize;
+ }
+ else
+ {
+ *sizeConverted = 0U;
+ memsize = size_kbytes / 8U;
+ while (memsize != 0x00U)
+ {
+ memsize >>= 1U;
+ (*sizeConverted)++;
+ }
+ }
+
+ return status;
+}
+
+static uint8_t SEMC_ConvertTiming(uint32_t time_ns, uint32_t clkSrc_Hz)
+{
+ assert(clkSrc_Hz > 0x00UL);
+
+ uint8_t clockCycles = 0;
+ uint32_t tClk_us;
+
+ clkSrc_Hz /= 1000000UL;
+ tClk_us = 1000000UL / clkSrc_Hz;
+
+ while ((tClk_us * clockCycles) < (time_ns * 1000UL))
+ {
+ clockCycles++;
+ }
+
+ return (clockCycles - 1U);
+}
+
+static status_t SEMC_ConfigureIPCommand(SEMC_Type *base, uint8_t size_bytes)
+{
+ status_t status = kStatus_Success;
+
+ if ((size_bytes > SEMC_IPCOMMANDDATASIZEBYTEMAX) || (size_bytes == 0x00U))
+ {
+ status = kStatus_SEMC_InvalidIpcmdDataSize;
+ }
+ else
+ {
+ /* Set data size. */
+ /* Note: It is better to set data size as the device data port width when transferring
+ * device command data. But for device memory data transfer, it can be set freely.
+ * Note: If the data size is greater than data port width, for example, datsz = 4, data port = 16bit,
+ * then the 4-byte data transfer will be split into two 2-byte transfers, the slave address
+ * will be switched automatically according to connected device type*/
+ base->IPCR1 = SEMC_IPCR1_DATSZ(size_bytes);
+ /* Clear data size. */
+ base->IPCR2 = 0;
+ /* Set data size. */
+ if (size_bytes < 4U)
+ {
+ base->IPCR2 |= SEMC_IPCR2_BM3_MASK;
+ }
+ if (size_bytes < 3U)
+ {
+ base->IPCR2 |= SEMC_IPCR2_BM2_MASK;
+ }
+ if (size_bytes < 2U)
+ {
+ base->IPCR2 |= SEMC_IPCR2_BM1_MASK;
+ }
+ }
+
+ return status;
+}
+
+static status_t SEMC_IsIPCommandDone(SEMC_Type *base)
+{
+ status_t status = kStatus_Success;
+
+ /* Poll status bit till command is done*/
+ while ((base->INTR & (uint32_t)SEMC_INTR_IPCMDDONE_MASK) == 0x00U)
+ {
+ };
+
+ /* Clear status bit */
+ base->INTR |= SEMC_INTR_IPCMDDONE_MASK;
+
+ /* Check error status */
+ if ((base->INTR & (uint32_t)SEMC_INTR_IPCMDERR_MASK) != 0x00U)
+ {
+ base->INTR |= SEMC_INTR_IPCMDERR_MASK;
+ status = kStatus_SEMC_IpCommandExecutionError;
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets the SEMC default basic configuration structure.
+ *
+ * The purpose of this API is to get the default SEMC
+ * configure structure for SEMC_Init(). User may use the initialized
+ * structure unchanged in SEMC_Init(), or modify some fields of the
+ * structure before calling SEMC_Init().
+ * Example:
+ code
+ semc_config_t config;
+ SEMC_GetDefaultConfig(&config);
+ endcode
+ * param config The SEMC configuration structure pointer.
+ */
+void SEMC_GetDefaultConfig(semc_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ semc_queuea_weight_struct_t *queueaWeight = &(config->queueWeight.queueaWeight.queueaConfig);
+ semc_queueb_weight_struct_t *queuebWeight = &(config->queueWeight.queuebWeight.queuebConfig);
+
+ /* Get default settings. */
+ config->dqsMode = kSEMC_Loopbackinternal;
+ config->cmdTimeoutCycles = 0;
+ config->busTimeoutCycles = 0x1F;
+
+ queueaWeight->qos = SEMC_BMCR0_TYPICAL_WQOS;
+ queueaWeight->aging = SEMC_BMCR0_TYPICAL_WAGE;
+ queueaWeight->slaveHitSwith = SEMC_BMCR0_TYPICAL_WSH;
+ queueaWeight->slaveHitNoswitch = SEMC_BMCR0_TYPICAL_WRWS;
+ queuebWeight->qos = SEMC_BMCR1_TYPICAL_WQOS;
+ queuebWeight->aging = SEMC_BMCR1_TYPICAL_WAGE;
+ queuebWeight->slaveHitSwith = SEMC_BMCR1_TYPICAL_WRWS;
+ queuebWeight->weightPagehit = SEMC_BMCR1_TYPICAL_WPH;
+ queuebWeight->bankRotation = SEMC_BMCR1_TYPICAL_WBR;
+}
+
+/*!
+ * brief Initializes SEMC.
+ * This function ungates the SEMC clock and initializes SEMC.
+ * This function must be called before calling any other SEMC driver functions.
+ *
+ * param base SEMC peripheral base address.
+ * param configure The SEMC configuration structure pointer.
+ */
+void SEMC_Init(SEMC_Type *base, semc_config_t *configure)
+{
+ assert(configure != NULL);
+
+ uint8_t index = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Un-gate sdram controller clock. */
+ CLOCK_EnableClock(s_semcClock[SEMC_GetInstance(base)]);
+ CLOCK_EnableClock(s_semcExtClock[SEMC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Initialize all BR to zero due to the default base address set. */
+ for (index = 0; index < SEMC_BR_REG_NUM; index++)
+ {
+ base->BR[index] = 0;
+ }
+
+ /* Software reset for SEMC internal logical . */
+ base->MCR = SEMC_MCR_SWRST_MASK;
+ while ((base->MCR & (uint32_t)SEMC_MCR_SWRST_MASK) != 0x00U)
+ {
+ }
+
+ /* Configure, disable module first. */
+ base->MCR |= SEMC_MCR_MDIS_MASK | SEMC_MCR_BTO(configure->busTimeoutCycles) |
+ SEMC_MCR_CTO(configure->cmdTimeoutCycles) | SEMC_MCR_DQSMD(configure->dqsMode);
+
+ /* Configure Queue 0/1 for AXI bus. */
+ base->BMCR0 = (uint32_t)(configure->queueWeight.queueaWeight.queueaValue);
+ base->BMCR1 = (uint32_t)(configure->queueWeight.queuebWeight.queuebValue);
+
+ /* Enable SEMC. */
+ base->MCR &= ~SEMC_MCR_MDIS_MASK;
+}
+
+/*!
+ * brief Deinitializes the SEMC module and gates the clock.
+ * This function gates the SEMC clock. As a result, the SEMC
+ * module doesn't work after calling this function.
+ *
+ * param base SEMC peripheral base address.
+ */
+void SEMC_Deinit(SEMC_Type *base)
+{
+ /* Disable module. Check there is no pending command before disable module. */
+ while ((base->STS0 & (uint32_t)SEMC_STS0_IDLE_MASK) == 0x00U)
+ {
+ ;
+ }
+
+ base->MCR |= SEMC_MCR_MDIS_MASK | SEMC_MCR_SWRST_MASK;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable SDRAM clock. */
+ CLOCK_DisableClock(s_semcClock[SEMC_GetInstance(base)]);
+ CLOCK_DisableClock(s_semcExtClock[SEMC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Configures SDRAM controller in SEMC.
+ *
+ * param base SEMC peripheral base address.
+ * param cs The chip selection.
+ * param config The sdram configuration.
+ * param clkSrc_Hz The SEMC clock frequency.
+ */
+status_t SEMC_ConfigureSDRAM(SEMC_Type *base, semc_sdram_cs_t cs, semc_sdram_config_t *config, uint32_t clkSrc_Hz)
+{
+ assert(config != NULL);
+ assert(clkSrc_Hz > 0x00U);
+ assert(config->refreshBurstLen > 0x00U);
+
+ uint8_t memsize;
+ status_t result = kStatus_Success;
+ uint16_t prescale = (uint16_t)(config->tPrescalePeriod_Ns / 16U / (1000000000U / clkSrc_Hz));
+ uint32_t refresh;
+ uint32_t urgentRef;
+ uint32_t idle;
+ uint32_t mode;
+ uint32_t timing;
+
+ if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ if (config->csxPinMux == kSEMC_MUXA8)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+
+ if (prescale > 256U)
+ {
+ return kStatus_SEMC_InvalidTimerSetting;
+ }
+
+ refresh = config->refreshPeriod_nsPerRow / config->tPrescalePeriod_Ns;
+ urgentRef = config->refreshUrgThreshold / config->tPrescalePeriod_Ns;
+ idle = config->tIdleTimeout_Ns / config->tPrescalePeriod_Ns;
+
+ uint32_t iocReg = base->IOCR & (~((uint32_t)SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->csxPinMux));
+
+ /* Base control. */
+ result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ base->BR[cs] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK;
+ base->SDRAMCR0 = SEMC_SDRAMCR0_PS(config->portSize) | SEMC_SDRAMCR0_BL(config->burstLen) |
+ SEMC_SDRAMCR0_COL(config->columnAddrBitNum) | SEMC_SDRAMCR0_CL(config->casLatency);
+ /* IOMUX setting. */
+ if (cs != kSEMC_SDRAM_CS0)
+ {
+ base->IOCR = iocReg | ((uint32_t)cs << (uint32_t)config->csxPinMux);
+ }
+
+ base->IOCR &= ~SEMC_IOCR_MUX_A8_MASK;
+
+ timing = SEMC_SDRAMCR1_PRE2ACT(SEMC_ConvertTiming(config->tPrecharge2Act_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_ACT2RW(SEMC_ConvertTiming(config->tAct2ReadWrite_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_RFRC(SEMC_ConvertTiming(config->tRefreshRecovery_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_WRC(SEMC_ConvertTiming(config->tWriteRecovery_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_CKEOFF(SEMC_ConvertTiming(config->tCkeOff_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR1_ACT2PRE(SEMC_ConvertTiming(config->tAct2Prechage_Ns, clkSrc_Hz));
+ /* SDRAMCR1 timing setting. */
+ base->SDRAMCR1 = timing;
+
+ timing = SEMC_SDRAMCR2_SRRC(SEMC_ConvertTiming(config->tSelfRefRecovery_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR2_REF2REF(SEMC_ConvertTiming(config->tRefresh2Refresh_Ns, clkSrc_Hz));
+ timing |= SEMC_SDRAMCR2_ACT2ACT(SEMC_ConvertTiming(config->tAct2Act_Ns, clkSrc_Hz)) | SEMC_SDRAMCR2_ITO(idle);
+ /* SDRAMCR2 timing setting. */
+ base->SDRAMCR2 = timing;
+
+ /* SDRAMCR3 timing setting. */
+ base->SDRAMCR3 = SEMC_SDRAMCR3_REBL((uint32_t)config->refreshBurstLen - 1UL) |
+ /* N * 16 * 1s / clkSrc_Hz = config->tPrescalePeriod_Ns */
+ SEMC_SDRAMCR3_PRESCALE(prescale) | SEMC_SDRAMCR3_RT(refresh) | SEMC_SDRAMCR3_UT(urgentRef);
+
+ SEMC->IPCR1 = 0x2U;
+ SEMC->IPCR2 = 0U;
+
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_Prechargeall, 0, NULL);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_AutoRefresh, 0, NULL);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_AutoRefresh, 0, NULL);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ /* Mode setting value. */
+ mode = (uint32_t)config->burstLen | (((uint32_t)config->casLatency) << SEMC_SDRAM_MODESETCAL_OFFSET);
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, (uint32_t)kSEMC_SDRAMCM_Modeset, mode, NULL);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ /* Enables refresh */
+ base->SDRAMCR3 |= SEMC_SDRAMCR3_REN_MASK;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures NAND controller in SEMC.
+ *
+ * param base SEMC peripheral base address.
+ * param config The nand configuration.
+ * param clkSrc_Hz The SEMC clock frequency.
+ */
+status_t SEMC_ConfigureNAND(SEMC_Type *base, semc_nand_config_t *config, uint32_t clkSrc_Hz)
+{
+ assert(config != NULL);
+ assert(config->timingConfig != NULL);
+
+ uint8_t memsize;
+ status_t result;
+ uint32_t timing;
+
+ if ((config->axiAddress < SEMC_STARTADDRESS) || (config->axiAddress > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ if (config->cePinMux == kSEMC_MUXRDY)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+
+ uint32_t iocReg =
+ base->IOCR & (~(((uint32_t)SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->cePinMux) | SEMC_IOCR_MUX_RDY_MASK));
+
+ /* Base control. */
+ if (config->rdyactivePolarity == kSEMC_RdyActivehigh)
+ {
+ base->MCR |= SEMC_MCR_WPOL1_MASK;
+ }
+ else
+ {
+ base->MCR &= ~SEMC_MCR_WPOL1_MASK;
+ }
+ result = SEMC_CovertMemorySize(base, config->axiMemsize_kbytes, &memsize);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ base->BR[4] = (config->axiAddress & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK;
+
+ result = SEMC_CovertMemorySize(base, config->ipgMemsize_kbytes, &memsize);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ base->BR[8] = (config->ipgAddress & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK;
+
+ /* IOMUX setting. */
+ if ((uint32_t)config->cePinMux != 0x00U)
+ {
+ base->IOCR = iocReg | ((uint32_t)SEMC_IOCR_NAND_CE << (uint32_t)config->cePinMux);
+ }
+ else
+ {
+ base->IOCR = iocReg | ((uint32_t)1U << (uint32_t)config->cePinMux);
+ }
+
+ base->NANDCR0 = SEMC_NANDCR0_PS(config->portSize) | SEMC_NANDCR0_BL(config->burstLen) |
+ SEMC_NANDCR0_EDO(config->edoModeEnabled) | SEMC_NANDCR0_COL(config->columnAddrBitNum);
+
+ timing = SEMC_NANDCR1_CES(SEMC_ConvertTiming(config->timingConfig->tCeSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_CEH(SEMC_ConvertTiming(config->timingConfig->tCeHold_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_WEL(SEMC_ConvertTiming(config->timingConfig->tWeLow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_WEH(SEMC_ConvertTiming(config->timingConfig->tWeHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_REL(SEMC_ConvertTiming(config->timingConfig->tReLow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_REH(SEMC_ConvertTiming(config->timingConfig->tReHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_TA(SEMC_ConvertTiming(config->timingConfig->tTurnAround_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR1_CEITV(SEMC_ConvertTiming(config->timingConfig->tCeInterval_Ns, clkSrc_Hz));
+ /* NANDCR1 timing setting. */
+ base->NANDCR1 = timing;
+
+ timing = SEMC_NANDCR2_TWHR(SEMC_ConvertTiming(config->timingConfig->tWehigh2Relow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR2_TRHW(SEMC_ConvertTiming(config->timingConfig->tRehigh2Welow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR2_TADL(SEMC_ConvertTiming(config->timingConfig->tAle2WriteStart_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR2_TRR(SEMC_ConvertTiming(config->timingConfig->tReady2Relow_Ns, clkSrc_Hz));
+ timing |= SEMC_NANDCR2_TWB(SEMC_ConvertTiming(config->timingConfig->tWehigh2Busy_Ns, clkSrc_Hz));
+
+ /* NANDCR2 timing setting. */
+ base->NANDCR2 = timing;
+
+ /* NANDCR3 timing setting. */
+ base->NANDCR3 = (uint32_t)config->arrayAddrOption;
+ return kStatus_Success;
+}
+
+/*!
+ * brief Configures NOR controller in SEMC.
+ *
+ * param base SEMC peripheral base address.
+ * param config The nor configuration.
+ * param clkSrc_Hz The SEMC clock frequency.
+ */
+status_t SEMC_ConfigureNOR(SEMC_Type *base, semc_nor_config_t *config, uint32_t clkSrc_Hz)
+{
+ assert(config != NULL);
+
+ uint8_t memsize;
+ status_t result;
+ uint32_t timing;
+
+ if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ uint32_t iocReg = base->IOCR & (~((uint32_t)SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->cePinMux));
+ uint32_t muxCe = (config->cePinMux == kSEMC_MUXRDY) ?
+ (SEMC_IOCR_NOR_CE - 1U) :
+ ((config->cePinMux == kSEMC_MUXA8) ? SEMC_IOCR_NOR_CE_A8 : SEMC_IOCR_NOR_CE);
+
+ /* IOMUX setting. */
+ base->IOCR = iocReg | (muxCe << (uint32_t)config->cePinMux);
+ /* Address bit setting. */
+ if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE)
+ {
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 1U))
+ {
+ /* Address bit 24 (A24) */
+ base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX0_MASK;
+ if (config->cePinMux == kSEMC_MUXCSX0)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ }
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 2U))
+ {
+ /* Address bit 25 (A25) */
+ base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX1_MASK;
+ if (config->cePinMux == kSEMC_MUXCSX1)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ }
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 3U))
+ {
+ /* Address bit 26 (A26) */
+ base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX2_MASK;
+ if (config->cePinMux == kSEMC_MUXCSX2)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ }
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 4U))
+ {
+ if (config->addr27 == kSEMC_NORA27_MUXCSX3)
+ {
+ /* Address bit 27 (A27) */
+ base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX3_MASK;
+ }
+ else if (config->addr27 == kSEMC_NORA27_MUXRDY)
+ {
+ base->IOCR |= SEMC_IOCR_MUX_RDY_MASK;
+ }
+ else
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ if (config->cePinMux == kSEMC_MUXCSX3)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ }
+ if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX)
+ {
+ return kStatus_SEMC_InvalidAddressPortWidth;
+ }
+ }
+
+ /* Base control. */
+ if (config->rdyactivePolarity == kSEMC_RdyActivehigh)
+ {
+ base->MCR |= SEMC_MCR_WPOL0_MASK;
+ }
+ else
+ {
+ base->MCR &= ~SEMC_MCR_WPOL0_MASK;
+ }
+ result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ base->BR[5] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK;
+ base->NORCR0 = SEMC_NORCR0_PS(config->portSize) | SEMC_NORCR0_BL(config->burstLen) |
+ SEMC_NORCR0_AM(config->addrMode) | SEMC_NORCR0_ADVP(config->advActivePolarity) |
+ SEMC_NORCR0_COL(config->columnAddrBitNum);
+
+ timing = SEMC_NORCR1_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR1_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz));
+
+ /* NORCR1 timing setting. */
+ base->NORCR1 = timing;
+
+ timing = SEMC_NORCR2_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz));
+#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME)
+ timing |= SEMC_NORCR2_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz));
+#endif /* FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME */
+#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME)
+ timing |= SEMC_NORCR2_WDH(SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz));
+#endif /* FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME */
+ timing |= SEMC_NORCR2_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR2_AWDH(SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz));
+ timing |= SEMC_NORCR2_LC(config->latencyCount) | SEMC_NORCR2_RD(config->readCycle);
+
+ /* NORCR2 timing setting. */
+ base->NORCR2 = timing;
+
+ return SEMC_ConfigureIPCommand(base, ((uint8_t)config->portSize + 1U));
+}
+
+/*!
+ * brief Configures SRAM controller in SEMC.
+ *
+ * param base SEMC peripheral base address.
+ * param config The sram configuration.
+ * param clkSrc_Hz The SEMC clock frequency.
+ */
+status_t SEMC_ConfigureSRAM(SEMC_Type *base, semc_sram_config_t *config, uint32_t clkSrc_Hz)
+{
+ assert(config != NULL);
+
+ uint8_t memsize;
+ uint32_t timing;
+ status_t result = kStatus_Success;
+
+ if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ uint32_t iocReg = base->IOCR & (~((uint32_t)SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->cePinMux));
+ uint32_t muxCe = (config->cePinMux == kSEMC_MUXRDY) ?
+ (SEMC_IOCR_PSRAM_CE - 1U) :
+ ((config->cePinMux == kSEMC_MUXA8) ? SEMC_IOCR_PSRAM_CE_A8 : SEMC_IOCR_PSRAM_CE);
+
+ /* IOMUX setting. */
+ base->IOCR = iocReg | (muxCe << (uint32_t)config->cePinMux);
+ /* Address bit setting. */
+ if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE)
+ {
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 1U))
+ {
+ /* Address bit 24 (A24) */
+ base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX0_MASK;
+ if (config->cePinMux == kSEMC_MUXCSX0)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ }
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 2U))
+ {
+ /* Address bit 25 (A25) */
+ base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX1_MASK;
+ if (config->cePinMux == kSEMC_MUXCSX1)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ }
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 3U))
+ {
+ /* Address bit 26 (A26) */
+ base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX2_MASK;
+ if (config->cePinMux == kSEMC_MUXCSX2)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ }
+ if (config->addrPortWidth >= (SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 4U))
+ {
+ if (config->addr27 == kSEMC_NORA27_MUXCSX3)
+ {
+ /* Address bit 27 (A27) */
+ base->IOCR &= ~(uint32_t)SEMC_IOCR_MUX_CSX3_MASK;
+ }
+ else if (config->addr27 == kSEMC_NORA27_MUXRDY)
+ {
+ base->IOCR |= SEMC_IOCR_MUX_RDY_MASK;
+ }
+ else
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+
+ if (config->cePinMux == kSEMC_MUXCSX3)
+ {
+ return kStatus_SEMC_InvalidSwPinmuxSelection;
+ }
+ }
+ if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX)
+ {
+ return kStatus_SEMC_InvalidAddressPortWidth;
+ }
+ }
+ /* Base control. */
+ result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ base->BR[6] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK;
+
+ /* SRAMCR0 timing setting. */
+ base->SRAMCR0 = SEMC_SRAMCR0_PS(config->portSize) | SEMC_SRAMCR0_BL(config->burstLen) |
+ SEMC_SRAMCR0_AM(config->addrMode) | SEMC_SRAMCR0_ADVP(config->advActivePolarity) |
+ SEMC_SRAMCR0_COL_MASK;
+
+ timing = SEMC_SRAMCR1_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR1_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz));
+
+ /* SRAMCR1 timing setting. */
+ base->SRAMCR1 = timing;
+
+ timing = SEMC_SRAMCR2_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR2_WDH((uint32_t)SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz) + 1UL);
+ timing |= SEMC_SRAMCR2_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR2_AWDH(SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz));
+ timing |= SEMC_SRAMCR2_LC(config->latencyCount) | SEMC_SRAMCR2_RD((uint32_t)config->readCycle - 1UL);
+ timing |= SEMC_SRAMCR2_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz));
+
+ /* SRAMCR2 timing setting. */
+ base->SRAMCR2 = timing;
+
+ return result;
+}
+
+/*!
+ * brief Configures DBI controller in SEMC.
+ *
+ * param base SEMC peripheral base address.
+ * param config The dbi configuration.
+ * param clkSrc_Hz The SEMC clock frequency.
+ */
+status_t SEMC_ConfigureDBI(SEMC_Type *base, semc_dbi_config_t *config, uint32_t clkSrc_Hz)
+{
+ assert(config != NULL);
+
+ uint8_t memsize;
+ status_t result;
+ uint32_t timing;
+
+ if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS))
+ {
+ return kStatus_SEMC_InvalidBaseAddress;
+ }
+
+ uint32_t iocReg = base->IOCR & (~((uint32_t)SEMC_IOCR_PINMUXBITWIDTH << (uint32_t)config->csxPinMux));
+ uint32_t muxCsx = (config->csxPinMux == kSEMC_MUXRDY) ?
+ (SEMC_IOCR_DBI_CSX - 1U) :
+ ((config->csxPinMux == kSEMC_MUXA8) ? SEMC_IOCR_DBI_CSX_A8 : SEMC_IOCR_DBI_CSX);
+
+ /* IOMUX setting. */
+ base->IOCR = iocReg | (muxCsx << (uint32_t)config->csxPinMux);
+ /* Base control. */
+ result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+ base->BR[7] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK;
+
+ /* DBICR0 timing setting. */
+ base->DBICR0 =
+ SEMC_DBICR0_PS(config->portSize) | SEMC_DBICR0_BL(config->burstLen) | SEMC_DBICR0_COL(config->columnAddrBitNum);
+
+ timing = SEMC_DBICR1_CES(SEMC_ConvertTiming(config->tCsxSetup_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_CEH(SEMC_ConvertTiming(config->tCsxHold_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_WEL(SEMC_ConvertTiming(config->tWexLow_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_WEH(SEMC_ConvertTiming(config->tWexHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_REL(SEMC_ConvertTiming(config->tRdxLow_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_REH(SEMC_ConvertTiming(config->tRdxHigh_Ns, clkSrc_Hz));
+ timing |= SEMC_DBICR1_CEITV(SEMC_ConvertTiming(config->tCsxInterval_Ns, clkSrc_Hz));
+
+ /* DBICR1 timing setting. */
+ base->DBICR1 = timing;
+ return SEMC_ConfigureIPCommand(base, ((uint8_t)config->portSize + 1U));
+}
+
+/*!
+ * brief SEMC IP command access.
+ *
+ * param base SEMC peripheral base address.
+ * param type SEMC memory type. refer to "semc_mem_type_t"
+ * param address SEMC device address.
+ * param command SEMC IP command.
+ * For NAND device, we should use the SEMC_BuildNandIPCommand to get the right nand command.
+ * For NOR/DBI device, take refer to "semc_ipcmd_nor_dbi_t".
+ * For SRAM device, take refer to "semc_ipcmd_sram_t".
+ * For SDRAM device, take refer to "semc_ipcmd_sdram_t".
+ * param write Data for write access.
+ * param read Data pointer for read data out.
+ */
+status_t SEMC_SendIPCommand(
+ SEMC_Type *base, semc_mem_type_t type, uint32_t address, uint32_t command, uint32_t write, uint32_t *read)
+{
+ uint32_t cmdMode;
+ bool readCmd = false;
+ bool writeCmd = false;
+ status_t result;
+
+ /* Clear status bit */
+ base->INTR |= SEMC_INTR_IPCMDDONE_MASK;
+ /* Set address. */
+ base->IPCR0 = address;
+
+ /* Check command mode. */
+ cmdMode = (uint32_t)command & 0x0FU;
+ switch (type)
+ {
+ case kSEMC_MemType_NAND:
+ readCmd = (cmdMode == (uint32_t)kSEMC_NANDCM_CommandAddressRead) ||
+ (cmdMode == (uint32_t)kSEMC_NANDCM_CommandRead) || (cmdMode == (uint32_t)kSEMC_NANDCM_Read);
+ writeCmd = (cmdMode == (uint32_t)kSEMC_NANDCM_CommandAddressWrite) ||
+ (cmdMode == (uint32_t)kSEMC_NANDCM_CommandWrite) || (cmdMode == (uint32_t)kSEMC_NANDCM_Write);
+ break;
+ case kSEMC_MemType_NOR:
+ case kSEMC_MemType_8080:
+ readCmd = (cmdMode == (uint32_t)kSEMC_NORDBICM_Read);
+ writeCmd = (cmdMode == (uint32_t)kSEMC_NORDBICM_Write);
+ break;
+ case kSEMC_MemType_SRAM:
+ readCmd = (cmdMode == (uint32_t)kSEMC_SRAMCM_ArrayRead) || (cmdMode == (uint32_t)kSEMC_SRAMCM_RegRead);
+ writeCmd = (cmdMode == (uint32_t)kSEMC_SRAMCM_ArrayWrite) || (cmdMode == (uint32_t)kSEMC_SRAMCM_RegWrite);
+ break;
+ case kSEMC_MemType_SDRAM:
+ readCmd = (cmdMode == (uint32_t)kSEMC_SDRAMCM_Read);
+ writeCmd = (cmdMode == (uint32_t)kSEMC_SDRAMCM_Write) || (cmdMode == (uint32_t)kSEMC_SDRAMCM_Modeset);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+ if (writeCmd)
+ {
+ /* Set data. */
+ base->IPTXDAT = write;
+ }
+
+ /* Set command code. */
+ base->IPCMD = command | SEMC_IPCMD_KEY(SEMC_IPCOMMANDMAGICKEY);
+ /* Wait for command done. */
+ result = SEMC_IsIPCommandDone(base);
+ if (result != kStatus_Success)
+ {
+ return result;
+ }
+
+ if (readCmd)
+ {
+ /* Get the read data */
+ *read = base->IPRXDAT;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief SEMC NAND device memory write through IP command.
+ *
+ * param base SEMC peripheral base address.
+ * param address SEMC NAND device address.
+ * param data Data for write access.
+ * param size_bytes Data length.
+ */
+status_t SEMC_IPCommandNandWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes)
+{
+ assert(data != NULL);
+
+ status_t result = kStatus_Success;
+ uint16_t ipCmd;
+ uint32_t tempData = 0;
+
+ union
+ {
+ uint32_t *u32Data;
+ uint8_t *u8Data;
+ } tmpData;
+
+ tmpData.u8Data = data;
+
+ /* Write command built */
+ ipCmd = SEMC_BuildNandIPCommand(0, kSEMC_NANDAM_ColumnRow, kSEMC_NANDCM_Write);
+ while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX)
+ {
+ /* Configure IP command data size. */
+ (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX);
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, *tmpData.u32Data, NULL);
+ if (result != kStatus_Success)
+ {
+ break;
+ }
+
+ data += SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ }
+
+ if ((result == kStatus_Success) && (size_bytes != 0x00U))
+ {
+ (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes);
+
+ while (size_bytes != 0x00U)
+ {
+ tempData |= ((uint32_t)(data + size_bytes - 1U) << ((size_bytes - 1U) * SEMC_BYTE_NUMBIT));
+ size_bytes--;
+ }
+
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, tempData, NULL);
+ }
+
+ return result;
+}
+
+/*!
+ * brief SEMC NAND device memory read through IP command.
+ *
+ * param base SEMC peripheral base address.
+ * param address SEMC NAND device address.
+ * param data Data pointer for data read out.
+ * param size_bytes Data length.
+ */
+status_t SEMC_IPCommandNandRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes)
+{
+ assert(data != NULL);
+
+ status_t result = kStatus_Success;
+ uint16_t ipCmd;
+ uint32_t tempData = 0;
+
+ /* Configure IP command data size. */
+ (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX);
+ /* Read command built */
+ ipCmd = SEMC_BuildNandIPCommand(0, kSEMC_NANDAM_ColumnRow, kSEMC_NANDCM_Read);
+
+ union
+ {
+ uint32_t *u32Data;
+ uint8_t *u8Data;
+ } tmpData;
+
+ tmpData.u8Data = data;
+
+ while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX)
+ {
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, 0, tmpData.u32Data);
+ if (result != kStatus_Success)
+ {
+ break;
+ }
+
+ data += SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ }
+
+ if ((result == kStatus_Success) && (size_bytes != 0x00U))
+ {
+ (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes);
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, 0, &tempData);
+
+ while (size_bytes != 0x00U)
+ {
+ size_bytes--;
+ *(data + size_bytes) = (uint8_t)((tempData >> (SEMC_BYTE_NUMBIT * size_bytes)) & 0xFFU);
+ }
+ }
+
+ return result;
+}
+
+/*!
+ * brief SEMC NOR device memory read through IP command.
+ *
+ * param base SEMC peripheral base address.
+ * param address SEMC NOR device address.
+ * param data Data pointer for data read out.
+ * param size_bytes Data length.
+ */
+status_t SEMC_IPCommandNorRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes)
+{
+ assert(data != NULL);
+
+ uint32_t tempData = 0;
+ status_t result = kStatus_Success;
+ uint8_t dataSize = (uint8_t)base->NORCR0 & SEMC_NORCR0_PS_MASK;
+
+ /* Configure IP command data size. */
+ (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX);
+
+ union
+ {
+ uint32_t *u32Data;
+ uint8_t *u8Data;
+ } tmpData;
+
+ tmpData.u8Data = data;
+
+ while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX)
+ {
+ result =
+ SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Read, 0, tmpData.u32Data);
+ if (result != kStatus_Success)
+ {
+ break;
+ }
+
+ data += SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ }
+
+ if ((result == kStatus_Success) && (size_bytes != 0x00U))
+ {
+ (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes);
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Read, 0, &tempData);
+ while (size_bytes != 0x00U)
+ {
+ size_bytes--;
+ *(data + size_bytes) = (uint8_t)((tempData >> (SEMC_BYTE_NUMBIT * size_bytes)) & 0xFFU);
+ }
+ }
+
+ (void)SEMC_ConfigureIPCommand(base, dataSize);
+ return result;
+}
+
+/*!
+ * brief SEMC NOR device memory write through IP command.
+ *
+ * param base SEMC peripheral base address.
+ * param address SEMC NOR device address.
+ * param data Data for write access.
+ * param size_bytes Data length.
+ */
+status_t SEMC_IPCommandNorWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes)
+{
+ assert(data != NULL);
+
+ uint32_t tempData = 0;
+ status_t result = kStatus_Success;
+ uint8_t dataSize = (uint8_t)base->NORCR0 & SEMC_NORCR0_PS_MASK;
+
+ union
+ {
+ uint32_t *u32Data;
+ uint8_t *u8Data;
+ } tmpData;
+
+ tmpData.u8Data = data;
+
+ /* Write command built */
+ while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX)
+ {
+ /* Configure IP command data size. */
+ (void)SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX);
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Write, *tmpData.u32Data,
+ NULL);
+ if (result != kStatus_Success)
+ {
+ break;
+ }
+ size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ data += SEMC_IPCOMMANDDATASIZEBYTEMAX;
+ }
+
+ if ((result == kStatus_Success) && (size_bytes != 0x00U))
+ {
+ (void)SEMC_ConfigureIPCommand(base, (uint8_t)size_bytes);
+
+ while (size_bytes != 0x00U)
+ {
+ tempData |= ((uint32_t) * (data + size_bytes - 1U) << ((size_bytes - 1U) * SEMC_BYTE_NUMBIT));
+ size_bytes--;
+ }
+
+ result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, (uint16_t)kSEMC_NORDBICM_Write, tempData, NULL);
+ }
+ (void)SEMC_ConfigureIPCommand(base, dataSize);
+
+ return result;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_snvs_hp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_snvs_hp.c
new file mode 100644
index 0000000000..2a2e0c7e40
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_snvs_hp.c
@@ -0,0 +1,573 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2019, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_snvs_hp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.snvs_hp"
+#endif
+
+#define SECONDS_IN_A_DAY (86400U)
+#define SECONDS_IN_A_HOUR (3600U)
+#define SECONDS_IN_A_MINUTE (60U)
+#define DAYS_IN_A_YEAR (365U)
+#define YEAR_RANGE_START (1970U)
+#define YEAR_RANGE_END (2099U)
+
+#if !(defined(SNVS_HPSR_PI_MASK))
+#define SNVS_HPSR_PI_MASK (0x2U)
+#endif
+#if !(defined(SNVS_HPSR_HPTA_MASK))
+#define SNVS_HPSR_HPTA_MASK (0x1U)
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Checks whether the date and time passed in is valid
+ *
+ * @param datetime Pointer to structure where the date and time details are stored
+ *
+ * @return Returns false if the date & time details are out of range; true if in range
+ */
+static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from datetime to seconds
+ *
+ * @param datetime Pointer to datetime structure where the date and time details are stored
+ *
+ * @return The result of the conversion in seconds
+ */
+static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from seconds to a datetime structure
+ *
+ * @param seconds Seconds value that needs to be converted to datetime format
+ * @param datetime Pointer to the datetime structure where the result of the conversion is stored
+ */
+static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime);
+
+/*!
+ * @brief Returns RTC time in seconds.
+ *
+ * This function is used internally to get actual RTC time in seconds.
+ *
+ * @param base SNVS peripheral base address
+ *
+ * @return RTC time in seconds
+ */
+static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base);
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+/*!
+ * @brief Get the SNVS instance from peripheral base address.
+ *
+ * @param base SNVS peripheral base address.
+ *
+ * @return SNVS instance.
+ */
+static uint32_t SNVS_HP_GetInstance(SNVS_Type *base);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+/*! @brief Pointer to snvs_hp clock. */
+static const clock_ip_name_t s_snvsHpClock[] = SNVS_HP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static bool SNVS_HP_CheckDatetimeFormat(const snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Check year, month, hour, minute, seconds */
+ if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
+ (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
+ {
+ /* If not correct then error*/
+ return false;
+ }
+
+ /* Adjust the days in February for a leap year */
+ if ((((datetime->year & 3U) == 0U) && (datetime->year % 100U != 0U)) || (datetime->year % 400U == 0U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ /* Check the validity of the day */
+ if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t SNVS_HP_ConvertDatetimeToSeconds(const snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ /* Number of days from begin of the non Leap-year*/
+ /* Number of days from begin of the non Leap-year*/
+ uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
+ uint32_t seconds;
+
+ /* Compute number of days from 1970 till given year*/
+ seconds = (((uint32_t)datetime->year - 1970U) * DAYS_IN_A_YEAR);
+ /* Add leap year days */
+ seconds += (((uint32_t)datetime->year / 4U) - (1970U / 4U));
+ /* Add number of days till given month*/
+ seconds += monthDays[datetime->month];
+ /* Add days in given month. We subtract the current day as it is
+ * represented in the hours, minutes and seconds field*/
+ seconds += ((uint32_t)datetime->day - 1U);
+ /* For leap year if month less than or equal to Febraury, decrement day counter*/
+ if ((0U == (datetime->year & 3U)) && (datetime->month <= 2U))
+ {
+ seconds--;
+ }
+
+ seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
+ (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
+
+ return seconds;
+}
+
+static void SNVS_HP_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t x;
+ uint32_t secondsRemaining, days;
+ uint16_t daysInYear;
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Start with the seconds value that is passed in to be converted to date time format */
+ secondsRemaining = seconds;
+
+ /* Calcuate the number of days, we add 1 for the current day which is represented in the
+ * hours and seconds field
+ */
+ days = secondsRemaining / SECONDS_IN_A_DAY + 1U;
+
+ /* Update seconds left*/
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
+
+ /* Calculate the datetime hour, minute and second fields */
+ datetime->hour = (uint8_t)(secondsRemaining / SECONDS_IN_A_HOUR);
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
+ datetime->minute = (uint8_t)(secondsRemaining / 60U);
+ datetime->second = (uint8_t)(secondsRemaining % SECONDS_IN_A_MINUTE);
+
+ /* Calculate year */
+ daysInYear = DAYS_IN_A_YEAR;
+ datetime->year = YEAR_RANGE_START;
+ while (days > daysInYear)
+ {
+ /* Decrease day count by a year and increment year by 1 */
+ days -= daysInYear;
+ datetime->year++;
+
+ /* Adjust the number of days for a leap year */
+ if ((datetime->year & 3U) != 0U)
+ {
+ daysInYear = DAYS_IN_A_YEAR;
+ }
+ else
+ {
+ daysInYear = DAYS_IN_A_YEAR + 1U;
+ }
+ }
+
+ /* Adjust the days in February for a leap year */
+ if (0U == (datetime->year & 3U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ for (x = 1U; x <= 12U; x++)
+ {
+ if (days <= daysPerMonth[x])
+ {
+ datetime->month = (uint8_t)x;
+ break;
+ }
+ else
+ {
+ days -= daysPerMonth[x];
+ }
+ }
+
+ datetime->day = (uint8_t)days;
+}
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+static uint32_t SNVS_HP_GetInstance(SNVS_Type *base)
+{
+ return 0U;
+}
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*!
+ * brief Initialize the SNVS.
+ *
+ * note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_HP_Init(SNVS_Type *base)
+{
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+ uint32_t instance = SNVS_HP_GetInstance(base);
+ CLOCK_EnableClock(s_snvsHpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Deinitialize the SNVS.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_HP_Deinit(SNVS_Type *base)
+{
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+ uint32_t instance = SNVS_HP_GetInstance(base);
+ CLOCK_DisableClock(s_snvsHpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * param base SNVS peripheral base address
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_HP_RTC_Init(SNVS_Type *base, const snvs_hp_rtc_config_t *config)
+{
+ assert(config != NULL);
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+ uint32_t instance = SNVS_HP_GetInstance(base);
+ CLOCK_EnableClock(s_snvsHpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN_MASK;
+
+ base->HPCR = SNVS_HPCR_PI_FREQ(config->periodicInterruptFreq);
+
+ if (config->rtcCalEnable)
+ {
+ base->HPCR |= SNVS_HPCR_HPCALB_VAL_MASK & (config->rtcCalValue << SNVS_HPCR_HPCALB_VAL_SHIFT);
+ base->HPCR |= SNVS_HPCR_HPCALB_EN_MASK;
+ }
+}
+
+/*!
+ * brief Stops the RTC and SRTC timers.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_HP_RTC_Deinit(SNVS_Type *base)
+{
+ base->HPCR &= ~SNVS_HPCR_RTC_EN_MASK;
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_HP_CLOCKS))
+ uint32_t instance = SNVS_HP_GetInstance(base);
+ CLOCK_DisableClock(s_snvsHpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Fills in the SNVS config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->rtccalenable = false;
+ * config->rtccalvalue = 0U;
+ * config->PIFreq = 0U;
+ * endcode
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_HP_RTC_GetDefaultConfig(snvs_hp_rtc_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->rtcCalEnable = false;
+ config->rtcCalValue = 0U;
+ config->periodicInterruptFreq = 0U;
+}
+
+static uint32_t SNVS_HP_RTC_GetSeconds(SNVS_Type *base)
+{
+ uint32_t seconds = 0;
+ uint32_t tmp = 0;
+
+ /* Do consecutive reads until value is correct */
+ do
+ {
+ seconds = tmp;
+ tmp = (base->HPRTCMR << 17U);
+ tmp |= (base->HPRTCLR >> 15U);
+ } while (tmp != seconds);
+
+ return seconds;
+}
+
+/*!
+ * brief Sets the SNVS RTC date and time according to the given time structure.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the date and time details are stored.
+ *
+ * return kStatus_Success: Success in setting the time and starting the SNVS RTC
+ * kStatus_InvalidArgument: Error because the datetime format is incorrect
+ */
+status_t SNVS_HP_RTC_SetDatetime(SNVS_Type *base, const snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t seconds = 0U;
+ uint32_t tmp = base->HPCR;
+
+ /* disable RTC */
+ SNVS_HP_RTC_StopTimer(base);
+
+ /* Return error if the time provided is not valid */
+ if (!(SNVS_HP_CheckDatetimeFormat(datetime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Set time in seconds */
+ seconds = SNVS_HP_ConvertDatetimeToSeconds(datetime);
+
+ base->HPRTCMR = (uint32_t)(seconds >> 17U);
+ base->HPRTCLR = (uint32_t)(seconds << 15U);
+
+ /* reenable RTC in case that it was enabled before */
+ if ((tmp & SNVS_HPCR_RTC_EN_MASK) != 0U)
+ {
+ SNVS_HP_RTC_StartTimer(base);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the SNVS RTC time and stores it in the given time structure.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the date and time details are stored.
+ */
+void SNVS_HP_RTC_GetDatetime(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ SNVS_HP_ConvertSecondsToDatetime(SNVS_HP_RTC_GetSeconds(base), datetime);
+}
+
+/*!
+ * brief Sets the SNVS RTC alarm time.
+ *
+ * The function sets the RTC alarm. It also checks whether the specified alarm time
+ * is greater than the present time. If not, the function does not set the alarm
+ * and returns an error.
+ *
+ * param base SNVS peripheral base address
+ * param alarmTime Pointer to the structure where the alarm time is stored.
+ *
+ * return kStatus_Success: success in setting the SNVS RTC alarm
+ * kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
+ * kStatus_Fail: Error because the alarm time has already passed
+ */
+status_t SNVS_HP_RTC_SetAlarm(SNVS_Type *base, const snvs_hp_rtc_datetime_t *alarmTime)
+{
+ assert(alarmTime != NULL);
+
+ uint32_t alarmSeconds = 0U;
+ uint32_t currSeconds = 0U;
+ uint32_t tmp = base->HPCR;
+
+ /* Return error if the alarm time provided is not valid */
+ if (!(SNVS_HP_CheckDatetimeFormat(alarmTime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ alarmSeconds = SNVS_HP_ConvertDatetimeToSeconds(alarmTime);
+ currSeconds = SNVS_HP_RTC_GetSeconds(base);
+
+ /* Return error if the alarm time has passed */
+ if (alarmSeconds < currSeconds)
+ {
+ return kStatus_Fail;
+ }
+
+ /* disable RTC alarm interrupt */
+ base->HPCR &= ~SNVS_HPCR_HPTA_EN_MASK;
+ while ((base->HPCR & SNVS_HPCR_HPTA_EN_MASK) != 0U)
+ {
+ }
+
+ /* Set alarm in seconds*/
+ base->HPTAMR = (uint32_t)(alarmSeconds >> 17U);
+ base->HPTALR = (uint32_t)(alarmSeconds << 15U);
+
+ /* reenable RTC alarm interrupt in case that it was enabled before */
+ base->HPCR = tmp;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Returns the SNVS RTC alarm time.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the alarm date and time details are stored.
+ */
+void SNVS_HP_RTC_GetAlarm(SNVS_Type *base, snvs_hp_rtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t alarmSeconds = 0U;
+
+ /* Get alarm in seconds */
+ alarmSeconds = (base->HPTAMR << 17U);
+ alarmSeconds |= (base->HPTALR >> 15U);
+
+ SNVS_HP_ConvertSecondsToDatetime(alarmSeconds, datetime);
+}
+
+#if (defined(FSL_FEATURE_SNVS_HAS_SRTC) && (FSL_FEATURE_SNVS_HAS_SRTC > 0))
+/*!
+ * brief The function synchronizes RTC counter value with SRTC.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_HP_RTC_TimeSynchronize(SNVS_Type *base)
+{
+ uint32_t tmp = base->HPCR;
+
+ /* disable RTC */
+ SNVS_HP_RTC_StopTimer(base);
+
+ base->HPCR |= SNVS_HPCR_HP_TS_MASK;
+
+ /* reenable RTC in case that it was enabled before */
+ if ((tmp & SNVS_HPCR_RTC_EN_MASK) != 0U)
+ {
+ SNVS_HP_RTC_StartTimer(base);
+ }
+}
+#endif /* FSL_FEATURE_SNVS_HAS_SRTC */
+
+/*!
+ * brief Gets the SNVS status flags.
+ *
+ * param base SNVS peripheral base address
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::snvs_status_flags_t
+ */
+uint32_t SNVS_HP_RTC_GetStatusFlags(SNVS_Type *base)
+{
+ uint32_t flags = 0U;
+
+ if ((base->HPSR & SNVS_HPSR_PI_MASK) != 0U)
+ {
+ flags |= (uint32_t)kSNVS_RTC_PeriodicInterruptFlag;
+ }
+
+ if ((base->HPSR & SNVS_HPSR_HPTA_MASK) != 0U)
+ {
+ flags |= (uint32_t)kSNVS_RTC_AlarmInterruptFlag;
+ }
+
+ return flags;
+}
+
+/*!
+ * brief Gets the enabled SNVS interrupts.
+ *
+ * param base SNVS peripheral base address
+ *
+ * return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::snvs_interrupt_enable_t
+ */
+uint32_t SNVS_HP_RTC_GetEnabledInterrupts(SNVS_Type *base)
+{
+ uint32_t val = 0U;
+
+ if ((base->HPCR & SNVS_HPCR_PI_EN_MASK) != 0U)
+ {
+ val |= (uint32_t)kSNVS_RTC_PeriodicInterrupt;
+ }
+
+ if ((base->HPCR & SNVS_HPCR_HPTA_EN_MASK) != 0U)
+ {
+ val |= (uint32_t)kSNVS_RTC_AlarmInterrupt;
+ }
+
+ return val;
+}
+
+#if defined(FSL_FEATURE_SNVS_HAS_SET_LOCK) && (FSL_FEATURE_SNVS_HAS_SET_LOCK > 0)
+/*!
+ * brief Set SNVS HP Set locks.
+ *
+ * param base SNVS peripheral base address
+ *
+ */
+void SNVS_HP_SetLocks(SNVS_Type *base)
+{
+ uint32_t sec_config = ((OCOTP_CTRL->HW_OCOTP_OTFAD_CFG3 & OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_MASK) >>
+ OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_SHIFT);
+
+ if (sec_config == SEC_CONFIG_OPEN)
+ {
+ /* Enable non-secure SW access */
+ base->HPCOMR |= SNVS_HPCOMR_NPSWA_EN(1);
+ }
+
+ /* Set LP Software Reset Disable lock and ZMK Write Soft Lock */
+ base->HPCOMR |= SNVS_HPCOMR_LP_SWR_DIS(1);
+ base->HPLR |= SNVS_HPLR_ZMK_WSL(1);
+}
+#endif /* FSL_FEATURE_SNVS_HAS_SET_LOCK */
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_snvs_lp.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_snvs_lp.c
new file mode 100644
index 0000000000..bf5a7cb023
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_snvs_lp.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2019, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_snvs_lp.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.snvs_lp"
+#endif
+
+#define SECONDS_IN_A_DAY (86400U)
+#define SECONDS_IN_A_HOUR (3600U)
+#define SECONDS_IN_A_MINUTE (60U)
+#define DAYS_IN_A_YEAR (365U)
+#define YEAR_RANGE_START (1970U)
+#define YEAR_RANGE_END (2099U)
+
+#define SNVS_DEFAULT_PGD_VALUE (0x41736166U)
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Checks whether the date and time passed in is valid
+ *
+ * @param datetime Pointer to structure where the date and time details are stored
+ *
+ * @return Returns false if the date & time details are out of range; true if in range
+ */
+static bool SNVS_LP_CheckDatetimeFormat(const snvs_lp_srtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from datetime to seconds
+ *
+ * @param datetime Pointer to datetime structure where the date and time details are stored
+ *
+ * @return The result of the conversion in seconds
+ */
+static uint32_t SNVS_LP_ConvertDatetimeToSeconds(const snvs_lp_srtc_datetime_t *datetime);
+
+/*!
+ * @brief Converts time data from seconds to a datetime structure
+ *
+ * @param seconds Seconds value that needs to be converted to datetime format
+ * @param datetime Pointer to the datetime structure where the result of the conversion is stored
+ */
+static void SNVS_LP_ConvertSecondsToDatetime(uint32_t seconds, snvs_lp_srtc_datetime_t *datetime);
+
+/*!
+ * @brief Returns SRTC time in seconds.
+ *
+ * This function is used internally to get actual SRTC time in seconds.
+ *
+ * @param base SNVS peripheral base address
+ *
+ * @return SRTC time in seconds
+ */
+static uint32_t SNVS_LP_SRTC_GetSeconds(SNVS_Type *base);
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+/*!
+ * @brief Get the SNVS instance from peripheral base address.
+ *
+ * @param base SNVS peripheral base address.
+ *
+ * @return SNVS instance.
+ */
+static uint32_t SNVS_LP_GetInstance(SNVS_Type *base);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+/*! @brief Pointer to snvs_lp clock. */
+const clock_ip_name_t s_snvsLpClock[] = SNVS_LP_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static bool SNVS_LP_CheckDatetimeFormat(const snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Check year, month, hour, minute, seconds */
+ if ((datetime->year < YEAR_RANGE_START) || (datetime->year > YEAR_RANGE_END) || (datetime->month > 12U) ||
+ (datetime->month < 1U) || (datetime->hour >= 24U) || (datetime->minute >= 60U) || (datetime->second >= 60U))
+ {
+ /* If not correct then error*/
+ return false;
+ }
+
+ /* Adjust the days in February for a leap year */
+ if ((((datetime->year & 3U) == 0U) && (datetime->year % 100U != 0U)) || (datetime->year % 400U == 0U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ /* Check the validity of the day */
+ if ((datetime->day > daysPerMonth[datetime->month]) || (datetime->day < 1U))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static uint32_t SNVS_LP_ConvertDatetimeToSeconds(const snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ /* Number of days from begin of the non Leap-year*/
+ /* Number of days from begin of the non Leap-year*/
+ uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
+ uint32_t seconds;
+
+ /* Compute number of days from 1970 till given year*/
+ seconds = ((uint32_t)datetime->year - 1970U) * DAYS_IN_A_YEAR;
+ /* Add leap year days */
+ seconds += (((uint32_t)datetime->year / 4U) - (1970U / 4U));
+ /* Add number of days till given month*/
+ seconds += monthDays[datetime->month];
+ /* Add days in given month. We subtract the current day as it is
+ * represented in the hours, minutes and seconds field*/
+ seconds += ((uint32_t)datetime->day - 1U);
+ /* For leap year if month less than or equal to Febraury, decrement day counter*/
+ if ((0U == (datetime->year & 3U)) && (datetime->month <= 2U))
+ {
+ seconds--;
+ }
+
+ seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
+ (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;
+
+ return seconds;
+}
+
+static void SNVS_LP_ConvertSecondsToDatetime(uint32_t seconds, snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t x;
+ uint32_t secondsRemaining, days;
+ uint16_t daysInYear;
+ /* Table of days in a month for a non leap year. First entry in the table is not used,
+ * valid months start from 1
+ */
+ uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};
+
+ /* Start with the seconds value that is passed in to be converted to date time format */
+ secondsRemaining = seconds;
+
+ /* Calcuate the number of days, we add 1 for the current day which is represented in the
+ * hours and seconds field
+ */
+ days = secondsRemaining / SECONDS_IN_A_DAY + 1U;
+
+ /* Update seconds left*/
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
+
+ /* Calculate the datetime hour, minute and second fields */
+ datetime->hour = (uint8_t)(secondsRemaining / SECONDS_IN_A_HOUR);
+ secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
+ datetime->minute = (uint8_t)(secondsRemaining / 60U);
+ datetime->second = (uint8_t)(secondsRemaining % SECONDS_IN_A_MINUTE);
+
+ /* Calculate year */
+ daysInYear = DAYS_IN_A_YEAR;
+ datetime->year = YEAR_RANGE_START;
+ while (days > daysInYear)
+ {
+ /* Decrease day count by a year and increment year by 1 */
+ days -= daysInYear;
+ datetime->year++;
+
+ /* Adjust the number of days for a leap year */
+ if ((datetime->year & 3U) != 0U)
+ {
+ daysInYear = DAYS_IN_A_YEAR;
+ }
+ else
+ {
+ daysInYear = DAYS_IN_A_YEAR + 1U;
+ }
+ }
+
+ /* Adjust the days in February for a leap year */
+ if (0U == (datetime->year & 3U))
+ {
+ daysPerMonth[2] = 29U;
+ }
+
+ for (x = 1U; x <= 12U; x++)
+ {
+ if (days <= daysPerMonth[x])
+ {
+ datetime->month = (uint8_t)x;
+ break;
+ }
+ else
+ {
+ days -= daysPerMonth[x];
+ }
+ }
+
+ datetime->day = (uint8_t)days;
+}
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+static uint32_t SNVS_LP_GetInstance(SNVS_Type *base)
+{
+ return 0U;
+}
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*!
+ * brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * param base SNVS peripheral base address
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_Init(SNVS_Type *base)
+{
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+ uint32_t instance = SNVS_LP_GetInstance(base);
+ CLOCK_EnableClock(s_snvsLpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Power glitch detector: set the PGD value and clear the previous status. */
+ base->LPPGDR = SNVS_DEFAULT_PGD_VALUE;
+ base->LPSR = SNVS_LPSR_PGD_MASK;
+}
+
+/*!
+ * brief Deinit the SNVS LP section.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_LP_Deinit(SNVS_Type *base)
+{
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+ uint32_t instance = SNVS_LP_GetInstance(base);
+ CLOCK_DisableClock(s_snvsLpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Ungates the SNVS clock and configures the peripheral for basic operation.
+ *
+ * note This API should be called at the beginning of the application using the SNVS driver.
+ *
+ * param base SNVS peripheral base address
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_SRTC_Init(SNVS_Type *base, const snvs_lp_srtc_config_t *config)
+{
+ assert(config != NULL);
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+ uint32_t instance = SNVS_LP_GetInstance(base);
+ CLOCK_EnableClock(s_snvsLpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ int pin;
+
+ if (config->srtcCalEnable)
+ {
+ base->LPCR = SNVS_LPCR_LPCALB_VAL_MASK & (config->srtcCalValue << SNVS_LPCR_LPCALB_VAL_SHIFT);
+ base->LPCR |= SNVS_LPCR_LPCALB_EN_MASK;
+ }
+
+ for (pin = (int32_t)kSNVS_ExternalTamper1; pin <= (int32_t)SNVS_LP_MAX_TAMPER; pin++)
+ {
+ SNVS_LP_DisableExternalTamper(SNVS, (snvs_lp_external_tamper_t)pin);
+ SNVS_LP_ClearExternalTamperStatus(SNVS, (snvs_lp_external_tamper_t)pin);
+ }
+}
+
+/*!
+ * brief Stops the SRTC timer.
+ *
+ * param base SNVS peripheral base address
+ */
+void SNVS_LP_SRTC_Deinit(SNVS_Type *base)
+{
+ base->LPCR &= ~SNVS_LPCR_SRTC_ENV_MASK;
+
+#if (!(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && \
+ defined(SNVS_LP_CLOCKS))
+ uint32_t instance = SNVS_LP_GetInstance(base);
+ CLOCK_DisableClock(s_snvsLpClock[instance]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Fills in the SNVS_LP config struct with the default settings.
+ *
+ * The default values are as follows.
+ * code
+ * config->srtccalenable = false;
+ * config->srtccalvalue = 0U;
+ * endcode
+ * param config Pointer to the user's SNVS configuration structure.
+ */
+void SNVS_LP_SRTC_GetDefaultConfig(snvs_lp_srtc_config_t *config)
+{
+ assert(config != NULL);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->srtcCalEnable = false;
+ config->srtcCalValue = 0U;
+}
+
+static uint32_t SNVS_LP_SRTC_GetSeconds(SNVS_Type *base)
+{
+ uint32_t seconds = 0;
+ uint32_t tmp = 0;
+
+ /* Do consecutive reads until value is correct */
+ do
+ {
+ seconds = tmp;
+ tmp = (base->LPSRTCMR << 17U);
+ tmp |= (base->LPSRTCLR >> 15U);
+ } while (tmp != seconds);
+
+ return seconds;
+}
+
+/*!
+ * brief Sets the SNVS SRTC date and time according to the given time structure.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the date and time details are stored.
+ *
+ * return kStatus_Success: Success in setting the time and starting the SNVS SRTC
+ * kStatus_InvalidArgument: Error because the datetime format is incorrect
+ */
+status_t SNVS_LP_SRTC_SetDatetime(SNVS_Type *base, const snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t seconds = 0U;
+ uint32_t tmp = base->LPCR;
+
+ /* disable RTC */
+ SNVS_LP_SRTC_StopTimer(base);
+
+ /* Return error if the time provided is not valid */
+ if (!(SNVS_LP_CheckDatetimeFormat(datetime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Set time in seconds */
+ seconds = SNVS_LP_ConvertDatetimeToSeconds(datetime);
+
+ base->LPSRTCMR = (uint32_t)(seconds >> 17U);
+ base->LPSRTCLR = (uint32_t)(seconds << 15U);
+
+ /* reenable SRTC in case that it was enabled before */
+ if ((tmp & SNVS_LPCR_SRTC_ENV_MASK) != 0U)
+ {
+ SNVS_LP_SRTC_StartTimer(base);
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets the SNVS SRTC time and stores it in the given time structure.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the date and time details are stored.
+ */
+void SNVS_LP_SRTC_GetDatetime(SNVS_Type *base, snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ SNVS_LP_ConvertSecondsToDatetime(SNVS_LP_SRTC_GetSeconds(base), datetime);
+}
+
+/*!
+ * brief Sets the SNVS SRTC alarm time.
+ *
+ * The function sets the SRTC alarm. It also checks whether the specified alarm
+ * time is greater than the present time. If not, the function does not set the alarm
+ * and returns an error.
+ * Please note, that SRTC alarm has limited resolution because only 32 most
+ * significant bits of SRTC counter are compared to SRTC Alarm register.
+ * If the alarm time is beyond SRTC resolution, the function does not set the alarm
+ * and returns an error.
+ *
+ * param base SNVS peripheral base address
+ * param alarmTime Pointer to the structure where the alarm time is stored.
+ *
+ * return kStatus_Success: success in setting the SNVS SRTC alarm
+ * kStatus_InvalidArgument: Error because the alarm datetime format is incorrect
+ * kStatus_Fail: Error because the alarm time has already passed or is beyond resolution
+ */
+status_t SNVS_LP_SRTC_SetAlarm(SNVS_Type *base, const snvs_lp_srtc_datetime_t *alarmTime)
+{
+ assert(alarmTime != NULL);
+
+ uint32_t alarmSeconds = 0U;
+ uint32_t currSeconds = 0U;
+ uint32_t tmp = base->LPCR;
+
+ /* Return error if the alarm time provided is not valid */
+ if (!(SNVS_LP_CheckDatetimeFormat(alarmTime)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ alarmSeconds = SNVS_LP_ConvertDatetimeToSeconds(alarmTime);
+ currSeconds = SNVS_LP_SRTC_GetSeconds(base);
+
+ /* Return error if the alarm time has passed */
+ if (alarmSeconds <= currSeconds)
+ {
+ return kStatus_Fail;
+ }
+
+ /* disable SRTC alarm interrupt */
+ base->LPCR &= ~SNVS_LPCR_LPTA_EN_MASK;
+ while ((base->LPCR & SNVS_LPCR_LPTA_EN_MASK) != 0U)
+ {
+ }
+
+ /* Set alarm in seconds*/
+ base->LPTAR = alarmSeconds;
+
+ /* reenable SRTC alarm interrupt in case that it was enabled before */
+ base->LPCR = tmp;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Returns the SNVS SRTC alarm time.
+ *
+ * param base SNVS peripheral base address
+ * param datetime Pointer to the structure where the alarm date and time details are stored.
+ */
+void SNVS_LP_SRTC_GetAlarm(SNVS_Type *base, snvs_lp_srtc_datetime_t *datetime)
+{
+ assert(datetime != NULL);
+
+ uint32_t alarmSeconds = 0U;
+
+ /* Get alarm in seconds */
+ alarmSeconds = base->LPTAR;
+
+ SNVS_LP_ConvertSecondsToDatetime(alarmSeconds, datetime);
+}
+
+/*!
+ * brief Gets the SNVS status flags.
+ *
+ * param base SNVS peripheral base address
+ *
+ * return The status flags. This is the logical OR of members of the
+ * enumeration ::snvs_status_flags_t
+ */
+uint32_t SNVS_LP_SRTC_GetStatusFlags(SNVS_Type *base)
+{
+ uint32_t flags = 0U;
+
+ if ((base->LPSR & SNVS_LPSR_LPTA_MASK) != 0U)
+ {
+ flags |= (uint32_t)kSNVS_SRTC_AlarmInterruptFlag;
+ }
+
+ return flags;
+}
+
+/*!
+ * brief Gets the enabled SNVS interrupts.
+ *
+ * param base SNVS peripheral base address
+ *
+ * return The enabled interrupts. This is the logical OR of members of the
+ * enumeration ::snvs_interrupt_enable_t
+ */
+uint32_t SNVS_LP_SRTC_GetEnabledInterrupts(SNVS_Type *base)
+{
+ uint32_t val = 0U;
+
+ if ((base->LPCR & SNVS_LPCR_LPTA_EN_MASK) != 0U)
+ {
+ val |= (uint32_t)kSNVS_SRTC_AlarmInterrupt;
+ }
+
+ return val;
+}
+
+/*!
+ * brief Enables the specified SNVS external tamper.
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ * param polarity Polarity of external tamper
+ */
+void SNVS_LP_EnableExternalTamper(SNVS_Type *base,
+ snvs_lp_external_tamper_t pin,
+ snvs_lp_external_tamper_polarity_t polarity)
+{
+ switch (pin)
+ {
+ case (kSNVS_ExternalTamper1):
+ base->LPTDCR =
+ (base->LPTDCR & ~(1UL << SNVS_LPTDCR_ET1P_SHIFT)) | ((uint32_t)polarity << SNVS_LPTDCR_ET1P_SHIFT);
+ base->LPTDCR |= SNVS_LPTDCR_ET1_EN_MASK;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ base->LPTDCR = (base->LPTDCR & ~(1U << SNVS_LPTDCR_ET2P_SHIFT)) | (polarity << SNVS_LPTDCR_ET2P_SHIFT);
+ base->LPTDCR |= SNVS_LPTDCR_ET2_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper3):
+ base->LPTDC2R = (base->LPTDC2R & ~(1U << SNVS_LPTDC2R_ET3P_SHIFT)) | (polarity << SNVS_LPTDC2R_ET3P_SHIFT);
+ base->LPTDC2R |= SNVS_LPTDC2R_ET3_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper4):
+ base->LPTDC2R = (base->LPTDC2R & ~(1U << SNVS_LPTDC2R_ET4P_SHIFT)) | (polarity << SNVS_LPTDC2R_ET4P_SHIFT);
+ base->LPTDC2R |= SNVS_LPTDC2R_ET4_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper5):
+ base->LPTDC2R = (base->LPTDC2R & ~(1U << SNVS_LPTDC2R_ET5P_SHIFT)) | (polarity << SNVS_LPTDC2R_ET5P_SHIFT);
+ base->LPTDC2R |= SNVS_LPTDC2R_ET5_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper6):
+ base->LPTDC2R = (base->LPTDC2R & ~(1U << SNVS_LPTDC2R_ET6P_SHIFT)) | (polarity << SNVS_LPTDC2R_ET6P_SHIFT);
+ base->LPTDC2R |= SNVS_LPTDC2R_ET6_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper7):
+ base->LPTDC2R = (base->LPTDC2R & ~(1U << SNVS_LPTDC2R_ET7P_SHIFT)) | (polarity << SNVS_LPTDC2R_ET7P_SHIFT);
+ base->LPTDC2R |= SNVS_LPTDC2R_ET7_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper8):
+ base->LPTDC2R = (base->LPTDC2R & ~(1U << SNVS_LPTDC2R_ET8P_SHIFT)) | (polarity << SNVS_LPTDC2R_ET8P_SHIFT);
+ base->LPTDC2R |= SNVS_LPTDC2R_ET8_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper9):
+ base->LPTDC2R = (base->LPTDC2R & ~(1U << SNVS_LPTDC2R_ET9P_SHIFT)) | (polarity << SNVS_LPTDC2R_ET9P_SHIFT);
+ base->LPTDC2R |= SNVS_LPTDC2R_ET9_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper10):
+ base->LPTDC2R =
+ (base->LPTDC2R & ~(1U << SNVS_LPTDC2R_ET10P_SHIFT)) | (polarity << SNVS_LPTDC2R_ET10P_SHIFT);
+ base->LPTDC2R |= SNVS_LPTDC2R_ET10_EN_MASK;
+ break;
+#endif
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+}
+
+/*!
+ * brief Disables the specified SNVS external tamper.
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ */
+void SNVS_LP_DisableExternalTamper(SNVS_Type *base, snvs_lp_external_tamper_t pin)
+{
+ switch (pin)
+ {
+ case (kSNVS_ExternalTamper1):
+ base->LPTDCR &= ~SNVS_LPTDCR_ET1_EN_MASK;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ base->LPTDCR &= ~SNVS_LPTDCR_ET2_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper3):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET3_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper4):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET4_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper5):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET5_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper6):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET6_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper7):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET7_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper8):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET8_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper9):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET9_EN_MASK;
+ break;
+ case (kSNVS_ExternalTamper10):
+ base->LPTDC2R &= ~SNVS_LPTDC2R_ET10_EN_MASK;
+ break;
+#endif
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+}
+
+/*!
+ * brief Returns status of the specified external tamper.
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ *
+ * return The status flag. This is the enumeration ::snvs_external_tamper_status_t
+ */
+snvs_lp_external_tamper_status_t SNVS_LP_GetExternalTamperStatus(SNVS_Type *base, snvs_lp_external_tamper_t pin)
+{
+ snvs_lp_external_tamper_status_t status = kSNVS_TamperNotDetected;
+
+ switch (pin)
+ {
+ case (kSNVS_ExternalTamper1):
+ status = (bool)(base->LPSR & SNVS_LPSR_ET1D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ status = (base->LPSR & SNVS_LPSR_ET2D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper3):
+ status = (base->LPTDSR & SNVS_LPTDSR_ET3D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper4):
+ status = (base->LPTDSR & SNVS_LPTDSR_ET4D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper5):
+ status = (base->LPTDSR & SNVS_LPTDSR_ET5D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper6):
+ status = (base->LPTDSR & SNVS_LPTDSR_ET6D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper7):
+ status = (base->LPTDSR & SNVS_LPTDSR_ET7D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper8):
+ status = (base->LPTDSR & SNVS_LPTDSR_ET8D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper9):
+ status = (base->LPTDSR & SNVS_LPTDSR_ET9D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+ case (kSNVS_ExternalTamper10):
+ status = (base->LPTDSR & SNVS_LPTDSR_ET10D_MASK) ? kSNVS_TamperDetected : kSNVS_TamperNotDetected;
+ break;
+#endif
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+ return status;
+}
+
+/*!
+ * brief Clears status of the specified external tamper.
+ *
+ * param base SNVS peripheral base address
+ * param pin SNVS external tamper pin
+ */
+void SNVS_LP_ClearExternalTamperStatus(SNVS_Type *base, snvs_lp_external_tamper_t pin)
+{
+ base->LPSR |= SNVS_LPSR_ET1D_MASK;
+
+ switch (pin)
+ {
+ case (kSNVS_ExternalTamper1):
+ base->LPSR |= SNVS_LPSR_ET1D_MASK;
+ break;
+#if defined(FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER) && (FSL_FEATURE_SNVS_HAS_MULTIPLE_TAMPER > 1)
+ case (kSNVS_ExternalTamper2):
+ base->LPSR |= SNVS_LPSR_ET2D_MASK;
+ break;
+ case (kSNVS_ExternalTamper3):
+ base->LPTDSR |= SNVS_LPTDSR_ET3D_MASK;
+ break;
+ case (kSNVS_ExternalTamper4):
+ base->LPTDSR |= SNVS_LPTDSR_ET4D_MASK;
+ break;
+ case (kSNVS_ExternalTamper5):
+ base->LPTDSR |= SNVS_LPTDSR_ET5D_MASK;
+ break;
+ case (kSNVS_ExternalTamper6):
+ base->LPTDSR |= SNVS_LPTDSR_ET6D_MASK;
+ break;
+ case (kSNVS_ExternalTamper7):
+ base->LPTDSR |= SNVS_LPTDSR_ET7D_MASK;
+ break;
+ case (kSNVS_ExternalTamper8):
+ base->LPTDSR |= SNVS_LPTDSR_ET8D_MASK;
+ break;
+ case (kSNVS_ExternalTamper9):
+ base->LPTDSR |= SNVS_LPTDSR_ET9D_MASK;
+ break;
+ case (kSNVS_ExternalTamper10):
+ base->LPTDSR |= SNVS_LPTDSR_ET10D_MASK;
+ break;
+#endif
+ default:
+ /* All the cases have been listed above, the default clause should not be reached. */
+ break;
+ }
+}
+
+/*!
+ * brief Get the current Monotonic Counter.
+ *
+ * param base SNVS peripheral base address
+ * return Current Monotonic Counter value.
+ */
+uint64_t SNVS_LP_GetMonotonicCounter(SNVS_Type *base)
+{
+ uint32_t mc_lsb, mc_msb;
+
+ mc_msb = base->LPSMCMR;
+ mc_lsb = base->LPSMCLR;
+
+ return ((uint64_t)mc_msb << 32UL) | (uint64_t)mc_lsb;
+}
+
+/*!
+ * brief Write Zeroizable Master Key (ZMK) to the SNVS registers.
+ *
+ * param base SNVS peripheral base address
+ * param ZMKey The ZMK write to the SNVS register.
+ */
+void SNVS_LP_WriteZeroizableMasterKey(SNVS_Type *base, uint32_t ZMKey[SNVS_ZMK_REG_COUNT])
+{
+ uint8_t i = 0;
+
+ for (i = 0; i < SNVS_ZMK_REG_COUNT; i++)
+ {
+ base->LPZMKR[i] = ZMKey[i];
+ }
+}
+
+#if defined(FSL_FEATURE_SNVS_HAS_STATE_TRANSITION) && (FSL_FEATURE_SNVS_HAS_STATE_TRANSITION > 0)
+/*!
+ * brief Transition SNVS SSM state to Trusted/Non-secure from Check state
+ *
+ * param base SNVS peripheral base address
+ *
+ * return kStatus_Success: Success in transitioning SSM State
+ * kStatus_Fail: SSM State transition failed
+ */
+status_t SNVS_LP_SSM_State_Transition(SNVS_Type *base)
+{
+ uint32_t curr_ssm_state = ((base->HPSR & SNVS_HPSR_SSM_STATE_MASK) >> SNVS_HPSR_SSM_STATE_SHIFT);
+ uint32_t sec_config = ((OCOTP_CTRL->HW_OCOTP_OTFAD_CFG3 & OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_MASK) >>
+ OCOTP_CTRL_HW_OCOTP_SEC_CONFIG1_SHIFT);
+
+ /* Check if SSM State is Check state */
+ if (curr_ssm_state == SNVS_SSM_STATE_CHECK)
+ {
+ if (sec_config == SEC_CONFIG_OPEN)
+ {
+ /* Transition to Non-secure state */
+ base->HPCOMR |= SNVS_HPCOMR_SW_SV(1);
+ }
+ else
+ {
+ /* Transition to Trusted state */
+ base->HPCOMR |= SNVS_HPCOMR_SSM_ST(1);
+ }
+ }
+
+ uint32_t new_ssm_state = ((base->HPSR & SNVS_HPSR_SSM_STATE_MASK) >> SNVS_HPSR_SSM_STATE_SHIFT);
+
+ if (new_ssm_state != SNVS_SSM_STATE_CHECK)
+ {
+ return kStatus_Success;
+ }
+ else
+ {
+ return kStatus_Fail;
+ }
+}
+#endif /* FSL_FEATURE_SNVS_HAS_STATE_TRANSITION */
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_spdif.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_spdif.c
new file mode 100644
index 0000000000..ef06114dd6
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_spdif.c
@@ -0,0 +1,828 @@
+/*
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_spdif.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.spdif"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*! @brief spdif transfer state. */
+enum
+{
+ kSPDIF_Busy = 0x0U, /*!< SPDIF is busy */
+ kSPDIF_Idle, /*!< Transfer is done. */
+ kSPDIF_Error /*!< Transfer error occurred. */
+};
+
+/*! @brief Typedef for spdif tx interrupt handler. */
+typedef void (*spdif_isr_t)(SPDIF_Type *base, spdif_handle_t *handle);
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Base pointer array */
+static SPDIF_Type *const s_spdifBases[] = SPDIF_BASE_PTRS;
+/*! @brief SPDIF handle pointer */
+static spdif_handle_t *s_spdifHandle[ARRAY_SIZE(s_spdifBases)][2];
+/* IRQ number array */
+static const IRQn_Type s_spdifIRQ[] = SPDIF_IRQS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_spdifClock[] = SPDIF_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+/*! @brief Pointer to IRQ handler for each instance. */
+static spdif_isr_t s_spdifTxIsr;
+/*! @brief Pointer to IRQ handler for each instance. */
+static spdif_isr_t s_spdifRxIsr;
+/*! @brief Used for spdif gain */
+static uint8_t s_spdif_gain[8] = {24U, 16U, 12U, 8U, 6U, 4U, 3U, 1U};
+static uint8_t s_spdif_tx_watermark[4] = {16, 12, 8, 4};
+static uint8_t s_spdif_rx_watermark[4] = {1, 4, 8, 16};
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+uint32_t SPDIF_GetInstance(SPDIF_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_spdifBases); instance++)
+ {
+ if (s_spdifBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_spdifBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the SPDIF peripheral.
+ *
+ * Ungates the SPDIF clock, resets the module, and configures SPDIF with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * SPDIF_GetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the SPDIF driver. Otherwise, accessing the SPDIF module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base SPDIF base pointer
+ * param config SPDIF configuration structure.
+ */
+void SPDIF_Init(SPDIF_Type *base, const spdif_config_t *config)
+{
+ uint32_t val = 0;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the SPDIF clock */
+ CLOCK_EnableClock(s_spdifClock[SPDIF_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset the internal logic */
+ base->SCR |= SPDIF_SCR_SOFT_RESET_MASK;
+
+ /* Waiting for reset finish */
+ while ((base->SCR & SPDIF_SCR_SOFT_RESET_MASK) != 0x00U)
+ {
+ }
+
+ /* Setting the SPDIF settings */
+ base->SCR = SPDIF_SCR_RXFIFOFULL_SEL(config->rxFullSelect) | SPDIF_SCR_RXAUTOSYNC(config->isRxAutoSync) |
+ SPDIF_SCR_TXAUTOSYNC(config->isRxAutoSync) | SPDIF_SCR_TXFIFOEMPTY_SEL(config->txFullSelect) |
+ SPDIF_SCR_TXFIFO_CTRL(1U) | SPDIF_SCR_VALCTRL(config->validityConfig) |
+ SPDIF_SCR_TXSEL(config->txSource) | SPDIF_SCR_USRC_SEL(config->uChannelSrc);
+
+ /* Set DPLL clock source */
+ base->SRPC = SPDIF_SRPC_CLKSRC_SEL(config->DPLLClkSource) | SPDIF_SRPC_GAINSEL(config->gain);
+
+ /* Set SPDIF tx clock source */
+ val = base->STC & ~SPDIF_STC_TXCLK_SOURCE_MASK;
+ val |= SPDIF_STC_TXCLK_SOURCE(config->txClkSource);
+ base->STC = val;
+}
+
+/*!
+ * brief De-initializes the SPDIF peripheral.
+ *
+ * This API gates the SPDIF clock. The SPDIF module can't operate unless SPDIF_Init is called to enable the clock.
+ *
+ * param base SPDIF base pointer
+ */
+void SPDIF_Deinit(SPDIF_Type *base)
+{
+ SPDIF_TxEnable(base, false);
+ SPDIF_RxEnable(base, false);
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_spdifClock[SPDIF_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Sets the SPDIF configuration structure to default values.
+ *
+ * This API initializes the configuration structure for use in SPDIF_Init.
+ * The initialized structure can remain unchanged in SPDIF_Init, or it can be modified
+ * before calling SPDIF_Init.
+ * This is an example.
+ code
+ spdif_config_t config;
+ SPDIF_GetDefaultConfig(&config);
+ endcode
+ *
+ * param config pointer to master configuration structure
+ */
+void SPDIF_GetDefaultConfig(spdif_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->isTxAutoSync = true;
+ config->isRxAutoSync = true;
+ config->DPLLClkSource = 1;
+ config->txClkSource = 1;
+ config->rxFullSelect = kSPDIF_RxFull8Samples;
+ config->txFullSelect = kSPDIF_TxEmpty8Samples;
+ config->uChannelSrc = kSPDIF_UChannelFromTx;
+ config->txSource = kSPDIF_txNormal;
+ config->validityConfig = kSPDIF_validityFlagAlwaysClear;
+ config->gain = kSPDIF_GAIN_8;
+}
+
+/*!
+ * brief Enables/disables the SPDIF Tx.
+ *
+ * param base SPDIF base pointer
+ * param enable True means enable SPDIF Tx, false means disable.
+ */
+void SPDIF_TxEnable(SPDIF_Type *base, bool enable)
+{
+ uint32_t val = 0;
+
+ if (enable)
+ {
+ /* Open Tx FIFO */
+ val = base->SCR & (~SPDIF_SCR_TXFIFO_CTRL_MASK);
+ val |= SPDIF_SCR_TXFIFO_CTRL(1U);
+ base->SCR = val;
+ /* Enable transfer clock */
+ base->STC |= SPDIF_STC_TX_ALL_CLK_EN_MASK;
+ }
+ else
+ {
+ base->SCR &= ~(SPDIF_SCR_TXFIFO_CTRL_MASK | SPDIF_SCR_TXSEL_MASK);
+ /* Disable transfer clock */
+ base->STC &= ~SPDIF_STC_TX_ALL_CLK_EN_MASK;
+ }
+}
+
+/*!
+ * brief Configures the SPDIF Tx sample rate.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate.
+ *
+ * param base SPDIF base pointer.
+ * param sampleRate_Hz SPDIF sample rate frequency in Hz.
+ * param sourceClockFreq_Hz SPDIF tx clock source frequency in Hz.
+ */
+void SPDIF_TxSetSampleRate(SPDIF_Type *base, uint32_t sampleRate_Hz, uint32_t sourceClockFreq_Hz)
+{
+ uint32_t clkDiv = sourceClockFreq_Hz / (sampleRate_Hz * 64U);
+ uint32_t mod = sourceClockFreq_Hz % (sampleRate_Hz * 64U);
+ uint32_t val = 0;
+ uint8_t clockSource = (uint8_t)(((base->STC) & SPDIF_STC_TXCLK_SOURCE_MASK) >> SPDIF_STC_TXCLK_SOURCE_SHIFT);
+
+ /* Compute the nearest divider */
+ if (mod > ((sampleRate_Hz * 64U) / 2U))
+ {
+ clkDiv += 1U;
+ }
+
+ /* If use divided systeme clock */
+ if (clockSource == 5U)
+ {
+ if (clkDiv > 256U)
+ {
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_SYSCLK_DF((clkDiv / 128U) - 1U) | SPDIF_STC_TXCLK_DF(127U);
+ base->STC = val;
+ }
+ else
+ {
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_SYSCLK_DF(1U) | SPDIF_STC_TXCLK_DF(clkDiv - 1U);
+ base->STC = val;
+ }
+ }
+ else
+ {
+ /* Other clock only uses txclk div */
+ val = base->STC & (~(SPDIF_STC_TXCLK_DF_MASK | SPDIF_STC_SYSCLK_DF_MASK));
+ val |= SPDIF_STC_TXCLK_DF(clkDiv - 1U);
+ base->STC = val;
+ }
+}
+
+/*!
+ * brief Configures the SPDIF Rx audio format.
+ *
+ * The audio format can be changed at run-time. This function configures the sample rate and audio data
+ * format to be transferred.
+ *
+ * param base SPDIF base pointer.
+ * param clockSourceFreq_Hz SPDIF system clock frequency in hz.
+ */
+uint32_t SPDIF_GetRxSampleRate(SPDIF_Type *base, uint32_t clockSourceFreq_Hz)
+{
+ uint64_t gain = s_spdif_gain[((base->SRPC & SPDIF_SRPC_GAINSEL_MASK) >> SPDIF_SRPC_GAINSEL_SHIFT)];
+ uint32_t measure = 0;
+ uint32_t sampleRate = 0;
+ uint64_t temp = 0;
+
+ /* Wait the DPLL locked */
+ while ((base->SRPC & SPDIF_SRPC_LOCK_MASK) == 0U)
+ {
+ }
+
+ /* Get the measure value */
+ measure = base->SRFM;
+ temp = (uint64_t)measure * (uint64_t)clockSourceFreq_Hz;
+ temp /= 1024U * 1024U * 128U * gain;
+ sampleRate = (uint32_t)temp;
+
+ return sampleRate;
+}
+
+/*!
+ * brief Sends data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SPDIF base pointer.
+ * param buffer Pointer to the data to be written.
+ * param size Bytes to be written.
+ */
+void SPDIF_WriteBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size)
+{
+ assert(buffer != NULL);
+ assert((size % 6U) == 0U);
+
+ uint32_t i = 0, j = 0, data = 0;
+
+ while (i < size)
+ {
+ /* Wait until it can write data */
+ while ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_TxFIFOEmpty) == 0x00U)
+ {
+ }
+
+ /* Write left channel data */
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteLeftData(base, data);
+
+ /* Write right channel data */
+ data = 0;
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteRightData(base, data);
+
+ i += 6U;
+ }
+}
+
+/*!
+ * brief Receives data using a blocking method.
+ *
+ * note This function blocks by polling until data is ready to be sent.
+ *
+ * param base SPDIF base pointer.
+ * param buffer Pointer to the data to be read.
+ * param size Bytes to be read.
+ */
+void SPDIF_ReadBlocking(SPDIF_Type *base, uint8_t *buffer, uint32_t size)
+{
+ assert(buffer != NULL);
+ assert((size % 6U) == 0U);
+
+ uint32_t i = 0, j = 0, data = 0;
+
+ while (i < size)
+ {
+ /* Wait until it can write data */
+ while ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxFIFOFull) == 0x00U)
+ {
+ }
+
+ /* Write left channel data */
+ data = SPDIF_ReadLeftData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = ((uint8_t)(data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ /* Write right channel data */
+ data = SPDIF_ReadRightData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = ((uint8_t)(data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ i += 6U;
+ }
+}
+
+/*!
+ * brief Initializes the SPDIF Tx handle.
+ *
+ * This function initializes the Tx handle for the SPDIF Tx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function
+ */
+void SPDIF_TransferTxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_spdifHandle[SPDIF_GetInstance(base)][0] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->watermark =
+ s_spdif_tx_watermark[(base->SCR & SPDIF_SCR_TXFIFOEMPTY_SEL_MASK) >> SPDIF_SCR_TXFIFOEMPTY_SEL_SHIFT];
+
+ /* Set the isr pointer */
+ s_spdifTxIsr = SPDIF_TransferTxHandleIRQ;
+
+ /* Enable Tx irq */
+ (void)EnableIRQ(s_spdifIRQ[SPDIF_GetInstance(base)]);
+}
+
+/*!
+ * brief Initializes the SPDIF Rx handle.
+ *
+ * This function initializes the Rx handle for the SPDIF Rx transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function.
+ */
+void SPDIF_TransferRxCreateHandle(SPDIF_Type *base,
+ spdif_handle_t *handle,
+ spdif_transfer_callback_t callback,
+ void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_spdifHandle[SPDIF_GetInstance(base)][1] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->watermark =
+ s_spdif_rx_watermark[(base->SCR & SPDIF_SCR_RXFIFOFULL_SEL_MASK) >> SPDIF_SCR_RXFIFOFULL_SEL_SHIFT];
+
+ /* Set the isr pointer */
+ s_spdifRxIsr = SPDIF_TransferRxHandleIRQ;
+
+ /* Enable Rx irq */
+ (void)EnableIRQ(s_spdifIRQ[SPDIF_GetInstance(base)]);
+}
+
+/*!
+ * brief Performs an interrupt non-blocking send transfer on SPDIF.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_TxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the spdif_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SPDIF_TxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferSendNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->spdifQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].data = xfer->data;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Set the state to busy */
+ handle->state = kSPDIF_Busy;
+
+ /* Enable interrupt */
+ SPDIF_EnableInterrupts(base, kSPDIF_TxFIFOEmpty);
+
+ /* Enable Tx transfer */
+ SPDIF_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on SPDIF.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the SPDIF_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_SPDIF_Busy, the transfer
+ * is finished.
+ *
+ * param base SPDIF base pointer
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the spdif_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_SPDIF_RxBusy Previous receive still not finished.
+ * retval kStatus_InvalidArgument The input parameter is invalid.
+ */
+status_t SPDIF_TransferReceiveNonBlocking(SPDIF_Type *base, spdif_handle_t *handle, spdif_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->spdifQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].data = xfer->data;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].udata = xfer->udata;
+ handle->spdifQueue[handle->queueUser].qdata = xfer->qdata;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = kSPDIF_Busy;
+
+ /* Enable interrupt */
+ SPDIF_EnableInterrupts(base, (uint32_t)kSPDIF_UChannelReceiveRegisterFull |
+ (uint32_t)kSPDIF_QChannelReceiveRegisterFull | (uint32_t)kSPDIF_RxFIFOFull |
+ (uint32_t)kSPDIF_RxControlChannelChange);
+
+ /* Enable Rx transfer */
+ SPDIF_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Gets a set byte count.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param count Bytes count sent.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetSendCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->spdifQueue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets a received byte count.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ * param count Bytes count received.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
+ */
+status_t SPDIF_TransferGetReceiveCount(SPDIF_Type *base, spdif_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+ uint8_t queueDriver = handle->queueDriver;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[queueDriver] - handle->spdifQueue[queueDriver].dataSize);
+ }
+
+ return status;
+}
+
+/*!
+ * brief Aborts the current send.
+ *
+ * note This API can be called any time when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortSend(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Use FIFO request interrupt and fifo error */
+ SPDIF_DisableInterrupts(base, kSPDIF_TxFIFOEmpty);
+
+ handle->state = kSPDIF_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->spdifQueue, 0, sizeof(spdif_transfer_t) * SPDIF_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Aborts the current IRQ receive.
+ *
+ * note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base SPDIF base pointer
+ * param handle Pointer to the spdif_handle_t structure which stores the transfer state.
+ */
+void SPDIF_TransferAbortReceive(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable interrupt */
+ SPDIF_DisableInterrupts(base, (uint32_t)kSPDIF_UChannelReceiveRegisterFull |
+ (uint32_t)kSPDIF_QChannelReceiveRegisterFull | (uint32_t)kSPDIF_RxFIFOFull |
+ (uint32_t)kSPDIF_RxControlChannelChange);
+
+ handle->state = kSPDIF_Idle;
+
+ /* Clear the queue */
+ (void)memset(handle->spdifQueue, 0, sizeof(spdif_transfer_t) * SPDIF_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferTxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = handle->spdifQueue[handle->queueDriver].data;
+ uint8_t dataSize = 0;
+ uint32_t i = 0, j = 0, data = 0;
+
+ /* Do Transfer */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_TxFIFOEmpty) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_TxFIFOEmpty) != 0x00U))
+ {
+ dataSize = handle->watermark;
+ while (i < dataSize)
+ {
+ data = 0;
+ /* Write left channel data */
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteLeftData(base, data);
+
+ /* Write right channel data */
+ data = 0;
+ for (j = 0; j < 3U; j++)
+ {
+ data |= ((uint32_t)(*buffer) << (j * 8U));
+ buffer++;
+ }
+ SPDIF_WriteRightData(base, data);
+
+ i++;
+ }
+ handle->spdifQueue[handle->queueDriver].dataSize -= (uint32_t)dataSize * 6U;
+ handle->spdifQueue[handle->queueDriver].data += dataSize * 6U;
+
+ /* If finished a block, call the callback function */
+ if (handle->spdifQueue[handle->queueDriver].dataSize == 0U)
+ {
+ (void)memset(&handle->spdifQueue[handle->queueDriver], 0, sizeof(spdif_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_TxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->spdifQueue[handle->queueDriver].data == NULL)
+ {
+ SPDIF_TransferAbortSend(base, handle);
+ }
+ }
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base SPDIF base pointer.
+ * param handle Pointer to the spdif_handle_t structure.
+ */
+void SPDIF_TransferRxHandleIRQ(SPDIF_Type *base, spdif_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint8_t *buffer = NULL;
+ uint8_t dataSize = 0;
+ uint32_t i = 0, j = 0, data = 0;
+
+ /* Handle Cnew flag */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxControlChannelChange) != 0x00U)
+ {
+ /* Clear the interrupt flag */
+ SPDIF_ClearStatusFlags(base, SPDIF_SIE_CNEW_MASK);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxCnew, handle->userData);
+ }
+ }
+
+ /* Handle illegal symbol */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxIllegalSymbol) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxIllegalSymbol);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxIllegalSymbol, handle->userData);
+ }
+ }
+
+ /* Handle Parity Bit Error */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxParityBitError) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxParityBitError);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxParityBitError, handle->userData);
+ }
+ }
+
+ /* Handle DPlocked */
+ if ((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxDPLLLocked) != 0x00U)
+ {
+ SPDIF_ClearStatusFlags(base, kSPDIF_RxDPLLLocked);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxDPLLLocked, handle->userData);
+ }
+ }
+
+ /* Handle Q channel full flag */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_QChannelReceiveRegisterFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_QChannelReceiveRegisterFull) != 0x00U))
+ {
+ buffer = handle->spdifQueue[handle->queueDriver].qdata;
+ data = SPDIF_ReadQChannel(base);
+ buffer[0] = (uint8_t)data & 0xFFU;
+ buffer[1] = (uint8_t)(data >> 8U) & 0xFFU;
+ buffer[2] = (uint8_t)(data >> 16U) & 0xFFU;
+ }
+
+ /* Handle U channel full flag */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_UChannelReceiveRegisterFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_UChannelReceiveRegisterFull) != 0x00U))
+ {
+ buffer = handle->spdifQueue[handle->queueDriver].udata;
+ data = SPDIF_ReadUChannel(base);
+ buffer[0] = (uint8_t)data & 0xFFU;
+ buffer[1] = (uint8_t)(data >> 8U) & 0xFFU;
+ buffer[2] = (uint8_t)(data >> 16U) & 0xFFU;
+ }
+
+ /* Handle audio data transfer */
+ if (((SPDIF_GetStatusFlag(base) & (uint32_t)kSPDIF_RxFIFOFull) != 0x00U) &&
+ ((base->SIE & (uint32_t)kSPDIF_RxFIFOFull) != 0x00U))
+ {
+ dataSize = handle->watermark;
+ buffer = handle->spdifQueue[handle->queueDriver].data;
+ while (i < dataSize)
+ {
+ /* Read left channel data */
+ data = SPDIF_ReadLeftData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = (uint8_t)((data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ /* Read right channel data */
+ data = SPDIF_ReadRightData(base);
+ for (j = 0; j < 3U; j++)
+ {
+ *buffer = (uint8_t)((data >> (j * 8U)) & 0xFFU);
+ buffer++;
+ }
+
+ i++;
+ }
+ handle->spdifQueue[handle->queueDriver].dataSize -= (uint32_t)dataSize * 6U;
+ handle->spdifQueue[handle->queueDriver].data += dataSize * 6U;
+
+ /* If finished a block, call the callback function */
+ if (handle->spdifQueue[handle->queueDriver].dataSize == 0x00U)
+ {
+ (void)memset(&handle->spdifQueue[handle->queueDriver], 0, sizeof(spdif_transfer_t));
+ handle->queueDriver = (handle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_SPDIF_RxIdle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->spdifQueue[handle->queueDriver].data == NULL)
+ {
+ SPDIF_TransferAbortReceive(base, handle);
+ }
+ }
+}
+
+#if defined(SPDIF)
+void SPDIF_DriverIRQHandler(void)
+{
+ if ((s_spdifHandle[0][0] != NULL) && (s_spdifTxIsr != NULL))
+ {
+ s_spdifTxIsr(SPDIF, s_spdifHandle[0][0]);
+ }
+
+ if ((s_spdifHandle[0][1] != NULL) && (s_spdifRxIsr != NULL))
+ {
+ s_spdifRxIsr(SPDIF, s_spdifHandle[0][1]);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_spdif_edma.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_spdif_edma.c
new file mode 100644
index 0000000000..8338a55f58
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_spdif_edma.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2017-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_spdif_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.spdif_edma"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32U) & ~0x1FU)
+
+/*<! Structure definition for uart_edma_private_handle_t. The structure is private. */
+typedef struct _spdif_edma_private_handle
+{
+ SPDIF_Type *base;
+ spdif_edma_handle_t *handle;
+} spdif_edma_private_handle_t;
+
+/*!
+ * @brief Used for conversion between `void*` and `uint32_t`.
+ */
+typedef union pvoid_to_u32
+{
+ void *pvoid;
+ uint32_t u32;
+} pvoid_to_u32_t;
+
+/*! @brief spdif edma transfer state. */
+enum
+{
+ kSPDIF_Busy = 0x0U, /*!< SPDIF is busy */
+ kSPDIF_Idle, /*!< Transfer is done. */
+};
+
+/*<! Private handle only used for internally. */
+static spdif_edma_private_handle_t s_edmaPrivateHandle[FSL_FEATURE_SOC_SPDIF_COUNT][2];
+static uint8_t s_spdif_tx_watermark[4] = {16, 12, 8, 4};
+static uint8_t s_spdif_rx_watermark[4] = {1, 4, 8, 16};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Submit SPDIF tcds to EDMA.
+ *
+ * @param base SPDIF base pointer.
+ */
+static status_t SPDIF_SubmitTransfer(edma_handle_t *handle,
+ const edma_transfer_config_t *config,
+ uint32_t rightChannel);
+
+/*!
+ * @brief SPDIF EDMA callback for send.
+ *
+ * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief SPDIF EDMA callback for receive.
+ *
+ * @param handle pointer to spdif_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static void SPDIF_TxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
+ spdif_edma_handle_t *spdifHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
+ spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (spdifHandle->callback != NULL)
+ {
+ (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_TxIdle, spdifHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
+ {
+ SPDIF_TransferAbortSendEDMA(privHandle->base, spdifHandle);
+ }
+}
+
+static void SPDIF_RxEDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ spdif_edma_private_handle_t *privHandle = (spdif_edma_private_handle_t *)userData;
+ spdif_edma_handle_t *spdifHandle = privHandle->handle;
+
+ /* If finished a block, call the callback function */
+ (void)memset(&spdifHandle->spdifQueue[spdifHandle->queueDriver], 0, sizeof(spdif_edma_transfer_t));
+ spdifHandle->queueDriver = (spdifHandle->queueDriver + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+ if (spdifHandle->callback != NULL)
+ {
+ (spdifHandle->callback)(privHandle->base, spdifHandle, kStatus_SPDIF_RxIdle, spdifHandle->userData);
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (spdifHandle->spdifQueue[spdifHandle->queueDriver].rightData == NULL)
+ {
+ SPDIF_TransferAbortReceiveEDMA(privHandle->base, spdifHandle);
+ }
+}
+
+static status_t SPDIF_SubmitTransfer(edma_handle_t *handle, const edma_transfer_config_t *config, uint32_t rightChannel)
+{
+ edma_tcd_t *tcdRegs = (edma_tcd_t *)&handle->base->TCD[handle->channel];
+ uint32_t primask;
+ uint16_t csr;
+ int8_t currentTcd;
+ int8_t previousTcd;
+ int8_t nextTcd;
+ int8_t tcdUsed = handle->tcdUsed;
+ int8_t tcdSize = handle->tcdSize;
+
+ /* Check if tcd pool is full. */
+ primask = DisableGlobalIRQ();
+ if (tcdUsed >= tcdSize)
+ {
+ EnableGlobalIRQ(primask);
+
+ return kStatus_EDMA_QueueFull;
+ }
+ currentTcd = handle->tail;
+ handle->tcdUsed++;
+ /* Calculate index of next TCD */
+ nextTcd = currentTcd + 0x01;
+ if (nextTcd == handle->tcdSize)
+ {
+ nextTcd = 0x00;
+ }
+ /* Advance queue tail index */
+ handle->tail = nextTcd;
+ EnableGlobalIRQ(primask);
+ /* Calculate index of previous TCD */
+ previousTcd = (currentTcd != 0x00) ? (currentTcd - 0x01) : (handle->tcdSize - 0x01);
+ /* Configure current TCD block. */
+ EDMA_TcdReset(&handle->tcdPool[currentTcd]);
+ EDMA_TcdSetTransferConfig(&handle->tcdPool[currentTcd], config, NULL);
+ /* Set channel link */
+ EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MinorLink, rightChannel);
+ EDMA_TcdSetChannelLink(&handle->tcdPool[currentTcd], kEDMA_MajorLink, rightChannel);
+ /* Enable major interrupt */
+ handle->tcdPool[currentTcd].CSR |= DMA_CSR_INTMAJOR_MASK;
+ /* Link current TCD with next TCD for identification of current TCD */
+ handle->tcdPool[currentTcd].DLAST_SGA = (uint32_t)&handle->tcdPool[nextTcd];
+ /* Chain from previous descriptor unless tcd pool size is 1(this descriptor is its own predecessor). */
+ if (currentTcd != previousTcd)
+ {
+ /* Enable scatter/gather feature in the previous TCD block. */
+ csr = (handle->tcdPool[previousTcd].CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
+ handle->tcdPool[previousTcd].CSR = csr;
+ /*
+ Check if the TCD block in the registers is the previous one (points to current TCD block). It
+ is used to check if the previous TCD linked has been loaded in TCD register. If so, it need to
+ link the TCD register in case link the current TCD with the dead chain when TCD loading occurs
+ before link the previous TCD block.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[currentTcd])
+ {
+ /* Enable scatter/gather also in the TCD registers. */
+ csr = (tcdRegs->CSR | (uint16_t)DMA_CSR_ESG_MASK) & ~(uint16_t)DMA_CSR_DREQ_MASK;
+ /* Must write the CSR register one-time, because the transfer maybe finished anytime. */
+ tcdRegs->CSR = csr;
+ /*
+ It is very important to check the ESG bit!
+ Because this hardware design: if DONE bit is set, the ESG bit can not be set. So it can
+ be used to check if the dynamic TCD link operation is successful. If ESG bit is not set
+ and the DLAST_SGA is not the next TCD address(it means the dynamic TCD link succeed and
+ the current TCD block has been loaded into TCD registers), it means transfer finished
+ and TCD link operation fail, so must install TCD content into TCD registers and enable
+ transfer again. And if ESG is set, it means transfer has notfinished, so TCD dynamic
+ link succeed.
+ */
+ if ((tcdRegs->CSR & DMA_CSR_ESG_MASK) != 0x00U)
+ {
+ return kStatus_Success;
+ }
+ /*
+ Check whether the current TCD block is already loaded in the TCD registers. It is another
+ condition when ESG bit is not set: it means the dynamic TCD link succeed and the current
+ TCD block has been loaded into TCD registers.
+ */
+ if (tcdRegs->DLAST_SGA == (uint32_t)&handle->tcdPool[nextTcd])
+ {
+ return kStatus_Success;
+ }
+ /*
+ If go to this, means the previous transfer finished, and the DONE bit is set.
+ So shall configure TCD registers.
+ */
+ }
+ else if (tcdRegs->DLAST_SGA != 0x00U)
+ {
+ /* The current TCD block has been linked successfully. */
+ return kStatus_Success;
+ }
+ else
+ {
+ /*
+ DLAST_SGA is 0 and it means the first submit transfer, so shall configure
+ TCD registers.
+ */
+ }
+ }
+ /* There is no live chain, TCD block need to be installed in TCD registers. */
+ EDMA_InstallTCD(handle->base, handle->channel, &handle->tcdPool[currentTcd]);
+ /* Enable channel request again. */
+ if ((handle->flags & 0x80U) != 0x00U)
+ {
+ handle->base->SERQ = DMA_SERQ_SERQ(handle->channel);
+ }
+ else
+ {
+ ; /* Intentional empty */
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the SPDIF eDMA handle.
+ *
+ * This function initializes the SPDIF master DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param base SPDIF peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferTxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle)
+{
+ assert(handle != NULL);
+ assert(dmaLeftHandle != NULL);
+ assert(dmaRightHandle != NULL);
+
+ uint32_t instance = SPDIF_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set spdif base to handle */
+ handle->dmaLeftHandle = dmaLeftHandle;
+ handle->dmaRightHandle = dmaRightHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->count =
+ s_spdif_tx_watermark[(base->SCR & SPDIF_SCR_TXFIFOEMPTY_SEL_MASK) >> SPDIF_SCR_TXFIFOEMPTY_SEL_SHIFT];
+
+ /* Set SPDIF state to idle */
+ handle->state = kSPDIF_Idle;
+
+ s_edmaPrivateHandle[instance][0].base = base;
+ s_edmaPrivateHandle[instance][0].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
+ EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel, only right channel finished, a transfer finished */
+ EDMA_SetCallback(dmaRightHandle, SPDIF_TxEDMACallback, &s_edmaPrivateHandle[instance][0]);
+}
+
+/*!
+ * brief Initializes the SPDIF Rx eDMA handle.
+ *
+ * This function initializes the SPDIF slave DMA handle, which can be used for other SPDIF master transactional APIs.
+ * Usually, for a specified SPDIF instance, call this API once to get the initialized handle.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param base SPDIF peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaLeftHandle eDMA handle pointer for left channel, this handle shall be static allocated by users.
+ * param dmaRightHandle eDMA handle pointer for right channel, this handle shall be static allocated by users.
+ */
+void SPDIF_TransferRxCreateHandleEDMA(SPDIF_Type *base,
+ spdif_edma_handle_t *handle,
+ spdif_edma_callback_t callback,
+ void *userData,
+ edma_handle_t *dmaLeftHandle,
+ edma_handle_t *dmaRightHandle)
+{
+ assert(handle != NULL);
+ assert(dmaLeftHandle != NULL);
+ assert(dmaRightHandle != NULL);
+
+ uint32_t instance = SPDIF_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set spdif base to handle */
+ handle->dmaLeftHandle = dmaLeftHandle;
+ handle->dmaRightHandle = dmaRightHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->count = s_spdif_rx_watermark[(base->SCR & SPDIF_SCR_RXFIFOFULL_SEL_MASK) >> SPDIF_SCR_RXFIFOFULL_SEL_SHIFT];
+
+ /* Set SPDIF state to idle */
+ handle->state = kSPDIF_Idle;
+
+ s_edmaPrivateHandle[instance][1].base = base;
+ s_edmaPrivateHandle[instance][1].handle = handle;
+
+ /* Need to use scatter gather */
+ EDMA_InstallTCDMemory(dmaLeftHandle, STCD_ADDR(handle->leftTcd), SPDIF_XFER_QUEUE_SIZE);
+ EDMA_InstallTCDMemory(dmaRightHandle, STCD_ADDR(handle->rightTcd), SPDIF_XFER_QUEUE_SIZE);
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaRightHandle, SPDIF_RxEDMACallback, &s_edmaPrivateHandle[instance][1]);
+}
+
+/*!
+ * brief Performs a non-blocking SPDIF transfer using DMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * SPDIF_GetTransferStatus to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param xfer Pointer to the DMA transfer structure.
+ * retval kStatus_Success Start a SPDIF eDMA send successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_TxBusy SPDIF is busy sending data.
+ */
+status_t SPDIF_TransferSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ pvoid_to_u32_t destAddr;
+ edma_transfer_config_t config = {0};
+ destAddr.u32 = SPDIF_TxGetLeftDataRegisterAddress(base);
+
+ /* Check if input parameter invalid */
+ if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
+ (handle->spdifQueue[handle->queueUser].rightData != NULL))
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = kSPDIF_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].leftData = xfer->leftData;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
+ handle->nbytes = handle->count * 8U;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, xfer->leftData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_MemoryToPeripheral);
+ (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
+
+ /* Prepare right channel */
+ destAddr.u32 = SPDIF_TxGetRightDataRegisterAddress(base);
+ EDMA_PrepareTransfer(&config, xfer->rightData, 4U, destAddr.pvoid, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_MemoryToPeripheral);
+ (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaLeftHandle);
+ EDMA_StartTransfer(handle->dmaRightHandle);
+
+ /* Enable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, true);
+
+ /* Enable SPDIF Tx clock */
+ SPDIF_TxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Performs a non-blocking SPDIF receive using eDMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * the SPDIF_GetReceiveRemainingBytes to poll the transfer status and check whether the SPDIF transfer is finished.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a SPDIF eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_RxBusy SPDIF is busy receiving data.
+ */
+status_t SPDIF_TransferReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, spdif_edma_transfer_t *xfer)
+{
+ assert(handle != NULL);
+ assert(xfer != NULL);
+
+ pvoid_to_u32_t srcAddr;
+ edma_transfer_config_t config = {0};
+ srcAddr.u32 = SPDIF_RxGetLeftDataRegisterAddress(base);
+
+ /* Check if input parameter invalid */
+ if ((xfer->leftData == NULL) || (xfer->dataSize == 0U) || (xfer->rightData == NULL))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((handle->spdifQueue[handle->queueUser].leftData != NULL) ||
+ (handle->spdifQueue[handle->queueUser].rightData != NULL))
+ {
+ return kStatus_SPDIF_QueueFull;
+ }
+
+ /* Change the state of handle */
+ handle->state = kSPDIF_Busy;
+
+ /* Update the queue state */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].leftData = xfer->leftData;
+ handle->spdifQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->spdifQueue[handle->queueUser].rightData = xfer->rightData;
+ handle->queueUser = (handle->queueUser + 0x01U) % SPDIF_XFER_QUEUE_SIZE;
+
+ /* Store the initially configured eDMA minor byte transfer count into the SPDIF handle */
+ handle->nbytes = handle->count * 8U;
+
+ /* Prepare edma configure */
+ EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->leftData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_PeripheralToMemory);
+ /* Use specific submit function to enable channel link */
+ (void)SPDIF_SubmitTransfer(handle->dmaLeftHandle, &config, handle->dmaRightHandle->channel);
+
+ /* Prepare right channel */
+ srcAddr.u32 = SPDIF_RxGetRightDataRegisterAddress(base);
+ EDMA_PrepareTransfer(&config, srcAddr.pvoid, 4U, xfer->rightData, 4U, (uint32_t)handle->count * 4U, xfer->dataSize,
+ kEDMA_PeripheralToMemory);
+ (void)EDMA_SubmitTransfer(handle->dmaRightHandle, &config);
+
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaLeftHandle);
+ EDMA_StartTransfer(handle->dmaRightHandle);
+
+ /* Enable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, true);
+
+ /* Enable SPDIF Rx clock */
+ SPDIF_RxEnable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a SPDIF transfer using eDMA.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortSendEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaLeftHandle);
+ EDMA_AbortTransfer(handle->dmaRightHandle);
+
+ /* Disable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_TxDMAEnable, false);
+
+ /* Set internal state */
+ (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+
+ /* Set the handle state */
+ handle->state = kSPDIF_Idle;
+}
+
+/*!
+ * brief Aborts a SPDIF receive using eDMA.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ */
+void SPDIF_TransferAbortReceiveEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaLeftHandle);
+ EDMA_AbortTransfer(handle->dmaRightHandle);
+
+ /* Disable DMA enable bit */
+ SPDIF_EnableDMA(base, kSPDIF_RxDMAEnable, false);
+
+ /* Set internal state */
+ (void)memset(handle->spdifQueue, 0, sizeof(handle->spdifQueue));
+ (void)memset(handle->transferSize, 0, sizeof(handle->transferSize));
+ handle->queueUser = 0U;
+ handle->queueDriver = 0U;
+
+ /* Set the handle state */
+ handle->state = kSPDIF_Idle;
+}
+
+/*!
+ * brief Gets byte count sent by SPDIF.
+ *
+ * param base SPDIF base pointer.
+ * param handle SPDIF eDMA handle pointer.
+ * param count Bytes count sent by SPDIF.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetSendCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
+ }
+
+ return status;
+}
+
+/*!
+ * brief Gets byte count received by SPDIF.
+ *
+ * param base SPDIF base pointer
+ * param handle SPDIF eDMA handle pointer.
+ * param count Bytes count received by SPDIF.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t SPDIF_TransferGetReceiveCountEDMA(SPDIF_Type *base, spdif_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ status_t status = kStatus_Success;
+
+ if (handle->state != (uint32_t)kSPDIF_Busy)
+ {
+ status = kStatus_NoTransferInProgress;
+ }
+ else
+ {
+ *count = (handle->transferSize[handle->queueDriver] -
+ (uint32_t)handle->nbytes *
+ EDMA_GetRemainingMajorLoopCount(handle->dmaRightHandle->base, handle->dmaRightHandle->channel));
+ }
+
+ return status;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_src.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_src.c
new file mode 100644
index 0000000000..10af22893a
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_src.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_src.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.src"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+/*!
+ * brief Clear the status flags of SRC.
+ *
+ * param base SRC peripheral base address.
+ * param Mask value of status flags to be cleared, see to #_src_reset_status_flags.
+ */
+void SRC_ClearResetStatusFlags(SRC_Type *base, uint32_t flags)
+{
+ uint32_t tmp32 = base->SRSR;
+
+ if (0U != (SRC_SRSR_TSR_MASK & flags))
+ {
+ tmp32 &= ~SRC_SRSR_TSR_MASK; /* Write 0 to clear. */
+ }
+
+ if (0U != (SRC_SRSR_W1C_BITS_MASK & flags))
+ {
+ tmp32 |= (SRC_SRSR_W1C_BITS_MASK & flags); /* Write 1 to clear. */
+ }
+
+ base->SRSR = tmp32;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_tempmon.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_tempmon.c
new file mode 100644
index 0000000000..1f65d3bc5f
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_tempmon.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2018-2019 NXP
+ * All rights reserved.
+ *
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_tempmon.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.tempmon"
+#endif
+
+/*! @brief TEMPMON calibration data mask. */
+#define TEMPMON_HOTTEMPMASK 0xFFU
+#define TEMPMON_HOTTEMPSHIFT 0x00U
+#define TEMPMON_HOTCOUNTMASK 0xFFF00U
+#define TEMPMON_HOTCOUNTSHIFT 0X08U
+#define TEMPMON_ROOMCOUNTMASK 0xFFF00000U
+#define TEMPMON_ROOMCOUNTSHIFT 0x14U
+
+/*! @brief the room temperature. */
+#define TEMPMON_ROOMTEMP 25.0f
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+static uint32_t s_hotTemp; /*!< The value of TEMPMON_TEMPSENSE0[TEMP_VALUE] at room temperature .*/
+static uint32_t s_hotCount; /*!< The value of TEMPMON_TEMPSENSE0[TEMP_VALUE] at the hot temperature.*/
+static float s_hotT_ROOM; /*!< The value of s_hotTemp minus room temperature(25��).*/
+static uint32_t s_roomC_hotC; /*!< The value of s_roomCount minus s_hotCount.*/
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+/*!
+ * brief Initializes the TEMPMON module.
+ *
+ * param base TEMPMON base pointer
+ * param config Pointer to configuration structure.
+ */
+void TEMPMON_Init(TEMPMON_Type *base, const tempmon_config_t *config)
+{
+ assert(NULL != config);
+
+ uint32_t calibrationData;
+ uint32_t roomCount;
+
+ /* Power on the temperature sensor*/
+ base->TEMPSENSE0 &= ~TEMPMON_TEMPSENSE0_POWER_DOWN_MASK;
+
+ /* Set temperature monitor frequency */
+ base->TEMPSENSE1 = TEMPMON_TEMPSENSE1_MEASURE_FREQ(config->frequency);
+
+ /* ready to read calibration data */
+ calibrationData = OCOTP->ANA1;
+ s_hotTemp = (uint32_t)(calibrationData & TEMPMON_HOTTEMPMASK) >> TEMPMON_HOTTEMPSHIFT;
+ s_hotCount = (uint32_t)(calibrationData & TEMPMON_HOTCOUNTMASK) >> TEMPMON_HOTCOUNTSHIFT;
+ roomCount = (uint32_t)(calibrationData & TEMPMON_ROOMCOUNTMASK) >> TEMPMON_ROOMCOUNTSHIFT;
+
+ s_hotT_ROOM = (float)s_hotTemp - TEMPMON_ROOMTEMP;
+ s_roomC_hotC = roomCount - s_hotCount;
+
+ /* Set alarm temperature */
+ TEMPMON_SetTempAlarm(base, config->highAlarmTemp, kTEMPMON_HighAlarmMode);
+ TEMPMON_SetTempAlarm(base, config->panicAlarmTemp, kTEMPMON_PanicAlarmMode);
+ TEMPMON_SetTempAlarm(base, config->lowAlarmTemp, kTEMPMON_LowAlarmMode);
+}
+
+/*!
+ * brief Deinitializes the TEMPMON module.
+ *
+ * param base TEMPMON base pointer
+ */
+void TEMPMON_Deinit(TEMPMON_Type *base)
+{
+ base->TEMPSENSE0 |= TEMPMON_TEMPSENSE0_POWER_DOWN_MASK;
+}
+
+/*!
+ * brief Gets the default configuration structure.
+ *
+ * This function initializes the TEMPMON configuration structure to a default value. The default
+ * values are:
+ * tempmonConfig->frequency = 0x02U;
+ * tempmonConfig->highAlarmTemp = 44U;
+ * tempmonConfig->panicAlarmTemp = 90U;
+ * tempmonConfig->lowAlarmTemp = 39U;
+ *
+ * param config Pointer to a configuration structure.
+ */
+void TEMPMON_GetDefaultConfig(tempmon_config_t *config)
+{
+ assert(config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ /* Default measure frequency */
+ config->frequency = 0x03U;
+ /* Default high alarm temperature */
+ config->highAlarmTemp = 40U;
+ /* Default panic alarm temperature */
+ config->panicAlarmTemp = 90U;
+ /* Default low alarm temperature */
+ config->lowAlarmTemp = 20U;
+}
+
+/*!
+ * brief Get current temperature with the fused temperature calibration data.
+ *
+ * param base TEMPMON base pointer
+ * return current temperature with degrees Celsius.
+ */
+float TEMPMON_GetCurrentTemperature(TEMPMON_Type *base)
+{
+ /* Check arguments */
+ assert(NULL != base);
+
+ uint32_t nmeas;
+ float tmeas;
+
+ while (0U == (base->TEMPSENSE0 & TEMPMON_TEMPSENSE0_FINISHED_MASK))
+ {
+ }
+
+ /* ready to read temperature code value */
+ nmeas = (base->TEMPSENSE0 & TEMPMON_TEMPSENSE0_TEMP_CNT_MASK) >> TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT;
+
+ /* Calculate temperature */
+ tmeas = (float)s_hotTemp - (((float)nmeas - (float)s_hotCount) * s_hotT_ROOM / (float)s_roomC_hotC);
+
+ return tmeas;
+}
+
+/*!
+ * brief Set the temperature count (raw sensor output) that will generate an alarm interrupt.
+ *
+ * param base TEMPMON base pointer
+ * param tempVal The alarm temperature with degrees Celsius
+ * param alarmMode The alarm mode.
+ */
+void TEMPMON_SetTempAlarm(TEMPMON_Type *base, uint32_t tempVal, tempmon_alarm_mode alarmMode)
+{
+ /* Check arguments */
+ assert(NULL != base);
+
+ uint32_t tempCodeVal;
+ uint32_t tempRegVal;
+
+ /* Calculate alarm temperature code value */
+ tempCodeVal = (uint32_t)(s_hotCount + (s_hotTemp - tempVal) * s_roomC_hotC / (uint32_t)s_hotT_ROOM);
+
+ switch (alarmMode)
+ {
+ case kTEMPMON_HighAlarmMode:
+ /* Clear alarm value and set a new high alarm temperature code value */
+ tempRegVal = base->TEMPSENSE0;
+ tempRegVal =
+ (tempRegVal & ~TEMPMON_TEMPSENSE0_ALARM_VALUE_MASK) | TEMPMON_TEMPSENSE0_ALARM_VALUE(tempCodeVal);
+ base->TEMPSENSE0 = tempRegVal;
+ break;
+
+ case kTEMPMON_PanicAlarmMode:
+ /* Clear panic alarm value and set a new panic alarm temperature code value */
+ tempRegVal = base->TEMPSENSE2;
+ tempRegVal = (tempRegVal & ~TEMPMON_TEMPSENSE2_PANIC_ALARM_VALUE_MASK) |
+ TEMPMON_TEMPSENSE2_PANIC_ALARM_VALUE(tempCodeVal);
+ base->TEMPSENSE2 = tempRegVal;
+ break;
+
+ case kTEMPMON_LowAlarmMode:
+ /* Clear low alarm value and set a new low alarm temperature code value */
+ tempRegVal = base->TEMPSENSE2;
+ tempRegVal = (tempRegVal & ~TEMPMON_TEMPSENSE2_LOW_ALARM_VALUE_MASK) |
+ TEMPMON_TEMPSENSE2_LOW_ALARM_VALUE(tempCodeVal);
+ base->TEMPSENSE2 = tempRegVal;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_trng.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_trng.c
new file mode 100644
index 0000000000..4f4773d9c0
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_trng.c
@@ -0,0 +1,1935 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2017, 2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "fsl_trng.h"
+
+#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && FSL_FEATURE_SOC_TRNG_COUNT
+
+/*******************************************************************************
+ * Definitions
+ *******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.trng"
+#endif
+
+/* Default values for user configuration structure.*/
+#if (defined(KW40Z4_SERIES) || defined(KW41Z4_SERIES) || defined(KW31Z4_SERIES) || defined(KW21Z4_SERIES) || \
+ defined(MCIMX7U5_M4_SERIES) || defined(KW36Z4_SERIES) || defined(KW37A4_SERIES) || defined(KW37Z4_SERIES) || \
+ defined(KW38A4_SERIES) || defined(KW38Z4_SERIES) || defined(KW39A4_SERIES) || defined(KW35Z4_SERIES))
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV kTRNG_RingOscDiv8
+#elif (defined(KV56F24_SERIES) || defined(KV58F24_SERIES) || defined(KL28Z7_SERIES) || defined(KL81Z7_SERIES) || \
+ defined(KL82Z7_SERIES) || defined(K32L2A41A_SERIES))
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV kTRNG_RingOscDiv4
+#elif defined(K81F25615_SERIES)
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV kTRNG_RingOscDiv2
+#else
+/* Default value for the TRNG user configuration structure can be optionally
+ defined by device specific preprocessor macros. */
+#if defined(FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_OSC_DIV) && \
+ (FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_OSC_DIV > 0)
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV (FSL_FEATURE_TRNG_USER_CONFIG_DEFAULT_OSC_DIV_VALUE)
+#else
+#define TRNG_USER_CONFIG_DEFAULT_OSC_DIV kTRNG_RingOscDiv0
+#endif
+#endif
+
+#define TRNG_USER_CONFIG_DEFAULT_LOCK 0
+#define TRNG_USER_CONFIG_DEFAULT_ENTROPY_DELAY 3200
+#define TRNG_USER_CONFIG_DEFAULT_SAMPLE_SIZE 2500
+#define TRNG_USER_CONFIG_DEFAULT_SPARSE_BIT_LIMIT 63
+#define TRNG_USER_CONFIG_DEFAULT_RETRY_COUNT 1
+#define TRNG_USER_CONFIG_DEFAULT_RUN_MAX_LIMIT 34
+
+#define TRNG_USER_CONFIG_DEFAULT_MONOBIT_MAXIMUM 1384
+#define TRNG_USER_CONFIG_DEFAULT_MONOBIT_MINIMUM (TRNG_USER_CONFIG_DEFAULT_MONOBIT_MAXIMUM - 268)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MAXIMUM 405
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MAXIMUM - 178)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MAXIMUM 220
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MAXIMUM - 122)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MAXIMUM 125
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MAXIMUM - 88)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MAXIMUM 75
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MAXIMUM - 64)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MAXIMUM 47
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MAXIMUM - 46)
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MAXIMUM 47
+#define TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MINIMUM (TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MAXIMUM - 46)
+#define TRNG_USER_CONFIG_DEFAULT_POKER_MAXIMUM 26912
+#define TRNG_USER_CONFIG_DEFAULT_POKER_MINIMUM (TRNG_USER_CONFIG_DEFAULT_POKER_MAXIMUM - 2467)
+
+#if defined(FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM) && \
+ (FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM > 0)
+#define TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM (FSL_FEATURE_TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM_VALUE)
+#else
+#define TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM 25600
+#endif
+
+#if defined(FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM) && \
+ (FSL_FEATURE_TRNG_FORCE_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM > 0)
+#define TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM (FSL_FEATURE_TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM_VALUE)
+#else
+#define TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM 1600
+#endif
+
+/*! @brief TRNG work mode */
+typedef enum _trng_work_mode
+{
+ kTRNG_WorkModeRun = 0U, /*!< Run Mode. */
+ kTRNG_WorkModeProgram = 1U /*!< Program Mode. */
+} trng_work_mode_t;
+
+/*! @brief TRNG statistical check type*/
+typedef enum _trng_statistical_check
+{
+ kTRNG_StatisticalCheckMonobit =
+ 1U, /*!< Statistical check of number of ones/zero detected during entropy generation. */
+ kTRNG_StatisticalCheckRunBit1, /*!< Statistical check of number of runs of length 1 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit2, /*!< Statistical check of number of runs of length 2 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit3, /*!< Statistical check of number of runs of length 3 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit4, /*!< Statistical check of number of runs of length 4 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit5, /*!< Statistical check of number of runs of length 5 detected during entropy
+ generation. */
+ kTRNG_StatisticalCheckRunBit6Plus, /*!< Statistical check of number of runs of length 6 or more detected during
+ entropy generation. */
+ kTRNG_StatisticalCheckPoker, /*!< Statistical check of "Poker Test". */
+ kTRNG_StatisticalCheckFrequencyCount /*!< Statistical check of entropy sample frequency count. */
+} trng_statistical_check_t;
+
+/*******************************************************************************
+ * TRNG_SCMISC - RNG Statistical Check Miscellaneous Register
+ ******************************************************************************/
+/*!
+ * @name Register TRNG_SCMISC, field RTY_CT[19:16] (RW)
+ *
+ * RETRY COUNT. If a statistical check fails during the TRNG Entropy Generation,
+ * the RTY_CT value indicates the number of times a retry should occur before
+ * generating an error. This field is writable only if MCTL[PRGM] bit is 1. This
+ * field will read zeroes if MCTL[PRGM] = 0. This field is cleared to 1h by writing
+ * the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCMISC_RTY_CT field. */
+#define TRNG_RD_SCMISC_RTY_CT(base) ((TRNG_SCMISC_REG(base) & TRNG_SCMISC_RTY_CT_MASK) >> TRNG_SCMISC_RTY_CT_SHIFT)
+
+/*! @brief Set the RTY_CT field to a new value. */
+#define TRNG_WR_SCMISC_RTY_CT(base, value) (TRNG_RMW_SCMISC(base, TRNG_SCMISC_RTY_CT_MASK, TRNG_SCMISC_RTY_CT(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCML - RNG Statistical Check Monobit Limit Register
+ ******************************************************************************/
+/*!
+ * @brief TRNG_SCML - RNG Statistical Check Monobit Limit Register (RW)
+ *
+ * Reset value: 0x010C0568U
+ *
+ * The RNG Statistical Check Monobit Limit Register defines the allowable
+ * maximum and minimum number of ones/zero detected during entropy generation. To pass
+ * the test, the number of ones/zeroes generated must be less than the programmed
+ * maximum value, and the number of ones/zeroes generated must be greater than
+ * (maximum - range). If this test fails, the Retry Counter in SCMISC will be
+ * decremented, and a retry will occur if the Retry Count has not reached zero. If
+ * the Retry Count has reached zero, an error will be generated. Note that this
+ * offset (0xBASE_0620) is used as SCML only if MCTL[PRGM] is 1. If MCTL[PRGM] is 0,
+ * this offset is used as SCMC readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCML register
+ */
+/*@{*/
+#define TRNG_SCML_REG(base) ((base)->SCML)
+#define TRNG_RD_SCML(base) (TRNG_SCML_REG(base))
+#define TRNG_WR_SCML(base, value) (TRNG_SCML_REG(base) = (value))
+#define TRNG_RMW_SCML(base, mask, value) (TRNG_WR_SCML(base, (TRNG_RD_SCML(base) & ~(mask)) | (value)))
+/*@}*/
+/*!
+ * @name Register TRNG_SCML, field MONO_MAX[15:0] (RW)
+ *
+ * Monobit Maximum Limit. Defines the maximum allowable count taken during
+ * entropy generation. The number of ones/zeroes detected during entropy generation
+ * must be less than MONO_MAX, else a retry or error will occur. This register is
+ * cleared to 00056Bh (decimal 1387) by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCML_MONO_MAX field. */
+#define TRNG_RD_SCML_MONO_MAX(base) ((TRNG_SCML_REG(base) & TRNG_SCML_MONO_MAX_MASK) >> TRNG_SCML_MONO_MAX_SHIFT)
+
+/*! @brief Set the MONO_MAX field to a new value. */
+#define TRNG_WR_SCML_MONO_MAX(base, value) (TRNG_RMW_SCML(base, TRNG_SCML_MONO_MAX_MASK, TRNG_SCML_MONO_MAX(value)))
+/*@}*/
+/*!
+ * @name Register TRNG_SCML, field MONO_RNG[31:16] (RW)
+ *
+ * Monobit Range. The number of ones/zeroes detected during entropy generation
+ * must be greater than MONO_MAX - MONO_RNG, else a retry or error will occur.
+ * This register is cleared to 000112h (decimal 274) by writing the MCTL[RST_DEF]
+ * bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCML_MONO_RNG field. */
+#define TRNG_RD_SCML_MONO_RNG(base) ((TRNG_SCML_REG(base) & TRNG_SCML_MONO_RNG_MASK) >> TRNG_SCML_MONO_RNG_SHIFT)
+
+/*! @brief Set the MONO_RNG field to a new value. */
+#define TRNG_WR_SCML_MONO_RNG(base, value) (TRNG_RMW_SCML(base, TRNG_SCML_MONO_RNG_MASK, TRNG_SCML_MONO_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR1L - RNG Statistical Check Run Length 1 Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR1L - RNG Statistical Check Run Length 1 Limit Register (RW)
+ *
+ * Reset value: 0x00B20195U
+ *
+ * The RNG Statistical Check Run Length 1 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 1 detected during entropy
+ * generation. To pass the test, the number of runs of length 1 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 1 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_0624) is used as SCR1L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR1C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR1L register
+ */
+/*@{*/
+#define TRNG_SCR1L_REG(base) ((base)->SCR1L)
+#define TRNG_RD_SCR1L(base) (TRNG_SCR1L_REG(base))
+#define TRNG_WR_SCR1L(base, value) (TRNG_SCR1L_REG(base) = (value))
+#define TRNG_RMW_SCR1L(base, mask, value) (TRNG_WR_SCR1L(base, (TRNG_RD_SCR1L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR1L, field RUN1_MAX[14:0] (RW)
+ *
+ * Run Length 1 Maximum Limit. Defines the maximum allowable runs of length 1
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 1 detected during entropy generation must be less than RUN1_MAX, else a
+ * retry or error will occur. This register is cleared to 01E5h (decimal 485) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR1L_RUN1_MAX field. */
+#define TRNG_RD_SCR1L_RUN1_MAX(base) ((TRNG_SCR1L_REG(base) & TRNG_SCR1L_RUN1_MAX_MASK) >> TRNG_SCR1L_RUN1_MAX_SHIFT)
+
+/*! @brief Set the RUN1_MAX field to a new value. */
+#define TRNG_WR_SCR1L_RUN1_MAX(base, value) (TRNG_RMW_SCR1L(base, TRNG_SCR1L_RUN1_MAX_MASK, TRNG_SCR1L_RUN1_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR1L, field RUN1_RNG[30:16] (RW)
+ *
+ * Run Length 1 Range. The number of runs of length 1 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN1_MAX - RUN1_RNG, else a
+ * retry or error will occur. This register is cleared to 0102h (decimal 258) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR1L_RUN1_RNG field. */
+#define TRNG_RD_SCR1L_RUN1_RNG(base) ((TRNG_SCR1L_REG(base) & TRNG_SCR1L_RUN1_RNG_MASK) >> TRNG_SCR1L_RUN1_RNG_SHIFT)
+
+/*! @brief Set the RUN1_RNG field to a new value. */
+#define TRNG_WR_SCR1L_RUN1_RNG(base, value) (TRNG_RMW_SCR1L(base, TRNG_SCR1L_RUN1_RNG_MASK, TRNG_SCR1L_RUN1_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR2L - RNG Statistical Check Run Length 2 Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR2L - RNG Statistical Check Run Length 2 Limit Register (RW)
+ *
+ * Reset value: 0x007A00DCU
+ *
+ * The RNG Statistical Check Run Length 2 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 2 detected during entropy
+ * generation. To pass the test, the number of runs of length 2 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 2 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_0628) is used as SCR2L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR2C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR2L register
+ */
+/*@{*/
+#define TRNG_SCR2L_REG(base) ((base)->SCR2L)
+#define TRNG_RD_SCR2L(base) (TRNG_SCR2L_REG(base))
+#define TRNG_WR_SCR2L(base, value) (TRNG_SCR2L_REG(base) = (value))
+#define TRNG_RMW_SCR2L(base, mask, value) (TRNG_WR_SCR2L(base, (TRNG_RD_SCR2L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR2L bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR2L, field RUN2_MAX[13:0] (RW)
+ *
+ * Run Length 2 Maximum Limit. Defines the maximum allowable runs of length 2
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 2 detected during entropy generation must be less than RUN2_MAX, else a
+ * retry or error will occur. This register is cleared to 00DCh (decimal 220) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR2L_RUN2_MAX field. */
+#define TRNG_RD_SCR2L_RUN2_MAX(base) ((TRNG_SCR2L_REG(base) & TRNG_SCR2L_RUN2_MAX_MASK) >> TRNG_SCR2L_RUN2_MAX_SHIFT)
+
+/*! @brief Set the RUN2_MAX field to a new value. */
+#define TRNG_WR_SCR2L_RUN2_MAX(base, value) (TRNG_RMW_SCR2L(base, TRNG_SCR2L_RUN2_MAX_MASK, TRNG_SCR2L_RUN2_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR2L, field RUN2_RNG[29:16] (RW)
+ *
+ * Run Length 2 Range. The number of runs of length 2 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN2_MAX - RUN2_RNG, else a
+ * retry or error will occur. This register is cleared to 007Ah (decimal 122) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR2L_RUN2_RNG field. */
+#define TRNG_RD_SCR2L_RUN2_RNG(base) ((TRNG_SCR2L_REG(base) & TRNG_SCR2L_RUN2_RNG_MASK) >> TRNG_SCR2L_RUN2_RNG_SHIFT)
+
+/*! @brief Set the RUN2_RNG field to a new value. */
+#define TRNG_WR_SCR2L_RUN2_RNG(base, value) (TRNG_RMW_SCR2L(base, TRNG_SCR2L_RUN2_RNG_MASK, TRNG_SCR2L_RUN2_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR3L - RNG Statistical Check Run Length 3 Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR3L - RNG Statistical Check Run Length 3 Limit Register (RW)
+ *
+ * Reset value: 0x0058007DU
+ *
+ * The RNG Statistical Check Run Length 3 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 3 detected during entropy
+ * generation. To pass the test, the number of runs of length 3 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 3 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_062C) is used as SCR3L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR3C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR3L register
+ */
+/*@{*/
+#define TRNG_SCR3L_REG(base) ((base)->SCR3L)
+#define TRNG_RD_SCR3L(base) (TRNG_SCR3L_REG(base))
+#define TRNG_WR_SCR3L(base, value) (TRNG_SCR3L_REG(base) = (value))
+#define TRNG_RMW_SCR3L(base, mask, value) (TRNG_WR_SCR3L(base, (TRNG_RD_SCR3L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR3L bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR3L, field RUN3_MAX[12:0] (RW)
+ *
+ * Run Length 3 Maximum Limit. Defines the maximum allowable runs of length 3
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 3 detected during entropy generation must be less than RUN3_MAX, else a
+ * retry or error will occur. This register is cleared to 007Dh (decimal 125) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR3L_RUN3_MAX field. */
+#define TRNG_RD_SCR3L_RUN3_MAX(base) ((TRNG_SCR3L_REG(base) & TRNG_SCR3L_RUN3_MAX_MASK) >> TRNG_SCR3L_RUN3_MAX_SHIFT)
+
+/*! @brief Set the RUN3_MAX field to a new value. */
+#define TRNG_WR_SCR3L_RUN3_MAX(base, value) (TRNG_RMW_SCR3L(base, TRNG_SCR3L_RUN3_MAX_MASK, TRNG_SCR3L_RUN3_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR3L, field RUN3_RNG[28:16] (RW)
+ *
+ * Run Length 3 Range. The number of runs of length 3 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN3_MAX - RUN3_RNG, else a
+ * retry or error will occur. This register is cleared to 0058h (decimal 88) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR3L_RUN3_RNG field. */
+#define TRNG_RD_SCR3L_RUN3_RNG(base) ((TRNG_SCR3L_REG(base) & TRNG_SCR3L_RUN3_RNG_MASK) >> TRNG_SCR3L_RUN3_RNG_SHIFT)
+
+/*! @brief Set the RUN3_RNG field to a new value. */
+#define TRNG_WR_SCR3L_RUN3_RNG(base, value) (TRNG_RMW_SCR3L(base, TRNG_SCR3L_RUN3_RNG_MASK, TRNG_SCR3L_RUN3_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR4L - RNG Statistical Check Run Length 4 Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR4L - RNG Statistical Check Run Length 4 Limit Register (RW)
+ *
+ * Reset value: 0x0040004BU
+ *
+ * The RNG Statistical Check Run Length 4 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 4 detected during entropy
+ * generation. To pass the test, the number of runs of length 4 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 4 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_0630) is used as SCR4L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR4C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR4L register
+ */
+/*@{*/
+#define TRNG_SCR4L_REG(base) ((base)->SCR4L)
+#define TRNG_RD_SCR4L(base) (TRNG_SCR4L_REG(base))
+#define TRNG_WR_SCR4L(base, value) (TRNG_SCR4L_REG(base) = (value))
+#define TRNG_RMW_SCR4L(base, mask, value) (TRNG_WR_SCR4L(base, (TRNG_RD_SCR4L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR4L bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR4L, field RUN4_MAX[11:0] (RW)
+ *
+ * Run Length 4 Maximum Limit. Defines the maximum allowable runs of length 4
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 4 detected during entropy generation must be less than RUN4_MAX, else a
+ * retry or error will occur. This register is cleared to 004Bh (decimal 75) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR4L_RUN4_MAX field. */
+#define TRNG_RD_SCR4L_RUN4_MAX(base) ((TRNG_SCR4L_REG(base) & TRNG_SCR4L_RUN4_MAX_MASK) >> TRNG_SCR4L_RUN4_MAX_SHIFT)
+
+/*! @brief Set the RUN4_MAX field to a new value. */
+#define TRNG_WR_SCR4L_RUN4_MAX(base, value) (TRNG_RMW_SCR4L(base, TRNG_SCR4L_RUN4_MAX_MASK, TRNG_SCR4L_RUN4_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR4L, field RUN4_RNG[27:16] (RW)
+ *
+ * Run Length 4 Range. The number of runs of length 4 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN4_MAX - RUN4_RNG, else a
+ * retry or error will occur. This register is cleared to 0040h (decimal 64) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR4L_RUN4_RNG field. */
+#define TRNG_RD_SCR4L_RUN4_RNG(base) ((TRNG_SCR4L_REG(base) & TRNG_SCR4L_RUN4_RNG_MASK) >> TRNG_SCR4L_RUN4_RNG_SHIFT)
+
+/*! @brief Set the RUN4_RNG field to a new value. */
+#define TRNG_WR_SCR4L_RUN4_RNG(base, value) (TRNG_RMW_SCR4L(base, TRNG_SCR4L_RUN4_RNG_MASK, TRNG_SCR4L_RUN4_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR5L - RNG Statistical Check Run Length 5 Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR5L - RNG Statistical Check Run Length 5 Limit Register (RW)
+ *
+ * Reset value: 0x002E002FU
+ *
+ * The RNG Statistical Check Run Length 5 Limit Register defines the allowable
+ * maximum and minimum number of runs of length 5 detected during entropy
+ * generation. To pass the test, the number of runs of length 5 (for samples of both 0
+ * and 1) must be less than the programmed maximum value, and the number of runs of
+ * length 5 must be greater than (maximum - range). If this test fails, the
+ * Retry Counter in SCMISC will be decremented, and a retry will occur if the Retry
+ * Count has not reached zero. If the Retry Count has reached zero, an error will
+ * be generated. Note that this address (0xBASE_0634) is used as SCR5L only if
+ * MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this address is used as SCR5C readback
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR5L register
+ */
+/*@{*/
+#define TRNG_SCR5L_REG(base) ((base)->SCR5L)
+#define TRNG_RD_SCR5L(base) (TRNG_SCR5L_REG(base))
+#define TRNG_WR_SCR5L(base, value) (TRNG_SCR5L_REG(base) = (value))
+#define TRNG_RMW_SCR5L(base, mask, value) (TRNG_WR_SCR5L(base, (TRNG_RD_SCR5L(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR5L bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR5L, field RUN5_MAX[10:0] (RW)
+ *
+ * Run Length 5 Maximum Limit. Defines the maximum allowable runs of length 5
+ * (for both 0 and 1) detected during entropy generation. The number of runs of
+ * length 5 detected during entropy generation must be less than RUN5_MAX, else a
+ * retry or error will occur. This register is cleared to 002Fh (decimal 47) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR5L_RUN5_MAX field. */
+#define TRNG_RD_SCR5L_RUN5_MAX(base) ((TRNG_SCR5L_REG(base) & TRNG_SCR5L_RUN5_MAX_MASK) >> TRNG_SCR5L_RUN5_MAX_SHIFT)
+
+/*! @brief Set the RUN5_MAX field to a new value. */
+#define TRNG_WR_SCR5L_RUN5_MAX(base, value) (TRNG_RMW_SCR5L(base, TRNG_SCR5L_RUN5_MAX_MASK, TRNG_SCR5L_RUN5_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR5L, field RUN5_RNG[26:16] (RW)
+ *
+ * Run Length 5 Range. The number of runs of length 5 (for both 0 and 1)
+ * detected during entropy generation must be greater than RUN5_MAX - RUN5_RNG, else a
+ * retry or error will occur. This register is cleared to 002Eh (decimal 46) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR5L_RUN5_RNG field. */
+#define TRNG_RD_SCR5L_RUN5_RNG(base) ((TRNG_SCR5L_REG(base) & TRNG_SCR5L_RUN5_RNG_MASK) >> TRNG_SCR5L_RUN5_RNG_SHIFT)
+
+/*! @brief Set the RUN5_RNG field to a new value. */
+#define TRNG_WR_SCR5L_RUN5_RNG(base, value) (TRNG_RMW_SCR5L(base, TRNG_SCR5L_RUN5_RNG_MASK, TRNG_SCR5L_RUN5_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCR6PL - RNG Statistical Check Run Length 6+ Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCR6PL - RNG Statistical Check Run Length 6+ Limit Register (RW)
+ *
+ * Reset value: 0x002E002FU
+ *
+ * The RNG Statistical Check Run Length 6+ Limit Register defines the allowable
+ * maximum and minimum number of runs of length 6 or more detected during entropy
+ * generation. To pass the test, the number of runs of length 6 or more (for
+ * samples of both 0 and 1) must be less than the programmed maximum value, and the
+ * number of runs of length 6 or more must be greater than (maximum - range). If
+ * this test fails, the Retry Counter in SCMISC will be decremented, and a retry
+ * will occur if the Retry Count has not reached zero. If the Retry Count has
+ * reached zero, an error will be generated. Note that this offset (0xBASE_0638) is
+ * used as SCR6PL only if MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this offset is
+ * used as SCR6PC readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCR6PL register
+ */
+/*@{*/
+#define TRNG_SCR6PL_REG(base) ((base)->SCR6PL)
+#define TRNG_RD_SCR6PL(base) (TRNG_SCR6PL_REG(base))
+#define TRNG_WR_SCR6PL(base, value) (TRNG_SCR6PL_REG(base) = (value))
+#define TRNG_RMW_SCR6PL(base, mask, value) (TRNG_WR_SCR6PL(base, (TRNG_RD_SCR6PL(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCR6PL bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCR6PL, field RUN6P_MAX[10:0] (RW)
+ *
+ * Run Length 6+ Maximum Limit. Defines the maximum allowable runs of length 6
+ * or more (for both 0 and 1) detected during entropy generation. The number of
+ * runs of length 6 or more detected during entropy generation must be less than
+ * RUN6P_MAX, else a retry or error will occur. This register is cleared to 002Fh
+ * (decimal 47) by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR6PL_RUN6P_MAX field. */
+#define TRNG_RD_SCR6PL_RUN6P_MAX(base) \
+ ((TRNG_SCR6PL_REG(base) & TRNG_SCR6PL_RUN6P_MAX_MASK) >> TRNG_SCR6PL_RUN6P_MAX_SHIFT)
+
+/*! @brief Set the RUN6P_MAX field to a new value. */
+#define TRNG_WR_SCR6PL_RUN6P_MAX(base, value) \
+ (TRNG_RMW_SCR6PL(base, TRNG_SCR6PL_RUN6P_MAX_MASK, TRNG_SCR6PL_RUN6P_MAX(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SCR6PL, field RUN6P_RNG[26:16] (RW)
+ *
+ * Run Length 6+ Range. The number of runs of length 6 or more (for both 0 and
+ * 1) detected during entropy generation must be greater than RUN6P_MAX -
+ * RUN6P_RNG, else a retry or error will occur. This register is cleared to 002Eh
+ * (decimal 46) by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCR6PL_RUN6P_RNG field. */
+#define TRNG_RD_SCR6PL_RUN6P_RNG(base) \
+ ((TRNG_SCR6PL_REG(base) & TRNG_SCR6PL_RUN6P_RNG_MASK) >> TRNG_SCR6PL_RUN6P_RNG_SHIFT)
+
+/*! @brief Set the RUN6P_RNG field to a new value. */
+#define TRNG_WR_SCR6PL_RUN6P_RNG(base, value) \
+ (TRNG_RMW_SCR6PL(base, TRNG_SCR6PL_RUN6P_RNG_MASK, TRNG_SCR6PL_RUN6P_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_PKRMAX - RNG Poker Maximum Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_PKRMAX - RNG Poker Maximum Limit Register (RW)
+ *
+ * Reset value: 0x00006920U
+ *
+ * The RNG Poker Maximum Limit Register defines Maximum Limit allowable during
+ * the TRNG Statistical Check Poker Test. Note that this offset (0xBASE_060C) is
+ * used as PKRMAX only if MCTL[PRGM] is 1. If MCTL[PRGM] is 0, this offset is used
+ * as the PKRSQ readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_PKRMAX register
+ */
+/*@{*/
+#define TRNG_PKRMAX_REG(base) ((base)->PKRMAX)
+#define TRNG_RD_PKRMAX(base) (TRNG_PKRMAX_REG(base))
+#define TRNG_WR_PKRMAX(base, value) (TRNG_PKRMAX_REG(base) = (value))
+#define TRNG_RMW_PKRMAX(base, mask, value) (TRNG_WR_PKRMAX(base, (TRNG_RD_PKRMAX(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_PKRMAX bitfields
+ */
+
+/*!
+ * @name Register TRNG_PKRMAX, field PKR_MAX[23:0] (RW)
+ *
+ * Poker Maximum Limit. During the TRNG Statistical Checks, a "Poker Test" is
+ * run which requires a maximum and minimum limit. The maximum allowable result is
+ * programmed in the PKRMAX[PKR_MAX] register. This field is writable only if
+ * MCTL[PRGM] bit is 1. This register is cleared to 006920h (decimal 26912) by
+ * writing the MCTL[RST_DEF] bit to 1. Note that the PKRMAX and PKRRNG registers
+ * combined are used to define the minimum allowable Poker result, which is PKR_MAX -
+ * PKR_RNG + 1. Note that if MCTL[PRGM] bit is 0, this register address is used
+ * to read the Poker Test Square Calculation result in register PKRSQ, as defined
+ * in the following section.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_PKRMAX_PKR_MAX field. */
+#define TRNG_RD_PKRMAX_PKR_MAX(base) ((TRNG_PKRMAX_REG(base) & TRNG_PKRMAX_PKR_MAX_MASK) >> TRNG_PKRMAX_PKR_MAX_SHIFT)
+
+/*! @brief Set the PKR_MAX field to a new value. */
+#define TRNG_WR_PKRMAX_PKR_MAX(base, value) \
+ (TRNG_RMW_PKRMAX(base, TRNG_PKRMAX_PKR_MAX_MASK, TRNG_PKRMAX_PKR_MAX(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_PKRRNG - RNG Poker Range Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_PKRRNG - RNG Poker Range Register (RW)
+ *
+ * Reset value: 0x000009A3U
+ *
+ * The RNG Poker Range Register defines the difference between the TRNG Poker
+ * Maximum Limit and the minimum limit. These limits are used during the TRNG
+ * Statistical Check Poker Test.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_PKRRNG register
+ */
+/*@{*/
+#define TRNG_PKRRNG_REG(base) ((base)->PKRRNG)
+#define TRNG_RD_PKRRNG(base) (TRNG_PKRRNG_REG(base))
+#define TRNG_WR_PKRRNG(base, value) (TRNG_PKRRNG_REG(base) = (value))
+#define TRNG_RMW_PKRRNG(base, mask, value) (TRNG_WR_PKRRNG(base, (TRNG_RD_PKRRNG(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_PKRRNG bitfields
+ */
+
+/*!
+ * @name Register TRNG_PKRRNG, field PKR_RNG[15:0] (RW)
+ *
+ * Poker Range. During the TRNG Statistical Checks, a "Poker Test" is run which
+ * requires a maximum and minimum limit. The maximum is programmed in the
+ * RTPKRMAX[PKR_MAX] register, and the minimum is derived by subtracting the PKR_RNG
+ * value from the programmed maximum value. This field is writable only if
+ * MCTL[PRGM] bit is 1. This field will read zeroes if MCTL[PRGM] = 0. This field is
+ * cleared to 09A3h (decimal 2467) by writing the MCTL[RST_DEF] bit to 1. Note that
+ * the minimum allowable Poker result is PKR_MAX - PKR_RNG + 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_PKRRNG_PKR_RNG field. */
+#define TRNG_RD_PKRRNG_PKR_RNG(base) ((TRNG_PKRRNG_REG(base) & TRNG_PKRRNG_PKR_RNG_MASK) >> TRNG_PKRRNG_PKR_RNG_SHIFT)
+
+/*! @brief Set the PKR_RNG field to a new value. */
+#define TRNG_WR_PKRRNG_PKR_RNG(base, value) \
+ (TRNG_RMW_PKRRNG(base, TRNG_PKRRNG_PKR_RNG_MASK, TRNG_PKRRNG_PKR_RNG(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_FRQMAX - RNG Frequency Count Maximum Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_FRQMAX - RNG Frequency Count Maximum Limit Register (RW)
+ *
+ * Reset value: 0x00006400U
+ *
+ * The RNG Frequency Count Maximum Limit Register defines the maximum allowable
+ * count taken by the Entropy sample counter during each Entropy sample. During
+ * any sample period, if the count is greater than this programmed maximum, a
+ * Frequency Count Fail is flagged in MCTL[FCT_FAIL] and an error is generated. Note
+ * that this address (061C) is used as FRQMAX only if MCTL[PRGM] is 1. If
+ * MCTL[PRGM] is 0, this address is used as FRQCNT readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_FRQMAX register
+ */
+/*@{*/
+#define TRNG_FRQMAX_REG(base) ((base)->FRQMAX)
+#define TRNG_RD_FRQMAX(base) (TRNG_FRQMAX_REG(base))
+#define TRNG_WR_FRQMAX(base, value) (TRNG_FRQMAX_REG(base) = (value))
+#define TRNG_RMW_FRQMAX(base, mask, value) (TRNG_WR_FRQMAX(base, (TRNG_RD_FRQMAX(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_FRQMAX bitfields
+ */
+
+/*!
+ * @name Register TRNG_FRQMAX, field FRQ_MAX[21:0] (RW)
+ *
+ * Frequency Counter Maximum Limit. Defines the maximum allowable count taken
+ * during each entropy sample. This field is writable only if MCTL[PRGM] bit is 1.
+ * This register is cleared to 000640h by writing the MCTL[RST_DEF] bit to 1.
+ * Note that if MCTL[PRGM] bit is 0, this register address is used to read the
+ * Frequency Count result in register FRQCNT, as defined in the following section.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_FRQMAX_FRQ_MAX field. */
+#define TRNG_RD_FRQMAX_FRQ_MAX(base) ((TRNG_FRQMAX_REG(base) & TRNG_FRQMAX_FRQ_MAX_MASK) >> TRNG_FRQMAX_FRQ_MAX_SHIFT)
+
+/*! @brief Set the FRQ_MAX field to a new value. */
+#define TRNG_WR_FRQMAX_FRQ_MAX(base, value) \
+ (TRNG_RMW_FRQMAX(base, TRNG_FRQMAX_FRQ_MAX_MASK, TRNG_FRQMAX_FRQ_MAX(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_FRQMIN - RNG Frequency Count Minimum Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_FRQMIN - RNG Frequency Count Minimum Limit Register (RW)
+ *
+ * Reset value: 0x00000640U
+ *
+ * The RNG Frequency Count Minimum Limit Register defines the minimum allowable
+ * count taken by the Entropy sample counter during each Entropy sample. During
+ * any sample period, if the count is less than this programmed minimum, a
+ * Frequency Count Fail is flagged in MCTL[FCT_FAIL] and an error is generated.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_FRQMIN register
+ */
+/*@{*/
+#define TRNG_FRQMIN_REG(base) ((base)->FRQMIN)
+#define TRNG_RD_FRQMIN(base) (TRNG_FRQMIN_REG(base))
+#define TRNG_WR_FRQMIN(base, value) (TRNG_FRQMIN_REG(base) = (value))
+#define TRNG_RMW_FRQMIN(base, mask, value) (TRNG_WR_FRQMIN(base, (TRNG_RD_FRQMIN(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_FRQMIN bitfields
+ */
+
+/*!
+ * @name Register TRNG_FRQMIN, field FRQ_MIN[21:0] (RW)
+ *
+ * Frequency Count Minimum Limit. Defines the minimum allowable count taken
+ * during each entropy sample. This field is writable only if MCTL[PRGM] bit is 1.
+ * This field will read zeroes if MCTL[PRGM] = 0. This field is cleared to 0000h64
+ * by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_FRQMIN_FRQ_MIN field. */
+#define TRNG_RD_FRQMIN_FRQ_MIN(base) ((TRNG_FRQMIN_REG(base) & TRNG_FRQMIN_FRQ_MIN_MASK) >> TRNG_FRQMIN_FRQ_MIN_SHIFT)
+
+/*! @brief Set the FRQ_MIN field to a new value. */
+#define TRNG_WR_FRQMIN_FRQ_MIN(base, value) \
+ (TRNG_RMW_FRQMIN(base, TRNG_FRQMIN_FRQ_MIN_MASK, TRNG_FRQMIN_FRQ_MIN(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_MCTL - RNG Miscellaneous Control Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_MCTL - RNG Miscellaneous Control Register (RW)
+ *
+ * Reset value: 0x00012001U
+ *
+ * This register is intended to be used for programming, configuring and testing
+ * the RNG. It is the main register to read/write, in order to enable Entropy
+ * generation, to stop entropy generation and to block access to entropy registers.
+ * This is done via the special TRNG_ACC and PRGM bits below. The RNG
+ * Miscellaneous Control Register is a read/write register used to control the RNG's True
+ * Random Number Generator (TRNG) access, operation and test. Note that in many
+ * cases two RNG registers share the same address, and a particular register at the
+ * shared address is selected based upon the value in the PRGM field of the MCTL
+ * register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_MCTL register
+ */
+/*@{*/
+#define TRNG_MCTL_REG(base) ((base)->MCTL)
+#define TRNG_RD_MCTL(base) (TRNG_MCTL_REG(base))
+#define TRNG_WR_MCTL(base, value) (TRNG_MCTL_REG(base) = (value))
+#define TRNG_RMW_MCTL(base, mask, value) (TRNG_WR_MCTL(base, (TRNG_RD_MCTL(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field FOR_SCLK[7] (RW)
+ *
+ * Force System Clock. If set, the system clock is used to operate the TRNG,
+ * instead of the ring oscillator. This is for test use only, and indeterminate
+ * results may occur. This bit is writable only if PRGM bit is 1, or PRGM bit is
+ * being written to 1 simultaneously to writing this bit. This bit is cleared by
+ * writing the RST_DEF bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_FOR_SCLK field. */
+#define TRNG_RD_MCTL_FOR_SCLK(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_FOR_SCLK_MASK) >> TRNG_MCTL_FOR_SCLK_SHIFT)
+
+/*! @brief Set the FOR_SCLK field to a new value. */
+#define TRNG_WR_MCTL_FOR_SCLK(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_FOR_SCLK_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_FOR_SCLK(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field OSC_DIV[3:2] (RW)
+ *
+ * Oscillator Divide. Determines the amount of dividing done to the ring
+ * oscillator before it is used by the TRNG.This field is writable only if PRGM bit is
+ * 1, or PRGM bit is being written to 1 simultaneously to writing this field. This
+ * field is cleared to 00 by writing the RST_DEF bit to 1.
+ *
+ * Values:
+ * - 0b00 - use ring oscillator with no divide
+ * - 0b01 - use ring oscillator divided-by-2
+ * - 0b10 - use ring oscillator divided-by-4
+ * - 0b11 - use ring oscillator divided-by-8
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_OSC_DIV field. */
+#define TRNG_RD_MCTL_OSC_DIV(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_OSC_DIV_MASK) >> TRNG_MCTL_OSC_DIV_SHIFT)
+
+/*! @brief Set the OSC_DIV field to a new value. */
+#define TRNG_WR_MCTL_OSC_DIV(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_OSC_DIV_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_OSC_DIV(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field SAMP_MODE[1:0] (RW)
+ *
+ * Sample Mode. Determines the method of sampling the ring oscillator while
+ * generating the Entropy value:This field is writable only if PRGM bit is 1, or PRGM
+ * bit is being written to 1 simultaneously with writing this field. This field
+ * is cleared to 01 by writing the RST_DEF bit to 1.
+ *
+ * Values:
+ * - 0b00 - use Von Neumann data into both Entropy shifter and Statistical
+ * Checker
+ * - 0b01 - use raw data into both Entropy shifter and Statistical Checker
+ * - 0b10 - use Von Neumann data into Entropy shifter. Use raw data into
+ * Statistical Checker
+ * - 0b11 - reserved.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_SAMP_MODE field. */
+#define TRNG_RD_MCTL_SAMP_MODE(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_SAMP_MODE_MASK) >> TRNG_MCTL_SAMP_MODE_SHIFT)
+
+/*! @brief Set the SAMP_MODE field to a new value. */
+#define TRNG_WR_MCTL_SAMP_MODE(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_SAMP_MODE_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_SAMP_MODE(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field PRGM[16] (RW)
+ *
+ * Programming Mode Select. When this bit is 1, the TRNG is in Program Mode,
+ * otherwise it is in Run Mode. No Entropy value will be generated while the TRNG is
+ * in Program Mode. Note that different RNG registers are accessible at the same
+ * address depending on whether PRGM is set to 1 or 0. This is noted in the RNG
+ * register descriptions.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_PRGM field. */
+#define TRNG_RD_MCTL_PRGM(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_PRGM_MASK) >> TRNG_MCTL_PRGM_SHIFT)
+
+/*! @brief Set the PRGM field to a new value. */
+#define TRNG_WR_MCTL_PRGM(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_PRGM_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_PRGM(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field RST_DEF[6] (WO)
+ *
+ * Reset Defaults. Writing a 1 to this bit clears various TRNG registers, and
+ * bits within registers, to their default state. This bit is writable only if PRGM
+ * bit is 1, or PRGM bit is being written to 1 simultaneously to writing this
+ * bit. Reading this bit always produces a 0.
+ */
+/*@{*/
+/*! @brief Set the RST_DEF field to a new value. */
+#define TRNG_WR_MCTL_RST_DEF(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_RST_DEF_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_RST_DEF(value)))
+/*@}*/
+
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC) && (FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC > 0))
+/*!
+ * @name Register TRNG_MCTL, field TRNG_ACC[5] (RW)
+ *
+ * TRNG Access Mode. If this bit is set to 1, the TRNG will generate an Entropy
+ * value that can be read via the ENT0-ENT15 registers. The Entropy value may be
+ * read once the ENT VAL bit is asserted. Also see ENTa register descriptions
+ * (For a = 0 to 15).
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_TRNG_ACC field. */
+#define TRNG_RD_MCTL_TRNG_ACC(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_TRNG_ACC_MASK) >> TRNG_MCTL_TRNG_ACC_SHIFT)
+
+/*! @brief Set the TRNG_ACC field to a new value. */
+#define TRNG_WR_MCTL_TRNG_ACC(base, value) \
+ (TRNG_RMW_MCTL(base, (TRNG_MCTL_TRNG_ACC_MASK | TRNG_MCTL_ERR_MASK), TRNG_MCTL_TRNG_ACC(value)))
+/*@}*/
+#endif
+
+/*!
+ * @name Register TRNG_MCTL, field TSTOP_OK[13] (RO)
+ *
+ * TRNG_OK_TO_STOP. Software should check that this bit is a 1 before
+ * transitioning RNG to low power mode (RNG clock stopped). RNG turns on the TRNG
+ * free-running ring oscillator whenever new entropy is being generated and turns off the
+ * ring oscillator when entropy generation is complete. If the RNG clock is
+ * stopped while the TRNG ring oscillator is running, the oscillator will continue
+ * running even though the RNG clock is stopped. TSTOP_OK is asserted when the TRNG
+ * ring oscillator is not running. and therefore it is ok to stop the RNG clock.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_TSTOP_OK field. */
+#define TRNG_RD_MCTL_TSTOP_OK(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_TSTOP_OK_MASK) >> TRNG_MCTL_TSTOP_OK_SHIFT)
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field ENT_VAL[10] (RO)
+ *
+ * Read only: Entropy Valid. Will assert only if TRNG ACC bit is set, and then
+ * after an entropy value is generated. Will be cleared when ENT15 is read. (ENT0
+ * through ENT14 should be read before reading ENT15).
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_ENT_VAL field. */
+#define TRNG_RD_MCTL_ENT_VAL(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_ENT_VAL_MASK) >> TRNG_MCTL_ENT_VAL_SHIFT)
+/*@}*/
+
+/*!
+ * @name Register TRNG_MCTL, field ERR[12] (W1C)
+ *
+ * Read: Error status. 1 = error detected. 0 = no error.Write: Write 1 to clear
+ * errors. Writing 0 has no effect.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_MCTL_ERR field. */
+#define TRNG_RD_MCTL_ERR(base) ((TRNG_MCTL_REG(base) & TRNG_MCTL_ERR_MASK) >> TRNG_MCTL_ERR_SHIFT)
+
+/*! @brief Set the ERR field to a new value. */
+#define TRNG_WR_MCTL_ERR(base, value) (TRNG_RMW_MCTL(base, TRNG_MCTL_ERR_MASK, TRNG_MCTL_ERR(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SDCTL - RNG Seed Control Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SDCTL - RNG Seed Control Register (RW)
+ *
+ * Reset value: 0x0C8009C4U
+ *
+ * The RNG Seed Control Register contains two fields. One field defines the
+ * length (in system clocks) of each Entropy sample (ENT_DLY), and the other field
+ * indicates the number of samples that will taken during each TRNG Entropy
+ * generation (SAMP_SIZE).
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SDCTL register
+ */
+/*@{*/
+#define TRNG_SDCTL_REG(base) ((base)->SDCTL)
+#define TRNG_RD_SDCTL(base) (TRNG_SDCTL_REG(base))
+#define TRNG_WR_SDCTL(base, value) (TRNG_SDCTL_REG(base) = (value))
+#define TRNG_RMW_SDCTL(base, mask, value) (TRNG_WR_SDCTL(base, (TRNG_RD_SDCTL(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SDCTL bitfields
+ */
+
+/*!
+ * @name Register TRNG_SDCTL, field SAMP_SIZE[15:0] (RW)
+ *
+ * Sample Size. Defines the total number of Entropy samples that will be taken
+ * during Entropy generation. This field is writable only if MCTL[PRGM] bit is 1.
+ * This field will read zeroes if MCTL[PRGM] = 0. This field is cleared to 09C4h
+ * (decimal 2500) by writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SDCTL_SAMP_SIZE field. */
+#define TRNG_RD_SDCTL_SAMP_SIZE(base) ((TRNG_SDCTL_REG(base) & TRNG_SDCTL_SAMP_SIZE_MASK) >> TRNG_SDCTL_SAMP_SIZE_SHIFT)
+
+/*! @brief Set the SAMP_SIZE field to a new value. */
+#define TRNG_WR_SDCTL_SAMP_SIZE(base, value) \
+ (TRNG_RMW_SDCTL(base, TRNG_SDCTL_SAMP_SIZE_MASK, TRNG_SDCTL_SAMP_SIZE(value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SDCTL, field ENT_DLY[31:16] (RW)
+ *
+ * Entropy Delay. Defines the length (in system clocks) of each Entropy sample
+ * taken. This field is writable only if MCTL[PRGM] bit is 1. This field will read
+ * zeroes if MCTL[PRGM] = 0. This field is cleared to 0C80h (decimal 3200) by
+ * writing the MCTL[RST_DEF] bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SDCTL_ENT_DLY field. */
+#define TRNG_RD_SDCTL_ENT_DLY(base) ((TRNG_SDCTL_REG(base) & TRNG_SDCTL_ENT_DLY_MASK) >> TRNG_SDCTL_ENT_DLY_SHIFT)
+
+/*! @brief Set the ENT_DLY field to a new value. */
+#define TRNG_WR_SDCTL_ENT_DLY(base, value) (TRNG_RMW_SDCTL(base, TRNG_SDCTL_ENT_DLY_MASK, TRNG_SDCTL_ENT_DLY(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SBLIM - RNG Sparse Bit Limit Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SBLIM - RNG Sparse Bit Limit Register (RW)
+ *
+ * Reset value: 0x0000003FU
+ *
+ * The RNG Sparse Bit Limit Register is used when Von Neumann sampling is
+ * selected during Entropy Generation. It defines the maximum number of consecutive Von
+ * Neumann samples which may be discarded before an error is generated. Note
+ * that this address (0xBASE_0614) is used as SBLIM only if MCTL[PRGM] is 1. If
+ * MCTL[PRGM] is 0, this address is used as TOTSAM readback register.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SBLIM register
+ */
+/*@{*/
+#define TRNG_SBLIM_REG(base) ((base)->SBLIM)
+#define TRNG_RD_SBLIM(base) (TRNG_SBLIM_REG(base))
+#define TRNG_WR_SBLIM(base, value) (TRNG_SBLIM_REG(base) = (value))
+#define TRNG_RMW_SBLIM(base, mask, value) (TRNG_WR_SBLIM(base, (TRNG_RD_SBLIM(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SBLIM bitfields
+ */
+
+/*!
+ * @name Register TRNG_SBLIM, field SB_LIM[9:0] (RW)
+ *
+ * Sparse Bit Limit. During Von Neumann sampling (if enabled by MCTL[SAMP_MODE],
+ * samples are discarded if two consecutive raw samples are both 0 or both 1. If
+ * this discarding occurs for a long period of time, it indicates that there is
+ * insufficient Entropy. The Sparse Bit Limit defines the maximum number of
+ * consecutive samples that may be discarded before an error is generated. This field
+ * is writable only if MCTL[PRGM] bit is 1. This register is cleared to 03hF by
+ * writing the MCTL[RST_DEF] bit to 1. Note that if MCTL[PRGM] bit is 0, this
+ * register address is used to read the Total Samples count in register TOTSAM, as
+ * defined in the following section.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SBLIM_SB_LIM field. */
+#define TRNG_RD_SBLIM_SB_LIM(base) ((TRNG_SBLIM_REG(base) & TRNG_SBLIM_SB_LIM_MASK) >> TRNG_SBLIM_SB_LIM_SHIFT)
+
+/*! @brief Set the SB_LIM field to a new value. */
+#define TRNG_WR_SBLIM_SB_LIM(base, value) (TRNG_RMW_SBLIM(base, TRNG_SBLIM_SB_LIM_MASK, TRNG_SBLIM_SB_LIM(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SCMISC - RNG Statistical Check Miscellaneous Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SCMISC - RNG Statistical Check Miscellaneous Register (RW)
+ *
+ * Reset value: 0x0001001FU
+ *
+ * The RNG Statistical Check Miscellaneous Register contains the Long Run
+ * Maximum Limit value and the Retry Count value. This register is accessible only when
+ * the MCTL[PRGM] bit is 1, otherwise this register will read zeroes, and cannot
+ * be written.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SCMISC register
+ */
+/*@{*/
+#define TRNG_SCMISC_REG(base) ((base)->SCMISC)
+#define TRNG_RD_SCMISC(base) (TRNG_SCMISC_REG(base))
+#define TRNG_WR_SCMISC(base, value) (TRNG_SCMISC_REG(base) = (value))
+#define TRNG_RMW_SCMISC(base, mask, value) (TRNG_WR_SCMISC(base, (TRNG_RD_SCMISC(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*
+ * Constants & macros for individual TRNG_SCMISC bitfields
+ */
+
+/*!
+ * @name Register TRNG_SCMISC, field LRUN_MAX[7:0] (RW)
+ *
+ * LONG RUN MAX LIMIT. This value is the largest allowable number of consecutive
+ * samples of all 1, or all 0, that is allowed during the Entropy generation.
+ * This field is writable only if MCTL[PRGM] bit is 1. This field will read zeroes
+ * if MCTL[PRGM] = 0. This field is cleared to 22h by writing the MCTL[RST_DEF]
+ * bit to 1.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SCMISC_LRUN_MAX field. */
+#define TRNG_RD_SCMISC_LRUN_MAX(base) \
+ ((TRNG_SCMISC_REG(base) & TRNG_SCMISC_LRUN_MAX_MASK) >> TRNG_SCMISC_LRUN_MAX_SHIFT)
+
+/*! @brief Set the LRUN_MAX field to a new value. */
+#define TRNG_WR_SCMISC_LRUN_MAX(base, value) \
+ (TRNG_RMW_SCMISC(base, TRNG_SCMISC_LRUN_MAX_MASK, TRNG_SCMISC_LRUN_MAX(value)))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_ENT - RNG TRNG Entropy Read Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_ENT - RNG TRNG Entropy Read Register (RO)
+ *
+ * Reset value: 0x00000000U
+ *
+ * The RNG TRNG can be programmed to generate an entropy value that is readable
+ * via the SkyBlue bus. To do this, set the MCTL[TRNG_ACC] bit to 1. Once the
+ * entropy value has been generated, the MCTL[ENT_VAL] bit will be set to 1. At this
+ * point, ENT0 through ENT15 may be read to retrieve the 512-bit entropy value.
+ * Note that once ENT15 is read, the entropy value will be cleared and a new
+ * value will begin generation, so it is important that ENT15 be read last. These
+ * registers are readable only when MCTL[PRGM] = 0 (Run Mode), MCTL[TRNG_ACC] = 1
+ * (TRNG access mode) and MCTL[ENT_VAL] = 1, otherwise zeroes will be read.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_ENT register
+ */
+/*@{*/
+#define TRNG_ENT_REG(base, index) ((base)->ENT[index])
+#define TRNG_RD_ENT(base, index) (TRNG_ENT_REG(base, index))
+/*@}*/
+
+/*******************************************************************************
+ * TRNG_SEC_CFG - RNG Security Configuration Register
+ ******************************************************************************/
+
+/*!
+ * @brief TRNG_SEC_CFG - RNG Security Configuration Register (RW)
+ *
+ * Reset value: 0x00000000U
+ *
+ * The RNG Security Configuration Register is a read/write register used to
+ * control the test mode, programmability and state modes of the RNG. Many bits are
+ * place holders for this version. More configurability will be added here. Clears
+ * on asynchronous reset. For SA-TRNG releases before 2014/July/01, offsets 0xA0
+ * to 0xAC used to be 0xB0 to 0xBC respectively. So, update newer tests that use
+ * these registers, if hard coded.
+ */
+/*!
+ * @name Constants and macros for entire TRNG_SEC_CFG register
+ */
+/*@{*/
+#define TRNG_SEC_CFG_REG(base) ((base)->SEC_CFG)
+#define TRNG_RD_SEC_CFG(base) (TRNG_SEC_CFG_REG(base))
+#define TRNG_WR_SEC_CFG(base, value) (TRNG_SEC_CFG_REG(base) = (value))
+#define TRNG_RMW_SEC_CFG(base, mask, value) (TRNG_WR_SEC_CFG(base, (TRNG_RD_SEC_CFG(base) & ~(mask)) | (value)))
+/*@}*/
+
+/*!
+ * @name Register TRNG_SEC_CFG, field NO_PRGM[1] (RW)
+ *
+ * If set the TRNG registers cannot be programmed. That is, regardless of the
+ * TRNG access mode in the SA-TRNG Miscellaneous Control Register.
+ *
+ * Values:
+ * - 0b0 - Programability of registers controlled only by the RNG Miscellaneous
+ * Control Register's access mode bit.
+ * - 0b1 - Overides RNG Miscellaneous Control Register access mode and prevents
+ * TRNG register programming.
+ */
+/*@{*/
+/*! @brief Read current value of the TRNG_SEC_CFG_NO_PRGM field. */
+#define TRNG_RD_SEC_CFG_NO_PRGM(base) \
+ ((TRNG_SEC_CFG_REG(base) & TRNG_SEC_CFG_NO_PRGM_MASK) >> TRNG_SEC_CFG_NO_PRGM_SHIFT)
+
+/*! @brief Set the NO_PRGM field to a new value. */
+#define TRNG_WR_SEC_CFG_NO_PRGM(base, value) \
+ (TRNG_RMW_SEC_CFG(base, TRNG_SEC_CFG_NO_PRGM_MASK, TRNG_SEC_CFG_NO_PRGM(value)))
+/*@}*/
+
+/*! @brief Array to map TRNG instance number to base pointer. */
+static TRNG_Type *const s_trngBases[] = TRNG_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Clock array name */
+static const clock_ip_name_t s_trngClock[] = TRNG_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Prototypes
+ *******************************************************************************/
+static status_t trng_ApplyUserConfig(TRNG_Type *base, const trng_config_t *userConfig);
+static status_t trng_SetRetryCount(TRNG_Type *base, uint8_t retry_count);
+static status_t trng_SetMonobitLimit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit1Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit2Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit3Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit4Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit5Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetRunBit6Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetPokerMaxLimit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum);
+static status_t trng_SetFrequencyCountMaxLimit(TRNG_Type *base, uint32_t limit_minimum, uint32_t limit_maximum);
+static status_t trng_SetStatisticalCheckLimit(TRNG_Type *base,
+ trng_statistical_check_t statistical_check,
+ const trng_statistical_check_limit_t *limit);
+static uint32_t trng_ReadEntropy(TRNG_Type *base, uint32_t index);
+static uint32_t trng_GetInstance(TRNG_Type *base);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t trng_GetInstance(TRNG_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_trngBases); instance++)
+ {
+ if (s_trngBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_trngBases));
+
+ return instance;
+}
+
+/*FUNCTION*********************************************************************
+ *
+ * Function Name : TRNG_InitUserConfigDefault
+ * Description : Initializes user configuration structure to default settings.
+ *
+ *END*************************************************************************/
+/*!
+ * brief Initializes the user configuration structure to default values.
+ *
+ * This function initializes the configuration structure to default values. The default
+ * values are as follows.
+ * code
+ * userConfig->lock = 0;
+ * userConfig->clockMode = kTRNG_ClockModeRingOscillator;
+ * userConfig->ringOscDiv = kTRNG_RingOscDiv0; Or to other kTRNG_RingOscDiv[2|8] depending on the platform.
+ * userConfig->sampleMode = kTRNG_SampleModeRaw;
+ * userConfig->entropyDelay = 3200;
+ * userConfig->sampleSize = 2500;
+ * userConfig->sparseBitLimit = TRNG_USER_CONFIG_DEFAULT_SPARSE_BIT_LIMIT;
+ * userConfig->retryCount = 63;
+ * userConfig->longRunMaxLimit = 34;
+ * userConfig->monobitLimit.maximum = 1384;
+ * userConfig->monobitLimit.minimum = 1116;
+ * userConfig->runBit1Limit.maximum = 405;
+ * userConfig->runBit1Limit.minimum = 227;
+ * userConfig->runBit2Limit.maximum = 220;
+ * userConfig->runBit2Limit.minimum = 98;
+ * userConfig->runBit3Limit.maximum = 125;
+ * userConfig->runBit3Limit.minimum = 37;
+ * userConfig->runBit4Limit.maximum = 75;
+ * userConfig->runBit4Limit.minimum = 11;
+ * userConfig->runBit5Limit.maximum = 47;
+ * userConfig->runBit5Limit.minimum = 1;
+ * userConfig->runBit6PlusLimit.maximum = 47;
+ * userConfig->runBit6PlusLimit.minimum = 1;
+ * userConfig->pokerLimit.maximum = 26912;
+ * userConfig->pokerLimit.minimum = 24445;
+ * userConfig->frequencyCountLimit.maximum = 25600;
+ * userConfig->frequencyCountLimit.minimum = 1600;
+ * endcode
+ *
+ * param userConfig User configuration structure.
+ * return If successful, returns the kStatus_TRNG_Success. Otherwise, it returns an error.
+ */
+status_t TRNG_GetDefaultConfig(trng_config_t *userConfig)
+{
+ status_t result;
+
+ if (userConfig != NULL)
+ {
+ /* Initializes the configuration structure to default values. */
+
+ /* Lock programmability of TRNG registers. */
+ userConfig->lock = (bool)TRNG_USER_CONFIG_DEFAULT_LOCK;
+ /* Clock settings */
+ userConfig->clockMode = kTRNG_ClockModeRingOscillator;
+ userConfig->ringOscDiv = TRNG_USER_CONFIG_DEFAULT_OSC_DIV;
+ userConfig->sampleMode = kTRNG_SampleModeRaw;
+ /* Seed control*/
+ userConfig->entropyDelay = TRNG_USER_CONFIG_DEFAULT_ENTROPY_DELAY;
+ userConfig->sampleSize = TRNG_USER_CONFIG_DEFAULT_SAMPLE_SIZE;
+ userConfig->sparseBitLimit = TRNG_USER_CONFIG_DEFAULT_SPARSE_BIT_LIMIT;
+
+ /* Statistical Check Parameters.*/
+ userConfig->retryCount = TRNG_USER_CONFIG_DEFAULT_RETRY_COUNT;
+ userConfig->longRunMaxLimit = TRNG_USER_CONFIG_DEFAULT_RUN_MAX_LIMIT;
+
+ userConfig->monobitLimit.maximum = TRNG_USER_CONFIG_DEFAULT_MONOBIT_MAXIMUM;
+ userConfig->monobitLimit.minimum = TRNG_USER_CONFIG_DEFAULT_MONOBIT_MINIMUM;
+ userConfig->runBit1Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MAXIMUM;
+ userConfig->runBit1Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT1_MINIMUM;
+ userConfig->runBit2Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MAXIMUM;
+ userConfig->runBit2Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT2_MINIMUM;
+ userConfig->runBit3Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MAXIMUM;
+ userConfig->runBit3Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT3_MINIMUM;
+ userConfig->runBit4Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MAXIMUM;
+ userConfig->runBit4Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT4_MINIMUM;
+ userConfig->runBit5Limit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MAXIMUM;
+ userConfig->runBit5Limit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT5_MINIMUM;
+ userConfig->runBit6PlusLimit.maximum = TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MAXIMUM;
+ userConfig->runBit6PlusLimit.minimum = TRNG_USER_CONFIG_DEFAULT_RUNBIT6PLUS_MINIMUM;
+ /* Limits for statistical check of "Poker Test". */
+ userConfig->pokerLimit.maximum = TRNG_USER_CONFIG_DEFAULT_POKER_MAXIMUM;
+ userConfig->pokerLimit.minimum = TRNG_USER_CONFIG_DEFAULT_POKER_MINIMUM;
+ /* Limits for statistical check of entropy sample frequency count. */
+ userConfig->frequencyCountLimit.maximum = TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MAXIMUM;
+ userConfig->frequencyCountLimit.minimum = TRNG_USER_CONFIG_DEFAULT_FREQUENCY_MINIMUM;
+
+ result = kStatus_Success;
+ }
+ else
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ return result;
+}
+
+/*!
+ * @brief Sets the TRNG retry count.
+ *
+ * This function sets the retry counter which defines the number of times a
+ * statistical check may fails during the TRNG Entropy Generation before
+ * generating an error.
+ */
+static status_t trng_SetRetryCount(TRNG_Type *base, uint8_t retry_count)
+{
+ status_t status;
+
+ if ((retry_count >= 1u) && (retry_count <= 15u))
+ {
+ /* Set retry count.*/
+ TRNG_WR_SCMISC_RTY_CT(base, retry_count);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Check Monobit Limit Register .
+ *
+ * This function set register TRNG_SCML - Statistical Check Monobit Limit Register
+ */
+static status_t trng_SetMonobitLimit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0xffffu) && (limit_maximum <= 0xffffu))
+
+ {
+ /* Set TRNG_SCML register */
+ TRNG_WR_SCML_MONO_MAX(base, limit_maximum);
+ TRNG_WR_SCML_MONO_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 1 Limit Register .
+ *
+ * This function set register TRNG_SCR1L - Statistical Check Run Length 1 Limit Register
+ */
+static status_t trng_SetRunBit1Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x7fffu) && (limit_maximum <= 0x7fffu))
+ {
+ /* Set TRNG_SCR1L register */
+ TRNG_WR_SCR1L_RUN1_MAX(base, limit_maximum);
+ TRNG_WR_SCR1L_RUN1_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 2 Limit Register .
+ *
+ * This function set register TRNG_SCR2L - Statistical Check Run Length 2 Limit Register
+ */
+static status_t trng_SetRunBit2Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x3fffu) && (limit_maximum <= 0x3fffu))
+ {
+ /* Set TRNG_SCR2L register */
+ TRNG_WR_SCR2L_RUN2_MAX(base, limit_maximum);
+ TRNG_WR_SCR2L_RUN2_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 3 Limit Register .
+ *
+ * This function set register TRNG_SCR3L - Statistical Check Run Length 3 Limit Register
+ */
+static status_t trng_SetRunBit3Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x1fffu) && (limit_maximum <= 0x1fffu))
+ {
+ /* Set TRNG_SCR3L register */
+ TRNG_WR_SCR3L_RUN3_MAX(base, limit_maximum);
+ TRNG_WR_SCR3L_RUN3_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 4 Limit Register .
+ * This function set register TRNG_SCR4L - Statistical Check Run Length 4 Limit Register
+ */
+static status_t trng_SetRunBit4Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0xfffu) && (limit_maximum <= 0xfffu))
+ {
+ /* Set TRNG_SCR4L register */
+ TRNG_WR_SCR4L_RUN4_MAX(base, limit_maximum);
+ TRNG_WR_SCR4L_RUN4_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 5 Limit Register .
+ * This function set register TRNG_SCR5L - Statistical Check Run Length 5 Limit Register
+ */
+static status_t trng_SetRunBit5Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x7ffu) && (limit_maximum <= 0x7ffu))
+ {
+ /* Set TRNG_SCR5L register */
+ TRNG_WR_SCR5L_RUN5_MAX(base, limit_maximum);
+ TRNG_WR_SCR5L_RUN5_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Statistical Check Run Length 6 Limit Register .
+ * This function set register TRNG_SCR6L - Statistical Check Run Length 6 Limit Register
+ */
+static status_t trng_SetRunBit6Limit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0x7ffu) && (limit_maximum <= 0x7ffu))
+ {
+ /* Set TRNG_SCR6L register */
+ TRNG_WR_SCR6PL_RUN6P_MAX(base, limit_maximum);
+ TRNG_WR_SCR6PL_RUN6P_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Poker Maximum Limit Register.
+ * This function set register TRNG_PKRMAX - Poker Maximum Limit Register
+ */
+static status_t trng_SetPokerMaxLimit(TRNG_Type *base, uint32_t range, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((range <= 0xffffu) && (limit_maximum <= 0xffffffu))
+ {
+ /* Set TRNG_PKRMAX register */
+ TRNG_WR_PKRMAX_PKR_MAX(base, limit_maximum);
+ TRNG_WR_PKRRNG_PKR_RNG(base, range);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical Frequency Count Maximum Limit Register.
+ * This function set register TRNG_FRQMAX - Frequency Count Maximum Limit Register
+ */
+static status_t trng_SetFrequencyCountMaxLimit(TRNG_Type *base, uint32_t limit_minimum, uint32_t limit_maximum)
+{
+ status_t status;
+
+ /* Check input parameters*/
+ if ((limit_minimum <= 0x3fffffu) && (limit_maximum <= 0x3fffffu))
+ {
+ /* Set FRQMAX register */
+ TRNG_WR_FRQMAX_FRQ_MAX(base, limit_maximum);
+ TRNG_WR_FRQMIN_FRQ_MIN(base, limit_minimum);
+ status = kStatus_Success;
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ return status;
+}
+
+/*!
+ * @brief Sets statistical check limits.
+ *
+ * This function is used to set minimum and maximum limits of statistical checks.
+ *
+ */
+static status_t trng_SetStatisticalCheckLimit(TRNG_Type *base,
+ trng_statistical_check_t statistical_check,
+ const trng_statistical_check_limit_t *limit)
+{
+ uint32_t range;
+ status_t status = kStatus_Success;
+
+ if ((NULL != limit) && (limit->maximum > limit->minimum))
+ {
+ range = limit->maximum - limit->minimum; /* Registers use range instead of minimum value.*/
+
+ if (statistical_check == kTRNG_StatisticalCheckMonobit) /* Allowable maximum and minimum number of ones/zero
+ detected during entropy generation. */
+ {
+ status = trng_SetMonobitLimit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit1) /* Allowable maximum and minimum number of runs of
+ length 1 detected during entropy generation. */
+ {
+ status = trng_SetRunBit1Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit2) /* Allowable maximum and minimum number of runs of
+ length 2 detected during entropy generation. */
+ {
+ status = trng_SetRunBit2Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit3) /* Allowable maximum and minimum number of runs of
+ length 3 detected during entropy generation. */
+ {
+ status = trng_SetRunBit3Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit4) /* Allowable maximum and minimum number of runs of
+ length 4 detected during entropy generation. */
+ {
+ status = trng_SetRunBit4Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit5) /* Allowable maximum and minimum number of runs of
+ length 5 detected during entropy generation. */
+ {
+ status = trng_SetRunBit5Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckRunBit6Plus) /* Allowable maximum and minimum number of
+ length 6 or more detected during entropy
+ generation */
+ {
+ status = trng_SetRunBit6Limit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckPoker) /* Allowable maximum and minimum limit of "Poker
+ Test" detected during entropy generation . */
+ {
+ status = trng_SetPokerMaxLimit(base, range, limit->maximum);
+ }
+ else if (statistical_check == kTRNG_StatisticalCheckFrequencyCount) /* Allowable maximum and minimum limit of
+ entropy sample frquency count during
+ entropy generation . */
+ {
+ status = trng_SetFrequencyCountMaxLimit(base, limit->minimum, limit->maximum);
+ }
+ else
+ {
+ status = kStatus_InvalidArgument;
+ }
+ }
+
+ return status;
+}
+
+/*FUNCTION*********************************************************************
+ *
+ * Function Name : trng_ApplyUserConfig
+ * Description : Apply user configuration settings to TRNG module.
+ *
+ *END*************************************************************************/
+static status_t trng_ApplyUserConfig(TRNG_Type *base, const trng_config_t *userConfig)
+{
+ status_t status;
+
+ /* Set retry count */
+ status = trng_SetRetryCount(base, userConfig->retryCount);
+
+ /* Set statistical check limit */
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckMonobit, &userConfig->monobitLimit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit1, &userConfig->runBit1Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit2, &userConfig->runBit2Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit3, &userConfig->runBit3Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit4, &userConfig->runBit4Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit5, &userConfig->runBit5Limit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckRunBit6Plus, &userConfig->runBit6PlusLimit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status = trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckPoker, &userConfig->pokerLimit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ status =
+ trng_SetStatisticalCheckLimit(base, kTRNG_StatisticalCheckFrequencyCount, &userConfig->frequencyCountLimit);
+ }
+
+ if (kStatus_Success == status)
+ {
+ /* Set clock mode used to operate TRNG */
+ TRNG_WR_MCTL_FOR_SCLK(base, userConfig->clockMode);
+ /* Set ring oscillator divider used by TRNG */
+ TRNG_WR_MCTL_OSC_DIV(base, userConfig->ringOscDiv);
+ /* Set sample mode of the TRNG ring oscillator. */
+ TRNG_WR_MCTL_SAMP_MODE(base, userConfig->sampleMode);
+ /* Set length of each Entropy sample taken */
+ TRNG_WR_SDCTL_ENT_DLY(base, userConfig->entropyDelay);
+ /* Set number of entropy samples that will be taken during Entropy generation */
+ TRNG_WR_SDCTL_SAMP_SIZE(base, userConfig->sampleSize);
+ /* Set Sparse Bit Limit */
+ TRNG_WR_SBLIM_SB_LIM(base, userConfig->sparseBitLimit);
+ TRNG_WR_SCMISC_LRUN_MAX(base, userConfig->longRunMaxLimit);
+ }
+
+ return status;
+}
+
+/*!
+ * @brief Gets a entry data from the TRNG.
+ *
+ * This function gets an entropy data from TRNG.
+ * Entropy data is spread over TRNG_ENT_COUNT registers.
+ * Read register number is defined by index parameter.
+ */
+static uint32_t trng_ReadEntropy(TRNG_Type *base, uint32_t index)
+{
+ uint32_t data;
+
+ index = index % TRNG_ENT_COUNT; /* This way we can use incremental index without limit control from application.*/
+
+ data = TRNG_RD_ENT(base, index);
+
+ if (index == (TRNG_ENT_COUNT - 1u))
+ {
+ /* Dummy read. Defect workaround.
+ * TRNG could not clear ENT_VAL flag automatically, application
+ * had to do a dummy reading operation for anyone TRNG register
+ * to clear it firstly, then to read the RTENT0 to RTENT15 again */
+ index = TRNG_RD_ENT(base, 0);
+ }
+
+ return data;
+}
+
+/*!
+ * brief Initializes the TRNG.
+ *
+ * This function initializes the TRNG.
+ * When called, the TRNG entropy generation starts immediately.
+ *
+ * param base TRNG base address
+ * param userConfig Pointer to the initialization configuration structure.
+ * return If successful, returns the kStatus_TRNG_Success. Otherwise, it returns an error.
+ */
+status_t TRNG_Init(TRNG_Type *base, const trng_config_t *userConfig)
+{
+ status_t result;
+
+ /* Check input parameters.*/
+ if ((base != NULL) && (userConfig != NULL))
+ {
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the clock gate. */
+ CLOCK_EnableClock(s_trngClock[trng_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Reset the registers of TRNG module to reset state. */
+ /* Must be in program mode.*/
+ TRNG_WR_MCTL_PRGM(base, kTRNG_WorkModeProgram);
+ /* Reset Defaults.*/
+ TRNG_WR_MCTL_RST_DEF(base, 1);
+
+ /* Set configuration.*/
+ if ((result = trng_ApplyUserConfig(base, userConfig)) == kStatus_Success)
+ {
+ /* Start entropy generation.*/
+ /* Set to Run mode.*/
+ TRNG_WR_MCTL_PRGM(base, kTRNG_WorkModeRun);
+#if !(defined(FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC) && (FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC > 0))
+ /* Enable TRNG Access Mode. To generate an Entropy
+ * value that can be read via the true0-true15 registers.*/
+ TRNG_WR_MCTL_TRNG_ACC(base, 1);
+#endif /* !FSL_FEATURE_TRNG_HAS_NO_TRNG_ACC */
+
+ (void)trng_ReadEntropy(base, (TRNG_ENT_COUNT - 1u));
+
+ if (true == userConfig->lock) /* Disable programmability of TRNG registers. */
+ {
+ TRNG_WR_SEC_CFG_NO_PRGM(base, 1);
+ }
+
+ result = kStatus_Success;
+ }
+ }
+ else
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ return result;
+}
+
+/*!
+ * brief Shuts down the TRNG.
+ *
+ * This function shuts down the TRNG.
+ *
+ * param base TRNG base address.
+ */
+void TRNG_Deinit(TRNG_Type *base)
+{
+ /* Check input parameters.*/
+ if (NULL != base)
+ {
+ /* Move to program mode. Stop entropy generation.*/
+ TRNG_WR_MCTL_PRGM(base, kTRNG_WorkModeProgram);
+
+ /* Check before clock stop.
+ TRNG turns on the TRNG free-running ring oscillator whenever new entropy
+ is being generated and turns off the ring oscillator when entropy generation
+ is complete. If the TRNG clock is stopped while the TRNG ring oscillator
+ is running, the oscillator continues running though the RNG clock.
+ is stopped. */
+ while (TRNG_RD_MCTL_TSTOP_OK(base) == 0u)
+ {
+ }
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable Clock*/
+ CLOCK_DisableClock(s_trngClock[trng_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ }
+}
+
+/*!
+ * brief Gets random data.
+ *
+ * This function gets random data from the TRNG.
+ *
+ * param base TRNG base address.
+ * param data Pointer address used to store random data.
+ * param dataSize Size of the buffer pointed by the data parameter.
+ * return random data
+ */
+status_t TRNG_GetRandomData(TRNG_Type *base, void *data, size_t dataSize)
+{
+ status_t result = kStatus_Success;
+ uint32_t random_32;
+ uint8_t *random_p;
+ uint32_t random_size;
+ uint8_t *data_p = (uint8_t *)data;
+ uint32_t i;
+ uint32_t tmpValidFlag;
+ uint32_t tmpErrorFlag;
+
+ int index = 0;
+
+ /* Check input parameters.*/
+ if ((NULL != base) && (NULL != data) && (0U != dataSize))
+ {
+ do
+ {
+ /* Wait for Valid or Error flag*/
+ tmpValidFlag = TRNG_RD_MCTL_ENT_VAL(base);
+ tmpErrorFlag = TRNG_RD_MCTL_ERR(base);
+ while ((tmpValidFlag == 0u) && (tmpErrorFlag == 0u))
+ {
+ tmpValidFlag = TRNG_RD_MCTL_ENT_VAL(base);
+ tmpErrorFlag = TRNG_RD_MCTL_ERR(base);
+ }
+
+ /* Check HW error.*/
+ if (0U != TRNG_RD_MCTL_ERR(base))
+ {
+ result = kStatus_Fail; /* TRNG module error occurred */
+ /* Clear error.*/
+ TRNG_WR_MCTL_ERR(base, 1);
+ break; /* No sense stay here.*/
+ }
+
+ /* Read Entropy.*/
+ random_32 = trng_ReadEntropy(base, (uint32_t)index++);
+
+ random_p = (uint8_t *)&random_32;
+
+ if (dataSize < sizeof(random_32))
+ {
+ random_size = dataSize;
+ }
+ else
+ {
+ random_size = sizeof(random_32);
+ }
+
+ for (i = 0U; i < random_size; i++)
+ {
+ *data_p++ = *random_p++;
+ }
+
+ dataSize -= random_size;
+ } while (dataSize > 0u);
+
+ /* Start a new entropy generation.
+ It is done by reading of the last entropy register.*/
+ if (((unsigned)index % TRNG_ENT_COUNT) != (TRNG_ENT_COUNT - 1u))
+ {
+ (void)trng_ReadEntropy(base, (TRNG_ENT_COUNT - 1u));
+ }
+ }
+ else
+ {
+ result = kStatus_InvalidArgument;
+ }
+
+ return result;
+}
+
+#endif /* FSL_FEATURE_SOC_TRNG_COUNT */
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_tsc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_tsc.c
new file mode 100644
index 0000000000..403f661fa6
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_tsc.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_tsc.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.tsc"
+#endif
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get instance number for TSC module.
+ *
+ * @param base TSC peripheral base address
+ */
+static uint32_t TSC_GetInstance(TSC_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief Pointers to TSC bases for each instance. */
+static TSC_Type *const s_tscBases[] = TSC_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief Pointers to ADC clocks for each instance. */
+static const clock_ip_name_t s_tscClocks[] = TSC_CLOCKS;
+#endif
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t TSC_GetInstance(TSC_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_tscBases); instance++)
+ {
+ if (s_tscBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_tscBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initialize the TSC module.
+ *
+ * param base TSC peripheral base address.
+ * param config Pointer to "tsc_config_t" structure.
+ */
+void TSC_Init(TSC_Type *base, const tsc_config_t *config)
+{
+ assert(NULL != config);
+ assert(config->measureDelayTime <= 0xFFFFFFU);
+
+ uint32_t tmp32;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the TSC clock. */
+ CLOCK_EnableClock(s_tscClocks[TSC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+ /* Configure TSC_BASIC_SETTING register. */
+ tmp32 = TSC_BASIC_SETTING_MEASURE_DELAY_TIME(config->measureDelayTime) |
+ TSC_BASIC_SETTING__4_5_WIRE(config->detectionMode);
+ if (config->enableAutoMeasure)
+ {
+ tmp32 |= TSC_BASIC_SETTING_AUTO_MEASURE_MASK;
+ }
+ base->BASIC_SETTING = tmp32;
+ /* Configure TSC_PS_INPUT_BUFFER_ADDR register. */
+ base->PRE_CHARGE_TIME = TSC_PRE_CHARGE_TIME_PRE_CHARGE_TIME(config->prechargeTime);
+}
+
+/*!
+ * brief De-initializes the TSC module.
+ *
+ * param base TSC peripheral base address.
+ */
+void TSC_Deinit(TSC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable the TSC clcok. */
+ CLOCK_DisableClock(s_tscClocks[TSC_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Gets an available pre-defined settings for the controller's configuration.
+ *
+ * This function initializes the converter configuration structure with available settings.
+ * The default values of measureDelayTime and prechargeTime is tested on LCD8000-43T screen and work normally.
+ * The default values are:
+ * code
+ * config->enableAutoMeausre = false;
+ * config->measureDelayTime = 0xFFFFU;
+ * config->prechargeTime = 0xFFFFU;
+ * config->detectionMode = kTSC_4WireDetectionMode;
+ * endCode
+ * param config Pointer to "tsc_config_t" structure.
+ */
+void TSC_GetDefaultConfig(tsc_config_t *config)
+{
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableAutoMeasure = false;
+ config->measureDelayTime = 0xFFFFU;
+ config->prechargeTime = 0xFFFFU;
+ config->detectionMode = kTSC_Detection4WireMode;
+}
+
+/*!
+ * brief Get Y coordinate value or X coordinate value. The value is an ADC conversion value.
+ *
+ * param base TSC peripheral base address.
+ * param selection Select alternative measure value which is Y coordinate value or X coordinate value.
+ * See "tsc_corrdinate_value_selection_t".
+ * return If selection is "kTSC_XCoordinateValueSelection", the API returns x-coordinate vlaue.
+ * If selection is "kTSC_YCoordinateValueSelection", the API returns y-coordinate vlaue.
+ */
+uint32_t TSC_GetMeasureValue(TSC_Type *base, tsc_corrdinate_value_selection_t selection)
+{
+ uint32_t tmp32 = 0;
+
+ if (selection == kTSC_XCoordinateValueSelection)
+ {
+ tmp32 = ((base->MEASEURE_VALUE) & TSC_MEASEURE_VALUE_X_VALUE_MASK) >> TSC_MEASEURE_VALUE_X_VALUE_SHIFT;
+ }
+ else if (selection == kTSC_YCoordinateValueSelection)
+ {
+ tmp32 = ((base->MEASEURE_VALUE) & TSC_MEASEURE_VALUE_Y_VALUE_MASK) >> TSC_MEASEURE_VALUE_Y_VALUE_SHIFT;
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ return tmp32;
+}
+
+/*!
+ * brief Send hardware trigger signal to ADC in debug mode. The trigger signal must last at least 1 ips clock period.
+ *
+ * param base TSC peripheral base address.
+ * param hwts Hardware trigger select signal, select which channel to start conversion. See "tsc_trigger_signal_t".
+ * On ADC side, HWTS = 1 << x indicates the x logic channel is selected to start hardware ADC conversion.
+ * param enable Switcher of the trigger signal. "true" means generate trigger signal, "false" means don't generate
+ * trigger signal.
+ */
+void TSC_DebugTriggerSignalToADC(TSC_Type *base, tsc_trigger_signal_t hwts, bool enable)
+{
+ if (enable)
+ {
+ /* TSC_DEBUG_MODE_EXT_HWTS field should be writed before writing TSC_DEBUG_MODE_TRIGGER field.
+ If the two fields are writed at the same time, the trigger couldn't work as expect. */
+ base->DEBUG_MODE &= ~TSC_DEBUG_MODE_EXT_HWTS_MASK;
+ base->DEBUG_MODE |= TSC_DEBUG_MODE_EXT_HWTS(hwts);
+ base->DEBUG_MODE |= TSC_DEBUG_MODE_TRIGGER_MASK;
+ }
+ else
+ {
+ base->DEBUG_MODE &= ~TSC_DEBUG_MODE_TRIGGER_MASK;
+ }
+}
+
+/*!
+ * brief Enable/Disable detection in debug mode.
+ *
+ * param base TSC peripheral base address.
+ * param detectionMode Set detect mode. See "tsc_detection_mode_t"
+ * param enable Switcher of detect enable. "true" means enable detection, "false" means disable detection.
+ */
+void TSC_DebugEnableDetection(TSC_Type *base, tsc_detection_mode_t detectionMode, bool enable)
+{
+ if (detectionMode == kTSC_Detection4WireMode)
+ {
+ if (enable)
+ {
+ base->DEBUG_MODE2 |= TSC_DEBUG_MODE2_DETECT_ENABLE_FOUR_WIRE_MASK;
+ }
+ else
+ {
+ base->DEBUG_MODE2 &= ~TSC_DEBUG_MODE2_DETECT_ENABLE_FOUR_WIRE_MASK;
+ }
+ }
+ else if (detectionMode == kTSC_Detection5WireMode)
+ {
+ if (enable)
+ {
+ base->DEBUG_MODE2 |= TSC_DEBUG_MODE2_DETECT_ENABLE_FIVE_WIRE_MASK;
+ }
+ else
+ {
+ base->DEBUG_MODE2 &= ~TSC_DEBUG_MODE2_DETECT_ENABLE_FIVE_WIRE_MASK;
+ }
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+}
+
+/*!
+ * brief Set TSC port mode in debug mode.(pull down, pull up and 200k-pull up)
+ *
+ * param base TSC peripheral base address.
+ * param port TSC controller ports.
+ * param mode TSC port mode.(pull down, pull up and 200k-pull up)
+ */
+void TSC_DebugSetPortMode(TSC_Type *base, tsc_port_source_t port, tsc_port_mode_t mode)
+{
+ uint32_t tmp32;
+
+ tmp32 = base->DEBUG_MODE2;
+ switch (port)
+ {
+ case kTSC_WiperPortSource:
+ tmp32 &= ~(TSC_DEBUG_MODE2_WIPER_200K_PULL_UP_MASK | TSC_DEBUG_MODE2_WIPER_PULL_UP_MASK |
+ TSC_DEBUG_MODE2_WIPER_PULL_DOWN_MASK);
+ tmp32 |= ((uint32_t)mode << TSC_DEBUG_MODE2_WIPER_PULL_DOWN_SHIFT);
+ break;
+ case kTSC_YnlrPortSource:
+ tmp32 &= ~(TSC_DEBUG_MODE2_YNLR_200K_PULL_UP_MASK | TSC_DEBUG_MODE2_YNLR_PULL_UP_MASK |
+ TSC_DEBUG_MODE2_YNLR_PULL_DOWN_MASK);
+ tmp32 |= ((uint32_t)mode << TSC_DEBUG_MODE2_YNLR_PULL_DOWN_SHIFT);
+ break;
+ case kTSC_YpllPortSource:
+ tmp32 &= ~(TSC_DEBUG_MODE2_YPLL_200K_PULL_UP_MASK | TSC_DEBUG_MODE2_YPLL_PULL_UP_MASK |
+ TSC_DEBUG_MODE2_YPLL_PULL_DOWN_MASK);
+ tmp32 |= ((uint32_t)mode << TSC_DEBUG_MODE2_YPLL_PULL_DOWN_SHIFT);
+ break;
+ case kTSC_XnurPortSource:
+ tmp32 &= ~(TSC_DEBUG_MODE2_XNUR_200K_PULL_UP_MASK | TSC_DEBUG_MODE2_XNUR_PULL_UP_MASK |
+ TSC_DEBUG_MODE2_XNUR_PULL_DOWN_MASK);
+ tmp32 |= ((uint32_t)mode << TSC_DEBUG_MODE2_XNUR_PULL_DOWN_SHIFT);
+ break;
+ case kTSC_XpulPortSource:
+ tmp32 &= ~(TSC_DEBUG_MODE2_XPUL_200K_PULL_UP_MASK | TSC_DEBUG_MODE2_XPUL_PULL_UP_MASK |
+ TSC_DEBUG_MODE2_XPUL_PULL_DOWN_MASK);
+ tmp32 |= ((uint32_t)mode << TSC_DEBUG_MODE2_XPUL_PULL_DOWN_SHIFT);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ base->DEBUG_MODE2 = tmp32;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_usdhc.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_usdhc.c
new file mode 100644
index 0000000000..8dd37e6345
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_usdhc.c
@@ -0,0 +1,2126 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_usdhc.h"
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+#include "fsl_cache.h"
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.usdhc"
+#endif
+
+/*! @brief Clock setting */
+/* Max SD clock divisor from base clock */
+#define USDHC_MAX_DVS ((USDHC_SYS_CTRL_DVS_MASK >> USDHC_SYS_CTRL_DVS_SHIFT) + 1U)
+#define USDHC_MAX_CLKFS ((USDHC_SYS_CTRL_SDCLKFS_MASK >> USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U)
+#define USDHC_PREV_DVS(x) ((x) -= 1U)
+#define USDHC_PREV_CLKFS(x, y) ((x) >>= (y))
+/*! @brief USDHC ADMA table address align size */
+#define USDHC_ADMA_TABLE_ADDRESS_ALIGN (4U)
+
+/* Typedef for interrupt handler. */
+typedef void (*usdhc_isr_t)(USDHC_Type *base, usdhc_handle_t *handle);
+/*! @brief check flag avalibility */
+#define IS_USDHC_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL)
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief Get the instance.
+ *
+ * @param base USDHC peripheral base address.
+ * @return Instance number.
+ */
+static uint32_t USDHC_GetInstance(USDHC_Type *base);
+
+/*!
+ * @brief Start transfer according to current transfer state
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @param flag data present flag
+ * @param enDMA DMA enable flag
+ */
+static status_t USDHC_SetDataTransferConfig(USDHC_Type *base,
+ usdhc_data_t *data,
+ uint32_t *dataPresentFlag,
+ bool enDMA);
+
+/*!
+ * @brief Receive command response
+ *
+ * @param base USDHC peripheral base address.
+ * @param command Command to be sent.
+ */
+static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command);
+
+/*!
+ * @brief Read DATAPORT when buffer enable bit is set.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be read.
+ * @param transferredWords The number of data words have been transferred last time transaction.
+ * @return The number of total data words have been transferred after this time transaction.
+ */
+static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
+
+/*!
+ * @brief Read data by using DATAPORT polling way.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be read.
+ * @retval kStatus_Fail Read DATAPORT failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
+
+/*!
+ * @brief Write DATAPORT when buffer enable bit is set.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be read.
+ * @param transferredWords The number of data words have been transferred last time.
+ * @return The number of total data words have been transferred after this time transaction.
+ */
+static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
+
+/*!
+ * @brief Write data by using DATAPORT polling way.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @retval kStatus_Fail Write DATAPORT failed.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
+
+/*!
+ * @brief Transfer data by polling way.
+ *
+ * @param base USDHC peripheral base address.
+ * @param data Data to be transferred.
+ * @param use DMA flag.
+ * @retval kStatus_Fail Transfer data failed.
+ * @retval kStatus_InvalidArgument Argument is invalid.
+ * @retval kStatus_Success Operate successfully.
+ */
+static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA);
+
+/*!
+ * @brief Handle card detect interrupt.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param interruptFlags Card detect related interrupt flags.
+ */
+static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle command interrupt.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param interruptFlags Command related interrupt flags.
+ */
+static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle data interrupt.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param interruptFlags Data related interrupt flags.
+ */
+static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
+
+/*!
+ * @brief Handle SDIO card interrupt signal.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ */
+static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle);
+
+/*!
+ * @brief Handle SDIO block gap event.
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ */
+static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle);
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+/*!
+ * @brief Handle retuning
+ *
+ * @param base USDHC peripheral base address.
+ * @param handle USDHC handle.
+ * @param interrupt flags
+ */
+static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
+#endif
+
+/*!
+ * @brief wait command done
+ *
+ * @param base USDHC peripheral base address.
+ * @param command configuration
+ * @param pollingCmdDone polling command done flag
+ */
+static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/*! @brief USDHC base pointer array */
+static USDHC_Type *const s_usdhcBase[] = USDHC_BASE_PTRS;
+
+/*! @brief USDHC internal handle pointer array */
+static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {NULL};
+
+/*! @brief USDHC IRQ name array */
+static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/*! @brief USDHC clock array name */
+static const clock_ip_name_t s_usdhcClock[] = USDHC_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
+/*! @brief Pointers to USDHC resets for each instance. */
+static const reset_ip_name_t s_usdhcResets[] = USDHC_RSTS;
+#endif
+
+/* USDHC ISR for transactional APIs. */
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
+static usdhc_isr_t s_usdhcIsr = (usdhc_isr_t)DefaultISR;
+#else
+static usdhc_isr_t s_usdhcIsr;
+#endif
+/*! @brief Dummy data buffer for mmc boot mode */
+AT_NONCACHEABLE_SECTION_ALIGN(uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN);
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t USDHC_GetInstance(USDHC_Type *base)
+{
+ uint8_t instance = 0;
+
+ while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base))
+ {
+ instance++;
+ }
+
+ assert(instance < ARRAY_SIZE(s_usdhcBase));
+
+ return instance;
+}
+
+static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, usdhc_data_t *data, uint32_t *dataPresentFlag, bool enDMA)
+{
+ uint32_t mixCtrl = base->MIX_CTRL;
+
+ if (data != NULL)
+ {
+ /* if transfer boot continous, only need set the CREQ bit, leave others as it is */
+ if (data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous)
+ {
+ /* clear stop at block gap request */
+ base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK;
+ /* continous transfer data */
+ base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK;
+ return kStatus_Success;
+ }
+
+ /* check data inhibit flag */
+ if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_DataInhibitFlag))
+ {
+ return kStatus_USDHC_BusyTransferring;
+ }
+ /* check transfer block count */
+ if ((data->blockCount > USDHC_MAX_BLOCK_COUNT) || ((data->txData == NULL) && (data->rxData == NULL)))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* config mix parameter */
+ mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
+ USDHC_MIX_CTRL_AC12EN_MASK);
+
+ if (data->rxData != NULL)
+ {
+ mixCtrl |= USDHC_MIX_CTRL_DTDSEL_MASK;
+ }
+
+ if (data->blockCount > 1U)
+ {
+ mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
+ /* auto command 12 */
+ if (data->enableAutoCommand12)
+ {
+ mixCtrl |= USDHC_MIX_CTRL_AC12EN_MASK;
+ }
+ }
+
+ /* auto command 23, auto send set block count cmd before multiple read/write */
+ if ((data->enableAutoCommand23))
+ {
+ mixCtrl |= USDHC_MIX_CTRL_AC23EN_MASK;
+ base->VEND_SPEC2 |= USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
+ /* config the block count to DS_ADDR */
+ base->DS_ADDR = data->blockCount;
+ }
+ else
+ {
+ mixCtrl &= ~USDHC_MIX_CTRL_AC23EN_MASK;
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
+ }
+
+ /* if transfer boot data, leave the block count to USDHC_SetMmcBootConfig function */
+ if (data->dataType != (uint32_t)kUSDHC_TransferDataBoot)
+ {
+ /* config data block size/block count */
+ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
+ (USDHC_BLK_ATT_BLKSIZE(data->blockSize) | USDHC_BLK_ATT_BLKCNT(data->blockCount)));
+ }
+ else
+ {
+ mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
+ base->PROT_CTRL |= USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK;
+ }
+
+ /* data present flag */
+ *dataPresentFlag |= (uint32_t)kUSDHC_DataPresentFlag;
+ }
+ else
+ {
+ /* clear data flags */
+ mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
+ USDHC_MIX_CTRL_AC12EN_MASK | USDHC_MIX_CTRL_AC23EN_MASK);
+
+ if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
+ {
+ return kStatus_USDHC_BusyTransferring;
+ }
+ }
+
+ /* config the mix parameter */
+ base->MIX_CTRL = mixCtrl;
+
+ return kStatus_Success;
+}
+
+void USDHC_SetDataConfig(USDHC_Type *base,
+ usdhc_transfer_direction_t dataDirection,
+ uint32_t blockCount,
+ uint32_t blockSize)
+{
+ assert(blockCount <= USDHC_MAX_BLOCK_COUNT);
+
+ uint32_t mixCtrl = base->MIX_CTRL;
+
+ /* block attribute configuration */
+ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
+ (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
+
+ /* config mix parameter */
+ mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK);
+
+ mixCtrl |= USDHC_MIX_CTRL_DTDSEL(dataDirection) | (blockCount > 1U ? USDHC_MIX_CTRL_MSBSEL_MASK : 0U);
+
+ base->MIX_CTRL = mixCtrl;
+}
+
+static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command)
+{
+ assert(command != NULL);
+
+ uint32_t response0 = base->CMD_RSP0;
+ uint32_t response1 = base->CMD_RSP1;
+ uint32_t response2 = base->CMD_RSP2;
+
+ if (command->responseType != kCARD_ResponseTypeNone)
+ {
+ command->response[0U] = response0;
+ if (command->responseType == kCARD_ResponseTypeR2)
+ {
+ /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
+ after removed internal CRC7 and end bit. */
+ command->response[0U] <<= 8U;
+ command->response[1U] = (response1 << 8U) | ((response0 & 0xFF000000U) >> 24U);
+ command->response[2U] = (response2 << 8U) | ((response1 & 0xFF000000U) >> 24U);
+ command->response[3U] = (base->CMD_RSP3 << 8U) | ((response2 & 0xFF000000U) >> 24U);
+ }
+ }
+
+ /* check response error flag */
+ if ((command->responseErrorFlags != 0U) &&
+ ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) ||
+ (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5)))
+ {
+ if (((command->responseErrorFlags) & (command->response[0U])) != 0U)
+ {
+ return kStatus_USDHC_SendCommandFailed;
+ }
+ }
+
+ return kStatus_Success;
+}
+
+static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
+{
+ uint32_t i;
+ uint32_t totalWords;
+ uint32_t wordsCanBeRead; /* The words can be read at this time. */
+ uint32_t readWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> USDHC_WTMK_LVL_RD_WML_SHIFT);
+
+ /* If DMA is enable, do not need to polling data port */
+ if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
+ {
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
+ if (readWatermark >= totalWords)
+ {
+ wordsCanBeRead = totalWords;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
+ transfers watermark level words. */
+ else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
+ {
+ wordsCanBeRead = readWatermark;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers
+ left
+ words. */
+ else
+ {
+ wordsCanBeRead = (totalWords - transferredWords);
+ }
+
+ i = 0U;
+ while (i < wordsCanBeRead)
+ {
+ data->rxData[transferredWords++] = USDHC_ReadData(base);
+ i++;
+ }
+ }
+
+ return transferredWords;
+}
+
+static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
+{
+ uint32_t totalWords;
+ uint32_t transferredWords = 0U, interruptStatus = 0U;
+ status_t error = kStatus_Success;
+
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ while ((error == kStatus_Success) && (transferredWords < totalWords))
+ {
+ while (
+ !(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_BufferReadReadyFlag |
+ (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+
+ /* during std tuning process, software do not need to read data, but wait BRR is enough */
+ if ((data->dataType == (uint32_t)kUSDHC_TransferDataTuning) &&
+ (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_BufferReadReadyFlag)))
+ {
+ USDHC_ClearInterruptStatusFlags(base,
+ (uint32_t)kUSDHC_BufferReadReadyFlag | (uint32_t)kUSDHC_TuningPassFlag);
+
+ return kStatus_Success;
+ }
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
+ /* if tuning error occur ,return directly */
+ error = kStatus_USDHC_TuningError;
+ }
+#endif
+ else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ /* clear data error flag */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ if (error == kStatus_Success)
+ {
+ transferredWords = USDHC_ReadDataPort(base, data, transferredWords);
+ /* clear buffer read ready */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
+ interruptStatus = 0U;
+ }
+ }
+
+ /* Clear data complete flag after the last read operation. */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataCompleteFlag);
+
+ return error;
+}
+
+static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
+{
+ uint32_t i;
+ uint32_t totalWords;
+ uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
+ uint32_t writeWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> USDHC_WTMK_LVL_WR_WML_SHIFT);
+
+ /* If DMA is enable, do not need to polling data port */
+ if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
+ {
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
+
+ /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
+ if (writeWatermark >= totalWords)
+ {
+ wordsCanBeWrote = totalWords;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
+ transfers watermark level words. */
+ else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
+ {
+ wordsCanBeWrote = writeWatermark;
+ }
+ /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
+ words. */
+ else
+ {
+ wordsCanBeWrote = (totalWords - transferredWords);
+ }
+
+ i = 0U;
+ while (i < wordsCanBeWrote)
+ {
+ USDHC_WriteData(base, data->txData[transferredWords++]);
+ i++;
+ }
+ }
+
+ return transferredWords;
+}
+
+static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
+{
+ uint32_t totalWords;
+
+ uint32_t transferredWords = 0U, interruptStatus = 0U;
+ status_t error = kStatus_Success;
+
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (data->blockSize % sizeof(uint32_t) != 0U)
+ {
+ data->blockSize +=
+ sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
+ }
+
+ totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
+
+ while ((error == kStatus_Success) && (transferredWords < totalWords))
+ {
+ while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_BufferWriteReadyFlag |
+ (uint32_t)kUSDHC_DataErrorFlag |
+ (uint32_t)kUSDHC_TuningErrorFlag)))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
+ /* if tuning error occur ,return directly */
+ return kStatus_USDHC_TuningError;
+ }
+ else
+#endif
+ if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ /* clear data error flag */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ if (error == kStatus_Success)
+ {
+ transferredWords = USDHC_WriteDataPort(base, data, transferredWords);
+ /* clear buffer write ready */
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferWriteReadyFlag);
+ interruptStatus = 0U;
+ }
+ }
+
+ /* Wait write data complete or data transfer error after the last writing operation. */
+ while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag)))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+
+ if ((interruptStatus & (uint32_t)kUSDHC_DataErrorFlag) != 0UL)
+ {
+ if (!(data->enableIgnoreError))
+ {
+ error = kStatus_Fail;
+ }
+ }
+ USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag));
+
+ return error;
+}
+
+/*!
+ * brief send command function
+ *
+ * param base USDHC peripheral base address.
+ * param command configuration
+ */
+void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command)
+{
+ assert(NULL != command);
+
+ uint32_t xferType = base->CMD_XFR_TYP, flags = command->flags;
+
+ if (((base->PRES_STATE & (uint32_t)kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty))
+ {
+ if ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR5) ||
+ (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR7))
+ {
+ flags |= ((uint32_t)kUSDHC_ResponseLength48Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
+ (uint32_t)kUSDHC_EnableIndexCheckFlag);
+ }
+ else if ((command->responseType == kCARD_ResponseTypeR1b) || (command->responseType == kCARD_ResponseTypeR5b))
+ {
+ flags |= ((uint32_t)kUSDHC_ResponseLength48BusyFlag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
+ (uint32_t)kUSDHC_EnableIndexCheckFlag);
+ }
+ else if (command->responseType == kCARD_ResponseTypeR2)
+ {
+ flags |= ((uint32_t)kUSDHC_ResponseLength136Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag);
+ }
+ else if ((command->responseType == kCARD_ResponseTypeR3) || (command->responseType == kCARD_ResponseTypeR4))
+ {
+ flags |= ((uint32_t)kUSDHC_ResponseLength48Flag);
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+
+ if (command->type == kCARD_CommandTypeAbort)
+ {
+ flags |= (uint32_t)kUSDHC_CommandTypeAbortFlag;
+ }
+
+ /* config cmd index */
+ xferType &= ~(USDHC_CMD_XFR_TYP_CMDINX_MASK | USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK |
+ USDHC_CMD_XFR_TYP_CCCEN_MASK | USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK);
+
+ xferType |=
+ (((command->index << USDHC_CMD_XFR_TYP_CMDINX_SHIFT) & USDHC_CMD_XFR_TYP_CMDINX_MASK) |
+ ((flags) & (USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK | USDHC_CMD_XFR_TYP_CCCEN_MASK |
+ USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK)));
+
+ /* config the command xfertype and argument */
+ base->CMD_ARG = command->argument;
+ base->CMD_XFR_TYP = xferType;
+ }
+
+ if (command->type == kCARD_CommandTypeEmpty)
+ {
+ /* disable CMD done interrupt for empty command */
+ base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK;
+ }
+}
+
+static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone)
+{
+ assert(NULL != command);
+
+ status_t error = kStatus_Success;
+ uint32_t interruptStatus = 0U;
+ /* check if need polling command done or not */
+ if (pollingCmdDone)
+ {
+ /* Wait command complete or USDHC encounters error. */
+ while (!(IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_CommandFlag)))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+
+ if ((interruptStatus & (uint32_t)kUSDHC_CommandErrorFlag) != 0UL)
+ {
+ error = kStatus_Fail;
+ }
+
+ /* Receive response when command completes successfully. */
+ if (error == kStatus_Success)
+ {
+ error = USDHC_ReceiveCommandResponse(base, command);
+ }
+
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
+ }
+
+ return error;
+}
+
+static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA)
+{
+ status_t error = kStatus_Success;
+ uint32_t interruptStatus = 0U;
+
+ if (enDMA)
+ {
+ /* Wait data complete or USDHC encounters error. */
+ while (!(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
+ {
+ interruptStatus = USDHC_GetInterruptStatusFlags(base);
+ }
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
+ {
+ error = kStatus_USDHC_TuningError;
+ }
+ else
+#endif
+ if (IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
+ {
+ if ((!(data->enableIgnoreError)) || (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataTimeoutFlag)))
+ {
+ error = kStatus_USDHC_TransferDataFailed;
+ }
+ }
+ else
+ {
+ /* Intentional empty */
+ }
+ /* load dummy data */
+ if ((data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success))
+ {
+ *(data->rxData) = s_usdhcBootDummy;
+ }
+
+ USDHC_ClearInterruptStatusFlags(
+ base, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningPassFlag | (uint32_t)kUSDHC_TuningErrorFlag));
+ }
+ else
+ {
+ if (data->rxData != NULL)
+ {
+ error = USDHC_ReadByDataPortBlocking(base, data);
+ if (error != kStatus_Success)
+ {
+ return error;
+ }
+ }
+ else
+ {
+ error = USDHC_WriteByDataPortBlocking(base, data);
+ if (error != kStatus_Success)
+ {
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+/*!
+ * brief USDHC module initialization function.
+ *
+ * Configures the USDHC according to the user configuration.
+ *
+ * Example:
+ code
+ usdhc_config_t config;
+ config.cardDetectDat3 = false;
+ config.endianMode = kUSDHC_EndianModeLittle;
+ config.dmaMode = kUSDHC_DmaModeAdma2;
+ config.readWatermarkLevel = 128U;
+ config.writeWatermarkLevel = 128U;
+ USDHC_Init(USDHC, &config);
+ endcode
+ *
+ * param base USDHC peripheral base address.
+ * param config USDHC configuration information.
+ * retval kStatus_Success Operate successfully.
+ */
+void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config)
+{
+ assert(config != NULL);
+ assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U));
+ assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U));
+#if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
+ assert(config->writeBurstLen <= 16U);
+#endif
+ uint32_t proctl, sysctl, wml;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable USDHC clock. */
+ CLOCK_EnableClock(s_usdhcClock[USDHC_GetInstance(base)]);
+#endif
+
+#if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
+ /* Reset the USDHC module */
+ RESET_PeripheralReset(s_usdhcResets[USDHC_GetInstance(base)]);
+#endif
+
+ /* Reset ALL USDHC. */
+ base->SYS_CTRL |= USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK;
+
+ proctl = base->PROT_CTRL;
+ wml = base->WTMK_LVL;
+ sysctl = base->SYS_CTRL;
+
+ proctl &= ~(USDHC_PROT_CTRL_EMODE_MASK | USDHC_PROT_CTRL_DMASEL_MASK);
+ /* Endian mode*/
+ proctl |= USDHC_PROT_CTRL_EMODE(config->endianMode);
+
+#if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
+ /* Watermark level */
+ wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK);
+ wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel));
+#else
+ /* Watermark level */
+ wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK | USDHC_WTMK_LVL_RD_BRST_LEN_MASK |
+ USDHC_WTMK_LVL_WR_BRST_LEN_MASK);
+ wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel) |
+ USDHC_WTMK_LVL_RD_BRST_LEN(config->readBurstLen) | USDHC_WTMK_LVL_WR_BRST_LEN(config->writeBurstLen));
+#endif
+
+ /* config the data timeout value */
+ sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK;
+ sysctl |= USDHC_SYS_CTRL_DTOCV(config->dataTimeout);
+
+ base->SYS_CTRL = sysctl;
+ base->WTMK_LVL = wml;
+ base->PROT_CTRL = proctl;
+
+#if FSL_FEATURE_USDHC_HAS_EXT_DMA
+ /* disable external DMA */
+ base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
+#endif
+ /* disable internal DMA and DDR mode */
+ base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | USDHC_MIX_CTRL_DDR_EN_MASK);
+ /* disable interrupt, enable all the interrupt status, clear status. */
+ base->INT_STATUS_EN = kUSDHC_AllInterruptFlags;
+ base->INT_SIGNAL_EN = 0UL;
+ base->INT_STATUS = kUSDHC_AllInterruptFlags;
+}
+
+/*!
+ * brief Deinitializes the USDHC.
+ *
+ * param base USDHC peripheral base address.
+ */
+void USDHC_Deinit(USDHC_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable clock. */
+ CLOCK_DisableClock(s_usdhcClock[USDHC_GetInstance(base)]);
+#endif
+}
+
+/*!
+ * brief Resets the USDHC.
+ *
+ * param base USDHC peripheral base address.
+ * param mask The reset type mask(_usdhc_reset).
+ * param timeout Timeout for reset.
+ * retval true Reset successfully.
+ * retval false Reset failed.
+ */
+bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout)
+{
+ base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ | USDHC_SYS_CTRL_RSTT_MASK
+#endif
+ ));
+ /* Delay some time to wait reset success. */
+ while (IS_USDHC_FLAG_SET(base->SYS_CTRL, mask))
+ {
+ if (timeout == 0UL)
+ {
+ break;
+ }
+ timeout--;
+ }
+
+ return ((0UL == timeout) ? false : true);
+}
+
+/*!
+ * brief Gets the capability information.
+ *
+ * param base USDHC peripheral base address.
+ * param capability Structure to save capability information.
+ */
+void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability)
+{
+ assert(capability != NULL);
+
+ uint32_t htCapability;
+ uint32_t maxBlockLength;
+
+ htCapability = base->HOST_CTRL_CAP;
+
+ /* Get the capability of USDHC. */
+ maxBlockLength = ((htCapability & USDHC_HOST_CTRL_CAP_MBL_MASK) >> USDHC_HOST_CTRL_CAP_MBL_SHIFT);
+ capability->maxBlockLength = (512UL << maxBlockLength);
+ /* Other attributes not in HTCAPBLT register. */
+ capability->maxBlockCount = USDHC_MAX_BLOCK_COUNT;
+ capability->flags =
+ (htCapability & (USDHC_HOST_CTRL_CAP_ADMAS_MASK | USDHC_HOST_CTRL_CAP_HSS_MASK | USDHC_HOST_CTRL_CAP_DMAS_MASK |
+ USDHC_HOST_CTRL_CAP_SRS_MASK | USDHC_HOST_CTRL_CAP_VS33_MASK));
+ capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS30_MASK;
+ capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS18_MASK;
+ capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK;
+#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR104_MODE
+ capability->flags |= USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK;
+#endif
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR50_MODE
+ capability->flags |= USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK;
+#endif
+ /* USDHC support 4/8 bit data bus width. */
+ capability->flags |= (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0UL) | (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1UL);
+}
+
+/*!
+ * brief Sets the SD bus clock frequency.
+ *
+ * param base USDHC peripheral base address.
+ * param srcClock_Hz USDHC source clock frequency united in Hz.
+ * param busClock_Hz SD bus clock frequency united in Hz.
+ *
+ * return The nearest frequency of busClock_Hz configured to SD bus.
+ */
+uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
+{
+ assert(srcClock_Hz != 0U);
+ assert(busClock_Hz != 0U);
+
+ uint32_t totalDiv = 0UL;
+ uint32_t divisor = 0UL;
+ uint32_t prescaler = 0UL;
+ uint32_t sysctl = 0UL;
+ uint32_t nearestFrequency = 0UL;
+
+ if (busClock_Hz > srcClock_Hz)
+ {
+ busClock_Hz = srcClock_Hz;
+ }
+
+ /* calucate total divisor first */
+ if ((totalDiv = srcClock_Hz / busClock_Hz) > (USDHC_MAX_CLKFS * USDHC_MAX_DVS))
+ {
+ return 0UL;
+ }
+
+ if (totalDiv != 0UL)
+ {
+ /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */
+ if ((srcClock_Hz / totalDiv) > busClock_Hz)
+ {
+ totalDiv++;
+ }
+
+ /* divide the total divisor to div and prescaler */
+ if (totalDiv > USDHC_MAX_DVS)
+ {
+ prescaler = totalDiv / USDHC_MAX_DVS;
+ /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */
+ while (((USDHC_MAX_CLKFS % prescaler) != 0UL) || (prescaler == 1UL))
+ {
+ prescaler++;
+ }
+ /* calucate the divisor */
+ divisor = totalDiv / prescaler;
+ /* fine tuning the divisor until divisor * prescaler >= totalDiv */
+ while ((divisor * prescaler) < totalDiv)
+ {
+ divisor++;
+ if (divisor > USDHC_MAX_DVS)
+ {
+ if ((prescaler <<= 1UL) > USDHC_MAX_CLKFS)
+ {
+ return 0UL;
+ }
+ divisor = totalDiv / prescaler;
+ }
+ }
+ }
+ else
+ {
+ /* in this situation , divsior and SDCLKFS can generate same clock
+ use SDCLKFS*/
+ if (((totalDiv % 2UL) != 0UL) && (totalDiv != 1UL))
+ {
+ divisor = totalDiv;
+ prescaler = 1UL;
+ }
+ else
+ {
+ divisor = 1UL;
+ prescaler = totalDiv;
+ }
+ }
+ nearestFrequency = srcClock_Hz / (divisor == 0UL ? 1UL : divisor) / prescaler;
+ }
+ /* in this condition , srcClock_Hz = busClock_Hz, */
+ else
+ {
+ /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the
+ totoal divider = 2U */
+ divisor = 0UL;
+ prescaler = 0UL;
+ nearestFrequency = srcClock_Hz;
+ }
+
+ /* calucate the value write to register */
+ if (divisor != 0UL)
+ {
+ USDHC_PREV_DVS(divisor);
+ }
+ /* calucate the value write to register */
+ if (prescaler != 0UL)
+ {
+ USDHC_PREV_CLKFS(prescaler, 1UL);
+ }
+
+ /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
+ sysctl = base->SYS_CTRL;
+ sysctl &= ~(USDHC_SYS_CTRL_DVS_MASK | USDHC_SYS_CTRL_SDCLKFS_MASK);
+ sysctl |= (USDHC_SYS_CTRL_DVS(divisor) | USDHC_SYS_CTRL_SDCLKFS(prescaler));
+ base->SYS_CTRL = sysctl;
+
+ /* Wait until the SD clock is stable. */
+ while (!IS_USDHC_FLAG_SET(base->PRES_STATE, USDHC_PRES_STATE_SDSTB_MASK))
+ {
+ }
+
+ return nearestFrequency;
+}
+
+/*!
+ * brief Sends 80 clocks to the card to set it to the active state.
+ *
+ * This function must be called each time the card is inserted to ensure that the card can receive the command
+ * correctly.
+ *
+ * param base USDHC peripheral base address.
+ * param timeout Timeout to initialize card.
+ * retval true Set card active successfully.
+ * retval false Set card active failed.
+ */
+bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout)
+{
+ base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK;
+ /* Delay some time to wait card become active state. */
+ while (IS_USDHC_FLAG_SET(base->SYS_CTRL, USDHC_SYS_CTRL_INITA_MASK))
+ {
+ if (0UL == timeout)
+ {
+ break;
+ }
+ timeout--;
+ }
+
+ return ((0UL == timeout) ? false : true);
+}
+
+/*!
+ * brief the enable/disable DDR mode
+ *
+ * param base USDHC peripheral base address.
+ * param enable/disable flag
+ * param nibble position
+ */
+void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos)
+{
+ uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> USDHC_SYS_CTRL_SDCLKFS_SHIFT;
+
+ if (enable)
+ {
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK;
+ base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | USDHC_MIX_CTRL_NIBBLE_POS(nibblePos));
+ prescaler >>= 1UL;
+ }
+ else
+ {
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK;
+
+ if (prescaler == 0UL)
+ {
+ prescaler += 1UL;
+ }
+ else
+ {
+ prescaler <<= 1UL;
+ }
+ }
+
+ base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | USDHC_SYS_CTRL_SDCLKFS(prescaler);
+}
+
+/*!
+ * brief Configures the MMC boot feature.
+ *
+ * Example:
+ code
+ usdhc_boot_config_t config;
+ config.ackTimeoutCount = 4;
+ config.bootMode = kUSDHC_BootModeNormal;
+ config.blockCount = 5;
+ config.enableBootAck = true;
+ config.enableBoot = true;
+ config.enableAutoStopAtBlockGap = true;
+ USDHC_SetMmcBootConfig(USDHC, &config);
+ endcode
+ *
+ * param base USDHC peripheral base address.
+ * param config The MMC boot configuration information.
+ */
+void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config)
+{
+ assert(config != NULL);
+ assert(config->ackTimeoutCount <= (USDHC_MMC_BOOT_DTOCV_ACK_MASK >> USDHC_MMC_BOOT_DTOCV_ACK_SHIFT));
+ assert(config->blockCount <= (USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK >> USDHC_MMC_BOOT_BOOT_BLK_CNT_SHIFT));
+
+ uint32_t mmcboot = base->MMC_BOOT;
+
+ mmcboot &= ~(USDHC_MMC_BOOT_DTOCV_ACK_MASK | USDHC_MMC_BOOT_BOOT_MODE_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK);
+ mmcboot |= USDHC_MMC_BOOT_DTOCV_ACK(config->ackTimeoutCount) | USDHC_MMC_BOOT_BOOT_MODE(config->bootMode);
+
+ if (config->enableBootAck)
+ {
+ mmcboot |= USDHC_MMC_BOOT_BOOT_ACK_MASK;
+ }
+ if (config->enableAutoStopAtBlockGap)
+ {
+ mmcboot |=
+ USDHC_MMC_BOOT_AUTO_SABG_EN_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT(USDHC_MAX_BLOCK_COUNT - config->blockCount);
+ /* always set the block count to USDHC_MAX_BLOCK_COUNT to use auto stop at block gap feature */
+ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
+ (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(USDHC_MAX_BLOCK_COUNT)));
+ }
+ else
+ {
+ base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
+ (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(config->blockCount)));
+ }
+
+ base->MMC_BOOT = mmcboot;
+}
+
+/*!
+ * brief Sets the ADMA1 descriptor table configuration.
+ *
+ * param admaTable Adma table address.
+ * param admaTableWords Adma table length.
+ * param dataBufferAddr Data buffer address.
+ * param dataBytes Data length.
+ * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * reference _usdhc_adma_flag.
+ * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetADMA1Descriptor(
+ uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
+{
+ assert(NULL != admaTable);
+ assert(NULL != dataBufferAddr);
+
+ uint32_t miniEntries, startEntries = 0UL,
+ maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma1_descriptor_t);
+ usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(uint32_t)(admaTable);
+ uint32_t i, dmaBufferLen = 0UL;
+ const uint32_t *data = dataBufferAddr;
+
+ if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0UL)
+ {
+ return kStatus_USDHC_DMADataAddrNotAlign;
+ }
+
+ if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
+ {
+ return kStatus_USDHC_NotSupport;
+ }
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (dataBytes % sizeof(uint32_t) != 0UL)
+ {
+ /* make the data length as word-aligned */
+ dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
+ }
+
+ /* Check if ADMA descriptor's number is enough. */
+ if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
+ {
+ miniEntries = dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ }
+ else
+ {
+ miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
+ }
+
+ /* ADMA1 needs two descriptors to finish a transfer */
+ miniEntries <<= 1UL;
+
+ if (miniEntries + startEntries > maxEntries)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ for (i = startEntries; i < (miniEntries + startEntries); i += 2UL)
+ {
+ if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
+ {
+ dmaBufferLen = USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ }
+ else
+ {
+ dmaBufferLen = dataBytes;
+ }
+
+ adma1EntryAddress[i] = (dmaBufferLen << USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
+ adma1EntryAddress[i] |= (uint32_t)kUSDHC_Adma1DescriptorTypeSetLength;
+ adma1EntryAddress[i + 1UL] = (uint32_t)(data);
+ adma1EntryAddress[i + 1UL] |= (uint32_t)kUSDHC_Adma1DescriptorTypeTransfer;
+ data += dmaBufferLen / sizeof(uint32_t);
+ dataBytes -= dmaBufferLen;
+ }
+ /* the end of the descriptor */
+ adma1EntryAddress[i - 1UL] |= (uint32_t)kUSDHC_Adma1DescriptorEndFlag;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sets the ADMA2 descriptor table configuration.
+ *
+ * param admaTable Adma table address.
+ * param admaTableWords Adma table length.
+ * param dataBufferAddr Data buffer address.
+ * param dataBytes Data Data length.
+ * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * reference _usdhc_adma_flag.
+ * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetADMA2Descriptor(
+ uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
+{
+ assert(NULL != admaTable);
+ assert(NULL != dataBufferAddr);
+
+ uint32_t miniEntries, startEntries = 0UL,
+ maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma2_descriptor_t);
+ usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(uint32_t)(admaTable);
+ uint32_t i, dmaBufferLen = 0UL;
+ const uint32_t *data = dataBufferAddr;
+
+ if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
+ {
+ return kStatus_USDHC_DMADataAddrNotAlign;
+ }
+ /*
+ * Add non aligned access support ,user need make sure your buffer size is big
+ * enough to hold the data,in other words,user need make sure the buffer size
+ * is 4 byte aligned
+ */
+ if (dataBytes % sizeof(uint32_t) != 0UL)
+ {
+ /* make the data length as word-aligned */
+ dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
+ }
+
+ /* Check if ADMA descriptor's number is enough. */
+ if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
+ {
+ miniEntries = dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ }
+ else
+ {
+ miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
+ }
+ /* calucate the start entry for multiple descriptor mode, ADMA engine is not stop, so update the descriptor
+ data adress and data size is enough */
+ if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
+ {
+ for (i = 0UL; i < maxEntries; i++)
+ {
+ if ((adma2EntryAddress[i].attribute & (uint32_t)kUSDHC_Adma2DescriptorValidFlag) == 0UL)
+ {
+ break;
+ }
+ }
+ startEntries = i;
+ /* add one entry for dummy entry */
+ miniEntries += 1UL;
+ }
+
+ if ((miniEntries + startEntries) > maxEntries)
+ {
+ return kStatus_OutOfRange;
+ }
+
+ for (i = startEntries; i < (miniEntries + startEntries); i++)
+ {
+ if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
+ {
+ dmaBufferLen = USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
+ }
+ else
+ {
+ dmaBufferLen = (dataBytes == 0UL ? sizeof(uint32_t) :
+ dataBytes); /* adma don't support 0 data length transfer descriptor */
+ }
+
+ /* Each descriptor for ADMA2 is 64-bit in length */
+ adma2EntryAddress[i].address = (dataBytes == 0UL) ? &s_usdhcBootDummy : data;
+ adma2EntryAddress[i].attribute = (dmaBufferLen << USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
+ adma2EntryAddress[i].attribute |=
+ (dataBytes == 0UL) ?
+ 0UL :
+ ((uint32_t)kUSDHC_Adma2DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma2DescriptorInterruptFlag);
+ data += (dmaBufferLen / sizeof(uint32_t));
+
+ if (dataBytes != 0UL)
+ {
+ dataBytes -= dmaBufferLen;
+ }
+ }
+
+ /* add a dummy valid ADMA descriptor for multiple descriptor mode, this is useful when transfer boot data, the ADMA
+ engine
+ will not stop at block gap */
+ if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
+ {
+ adma2EntryAddress[startEntries + 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorTypeTransfer;
+ }
+ else
+ {
+ /* set the end bit */
+ adma2EntryAddress[i - 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorEndFlag;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Internal DMA configuration.
+ * This function is used to config the USDHC DMA related registers.
+ * param base USDHC peripheral base address.
+ * param adma configuration
+ * param dataAddr transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL.
+ * param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it to
+ * false.
+ * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetInternalDmaConfig(USDHC_Type *base,
+ usdhc_adma_config_t *dmaConfig,
+ const uint32_t *dataAddr,
+ bool enAutoCmd23)
+{
+ assert(dmaConfig != NULL);
+ assert(dataAddr != NULL);
+ assert((NULL != dmaConfig->admaTable) &&
+ (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
+
+#if FSL_FEATURE_USDHC_HAS_EXT_DMA
+ /* disable the external DMA if support */
+ base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
+#endif
+
+ if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
+ {
+ /* check DMA data buffer address align or not */
+ if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
+ {
+ return kStatus_USDHC_DMADataAddrNotAlign;
+ }
+ /* in simple DMA mode if use auto CMD23, address should load to ADMA addr,
+ and block count should load to DS_ADDR*/
+ if (enAutoCmd23)
+ {
+ base->ADMA_SYS_ADDR = (uint32_t)dataAddr;
+ }
+ else
+ {
+ base->DS_ADDR = (uint32_t)dataAddr;
+ }
+ }
+ else
+ {
+ /* When use ADMA, disable simple DMA */
+ base->DS_ADDR = 0UL;
+ base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable);
+ }
+
+#if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
+ /* select DMA mode and config the burst length */
+ base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
+ base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
+#else
+ /* select DMA mode and config the burst length */
+ base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | USDHC_PROT_CTRL_BURST_LEN_EN_MASK);
+ base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode) | USDHC_PROT_CTRL_BURST_LEN_EN(dmaConfig->burstLen);
+#endif
+ /* enable DMA */
+ base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Sets the DMA descriptor table configuration.
+ * A high level DMA descriptor configuration function.
+ * param base USDHC peripheral base address.
+ * param adma configuration
+ * param data Data descriptor
+ * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
+ * reference _usdhc_adma_flag
+ * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_SetAdmaTableConfig(USDHC_Type *base,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_data_t *dataConfig,
+ uint32_t flags)
+{
+ assert(NULL != dmaConfig);
+ assert((NULL != dmaConfig->admaTable) &&
+ (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
+ assert(NULL != dataConfig);
+
+ status_t error = kStatus_Fail;
+ uint32_t bootDummyOffset =
+ dataConfig->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0UL;
+ const uint32_t *data =
+ (const uint32_t *)((uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) +
+ bootDummyOffset);
+ uint32_t blockSize = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset;
+
+#if FSL_FEATURE_USDHC_HAS_EXT_DMA
+ if (dmaConfig->dmaMode == kUSDHC_ExternalDMA)
+ {
+ /* enable the external DMA */
+ base->VEND_SPEC |= USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
+ }
+ else
+#endif
+ if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
+ {
+ error = kStatus_Success;
+ }
+ else if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
+ {
+ error = USDHC_SetADMA1Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
+ }
+ /* ADMA2 */
+ else
+ {
+ error = USDHC_SetADMA2Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
+ }
+
+ /* for internal dma, internal DMA configurations should not update the configurations when continous transfer the
+ * boot data, only the DMA descriptor need update */
+ if ((dmaConfig->dmaMode != kUSDHC_ExternalDMA) && (error == kStatus_Success) &&
+ (dataConfig->dataType != (uint32_t)kUSDHC_TransferDataBootcontinous))
+ {
+ error = USDHC_SetInternalDmaConfig(base, dmaConfig, data, dataConfig->enableAutoCommand23);
+ }
+
+ return error;
+}
+
+/*!
+ * brief Transfers the command/data using a blocking method.
+ *
+ * This function waits until the command response/data is received or the USDHC encounters an error by polling the
+ * status
+ * flag.
+ * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
+ * the re-entry mechanism.
+ *
+ * note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API.
+ *
+ * param base USDHC peripheral base address.
+ * param adma configuration
+ * param transfer Transfer content.
+ * retval kStatus_InvalidArgument Argument is invalid.
+ * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
+ * retval kStatus_USDHC_SendCommandFailed Send command failed.
+ * retval kStatus_USDHC_TransferDataFailed Transfer data failed.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer)
+{
+ assert(transfer != NULL);
+
+ status_t error = kStatus_Fail;
+ usdhc_command_t *command = transfer->command;
+ usdhc_data_t *data = transfer->data;
+ bool enDMA = true;
+ bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ /*check re-tuning request*/
+ if ((USDHC_GetInterruptStatusFlags(base) & (uint32_t)kUSDHC_ReTuningEventFlag) != 0UL)
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
+ return kStatus_USDHC_ReTuningRequest;
+ }
+#endif
+
+ /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
+ if ((data != NULL) && (dmaConfig != NULL) && (!executeTuning))
+ {
+ error = USDHC_SetAdmaTableConfig(
+ base, dmaConfig, data,
+ (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, kUSDHC_TransferDataBoot) ? kUSDHC_AdmaDescriptorMultipleFlag :
+ kUSDHC_AdmaDescriptorSingleFlag));
+ }
+
+ /* if the DMA desciptor configure fail or not needed , disable it */
+ if (error != kStatus_Success)
+ {
+ enDMA = false;
+ /* disable DMA, using polling mode in this situation */
+ USDHC_EnableInternalDMA(base, false);
+ }
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ else
+ {
+ if (data->txData != NULL)
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
+ }
+ else
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
+ }
+ }
+#endif
+
+ /* config the data transfer parameter */
+ error = USDHC_SetDataTransferConfig(base, data, &(command->flags), enDMA);
+ if (kStatus_Success != error)
+ {
+ return error;
+ }
+ /* send command first */
+ USDHC_SendCommand(base, command);
+ /* wait command done */
+ error =
+ USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == (uint32_t)kUSDHC_TransferDataNormal));
+ if (kStatus_Success != error)
+ {
+ return kStatus_USDHC_SendCommandFailed;
+ }
+
+ /* wait transfer data finsih */
+ if (data != NULL)
+ {
+ error = USDHC_TransferDataBlocking(base, data, enDMA);
+ if (kStatus_Success != error)
+ {
+ return error;
+ }
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Transfers the command/data using an interrupt and an asynchronous method.
+ *
+ * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or encounter an
+ * error.
+ * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
+ * the re-entry mechanism.
+ *
+ * note Call the API 'USDHC_TransferCreateHandle' when calling this API.
+ *
+ * param base USDHC peripheral base address.
+ * param handle USDHC handle.
+ * param adma configuration.
+ * param transfer Transfer content.
+ * retval kStatus_InvalidArgument Argument is invalid.
+ * retval kStatus_USDHC_BusyTransferring Busy transferring.
+ * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
+ * retval kStatus_Success Operate successfully.
+ */
+status_t USDHC_TransferNonBlocking(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ usdhc_adma_config_t *dmaConfig,
+ usdhc_transfer_t *transfer)
+{
+ assert(handle != NULL);
+ assert(transfer != NULL);
+
+ status_t error = kStatus_Fail;
+ usdhc_command_t *command = transfer->command;
+ usdhc_data_t *data = transfer->data;
+ bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
+ bool enDMA = true;
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ /*check re-tuning request*/
+ if ((USDHC_GetInterruptStatusFlags(base) & ((uint32_t)kUSDHC_ReTuningEventFlag)) != 0UL)
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
+ return kStatus_USDHC_ReTuningRequest;
+ }
+#endif
+ /* Save command and data into handle before transferring. */
+
+ handle->command = command;
+ handle->data = data;
+ /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
+ handle->transferredWords = 0UL;
+
+ /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
+ if ((data != NULL) && (dmaConfig != NULL) && (!executeTuning))
+ {
+ error =
+ USDHC_SetAdmaTableConfig(base, dmaConfig, data,
+ (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, (uint32_t)kUSDHC_TransferDataBoot) ?
+ kUSDHC_AdmaDescriptorMultipleFlag :
+ kUSDHC_AdmaDescriptorSingleFlag));
+ }
+
+ /* if the DMA desciptor configure fail or not needed , disable it */
+ if (error != kStatus_Success)
+ {
+ /* disable DMA, using polling mode in this situation */
+ USDHC_EnableInternalDMA(base, false);
+ enDMA = false;
+ }
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ else
+ {
+ if (data->txData != NULL)
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
+ }
+ else
+ {
+ /* clear the DCACHE */
+ DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
+ }
+ }
+#endif
+
+ error = USDHC_SetDataTransferConfig(base, data, &(command->flags), enDMA);
+ if (kStatus_Success != error)
+ {
+ return error;
+ }
+
+ /* enable interrupt per transfer request */
+ if (handle->data != NULL)
+ {
+ USDHC_ClearInterruptStatusFlags(
+ base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) | (uint32_t)kUSDHC_CommandFlag);
+ USDHC_EnableInterruptSignal(
+ base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) | (uint32_t)kUSDHC_CommandFlag);
+ }
+ else
+ {
+ USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
+ USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
+ }
+
+ /* send command first */
+ USDHC_SendCommand(base, command);
+
+ return kStatus_Success;
+}
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+/*!
+ * brief manual tuning trigger or abort
+ * User should handle the tuning cmd and find the boundary of the delay
+ * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS
+ * This function should called before USDHC_AdjustDelayforSDR104 function
+ * param base USDHC peripheral base address.
+ * param tuning enable flag
+ */
+void USDHC_EnableManualTuning(USDHC_Type *base, bool enable)
+{
+ if (enable)
+ {
+ /* make sure std_tun_en bit is clear */
+ base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
+ /* disable auto tuning here */
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK;
+ /* execute tuning for SDR104 mode */
+ base->MIX_CTRL |=
+ USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK | USDHC_MIX_CTRL_FBCLK_SEL_MASK;
+ }
+ else
+ { /* abort the tuning */
+ base->MIX_CTRL &= ~USDHC_MIX_CTRL_EXE_TUNE_MASK;
+ }
+}
+
+/*!
+ * brief the SDR104 mode delay setting adjust
+ * This function should called after USDHC_ManualTuningForSDR104
+ * param base USDHC peripheral base address.
+ * param delay setting configuration
+ * retval kStatus_Fail config the delay setting fail
+ * retval kStatus_Success config the delay setting success
+ */
+status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay)
+{
+ uint32_t clkTuneCtrl = 0UL;
+
+ clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
+
+ clkTuneCtrl &= ~USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK;
+
+ clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(delay);
+
+ /* load the delay setting */
+ base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
+ /* check delat setting error */
+ if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
+ USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
+ {
+ return kStatus_Fail;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief the enable standard tuning function
+ * The standard tuning window and tuning counter use the default config
+ * tuning cmd is send by the software, user need to check the tuning result
+ * can be used for SDR50,SDR104,HS200 mode tuning
+ * param base USDHC peripheral base address.
+ * param tuning start tap
+ * param tuning step
+ * param enable/disable flag
+ */
+void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable)
+{
+ uint32_t tuningCtrl = 0UL;
+
+ if (enable)
+ {
+ /* feedback clock */
+ base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK;
+ /* config tuning start and step */
+ tuningCtrl = base->TUNING_CTRL;
+ tuningCtrl &= ~(USDHC_TUNING_CTRL_TUNING_START_TAP_MASK | USDHC_TUNING_CTRL_TUNING_STEP_MASK);
+ tuningCtrl |= (USDHC_TUNING_CTRL_TUNING_START_TAP(tuningStartTap) | USDHC_TUNING_CTRL_TUNING_STEP(step) |
+ USDHC_TUNING_CTRL_STD_TUNING_EN_MASK);
+ base->TUNING_CTRL = tuningCtrl;
+
+ /* excute tuning */
+ base->AUTOCMD12_ERR_STATUS |=
+ (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
+ }
+ else
+ {
+ /* disable the standard tuning */
+ base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
+ /* clear excute tuning */
+ base->AUTOCMD12_ERR_STATUS &=
+ ~(USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
+ }
+}
+
+#if FSL_FEATURE_USDHC_HAS_HS400_MODE
+/*!
+ * brief config the strobe DLL delay target and update interval
+ *
+ * param base USDHC peripheral base address.
+ * param delayTarget delay target
+ * param updateInterval update interval
+ */
+void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval)
+{
+ assert(delayTarget <= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_MASK >>
+ USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT));
+
+ /* reset strobe dll firstly */
+ base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK;
+ /* clear reset and other register fields */
+ base->STROBE_DLL_CTRL = 0;
+ /* configure the DELAY target and update interval */
+ base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK |
+ USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT(updateInterval) |
+ USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET(delayTarget);
+
+ while (
+ (USDHC_GetStrobeDLLStatus(base) & (USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK |
+ USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)) !=
+ ((USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK | USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)))
+ {
+ }
+}
+#endif
+
+/*!
+ * brief the auto tuning enbale for CMD/DATA line
+ *
+ * param base USDHC peripheral base address.
+ */
+void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base)
+{
+ uint32_t busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT;
+
+ base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_CMD_EN_MASK;
+
+ /* 1bit data width */
+ if (busWidth == 0UL)
+ {
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
+ base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
+ }
+ /* 4bit data width */
+ else if (busWidth == 1UL)
+ {
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
+ }
+ /* 8bit data width */
+ else
+ {
+ base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
+ base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
+ }
+}
+#endif /* FSL_FEATURE_USDHC_HAS_SDR50_MODE */
+
+static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInsertionFlag))
+ {
+ if (handle->callback.CardInserted != NULL)
+ {
+ handle->callback.CardInserted(base, handle->userData);
+ }
+ }
+ else
+ {
+ if (handle->callback.CardRemoved != NULL)
+ {
+ handle->callback.CardRemoved(base, handle->userData);
+ }
+ }
+}
+
+static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->command != NULL);
+
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandErrorFlag))
+ {
+ if (handle->callback.TransferComplete != NULL)
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
+ }
+ }
+ else
+ {
+ /* Receive response */
+ if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command))
+ {
+ if (handle->callback.TransferComplete != NULL)
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
+ }
+ }
+ else
+ {
+ if (handle->callback.TransferComplete != NULL)
+ {
+ handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandSuccess, handle->userData);
+ }
+ }
+ }
+ /* disable interrupt signal and reset command pointer */
+ USDHC_DisableInterruptSignal(base, kUSDHC_CommandFlag);
+ handle->command = NULL;
+}
+
+static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->data != NULL);
+
+ status_t transferStatus = kStatus_USDHC_BusyTransferring;
+ uint32_t transferredWords = handle->transferredWords;
+
+ if ((!(handle->data->enableIgnoreError)) &&
+ (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
+ {
+ transferStatus = kStatus_USDHC_TransferDataFailed;
+ }
+ else
+ {
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
+ {
+ /* std tuning process only need to wait BRR */
+ if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
+ {
+ transferStatus = kStatus_USDHC_TransferDataComplete;
+ }
+ else
+ {
+ handle->transferredWords = USDHC_ReadDataPort(base, handle->data, transferredWords);
+ }
+ }
+ else if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferWriteReadyFlag))
+ {
+ handle->transferredWords = USDHC_WriteDataPort(base, handle->data, transferredWords);
+ }
+ else
+ {
+ if ((IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag)) &&
+ (handle->data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous))
+ {
+ *(handle->data->rxData) = s_usdhcBootDummy;
+ }
+
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
+ {
+ transferStatus = kStatus_USDHC_TransferDataComplete;
+
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+ if (handle->data->rxData != NULL)
+ {
+ DCACHE_InvalidateByRange((uint32_t)(handle->data->rxData),
+ (handle->data->blockSize) * (handle->data->blockCount));
+ }
+#endif
+ }
+ }
+ }
+
+ if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
+ {
+ handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
+ USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag);
+ handle->data = NULL;
+ }
+}
+
+static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle)
+{
+ if (handle->callback.SdioInterrupt != NULL)
+ {
+ handle->callback.SdioInterrupt(base, handle->userData);
+ }
+}
+
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
+{
+ assert(handle->callback.ReTuning != NULL);
+ /* retuning request */
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_TuningErrorFlag))
+ {
+ handle->callback.ReTuning(base, handle->userData); /* retuning fail */
+ }
+}
+#endif
+
+static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle)
+{
+ if (handle->callback.BlockGap != NULL)
+ {
+ handle->callback.BlockGap(base, handle->userData);
+ }
+}
+
+/*!
+ * brief Creates the USDHC handle.
+ *
+ * param base USDHC peripheral base address.
+ * param handle USDHC handle pointer.
+ * param callback Structure pointer to contain all callback functions.
+ * param userData Callback function parameter.
+ */
+void USDHC_TransferCreateHandle(USDHC_Type *base,
+ usdhc_handle_t *handle,
+ const usdhc_transfer_callback_t *callback,
+ void *userData)
+{
+ assert(handle != NULL);
+ assert(callback != NULL);
+
+ /* Zero the handle. */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set the callback. */
+ handle->callback.CardInserted = callback->CardInserted;
+ handle->callback.CardRemoved = callback->CardRemoved;
+ handle->callback.SdioInterrupt = callback->SdioInterrupt;
+ handle->callback.BlockGap = callback->BlockGap;
+ handle->callback.TransferComplete = callback->TransferComplete;
+ handle->callback.ReTuning = callback->ReTuning;
+ handle->userData = userData;
+
+ /* Save the handle in global variables to support the double weak mechanism. */
+ s_usdhcHandle[USDHC_GetInstance(base)] = handle;
+
+ /* save IRQ handler */
+ s_usdhcIsr = USDHC_TransferHandleIRQ;
+
+ (void)EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]);
+}
+
+/*!
+ * brief IRQ handler for the USDHC.
+ *
+ * This function deals with the IRQs on the given host controller.
+ *
+ * param base USDHC peripheral base address.
+ * param handle USDHC handle.
+ */
+void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ uint32_t interruptFlags;
+
+ interruptFlags = USDHC_GetEnabledInterruptStatusFlags(base);
+
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardDetectFlag))
+ {
+ USDHC_TransferHandleCardDetect(base, handle, interruptFlags);
+ }
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandFlag))
+ {
+ USDHC_TransferHandleCommand(base, handle, interruptFlags);
+ }
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataFlag))
+ {
+ USDHC_TransferHandleData(base, handle, interruptFlags);
+ }
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInterruptFlag))
+ {
+ USDHC_TransferHandleSdioInterrupt(base, handle);
+ }
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BlockGapEventFlag))
+ {
+ USDHC_TransferHandleBlockGap(base, handle);
+ }
+#if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
+ if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_SDR104TuningFlag))
+ {
+ USDHC_TransferHandleReTuning(base, handle, interruptFlags);
+ }
+#endif
+ USDHC_ClearInterruptStatusFlags(base, interruptFlags);
+}
+
+#ifdef USDHC0
+void USDHC0_DriverIRQHandler(void)
+{
+ s_usdhcIsr(s_usdhcBase[0U], s_usdhcHandle[0U]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#ifdef USDHC1
+void USDHC1_DriverIRQHandler(void)
+{
+ s_usdhcIsr(s_usdhcBase[1U], s_usdhcHandle[1U]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+
+#ifdef USDHC2
+void USDHC2_DriverIRQHandler(void)
+{
+ s_usdhcIsr(s_usdhcBase[2U], s_usdhcHandle[2U]);
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#endif
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_wdog.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_wdog.c
new file mode 100644
index 0000000000..ea6c970b33
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_wdog.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2016, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_wdog.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.wdog01"
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+static WDOG_Type *const s_wdogBases[] = WDOG_BASE_PTRS;
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of WDOG clock name. */
+static const clock_ip_name_t s_wdogClock[] = WDOG_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+static const IRQn_Type s_wdogIRQ[] = WDOG_IRQS;
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static uint32_t WDOG_GetInstance(WDOG_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_wdogBases); instance++)
+ {
+ if (s_wdogBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_wdogBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the WDOG configuration structure.
+ *
+ * This function initializes the WDOG configuration structure to default values. The default
+ * values are as follows.
+ * code
+ * wdogConfig->enableWdog = true;
+ * wdogConfig->workMode.enableWait = true;
+ * wdogConfig->workMode.enableStop = false;
+ * wdogConfig->workMode.enableDebug = false;
+ * wdogConfig->enableInterrupt = false;
+ * wdogConfig->enablePowerdown = false;
+ * wdogConfig->resetExtension = flase;
+ * wdogConfig->timeoutValue = 0xFFU;
+ * wdogConfig->interruptTimeValue = 0x04u;
+ * endcode
+ *
+ * param config Pointer to the WDOG configuration structure.
+ * see wdog_config_t
+ */
+void WDOG_GetDefaultConfig(wdog_config_t *config)
+{
+ assert(NULL != config);
+
+ /* Initializes the configure structure to zero. */
+ (void)memset(config, 0, sizeof(*config));
+
+ config->enableWdog = true;
+ config->workMode.enableWait = false;
+ config->workMode.enableStop = false;
+ config->workMode.enableDebug = false;
+ config->enableInterrupt = false;
+ config->softwareResetExtension = false;
+ config->enablePowerDown = false;
+ config->timeoutValue = 0xffu;
+ config->interruptTimeValue = 0x04u;
+ config->enableTimeOutAssert = false;
+}
+
+/*!
+ * brief Initializes the WDOG.
+ *
+ * This function initializes the WDOG. When called, the WDOG runs according to the configuration.
+ *
+ * This is an example.
+ * code
+ * wdog_config_t config;
+ * WDOG_GetDefaultConfig(&config);
+ * config.timeoutValue = 0xffU;
+ * config->interruptTimeValue = 0x04u;
+ * WDOG_Init(wdog_base,&config);
+ * endcode
+ *
+ * param base WDOG peripheral base address
+ * param config The configuration of WDOG
+ */
+void WDOG_Init(WDOG_Type *base, const wdog_config_t *config)
+{
+ assert(NULL != config);
+
+ uint16_t value = 0u;
+ uint32_t primaskValue = 0U;
+
+ value = WDOG_WCR_WDE(config->enableWdog) | WDOG_WCR_WDW(config->workMode.enableWait) |
+ WDOG_WCR_WDZST(config->workMode.enableStop) | WDOG_WCR_WDBG(config->workMode.enableDebug) |
+ WDOG_WCR_SRE(config->softwareResetExtension) | WDOG_WCR_WT(config->timeoutValue) |
+ WDOG_WCR_WDT(config->enableTimeOutAssert) | WDOG_WCR_SRS_MASK | WDOG_WCR_WDA_MASK;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Set configuration */
+ CLOCK_EnableClock(s_wdogClock[WDOG_GetInstance(base)]);
+#endif
+
+ primaskValue = DisableGlobalIRQ();
+ base->WICR = WDOG_WICR_WICT(config->interruptTimeValue) | WDOG_WICR_WIE(config->enableInterrupt);
+ base->WMCR = WDOG_WMCR_PDE(config->enablePowerDown);
+ base->WCR = value;
+ EnableGlobalIRQ(primaskValue);
+ if (config->enableInterrupt)
+ {
+ (void)EnableIRQ(s_wdogIRQ[WDOG_GetInstance(base)]);
+ }
+}
+
+/*!
+ * brief Shuts down the WDOG.
+ *
+ * This function shuts down the WDOG.
+ * Watchdog Enable bit is a write one once only bit. It is not
+ * possible to clear this bit by a software write, once the bit is set.
+ * This bit(WDE) can be set/reset only in debug mode(exception).
+ */
+void WDOG_Deinit(WDOG_Type *base)
+{
+ if (0U != (base->WCR & WDOG_WCR_WDBG_MASK))
+ {
+ WDOG_Disable(base);
+ }
+}
+
+/*!
+ * brief Gets the WDOG all reset status flags.
+ *
+ * This function gets all reset status flags.
+ *
+ * code
+ * uint16_t status;
+ * status = WDOG_GetStatusFlags (wdog_base);
+ * endcode
+ * param base WDOG peripheral base address
+ * return State of the status flag: asserted (true) or not-asserted (false).see _wdog_status_flags
+ * - true: a related status flag has been set.
+ * - false: a related status flag is not set.
+ */
+uint16_t WDOG_GetStatusFlags(WDOG_Type *base)
+{
+ uint16_t status_flag = 0U;
+
+ status_flag |= (base->WCR & WDOG_WCR_WDE_MASK);
+ status_flag |= (base->WRSR & WDOG_WRSR_POR_MASK);
+ status_flag |= (base->WRSR & WDOG_WRSR_TOUT_MASK);
+ status_flag |= (base->WRSR & WDOG_WRSR_SFTW_MASK);
+ status_flag |= (base->WICR & WDOG_WICR_WTIS_MASK);
+
+ return status_flag;
+}
+
+/*!
+ * brief Clears the WDOG flag.
+ *
+ * This function clears the WDOG status flag.
+ *
+ * This is an example for clearing the interrupt flag.
+ * code
+ * WDOG_ClearStatusFlags(wdog_base,KWDOG_InterruptFlag);
+ * endcode
+ * param base WDOG peripheral base address
+ * param mask The status flags to clear.
+ * The parameter could be any combination of the following values.
+ * kWDOG_TimeoutFlag
+ */
+void WDOG_ClearInterruptStatus(WDOG_Type *base, uint16_t mask)
+{
+ if (0U != (mask & (uint16_t)kWDOG_InterruptFlag))
+ {
+ base->WICR |= WDOG_WICR_WTIS_MASK;
+ }
+}
+
+/*!
+ * brief Refreshes the WDOG timer.
+ *
+ * This function feeds the WDOG.
+ * This function should be called before the WDOG timer is in timeout. Otherwise, a reset is asserted.
+ *
+ * param base WDOG peripheral base address
+ */
+void WDOG_Refresh(WDOG_Type *base)
+{
+ uint32_t primaskValue = 0U;
+
+ /* Disable the global interrupt to protect refresh sequence */
+ primaskValue = DisableGlobalIRQ();
+ base->WSR = WDOG_REFRESH_KEY & 0xFFFFU;
+ base->WSR = (WDOG_REFRESH_KEY >> 16U) & 0xFFFFU;
+ EnableGlobalIRQ(primaskValue);
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_xbara.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_xbara.c
new file mode 100644
index 0000000000..cc6307bbb6
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_xbara.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_xbara.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xbara"
+#endif
+
+/* Macros for entire XBARA_CTRL register. */
+#define XBARA_CTRLx(base, index) (((volatile uint16_t *)(&((base)->CTRL0)))[(index)])
+
+typedef union
+{
+ uint8_t _u8[2];
+ uint16_t _u16;
+} xbara_u8_u16_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the XBARA instance from peripheral base address.
+ *
+ * @param base XBARA peripheral base address.
+ * @return XBARA instance.
+ */
+static uint32_t XBARA_GetInstance(XBARA_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of XBARA peripheral base address. */
+static XBARA_Type *const s_xbaraBases[] = XBARA_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of XBARA clock name. */
+static const clock_ip_name_t s_xbaraClock[] = XBARA_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t XBARA_GetInstance(XBARA_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_xbaraBases); instance++)
+ {
+ if (s_xbaraBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_xbaraBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the XBARA module.
+ *
+ * This function un-gates the XBARA clock.
+ *
+ * param base XBARA peripheral address.
+ */
+void XBARA_Init(XBARA_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable XBARA module clock. */
+ CLOCK_EnableClock(s_xbaraClock[XBARA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Shuts down the XBARA module.
+ *
+ * This function disables XBARA clock.
+ *
+ * param base XBARA peripheral address.
+ */
+void XBARA_Deinit(XBARA_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable XBARA module clock. */
+ CLOCK_DisableClock(s_xbaraClock[XBARA_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Sets a connection between the selected XBARA_IN[*] input and the XBARA_OUT[*] output signal.
+ *
+ * This function connects the XBARA input to the selected XBARA output.
+ * If more than one XBARA module is available, only the inputs and outputs from the same module
+ * can be connected.
+ *
+ * Example:
+ code
+ XBARA_SetSignalsConnection(XBARA, kXBARA_InputPIT_TRG0, kXBARA_OutputDMAMUX18);
+ endcode
+ *
+ * param base XBARA peripheral address.
+ * param input XBARA input signal.
+ * param output XBARA output signal.
+ */
+void XBARA_SetSignalsConnection(XBARA_Type *base, xbar_input_signal_t input, xbar_output_signal_t output)
+{
+ xbara_u8_u16_t regVal;
+ uint8_t byteInReg;
+ uint8_t outputIndex = (uint8_t)output;
+
+ byteInReg = outputIndex % 2U;
+
+ regVal._u16 = XBARA_SELx(base, outputIndex);
+
+ regVal._u8[byteInReg] = (uint8_t)input;
+
+ XBARA_SELx(base, outputIndex) = regVal._u16;
+}
+
+/*!
+ * brief Gets the active edge detection status.
+ *
+ * This function gets the active edge detect status of all XBARA_OUTs. If the
+ * active edge occurs, the return value is asserted. When the interrupt or the DMA
+ * functionality is enabled for the XBARA_OUTx, this field is 1 when the interrupt
+ * or DMA request is asserted and 0 when the interrupt or DMA request has been
+ * cleared.
+ *
+ * param base XBARA peripheral address.
+ * return the mask of these status flag bits.
+ */
+uint32_t XBARA_GetStatusFlags(XBARA_Type *base)
+{
+ uint32_t status_flag;
+
+ status_flag = ((uint32_t)base->CTRL0 & (XBARA_CTRL0_STS0_MASK | XBARA_CTRL0_STS1_MASK));
+
+ status_flag |= (((uint32_t)base->CTRL1 & (XBARA_CTRL1_STS2_MASK | XBARA_CTRL1_STS3_MASK)) << 16U);
+
+ return status_flag;
+}
+
+/*!
+ * brief Clears the edge detection status flags of relative mask.
+ *
+ * param base XBARA peripheral address.
+ * param mask the status flags to clear.
+ */
+void XBARA_ClearStatusFlags(XBARA_Type *base, uint32_t mask)
+{
+ uint16_t regVal;
+
+ /* Assign regVal to CTRL0 register's value */
+ regVal = (base->CTRL0);
+ /* Perform this command to avoid writing 1 into interrupt flag bits */
+ regVal &= (uint16_t)(~(XBARA_CTRL0_STS0_MASK | XBARA_CTRL0_STS1_MASK));
+ /* Write 1 to interrupt flag bits corresponding to mask */
+ regVal |= (uint16_t)(mask & (XBARA_CTRL0_STS0_MASK | XBARA_CTRL0_STS1_MASK));
+ /* Write regVal value into CTRL0 register */
+ base->CTRL0 = regVal;
+
+ /* Assign regVal to CTRL1 register's value */
+ regVal = (base->CTRL1);
+ /* Perform this command to avoid writing 1 into interrupt flag bits */
+ regVal &= (uint16_t)(~(XBARA_CTRL1_STS2_MASK | XBARA_CTRL1_STS3_MASK));
+ /* Write 1 to interrupt flag bits corresponding to mask */
+ regVal |= (uint16_t)((mask >> 16U) & (XBARA_CTRL1_STS2_MASK | XBARA_CTRL1_STS3_MASK));
+ /* Write regVal value into CTRL1 register */
+ base->CTRL1 = regVal;
+}
+
+/*!
+ * brief Configures the XBARA control register.
+ *
+ * This function configures an XBARA control register. The active edge detection
+ * and the DMA/IRQ function on the corresponding XBARA output can be set.
+ *
+ * Example:
+ code
+ xbara_control_config_t userConfig;
+ userConfig.activeEdge = kXBARA_EdgeRising;
+ userConfig.requestType = kXBARA_RequestInterruptEnalbe;
+ XBARA_SetOutputSignalConfig(XBARA, kXBARA_OutputDMAMUX18, &userConfig);
+ endcode
+ *
+ * param base XBARA peripheral address.
+ * param output XBARA output number.
+ * param controlConfig Pointer to structure that keeps configuration of control register.
+ */
+void XBARA_SetOutputSignalConfig(XBARA_Type *base,
+ xbar_output_signal_t output,
+ const xbara_control_config_t *controlConfig)
+{
+ uint8_t outputIndex = (uint8_t)output;
+ uint8_t regIndex;
+ uint8_t byteInReg;
+ xbara_u8_u16_t regVal;
+
+ assert(outputIndex < (uint32_t)FSL_FEATURE_XBARA_INTERRUPT_COUNT);
+
+ regIndex = outputIndex / 2U;
+ byteInReg = outputIndex % 2U;
+
+ regVal._u16 = XBARA_CTRLx(base, regIndex);
+
+ /* Don't clear the status flags. */
+ regVal._u16 &= (uint16_t)(~(XBARA_CTRL0_STS0_MASK | XBARA_CTRL0_STS1_MASK));
+
+ regVal._u8[byteInReg] = (uint8_t)(XBARA_CTRL0_EDGE0(controlConfig->activeEdge) |
+ (uint16_t)(((uint32_t)controlConfig->requestType) << XBARA_CTRL0_DEN0_SHIFT));
+
+ XBARA_CTRLx(base, regIndex) = regVal._u16;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_xbarb.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_xbarb.c
new file mode 100644
index 0000000000..c1878a2ae4
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/drivers/fsl_xbarb.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_xbarb.h"
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xbarb"
+#endif
+
+typedef union
+{
+ uint8_t _u8[2];
+ uint16_t _u16;
+} xbarb_u8_u16_t;
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+
+/*!
+ * @brief Get the XBARB instance from peripheral base address.
+ *
+ * @param base XBARB peripheral base address.
+ * @return XBARB instance.
+ */
+static uint32_t XBARB_GetInstance(XBARB_Type *base);
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/* Array of XBARB peripheral base address. */
+static XBARB_Type *const s_xbarbBases[] = XBARB_BASE_PTRS;
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Array of XBARB clock name. */
+static const clock_ip_name_t s_xbarbClock[] = XBARB_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+
+static uint32_t XBARB_GetInstance(XBARB_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_xbarbBases); instance++)
+ {
+ if (s_xbarbBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_xbarbBases));
+
+ return instance;
+}
+
+/*!
+ * brief Initializes the XBARB module.
+ *
+ * This function un-gates the XBARB clock.
+ *
+ * param base XBARB peripheral address.
+ */
+void XBARB_Init(XBARB_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable XBARB module clock. */
+ CLOCK_EnableClock(s_xbarbClock[XBARB_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Shuts down the XBARB module.
+ *
+ * This function disables XBARB clock.
+ *
+ * param base XBARB peripheral address.
+ */
+void XBARB_Deinit(XBARB_Type *base)
+{
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Disable XBARB module clock. */
+ CLOCK_DisableClock(s_xbarbClock[XBARB_GetInstance(base)]);
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Configures a connection between the selected XBARB_IN[*] input and the XBARB_OUT[*] output signal.
+ *
+ * This function configures which XBARB input is connected to the selected XBARB output.
+ * If more than one XBARB module is available, only the inputs and outputs from the same module
+ * can be connected.
+ *
+ * param base XBARB peripheral address.
+ * param input XBARB input signal.
+ * param output XBARB output signal.
+ */
+void XBARB_SetSignalsConnection(XBARB_Type *base, xbar_input_signal_t input, xbar_output_signal_t output)
+{
+ xbarb_u8_u16_t regVal;
+ uint8_t byteInReg;
+ uint8_t outputIndex = (uint8_t)output;
+
+ byteInReg = outputIndex % 2U;
+
+ regVal._u16 = XBARB_SELx(base, outputIndex);
+
+ regVal._u8[byteInReg] = (uint8_t)input;
+
+ XBARB_SELx(base, outputIndex) = regVal._u16;
+}
diff --git a/bsps/arm/imxrt/nxp/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.c b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.c
new file mode 100644
index 0000000000..41b273f70b
--- /dev/null
+++ b/bsps/arm/imxrt/nxp/devices/MIMXRT1052/xip/fsl_flexspi_nor_boot.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_flexspi_nor_boot.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.xip_device"
+#endif
+
+#if defined(XIP_BOOT_HEADER_ENABLE) && (XIP_BOOT_HEADER_ENABLE == 1)
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+ __attribute__((section(".boot_hdr.ivt")))
+#elif defined(__ICCARM__)
+#pragma location=".boot_hdr.ivt"
+#endif
+/*************************************
+ * IVT Data
+ *************************************/
+const ivt image_vector_table = {
+ IVT_HEADER, /* IVT Header */
+ IMAGE_ENTRY_ADDRESS, /* Image Entry Function */
+ IVT_RSVD, /* Reserved = 0 */
+ (uint32_t)DCD_ADDRESS, /* Address where DCD information is stored */
+ (uint32_t)BOOT_DATA_ADDRESS, /* Address where BOOT Data Structure is stored */
+ (uint32_t)&image_vector_table, /* Pointer to IVT Self (absolute address */
+ (uint32_t)CSF_ADDRESS, /* Address where CSF file is stored */
+ IVT_RSVD /* Reserved = 0 */
+};
+
+#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__GNUC__)
+ __attribute__((section(".boot_hdr.boot_data")))
+#elif defined(__ICCARM__)
+#pragma location=".boot_hdr.boot_data"
+#endif
+/*************************************
+ * Boot Data
+ *************************************/
+const BOOT_DATA_T boot_data = {
+ FLASH_BASE, /* boot start location */
+ FLASH_SIZE, /* size */
+ PLUGIN_FLAG, /* Plugin flag*/
+ 0xFFFFFFFF /* empty - extra data word */
+};
+#endif
+
+