Forums

SSP DMA fails to write to memory?

Started by Triffid Hunter December 15, 2013
Hi,

I'm attempting to read sectors of an SD card via SSP.

All works fine when I manage the SSP fifos myself, however I'd like to do
this via DMA instead.

For DMA, I set one DMA channel to read from memory and write to SSP, while
another channel reads from SSP and writes to memory.

The trouble is, the read block is mostly unwritten- only every 2nd,3rd or
4th transfer actually writes to memory! I have verified this by filling the
region with 0xFF before beginning the transfer. The words that get written
contain correct data.

Any ideas how I could solve this dilemma, and have successful DMA transfers?

I set the memory->SSP transfer to no-increment since I just want to send
the same byte over and over again.

Debug output, when I begin the transfer:

*** DMA Channel: 7
IntStat: 0 TCStat: 0 ErrStat: 0
DMA Control (0x500041EC):
TransferSize: 126
SBSize: 0 (0=1,1=4,2=8,3,...)
DBSize: 1 (0=1,1=4,2=8,3,...)
SWidth: 2 (0=8,1,22)
DWidth: 0 (0=8,1,22)
SI: 0
DI: 0
I: 1
DMA Config (0x500041F0):
E: 1
SrcPeripheral: 4
DestPeripheral: 2
TransferType: 1 (0=M2M,1=M2P,2=P2M,3=P2P)
IE: 1
ITC: 1
Active: 1
Halt: 0
DMA SrcAddr: 0x10007D90
DMA DstAddr: 0x40030008
*** DMA Channel: 6
IntStat: 0 TCStat: 0 ErrStat: 0
DMA Control (0x500041CC):
TransferSize: 512
SBSize: 1 (0=1,1=4,2=8,3,...)
DBSize: 1 (0=1,1=4,2=8,3,...)
SWidth: 0 (0=8,1,22)
DWidth: 2 (0=8,1,22)
SI: 0
DI: 1
I: 1
DMA Config (0x500041D0):
E: 1
SrcPeripheral: 3
DestPeripheral: 24
TransferType: 2 (0=M2M,1=M2P,2=P2M,3=P2P)
IE: 1
ITC: 1
Active: 1
Halt: 0
DMA SrcAddr: 0x40030008
DMA DstAddr: 0x10007DF0
And when it completes:

*** DMA Channel: 7
IntStat: 1 TCStat: 1 ErrStat: 0
DMA Control (0x500041EC):
TransferSize: 0
SBSize: 0 (0=1,1=4,2=8,3,...)
DBSize: 1 (0=1,1=4,2=8,3,...)
SWidth: 2 (0=8,1,22)
DWidth: 0 (0=8,1,22)
SI: 0
DI: 0
I: 1
DMA Config (0x500041F0):
E: 0
SrcPeripheral: 4
DestPeripheral: 2
TransferType: 1 (0=M2M,1=M2P,2=P2M,3=P2P)
IE: 1
ITC: 1
Active: 0
Halt: 0
DMA SrcAddr: 0x10007D90
DMA DstAddr: 0x40030008
*** DMA Channel: 6
IntStat: 1 TCStat: 1 ErrStat: 0
DMA Control (0x500041CC):
TransferSize: 0
SBSize: 1 (0=1,1=4,2=8,3,...)
DBSize: 1 (0=1,1=4,2=8,3,...)
SWidth: 0 (0=8,1,22)
DWidth: 2 (0=8,1,22)
SI: 0
DI: 1
I: 1
DMA Config (0x500041D0):
E: 0
SrcPeripheral: 3
DestPeripheral: 24
TransferType: 2 (0=M2M,1=M2P,2=P2M,3=P2P)
IE: 1
ITC: 1
Active: 0
Halt: 0
DMA SrcAddr: 0x40030008
DMA DstAddr: 0x10007FEC

buffer 0x10007DF0:

0xFF 0xFF 0xFF 0xFF 0x20 0x20 0x20 0x20 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0x02 0x00 0x02 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x85 0x00
0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xD6 0x1C 0x20 0x53 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0x53 0x44 0x46 0x41 0xFF 0xFF 0xFF 0xFF 0x20 0x20
0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF
0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00
0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF
0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00
0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF
0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF
0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00
0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF
0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00
0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF
0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF
0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF
0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00
0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF
0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00
0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00
0x55 0xAA

An Engineer's Guide to the LPC2100 Series

Hi,

From: l... [mailto:l...] On Behalf Of Triffid Hunter
Sent: 16 December 2013 02:41
To: l...
Subject: [lpc2000] SSP DMA fails to write to memory?

Hi,

I'm attempting to read sectors of an SD card via SSP.

All works fine when I manage the SSP fifos myself, however I'd like to do this via DMA instead.

For DMA, I set one DMA channel to read from memory and write to SSP, while another channel reads from SSP and writes to memory.

The trouble is, the read block is mostly unwritten- only every 2nd,3rd or 4th transfer actually writes to memory! I have verified this by filling the region with 0xFF before beginning the transfer. The words that get written contain correct data.

Any ideas how I could solve this dilemma, and have successful DMA transfers?

