mikrocontroller.net

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


Autor: shifter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: shifter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Düsentrieb (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: shifter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-)

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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)
; init
in  Rb, <port>
ldi Ra, <wert>

; out
bst  Ra, 0
bld  Rb, <pad>
out  <port>
sbi  <clock>
cbi  <clock>
...

Vorteil: schneller und keine Clock auf serdata bei 0xff
Nachteil: Nicht IRQ-sicher

Autor: Joerg Wolfram (joergwolfram)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dürfen clock und Date auf dem gleichen Port liegen?
  in  r17,port  ;1 get port data
  bst  datareg,7  ;1 get pix 7
  bld  r17,dpin  ;1 set data
  ori  r17,cmask  ;1 mask for set clock
  out  port,r17  ;1 out
  andi  r17,invcmask  ;1 mask for clear clock
  out  port,r17  ;1
  
  bst  datareg,6  ;1 get pix 7
  bld  r17,dpin  ;1 set data
  ori  r17,cmask  ;1 mask for set clock
  out  port,r17  ;1 out
  andi  r17,invcmask  ;1 mask for clear clock
  out  port,r17  ;1
  ...  
  
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...

Autor: shifter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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! 
:-)

Autor: shifter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke auch Wolfram, der Geist sprudelt wieder! :-)

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.
; out.0
bst  Ra, 0
bld  Rb, <pad>
out  <port>  ;; <clock>=1, <data>=.0
cbi  <clock> ;; <clock>=0

; out.1
bst  Ra, 1
bld  Rb, <pad>
out  <port>  ;; <clock>=1, <data>=.1
cbi  <clock> ;; <clock>=0

...

und indem man das CBI bzw. SBI durch OUT mit entsprechendem Wert ersetzt 
ist man bei 8*4 T = 32 T :-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann es mit 5 Takten pro Bit:

.nolist
.include "tn2313def.inc"
.list

.equ    SPI_PORT = PORTD
.equ    SPI_DATA = PD0
.equ    SPI_CLK = PD1

.def    data_lo = r16
.def    data_hi = r17
.def    wreg    = r18

spi_out:
        ldi     data_lo, 0
        ldi     data_hi, 1<<SPI_DATA

        out     SPI_PORT, data_lo
        sbrc    wreg, 7
        out     SPI_PORT, data_hi
        sbi     SPI_PORT, SPI_CLK

        out     SPI_PORT, data_lo
        sbrc    wreg, 6
        out     SPI_PORT, data_hi
        sbi     SPI_PORT, SPI_CLK

        out     SPI_PORT, data_lo
        sbrc    wreg, 5
        out     SPI_PORT, data_hi
        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

Autor: shifter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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! 
:-)

Autor: shifter (Gast)
Datum:

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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: shifter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: shifter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.