Hallo.
Ich habe da ein Problem. Ich nehme einen ATtiny24, betreibe den mit ca.
4V, hänge 2 LED dran (PortB 2, PortA 5) und an einen Pin (PortA 4) einen
Signalgenerator als Eingangsignalgeber. Der c-code darauf ist:
PCMSK0=(1<<PCINT4);/* Pin-Change-Interrupt an PA4 */
28
sei();
29
for(;;){}
30
return0;
31
}
, compiliert mit avr-gcc (GCC) 4.2.0 unter Verwendung von avr-libc
1.4.6.
Ziel zunächst soll es sein, dass LED1 mit halber Taktfrequenz und LED2
mit 4-tel Taktfrequenz blinkt. Dazu werte ich den Pin-Change-Interrupt
aus und LED1 blinkt wie erwartet. LED2 sollte durch die UND-Verknüpfung
nur jede 2. steigende Flanke ausnutzen. Das Problem hierbei: LED2 blinkt
mit gleicher Frequenz/Phasenlage wie LED1. Gerade so, als ob "if (clk &
0x01)" nicht gegeben sei. Ändere ich die Bedingung für LED2 auf "if (clk
& 0x02)", dann blinkt LED2 gar nicht mehr. Bei "if (clk < 16)" wiederum
Dauerblinken, obwohl beim Übersteichen des Zahlenbereiches Pausen
auftreten sollten. Vom generierten assemblercode sieht es gar nicht so
schlecht aus (hier nur Interrupt-Routine).
1
ISR(PCINT0_vect) {
2
68: 1f 92 push r1
3
6a: 0f 92 push r0
4
6c: 0f b6 in r0, 0x3f ; 63
5
6e: 0f 92 push r0
6
70: 11 24 eor r1, r1
7
72: 8f 93 push r24
8
if (PINA & (1 << PCINT4)) {
9
74: cc 9b sbis 0x19, 4 ; 25
10
76: 13 c0 rjmp .+38 ; 0x9e <__vector_2+0x36>
11
/* steigende Flanke */
12
toggleLED1();
13
78: c2 9b sbis 0x18, 2 ; 24
14
7a: 02 c0 rjmp .+4 ; 0x80 <__vector_2+0x18>
15
7c: c2 98 cbi 0x18, 2 ; 24
16
7e: 01 c0 rjmp .+2 ; 0x82 <__vector_2+0x1a>
17
80: c2 9a sbi 0x18, 2 ; 24
18
clk += 1;
19
82: 80 91 60 00 lds r24, 0x0060
20
86: 8f 5f subi r24, 0xFF ; 255
21
88: 80 93 60 00 sts 0x0060, r24
22
if (clk & 0x01) {
23
8c: 80 91 60 00 lds r24, 0x0060
24
90: 80 ff sbrs r24, 0
25
92: 05 c0 rjmp .+10 ; 0x9e <__vector_2+0x36>
26
toggleLED2();
27
94: dd 9b sbis 0x1b, 5 ; 27
28
96: 02 c0 rjmp .+4 ; 0x9c <__vector_2+0x34>
29
98: dd 98 cbi 0x1b, 5 ; 27
30
9a: 01 c0 rjmp .+2 ; 0x9e <__vector_2+0x36>
31
9c: dd 9a sbi 0x1b, 5 ; 27
32
9e: 8f 91 pop r24
33
a0: 0f 90 pop r0
34
a2: 0f be out 0x3f, r0 ; 63
35
a4: 0f 90 pop r0
36
a6: 1f 90 pop r1
37
a8: 18 95 reti
Probiere schon seit Tagen und komme nicht weiter. Es scheint mir, als ob
der Tiny nicht das macht, was er sollte. Im Errata habe ich nichts
gefunden, aber vielleicht weiss ja einer von euch was hier los ist.
Gruß
Marco
Zu deinem Problem kann ich nichts sagen, außer: Bist du sicher, dass im
AVR dass richtige Programm 'steckt' ? ;) Oder ein Kurzschluss bei den
LEDs ... Der Code oben sieht korrekt aus (wenn auch merkwürdig )
mir fallen solche Sachen ein , wie z.B.
- volatile braucht man, wenn eine Variable in main() UND isr geändert
wird (hier tut's 'static' auch - erzeugt aber weniger asm-code)
- die TOGGLE-macros sind seeehr umständlich: PORTx ^=(1<<PINy) würde
auch gehen (^ ist XOR in C)
- und clk würde ich als unsigned Typen nehmen (ist aber wohl 'ne
Prinzipfrage, nichts generelles)
( - ein "clk % 2" ist besser lesbar als "clk & 1", imho!)
Aber wie gesagt, in dem geposteten Code kann ich keine wirklichen Fehler
entdecken
hth. Jörg
Haarscharf ;)
das do{...}while war/ist, glaube ich, ein Konstrukt um längere Makros zu
schreiben, an die man beim aufrufen trotzdem ein Semikolon anhängen
kann. An einen {...} Block darf man ja kein ";" anhängen.
gruß Jörg
nach deiner Beschreibung schaut es ja so aus als ob cnt nicht erhöht
würde,
der Compiler macht da ja ein interessantes cnt -(-1) draus.
Hast du schon den Vorschlag von Jörg probiert cnt unsigned zu machen?
@ zum richtigen Programm:
Die Bytes, die ich aus dem Flash auslesen kann, sind diesselben wie
avr-objdump -d ausspuckt.
@volatile, static, signed, unsigned, ...:
Habe alle probiert. Macht das Programm nicht funktionsfähig.
Letztendlich läuft es immer auf ein "lds/sts 0x0060" hinaus.
@warum do{}while(0)?
Keine Ahnung. Habe ich mal irgendwo aufgeschnappt. Einfache
Blockklammerung geht natürlich auch. Aber ist eh' nur Präprozessor. An
eine {}-Klammerung darf man natürlich soviele Leeranweisungen
dranhängen, wie man will. Die EXOR-Variante hatte ich natürlich auch
schon (spart 2 Bytes ein). Warum hier das Komplizierte, egal.
@PINA = _BV(PA5)
In der Tat. Funktioniert prima. Wer die Datenblätter liest, ist halt im
Vorteil. Danke für den Tip.
Es scheint mir, als ob der Befehl "clk += 1", der zu "subi r24, 0xFF"
umgewandelt wird, oder ein anderer Befehl, kaputt ist. Kann es denn
sein, daß der AVR seine eigene Maschinensprache teilweise nicht mehr
versteht?
was mir etwas befremdlich vorkommt ist die Speicheradresse von cnt,
irgendwie so mitten drin. Ich bin ziemlich sicher dass du keinen Fehler
im AVR entdeckt hast, sondern dass irgendwer (der Stack) auf deinem
armen cnt rumprügelt ...
> @warum do{}while(0)?> Keine Ahnung. Habe ich mal irgendwo aufgeschnappt.
Ist doch immer schön, wenn jemand irgendwas von irgendwo übernimmt, ohne
einen Grund zu kennen.
> Einfache Blockklammerung geht natürlich auch.
Solange sie nicht in einem if steht:
[C]
if (blah)
toggleLED1();
else
toggleLED2();
[C]
Ohne die while-Schleife bekommst du das nicht durch den Compiler.
Man könnte aber auch ganz profan ne Funktion draus machen und die als
inline deklarieren.
Dann ist der Code sogar wieder leserlich und verstehbar.
Peter
Marco S wrote:
> Es scheint mir, als ob der Befehl "clk += 1", der zu "subi r24, 0xFF"> umgewandelt wird, oder ein anderer Befehl, kaputt ist. Kann es denn> sein, daß der AVR seine eigene Maschinensprache teilweise nicht mehr> versteht?
Das ist schon richtig so, falls dir das noch nich so klar geworden ist.
Der AVR kann keine Addition mit einem Immediate. Nur eine Subtraktion.
Also:
1. a+b == a - (-b)
2. -1 == 0xFF == 0b11111111
Hi,
--------------------------
Und auf neueren AVRs wie dem Tiny24 mit
PINA = _BV(PA5)
noch einfacher.
--------------------------
Uppps - was hab ich denn da verpasst ?!?
Es wäre nett wenn mir jemand auf die Sprünge helfen könnte.
Wieso "toggelt" PINA = _BV(PA5 ) ?
Grüße,
Stefan
Stefan Sczekalla wrote:
> Hi,>> --------------------------> Und auf neueren AVRs wie dem Tiny24 mit> PINA = _BV(PA5)> noch einfacher.> -------------------------->> Uppps - was hab ich denn da verpasst ?!?> Es wäre nett wenn mir jemand auf die Sprünge helfen könnte.> Wieso "toggelt" PINA = _BV(PA5 ) ?>> Grüße,>> Stefan
Mega644 Datenblatt (02/07 Seite 68):
> However, writing a logic one to a bit in the PINx Register, will result in> a toggle in the corresponding bit in the Data Register.
Seite 70:
> Writing a logic one to PINxn toggles the value of PORTxn, independent on> the value of DDRxn. Note that the SBI instruction can be used to toggle> one single bit in a port.
Bin endlich zum Testen gekommen.
Wenn man davon absieht, dass ich 'ne Weile gesucht habe um zu merken,
dass auf dem STK500/505 Port A5 (der ja auch für ISP benutzt wird)
offenbar nach A4 geroutet wird, funktioniert ansonsten dein Programm
genau so, wie von dir vorgesehen.
Es wurde immer verrückter und jetzt ...
Habe mehrere avr-gcc Versionen probiert:
avr-gcc-3.4.6
avr-gcc-4.1.2
avr-gcc-4.2.0
avr-gcc-4.2.1.20070703
Überall dasselbe. Dann mal aus Neugier WinAVR-20070525 unter WinXP
probiert (zuvor alles unter linux) und damit das Programm, was oben
Angegeben ist compiliert. Dann das Hex-File genommen und unter linux
programmiert 1). Wunder oh Wunder; Programm läuft. Baff. Dann das o.a.
Programm mit dem o.a. Compiler übersetzt, programmiert und läuft. Hä?
Während Tage zuvor der Fehler bei mir wenigstens reproduzierbar war,
geht selbst dies nicht meht. Dafür läuft es, wie es soll. Na gut.
Assemblercode von Windows- und Linux-Version verglichen. Fast identisch.
Unter der Linuxvesion wird der Stackpointer nicht nur in __ctors_end,
sondern nochmal bei Eintritt in main initiiert. Da in main eine
Endlosschleife steht, sollte dies unbedeutend sein.
1) Genervt vom Suchen, dass unter XP wohl kein Parallelportprogrammierer
existiert, habe ich mich entschlossen einen AVR910-Typ zu bauen. Also
mal eben auf dem Steckbrett einen 2313 nach dem Plan von
http://www.mikrocontroller-projekte.de/ aufgesteckt. Auch um mal zu
sehen, ob diese Schnittstellenlösung 115200 kBit schafft. Mit 2k2 in der
Ausgangsstufe auch bei meinem hochkapazitiven Kabel. Funzt, also alles
auf Lochraster. Nach dem Debuggen nicht vorhandener Leckströme durfte
AVRStudio4 ran. Wunderbar, programmiert blitzschnell. Dann das ganze
unter Linux und avrdude. Über 54 sek. für knapp 700 Byte sind im
avr910-Modus schleppend langsam. Im avr109 oder butterfly-Modus geht's
schneller, dafür landen aber nur 0xFF im kompletten flash. Gut das es
Python gibt (gut 0.7 sek).
Marco S wrote:
> Assemblercode von Windows- und Linux-Version verglichen. Fast> identisch. Unter der Linuxvesion wird der Stackpointer nicht nur in> __ctors_end, sondern nochmal bei Eintritt in main initiiert. Da in> main eine Endlosschleife steht, sollte dies unbedeutend sein.
Deinem Unix-Compiler fehlt der ATmega256x-Patch, der uns nebenbei noch
beschert hat, dass main() nun eine normale Funktion geworden ist. Das
wird künftig mal dahingehend aufgelöst werden, dass main() entweder
mit __attribute__((OS_task)) oder __attribute__((OS_main)) deklariert
wird, um seine bisherige Sonderrolle zu erhalten.
> 1) Genervt vom Suchen, dass unter XP wohl kein> Parallelportprogrammierer existiert, habe ich mich entschlossen> einen AVR910-Typ zu bauen.
Bau dir lieber einen USBisp oder USBasp, die sind schneller. Oder
kauf dir einen AVR Dragon. Der kann bei Bedarf auch gleich noch
HV-Programmierung.