PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : SPI-Kommunikation, mir fehlt der Ansatz...



Geistesblitz
16.02.2014, 14:58
Ich versuche gerade, mittels SPI mit einem AS5048A (http://www1.futureelectronics.com/doc/AUSTRIAMICROSYSTEMS/AS5048DB.pdf) zu kommunizieren, allerdings bin ich gerade ein wenig überfordert. Wie konfiguriert man den SPI-Bus richtig? Und wie läuft das eigentlich genau mit der Kommunikation ab?
Ich dachte jetzt eigentlich, dass ich ein Byte sende und dann ein Byte zurück bekomme, oder sind das immer zwei Bytes (wegen 16-Bit?). Irgendwie steh ich da noch total auf dem Schlauch.
Hier mal mein kleines Testprogramm:


$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 16000000
$baud = 9600

Config Spi = Hard , Interrupt = On , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 16

Config Lcdpin = Pin , Db4 = Porta.3 , Db5 = Porta.2 , Db6 = Porta.1 , _
Db7 = Porta.0 , E = Porta.4 , Rs = Porta.5
Config Lcd = 20 * 4
Cursor Off
Cls

Spiinit

Dim Angle As Integer

Do
Angle = Spimove(&h3fff , 2)
Locate 1 , 1
Lcd Angle
Waitms 100
Loop

Beim Kompilieren bekomm ich dann drei Fehler: Invalid Datatype, Variable not dimensioned und Loop expected
Keine Ahnung, wie ich da rangehen soll...

Edit: 0x3fff ist natürlich schwachsinn, &h3fff muss es heißen, aber irgendwie bekomm ich trotzdem nix gescheites...

Sauerbruch
16.02.2014, 17:18
Alle SPI-Befehle können meines Wissens nach nur Byte-Variablen verarbeiten, ganz gleich in welche Richtung. Deswegen meckert Bascom sowohl die Integer-Variable Angle als auch den Wert &h3fff an. Der Rest (Loop expected) ist glaube ich nur so´n Nachmaulen, das der Compiler manchmal macht, wenn ihm was sauer aufstößt.

Du müsstest also &h3FFF erstmal in ein Array aus 2 Bytes zerlegen:

A(1) = &h3F
A(2) = &hFF

Und für Angle legst Du ebenfalls ein Array aus 2 Bytes an:

Dim Angle as Byte(2)


Diese Zeile

Angle(1) = Spimove (A(1),2)

sendet dann &h3F und &hFF nacheinander raus, und das zurückkommende Ergebnis wird in Angle(1) und Angle(2) abgelegt. Daraus müsstest Du dann nur noch einen Integer machen.

Steht übrigens auch sehr schön in der Bascom-Hilfe erklärt :)

Geistesblitz
16.02.2014, 23:17
Die hab ich mittlerweile auch schon gefunden, muss ich mal ausprobieren.
Kann man eigentlich bei Soft-SPI die Einstellungen genauso vornehmen wie bei Hard-SPI, also zB. die Frequenz etc? Die Hard-SPI blockiert mir sonst den Programmieranschluss (oder da ist irgendwo auch noch ein Fehler in der Verdrahtung).

- - - Aktualisiert - - -

Ich musste feststellen, dass ich die Leitungen nicht richtig verdrahtet hatte :oops:
Mein Code sieht nun folgendermaßen aus:


$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 16000000
$baud = 9600

Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 1 , Clockrate = 16

Config Lcdpin = Pin , Db4 = Porta.3 , Db5 = Porta.2 , Db6 = Porta.1 , _
Db7 = Porta.0 , E = Porta.4 , Rs = Porta.5
Config Lcd = 20 * 4
Cursor Off
Cls

Spiinit

Dim Angle(2) As Byte

Wait 1

Angle(1) = Spimove(&H4001 , 2)

Do
Angle(1) = Spimove(&Hffff , 2)
Cls
Locate 1 , 1
Lcd Angle(1)
Locate 1 , 5
Lcd Angle(2)
Waitms 10
Loop

Auf dem Display erhalte ich nur
192 0
Entspricht also der Bitfolge
1100 0000 0000 0000
wie es also wohl aussieht, bekomm ich nur ein Errorflag, vielleicht durch das flashen des Controllers noch. Nun hab ich aber schon einen Error-Reset eingefügt, das Problem geht aber nicht weg. Weiß jemand Rat?
Ich bin mir auch nicht ganz sicher, ob ich die Daten richtig sende. Der Sensor will ja immer 16 Bit auf einmal haben...

Geistesblitz
17.02.2014, 12:11
Hmm, einfach so die Beiträge zusammenführen...kein Wunder, dass dann keiner antwortet.
Weiß einer, wo das Problem liegt?

