GPDMA + DAC, V2.12

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

GPDMA + DAC, V2.12

1,348 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mch0 on Sat Sep 13 15:25:48 MST 2014
Hi,

when I tried to run the DAC by GPDMA I ran into two problems with the current LPCOpen libraries (2.12). The good news first: Finally all runs as expected. But I think there is room for improvement for an upcoming 2.13 of LPCOpen.

1. Transfer width
The DAC has a 32bit register for the value, all right. However, only the lower halfword contains the value that will be converted, the upper halfword contains static information.
So when you create a table im memory for DAC output, you would naturally use a table with 16bit entries.
However, in LPCOpen 2.12 the "natural width" for the DAC is looked up as a WORD, i.e. 32 bit.
These values are predefined in a lookup table in gpdma_18xx_43cc.c:

/* Optimized Peripheral Source and Destination transfer width (18xx,43xx) */
static const uint8_t GPDMA_LUTPerWid[] = {
...


I suggest to change the entry for the DAC (third from bottom) from GPDMA_WIDTH_WORD to GPDMA_WIDTH_HALFWORD.

With that the DMA will write only the lower 16 bits into the DAC value register - works perfectly. This cuts the table space in memory in half. The DMA also uses less bandwith, since the memory read requests are also halved.

2. GPDMA setup
I found it very complicated to set up a linked list transfer, when a peripheral is involved. I am not sure whether I missed the "easy" way, but here it goes.
When you use linked lists you have to provide the (chain of) LLI descriptors. There is a function to help you prepare one: Chip_GPDMA_PrepareDescriptor().
That's fine, because you don't want to calculate the control word entry yourself.
But: This function expects a lookup value for a peripheral, if one is used.
So you don't enter the "real target" but e.g. GPDMA_CONN_DAC for the DAC. The function then looks up the target address for you (fine) and uses this value also for other calculations.
After the call this entry is replaced by the real address (fine again).
But after preparing the LLI you have to pass a pointer to it when you prepare the actual transfer with
Chip_GPDMA_SGTransfer() that function also expects the "lookup value", not the already transformed one!
If you give it the LUT value (again) the GPDMA will crash later, if you give it the real address, it will crash when trying to use it for look-up.

I found no way to resolve the problem with the current DAC API.
My workaround does not look nice, I had to create a temporary LLI to get the second function working:

// fill in the real LLI, this also calculates the correct control word
Chip_GPDMA_PrepareDescriptor(LPC_GPDMA,&daclli, (uint32_t)dacfield, GPDMA_CONN_DAC, 1024, GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA, &daclli);

// create a temporary LLI for the API call, this can be discarded after the call
templli.ctrl=daclli.ctrl;
templli.lli=(uint32_t)&daclli;
templli.src=daclli.src;
templli.dst=GPDMA_CONN_DAC;

// now arm the channel for transfers , the chain starts with the real LLI
Chip_GPDMA_SGTransfer(LPC_GPDMA, dmaChannelNum, &templli, GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA);


If I have not overlooked the simple & easy solution I'd suggest a change in the API to use "cooked" and "real" values in a more consistent way.

However, once you get the GPDMA/DAC running, it's a charm  . With a single LLI descriptor, linked back to itself, you have a complete function generator running in the background ...

Best regards,

Mike




Labels (1)
2 Replies

669 Views
denistcherniak
Contributor I

This is a very interesting read indeed! I am stuck with a similar problem with linked lists, and I can't seem to get it up and running. What I am trying to accomplish is to output a frame buffer to a display through the SSP. The frame buffer size is too large to be output through one DMA transfer, which is why I am trying to accomplish it through 3 transfers linked together.

As far as I understand from your explanation of the double look up bug and from my own poking around LPCOpen, it should be necessary to create the temporary list for the first descriptor - the one actually fed to Chip_GPDMA_SGTransfer, the following descriptors should work fine, after initialization with Chip_GPDMA_PrepareDescriptor?

After I have created a temp descriptor my code no longer crashes, however, only the first transfer is completed (1/3) of the display is drawn. It seems that the subsequent lists are never executed, also the DMA Interrupt routine is never called (if I set the lli of descriptor_1 to 0, it is called). 

I would be very grateful, if someone could shed some light on what it is, that I am not understanding/have goofed up! My code is as follows:

DMA_TransferDescriptor_t descriptor_1;
DMA_TransferDescriptor_t descriptor_2;
DMA_TransferDescriptor_t descriptor_3;
DMA_TransferDescriptor_t temp_descriptor_1;

Chip_GPDMA_PrepareDescriptor(LPC_GPDMA, &descriptor_1, (uint32_t)&(display_config->fb[0]), display_config->dma_connection, FB_SIZE/3, GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA, &descriptor_1);
Chip_GPDMA_PrepareDescriptor(LPC_GPDMA, &descriptor_2, (uint32_t)&(display_config->fb[FB_SIZE/3]), display_config->dma_connection, FB_SIZE/3, GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA, &descriptor_3);
Chip_GPDMA_PrepareDescriptor(LPC_GPDMA, &descriptor_3, (uint32_t)&(display_config->fb[FB_SIZE/3 * 2]), display_config->dma_connection, FB_SIZE/3, GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA, 0);

temp_descriptor_1.ctrl = descriptor_1.ctrl;
temp_descriptor_1.lli = (uint32_t)&descriptor_2;
temp_descriptor_1.src = descriptor_1.src;
temp_descriptor_1.dst = display_config->dma_connection;

Chip_GPDMA_SGTransfer(LPC_GPDMA, display_config->dma_channel, &temp_descriptor_1, GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA);

Best regards,

Denis

0 Kudos

669 Views
a_bet
Contributor IV

This is a very, very helpful post. Please LPCXpresso support consider making a FAQ on this or even take care of this in the upcoming realese of the LPCOpen!
Many thanks to mch0 for all his posts about the LPC4370, they are helping me a lot with my thesis.

Cheers,
Andrea

0 Kudos