Forum: Mikrocontroller und Digitale Elektronik MSP430F2013 SPI Slave versendet komisch


von Niko H. (techniggo)


Angehängte Dateien:

Lesenswert?

Hallo,
Ich lass den MSP430F2013 als SPI Slave laufen und teste mit einem 
"Aardvark" SPI analyzer.
Ich möchte gerne 16bit übertragen, was allerdings zu gewissen Problemen 
führt.
Ich hab das Programm aus den Beispielen umgeschrieben und habe mir diese 
auch bereits angesehen und alle Register überprüft. Mein Code ist im 
Anhang, es geschieht folgendes:

SPI Master sendet: B6 C3   und empfängt: 11 11 (so wie es laut Init sein 
soll)
Slave geht in ISR, in die else anweisung. In USISR steht nun: 0xABCD 
(soweit auch richtig)

Nun sendet Master erneut: B6 C3. Master empfängt aber: CD B6 (CD= 
unteres Byte wird als oberes Byte gesendet; B6= Oberes Byte der gerade 
empfangenen Nachricht werden als unteres Byte gesendet)

Weder verstehe ich, warum die B6 mitgesendet wird, noch verstehe ich wo 
das "AB" hin ist. Das ist einfach verschwunden?! Wie geht das? Das sind 
doch nur zwei Schieberegister, wo immer lustig im Kreis geschoben wir 
oder nicht??!
Ich hab mir den Spaß auch auf dem Oszilloskop angesehen. Da kommen alle 
Nachrichten genauso über die Leitung, wie sie hier auch beschrieben 
werden. Der Analyzer macht seine Arbeit also Richtig, das Problem muss 
im MSP430 liegen, welcher hier die oberen 8Bit des Register unterschlägt 
:(

Kann mir jemand helfen, bzw. mir das erklären?

Gruß
Techniggo

PS. erste upload ist veraltet, kann den upload leider nicht weg 
editieren.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Niko H. schrieb:
> In USISR steht nun: 0xABCD (soweit auch richtig)

Wenn B6C3 gesendet wurde, ist ABCD richtig?

Wie stellst Du fest, was in USISR steht? Siehst Du Dir das etwas in 
einem Debugger an, oder gibst Du diesen Wert irgendwohin aus?

von Niko H. (techniggo)


Lesenswert?

Naja in der ISR geht das Programm ja in die "else" Anweisung und 
schreibt da "ABCD" ins USISR.
Ganz genau, ich stelle das im Debugger fest. Ich benutze IAR Kickstart, 
da kann ich mir an der Seite sämtliche USI register anzeigen lassen, 
unter anderem auch das USISR :)

PS: direkt nach dem senden, also am start der ISR steht übrigens auch 
tatsächlich "B6 C3" im USISR, so wie es soll. "ABCD" steht da erst, 
nachdem die entsprechende Zeiele durchlaufen ist...
Sorry, war unklar ausgedrückt :)

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Beim Betrachten von Hardwareregistern mit dem Debugger musst Du 
vorsichtig sein; denn das Auslesen ist ein Vorgang, der nicht 
unbedingt beliebig oft wiederholt werden kann.
Gerade bei UARTs und vergleichbaren Peripheriebausteinen löst das 
Auslesen das Empfangen weiterer Daten aus -- so daß nur exakt ein 
Lesezugriff pro ISR-Durchlauf statthaft ist.

Kopiere den gelesenen Wert in irgendeine Variable und sieh Dir die im 
Debugger an, aber nie direkt die Hardwareregister.

von Niko H. (techniggo)


Lesenswert?

Interessanter Hinweis, wusste ich nicht.
Habe jetzt je eine unsigned Int Variable vor und hinter dem 
"USISR=0xABCD" eingefügt. Es stehen aber dennoch die gleichen Werte 
drinn wie auch im Hardware Register, also vorher "B6C3", nachher "ABCD".

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Niko H. schrieb:
> Slave geht in ISR, in die else anweisung. In USISR steht nun: 0xABCD
> (soweit auch richtig)
1
 else
