summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/mcux-sdk/drivers/lpspi
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/imxrt/mcux-sdk/drivers/lpspi')
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.c2421
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.h1158
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.c1052
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.h301
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_freertos.h107
5 files changed, 5039 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.c
new file mode 100644
index 0000000000..fd28621951
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.c
@@ -0,0 +1,2421 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 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,
+};
+
+/*
+ * <! Structure definition for variables that passed as parameters in LPSPI_MasterTransferBlocking.
+ * The structure is private.
+ */
+typedef struct _lpspi_transfer_blocking_param
+{
+ bool isTxMask;
+ bool isPcsContinuous;
+ uint8_t bytesEachWrite;
+ uint8_t bytesEachRead;
+ uint32_t rxRemainingByteCount;
+} lpspi_transfer_blocking_param_t;
+
+/*! @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 Wait for tx FIFO to be empty.
+ * This is not a public API.
+ * @param base LPSPI peripheral address.
+ * @return true for the tx FIFO is ready, false is not.
+ */
+static bool LPSPI_TxFifoReady(LPSPI_Type *base);
+
+/*!
+ * @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);
+
+/*!
+ * @brief introduce function static bool LPSPI_MasterTransferWriteAllTxData.
+ * This function was deal with write all Txdata.
+ *
+ * @param base LPSPI peripheral address.
+ * @param stateParams Pass the address of the parent function variable.
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool LPSPI_MasterTransferWriteAllTxData(LPSPI_Type *base,
+ lpspi_transfer_t *transfer,
+ lpspi_transfer_blocking_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPSPI_MasterTransferClearTCR.
+ * This function was deal with clear TCR.
+ *
+ * @param base LPSPI peripheral address.
+ * @param stateParams Pass the address of the parent function variable.
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool LPSPI_MasterTransferClearTCR(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPSPI_MasterTransferReadDataInFifo.
+ * This function was deal with read data in fifo.
+ *
+ * @param base LPSPI peripheral address.
+ * @param stateParams Pass the address of the parent function variable.
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool LPSPI_MasterTransferReadDataInFifo(LPSPI_Type *base,
+ lpspi_transfer_t *transfer,
+ lpspi_transfer_blocking_param_t *stateParams);
+
+/*!
+ * @brief introduce function LPSPI_MasterTransferReadDataInFifoNoBuf.
+ * This function was deal with no buf in fifo.
+ *
+ * @param base LPSPI peripheral address.
+ * @param stateParams Pass the address of the parent function variable.
+ *
+ * @return default is true when No abnormality.
+ * @return false when time out.
+ */
+static bool LPSPI_MasterTransferReadDataInFifoNoBuf(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams);
+
+/*******************************************************************************
+ * 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 != NULL);
+
+ 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_SAMPLE_MASK)) |
+ LPSPI_CFGR1_OUTCFG(masterConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(masterConfig->pinCfg) |
+ LPSPI_CFGR1_NOSTALL(0) | LPSPI_CFGR1_SAMPLE((uint32_t)masterConfig->enableInputDelay);
+
+ /* 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 != NULL);
+
+ /* 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;
+
+ masterConfig->enableInputDelay = false;
+}
+
+/*!
+ * 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 != NULL);
+
+#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 != NULL);
+
+ /* 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 != NULL);
+
+ /* 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.
+ */
+#if defined(FSL_FEATURE_LPSPI_HAS_CCR1) && FSL_FEATURE_LPSPI_HAS_CCR1
+ /* When CCR1 is present, the CCR[DBT] and CCR[SCKDIV] is write only, all read will return 0
+ The real DBT and SCKDIV can be obtained in CCR1, CCR[DBT]=CCR1[SCKSCK] and CCR[SCKDIV]=CCR1[SCKHLD]+CCR1[SCKSET]
+ So when changing either CCR[DBT] or CCR[SCKDIV] make sure the other value is not overwritten by 0 */
+ base->CCR = base->CCR | LPSPI_CCR_DBT((base->CCR1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT) |
+ LPSPI_CCR_SCKDIV(bestScaler);
+#else
+ base->CCR = (base->CCR & ~LPSPI_CCR_SCKDIV_MASK) | LPSPI_CCR_SCKDIV(bestScaler);
+#endif /* FSL_FEATURE_LPSPI_HAS_CCR1 */
+
+ /* 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 */
+#if defined(FSL_FEATURE_LPSPI_HAS_CCR1) && FSL_FEATURE_LPSPI_HAS_CCR1
+ /* When CCR1 is present, the CCR[DBT] and CCR[SCKDIV] is write only, all read will return 0
+ The real DBT and SCKDIV can be obtained in CCR1, CCR[DBT]=CCR1[SCKSCK] and CCR[SCKDIV]=CCR1[SCKHLD]+CCR1[SCKSET]
+ So when changing either CCR[DBT] or CCR[SCKDIV] make sure the other value is not overwritten by 0 */
+ uint32_t dbt = (base->CCR1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT;
+ uint32_t sckdiv = (base->CCR1 & LPSPI_CCR1_SCKHLD_MASK) >> LPSPI_CCR1_SCKHLD_SHIFT;
+ sckdiv += (base->CCR1 & LPSPI_CCR1_SCKSET_MASK) >> LPSPI_CCR1_SCKSET_SHIFT;
+ switch (whichDelay)
+ {
+ case kLPSPI_PcsToSck:
+ base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler) | LPSPI_CCR_DBT(dbt) |
+ LPSPI_CCR_SCKDIV(sckdiv);
+
+ break;
+ case kLPSPI_LastSckToPcs:
+ base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler) | LPSPI_CCR_DBT(dbt) |
+ LPSPI_CCR_SCKDIV(sckdiv);
+
+ break;
+ case kLPSPI_BetweenTransfer:
+ base->CCR = base->CCR | LPSPI_CCR_DBT(scaler) | LPSPI_CCR_SCKDIV(sckdiv);
+#else
+ 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);
+#endif /* FSL_FEATURE_LPSPI_HAS_CCR1 */
+ 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 != NULL);
+
+ /* 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 base LPSPI peripheral address.
+ * param transfer the transfer struct to be used.
+ * param isEdma True to check for EDMA transfer, false to check interrupt non-blocking transfer
+ * return Return true for right and false for wrong.
+ */
+bool LPSPI_CheckTransferArgument(LPSPI_Type *base, lpspi_transfer_t *transfer, bool isEdma)
+{
+ assert(transfer != NULL);
+ uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U;
+ uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U;
+ uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK);
+ /* 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;
+ }
+ }
+ }
+
+ /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */
+ if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut)))
+ {
+ /* The 3-wire mode can't send and receive data at the same time. */
+ if ((transfer->txData != NULL) && (transfer->rxData != NULL))
+ {
+ return false;
+ }
+ if (NULL == transfer->txData)
+ {
+ base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK;
+ }
+ }
+
+ if (isEdma && ((bytesPerFrame % 4U) == 3U))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static bool LPSPI_MasterTransferWriteAllTxData(LPSPI_Type *base,
+ lpspi_transfer_t *transfer,
+ lpspi_transfer_blocking_param_t *stateParams)
+{
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ uint32_t txRemainingByteCount = transfer->dataSize;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ uint32_t wordToSend =
+ ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24);
+ uint32_t rxFifoMaxBytes = MIN(bytesPerFrame, 4U) * LPSPI_GetRxFifoSize(base);
+ uint32_t readData;
+ /*Write the TX data until txRemainingByteCount is equal to 0 */
+ while (txRemainingByteCount > 0U)
+ {
+ if (txRemainingByteCount < (stateParams->bytesEachWrite))
+ {
+ (stateParams->bytesEachWrite) = (uint8_t)txRemainingByteCount;
+ }
+
+ /*Wait until TX FIFO is not full*/
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base)) && (--waitTimes) != 0U))
+#else
+ while (LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+
+ /* To prevent rxfifo overflow, ensure transmitting and receiving are executed in parallel */
+ if (((NULL == (transfer->rxData)) ||
+ ((stateParams->rxRemainingByteCount) - txRemainingByteCount) < rxFifoMaxBytes))
+ {
+ if (stateParams->isTxMask)
+ {
+ /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared
+ by hardware every time when TCR[FRAMESZ] bit of data is transfered.
+ In this case TCR[TXMSK] should be set to initiate each transfer. */
+ base->TCR |= LPSPI_TCR_TXMSK_MASK;
+ if (stateParams->isPcsContinuous && (txRemainingByteCount == bytesPerFrame))
+ {
+ /* For the last piece of frame size of data, if is PCS continous mode(TCR[CONT]), TCR[CONTC] should
+ * be cleared to de-assert the PCS. Be sure to clear the TXMSK as well otherwise another FRAMESZ
+ * of data will be received. */
+ base->TCR &= ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK | LPSPI_TCR_TXMSK_MASK);
+ }
+ txRemainingByteCount -= bytesPerFrame;
+ }
+ else
+ {
+ if ((transfer->txData) != NULL)
+ {
+ wordToSend = LPSPI_CombineWriteData((transfer->txData), (stateParams->bytesEachWrite), isByteSwap);
+ (transfer->txData) += (stateParams->bytesEachWrite);
+ }
+ /* Otherwise push data to tx FIFO to initiate transfer */
+ LPSPI_WriteData(base, wordToSend);
+ txRemainingByteCount -= (stateParams->bytesEachWrite);
+ }
+ }
+
+ /* Check whether there is RX data in RX FIFO . Read out the RX data so that the RX FIFO would not overrun. */
+ if (((transfer->rxData) != NULL) && ((stateParams->rxRemainingByteCount) != 0U))
+ {
+ /* To ensure parallel execution in 3-wire mode, after writting 1 to TXMSK to generate clock of
+ bytesPerFrame's data wait until bytesPerFrame's data is received. */
+ while ((stateParams->isTxMask) && (LPSPI_GetRxFifoCount(base) == 0U))
+ {
+ }
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetRxFifoCount(base) != 0U)
+#endif
+ {
+ readData = LPSPI_ReadData(base);
+ if ((stateParams->rxRemainingByteCount) < (stateParams->bytesEachRead))
+ {
+ (stateParams->bytesEachRead) = (uint8_t)(stateParams->rxRemainingByteCount);
+ }
+
+ LPSPI_SeparateReadData((transfer->rxData), readData, (stateParams->bytesEachRead), isByteSwap);
+ (transfer->rxData) += (stateParams->bytesEachRead);
+
+ (stateParams->rxRemainingByteCount) -= (stateParams->bytesEachRead);
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ }
+ }
+ return true;
+}
+
+static bool LPSPI_MasterTransferClearTCR(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams)
+{
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base)) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetTxFifoCount(base) == LPSPI_GetRxFifoSize(base))
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK));
+ return true;
+}
+
+static bool LPSPI_MasterTransferReadDataInFifo(LPSPI_Type *base,
+ lpspi_transfer_t *transfer,
+ lpspi_transfer_blocking_param_t *stateParams)
+{
+ uint32_t readData;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ while ((stateParams->rxRemainingByteCount) > 0U)
+ {
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while (LPSPI_GetRxFifoCount(base) != 0U)
+#endif
+ {
+ readData = LPSPI_ReadData(base);
+
+ if ((stateParams->rxRemainingByteCount) < (stateParams->bytesEachRead))
+ {
+ (stateParams->bytesEachRead) = (uint8_t)(stateParams->rxRemainingByteCount);
+ }
+
+ LPSPI_SeparateReadData((transfer->rxData), readData, (stateParams->bytesEachRead), isByteSwap);
+ (transfer->rxData) += (stateParams->bytesEachRead);
+
+ (stateParams->rxRemainingByteCount) -= (stateParams->bytesEachRead);
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ }
+ return true;
+}
+
+static bool LPSPI_MasterTransferReadDataInFifoNoBuf(LPSPI_Type *base, lpspi_transfer_blocking_param_t *stateParams)
+{
+#if SPI_RETRY_TIMES
+ uint32_t 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 false;
+ }
+#endif
+ 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 != NULL);
+
+ /* Check that LPSPI is not busy.*/
+ if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ModuleBusyFlag) != 0U)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+ LPSPI_Enable(base, false);
+ /* Check arguements */
+ if (!LPSPI_CheckTransferArgument(base, transfer, false))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+
+ /* Variables */
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+ uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK);
+ lpspi_transfer_blocking_param_t stateParams;
+ (void)memset(&stateParams, 0, sizeof(stateParams));
+
+ stateParams.isTxMask = false;
+ stateParams.rxRemainingByteCount = transfer->dataSize;
+ /*The TX and RX FIFO sizes are always the same*/
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ /* No need to configure PCS continous if the transfer byte count is smaller than frame size */
+ stateParams.isPcsContinuous = (((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U) &&
+ (bytesPerFrame < transfer->dataSize));
+
+ /* Mask tx data in half duplex mode */
+ if (((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) &&
+ (transfer->txData == NULL))
+ {
+ stateParams.isTxMask = true;
+ }
+
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+ LPSPI_Enable(base, true);
+
+ /* Configure transfer control register. */
+ 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_PCS(whichPcs);
+
+ /*TCR is also shared the FIFO, so wait for TCR written.*/
+ if (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ /* PCS should be configured separately from the other bits, otherwise it will not take effect. */
+ base->TCR |= LPSPI_TCR_CONT(stateParams.isPcsContinuous) | LPSPI_TCR_CONTC(stateParams.isPcsContinuous) |
+ LPSPI_TCR_RXMSK(NULL == transfer->rxData);
+
+ /*TCR is also shared the FIFO, so wait for TCR written.*/
+ if (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ if (bytesPerFrame <= 4U)
+ {
+ stateParams.bytesEachWrite = (uint8_t)bytesPerFrame;
+ stateParams.bytesEachRead = (uint8_t)bytesPerFrame;
+ }
+ else
+ {
+ stateParams.bytesEachWrite = 4U;
+ stateParams.bytesEachRead = 4U;
+ }
+
+ if (false == LPSPI_MasterTransferWriteAllTxData(base, transfer, &stateParams))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ if (stateParams.isPcsContinuous && !stateParams.isTxMask)
+ {
+ /* In PCS continous mode(TCR[CONT]), after write all the data in TX FIFO, TCR[CONTC] and TCR[CONT] should be
+ cleared to de-assert the PCS. Note that TCR register also use the TX FIFO. Also CONTC should be cleared when
+ tx is not masked, otherwise written to TCR register with TXMSK bit wet will initiate a new transfer. */
+ if (false == LPSPI_MasterTransferClearTCR(base, &stateParams))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+ }
+
+ /*Read out the RX data in FIFO*/
+ if (transfer->rxData != NULL)
+ {
+ if (false == LPSPI_MasterTransferReadDataInFifo(base, transfer, &stateParams))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+ }
+ else
+ {
+ /* If no RX buffer, then transfer is not complete until transfer complete flag sets */
+ if (false == LPSPI_MasterTransferReadDataInFifoNoBuf(base, &stateParams))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+ }
+
+ 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 != NULL);
+ assert(transfer != NULL);
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+
+ LPSPI_Enable(base, false);
+ /* Check arguements */
+ if (!LPSPI_CheckTransferArgument(base, transfer, false))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ /* Flush FIFO, clear status, disable all the interrupts. */
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+
+ /* Variables */
+ bool isRxMask = false;
+ uint8_t txWatermark;
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+ uint32_t tmpTimes;
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT;
+ uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK);
+
+ /* Assign the original value for members of transfer handle. */
+ handle->state = (uint8_t)kLPSPI_Busy;
+ handle->txData = transfer->txData;
+ handle->rxData = transfer->rxData;
+ handle->txRemainingByteCount = transfer->dataSize;
+ handle->rxRemainingByteCount = transfer->dataSize;
+ handle->totalByteCount = transfer->dataSize;
+ handle->writeTcrInIsr = false;
+ handle->bytesPerFrame = (uint16_t)((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ /* No need to configure PCS continous if the transfer byte count is smaller than frame size */
+ bool isPcsContinuous = (((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U) &&
+ (transfer->dataSize > handle->bytesPerFrame));
+ handle->writeRegRemainingTimes =
+ (transfer->dataSize / (uint32_t)handle->bytesPerFrame) * (((uint32_t)handle->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 = isPcsContinuous;
+ handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ /*Calculate the bytes for write/read the TX/RX register each time*/
+ if (handle->bytesPerFrame <= 4U)
+ {
+ handle->bytesEachWrite = (uint8_t)handle->bytesPerFrame;
+ handle->bytesEachRead = (uint8_t)handle->bytesPerFrame;
+ }
+ else
+ {
+ handle->bytesEachWrite = 4U;
+ handle->bytesEachRead = 4U;
+ }
+
+ /*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);
+
+ /* If there is no rxData, mask the receive data so that receive data is not stored in receive FIFO. */
+ if (handle->rxData == NULL)
+ {
+ isRxMask = true;
+ handle->rxRemainingByteCount = 0;
+ }
+
+ /* Mask tx data in half duplex mode since the tx/rx share the same pin, so that the data received from slave is not
+ * interfered. */
+ if (((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) &&
+ (handle->txData == NULL))
+ {
+ handle->isTxMask = true;
+ }
+
+ /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+
+ /* Enable module for following configuration of TCR to take effect. */
+ LPSPI_Enable(base, true);
+
+ /* Configure transfer control register. */
+ 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_PCS(whichPcs);
+
+ /*TCR is also shared the FIFO , so wait for TCR written.*/
+ if (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ /* PCS should be configured separately from the other bits, otherwise it will not take effect. */
+ base->TCR |= LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(isPcsContinuous) | LPSPI_TCR_RXMSK(isRxMask);
+
+ /* 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 (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ if (handle->isTxMask)
+ {
+ /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared by
+ hardware every time when TCR[FRAMESZ] bit of data is transfered. In this case TCR[TXMSK] should be set to
+ initiate each transfer. */
+
+ base->TCR |= LPSPI_TCR_TXMSK_MASK;
+ handle->txRemainingByteCount -= (uint32_t)handle->bytesPerFrame;
+ }
+ else
+ {
+ /* Fill up the TX data in FIFO to initiate transfer */
+ 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)
+ {
+ if (handle->isTxMask)
+ {
+ /* if tx data is masked, transfer is initiated by writing 1 to TCR[TXMSK] and TCR[FRMESZ] bits of data is
+ read. If rx water mark is set larger than TCR[FRMESZ], rx interrupt will not be generated. Lower the rx
+ water mark setting */
+ if ((handle->bytesPerFrame / 4U) < (uint16_t)handle->rxWatermark)
+ {
+ handle->rxWatermark =
+ (uint8_t)(handle->bytesPerFrame / 4U) > 0U ? (uint8_t)(handle->bytesPerFrame / 4U - 1U) : 0U;
+ base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(handle->rxWatermark);
+ }
+ }
+ else
+ {
+ /*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 != NULL);
+
+ 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 != NULL);
+
+ /* 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 != 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 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 != NULL);
+
+ /* 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 != NULL);
+
+ 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)
+ {
+ if (handle->isTxMask)
+ {
+ /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared by
+ hardware every time when TCR[FRAMESZ] bit of data is transfered.
+ In this case TCR[TXMSK] should be set to initiate each transfer. */
+ base->TCR |= LPSPI_TCR_TXMSK_MASK;
+ if ((handle->txRemainingByteCount == (uint32_t)handle->bytesPerFrame) && (handle->isPcsContinuous))
+ {
+ /* For the last piece of frame size of data, if is PCS continous mode(TCR[CONT]), TCR[CONTC] should
+ * be cleared to de-assert the PCS. Be sure to clear the TXMSK as well otherwise another FRAMESZ
+ * of data will be received. */
+ base->TCR &= ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK | LPSPI_TCR_TXMSK_MASK);
+ }
+ handle->txRemainingByteCount -= (uint32_t)handle->bytesPerFrame;
+ }
+ else
+ {
+ LPSPI_MasterTransferFillUpTxFifo(base, handle);
+ }
+ }
+ else
+ {
+ if ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize)))
+ {
+ if ((handle->isPcsContinuous) && (handle->writeTcrInIsr) && (!handle->isTxMask))
+ {
+ 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 != NULL);
+
+ /* 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 != NULL);
+ assert(transfer != NULL);
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+ LPSPI_Enable(base, false);
+ /* Check arguements */
+ if (!LPSPI_CheckTransferArgument(base, transfer, false))
+ {
+ 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);
+
+ /* Variables */
+ bool isRxMask = false;
+ bool isTxMask = false;
+ uint8_t txWatermark;
+ uint32_t readRegRemainingTimes;
+ uint32_t whichPcs = (transfer->configFlags & LPSPI_SLAVE_PCS_MASK) >> LPSPI_SLAVE_PCS_SHIFT;
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+
+ /* Assign the original value for members of transfer handle. */
+ handle->state = (uint8_t)kLPSPI_Busy;
+ 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);
+ /*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;
+ }
+ /* Set proper RX and TX watermarks to reduce the ISR response times. */
+ if (handle->fifoSize > 1U)
+ {
+ txWatermark = 1U;
+ handle->rxWatermark = handle->fifoSize - 2U;
+ }
+ else
+ {
+ txWatermark = 0U;
+ handle->rxWatermark = 0U;
+ }
+ LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark);
+
+ /* If there is no rxData, mask the receive data so that receive data is not stored in receive FIFO. */
+ if (handle->rxData == NULL)
+ {
+ isRxMask = true;
+ handle->rxRemainingByteCount = 0U;
+ }
+ /* If there is no txData, mask the transmit data so that no data is loaded from transmit FIFO and output pin
+ * is tristated. */
+ if (handle->txData == NULL)
+ {
+ isTxMask = true;
+ handle->txRemainingByteCount = 0U;
+ }
+
+ /* Enable module for following configuration of TCR to take effect. */
+ LPSPI_Enable(base, true);
+
+ 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_RXMSK(isRxMask) | LPSPI_TCR_TXMSK(isTxMask) | LPSPI_TCR_PCS(whichPcs);
+
+ /* 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 (!LPSPI_TxFifoReady(base))
+ {
+ return kStatus_LPSPI_Timeout;
+ }
+
+ /* 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);
+ }
+
+ /* RX request and FIFO overflow request enable */
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable | (uint32_t)kLPSPI_ReceiveErrorInterruptEnable);
+ }
+ else
+ {
+ LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable);
+ }
+
+ 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 != NULL);
+
+ 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 != NULL);
+
+ 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 != NULL);
+
+ /* 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 != NULL);
+
+ uint32_t readData; /* variable to store word read from RX FIFO */
+ uint8_t bytesEachRead = handle->bytesEachRead;
+ 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))
+ {
+ LPSPI_SlaveTransferFillUpTxFifo(base, handle);
+ }
+
+ 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 != NULL);
+
+ 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 bool LPSPI_TxFifoReady(LPSPI_Type *base)
+{
+#if SPI_RETRY_TIMES
+ uint32_t waitTimes = SPI_RETRY_TIMES;
+ while (((uint8_t)LPSPI_GetTxFifoCount(base) != 0U) && (--waitTimes != 0U))
+#else
+ while ((uint8_t)LPSPI_GetTxFifoCount(base) != 0U)
+#endif
+ {
+ }
+#if SPI_RETRY_TIMES
+ if (waitTimes == 0U)
+ {
+ return false;
+ }
+#endif
+ return true;
+}
+
+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);
+void LPSPI0_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[0] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI0, s_lpspiHandle[0]);
+}
+#endif
+
+#if defined(LPSPI1)
+void LPSPI1_DriverIRQHandler(void);
+void LPSPI1_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[1] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI1, s_lpspiHandle[1]);
+}
+#endif
+
+#if defined(LPSPI2)
+void LPSPI2_DriverIRQHandler(void);
+void LPSPI2_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[2] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI2, s_lpspiHandle[2]);
+}
+#endif
+
+#if defined(LPSPI3)
+void LPSPI3_DriverIRQHandler(void);
+void LPSPI3_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[3] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI3, s_lpspiHandle[3]);
+}
+#endif
+
+#if defined(LPSPI4)
+void LPSPI4_DriverIRQHandler(void);
+void LPSPI4_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[4] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI4, s_lpspiHandle[4]);
+}
+#endif
+
+#if defined(LPSPI5)
+void LPSPI5_DriverIRQHandler(void);
+void LPSPI5_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[5] != NULL);
+ LPSPI_CommonIRQHandler(LPSPI5, s_lpspiHandle[5]);
+}
+#endif
+
+#if defined(DMA__LPSPI0)
+void DMA_SPI0_INT_DriverIRQHandler(void);
+void DMA_SPI0_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)] != NULL);
+ LPSPI_CommonIRQHandler(DMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]);
+}
+#endif
+
+#if defined(DMA__LPSPI1)
+void DMA_SPI1_INT_DriverIRQHandler(void);
+void DMA_SPI1_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)] != NULL);
+ LPSPI_CommonIRQHandler(DMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]);
+}
+#endif
+#if defined(DMA__LPSPI2)
+void DMA_SPI2_INT_DriverIRQHandler(void);
+void DMA_SPI2_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)] != NULL);
+ LPSPI_CommonIRQHandler(DMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]);
+}
+#endif
+
+#if defined(DMA__LPSPI3)
+void DMA_SPI3_INT_DriverIRQHandler(void);
+void DMA_SPI3_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)] != NULL);
+ LPSPI_CommonIRQHandler(DMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI0)
+void ADMA_SPI0_INT_DriverIRQHandler(void);
+void ADMA_SPI0_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)] != NULL);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI1)
+void ADMA_SPI1_INT_DriverIRQHandler(void);
+void ADMA_SPI1_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)] != NULL);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]);
+}
+#endif
+#if defined(ADMA__LPSPI2)
+void ADMA_SPI2_INT_DriverIRQHandler(void);
+void ADMA_SPI2_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)] != NULL);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]);
+}
+#endif
+
+#if defined(ADMA__LPSPI3)
+void ADMA_SPI3_INT_DriverIRQHandler(void);
+void ADMA_SPI3_INT_DriverIRQHandler(void)
+{
+ assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)] != NULL);
+ LPSPI_CommonIRQHandler(ADMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]);
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.h
new file mode 100644
index 0000000000..98a4116982
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi.h
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPSPI_H_
+#define _FSL_LPSPI_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup lpspi_driver
+ * @{
+ */
+
+/**********************************************************************************************************************
+ * Definitions
+ *********************************************************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPSPI driver version. */
+#define FSL_LPSPI_DRIVER_VERSION (MAKE_VERSION(2, 4, 0))
+/*@}*/
+
+#ifndef LPSPI_DUMMY_DATA
+/*! @brief LPSPI dummy data if no Tx data.*/
+#define LPSPI_DUMMY_DATA (0x00U) /*!< Dummy data used for tx if there is not txData. */
+#endif
+
+/*! @brief Retry times for waiting flag. */
+#ifndef SPI_RETRY_TIMES
+#define SPI_RETRY_TIMES 0U /* Define to zero means keep waiting until the flag is assert/deassert. */
+#endif
+
+/*! @brief Global variable for dummy data value setting. */
+extern volatile uint8_t g_lpspiDummyData[];
+
+/*! @brief Status for the LPSPI driver.*/
+enum
+{
+ kStatus_LPSPI_Busy = MAKE_STATUS(kStatusGroup_LPSPI, 0), /*!< LPSPI transfer is busy.*/
+ kStatus_LPSPI_Error = MAKE_STATUS(kStatusGroup_LPSPI, 1), /*!< LPSPI driver error. */
+ kStatus_LPSPI_Idle = MAKE_STATUS(kStatusGroup_LPSPI, 2), /*!< LPSPI is idle.*/
+ kStatus_LPSPI_OutOfRange = MAKE_STATUS(kStatusGroup_LPSPI, 3), /*!< LPSPI transfer out Of range. */
+ kStatus_LPSPI_Timeout = MAKE_STATUS(kStatusGroup_LPSPI, 4) /*!< LPSPI timeout polling status flags. */
+};
+
+/*! @brief LPSPI status flags in SPIx_SR register.*/
+enum _lpspi_flags
+{
+ kLPSPI_TxDataRequestFlag = LPSPI_SR_TDF_MASK, /*!< Transmit data flag */
+ kLPSPI_RxDataReadyFlag = LPSPI_SR_RDF_MASK, /*!< Receive data flag */
+ kLPSPI_WordCompleteFlag = LPSPI_SR_WCF_MASK, /*!< Word Complete flag */
+ kLPSPI_FrameCompleteFlag = LPSPI_SR_FCF_MASK, /*!< Frame Complete flag */
+ kLPSPI_TransferCompleteFlag = LPSPI_SR_TCF_MASK, /*!< Transfer Complete flag */
+ kLPSPI_TransmitErrorFlag = LPSPI_SR_TEF_MASK, /*!< Transmit Error flag (FIFO underrun) */
+ kLPSPI_ReceiveErrorFlag = LPSPI_SR_REF_MASK, /*!< Receive Error flag (FIFO overrun) */
+ kLPSPI_DataMatchFlag = LPSPI_SR_DMF_MASK, /*!< Data Match flag */
+ kLPSPI_ModuleBusyFlag = LPSPI_SR_MBF_MASK, /*!< Module Busy flag */
+ kLPSPI_AllStatusFlag = (LPSPI_SR_TDF_MASK | LPSPI_SR_RDF_MASK | LPSPI_SR_WCF_MASK | LPSPI_SR_FCF_MASK |
+ LPSPI_SR_TCF_MASK | LPSPI_SR_TEF_MASK | LPSPI_SR_REF_MASK | LPSPI_SR_DMF_MASK |
+ LPSPI_SR_MBF_MASK) /*!< Used for clearing all w1c status flags */
+};
+
+/*! @brief LPSPI interrupt source.*/
+enum _lpspi_interrupt_enable
+{
+ kLPSPI_TxInterruptEnable = LPSPI_IER_TDIE_MASK, /*!< Transmit data interrupt enable */
+ kLPSPI_RxInterruptEnable = LPSPI_IER_RDIE_MASK, /*!< Receive data interrupt enable */
+ kLPSPI_WordCompleteInterruptEnable = LPSPI_IER_WCIE_MASK, /*!< Word complete interrupt enable */
+ kLPSPI_FrameCompleteInterruptEnable = LPSPI_IER_FCIE_MASK, /*!< Frame complete interrupt enable */
+ kLPSPI_TransferCompleteInterruptEnable = LPSPI_IER_TCIE_MASK, /*!< Transfer complete interrupt enable */
+ kLPSPI_TransmitErrorInterruptEnable = LPSPI_IER_TEIE_MASK, /*!< Transmit error interrupt enable(FIFO underrun)*/
+ kLPSPI_ReceiveErrorInterruptEnable = LPSPI_IER_REIE_MASK, /*!< Receive Error interrupt enable (FIFO overrun) */
+ kLPSPI_DataMatchInterruptEnable = LPSPI_IER_DMIE_MASK, /*!< Data Match interrupt enable */
+ kLPSPI_AllInterruptEnable =
+ (LPSPI_IER_TDIE_MASK | LPSPI_IER_RDIE_MASK | LPSPI_IER_WCIE_MASK | LPSPI_IER_FCIE_MASK | LPSPI_IER_TCIE_MASK |
+ LPSPI_IER_TEIE_MASK | LPSPI_IER_REIE_MASK | LPSPI_IER_DMIE_MASK) /*!< All above interrupts enable.*/
+};
+
+/*! @brief LPSPI DMA source.*/
+enum _lpspi_dma_enable
+{
+ kLPSPI_TxDmaEnable = LPSPI_DER_TDDE_MASK, /*!< Transmit data DMA enable */
+ kLPSPI_RxDmaEnable = LPSPI_DER_RDDE_MASK /*!< Receive data DMA enable */
+};
+
+/*! @brief LPSPI master or slave mode configuration.*/
+typedef enum _lpspi_master_slave_mode
+{
+ kLPSPI_Master = 1U, /*!< LPSPI peripheral operates in master mode.*/
+ kLPSPI_Slave = 0U /*!< LPSPI peripheral operates in slave mode.*/
+} lpspi_master_slave_mode_t;
+
+/*! @brief LPSPI Peripheral Chip Select (PCS) configuration (which PCS to configure).*/
+typedef enum _lpspi_which_pcs_config
+{
+ kLPSPI_Pcs0 = 0U, /*!< PCS[0] */
+ kLPSPI_Pcs1 = 1U, /*!< PCS[1] */
+ kLPSPI_Pcs2 = 2U, /*!< PCS[2] */
+ kLPSPI_Pcs3 = 3U /*!< PCS[3] */
+} lpspi_which_pcs_t;
+
+/*! @brief LPSPI Peripheral Chip Select (PCS) Polarity configuration.*/
+typedef enum _lpspi_pcs_polarity_config
+{
+ kLPSPI_PcsActiveHigh = 1U, /*!< PCS Active High (idles low) */
+ kLPSPI_PcsActiveLow = 0U /*!< PCS Active Low (idles high) */
+} lpspi_pcs_polarity_config_t;
+
+/*! @brief LPSPI Peripheral Chip Select (PCS) Polarity.*/
+enum _lpspi_pcs_polarity
+{
+ kLPSPI_Pcs0ActiveLow = 1U << 0, /*!< Pcs0 Active Low (idles high). */
+ kLPSPI_Pcs1ActiveLow = 1U << 1, /*!< Pcs1 Active Low (idles high). */
+ kLPSPI_Pcs2ActiveLow = 1U << 2, /*!< Pcs2 Active Low (idles high). */
+ kLPSPI_Pcs3ActiveLow = 1U << 3, /*!< Pcs3 Active Low (idles high). */
+ kLPSPI_PcsAllActiveLow = 0xFU /*!< Pcs0 to Pcs5 Active Low (idles high). */
+};
+
+/*! @brief LPSPI clock polarity configuration.*/
+typedef enum _lpspi_clock_polarity
+{
+ kLPSPI_ClockPolarityActiveHigh = 0U, /*!< CPOL=0. Active-high LPSPI clock (idles low)*/
+ kLPSPI_ClockPolarityActiveLow = 1U /*!< CPOL=1. Active-low LPSPI clock (idles high)*/
+} lpspi_clock_polarity_t;
+
+/*! @brief LPSPI clock phase configuration.*/
+typedef enum _lpspi_clock_phase
+{
+ kLPSPI_ClockPhaseFirstEdge = 0U, /*!< CPHA=0. Data is captured on the leading edge of the SCK and changed on the
+ following edge.*/
+ kLPSPI_ClockPhaseSecondEdge = 1U /*!< CPHA=1. Data is changed on the leading edge of the SCK and captured on the
+ following edge.*/
+} lpspi_clock_phase_t;
+
+/*! @brief LPSPI data shifter direction options.*/
+typedef enum _lpspi_shift_direction
+{
+ kLPSPI_MsbFirst = 0U, /*!< Data transfers start with most significant bit.*/
+ kLPSPI_LsbFirst = 1U /*!< Data transfers start with least significant bit.*/
+} lpspi_shift_direction_t;
+
+/*! @brief LPSPI Host Request select configuration. */
+typedef enum _lpspi_host_request_select
+{
+ kLPSPI_HostReqExtPin = 0U, /*!< Host Request is an ext pin. */
+ kLPSPI_HostReqInternalTrigger = 1U /*!< Host Request is an internal trigger. */
+} lpspi_host_request_select_t;
+
+/*! @brief LPSPI Match configuration options. */
+typedef enum _lpspi_match_config
+{
+ kLPSI_MatchDisabled = 0x0U, /*!< LPSPI Match Disabled. */
+ kLPSI_1stWordEqualsM0orM1 = 0x2U, /*!< LPSPI Match Enabled. */
+ kLPSI_AnyWordEqualsM0orM1 = 0x3U, /*!< LPSPI Match Enabled. */
+ kLPSI_1stWordEqualsM0and2ndWordEqualsM1 = 0x4U, /*!< LPSPI Match Enabled. */
+ kLPSI_AnyWordEqualsM0andNxtWordEqualsM1 = 0x5U, /*!< LPSPI Match Enabled. */
+ kLPSI_1stWordAndM1EqualsM0andM1 = 0x6U, /*!< LPSPI Match Enabled. */
+ kLPSI_AnyWordAndM1EqualsM0andM1 = 0x7U, /*!< LPSPI Match Enabled. */
+} lpspi_match_config_t;
+
+/*! @brief LPSPI pin (SDO and SDI) configuration. */
+typedef enum _lpspi_pin_config
+{
+ kLPSPI_SdiInSdoOut = 0U, /*!< LPSPI SDI input, SDO output. */
+ kLPSPI_SdiInSdiOut = 1U, /*!< LPSPI SDI input, SDI output. */
+ kLPSPI_SdoInSdoOut = 2U, /*!< LPSPI SDO input, SDO output. */
+ kLPSPI_SdoInSdiOut = 3U /*!< LPSPI SDO input, SDI output. */
+} lpspi_pin_config_t;
+
+/*! @brief LPSPI data output configuration. */
+typedef enum _lpspi_data_out_config
+{
+ kLpspiDataOutRetained = 0U, /*!< Data out retains last value when chip select is de-asserted */
+ kLpspiDataOutTristate = 1U /*!< Data out is tristated when chip select is de-asserted */
+} lpspi_data_out_config_t;
+
+/*! @brief LPSPI transfer width configuration. */
+typedef enum _lpspi_transfer_width
+{
+ kLPSPI_SingleBitXfer = 0U, /*!< 1-bit shift at a time, data out on SDO, in on SDI (normal mode) */
+ kLPSPI_TwoBitXfer = 1U, /*!< 2-bits shift out on SDO/SDI and in on SDO/SDI */
+ kLPSPI_FourBitXfer = 2U /*!< 4-bits shift out on SDO/SDI/PCS[3:2] and in on SDO/SDI/PCS[3:2] */
+} lpspi_transfer_width_t;
+
+/*! @brief LPSPI delay type selection.*/
+typedef enum _lpspi_delay_type
+{
+ kLPSPI_PcsToSck = 1U, /*!< PCS-to-SCK delay. */
+ kLPSPI_LastSckToPcs, /*!< Last SCK edge to PCS delay. */
+ kLPSPI_BetweenTransfer /*!< Delay between transfers. */
+} lpspi_delay_type_t;
+
+#define LPSPI_MASTER_PCS_SHIFT (4U) /*!< LPSPI master PCS shift macro , internal used. */
+#define LPSPI_MASTER_PCS_MASK (0xF0U) /*!< LPSPI master PCS shift macro , internal used. */
+
+/*! @brief Use this enumeration for LPSPI master transfer configFlags. */
+enum _lpspi_transfer_config_flag_for_master
+{
+ kLPSPI_MasterPcs0 = 0U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS0 signal */
+ kLPSPI_MasterPcs1 = 1U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS1 signal */
+ kLPSPI_MasterPcs2 = 2U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS2 signal */
+ kLPSPI_MasterPcs3 = 3U << LPSPI_MASTER_PCS_SHIFT, /*!< LPSPI master transfer use PCS3 signal */
+
+ kLPSPI_MasterPcsContinuous = 1U << 20, /*!< Is PCS signal continuous */
+
+ kLPSPI_MasterByteSwap =
+ 1U << 22 /*!< Is master swap the byte.
+ * For example, when want to send data 1 2 3 4 5 6 7 8 (suppose you set
+ * lpspi_shift_direction_t to MSB).
+ * 1. If you set bitPerFrame = 8 , no matter the kLPSPI_MasterByteSwapyou flag is used
+ * or not, the waveform is 1 2 3 4 5 6 7 8.
+ * 2. If you set bitPerFrame = 16 :
+ * (1) the waveform is 2 1 4 3 6 5 8 7 if you do not use the kLPSPI_MasterByteSwap flag.
+ * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_MasterByteSwap flag.
+ * 3. If you set bitPerFrame = 32 :
+ * (1) the waveform is 4 3 2 1 8 7 6 5 if you do not use the kLPSPI_MasterByteSwap flag.
+ * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_MasterByteSwap flag.
+ */
+};
+
+#define LPSPI_SLAVE_PCS_SHIFT (4U) /*!< LPSPI slave PCS shift macro , internal used. */
+#define LPSPI_SLAVE_PCS_MASK (0xF0U) /*!< LPSPI slave PCS shift macro , internal used. */
+
+/*! @brief Use this enumeration for LPSPI slave transfer configFlags. */
+enum _lpspi_transfer_config_flag_for_slave
+{
+ kLPSPI_SlavePcs0 = 0U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS0 signal */
+ kLPSPI_SlavePcs1 = 1U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS1 signal */
+ kLPSPI_SlavePcs2 = 2U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS2 signal */
+ kLPSPI_SlavePcs3 = 3U << LPSPI_SLAVE_PCS_SHIFT, /*!< LPSPI slave transfer use PCS3 signal */
+
+ kLPSPI_SlaveByteSwap =
+ 1U << 22 /*!< Is slave swap the byte.
+ * For example, when want to send data 1 2 3 4 5 6 7 8 (suppose you set
+ * lpspi_shift_direction_t to MSB).
+ * 1. If you set bitPerFrame = 8 , no matter the kLPSPI_SlaveByteSwap flag is used
+ * or not, the waveform is 1 2 3 4 5 6 7 8.
+ * 2. If you set bitPerFrame = 16 :
+ * (1) the waveform is 2 1 4 3 6 5 8 7 if you do not use the kLPSPI_SlaveByteSwap flag.
+ * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_SlaveByteSwap flag.
+ * 3. If you set bitPerFrame = 32 :
+ * (1) the waveform is 4 3 2 1 8 7 6 5 if you do not use the kLPSPI_SlaveByteSwap flag.
+ * (2) the waveform is 1 2 3 4 5 6 7 8 if you use the kLPSPI_SlaveByteSwap flag.
+ */
+};
+
+/*! @brief LPSPI transfer state, which is used for LPSPI transactional API state machine. */
+enum _lpspi_transfer_state
+{
+ kLPSPI_Idle = 0x0U, /*!< Nothing in the transmitter/receiver. */
+ kLPSPI_Busy, /*!< Transfer queue is not finished. */
+ kLPSPI_Error /*!< Transfer error. */
+};
+
+/*! @brief LPSPI master configuration structure.*/
+typedef struct _lpspi_master_config
+{
+ uint32_t baudRate; /*!< Baud Rate for LPSPI. */
+ uint32_t bitsPerFrame; /*!< Bits per frame, minimum 8, maximum 4096.*/
+ lpspi_clock_polarity_t cpol; /*!< Clock polarity. */
+ lpspi_clock_phase_t cpha; /*!< Clock phase. */
+ lpspi_shift_direction_t direction; /*!< MSB or LSB data shift direction. */
+
+ uint32_t pcsToSckDelayInNanoSec; /*!< PCS to SCK delay time in nanoseconds, setting to 0 sets the minimum delay.
+ It sets the boundary value if out of range.*/
+ uint32_t lastSckToPcsDelayInNanoSec; /*!< Last SCK to PCS delay time in nanoseconds, setting to 0 sets the minimum
+ delay. It sets the boundary value if out of range.*/
+ uint32_t betweenTransferDelayInNanoSec; /*!< After the SCK delay time with nanoseconds, setting to 0 sets the
+ minimum delay. It sets the boundary value if out of range.*/
+
+ lpspi_which_pcs_t whichPcs; /*!< Desired Peripheral Chip Select (PCS). */
+ lpspi_pcs_polarity_config_t pcsActiveHighOrLow; /*!< Desired PCS active high or low */
+
+ lpspi_pin_config_t pinCfg; /*!< Configures which pins are used for input and output data
+ *during single bit transfers.*/
+
+ lpspi_data_out_config_t dataOutConfig; /*!< Configures if the output data is tristated
+ * between accesses (LPSPI_PCS is negated). */
+ bool enableInputDelay; /*!< Enable master to sample the input data on a delayed SCK. This can help improve slave
+ setup time. Refer to device data sheet for specific time length. */
+} lpspi_master_config_t;
+
+/*! @brief LPSPI slave configuration structure.*/
+typedef struct _lpspi_slave_config
+{
+ uint32_t bitsPerFrame; /*!< Bits per frame, minimum 8, maximum 4096.*/
+ lpspi_clock_polarity_t cpol; /*!< Clock polarity. */
+ lpspi_clock_phase_t cpha; /*!< Clock phase. */
+ lpspi_shift_direction_t direction; /*!< MSB or LSB data shift direction. */
+
+ lpspi_which_pcs_t whichPcs; /*!< Desired Peripheral Chip Select (pcs) */
+ lpspi_pcs_polarity_config_t pcsActiveHighOrLow; /*!< Desired PCS active high or low */
+
+ lpspi_pin_config_t pinCfg; /*!< Configures which pins are used for input and output data
+ *during single bit transfers.*/
+
+ lpspi_data_out_config_t dataOutConfig; /*!< Configures if the output data is tristated
+ * between accesses (LPSPI_PCS is negated). */
+} lpspi_slave_config_t;
+
+/*!
+ * @brief Forward declaration of the _lpspi_master_handle typedefs.
+ */
+typedef struct _lpspi_master_handle lpspi_master_handle_t;
+
+/*!
+ * @brief Forward declaration of the _lpspi_slave_handle typedefs.
+ */
+typedef struct _lpspi_slave_handle lpspi_slave_handle_t;
+
+/*!
+ * @brief Master completion callback function pointer type.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle Pointer to the handle for the LPSPI master.
+ * @param status Success or error code describing whether the transfer is completed.
+ * @param userData Arbitrary pointer-dataSized value passed from the application.
+ */
+typedef void (*lpspi_master_transfer_callback_t)(LPSPI_Type *base,
+ lpspi_master_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*!
+ * @brief Slave completion callback function pointer type.
+ *
+ * @param base LPSPI peripheral address.
+ * @param handle Pointer to the handle for the LPSPI slave.
+ * @param status Success or error code describing whether the transfer is completed.
+ * @param userData Arbitrary pointer-dataSized value passed from the application.
+ */
+typedef void (*lpspi_slave_transfer_callback_t)(LPSPI_Type *base,
+ lpspi_slave_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief LPSPI master/slave transfer structure.*/
+typedef struct _lpspi_transfer
+{
+ uint8_t *txData; /*!< Send buffer. */
+ uint8_t *rxData; /*!< Receive buffer. */
+ volatile size_t dataSize; /*!< Transfer bytes. */
+
+ uint32_t configFlags; /*!< Transfer transfer configuration flags. Set from _lpspi_transfer_config_flag_for_master if
+ the transfer is used for master or _lpspi_transfer_config_flag_for_slave enumeration if the
+ transfer is used for slave.*/
+} lpspi_transfer_t;
+
+/*! @brief LPSPI master transfer handle structure used for transactional API. */
+struct _lpspi_master_handle
+{
+ volatile bool isPcsContinuous; /*!< Is PCS continuous in transfer. */
+ volatile bool writeTcrInIsr; /*!< A flag that whether should write TCR in ISR. */
+
+ volatile bool isByteSwap; /*!< A flag that whether should byte swap. */
+ volatile bool isTxMask; /*!< A flag that whether TCR[TXMSK] is set. */
+ volatile uint16_t bytesPerFrame; /*!< Number of bytes in each frame */
+
+ volatile uint8_t fifoSize; /*!< FIFO dataSize. */
+
+ volatile uint8_t rxWatermark; /*!< Rx watermark. */
+
+ volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */
+ volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */
+
+ uint8_t *volatile txData; /*!< Send buffer. */
+ uint8_t *volatile rxData; /*!< Receive buffer. */
+ volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/
+ volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/
+
+ volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */
+ volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */
+
+ uint32_t totalByteCount; /*!< Number of transfer bytes*/
+
+ uint32_t txBuffIfNull; /*!< Used if the txData is NULL. */
+
+ volatile uint8_t state; /*!< LPSPI transfer state , _lpspi_transfer_state.*/
+
+ lpspi_master_transfer_callback_t callback; /*!< Completion callback. */
+ void *userData; /*!< Callback user data. */
+};
+
+/*! @brief LPSPI slave transfer handle structure used for transactional API. */
+struct _lpspi_slave_handle
+{
+ volatile bool isByteSwap; /*!< A flag that whether should byte swap. */
+
+ volatile uint8_t fifoSize; /*!< FIFO dataSize. */
+
+ volatile uint8_t rxWatermark; /*!< Rx watermark. */
+
+ volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */
+ volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */
+
+ uint8_t *volatile txData; /*!< Send buffer. */
+ uint8_t *volatile rxData; /*!< Receive buffer. */
+
+ volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/
+ volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/
+
+ volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */
+ volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */
+
+ uint32_t totalByteCount; /*!< Number of transfer bytes*/
+
+ volatile uint8_t state; /*!< LPSPI transfer state , _lpspi_transfer_state.*/
+
+ volatile uint32_t errorCount; /*!< Error count for slave transfer.*/
+
+ lpspi_slave_transfer_callback_t callback; /*!< Completion callback. */
+ void *userData; /*!< Callback user data. */
+};
+
+/**********************************************************************************************************************
+ * API
+ *********************************************************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @brief Enables the LPSPI peripheral and sets the MCR MDIS to 0.
+ *
+ * @param base LPSPI peripheral address.
+ * @param enable Pass true to enable module, false to disable module.
+ */
+static inline void LPSPI_Enable(LPSPI_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CR |= LPSPI_CR_MEN_MASK;
+ }
+ else
+ {
+ base->CR &= ~LPSPI_CR_MEN_MASK;
+ }
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the LPSPI status flag state.
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI status(in SR register).
+ */
+static inline uint32_t LPSPI_GetStatusFlags(LPSPI_Type *base)
+{
+ return (base->SR);
+}
+
+/*!
+ * @brief Gets the LPSPI Tx FIFO size.
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI Tx FIFO size.
+ */
+static inline uint8_t LPSPI_GetTxFifoSize(LPSPI_Type *base)
+{
+ return (1U << ((base->PARAM & LPSPI_PARAM_TXFIFO_MASK) >> LPSPI_PARAM_TXFIFO_SHIFT));
+}
+
+/*!
+ * @brief Gets the LPSPI Rx FIFO size.
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI Rx FIFO size.
+ */
+static inline uint8_t LPSPI_GetRxFifoSize(LPSPI_Type *base)
+{
+ return (1U << ((base->PARAM & LPSPI_PARAM_RXFIFO_MASK) >> LPSPI_PARAM_RXFIFO_SHIFT));
+}
+
+/*!
+ * @brief Gets the LPSPI Tx FIFO count.
+ * @param base LPSPI peripheral address.
+ * @return The number of words in the transmit FIFO.
+ */
+static inline uint32_t LPSPI_GetTxFifoCount(LPSPI_Type *base)
+{
+ return ((base->FSR & LPSPI_FSR_TXCOUNT_MASK) >> LPSPI_FSR_TXCOUNT_SHIFT);
+}
+
+/*!
+ * @brief Gets the LPSPI Rx FIFO count.
+ * @param base LPSPI peripheral address.
+ * @return The number of words in the receive FIFO.
+ */
+static inline uint32_t LPSPI_GetRxFifoCount(LPSPI_Type *base)
+{
+ return ((base->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT);
+}
+
+/*!
+ * @brief Clears the LPSPI status flag.
+ *
+ * This function clears the desired status bit by using a write-1-to-clear. The user passes in the base and the
+ * desired status flag bit to clear. The list of status flags is defined in the _lpspi_flags.
+ * Example usage:
+ * @code
+ * LPSPI_ClearStatusFlags(base, kLPSPI_TxDataRequestFlag|kLPSPI_RxDataReadyFlag);
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param statusFlags The status flag used from type _lpspi_flags.
+ */
+static inline void LPSPI_ClearStatusFlags(LPSPI_Type *base, uint32_t statusFlags)
+{
+ base->SR = statusFlags; /*!< The status flags are cleared by writing 1 (w1c).*/
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the LPSPI interrupts.
+ *
+ * This function configures the various interrupt masks of the LPSPI. The parameters are base and an interrupt mask.
+ * Note that, for Tx fill and Rx FIFO drain requests, enabling the interrupt request disables the DMA request.
+ *
+ * @code
+ * LPSPI_EnableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable );
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The interrupt mask; Use the enum _lpspi_interrupt_enable.
+ */
+static inline void LPSPI_EnableInterrupts(LPSPI_Type *base, uint32_t mask)
+{
+ base->IER |= mask;
+}
+
+/*!
+ * @brief Disables the LPSPI interrupts.
+ *
+ * @code
+ * LPSPI_DisableInterrupts(base, kLPSPI_TxInterruptEnable | kLPSPI_RxInterruptEnable );
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The interrupt mask; Use the enum _lpspi_interrupt_enable.
+ */
+static inline void LPSPI_DisableInterrupts(LPSPI_Type *base, uint32_t mask)
+{
+ base->IER &= ~mask;
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables the LPSPI DMA request.
+ *
+ * This function configures the Rx and Tx DMA mask of the LPSPI. The parameters are base and a DMA mask.
+ * @code
+ * LPSPI_EnableDMA(base, kLPSPI_TxDmaEnable | kLPSPI_RxDmaEnable);
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The interrupt mask; Use the enum _lpspi_dma_enable.
+ */
+static inline void LPSPI_EnableDMA(LPSPI_Type *base, uint32_t mask)
+{
+ base->DER |= mask;
+}
+
+/*!
+ * @brief Disables the LPSPI DMA request.
+ *
+ * This function configures the Rx and Tx DMA mask of the LPSPI. The parameters are base and a DMA mask.
+ * @code
+ * SPI_DisableDMA(base, kLPSPI_TxDmaEnable | kLPSPI_RxDmaEnable);
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The interrupt mask; Use the enum _lpspi_dma_enable.
+ */
+static inline void LPSPI_DisableDMA(LPSPI_Type *base, uint32_t mask)
+{
+ base->DER &= ~mask;
+}
+
+/*!
+ * @brief Gets the LPSPI Transmit Data Register address for a DMA operation.
+ *
+ * This function gets the LPSPI Transmit Data Register address because this value is needed
+ * for the DMA operation.
+ * This function can be used for either master or slave mode.
+ *
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI Transmit Data Register address.
+ */
+static inline uint32_t LPSPI_GetTxRegisterAddress(LPSPI_Type *base)
+{
+ return (uint32_t) & (base->TDR);
+}
+
+/*!
+ * @brief Gets the LPSPI Receive Data Register address for a DMA operation.
+ *
+ * This function gets the LPSPI Receive Data Register address because this value is needed
+ * for the DMA operation.
+ * This function can be used for either master or slave mode.
+ *
+ * @param base LPSPI peripheral address.
+ * @return The LPSPI Receive Data Register address.
+ */
+static inline uint32_t LPSPI_GetRxRegisterAddress(LPSPI_Type *base)
+{
+ return (uint32_t) & (base->RDR);
+}
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+
+/*!
+ * @brief Check the argument for transfer .
+ *
+ * @param base LPSPI peripheral address.
+ * @param transfer the transfer struct to be used.
+ * @param isEdma True to check for EDMA transfer, false to check interrupt non-blocking transfer
+ * @return Return true for right and false for wrong.
+ */
+bool LPSPI_CheckTransferArgument(LPSPI_Type *base, lpspi_transfer_t *transfer, bool isEdma);
+
+/*!
+ * @brief Configures the LPSPI for either master or slave.
+ *
+ * Note that the CFGR1 should only be written when the LPSPI is disabled (LPSPIx_CR_MEN = 0).
+ *
+ * @param base LPSPI peripheral address.
+ * @param mode Mode setting (master or slave) of type lpspi_master_slave_mode_t.
+ */
+static inline void LPSPI_SetMasterSlaveMode(LPSPI_Type *base, lpspi_master_slave_mode_t mode)
+{
+ base->CFGR1 = (base->CFGR1 & (~LPSPI_CFGR1_MASTER_MASK)) | LPSPI_CFGR1_MASTER(mode);
+}
+
+/*!
+ * @brief Configures the peripheral chip select used for the transfer.
+ *
+ * @param base LPSPI peripheral address.
+ * @param select LPSPI Peripheral Chip Select (PCS) configuration.
+ */
+static inline void LPSPI_SelectTransferPCS(LPSPI_Type *base, lpspi_which_pcs_t select)
+{
+ base->TCR = (base->TCR & (~LPSPI_TCR_PCS_MASK)) | LPSPI_TCR_PCS((uint8_t)select);
+}
+
+/*!
+ * @brief Set the PCS signal to continuous or uncontinuous mode.
+ *
+ * @note In master mode, continuous transfer will keep the PCS asserted at the end of the frame size, until a command
+ * word is received that starts a new frame. So PCS must be set back to uncontinuous when transfer finishes.
+ * In slave mode, when continuous transfer is enabled, the LPSPI will only transmit the first frame size bits, after
+ * that the LPSPI will transmit received data back (assuming a 32-bit shift register).
+ *
+ * @param base LPSPI peripheral address.
+ * @param IsContinous True to set the transfer PCS to continuous mode, false to set to uncontinuous mode.
+ */
+static inline void LPSPI_SetPCSContinous(LPSPI_Type *base, bool IsContinous)
+{
+ if (IsContinous)
+ {
+ base->TCR |= LPSPI_TCR_CONT_MASK;
+ }
+ else
+ {
+ base->TCR &= ~LPSPI_TCR_CONT_MASK;
+ }
+}
+
+/*!
+ * @brief Returns whether the LPSPI module is in master mode.
+ *
+ * @param base LPSPI peripheral address.
+ * @return Returns true if the module is in master mode or false if the module is in slave mode.
+ */
+static inline bool LPSPI_IsMaster(LPSPI_Type *base)
+{
+ return (bool)((base->CFGR1) & LPSPI_CFGR1_MASTER_MASK);
+}
+
+/*!
+ * @brief Flushes the LPSPI FIFOs.
+ *
+ * @param base LPSPI peripheral address.
+ * @param flushTxFifo Flushes (true) the Tx FIFO, else do not flush (false) the Tx FIFO.
+ * @param flushRxFifo Flushes (true) the Rx FIFO, else do not flush (false) the Rx FIFO.
+ */
+static inline void LPSPI_FlushFifo(LPSPI_Type *base, bool flushTxFifo, bool flushRxFifo)
+{
+ base->CR |= ((uint32_t)flushTxFifo << LPSPI_CR_RTF_SHIFT) | ((uint32_t)flushRxFifo << LPSPI_CR_RRF_SHIFT);
+}
+
+/*!
+ * @brief Sets the transmit and receive FIFO watermark values.
+ *
+ * This function allows the user to set the receive and transmit FIFO watermarks. The function
+ * does not compare the watermark settings to the FIFO size. The FIFO watermark should not be
+ * equal to or greater than the FIFO size. It is up to the higher level driver to make this check.
+ *
+ * @param base LPSPI peripheral address.
+ * @param txWater The TX FIFO watermark value. Writing a value equal or greater than the FIFO size is truncated.
+ * @param rxWater The RX FIFO watermark value. Writing a value equal or greater than the FIFO size is truncated.
+ */
+static inline void LPSPI_SetFifoWatermarks(LPSPI_Type *base, uint32_t txWater, uint32_t rxWater)
+{
+ base->FCR = LPSPI_FCR_TXWATER(txWater) | LPSPI_FCR_RXWATER(rxWater);
+}
+
+/*!
+ * @brief Configures all LPSPI peripheral chip select polarities simultaneously.
+ *
+ * Note that the CFGR1 should only be written when the LPSPI is disabled (LPSPIx_CR_MEN = 0).
+ *
+ * This is an example: PCS0 and PCS1 set to active low and other PCSs set to active high. Note that the number of
+ * PCS is device-specific.
+ * @code
+ * LPSPI_SetAllPcsPolarity(base, kLPSPI_Pcs0ActiveLow | kLPSPI_Pcs1ActiveLow);
+ * @endcode
+ *
+ * @param base LPSPI peripheral address.
+ * @param mask The PCS polarity mask; Use the enum _lpspi_pcs_polarity.
+ */
+static inline void LPSPI_SetAllPcsPolarity(LPSPI_Type *base, uint32_t mask)
+{
+ base->CFGR1 = (base->CFGR1 & ~LPSPI_CFGR1_PCSPOL_MASK) | LPSPI_CFGR1_PCSPOL(~mask);
+}
+
+/*!
+ * @brief Configures the frame size.
+ *
+ * The minimum frame size is 8-bits and the maximum frame size is 4096-bits. If the frame size is less than or equal
+ * to 32-bits, the word size and frame size are identical. If the frame size is greater than 32-bits, the word
+ * size is 32-bits for each word except the last (the last word contains the remainder bits if the frame size is not
+ * divisible by 32). The minimum word size is 2-bits. A frame size of 33-bits (or similar) is not supported.
+ *
+ * Note 1: The transmit command register should be initialized before enabling the LPSPI in slave mode, although
+ * the command register does not update until after the LPSPI is enabled. After it is enabled, the transmit command
+ * register
+ * should only be changed if the LPSPI is idle.
+ *
+ * Note 2: The transmit and command FIFO is a combined FIFO that includes both transmit data and command words. That
+ * means the TCR register should be written to when the Tx FIFO is not full.
+ *
+ * @param base LPSPI peripheral address.
+ * @param frameSize The frame size in number of bits.
+ */
+static inline void LPSPI_SetFrameSize(LPSPI_Type *base, uint32_t frameSize)
+{
+ base->TCR = (base->TCR & ~LPSPI_TCR_FRAMESZ_MASK) | LPSPI_TCR_FRAMESZ(frameSize - 1U);
+}
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @brief Writes data into the transmit data buffer.
+ *
+ * This function writes data passed in by the user to the Transmit Data Register (TDR).
+ * The user can pass up to 32-bits of data to load into the TDR. If the frame size exceeds 32-bits,
+ * the user has to manage sending the data one 32-bit word at a time.
+ * Any writes to the TDR result in an immediate push to the transmit FIFO.
+ * This function can be used for either master or slave modes.
+ *
+ * @param base LPSPI peripheral address.
+ * @param data The data word to be sent.
+ */
+static inline void LPSPI_WriteData(LPSPI_Type *base, uint32_t data)
+{
+ base->TDR = data;
+}
+
+/*!
+ * @brief Reads data from the data buffer.
+ *
+ * This function reads the data from the Receive Data Register (RDR).
+ * This function can be used for either master or slave mode.
+ *
+ * @param base LPSPI peripheral address.
+ * @return The data read from the data buffer.
+ */
+static inline uint32_t LPSPI_ReadData(LPSPI_Type *base)
+{
+ return (base->RDR);
+}
+
+/*!
+ * @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);
+
+/*!
+ *@}
+ */
+
+/*!
+ * @name Transactional
+ * @{
+ */
+/*Transactional APIs*/
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ *@}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /*_FSL_LPSPI_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.c
new file mode 100644
index 0000000000..92e8bbdb4d
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.c
@@ -0,0 +1,1052 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 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 != NULL);
+
+ 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 != NULL);
+ assert(edmaRxRegToRxDataHandle != NULL);
+ assert(edmaTxDataToTxRegHandle != NULL);
+
+ /* 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;
+}
+
+static void LPSPI_PrepareTransferEDMA(LPSPI_Type *base)
+{
+ /* Flush FIFO, clear status, disable all the inerrupts and DMA requests. */
+ LPSPI_FlushFifo(base, true, true);
+ LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
+ LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
+ LPSPI_DisableDMA(base, (uint32_t)kLPSPI_RxDmaEnable | (uint32_t)kLPSPI_TxDmaEnable);
+}
+
+/*!
+ * 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 != NULL);
+ assert(transfer != NULL);
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+
+ /* Disable module before configuration */
+ LPSPI_Enable(base, false);
+ /* Check arguements */
+ if (!LPSPI_CheckTransferArgument(base, transfer, true))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ LPSPI_PrepareTransferEDMA(base);
+
+ /* Variables */
+ bool isThereExtraTxBytes = false;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ bool isPcsContinuous = ((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U);
+ uint32_t instance = LPSPI_GetInstance(base);
+ uint8_t dummyData = g_lpspiDummyData[instance];
+ uint8_t bytesLastWrite = 0;
+ /*Used for byte swap*/
+ uint32_t addrOffset = 0;
+ 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;
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ edma_transfer_config_t transferConfigRx = {0};
+ edma_transfer_config_t transferConfigTx = {0};
+ edma_tcd_t *softwareTCD_pcsContinuous = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[2]) & (~0x1FU));
+ edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
+
+ handle->state = (uint8_t)kLPSPI_Busy;
+ 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 = isPcsContinuous;
+ handle->isByteSwap = isByteSwap;
+ handle->isThereExtraRxBytes = false;
+
+ /*Because DMA is fast enough , so set the RX and TX watermarks to 0 .*/
+ LPSPI_SetFifoWatermarks(base, 0U, 0U);
+
+ /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+
+ /* Enable module for following configuration of TCR to take effect. */
+ LPSPI_Enable(base, true);
+
+ /* 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_BYSW(isByteSwap) | 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;
+
+ 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;
+ }
+ }
+
+ EDMA_SetCallback(handle->edmaRxRegToRxDataHandle, EDMA_LpspiMasterCallback,
+ &s_lpspiMasterEdmaPrivateHandle[instance]);
+
+ /* Configure rx EDMA transfer */
+ 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;
+
+ addrOffset = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigRx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 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 + addrOffset;
+ 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);
+
+ /* Configure tx EDMA transfer */
+ 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;
+
+ addrOffset = 0;
+ switch (bytesLastWrite)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 2;
+ }
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
+ 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;
+
+ addrOffset = 0U;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+
+ if (handle->isByteSwap)
+ {
+ addrOffset = 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 + addrOffset;
+
+ 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 != NULL);
+ assert(g_lpspiEdmaPrivateHandle != NULL);
+
+ 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 != NULL);
+
+ 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 != 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;
+
+ 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 != NULL);
+ assert(edmaRxRegToRxDataHandle != NULL);
+ assert(edmaTxDataToTxRegHandle != NULL);
+
+ /* 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 != NULL);
+ assert(transfer != NULL);
+
+ /* Check that we're not busy.*/
+ if (handle->state == (uint8_t)kLPSPI_Busy)
+ {
+ return kStatus_LPSPI_Busy;
+ }
+ /* Disable module before configuration. */
+ LPSPI_Enable(base, false);
+ /* Check arguements, also dma transfer can not support 3 bytes */
+ if (!LPSPI_CheckTransferArgument(base, transfer, true))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ LPSPI_PrepareTransferEDMA(base);
+
+ /* Variables */
+ bool isThereExtraTxBytes = false;
+ bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U);
+ uint8_t bytesLastWrite = 0;
+ uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)];
+ uint32_t mask = (uint32_t)kLPSPI_RxDmaEnable;
+
+ /* Used for byte swap */
+ uint32_t addrOffset = 0;
+ 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;
+ uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
+ edma_transfer_config_t transferConfigRx = {0};
+ edma_transfer_config_t transferConfigTx = {0};
+ edma_tcd_t *softwareTCD_extraBytes = (edma_tcd_t *)((uint32_t)(&handle->lpspiSoftwareTCD[1]) & (~0x1FU));
+
+ /* Assign the original value for members of transfer handle. */
+ handle->state = (uint8_t)kLPSPI_Busy;
+ 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 = isByteSwap;
+ handle->isThereExtraRxBytes = false;
+
+ /* Because DMA is fast enough, set the RX and TX watermarks to 0. */
+ LPSPI_SetFifoWatermarks(base, 0U, 0U);
+
+ /* Transfers will stall when transmit FIFO is empty or receive FIFO is full. */
+ base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK);
+
+ /* Enable module for following configuration of TCR to take effect. */
+ LPSPI_Enable(base, true);
+
+ /* For DMA transfer, mask the transmit data if the tx data is null, for rx the receive data should not be masked at
+ any time since we use rx dma transfer finish cllback to indicate transfer finish. */
+ base->TCR =
+ (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_BYSW_MASK | LPSPI_TCR_TXMSK_MASK)) |
+ LPSPI_TCR_TXMSK(transfer->txData == NULL) | LPSPI_TCR_BYSW(isByteSwap) | 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;
+
+ 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;
+ }
+ }
+
+ 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;
+
+ addrOffset = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigRx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigRx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 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 + addrOffset;
+ 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);
+ EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
+ }
+
+ /*Tx*/
+ if (handle->txData != NULL)
+ {
+ EDMA_ResetChannel(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel);
+ if (isThereExtraTxBytes)
+ {
+ transferConfigTx.srcAddr = (uint32_t) & (transfer->txData[transfer->dataSize - bytesLastWrite]);
+ transferConfigTx.srcOffset = 1;
+ transferConfigTx.destOffset = 0;
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ addrOffset = 0;
+ switch (bytesLastWrite)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 2;
+ }
+ break;
+
+ default:
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ assert(false);
+ break;
+ }
+
+ transferConfigTx.destAddr = (uint32_t)txAddr + addrOffset;
+ transferConfigTx.majorLoopCounts = 1;
+
+ EDMA_TcdReset(softwareTCD_extraBytes);
+ EDMA_TcdSetTransferConfig(softwareTCD_extraBytes, &transferConfigTx, NULL);
+ }
+
+ transferConfigTx.srcAddr = (uint32_t)(handle->txData);
+ transferConfigTx.srcOffset = 1;
+ transferConfigTx.destOffset = 0;
+ transferConfigTx.srcTransferSize = kEDMA_TransferSize1Bytes;
+ addrOffset = 0;
+ switch (handle->bytesEachRead)
+ {
+ case (1U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize1Bytes;
+ transferConfigTx.minorLoopBytes = 1;
+ if (handle->isByteSwap)
+ {
+ addrOffset = 3;
+ }
+ break;
+
+ case (2U):
+ transferConfigTx.destTransferSize = kEDMA_TransferSize2Bytes;
+ transferConfigTx.minorLoopBytes = 2;
+
+ if (handle->isByteSwap)
+ {
+ addrOffset = 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 + addrOffset;
+ 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);
+ mask |= (uint32_t)kLPSPI_TxDmaEnable;
+ }
+
+ LPSPI_EnableDMA(base, mask);
+
+ return kStatus_Success;
+}
+
+static void EDMA_LpspiSlaveCallback(edma_handle_t *edmaHandle,
+ void *g_lpspiEdmaPrivateHandle,
+ bool transferDone,
+ uint32_t tcds)
+{
+ assert(edmaHandle != NULL);
+ assert(g_lpspiEdmaPrivateHandle != NULL);
+
+ 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 != NULL);
+
+ 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 != 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;
+
+ 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/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.h
new file mode 100644
index 0000000000..02ce26103f
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_edma.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_LPSPI_EDMA_H_
+#define _FSL_LPSPI_EDMA_H_
+
+#include "fsl_lpspi.h"
+#include "fsl_edma.h"
+
+/*!
+ * @addtogroup lpspi_edma_driver
+ * @{
+ */
+
+/***********************************************************************************************************************
+ * Definitions
+ **********************************************************************************************************************/
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPSPI EDMA driver version. */
+#define FSL_LPSPI_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 3, 1))
+/*@}*/
+
+/*!
+ * @brief Forward declaration of the _lpspi_master_edma_handle typedefs.
+ */
+typedef struct _lpspi_master_edma_handle lpspi_master_edma_handle_t;
+
+/*!
+ * @brief Forward declaration of the _lpspi_slave_edma_handle typedefs.
+ */
+typedef struct _lpspi_slave_edma_handle lpspi_slave_edma_handle_t;
+
+/*!
+ * @brief Completion callback function pointer type.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle Pointer to the handle for the LPSPI master.
+ * @param status Success or error code describing whether the transfer completed.
+ * @param userData Arbitrary pointer-dataSized value passed from the application.
+ */
+typedef void (*lpspi_master_edma_transfer_callback_t)(LPSPI_Type *base,
+ lpspi_master_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+/*!
+ * @brief Completion callback function pointer type.
+ *
+ * @param base LPSPI peripheral base address.
+ * @param handle Pointer to the handle for the LPSPI slave.
+ * @param status Success or error code describing whether the transfer completed.
+ * @param userData Arbitrary pointer-dataSized value passed from the application.
+ */
+typedef void (*lpspi_slave_edma_transfer_callback_t)(LPSPI_Type *base,
+ lpspi_slave_edma_handle_t *handle,
+ status_t status,
+ void *userData);
+
+/*! @brief LPSPI master eDMA transfer handle structure used for transactional API. */
+struct _lpspi_master_edma_handle
+{
+ volatile bool isPcsContinuous; /*!< Is PCS continuous in transfer. */
+
+ volatile bool isByteSwap; /*!< A flag that whether should byte swap. */
+
+ volatile uint8_t fifoSize; /*!< FIFO dataSize. */
+
+ volatile uint8_t rxWatermark; /*!< Rx watermark. */
+
+ volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */
+ volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */
+
+ volatile uint8_t bytesLastRead; /*!< Bytes for last read RDR. */
+ volatile bool isThereExtraRxBytes; /*!< Is there extra RX byte. */
+
+ uint8_t *volatile txData; /*!< Send buffer. */
+ uint8_t *volatile rxData; /*!< Receive buffer. */
+ volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/
+ volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/
+
+ volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */
+ volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */
+
+ uint32_t totalByteCount; /*!< Number of transfer bytes*/
+
+ uint32_t txBuffIfNull; /*!< Used if there is not txData for DMA purpose.*/
+ uint32_t rxBuffIfNull; /*!< Used if there is not rxData for DMA purpose.*/
+
+ uint32_t transmitCommand; /*!< Used to write TCR for DMA purpose.*/
+
+ volatile uint8_t state; /*!< LPSPI transfer state , _lpspi_transfer_state.*/
+
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+
+ lpspi_master_edma_transfer_callback_t callback; /*!< Completion callback. */
+ void *userData; /*!< Callback user data. */
+
+ edma_handle_t *edmaRxRegToRxDataHandle; /*!<edma_handle_t handle point used for RxReg to RxData buff*/
+ edma_handle_t *edmaTxDataToTxRegHandle; /*!<edma_handle_t handle point used for TxData to TxReg buff*/
+
+ edma_tcd_t lpspiSoftwareTCD[3]; /*!<SoftwareTCD, internal used*/
+};
+
+/*! @brief LPSPI slave eDMA transfer handle structure used for transactional API.*/
+struct _lpspi_slave_edma_handle
+{
+ volatile bool isByteSwap; /*!< A flag that whether should byte swap. */
+
+ volatile uint8_t fifoSize; /*!< FIFO dataSize. */
+
+ volatile uint8_t rxWatermark; /*!< Rx watermark. */
+
+ volatile uint8_t bytesEachWrite; /*!< Bytes for each write TDR. */
+ volatile uint8_t bytesEachRead; /*!< Bytes for each read RDR. */
+
+ volatile uint8_t bytesLastRead; /*!< Bytes for last read RDR. */
+ volatile bool isThereExtraRxBytes; /*!< Is there extra RX byte. */
+
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+
+ uint8_t *volatile txData; /*!< Send buffer. */
+ uint8_t *volatile rxData; /*!< Receive buffer. */
+ volatile size_t txRemainingByteCount; /*!< Number of bytes remaining to send.*/
+ volatile size_t rxRemainingByteCount; /*!< Number of bytes remaining to receive.*/
+
+ volatile uint32_t writeRegRemainingTimes; /*!< Write TDR register remaining times. */
+ volatile uint32_t readRegRemainingTimes; /*!< Read RDR register remaining times. */
+
+ uint32_t totalByteCount; /*!< Number of transfer bytes*/
+
+ uint32_t txBuffIfNull; /*!< Used if there is not txData for DMA purpose.*/
+ uint32_t rxBuffIfNull; /*!< Used if there is not rxData for DMA purpose.*/
+
+ volatile uint8_t state; /*!< LPSPI transfer state.*/
+
+ uint32_t errorCount; /*!< Error count for slave transfer.*/
+
+ lpspi_slave_edma_transfer_callback_t callback; /*!< Completion callback. */
+ void *userData; /*!< Callback user data. */
+
+ edma_handle_t *edmaRxRegToRxDataHandle; /*!<edma_handle_t handle point used for RxReg to RxData buff*/
+ edma_handle_t *edmaTxDataToTxRegHandle; /*!<edma_handle_t handle point used for TxData to TxReg*/
+
+ edma_tcd_t lpspiSoftwareTCD[2]; /*!<SoftwareTCD, internal used*/
+};
+
+/***********************************************************************************************************************
+ * API
+ **********************************************************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*Transactional APIs*/
+
+/*!
+ * @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 Tx 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 edmaTxDataToTxRegHandle.
+ * (2) For a shared DMA request source, enable and set the Rx/Tx 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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+/*!
+ * @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);
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*! @}*/
+
+#endif /*_FSL_LPSPI_EDMA_H_*/
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_freertos.h b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_freertos.h
new file mode 100644
index 0000000000..ab4c647907
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/lpspi/fsl_lpspi_freertos.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, Freescale Semiconductor, Inc.
+ * Copyright 2016-2022 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef __FSL_LPSPI_FREERTOS_H__
+#define __FSL_LPSPI_FREERTOS_H__
+
+#include "FreeRTOS.h"
+#include "portable.h"
+#include "semphr.h"
+
+#include "fsl_lpspi.h"
+
+/*!
+ * @addtogroup lpspi_freertos_driver LPSPI FreeRTOS Driver
+ * @{
+ */
+
+/**********************************************************************************************************************
+ * Definitions
+ *********************************************************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+/*! @brief LPSPI FreeRTOS driver version 2.3.1. */
+#define FSL_LPSPI_FREERTOS_DRIVER_VERSION (MAKE_VERSION(2, 3, 1))
+/*@}*/
+
+/*!
+ * @cond RTOS_PRIVATE
+ * @brief LPSPI FreeRTOS handle
+ */
+typedef struct _lpspi_rtos_handle
+{
+ LPSPI_Type *base; /*!< LPSPI base address */
+ lpspi_master_handle_t drv_handle; /*!< Handle of the underlying driver, treated as opaque by the RTOS layer */
+ status_t async_status;
+ SemaphoreHandle_t mutex; /*!< Mutex to lock the handle during a trasfer */
+ SemaphoreHandle_t event; /*!< Semaphore to notify and unblock task when transfer ends */
+} lpspi_rtos_handle_t;
+/*! \endcond */
+
+/**********************************************************************************************************************
+ * API
+ *********************************************************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name LPSPI RTOS Operation
+ * @{
+ */
+
+/*!
+ * @brief Initializes LPSPI.
+ *
+ * This function initializes the LPSPI module and related RTOS context.
+ *
+ * @param handle The RTOS LPSPI handle, the pointer to an allocated space for RTOS context.
+ * @param base The pointer base address of the LPSPI instance to initialize.
+ * @param masterConfig Configuration structure to set-up LPSPI in master mode.
+ * @param srcClock_Hz Frequency of input clock of the LPSPI module.
+ * @return status of the operation.
+ */
+status_t LPSPI_RTOS_Init(lpspi_rtos_handle_t *handle,
+ LPSPI_Type *base,
+ const lpspi_master_config_t *masterConfig,
+ uint32_t srcClock_Hz);
+
+/*!
+ * @brief Deinitializes the LPSPI.
+ *
+ * This function deinitializes the LPSPI module and related RTOS context.
+ *
+ * @param handle The RTOS LPSPI handle.
+ */
+status_t LPSPI_RTOS_Deinit(lpspi_rtos_handle_t *handle);
+
+/*!
+ * @brief Performs SPI transfer.
+ *
+ * This function performs an SPI transfer according to data given in the transfer structure.
+ *
+ * @param handle The RTOS LPSPI handle.
+ * @param transfer Structure specifying the transfer parameters.
+ * @return status of the operation.
+ */
+status_t LPSPI_RTOS_Transfer(lpspi_rtos_handle_t *handle, lpspi_transfer_t *transfer);
+
+/*!
+ * @}
+ */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+
+#endif /* __FSL_LPSPI_FREERTOS_H__ */