Hallo v.a. an alle Assembler-Götter.
Ich habe ein kleines Problem mit der Laufzeit - auf meinem ATMEGA32 mit
16MHz liegt auf INT2 ein Clock-Signal. Das Clock-Signal kommt alle paar
Sekunden und taktet dann 80 Bits, die gesampelt werden sollen.
Das Sampling des Datenpins erfolgt auf fallender Flanke des
Clock-Signals.
Der Abstand zwischen den fallenden Flanken ist 3.3µs.
Insgesamt kommen 80 Takte (80 Bits) die gesampelt werden sollen.
In C sieht die IRQ so aus:
1
ISR(INT2_vect)
2
{
3
r[r_cnt] = PIN_R & (1 << DATA_R);
4
r_cnt++;
5
}
Assembler mit -os:
1
ISR(INT2_vect)
2
{
3
d8: 1f 92 push r1
4
da: 0f 92 push r0
5
dc: 0f b6 in r0, 0x3f ; 63
6
de: 0f 92 push r0
7
e0: 11 24 eor r1, r1
8
e2: 8f 93 push r24
9
e4: 9f 93 push r25
10
e6: ef 93 push r30
11
e8: ff 93 push r31
12
r[r_cnt] = PIN_R & (1 << DATA_R);
13
ea: 90 91 92 01 lds r25, 0x0192
14
ee: 80 b3 in r24, 0x10 ; 16
15
f0: e5 e4 ldi r30, 0x45 ; 69
16
f2: f1 e0 ldi r31, 0x01 ; 1
17
f4: e9 0f add r30, r25
18
f6: f1 1d adc r31, r1
19
f8: 80 78 andi r24, 0x80 ; 128
20
fa: 80 83 st Z, r24
21
r_cnt++;
22
fc: 9f 5f subi r25, 0xFF ; 255
23
fe: 90 93 92 01 sts 0x0192, r25
24
}
25
102: ff 91 pop r31
26
104: ef 91 pop r30
27
106: 9f 91 pop r25
28
108: 8f 91 pop r24
29
10a: 0f 90 pop r0
30
10c: 0f be out 0x3f, r0 ; 63
31
10e: 0f 90 pop r0
32
110: 1f 90 pop r1
33
112: 18 95 reti
34
}
Dauer von 48 Cycles bei 16MHz sind 3µs. Nun würde ich gerne wissen, ob
es eine Implementierung in Assembler gibt, die ich mit meinem C-Projekt
nutzen kann.
Wäre für Tipps oder Beispiele dankbar.
Gruß,
Detlef
wirklich viel zu machen ist da nicht. selbst mit ASM sieht es nicht so
aus ob man da noch etwas sparen kann.
Wenn man die aktuelle adresse r[r_cnt] in Register sich merken könnte,
dann spart man etwas. Aber diese möglichkeit besteht nur wenn man alles
in ASM programmiert.
Dann würde das laden und speichern von r_cnt wegfallen sowie die
addition.
Teste mal was bei C mit folgenden Code:
uint8_t* WritePos = r;
ISR(INT2_vect)
{
*WritePos = PIN_R & (1 << DATA_R);
WritePos++;
}
> Dauer von 48 Cycles bei 16MHz sind 3µs. Nun würde ich gerne wissen, ob> es eine Implementierung in Assembler gibt, die ich mit meinem C-Projekt> nutzen kann.
Ein INTERRUPT um schnelle Signale zu bearbeiten ?
Ja bist du denn mit dem Klammerbeutel gepudert ?
Es werden alle Bits in einer Schleife eingesammelt
und erst nach 264us die Interrupt-Routine verlassen
(mna knn auhc ganz stumpf 256 mal im 1.1us Abstand
die beiden Bits CLD und DATA einsammeln und erst
hinterher auswerten, ob das Datenmust welches nach
dem Interrupt kam irgendwie passend ist oder nur ein
Störsignal war, dann klappt das sogar mit einem 2MHz
uC).
Wenn das deine sonstigen Prozesse stört, baust du in
die Interrupt-Routine noch Befehle ein, die innerhalb
der 3.3us Wartezeit diese -falls nötig- bearbeiten,
viele Befehle dürfen es nicht sein, falls es mehr sind
weisst du sowieso schon, daß dein uC dafür zu langsam
ist.
Wollte man wirklich Assembler programmieren, sorgt
man erst mal dafür, daß bestimmte Register im Hauptprogramm
nicht verwendet werden, so daß sie in der Interrupt-Routine
nicht gerettet werden müssen, und andere Werte vor dem ersten
Interrupt passend initialisiert sind. Dann besteht die nur noch
aus
*data=INPUT_PORT
data++;
Erst HINTERHER wird das passende bit aus dem PORT maskiert.
Übrigens hast du mit deiner Interrupt-Routine noch das Riesen
Problem, daß du nicht merkst, wenn nur 79 statt 80 Interrupts
kommen weil einer verloren gint. Nach dem ersten Interrupt
musst du nach 280us abbrechen und die Botschaft verwerfen,
noch exakter müsstest du sogar bei jedem Interrupt gucken,
ob der vorherige 3-3.6us her war, und wenn nicht, dieses als
Störung verwerfen.
Das alles geht in einem nicht per Interrupt sondern per Laufzeit
der Befehle angepassten Assemblerprogramm viel einfacher zu
beachten.
Falls es die Pinbelegung auf deinem Board zulässt, könntest du auch SPI
verwenden. µC als Slave, MOSI als Dateneingang und CLK als Takteingang.
Nach jeweils 8 Bits bekommst du einen Interrupt und kannst in 8*3,5µs =
28µs bequem das komplette Byte kopieren.
Peter II schrieb:> wirklich viel zu machen ist da nicht. selbst mit ASM sieht es nicht so> aus ob man da noch etwas sparen kann.
Naja, nach grober Schätzung würde ich sagen, dass man etwa 40 bis 50 %
weniger Takte brauchen würde. C ist bei solchen Dingen immer etwas
umständlich.
Wenn man das ganze Programm in Assembler schreiben würde, hätte man
noch mehr Einfluss auf die Registerbelegung, dann könnte man
wahrscheinlich 70 bis 80 % der Takte sparen.
> Wenn man die aktuelle adresse r[r_cnt] in Register sich merken könnte,> dann spart man etwas. Aber diese möglichkeit besteht nur wenn man alles> in ASM programmiert.
Richtig!
Was ohne viel Aufwand auch ein bisschen Beschleunigung bringen würde,
wäre natürlich, auf einen aktuellen Baustein umzusteigen: ATmega324A.
Der schafft dann 20 MHz Takt und nicht nur 16 wie das alte Modell.
Markus Weber schrieb:> Naja, nach grober Schätzung würde ich sagen, dass man etwa 40 bis 50 %> weniger Takte brauchen würde. C ist bei solchen Dingen immer etwas> umständlich.
da bin ich ja gespannt, sagt doch mal was du alles einsparen willst (nur
die umsetung von C nach ASM ohne globale änderungen).
Verwendet man einen Zeiger zum Speichern (hier addr), sieht es so aus:
1
push r24
2
in r24, __SREG__
3
push r24
4
push r30
5
push r31
6
7
lds r30, addr
8
lds r31, addr+1
9
in r24, 0x16
10
andi r24, 1 << 7
11
st Z+, r24
12
sts r30, addr
13
sts r31, addr+1
14
15
pop r31
16
pop r30
17
pop r24
18
out __SREG__, r24
19
pop r24
20
reti
Hier ist nicht einzusehen, warum das Extrahieren des Bits in der ISR
geschehen muss. Das kann ebenso nach dem Samplen während der Auswertung
geschehen. Damit vereinfacht sich die ISR weiter, denn SREG wird nicht
verändert:
Johann L. schrieb:> Eine Abkürzung geht zum Beispiel so:
das hast du glück gehabt mehr als 40% weniger.
Auf die Idee mit dem
subi r30, lo8(-(r-1))
sbci r31, hi8(-(r-1))
bin ich beim überfliegen nicht gekommen.
> push r24> push r30> push r31>> lds r30, addr> lds r31, addr+1> in r24, 0x16> st Z+, r24> sts r30, addr> sts r31, addr+1> pop r31> pop r30> pop r24> reti
Das entspricht ja meinem Vorschlag, Pointer und Bits hinterher
maskieren.
Wenn man die Register 24, 30, 31 nun noch reserviert
-ffixed-24 -ffixed-30 -ffixed-31
entfällt das push und pop (vorausgesetzt man hat ALLEN C Code damit
kompiliert, auch die verwendeten library Funktionen) und initialisisren
der Register r30 und r31 auf addr (das hat dann schon das Rahmenprogramm
gemacht)
in r24, 0x16
st Z+, r24
reti
Allerdings sind r30/r31 zu wichtig, um sie zu reservieren, man sollte
eher r26/r27 nehmen
lds r26, addr ; Rahmenprogramm
lds r27, addr+1
-ffixed-24 -ffixed-26 -ffixed-27
ISR(INT2_vect)
{
in r24, 0x16
st X+, r24
reti
}
MaWin schrieb:> Wenn man die Register 24, 30, 31 nun noch reserviert>> -ffixed-24 -ffixed-30 -ffixed-31
Damit wirst du kein lauffähiges Programm mehr hinbekommen.
@PeterII:
Der Versuch erbrachte 53 Zyklen, also 5 Zyklen mehr.
@MaWin
>Ja bist du denn mit dem Klammerbeutel gepudert ?
Nein, aber es gibt immer wieder so Deppen im Netz, stimmts?
In der ISR per Schleife lassen sich die Daten nicht sammeln, da die
Clock-Takte nicht in zeitlich konstanten Abstand kommen.Mal ist der
Abstand 3.5µs, mal 4, mal 5.5, ...
D.h. in der Schleife müsste ich den Clk-Pin sampeln und speichern um die
Flanke zu bekommen. Würde in C oder so ähnlich aussehen
1
ISR(INT2_vect)
2
{
3
do
4
{
5
// Samplen und Speichern des CLK Pins
6
if(PINB & (1 << PINB2))
7
prev = 0x01;
8
else
9
{
10
// Falls fallende Flanke
11
if(
12
(prev == 0x01) // Clock-Pin voriges Sample
13
)
14
{
15
r[r_cnt] = PINB & (1 << PINB2);
16
r_cnt++;
17
prev=0;
18
}
19
}
20
21
irq_cnt++;
22
} while(irq_cnt<1000); // in Schleife bleiben bis sicher mehr als genug Zeit vorbei ist für die 80 bits
Man sieht schon, es werden zu viele Statements um jedes Clk-Signal
erkennen zu können. Also Danke für den Tipp, war aber leider nichts.
@Johann: Das Entfernen der Maskierung des Bits in C hat einen Zyklus
gebracht. Allerdings wird C nichts werden (hab einen Test gefahren und
in der ISR nur einen Pin aktiviert, selbst so vergehen zwischen Flanke
und Pin hoch >2µs).
D.h. ich werds mit Inline-Assembler versuchen. Seit dem Studium ist
einige Zeit vorbei, mal schauen wie weit ich komme.
Detlef schrieb:> Das Clock-Signal kommt alle paar> Sekunden und taktet dann 80 Bits, die gesampelt werden sollen.
Hörst Du nicht die lauten Schreie?
Das SPI ruft doch ganz laut: "Hier, nimm mich dafür".
Das sind dann 10 Interrupts und Du hast 8 * 3,3µs Zeit, das Byte bequem
im Interrupt abzuholen.
Peter
@Ingo: Falls du den C-Optimizer meinst - hab alle Optionen durch, der
generierte Assembler-Code ist bei o3 und os gleich und am kleinsten.
@Peter Danegger: SPI ist bereits in Benutzung, sorry.
Detlef schrieb:> @Peter Danegger: SPI ist bereits in Benutzung, sorry.
Wirklich als Slave?
SPI-Master geht auch super als Bit-Banging mit beliebigen Pins.
Oder noch bequemer mit einer der UARTs des ATmega324.
Peter
Detlef schrieb:> In der ISR per Schleife lassen sich die Daten nicht sammeln, da die> Clock-Takte nicht in zeitlich konstanten Abstand kommen.Mal ist der> Abstand 3.5µs, mal 4, mal 5.5, ...>> D.h. in der Schleife müsste ich den Clk-Pin sampeln und speichern um die> Flanke zu bekommen. Würde in C oder so ähnlich aussehen> ISR(INT2_vect)> {> do> {> // Samplen und Speichern des CLK Pins> if(PINB & (1 << PINB2))> prev = 0x01;> else> {> // Falls fallende Flanke> if(> (prev == 0x01) // Clock-Pin voriges Sample> )> {> r[r_cnt] = PINB & (1 << PINB2);> r_cnt++;> prev=0;> }> }>> irq_cnt++;> } while(irq_cnt<1000); // in Schleife bleiben bis sicher mehr als genug Zeit
vorbei ist für die 80 bits
>> Man sieht schon, es werden zu viele Statements um jedes Clk-Signal> erkennen zu können. Also Danke für den Tipp, war aber leider nichts.
Grundsätzlich wär mir unwohl den ISR für 400 mS zu blockieren, aber
Was wäre denn mit:
1
ISR(INT2_vect){
2
uint8_tcount=79;
3
4
*r=PINB;// erstes bit speichern
5
r++;
6
7
while(count--){
8
while(!(PINB&(1<<PINB2))){
9
// warten bis clock high wird
10
}
11
12
while((PINB&(1<<PINB2))){
13
// warten bis clock low wird
14
}
15
*r=PINB;// naechstes bit speichern
16
r++;
17
}
18
19
}
Grob geschätzt würd ich sagen, dass das schnell genug sein sollte.
Peter Dannegger schrieb:> Wirklich als Slave?>> SPI-Master geht auch super als Bit-Banging mit beliebigen Pins.> Oder noch bequemer mit einer der UARTs des ATmega324.>>> Peter
Der µC ist ein SPI Slave, ein ATMEGA32 ist bereits gesetzt. Der eine
UART ist ebenfalls schon in Benutzung. Es muss also mit INT2 gehen.
Verwirrter Anfänger schrieb:> Grob geschätzt würd ich sagen, dass das schnell genug sein sollte.
Lieber messen und dann posten. Dein Code ist die langsamste Variante,
mit 66 Zyklen.
Was macht dein Code wenn keine 80 Bits ankommen? Aha, n langes
Gesicht... Da muss mindestens ein Abbruch rein, aber dann wird wieder
eng. SPI ist Denk ich mal das Beste
Johann L. schrieb:> Hier ist nicht einzusehen, warum das Extrahieren des Bits in der ISR> geschehen muss. Das kann ebenso nach dem Samplen während der Auswertung> geschehen. Damit vereinfacht sich die ISR weiter, denn SREG wird nicht> verändert:> push r24> push r30> push r31>> lds r30, addr> lds r31, addr+1> in r24, 0x16> st Z+, r24> sts r30, addr> sts r31, addr+1>> pop r31> pop r30> pop r24> reti
Johann, dein Vorschlag erscheint mir am sinnvollsten. Aber eine Frage,
da ich ja nicht so fit bin mit Assembler. Müsste es nicht
> sts addr, r30> sts addr+1, r31
heißen?
Gruß
Detlef
Detlef schrieb:> Müsste es nicht>>> sts addr, r30>> sts addr+1, r31>> heißen?
Jepp. Typo.
Ein paar weitere, erbärmliche Ticks lassen sich sparen, indem zB addr in
einem globalen Register gehalten wird. Allerdings gibt's ein paar Haken
und Ösen dann:
1) Kein Modul (auch nicht aus einer Bibliothek) darf die Register
verwenden.
2) Globale Register sind nicht volatile, was die Synchronisierung
schwer handhabbar macht.
3) ABI beachten
Man muss also genau wissen, was man tut :o)
Johann L. schrieb:> Globale Register sind nicht volatile, was die Synchronisierung> schwer handhabbar macht.
register sind doch immer volatile
und was sollen nicht globele Register sein?
> while(!(PINB & (1 << PINB2))) { // warten bis clock high wird> while((PINB & (1 << PINB2))) { // warten bis clock low wird
Geile Endlosscheifen.
Schreibt ihr eigentlich immer Programme, die nur bei schönen
Wetter funktionieren und wenn mal 79 statt 80 Takte kommen
quasi abgestürzt sind, und -noch schlimmer- sich nur sehr
schwer wieder synchronisieren (sie warten auf weitere 79
aus Zufall fehlende Bits...)
}
> Damit wirst du kein lauffähiges Programm mehr hinbekommen.
Drum schrieb ich ja drunter, was man besser machen sollte.
Da hast du wohl schon dein Aufmerksamskeitsdefizit bekommen.
Auch denkbar ist, des zu füllende Objekt (r) an eine bestimmte Adresse
wie 0x100 zu legen, was die Adressarithmetik vereinfacht: High-Byte ist
0x1 und Low-Byte der Index (r_cnt).
Peter II schrieb:> Johann L. schrieb:>> Globale Register sind nicht volatile, was die Synchronisierung>> schwer handhabbar macht.>> register sind doch immer volatile
Nö, sie sind nie volatile. Übersetze folgenden Code:
1
registervolatilecharr2asm("2");
2
3
voidfoo(void)
4
{
5
externcharvolatilev;
6
r2=0;
7
while(!r2);
8
v=1;
9
}
und avr-gcc 4.8 macht daraus korrekt:
1
foo:
2
.L3:
3
rjmp .L3
> und was sollen nicht globele Register sein?
Lokale Register-Variablen, wie die globalen eine GNU-Erweiterung.
Johann L. schrieb:> Nö, sie sind nie volatile. Übersetze folgenden Code:
das meinst du.
Ich dachte an Atmel-ASM
ldi R16, 234
und da muss man nichts mit volatile beachten.
MaWin schrieb:>Johann L. schrieb:>> MaWin schrieb:>>> Wenn man die Register 24, 30, 31 nun noch reserviert>>>>>> -ffixed-24 -ffixed-30 -ffixed-31>>>> Damit wirst du kein lauffähiges Programm mehr hinbekommen.>> Drum schrieb ich ja drunter, was man besser machen sollte.> Da hast du wohl schon dein Aufmerksamskeitsdefizit bekommen.MaWin schrieb:> -ffixed-24 -ffixed-26 -ffixed-27
Ditto in Grün. Allein die Idee zeigt, daß du besser die Finger davon
lässt...
Peter II schrieb:> Johann L. schrieb:>> Nö, sie sind nie volatile.>> das meinst du.> Ich dachte an Atmel-ASM>> ldi R16, 234>> und da muss man nichts mit volatile beachten.
Muss man in Assembler eh nie. Oder optimiert der Atmel-ASM
"überflüssige" Instruktionen raus wenn er erkennt, daß die keinen Effekt
haben?
Oder hat "volatile" in Assembler eine Bedeutung?
Johann L. schrieb:> Oder hat "volatile" in Assembler eine Bedeutung?
nein, aus dem Grund hatte mich ja die aussage (inline)asm und volatile
verwundert.
Hi,
bitte nicht schlagen, dem Meisten was hier diskutiert wird kann ich
nicht folgen mangels ausreichender ASM oder C Kenntnisse.
Aus Neugier habe ich das mal in Bascom probiert, allerdings ohne Int,
einfach nur pollen und die Bits in ein Array feuern.
Ich denke das versteht hier jeder was es macht:
Do
If Pind.2 = 0 Then Gosub Int0isr
Loop
Int0isr:
For Datindex = 1 To 80
Do
Loop Until Pind.2 = 0
Datarray(datindex) = Pind.3
Do
Loop Until Pind.2 = 1
Next
Return
Die If-Abfrage ist nur drin, weil Bascom den Int nicht simulieren mag,
der Sprung kostet in Bascom aber dieselben Takte. Das sind viel zu
viele, weil Bascom alle Register sichert, ob die nun gebraucht werden
oder nicht.
Kann man ihm aber abgewöhnen, nur mit dem Gosub geht das nicht.
Der Sprung in die ISR bis das erste Bit gespeichert wird dauert 86
Takte.
Kann man wie gesagt schneller machen.
Dann dauert dieses Pollen komplett 41 Takte, wenn das "Until" jeweils
sofort erfüllt ist.
Die For Next sieht so aus:
24: For Datindex = 1 To 80
+00000070: E081 LDI R24,0x01 Load immediate
+00000071: 938000B0 STS 0x00B0,R24 Store direct to data
space
+00000073: 910000B0 LDS R16,0x00B0 Load direct from data
space
+00000075: 3500 CPI R16,0x50 Compare with immediate
24: For Datindex = 1 To 80
+00000076: F018 BRCS PC+0x04 Branch if carry set
+00000077: F011 BREQ PC+0x03 Branch if equal
24: For Datindex = 1 To 80
+00000078: 940C0097 JMP 0x00000097 Jump
26: Loop Until Pind.2 = 0
+0000007A: 9982 SBIC 0x10,2 Skip if bit in I/O
register cleared
+0000007B: 940C007A JMP 0x0000007A Jump
27: Datarray(datindex) = Pind.3
+0000007D: E3A0 LDI R26,0x30 Load immediate
+0000007E: E0B0 LDI R27,0x00 Load immediate
27: Datarray(datindex) = Pind.3
+0000007F: 918C LD R24,X Load indirect
+00000080: FB83 BST R24,3 Bit store from
register to T
27: Datarray(datindex) = Pind.3
+00000081: EBA0 LDI R26,0xB0 Load immediate
+00000082: E0B0 LDI R27,0x00 Load immediate
27: Datarray(datindex) = Pind.3
+00000083: 90AD LD R10,X+ Load indirect and
postincrement
+00000084: 24BB CLR R11 Clear Register
27: Datarray(datindex) = Pind.3
+00000085: E5AF LDI R26,0x5F Load immediate
+00000086: E0B0 LDI R27,0x00 Load immediate
27: Datarray(datindex) = Pind.3
+00000087: 0DAA ADD R26,R10 Add without carry
+00000088: 1DBB ADC R27,R11 Add with carry
27: Datarray(datindex) = Pind.3
+00000089: 2788 CLR R24 Clear Register
+0000008A: F980 BLD R24,0 Bit load from T to
register
27: Datarray(datindex) = Pind.3
+0000008B: 938C ST X,R24 Store indirect
29: Loop Until Pind.2 = 1
+0000008C: 9B82 SBIS 0x10,2 Skip if bit in I/O
register set
+0000008D: 940C008C JMP 0x0000008C Jump
30: Next
+0000008F: EBA0 LDI R26,0xB0 Load immediate
+00000090: E0B0 LDI R27,0x00 Load immediate
30: Next
+00000091: 918C LD R24,X Load indirect
+00000092: 5F8F SUBI R24,0xFF Subtract immediate
30: Next
+00000093: 938C ST X,R24 Store indirect
+00000094: F410 BRCC PC+0x03 Branch if carry
cleared
30: Next
+00000095: 940C0073 JMP 0x00000073 Jump
Vielleicht inspiriert das die Spezis hier ja irgendwie.
Ich könnte maximal herauslesen, welche Register ich manuell sichern
müsste um das ganze maximal zu beschleunigen.
Verschwendet natürlich Ram ohne Ende aber so gehts schnell.
Es bleibt das Problem, daß die Sache hängt wenn ein Fehler auftritt, so
würde ich das auch garantiert nicht umsetzen. Aber mit "Notausstieg"
wird das sicher zu langsam.
Ach ja, den Mega324 kann man doch fast so in das Design reinwerfen. Was
der 32 kann, das kann der auch und soweit sind sie Pinkompatibel, oder?
Gruß,
Norbert
Detlef schrieb:> Das Entfernen der Maskierung des Bits in C hat einen Zyklus gebracht.
Klar. Ziel der Übung ist nämlich, daß SREG nicht mehr verändert wird,
was einen kleineren ISR-Prolog / -Epilog ermöglicht. Mit einer ISR in C
kann daraus kein Gewinn gezogen werden [1] – ausser dem Sparen der
genannten, einen Instruktion.
[1] http://gcc.gnu.org/PR20296Peter II schrieb:> Johann L. schrieb:>> Oder hat "volatile" in Assembler eine Bedeutung?>> nein, aus dem Grund hatte mich ja die aussage (inline)asm und volatile> verwundert.
Es gibt ja nicht nur die ISR, die evtl. in Assembler steht, sondern auch
noch den "normalen" Code in C. Alles nach asm umzuschreiben ist i.d.R.
der Overkill und nicht zielführend. Daher steht die ISR dann in asm und
der Rest in C.
Der C-Teil muss bei einen globalen Register, das in der ISR geändert
wird (egal ob durch asm oder durch C), damit klarkommen, daß globale
Register nicht volatile sind. Eine Möglichkeit wäre, auch das Register
per asm zu laden, was in der Richtung:
Norbert S. schrieb:> Vielleicht inspiriert das die Spezis hier ja irgendwie.
Insprieren nein, transpirieren ja.
Es ist eine Bestätigung, dass Bascom nichts taugt.
> Ach ja, den Mega324 kann man doch fast so in das Design reinwerfen. Was> der 32 kann,
Man kann sich auch nen Knopf an die Backe nähen und ein Klavier
dranhängen.
> das kann der auch und soweit sind sie Pinkompatibel, oder?
Das weißt du nicht? Schäm!
@Johann, habe nun die ISR in ASM implementiert. Damit funktioniert das
Sampling hervorragend. Danke für die Hilfe, ohne Beispiel hätte ich mich
nimmer getraut das AVR ASM Manual in die Hand zu nehmen. Jetzt wos geht
ist es ganz einleuchtend.
Danke auch an die anderen.
Gruß,
Detlef