Tool/software:
Hi, Ti,
I want to use SPI Master and Slave with DMA.
For this, I desigend SPI1 Master only and SPI3 Slave only.
Master function is no problem, but SPI3 Slave only function, it has a problem.
I intented to this function should be working without tx dummy, because some examples from e2e I couldn't see dummy tx.
so I need you cofirm my codes attatche.
Also here is my H/W connection. additionally I'm not using ENA control signal.
#include "ChComm.h" spiDAT1_t g_stSpi1Fmt = { .CS_HOLD = FALSE, .DFSEL = SPI_FMT_0, .WDEL = 0U, .CSNR = SPI_CS_1 /* 0xFD */ }; spiDAT1_t g_stSpi3Fmt = { .CS_HOLD = FALSE, .DFSEL = SPI_FMT_0, .WDEL = 0U, .CSNR = SPI_CS_0 /* 0xFE */ }; static uint8 g_aTxData[1024] = {0,}; static uint8 g_aRxData[1024] = {0,}; static uint16 g_aTxDat1[ SPI_WORDS_FROM_BYTES(SPI_MAX_BYTES) ]; static uint16 g_aRxBuf[ SPI_WORDS_FROM_BYTES(SPI_MAX_BYTES) ] = {0,}; static g_dmaCTRL g_stTxSpiDmaCtrlPkt; static g_dmaCTRL g_stRxSpiDmaCtrlPkt; static uint32 g_nRxCnt = 0U; uint32 nLen = 1001U; void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel) { uint32 nTimeout = 10000000U; uint32 nStatus = 0; switch (channel) { case DMA_CH_SPI1_TX: if(inttype == BTC) { SPI1_TX->INT0 &= ~((uint32)SPI_INT_TX_DMA_EN); dmaREG->BTCFLAG = (uint32)(1U << DMA_CH_SPI1_TX); dmaREG->HBCFLAG = (uint32)(1U << DMA_CH_SPI1_TX); } break; case DMA_CH_SPI3_TX: if(inttype == BTC) { SPI3_TX->INT0 &= ~((uint32)SPI_INT_TX_DMA_EN); dmaREG->BTCFLAG = (uint32)(1U << DMA_CH_SPI3_TX); dmaREG->HBCFLAG = (uint32)(1U << DMA_CH_SPI3_TX); } break; case DMA_CH_SPI3_RX: if(inttype == BTC) { // while (dmaGetInterruptStatus(DMA_CH_SPI3_RX, BTC) == 0U) { } SPI3_RX->INT0 &= ~(uint32)SPI_DMA_REQ_EN; dmaREG->BTCFLAG = (uint32)(1U << DMA_CH_SPI3_RX); dmaREG->HBCFLAG = (uint32)(1U << DMA_CH_SPI3_RX); Spi3RxFinalize(g_aRxData, nLen); // NotifyChCommStatus(); } break; } return; } static void PackBytesToWords16(const uint8 *pIn, uint32 nLen, uint16 *pOut16, uint32 *pOutWords) { uint32 nWordCnt = 0U; for (uint32 i = 0U; i < nLen; i += 2U) { uint16 nHi = pIn[i]; uint16 nLo = (i + 1U < nLen) ? pIn[i + 1U] : 0U; pOut16[nWordCnt++] = (uint16)((nHi << 8) | nLo); /* MSB-first */ } *pOutWords = nWordCnt; return; } static void UnpackWords16ToBytes(const uint16 *pIn16, uint32 nWords, uint8 *pOut, uint32 nLenBytes) { uint32 nPos = 0U; for (uint32 i = 0U; i < nWords; ++i) { if (nPos < nLenBytes) { pOut[nPos++] = (uint8)((pIn16[i] >> 8) & 0xFFU); } /* MSB */ if (nPos < nLenBytes) { pOut[nPos++] = (uint8)( pIn16[i] & 0xFFU); } /* LSB */ } return; } static void dmaConfigCtrlTxPacket (uint32 nSrcAddr, uint32 nDestAddr, uint16 nElmntCnt, uint16 nFrameCnt) { /* - configuring dma control packets */ g_stTxSpiDmaCtrlPkt.SADD = nSrcAddr; g_stTxSpiDmaCtrlPkt.DADD = nDestAddr; g_stTxSpiDmaCtrlPkt.CHCTRL = 0; g_stTxSpiDmaCtrlPkt.FRCNT = nFrameCnt; //1000 g_stTxSpiDmaCtrlPkt.ELCNT = nElmntCnt; //1 g_stTxSpiDmaCtrlPkt.ELDOFFSET = 0; g_stTxSpiDmaCtrlPkt.ELSOFFSET = 0; g_stTxSpiDmaCtrlPkt.FRDOFFSET = 0; g_stTxSpiDmaCtrlPkt.FRSOFFSET = 0; g_stTxSpiDmaCtrlPkt.PORTASGN = PORTA_READ_PORTB_WRITE; g_stTxSpiDmaCtrlPkt.RDSIZE = ACCESS_16_BIT; g_stTxSpiDmaCtrlPkt.WRSIZE = ACCESS_16_BIT; g_stTxSpiDmaCtrlPkt.TTYPE = FRAME_TRANSFER; g_stTxSpiDmaCtrlPkt.ADDMODERD = ADDR_INC1; g_stTxSpiDmaCtrlPkt.ADDMODEWR = ADDR_FIXED; g_stTxSpiDmaCtrlPkt.AUTOINIT = AUTOINIT_OFF; return; } static void dmaConfigCtrlRxPacket (uint32 nSrcAddr, uint32 nDestAddr, uint16 nElmntCnt, uint16 nFrameCnt) { /* - configuring dma control packets */ g_stRxSpiDmaCtrlPkt.SADD = nSrcAddr; g_stRxSpiDmaCtrlPkt.DADD = nDestAddr; g_stRxSpiDmaCtrlPkt.CHCTRL = 0; g_stRxSpiDmaCtrlPkt.FRCNT = nFrameCnt; g_stRxSpiDmaCtrlPkt.ELCNT = nElmntCnt; g_stRxSpiDmaCtrlPkt.ELDOFFSET = 0; g_stRxSpiDmaCtrlPkt.ELSOFFSET = 0; g_stRxSpiDmaCtrlPkt.FRDOFFSET = 0; g_stRxSpiDmaCtrlPkt.FRSOFFSET = 0; g_stRxSpiDmaCtrlPkt.PORTASGN = PORTB_READ_PORTA_WRITE; g_stRxSpiDmaCtrlPkt.RDSIZE = ACCESS_16_BIT; g_stRxSpiDmaCtrlPkt.WRSIZE = ACCESS_16_BIT; g_stRxSpiDmaCtrlPkt.TTYPE = FRAME_TRANSFER; g_stRxSpiDmaCtrlPkt.ADDMODERD = ADDR_FIXED; g_stRxSpiDmaCtrlPkt.ADDMODEWR = ADDR_INC1; g_stRxSpiDmaCtrlPkt.AUTOINIT = AUTOINIT_OFF; return; } /* DMA: SPI1 TX (Source=DAT1[], Dest=&SPI1_TX->DAT1) */ static void SpiDmaTxConfig(uint16 *pSrcDat1, uint32 nWordLen, dmaChannel_t eDmaChannel) { dmaChannel_t nCh = (eDmaChannel == DMA_CH_SPI1_TX) ? DMA_CH_SPI1_TX : DMA_CH_SPI3_TX; uint32 nDst = (eDmaChannel == DMA_CH_SPI1_TX) ? SPI1_DMA_TX_ADDR : SPI3_DMA_TX_ADDR; volatile spiBASE_t *pSpiTx = (eDmaChannel == DMA_CH_SPI1_TX) ? SPI1_TX : SPI3_TX; dmaREG->BTCFLAG = (uint32)(1U << nCh); dmaREG->HBCFLAG = (uint32)(1U << nCh); dmaConfigCtrlTxPacket((uint32)pSrcDat1, nDst, 1, (uint16)nWordLen); dmaSetCtrlPacket(nCh, g_stTxSpiDmaCtrlPkt); pSpiTx->INT0 |= (uint32)SPI_INT_TX_DMA_EN; dmaSetChEnable(nCh, DMA_HW); return; } /* DMA: SPI3 RX (Source=&SPI3_RX->BUF, Dest=g_aRxBuf[]) */ static void SpiDmaRxConfig(uint16 *pDestBuf, uint16 nWordLen) { dmaREG->BTCFLAG = (uint32)(1U << DMA_CH_SPI3_RX); dmaREG->FTCFLAG = (uint32)(1U << DMA_CH_SPI3_RX); dmaConfigCtrlRxPacket(SPI3_DMA_RX_ADDR, (uint32)pDestBuf, 1, nWordLen); dmaSetCtrlPacket(DMA_CH_SPI3_RX, g_stRxSpiDmaCtrlPkt); //Src: SPI->BUF, Dest: Variable // SPI3_RX->INT0 |= ((uint32)SPI_INT_RX_DMA_EN); /* DMAREQEN=1 */ dmaSetChEnable(DMA_CH_SPI3_RX, DMA_HW); /* HW trigger by SPI3 RX */ return; } E_SPI_STATE_RESULT Spi3RxReady(uint32 nLen) { if (nLen == 0U || nLen > SPI_MAX_BYTES) { return eSPI_STATE_ERR_PARAM; } g_nRxCnt = SPI_WORDS_FROM_BYTES(nLen); /* RX DMA: SPI3_RX->BUF -> g_aRxBuf[] */ SpiDmaRxConfig(g_aRxBuf, g_nRxCnt); return eSPI_STATE_OK; } E_SPI_STATE_RESULT Spi3TxDummy(const uint8 *pData, uint32 nLen) { uint32 nWords = 0U; if (pData == NULL || nLen == 0U || nLen > SPI_MAX_BYTES) { return eSPI_STATE_ERR_PARAM; } PackBytesToWords16(pData, nLen, g_aTxDat1, &nWords); SpiDmaTxConfig(g_aTxDat1, nWords, DMA_CH_SPI3_TX); return eSPI_STATE_OK; } E_SPI_STATE_RESULT Spi1TxSend(const uint8 *pData, uint32 nLen) { uint32 nWords = 0U; if (pData == NULL || nLen == 0U || nLen > SPI_MAX_BYTES) { return eSPI_STATE_ERR_PARAM; } PackBytesToWords16(pData, nLen, g_aTxDat1, &nWords); SpiDmaTxConfig(g_aTxDat1, nWords, DMA_CH_SPI1_TX); return eSPI_STATE_OK; } E_SPI_STATE_RESULT Spi3RxFinalize(uint8 *pOut, uint32 nLen) { if (pOut == NULL || nLen == 0U || nLen > SPI_MAX_BYTES) { return eSPI_STATE_ERR_PARAM; } if (g_nRxCnt != SPI_WORDS_FROM_BYTES(nLen)) { return eSPI_STATE_ERR_PARAM; } UnpackWords16ToBytes((const uint16 *)g_aRxBuf, g_nRxCnt, pOut, nLen); return eSPI_STATE_OK; } void Spi3Init(void) { uint16 *pSpiCfg = (uint16 *)((uint32)(&SPI3_TX->DAT1)+2); *pSpiCfg = ( (uint16)(g_stSpi3Fmt.DFSEL << 8U) | (uint16)(g_stSpi3Fmt.CSNR << 0U) | (uint32)((g_stSpi3Fmt.WDEL) ? 0x0400U : 0 == 1 ? 0x0400U : 0U) | (uint32)((g_stSpi3Fmt.CS_HOLD) ? 0x1000U : 0 == 1 ? 0x0400U : 0U) ); dmaReqAssign(DMA_CH_SPI3_TX, DMA_REQ_SPI3_TX); dmaReqAssign(DMA_CH_SPI3_RX, DMA_REQ_SPI3_RX); dmaEnableInterrupt(DMA_CH_SPI3_TX, BTC, DMA_INTA); dmaEnableInterrupt(DMA_CH_SPI3_TX, HBC, DMA_INTA); dmaEnableInterrupt(DMA_CH_SPI3_RX, BTC, DMA_INTA); dmaEnableInterrupt(DMA_CH_SPI3_RX, HBC, DMA_INTA); SPI3_TX->INT0 &= ~(uint32)SPI_INT_TX_DMA_EN; SPI3_RX->INT0 &= ~(uint32)SPI_INT_RX_DMA_EN; //명시적 dmaREG->BTCFLAG = (1U << DMA_CH_SPI3_RX); dmaREG->HBCFLAG = (1U << DMA_CH_SPI3_RX); // dmaREG->BTCFLAG = ((1U << DMA_CH_SPI3_TX) | (1U << DMA_CH_SPI3_RX)); dmaREG->HBCFLAG = ((1U << DMA_CH_SPI3_TX) | (1U << DMA_CH_SPI3_RX)); return; } void Spi1Init(void) { uint16 *pSpiCfg = (uint16 *)((uint32)(&SPI1_TX->DAT1)+2); *pSpiCfg = ( (uint16)(g_stSpi1Fmt.DFSEL << 8U) | (uint16)(g_stSpi1Fmt.CSNR << 0U) | (uint32)((g_stSpi1Fmt.WDEL) ? 0x0400U : 0 == 1 ? 0x0400U : 0U) | (uint32)((g_stSpi1Fmt.CS_HOLD) ? 0x1000U : 0 == 1 ? 0x0400U : 0U) ); dmaReqAssign(DMA_CH_SPI1_TX, DMA_REQ_SPI1_TX); dmaEnableInterrupt(DMA_CH_SPI1_TX, BTC, DMA_INTA); dmaEnableInterrupt(DMA_CH_SPI1_TX, HBC, DMA_INTA); SPI1_TX->INT0 &= ~(uint32)SPI_INT_TX_DMA_EN; dmaREG->BTCFLAG = (1U << DMA_CH_SPI1_TX); dmaREG->HBCFLAG = (1U << DMA_CH_SPI1_TX); return; } uint8 bFlag = FALSE; void SpiCommInit(void) { dmaEnable(); if(bFlag == TRUE) { Spi1Init(); } else { Spi3Init(); } return; } void SpiCommTest(void) { spiInit(); SpiCommInit(); if(bFlag == TRUE) { while(1) { for (uint32 i = 0; i < nLen; ++i) { g_aTxData[i] = (uint8)(i & 0xFFU); } Spi1TxSend(g_aTxData, nLen); for (uint32 j = 0; j < 0x2000000; j++); } } else { // while(1) { Spi3RxReady(nLen); // for (uint32 j = 0; j < 0x2000000; j++); } (void)Spi3TxDummy(g_aTxData, nLen); Spi3RxFinalize(g_aRxData, nLen); } while(1); return; }
#ifndef __SPICOMM_H__ #define __SPICOMM_H__ #include "HL_sys_common.h" #include "HL_spi.h" #include "HL_sys_dma.h" #define SPI1_TX spiREG1 /* Master */ #define SPI3_TX spiREG3 /* Slave */ #define SPI3_RX spiREG3 #define DMA_CH_SPI1_TX DMA_CH0 #define DMA_CH_SPI3_TX DMA_CH1 #define DMA_CH_SPI3_RX DMA_CH2 #define DMA_REQ_SPI1_TX DMA_REQ1 #define DMA_REQ_SPI3_TX DMA_REQ15 #define DMA_REQ_SPI3_RX DMA_REQ14 #define SPI1_DMA_TX_ADDR ((uint32)(&(SPI1_TX->DAT1)) + 0) #define SPI3_DMA_TX_ADDR ((uint32)(&(SPI3_TX->DAT1)) + 0) #define SPI3_DMA_RX_ADDR ((uint32)(&(SPI3_RX->BUF)) + 0) #define SPI_GCR1_SPIEN (1U << 24) #define SPI_DMA_REQ_EN (1U << 16) #define SPI_INT_RX_DMA_EN SPI_DMA_REQ_EN #define SPI_INT_TX_DMA_EN SPI_DMA_REQ_EN #define SPI_MAX_BYTES (1024U) #define SPI_WORDS_FROM_BYTES(nBytes) (((nBytes) + 1U) / 2U) typedef enum __eSPI_STATE_RESULT { eSPI_STATE_OK = 0, eSPI_STATE_ERR_PARAM, eSPI_STATE_ERR_BUSY, eSPI_STATE_ERR_TIMEOUT, eSPI_STATE_ERR_DMA, eSPI_STATE_ERR_MISC } E_SPI_STATE_RESULT; #define SPI_DAT1_DFSEL_SHIFT (24U) #define SPI_DAT1_CSNR_SHIFT (16U) #define SPI_FMT_WAITENA_BIT (21U) E_SPI_STATE_RESULT Spi3RxReady(uint32 nLen); E_SPI_STATE_RESULT Spi1TxSend(const uint8 *pData, uint32 nLen); E_SPI_STATE_RESULT Spi3RxFinalize(uint8 *pOut, uint32 nLen); void Spi3Init(void); void Spi1Init(void); void SpiCommInit(void); void SpiCommTest(void); #endif /* __SPICOMM_H__ */
Best Regards,