Forum: Mikrocontroller und Digitale Elektronik SPI unstabil


von Yaro (Gast)


Lesenswert?

Hallo Leute,

ich bin gerade dabei, mir ein LCD-Modul zu basteln, was ich über I2C und 
über SPI ansteuern kann. Auf dem Modul sitzt ein ATmega8, angesprochen 
wird es auch von ATmegas.
I2C funktioniert schon, allerdings habe ich mit dem SPI Probleme...
Manchmal funktioniert die Übertragung schlecht, manchmal garnicht, 
manchmal bricht sie zusammen...
Habe schon öfter mit SPI gearbeitet, aber noch nie solche Probleme 
gehabt...
Habe die beiden Platinen mit einem Flachbandkabel verbunden, schon 2 
verschiedene Sender ausprobiert (um Hardwarefehler auszuschließen). Auf 
dem LCD-Modul sollte auch kein Hardware-Fehler sein, die Leitungen sind 
sauber von einander getrennt.

Ansteuerroutinen sind folgende (Ausschnitt)
Sender
1
void lcdSPIInit(uint8_t operation){ //1: save SPI-settings, Init lcd SPI; 0: restore SPI
2
  static uint8_t spcr;
3
  static uint8_t spiPort, spiDDR;
4
5
  if(operation == 1){
6
    spcr = SPCR;
7
    spiPort = SPI_PORT;
8
    spiDDR = SPI_DDR;
9
10
    CHIPSELECT_DDR |= (1<<CHIPSELECT_PIN);
11
12
    SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);
13
    SPI_PORT |= (1<<MOSI_PIN) | (1<<SCK_PIN);
14
    SPI_DDR |= (1<<MOSI_PIN) | (1<<SCK_PIN);
15
    CHIPSELECT_PORT &= ~(1<<CHIPSELECT_PIN);
16
  }else if(operation == 0){
17
    CHIPSELECT_PORT |= (1<<CHIPSELECT_PIN);
18
    _delay_us(1);
19
    SPI_DDR = spiDDR;
20
    SPI_PORT = spiPort;
21
    SPCR = spcr;
22
  }
23
24
}
25
26
void lcdSPI_data(char data){   //Char ausgeben
27
  lcdSPIInit(1);
28
  SPDR = data;
29
  while(!SPI_READY);
30
  _delay_us(10);
31
  SPDR = 1;
32
  while(!SPI_READY);
33
  lcdSPIInit(0);
34
  _delay_ms(5);
35
}
36
37
void lcdSPI_string(char *data){    //Char-Array ausgeben
38
  lcdSPIInit(1);
39
  while(*data){
40
    SPDR = *data;
41
    while(!SPI_READY);
42
    _delay_us(20);
43
    data++;
44
  }
45
  SPDR = '\0';
46
  while(!SPI_READY);
47
  _delay_us(20);
48
  SPDR = 2;
49
  while(!SPI_READY);
50
  lcdSPIInit(0);
51
  _delay_ms(5);
52
}


Empfänger:
1
int main(void){
2
  volatile char i;
3
4
  _delay_ms(10);
5
  extern char buf[17];
6
  SPIInit();
7
  TWIInit();
8
  lcd_init();
9
  DDRC |= 0x08;  //Hintergurndbeleuchtung
10
  PORTC &= ~0x08; //aus
11
12
  buf[16] = 0;  //absicherung, um ein unabgeschl. Array zu vermeiden
13
14
  sei();
15
16
  while(1){
17
    i++;
18
  }
19
20
  return 0;
21
}
22
23
24
void SPIInit(void){
25
  DDRB &= ~0x2C;  //SCK,MOSI,SS is Input
26
  DDRB |= 0x10;   //MISO Output
27
28
  SPCR = (1<<SPIE) | (1<<SPE);
29
}
30
31
32
ISR(SPI_STC_vect){
33
  extern uint8_t data, bufpos;
34
  extern char buf[17];
35
36
  data = SPDR;
37
38
  if(data <= 31 && data != 0){
39
    switch(data){
40
      case 1:
41
        lcd_data(buf[0]);
42
      break;
43
      case 2:
44
        lcd_string(buf);
45
      break;
46
      case 3:
47
        lcd_clear();
48
      break;
49
      case 4:
50
        lcd_set_cursor(buf[0]-40, buf[1]-40);
51
      break;
52
      case 5:
53
        PORTC |= 0x08;  //Hintergrundbeleuchtung an
54
      break;
55
      case 6:
56
        PORTC &= ~0x08;  //Hintergrundbeleuchtung aus
57
      break;
58
      default: lcd_string("SPI-ERROR!!");
59
    }
60
    bufpos = 0;
61
  }else if(bufpos < 16){
62
      buf[bufpos++] = data;
63
  }
64
}

Ich sitzt schon seit einigen Stunden an diesem Problem, komme dem Fehler 
aber nicht auf die schliche...