Sauerbruch
17.02.2014, 19:55
Ich habe mir gerade das Datenblatt von diesem Magnetsensor angeschaut - ein interessantes Teilchen :-)
Was ich nicht ganz verstehe: Welches Kommando steckt hinter &hFFFF?

Und hast Du schon mal versucht, die 16 Bits in Form von zwei hintereinander gesendeten Bytes zu verpacken?
Ich habe mal ´ne Menge mit RFM01 und RFM02-Bausteinen gemacht (kleine 70cm-Sender und -Empfänger), die auch immer 16 Bits in Folge sehen wollen. Das ging mit einem Array aus zwei Bytes ganz hervorragend...

.:Sebastian:.
17.02.2014, 21:54
Moin,

ich kenne das Problem, der AS5048 macht nur fast SPI.
Stattdessen kommt da SSI zum Einsatz.
Das ist fast kompatibel zu SPI in Modus 2 (Ruhepegel ist High, Bits werden bei fallender Flanke gelesen) nur wird das erste Bit eine Flanke zu spät raus-geschoben. (Vergleich mal Diagramme im Datasheet vom Mega mit denen vom AS5048.)

Ich hab das ganze mal hier (http://sindri.sebastians-site.de/MagneticRotaryEncoder#The_Software) recht ausführlich auf englisch erläutert.
Fall die Sprache ein Problem ist kann ich das ganze auch nochmal auf Deutsch hier posten. Fehlt nur gerade die Zeit.

Kurzfassung fürs auslesen ist die:
1. CS-Pin am AS5048 low ziehen und für beide Bytes low halten (als nicht das SS-Signal vom Hardware SPI benutzen, das wird nach jedem Byte kurz high, sondern den Pin selber schalten).
2. Einmal ein Byte irgendwas senden, was ist egal du willst nur 8 Taktzyklen auf deiner Clockleitung.
3. Empfangsregister auslesen
4. Wert um 9 Bit links schieben. (Es ist dein höherwertiges Byte und dein erstes Bit ist immer 0, siehe mein Link).
5. Einmal ein Byte irgendwas senden, was ist wieder egal du willst nur 8 Taktzyklen auf deiner Clockleitung.
6. Empfangsregister auslesen
7. Wert um 1 Bit links schieben und an das Highbyte dran verodern.
8. Manuell den Datenpin lesen für das letzte Bit
9. Das letzte Bit im Ergebnis entsprechend setzen.
10. CS auf high setzen

Ich habe leider keine Ahnung wie man das genau in bascom tut.
Ich kann nur C und Assembler.

Fall C-Code was hilft: http://sindri.sebastians-site.de/hg/sindri/file/encoder_release_1.3/firmware/AS5043_tests/include/AS5043.c#l26
Das ist getestet und von mehren Leuten validiert.

Gruß
Sebastian

Geistesblitz
17.02.2014, 22:14
Vielen Dank für deine Erklärung, nur glaube ich, dass wir von verschiedenen ICs reden. Ich hab einen AS5048A, in deinem Link schreibst du aber von einem AS5043.
Wahrscheinlich hast du dich da verlesen, kann ja mal passieren.
Bei meinem IC soll man nämlich auch etwas senden können, nicht nur auslesen.
Das mit dem manuellen SS über zwei Bytes werd ich mal ausprobieren, das war ein guter Tipp.

Edit: das &hffff sollte eigentlich heißen: ich will auf das register &h3fff (angle-register) zugreifen, zusätzlich aber eben noch bit 14 (read) und bit 15 (parity) gesetzt -> wird zu &hffff

Edit²:
Hab das jetzt mal ausprobiert, hab die Adressen in Byte-Arrays geschrieben und die SS-Leitung auf einen anderen Pin gesetzt. Ergebnis ist immernoch das Gleiche wie vorher. Hier der Code:

$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 16000000
$baud = 9600

Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 1 , Clockrate = 128

Config Lcdpin = Pin , Db4 = Porta.3 , Db5 = Porta.2 , Db6 = Porta.1 , _
Db7 = Porta.0 , E = Porta.4 , Rs = Porta.5
Config Lcd = 20 * 4
Cursor Off
Cls
Config Portb.3 = Output
Portb.3 = 1

Spiinit

Dim Anglereg(2) As Byte
Dim Errorreg(2) As Byte
Anglereg(1) = &HFF
Anglereg(2) = &HFF
Errorreg(1) = &H40
Errorreg(2) = &H01

Dim Angle(2) As Byte

Wait 1

Portb.3 = 0
Angle(1) = Spimove(errorreg(1) , 2)
Portb.3 = 1

Do
Portb.3 = 0
Angle(1) = Spimove(anglereg(1) , 2)
Portb.3 = 1
Cls
Locate 1 , 1
Lcd Angle(1)
Locate 1 , 5
Lcd Angle(2)
Waitms 10
Loop

Edit³:
Ich glaub, ich habs jetzt:

$regfile = "m32def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 16000000
$baud = 9600

Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 1 , Clockrate = 128

Config Lcdpin = Pin , Db4 = Porta.3 , Db5 = Porta.2 , Db6 = Porta.1 , _
Db7 = Porta.0 , E = Porta.4 , Rs = Porta.5
Config Lcd = 20 * 4
Cursor Off
Cls
Config Portb.3 = Output
Portb.3 = 1

Spiinit

Dim Anglereg(2) As Byte
Dim Errorreg(2) As Byte
Anglereg(1) = &HFF
Anglereg(2) = &HFF
Errorreg(1) = &H40
Errorreg(2) = &H01

Dim Angle(2) As Byte

Wait 1

Portb.3 = 0
waitus 10
Angle(1) = Spimove(errorreg(1) , 1)
Angle(2) = Spimove(errorreg(2) , 1)
waitus 10
Portb.3 = 1

Do
Portb.3 = 0
waitus 10
Angle(1) = Spimove(anglereg(1) , 1)
Angle(2) = Spimove(anglereg(2) , 1)
waitus 10
Portb.3 = 1
angle(1)=angle(1) and &b00111111
Cls
Locate 1 , 1
Lcd Angle(1)
Locate 1 , 5
Lcd Angle(2)
Waitms 10
Loop

Sende die Bytes jetzt wirklich einzeln. Dachte eigentlich, wenn ich angle(1)=SPIMOVE(anglereg(1),2) angebe, dass er dann automatisch das Byte an der nächsten Stelle als nächstes sendet und auch ins Folgende schreibt, aber anscheinend hab ich das missverstanden. Nun lese ich ab 6 12x (ein bisschen verrauscht, letzte Stelle springt schön, muss ich wohl noch ein wenig filtern) und wenn ich den Magneten drehe 6 3x

.:Sebastian:.
17.02.2014, 23:19
Moin,

ja da fehlt ein Satz in meinem ersten Posting und zwar: "Ich habe grade kein Datasheet da, aber ich glaube mich zu erinnern, dass der AS5048 die 14bit Version vom AS5043 ist."
Muss das Posting-Formular wohl gefressen haben.
Stimmt nicht ganz, der 48er hat echtes SPI, nicht nur SSI und ist etwas neuer als der AS4043.

Aber CS über beide Bytes low halten kann schon mal nicht schaden.
Siehe figure 4.2.2 im Datasheet vom AS5048

Ansonsten würde ich nochmal Prüfen ob die Reihenfolge der Bits stimmt.
Also erst das Highbyte dann das Lowbyte, jeweils mit dem MSB zuerst.

Gruß
Sebastian

Geistesblitz
17.02.2014, 23:44
Da die LSBs am ehesten vom Messrauschen betroffen sind, denke ich mal, dass es so herum richtig sein muss. Das Datasheet zum AS5048A und -B hab ich doch im Eingangspost verlinkt, wie schwer kann das dann zu finden sein? Hab jetzt noch ein wenig mit Hilfe von Overlay gearbeitet, um alles in einem Integerwert zu verstauen, jetzt kann ich endlich mit dem nächsten Schritt in meinem Programm weitermachen :)

