PeripheralDriver_Flagchip_F.../Src/fc7xxx_driver_fcspi.c

3230 lines
136 KiB
C

/**
* @file fc7xxx_driver_fcspi.c
* @author Flagchip
* @brief FC7xxx FCSPI driver type definition and API
* @version 0.1.0
* @date 2024-01-14
*
* @copyright Copyright (c) 2023 Flagchip Semiconductors Co., Ltd.
*
*/
/* ********************************************************************************
* Revision History:
*
* Version Date Initials CR# Descriptions
* --------- ---------- ------------ ---------- ---------------
* 0.1.0 2024/01/12 Flagchip071 N/A First version for FC240
******************************************************************************** */
#include "interrupt_manager.h"
#include "fc7xxx_driver_fcspi.h"
#define FCSPI_DRV_STATUS_REG_W1C_U32 ((uint32_t)( FCSPI_STATUS_DMF(1) | \
FCSPI_STATUS_RX_FO(1) | \
FCSPI_STATUS_TX_FU(1) | \
FCSPI_STATUS_TCF(1) | \
FCSPI_STATUS_FEF(1) | \
FCSPI_STATUS_RX_WF(1)))
#define FCSPI_DRV_STATUS_REG_W1C_MASK_U32 ((uint32_t)(FCSPI_STATUS_DMF_MASK | \
FCSPI_STATUS_RX_FO_MASK | \
FCSPI_STATUS_TX_FU_MASK | \
FCSPI_STATUS_TCF_MASK | \
FCSPI_STATUS_FEF_MASK | \
FCSPI_STATUS_RX_WF_MASK))
#define FCSPI_DRV_INT_EN_REG_ALL_U32 ((uint32_t)(FCSPI_INT_EN_DMIE(1) | \
FCSPI_INT_EN_RFOIE(1) | \
FCSPI_INT_EN_TFUIE(1) | \
FCSPI_INT_EN_TCIE(1) | \
FCSPI_INT_EN_FEIE(1) | \
FCSPI_INT_EN_RWIE(1) | \
FCSPI_INT_EN_RX_PEIE(1) | \
FCSPI_INT_EN_TX_PEIE(1) | \
FCSPI_INT_EN_RFIE(1) | \
FCSPI_INT_EN_TFIE(1)))
#define FCSPI_DRV_RX_FIFO_WORD_CNT (8)
#define FCSPI_DRV_TX_FIFO_WORD_CNT (8)
#define FCSPI_CFGR1_PCS23_PCS_MODE_U32 FCSPI_CFG1_PCS_CFG(0) /* PCS[3:2] as PCS feature */
#define FCSPI_CFGR1_PCS23_DATABUS_IN_4BIT_MODE_U32 FCSPI_CFG1_PCS_CFG(1) /* PCS[3:2] as data bus in 4-bit mode */
#define FCSPI_CFGR1_OUTCFG_RETAIN_LAST_WHEN_NEGATE_U32 FCSPI_CFG1_OUT_CFG(0)
#define FCSPI_CFGR1_OUTCFG_TRISTATE_WHEN_NEGATE_U32 FCSPI_CFG1_OUT_CFG(1)
#define FCSPI_CFGR1_PINCFG_SIN_INPUT_SOUT_OUTPUT_U32 FCSPI_CFG1_PIN_CFG(0) /* SIN is used for input data and SOUT for output data */
#define FCSPI_CFGR1_PINCFG_SIN_INPUT_OUTPUT_U32 FCSPI_CFG1_PIN_CFG(1) /* SIN is used for both input and output data */
#define FCSPI_CFGR1_PINCFG_SOUT_INPUT_OUTPUT_U32 FCSPI_CFG1_PIN_CFG(2) /* SOUT is used for both input and output data */
#define FCSPI_CFGR1_PINCFG_SOUT_INPUT_SIN_OUTPUT_U32 FCSPI_CFG1_PIN_CFG(3) /* SOUT is used for input data and SIN for output data */
#define FCSPI_CFGR1_PCS0_ACTIVE_HIGH_U32 FCSPI_CFG1_PCS_POL(1) /* Peripheral Chip Select Polarity - Active High */
#define FCSPI_CFGR1_PCS0_POL_MASK_U32 FCSPI_CFG1_PCS_POL(1)
#define FCSPI_CFGR1_PCS1_ACTIVE_HIGH_U32 FCSPI_CFG1_PCS_POL(2) /* Peripheral Chip Select Polarity - Active High */
#define FCSPI_CFGR1_PCS1_POL_MASK_U32 FCSPI_CFG1_PCS_POL(2)
#define FCSPI_CFGR1_PCS2_ACTIVE_HIGH_U32 FCSPI_CFG1_PCS_POL(4) /* Peripheral Chip Select Polarity - Active High */
#define FCSPI_CFGR1_PCS2_POL_MASK_U32 FCSPI_CFG1_PCS_POL(4)
#define FCSPI_CFGR1_PCS3_ACTIVE_HIGH_U32 FCSPI_CFG1_PCS_POL(8) /* Peripheral Chip Select Polarity - Active High */
#define FCSPI_CFGR1_PCS3_POL_MASK_U32 FCSPI_CFG1_PCS_POL(8)
#define FCSPI_TRCR_SCKPOL_ACTIVE_HIGH_U32 FCSPI_TR_CTRL_SCK_POL(0) /* When inactive, SCK is low */
#define FCSPI_TRCR_SCKPOL_ACTIVE_LOW_U32 FCSPI_TR_CTRL_SCK_POL(1) /* When inactive, SCK is high */
#define FCSPI_TRCR_SCKPHA_CAP_LEADING_U32 FCSPI_TR_CTRL_SCK_PHA(0) /* Data is changed on the leading edge of SCK and captured on the following edge */
#define FCSPI_TRCR_SCKPHA_CAP_TRAILING_U32 FCSPI_TR_CTRL_SCK_PHA(1) /* Data is captured on the leading edge of SCK and changed on the following edge */
#define FCSPI_TRCR_PRESCALE_1_U32 FCSPI_TR_CTRL_PRESCALE(0) /* Divide by 1 */
#define FCSPI_TRCR_PRESCALE_2_U32 FCSPI_TR_CTRL_PRESCALE(1) /* Divide by 2 */
#define FCSPI_TRCR_PRESCALE_4_U32 FCSPI_TR_CTRL_PRESCALE(2) /* Divide by 4 */
#define FCSPI_TRCR_PRESCALE_8_U32 FCSPI_TR_CTRL_PRESCALE(3) /* Divide by 8 */
#define FCSPI_TRCR_PRESCALE_16_U32 FCSPI_TR_CTRL_PRESCALE(4) /* Divide by 16 */
#define FCSPI_TRCR_PRESCALE_32_U32 FCSPI_TR_CTRL_PRESCALE(5) /* Divide by 32 */
#define FCSPI_TRCR_PRESCALE_64_U32 FCSPI_TR_CTRL_PRESCALE(6) /* Divide by 64 */
#define FCSPI_TRCR_PRESCALE_128_U32 FCSPI_TR_CTRL_PRESCALE(7) /* Divide by 128 */
#define FCSPI_TRCR_PCS0_EN_U32 FCSPI_TR_CTRL_PCS(0) /* Transfer using FCSPI_PCS[0] */
#define FCSPI_TRCR_PCS1_EN_U32 FCSPI_TR_CTRL_PCS(1) /* Transfer using FCSPI_PCS[1] */
#define FCSPI_TRCR_PCS2_EN_U32 FCSPI_TR_CTRL_PCS(2) /* Transfer using FCSPI_PCS[2] */
#define FCSPI_TRCR_PCS3_EN_U32 FCSPI_TR_CTRL_PCS(3) /* Transfer using FCSPI_PCS[3] */
#define FCSPI_TRCR_MSB_U32 FCSPI_TR_CTRL_LSBF(0) /* Data is transferred MSB first */
#define FCSPI_TRCR_LSB_U32 FCSPI_TR_CTRL_LSBF(1) /* Data is transferred LSB first */
#define FCSPI_TRCR_BYSW_EN_U32 FCSPI_TR_CTRL_BYSW(1) /* Byte swap enabled */
#define FCSPI_TRCR_BYSW_DIS_U32 FCSPI_TR_CTRL_BYSW(0) /* Byte swap disable */
#define FCSPI_TRCR_CONT_EN_U32 FCSPI_TR_CTRL_CT_EN(1) /* Continuous transfer enabled */
#define FCSPI_TRCR_CONT_DIS_U32 FCSPI_TR_CTRL_CT_EN(0) /* Continuous transfer disabled */
#define FCSPI_TRCR_CONTC_EN_U32 FCSPI_TR_CTRL_CT_GO(1) /* Command word for continuing transfer */
#define FCSPI_TRCR_WIDTH_1_U32 FCSPI_TR_CTRL_WIDTH(0) /* Single bit transfer */
#define FCSPI_TRCR_WIDTH_2_U32 FCSPI_TR_CTRL_WIDTH(1) /* Two bita transfer */
#define FCSPI_TRCR_WIDTH_4_U32 FCSPI_TR_CTRL_WIDTH(2) /* Four bits transfer */
#define ITCM_START_ADDRESS 0x0u
#define ITCM_END_ADDRESS 0xFFFFu
#define DTCM_START_ADDRESS 0x20000000u
#define DTCM_END_ADDRESS 0x2001FFFFu
#define ITCM_TO_BACKDOOR_OFFSET 0x24000000u
#define DTCM_TO_BACKDOOR_OFFSET 0x02000000u
typedef enum {
SIN_INPUT_SOUT_OUTPUT = 0,
SIN_INPUT_OUTPUT = 1,
SOUT_INPUT_OUTPUT = 2,
SOUT_INPUT_SIN_OUTPUT = 3
} FCSPI_PinModeType;
typedef enum {
FCSPI_PRESCALE_1 = 0,
FCSPI_PRESCALE_2 = 1,
FCSPI_PRESCALE_4 = 2,
FCSPI_PRESCALE_8 = 3,
FCSPI_PRESCALE_16 = 4,
FCSPI_PRESCALE_32 = 5,
FCSPI_PRESCALE_64 = 6,
FCSPI_PRESCALE_128 = 7,
FCSPI_PRESCALE_MAX = 8
} FCSPI_PrescaleValueType;
typedef enum {
FCSPI_TRANSFER_1_BIT = 0, /* 1-bit shift at a time, data out on SDO, in on SDI (normal mode) */
FCSPI_TRANSFER_2_BIT = 1, /* 2-bits shift out on SDO/SDI and in on SDO/SDI */
FCSPI_TRANSFER_4_BIT = 2 /* 4-bits shift out on SDO/SDI/PCS[3:2] and in on SDO/SDI/PCS[3:2] */
} FCSPI_TransferWidthType;
typedef enum {
PINOUT_RETAIN_LAST = 0,
PINOUT_TRISTATE = 1
} FCSPI_NegatedPinOutStatType;
typedef enum {
PCS2_3_PCS = 0,
PCS2_3_DATA_BUS_IN_4BIT_MODE = 1
} FCSPI_PCS2_3ModeType;
typedef struct {
FCSPI_SckPolarityType eSckPolarity;
FCSPI_SckSamplePhaseType eSckPhase;
FCSPI_PrescaleValueType ePrescalerValue;
FCSPI_PCSType ePCSSelect;
FCSPI_BitFirstOrderType eBitFirstOrder;
FCSPI_AtomicBoolType eByteSwap;
FCSPI_AtomicBoolType eContTransEnable;
FCSPI_AtomicBoolType eContCmdEnable;
FCSPI_AtomicBoolType eRxDisable;
FCSPI_AtomicBoolType eTxDisable;
FCSPI_TransferWidthType eTransferWidth;
uint16_t u16FrameBitCnt;
} FCSPI_TxRxCtrlType;
typedef enum {
FCSPI_TRANSFER_OK = 0U, /* Transfer OK */
FCSPI_TRANSFER_TX_FAIL, /* Error during transmission */
FCSPI_TRANSFER_RX_FAIL, /* Error during reception */
FCSPI_TRANSFER_ABORT, /* Transfer is aborted */
} FCSPI_TransferStatusType;
typedef struct {
uint16_t u16BitsPerFrame; /* count of bits per frame: 8-4096bits */
uint16_t u16BytesCntFrameNeed; /* count of bytes per frame: 1-512bytes for external buffer passed into driver */
FCSPI_BitFirstOrderType eBitFirstOrder; /* MSB/LSB first to send/receive */
uint8_t u8TxFifoSize; /* Tx fifo size */
uint8_t u8RxFifoSize; /* Rx fifo size */
FCSPI_TriggerDmaInfType tTriggerDmaInf;
FCSPI_TriggerSrcType eTransferTriggerSrc; /* Type of transfer */
FCSPI_StopCbType pStopNotifyCb; /* callback to transfer stop, transfer successfully or aborted */
FCSPI_SemaphoreResetCbType pSemaResetCb; /* synchronous send need, reset the semaphore */
FCSPI_SemaphoreTakeCbType pSemaTakeCb; /* synchronous send need, acquire the semaphore */
FCSPI_SemaphorePostCbType pSemaPostCb; /* synchronous send need, release the semaphore outside of the interrupt */
uint32_t u32DmaDummyData; /* DMA mode, TX is NULL, just send this data, RX is NULL, just store in this var */
FCSPI_SckSamplePhaseType eSckSamplePhase; /* select which edge of active sck clock to capture data */
FCSPI_SckPolarityType eSckPolarity; /* select output sclk clock polarity */
FCSPI_PCSType ePcs; /* chip select pin */
FCSPI_PcsPolarityType ePcsPolarity; /* chip select pin polarity */
/* only master mode use, slave not */
FCSPI_AtomicBoolType eIsPcsContinuous; /* Option to keep chip select asserted until transfer complete; needed for TCR programming */
uint32_t u32FCSpiSrcClk; /* Module source clock */
uint32_t u32Baundrate; /* the bit per second of current transmission */
/* dynamic state */
volatile uint8_t u8WaitSemaphore;
const uint8_t *pbyTxBuff; /* The buffer from which transmitted bytes are taken */
uint8_t *pbyRxBuff; /* The buffer into which received bytes are placed */
volatile uint16_t u16TxIndex;
volatile uint16_t u16RxIndex;
volatile uint16_t u16TxByteCntRemainToSend; /* Number of bytes remaining to send */
volatile uint16_t u16RxByteCntRemainToGet; /* Number of bytes remaining to receive */
volatile uint16_t u16TxSendByteCntOfCurFrame; /* Number of bytes from current frame which were already sent */
volatile uint16_t u16RxGetByteCntOfCurFrame; /* Number of bytes from current frame which were already received */
volatile FCSPI_TransferStatusType eTransferStat; /* The status of the current */
volatile FCSPI_AtomicBoolType eIsInTransfer; /* True if there is an active transfer */
} FCSPI_DrvStateType;
typedef struct
{
FCSPI_MemMapPtr tFCSpiInstance;
FCSPI_DrvStateType tFCSpiStat;
IRQn_Type eFCSpiIrq;
} FCSPI_DriverInfoType;
static FCSPI_DriverInfoType s_atFCSpiInfo[FCSPI_INSTANCE_COUNT] = {
{FCSPI0, {0} ,FCSPI0_IRQn},
{FCSPI1, {0} ,FCSPI1_IRQn},
{FCSPI2, {0} ,FCSPI2_IRQn},
{FCSPI3, {0} ,FCSPI3_IRQn},
{FCSPI4, {0} ,FCSPI4_IRQn},
{FCSPI5, {0} ,FCSPI5_IRQn}
};
/* soft reset just reset the logic and registers except CTRL */
static void FCSpi_Hw_Reset(FCSPI_InstanceType eInst,
FCSPI_AtomicBoolType eRxFifo,
FCSPI_AtomicBoolType eTxFifo,
FCSPI_AtomicBoolType eSoftRst);
static FCSPI_StatusType FCSpi_Hw_Disable(FCSPI_InstanceType eInst);
/* get status value and check using macro */
#define FCSpi_Hw_ChkBusy(status) (((status) & FCSPI_STATUS_BF_MASK) != 0U)
#define FCSpi_Hw_ChkDataMatch(status) (((status) & FCSPI_STATUS_DMF_MASK) != 0U)
#define FCSpi_Hw_ChkRxFifoOverflow(status) (((status) & FCSPI_STATUS_RX_FO_MASK) != 0U)
#define FCSpi_Hw_ChkTxFifoUnderrun(status) (((status) & FCSPI_STATUS_TX_FU_MASK) != 0U)
#define FCSpi_Hw_ChkTransferComplete(status) (((status) & FCSPI_STATUS_TCF_MASK) != 0U)
#define FCSpi_Hw_ChkFrameEndDetected(status) (((status) & FCSPI_STATUS_FEF_MASK) != 0U)
#define FCSpi_Hw_ChkReceiveWordComplete(status) (((status) & FCSPI_STATUS_RX_WF_MASK) != 0U)
#define FCSpi_Hw_ChkRxGreaterThanWater(status) (((status) & FCSPI_STATUS_RX_FF_MASK) != 0U)
#define FCSpi_Hw_ChkTxEqualOrLessThanWater(status) (((status) & FCSPI_STATUS_TX_FF_MASK) != 0U)
static void FCSpi_Hw_ClearSomeStatusW1CFlag(FCSPI_InstanceType eInst, uint32_t u32FlagBitSet); /* refer to FCSPI_DRV_STATUS_REG_W1C_U32 */
static void FCSpi_Hw_EnableMoreInterrupts(FCSPI_InstanceType eInst, uint32_t u32Interrupts); /* refer to FCSPI_INT_EN_DMIE(1) */
static void FCSpi_Hw_DisableSomeInterrupts(FCSPI_InstanceType eInst, uint32_t u32Interrupts); /* refer to FCSPI_INT_EN_DMIE(1) */
#define FCSpi_Hw_EnableTransmitDataInterrupt(eInst) FCSpi_Hw_EnableMoreInterrupts((eInst), FCSPI_INT_EN_TFIE_MASK)
#define FCSpi_Hw_DisableTransmitDataInterrupt(eInst) FCSpi_Hw_DisableSomeInterrupts((eInst), FCSPI_INT_EN_TFIE_MASK)
#define FCSpi_Hw_EnableReceiveDataInterrupt(eInst) FCSpi_Hw_EnableMoreInterrupts((eInst), FCSPI_INT_EN_RFIE_MASK)
#define FCSpi_Hw_DisableReceiveDataInterrupt(eInst) FCSpi_Hw_DisableSomeInterrupts((eInst), FCSPI_INT_EN_RFIE_MASK)
#define FCSpi_Hw_EnableTransmitCompleteInterrupt(eInst) FCSpi_Hw_EnableMoreInterrupts((eInst), FCSPI_INT_EN_TCIE_MASK)
#define FCSpi_Hw_DisableTransmitCompleteInterrupt(eInst) FCSpi_Hw_DisableSomeInterrupts((eInst), FCSPI_INT_EN_TCIE_MASK)
static void FCSpi_Hw_SetPcs_2_3_Mode(FCSPI_InstanceType eInst, FCSPI_PCS2_3ModeType eMode);
static void FCSpi_Hw_SetPin(FCSPI_InstanceType eInst, FCSPI_PinModeType eMode, FCSPI_NegatedPinOutStatType eStat);
static void FCSpi_Hw_SetOnePcsPolarity(FCSPI_InstanceType eInst,
FCSPI_PCSType ePcs, FCSPI_PcsPolarityType ePolarity);
static void FCSpi_Hw_Master_SetSckLoopbackSample(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType eEnable);
#define FCSpi_Hw_PrescalerRegToActualVal(eVal) (((uint32_t)1) << ((uint8_t)(eVal)))
static void FCSpi_Hw_SetContinuousCommand(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType eEnable);
static void FCSpi_Hw_SelectUsePcs(FCSPI_InstanceType eInst, FCSPI_PCSType ePCS);
static uint32_t FCSpi_Hw_Master_CalcBaudRate(const FCSPI_MasterCfgType *pCfg, uint32_t *pdwPrescaleRegVal, uint32_t *pdwActualSckDiv);
static FCSPI_StatusType FCSpi_Hw_SetTRCR(FCSPI_InstanceType eInst, FCSPI_TxRxCtrlType *ptCtrl);
static FCSPI_PrescaleValueType FCSpi_Hw_GetRegPrescalerVal(FCSPI_InstanceType eInst);
static void FCSpi_Hw_Get_SCK_PCS_DIV_Hold(FCSPI_InstanceType eInst, uint8_t *pbySCKPCS, uint8_t *pbyPCSSCK, uint8_t *pbyPCSPCS, uint8_t *pbySCKDIV);
static void FCSpi_Hw_Set_SCK_PCS_DIV_Hold(FCSPI_InstanceType eInst, uint8_t u8SCKPCS, uint8_t u8PCSSCK, uint8_t u8PCSPCS, uint8_t u8SCKDIV);
static void FCSpi_Hw_Set_SCK_PCS_Hold(FCSPI_InstanceType eInst, uint8_t u8SCKPCS, uint8_t u8PCSSCK, uint8_t u8PCSPCS);
static void FCSpi_Hw_SetRxTxDmaEnableStatus(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType eRxEnable, FCSPI_AtomicBoolType eTxEnable);
static void fcspi_read_rx_fifo(FCSPI_InstanceType eInst);
static void fcspi_write_tx_fifo(FCSPI_InstanceType eInst);
static void fcspi_master_clean_transfer(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInInterrupt);
static void fcspi_master_abort_transfer(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInISR);
static void fcspi_master_dma_rx_err_interrupt(FCSPI_InstanceType eInst);
static void fcspi_0_master_dma_rx_err_interrupt(void);
static void fcspi_1_master_dma_rx_err_interrupt(void);
static void fcspi_2_master_dma_rx_err_interrupt(void);
static void fcspi_3_master_dma_rx_err_interrupt(void);
static void fcspi_4_master_dma_rx_err_interrupt(void);
static void fcspi_5_master_dma_rx_err_interrupt(void);
static void fcspi_master_dma_rx_finish_interrupt(void);
static void fcspi_master_dma_tx_err_interrupt(FCSPI_InstanceType eInst);
static void fcspi_0_master_dma_tx_err_interrupt(void);
static void fcspi_1_master_dma_tx_err_interrupt(void);
static void fcspi_2_master_dma_tx_err_interrupt(void);
static void fcspi_3_master_dma_tx_err_interrupt(void);
static void fcspi_4_master_dma_tx_err_interrupt(void);
static void fcspi_5_master_dma_tx_err_interrupt(void);
static void fcspi_master_dma_tx_finish_interrupt(FCSPI_InstanceType eInst);
static void fcspi_0_master_dma_tx_finish_interrupt(void);
static void fcspi_1_master_dma_tx_finish_interrupt(void);
static void fcspi_2_master_dma_tx_finish_interrupt(void);
static void fcspi_3_master_dma_tx_finish_interrupt(void);
static void fcspi_4_master_dma_tx_finish_interrupt(void);
static void fcspi_5_master_dma_tx_finish_interrupt(void);
static FCSPI_StatusType fcspi_master_async_transfer_bytes(FCSPI_InstanceType eInst,
const uint8_t *pSendBuffer, uint8_t *pReceiveBuffer,
uint16_t u16TransferByteCnt);
static FCSPI_StatusType fcspi_master_trigger(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInIsr);
static void fcspi_slave_clean_transfer(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInInterrupt);
static void fcspi_slave_abort_transfer(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInInterrupt);
static void fcspi_slave_dma_rx_err_interrupt(FCSPI_InstanceType eInst);
static void fcspi_0_slave_dma_rx_err_interrupt(void);
static void fcspi_1_slave_dma_rx_err_interrupt(void);
static void fcspi_2_slave_dma_rx_err_interrupt(void);
static void fcspi_3_slave_dma_rx_err_interrupt(void);
static void fcspi_4_slave_dma_rx_err_interrupt(void);
static void fcspi_5_slave_dma_rx_err_interrupt(void);
static void fcspi_slave_dma_rx_finish_interrupt(FCSPI_InstanceType eInst);
static void fcspi_0_slave_dma_rx_finish_interrupt(void);
static void fcspi_1_slave_dma_rx_finish_interrupt(void);
static void fcspi_2_slave_dma_rx_finish_interrupt(void);
static void fcspi_3_slave_dma_rx_finish_interrupt(void);
static void fcspi_4_slave_dma_rx_finish_interrupt(void);
static void fcspi_5_slave_dma_rx_finish_interrupt(void);
static void fcspi_slave_dma_tx_err_interrupt(FCSPI_InstanceType eInst);
static void fcspi_0_slave_dma_tx_err_interrupt(void);
static void fcspi_1_slave_dma_tx_err_interrupt(void);
static void fcspi_2_slave_dma_tx_err_interrupt(void);
static void fcspi_3_slave_dma_tx_err_interrupt(void);
static void fcspi_4_slave_dma_tx_err_interrupt(void);
static void fcspi_5_slave_dma_tx_err_interrupt(void);
static void fcspi_slave_dma_tx_finish_interrupt(FCSPI_InstanceType eInst);
static void fcspi_0_slave_dma_tx_finish_interrupt(void);
static void fcspi_1_slave_dma_tx_finish_interrupt(void);
static void fcspi_2_slave_dma_tx_finish_interrupt(void);
static void fcspi_3_slave_dma_tx_finish_interrupt(void);
static void fcspi_4_slave_dma_tx_finish_interrupt(void);
static void fcspi_5_slave_dma_tx_finish_interrupt(void);
static FCSPI_StatusType fcspi_slave_async_transfer_bytes(FCSPI_InstanceType eInst,
const uint8_t *pSendBuffer, uint8_t *pReceiveBuffer, uint16_t u16TransferByteCnt);
static FCSPI_StatusType fcspi_slave_trigger(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInISR);
static void fcspi_irq_handler(FCSPI_InstanceType eInst);
static void FCSpi_Hw_Reset(FCSPI_InstanceType eInst,
FCSPI_AtomicBoolType eRxFifo, FCSPI_AtomicBoolType eTxFifo, FCSPI_AtomicBoolType eSoftRst)
{
uint32_t u32Flag = 0U;
uint32_t u32OldFlag = FCSPI_HWA_GetCtrlValue(s_atFCSpiInfo[eInst].tFCSpiInstance);
uint32_t u32Mask = FCSPI_CTRL_MASK;
if (eRxFifo)
{
u32Flag |= FCSPI_CTRL_RST_RF(1);
}
if (eTxFifo)
{
u32Flag |= FCSPI_CTRL_RST_TF(1);
}
if (FCSPI_TRUE == eSoftRst)
{
u32Flag |= FCSPI_CTRL_SW_RST(1);
}
u32Flag |= u32OldFlag;
FCSPI_HWA_SetCtrlValue(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
/* no need delay */
if (FCSPI_TRUE == eSoftRst)
{
FCSPI_HWA_SetCtrlValue(s_atFCSpiInfo[eInst].tFCSpiInstance, 0U);
}
else
{
FCSPI_HWA_SetCtrlValue(s_atFCSpiInfo[eInst].tFCSpiInstance, (u32OldFlag & u32Mask));
}
}
#ifdef FCSPI_DRV_INTERNAL_FUNC_EN
static FCSPI_AtomicBoolType FCSpi_Hw_ChkEnabled(FCSPI_InstanceType eInst)
{
return (FCSPI_AtomicBoolType)((FCSPI_HWA_GetCtrlValue(s_atFCSpiInfo[eInst].tFCSpiInstance) &
FCSPI_CTRL_M_EN_MASK) >> FCSPI_CTRL_M_EN_SHIFT);
}
#endif
static FCSPI_StatusType FCSpi_Hw_Disable(FCSPI_InstanceType eInst)
{
FCSPI_StatusType eStatus = FCSPI_STATUS_SUCCESS;
if (0U != (FCSPI_HWA_GetStatus(s_atFCSpiInfo[eInst].tFCSpiInstance) & FCSPI_STATUS_BF_MASK))
{
eStatus = FCSPI_STATUS_BUSY;
}
else
{
FCSPI_HWA_ModuleDisable(s_atFCSpiInfo[eInst].tFCSpiInstance);
}
return eStatus;
}
static void FCSpi_Hw_ClearSomeStatusW1CFlag(
FCSPI_InstanceType eInst, uint32_t u32FlagBitSet) /* refer to FCSPI_DRV_STATUS_REG_W1C_U32 */
{
FCSPI_HWA_ClearStatus(s_atFCSpiInfo[eInst].tFCSpiInstance, (u32FlagBitSet & FCSPI_DRV_STATUS_REG_W1C_MASK_U32));
}
#ifdef FCSPI_DRV_INTERNAL_FUNC_EN
static void FCSpi_Hw_SetAllInterruptEnableStatus(
FCSPI_InstanceType eInst, uint32_t u32Interrupts) /* refer to FCSPI_DRV_INT_EN_REG_ALL_U32 */
{
FCSPI_HWA_SetInterruptEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance, (u32Interrupts & FCSPI_INT_EN_MASK));
}
static uint32_t FCSpi_Hw_GetAllInterruptEnableStatus(FCSPI_InstanceType eInst)
{
return FCSPI_HWA_GetIntrruptEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance);
}
#endif
static void FCSpi_Hw_EnableMoreInterrupts(FCSPI_InstanceType eInst, uint32_t u32Interrupts)
{
uint32_t u32RegVal = FCSPI_HWA_GetIntrruptEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance);
u32RegVal |= (u32Interrupts & FCSPI_INT_EN_MASK);
FCSPI_HWA_SetInterruptEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32RegVal);
}
static void FCSpi_Hw_DisableSomeInterrupts(FCSPI_InstanceType eInst, uint32_t u32Interrupts)
{
uint32_t u32RegVal = FCSPI_HWA_GetIntrruptEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance);
u32RegVal &= (~(u32Interrupts & FCSPI_INT_EN_MASK));
FCSPI_HWA_SetInterruptEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32RegVal);
}
static void FCSpi_Hw_SetRxTxDmaEnableStatus(
FCSPI_InstanceType eInst, FCSPI_AtomicBoolType eRxEnable, FCSPI_AtomicBoolType eTxEnable)
{
uint32_t u32Flag = 0U;
if (eRxEnable)
{
u32Flag |= FCSPI_DMA_EN_RFDE(1);
}
if (eTxEnable)
{
u32Flag |= FCSPI_DMA_EN_TFDE(1);
}
FCSPI_HWA_SetDMAEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
#ifdef FCSPI_DRV_INTERNAL_FUNC_EN
static void FCSpi_Hw_SetRxDmaEnableStatus(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType eEnable)
{
uint32_t u32RegVal = FCSPI_HWA_GetDMAEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (eEnable)
{
u32RegVal |= FCSPI_DMA_EN_RFDE(1);
}
else
{
u32RegVal &= (~(FCSPI_DMA_EN_RFDE_MASK));
}
FCSPI_HWA_SetDMAEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32RegVal);
}
static void FCSpi_Hw_SetTxDmaEnableStatus(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType eEnable)
{
uint32_t u32RegVal = FCSPI_HWA_GetDMAEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (FCSPI_TRUE == eEnable)
{
u32RegVal |= FCSPI_DMA_EN_TFDE(1);
}
else
{
u32RegVal &= (~(FCSPI_DMA_EN_TFDE_MASK));
}
FCSPI_HWA_SetDMAEnableReg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32RegVal);
}
#endif
static void FCSpi_Hw_SetPcs_2_3_Mode(FCSPI_InstanceType eInst, FCSPI_PCS2_3ModeType eMode)
{
uint32_t u32RegVal = FCSPI_HWA_GetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (PCS2_3_PCS == eMode)
{
u32RegVal &= (~(FCSPI_CFG1_PCS_CFG_MASK));
}
else
{
u32RegVal |= (FCSPI_CFGR1_PCS23_DATABUS_IN_4BIT_MODE_U32);
}
FCSPI_HWA_SetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32RegVal);
}
static void FCSpi_Hw_SetPin(FCSPI_InstanceType eInst,
FCSPI_PinModeType eMode, FCSPI_NegatedPinOutStatType eStat)
{
uint32_t u32Flag = FCSPI_HWA_GetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance);
u32Flag &= (~(FCSPI_CFG1_PIN_CFG_MASK));
u32Flag &= (~(FCSPI_CFG1_OUT_CFG_MASK));
switch (eMode)
{
case SIN_INPUT_OUTPUT:
u32Flag |= FCSPI_CFGR1_PINCFG_SIN_INPUT_OUTPUT_U32;
break;
case SOUT_INPUT_OUTPUT:
u32Flag |= FCSPI_CFGR1_PINCFG_SOUT_INPUT_OUTPUT_U32;
break;
case SOUT_INPUT_SIN_OUTPUT:
u32Flag |= FCSPI_CFGR1_PINCFG_SOUT_INPUT_SIN_OUTPUT_U32;
break;
case SIN_INPUT_SOUT_OUTPUT:
u32Flag |= FCSPI_CFGR1_PINCFG_SIN_INPUT_SOUT_OUTPUT_U32;
break;
default:
u32Flag |= FCSPI_CFGR1_PINCFG_SIN_INPUT_SOUT_OUTPUT_U32;
break;
}
if (PINOUT_RETAIN_LAST == eStat)
{
u32Flag |= FCSPI_CFGR1_OUTCFG_RETAIN_LAST_WHEN_NEGATE_U32;
}
else
{
u32Flag |= FCSPI_CFGR1_OUTCFG_TRISTATE_WHEN_NEGATE_U32;
}
FCSPI_HWA_SetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
#ifdef FCSPI_DRV_INTERNAL_FUNC_EN
static void FCSpi_Hw_SetPcsPolarity(FCSPI_InstanceType eInst,
FCSPI_AtomicBoolType eSetPCS0, FCSPI_PcsPolarityType ePCS0Polarity,
FCSPI_AtomicBoolType eSetPCS1, FCSPI_PcsPolarityType ePCS1Polarity,
FCSPI_AtomicBoolType eSetPCS2, FCSPI_PcsPolarityType ePCS2Polarity,
FCSPI_AtomicBoolType eSetPCS3, FCSPI_PcsPolarityType ePCS3Polarity)
{
uint32_t u32Flag = FCSPI_HWA_GetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (eSetPCS0)
{
if (FCSPI_PCS_POL_ACTIVE_HIGH == ePCS0Polarity)
u32Flag |= FCSPI_CFGR1_PCS0_ACTIVE_HIGH_U32;
else
u32Flag &= (~(FCSPI_CFGR1_PCS0_POL_MASK_U32));
}
if (eSetPCS1)
{
if (FCSPI_PCS_POL_ACTIVE_HIGH == ePCS1Polarity)
u32Flag |= FCSPI_CFGR1_PCS1_ACTIVE_HIGH_U32;
else
u32Flag &= (~(FCSPI_CFGR1_PCS1_POL_MASK_U32));
}
if (eSetPCS2)
{
if (FCSPI_PCS_POL_ACTIVE_HIGH == ePCS2Polarity)
u32Flag |= FCSPI_CFGR1_PCS2_ACTIVE_HIGH_U32;
else
u32Flag &= (~(FCSPI_CFGR1_PCS2_POL_MASK_U32));
}
if (eSetPCS3)
{
if (FCSPI_PCS_POL_ACTIVE_HIGH == ePCS3Polarity)
u32Flag |= FCSPI_CFGR1_PCS3_ACTIVE_HIGH_U32;
else
u32Flag &= (~(FCSPI_CFGR1_PCS3_POL_MASK_U32));
}
FCSPI_HWA_SetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
#endif
static void FCSpi_Hw_SetOnePcsPolarity(FCSPI_InstanceType eInst,
FCSPI_PCSType ePcs, FCSPI_PcsPolarityType ePolarity)
{
uint32_t u32Flag = FCSPI_HWA_GetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (FCSPI_PCS_POL_ACTIVE_HIGH == ePolarity)
{
if (0U == ((((uint32_t)0x1) << (FCSPI_CFG1_PCS_POL_SHIFT + (uint32_t)ePcs)) & u32Flag))
{
u32Flag |= (((uint32_t)0x1) << (FCSPI_CFG1_PCS_POL_SHIFT + (uint32_t)ePcs));
}
}
else /* active low */
{
if (0U != ((((uint32_t)0x1) << (FCSPI_CFG1_PCS_POL_SHIFT + (uint32_t)ePcs)) & u32Flag))
{
u32Flag &= (~(((uint32_t)0x1) << (FCSPI_CFG1_PCS_POL_SHIFT + (uint32_t)ePcs)));
}
}
FCSPI_HWA_SetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
/* before call this function, ensure in master mode */
static void FCSpi_Hw_Master_SetSckLoopbackSample(
FCSPI_InstanceType eInst, FCSPI_AtomicBoolType eEnable)
{
uint32_t u32Flag = FCSPI_HWA_GetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (FCSPI_TRUE == eEnable)
{
if (FCSPI_CFG1_SCK_LB(1) != (u32Flag & FCSPI_CFG1_SCK_LB_MASK))
{
u32Flag |= FCSPI_CFG1_SCK_LB(1);
}
}
else
{
if (FCSPI_CFG1_SCK_LB(0) != (u32Flag & FCSPI_CFG1_SCK_LB_MASK))
{
u32Flag &= (~(FCSPI_CFG1_SCK_LB_MASK));
}
}
FCSPI_HWA_SetCFG1Reg(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
static void FCSpi_Hw_Set_SCK_PCS_DIV_Hold(FCSPI_InstanceType eInst,
uint8_t u8SCKPCS, uint8_t u8PCSSCK, uint8_t u8PCSPCS, uint8_t u8SCKDIV)
{
uint32_t u32Flag = FCSPI_HWA_GetClockConfig(s_atFCSpiInfo[eInst].tFCSpiInstance);
uint32_t u32Val;
{
u32Val = u8SCKPCS;
u32Flag &= (~(FCSPI_CLK_CFG_SCKPCS_MASK));
u32Flag |= (u32Val << FCSPI_CLK_CFG_SCKPCS_SHIFT);
}
{
u32Val = u8PCSSCK;
u32Flag &= (~(FCSPI_CLK_CFG_PCSSCK_MASK));
u32Flag |= (u32Val << FCSPI_CLK_CFG_PCSSCK_SHIFT);
}
{
u32Val = u8PCSPCS;
u32Flag &= (~(FCSPI_CLK_CFG_PCSPCS_MASK));
u32Flag |= (u32Val << FCSPI_CLK_CFG_PCSPCS_SHIFT);
}
{
u32Val = u8SCKDIV;
u32Flag &= (~(FCSPI_CLK_CFG_SCKDIV_MASK));
u32Flag |= (u32Val << FCSPI_CLK_CFG_SCKDIV_SHIFT);
}
{
FCSPI_HWA_SetClockConfig(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
}
static void FCSpi_Hw_Set_SCK_PCS_Hold(FCSPI_InstanceType eInst,
uint8_t u8SCKPCS, uint8_t u8PCSSCK, uint8_t u8PCSPCS)
{
uint32_t u32Flag = FCSPI_HWA_GetClockConfig(s_atFCSpiInfo[eInst].tFCSpiInstance);
uint32_t u32Val;
{
u32Val = u8SCKPCS;
u32Flag &= (~(FCSPI_CLK_CFG_SCKPCS_MASK));
u32Flag |= (u32Val << FCSPI_CLK_CFG_SCKPCS_SHIFT);
}
{
u32Val = u8PCSSCK;
u32Flag &= (~(FCSPI_CLK_CFG_PCSSCK_MASK));
u32Flag |= (u32Val << FCSPI_CLK_CFG_PCSSCK_SHIFT);
}
{
u32Val = u8PCSPCS;
u32Flag &= (~(FCSPI_CLK_CFG_PCSPCS_MASK));
u32Flag |= (u32Val << FCSPI_CLK_CFG_PCSPCS_SHIFT);
}
{
FCSPI_HWA_SetClockConfig(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
}
static void FCSpi_Hw_Get_SCK_PCS_DIV_Hold(FCSPI_InstanceType eInst,
uint8_t *pbySCKPCS,
uint8_t *pbyPCSSCK,
uint8_t *pbyPCSPCS,
uint8_t *pbySCKDIV)
{
uint32_t u32Flag = FCSPI_HWA_GetClockConfig(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (pbySCKPCS != NULL)
{
*pbySCKPCS = (uint8_t)((u32Flag & FCSPI_CLK_CFG_SCKPCS_MASK) >> FCSPI_CLK_CFG_SCKPCS_SHIFT);
}
if (pbyPCSSCK != NULL)
{
*pbyPCSSCK = (uint8_t)((u32Flag & FCSPI_CLK_CFG_PCSSCK_MASK) >> FCSPI_CLK_CFG_PCSSCK_SHIFT);
}
if (pbyPCSPCS != NULL)
{
*pbyPCSPCS = (uint8_t)((u32Flag & FCSPI_CLK_CFG_PCSPCS_MASK) >> FCSPI_CLK_CFG_PCSPCS_SHIFT);
}
if (pbySCKDIV != NULL)
{
*pbySCKDIV = ((uint8_t)(u32Flag & FCSPI_CLK_CFG_SCKDIV_MASK) >> FCSPI_CLK_CFG_SCKDIV_SHIFT);
}
}
#ifdef FCSPI_DRV_INTERNAL_FUNC_EN
static void FCSpi_Hw_GetTRCR(FCSPI_InstanceType eInst, FCSPI_TxRxCtrlType *ptCtrl)
{
uint32_t u32Flag = FCSPI_HWA_GetTxRxControl(s_atFCSpiInfo[eInst].tFCSpiInstance);
ptCtrl->eSckPolarity = (FCSPI_SckPolarityType)
((u32Flag & FCSPI_TR_CTRL_SCK_POL_MASK) >> FCSPI_TR_CTRL_SCK_POL_SHIFT);
ptCtrl->eSckPhase = (FCSPI_SckSamplePhaseType)
((u32Flag & FCSPI_TR_CTRL_SCK_PHA_MASK) >> FCSPI_TR_CTRL_SCK_PHA_SHIFT);
ptCtrl->ePrescalerValue = (FCSPI_PrescaleValueType)
((u32Flag & FCSPI_TR_CTRL_PRESCALE_MASK) >> FCSPI_TR_CTRL_PRESCALE_SHIFT);
ptCtrl->ePCSSelect = (FCSPI_PCSType)
((u32Flag & FCSPI_TR_CTRL_PCS_MASK) >> FCSPI_TR_CTRL_PCS_SHIFT);
ptCtrl->eBitFirstOrder = (FCSPI_BitFirstOrderType)
((u32Flag & FCSPI_TR_CTRL_LSBF_MASK) >> FCSPI_TR_CTRL_LSBF_SHIFT);
ptCtrl->eByteSwap = (FCSPI_AtomicBoolType)
((u32Flag & FCSPI_TR_CTRL_BYSW_MASK) >> FCSPI_TR_CTRL_BYSW_SHIFT);
ptCtrl->eContTransEnable = (FCSPI_AtomicBoolType)
((u32Flag & FCSPI_TR_CTRL_CT_EN_MASK) >> FCSPI_TR_CTRL_CT_EN_SHIFT);
ptCtrl->eContCmdEnable = (FCSPI_AtomicBoolType)
((u32Flag & FCSPI_TR_CTRL_CT_GO_MASK) >> FCSPI_TR_CTRL_CT_GO_SHIFT);
ptCtrl->eRxDisable = (FCSPI_AtomicBoolType)
((u32Flag & FCSPI_TR_CTRL_RX_MSK_MASK) >> FCSPI_TR_CTRL_RX_MSK_SHIFT);
ptCtrl->eTxDisable = (FCSPI_AtomicBoolType)
((u32Flag & FCSPI_TR_CTRL_TX_MSK_MASK) >> FCSPI_TR_CTRL_TX_MSK_SHIFT);
ptCtrl->eTransferWidth = (FCSPI_TransferWidthType)
((u32Flag & FCSPI_TR_CTRL_WIDTH_MASK) >> FCSPI_TR_CTRL_WIDTH_SHIFT);
ptCtrl->u16FrameBitCnt = (uint16_t)
(((u32Flag & FCSPI_TR_CTRL_FRM_SZ_MASK) >> FCSPI_TR_CTRL_FRM_SZ_SHIFT)+1);
}
#endif
static FCSPI_StatusType FCSpi_Hw_SetTRCR(FCSPI_InstanceType eInst, FCSPI_TxRxCtrlType *ptCtrl)
{
uint32_t u32Flag = 0U;
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
if ((ptCtrl->u16FrameBitCnt < ((uint16_t)8)) ||
(((uint16_t)0) != (ptCtrl->u16FrameBitCnt & ((uint16_t)0x1))))
{
eRet = FCSPI_STATUS_PARAM_ERR;
}
else
{
u32Flag |= (((uint32_t)(ptCtrl->eSckPolarity)) << FCSPI_TR_CTRL_SCK_POL_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->eSckPhase)) << FCSPI_TR_CTRL_SCK_PHA_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->ePrescalerValue)) << FCSPI_TR_CTRL_PRESCALE_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->ePCSSelect)) << FCSPI_TR_CTRL_PCS_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->eBitFirstOrder)) << FCSPI_TR_CTRL_LSBF_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->eByteSwap)) << FCSPI_TR_CTRL_BYSW_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->eContTransEnable)) << FCSPI_TR_CTRL_CT_EN_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->eContCmdEnable)) << FCSPI_TR_CTRL_CT_GO_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->eRxDisable)) << FCSPI_TR_CTRL_RX_MSK_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->eTxDisable)) << FCSPI_TR_CTRL_TX_MSK_SHIFT);
u32Flag |= (((uint32_t)(ptCtrl->eTransferWidth)) << FCSPI_TR_CTRL_WIDTH_SHIFT);
u32Flag |= (((uint32_t)((uint16_t)(ptCtrl->u16FrameBitCnt - (uint16_t)1))) << FCSPI_TR_CTRL_FRM_SZ_SHIFT);
FCSPI_HWA_SetTxRxControl(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
return eRet;
}
/* caution:write TR_CTRL */
static void FCSpi_Hw_SelectUsePcs(FCSPI_InstanceType eInst, FCSPI_PCSType ePCS)
{
uint32_t u32Flag = FCSPI_HWA_GetTxRxControl(s_atFCSpiInfo[eInst].tFCSpiInstance);
u32Flag &= (~(FCSPI_TR_CTRL_PCS_MASK));
u32Flag |= (((uint32_t)ePCS) << FCSPI_TR_CTRL_PCS_SHIFT);
FCSPI_HWA_SetTxRxControl(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
static FCSPI_PrescaleValueType FCSpi_Hw_GetRegPrescalerVal(FCSPI_InstanceType eInst)
{
return (FCSPI_PrescaleValueType)((FCSPI_HWA_GetTxRxControl(s_atFCSpiInfo[eInst].tFCSpiInstance) &
FCSPI_TR_CTRL_PRESCALE_MASK) >> FCSPI_TR_CTRL_PRESCALE_SHIFT);
}
/* caution:write TR_CTRL */
static void FCSpi_Hw_SetContinuousCommand(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType eEnable)
{
uint32_t u32Flag = FCSPI_HWA_GetTxRxControl(s_atFCSpiInfo[eInst].tFCSpiInstance);
u32Flag &= (~(FCSPI_TR_CTRL_CT_GO_MASK));
u32Flag |= (((uint32_t)eEnable) << FCSPI_TR_CTRL_CT_GO_SHIFT);
FCSPI_HWA_SetTxRxControl(s_atFCSpiInfo[eInst].tFCSpiInstance, u32Flag);
}
#ifdef FCSPI_DRV_INTERNAL_FUNC_EN
static uint32_t FCSpi_Hw_ReadRxFifoFirstEntry(FCSPI_InstanceType eInst)
{
return FCSPI_HWA_ReadData(s_atFCSpiInfo[eInst].tFCSpiInstance);
}
#endif
#ifdef FCSPI_DRV_INTERNAL_FUNC_EN
static void FCSpi_Hw_WriteDataToTxFifo(FCSPI_InstanceType eInst, uint32_t u32TxData)
{
FCSPI_HWA_WriteData(s_atFCSpiInfo[eInst].tFCSpiInstance, u32TxData);
}
#endif
/*
* Before call this function, ensure the FCSPI is disabled and in MASTER mode.
* Src Clk -> Prescaler -> sck divider -> SCLK
*/
#define FCSPI_CAL_DISTANCE(x, y) ((x) > (y) ? ((x) - (y)) : ((y) - (x)))
typedef struct {
uint32_t u32CacheTargetBps;
uint32_t u32CacheSrcClkHz;
uint32_t u32CachePrescaleRegVal;
uint32_t u32CacheBps;
uint32_t u32CacheSckDiv;
} FCSPI_BaundrateCacheType;
#define FCSPI_PCS_CLK_CACHE_CNT ((uint8_t)2)
/* Often use case, just set the same baundrate for specific external device linked with one FCSPI PCS */
static uint32_t FCSpi_Hw_Master_CalcBaudRate(const FCSPI_MasterCfgType *pCfg,
uint32_t *pdwPrescaleRegVal, uint32_t *pdwActualSckDiv)
{
uint32_t u32TargetBps = pCfg->u32BitCntPerSecond;
uint32_t u32SrcClkHz = pCfg->u32FCSpiSrcClk;
uint32_t u32TestFreq = 0U;
int16_t s16TestSckDivRegVal = (int16_t)0;
uint8_t u8PrescalerRegVal = (uint8_t)0;
int16_t s16SckDivLow, s16SckDivHigh;
uint32_t u32Prescale = 0U;
uint32_t u32ActualBps = 0U;
uint32_t u32ActualSckDiv = 0U;
uint32_t u32ActualPrescaleRegVal = 0U;
uint32_t u32ThisPrescaleBestBps = 0U;
uint32_t u32ThisPrescaleBestSckDiv = 0U;
uint32_t u32AbsDistance1, u32AbsDistance2;
uint8_t u8Find = (uint8_t)0;
uint32_t u32Ret = 0U;
if (u32SrcClkHz < (u32TargetBps * 2U))
{
u32Ret = 0U;
}
else
{
if ((uint8_t)0 == u8Find)
{
u32ActualSckDiv = 0U;
u32ActualPrescaleRegVal = 0U;
u32ActualBps = (uint32_t)(u32SrcClkHz / ((uint32_t)((((uint32_t)1) <<
u32ActualPrescaleRegVal) * (u32ActualSckDiv + (uint32_t)2U))));
for (u8PrescalerRegVal = (uint8_t)0; u8PrescalerRegVal < FCSPI_PRESCALE_MAX; ++u8PrescalerRegVal)
{
s16SckDivLow = (int16_t)0;
if ((FCSPI_SCK_SAMPLE_SECOND_EDGE == pCfg->eSckSamplePhase) && /* sample the 2nd edge */
(FCSPI_FALSE != pCfg->eIsPcsContinuous)) /* continuous pcs */
{
/* hw bug fix, sck must be 0 */
s16SckDivHigh = (int16_t)0;
}
else
{
s16SckDivHigh = (int16_t)255;
}
u32Prescale = ((uint32_t)1) << u8PrescalerRegVal;
u32ThisPrescaleBestSckDiv = 0U;
u32ThisPrescaleBestBps = (uint32_t)(u32SrcClkHz / ((uint32_t)(u32Prescale *
(u32ThisPrescaleBestSckDiv + (uint32_t)2U))));
while(s16SckDivHigh > s16SckDivLow)
{
s16TestSckDivRegVal = s16SckDivLow + s16SckDivHigh;
s16TestSckDivRegVal = (s16TestSckDivRegVal / (int16_t)2);
u32TestFreq = (uint32_t)(u32SrcClkHz /
((uint32_t)(u32Prescale * ((uint32_t)s16TestSckDivRegVal + (uint32_t)2U))));
u32AbsDistance1 = FCSPI_CAL_DISTANCE(u32TargetBps, u32ThisPrescaleBestBps);
u32AbsDistance2 = FCSPI_CAL_DISTANCE(u32TargetBps, u32TestFreq);
if (u32AbsDistance1 > u32AbsDistance2)
{
u32ThisPrescaleBestBps = u32TestFreq;
u32ThisPrescaleBestSckDiv = (uint32_t)s16TestSckDivRegVal;
}
if (u32TestFreq == u32TargetBps)
{
break;
}
else if (u32TestFreq < u32TargetBps)
{
s16SckDivHigh = s16TestSckDivRegVal - 1;
}
else
{
s16SckDivLow = s16TestSckDivRegVal + 1;
}
}
u32AbsDistance1 = FCSPI_CAL_DISTANCE(u32TargetBps, u32ActualBps);
u32AbsDistance2 = FCSPI_CAL_DISTANCE(u32TargetBps, u32ThisPrescaleBestBps);
if (u32AbsDistance1 > u32AbsDistance2)
{
u32ActualBps = u32ThisPrescaleBestBps;
u32ActualSckDiv = u32ThisPrescaleBestSckDiv;
u32ActualPrescaleRegVal = u8PrescalerRegVal;
}
if(u32ThisPrescaleBestBps == u32TargetBps)
{
break;
}
}
if (0U != u32ActualBps)
{
if (NULL != pdwActualSckDiv)
{
*pdwActualSckDiv = u32ActualSckDiv;
}
if (NULL != pdwPrescaleRegVal)
{
*pdwPrescaleRegVal = u32ActualPrescaleRegVal;
}
}
/* return the actual calculated baud rate */
u32Ret = u32ActualBps;
}
}
return u32Ret;
}
/* Master/Slave side all use */
static void fcspi_read_rx_fifo(FCSPI_InstanceType eInst)
{
uint32_t u32RxWordData = 0U;
uint16_t u16ByteCount = (uint16_t)0;
uint8_t u8ByteIndex = (uint8_t)0;
uint8_t u8WordCntInRxFifo = FCSPI_HWA_GetRxFifoStoredCount(s_atFCSpiInfo[eInst].tFCSpiInstance);
while (u8WordCntInRxFifo > (uint8_t)0)
{
u32RxWordData = FCSPI_HWA_ReadData(s_atFCSpiInfo[eInst].tFCSpiInstance);
/* Get the number of bytes which can be read from this 32 bites */
if (s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed <=
(s_atFCSpiInfo[eInst].tFCSpiStat.u16RxGetByteCntOfCurFrame + (uint16_t)4))
{
u16ByteCount = (uint16_t)(s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed -
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxGetByteCntOfCurFrame);
}
else
{
u16ByteCount = (uint16_t)4;
}
/* Generate the word which will be write in buffer. */
for (u8ByteIndex = (uint8_t)0; u8ByteIndex < u16ByteCount; ++u8ByteIndex)
{
(s_atFCSpiInfo[eInst].tFCSpiStat.pbyRxBuff)[s_atFCSpiInfo[eInst].tFCSpiStat.u16RxIndex] =
(uint8_t)((u32RxWordData >> (uint32_t)((uint32_t)u8ByteIndex * (uint32_t)8)) & (uint8_t)0xFF);
(s_atFCSpiInfo[eInst].tFCSpiStat.u16RxIndex)++;
}
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxGetByteCntOfCurFrame =
(uint16_t)((s_atFCSpiInfo[eInst].tFCSpiStat.u16RxGetByteCntOfCurFrame +
u16ByteCount) % s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed);
/* Update internal variable used in transmission. */
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet =
(uint16_t)(s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet - u16ByteCount);
/* Verify if all bytes were sent. */
if ((uint16_t)0 == s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet)
{
break;
}
u8WordCntInRxFifo--;
}
}
static void fcspi_write_tx_fifo(FCSPI_InstanceType eInst)
{
uint32_t u32DataToSend = 0U;
uint16_t u16ThisSendByteCnt = (uint16_t)0;
uint8_t u8TxFifoFreeWordCnt = (uint8_t)(s_atFCSpiInfo[eInst].tFCSpiStat.u8TxFifoSize -
(uint8_t)FCSPI_HWA_GetTxFifoStoredCount(s_atFCSpiInfo[eInst].tFCSpiInstance));
uint16_t u16BytesTxLeft = s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend;
while ((u8TxFifoFreeWordCnt != (uint8_t)0) && ((uint16_t)0 != u16BytesTxLeft))
{
if (FCSPI_TRUE == s_atFCSpiInfo[eInst].tFCSpiStat.eIsPcsContinuous)
{
if((uint16_t)1 == s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend)
{
/* Disable continuous PCS */
FCSpi_Hw_SetContinuousCommand(eInst, FCSPI_FALSE);
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend = (uint16_t)0;
u16BytesTxLeft = (uint16_t)0;
break;
}
}
/* Get the number of bytes which can be written in a single 32 bits word. */
if ((s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed -
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxSendByteCntOfCurFrame) <= (uint16_t)4)
{
u16ThisSendByteCnt = (uint16_t)(s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed -
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxSendByteCntOfCurFrame);
}
else
{
u16ThisSendByteCnt = (uint16_t)4;
}
u32DataToSend = 0U;
if (NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff)
{
switch(s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed)
{
case 1:
u32DataToSend = *((const uint8_t *)&(s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff[s_atFCSpiInfo[eInst].tFCSpiStat.u16TxIndex]));
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxIndex += sizeof(uint8_t);
break;
case 2:
u32DataToSend = *((const uint16_t *)&(s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff[s_atFCSpiInfo[eInst].tFCSpiStat.u16TxIndex]));
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxIndex += sizeof(uint16_t);
break;
default:
u32DataToSend = *((const uint32_t *)&(s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff[s_atFCSpiInfo[eInst].tFCSpiStat.u16TxIndex]));
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxIndex += sizeof(uint32_t);
break;
}
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxSendByteCntOfCurFrame =
(uint16_t)((s_atFCSpiInfo[eInst].tFCSpiStat.u16TxSendByteCntOfCurFrame + u16ThisSendByteCnt) %
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed);
}
FCSPI_HWA_WriteData(s_atFCSpiInfo[eInst].tFCSpiInstance, u32DataToSend);
/* Update internal variable used in transmission. */
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend -= u16ThisSendByteCnt;
u16BytesTxLeft = s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend;
u8TxFifoFreeWordCnt -= (uint8_t)1;
}
}
/* MASTER side API */
/*----------------------------------------------------------------------------*/
/**
* @brief Init the FCSpi instance as spi master side
*
* @param eInst Which FCSpi Hardware instance
* @param pCfg Configuration of the FCSpi, MUST NOT NULL
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when configure successfully. Others, some error occur.
*/
FCSPI_StatusType FCSPI_Master_Init(const FCSPI_InstanceType eInst, const FCSPI_MasterCfgType *pCfg)
{
uint32_t u32BaudRate = 0U;
uint32_t u32PrescaleRegVal = 0U;
uint32_t u32SckDiv = 0U;
FCSPI_TxRxCtrlType tTxRxCtrlCfg;
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
if (NULL != pCfg)
{
if ((pCfg->u16BitCountPerFrame >= (uint16_t)8) &&
(pCfg->u16BitCountPerFrame <= (uint16_t)4096)) /* TR_CTRL[FRM_SZ] 12bits */
{
u32BaudRate = FCSpi_Hw_Master_CalcBaudRate(pCfg, &u32PrescaleRegVal, &u32SckDiv);
if (0U != u32BaudRate)
{
FCSpi_Hw_Reset(eInst, FCSPI_FALSE, FCSPI_FALSE, FCSPI_TRUE);
FCSPI_HWA_SetMasterMode(s_atFCSpiInfo[eInst].tFCSpiInstance);
FCSpi_Hw_SetPcs_2_3_Mode(eInst, PCS2_3_PCS);
FCSpi_Hw_SetPin(eInst, SIN_INPUT_SOUT_OUTPUT, PINOUT_RETAIN_LAST);
/* set internal state parameters for spi */
s_atFCSpiInfo[eInst].tFCSpiStat.u8TxFifoSize = (uint8_t)FCSPI_DRV_TX_FIFO_WORD_CNT;
s_atFCSpiInfo[eInst].tFCSpiStat.u8RxFifoSize = (uint8_t)FCSPI_DRV_RX_FIFO_WORD_CNT;
s_atFCSpiInfo[eInst].tFCSpiStat.u32DmaDummyData = 0U;
s_atFCSpiInfo[eInst].tFCSpiStat.u16BitsPerFrame = pCfg->u16BitCountPerFrame;
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed = (uint16_t)(((pCfg->u16BitCountPerFrame + (uint16_t)7)) >> (uint16_t)3);
s_atFCSpiInfo[eInst].tFCSpiStat.eIsPcsContinuous = pCfg->eIsPcsContinuous;
s_atFCSpiInfo[eInst].tFCSpiStat.u32FCSpiSrcClk = pCfg->u32FCSpiSrcClk;
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_FALSE;
s_atFCSpiInfo[eInst].tFCSpiStat.eBitFirstOrder = pCfg->eBitFirstOrder;
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc = pCfg->eTransferTriggerSrc;
s_atFCSpiInfo[eInst].tFCSpiStat.eSckPolarity = pCfg->eSckPolarity;
s_atFCSpiInfo[eInst].tFCSpiStat.eSckSamplePhase = pCfg->eSckSamplePhase;
s_atFCSpiInfo[eInst].tFCSpiStat.ePcs = pCfg->ePcs;
s_atFCSpiInfo[eInst].tFCSpiStat.ePcsPolarity = pCfg->ePcsPolarity;
s_atFCSpiInfo[eInst].tFCSpiStat.u32Baundrate = u32BaudRate;
/* DMA require frames of 3 bytes per frame handled as 4 bytes per frame. */
if (s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed == (uint16_t)3)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed = (uint16_t)4;
}
/* 4 bytes align requirement when > 32bits */
if (s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed > (uint16_t)4)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed =
((((s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed + (uint16_t)3)) >> (uint16_t)2)) << (uint16_t)2;
}
s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf = pCfg->tTriggerDmaInf;
s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb = pCfg->pStopNotifyCb;
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaResetCb = pCfg->pSemaResetCb;
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaTakeCb = pCfg->pSemaTakeCb;
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaPostCb = pCfg->pSemaPostCb;
/* Configure the desired PCS polarity */
FCSpi_Hw_SetOnePcsPolarity(eInst, pCfg->ePcs, pCfg->ePcsPolarity);
/* enable sample delay */
FCSpi_Hw_Master_SetSckLoopbackSample(eInst, FCSPI_TRUE);
/* set up the baudrate */
FCSpi_Hw_Set_SCK_PCS_DIV_Hold(eInst,
(uint8_t)(u32SckDiv >> 2U),
(uint8_t)(u32SckDiv >> 2U),
(uint8_t)(u32SckDiv >> 2U),
(uint8_t)u32SckDiv); /* write best baudrate scaler to SCKDIV */
/* Write the TCR for this transfer. */
tTxRxCtrlCfg.eSckPolarity = pCfg->eSckPolarity;
tTxRxCtrlCfg.eSckPhase = pCfg->eSckSamplePhase;
tTxRxCtrlCfg.ePrescalerValue = (FCSPI_PrescaleValueType)u32PrescaleRegVal;
tTxRxCtrlCfg.ePCSSelect = pCfg->ePcs;
tTxRxCtrlCfg.eBitFirstOrder = pCfg->eBitFirstOrder;
tTxRxCtrlCfg.eByteSwap = FCSPI_FALSE;
tTxRxCtrlCfg.eContTransEnable = pCfg->eIsPcsContinuous;
tTxRxCtrlCfg.eContCmdEnable = FCSPI_FALSE;
tTxRxCtrlCfg.eRxDisable = FCSPI_FALSE;
tTxRxCtrlCfg.eTxDisable = FCSPI_FALSE;
tTxRxCtrlCfg.eTransferWidth = FCSPI_TRANSFER_1_BIT;
tTxRxCtrlCfg.u16FrameBitCnt = pCfg->u16BitCountPerFrame;
eRet = FCSpi_Hw_SetTRCR(eInst, &tTxRxCtrlCfg);
if (FCSPI_STATUS_SUCCESS == eRet)
{
if (FCSPI_TRANSFER_TRIGGER_SRC_USER_POLL != pCfg->eTransferTriggerSrc)
{
IntMgr_EnableInterrupt(s_atFCSpiInfo[eInst].eFCSpiIrq);
}
FCSPI_HWA_ModuleEnable(s_atFCSpiInfo[eInst].tFCSpiInstance);
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
}
else
{
eRet = FCSPI_STATUS_PARAM_ERR;
}
}
else
{
eRet = FCSPI_STATUS_PARAM_ERR;
}
return eRet;
}
/**
* @brief Deinit the FCSpi
*
* @param eInst Which FCSpi Hardware instance
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when deinit the FCSpi successfully. Others, the hardware is busy now.
*/
FCSPI_StatusType FCSPI_Deinit(const FCSPI_InstanceType eInst)
{
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
if (FCSPI_TRUE != s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer)
{
/* reset registers, disabling spi module */
FCSpi_Hw_Reset(eInst, FCSPI_FALSE, FCSPI_FALSE, FCSPI_TRUE);
}
else
{
eRet = FCSPI_STATUS_BUSY;
}
return eRet;
}
/**
* @brief Configure the holding time (in us) between PCS and SCK
*
* @param eInst Which FCSpi Hardware instance
* @param pCfg Configure the delay parameters between PCS and SCK, MUST NOT null
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when configure successfully. Others, the hardware is busy now.
*/
FCSPI_StatusType FCSPI_Master_SetSckPcsHoldTime(const FCSPI_InstanceType eInst,
const FCSPI_MasterSckPcsHoldTimeType *pCfg)
{
FCSPI_StatusType eStat = FCSPI_STATUS_SUCCESS;
uint32_t u32PCSPCSCycle,
u32SCKPCSCycle,
u32PCSSCKCycle;
FCSPI_PrescaleValueType ePrescaler;
uint32_t u32PrescaleValue;
uint32_t u32ClkAfterScalePerUs;
if (NULL != pCfg)
{
/* disable FCSPI first */
eStat = FCSpi_Hw_Disable(eInst);
if (FCSPI_STATUS_SUCCESS == eStat)
{
ePrescaler = FCSpi_Hw_GetRegPrescalerVal(eInst);
u32PrescaleValue = FCSpi_Hw_PrescalerRegToActualVal(ePrescaler);
if (0U != u32PrescaleValue) /* actually unreachable */
{
u32ClkAfterScalePerUs = (uint32_t)(s_atFCSpiInfo[eInst].tFCSpiStat.u32FCSpiSrcClk /
u32PrescaleValue / (uint32_t)1000000);
u32PCSPCSCycle = pCfg->u32PCStoPCSHoldUs * u32ClkAfterScalePerUs;
u32SCKPCSCycle = pCfg->u32SCKtoPCSHoldUs * u32ClkAfterScalePerUs;
u32PCSSCKCycle = pCfg->u32PCStoSCKHoldUs * u32ClkAfterScalePerUs;
if (u32PCSPCSCycle > (uint32_t)257U)
{
u32PCSPCSCycle = (uint32_t)257U;
}
if(u32SCKPCSCycle > (uint32_t)256U)
{
u32SCKPCSCycle = (uint32_t)256U;
}
if(u32PCSSCKCycle > (uint32_t)256U)
{
u32PCSSCKCycle = (uint32_t)256U;
}
if (u32PCSPCSCycle < (uint32_t)2U)
{
u32PCSPCSCycle = (uint32_t)2U;
}
if(u32SCKPCSCycle == (uint32_t)0)
{
u32SCKPCSCycle = (uint32_t)1U;
}
if(u32PCSSCKCycle == (uint32_t)0U)
{
u32PCSSCKCycle = (uint32_t)1U;
}
FCSpi_Hw_Set_SCK_PCS_Hold(eInst,
(uint8_t)(u32SCKPCSCycle - 1U),
(uint8_t)(u32PCSSCKCycle - 1U),
(uint8_t)(u32PCSPCSCycle - 2U));
/* Enable module */
FCSPI_HWA_ModuleEnable(s_atFCSpiInfo[eInst].tFCSpiInstance);
}
else
{
eStat = FCSPI_STATUS_ERROR;
}
}
else
{
eStat = FCSPI_STATUS_BUSY;
}
}
else
{
eStat = FCSPI_STATUS_PARAM_ERR;
}
return eStat;
}
/**
* @brief Configure the holding time (in SCK/100) between PCS and SCK
*
* @param eInst Which FCSpi Hardware instance
* @param pCfg Configure the delay parameters between PCS and SCK, MUST NOT null
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when configure successfully. Others, the hardware is busy now.
*/
FCSPI_StatusType FCSPI_Master_SetSckPcsHoldSckPercentage(
const FCSPI_InstanceType eInst, const FCSPI_MasterSckPcsHoldSckCycleType *pCfg)
{
uint8_t u8PCSPCSCycle;
uint8_t u8SCKPCSCycle;
uint8_t u8PCSSCKCycle;
uint8_t u8SckDiv;
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
if (NULL != pCfg)
{
/* disable FCSPI first */
eRet = FCSpi_Hw_Disable(eInst);
if (FCSPI_STATUS_SUCCESS == eRet)
{
FCSpi_Hw_Get_SCK_PCS_DIV_Hold(eInst, NULL, NULL, NULL, &u8SckDiv);
u8PCSPCSCycle = (uint8_t)((uint32_t)pCfg->u32PCStoPCSHoldPercentage *
(uint32_t)u8SckDiv / (uint32_t)100);
u8SCKPCSCycle = (uint8_t)((uint32_t)pCfg->u32SCKtoPCSHoldPercentage *
(uint32_t)u8SckDiv / (uint32_t)100);
u8PCSSCKCycle = (uint8_t)((uint32_t)pCfg->u32PCStoSCKHoldPercentage *
(uint32_t)u8SckDiv / (uint32_t)100);
if (u8PCSPCSCycle < (uint8_t)2)
{
u8PCSPCSCycle = (uint8_t)2;
}
if(u8SCKPCSCycle == (uint8_t)0)
{
u8SCKPCSCycle = (uint8_t)1;
}
if(u8PCSSCKCycle == (uint8_t)0)
{
u8PCSSCKCycle = (uint8_t)1;
}
FCSpi_Hw_Set_SCK_PCS_Hold(eInst,
(uint8_t)(u8SCKPCSCycle - (uint8_t)1),
(uint8_t)(u8PCSSCKCycle - (uint8_t)1),
(uint8_t)(u8PCSPCSCycle - (uint8_t)2));
/* Enable module */
FCSPI_HWA_ModuleEnable(s_atFCSpiInfo[eInst].tFCSpiInstance);
}
else
{
eRet = FCSPI_STATUS_BUSY;
}
}
else
{
eRet = FCSPI_STATUS_PARAM_ERR;
}
return eRet;
}
/**
* @brief Select the PCS to use and configure
*
* @param eInst Which FCSpi Hardware instance
* @param pCfg Parameters about PCS configuration, MUST NOT null
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when configure successfully. Others, the hardware is busy now.
*/
FCSPI_StatusType FCSPI_Master_SelectPcs(
const FCSPI_InstanceType eInst, const FCSPI_MasterPcsConfType *pCfg)
{
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
if (pCfg)
{
eRet = FCSpi_Hw_Disable(eInst);
if (FCSPI_STATUS_SUCCESS == eRet)
{
FCSpi_Hw_SetOnePcsPolarity(eInst, pCfg->ePcs, pCfg->ePolarity);
FCSPI_HWA_ModuleEnable(s_atFCSpiInfo[eInst].tFCSpiInstance);
FCSpi_Hw_SelectUsePcs(eInst, pCfg->ePcs);
}
else
{
eRet = FCSPI_STATUS_BUSY;
}
}
else
{
eRet = FCSPI_STATUS_PARAM_ERR;
}
return eRet;
}
static void fcspi_master_clean_transfer(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInInterrupt)
{
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_FALSE;
if (FCSPI_TRANSFER_TRIGGER_SRC_DMA_ISR == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc)
{
FCSpi_Hw_SetRxTxDmaEnableStatus(eInst, FCSPI_FALSE, FCSPI_FALSE);
}
else
{
FCSpi_Hw_DisableSomeInterrupts(eInst,
FCSPI_INT_EN_RFIE(1) | FCSPI_INT_EN_TFIE(1));
}
FCSpi_Hw_DisableSomeInterrupts(eInst,
FCSPI_INT_EN_RFOIE(1) | FCSPI_INT_EN_TFUIE(1) | FCSPI_INT_EN_TCIE(1));
FCSpi_Hw_ClearSomeStatusW1CFlag(eInst,
FCSPI_STATUS_RX_FO(1) | FCSPI_STATUS_TX_FU(1) | FCSPI_STATUS_TCF(1));
if (FCSPI_TRUE == bIsInInterrupt)
{
if (NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb(eInst, FCSPI_TRUE);
}
if (s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaPostCb(eInst, FCSPI_TRUE);
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
}
}
else
{
if (NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb(eInst, FCSPI_FALSE);
}
if (s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaPostCb(eInst, FCSPI_FALSE);
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
}
}
}
static void fcspi_master_abort_transfer(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInISR)
{
fcspi_master_clean_transfer(eInst, bIsInISR);
/* clean the fifo */
FCSpi_Hw_Reset(eInst, FCSPI_TRUE, FCSPI_TRUE, FCSPI_FALSE);
FCSpi_Hw_Reset(eInst, FCSPI_TRUE, FCSPI_TRUE, FCSPI_FALSE); /* for shifter */
}
static void fcspi_master_dma_rx_err_interrupt(FCSPI_InstanceType eInst)
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_RX_FAIL;
fcspi_master_abort_transfer(eInst, FCSPI_TRUE);
}
static void fcspi_0_master_dma_rx_err_interrupt(void)
{
fcspi_master_dma_rx_err_interrupt(FCSPI_0);
}
static void fcspi_1_master_dma_rx_err_interrupt(void)
{
fcspi_master_dma_rx_err_interrupt(FCSPI_1);
}
static void fcspi_2_master_dma_rx_err_interrupt(void)
{
fcspi_master_dma_rx_err_interrupt(FCSPI_2);
}
static void fcspi_3_master_dma_rx_err_interrupt(void)
{
fcspi_master_dma_rx_err_interrupt(FCSPI_3);
}
static void fcspi_4_master_dma_rx_err_interrupt(void)
{
fcspi_master_dma_rx_err_interrupt(FCSPI_4);
}
static void fcspi_5_master_dma_rx_err_interrupt(void)
{
fcspi_master_dma_rx_err_interrupt(FCSPI_5);
}
static void fcspi_master_dma_rx_finish_interrupt(void)
{
; /* in master mode, the tx trigger the sclk output, so when rx finish, ignore. */
}
static void fcspi_master_dma_tx_err_interrupt(FCSPI_InstanceType eInst)
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_TX_FAIL;
fcspi_master_abort_transfer(eInst, FCSPI_TRUE);
}
static void fcspi_0_master_dma_tx_err_interrupt(void)
{
fcspi_master_dma_tx_err_interrupt(FCSPI_0);
}
static void fcspi_1_master_dma_tx_err_interrupt(void)
{
fcspi_master_dma_tx_err_interrupt(FCSPI_1);
}
static void fcspi_2_master_dma_tx_err_interrupt(void)
{
fcspi_master_dma_tx_err_interrupt(FCSPI_2);
}
static void fcspi_3_master_dma_tx_err_interrupt(void)
{
fcspi_master_dma_tx_err_interrupt(FCSPI_3);
}
static void fcspi_4_master_dma_tx_err_interrupt(void)
{
fcspi_master_dma_tx_err_interrupt(FCSPI_4);
}
static void fcspi_5_master_dma_tx_err_interrupt(void)
{
fcspi_master_dma_tx_err_interrupt(FCSPI_5);
}
static void fcspi_master_dma_tx_finish_interrupt(FCSPI_InstanceType eInst)
{
if (FCSPI_TRUE == s_atFCSpiInfo[eInst].tFCSpiStat.eIsPcsContinuous)
{
FCSpi_Hw_SetContinuousCommand(eInst, FCSPI_FALSE);
}
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend = (uint16_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet = (uint16_t)0;
/* DMA -> TX FIFO -> PIN, DMA send to tx fifo finish, enable tx fifo finish interrupt */
FCSpi_Hw_EnableTransmitCompleteInterrupt(eInst);
}
static void fcspi_0_master_dma_tx_finish_interrupt(void)
{
fcspi_master_dma_tx_finish_interrupt(FCSPI_0);
}
static void fcspi_1_master_dma_tx_finish_interrupt(void)
{
fcspi_master_dma_tx_finish_interrupt(FCSPI_1);
}
static void fcspi_2_master_dma_tx_finish_interrupt(void)
{
fcspi_master_dma_tx_finish_interrupt(FCSPI_2);
}
static void fcspi_3_master_dma_tx_finish_interrupt(void)
{
fcspi_master_dma_tx_finish_interrupt(FCSPI_3);
}
static void fcspi_4_master_dma_tx_finish_interrupt(void)
{
fcspi_master_dma_tx_finish_interrupt(FCSPI_4);
}
static void fcspi_5_master_dma_tx_finish_interrupt(void)
{
fcspi_master_dma_tx_finish_interrupt(FCSPI_5);
}
/* if enter transfer state, return success, others, not start tranfer */
static FCSPI_StatusType fcspi_master_async_transfer_bytes(FCSPI_InstanceType eInst,
const uint8_t *pSendBuffer, uint8_t *pReceiveBuffer,
uint16_t u16TransferByteCnt)
{
DMA_InterruptCfgType tDmaTxInterruptCfg = {0};
DMA_ChannelCfgType tDmaTxChnlCfg = {0};
uint8_t u8DmaTxBlkByteCnt = (uint8_t)1;
DMA_InterruptCfgType tDmaRxInterruptCfg = {0};
DMA_ChannelCfgType tDmaRxChnlCfg = {0};
uint8_t u8DmaRxBlkByteCnt = (uint8_t)1;
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
uint32_t u32StatRegVal = 0u;
if ((uint16_t)0 != s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed)
{
if ((uint16_t)0 != u16TransferByteCnt)
{
if ((u16TransferByteCnt % s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed) == (uint16_t)0)
{
u32StatRegVal = FCSPI_HWA_GetStatus(s_atFCSpiInfo[eInst].tFCSpiInstance);
if ((FCSPI_TRUE != s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer) &&
(!FCSpi_Hw_ChkBusy(u32StatRegVal)))
{
if (!FCSpi_Hw_ChkBusy(FCSPI_HWA_GetStatus(s_atFCSpiInfo[eInst].tFCSpiInstance)))
{
FCSpi_Hw_Reset(eInst, FCSPI_TRUE, FCSPI_TRUE, FCSPI_FALSE);
FCSpi_Hw_Reset(eInst, FCSPI_TRUE, FCSPI_TRUE, FCSPI_FALSE); /* ensure clear data in shifter */
/* if pcs need continuous, set command continuous bit */
if (s_atFCSpiInfo[eInst].tFCSpiStat.eIsPcsContinuous)
{
FCSpi_Hw_SetContinuousCommand(eInst, FCSPI_TRUE);
}
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_OK;
FCSPI_HWA_SetWatermark(s_atFCSpiInfo[eInst].tFCSpiInstance, (uint8_t)0, (uint8_t)2);
FCSpi_Hw_ClearSomeStatusW1CFlag(eInst, FCSPI_DRV_STATUS_REG_W1C_U32);
FCSpi_Hw_EnableMoreInterrupts(eInst, FCSPI_INT_EN_TFUIE(1));
/* if rx needed, enable overflow interrupt and rx */
if (NULL != pReceiveBuffer)
{
FCSpi_Hw_EnableMoreInterrupts(eInst, FCSPI_INT_EN_RFOIE(1));
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet = u16TransferByteCnt;
FCSPI_HWA_EnableRxDataMask(s_atFCSpiInfo[eInst].tFCSpiInstance, FCSPI_TRUE);
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet = (uint16_t)0;
FCSPI_HWA_EnableRxDataMask(s_atFCSpiInfo[eInst].tFCSpiInstance, FCSPI_FALSE);
}
if (FCSPI_TRANSFER_TRIGGER_SRC_DMA_ISR == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc)
{
/* TX */
tDmaTxChnlCfg.u8ChannelPriority = s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8TxDMAChannelPriority;
tDmaTxChnlCfg.bDestAddrLoopbackEn = false;
tDmaTxChnlCfg.bSrcAddrLoopbackEn = false;
tDmaTxChnlCfg.bAutoStop = true; /* auto stop dma after send finish */
tDmaTxChnlCfg.bSrcCircularBufferEn = false;
tDmaTxChnlCfg.bDestCircularBufferEn = false;
switch (s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed)
{
case 1:
tDmaTxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_1B;
tDmaTxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_1B;
tDmaTxChnlCfg.bSrcBlockOffsetEn = true;
tDmaTxChnlCfg.s32BlockOffset = (int32_t)1;
u8DmaTxBlkByteCnt = (uint8_t)1;
break;
case 2:
tDmaTxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_2B;
tDmaTxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_2B;
tDmaTxChnlCfg.bSrcBlockOffsetEn = true;
tDmaTxChnlCfg.s32BlockOffset = (int32_t)2;
u8DmaTxBlkByteCnt = (uint8_t)2;
break;
default:
tDmaTxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_4B;
tDmaTxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_4B;
tDmaTxChnlCfg.bSrcBlockOffsetEn = true;
tDmaTxChnlCfg.s32BlockOffset = (int32_t)4;
u8DmaTxBlkByteCnt = (uint8_t)4;
break;
}
tDmaTxChnlCfg.u16BlockCount = u16TransferByteCnt / u8DmaTxBlkByteCnt;
tDmaTxChnlCfg.bDestBlockOffsetEn = false;
tDmaTxInterruptCfg.bTransferCompleteIntEn = true;
tDmaTxInterruptCfg.bTransferErrorIntEn = true;
switch (eInst)
{
case FCSPI_0:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI0_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_0_master_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_0_master_dma_tx_err_interrupt;
break;
case FCSPI_1:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI1_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_1_master_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_1_master_dma_tx_err_interrupt;
break;
case FCSPI_2:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI2_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_2_master_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_2_master_dma_tx_err_interrupt;
break;
case FCSPI_3:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI3_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_3_master_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_3_master_dma_tx_err_interrupt;
break;
case FCSPI_4:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI4_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_4_master_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_4_master_dma_tx_err_interrupt;
break;
case FCSPI_5:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI5_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_5_master_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_5_master_dma_tx_err_interrupt;
break;
default:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI3_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_3_master_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_3_master_dma_tx_err_interrupt;
break;
}
tDmaTxChnlCfg.eDestIncMode = DMA_INCREMENT_DISABLE;
tDmaTxChnlCfg.eSrcIncMode = DMA_INCREMENT_DISABLE;
tDmaTxChnlCfg.pDestBuffer = FCSPI_HWA_GetTxDataAddr(s_atFCSpiInfo[eInst].tFCSpiInstance);
tDmaTxChnlCfg.u32BlockSize = (uint32_t)u8DmaTxBlkByteCnt;
if (NULL != pSendBuffer)
{
tDmaTxChnlCfg.pSrcBuffer = pSendBuffer;
}
else
{
tDmaTxChnlCfg.pSrcBuffer = &(s_atFCSpiInfo[eInst].tFCSpiStat.u32DmaDummyData);
tDmaTxChnlCfg.bSrcBlockOffsetEn = false; /* if send buffer is NULL, just send dummy data, MUST fix the source to the dummy variable */
tDmaTxChnlCfg.s32BlockOffset = (int32_t)0;
}
DMA_InitChannel(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance, (DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8TxDMAChannel, &tDmaTxChnlCfg);
/* RX */
/* if needed, configure the DMA Rx function */
if (NULL != pReceiveBuffer)
{
tDmaRxChnlCfg.u8ChannelPriority = s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8RxDMAChannelPriority;
tDmaRxChnlCfg.bDestAddrLoopbackEn = false;
tDmaRxChnlCfg.bSrcAddrLoopbackEn = false;
tDmaRxChnlCfg.bAutoStop = true; /* auto stop dma after send finish */
tDmaRxChnlCfg.bSrcCircularBufferEn = false;
tDmaRxChnlCfg.bDestCircularBufferEn = false;
switch (s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed)
{
case 1:
tDmaRxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_1B;
tDmaRxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_1B;
tDmaRxChnlCfg.bDestBlockOffsetEn = true;
tDmaRxChnlCfg.s32BlockOffset = (int32_t)1;
u8DmaRxBlkByteCnt = (uint8_t)1;
break;
case 2:
tDmaRxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_2B;
tDmaRxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_2B;
tDmaRxChnlCfg.bDestBlockOffsetEn = true;
tDmaRxChnlCfg.s32BlockOffset = (int32_t)2;
u8DmaRxBlkByteCnt = (uint8_t)2;
break;
default:
tDmaRxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_4B;
tDmaRxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_4B;
tDmaRxChnlCfg.bDestBlockOffsetEn = true;
tDmaRxChnlCfg.s32BlockOffset = (int32_t)4;
u8DmaRxBlkByteCnt = (uint8_t)4;
break;
}
tDmaRxChnlCfg.u16BlockCount = u16TransferByteCnt / u8DmaRxBlkByteCnt;
tDmaRxChnlCfg.bSrcBlockOffsetEn = false;
tDmaRxInterruptCfg.bTransferCompleteIntEn = true;
tDmaRxInterruptCfg.bTransferErrorIntEn = true;
switch (eInst)
{
case FCSPI_0:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI0_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_master_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_0_master_dma_rx_err_interrupt;
break;
case FCSPI_1:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI1_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_master_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_1_master_dma_rx_err_interrupt;
break;
case FCSPI_2:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI2_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_master_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_2_master_dma_rx_err_interrupt;
break;
case FCSPI_3:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI3_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_master_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_3_master_dma_rx_err_interrupt;
break;
case FCSPI_4:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI4_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_master_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_4_master_dma_rx_err_interrupt;
break;
case FCSPI_5:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI5_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_master_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_5_master_dma_rx_err_interrupt;
break;
default:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI3_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_master_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_3_master_dma_rx_err_interrupt;
break;
}
tDmaRxChnlCfg.eDestIncMode = DMA_INCREMENT_DISABLE;
tDmaRxChnlCfg.eSrcIncMode = DMA_INCREMENT_DISABLE;
tDmaRxChnlCfg.pSrcBuffer = FCSPI_HWA_GetRxDataAddr(s_atFCSpiInfo[eInst].tFCSpiInstance);
tDmaRxChnlCfg.u32BlockSize = (uint32_t)u8DmaRxBlkByteCnt;
tDmaRxChnlCfg.pDestBuffer = pReceiveBuffer;
DMA_InitChannel(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8RxDMAChannel, &tDmaRxChnlCfg);
DMA_InitChannelInterrupt(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8RxDMAChannel, &tDmaRxInterruptCfg);
DMA_StartChannel(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8RxDMAChannel);
}
DMA_InitChannelInterrupt(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8TxDMAChannel, &tDmaTxInterruptCfg);
DMA_StartChannel(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8TxDMAChannel);
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_TRUE;
if (pReceiveBuffer)
{
FCSpi_Hw_SetRxTxDmaEnableStatus(eInst, FCSPI_TRUE, FCSPI_TRUE);
}
else
{
/* only enable TX DMA */
FCSpi_Hw_SetRxTxDmaEnableStatus(eInst, FCSPI_FALSE, FCSPI_TRUE);
}
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff = pSendBuffer;
s_atFCSpiInfo[eInst].tFCSpiStat.pbyRxBuff = pReceiveBuffer;
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxIndex = (uint16_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxIndex = (uint16_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxSendByteCntOfCurFrame = (uint16_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxGetByteCntOfCurFrame = (uint16_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend = u16TransferByteCnt;
if (FCSPI_TRUE == s_atFCSpiInfo[eInst].tFCSpiStat.eIsPcsContinuous)
{
/* continuous transfer need an extra word to negate PCS */
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend++;
}
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_TRUE;
if (NULL != pReceiveBuffer) /* need rx fifo */
{
FCSpi_Hw_EnableMoreInterrupts(eInst, FCSPI_INT_EN_RFIE(1) | FCSPI_INT_EN_TFIE(1));
}
else
{
FCSpi_Hw_EnableMoreInterrupts(eInst, FCSPI_INT_EN_TFIE(1));
}
}
eRet = FCSPI_STATUS_SUCCESS;
}
else
{
eRet = FCSPI_STATUS_BUSY;
}
}
else
{
eRet = FCSPI_STATUS_BUSY;
}
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
}
else
{
eRet = FCSPI_STATUS_NO_DATA;
}
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
return eRet;
}
/**
* @brief Send and receive asynchronously
* 1) If the trigger source is driver user poll, this api not support this mode.
* 2) If the trigger source is interrupt or DMA, this api will start the transmission, then return immediately.
* After transmission stop, it will trigger an interrupt.
* During the transmission, the send data buffer and receive data buffer
* should keep valid until the transmission stop.
* @param eInst Which FCSpi Hardware instance
* @param pCfg the data information, MUST NOT null
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when start transfer successfully. Others, some error occur.
*/
FCSPI_StatusType FCSPI_AsyncTransfer(const FCSPI_InstanceType eInst, const FCSPI_AsyncDataInfType *pCfg)
{
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
if (NULL != pCfg)
{
if (FCSPI_TRANSFER_TRIGGER_SRC_USER_POLL != s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc)
{
if (FCSPI_MODE_MASTER == FCSPI_HWA_CheckMode(s_atFCSpiInfo[eInst].tFCSpiInstance))
{
eRet = fcspi_master_async_transfer_bytes(eInst,
pCfg->pSendBuffer, pCfg->pReceiveBuffer,
pCfg->u16FrameCount * s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed);
}
else
{
eRet = fcspi_slave_async_transfer_bytes(eInst, pCfg->pSendBuffer, pCfg->pReceiveBuffer,
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed * pCfg->u16FrameCount);
}
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
}
else
{
eRet = FCSPI_STATUS_PARAM_ERR;
}
return eRet;
}
/**
* @brief Send and receive synchronously
* 1) If the semaphore callbacks are configured,
* and the driver is configured transmitting triggered by interrupt, or by DMA,
* the driver will use semaphore to wait the transmission stopped.
* In this case, the timeout value is passed to semaphore callback directly.
* 2) If the semaphore callbacks are not configured,
* this api will poll the status when triggered by interrupt or DMA,
* or poll to trigger the transmission when the mode is "FCSPI_TRANSFER_TRIGGER_SRC_USER_POLL".
* In this case, the timeout value has different meaning for different trigger mode.
* Read the source code for detail.
* @param eInst Which FCSpi Hardware instance
* @param pCfg the data information, MUST NOT null
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when transfer successfully. Others, some error occur.
*/
FCSPI_StatusType FCSPI_SyncTransfer(const FCSPI_InstanceType eInst, const FCSPI_SyncDataInfType *pCfg)
{
FCSPI_StatusType tStatus;
FCSPI_SemaphoreStatType tSemaStat;
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
FCSPI_AtomicBoolType bIsMaster;
uint32_t u32MonitorTimeout = 0xFFFFFFFFu;
uint16_t u16RxRemain = (uint16_t)0;
uint16_t u16TxRemain = (uint16_t)0;
uint16_t u16PreRxRemain = (uint16_t)0;
uint16_t u16PreTxRemain = (uint16_t)0;
uint32_t u32TryTimeout = 0xFFFFFFFFu;
FCSPI_AtomicBoolType bIsBlockType = FCSPI_TRUE;
bIsMaster = (FCSPI_MODE_MASTER == FCSPI_HWA_CheckMode(s_atFCSpiInfo[eInst].tFCSpiInstance)) ? FCSPI_TRUE : FCSPI_FALSE;
FCSPI_AtomicBoolType bNeedExitLoop = FCSPI_FALSE;
if (NULL != pCfg)
{
if ((uint16_t)0 != pCfg->u16FrameCount)
{
if ((NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pSemaResetCb) &&
(NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pSemaTakeCb) &&
(NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pSemaPostCb) &&
((FCSPI_TRANSFER_TRIGGER_SRC_ISR == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc) ||
(FCSPI_TRANSFER_TRIGGER_SRC_DMA_ISR == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc)))
{
if (FCSPI_SEMAPHORE_SUCCESS == s_atFCSpiInfo[eInst].tFCSpiStat.pSemaResetCb(eInst))
{
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)1;
if (FCSPI_TRUE == bIsMaster)
{
tStatus = fcspi_master_async_transfer_bytes(eInst, pCfg->pSendBuffer, pCfg->pReceiveBuffer,
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed * pCfg->u16FrameCount);
}
else
{
tStatus = fcspi_slave_async_transfer_bytes(eInst, pCfg->pSendBuffer, pCfg->pReceiveBuffer,
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed * pCfg->u16FrameCount);
}
if (FCSPI_STATUS_SUCCESS == tStatus)
{
tSemaStat = s_atFCSpiInfo[eInst].tFCSpiStat.pSemaTakeCb(eInst, pCfg->u32Timeout);
if (FCSPI_SEMAPHORE_FAIL == tSemaStat)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_ABORT;
if (FCSPI_TRUE == bIsMaster)
{
fcspi_master_abort_transfer(eInst, FCSPI_FALSE);
}
else
{
fcspi_slave_abort_transfer(eInst, FCSPI_FALSE);
}
eRet = FCSPI_STATUS_ERROR;
}
else if (FCSPI_SEMAPHORE_TIMEOUT == tSemaStat)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_ABORT;
if (FCSPI_TRUE == bIsMaster)
{
fcspi_master_abort_transfer(eInst, FCSPI_FALSE);
}
else
{
fcspi_slave_abort_transfer(eInst, FCSPI_FALSE);
}
eRet = FCSPI_STATUS_SYNC_TIMEOUT;
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
if (FCSPI_TRANSFER_OK != s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat)
{
eRet = FCSPI_STATUS_TRANSFER_FAIL;
}
else
{
eRet = FCSPI_STATUS_SUCCESS;
}
}
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
eRet = tStatus;
}
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
}
else
{
if (FCSPI_TRUE == bIsMaster)
{
tStatus = fcspi_master_async_transfer_bytes(eInst, pCfg->pSendBuffer, pCfg->pReceiveBuffer,
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed * pCfg->u16FrameCount);
}
else
{
tStatus = fcspi_slave_async_transfer_bytes(eInst, pCfg->pSendBuffer, pCfg->pReceiveBuffer,
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed * pCfg->u16FrameCount);
}
if (FCSPI_STATUS_SUCCESS == tStatus)
{
if (pCfg->u32Timeout > 0u)
{
u32TryTimeout = pCfg->u32Timeout;
bIsBlockType = FCSPI_FALSE;
}
else
{
bIsBlockType = FCSPI_TRUE;
}
if (FCSPI_TRANSFER_TRIGGER_SRC_USER_POLL == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc)
{
if (FCSPI_TRUE == bIsMaster)
{
do {
eRet = fcspi_master_trigger(eInst, FCSPI_FALSE);
if (FCSPI_FALSE == bIsBlockType)
{
u32TryTimeout--;
if (0u == u32TryTimeout)
{
break;
}
}
} while (FCSPI_STATUS_TRIGGER_OK == eRet);
}
else
{
do {
eRet = fcspi_slave_trigger(eInst, FCSPI_FALSE);
if (FCSPI_FALSE == bIsBlockType)
{
u32TryTimeout--;
if (0u == u32TryTimeout)
{
break;
}
}
} while (FCSPI_STATUS_TRIGGER_OK == eRet);
}
if (FCSPI_STATUS_TRIGGER_FINISH == eRet)
{
eRet = FCSPI_STATUS_SUCCESS;
}
else if ((FCSPI_FALSE == bIsBlockType) && (0u == u32TryTimeout))
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_ABORT;
if (FCSPI_TRUE == bIsMaster)
{
fcspi_master_abort_transfer(eInst, FCSPI_FALSE);
}
else
{
fcspi_slave_abort_transfer(eInst, FCSPI_FALSE);
}
eRet = FCSPI_STATUS_SYNC_TIMEOUT;
}
else
{
eRet = FCSPI_STATUS_TRANSFER_FAIL;
}
}
else if ((FCSPI_TRANSFER_TRIGGER_SRC_ISR == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc) ||
(FCSPI_TRANSFER_TRIGGER_SRC_DMA_ISR == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc))
{
u32MonitorTimeout = 0xfffff00u; /* ensure 1s */
u16PreRxRemain = s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet;
u16PreTxRemain = s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend;
while (FCSPI_TRUE == s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer)
{
u32MonitorTimeout--;
if (0u == u32MonitorTimeout)
{
bNeedExitLoop = FCSPI_FALSE;
u16RxRemain = s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet;
u16TxRemain = s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend;
if (((u16PreRxRemain == u16RxRemain) && ((uint16_t)0 != u16RxRemain)) ||
((u16PreTxRemain == u16TxRemain) && ((uint16_t)0 != u16TxRemain)))
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_ABORT;
if (FCSPI_TRUE == bIsMaster)
{
fcspi_master_abort_transfer(eInst, FCSPI_FALSE);
}
else
{
fcspi_slave_abort_transfer(eInst, FCSPI_FALSE);
}
bNeedExitLoop = FCSPI_TRUE;
}
else
{
u16PreRxRemain = u16RxRemain;
u16PreTxRemain = u16TxRemain;
u32MonitorTimeout = 0xfffff00u;
if (FCSPI_FALSE == bIsBlockType)
{
u32TryTimeout--;
if (0u == u32TryTimeout)
{
bNeedExitLoop = FCSPI_TRUE;
}
}
}
if (FCSPI_TRUE == bNeedExitLoop)
{
break;
}
}
}
if ((FCSPI_FALSE == bIsBlockType) && (0u == u32TryTimeout))
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_ABORT;
if (FCSPI_TRUE == bIsMaster)
{
fcspi_master_abort_transfer(eInst, FCSPI_FALSE);
}
else
{
fcspi_slave_abort_transfer(eInst, FCSPI_FALSE);
}
eRet = FCSPI_STATUS_SYNC_TIMEOUT;
}
else if (FCSPI_TRANSFER_OK == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat)
{
eRet = FCSPI_STATUS_SUCCESS;
}
else
{
eRet = FCSPI_STATUS_TRANSFER_FAIL;
}
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_ABORT;
if (FCSPI_TRUE == bIsMaster)
{
fcspi_master_abort_transfer(eInst, FCSPI_FALSE);
}
else
{
fcspi_slave_abort_transfer(eInst, FCSPI_FALSE);
}
eRet = FCSPI_STATUS_TRANSFER_FAIL;
}
}
else
{
eRet = tStatus;
}
}
}
else
{
eRet = FCSPI_STATUS_SUCCESS;
}
}
else
{
eRet = FCSPI_STATUS_PARAM_ERR;
}
return eRet;
}
static FCSPI_StatusType fcspi_master_trigger(
FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInIsr)
{
uint32_t u32StatusRegValue;
FCSPI_StatusType eRet = FCSPI_STATUS_TRIGGER_OK;
/* if an error is detected the transfer will be aborted */
u32StatusRegValue = FCSPI_HWA_GetStatus(s_atFCSpiInfo[eInst].tFCSpiInstance);
/* if tx need more data but hungry, and has data, sth wrong */
if (FCSpi_Hw_ChkTxFifoUnderrun(u32StatusRegValue) &&
(NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff))
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_TX_FAIL;
fcspi_master_abort_transfer(eInst, bIsInIsr);
eRet = FCSPI_STATUS_TRIGGER_ABORT_TX_FAIL;
}
/* if rx need more space but overflow, and has space to store, sth wrong */
else if (FCSpi_Hw_ChkRxFifoOverflow(u32StatusRegValue) &&
(NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pbyRxBuff))
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_RX_FAIL;
fcspi_master_abort_transfer(eInst, bIsInIsr);
eRet = FCSPI_STATUS_TRIGGER_ABORT_RX_FAIL;
}
/* rx data ready */
else
{
if (FCSpi_Hw_ChkRxGreaterThanWater(u32StatusRegValue))
{
if ((uint16_t)0 != s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet)
{
fcspi_read_rx_fifo(eInst);
}
}
/* transmit some, need add more */
if (FCSpi_Hw_ChkTxEqualOrLessThanWater(u32StatusRegValue))
{
if ((uint16_t)0 != s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend)
{
fcspi_write_tx_fifo(eInst);
}
}
if ((uint16_t)0 == s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend)
{
/* disable tx interrupt. enable tx completion interrupt.*/
FCSpi_Hw_DisableTransmitDataInterrupt(eInst);
FCSpi_Hw_EnableTransmitCompleteInterrupt(eInst);
/* tx finish first, if rx also finish, just check completion */
if ((uint16_t)0 == s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet)
{
u32StatusRegValue = FCSPI_HWA_GetStatus(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (FCSpi_Hw_ChkTransferComplete(u32StatusRegValue))
{
fcspi_master_clean_transfer(eInst, bIsInIsr);
eRet = FCSPI_STATUS_TRIGGER_FINISH;
}
}
}
}
return eRet;
}
/******************************************************************************/
static void fcspi_slave_clean_transfer(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInInterrupt)
{
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_FALSE;
if (FCSPI_TRANSFER_TRIGGER_SRC_DMA_ISR == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc)
{
FCSpi_Hw_SetRxTxDmaEnableStatus(eInst, FCSPI_FALSE, FCSPI_FALSE);
}
else
{
FCSpi_Hw_DisableSomeInterrupts(eInst, FCSPI_INT_EN_RFIE(1) | FCSPI_INT_EN_TFIE(1));
}
FCSpi_Hw_DisableSomeInterrupts(eInst, FCSPI_INT_EN_RFOIE(1) | FCSPI_INT_EN_TFUIE(1));
FCSpi_Hw_ClearSomeStatusW1CFlag(eInst, FCSPI_STATUS_RX_FO(1) | FCSPI_STATUS_TX_FU(1));
if (FCSPI_TRUE == bIsInInterrupt)
{
if (NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb(eInst, FCSPI_TRUE);
}
if (s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaPostCb(eInst, FCSPI_TRUE);
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
}
}
else
{
if (NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb(eInst, FCSPI_FALSE);
}
if (s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaPostCb(eInst, FCSPI_FALSE);
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
}
}
}
static void fcspi_slave_abort_transfer(FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInInterrupt)
{
fcspi_slave_clean_transfer(eInst, bIsInInterrupt);
FCSpi_Hw_Reset(eInst, FCSPI_TRUE, FCSPI_TRUE, FCSPI_FALSE);
FCSpi_Hw_Reset(eInst, FCSPI_TRUE, FCSPI_TRUE, FCSPI_FALSE); /* for shifter */
}
/**
* @brief Init the FCSpi instance as spi slave side
*
* @param eInst Which FCSpi Hardware instance
* @param pCfg Configuration of the FCSpi
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when configure successfully. Others, some error occur.
*/
FCSPI_StatusType FCSPI_Slave_Init(const FCSPI_InstanceType eInst, const FCSPI_SlaveCfgType * pCfg)
{
FCSPI_TxRxCtrlType tTxRxCtrlCfg;
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
s_atFCSpiInfo[eInst].tFCSpiStat.eBitFirstOrder = pCfg->eBitFirstOrder;
s_atFCSpiInfo[eInst].tFCSpiStat.u16BitsPerFrame = pCfg->u16BitCountPerFrame;
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc = pCfg->eTransferTriggerSrc;
s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf = pCfg->tTriggerDmaInf;
s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb = pCfg->pStopNotifyCb;
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaResetCb = pCfg->pSemaResetCb;
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaTakeCb = pCfg->pSemaTakeCb;
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaPostCb = pCfg->pSemaPostCb;
s_atFCSpiInfo[eInst].tFCSpiStat.eSckPolarity = pCfg->eSckPolarity;
s_atFCSpiInfo[eInst].tFCSpiStat.eSckSamplePhase = pCfg->eSckSamplePhase;
s_atFCSpiInfo[eInst].tFCSpiStat.ePcs = pCfg->ePcs;
s_atFCSpiInfo[eInst].tFCSpiStat.ePcsPolarity = pCfg->ePcsPolarity;
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed =
(uint16_t)((s_atFCSpiInfo[eInst].tFCSpiStat.u16BitsPerFrame + (uint16_t)7) >> (uint16_t)3);
/* DMA use 4 bytes/frame. */
if ((uint16_t)3 == s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed = (uint16_t)4;
}
/* FCSPI require 4 bytes align when > 32bits. */
if (s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed > (uint16_t)4)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed = (uint16_t)
((((s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed + (uint16_t)3)) >> (uint16_t)2) << (uint16_t)2);
}
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_FALSE;
FCSpi_Hw_Reset(eInst, FCSPI_FALSE, FCSPI_FALSE, FCSPI_TRUE);
FCSPI_HWA_SetSlaveMode(s_atFCSpiInfo[eInst].tFCSpiInstance);
FCSpi_Hw_SetPcs_2_3_Mode(eInst, PCS2_3_PCS);
FCSpi_Hw_SetPin(eInst, SIN_INPUT_SOUT_OUTPUT, PINOUT_RETAIN_LAST);
/* set fifo size param */
s_atFCSpiInfo[eInst].tFCSpiStat.u8TxFifoSize = (uint8_t)FCSPI_DRV_TX_FIFO_WORD_CNT;
s_atFCSpiInfo[eInst].tFCSpiStat.u8RxFifoSize = (uint8_t)FCSPI_DRV_RX_FIFO_WORD_CNT;
s_atFCSpiInfo[eInst].tFCSpiStat.u32DmaDummyData = 0xFFu;
/* Set polarity */
FCSpi_Hw_SetOnePcsPolarity(eInst, pCfg->ePcs, pCfg->ePcsPolarity);
/* Write the TCR for this transfer */
tTxRxCtrlCfg.eSckPolarity = pCfg->eSckPolarity;
tTxRxCtrlCfg.eSckPhase = pCfg->eSckSamplePhase;
tTxRxCtrlCfg.ePrescalerValue = FCSPI_PRESCALE_1; /* not use */
tTxRxCtrlCfg.ePCSSelect = pCfg->ePcs;
tTxRxCtrlCfg.eBitFirstOrder = pCfg->eBitFirstOrder;
tTxRxCtrlCfg.eByteSwap = FCSPI_FALSE;
tTxRxCtrlCfg.eContTransEnable = FCSPI_FALSE; /* not use */
tTxRxCtrlCfg.eContCmdEnable = FCSPI_FALSE; /* not use */
tTxRxCtrlCfg.eRxDisable = FCSPI_FALSE;
tTxRxCtrlCfg.eTxDisable = FCSPI_FALSE;
tTxRxCtrlCfg.eTransferWidth = FCSPI_TRANSFER_1_BIT;
tTxRxCtrlCfg.u16FrameBitCnt = pCfg->u16BitCountPerFrame;
eRet = FCSpi_Hw_SetTRCR(eInst, &tTxRxCtrlCfg);
if (FCSPI_STATUS_SUCCESS == eRet)
{
FCSPI_HWA_ModuleEnable(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (FCSPI_TRANSFER_TRIGGER_SRC_USER_POLL != pCfg->eTransferTriggerSrc)
{
IntMgr_EnableInterrupt(s_atFCSpiInfo[eInst].eFCSpiIrq);
}
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
return eRet;
}
static void fcspi_slave_dma_rx_err_interrupt(FCSPI_InstanceType eInst)
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_RX_FAIL;
fcspi_slave_abort_transfer(eInst, FCSPI_TRUE);
}
static void fcspi_0_slave_dma_rx_err_interrupt(void)
{
fcspi_slave_dma_rx_err_interrupt(FCSPI_0);
}
static void fcspi_1_slave_dma_rx_err_interrupt(void)
{
fcspi_slave_dma_rx_err_interrupt(FCSPI_1);
}
static void fcspi_2_slave_dma_rx_err_interrupt(void)
{
fcspi_slave_dma_rx_err_interrupt(FCSPI_2);
}
static void fcspi_3_slave_dma_rx_err_interrupt(void)
{
fcspi_slave_dma_rx_err_interrupt(FCSPI_3);
}
static void fcspi_4_slave_dma_rx_err_interrupt(void)
{
fcspi_slave_dma_rx_err_interrupt(FCSPI_4);
}
static void fcspi_5_slave_dma_rx_err_interrupt(void)
{
fcspi_slave_dma_rx_err_interrupt(FCSPI_5);
}
static void fcspi_slave_dma_rx_finish_interrupt(FCSPI_InstanceType eInst)
{
fcspi_slave_abort_transfer(eInst, FCSPI_TRUE);
}
static void fcspi_0_slave_dma_rx_finish_interrupt(void)
{
fcspi_slave_dma_rx_finish_interrupt(FCSPI_0);
}
static void fcspi_1_slave_dma_rx_finish_interrupt(void)
{
fcspi_slave_dma_rx_finish_interrupt(FCSPI_1);
}
static void fcspi_2_slave_dma_rx_finish_interrupt(void)
{
fcspi_slave_dma_rx_finish_interrupt(FCSPI_2);
}
static void fcspi_3_slave_dma_rx_finish_interrupt(void)
{
fcspi_slave_dma_rx_finish_interrupt(FCSPI_3);
}
static void fcspi_4_slave_dma_rx_finish_interrupt(void)
{
fcspi_slave_dma_rx_finish_interrupt(FCSPI_4);
}
static void fcspi_5_slave_dma_rx_finish_interrupt(void)
{
fcspi_slave_dma_rx_finish_interrupt(FCSPI_5);
}
static void fcspi_slave_dma_tx_err_interrupt(FCSPI_InstanceType eInst)
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_TX_FAIL;
fcspi_slave_abort_transfer(eInst, FCSPI_TRUE);
}
static void fcspi_0_slave_dma_tx_err_interrupt(void)
{
fcspi_slave_dma_tx_err_interrupt(FCSPI_0);
}
static void fcspi_1_slave_dma_tx_err_interrupt(void)
{
fcspi_slave_dma_tx_err_interrupt(FCSPI_1);
}
static void fcspi_2_slave_dma_tx_err_interrupt(void)
{
fcspi_slave_dma_tx_err_interrupt(FCSPI_2);
}
static void fcspi_3_slave_dma_tx_err_interrupt(void)
{
fcspi_slave_dma_tx_err_interrupt(FCSPI_3);
}
static void fcspi_4_slave_dma_tx_err_interrupt(void)
{
fcspi_slave_dma_tx_err_interrupt(FCSPI_4);
}
static void fcspi_5_slave_dma_tx_err_interrupt(void)
{
fcspi_slave_dma_tx_err_interrupt(FCSPI_5);
}
static void fcspi_slave_dma_tx_finish_interrupt(FCSPI_InstanceType eInst)
{
fcspi_slave_abort_transfer(eInst, FCSPI_TRUE);
}
static void fcspi_0_slave_dma_tx_finish_interrupt(void)
{
fcspi_slave_dma_tx_finish_interrupt(FCSPI_0);
}
static void fcspi_1_slave_dma_tx_finish_interrupt(void)
{
fcspi_slave_dma_tx_finish_interrupt(FCSPI_1);
}
static void fcspi_2_slave_dma_tx_finish_interrupt(void)
{
fcspi_slave_dma_tx_finish_interrupt(FCSPI_2);
}
static void fcspi_3_slave_dma_tx_finish_interrupt(void)
{
fcspi_slave_dma_tx_finish_interrupt(FCSPI_3);
}
static void fcspi_4_slave_dma_tx_finish_interrupt(void)
{
fcspi_slave_dma_tx_finish_interrupt(FCSPI_4);
}
static void fcspi_5_slave_dma_tx_finish_interrupt(void)
{
fcspi_slave_dma_tx_finish_interrupt(FCSPI_5);
}
static FCSPI_StatusType fcspi_slave_async_transfer_bytes(FCSPI_InstanceType eInst,
const uint8_t *pSendBuffer, uint8_t *pReceiveBuffer, uint16_t u16TransferByteCnt)
{
DMA_InterruptCfgType tDmaTxInterruptCfg = {0};
DMA_ChannelCfgType tDmaTxChnlCfg = {0};
uint8_t u8DmaTxBlkByteCnt = (uint8_t)1;
DMA_InterruptCfgType tDmaRxInterruptCfg = {0};
DMA_ChannelCfgType tDmaRxChnlCfg = {0};
uint8_t u8DmaRxBlkByteCnt = (uint8_t)1;
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
if ((NULL == pSendBuffer) && (NULL == pReceiveBuffer))
{
eRet = FCSPI_STATUS_ERROR;
}
else if ((uint16_t)0 == s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed)
{
eRet = FCSPI_STATUS_ERROR;
}
else if ((uint16_t)0 == u16TransferByteCnt)
{
eRet = FCSPI_STATUS_NO_DATA;
}
else if ((uint16_t)0 != (u16TransferByteCnt % s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed))
{
eRet = FCSPI_STATUS_ERROR;
}
else if (FCSPI_TRUE == s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer)
{
eRet = FCSPI_STATUS_BUSY;
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_OK;
FCSpi_Hw_Reset(eInst, FCSPI_TRUE, FCSPI_TRUE, FCSPI_FALSE);
FCSpi_Hw_Reset(eInst, FCSPI_TRUE, FCSPI_TRUE, FCSPI_FALSE); /* for shifter */
FCSpi_Hw_ClearSomeStatusW1CFlag(eInst, FCSPI_DRV_STATUS_REG_W1C_U32);
/* in slave mode, rx and tx all enabled */
FCSpi_Hw_EnableMoreInterrupts(eInst, FCSPI_INT_EN_TFUIE(1) | FCSPI_INT_EN_RFOIE(1));
s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff = pSendBuffer;
s_atFCSpiInfo[eInst].tFCSpiStat.pbyRxBuff = pReceiveBuffer;
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxIndex = (uint16_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxIndex = (uint16_t)0;
if (FCSPI_TRANSFER_TRIGGER_SRC_DMA_ISR == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc)
{
FCSPI_HWA_SetWatermark(s_atFCSpiInfo[eInst].tFCSpiInstance, (uint8_t)0, (uint8_t)3);
/* TX */
tDmaTxChnlCfg.u8ChannelPriority = s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8TxDMAChannelPriority;
tDmaTxChnlCfg.bDestAddrLoopbackEn = false;
tDmaTxChnlCfg.bSrcAddrLoopbackEn = false;
tDmaTxChnlCfg.bAutoStop = true; /* auto stop dma after send finish */
tDmaTxChnlCfg.bSrcCircularBufferEn = false;
tDmaTxChnlCfg.bDestCircularBufferEn = false;
switch (s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed)
{
case 1:
tDmaTxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_1B;
tDmaTxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_1B;
tDmaTxChnlCfg.bSrcBlockOffsetEn = true;
tDmaTxChnlCfg.s32BlockOffset = (int32_t)1;
u8DmaTxBlkByteCnt = (uint8_t)1;
break;
case 2:
tDmaTxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_2B;
tDmaTxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_2B;
tDmaTxChnlCfg.bSrcBlockOffsetEn = true;
tDmaTxChnlCfg.s32BlockOffset = (int32_t)2;
u8DmaTxBlkByteCnt = (uint8_t)2;
break;
default:
tDmaTxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_4B;
tDmaTxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_4B;
tDmaTxChnlCfg.bSrcBlockOffsetEn = true;
tDmaTxChnlCfg.s32BlockOffset = (int32_t)4;
u8DmaTxBlkByteCnt = (uint8_t)4;
break;
}
tDmaTxChnlCfg.u16BlockCount = u16TransferByteCnt / u8DmaTxBlkByteCnt;
tDmaTxChnlCfg.bDestBlockOffsetEn = false;
tDmaTxInterruptCfg.bTransferCompleteIntEn = true;
tDmaTxInterruptCfg.bTransferErrorIntEn = true;
switch (eInst)
{
case FCSPI_0:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI0_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_0_slave_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_0_slave_dma_tx_err_interrupt;
break;
case FCSPI_1:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI1_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_1_slave_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_1_slave_dma_tx_err_interrupt;
break;
case FCSPI_2:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI2_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_2_slave_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_2_slave_dma_tx_err_interrupt;
break;
case FCSPI_3:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI3_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_3_slave_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_3_slave_dma_tx_err_interrupt;
break;
case FCSPI_4:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI4_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_4_slave_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_4_slave_dma_tx_err_interrupt;
break;
case FCSPI_5:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI5_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_5_slave_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_5_slave_dma_tx_err_interrupt;
break;
default:
tDmaTxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI3_TX;
tDmaTxInterruptCfg.pTransferCompleteNotify = fcspi_3_slave_dma_tx_finish_interrupt;
tDmaTxInterruptCfg.pTransferErrorNotify = fcspi_3_slave_dma_tx_err_interrupt;
break;
}
tDmaTxChnlCfg.eDestIncMode = DMA_INCREMENT_DISABLE;
tDmaTxChnlCfg.eSrcIncMode = DMA_INCREMENT_DISABLE;
tDmaTxChnlCfg.pDestBuffer = FCSPI_HWA_GetTxDataAddr(s_atFCSpiInfo[eInst].tFCSpiInstance);
tDmaTxChnlCfg.u32BlockSize = (uint32_t)u8DmaTxBlkByteCnt;
if (NULL != pSendBuffer)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend = u16TransferByteCnt;
tDmaTxChnlCfg.pSrcBuffer = pSendBuffer;
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend = (uint16_t)0;
tDmaTxChnlCfg.bSrcBlockOffsetEn = false; /* if send buffer is NULL, just send dummy data, MUST fix the source to the dummy variable */
tDmaTxChnlCfg.s32BlockOffset = (int32_t)0;
tDmaTxChnlCfg.pSrcBuffer = &(s_atFCSpiInfo[eInst].tFCSpiStat.u32DmaDummyData);
}
DMA_InitChannel(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8TxDMAChannel, &tDmaTxChnlCfg);
/* RX */
tDmaRxChnlCfg.u8ChannelPriority = s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8RxDMAChannelPriority;
tDmaRxChnlCfg.bDestAddrLoopbackEn = false;
tDmaRxChnlCfg.bSrcAddrLoopbackEn = false;
tDmaRxChnlCfg.bAutoStop = true; /* auto stop dma after send finish */
tDmaRxChnlCfg.bSrcCircularBufferEn = false;
tDmaRxChnlCfg.bDestCircularBufferEn = false;
switch (s_atFCSpiInfo[eInst].tFCSpiStat.u16BytesCntFrameNeed)
{
case 1:
tDmaRxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_1B;
tDmaRxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_1B;
tDmaRxChnlCfg.bDestBlockOffsetEn = true;
tDmaRxChnlCfg.s32BlockOffset = (int32_t)1;
u8DmaRxBlkByteCnt = (uint8_t)1;
break;
case 2:
tDmaRxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_2B;
tDmaRxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_2B;
tDmaRxChnlCfg.bDestBlockOffsetEn = true;
tDmaRxChnlCfg.s32BlockOffset = (int32_t)2;
u8DmaRxBlkByteCnt = (uint8_t)2;
break;
default:
tDmaRxChnlCfg.eDestDataSize = DMA_TRANSFER_SIZE_4B;
tDmaRxChnlCfg.eSrcDataSize = DMA_TRANSFER_SIZE_4B;
tDmaRxChnlCfg.bDestBlockOffsetEn = true;
tDmaRxChnlCfg.s32BlockOffset = (int32_t)4;
u8DmaRxBlkByteCnt = (uint8_t)4;
break;
}
tDmaRxChnlCfg.u16BlockCount = u16TransferByteCnt / u8DmaRxBlkByteCnt;
tDmaRxChnlCfg.bSrcBlockOffsetEn = false;
tDmaRxInterruptCfg.bTransferCompleteIntEn = true;
tDmaRxInterruptCfg.bTransferErrorIntEn = true;
switch (eInst)
{
case FCSPI_0:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI0_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_0_slave_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_0_slave_dma_rx_err_interrupt;
break;
case FCSPI_1:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI1_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_1_slave_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_1_slave_dma_rx_err_interrupt;
break;
case FCSPI_2:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI2_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_2_slave_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_2_slave_dma_rx_err_interrupt;
break;
case FCSPI_3:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI3_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_3_slave_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_3_slave_dma_rx_err_interrupt;
break;
case FCSPI_4:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI4_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_4_slave_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_4_slave_dma_rx_err_interrupt;
break;
case FCSPI_5:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI5_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_5_slave_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_5_slave_dma_rx_err_interrupt;
break;
default:
tDmaRxChnlCfg.eTriggerSrc = DMA_REQ_FCSPI3_RX;
tDmaRxInterruptCfg.pTransferCompleteNotify = fcspi_3_slave_dma_rx_finish_interrupt;
tDmaRxInterruptCfg.pTransferErrorNotify = fcspi_3_slave_dma_rx_err_interrupt;
break;
}
tDmaRxChnlCfg.eSrcIncMode = DMA_INCREMENT_DISABLE;
tDmaRxChnlCfg.eDestIncMode = DMA_INCREMENT_DISABLE;
tDmaRxChnlCfg.pSrcBuffer = FCSPI_HWA_GetRxDataAddr(s_atFCSpiInfo[eInst].tFCSpiInstance);
tDmaRxChnlCfg.u32BlockSize = (uint32_t)u8DmaRxBlkByteCnt;
if (NULL != pReceiveBuffer)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet = u16TransferByteCnt;
tDmaRxChnlCfg.pDestBuffer = pReceiveBuffer;
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet = (uint16_t)0;
tDmaRxChnlCfg.bDestBlockOffsetEn = false;
tDmaRxChnlCfg.s32BlockOffset = (int32_t)0;
tDmaRxChnlCfg.pDestBuffer = &(s_atFCSpiInfo[eInst].tFCSpiStat.u32DmaDummyData);
}
DMA_InitChannel(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8RxDMAChannel, &tDmaRxChnlCfg);
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_TRUE;
DMA_InitChannelInterrupt(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8RxDMAChannel, &tDmaRxInterruptCfg);
DMA_InitChannelInterrupt(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8TxDMAChannel, &tDmaTxInterruptCfg);
DMA_StartChannel(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8RxDMAChannel);
DMA_StartChannel(s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.eDMAInstance,
(DMA_ChannelType)s_atFCSpiInfo[eInst].tFCSpiStat.tTriggerDmaInf.u8TxDMAChannel);
FCSpi_Hw_SetRxTxDmaEnableStatus(eInst, FCSPI_TRUE, FCSPI_TRUE);
}
else
{
FCSPI_HWA_SetWatermark(s_atFCSpiInfo[eInst].tFCSpiInstance, (uint8_t)0, (uint8_t)2);
if (NULL == s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend = (uint16_t)0;
FCSPI_HWA_EnableTxDataMask(s_atFCSpiInfo[eInst].tFCSpiInstance, FCSPI_FALSE);
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend = u16TransferByteCnt;
FCSPI_HWA_EnableTxDataMask(s_atFCSpiInfo[eInst].tFCSpiInstance, FCSPI_TRUE);
}
if (NULL == s_atFCSpiInfo[eInst].tFCSpiStat.pbyRxBuff)
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet = (uint16_t)0;
FCSPI_HWA_EnableRxDataMask(s_atFCSpiInfo[eInst].tFCSpiInstance, FCSPI_FALSE);
}
else
{
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet = u16TransferByteCnt;
FCSPI_HWA_EnableRxDataMask(s_atFCSpiInfo[eInst].tFCSpiInstance, FCSPI_TRUE);
}
s_atFCSpiInfo[eInst].tFCSpiStat.u16RxGetByteCntOfCurFrame = (uint16_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.u16TxSendByteCntOfCurFrame = (uint16_t)0;
s_atFCSpiInfo[eInst].tFCSpiStat.eIsPcsContinuous = FCSPI_FALSE;
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_TRUE;
if (NULL != pReceiveBuffer) /* need rx fifo */
{
FCSpi_Hw_EnableMoreInterrupts(eInst, FCSPI_INT_EN_RFIE(1));
}
if (NULL != pSendBuffer)
{
FCSpi_Hw_EnableMoreInterrupts(eInst, FCSPI_INT_EN_TFIE(1));
}
}
}
return eRet;
}
static FCSPI_StatusType fcspi_slave_trigger(
FCSPI_InstanceType eInst, FCSPI_AtomicBoolType bIsInISR)
{
uint32_t u32StatusRegValue;
uint16_t u16RemainTx = (uint16_t)0;
uint16_t u16RemainRx = (uint16_t)0;
FCSPI_StatusType eRet = FCSPI_STATUS_TRIGGER_OK;
/* If an error is detected the transfer will be aborted */
u32StatusRegValue = FCSPI_HWA_GetStatus(s_atFCSpiInfo[eInst].tFCSpiInstance);
if (FCSpi_Hw_ChkTxFifoUnderrun(u32StatusRegValue) &&
(NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pbyTxBuff))
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_TX_FAIL;
fcspi_slave_abort_transfer(eInst, bIsInISR);
eRet = FCSPI_STATUS_TRIGGER_ABORT_TX_FAIL;
}
else if (FCSpi_Hw_ChkRxFifoOverflow(u32StatusRegValue) &&
(NULL != s_atFCSpiInfo[eInst].tFCSpiStat.pbyRxBuff))
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_RX_FAIL;
fcspi_slave_abort_transfer(eInst, bIsInISR);
eRet = FCSPI_STATUS_TRIGGER_ABORT_RX_FAIL;
}
/* rx data ready */
else
{
if (FCSpi_Hw_ChkRxGreaterThanWater(u32StatusRegValue))
{
if ((uint16_t)0 != s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet)
{
fcspi_read_rx_fifo(eInst);
}
}
/* transmit some, need add more */
if (FCSpi_Hw_ChkTxEqualOrLessThanWater(u32StatusRegValue))
{
if ((uint16_t)0 != s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend)
{
fcspi_write_tx_fifo(eInst);
}
}
if ((uint16_t)0 == s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend)
{
/* Disable TX flag. Software buffer is empty.*/
FCSpi_Hw_DisableTransmitDataInterrupt(eInst);
}
if ((uint16_t)0 == s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet)
{
FCSpi_Hw_DisableReceiveDataInterrupt(eInst);
}
u16RemainTx = s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend;
u16RemainRx = s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet;
if (((uint16_t)0 == u16RemainTx) && ((uint16_t)0 == u16RemainRx))
{
FCSpi_Hw_DisableSomeInterrupts(eInst, FCSPI_INT_EN_RFOIE(1) | FCSPI_INT_EN_TFUIE(1));
if (s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pStopNotifyCb(eInst, bIsInISR);
}
if (s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore)
{
s_atFCSpiInfo[eInst].tFCSpiStat.pSemaPostCb(eInst, bIsInISR);
s_atFCSpiInfo[eInst].tFCSpiStat.u8WaitSemaphore = (uint8_t)0;
}
s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer = FCSPI_FALSE;
eRet = FCSPI_STATUS_TRIGGER_FINISH;
}
}
return eRet;
}
/*----------------------------------------------------------------------------*/
/**
* @brief If it's in transfer, get its stat, or get the last transfer's stat.
*
* @param eInst Which FCSpi Hardware instance
* @param pCfg the transfer information, can be null
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when the last transfer is finish successfully. Others, busy or error occur.
*/
FCSPI_StatusType FCSPI_GetLatestTransferStat(const FCSPI_InstanceType eInst, FCSPI_TransferRemainInfType *pCfg)
{
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
if (NULL != pCfg)
{
pCfg->u32ByteCountReceiveRemained = s_atFCSpiInfo[eInst].tFCSpiStat.u16RxByteCntRemainToGet;
pCfg->u32ByteCountSendRemained = s_atFCSpiInfo[eInst].tFCSpiStat.u16TxByteCntRemainToSend;
}
if (FCSPI_TRANSFER_OK != s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat)
{
eRet = FCSPI_STATUS_ERROR;
}
else if (FCSPI_TRUE == s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer)
{
eRet = FCSPI_STATUS_BUSY;
}
else
{
eRet = FCSPI_STATUS_SUCCESS;
}
return eRet;
}
#ifdef FCSPI_DRV_INTERNAL_FUNC_EN
/**
* @brief Trigger the driver to transfer data when select FCSPI_TRANSFER_TRIGGER_SRC_USER_POLL
*
* @param eInst Which FCSpi Hardware instance
* @return FCSPI_StatusType FCSPI_STATUS_TRIGGER_OK when api trigger successfully, FCSPI_STATUS_TRIGGER_FINISH when all data transfer finish. Others, error happen.
*/
FCSPI_StatusType FCSPI_PollTrigger(FCSPI_InstanceType eInst)
{
FCSPI_StatusType eRet = FCSPI_STATUS_TRIGGER_OK;
if (FCSPI_TRANSFER_TRIGGER_SRC_USER_POLL == s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc)
{
if (FCSPI_TRUE == s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer)
{
if (FCSPI_MODE_MASTER == FCSPI_HWA_CheckMode(s_atFCSpiInfo[eInst].tFCSpiInstance))
{
eRet = fcspi_master_trigger(eInst, FCSPI_FALSE);
}
else
{
eRet = fcspi_slave_trigger(eInst, FCSPI_FALSE);
}
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
}
else
{
eRet = FCSPI_STATUS_ERROR;
}
return eRet;
}
#endif
/**
* @brief Select the trigger source(DMA with interrupt / interrupt / user poll)
*
* @param eInst Which FCSpi Hardware instance
* @param eSrc three source, 1) DMA move data between memory and registers, notified when finish by interrupt; 2) purely by interrupt; 3) purely by user poll.
* @return FCSPI_StatusType FCSPI_STATUS_SUCCESS when successfully. Others, error.
*/
FCSPI_StatusType FCSPI_SelectTriggerSrc(
FCSPI_InstanceType eInst, FCSPI_TriggerSrcType eSrc)
{
FCSPI_StatusType eRet = FCSPI_STATUS_SUCCESS;
uint32_t u32StatRegVal = 0u;
u32StatRegVal = FCSPI_HWA_GetStatus(s_atFCSpiInfo[eInst].tFCSpiInstance);
if ((FCSPI_TRUE != s_atFCSpiInfo[eInst].tFCSpiStat.eIsInTransfer) &&
(!FCSpi_Hw_ChkBusy(u32StatRegVal)))
{
switch (eSrc)
{
case FCSPI_TRANSFER_TRIGGER_SRC_ISR:
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc = eSrc;
break;
case FCSPI_TRANSFER_TRIGGER_SRC_DMA_ISR:
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc = eSrc;
break;
case FCSPI_TRANSFER_TRIGGER_SRC_USER_POLL:
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc = eSrc;
break;
default:
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferTriggerSrc = eSrc;
break;
}
}
else
{
eRet = FCSPI_STATUS_BUSY;
}
return eRet;
}
/**
* @brief Abort current transfer if exist, or just recovery the hardware.
*
* @param eInst Which FCSpi Hardware instance
*/
void FCSPI_AbortTransfer(const FCSPI_InstanceType eInst)
{
s_atFCSpiInfo[eInst].tFCSpiStat.eTransferStat = FCSPI_TRANSFER_ABORT;
if (FCSPI_MODE_MASTER == FCSPI_HWA_CheckMode(s_atFCSpiInfo[eInst].tFCSpiInstance))
{
fcspi_master_abort_transfer(eInst, FCSPI_FALSE);
}
else
{
fcspi_slave_abort_transfer(eInst, FCSPI_FALSE);
}
}
static void fcspi_irq_handler(FCSPI_InstanceType eInst)
{
if (FCSPI_MODE_MASTER == FCSPI_HWA_CheckMode(s_atFCSpiInfo[eInst].tFCSpiInstance))
{
fcspi_master_trigger(eInst, FCSPI_TRUE);
}
else
{
fcspi_slave_trigger(eInst, FCSPI_TRUE);
}
}
/**
* @brief fcspi 0 interrupt handler
*
* @note This function should be called as/in FCSPI 0 interrupt handler
*/
void FCSPI0_IRQHandler(void)
{
fcspi_irq_handler(FCSPI_0);
}
/**
* @brief fcspi 1 interrupt handler
*
* @note This function should be called as/in FCSPI 1 interrupt handler
*/
void FCSPI1_IRQHandler(void)
{
fcspi_irq_handler(FCSPI_1);
}
/**
* @brief fcspi 2 interrupt handler
*
* @note This function should be called as/in FCSPI 2 interrupt handler
*/
void FCSPI2_IRQHandler(void)
{
fcspi_irq_handler(FCSPI_2);
}
/**
* @brief fcspi 3 interrupt handler
*
* @note This function should be called as/in FCSPI 3 interrupt handler
*/
void FCSPI3_IRQHandler(void)
{
fcspi_irq_handler(FCSPI_3);
}
/**
* @brief fcspi 4 interrupt handler
*
* @note This function should be called as/in FCSPI 4 interrupt handler
*/
void FCSPI4_IRQHandler(void)
{
fcspi_irq_handler(FCSPI_4);
}
/**
* @brief fcspi 5 interrupt handler
*
* @note This function should be called as/in FCSPI 5 interrupt handler
*/
void FCSPI5_IRQHandler(void)
{
fcspi_irq_handler(FCSPI_5);
}