Forum: Mikrocontroller und Digitale Elektronik geht es noch schneller in ASM?


von shifter (Gast)


Lesenswert?

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?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von shifter (Gast)


Lesenswert?

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)

von Düsentrieb (Gast)


Lesenswert?

sbrc R17,7       '2 oder 3 Takte
      sbi port_data    '(2 Takte)
      sbrs R17,7       '2 oder 3 Takte
      cbi port_data    '(2 Takte)

von shifter (Gast)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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

von Joerg W. (joergwolfram)


Lesenswert?

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...

von shifter (Gast)


Lesenswert?

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

von shifter (Gast)


Lesenswert?

danke auch Wolfram, der Geist sprudelt wieder! :-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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 :-)

von Peter D. (peda)


Lesenswert?

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

von shifter (Gast)


Lesenswert?

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

von shifter (Gast)


Lesenswert?

ok, Georg johann Lay (gjlayde) hat den Preis gewonnen: eine Flasche 
kaltes Bier! Abzuholen in Berlin, Nähe Ku'damm!

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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...

von shifter (Gast)


Lesenswert?

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!

von Peter D. (peda)


Lesenswert?

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

von shifter (Gast)


Lesenswert?

@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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.