Hallo, ich versuche einen IO-Port zu schalten, brauche dafür ein auf 1-Clock-Zyklus genaues Timing und genau da liegt das Problem. Leider kann ich noch kein Assembler, deshalb versuche ich es in C. Damit es so unkompliziert wie möglich ist, sieht mein Code (gekürzt) so aus: uint8_t off = PORTB; uint8_t on = PORTB | (1<<PORTB4); if (bla) PORTB = on; else PORTB = off; if (bla) PORTB = on; else PORTB = off; if (bla) PORTB = on; else PORTB = off; if (bla) PORTB = on; else PORTB = off; if (bla) PORTB = on; else PORTB = off; if (bla) PORTB = on; else PORTB = off; if (bla) PORTB = on; else PORTB = off; if (bla) PORTB = on; else PORTB = off; Das funktioniert auch alles soweit, solange ich 01010101 setze. Setze ich allerdings 00001111 fällt mir auf, dass er anscheinend so "klug" ist, bei den sich wiederholenden Bits weniger Zyklen zu brauchen als bei dauernd wechselnden Bits, als ob es intern so nach "IF(differentStatus)Switch" ablaufen würde. Das ist natürlich prinzipiell sehr intelligent, aber in meinem Fall müssen die Timings halt genau stimmen. Laut ASM macht er es so: sbrs r24, 1 rjmp .+4 out 0x18, r25 rjmp .+2 out 0x18, r18 Sieht doch für mich als Laie eigentlich genau richtig aus. Dennoch brauchen die outs je nach Bitmuster verschieden lange....
Christian S. schrieb: > Das funktioniert auch alles soweit, solange ich 01010101 setze. Setze > ich allerdings 00001111 fällt mir auf, dass er anscheinend so "klug" > ist, bei den sich wiederholenden Bits weniger Zyklen zu brauchen als bei > dauernd wechselnden Bits, als ob es intern so nach > "IF(differentStatus)Switch" ablaufen würde. zeige dafür bitte brauchbaren code - wo wird denn 01010101 gesetzt? > Dennoch brauchen die outs je nach Bitmuster verschieden lange.... nein, ein out brauch immer gleich lange. Die Frage ist ob ein out immer das richtige ist. Zeige eine komplette Funktion und den Aufruf dafür.
>Sieht doch für mich als Laie eigentlich genau richtig aus. Dennoch >brauchen die outs je nach Bitmuster verschieden lange... Out ist out! Ob jetzt 8-mal nix 0x00 oder 8-mal was 0xff rausgeschaufelt wird, ist dem Befehl gleich.
Christian S. schrieb: > uint8_t off = PORTB; > uint8_t on = PORTB | (1<<PORTB4); > > if (bla) PORTB = on; else PORTB = off; > if (bla) PORTB = on; else PORTB = off; Dieser Code ist Schwachsinn. Die Variable off enthält den aktuellen Zustand von PORTB, die Variable on enthält den aktuellen Zustand, wobei zusätzlich PB4 gesetzt ist. Wenn aber das Bit einmal gesetzt wurde, ist es auch beim nächsten mal in der Variablen off gesetzt. Wenn, dann muss das so heißen:
1 | if (bla) PORTB |= (1<<PORTB4); else PORTB &= ~(1<<PORTB4); |
2 | if (bla) PORTB |= (1<<PORTB4); else PORTB &= ~(1<<PORTB4); |
3 | ...
|
Aber zurück zur eigentlichen Frage, nämlich zu den verschieden langen Abarbeitungszeiten: Es liegt nicht an der Portzuweisung, sondern an der Abarbeitung der if-Statements. Je nachdem, welche Bedingung TRUE ist, sind verschieden viele ifs durchlaufen worden. Das braucht unterschiedlich lange Zeiten. Abhilfe: Eine Tabelle. Vielleicht auch ein switch.
:
Bearbeitet durch Moderator
1 | uint8_t off = PORTB; |
2 | uint8_t on = PORTB | (1<<PORTB4); |
3 | |
4 | if (bla) PORTB = on; else PORTB = off; |
Im else-Zweig ergibt sich immer PORTB = PORTB; Soll das so sein?
Noch besser: Verwendung von Timer-Output-Compare. Das geht zwar nur mit dezidierten Timer-Pins, dafür kannst Du Dir aber auch sicher sein, daß da Timing passt. Bei Deiner Software-Lösung darfst Du entweder keine Interrupts verwenden oder Du musst sie für die Dauer des Pulses ausschalten. Gruß, Stefan
Es gibt die Möglichkeit den Versatz durch die unterschiedlichen Laufzeiten durch das auffüllen mit NOPs auszugleichen. In der Praxis artet das aber schnell in einen Job für den guten, alten Sisyphos aus. Soweit mir bekannt benötigen die einfachen out-Befehle 1 Tackt Zyklus, ein bedingter Sprung ohne Verzweigung ebenfalls einen Tackt und bei Verzweigung 2 Tackte.
Mittlerweile habe ich das Problem gefunden. Hier nochmal der Code, auf den es ankommt: sbrs r24, 1 rjmp .+4 out 0x18, r25 rjmp .+2 out 0x18, r18 Das Problem ist, dass die rjmps manchmal vor und manchmal nach dem out ausgeführt werden, was das Timing zerstört. Ich habe es jetzt durch nops gelöst, aber das kostet mich insgesamt 3 Takte. Kann man sich diesen Iftest irgendwie sparen? Irgendwie sowas wäre schön: PORTB = Bit 0 von byte X an Stelle PORTB4 packen PORTB = Bit 1 von byte X an Stelle PORTB4 packen PORTB = Bit 2 von byte X an Stelle PORTB4 packen PORTB = Bit 3 von byte X an Stelle PORTB4 packen PORTB = Bit 4 von byte X an Stelle PORTB4 packen PORTB = Bit 5 von byte X an Stelle PORTB4 packen PORTB = Bit 6 von byte X an Stelle PORTB4 packen PORTB = Bit 7 von byte X an Stelle PORTB4 packen Es geht einfach darum, einen UART Sender in Software zu implementieren. Dient für mich als Übung.
Christian S. schrieb: > Es geht einfach darum, einen UART Sender in Software zu implementieren. Benutze doch einen Timer dafür. Oder willst Du gar 115200 Baud oder mehr in Software hinbekommen?
> PORTB = Bit 4 von byte X an Stelle PORTB4 packen
Sollte dir diese Zeile nicht zu denken geben?!
mich wunder das es überhaupt ein out gibt. Du willst doch nur ein bit setzen. Mit out blockierst du den ganzen Port für andere dinge. Und bei einen Soft-Uart brauchst du eh pausen. Damit spielt das Timing gar keine so grosse rolle.
1 | uint8_t data = 0x12; |
2 | for( uint8_t i = 0; i < 8; ++i ) { |
3 | if ( data & 1 ) { |
4 | PORTB |= (1<<PB4) |
5 | } else { |
6 | PORTB &= ~(1<<PB4) |
7 | }
|
8 | data = data >> 1; |
9 | us_dalay(xxx); |
10 | }
|
damit sollte es schon funktionieren, die schleife könnte man auch noch aufdröseln aber da man eh warten muss sehen ich kaum sinn drin. In diesem code sollte auch kein OUT mehr vorhanden sein. Wie schnell willst du denn übertragen?
Christian S. schrieb: > Mittlerweile habe ich das Problem gefunden. Das Problem ist klar erkennbar. Wenn ich Dir ungebeten einen Rat geben darf, fange erst mal an C zu lernen, eine LED zu toggeln und das Datenblatt zu lesen. So in einem halben Jahr vielleicht schreibst Du mal eine Software UART. Das bisher gezeigt ist, mit Verlaub, grosser Murks. :-)
Christian S. schrieb: > Es geht einfach darum, einen UART Sender in Software zu implementieren. > Dient für mich als Übung. Hmmm... und warum schiebst du die Bits nicht einfach direkt raus? BST BLD OUT ... usw, insgesamt 8 Mal Dauert immer genau gleich lang, es sind keine Abfragen und keine Sprünge drin.
:
Bearbeitet durch User
Ich bin jetzt erfolgreich bei 1 MBit mit dem internen 8 MHz Resonator und will mal sehen ob 2 möglich sind. Dazu muss jedoch der IF-Test weg. Ich denke, aufgrund mancher Äusserungen kann ich auf diesem hohen Niveau keine Hilfe erwarten. Kein Problem, hab bisher alle meine Problem auch selbst lösen können. Dauert nur etwas länger ^^ Das mit BST und BLD könnte echt mal eine Möglichkeit sein. Habe mich immer gefragt, was dieser blöde 1 Bit Speicher soll. Danke :)
:
Bearbeitet durch User
Christian S. schrieb: > Ich bin jetzt erfolgreich bei 1 MBit mit dem internen 8 MHz Resonator > und will mal sehen ob 2 möglich sind. Sollte mit BST,BLD,OUT locker klappen bis 2,666 Mbps.
Wenn Du solche Geschwindigkeiten anstrebst (1 Bitlänge = 4 Taktzyklen), solltest Du dich mit (Inline-)Assembler beschäftigen. Die von Markus Weber vorgeschlagene BST / BLD -Lösung schafft die Geschwindigkeit. Der Empfang wird noch lustig, da Du die fallende Flanke des Startbits auf einen Taktzyklus genau erkennen must, und nur 6 Takte bis zum Abtasten des ersten Datenbits hast. Mit freundlichen Grüßen - Martin
Christian S. schrieb:
Das wirst Du sicher schaffen. Scheinst genügend hartnäckig zu sein. Du
gehst halt einen langen, steinigen Umweg. Schneller kämst Du zum Ziel,
wenn Du von vorne anfangen würdest.
Aber gut. Jedem seine Herausforderung. Viel Erfolg.
Es geht übrigens auch noch schneller: LSR OUT ... 8 Mal. -> 4 Mbps Aber dann wirds etwas schmutzig, weil du vom betreffenden Port nur Bit 0 für die Ausgabe benutzen kannst. Die übrigen Pins tragen nur Bitabfälle nach draußen. :-) Was natürlich nichts macht, wenn die übrigen Pins des Ports als Eingänge verwendet werden. Dann schaltet man nur die Pullups – wenn überhaupt, denn bei manchen neueren AVR gibts dafür ja ein eigenes Pullup-Register. Ach so: Manche AVR können auch mit 16 MHz internem Takt betrieben werden (z.B. ATtiny85, ATtiny861A). Vielleicht hilft dir das, die Geschwindigkeit noch weiter zu erhöhen...
Christian S. schrieb: > Ich bin jetzt erfolgreich bei 1 MBit mit dem internen 8 MHz Resonator Ist das eine Art Wettbewerb? Ansonsten ist es eher unverständlich, warum man für derartige Geschwindigkeiten nicht auf die vorhandene Hardware zurückgreift.
Jörg Wunsch schrieb: > Ansonsten ist es eher unverständlich, warum man für derartige > Geschwindigkeiten nicht auf die vorhandene Hardware zurückgreift. Öhm, ja, seh ich genauso. :-) Christian schreibt oben ja: "Dient für mich als Übung". Vielleicht plant er auch irgendwas Seltsames und will Worte mit 4 oder 10 bit Länge senden, dann wirds mit der Standard-Hardware auch wieder kompliziert.
Christian S. schrieb: > Irgendwie sowas wäre schön: > > PORTB = Bit 0 von byte X an Stelle PORTB4 packen > PORTB = Bit 1 von byte X an Stelle PORTB4 packen > PORTB = Bit 2 von byte X an Stelle PORTB4 packen > PORTB = Bit 3 von byte X an Stelle PORTB4 packen > PORTB = Bit 4 von byte X an Stelle PORTB4 packen > PORTB = Bit 5 von byte X an Stelle PORTB4 packen > PORTB = Bit 6 von byte X an Stelle PORTB4 packen > PORTB = Bit 7 von byte X an Stelle PORTB4 packen > > Es geht einfach darum, einen UART Sender in Software zu implementieren. > Dient für mich als Übung. Dann übe es bitte in einer Sprache, mit der du volle Kontrolle über das Timing hast. C ist keine solche Sprache, Assembler schon. Übrigens hast du einen Assembler, ein C-Compiler ist schließlich auch nur ein aufgebohrter Assembler, kann aber immer noch native Assembler-Instruktionen verstehen. Was nun dein Problem betrifft, geht die schnellste Lösung so (Byte x sei in Register R24, R16 sei unbenutzt/gesichert): cli ; 1 in R16,PORTB ; 1 cbr R16,1<<PORTB4 ; 1 Startbit out PORTB,R16 ; 1 bst R24,0 ; 1 bld R16,4 ; 1 out PORTB,R16 ; 1 bst R24,1 ;... bld R16,4 out PORTB,R16 bst R24,2 bld R16,4 out PORTB,R16 bst R24,3 bld R16,4 out PORTB,R16 bst R24,4 bld R16,4 out PORTB,R16 bst R24,5 bld R16,4 out PORTB,R16 bst R24,6 bld R16,4 out PORTB,R16 bst R24,7 bld R16,4 out PORTB,R16 sbr R16,1<<PORTB4 ; 1 Stopbit sei ; 1 out PORTB,R16 ; 1 Jedes Bit dauert drei Takte, die gesamte Routine 31 Takte. Die Bitrate entspricht einem Drittel des Systemtakts. Und, bevor du fragst: langsamer geht immer, das ist leicht. Schwierig wäre bloß noch schneller. Das geht, zumindest beim AVR8, nichtmal über die eingebaute UART-Hardware. Naja, bei den neueren kann man sie im SPI-Mode betreiben und erreicht dann bei der Bitrate sogar die Hälfte des Systemtaktes und das sogar ohne jegliche Interuptsperre.
c-hater schrieb: > Und, bevor du fragst: langsamer geht immer, das ist leicht. Schwierig > wäre bloß noch schneller. auch kein Problem. Wenn genug Flash vorhanden ist.
1 | switch( data ) { |
2 | case 0: |
3 | PORTB |= (1<<pb4); //start |
4 | PORTB &= ~(1<<pb4); //bit0 |
5 | PORTB &= ~(1<<pb4); //bit1 |
6 | PORTB &= ~(1<<pb4); //bit2 |
7 | PORTB &= ~(1<<pb4); //bit3 |
8 | PORTB &= ~(1<<pb4); //bit4 |
9 | PORTB &= ~(1<<pb4); //bit5 |
10 | PORTB &= ~(1<<pb4); //bit6 |
11 | PORTB &= ~(1<<pb4); //bit7 |
12 | PORTB |= (1<<pb4); //stop |
13 | break; |
14 | case 1: |
15 | PORTB |= (1<<pb4); //start |
16 | PORTB |= (1<<pb4); //bit0 |
17 | PORTB &= ~(1<<pb4); //bit1 |
18 | PORTB &= ~(1<<pb4); //bit2 |
19 | PORTB &= ~(1<<pb4); //bit3 |
20 | PORTB &= ~(1<<pb4); //bit4 |
21 | PORTB &= ~(1<<pb4); //bit5 |
22 | PORTB &= ~(1<<pb4); //bit6 |
23 | PORTB &= ~(1<<pb4); //bit7 |
24 | PORTB |= (1<<pb4); //stop |
25 | break; |
26 | //usw
|
27 | //....
|
28 | case 255: |
29 | //...
|
30 | }
|
:
Bearbeitet durch Moderator
Peter II schrieb: > [c] Da lach ich drüber... > switch( data ) { OMG. Switch mit 256 Zweigen. Selbst intelligente Compiler können das bestenfalls auf 8 Verzweigungen eindampfen (binärer Baum). Verzweigungen sind der Tod jeglichen getimeten Codes, wenn man sie einen C-Compiler machen läßt. Abgesehen davon kosten sie auch immer überproportional viel Rechenzeit. > PORTB |= (1<<pb4); //start > PORTB &= ~(1<<pb4); //bit0 > PORTB &= ~(1<<pb4); //bit1 > PORTB &= ~(1<<pb4); //bit2 > PORTB &= ~(1<<pb4); //bit3 > PORTB &= ~(1<<pb4); //bit4 > PORTB &= ~(1<<pb4); //bit5 > PORTB &= ~(1<<pb4); //bit6 > PORTB &= ~(1<<pb4); //bit7 > PORTB |= (1<<pb4); //stop Gute Compiler werden das als sbi/cbi übersetzen, also zwei Takte pro Bit brauchen. Schlechte Compiler oder auch gute Compiler mit "ungünstig" eingestellter Optimierung können da leicht auch mal 3 oder sogar 5 Takte pro bit draus machen... Abgesehen von diesen Betrachtungen ist der Code aber auch noch falsch. Das Startbit muß natürlich Low sein, aber das würde ich hier gern als Flüchtigkeitsfehler verbuchen wollen und nicht weiter diskutieren. Worüber ich eher diskutieren würde: der Ansatz mit dem präparierten Code natürlich auch in Assembler möglich. Bloß würde ein gelernter Asm-Programmierer natürlich keinen binären Baum verwenden, sondern einen berechneten Sprung. Das wäre natürlich auch in C möglich. Aber der Vergleich der beiden Routinen zeigt dann ganz deutlich, was ich an C so sehr hasse, den Bombast an Syntax, den man benötigt, um einfachste Sachverhalte auszudrücken, ohne dass man in der Compilerausgabe vor lauter Warnungen die Fehler nicht mehr sehen kann...
c-hater schrieb: > OMG. Switch mit 256 Zweigen. Selbst intelligente Compiler können das > bestenfalls auf 8 Verzweigungen eindampfen (binärer Baum). sie machen einfach eine Sprungtabelle draus, habe ich schon beim GCC gesehen. Sind dann bloss 2 oder 4 takte. > Gute Compiler werden das als sbi/cbi übersetzen, also zwei Takte pro Bit sbi/cbi brauchen doch nur 1 Takt? > Schlechte Compiler oder auch gute Compiler mit "ungünstig" Compiler die nicht mal cbi/sbi hinbekommen, kann man eh nicht ernsthaft einsetzten, damit würde ein Großteil der Programme nicht mehr laufen. Man kann sich schon darauf verlassen sie es können. > Abgesehen von diesen Betrachtungen ist der Code aber auch noch falsch. > Das Startbit muß natürlich Low sein, aber das würde ich hier gern als > Flüchtigkeitsfehler verbuchen wollen und nicht weiter diskutieren. ich war mir auch wegen der Reihenfolge der bits nichts sicher. Es ging ja nur ums Prinzip.
Peter II schrieb: > sbi/cbi brauchen doch nur 1 Takt? Hier liegst Du falsch, es sind 2 Takte. Hast es vermutlich mit SBR / CBR verwechselt, die brauchen tatsächlich nur einen Takt, arbeiten aber nur mit den CPU-Registern, könnten aber auch verwendet werden, ohne daß es langsamer wird:
1 | CBR r16, 1 << PB4 |
2 | OUT PORTB, r16 |
3 | SBR r16, 1 << PB4 |
4 | OUT PORTB, r16 |
5 | SBR r16, 1 << PB4 |
6 | OUT PORTB, r16 |
7 | CBR r16, 1 << PB4 |
8 | OUT PORTB, r16 |
9 | CBR r16, 1 << PB4 |
10 | OUT PORTB, r16 |
11 | CBR r16, 1 << PB4 |
12 | OUT PORTB, r16 |
13 | CBR r16, 1 << PB4 |
14 | OUT PORTB, r16 |
15 | SBR r16, 1 << PB4 |
16 | OUT PORTB, r16 |
17 | SBR r16, 1 << PB4 |
18 | OUT PORTB, r16 |
19 | SBR r16, 1 << PB4 |
20 | OUT PORTB, r16 |
-> 2 Takte pro ausgegebenem Bit Wer's richtig schnell will, berechnet die auszugebenden Bitmuster im Vorraus, und schreibt sie nur noch hintereinander raus:
1 | OUT PORTB, r6 |
2 | OUT PORTB, r7 |
3 | OUT PORTB, r8 |
4 | OUT PORTB, r9 |
5 | OUT PORTB, r10 |
6 | OUT PORTB, r11 |
7 | OUT PORTB, r12 |
8 | OUT PORTB, r13 |
9 | OUT PORTB, r14 |
10 | OUT PORTB, r15 |
-> 1 Takt pro ausgegebenem Bit Mit freundlichen Grüßen - Martin
Martin Schlüter schrieb: > Hier liegst Du falsch, es sind 2 Takte. Hast es vermutlich mit SBR / CBR > verwechselt, http://www.atmel.com/images/doc0856.pdf seite 123 Cycles : 2 Cycles XMEGA: 1 Cycles Reduced Core tinyAVR:1 naja, wir hatte beide recht.
Peter II schrieb: > sie machen einfach eine Sprungtabelle draus, habe ich schon beim GCC > gesehen. Sind dann bloss 2 oder 4 takte. Vier mag ich vielleicht noch glauben, zwei nimmer. Bis zum Beweis des Gegenteils würde ich das als offensichtliche Schutzbehauptung eines C-Gäubigen einstufen. Bitte Code vorlegen, der diese Behauptung beweisen kann. Bitte mit exakter Angabe von Compilerversion und verwendeten Optimierungsoptionen. Womit wir gleich beim nächsten Problem wären, der C-Kompatibilitätslüge... > sbi/cbi brauchen doch nur 1 Takt? Nein, zwei. Ziehe bitte die Lektüre des AVR "instruction set reference manual" in Betracht, bevor du Aussagen über das Timing von Instruktionen triffst. Es ist ja wirklich nicht schwer, die Instruktion des Interesses im Inhaltsverzeichnis anzuklicken und dann bis ganz unten runterzuscrollen, wo Atmel schamhaft die wichtigsten Infos hinschreibt...
c-hater schrieb: >> sbi/cbi brauchen doch nur 1 Takt? > > Nein, zwei. Ziehe bitte die Lektüre des AVR "instruction set reference > manual" in Betracht, bevor du Aussagen über das Timing von Instruktionen > triffst. Es ist ja wirklich nicht schwer, die Instruktion des Interesses > im Inhaltsverzeichnis anzuklicken und dann bis ganz unten > runterzuscrollen, wo Atmel schamhaft die wichtigsten Infos > hinschreibt... habe ich gemacht und geschrieben, das wir beide recht haben!
@Peter II (Gast): Da muß ich Dir Recht geben. Hatte es selber nicht nachgesehen, mache am meisten mit den ATmegas, und da sind es halt 2 Takte. Beim Xmega ist da wohl Einiges gemacht worden, da gibt es recht viele Unterschiede, z.B. auch bei den SRAM-Zugriffen. Mit freundlichen Grüßen - Martin
c-hater schrieb: > OMG. Switch mit 256 Zweigen. Selbst intelligente Compiler können das > bestenfalls auf 8 Verzweigungen eindampfen (binärer Baum). Sprungtabelle mit Funktionspointers ist eine andere Variante.
Peter II schrieb: > habe ich gemacht und geschrieben, das wir beide recht haben! Ja, ich wiederum habe das geschrieben, bevor ich deine diesbezüglich Antwort gelesen hatte.->Typisches Problem asynchroner Kommunikation, kein böser Wille. Übrigens: Ich wußte tatsächlich nicht, daß die XMegas die Sache in einem Takt abfackeln können, bei den Dingern stellt sich ja dank reichlich verfügbarer und potenter Hardware nur äußerst selten das Problem, etwas derartiges in Software abhandeln zu müssen, bei mir bisher halt noch nie. Trotzdem eine schöne Sache, denn ich habe wirklich etwas neues in diesem Thread gelernt, was ich vielleicht irgendwann mal brauchen kann. Und sei es nur zur Herstellung der Kompatibilität für Stücken gebrauchter Software...
c-hater schrieb: > Vier mag ich vielleicht noch glauben, zwei nimmer. Bis zum Beweis des > Gegenteils würde ich das als offensichtliche Schutzbehauptung eines > C-Gäubigen einstufen. Gell, das einzig Gute an C ist der Inline-Assembler. ;-) Ich geb zu, es gibt Momente, da seh ich das genauso wie du. Anscheinend klappt es tatsächlich 1:1 mit dem CPU-Takt. Allerdings sind dann die Stoppbits jeweils mehr als 10 Takte lang, was natürlich die DÜ-Geschwindigkeit in den Keller zieht. Oder gibt es eine bessere/schnellere Lösung?
1 | init: |
2 | clr r0 |
3 | clr r1 |
4 | inc r1 ; Annahme: Portpin 0 wird zum Senden verwendet |
5 | |
6 | next: |
7 | ... ; zu sendendes Byte in r30 erwartet |
8 | swap r30 |
9 | mov r31,r30 |
10 | andi r31,0x0f |
11 | ori r31,0x10 ; Startadresse der Ausgabeprozeduren (high) |
12 | andi r30,0xf0 |
13 | IJMP |
14 | |
15 | .org 0x1000 |
16 | out PORTB,r0 ; Startbit |
17 | out PORTB,r0 |
18 | out PORTB,r0 |
19 | out PORTB,r0 |
20 | out PORTB,r0 |
21 | out PORTB,r0 |
22 | out PORTB,r0 |
23 | out PORTB,r0 |
24 | out PORTB,r0 |
25 | out PORTB,r1 ; Stopbit |
26 | jmp next |
27 | |
28 | .org 0x1010 |
29 | out PORTB,r0 ; Startbit |
30 | out PORTB,r1 |
31 | out PORTB,r0 |
32 | out PORTB,r0 |
33 | out PORTB,r0 |
34 | out PORTB,r0 |
35 | out PORTB,r0 |
36 | out PORTB,r0 |
37 | out PORTB,r0 |
38 | out PORTB,r1 ; Stopbit |
39 | jmp next |
40 | |
41 | ... usw ... |
Markus Weber schrieb: > Gell, das einzig Gute an C ist der Inline-Assembler. ;-) wobei die Frage ist warum nicht dafür C verwenden, habe jetzt nichts da zu testen was da rauskommt.
1 | uint8_t r1 = 0; |
2 | uint8_t r2 = 1; |
3 | |
4 | switch( data ) { |
5 | case 0: |
6 | PORTB = r1; |
7 | PORTB = r0; |
8 | PORTB = r0; |
9 | PORTB = r0; |
10 | PORTB = r0; |
11 | PORTB = r0; |
12 | PORTB = r0; |
13 | PORTB = r0; |
14 | PORTB = r0; |
15 | PORTB = r1; |
16 | break; |
17 | |
18 | //...
|
19 | }
|
Besten Dank für die vielen umfangreichen Antworten. Das sind ca. 10 mal mehr Informationen, als ich erhofft habe. Damit kann ich mich jetzt sehr gut auseinandersetzen :)
könnte das schneller sein?
1 | next: |
2 | ... ; zu sendendes Byte in r30 erwartet |
3 | IJMP; |
4 | jmp SEND1; |
5 | jmp SEND2; |
6 | jmp SEND3; |
7 | .... |
8 | SEND1: |
9 | out PORTB,r0 ; Startbit |
10 | out PORTB,r0 |
11 | out PORTB,r0 |
12 | out PORTB,r0 |
13 | out PORTB,r0 |
14 | out PORTB,r0 |
15 | ... |
Peter II schrieb: > könnte das schneller sein? Ich glaube, du hast Recht! Quasi zweifach indirekt (indirekt mit anschließender Sprungtabelle) ist da wahrscheinlich schneller. Macht dann eine Stoppbitlänge von mehr als 7 Takten. Immer noch nicht gut, aber deutlich besser.
Warum hoffe ich bei solchen Diskussionen immer, dass der Programmierer des Flugzeugs, in dem ich gerade sitze, etwas mehr Erfahrung hatte? Jörg Wunsch hatte es mal kurz angesprochen, wie es Profis machen: sie lesen das Datenblatt ihres Controllers und nehmen eine Hardwarekomponente, die so eine Übertragung ohne Prozessorlast abhandeln kann... Mit dem SPI Interface kann ich z.B. ganz problemlos 4MBit/s bei 8MHz Takt erreichen. Und habe nebenher Zeit, das nächste Byte vorzubereiten.
:
Bearbeitet durch Moderator
Lothar Miller schrieb: > Warum hoffe ich bei solchen Diskussionen immer, dass der Programmierer > des Flugzeugs, in dem ich gerade sitze, etwas mehr Erfahrung hatte? > > Jörg Wunsch hatte es mal kurz angesprochen, wie es Profis machen: sie > lesen dad Datenblatt ihres Controllers und nehmen eine > Hardwarekomponente, die so eine Übertragung ohne Prozessorlast abhandeln > kann... > Mit dem SPI Interface kann ich z.bB. ganz problemlos 4MBit/s bei 8MHz > Takt erreichen. Und habe nebenher Zeit, das nächste Byte vorzubereiten. wenn es danach geht, hätte wir für die ersten PC spiele auch 10Jahre länger warten müssen. Zum glück gab es damals schon "kreative" Entwickler die alles aus der Hardware geholt haben.
Peter II schrieb: > wenn es danach geht, hätte wir für die ersten PC spiele auch 10Jahre > länger warten müssen. Zum glück gab es damals schon "kreative" > Entwickler die alles aus der Hardware geholt haben. Ich denke, da liegst du aber gewaltig daneben. Nicht die Geschwindigkeit war damals das Problem, sondern mangelnder RAM, sowohl bei den uC als auch bei der Videokarten. Ich glaube mein Vater hat sein Tandy damals 2000 DM bezahlt, die Umrüstung von 4KB(!) auf 16KB RAM hat so um die 500DM gekostet.
Marc Vesely schrieb: > Ich denke, da liegst du aber gewaltig daneben. > Nicht die Geschwindigkeit war damals das Problem, sondern mangelnder > RAM, sowohl bei den uC als auch bei der Videokarten. > Ich glaube mein Vater hat sein Tandy damals 2000 DM bezahlt, die > Umrüstung von 4KB(!) auf 16KB RAM hat so um die 500DM gekostet. wenn ich das lesen, klingt es aber nicht nach ram: http://de.wikipedia.org/wiki/Duff%E2%80%99s_Device
Peter II schrieb: > wenn ich das lesen, klingt es aber nicht nach ram: > > http://de.wikipedia.org/wiki/Duff%E2%80%99s_Device ??? Nix aus der Hardware rausgeholt, einen einfachen loop ausgerollt. Und funktioniert auch nur in C, normale Sprachen fallen nicht von einem Switch zum nächsten... Ihr seid alle so schnell wenns heisst c-hater anzuspucken, aber C ist ganz einfach ein Witz von einer Sprache.
:
Bearbeitet durch User
Peter II schrieb: > wenn ich das lesen, klingt es aber nicht nach ram: Hat aber nichts mit normalem PC zu tun, sondern mit früher Videobearbeitung. https://de.wikipedia.org/wiki/Lucasfilm Zurück zum Thema des Threads: ich bin gewiss ein großer Verfechter davon, auch bei Controllern möglichst portable Software in einer höheren Programmiersprache zu zimmern. Aber wenn man wirklich auf den Takt genau etwas machen will, und keinerlei Hardware dafür abstellen kann (nichtmal einen Timer), dann bleibt in der Tat nur das händische Auszählen der Takte in einem Stück Assemblercode – egal, ob man das nun zum eigenen Zeitvertreib oder aus echter Notwendigkeit heraus tun möchte.
Marc Vesely schrieb: > Nix aus der Hardware rausgeholt, einen einfachen loop ausgerollt. damit konnte mehr Daten als sonst mit der gleichen CPU verarbeitet werden. Das verstehe ich schon unter, mehr als der gleichen Hardware rausgeholt.
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.