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)
@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 :-)
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!
:-)
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
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...