.:Sebastian:.
18.02.2014, 00:00
Das Datasheet zum AS5048A und -B hab ich doch im Eingangspost verlinkt, wie schwer kann das dann zu finden sein?


Das ist alles ganz leicht wenn man über einen Internetzugang verfügt.
Ich sitze hier aber Moment gerade bei lauschigen 368kbit/s die ich mir mit 4 anderen Leuten teilen muss.
Da kann man hat mal so seine 10-20min auf das Datasheet warten und da ich mir ziemlich sicher war das der 48er auch nur SSI hat, hab ich halt mal schnell was geschrieben.

Außerdem vergiss die Bit-Order die passt bei dir, ich hatte dein letztes Posting, so missverstanden das die Werte immer noch nicht passen

Aber kein Problem, das nächste spare ich mir den Aufwand einfach, wenn es dich stört dass ich halt mal daneben lag.

Gruß
Sebastian

Geistesblitz
18.02.2014, 00:16
Nee, sorry, bin heute wohl ein wenig gereizt, wollte dich nicht anfahren. Hatte nur nicht damit gerechnet, dass heutzutage jemand noch zu solchen Bedingungen ins Internet geht.
Damit wären jetzt hoffentlich auch alle Missverständnisse geklärt. Letztendlich haben mich deine Gedanken zu der Sache ja dazu bewegt, daran weiter zu probieren ;)