This is a PL08x device, so make sure you read the error status from the DMA to see if it detected any bus contention.
I set the memory->SSP transfer to no-increment since I just want to send the same byte over and over again.

Debug output, when I begin the transfer:

*** DMA Channel: 7
IntStat: 0 TCStat: 0 ErrStat: 0
DMA Control (0x500041EC):
TransferSize: 126
SBSize: 0 (0=1,1=4,2=8,3,...)
DBSize: 1 (0=1,1=4,2=8,3,...)
SWidth: 2 (0=8,1,22)
DWidth: 0 (0=8,1,22)
SI: 0
DI: 0
I: 1
DMA Config (0x500041F0):
E: 1
SrcPeripheral: 4
DestPeripheral: 2
TransferType: 1 (0=M2M,1=M2P,2=P2M,3=P2P)

Try enabling the SSP FIFOs and setting the source burst size to ½ the FIFO size (I believe the PL022 FIFO is 16 deep so you will require a burst size of 8). I did have this working at one point, but I’ve forgotten the actual configuration…

--

Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk

SolderCore Development Platform http://www.soldercore.com
I learned the hard way, at least on the Cortex M3, that parts of RAM are disabled when you enter low power (idle) mode while DMA is running.
Turns out, DMA only works with AHB ram, not main ram. Pointing the DMA at a
buffer in AHB ram gives perfect transfers.

I can't find any mention of this critically important piece of information
in §31 of UM10360 other than a few vague mentions of AHB, and the examples
using addresses in the 0x20000000 block. The block diagram at the end of
§1.10 shows a connection between DMA controller and 32k SRAM bank, and §2.5
says that there's an arbitrator which *should* sort it out automagically.

The DMA error flag was never set. I couldn't find any other indication
anywhere else of an error being flagged either- just silent failure.

As for burst sizes, LPC17xxLib itself uses 4 transfers as burst size for
the SSP, and the FIFOs are "8 frames" where a frame can hold 4-16 bits so I
think 4 transfer burst is correct.
I've also determined that the SSP FIFOs seem to be broken...

/numerous/ variations of:

int i = 0, j = 0, k = 0;
while (i < length)
{
for (;k < 8 && (j < length); k++)
data->ssp->DR = tx[j++];

while (data->ssp->SR & SSP_SR_BSY);

for (; k && (i < length); k--)
rx[i++] = data->ssp->DR;
}

or:

int i = 0, j = 0;
while (i < length)
{
if (data->ssp->SR & SSP_SR_TNF)
data->ssp->DR = tx[j++];
while (data->ssp->SR & SSP_SR_RNE)
rx[i++] = data->ssp->DR;
}

will end up either stuck in infinite loops or returning garbage data
because RNE deasserts when fewer chars have been read than have been
written - apparently, the RX FIFO loses frames when accessed in this way.

I must send and receive one byte at a time if I want valid data- I
apparently can't use the FIFOs unless I'm only transmitting, and don't care
how much I receive.

Any insight on my SSP FIFO usage is most welcome

In case it's relevant, my chip has date/revision code 1211A
On 17 December 2013 01:46, Paul Curtis wrote:

> Hi,
>
> *From:* l... [mailto:l...] *On
> Behalf Of *Triffid Hunter
> *Sent:* 16 December 2013 02:41
> *To:* l...
> *Subject:* [lpc2000] SSP DMA fails to write to memory?
>
> Hi,
>
> I'm attempting to read sectors of an SD card via SSP.
>
> All works fine when I manage the SSP fifos myself, however I'd like to do
> this via DMA instead.
>
> For DMA, I set one DMA channel to read from memory and write to SSP, while
> another channel reads from SSP and writes to memory.
>
> The trouble is, the read block is mostly unwritten- only every 2nd,3rd or
> 4th transfer actually writes to memory! I have verified this by filling the
> region with 0xFF before beginning the transfer. The words that get written
> contain correct data.
>
> Any ideas how I could solve this dilemma, and have successful DMA
> transfers?
>
> This is a PL08x device, so make sure you read the error status from the
> DMA to see if it detected any bus contention.
> I set the memory->SSP transfer to no-increment since I just want to send
> the same byte over and over again.
>
> Debug output, when I begin the transfer:
>
> *** DMA Channel: 7
> IntStat: 0 TCStat: 0 ErrStat: 0
> DMA Control (0x500041EC):
> TransferSize: 126
> SBSize: 0 (0=1,1=4,2=8,3,...)
> DBSize: 1 (0=1,1=4,2=8,3,...)
> SWidth: 2 (0=8,1,22)
> DWidth: 0 (0=8,1,22)
> SI: 0
> DI: 0
> I: 1
> DMA Config (0x500041F0):
> E: 1
> SrcPeripheral: 4
> DestPeripheral: 2
> TransferType: 1 (0=M2M,1=M2P,2=P2M,3=P2P)
>
> Try enabling the SSP FIFOs and setting the source burst size to ½ the FIFO
> size (I believe the PL022 FIFO is 16 deep so you will require a burst size
> of 8). I did have this working at one point, but I’ve forgotten the actual
> configuration…
>
> --
>
> Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
>
> SolderCore Development Platform http://www.soldercore.com
Hi,

