I'm working on trying to use SPI+DMA direct from registers. I have the code working through NXP's API for the LPC55S69, which works. But it takes 24.7us to excute the SPI_MasterTransferDMA() function. This means that I end up missing interrupts (which are coming in every 62.5 us) and there is little time for any other processing with this overhead. To put this in context the part is running at 150MHz, so we are spending 3507 cycles executing an API function.
So I have extracted what I thought is the majority of the relevant code to directly talk to the registers, but I seem to be missing something.
FLEXCOMM4_DMA_Handle.state = (uint8_t)1; // kSPI_Busy
FLEXCOMM4_DMA_Handle.transferSize = num_bytes;
// Clear FIFOs.
FLEXCOMM4_PERIPHERAL->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
FLEXCOMM4_PERIPHERAL->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
// Enable rx&tx dma
FLEXCOMM4_PERIPHERAL->FIFOCFG |= SPI_FIFOCFG_DMARX_MASK | SPI_FIFOCFG_DMATX_MASK;
// base address is the same for TX&RX, so only need to set it once.
FLEXCOMM4_TX_DMA_BASEADDR->SRAMBASE = (uint32_t) &desc_table[0];
// receive
// enable peripheral request
FLEXCOMM4_RX_DMA_BASEADDR->CHANNEL[FLEXCOMM4_RX_DMA_CHANNEL].CFG |= DMA_CHANNEL_CFG_PERIPHREQEN_MASK;
const uint32_t rxfercfg = DMA_CHANNEL_XFERCFG_CFGVALID(1)
| DMA_CHANNEL_XFERCFG_RELOAD(0)
| DMA_CHANNEL_XFERCFG_SWTRIG(0)
| DMA_CHANNEL_XFERCFG_CLRTRIG(1)
| DMA_CHANNEL_XFERCFG_SETINTA(1)
| DMA_CHANNEL_XFERCFG_SETINTB(0)
| DMA_CHANNEL_XFERCFG_WIDTH(0)
| DMA_CHANNEL_XFERCFG_SRCINC(0)
| DMA_CHANNEL_XFERCFG_DSTINC(1)
| DMA_CHANNEL_XFERCFG_XFERCOUNT(num_bytes - 1)
;
desc_table[FLEXCOMM4_RX_DMA_CHANNEL].xfercfg = rxfercfg;
desc_table[FLEXCOMM4_RX_DMA_CHANNEL].srcEndAddr = DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)&(FLEXCOMM4_PERIPHERAL->FIFORD), 0, 0, 0);
desc_table[FLEXCOMM4_RX_DMA_CHANNEL].dstEndAddr = DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)g_afe_data.recv_buffer, 1, num_bytes, 1);
desc_table[FLEXCOMM4_RX_DMA_CHANNEL].linkToNextDesc = NULL;
FLEXCOMM4_RX_DMA_BASEADDR->CHANNEL[FLEXCOMM4_RX_DMA_CHANNEL].XFERCFG = rxfercfg;
// transmit
// enable peripheral request
FLEXCOMM4_TX_DMA_BASEADDR->CHANNEL[FLEXCOMM4_TX_DMA_CHANNEL].CFG |= DMA_CHANNEL_CFG_PERIPHREQEN_MASK;
const uint32_t txfercfg = DMA_CHANNEL_XFERCFG_CFGVALID(1)
| DMA_CHANNEL_XFERCFG_RELOAD(0)
| DMA_CHANNEL_XFERCFG_SWTRIG(0)
| DMA_CHANNEL_XFERCFG_CLRTRIG(1)
| DMA_CHANNEL_XFERCFG_SETINTA(1)
| DMA_CHANNEL_XFERCFG_SETINTB(0)
| DMA_CHANNEL_XFERCFG_WIDTH(0)
| DMA_CHANNEL_XFERCFG_SRCINC(1)
| DMA_CHANNEL_XFERCFG_DSTINC(0)
| DMA_CHANNEL_XFERCFG_XFERCOUNT(num_bytes - 1)
;
desc_table[FLEXCOMM4_TX_DMA_CHANNEL].xfercfg = txfercfg;
desc_table[FLEXCOMM4_TX_DMA_CHANNEL].srcEndAddr = DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)g_afe_data.send_buffer, 1, num_bytes, 1);
desc_table[FLEXCOMM4_TX_DMA_CHANNEL].dstEndAddr = DMA_DESCRIPTOR_END_ADDRESS((uint32_t *)&(FLEXCOMM4_PERIPHERAL->FIFOWR), 0, 0, 0);
desc_table[FLEXCOMM4_TX_DMA_CHANNEL].linkToNextDesc = NULL;
FLEXCOMM4_TX_DMA_BASEADDR->CHANNEL[FLEXCOMM4_TX_DMA_CHANNEL].XFERCFG = txfercfg;
FLEXCOMM4_DMA_Handle.rxInProgress = true;
FLEXCOMM4_DMA_Handle.txInProgress = true;
uint32_t tmpData = 0U;
//tmpData |= ((txfercfg.configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
tmpData |= (uint32_t)kSPI_FrameAssert;
spi_config_t *spi_config_p = (spi_config_t *)SPI_GetConfig(FLEXCOMM4_PERIPHERAL);
tmpData |= ((uint32_t)SPI_DEASSERT_ALL & (~(uint32_t)SPI_DEASSERTNUM_SSEL((uint32_t)spi_config_p->sselNum)));
// set width of data - range asserted at entry
tmpData |= SPI_FIFOWR_LEN(kSPI_Data8Bits);
*((uint16_t *)((uint32_t)&FLEXCOMM4_PERIPHERAL->FIFOWR) + 1) = (uint16_t)(tmpData >> 16U);
DMA_StartTransfer(FLEXCOMM4_DMA_Handle.rxHandle);
DMA_StartTransfer(FLEXCOMM4_DMA_Handle.txHandle);
are done in a separate function.
已解决! 转到解答。
Hi,
Because the DMA functions well in SDK package, I suggest you screen-copy the DMA register in debugger.
For your register level code written manually, you also screen-copy the DMA register.
Compare the DMA register and get the difference, maybe it is helpful.
Hope it can help you
BR
XiuangJun Rong
Thanks but I have all the setup already configured and if I use the SPI_MasterTransferDMA() then everything works but the code path through the SPI_MasterTransferDMA() takes too long to execute. So I was manually trying to directly write the registers since it is the same buffers and transfer size every time it shouldn't be needed to configure absolutely everything again to do the same transfer again.
Hi,
Because the DMA functions well in SDK package, I suggest you screen-copy the DMA register in debugger.
For your register level code written manually, you also screen-copy the DMA register.
Compare the DMA register and get the difference, maybe it is helpful.
Hope it can help you
BR
XiuangJun Rong
Thanks for the reply, that is basically what I ended up doing in the end.
The issue was in not having a linked DMA transfer for the last byte being sent so that the SSEL was de-asserted at the end of transmission.
I appreciate all the help.
Regards,
Tim.
Hi,
If you write register directly, you have to enable the gated clock
1)enable the DMA clock and spi clock
SYSCON->AHBCLKCTRL[0]|=1<<20; //enable DMA0
SYSCON->AHBCLKCTRL[1]|=1<<15; //enable FC4
2)For the SPI4, I suggest you initialize the SPI4 with line:
SPI_MasterGetDefaultConfig(&userConfig);
srcFreq = EXAMPLE_SPI_MASTER_CLK_FREQ;
userConfig.sselNum = (spi_ssel_t)EXAMPLE_SPI_SSEL;
userConfig.sselPol = (spi_spol_t)EXAMPLE_SPI_SPOL;
SPI_MasterInit(SPI4, &userConfig, srcFreq);
The above code will enable spi4 clock and initialize PSIDE
Pls have a try
BR
XiangJun Rong