scatter / gather dma

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

scatter / gather dma

1,456 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wdawson61 on Tue Aug 16 15:06:59 MST 2011
I want to use scatter gather dma to drive an LCD display that requires:

1.) Clear p0[8] (lcd_a0).
2.) Send some commands via ssp1 while lcd_a0 is low; (init, user contrast, etc)
3.) Clear p0[8] (lcd_a0) (redundant, but for a reason ;) )
4.) Send 3 byte address select next LCD page (page and column) via ssp, while lcd_a0 is low.
5.) Set p0[8] (lcd_a0).
6.) Send 128 byte page data via ssp1 while lcd_a0 is high.
7.) If user-requested commands to be sent (contrast, etc ) goto 1, else goto 3.

I am trying to implement this using a scatter/ gather list on DMACH1.

I request TC (bit 31) on the last LLI with a link of 0.  In the DMA_IRQ I determine if any user-generated commands (brightness, bias, contrast, etc) are waiting to be sent, If so the DMACCH1LLI is programmed with the addr of element 0 of the list, otherwise the extra commands are skipped and the list is started at element 2.

My question is:

[B]Can a transfer from memory to GPIOn (accessed as a byte) be done as a memory to peripheral transfer, and if so, can I use the SSP1TX DMACBREQ signal to gate the GPIO transfer to be sure that the previous ssp transfer has completed before the GPIO is set or cleared by the GPIO LLI? 
[/B]

This is necessary so the lcd_a0 pin (Register Select) is in the correct state for the display when the spi command is clocked in.

As you can see from the code, my scat/gat list is alternating GPIO and SSP writes.  Is there another way to do this?  Other than sitting in a nice, tight, CPU-intensive little loop?



Quote:

void dispdma_StartEngine()
{
PDMA_LLI pNext = &g_DmaLLI[0];
/* Ch1 set for M2P transfer from FrameBuff to SSP1. */
LPC_GPDMACH1->DMACCDestAddr         = pNext->dest;
LPC_GPDMACH1->DMACCSrcAddr = pNext->src;
LPC_GPDMACH1->DMACCControl = pNext->control;
LPC_GPDMACH1->DMACCLLI = pNext->link;

/* The burst size is set to 1, source and dest transfer width is
8 bits(byte), Terminal Count Int enable */
LPC_GPDMACH1->DMACCConfig = (0x0C001 | (DMA_SSP1_TX << 6) | (0x00 << 1)| (M2P << 11));


}



void dispdma_buildLlist()
{
int n = 0, idx=0;
PDMA_LLI pNext = &g_DmaLLI;

// Set up auxilary blocks but set transfer length of command block to 0
// Setup GPIO to make A0=0
pNext->dest = (void*) &LPC_GPIO0->FIOCLR1; // make a0=0
pNext->src = (void*) &LcdA0;
pNext->control = 1; // Length=1
pNext->link = pNext+1;

/*
* This block will be modified on the fly to allow sending of commands to the LCD
*/

// Setup LCD Commands to set page / column
(++pNext)->dest = (void*) &LPC_SSP1->DR;
pNext->src = NULL; // Initialized when commands to be sent to display
pNext->control = 0; // Length=0- no TC
pNext->link = pNext+1;


for (n = 0; n < 8; n++)
{
// Setup GPIO to make A0=0
(++pNext)->dest = (void*) &LPC_GPIO0->FIOCLR1; // make a0=0
pNext->src = (void*) &LcdA0;
pNext->control = 1; // Length=1
pNext->link = pNext+1; // Next link

// Setup LCD Commands to set page / column
(++pNext)->dest = (void*) &LPC_SSP1->DR;
pNext->src = (void*) &g_LcdAddrTab[n * 3]; // Index to proper 3-byte address command in table
pNext->control = 3 | (DMA_SI); // Length=3
pNext->link = pNext+1; // Next Link

// Setup GPIO to make A0=1
(++pNext)->dest = (void*) &LPC_GPIO0->FIOSET1; // make a0=1
pNext->src = (void*) &LcdA0; // Bitmap to set
pNext->control = 1; // Length=1
pNext->link = pNext+1; // Next link

// Setup LCD Commands to set page / column
(++pNext)->dest = (void*) &LPC_SSP1->DR;
pNext->src = (void*) &LCDFrameBuff.Data[n][0]; // Point to page data for display
pNext->control = 128 | DMA_SI; // Length=128
pNext->link = pNext+1; // Next Link
}

// Terminate the list and cause a TC interrupt on the last element
pNext->control |= 0x80000000;
pNext->link = 0;

}