I'm not quite sure about which chip you are speaking. But if it is a
Cortex M3 from NXP the SSP
block is a ARM PrimeCell (PL022), see at
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0194g/index.html

There are some additional registers (not mentioned by NXP) which might
help to test what's going on.

Regards
Herbert

Am 17.12.2013 05:37, schrieb Triffid Hunter:
> Turns out, DMA only works with AHB ram, not main ram. Pointing the DMA
> at a buffer in AHB ram gives perfect transfers.
>
> I can't find any mention of this critically important piece of
> information in §31 of UM10360 other than a few vague mentions of AHB,
> and the examples using addresses in the 0x20000000 block. The block
> diagram at the end of §1.10 shows a connection between DMA controller
> and 32k SRAM bank, and §2.5 says that there's an arbitrator which
> *should* sort it out automagically.
>
> The DMA error flag was never set. I couldn't find any other indication
> anywhere else of an error being flagged either- just silent failure.
>
> As for burst sizes, LPC17xxLib itself uses 4 transfers as burst size
> for the SSP, and the FIFOs are "8 frames" where a frame can hold 4-16
> bits so I think 4 transfer burst is correct.
> I've also determined that the SSP FIFOs seem to be broken...
>
> /numerous/ variations of:
>
> int i = 0, j = 0, k = 0;
> while (i < length)
> {
> for (;k < 8 && (j < length); k++)
> data->ssp->DR = tx[j++];
>
> while (data->ssp->SR & SSP_SR_BSY);
>
> for (; k && (i < length); k--)
> rx[i++] = data->ssp->DR;
> }
>
> or:
>
> int i = 0, j = 0;
> while (i < length)
> {
> if (data->ssp->SR & SSP_SR_TNF)
> data->ssp->DR = tx[j++];
> while (data->ssp->SR & SSP_SR_RNE)
> rx[i++] = data->ssp->DR;
> }
>
> will end up either stuck in infinite loops or returning garbage data
> because RNE deasserts when fewer chars have been read than have been
> written - apparently, the RX FIFO loses frames when accessed in this way.
>
> I must send and receive one byte at a time if I want valid data- I
> apparently can't use the FIFOs unless I'm only transmitting, and don't
> care how much I receive.
>
> Any insight on my SSP FIFO usage is most welcome
>
> In case it's relevant, my chip has date/revision code 1211A
> On 17 December 2013 01:46, Paul Curtis > > wrote:
>
> Hi,
>
> *From:*l...
> [mailto:l... ]
> *On Behalf Of *Triffid Hunter
> *Sent:* 16 December 2013 02:41
> *To:* l...
> *Subject:* [lpc2000] SSP DMA fails to write to memory?
>
> Hi,
>
> I'm attempting to read sectors of an SD card via SSP.
>
> All works fine when I manage the SSP fifos myself, however I'd
> like to do this via DMA instead.
>
> For DMA, I set one DMA channel to read from memory and write to
> SSP, while another channel reads from SSP and writes to memory.
>
> The trouble is, the read block is mostly unwritten- only every
> 2nd,3rd or 4th transfer actually writes to memory! I have verified
> this by filling the region with 0xFF before beginning the
> transfer. The words that get written contain correct data.
>
> Any ideas how I could solve this dilemma, and have successful DMA
> transfers?
>
> This is a PL08x device, so make sure you read the error status
> from the DMA to see if it detected any bus contention.
> I set the memory->SSP transfer to no-increment since I just want
> to send the same byte over and over again.
>
> Debug output, when I begin the transfer:
>
> *** DMA Channel: 7
> IntStat: 0 TCStat: 0 ErrStat: 0
> DMA Control (0x500041EC):
> TransferSize: 126
> SBSize: 0 (0=1,1=4,2=8,3,...)
> DBSize: 1 (0=1,1=4,2=8,3,...)
> SWidth: 2 (0=8,1,22)
> DWidth: 0 (0=8,1,22)
> SI: 0
> DI: 0
> I: 1
> DMA Config (0x500041F0):
> E: 1
> SrcPeripheral: 4
> DestPeripheral: 2
> TransferType: 1 (0=M2M,1=M2P,2=P2M,3=P2P)
>
> Try enabling the SSP FIFOs and setting the source burst size to ½
> the FIFO size (I believe the PL022 FIFO is 16 deep so you will
> require a burst size of 8). I did have this working at one point,
> but I’ve forgotten the actual configuration…
>
> --
>
> Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
> SolderCore Development Platform http://www.soldercore.com
>
I'm using DMA with SSP to and from both main RAM and AHB RAM. However, AHB RAM is disabled during the low powered modes, and I was entering idle mode in some cases, before a DMA transfer finished, and getting errors.

However, the AHB RAM appears to remain enabled if JTAG is enabled (connecter), leading to the frustrating situation where my program worked perfectly in debug, but not otherwise.

For my program, I just checked the DMA status before entering idle to avoid the problem.