Hallo Forum,
ich lerne gerade Assembler für den AVR und komme gewissermaßen nicht
weiter. Ich versuche einen SPI-Slave zu bauen, der von 12
angeschlossenen ADC's Daten ausliest und diese per SPI an den Master
übertragen kann. Da das ganze verdammt schnell gehen muss, habe ich mich
entschieden jetzt endlich mal assembler zu lernen. Das "Rundumzeugs" ist
kopiert, damit ich da nix falsch mache. Der Rest ist mehr oder weniger
mein Verschulden, soll heißen: Bitte schaut mal drüber, ich schaffe es
nämlich gerade nicht mehr, meinen Fehler zu finden.
Erstmal der Code:
; if CS is high again, stop filling the buffer ...
109
sbis PINB, 2
110
rjmp SPI_SlaveReceive ; else put next byte into the buffer
111
112
rjmp Main ; ... and go back to wait for next transmission
113
114
; da kommt noch der Code zum auslesen eines Sensorwertes, aber der ist erstmal wurscht weil bisher ungenutzt.
Soweit sogut. Was ich da denke zu tun:
Initialisieren der SPI-Schnittstelle als Slave. Erzeugen eines
Dummywertes (123), diesen ablegen an erster Stelle von "Data". Das erste
byte von "Data" in den Puffer legen und warten, dass es übertragen wird.
Dann solange die nächsten Bytes nachlegen, bis CS wieder high wird. Wird
CS high, zurückspringen zu Main.
Was nicht geht: Naja, es wird nix übertragen. Und ich hab keine Ahnung
wieso...
Schaut mal drüber, wenn ihr Lust und Zeit habt, mir würde es wahnsinnig
helfen! Danke,
Johannes
Du willst also von abgesetzten ADCs per SPI die Daten an deinen AVR
holen?
Dann müsstest du den Atmel aber bei SPI im MasterMode betreiben. Denn er
ist ja der Master, der die SPI-Slaves (ADCs) anspricht...
Entweder habe ich was falsch verstanden oder Du hast einen
Denkfehler. Ein Slave kann NIEMALS eine Aktion ausführen,
das ist Sache des Masters!
Und ADC sind immer Slaves!
Ich würde das so lösen:
Den µC als MASTER definieren, jedem der ADCs eine Chip-Select
Leitung verpassen.
Bei dem ADC den ich auslesen will die CS-Leitung auf L, damit
ist der ADC angesprochen, und die Daten per SPI abholen/reinschreiben.
Wenn fertig: CS-Leitung wieder auf H, und
den nächsten ADC ansprechen.
Dann kann man auch die SPI-Schnittstelle des ATMEGA verwenden.
Man spart sich einigees an Code, wenn man die HW-SPI-Schnittstelle
einsetzt. (Datenblatt)
Sorry, habe mich unklar ausgedrück. Ich habe 12 ADCs dranhängen, die ich
auslesen möchte. Da ich alle Werte möglichst exakt parallel brauche,
habe ich das SPI zu den ADCs per Software gelöst. Dabei teilen sich alle
ADCs MOSI, SCK und CS. Die MISO-Leitungen sind von jedem ADC einzeln an
Portpins geführt. Somit kann ich alle 12 parallel auslesen. Wie gesagt,
das geht über Software-SPI.
Das ist aber momentan noch gar nicht das Problem.
Die Daten sollen dann nämlich von einem anderen Board (STM32 mit Midibox
firmware drauf) ausgelesen werden. Dazu muss mein Atmega48 im
Slave-Modus sein. Wenn ich 96 mal 12 bit übertragen will, und das auch
noch mit 1000Hz, dann brauche ich das Hardware-SPI des AVR zur
Kommunikation mit dem STM32-Board. Und das versuche ich gerade zum
laufen zu bekommen.
Dazu generiere ich einfach irgendwelche Daten, die ich mir dann vom
STM32 abholen lassen will. Nur genau das geht noch nicht.
Lassen wir die ADCs erstmal außen vor: Ich bekomme einfach diese
Testdaten (123) nicht vom Slave (dieser AVR) zum Master (STM32).
Johannes
PS: Damit es nicht zu Verwirrungen führt: Ich initialisiere teile von
PORTC als Ausgang. Im Kommentar steht was von SCK usw. Das sind die
Leitungen an denen die ADC's hängen. Die sind momentan noch irrelevant.
>Die Daten sollen dann nämlich von einem anderen Board (STM32 mit Midibox>firmware drauf) ausgelesen werden. Dazu muss mein Atmega48 im>Slave-Modus sein. Wenn ich 96 mal 12 bit übertragen will, und das auch>noch mit 1000Hz, dann brauche ich das Hardware-SPI des AVR zur>Kommunikation mit dem STM32-Board. Und das versuche ich gerade zum>laufen zu bekommen.
Das ist doch Unsinn.
Wozu willst du die ADCs per SPI durch einen Atmel auslesen, um diese
Daten dann per SPI an einen anderen µC weiterzuleiten?
Warum liest der andere µC die Daten nicht direkt von den ADC per SPI
aus?
Steffen H. schrieb:> Schau mal hier: ; PortB> ldi rHilf,0b00010000 ; only PB4 for MISO> out DDRB,rHilf> Du hast den SS-Pin auf Ausgang gesetzt! Damit fungiert dein HW-SPI als> Master!
Hä? Steh ich auf dem Schlach? Ich setzte nur PB4 als Ausgang. Und das
ist am ATMega48 ein MISO Pin. PB2 wäre SS, aber der ist doch als Input
eingestellt.
Matthias Lipinsky schrieb:> Das ist doch Unsinn.>> Wozu willst du die ADCs per SPI durch einen Atmel auslesen, um diese> Daten dann per SPI an einen anderen µC weiterzuleiten?>> Warum liest der andere µC die Daten nicht direkt von den ADC per SPI> aus?
Nunja, ich verwende hier zwei Boards, die als solche schon vorhanden
waren und nun einem neuen Zweck dienen sollen. Würde ich es so machen,
wie du vorschlägst, so müsste ich die SMD-ADCs wieder auslöten und ein
neues Board ätzen usw. usw. Daher wollte ich es erstmal so versuchen.
Ist im Endeffekt auch nicht mehr Aufwand.
Danke schonmal,
Johannes
Johannes Neumann schrieb:> Steffen H. schrieb:>> Schau mal hier: ; PortB>> ldi rHilf,0b00010000 ; only PB4 for MISO>> out DDRB,rHilf>> Du hast den SS-Pin auf Ausgang gesetzt! Damit fungiert dein HW-SPI als>> Master!>> Hä? Steh ich auf dem Schlach? Ich setzte nur PB4 als Ausgang. Und das> ist am ATMega48 ein MISO Pin. PB2 wäre SS, aber der ist doch als Input> eingestellt.
Ganz abgesehen davon sollte der PIN laut Datenblatt automatisch ein
Input sein. Ich habe lediglich Einfluss auf das Verhalten von MISO.
Ich habe inzwischen noch etwas herumprobiert. Clock und Phase sollte
beides 1 sein, das hatte ich bisher in der Initialisierung vergessen.
Auch dachte ich, kann es nicht schaden, SPDR nach jedem
gesendeten/empfangenen Byte auch mal zu lesen: Habe im Datenblatt keinen
expliziten Hinweis darauf gefunden, ob man das machen muss, aber es kann
ja nicht schaden.
Ich habe außerdem alle Kabel überprüft.
Ich habe außerdem herausgefunden, dass die Übertragung geht, wenn ich
den Master SS invertiert ausgeben lasse, sprich: SS high schalten,
übertragen, SS Low schalten. Das sollte ja eigentlich andersherum
sein...
Johannes
Da ohne Interrupt gearbeitet wird, muss SPDR gelesen werden, sonst
wird SPIF nicht zurückgesetzt, die Übertragung bliebe also nach dem
ersten Byte stehen; siehe Datenblatt unter SPSR.SPIF .
der alte Hanns schrieb:> Da ohne Interrupt gearbeitet wird, muss SPDR gelesen werden, sonst> wird SPIF nicht zurückgesetzt, die Übertragung bliebe also nach dem> ersten Byte stehen; siehe Datenblatt unter SPSR.SPIF .
Ok, das hatte ich irgendwie nicht gesehen. Danke
So, ich habe jetzt folgendes am Laufen: SPI geht mit richtiger SS
Polarität. Ich generiere für die ersten 6 Bytes die Daten 1,2,3,4,5,6
und lasse sie mir am Master auf einem LCD darstellen. Beim ersten Mal
lesen bekomme ich: 255,1,2,3,4,5 danach immer 0,1,2,3,4,5. Da erscheint
irgendwie ein Murks-Byte in der Übertragung, nur woher? Meines Erachtens
sollte es das eigentlich nicht: Ich lade ja das erste Byte (Wert: 1) in
SPDR und ware danach, bis es übertragen wurde. Erst danach schiebe ich
die Bytes mit 2,3,4,5,6 raus.
Mein Code sieht jetzt so aus:
1
Main:
2
; create some dummy data to transmit
3
4
ldi ZL, LOW(Data)
5
ldi ZH, HIGH(Data)
6
ldi rHilf,1
7
st Z+, rHilf
8
ldi rHilf,2
9
st Z+, rHilf
10
ldi rHilf,3
11
st Z+, rHilf
12
ldi rHilf,4
13
st Z+, rHilf
14
ldi rHilf,5
15
st Z+, rHilf
16
ldi rHilf,6
17
st Z+, rHilf
18
19
20
; put first byte into send buffer
21
22
; point to first byte of "Data"
23
ldi ZL, LOW(Data)
24
ldi ZH, HIGH(Data)
25
; load the byte
26
ld rHilf, Z+
27
; put into buffer
28
out SPDR, rHilf
29
30
SPI_SlaveReceive:
31
32
; if CS is high (for whatever reason) ...
33
sbic PINB, 2
34
rjmp Main ; ... jump back to main
35
36
; Wait for reception complete
37
in rHilf, SPSR
38
sbrs rHilf, SPIF ; if not complete...
39
rjmp SPI_SlaveReceive ; ... check again
40
41
42
; if complete, load the next byte
43
ld rHilf, Z+
44
; put into buffer
45
out SPDR, rHilf
46
; dummy read data
47
in rHilf,SPDR
48
49
; if CS is still low ...
50
sbis PINB, 2
51
rjmp SPI_SlaveReceive ; ... put next byte into the buffer
52
53
rjmp Main ; else go back to readout and wait for next transmission
Hi
Dein erstes Byte muss schon im SPDR vom Slave liegen bevor der Master
anfängt zu Lesen. Das erste Byte ist sonst der zufälligen Wert, der
gerade im SPDR ist.
MfG Spess
spess53 schrieb:> Hi>> Dein erstes Byte muss schon im SPDR vom Slave liegen bevor der Master> anfängt zu Lesen. Das erste Byte ist sonst der zufälligen Wert, der> gerade im SPDR ist.>> MfG Spess
Das mach ich doch - denke ich. Siehe hier:
1
; put first byte into send buffer
2
3
; point to first byte of "Data"
4
ldi ZL, LOW(Data)
5
ldi ZH, HIGH(Data)
6
; load the byte
7
ld rHilf, Z+
8
; put into buffer => Diese stelle meine ich. Das Byte landet in SPDR bevor der Master zu empfangen veruscht
Der Master braucht mehrere Sekunden zum booten, erst danach startet er
die Kommuniktaion. Der Slave sollte da deutlich schneller sein. Ich
hoffe, das war, was du meintest.