Forum: Mikrocontroller und Digitale Elektronik [ATmega644PA] SPI: SPIF wird auf einer Hardware gesetzt, auf anderer nicht


von J. W. (jw-lighting)


Angehängte Dateien:

Lesenswert?

Moin,

langsam gehen mir die Ideen aus.

Ich habe hier zwei verschiedene PCBs, eins dient als Entwicklungsboard 
für die Software, das andere soll die finale Hardware für unser Produkt 
werden.

Auf dem Entwicklungsboard sind Display (EA-DOGM128), RS-232 für 
Debugging und Taster integriert.

Das finale PCB enthält nur den Controller mit dem üblichen Hühnerfutter 
drum herum und gibt die Signale über einen Pfostenstecker an die Platine 
in der Frontplatte mit Display und Co weiter.

Für das EA-DOGM128 nutze ich SPI. Auf dem Entwicklungsboard funktioniert 
das prima.

Auf dem finalen PCB wird mit der selben Software allerdings (soweit habe 
ich den Fehler eingegrenzt) wohl SPIF nicht gesetzt, sodass sich der 
Controller im while festfährt. SS habe ich als Ausgang (für CS vom 
Display) gesetzt!

Ich habe schon ausgeschlossen, dass die Leiterbahnen für's SPI 
untereinander, gg. 5V oder GND kurzgeschlossen sind.

Mir gehen die Ideen aus, wo das Problem liegen könnte... Habe auch schon 
den Controller getauscht.

PD5 nutze ich hier zum debuggen (DDRD wird dafür in main() gesetzt):

1
#define DOGM_SET_DDR()          DISPDDR |= (1<<DISPCS)|(1<<DISPRESET)|(1<<DISPA0)
2
#define DOGM_INIT_SPI()         SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA);\
3
                                SPSR = (1 << SPI2X);
4
#define DOGM_SELECT()           DISPPORT &= ~(1<<DISPCS)
5
#define DOGM_UNSELECT()         DISPPORT |= (1<<DISPCS)
6
#define DOGM_COMMAND()          DISPPORT &= ~(1<<DISPA0)
7
#define DOGM_DATA()             DISPPORT |= (1<<DISPA0)
8
#define DOGM_RESET()            DISPPORT &= ~(1<<DISPRESET)
9
#define DOGM_RUN()              DISPPORT |= (1<<DISPRESET); SPSR |= (1 << SPIF)
10
11
#define DOGM_SPIDR              SPDR
12
#define DOGM_BUSY_WAITING()     while(!(SPSR & (1<<SPIF)));
13
14
void dogm_init(void) {
15
    DOGM_SET_DDR();
16
    dogm_init_spi();
17
18
    // ...
19
}
20
21
inline void dogm_send(uint8_t byte) {
22
23
    PORTD |= (1 << PD5);
24
25
    uint8_t SPCRbak, SPSRbak;
26
    SPCRbak = SPCR;
27
    SPSRbak = SPSR;
28
29
    DOGM_INIT_SPI();
30
31
    DOGM_SELECT();
32
    DOGM_SPIDR = byte;
33
    DOGM_BUSY_WAITING();
34
35
    PORTD &= ~(1 << PD5);
36
37
    DOGM_UNSELECT();
38
39
    // tidy up
40
    SPCR = SPCRbak;
41
    SPSR = SPSRbak;
42
43
}
44
45
void dogm_init_spi(void) {
46
    DISPDDR |= (1 << DISPMOSI) | (1 << DISPSCK);
47
}

Auf dem Entwicklungsboard wird PD5 kurz gesetzt und dann wieder 
zurückgesetzt.
Auf dem finalen PCB bleibt PD5 gesetzt.

Zweiter Versuch, diesmal Rücksetzen vor dem Wait:

1
inline void dogm_send(uint8_t byte) {
2
3
    PORTD |= (1 << PD5);
4
5
    uint8_t SPCRbak, SPSRbak;
6
    SPCRbak = SPCR;
7
    SPSRbak = SPSR;
8
9
    DOGM_INIT_SPI();
10
11
    DOGM_SELECT();
12
    DOGM_SPIDR = byte;
13
14
    PORTD &= ~(1 << PD5);
15
16
    DOGM_BUSY_WAITING();
17
    DOGM_UNSELECT();
18
19
    // tidy up
20
    SPCR = SPCRbak;
21
    SPSR = SPSRbak;
22
23
}
So sehe ich komischerweise gar keinen Puls an PD5 mehr.