Sieht jemand vielleicht was?

Gruß, Yaro

von Yaro (Gast)


Lesenswert?

Wenn ich mit lcdSPI_data(char data) sende, kommt es seltener zu 
Störungen.
Wenn ich mit lcdSPI_string(char *data) "Hello World" sende, dann ist der 
häufigste Fehler, dass statt dem o ein y ankommt, und der 
zweithäufigste, dass statt dem l ein c kommt... Oder es kommt überhaupt 
kein String an...
Die Fehler sind zwar oft die selben, lassen sich aben nicht (nicht in 
der gleichen Reihenfolge) reproduzieren, sondern sind zufällig.

Gruß, Yaro

von Yaro (Gast)


Lesenswert?

Ich bekomme das Problem ein wenig in Griff, wenn ich nach jedem Byte die 
SS-Leitung hoch und dann wieder runterziehe, um das SPI zu resetten. 
Dann verliere ich beim Senden zwar öfters mal einen Buchstaben, aber der 
Rest bleibt ok.
Trotzdem ist das doch kein wünschenswerter Zustand!
Ich hab mit SPI bisher noch nie solche Probleme gehabt! Es lief immer 
ohne Probleme!

Woran könnte sowas liegen?
Ich bin für jeden Tip dankbar!

Gruß, Yaro

von Peter D. (peda)


Lesenswert?

Du mußt das SPI im Empfänger puffern, da das LCD langsam ist.
Besonders ein Clear ist grausam, sollte man aber eh nicht verwenden, da 
dann das LCD flackert.
Professioneller ist, immer den Text überschreiben.


Peter

von Stefan E. (sternst)


Lesenswert?

Du "überfährst" den Empfänger wahrscheinlich einfach. Bedenke, dass dort 
Software die Bytes einzeln abholen muss. Und durch die LCD-Routinen im 
SPI-Interrupt ist es obendrein manchmal ziemlich langsame Software.

von Yaro (Gast)


Lesenswert?

Ich puffere den Empfänger. Auf das LCD gebe ich den Text erst dann aus, 
wenn das letzte Zeichen angekommen ist.
Ich schreibe zuerst alles in den Puffer, danach kommt dann das 
Steuerzeichen, mit dem das Modul weiß, was es mit den angekommenen Bytes 
tun soll.

Gruß,  Yaro

von Yaro (Gast)


Lesenswert?

Habe gerade mal den Prescaler verändert... ob ich ihn auf 16 oder auf 
128 habe, die Fehler sind die selben.

von bensch (Gast)


Lesenswert?

Wenn die SPI-Moden der beiden Teile nicht zusammenpassen, gibt's 
Timing-Probleme.

von Yaro (Gast)


Lesenswert?

Ursache gefunden! Begründung nicht!
Wenn ich im LCD-Modul MISO nicht als Output deklariere, dann geht alles 
ohne Fehler... (benutze MISO sowieso nicht)
Wie kann das sein?

Gruß, Yaro

von Flo (Gast)


Lesenswert?

Schaltplan bitte :-)

von Yaro (Gast)


Angehängte Dateien:

Lesenswert?

Im Schaltplan ist eigentlich nix besonderes...
Hab die Anschlüsse nicht beschriftet, aber da da kaum was ist, sollte 
man es erkennen.

Gruß, Yaro

von Yaro (Gast)


Lesenswert?

Außerdem stimmen die Werte an den Kondensatoren nicht...
Hatte nicht geplant, diesen Schaltplan jemandem zu zeigen....*schäm*

von Benjamin S. (recycler)


Lesenswert?

Du solltes Pullup- und Pulldown Widerstände verwenden. Dann schauts 
besser aus. Ausserdem auf das Timing achten.

von Yaro (Gast)


Lesenswert?

Wo sollen die Pullups und Pulldowns denn hin?
Ich dachte immer, SPI braucht keine externe Beschaltung.

Gruß, Yaro

von Benjamin S. (recycler)


Lesenswert?

Je schneller die Daten über den Bus gehen, umso mehr musst du an 
Beschaltung bzw. Layout machen. Bei MOSI MISO SCK nach GND und bei CS 
AUF VCC. Nimm mal 10k, wenn das zu viel ist, dann 1k. Das brauchst du, 
weil du immer Kapazitäten auf der Leitung hast.
Bei mir ging das bis 25 MHz gut, dann mochte der Controller nimmer.

von Yaro (Gast)


Lesenswert?

Werde ich beim nächsten Schaltplan berücksichtigen, danke!
Aber eine Antwort darauf, wieso  es mit MISO nicht geht und ohne schon.
Arbeite mit 16MHz, prescaler 16.

Gruß, Yaro

von Yaro (Gast)


Lesenswert?

EDIT: Aber eine Antwort darauf, wieso  es mit MISO nicht geht und ohne 
schon ...ist es nicht....
Sorry, bin im Moment echt ein bisschen gestresst....

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.