Hallo, ich möchte gerne einen Fifo per SPI von einem Slave auf einen Master übertragen. Der Fifo auf dem Slave soll slavefifo hier heissen. Die Werte in dem slavefifo sind 16bit breit. Per SPI kann ich nur 8bit Daten versenden. Hat jemand von Euch einen Link zu einer fertigen Routine, wie man größere Datenmengen darüber versenden kann?
Mein eigenes C-Programm auf dem Slave sieht bisher so aus:
1 | #include "mbed.h" |
2 | #include "ringbuffer.h" |
3 | |
4 | SPISlave device(p11, p12, p13, p14); // mosi, miso, sclk, ssel |
5 | Serial pc(USBTX, USBRX); |
6 | |
7 | RingBuffer mybuffer; |
8 | |
9 | #define order_getfifolength 220
|
10 | #define order_hole_elemente 221
|
11 | |
12 | void SendeElemente(uint16_t Anzahl) { |
13 | uint16_t Zaehler, |
14 | Element_16bit; |
15 | uint8_t Element1_8bit, |
16 | Element2_8bit; |
17 | |
18 | for (Zaehler=0; Zaehler<Anzahl; Zaehler++) { |
19 | Element_16bit = mybuffer.get(); |
20 | Element1_8bit = Element_16bit>>8; |
21 | Element2_8bit = Element_16bit & 0xFF; |
22 | device.reply(Element1_8bit); |
23 | device.reply(Element2_8bit); |
24 | }
|
25 | }
|
26 | |
27 | int main() { |
28 | pc.baud (115200); |
29 | |
30 | device.frequency(1000000); |
31 | |
32 | pc.format (8, SerialBase::None, 1); |
33 | uint8_t i, befehl, elem1, elem2; |
34 | |
35 | uint16_t Anz_Elements=0; |
36 | bool DatenSenden; |
37 | |
38 | pc.printf("\n\r Programm xxx wurde neu gestartet... "); |
39 | |
40 | // Fifo mit Werten fuellen:
|
41 | for (i=0; i<30; i++) { |
42 | mybuffer.put(0xF00+i); |
43 | pc.printf("\n\r (%i) ", 0xF00+i); |
44 | }
|
45 | |
46 | // for (i=0; i<20; i++) { device.reply(i); }
|
47 | |
48 | while (1) { // Hauptschleife |
49 | if (device.receive()) { // Liegen Daten am SPI-Port an?, if(0) |
50 | befehl = device.read(); |
51 | |
52 | switch (befehl) { |
53 | case (order_getfifolength): |
54 | Anz_Elements = mybuffer.Anzahl(); |
55 | elem1 = Anz_Elements>>8; |
56 | elem2 = Anz_Elements & 0xFF; |
57 | pc.printf ("\n\r fifo-laenge (%i), elem1(%i), elem2(%i)", Anz_Elements, elem1, elem2); |
58 | elem1=70; |
59 | device.reply(elem1); |
60 | device.reply(elem2); |
61 | DatenSenden = true; |
62 | while (DatenSenden) { |
63 | if (device.receive()) { |
64 | device.reply(elem2); |
65 | while (DatenSenden) { |
66 | // Warten, bis letztes Bit gesendet.
|
67 | if (device.receive()) {DatenSenden = false;} |
68 | }
|
69 | } // ende if(device_receive) |
70 | |
71 | } // Ende while(DatenSenden) |
72 | |
73 | |
74 | // device.reply(Anz_Elements & 0xFF);
|
75 | break; |
76 | case (order_hole_elemente): |
77 | pc.printf ("\n\r hole data aus fifo ..."); |
78 | break; |
79 | |
80 | } // Ende switch |
81 | } // Ende if(0) |
82 | |
83 | |
84 | } // Ende Hauptschleife |
85 | |
86 | |
87 | }
|
Mein Pythonprogramm auf dem Raspberry Pi bisher so:
1 | import RPi.GPIO as GPIO |
2 | |
3 | import spidev |
4 | import time |
5 | |
6 | val16 = 0b1100001101010101 |
7 | val16 = 0b0000000100000000 |
8 | |
9 | Anzahl_Werte_in_fifo = 30 |
10 | |
11 | order_getfifolength = 220 |
12 | order_hole_elemente = 221 |
13 | |
14 | |
15 | spi = spidev.SpiDev() |
16 | spi.open (0, 1) |
17 | spi.max_speed_hz = 1000000 |
18 | |
19 | #antwort = spi.xfer2([0xFF])
|
20 | #print (antwort)
|
21 | #print ("44544")
|
22 | a = val16>>8 |
23 | b = val16 & 0xFF |
24 | c = (a<<8) + b |
25 | #print (bin(val16))
|
26 | #print (bin(a))
|
27 | #print (bin(b))
|
28 | #print (bin(c))
|
29 | |
30 | print ("\n spi-readbytes-test:") |
31 | #result = spi.readbytes(25)
|
32 | #print (result)
|
33 | |
34 | # Anzahl holende Werte senden:
|
35 | |
36 | |
37 | # Sende Befehl, um Anzahl Elemente in Fifo zu ermitteln:
|
38 | spi.xfer2([order_getfifolength]) |
39 | time.sleep(0.01) |
40 | result=[] |
41 | result.append (spi.readbytes(1)[0]) |
42 | result.append (spi.readbytes(1)[0]) |
43 | print (result) |
44 | print (spi.readbytes(1)) |
45 | anzahl = (result[0]<<8)+result[1] |
46 | print ("\n Die Anzahl der Elemente im Fifo ist: %s, result(%s)" %(str(anzahl), str(result)) ) |
47 | time.sleep(1) |
48 | spi.xfer2([order_hole_elemente]) |
49 | |
50 | # Lese Anzahl der Werte (16bit)
|
51 | result=[] |
52 | result = spi.xfer2([0, 0]) |
53 | result=[] |
54 | result.append(12) |
55 | result.append(10) |
56 | print (result) |
57 | # 2x 8bit-Werte zu 16-bit Zahl zusammenfassen...
|
58 | Anzahl_Elemente = (result[0]<<8)+result[1] |
59 | |
60 | Anzahl_Elemente=30 |
61 | |
62 | Ergebnisse_8bit=[] |
63 | Ergebnisse_8bit = spi.readbytes(Anzahl_Elemente*2) |
64 | #print (Ergebnisse_8bit)
|
65 | |
66 | Ergebnisse_16bit=[] |
67 | for j in range (0, Anzahl_Elemente*2, 2): |
68 | Ergebnisse_16bit.append( (Ergebnisse_8bit[j]<<8)+Ergebnisse_8bit[j+1] ) |
69 | |
70 | #print (Ergebnisse_16bit)
|
71 | |
72 | spi.close() |
Warum nicht einfach 2x 8 Bit versenden und dann beim Empfänger wieder zusammensetzen? Bzw. im Zweifelsfalle eben nicht den Hardware-SS-Pin zu nehmen sondern eben einen beliebigen anderen Pin und dann eben eben zu Beginn der Übertragung diesen Pin auf LOW ziehen, erst die ersten 8 Bit und dann die zweiten 8 Bit übertragen und dann diesen Pin eben auf HIGH ziehen. Wo liegt das Problem?
Was ich gut hinbekommen habe, das ist die Zerlegung der 16bit-Werte in zwei 8bit-Werte mit dem Shifen >>8 und dem Unden & 0xFF - und das Zusammenbauen auf der Master-Seite. Jetzt geht es darum, eine Möglichkeit zu finden, viele Werte hintereinander gut zu übertragen. Mein Problem ist die Sache mit dem SPI-Port. Ich kann mir die Länge der zu übertragenden Daten ermitteln - nehmen wir mal an, ich möchte 30 Stück aus meinem Fifo lesen. Also muss der Master 60 mal 8bit-Werte holen (30 mal 16bit aus dem Fifo). Ein einfacher schöner Befehl wäre, wenn ich auf dem Raspberry Pi unter Python das machen könnte: spi.readbytes(Anzahl*2). Dann bekomme ich eine Liste in Python mit 60 Elementen. Leider funktioniert das auf der Slave-Seite nicht, die Daten dann so bereitzustellen, dass ich den spi.readbytes-Befehl ausführen kann. Es kommt dann nur ein Wert an. Auf der Slave-Seite muss ich mit dem Befehl .reply(value); den Wert an den SPI-Port schreiben, damit er bei der nächsten Leseoperation ausgewertet werden kann. Ich komme halt momentan auf keine neue Idee, wie ich das hinkriegen kann.
Stefan Schmidt schrieb: > Warum nicht einfach 2x 8 Bit versenden und dann beim Empfänger wieder > zusammensetzen? das klappt ja schon. Stefan Schmidt schrieb: > Bzw. im Zweifelsfalle eben nicht den Hardware-SS-Pin zu > nehmen sondern eben einen beliebigen ... Meinst Du, ich muss mir einen Software-SPI-Port entwickeln und nicht den Hardware-SPI benutzen?
Hugo Zahnfee schrieb: > Stefan Schmidt schrieb: >> Bzw. im Zweifelsfalle eben nicht den Hardware-SS-Pin zu >> nehmen sondern eben einen beliebigen ... > > Meinst Du, ich muss mir einen Software-SPI-Port entwickeln und nicht den > Hardware-SPI benutzen? Entweder du bleibst bei 8-Bit oder du benutzt ein eigenes 16-BIT-Software-SPI. --> Zerleg es is 2 Teile und nimm Hardware-SPI
Die Kombination funktioniert:
1 | Microcontroller (C): |
2 | |
3 | for (i=0; i<30; i++) { device.reply(i); } |
4 | |
5 | Master (Python): |
6 | |
7 | for kkkk in range (0, 30): |
8 | result.append(spi.readbytes(1)[0]) |
Was nicht geht ist das hier: Microcontroller(C): for (i=0; i<30; i++) { device.reply(i); } Master (Python): result = spi.readbytes(30) [/c] Ich verstehe einfach nicht, warum das mit dem spi.readbytes(30) nicht in einem Rutsch funktionieren tut :-(
In Python kenne ich mich nicht wirklich aus, aber prinzipiell habe ich es wie folgt implementiert gehabt: Ich habe einen beliebigen freien Pin (beispielsweise Pin PC1) mit dem SS-Pin vom Slave verbunden. Die restlichen Hardware-SPI-Pins habe ich beibehalten und alles entsprechend verkabelt. Dann habe ich unmittelbar vor dem Aktivieren der Übertragung mittels SPI einfach den Pin PC1 auf Low gezogen und die ersten 8 Bit ganz normal übertragen. Nach dem die Übertragung fertig ist wird ja der eigentliche Hardware-SS-Pin wieder auf High gezogen. Dies juckt den Slave ja nicht, da der Pin PC1 immer noch auf low ist. Daraufhin habe ich erneut eine SPI-Übertragung mit den zweiten 8 Bit gestartet und NACH DEM diese beendet war den Pin PC1 auf High gezogen. So sieht es für den Slave aus, als ob die 16 Bit am Stück übertragen wurden. Hauptsache der SS-Pin VOM SLAVE ist Low während der gesamten Übertragung(en).
In C würde das, was ich beschrieben habe so aussehen, wobei "command" der 16 Bit Befehl/Wert ist, welcher übertragen werden soll.
1 | for(int i = 0; i<2; i++){ |
2 | PORTC &= ~(1<<PC1); //PIN PC1 auf Low ziehen um dem Slave den Start der Übertragung zu signalisieren |
3 | uint8_t byte_to_send = (command && 0x00FF); //Die unteren 8 Bit maskieren |
4 | spi_send(byte_to_send); //Übertragen der unteren 8 Bit |
5 | byte_to_send = command >> 8; //Die oberen 8 Bit maskieren |
6 | spi_send(byte_to_send); // Übertragen der oberen 8 Bit |
7 | PORTC |= (1<<PC1); //PIN PC1 auf High ziehen um dem Slave die Beendigung der Übertragung zu Signalisieren |
8 | }
|
Hugo Zahnfee schrieb: > Die Kombination funktioniert: > Microcontroller (C): > > for (i=0; i<30; i++) { device.reply(i); } > > Master (Python): > > for kkkk in range (0, 30): > result.append(spi.readbytes(1)[0]) > > Was nicht geht ist das hier: > > Microcontroller(C): > > for (i=0; i<30; i++) { device.reply(i); } > > Master (Python): > > result = spi.readbytes(30) Also es scheint daran zu liegen, dass dein uC die Daten nicht rechtzeitig in den Buffer legen kann. Mit der funktionierenden Variante wird vermutlich für jedes Byte die SS Leitung auf Low gezogen und nach dem einen Byte wieder losgelassen. Das passiert 30 mal. Dabei hat der uC genug Zeit seinen Buffer zu füllen. Bei der nicht funktionieren Variante wird die SS Leitung nur einmal Low gezogen, dann werden schnell 30 Bytes versendet und danach wird die SS Leitung losgelassen.
sushi schrieb: > Bei der nicht funktionieren Variante wird die SS Leitung nur einmal Low > gezogen, dann werden schnell 30 Bytes versendet und danach wird die SS > Leitung losgelassen. Das wird das Problem sein. Ich habe mir den Quelltext nicht genau angesehen, aber ausgehend davon, dass der µC nur einen Puffer von 8 Bit hat muss natürlich JEDES MAL die SS-Leitung losgelassen werden. Ich habe ursprünglich nur auf die Anforderung geantwortet gehabt, mehr als 8 Bit auf einmal zu versenden. Habe angenommen, dass ein IC/Slave angesprochen werden sollte, welches eben einen (beispielsweise) 16 Bit langen Befehl braucht bzw. dessen Puffer groß genug ist.
Es kann aber auch sein, dass dein Chip dir per Interrupt Bescheid gibt, dass dein Puffer sich leert, und du dann dort schnell weitere Bits hineinschieben kannst...
Stefan Schmidt schrieb: > Das wird das Problem sein. Ich habe mir den Quelltext nicht genau > angesehen, aber ausgehend davon, dass der µC nur einen Puffer von 8 Bit > hat muss natürlich JEDES MAL die SS-Leitung losgelassen werden. So ist es. Ein SPI Slave hat keine andere (sichere) Möglichkeit signalisiert zu bekommen dass ein Datum eintrifft. Es sei denn er zählt die Clocks einzeln mit.
sushi schrieb: > Bei der nicht funktionieren Variante wird die SS Leitung nur einmal Low > gezogen, dann werden schnell 30 Bytes versendet und danach wird die SS > Leitung losgelassen. Ach so - Du meinst, der Buffer kann erst dann befüllt werden, wenn CS seinen Pegel ändert und "fertig" ist?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.