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.
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?
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 :)
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.
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".
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.
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.
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.
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?
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.
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?
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.
@ 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 ;)
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
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".
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.
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
__interruptvoiduniversal_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 ?
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...