Hallo zusammen,
ich beschäftige mich seit ein paar Tagen mit der USCI SPI Schnittstelle
des MSP430G2553 und habe das Beispiel von TI bereits durchgearbeitet.
Nun möchte ich jeweils 16-Bit übertragen und empfangen.
Das senden von 16-bit lässt sich recht einfach mit folgendem Code
erreichen:
Das Empfangen ist, das gebe ich zu, Schwachsinn! Mal wird cmd2 zuerst
empfangen, mal cmd1. Ich brauche also irgend eine Art Synchronimpuls.
Wie reaisiert man das bei SPI am Besten, es gibt ja keine direkte
Adressierung und ACKs wie z.B. bei I2C?!
Ich bin über jede Anregung sehr dankbar und bedanke mich bereits im
Vorraus herzlich für jede Unterstützung.
Beste Grüße,
MSPLer
Hallo,
danke für die schnelle Antwort. Das habe ich schon versucht.
Beim Slave habe ich P1.5 über PSEL und PSEL2 als CS-Signal konfiguriert
und UCMODE_2 gesetzt, sprich der Slave ist aktiv, wenn CS = 0.
Das CS Bit habe ich beim Master manuell als GPIO konfiguriert und
gesetzt. Dennoch führt das auch nicht zum gewünschtem Erfolg.
Gibt es von Seitens TI mehr Beispiele dazu?
MSPLer schrieb:> Das Empfangen habe ich wie folgt realisiert:
Wo läuft dieser "Empfangscode"? Auch auf dem Master?
> Nun möchte ich jeweils 16-Bit übertragen und empfangen.
Dir ist klar, wie SPI funktioniert? Dass beim SPI-Master
"Empfangen=Senden" ist? SPI ist nichts anderes als gekoppelte
Schieberegister. Für jedes gesendete Bit wird gleichzeitig eines
empfangen. Deshalb musst du nach dem Senden eines Bytes eigentlich nur
das Empfangsregister lesen, denn du hawst "nebenher" auch ein Byte
empfangen.
Siehe dort: http://www.lothar-miller.de/s9y/archives/15-SPI.html
> Das senden von 16-bit lässt sich recht einfach mit folgendem Code erreichen
Das ist schwachsinns Code!
Wie Lothar schon schrieb, SPI ist nur ein synchroner Bitstrom. Du kannst
also soviel Bit wie du auch immer willst an einem Stück übertragen. Es
gilt immer Daten anlegen und Strobe (Takt), Daten ...
@Lothar Miller:
> Wo läuft dieser "Empfangscode"? Auch auf dem Master?
Nein, der läuft auf dem Slave ab, ich verwende dazu zwei MSP430
Launchpads.
> Dir ist klar, wie SPI funktioniert?
Offensichtlich hab ich da was elementares falsch verstanden, danke für
den Link, der ist wirklich sehr hilfreich!
> Das senden von 16-bit lässt sich recht einfach mit folgendem Code erreichen> Das ist schwachsinns Code!
Wie würde man es besser machen? Wenn ich an einem Stück übertragen kann,
könnte ich es dann so schreiben? :
MSPLer schrieb:> Wie würde man es besser machen? Wenn ich an einem Stück übertragen kann,> könnte ich es dann so schreiben? :
Kenne mich mit MSP430G2553 nicht aus, aber vielleicht so:
MSPLer schrieb:> Wie würde man es besser machen? Wenn ich an einem Stück übertragen kann,> könnte ich es dann so schreiben? :>> while (!(IFG2 & UCA0TXIFG));> // USCI_A0 TX buffer ready?> UCA0TXBUF = cmd1;> UCA0TXBUF = cmd2;
Guck dir mal an, was du da schreibst. Du musst dem Schieberegister schon
eine Chance geben, seine Daten los zu werden, bevor du das nächste Byte
in den Sendepuffer schreibst.
Wie wäre es mit Interrupts? Das USCI kann das.
Die Aufgabenstellung ist völlig losgelöst vom uC oder der Art der
Übertragung. Es gibt einen Sendepuffer und einen Empfangespuffer. Der
Austausch erfolgt per Interrupt. Natürlich muss eine Synchronisation
erfolgen.
MSPLer schrieb:> Ich brauche also irgend eine Art Synchronimpuls.
Der Master mus ja /SS des gewünschten Slave auf low ziehen.
Damit kann der Slave einen Interrupt auslösen und seinen Byte-Counter
auf 0 setzen.
Sollte /SS nicht interruptfähig sein, muß man ihn zu einem
Interrupteingang parallel schalten.
Pseudocode:
Master:
/SS_slave = 0
spidata = byte_1
while( not done )
...
spidata = byte_n
while( not done )
/SS_slave = 1
Slave:
interrupt on /SS = 0:
bytecounter = 0
interrupt on receive:
inbuff[bytecounter++] = spidata
Hallo zusammen,
dank eurer Hilfe habe ich eine kleinen Fortschritt machen können.
Das senden von zwei Bytes habe ich nun anhand einer Funktion
implementiert, welche wie folgt aussieht:
1
while(count)
2
{
3
UCA0TXBUF=*tx_array;
4
tx_array++;
5
while((IFG2&UCA0TXIFG)==0);// wait for tx buffer to be ready
6
count--;
7
}
8
while((UCA0STAT&UCBUSY)==1);// wait for transfer to complete
9
IFG2&=~UCA0RXIFG;// clear the rx flag
Nun werden zwei Byte zumindest schon mal zuverlässig übertragen.
Als nächstes werde ich auf der SPI Slave Seite weiter fortfahren und
Interrupt gesteuert zwei Bytes empfangen.
@Lothar Miller: Deine anregende Kritik war gold Wert, ebenso der Link zu
deiner Seite, danke!
Eine Sache erscheint mir allerdings immer noch merkwürdig.
Auf der SPI Slave Seite habe ich "UCxSTE" aktiviert und UCMODE_2
gesetzt. Ich verstehe dieses Signal als Slave Select Signal, richtig?
Mich wundert nur, dass ich keinen Interrupt bekomme, wenn UCxSTE = 0
wird. Dann könnte ich dann nämlich meinen RXCounter auf Null zurück
setzen.
Das USCI-Modul bietet nur Interrupt für RX und TX.
MSPLer schrieb:> danke!
Keine Ursache.
Aber eines wollte ich noch loswerden: zur Kommunikation zwischen 2
Prozessoren würde ich eine "normale" serielle Schnittstelle nehmen (aka.
RS232 mit TTL-Pegeln).
Bei so einer Schnittstelle ist nämlich eine Antwort zeitlich nicht
zwingend an das Senden gekoppelt. Der Slave hat es wesentlich einfacher,
zu reagieren. Du wirst jetzt auf der Slave-Seite dann leicht erkennen,
dass dieser Zwang, sofort/schnell auf den SPI-Master reagieren zu
müssen, unschön ist...
@Lothar
Im SPI Modus sind die USCI Register nicht auf 1 Bit beschränkt. Denk mal
darüber nach. ;-)
Bei vielen uC erlaubt die synchrone Übertragung höhere Baudaten als die
asynchrone.
echter MSPler schrieb:> Im SPI Modus sind die USCI Register nicht auf 1 Bit beschränkt. Denk mal> darüber nach. ;-)
Gut, mach ich. Fertig. Das ging ja schnell... :-o
> Bei vielen uC erlaubt die synchrone Übertragung höhere Baudaten als die> asynchrone.
Schon klar. Nur ist es eben so, dass der Slave bei der RS232 antworten
kann, wenn er will und mit seinen Berechnungen fertig ist. Beim SPI
muss der Slave ständig gepollt werden, oder es muss sicherheitshalber
gewartet werden, bis er "fertig" ist. Der Slave kann von sich aus nicht
mit einer Übertragung beginnen. Als Workaround zu diesem Thema wird dann
oft der Übertragungswunsch des Slaves per zusätzlicher Interruptleitung
an den Master signalisiert.
Etwas komplett anderes ist hier z.B. ein mehrkanaliger ADC, der
gleichzeitig mit dem Senden des nächsten Kommandos den vorherigen
Wandlungswert zurückgibt. Da ist SPI super aufgehoben, weil der ADC ja
sowieso nichts "von sich aus" macht...
Lothar M. schrieb:> Nur ist es eben so, dass der Slave bei der RS232 antworten> kann, wenn er will und mit seinen Berechnungen fertig ist.
Noch schöner ist CAN, da nimmt einen die HW den ganzen Protokoll-,
Timing- und Fehlerschrunz ab. Da muß man wirklich nur was in den
Sendepuffer schreiben bzw. den Empfangspuffer auslesen. Minimal
aufwendiger wird es bei Paketen >8Byte.
Peter D. schrieb:> Noch schöner ist CAN, da nimmt einen die HW den ganzen Protokoll-,> Timing- und Fehlerschrunz ab.
Aber der Transceiver ist in den meisten uC nicht enthalten.
EDIT:
Ist wohl halb so schlimm, mit ein paar Dioden sollte das wohl auch auf
TTL-Ebene und ohne Transceiver gehen... ;-)
Man muss Client Server nur richtig zuordnen.:-(
Komisch, dass Displays und andere Peripherals synchron und nicht
asynchron angeschlossen werden? Da muss die Industrie aber noch viel vom
Loddar lernen. :-D :-D :-D
Och, es gibt auch Display Module, die über eine serielle Schnittstelle
angesprochen werden (TTL oder echtes RS232).
Ist halt alles eine Frage der FInanzen. Ein simples getaktetes
Schieberegister ist eben billiger als eine UART.
echter MSPler schrieb:> Komisch, dass Displays und andere Peripherals synchron und nicht> asynchron angeschlossen werden? Da muss die Industrie aber noch viel vom> Loddar lernen. :-D :-D :-D
Das ist doch Quatsch. Es gibt auch unendlich viel asynchron oder
"halbsynchron" betriebene Peripherie.
Siehe z.B. USB. Nicht gerade wenig verbreitet, oder bist du da anderer
Meinung?
Wie auch immer deine werte Meinung ist, Tatsache ist jedenfalls: USB
kann man bestenfalls als halbsynchron zu bezeichnen. Zwar ist die
Übertragung innerhalb der einzelnen Pakete synchron (sie tragen ihren
Takt ja in sich), aber das Timing der Pakete insgesamt ist eindeutig
asynchron, der jeweilige Empfänger muß sich auf den Paketbegin und das
darin enthaltene Sync-Muster jedesmal neu synchronisieren (genau
deswegen gibt's das nämlich überhaupt nur).
Oder ein anderes Beipiel, Ethernet in den heute üblichen Ausprägungen
zwischen 100MBit und 10GBit über Kupfer, auch nicht gerade wenig
verbreitet...
Hier ganz genau dieselbe Soße, innerhalb der Pakete synchron, Pakete
aber asynchron.
Ich könnte noch seitenweise weitere Beipiele anführen, aber die zwei
sollten allein schon reichen, um dir klar zu machen, wie wenig du
eigentlich weisst...
Karl H. schrieb:> Och, es gibt auch Display Module, die über eine serielle> Schnittstelle angesprochen werden (TTL oder echtes RS232).> Ist halt alles eine Frage der FInanzen. Ein simples getaktetes> Schieberegister ist eben billiger als eine UART.
Natürlich, es gibt auch heute noch Monitore mit VGA. :-(
@C-Ha...
Dein Nick, dieser Beitrag und viele deiner anderen outen dich als einen
Kasper der vergangegenen Zeit. Von dir ist nix zu erwarten. :-(
echter MSPler schrieb:>> Ist halt alles eine Frage der FInanzen. Ein simples getaktetes>> Schieberegister ist eben billiger als eine UART.>> Natürlich, es gibt auch heute noch Monitore mit VGA. :-(
Was hat das mit der Tatsache zu tun, dass Karl H. Recht hat ?
Knapp 2 Meter Kabel, nur ein Teilnehmer, was kann da billiger,
zuverlässiger und schneller sein ?
> @C-Ha...> Dein Nick, dieser Beitrag und viele deiner anderen outen dich als einen> Kasper der vergangegenen Zeit. Von dir ist nix zu erwarten. :-(
Ich bin nicht gerade sein Fan, aber wenn er etwas schreibt, dann weiss
er meistens wovon er spricht ( im Gegensatz zu dir ).
Was ist in seinem Beitrag falsch oder entspricht nicht den Tatsachen ?
Hallo zusammen,
> Du wirst jetzt auf der Slave-Seite dann leicht erkennen,>dass dieser Zwang, sofort/schnell auf den SPI-Master reagieren zu>müssen, unschön ist...
Ohja! Das habe ich .. :-(
Ich habe das Problem bisher so angegangen, dass ich auf der Slave Seite
in der ISR eine FSM implementiert habe, sieht als Minimalbeispiel
erstmal so aus:
Das empfangen klappt wie bisher wunderbar, nur beim Senden habe ich
massive Probleme.
Es sollen die Werte 80 und 10 zurück gesendet werden. In der ISR werden
auch die richtigen Werte in das Sendebuffer geschoben, das kann ich beim
Debuggen nachvollziehen.
Aber auf dem Oszilloskop sehe ich, dass 2x der Wert 80 übertragen wird.
Also offensichtlich mache ich hier etwas beim Senden und/oder Auslesen
falsch.
Meine Slave Konfiguration sieht wie folgt aus:
1
voidspi_config_slave()
2
{
3
P1SEL=BIT1+BIT2+BIT4+BIT5;
4
P1SEL2=BIT1+BIT2+BIT4+BIT5;
5
UCA0CTL1=UCSWRST;// **Put state machine in reset**
MSPLer schrieb:> Es sollen die Werte 80 und 10 zurück gesendet werden. In der ISR werden> auch die richtigen Werte in das Sendebuffer geschoben, das kann ich beim> Debuggen nachvollziehen.>> Aber auf dem Oszilloskop sehe ich, dass 2x der Wert 80 übertragen wird.> Also offensichtlich mache ich hier etwas beim Senden und/oder Auslesen> falsch.
LOL.
Weil du 2 Bytes hintereinander in der ISR senden willst ?
So geht das nicht. Dein Zeiger wird in der ISR auf:
1
src=(uint8_t*)tx_array;
gesetzt. Wenn du beim SPI etwas gesendet hast, hast du auch etwas
empfangen, also wird der INT gleich nach dem senden vom ersten Byte
wieder feuern und da du den Zeiger auf Anfang stellst...
MSPLer schrieb:>> Du wirst jetzt auf der Slave-Seite dann leicht erkennen, >dass dieser>> Zwang, sofort/schnell auf den SPI-Master reagieren zu >müssen, unschön>> ist...> Ohja! Das habe ich .. :-(
Ja, da wäre jetzt ein "echter MSPler" gefragt. Einer eben, der sich mit
den ganzen Registern im MSP auskennt...
Sagen wirs mal so:
Weil das Senden und das Empfangen beim SPI gleichzeitig passiert, musst
du das erste Byte im Slave schon bereitstellen, bevor der Master sein
erstes Datenbyte sendet. Dann sind beide Schieberegister mit den
aktuellen Daten ausgestattet und der Transfer kann beginnen. Dieses Byte
kannst du z.B. schon sofort nach der vorhergehenden Übertragung
bereitstellen (und hoffen, dass der Master sie irgendwann abholt). Oder
du reagierst recht zügig auf einen Interrupt und triggerst den mit der
fallenden SS-Flanke. Dann nicht viel Zeit verplempert und sofort das
Datenbyte ins Slave-TX-Register geschreiben!
Nach der Übertragung des ersten Bytes gibt es auf der Slaveseite
irgendein Signal/Interrupt, das die Übertragung eines Bytes
signalisiert. Das ist dann der Zeitpunkt, wo der Master sein zweites
Datenbyte ins Senderegister schreibt. Auf der Slave-Seite heißt das dann
"hurtig, hurtig", denn vor dem nächsten SPI-Takt muss auch der Slave das
nächste Datenbyte in sein TX-Register schreiben.
Und natürlich muss der Slave dann zusätzlich noch das empfangene Byte
rechtzeitig aus dem RX-Register auslesen, denn sonst wird das
überschrieben...
Mit ein wenig Glück hat der jeweilige uC noch ein paar
Double-Buffer-Stufen, um diese Hektik auf der Slave-Seite zu entspannen.
Dazu musst du das Datenblatt genau lesen.
MSPLer schrieb:> Ich habe das Problem bisher so angegangen...> #pragma vector=USCIAB0RX_VECTOR> __interrupt void USCI0RX_ISR (void)> {> .....> while ((IFG2 & UCA0RXIFG) == 0); // wait> while(TXByteCounter)> while ((IFG2 & UCA0TXIFG) == 1); // wait> while ((UCA0STAT & UCBUSY) == 1); // wait
In einem Interrupt hat ein while() nichts zu suchen. Da wird niemals
auf irgendwas gewartet! Du wirst nochmal drüber nachdenken müssen...
echter MSPler schrieb:> Da muss die Industrie aber noch viel vom Loddar lernen. :-D :-D :-D
Du hast da einen Schreibfehler im Satz.
Viele Slave-SPI sind leider nur ungepuffert bzw. nur mit Empfangspuffer
(z.B. AVR).
Dann muß der Master nach jedem Byte erstmal lange Gedenkpausen einlegen,
damit der Slave einen gerade laufenden Interrupt beenden kann, dann in
den SPI-Interrupt springen kann, dann dessen Prolog abrasselt, um
endlich das nächste Byte in das Schieberegister zu schreiben.
Nur ein gepufferter Slave kann schon das nächste Byte in den Puffer
schreiben, wärend der Master das vorherige noch rausschiebt.
Gesehen habe ich gepufferte Slaves bisher nur bei einigen 8051, z.B.
AT89LP4052.
Natürlich kann kein Slave hellsehen, welches Paket der Master als
nächstes lesen will. Da muß man sich ein Protokoll ausdenken. Z.B.
schickt der Master erstmal ein Kommando, liest dann ein Dummybyte,
wärend dessen der Slave das Kommando parst und die zu sendenden Daten
bereitstellt.
Peter D. schrieb:> Natürlich kann kein Slave hellsehen, welches Paket der Master als> nächstes lesen will. Da muß man sich ein Protokoll ausdenken. Z.B.> schickt der Master erstmal ein Kommando, liest dann ein Dummybyte,> wärend dessen der Slave das Kommando parst und die zu sendenden Daten> bereitstellt.
Klar.
Bei mir schreibt der Slave wenn er ein Kommando empfangen hat, 0xF0 ins
Senderegister und nachdem er dieses Kommando abgearbeitet hat, wird ein
0x55 ins Senderegister geschrieben, so weisst der Master gleich nach
dem ersten Byte ob der Slave schon fertig ist und ob er weiter senden
soll.
Wenn es aber ein kurzes, bzw. schnelles Kommando ist, wird mit zweitem
Byte etwas gewartet und das Resultat gleich abgeholt.
Peter D. schrieb:> Z.B. schickt der Master erstmal ein Kommando, liest dann ein Dummybyte,> wärend dessen der Slave das Kommando parst und die zu sendenden Daten> bereitstellt.
Und damit hoffenlich rechtzeitig fertig ist. So werden dann zum
Übertragen eines Bytes mindestens 3 Bytes hin und her geschickt...
Mit der seriellen Schnitte würde der Master die Anfrage senden, der
Slave würde dann diese Anfrage empfangen, danach irgendwann bearbeiten
und bei Gelegenheit die Antwort senden. Zetilich komplett entspannt mit
nur 2 Leitungen.
Und wenn der Slave dem Master was zu sagen hat, dann tut er es einfach
irgendwann. Er muss ja nicht warten, bis der Master ihm die
Gelegenheit zur Übertragung bietet, oder den Master per zusätzlicher
Interrupt-Leitung darum bitten.
Ich verwende SPI gerne. Aber eben für "dumme" Peripheriebausteine wie
IO-Schieberegister, ADC und DAC...
echter MSPler schrieb im Beitrag #4187019:
> Wenn ein Slave seine Daten sendet, wenn es ihm zeitlich gefällt, ist er> kein Slave mehr. :-(
Bei so einer Ansammlung geballter Idiotie kann man eigentlich nur den
Kopf schütteln.
Der Slave sendet seine Daten im vorgeschlagenen Verfahren keinesfalls,
wann immer er möchte, sondern immer noch genau dann, wenn der Master sie
anfordert.
Der springende Punkt ist, dass ich Master und Slave zu jeder Zeit
darüber einig sind, was der Slave auf zu der gegebenen Zeit auf die
Anfrage des Masters zu antworten hat. Das nennt man ein Protokoll!
Und sowas ist (ganz unabhängig davon, ob die Übertragung auf dem
PHY-Level synchron oder asynchron ist), seit einer schier unerfindlichen
Zahl von Jahren Grundlage jeglicher Technik. Und natürlich grundlegendes
Fachwissen eines jeden, der diese Technik zum "Zusammenspielen" bewegen
will oder muss.
An dir ist das wohl völlig vorbei gegangen...
[Hier wurde eine emotionale Aussage vom Moderator gelöscht]
echter MSPler schrieb im Beitrag #4187019:
> oder Loddar? :'(
Hör mal, du namenloser Irgendwer. Wenn du es nicht kapieren willst, dann
lässt du es sein. Aber ich werde jeden deiner Posts löschen, in dem du
mich so nennst. So einfach ist das.
echter MSPler schrieb im Beitrag #4187019:
> Man kann auch SPI nur halbduplex nutzen, wem s gefällt ... ;-)
Es gibt auch Datenprotokolle jenseits von SPI. Aber wenn einer (wie du
offenbar) nur einen Hammer hat, für den sieht die ganze Welt wie ein
Nagel aus.
Offenbar hast du als "echter MSPler" aber nichts zur Sache beizutragen.
Ich sehe in im gelöschten Post nur Zahnerei und Kleinkrämerei...
MSPLer schrieb:> Ich freue mich über jeden Ratschlag, ich habe leider im Moment keine :-(Marc V. schrieb:> Weil du 2 Bytes hintereinander in der ISR senden willst ?
Das mag ich so in diesem Forum - NETIQUETTE über alles.
TO könnte schreiben:
A) Nein, deine Antwort war nicht richtig.
B) Ja, das war es, danke.
C) Die Antwort half mir zwar nicht gerade viel, ich verstehe auch kein
bisschen wovon du da schreibst, da du aber ein Moderator bist,
muss ich bodentiefe Verbeugungen und unzählige Handküsse machen.
D) TO bleibt weiter ein A...h und schreibt nichts.
Nicht, das es einen Unterschied fur mich macht, aber es macht sehr
wohl einen Unterschied für Leute die vielleicht irgendwann vor einem
ähnlichem Problem stehen werden.
Wenn jemand vor einem Problem steht und genügend Zeit hat, rumzuweinen
und um Hilfe zu bitten, aber wenn sein Problem gelöst ist, nicht mehr
Zeit findet, um eine einfache Antwort zu schreiben, dann ist er ?
Genau das.
> Nicht, das es einen Unterschied fur mich macht, aber es macht sehr> wohl einen Unterschied für Leute die vielleicht irgendwann vor einem> ähnlichem Problem stehen werden.
Sorry, du hast natürlich Recht, entschuldige bitte meinen Fauxpax :-)
Ja, zwei Bytes hintereinander zu senden und das auf einmal bei Aufruf
der ISR ist natürlich Quatsch und macht keinen Sinn. Dummer
Anfängerfehler. Aber hey, ich bin ja auch ein Anfänger. ;-)
Ich habe mich von dem Gedanken verabschiedet auf einmal 2 Byte senden zu
wollen. Immerhin ist SPI grundsätzlich gesehen ja auch ein Byte
basiertes Protokoll, niemand hat was von zwei Byte gesagt.
Meine Aufgabe besteht im Grunde genommen darin einen gemeinsamen
Addressraum zu definieren, der im Slave Device abgebildet ist. Also der
Master möchte z.B. die Register der RTC im Slave lesen.
Der Master wird im weiteren Verlauf durch einen FPGA mit SPI-Makro
ersetzt werden. Da das I2C Modul des MSP schon anderweitig implementiert
ist, und die Hardware nur über SPI mit dem FPGA verbunden ist, bleibt
mir hierbei keine andere Wahl.
Ich werde also mit Hilfe von SPI als Grundlage ein eigenes Protokoll
entwickeln, der Master soll auf diesen Addressraum lesend und schreibend
zugreifen können.
Ich stelle mir das im Moment so vor:
Master möchte von Slave lesen und spricht ihn mit Adresse z.B 10 an
(schreiben wäre dann Adresse z.B. 11)
Slave bestätigt mit Status Code OK
Master sendet Register Adresse, von der er lesen möchte
Slave antwortet mit H-Byte
Master bestätigt
Slave antwortet mit L-Byte
Master beendet Kommunikation
Ob das so funktioniert, wird sich in der kommenden Woche zeigen ;-)
>Das mag ich so in diesem Forum - NETIQUETTE über alles.
Oh ja. Letzlich kann niemand alles wissen und was der eine nicht weiß,
weiß der andere umso besser. Ich bin ursprünglich VHDL-Entwickler und
beschäftige mich erst seit ein paar Wochen mit dem MSP430 und der µC
Entwicklung. Ich möchte niemanden anprangern oder kritisieren, meine
Aussage ist lediglich: Kinder, vertragt euch! :-)
Umso mehr möchte ich mich bei all denjenigen bedanken, die mir bei
meiner Aufgabe mit konstruktiver Kritik und gewinnbringenden Ratschlägen
zur Seite stehen, vielen Dank!
Euch allen noch einen schönen Sonntag.
Beste Grüße,
MSPler
MSPler schrieb:> Ich stelle mir das im Moment so vor:>> Master möchte von Slave lesen und spricht ihn mit Adresse z.B 10 an> (schreiben wäre dann Adresse z.B. 11)
OK, geht.
> Slave bestätigt mit Status Code OK
Slave schreibt bei jeder Statusanderung seinen neuen Status ins
SendeRegister. Auf diese Weise weiss der Master schon nach dem ersten
Byte ob er weiter senden soll. Bei jedem SPI_Rcv_Interrupt ( beim
Slave ) wird entweder der Status neu geschrieben oder das empfangene
Kommando wird dekodiert.
> Master sendet Register Adresse, von der er lesen möchte
Aber nur, wenn der vorher empfangene Byte Status_Ready bezeichnet.
> Slave antwortet mit H-Byte
Kann er nicht, Slave hat gerade Register Adresse empfangen, Master
muss also zuerst noch etwas senden, damit er auch etwas empfangen kann.
> Master bestätigt
Master wartet eine gewisse Zeit, sendet z.B. EOC (End Of Command) und
empfangt H-Byte.
> Slave antwortet mit L-Byte
Kann er nicht, siehe oben.
Master sendet z.B. EOR (End Of Request) und empfangt L-Byte.
> Master beendet Kommunikation
Hat er schon oben mit EOR getan.
> Ob das so funktioniert, wird sich in der kommenden Woche zeigen ;-)
Wird mit Sicherheit, SPI ist schnell und einfach zu implementieren.
echter MSPler schrieb im Beitrag #4188796:
> Der Kollege hat immer noch keine Lösung. Und jetzt? :-[ :-[ :-[
Und du hast immer noch keine Ahnung worum es hier überhaupt geht, nicht
zu reden davon, dass du keine Ahnung von uC und programmieren
überhaupt hast.
Schuster, bleib bei deinen Leisten und misch dich nicht in Sachen ein,
von denen du nichts versteht...
P.S.
Deine Beiträge werden sowieso gelöscht, bemühe dich nicht weiter
deinen Blödsinn zu senden.
LOL.
Schuster ...
So isses! Aber warum schreibst du dann hier? Denn ich sehe immer noch
keinen brauchbaren Code für den MSP. Hast du übererhaupt schon einmal
so ein Ding von Nahem gesehen? :-*
Marc V. schrieb:>> Master bestätigt> Master wartet eine gewisse Zeit, sendet z.B. EOC (End Of Command) und> empfangt H-Byte.
Tja, für ein derartiges Protokoll wäre ein I2C praktischer. Da kann der
Slave notfalls clock strechting betreiben, wenn er nicht mitkommt und
muß nicht immer ein komplettes "status not ready" zurückschicken.
MSPler schrieb:> Der Master wird im weiteren Verlauf durch einen FPGA mit SPI-Makro> ersetzt werden.
In dem Fall würde ich den MC als SPI-Master und den FPGA als SPI-Slave
benutzen.
Der FPGA muß ja nicht erst etwas anderes unterbrechen und in einen
Interrupt springen, hat also keinerlei Zeitprobleme, der MC dagegen
schon.
Als SPI-Master aber gibt der MC den Takt vor, kann sich also soviel Zeit
lassen, wie er lustig ist.
Und der SPI-Slave-FPGA kann über eine Leitung signalisieren, daß er
einen Transfer wünscht. Er ist quasi der Daten-Master, da er den
Transfer startet.
Marc V. schrieb:> Deine Beiträge werden sowieso gelöscht
Wie dort im Beitrag "Re: SPI 16-Bit Problem"
angekündigt: gelöscht wird, so lange der "echte MSPler" nur rotzfrech
rumrotzt und ausser Beleidigungen nichts an den Tag bringt.
echter MSPler schrieb:> Denn ich sehe immer noch keinen brauchbaren Code für den MSP.
Wie schon lange gesagt, da wäre jetzt mal ein echter "echter MSPler"
nötig. Der könnte sowas können...
Peter D. schrieb:> MSPler schrieb:>> Der Master wird im weiteren Verlauf durch einen FPGA mit SPI-Makro>> ersetzt werden.
Oha, Salamitaktik... :-/
> In dem Fall würde ich den MC als SPI-Master und den FPGA als SPI-Slave> benutzen.
Ich auch, denn das FPGA ist wegen der damit möglichen Parallelität auf
jeden Fall schnell genug. Wenn nicht, dann ist die Beschreibung
ungünstig und muss angepasst werden.
echter MSPler schrieb:> Schuster ...>> So isses! Aber warum schreibst du dann hier? Denn ich sehe immer noch> keinen brauchbaren Code für den MSP.
Aha. Leider wird hier im Forum meistens nur Hilfe geleistet, bei
Problemen geholfen usw.
Fertigen Code kriegt keiner.
> Hast du übererhaupt schon einmal so ein Ding von Nahem gesehen? :-*
Nicht naher als 60cm., muss ich zugeben. Allerdings habe ich bei
meinen 2 letzten Laptops die CPU auch noch nie gesehen...
Das erklärt deine Unwissenheit zur hardwarenahen Programmierung und
Kommunikation.
Und natürlich bekommt man hier im Forum fertigen Code. Warum auch nicht?
Der echte MSPler kennt den MSP430 und viele andere uCs. Und daher kann
er gut vergleichen und dir sagen, dass du dir den MSP einmal von ganz
Nahem ansehen solltest. Am Besten rein kriechen.
SPI mit der USCI ist einfach und wird natürlich per Interrupt genutzt.
echter MSPler schrieb:> Und natürlich bekommt man hier im Forum fertigen Code. Warum auch nicht?
Da bin ich aber auf deinen Code gespannt.
> Der echte MSPler kennt den MSP430 und viele andere uCs.
Vom Hörensagen, Internet oder Nachbar Anton ?
> SPI mit der USCI ist einfach und wird natürlich per Interrupt genutzt.
Wow, das hat dir wer erzählt ?
Und du hast den ganzen Satz behalten oder musstest du das aufschreiben?
Hat er dir auch erklärt, was ein Interrupt ist ?
>> Master sendet Register Adresse, von der er lesen möchte> Aber nur, wenn der vorher empfangene Byte Status_Ready bezeichnet.>> Slave antwortet mit H-Byte> Kann er nicht, Slave hat gerade Register Adresse empfangen, Master> muss also zuerst noch etwas senden, damit er auch etwas empfangen kann.>> Master bestätigt> Master wartet eine gewisse Zeit, sendet z.B. EOC (End Of Command) und> empfangt H-Byte.>> Slave antwortet mit L-Byte> Kann er nicht, siehe oben.> Master sendet z.B. EOR (End Of Request) und empfangt L-Byte.>> Master beendet Kommunikation> Hat er schon oben mit EOR getan.
Korrigiert, sieht es bisher so aus:
Master sendet 1 Byte (Bit 8: R/W, Bit 7-0 Register Adresse)
Slave antwortet mit ACK_READ oder ACK_WRITE
Master sendet H_BYTE_REQUEST
Slave antwortet mit oberen 8-Bit des 16-Bit Wortes
Master sendet L_BYTE_REQUEST
Slave antwortet mit unteren 8-Bit
Master sendet END_OF_REQUEST
Slave bestätigt und geht wieder in den IDLE Mode
Implementiert wird das ganze mit Hilfe einer FSM, die in der ISR
beschrieben ist.
Ein gewaltiges Problem habe ich nach wie vor:
Es kommt in unregelmäßigen Abständen vor, dass die Daten vom Slave zum
Master, also über MISO gesendete Worte, um mehrere Bits verschoben beim
Master ankommen. Also statt 00001101 kommt 00011010 beim Master an.
Ich habe alle Steckverbinderkabel schon ausgetauscht und sicher
gestellt, dass alles richtig verbunden ist. Das Taktsignal sieht sauber
aus, so wie man es bei 250 kHz Übertragugnsgeschwindigkeit erwartet.
Hat da Jemand schon mal ähnliche Erfahrungen gemacht?
MSPler schrieb:> Hat da Jemand schon mal ähnliche Erfahrungen gemacht?
Es könnte sein, dass du das TX Register des Slave nicht schnell genug
bedienst.
Wenn die Übertragung immer nur um 1 Bit verschoben ist, dann kann es
auch einfach ein falscher SPI-Modus sein. Wobei du sicher auf dem Master
und dem Slave den selben Mode verwendest.
> Korrigiert, sieht es bisher so aus: ...
Sehe ich das richtig: da sind jede Menge Dummy-Bytes unterwegs? Quasi
Halbduplex-Betrieb: immer nur Senden oder empfangen, aber nicht beides
gleichzeitig?
> um mehrere Bits verschoben beim Master ankommen.
Immer gleich viele Bits?
Und: renkt sich das dann wieder irgendwie ein?
Lothar M. schrieb:> MSPler schrieb:>> Hat da Jemand schon mal ähnliche Erfahrungen gemacht?> Es könnte sein, dass du das TX Register des Slave nicht schnell genug> bedienst.
Das halte ich erst mal für weniger wahrscheinlich, da sind wenige
if/else Zweige im FSM bis jetzt. Aber ausschließen möchte ich es nicht.
>>> Korrigiert, sieht es bisher so aus: ...> Sehe ich das richtig: da sind jede Menge Dummy-Bytes unterwegs? Quasi> Halbduplex-Betrieb: immer nur Senden oder empfangen, aber nicht beides> gleichzeitig?
Ja, das sind "jede Menge" Dummy Bytes unterwegs. Ich habe mit dem
"gleichzeitig" noch so meine Schwierigkeiten. Woher soll der Slave
wissen was er "gleichzeitig" senden soll, ohne das er weiß, was der
Master haben will ... ?!
>>> um mehrere Bits verschoben beim Master ankommen.> Immer gleich viele Bits?> Und: renkt sich das dann wieder irgendwie ein?
Nein, ganz und gar nicht, erst nach einem Reset des Devices
MSPler schrieb:> Woher soll der Slave wissen was er "gleichzeitig" senden soll, ohne das> er weiß, was der Master haben will ...
Ganz einfach: der Master sendet ein Kommando, das der Slave im
nächsten SPI Zyklus beantwortet. So ist zwischen "Frage" (vom Master)
und "Antwort" (vom Slave) immer 1 Zyklus Versatz. Aber(!) in jedem
Zyklus wird eine neue Frage gestellt und die jeweils vorhergehende
beantwortet.
Sieh dir einfach mal das SPI Protokoll eines mehrkanaligen ADC an. Beim
ersten SPI Zyklus ist die Antwort Blödsinn, weil zuvor noch keine Frage
gestellt wurde, aber danach kommt immer gleichzeitig mit dem nächsten
Kommando ein neuer AD Wert als Antwort.
Und was bringt das Ganze?
Komplette zeitliche Entspannung. Denn wen der Master den SS inaktiv
setzt muss der Master erst mal den erhaltenen Wert bearbeiten. Und
solange kann der Slave das eben erhaltene Kommando parsen, bearbeiten
und die Antwort für den nächsten SPI Zyklus bereitstellen. Ja, er kann
sogar vorbereitend schon mal das erste Antwortbyte ins TX-Register
schreiben.
MSPler schrieb:> Es kommt in unregelmäßigen Abständen vor, dass die Daten vom Slave zum> Master, also über MISO gesendete Worte, um mehrere Bits verschoben beim> Master ankommen. Also statt 00001101 kommt 00011010 beim Master an.>> Ich habe alle Steckverbinderkabel schon ausgetauscht und sicher> gestellt, dass alles richtig verbunden ist. Das Taktsignal sieht sauber> aus, so wie man es bei 250 kHz Übertragugnsgeschwindigkeit erwartet.
Wenn alle Steckverbinder in Ordnung sind und Taktsignal sauber, dann
liegt es nicht am Master.
SPI ist reine Hardware, da kann der Empfänger (in diesem Falle Master)
nichts durcheinanderbringen, der Sender (Slave) aber sehr wohl.
Es konnte allerdings sein, dass der Master zu schnell die Daten from
Slave anfordert, das hat der lkmiller gemeint.
MSPler schrieb:>> Es könnte sein, dass du das TX Register des Slave nicht schnell genug>> bedienst.> Das halte ich erst mal für weniger wahrscheinlich, da sind wenige> if/else Zweige im FSM bis jetzt. Aber ausschließen möchte ich es nicht.
Das halte ich für sehr wahrscheinlich, aber vielleicht hast du Recht.
> Ja, das sind "jede Menge" Dummy Bytes unterwegs. Ich habe mit dem> "gleichzeitig" noch so meine Schwierigkeiten. Woher soll der Slave> wissen was er "gleichzeitig" senden soll, ohne das er weiß, was der> Master haben will ... ?!
Deswegen schreibst du ein Protokoll, also eine Art Vereinbarung
zwischen Master und Slave mit einem Byte Versatz, z.B:
Master vorbereitet die Anfrage Slave ist bereit, 0x55 im SPI_TxReg
1
MASTER <====> SLAVE (Int_Routine)
2
A) Was macht man so? (0xAA) Nichts, habe gerade etwas Zeit.(0x55)
3
B) Na, dann lese mal (0x10) Ich erwarte dein Kommando. (0xAA)
4
C) Erst mal die Adresse (0x38) Ich warte auf die Adresse. (0x10)
5
Falls nötig, wartet MASTER ein bißchen, SLAVE liest Lo_Byte...
6
D) Und bitte noch Adresse(0x39) Hier kommt Byte aus Adr.0x38 (Lo_Byt)
7
Falls nötig, wartet MASTER ein bißchen, SLAVE liest Hi_Byte...
8
E) Das war es dann (0xA0) Hier kommt Byte aus Adr.0x39 (Hi_Byt)
Und genau diese viele "Warterei" (in fast jedem Schritt wird da "wenn
nötig" gewartet) möchte ich beim SPI nicht.
Ich mache eine Übertragung mit Vollgas fertig, werte die aus, mache was
Anderes und dann kommt wieder ein SPI Transfer mit Vollgas ohne
Warterei.
Allerdings muss ich eben damit klarkommen, dass ich die Antwort auf mein
Kommando erst beim nächsten SPI Zyklus bekomme.
Zwei unterschiedliche Strategien, die zum Ziel führen...
Lothar M. schrieb:> Und genau diese viele "Warterei" (in fast jedem Schritt wird da "wenn> nötig" gewartet) möchte ich beim SPI nicht.
Nun, es kommt auf die Anwendung und SPI Geschwindigkeit an, deswegen
sage ich auch 'falls notig'...
Allerdings ist 250KHz extrem langsam fur SPI. Ich fahre nie langsamer
als 2MHz. Somit bin ich sogar mit warten viel schneller als mit 250KHz
ohne warten.
> Ich mache eine Übertragung mit Vollgas fertig, werte die aus, mache was> Anderes und dann kommt wieder ein SPI Transfer mit Vollgas ohne> Warterei.
Beim ADC/DAC oder so etwas ist es auch am besten so, beim einfachem
lesen der Register lohnt sich das wiederum kaum.
Ich frage mich immer mehr, ob es sinnvoll ist, in der ISR eine FSM zu
implementieren.
Letzlich habe ich mit Hilfe eurer Anregungen nun ein funktionierendes
Stück Software, dass ein Register ansprechen und dann zwei Bytes
auslesen kann, aber irgendwie erscheint mir das viel zu kompliziert.
Ich habe nun auf Master Seite einige zeitliche Verzögerungen eingebaut,
insbesondere nachdem das CS auf low gezogen wird, nach dem Senden eines
Bytes etc.
Damit bekomme ich zumindest das unnötige Bit-Shifting etwas besser in
den Griff. Meine CPU läuft mittlerweile mit 8 MHz, statt mit 1 MHz und
die SPI Kommunikation mit 1 kHz. Meiner Meinung nach ist das alles
unkritisch.
Nur nochmal zum Verständnis, Senden eines Bytes:
MSPler schrieb:> Ich frage mich immer mehr, ob es sinnvoll ist, in der ISR eine FSM zu> implementieren.
Merke: schon ein schäbiger Zähler ist eine primitive FSM.
> Ich frage mich immer mehr, ob es sinnvoll ist, in der ISR eine FSM zu> implementieren.
Wenn schon irgendwas in einer FSM verwaltet werden soll, dann geht das
nur über eine FSM. Aber es wird eben niemals gewartet, sondern nur
der aktuelle Zustand ausgewertet und bei Bedarf weitergeschaltet. Wenn
in einer FSM ein delay() drin ist oder ein while(), dann sind Probleme
vorprogrammiert...
Wenn ich alle diese "while"-Bedingungen aus der ISR bzw. FSM heraus
nehme, wird überhaupt nichts mehr gesendet. Man könnte auch eine
for-Schleife nehmen. Wenn die Bedingung nach z.B. 500 Mal nicht erfüllt
ist --> break;
Ich halte euch auf dem Laufenden ;-)
Beste Grüße,
MSPler
MSPler schrieb:> Wenn ich alle diese "while"-Bedingungen aus der ISR bzw. FSM heraus> nehme, wird überhaupt nichts mehr gesendet.
Ja, wer sagt denn, dass man die so einfach herausnehmen kann? Die sind
in diesem Code sicher nicht zum Zeitvertreib drin (oder besser gesagt
genau dafür...).
> Das mit dem "while" in der ISR bzw. FSM habe ich bei TI gesehen.
Da hat der Praktikant einfach was hinprogrammiert, was in seinem Fall
sogar funktioniert haben kann.
Schlauer wäre es, den Interrupt so zu programmieren, dass er nur dann
kommt, wenn der TX Buffer leer und aufnahmebereit ist...
MSPler schrieb:> Das mit dem "while" in der ISR bzw. FSM habe ich bei TI gesehen. Hat> mich aber auch stutzig gemacht. Siehe Code:#pragma> vector=USCIAB0RX_VECTOR> __interrupt void USCI0RX_ISR (void)> {> while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?> UCA0TXBUF = UCA0RXBUF;> }
Hättest du ein bisschen aufmerksamer gelesen...
Marc V. schrieb:> Master vorbereitet die Anfrage Slave ist bereit, 0x55 im SPI_TxReg> MASTER <====> SLAVE (Int_Routine)> A) Was macht man so? (0xAA) Nichts, habe gerade etwas Zeit.(0x55)> B) Na, dann lese mal (0x10) Ich erwarte dein Kommando. (0xAA)> C) Erst mal die Adresse (0x38) Ich warte auf die Adresse. (0x10)
Dann hättest du gesehen, das der Slave den zuletzt empfangenen Byte
immer zurücksendet ( falls es sich um ein Kommando handelt ).
Nichts anderes wird auch im Beispiel von TI gemacht.
echter MSPler schrieb im Beitrag #4190781:
> Das wird ja immer spaßiger hier. Nachdem sich klein Marc weinend> verabschiedet hat, ...
Hat er nicht, nur wenn es dich betrifft, bin ich weg. Ich habe
viel Verständnis für geistig zurückgebliebene, aber das heißt noch
lange nicht, dass ich mit denen auch fruchtlose Diskussionen führen
muss...
>Schlauer wäre es, den Interrupt so zu programmieren, dass er nur dann>kommt, wenn der TX Buffer leer und aufnahmebereit ist...
Interessanter Gedanke. Letzlich müsste man in der Hauptroutine das TX
Buffer durch pollen abfragen und je nach Status den Interrupt frei
geben. Zumindest verstehe ich deine Aussage so.
> Hättest du ein bisschen aufmerksamer gelesen...
Ich habe das gelesen und (glaube ich) auch so umgesetzt. Irgendwo im
Source Code verbirgt sich dennoch ein Fehler, der mir heute verborgen
geblieben ist. Vielleicht sticht er mir morgen früh gleich ins Auge ;-)
Euch allen einen schönen Abend.
Und gewöhn dich daran, dass in C weniger oft mehr ist
1
while((IFG2&UCA0TXIFG)==1);
Ich habb keine Ahnung ob das UCA0TXIFG Bit so angeordnet ist, dass sich
nach Ausmaskierung eine 1 ergibt, wenn es gesetzt ist.
Ich will es auch gar nicht wissen. Denn ich weiss eines mit Sicherheit.
Wenn das Bit auf 1 ist dann ist das Ergebnis nach der Verundung nicht 0.
Und das reicht mir schon
1
while(IFG2&UCA0TXIFG);
diese Schleife läuft garantiert solange, wie das Bit gesetzt ist. Und
zwar unabhängig davon, an welcher Bitposition es sich im Register
befindet.
Manchmal ist es in C schlauer, nicht explizit einen Vergleich zu
schreiben, sondern auszunutzen, dass alle Ergebnisse ungleich 0 als
logisch TRUE gewertet werden. Nach der Maskierung mit dem & kommt
entweder 0 heraus (dann war das Bit auf 0) oder es kommt etwas ungleich
0 heraus (dann war das Bit 1). Welcher Zahlenwert sich nach der
Verundung genau ergibt, ist mir völlig schnuppe. Er ist nicht 0, und das
reicht.
Mit einem expliziten Vergleich auf 1 schiesst man sich in solchen Fällen
nur selbst ins Knie. Denn dazu muss das bewusste Bit an genau der
richtigen Stelle im Register sitzen. Tut es das nicht, dann kommt eben
nicht 1 raus, sondern 2 oder 4 oder 8 ...., und das ist nun mal nicht 1
Das ist eine der Sachen in C, bei denen Übereifer massiv schädlich ist.
Ich wollte eigentlich darauf hinaus, dass es Blödsinn ist Buffer A0
abzufragen, wenn man doch über B0 senden möchte.
Aber eure zusätzlichen Punkte treffen natürlich genauso zu.
Das ist eben "learning by doing" :-D