[ATmega644PA] SPI: SPIF wird auf einer Hardware gesetzt, auf anderer nicht

OP #4619539
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 :)
Angehängte Dateien:
OP #4619549
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
#4619614
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.
OP #4619640
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...
OP #4619674
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?
#4620262
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.
(Firma: matzetronics) #4620731
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
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren