Forum: Mikrocontroller und Digitale Elektronik ARM7 LPC2364 Probleme mit DMA


von Martin F. (godmen)


Lesenswert?

Hallo zusammen,

ich hoffe ich schreibe hier in das richtige Unterforum, konnte mich 
nicht entscheiden wo das jetz hingehört.

Ich bin Anfänger was ARM7 angeht und muss für meine Bachelorthesis nun 
einen LPC2364 von NXP programmieren. Das Ding soll später mal ein 
CAN-Telegramm empfangen und über SSP0 (SPI-Interface) an einen FPGA 
übergeben. Genauso soll vom FPGA ein CAN-Telegramm an SSP1 einkommen und 
wieder auf den CAN-Bus gesendet werden.
Zum Test habe ich nun einfach mal beide SPI schnittstellen verbunden.
Das Senden und Empfangen an den SPI Schnittstellen läuft dabei über DMA. 
Ich schreibe in einen Pufferspeicher eine CAN-Nachricht und Sende diese 
mit DMA Kanal 0 über SSP0 und Empfange mit DMA Kanal 1 an SSP1 das 
Telegramm und schreibe es in einen anderen Pufferspeicher.
Der CAN-Controller schreibt/ließt dabei aus dem entsprechenden Puffer um 
mit dem CAN-Bus zu kommunizieren.

So weit so gut. Ich habe nun zwei Probleme mit dem DMA.

1. Ich muss den DMA zum Empfangen insgesammt 3 mal Inizialisieren bis er 
richtig läuft (1 mal Initialisieren und garnichts passiert, 2. mal 
Initialisieren und es wird nur Datenmüll in den Puffer geschrieben, 
3.mal Initialiseren und alles läuft perfekt).
Das die SPI Nachricht dabei immer korrekt gesendet wird habe ich mit dem 
Oszi überprüft (das Ding beherscht SPI).
Wieso muss ich hier 3mal initialisieren, bzw. wo soll ich hier denn 
Anfangen nach dem Fehler zu suchen. Die Initialisierung ist immer 
gleich, ich wiederhole sie einfach in einer Schleife.

2. Nach dreimaligem Initialsieren läuft alles. Bis nach einer 
unbestimmten Anzahl CAN-Telegramme der Controller einen Reset macht (da 
gibts keine Regelmäßigkeit). Also wie wenn ich die Spannung abgezogen 
hätte beginnt er wieder mit der Initialisierung. Ich habe weder ein 
Watchdog noch sonstetwas laufen, dass diesen Reset auslößen könnte. 
Jemand Erfahrung mit sowas?

Falls ich hier irgendwelchen Code oder sonstwas anhängen soll, bitte 
bescheid geben.

Gruß
Martin

von Microman (Gast)


Lesenswert?

Hallo Martin,

habe auch schon mit dem LPC2364 und SSP sowie DMA gearbeitet. Hat alles 
wie gewünscht, stabil und nachvollziehbar funktioniert. Ich denke Du 
mußt wohl doch etwas Sourcecode posten, um dem Problem auf die Spur zu 
kommen.

Gruß Microman

von Martin F. (godmen)


Angehängte Dateien:

Lesenswert?

Hallo Microman,

danke für die Antwort. Habe mal alle .c und .h Files angehängt. Ich 
hoffe du findest dich zurecht. In der main.c wird verständlicherweiße 
die Mainloop abgearbeitet. In der DMA.c und SSP.c sind die 
Initialisierungsfunktionen für DMA und SPI. In der transfer.c sind die 
Funktionen die die eigentliche Arbeit machen.
Einige Funktionen werden nicht aufgerufen oder dienen nur dazu mir 
Speicherinhalte beim Debuggen an zu zeigen. Also nicht wündern. Ach sind 
viele Kommentare drinn was noch so fehlt, aber das ganze ist eben noch 
eine Baustelle.

Um den Download zu sparen habe ich die beiden funktionen die den DMA 
initialisierne mal noch als Text:

