AnsweredAssumed Answered

DMA for SPI(0) on LPC1549

Question asked by Simon Wood on Nov 11, 2019
Latest reply on Nov 19, 2019 by Sabina Bruce

Has anyone got SPI working with DMA on LPC1549 ? 

 

I've written generic setup code that works fine with DMA-USART0 (CH1 for correct peripheral request). Changing to SPI0 it doesn't do anything (CH7, dest = &(LPC_SPI0->TXDAT)) tried 8,16, and 32 bit transfer size just in case. Nothing. UART works just as expected (dma runs, transfers the byte array to UART tx). I've set the SPI_TXDATCTL_RXIGNORE flag. 

 

I do see in the user manual this:

25.7.5 DMA operation
A DMA request is provided for each SPI direction, and can be used in lieu of interrupts for
transferring data by configuring the DMA controller appropriately, and enabling the Rx
and/or Tx DMA via the CFG register. The DMA controller provides an acknowledgement
signal that clears the related request when it completes handling that request.
The transmitter DMA request is asserted when Tx DMA is enabled and the transmitter can
accept more data.
The receiver DMA request is asserted when Rx DMA is enabled and received data is
available to be read.

But if you look at the CFG register there is nothing defined to enable RX/TX DMA...

 

Thanks in advance for any help.

Simon. 

 

Extract of test code:

 

void initDMA()
{
Chip_DMA_Init(LPC_DMA);
Chip_DMA_Enable(LPC_DMA);
Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
}

void setupDMATransfer(DMA_CHID_T dmaChannel, volatile void* pPeriphTXAddress)
{
Chip_DMA_EnableChannel(LPC_DMA, dmaChannel);
Chip_DMA_EnableIntChannel(LPC_DMA, dmaChannel);
Chip_DMA_SetupChannelConfig(LPC_DMA, dmaChannel,
(DMA_CFG_PERIPHREQEN | DMA_CFG_TRIGBURST_SNGL | DMA_CFG_CHPRIORITY(0)));

dmaDesc.source = DMA_ADDR(&nSPIData[TX_BYTES - 1]);
dmaDesc.dest = DMA_ADDR(pPeriphTXAddress);
dmaDesc.next = DMA_ADDR(0);
dmaDesc.xfercfg = 0;
}

void DoDMA(DMA_CHID_T dmaChannel)
{
uint32_t nCfg = DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTA | DMA_XFERCFG_WIDTH_8
| DMA_XFERCFG_SRCINC_1 | DMA_XFERCFG_DSTINC_0 | DMA_XFERCFG_XFERCOUNT(TX_BYTES);

dmaDone = 0;
/* Setup transfer descriptor and validate it */
Chip_DMA_SetupTranChannel(LPC_DMA, dmaChannel, &dmaDesc);
Chip_DMA_SetupChannelTransfer(LPC_DMA, dmaChannel, nCfg);
Chip_DMA_SetValidChannel(LPC_DMA, dmaChannel);
Chip_DMA_SWTriggerChannel(LPC_DMA, dmaChannel);

// interrupt helper
dmaCurrentChannel = dmaChannel;

NVIC_EnableIRQ(DMA_IRQn);
}


void spiDMARXSync()
{
Chip_DMA_EnableChannel(LPC_DMA, DMAREQ_SPI0_RX);
Chip_DMA_SetupChannelConfig(LPC_DMA, DMAREQ_SPI0_RX,
(DMA_CFG_PERIPHREQEN | DMA_CFG_TRIGBURST_SNGL | DMA_CFG_CHPRIORITY(1)));

static uint8_t nRXSync;
static DMA_CHDESC_T rxDesc;

rxDesc.source = DMA_ADDR(LPC_SPI0->RXDAT);
rxDesc.dest = DMA_ADDR(&nRXSync);
rxDesc.next = DMA_ADDR(0);
rxDesc.xfercfg = 0;

uint32_t nCfg = DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTB | DMA_XFERCFG_WIDTH_8
| DMA_XFERCFG_SRCINC_0 | DMA_XFERCFG_DSTINC_0 | DMA_XFERCFG_XFERCOUNT(TX_BYTES);

Chip_DMA_SetupTranChannel(LPC_DMA, DMAREQ_SPI0_RX, &rxDesc);
Chip_DMA_SetupChannelTransfer(LPC_DMA, DMAREQ_SPI0_RX, nCfg);
Chip_DMA_SetValidChannel(LPC_DMA, DMAREQ_SPI0_RX);
Chip_DMA_SWTriggerChannel(LPC_DMA, DMAREQ_SPI0_RX);
}