2
 {
3
       USISRH = 0xBC;
4
    USISRL = 0xAD;

 Wo siehst du da 0xABCD ?

von Niko H. (techniggo)


Angehängte Dateien:

Lesenswert?

Oh man, peinlich. Hier kommt natürlich die richtige Datei, hatte 
ausversehen ne alte Version oben geladen, die wird auch direkt editiert!

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Niko H. schrieb:
> Slave geht in ISR, in die else anweisung. In USISR steht nun: 0xABCD
> (soweit auch richtig)
>
> Nun sendet Master erneut: B6 C3. Master empfängt aber: CD B6 (CD=
> unteres Byte wird als oberes Byte gesendet; B6= Oberes Byte der gerade
> empfangenen Nachricht werden als unteres Byte gesendet)
>
> Weder verstehe ich, warum die B6 mitgesendet wird, noch verstehe ich wo
> das "AB" hin ist. Das ist einfach verschwunden?! Wie geht das? Das sind

 Mach mal das Ganze 2-3 Mal hintereinander, ohne die Werte in USISR
 zu ändern.

von Niko H. (techniggo)


Lesenswert?

Also nicht USISR=ABCD schreiben?
Ohne diese Anweisung bekomme ich am Master aufgenommen
sende    B6 C3
empfange C3 B6
sende    B6 C3
empfange C3 B6
sende    B6 C3
empfange C3 B6
sende    B6 C3
empfange C3 B6
sende    B6 C3
empfange C3 B6

Das ist beliebig oft reproduzierbar. Der oben geschilderte Fall ist 
übrigens ebenso reproduzierbar.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Niko H. schrieb:
> sende    B6 C3
> empfange C3 B6
> sende    B6 C3
> empfange C3 B6
>
> Das ist beliebig oft reproduzierbar. Der oben geschilderte Fall ist
> übrigens ebenso reproduzierbar.

 Und ?
 LoByte von zuletzt gesendetem Word + HiByte von eben gesendetem Word.
 Was ist daran falsch ?
 Wahrscheinlich ist Register shadowed.

: Bearbeitet durch User
von Niko H. (techniggo)


Lesenswert?

Was ist shadowed? gespiegelt? also umgedreht vermutlich richtig? Hatte 
ich auch schon die Vermutung, aber wenn ich etwas ins Register schreibe, 
wo geht denn dann das Highbyte hin? Beziehungsweise, was wirklich 
interessant wäre: Wie bekomme ich das hin dann 16bit vernünftig zu 
übertragen?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Niko H. schrieb:
> Was ist shadowed? gespiegelt? also umgedreht vermutlich richtig? Hatte
> ich auch schon die Vermutung, aber wenn ich etwas ins Register schreibe,
> wo geht denn dann das Highbyte hin? Beziehungsweise, was wirklich
> interessant wäre: Wie bekomme ich das hin dann 16bit vernünftig zu
> übertragen?

 Du hast nach dem Empfang einen neuen Wert ins Register geschrieben,
 also 0xABCD. Wenn du diesen Wert gleich abschickst, ist es OK.
 Tust du aber nicht, sondern wartest auf Empfang.

 Da USI annimmt, dass das HiByte von vorhergehendem Empfang schon
 zurückgesendet würde, wird USISRH zu USISRL, und danach wird USISRH
 auch zurückgesendet, neuer Wert wird ins USISRL übernommen.

 EDIT:
 War noch nie in einem Kontroller drin, weiss auch nicht, ob das so
 wie oben beschrieben geht, nur meine Vermutung. ;-D

 Schreibe jetzt 0xCDAB ins Register.

: Bearbeitet durch User
von Niko H. (techniggo)


Lesenswert?

Ja, das leuchtet soweit ein.... Aaaaber: Ich muss doch auf Empfang 
warten, da mein Slave nicht von alleine Senden kann (Senden und 
Empfangen geht ja gleichzeitig übers selbe Register oder?!)
Ich verstehe immernoch nicht ganz die Logik, wie ich demnach 16bit 
versenden können sollte... Oder muss ich High und Low Byte komplett von 
einander getrennt übertragen? Wozu gibts dann ein 16 bit Register und 
nicht direkt nur ein 8Bit register?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Niko H. schrieb:
> Ich verstehe immernoch nicht ganz die Logik, wie ich demnach 16bit
> versenden können sollte... Oder muss ich High und Low Byte komplett von
> einander getrennt übertragen? Wozu gibts dann ein 16 bit Register und
> nicht direkt nur ein 8Bit register?

 Schau doch mal ins DaBla. Vielleicht hat USI nur Byte Access.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

1
// USI interrupt service routine
2
__interrupt void universal_serial_interface(void)
3
{
4
  if (0x59AA == USISR)  // <--- Lesezugriff auf USISR
5
  {
6
//    SD16CCTL0 &= ~ SD16IFG;               // clear ADC Interrupt Flag
7
//    SD16CCTL0 |= SD16SC;                  // AD Wandler starten
8
//    while (!(SD16CCTL0 & SD16IFG));       // AD Wandlung fertig ?
9
//    USICNT = 16;
10
    USISR = 0x3456;  // <---- Schreibzugriff auf USISR
11
 }
12
 else
13
 {
14
       empfangen = USISR; // <--- Lesezugriff auf USISR
15
       USISR = 0xABCD;   // <---- Schreibzugriff auf USISR
16
       senden = USISR;   // <---- Lesezugriff auf USISR
17
       USICNT = 16;
18
 }
19
}

Du greifst hier gleich dreimal lesend auf USISR zu, außer, wenn 0x59AA 
empfangen wurde.

Das solltest Du ändern.

von Niko H. (techniggo)


Lesenswert?

@ Marc:
DaBla und User Guide hab ich schon zig mal alles zu SPI und USI 
durchgeackert, hätte da nie irgendwo was entdeckt, dass es nur Byteweise 
geht.


@Rufus:
Die beiden Lesezugriffe mit "empfangen" und "senden" habe ich nur 
sporadisch eingefügt, weil du meintest ich sollte die Register mal in 
Variablen abspeichern und nicht im Debugger anschauen. Wenn die diese 
beiden Zeilen rausnehme, verhält sich der Controller immernoch gleich, 
und das bei je einem Lese- und einem Schreibzugriff, egal was er 
empfängt.
Naja also wenn der Controller das nicht hinbekommt, dann frage ich mich 
ernsthaft, was man mit einer Schnittstelle soll, über die man weder 
lesen, noch schreiben kann ;)

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Niko H. schrieb:
> DaBla und User Guide hab ich schon zig mal alles zu SPI und USI
> durchgeackert, hätte da nie irgendwo was entdeckt, dass es nur Byteweise
> geht.