Erstmalige Initialisierung des DMA:
1
int32_t DmaInit( int32_t channelNum, int32_t frameSize, int32_t frameAddress )
2
{
3
4
  PCONP |= (1 << 29);  /* Enable GP DMA clock, */
5
  
6
  GPDMA_INT_TCCLR = 0x03; /* Clear any pending interrupts */
7
  GPDMA_INT_ERR_CLR = 0x03; /* Clear error interrupt requests */
8
  
9
  if ( channelNum == 0 )
10
  {   
11
    /* Ch0  memory to SSP0. */
12
    GPDMA_CH0_SRC = frameAddress;
13
    GPDMA_CH0_DEST = DMA_SSP0DR;
14
    /* The burst size is set to 8, the size is 8 bit too. */
15
    /* Terminal Count Int enable */
16
    GPDMA_CH0_CTRL = (frameSize & 0x0FFF) | (0x02 << 12) | (0x02 << 15) | (1 << 26) | 0x80000000;
17
    
18
  }
19
  
20
  else if ( channelNum == 1 )
21
  {   
22
  
23
    /* Ch1 SSP1 to memory. */
24
    GPDMA_CH1_SRC = DMA_SSP1DR;
25
    GPDMA_CH1_DEST = frameAddress;
26
    /* The burst size is set to 4, the size is 8 bit too. */
27
    /* Terminal Count Int enable */
28
    GPDMA_CH1_CTRL = (frameSize & 0x0FFF) | (0x02 << 12) | (0x01 << 15) | (1 << 27) | 0x80000000;
29
    GPDMA_CH1_CFG |= 0x08001 | (0x03 << 1) | (0x02 << 11);  
30
  }
31
    
32
  /*else
33
  {
34
    return ( FALSE );
35
  } */
36
37
  GPDMA_CONFIG = 0x01;
38
39
  while ( !(GPDMA_CONFIG & 0x01) );    
40
  
41
  if ( install_irq( GPDMA_INT, (void *)DMAHandler, HIGHEST_PRIORITY ) == FALSE )
42
  {
43
    return ( FALSE );
44
  }
45
  return (TRUE);
46
}



Alle weiteren neu Initialisierungen nach dem Empfang von Daten:
1
int32_t DmaReInit( int32_t channelNum, int32_t frameSize, int32_t frameAddress )
2
{
3
  
4
  if ( channelNum == 0 )
5
  {   
6
    /* Ch0  memory to SSP0. */
7
    GPDMA_CH0_SRC = frameAddress;
8
    GPDMA_CH0_DEST = DMA_SSP0DR;
9
    /* The burst size is set to 8, the size is 8 bit too. */
10
    /* Terminal Count Int enable */
11
    GPDMA_CH0_CTRL = (frameSize & 0x0FFF) | (0x02 << 12)  | (0x01 << 15) | (1 << 26) | 0x80000000;     //wieso an stelle 15 ein 0x01 statt 0x02
12
    GPDMA_CH0_CFG |= 0x10001 | (0x00 << 1) | (0x01 << 11) | (0x00 << 15);    
13
  }
14
  
15
  else if ( channelNum == 1 )
16
  {     
17
    /* Ch1 SSP1 to memory. */
18
    GPDMA_CH1_SRC = DMA_SSP1DR;
19
    GPDMA_CH1_DEST = frameAddress;
20
    /* The burst size is set to 8, the size is 8 bit too. */
21
    /* Terminal Count Int enable */
22
    GPDMA_CH1_CTRL = (frameSize & 0x0FFF) | (0x02 << 12) | (0x02 << 15) | (1 << 27) | 0x80000000;
23
    GPDMA_CH1_CFG |= 0x00001 | (0x03 << 1) | (0x06 << 11);
24
  }
25
    
26
  else
27
  {
28
    return ( FALSE );
29
  }  
30
  return (TRUE);
31
}

von Microman (Gast)


Lesenswert?

Hallo Martin,

habe nur mal schnell drüber geschaut, aber leider huete nicht viel Zeit 
mir das genauer anzusehen. Werde es aber noch mit meinen Routine 
vergleichen. was mir auffällt in DmaReInit bei Channel-0 steht die 
Zeile:

GPDMA_CH0_CFG |= 0x10001 | (0x00 << 1) | (0x01 << 11) | (0x00 << 15);

Diese fehlt aber in der DmaInit Funktion. Ist das so korrekt?

Gruß Microman

von Martin F. (godmen)


Lesenswert?

Hallo Microman,

ja das ist korrekt, der CH0 wird beim erstmaligen Initialisieren nicht 
mit initialisiert, die if Verzweigung ist quasi nur ein relikt aus der 
Programmentstehung.

Gruß
Martin

von Microman (Gast)


Lesenswert?

Hallo Martin,

kurze Frage, hast Du immer noch die Probleme mit dem DMA?
Würde Dir sonst mal meine Sourcen raussuchen, die Du dann mal testen 
könntest.


Gruß

von Martin F. (godmen)


Lesenswert?

Hallo Microman,

habe den Fehler ende letzte Woche gefunden. Hatte letztendlich 
eigentlich garnichts mit dem DMA zu tun, hatte in einem Interrupt 
ausversehen "nested interrupts" aktiviert (besser nicht zuviel aus 
Beispielen abschreiben...). Wurde diser nun zufällig ausgelöst kam es 
zum Programmabsturz (hatte ja die Register nicht gesichert, da ich nie 
die Absicht hatte nested interrupts zu verwenden) bzw. fehlverhalten.
Nested interrupts deaktiviert und schon funktioniert alles.

An dieser Stelle nochmal Danke für deine Hilfe und deine Mühe!!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.