void setData()
{
memset(nSPIData, 0, sizeof(nSPIData));

for (int i = 0; i < TX_BYTES/2; i++)
{
nSPIData[i] = 0xFF;
}
}

void initOutput()
{
Chip_GPIO_SetPinDIROutput(LPC_GPIO, 0, LED_PIN_A);
Chip_GPIO_SetPinDIROutput(LPC_GPIO, 0, LED_PIN_B);

Chip_GPIO_SetPinOutLow(LPC_GPIO, 0, LED_PIN_B);

setData();
}

void initSPI()
{
Chip_SPI_Init(LPC_SPI0);
ConfigStruct.Mode = SPI_MODE_MASTER;
ConfigStruct.ClkDiv = 0xFFFF;
ConfigStruct.ClockMode = SPI_CLOCK_CPHA0_CPOL0;
ConfigStruct.DataOrder = SPI_DATA_MSB_FIRST;
ConfigStruct.SSELPol = SPI_CFG_SPOL0_LO;
Chip_SPI_SetConfig(LPC_SPI0, &ConfigStruct);
Chip_SPI_SetControlInfo(LPC_SPI0, 8, SPI_TXDATCTL_RXIGNORE | SPI_TXDATCTL_EOF);

Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
Chip_SWM_MovablePinAssign(SWM_UART0_TXD_O, 0xFF);
Chip_SWM_MovablePinAssign(SWM_SPI0_MOSI_IO, LED_PIN_A);
}

void initUART()
{
Chip_UART_Init(LPC_USART0);
Chip_Clock_SetUARTBaseClockRate(Chip_Clock_GetMainClockRate(), false);
Chip_UART_ConfigData(LPC_USART0, UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE | UART_CFG_STOPLEN_1);
Chip_UART_SetBaud(LPC_USART0, 1000);
Chip_UART_Enable(LPC_USART0);
Chip_UART_TXEnable(LPC_USART0);

Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
Chip_SWM_MovablePinAssign(SWM_SPI0_MOSI_IO, 0xFF);
Chip_SWM_MovablePinAssign(SWM_UART0_TXD_O, LED_PIN_A);
}

// direct write to code prove SPI config and that we can output the data and see the LED change
void pushSPI()
{
for (int i = 0; i < TX_BYTES; i++)
{
LPC_SPI0->TXDAT = nSPIData[i];
while (!(Chip_SPI_GetStatus(LPC_SPI0) & SPI_STAT_TXRDY))
{
;
}
}
}

// dma transfer that should be the same as above
void dmaSPI()
{
setupDMATransfer(DMAREQ_SPI0_TX, &(LPC_SPI0->TXDAT));
DoDMA(DMAREQ_SPI0_TX);
//spiDMARXSync();

// force first byte...
LPC_SPI0->TXDAT = 0xff;

while (!dmaDone)
{
;
}
}

void pushUART()
{
for (int i = 0; i < TX_BYTES; i++)
{
LPC_USART0->TXDATA = nSPIData[i];
while (!(Chip_UART_GetStatus(LPC_USART0) & UART_STAT_TXRDY))
{
;
}
}
}
void dmaUART()
{
setupDMATransfer(DMAREQ_USART0_TX, &(LPC_USART0->TXDATA));
DoDMA(DMAREQ_USART0_TX);

while (!dmaDone)
{
;
}
}

void doDMATest()
{
initOutput();
initDMA();

// test via UART
//initUART();
//pushUART();
//dmaUART();

// test via sPI
initSPI();
pushSPI();
pushSPI();
pushSPI();
pushSPI();
pushSPI();
dmaSPI();

while (1)
{
;
}
}

Outcomes