Hallo, ich versuche, möglichst schnell in AVR-Assembler Datenbytes aus einem Portpin in ein Schieberegister zu schieben, so ähnlich wie das SPI tut. In meinem speziellen Fall kann ich SPI nicht verwenden. Also ich habe das Register R17 und 2 Ausgangs-Pins Port_daten und Port_clock. Ich bin mit dem Befehlssatz noch nicht 100% vertraut. Meiner Meinung nach wäre folgende Vorgehensweise die schnellste, oder geht es noch schneller? 'erstes BIT (MSB first) cbi port_data '2 Takte sbrc R17,7 '2 oder 3 Takte sbi port_data '(2 Takte) sbi port_clock '2 Takte cbi port_clock '2 Takte rol R17 '1 Takt 'zweites BIT cbi port_data sbrc R17,7 sbi port_data sbi port_clock cbi port_clock rol R17 'drittes Bit cbi port_data sbrc R17,7 sbi port_data sbi port_clock cbi port_clock rol R17 'usw. Also in 8*11 Takten maximal wäre das Register bzw. 1 Byte gesendet. Ein bischen unschön finde ich dabei, daß ich auf der Datenleitung eine Frequenz erzeuge, auch wenn ich &HFF in R17 stehen hab (da könnte die datenleitung eigentlich permanent auf H bleiben). Wer bietet weniger?
Das ROL ist überflüssig, Du kannst direkt die Bit-Nummer im SBRC angeben. Es geht noch schneller, indem Du die 256 Fälle explizit unterscheidest und auskodierst.
Ja, da hast Du recht :-) das war früher mal dazu da, um den text mehrfach verwenden zu können.. Irgendwie hab ich gerade 'nen Knoten im Kopf, es müßte doch mit Sprüngen machbar sein, daß man sich das Umschalten spart, wenn das nächste Datenbit den gleichen Wert hat.. (ohne daß man durch das Testen wieder Zeit verliert)
sbrc R17,7 '2 oder 3 Takte sbi port_data '(2 Takte) sbrs R17,7 '2 oder 3 Takte cbi port_data '(2 Takte)
@Düsentrieb ok es ist genauso schnell - 11 Takte in jedem Fall sbrc R17,7 '2 oder 3 Takte sbi port_data '(2 Takte) sbrs R17,7 '2 oder 3 Takte cbi port_data '(2 Takte) sbi port_clock ' 2 Takte cbi port_clock ' 2 Takte zwar nicht schneller, aber schöner :-)
Die Sequemz CBI-SBRC-SBI (6-7 T) kann ersetzt werden durch BST-BLD-OUT (3 T) Dazu wird das auszugebende Byte in ein REG (a) gespeichert und der Port-Zustand des Ausgabe-Ports in ein Zweites (b)
1 | ; init |
2 | in Rb, <port> |
3 | ldi Ra, <wert> |
4 | |
5 | ; out |
6 | bst Ra, 0 |
7 | bld Rb, <pad> |
8 | out <port> |
9 | sbi <clock> |
10 | cbi <clock> |
11 | ... |
Vorteil: schneller und keine Clock auf serdata bei 0xff Nachteil: Nicht IRQ-sicher
Dürfen clock und Date auf dem gleichen Port liegen?
1 | in r17,port ;1 get port data |
2 | bst datareg,7 ;1 get pix 7 |
3 | bld r17,dpin ;1 set data |
4 | ori r17,cmask ;1 mask for set clock |
5 | out port,r17 ;1 out |
6 | andi r17,invcmask ;1 mask for clear clock |
7 | out port,r17 ;1 |
8 | |
9 | bst datareg,6 ;1 get pix 7 |
10 | bld r17,dpin ;1 set data |
11 | ori r17,cmask ;1 mask for set clock |
12 | out port,r17 ;1 out |
13 | andi r17,invcmask ;1 mask for clear clock |
14 | out port,r17 ;1 |
15 | ... |
braucht beide Leitungen am gleichen Port, benötigt dafür aber nur 8x6+1 = 49 Takte. Ausserdem darf kein Interrupt dazwischenkommen, der etwa andere Portpins am gleichen Port ändert... Gruß Jörg ...OK, da war je´mand schneller...
nee, irq kommt da nicht vor. Gut wenn man den ganzen Befehlssatz kennt! BST ist mir noch nicht aufgefallen - sehr geschickt! macht also 8*7 Takte für die Bits + 2 Takte fürs Init. danke, ich glaube, besser geht's nicht! Doch: jetzt könnte man noch daten und clock auf verschiedene Ports legen und den Trick mit dem Einlesen des Ports auch da anwenden, dann kann man für SBI und CBI noch 2x OUT (mit vorbelegten registern) schreiben und spart nochmal 2 Takte je bit. Ich danke Euch für die Befreiung aus der Gedankenklemme und für BST! :-)
Falls Port_daten und Port_clock beide aufm gleichen Port liegen, geht's noch schneller. Hier, weil man das SBI in das OUT ziehen kann. Das OUT setzt also <serdata> und <clock>. Dies, wenn <clock> neg-flankengetriggert ist. Wenn <clock> pos-flankengetriggert ist, dann ist die Sequenz OUT-SBI, ansonsten wie gesagt OUT-CBI. Ohne Initialisierung (3-4 T) dauert die Ausgabe dann 8*5T = 40T.
1 | ; out.0 |
2 | bst Ra, 0 |
3 | bld Rb, <pad> |
4 | out <port> ;; <clock>=1, <data>=.0 |
5 | cbi <clock> ;; <clock>=0 |
6 | |
7 | ; out.1 |
8 | bst Ra, 1 |
9 | bld Rb, <pad> |
10 | out <port> ;; <clock>=1, <data>=.1 |
11 | cbi <clock> ;; <clock>=0 |
12 | |
13 | ... |
und indem man das CBI bzw. SBI durch OUT mit entsprechendem Wert ersetzt ist man bei 8*4 T = 32 T :-)
Man kann es mit 5 Takten pro Bit:
1 | .nolist |
2 | .include "tn2313def.inc" |
3 | .list |
4 | |
5 | .equ SPI_PORT = PORTD |
6 | .equ SPI_DATA = PD0 |
7 | .equ SPI_CLK = PD1 |
8 | |
9 | .def data_lo = r16 |
10 | .def data_hi = r17 |
11 | .def wreg = r18 |
12 | |
13 | spi_out: |
14 | ldi data_lo, 0 |
15 | ldi data_hi, 1<<SPI_DATA |
16 | |
17 | out SPI_PORT, data_lo |
18 | sbrc wreg, 7 |
19 | out SPI_PORT, data_hi |
20 | sbi SPI_PORT, SPI_CLK |
21 | |
22 | out SPI_PORT, data_lo |
23 | sbrc wreg, 6 |
24 | out SPI_PORT, data_hi |
25 | sbi SPI_PORT, SPI_CLK |
26 | |
27 | out SPI_PORT, data_lo |
28 | sbrc wreg, 5 |
29 | out SPI_PORT, data_hi |
30 | sbi SPI_PORT, SPI_CLK |
usw. Schneller geht es nicht, da man das SBI für den Takt nicht durch ein OUT ersetzen kann, weil ja die Daten stabil sein müssen während der Taktflanke. Peter
also so sieht es jetzt aus (das Datenregister R17 sei vorher geladen): 'init: 'portb.4 ist data 'portc.2 ist clock in R19, portb '1 in R20, portc '1 andi R20, &HFB '1 für clock=0 in R21, portc '1 ori R21, &H04 '1 für clock=1 out portc, R20 '1 'erstes bit bst R17, 7 '1 bld R19, 4 '1 out portb, R19 '1 out portc, R21 '1 out portc, R20 '1 'zweites bis 8. bit genauso.. das macht also 6 Takte für die Init und 8*5 für die Bits = 46 Takte. Ich glaube, schneller geht's nicht. Wer unter 44 kommt, kriegt einen Preis! :-)
ok, Georg johann Lay (gjlayde) hat den Preis gewonnen: eine Flasche kaltes Bier! Abzuholen in Berlin, Nähe Ku'damm!
Was hängt denn für ein SPI-Slave dran? Wenn es ein 74*595 o.ä. ist dann werden die Daten per +-Flanke übernommen, und man könnte die 4T/Bit-Version verwenden. Allerdings passt das wohl net zu Deiner Verdrahtung (daten und clock an unterschiedlichen ports)? Ok, Berlin ist ja nur 800km von der Pampa weg...
nee, der AVR ist der SPI Slave. Weil ich also nicht wissen kann, wann der SPI-Master Daten haben will (der setzt SS und schon clockt er los wie wild), schiebe ich sie vorher in ein Schieberegister, dadurch habe ich den fehlenden Buffer zur Augangsseite hin ersetzt (MISO). Eingangsseitig benutze ich SPI, aber da gibt's ja nen Puffer, ich kann mit spif abfragen etc. kein Problem. Das SPDR konnte ich leider nicht als Schieberegister mißbrauchen, das hab ich vorher probiert, aber dann komme ich ich konflikt mit meiner eingangsseitigen Beschaltung. Das Schieberegister ist ein MC14557B / ich hoffe, es ist geeignet. Schade, daß Du in der Pampa wohnst. Berlin ist immer ne Reise wert!
Georg johann Lay wrote: > Was hängt denn für ein SPI-Slave dran? Wenn es ein 74*595 o.ä. ist dann > werden die Daten per +-Flanke übernommen, und man könnte die > 4T/Bit-Version verwenden. Hast Du es denn schon mal ausprobiert? Die Holdtime des 595 ist zwar 0, aber ich halte es für sehr riskant, die Daten gleichzeitig mit der übernehmenden Flanke zu ändern. Die kleinste Leitungskapazität und Dein 595 läuft Amok. Peter
@peda - kein Stress, das mit den 5 Takten sollte ausreichen. Aber jetzt wo Georg nicht so schnell herkommt, kannst Du ja das Bier abholen.. lach
Peter Dannegger wrote: > Georg johann Lay wrote: >> Was hängt denn für ein SPI-Slave dran? Wenn es ein 74*595 o.ä. ist dann >> werden die Daten per +-Flanke übernommen, und man könnte die >> 4T/Bit-Version verwenden. > > Hast Du es denn schon mal ausprobiert? > > Die Holdtime des 595 ist zwar 0, aber ich halte es für sehr riskant, die > Daten gleichzeitig mit der übernehmenden Flanke zu ändern. > > Peter Die übernehmende +-Flanke kommt ja erst 1T später. Die fallende Flanke sollte zusammen mit einem Wechsel an sdata ok sein. Bei einem AVR als HW-SPI-Slave muss man allerdings bestimmte SPI-Taktraten einhalten, die unter denen der vom HW-SPI-Master erzeugbaren liegen (bei gleicher F_CPU). Ob die Einschränkungen beim hiesigen SW-SPI relevant sind, ist noch zu prüfen. Georg-Johann
shifter wrote: > nee, der AVR ist der SPI Slave. Weil ich also nicht wissen kann, wann > der SPI-Master Daten haben will (der setzt SS und schon clockt er los > wie wild), schiebe ich sie vorher in ein Schieberegister, dadurch habe > ich den fehlenden Buffer zur Augangsseite hin ersetzt (MISO). > Eingangsseitig benutze ich SPI, aber da gibt's ja nen Puffer, ich kann > mit spif abfragen etc. kein Problem. Das SPDR konnte ich leider nicht > als Schieberegister mißbrauchen, das hab ich vorher probiert, aber dann > komme ich ich konflikt mit meiner eingangsseitigen Beschaltung. > > Das Schieberegister ist ein MC14557B / ich hoffe, es ist geeignet. http://www.datasheetcatalog.com/datasheets_pdf/M/C/1/4/MC14557B.shtml sagt, der MC14557B ist bei VDD=5V maximal bis f_CL = 1.7 MHz spezifiziert. Je nachdem, wie fix der AVR rennt, musst den µC eher bremsen als das asm zu tunen...
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.