DMA for SPI(0) on LPC1549

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

DMA for SPI(0) on LPC1549

1,910 Views
simonwood
Contributor II

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)
{
;
}
}

Labels (1)
Tags (1)
0 Kudos
Reply
3 Replies

1,657 Views
Sabina_Bruce
NXP Employee
NXP Employee

Hello Simon,

If you remove the UART portion of your code(comment it out including the initializing). Do you get the same results?

The description of the SPI API routines are described in chpater 39 of the user manual. Here you will find two code examples one with dma and one without dma. Here is also described the configuration for the CFG.

Best Regards,

Sabina

0 Kudos
Reply

1,657 Views
simonwood
Contributor II

Hi Sabina,

I did have a look at the DMA-SPI rom code, but it's far from clear (and written against a slightly different header set, so a lot of work to get it to compile).

Problem is solved, and of course it was me being stupid.

My initSPI code does everything apart from enable the SPI!

Interestingly, the TXRDY bit reads as 1 when not enabled, so the push code appeared to work whilst the DMA did not. 

Thanks for your time.

Regards

Simon.

0 Kudos
Reply

1,657 Views
Sabina_Bruce
NXP Employee
NXP Employee

Hi Simon,

I am glad you were able to resolve this. Thanks for posting your resolution as well as this helps us and other customers in the future. 

Best Regards,

Sabina

0 Kudos
Reply