Forum: Mikrocontroller und Digitale Elektronik SPI0 als Slave mit ARM7 LPC2148


von Geri (Gast)


Lesenswert?

Hallo zusammen

Ich versuche gerade am LPC2148 die SPI0 als Slave zu codieren.

Der Sender sendet Daten an den Slave (beide Boards mit LP2148).

Der Datenempfang funktioniert über eine Interruptroutine einwandfrei. 
Versuche ich hingegen Daten an den Master zurück zu senden, dann sendet 
der Slave mehr oder weniger Schrott. Das sehe ich, wenn ich den Ausgang 
MISO am Oszi, getriggert mit SEL0 anlege.

Das Senden funktioniert auch in der ISR. Zuvor wird der Sendepuffer
durch den Aufruf von SPI0WriteBuf(...) initialisiert. Das findet 
unmittelbar nach dem Detenempfang statt.
1
unsigned char SPI0_tx_buffer[50];
2
unsigned char SPI0_tx_len;
3
unsigned char SPI0_tx_Idx;
4
5
void SPI0WriteBuf(unsigned char* buf, unsigned char size)
6
{
7
    unsigned char i;
8
    unsigned char crc=0;
9
    
10
    memcpy(&SPI0_tx_buffer[0],buf,size);
11
    for (i=0; i< size; i++)
12
    {
13
        crc = crc8_Table[crc ^ SPI0_tx_buffer[i+3]];
14
    }
15
    SPI_tx_buffer[size] = crc;
16
    SPI0_tx_len = size + 1;
17
    SPI0_tx_len--;
18
    SPI0_tx_Idx++;  
19
    S0SPDR = SPI0_tx_buffer[0]; // fülle Puffer mit erstem Element
20
}
21
22
static void SPI0_Isr(void)
23
{
24
  static uint8_t NewData;
25
  static uint16_t Idx = 0;
26
  static uint8_t Mode = 0;
27
    
28
   if ((S0SPSR & 0x70) !=0)         // check status register for error
29
  {                                
30
    NewData = S0SPSR;
31
  }
32
  else
33
   if (Mode == 0x01)   // check if slave in send mode
34
  {
35
    NewData = S0SPDR;  
36
37
    if (SPI0_tx_len > 0)
38
    {
39
      SPI0_tx_len--;
40
      S0SPDR = SPI0_tx_buffer[SPI0_tx_Idx++];      
41
    }
42
    else
43
    {
44
      Mode = 0x00; // switch slaave to receive mode
45
    }
46
  }
47
  else
48
  {
49
    NewData = S0SPDR;   // read data received    
50
    // snip,  Verarbeitung empfanger Daten
51
    
52
  }
53
  S0SPINT  = 0x01;               // reset interrupt flag
54
  VICVectAddr = 0;               // reset VIC
55
}

Habt ihr vielleicht ein Idee

Vielen Dank für Eure Anregungen

Geri

von Geri (Gast)


Lesenswert?

Hm, vielleicht liegt es dran..

http://www.standardics.nxp.com/support/documents/microcontrollers/pdf/errata.lpc2148.pdf

Der Slave ist mit   S0SPCR   = 0x80; initialisiert (CPOL = 0; CHPA=0);

SCR beim Master = 0x20; // ca. 100 KHz

von Ralph (Gast)


Lesenswert?

Du wirst nie in den Sendepfad deiner ISR routine gelangen.
Zu Beginn der ISR initialisierst du Mode mit "0".
Da Mode danach niemals auf 0x01 gesetzt wird, ergibt sich daraus, das du 
bei der IF abfrage IMMER in den ELSE Pfad springst.
Sollte Mode extern geändert werden, dann muss Mode eine Globale und 
keine Locale Variable sein, und zudem mit dem Zusatz "volatile".

Der Slave sendet somit das was gerade im hardwarebuffer der SPI steht, 
und nicht das was du im SPI0_tx_buffer stehen hast.

von Geri (Gast)


Lesenswert?

Hallo Ralph

Vielen Dank für Deine Rückmeldung!

Ich habe in der ISR einen Teil herausgenommen. Gekennzeichnet mit

" // snip,  Verarbeitung empfanger Daten "

Sorry für die Konfusion, dieses Flag hätte ich im Thread nicht 
herausnehmen sollen.

In dieser Emfangsroutine wir nach erfolgreichem Empfang Mode auf 0x01 
gesetzt. Die ISR springt dann auch in den Sendeteil rein, das habe ich 
geprüft. Ich habe nach Angaben des Erata sheet dann noch verschiedene 
Konfigurationen mit CHPA =1 und höheren Taktraten versucht, allerdings 
erfolglos.

In der Zwischenzeit habe ich den Code nach SPI1 portiert und siehe da, 
die Kommunikation funktioniert einwandfrei. SPI1 ist dazu noch 
leistungsfähiger.

SPI0 als Slave würde ich nach meinem aktuellem Wissenstand niemand 
empfehlen. Vielleicht kann mir aber noch jemand das Gegenteil beweisen:)

Beste Grüsse

Geri

von Geri (Gast)


Lesenswert?

Hallo

Ich bin nun auf die SSP umgestiegen

Master (LPC2148) und Slave (LPC2148)


Das Senden von Daten vom Master zum Slave funktioniert einwandfrei. 
Möchte ich jedoch Daten vom Slave empfangen, dann wird - soweit ich es 
aktuell sehe - das erste Datenbyte vom Master mehrmals gelesen.


Die Receive-Routine beim Master sieht so aus:
1
unsigned char SpiReceiveByte( void )
2
{
3
  unsigned char incoming;
4
5
         while( !(SSPSR & (1<<TNF)) ) ;
6
  SSPDR = 0xFF;   /* wrtie dummy byte out to generate clock, then read data from MISO */ 
7
  while( !(SSPSR & (1<<RNE)) ) ;
8
  incoming = SSPDR;
9
  return(incoming);
10
}

Die Sende-Routine beim Slave sieht so aus:
1
unsigned char SpiSendByte(unsigned char outgoing)
2
{
3
  unsigned char incoming;
4
  
5
  while( !(SSPSR & (1<<TNF)) ) ; // wait until at least one byte if free in Fifo-Buffer
6
  SSPDR = outgoing;
7
  while( !(SSPSR & (1<<RNE)) ) ; // receive buf not empty
8
  incoming = SSPDR;
9
  return(incoming);
10
}

Beide Schnittstellen sind mit fClk = 333333 Hz initialisiert. CPOL = 0;

Hat jemand vielleicht eine Idee woran es liegen könnte

Vielen Dank und beste Grüsse

Geri

von Geri (Gast)


Lesenswert?

Noch eine Zusatzinfo. Soviel ich hier mit dem Oszi messen kann, sendet 
der Slave die richtigen Daten. Ich denke, es liegt demnach beim Master.

von Geri (Gast)


Lesenswert?

Hallo

Ich komme hier aber einfach nicht weiter.

Gibt es ausser dem Datenblatt von NXP eigentlich ein anderes brauchbares 
Dokument in dem die Programmierung der SPI1 erklärt wird?

Vielen Dank für einen Tipp

Geri

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.