Bilder der PCB-Layouts habe ich angehängt (MCU ist die, die NICHT 
funktioniert).
Auf der MCU-Platine mussten wir den Quarz etwas improvisiert auflöten, 
er hat aber Takt und ich kann beobachten, dass er nach dem Anlegen der 
Spannung kurz normal arbeitet. Daher denke ich nicht, dass ich ein 
Problem mit dem Takt habe?.


Ich hoffe auf eure Hilfe, vielleicht habt ihr ja Ideen, oder ein 
ähnliches Problem schon mal gelöst.

Viele Grüße :)

von Falk B. (falk)


Lesenswert?

Man MUSS das SS Pin als Ausgang definieren, siehe Datenblatt, "SS pin 
functionality".

von J. W. (jw-lighting)


Lesenswert?

> Man MUSS das SS Pin als Ausgang definieren, siehe Datenblatt, "SS pin
> functionality".
Jo, habe ich gemacht. Wäre das nicht der Fall, würde es ja auf beiden 
Boards nicht laufen...

> SS habe ich als Ausgang (für CS vom Display) gesetzt!

SS ist DISPCS im Code oben und damit PB4

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

>inline void dogm_send(uint8_t byte) {

...

Was soll der Schnee mit dem Backup der SPI-Register? Im Extremfall kann 
man sich damit ins Knie schießen, denn dort sind sensitive Bits drin.
Warum wir bei jedem Aufruf das SPI immer neu initialisiert?

DOGM_INIT_SPI();

Ausserdem fehlt dort das Einschalten des SPI-Moduls mit dem Enable Bit.
Alles in Allem ganz schön akademisch.

von J. W. (jw-lighting)


Lesenswert?

OK, weitere Erkenntnisse:

Die Konfiguration der DD-Register wird noch durchgeführt. (DISPRESET 
wird high).

Es erscheinen aber nie Daten oder Clock an MOSI bzw. SCK.

DISPCS ist tatsächlich low, würde aber ja zusammen mit den anderen Pins 
als Ausgang konfiguriert.

von J. W. (jw-lighting)


Lesenswert?

Falk B. schrieb:
>>inline void dogm_send(uint8_t byte) {
>
> ...
>
> Was soll der Schnee mit dem Backup der SPI-Register? Im Extremfall kann
> man sich damit ins Knie schießen, denn dort sind sensitive Bits drin.
> Warum wir bei jedem Aufruf das SPI immer neu initialisiert?
>
> DOGM_INIT_SPI();
>
> Ausserdem fehlt dort das Einschalten des SPI-Moduls mit dem Enable Bit.
> Alles in Allem ganz schön akademisch.

Danke für deinen Einwand! Was genau meinst du mit "sensitive Bits"? Auf 
der anderen Hardware gab es nie Probleme damit.

Ich nutze SPI auch (mit anderer Taktrate) um den zweiten Controller 
(ATtiny45) für High-Speed PWM (250kHz) mit Daten zu versorgen. Daher 
wird vor dem senden der Takt für das Display konfiguriert und die 
SPI-Konfiguration für den Tiny danach wiederhergestellt.

SPI funktioniert für das Display und für den Tiny "as is" auf dem 
Eval-Board aber hier nicht.

Es muss also einen Zusammenhang zur Hardware geben, das ist kein reines 
Software-Problem - leider...

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Also wenn dein Bestückungsaufdruck stimmt, ist auf dem einen Board ein 
Mega644 und auf dem anderen ein Mega324.

Das klingt für mich Unbedarften schon nach einem Hardware Unterschied.

von J. W. (jw-lighting)


Lesenswert?

Matthias S. schrieb:
> Also wenn dein Bestückungsaufdruck stimmt, ist auf dem einen Board ein
> Mega644 und auf dem anderen ein Mega324.
>
> Das klingt für mich Unbedarften schon nach einem Hardware Unterschied.

Stimmt. Das Eval-Board ist mit einem 324PA gestartet und hat dann später 
einen 644PA bekommen. Ich nutze ein und den selben 644PA (genauer: den 
gleichen) auf beiden Boards, einmal mit, einmal ohne Funktion.
Habe die Clock auch mehrfach überprüft und sogar mit Funktionsgenerator 
zugeführt, da ist kein Problem.

Wie könnte ein Unterschied in der Hardware denn dazu führen, dass SPI 
gar nicht mehr sendet?

von H.Joachim S. (crazyhorse)


Lesenswert?

J. W. schrieb:
> das andere soll die finale Hardware für unser Produkt
> werden.

Lange keine Platine ohne SMD mehr gesehen :-)
EMV-Prüfung schon gemacht? Fällt garantiert durch.

von J. W. (jw-lighting)


Lesenswert?

H.Joachim S. schrieb:
> Lange keine Platine ohne SMD mehr gesehen :-)