Table 15. Peripherals With Byte Access
1
USI USI control 0 USICTL0 078h
2
(MSP430F20x2 and MSP430F20x3) USI control 1 USICTL1 079h
3
USI clock control USICKCTL 07Ah
4
USI bit counter USICNT 07Bh
5
USI shift register USISR 07Ch
 Also, ich habe es nur einmal.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Marc Vesely schrieb:
> Peripherals With Byte Access

Das bedeutet, daß es auch byteweise geht.

Wäre es anders, wäre eine Registerdefinition für einen 16-Bit-Zugriff 
irgendwie ziemlich daneben.

Im "'F20xx Family User's Guide" (slau144j) wird auf Seite 405 in Tabelle 
14-2 USISR als Register mit "Word Access" beschrieben.

Und natürlich in 14-1 USISRL und USISRH als Register mit "Byte Access".

von Niko H. (techniggo)


Lesenswert?

Schau mal in den User Guide:

14.2.3.3 USISR Operation
The 16-bit USISR is made up of two 8-bit registers, USISRL and USISRH. 
Control bit USI16B selects the
number of bits of USISR that are used for data transmit and receive. 
When USI16B = 0, only the lower 8
bits, USISRL, are used.

von Niko H. (techniggo)


Lesenswert?

Ok, das heißt also das ist nur ein fake Register, und mann kann 
tatsächlich immer nur 1Byte aufeinmal senden?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Betrachtet man den User's Guide, so fällt dort das hier auf:

SPI Slave Mode

Once all bits are received, the data must be read from USISR
and new data loaded into USISR before the next clock edge
from the master.
In a typical application, after receiving data, the USI
software will read the USISR register, write new data to
USISR to be transmitted, and enable the USI module for the
next transfer by writing the number of bits to be
transferred to USICNTx.

(Hervorhebung von mir)

Wenn man das mit dem Code aus der ISR vergleicht, fehlt der letzte 
Schritt:
1
// USI interrupt service routine
2
__interrupt void universal_serial_interface(void)
3
{
4
  if (0x59AA == USISR)  // <--- Lesezugriff auf USISR
5
  {
6
//    SD16CCTL0 &= ~ SD16IFG;               // clear ADC Interrupt Flag
7
//    SD16CCTL0 |= SD16SC;                  // AD Wandler starten
8
//    while (!(SD16CCTL0 & SD16IFG));       // AD Wandlung fertig ?
9
//    USICNT = 16;
10
    USISR = 0x3456;  // <---- Schreibzugriff auf USISR
11
 }
12
 else
13
 {
14
       empfangen = USISR; // <--- Lesezugriff auf USISR
15
       USISR = 0xABCD;   // <---- Schreibzugriff auf USISR
16
       senden = USISR;   // <---- Lesezugriff auf USISR
17
       USICNT = 16;      // enable 
18
 }
19
}

Die Routine sollte so umgestaltet werden:
1
// USI interrupt service routine
2
__interrupt void universal_serial_interface(void)
3
{
4
  empfangen = USISR;        // <-- Lesezugriff USISR
5
6
  if (empfangen == 0x59AA)
7
    senden = 0x3456;
8
  else
9
    senden = 0xABCD;
10
11
  USISR = senden;           // <-- Schreibzugriff USISR
12
  USICNT = 16;              // enable
13
}

: Bearbeitet durch User
von Niko H. (techniggo)


Lesenswert?

Habe ich auch alles ausprobiert, trotzdem noch der gleiche Fehler...
Scheinbar hilft es alles nichts, dann muss ich wohl leider mit 8bit 
Übertragung leben, denn das funktioniert ja immerhin...

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.