LPC54102 Hardware Triggering DMA

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

LPC54102 Hardware Triggering DMA

989 Views
robertalkire
Contributor II

I have an application where I was using SPI to communicate with an external multichannel 24bit ADC and used DMA to move the samples into SRAM. I am using LPCopen  3.03 with GCC on a LPC54102 (custom board) M4F only. This has almost worked ok with some gotchas. I have a few questions and a LPCopen bug report. 

The ADC asserts data ready (DR) when data conversion is complete. DR is used  to trigger DMA to initiate an SPI transfer. Both data and transfer control can be sent with DMA to the SPI transmit through the TXDATCTL register. DR will also trigger the SPI RX channel to move data when available into SRAM using a pair of ping-pong buffers. At the end of the transfer, I want an interrupt that will ultimately trigger a thread to process the data.

I ended up using byte transfer rather than word because of endian problems between SPI (big endian) and the little endian ARM.  I couldn't find a good way for the DMA to deal with this on it's own. This requires some backend processing so If you know of a way, please let me know.

I needed a hardware trigger of the DMA which is documented in the datasheet but I couldn't find any working examples.

The documentation states that NVIC has to be enabled for GPIO to trigger the DMA. So it is straightforward to set that up as a pinint. 

Chip_INMUX_PinIntSel(PININTSELECT0, PIO1_1_PORT, PIO1_1_PIN);
Chip_PININT_ClearIntStatus(LPC_PININT, PININTCH(PININTSELECT0));
Chip_PININT_SetPinModeEdge(LPC_PININT, PININTCH(PININTSELECT0));
Chip_PININT_EnableIntLow(LPC_PININT, PININTCH(PININTSELECT0));
NVIC_EnableIRQ(PIN_INT0_IRQn);

The interrupt service routine doesn't really have to do much and adds unnecessary overhead. It could be used to clear the interrupt although I thought that was what DMA_XFERCFG_CLRTRIG was for but maybe both need to be cleared. I tried to not use it but DMA hardware trigger wont work without it. I need to test if the DMA trigger from the GPIO incurs a delay that might be seen with priortized interrupts because it is using the interrupt hardware. 

The DMA setup itself is:.

Chip_DMA_SetupChannelTransfer(LPC_DMA, DMAREQ_SPI0_TX, DMASPITXDescriptor[1].xfercfg);
Chip_DMA_EnableChannel(LPC_DMA, DMAREQ_SPI0_TX);
Chip_DMA_SetupChannelConfig(LPC_DMA, DMAREQ_SPI0_TX,
                           DMA_CFG_HWTRIGEN | DMA_CFG_TRIGPOL_LOW | DMA_CFG_TRIGTYPE_EDGE |
                           DMA_CFG_PERIPHREQEN | DMA_CFG_CHPRIORITY(1));

Map the pinint0 to DMA SPI TX/RX channels use the include file inmux_5410x.h with the following:

Chip_INMUX_SetDMATrigger(DMAREQ_SPI0_TX, DMATRIG_PININT0);
Chip_INMUX_SetDMATrigger(DMAREQ_SPI0_RX, DMATRIG_PININT0);

This didn't work.

There is a bug in LPCopen include file  inmux_5410x.h file lines 72-95. The enumeration DMA_TRIGSRC_T does not match the datasheet UM10850 pg 103 DMA_ITRIG_INMUX register definition. The problem is that the datasheet does not have entries for CT32B1 Match 1 or CT32B3 Match 1 while the include file does. Since pinint0 follows the timer entries, the enumeration is off by two. With that enumeration fixed, hardware trigger worked as expected.

Please take this as a bug report and it would be great if it got fixed?

Thanks 

Bob

Labels (2)
Tags (3)
4 Replies

223 Views
kennethkong852
Contributor I

Hi @robertalkire !

Hope all is well.