0 Kudos
7 Replies

960 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Fri Aug 19 01:13:41 MST 2011
Hi Wade,


Quote: wdawson61

I'm guessing the DMASync is only applicable to M2P / P2M / P2P transfers anyway and that they mean 0 = enabled ?



This is one of those things ...
Thee bits enable or disable the "synchronization logic for the DMA request signals". Unfortunately the user manual does not tell us what this synchronization logic is, how it works or what it is used for ...
The DMA request signals mentioned are internal connections between the GPDMA module and the peripherals. These request signals control when the GPDMA can read/write the different peripherals.

So yes, this synchronization controls the synchronization between the peripheral and the DMA controller. Switching this synchronization of does not make that much sense to me.

In your later posts:

Indeed, the GPDMA only controls the FIFO so the DMA interrupt is not synchronized with the transfer complete on the SPI. That's why I suggested to use the SPI interrupt. Unfortunately I just discovered there is no SPI interrupt on a transfer complete ... So it seems you are stuck with polling the BSY bit to wait for a transfer complete.
This however does mean that it can take up to 8 SPI words of polling ...
The DMA interrupt is fired as soon as DMA is finished. I think that means the FIFO is then still full (8 words) so that takes 64 SPI clock cycles plus the time for the not used SSEL toggle in between each word :(

Hm ... there goes my idea of a quick and easy setup of my LCD and SD-card DMA stuff ...  I've still got my LCD in a tight polling loop and SD card on interrupt based loop.

Regards,
[INDENT]Rob
[/INDENT]
0 Kudos

961 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wdawson61 on Thu Aug 18 18:41:27 MST 2011
Update:

I was able to get the DMA and linked (using my own linked list not the DMA controller's) method working by polling the BSY bit of SSP1->SR IN THE DMA ISR and not starting the next DMA transfer until the SSP is not busy (all data shifted and FIFO empty). I've lowered the DMA IRQ to the lowest in the system.  I haven't profiled yet, but it seems be working quite well as the system is quite snappy.
0 Kudos

961 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wdawson61 on Thu Aug 18 08:35:53 MST 2011

Quote:
Right?



Wrong! 

I forgot about the SSP FIFO. When the DMA SSP transfer is "done" it doesn't imply that the data has shifted onto the pins. Crap...

I guess, Rob65, you are (once again) correct.  I'll probably need to ditch most of my original concept and just use DMA for the SSP transfers - not the GPIO.

Drats...
0 Kudos

961 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wdawson61 on Thu Aug 18 05:18:37 MST 2011
Hi Rob. 

Thanks very much for your informational reply!  I had a suspicion  about whether or not the GPIOs were considered peripherals based on the the block diagram; they're on the ARM's side of the APB bridge.  The code did do "something;"  it toggled the GPIO at about a rate of 2 ms, but the SSP clock line never budged.

Since I already have the linked list built, I think I'll just add a config member to my dma_lli struct.  I'll request a TC interrupt on every element and program the appropriate transfer type, etc in the newly added config member.  In the DMA_TC isr, I'll load up the next element in the list to the DMAC regs including the config element programmed for the particular transfer type.  This way the GPIO / SSP guard is still in place as I'm always ensured that the GPIO transfer has completed before the SSP is started.

Right?

One other thing.  Section 5.14 DMA synchronization states:

Quote:

A bit set to 0 enables
the synchronization logic for a particular group of DMA requests. A bit set to 1 disables the
synchronization logic for a particular group of DMA requests. This register is reset to 0,
synchronization logic enabled.


it further states...

Quote:

Table 559. DMA Synchronization register (DMACSync - 0x5000 4034)
Bit Name Function
15:0 DMACSync Controls the synchronization logic for DMA request signals. Each bit represents one
set of DMA request lines as described in the preceding text:
0 - synchronization logic for the corresponding DMA request signals are disabled.
1 - synchronization logic for the corresponding request line signals are enabled.



I'm guessing the DMASync is only applicable to M2P / P2M / P2P transfers anyway and that they mean 0 = enabled ?

Thanks again,

Wade.
0 Kudos

961 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Wed Aug 17 23:42:56 MST 2011
Wade,

NXP is known to answer posts frequently, but sometimes they new a bit of time to figure out what the correct answer is.
There is however no guarantee that they will see, or answer, to your question. Whitecoe is right in stating this is a user forum but both NXP and Code Red are known to give support on their products via this medium.

having said this, what is your progress with your questions?
Did you test the code you posted?

I have used the same scatter/gather DMA engine on other NXP products but not (yet) on the lpc1xxx devices.

A scatter/gather linked list works on one DMA channel and a DMA channel is programmed to have either memory or a peripheral as source or destination.
In the DMACConfig register you program the type of transaction (memory-memory, peripheral-memory, memory-peripheral, peripheral-peripheral) and, in case of a peripheral, you also program the peripheral type.

In a number of places the user manual mentions which peripherals are supported. For the lpc17xx these are SSP 0/1, ADC, I2S 0/1, DAC and UART 0/1/2/3.
Peripheral transfers are only possible for these devices. The DMA controller needs some way of synchronizing its read/write actions with data being available at the device (i.e. data being available in a FIFO to start a read or a FIFO not being full to write).

So to answer your questions:

Quote:

Can a transfer from memory to GPIOn (accessed as a byte) be done as a  memory to peripheral transfer, and if so, can I use the SSP1TX DMACBREQ  signal to gate the GPIO transfer to be sure that the previous ssp  transfer has completed before the GPIO is set or cleared by the GPIO  LLI?

No, GPIO is not a peripheral as mentioned in the list. You need to use a memory transfer for this.
No, there is no way to use DMACBREQ to gate the progression in the scatter/gather list.

It is not possible to combine the two transfer types on one DMA channel using scatter/gather, a channel is programmed to be active with only one transfer type to only one peripheral. It is not possible to combine transfers to different peripherals (or TX/RX part of a peripheral) and/or memory on one scatter/gather channel.

The only way I see to solve this is using the interrupt from the SPI channel to guard each DMA driven SPI transfer.

Scatter/Gather is meant to be used for devices that need continuous, uninterrupted data streams that require a hard real time aspect. As an example; we have used scatter/gather with an MP3 player where the DMA streams blocks of audio to SSP, DAC or I2S while the processor is decoding new data and adding items to the linked list while doing so.

Regards,[INDENT]Rob
[/INDENT]P.s: using [ CODE ] instead of [ QUOTE ] keeps the indentations and uses a fixed with font making code more readable.
0 Kudos

961 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by whitecoe on Wed Aug 17 05:35:39 MST 2011

Quote: wdawson61
Is there a way to escalate this to someone in NXP?  A FAE or the like?



This is a user forum so there is no guaranteed escalation for questions, although NXP people do post to threads from time to time.

If you want support from NXP, then probably best contact them directly....
http://www.nxp.com/techsupport/index.php

HTH!
0 Kudos

961 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by wdawson61 on Wed Aug 17 04:17:12 MST 2011
Is there a way to escalate this to someone in NXP?  A FAE or the like?
0 Kudos