Da es sich um die Entwicklung eines Bausatzes für Azubis handelt, war 
das Teil des Anforderungskatalogs.

H.Joachim S. schrieb:
> EMV-Prüfung schon gemacht? Fällt garantiert durch.

Nein. Bin für Verbesserungsvorschläge bzw. Hinweise auf konkrete Fehler 
aber sehr dankbar.

von Peter D. (peda)


Lesenswert?

Wenn das SPI hängt, lies mal das Masterbit aus. Wenn es auf Slave 
umgesprungen ist, dann ist /SS kein Ausgang.
/SS muß vor dem SPI-Init auf Ausgang gesetzt werden und immer 
Ausgang bleiben.
Vermutlich ist auf dem Eval-Board am /SS ein Pullup, das geht auch.

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

J. W. schrieb:
> while(!(SPSR & (1<<SPIF)));

Wenn man sowieso immer drauf warten muss, das SPI fertig wird, kann mir 
mal jemand erklären, wo der wirkliche Vorteil der Hardware SPI gegenüber 
Bitbanging ist? Beim Bitbanging bekomme ich ja sogar noch einen Pin 
wieder frei - MISO wird ja für die DOGM nicht gebraucht.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@  Matthias Sch. (Firma: Matzetronics) (mschoeldgen)

>Wenn man sowieso immer drauf warten muss, das SPI fertig wird, kann mir
>mal jemand erklären, wo der wirkliche Vorteil der Hardware SPI gegenüber
>Bitbanging ist?

Wenn man es richtig macht (tm), kann man während der Übertragung eines 
Bytes schon das nächste über einen Pointer lesen und in einem Register 
bereithalten, um des dann mit minimaler Verzögerung in SPDR zu 
schreiben. Damit erreicht man einen nahezu ununterbrochenen Datenfluß 
mit maximaler Bitrate.

>Beim Bitbanging bekomme ich ja sogar noch einen Pin
>wieder frei - MISO wird ja für die DOGM nicht gebraucht.

MISO kann man auch bei SPI Nutzung als allgemeinen Eingang benutzen.

von Jens G. (jensg)


Lesenswert?

Um Fehler eingrenzen zu können (Hardware oder Software) würde ich auf 
dem EVAL-Board den Kontroller entfernen und eine Fassung darauf setzen.

So kann man ein Softwarefehler ausschließen, wenn es bei beiden µC auf 
dem EVAL-Board geht.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Falk B. schrieb:
> Wenn man es richtig macht (tm), kann man während der Übertragung eines
> Bytes schon das nächste über einen Pointer lesen

Ah, verstehe. Ich nehme aber mal an, das der o.a. Code davon keinen 
Gebrauch macht. Ich schlage also vor, die Senderoutine mal zu Fuss zu 
kodieren, um etwaige Verdrahtungsprobleme zu erkennen. Ist jetzt auch 
nicht so kompliziert:
1
// LCD connections on the Tiny26
2
#define LCD_PORT PORTA
3
#define LCD_DIR  DDRA
4
5
#define LCDDATA 4
6
#define LCDCLK 5
7
#define LCDCS 7
8
#define LCDA0 6
9
#define LCD_MASK ((1<<LCDDATA)|(1<<LCDCLK)|(1<<LCDA0)|(1<<LCDCS))
10
// LCD routines by bit banging as we have no more pins to use the hardware SPI
11
// note that LCDA0 is handled elsewhere
12
void lcd_out(const uint8_t data) {
13
uint8_t n = 8;
14
uint8_t shifter = data;
15
 LCD_PORT &= ~(1<<LCDCS);    // select LCD
16
    while (n>0) {
17
    LCD_PORT &= ~(1<<LCDCLK);  // clk lo
18
      if (shifter & 0x80) LCD_PORT |= (1<<LCDDATA);
19
     else LCD_PORT &= ~(1<<LCDDATA);
20
    shifter <<= 1;
21
      LCD_PORT |= (1<<LCDCLK);  // clk high
22
    n--;
23
    }
24
 LCD_PORT |= (1<<LCDCS);    // deselect LCD
25
}

: Bearbeitet durch User
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.