I am currently working on some application that is almost identical to what you have described here (i.e. having my LPC54102 interfacing with a 24-bit ADC, in my case it's MCP3561) and am trying to experiment with DMA setup with SPI, all using LPCopen v3.

Would you be willing to share your code for this matter for my reference as I am new to DMA configs so I like to have an idea how everything is tied together?

Any insights would be greatly appreciated and thank you in advance for your help!

-Kenneth

0 Kudos

203 Views
ralkire
Contributor I

This is a 7 year old post you are responding to. The project I was working on has long been mothballed and I don't have LPCxpresso installed. I have switched CPU manufactures. Even though NXP forwarded this to me, I had to create a new account to respond this, they didn't recognize my credentials.

I found the datasheet was more accurate than the code. I have about 5 include files that I modified for bug fixes, I let NXP know about the bugs but have no idea if anything was ever fixed.  I also don't recall having many examples to work from, but found the datasheet to be fairly accurate. 

I will tell you how I created and initialized the descriptors. For the above reasons,  I'd suggest taking it with a grain of salt. 

// DMAREQ_SPI0_TX CH 9
// DMAREQ_SPI0_RX CH 8
static DMA_CHDESC_T DMASPITXDescriptor[2] __attribute__ ((aligned(16)));
static DMA_CHDESC_T DMASPIRXDescriptor[2] __attribute__ ((aligned(16)));

// note that SPI0ADCTXDATA, ADCRXA, and ADCRXB are source/destination in memory for where the DMA transfer is directed to

int DMA_init(void)
{
DMASPITXDescriptor[0].source = (uint32_t) &SPI0ADCTXDATA[SPI0ADCTXDATALEN-1];
DMASPITXDescriptor[0].dest = (uint32_t) &LPC_SPI0->TXDATCTL;
DMASPITXDescriptor[0].next = (uint32_t) &DMASPITXDescriptor[1];
DMASPITXDescriptor[0].xfercfg = 0; // this should be ignored for SRAM descriptor table

DMASPITXDescriptor[1].source = (uint32_t) &SPI0ADCTXDATA[SPI0ADCTXDATALEN-1];
DMASPITXDescriptor[1].dest = (uint32_t) &LPC_SPI0->TXDATCTL;
DMASPITXDescriptor[1].next = (uint32_t) &DMASPITXDescriptor[1];
DMASPITXDescriptor[1].xfercfg = DMA_XFERCFG_CFGVALID |
   DMA_XFERCFG_RELOAD | DMA_XFERCFG_WIDTH_32 | DMA_XFERCFG_SRCINC_1 |
   DMA_XFERCFG_DSTINC_0 | DMA_XFERCFG_XFERCOUNT(SPI0ADCTXDATALEN);

DMASPIRXDescriptor[0].source = (uint32_t) &LPC_SPI0->RXDAT;
DMASPIRXDescriptor[0].dest = (uint32_t) &ADCRXA[sizeof(ADCRXA) - 1];
DMASPIRXDescriptor[0].next = (uint32_t) &DMASPIRXDescriptor[1];
DMASPIRXDescriptor[0].xfercfg = DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTA |
   DMA_XFERCFG_CLRTRIG | DMA_XFERCFG_RELOAD | DMA_XFERCFG_WIDTH_8 | DMA_XFERCFG_SRCINC_0 |
   DMA_XFERCFG_DSTINC_1 | DMA_XFERCFG_XFERCOUNT(sizeof(ADCRXA));

DMASPIRXDescriptor[1].source = (uint32_t) &LPC_SPI0->RXDAT;
DMASPIRXDescriptor[1].dest = (uint32_t) &ADCRXB[sizeof(ADCRXB) - 1];
DMASPIRXDescriptor[1].next = (uint32_t) &DMASPIRXDescriptor[0];
DMASPIRXDescriptor[1].xfercfg = DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTB |
                           DMA_XFERCFG_CLRTRIG | DMA_XFERCFG_RELOAD | DMA_XFERCFG_WIDTH_8 | DMA_XFERCFG_SRCINC_0 |
   DMA_XFERCFG_DSTINC_1 | DMA_XFERCFG_XFERCOUNT(sizeof(ADCRXB));

if (!Chip_DMA_SetupTranChannel(LPC_DMA, DMAREQ_SPI0_TX, &DMASPITXDescriptor[0])) return -1;


Chip_DMA_SetupChannelTransfer(LPC_DMA, DMAREQ_SPI0_TX, DMASPITXDescriptor[1].xfercfg);
Chip_DMA_EnableChannel(LPC_DMA, DMAREQ_SPI0_TX);
Chip_DMA_EnableIntChannel(LPC_DMA, DMAREQ_SPI0_TX);
Chip_DMA_SetupChannelConfig(LPC_DMA, DMAREQ_SPI0_TX,
                            DMA_CFG_HWTRIGEN | DMA_CFG_TRIGPOL_LOW | DMA_CFG_TRIGTYPE_EDGE |
DMA_CFG_PERIPHREQEN | DMA_CFG_CHPRIORITY(1));

if (!Chip_DMA_SetupTranChannel(LPC_DMA, DMAREQ_SPI0_RX, &DMASPIRXDescriptor[0])) return -1;

Chip_DMA_SetupChannelTransfer(LPC_DMA, DMAREQ_SPI0_RX, DMASPIRXDescriptor[1].xfercfg);
Chip_DMA_EnableChannel(LPC_DMA, DMAREQ_SPI0_RX);
Chip_DMA_EnableIntChannel(LPC_DMA, DMAREQ_SPI0_RX);
Chip_DMA_SetupChannelConfig(LPC_DMA, DMAREQ_SPI0_RX,
                            DMA_CFG_HWTRIGEN | DMA_CFG_TRIGPOL_LOW | DMA_CFG_TRIGTYPE_EDGE |
DMA_CFG_PERIPHREQEN  | DMA_CFG_CHPRIORITY(0));

NVIC_EnableIRQ(DMA_IRQn);
NVIC_EnableIRQ(PIN_INT0_IRQn);
return 0;
}

you will need an interrupt routine which is called when the transfer is complete. 

void DMA_IRQHandler(void)

The first DMA initializes and loops on the second descriptor. The second DMA ping-pongs between descriptors. 

Not much but good luck

Bob

 

 

0 Kudos

172 Views
kennethkong852
Contributor I
Much appreciated for your effort in responding to this aged post! Anything is helpful in getting started.
Cheers,
Ken
0 Kudos

671 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Robert Alkire,

Thanks for your reporting, and I will transfer the bug to the LPCopen team.
Have a great day,
TIC

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos