Great info. I missed the "APB access" point. Thanks for the heads up. Now
I need to find out if disabling the DMA during a watchdog feed will disrupt
a DMA in progress. If so (my guess is it probably will), then disabling the
watchdog during DMA operations will be the only choice.
Thanks again
_____
From: l... [mailto:l...] On Behalf Of
Daniel Gelbgras
Sent: Tuesday, May 08, 2007 3:43 PM
To: l...
Subject: Re: [lpc2000] Re: DMA->SSP/SPI Mystery on LPC2468
Hi Mark,
just about Watchdog problems:
extract of the LPC2468 Erratsheet :
"WDT.1:Accessing non-Watchdog APB registers
in the middle of the feed sequence causes a reset
Problem:After writing 0xAA to WDFEED, any APB register access
other than writing 0x55 to WDFEED may cause an immediate reset.
...
Workaround:Avoid APB accesses in the middle of the feed sequence.
This implies that interrupts and the GPDMA should be disabled
while feeding the Watchdog"
regards
Daniel
----- Original Message -----
From: "markcrow" >
To: .com>
Sent: Tuesday, May 08, 2007 5:21 PM
Subject: [lpc2000] Re: DMA->SSP/SPI Mystery on LPC2468
Just a follow up; I looked at your code and discovered that mine was
the same...AND I'm still getting the watchdog reset.
As it turns out, if a watchdog feed is performed when DMA is enabled
(in the DMA config register) a watchdog feed will cause a watchdog
reset. I'm going to ask NXP to look into this.
RE: the code below; DMACC0Control_SBSize_BIT and
DMACC0Control_DBSize_BIT weren't defined so I don't know for sure
what the two related fields in the DMA Channel 0 control register
were set to. However, I have tried various combinations and only
'1'
will work in both fields for some reason. DMA is transferring to
SSP0 which has an 8-byte FIFO and I'd like to set the dest burst size
to 8 (as well as the source burst size). Maybe I misunderstand what
a 'burst size' is???
--- In lpc2000@yahoogroups .com,
"arjanverheij"
wrote:
>
> Gents,
>
> Following is the code I used to get SPI going with DMA.
> A couple of notes:
> - the DMA controller can't access the normal RAM, so buffers and
LLI
> structures have to be in USB RAM or external RAM
> - I got weird things to happen (debugger lock up etc.) if I write
to
> DMACC1Configuration register BEFORE setting the
enable bit in
> DMACConfiguration
>
> About the code:
> - I soldered SSP0 to SSP1 (4 physical wires)
> - I call SPIwithDMA_Init from Main, after enabling interrupts and
> starting the RTC
> - SPIwithDMA_Init does 3 tests, and on my Embedded Artists 2468
> board they all complete without errors
> - I use Rowley CrossWorks
> #include "platform.h"
> #include
> #include #define VICSourceDMA 25
>
> #define USB_RAM 0x7FD00000
> #define USB_RAM_SIZE 0x00004000 //16KB (8KB on LPC23xx)
> #define ETH_RAM 0x7FE00000
> #define ETH_RAM_SIZE 0x00004000 //16KB
> #define BAT_RAM 0xE0084000
> #define BAT_RAM_SIZE 0x00000800 //2KB
>
> byte* sendBuf = (byte*)0x7FD00000;
> byte* recvBuf = (byte*)0x7FD00100;
> int sendFrameSize = 50;
> int recvFrameSize = 50;
> typedef struct tagDMAControl
> {
> unsigned TransferSize : 12;
> unsigned SrcBurstSize : 3; //000=1, 001=4, 010=8,
> 011, 1002, 101d, 1108, 111%6
> unsigned DstBurstSize : 3;
> unsigned SrcWidth : 3; //000its,
> 001bits, 0102bits
> unsigned DstWidth : 3;
> unsigned reseved : 2;
> unsigned SrcIncrement : 1;
> unsigned DstIncrement : 1;
> unsigned Protection : 3;
> unsigned TCIntEnable : 1;
> } DMAControl;
>
> typedef struct tagDMA_LinkedListItem
> {
> void* Source;
> void* Destination;
> void* NextLLI;
> DMAControl Control;
> } DMA_LinkedListItem;
> //Init SSP0 for master mode, 6Mbits/s
> void SSP0_Init()
> {
> //set I/O pin config for LPC2468
> //available pins:
> //SCK0 P0.15 P1.20 P2.22
> //SSEL0 p0.16 P1.21 P2.23
> //MISO0 p0.17 P1.23 P2.26
> //MOSI0 p0.18 P1.24 P2.27
>
> PINSEL0 |= (2 << 30); //SCK0 on P0.15
> PINSEL1 |= (2 << 0); //SSEL0 on P0.16
> PINSEL1 |= (2 << 2); //MISO0 on P0.17
> PINSEL1 |= (2 << 4); //MOSI0 on P0.18
>
> // enable clock to SSP0 just to make sure. By default, it's
> enabled already
> PCONP |= PCONP_PCSSP0;
> //set PCLK divider for SSP0 to 1
> PCLKSEL1 = (PCLKSEL1 & ~PCLKSEL1_PCLK_SSP0_MASK) | (1 <<
> PCLKSEL1_PCLK_SSP0_BIT);
>
> //NOTE: in slave mode CPSR must be >
> SSP0CPSR = 12; //SCK = CCLK / PCLKdiv /
> CPSR / SCR = 72/1/12/1 = 6 MHz
> SSP0CR0 = 0x000F; //16-bit, SPI, SPO=0, SPH=0, SCR=0
> SSP0CR1 = SSP0CR1_SSE; //Master mode, SSP enabled
>
> }
>
> //init SSP1 for slave mode, 6Mbits/s
> void SSP1_Init()
> {
> //set I/O pin config for LPC2468
> //available pins:
> //SCK1 P0.7 P1.31 P4.20
> //SSEL1 p0.6 P0.14 P4.21
> //MISO1 p0.8 P0.12 P4.22
> //MOSI1 p0.9 P0.13 P2.23
>
> PINSEL0 |= (2 << 14); //SCK0 on P0.7
> PINSEL0 |= (2 << 12); //SSEL0 on P0.6
> PINSEL0 |= (2 << 16); //MISO0 on P0.8
> PINSEL0 |= (2 << 18); //MOSI0 on P0.9
>
> // enable clock to SSP0 just to make sure. By default, it's
> enabled already
> PCONP |= PCONP_PCSSP1;
> //set PCLK divider for SSP0 to 1
> PCLKSEL0 = (PCLKSEL0 & ~PCLKSEL0_PCLK_SSP1_MASK) | (1 <<
> PCLKSEL0_PCLK_SSP1_BIT);
>
> //NOTE: in slave mode CPSR must be >
> SSP1CPSR = 12; //SCK = CCLK / PCLKdiv /
> CPSR / SCR = 72/1/12/1 = 6 MHz
> SSP1CR0 = 0x000F; //16-bit, SPI, SPO=0, SPH=0, SCR=0
> SSP1CR1 = SSP1CR1_MS | SSP1CR1_SSE; //Slave mode, SSP
> enabled
> }
> //this method tests transfering bytes from SSP0 to SSP1 and vice
> versa
> //returns number of errors
> int SPIwithDMA_TestWithoutDMA(int n)
> {
> int errors = 0;
> int i;
> unsigned short s, r, s2, r2;
>
> for (i=0; i
> {
> s = (unsigned short)(123 + (i << 5));
> s2 = (unsigned short)(567 + (i << 6));
>
> SSP1DR = s2;
> SSP0DR = s;
> while ( !(SSP1SR & SSP1SR_RNE) )
> ;
> r = SSP1DR;
> r2 = SSP0DR;
> if (r != s || r2 != s2)
> errors++;
> }
>
> return errors;
> }
> volatile uint PacketsReceived = 0;
> volatile uint DMAErrCount = 0;
> void DMAHandler( void )
> {
> uint regVal;
>
> regVal = DMACIntTCStatus;
> if ( regVal )
> {
> if (regVal & DMACIntTCStatus_IntTCStatus1) //then it
> was the receive channel
> PacketsReceived++;
> DMACIntTCClear |= regVal;
> }
>
> regVal = DMACIntErrorStatus;
> if ( regVal )
> {
> DMAErrCount++;
> DMACIntErrClr |= regVal;
> }
>
> #ifdef VECTORED_IRQ_INTERRUPTS
> VICVectAddr = 0; /* Acknowledge Interrupt */
> #endif //otherwise CrossWorks irq_handler will take care of
this
> }
> bool DMA_Init()
> {
> /* USB RAM is used for test.
> Please note, Ethernet has its own SRAM, but GPDMA can't
> access
> that. GPDMA can access USB SRAM and IRAM. Ethernet DMA
> controller can
> access both IRAM and Ethernet SRAM. */
> PCONP |= PCONP_PCGPDMA; /* Enable GPDMA clock */
>
> /* clear all interrupts on both channels */
> DMACIntTCClear = 0x03;
> DMACIntErrClr = 0x03;
>
> //install DMA interrupt handler
> ctl_set_isr(VICSourceDMA, 1, CTL_ISR_TRIGGER_FIXED,
> DMAHandler, 0);
> ctl_unmask_isr(VICSourceDMA);
>
> //NOTE: it seems the following needs to execute before
> accessing
> // DMACC1Configuration, otherwise the CPU locks up
> DMACConfiguration = 0x01; /* Enable DMA channels,
> little endian */
>
> return true;
> }
> //This function tries to transfer 1 packet from SSP0 to SSP1 with
DMA
> int SPIwithDMA_TestDMATransfer()
> {
> int i, wait=0, errors=0;
>
> //disable SSP from sending DMA requests
> SSP1DMACR = 0;
> SSP0DMACR = 0;
>
> /*Set up DMA channel 0 to stream data from memory to SSP0 */
> DMACC0SrcAddr = (int)sendBuf;
> DMACC0DestAddr = (int)&SSP0DR;
> /* The burst size is set to 8, the size is 8 bit too. */
> /* Terminal Count Int enable */
> DMACC0Control > (sendFrameSize & 0x0FFF)
> //transfer size
> | (1 << DMACC0Control_SBSize_BIT) //source
> burst size
> | (1 << DMACC0Control_DBSize_BIT) //dest.
> burst size
> | (1 << DMACC0Control_SWidth_BIT) //source
> transfer width
> | (1 << DMACC0Control_DWidth_BIT) //dest.
> transfer width
> | (1 << DMACC0Control_SI_BIT)
> //source increment
> | (0 << DMACC0Control_DI_BIT)
> //dest. increment
> | (1 << DMACC0Control_I_BIT);
> //Terminal Count interrupt
>
> /*Set up DMA channel 1 to stream data from SSP1 to memory */
> DMACC1SrcAddr = (int)&SSP1DR;
> DMACC1DestAddr = (int)recvBuf;
> /* The burst size is set to 8, the size is 8 bit too. */
> /* Terminal Count Int enable */
> DMACC1Control > (recvFrameSize & 0x0FFF)
> //transfer size
> | (1 << DMACC0Control_SBSize_BIT) //source
> burst size
> | (1 << DMACC0Control_DBSize_BIT) //dest.
> burst size
> | (1 << DMACC0Control_SWidth_BIT) //source
> transfer width
> | (1 << DMACC0Control_DWidth_BIT) //dest.
> transfer width
> | (0 << DMACC0Control_SI_BIT)
> //source increment
> | (1 << DMACC0Control_DI_BIT)
> //dest. increment
> | (1 << DMACC0Control_I_BIT);
> //Terminal Count interrupt
> //fill send packet with test pattern
> for(i=0; i<0x100; i++)
> {
> sendBuf[i] = i;
> recvBuf[i] = 0;
> }
>
> //src = n/a, dest = SSP0Tx, flow = M2P by P control,
> DMACC0Configuration > (1 << DMACC0Configuration_E_BIT)
> //enable
> | (0 << DMACC0Configuration_SrcPeripheral_BIT)
> //source periph
> | (0 << DMACC0Configuration_DestPeripheral_BIT)
> //dest. periph
> | (1 << DMACC0Configuration_FlowCntrl_BIT)
> //flow ctrl & transfer type
> | (1 << DMACC0Configuration_IE_BIT)
> //Error Int enable
> | (1 << DMACC0Configuration_ITC_BIT)
> //TC Int enable
> | (1 << DMACC0Configuration_L_BIT)
> //Lock AHB
> | (0 << DMACC0Configuration_A_BIT)
> //Active status
> | (0 << DMACC0Configuration_H_BIT);
> //Halt
>
> //src = SSP1Rx, dest = n/a, flow = P2M by P control,
> DMACC1Configuration > (1 << DMACC0Configuration_E_BIT)
> //enable
> | (3 << DMACC0Configuration_SrcPeripheral_BIT)
> //source periph
> | (0 << DMACC0Configuration_DestPeripheral_BIT)
> //dest. periph
> | (2 << DMACC0Configuration_FlowCntrl_BIT)
> //flow ctrl & transfer type
> | (1 << DMACC0Configuration_IE_BIT)
> //Error Int enable
> | (1 << DMACC0Configuration_ITC_BIT)
> //TC Int enable
> | (0 << DMACC0Configuration_L_BIT)
> //Lock AHB
> | (0 << DMACC0Configuration_A_BIT)
> //Active status
> | (0 << DMACC0Configuration_H_BIT);
> //Halt
>
> PacketsReceived = 0;
>
> //Enable the SSP DMA requests, receive first
> SSP1DMACR = (1 << SSP0DMACR_RXDMAE_BIT)
> | (0 << SSP0DMACR_TXDMAE_BIT);
> SSP0DMACR = (0 << SSP0DMACR_RXDMAE_BIT)
> | (1 << SSP0DMACR_TXDMAE_BIT);
>
> while(PacketsReceived < 1)
> wait++;
>
> //check received data
> for(i=0; i
> {
> if (recvBuf[i] != i)
> errors++;
> }
>
> return errors;
> }
> //declare buffers and LLI structs in USB RAM
> byte* TxBuf1 = (byte*)(USB_RAM + 0x200);
> byte* TxBuf2 = (byte*)(USB_RAM + 0x300);
> byte* RxBuf1 = (byte*)(USB_RAM + 0x400);
> byte* RxBuf2 = (byte*)(USB_RAM + 0x500);
> DMA_LinkedListItem* LLI_Tx1 = (DMA_LinkedListItem*)(USB_RAM +
0x600);
> DMA_LinkedListItem* LLI_Tx2 =
(DMA_LinkedListItem*)(USB_RAM +
0x610);
> DMA_LinkedListItem* LLI_Rx1 =
(DMA_LinkedListItem*)(USB_RAM +
0x620);
> DMA_LinkedListItem* LLI_Rx2 =
(DMA_LinkedListItem*)(USB_RAM +
0x630);
>
> int SPIwithDMA_TestLLI()
> {
> int i, wait=0, errors=0;
> unsigned long t0, t1;
>
> //disable both DMA channels while configuring
> // DMACC0Configuration &= ~DMACC0Configuration_E_BIT;
> // DMACC1Configuration &= ~DMACC1Configuration_E_BIT;
>
> //disable SSP from sending DMA requests
> SSP1DMACR = 0;
> SSP0DMACR = 0;
>
> //fill send packet with test pattern
> for(i=0; i<0x100; i++)
> {
> sendBuf[i] = i;
> recvBuf[i] = 0;
> }
>
> /*Set up DMA channel 0 to stream data from memory to SSP0 */
> DMACC0SrcAddr = (int)sendBuf;
> DMACC0DestAddr = (int)&SSP0DR;
> /* The burst size is set to 8, the size is 8 bit too. */
> /* Terminal Count Int enable */
> DMACC0Control > (sendFrameSize & 0x0FFF)
> //transfer size
> | (1 << DMACC0Control_SBSize_BIT) //source
> burst size
> | (1 << DMACC0Control_DBSize_BIT) //dest.
> burst size
> | (1 << DMACC0Control_SWidth_BIT) //source
> transfer width
> | (1 << DMACC0Control_DWidth_BIT) //dest.
> transfer width
> | (1 << DMACC0Control_SI_BIT)
> //source increment
> | (0 << DMACC0Control_DI_BIT)
> //dest. increment
> | (1 << DMACC0Control_I_BIT);
> //Terminal Count interrupt
>
> /*Set up DMA channel 1 to stream data from SSP1 to memory */
> DMACC1SrcAddr = (int)&SSP1DR;
> DMACC1DestAddr = (int)recvBuf;
> /* The burst size is set to 8, the size is 8 bit too. */
> /* Terminal Count Int enable */
> DMACC1Control > (recvFrameSize & 0x0FFF)
> //transfer size
> | (1 << DMACC0Control_SBSize_BIT) //source
> burst size
> | (1 << DMACC0Control_DBSize_BIT) //dest.
> burst size
> | (1 << DMACC0Control_SWidth_BIT) //source
> transfer width
> | (1 << DMACC0Control_DWidth_BIT) //dest.
> transfer width
> | (0 << DMACC0Control_SI_BIT)
> //source increment
> | (1 << DMACC0Control_DI_BIT)
> //dest. increment
> | (1 << DMACC0Control_I_BIT);
> //Terminal Count interrupt
> //src = n/a, dest = SSP0Tx, flow = M2P by P control,
> DMACC0Configuration > (1 << DMACC0Configuration_E_BIT)
> //enable
> | (0 << DMACC0Configuration_SrcPeripheral_BIT)
> //source periph
> | (0 << DMACC0Configuration_DestPeripheral_BIT)
> //dest. periph
> | (1 << DMACC0Configuration_FlowCntrl_BIT)
> //flow ctrl & transfer type
> | (1 << DMACC0Configuration_IE_BIT)
> //Error Int enable
> | (1 << DMACC0Configuration_ITC_BIT)
> //TC Int enable
> | (0 << DMACC0Configuration_L_BIT)
> //Lock AHB
> | (0 << DMACC0Configuration_A_BIT)
> //Active status
> | (0 << DMACC0Configuration_H_BIT);
> //Halt
>
> //src = SSP1Rx, dest = n/a, flow = P2M by P control,
> DMACC1Configuration > (1 << DMACC0Configuration_E_BIT)
> //enable
> | (3 << DMACC0Configuration_SrcPeripheral_BIT)
> //source periph
> | (0 << DMACC0Configuration_DestPeripheral_BIT)
> //dest. periph
> | (2 << DMACC0Configuration_FlowCntrl_BIT)
> //flow ctrl & transfer type
> | (1 << DMACC0Configuration_IE_BIT)
> //Error Int enable
> | (1 << DMACC0Configuration_ITC_BIT)
> //TC Int enable
> | (0 << DMACC0Configuration_L_BIT)
> //Lock AHB
> | (0 << DMACC0Configuration_A_BIT)
> //Active status
> | (0 << DMACC0Configuration_H_BIT);
> //Halt
>
> LLI_Tx1->Source = (void*)
> TxBuf1;
> LLI_Tx1->Destination = (void*)
> &SSP0DR;
> LLI_Tx1->NextLLI > (void*)LLI_Tx2;
> LLI_Tx1->Control.TransferSize = 50;
> LLI_Tx1->Control.SrcBurstSize = 1; //000=1, 001=4,
> 010=8, 011, 1002, 101d, 1108, 111%6
> LLI_Tx1->Control.DstBurstSize = 1;
> LLI_Tx1->Control.SrcWidth = 1; //000its,
> 001bits, 0102bits
> LLI_Tx1->Control.DstWidth = 1;
> LLI_Tx1->Control.SrcIncrement = 1;
> LLI_Tx1->Control.DstIncrement = 0;
> LLI_Tx1->Control.Protection = 0;
> LLI_Tx1->Control.TCIntEnable = 1;
>
> *LLI_Tx2 = *LLI_Tx1;
> LLI_Tx2->Source = (void*)TxBuf2;
> LLI_Tx2->NextLLI = null;
>
> LLI_Rx1->Source = (void*)
> &SSP1DR;
> LLI_Rx1->Destination = (void*)
> RxBuf1;
> LLI_Rx1->NextLLI > (void*)LLI_Rx2;
> LLI_Rx1->Control.TransferSize = 50;
> LLI_Rx1->Control.SrcBurstSize = 1; //000=1, 001=4,
> 010=8, 011, 1002, 101d, 1108, 111%6
> LLI_Rx1->Control.DstBurstSize = 1;
> LLI_Rx1->Control.SrcWidth = 1; //000its,
> 001bits, 0102bits
> LLI_Rx1->Control.DstWidth = 1;
> LLI_Rx1->Control.SrcIncrement = 0;
> LLI_Rx1->Control.DstIncrement = 1;
> LLI_Rx1->Control.Protection = 0;
> LLI_Rx1->Control.TCIntEnable = 1;
>
> *LLI_Rx2 = *LLI_Rx1;
> LLI_Rx2->Destination = (void*)RxBuf2;
> LLI_Rx2->NextLLI = null;
>
> for (i=0; i<0x100; i++) TxBuf1[i] = 0xAA;
> for (i=0; i<0x100; i++) TxBuf2[i] = 0xBB;
> for (i=0; i<0x100; i++) RxBuf1[i] = 0x00;
> for (i=0; i<0x100; i++) RxBuf2[i] = 0x00;
>
> DMACC0LLI = (int)LLI_Tx1;
> DMACC1LLI = (int)LLI_Rx1;
>
> PacketsReceived = 0;
> t0 = CTC;
> //Enable the SSP DMA requests, receiver first
> SSP1DMACR = (1 << SSP0DMACR_RXDMAE_BIT)
> | (0 << SSP0DMACR_TXDMAE_BIT);
> SSP0DMACR = (0 << SSP0DMACR_RXDMAE_BIT)
> | (1 << SSP0DMACR_TXDMAE_BIT);
>
> while(PacketsReceived < 3)
> wait++;
> t1 = CTC;
> debug_printf("TestLLI wait cycles: %d \r\n", wait);
> debug_printf("TestLLI time (ticks): %d \r\n", t1-t0);
>
> //check received data
> for(i=0; i
> if (recvBuf[i] != i)
> errors++;
> for (i=0; i<50; i++)
> if (RxBuf1[i] != TxBuf1[i])
> errors++;
> for (i=0; i<50; i++)
> if (RxBuf2[i] != TxBuf2[i])
> errors++;
>
> return errors;
> }
> void SPIwithDMA_Init()
> {
> int e, w;
>
> SSP0_Init();
> SSP1_Init();
> DMA_Init();
>
> e = SPIwithDMA_TestWithoutDMA(1000000);
> debug_printf("TestWithoutDMA returned %d errors\r\n", e);
> e = SPIwithDMA_TestDMATransfer();
> debug_printf("TestDMATransfer returned %d errors\r\n", e);
> e = SPIwithDMA_TestLLI();
> debug_printf("TestLLI returned %d errors\r\n", e);
> }
>
> --- In lpc2000@yahoogroups .com, "Ivan
Wu" wrote:
> >
> > Hi Mark,
> >
> > can you send me your code?
> > I am also have problem using the SPI.
> > Many thanks!
> >
> >
> > On 5/5/07, arjanverheij wrote:
> > >
> > > Mark,
> > >
> > > I just now got SSP with DMA working on a LPC2468. If you haven't
> > > resolved your problem I can send you my code.
> > >
> > > Arjan.
> > >
> > > --- In lpc2000@yahoogroups .com
> 40yahoogroups.com>, "markcrow"
> > > wrote:
> > > >
> > > > Using the sample code (from
> > > code.lpc23xx.lpc24xx.peripherals.usvision)
> > > > I got GP DMA to drive the SSP1 port (in SPI mode) on a
> LPC2368. I
> > > > ported that code over to a LPC2468 and now it won't work
(using
> > > SSP0
> > > > this time and also in SPI mode). I get a watchdog reset when I
> > > set the
> > > > Channel Enable bit in the Channel 0 configuration register. I
> > > have
> > > > meticulously checked every setting and every address on every
> > > GPDMA
> > > > register and can make no sense of this. The watchdog reset is
> not
> > > > legitimate as the watchdog timer is set to over 3 seconds and
> the
> > > reset
> > > > occurs instantaneously when the register is written to.
> > > >
> > > > Has anyone seen anything like this? Anyone using a LPC24xx and
> > > driving
> > > > an SSP via DMA with success?
> > > >
> > > > Thanks
> > > >
> > >
> > >
> > >
> >
> >
> >
> > --
> > B.R.
> > Ivan Wu (Өǿ)
> >
> >
> >
>
Yahoo! Groups Links