/* Problem AVR-Programmierung Seit zwei Tagen beiße ich mir die Zähne aus an meinem AVR-Entwicklungssystem, das anscheinend keinen lauffähigen code mehr erzeugt. Wird im angehängten Code-Beispiel die Zeile 6 auskommentiert, dann funktioniert die Portausgabe im Hauptprogramm nicht mehr. Der adressierte port ist dann zwar auf Ausgang programmiert, liefert jedoch low. Offenbar kann man den Fehler auch mit x-beliebigen anderen eingefügten dummy-code herbeiführen. Meine Entwicklungsumgebung besteht aus Kernel $ uname -a Linux pc4 3.16.0-5-amd64 #1 SMP Debian 3.16.51-3+deb8u1 (2018-01-08) x86_64 GNU/Linux Distribution $ lsb_release -a No LSB modules are available. Distributor ID: LinuxMint Description: LMDE 2 Betsy Release: 2 Codename: betsy IDE Codeblocks aus SVN build 04.Feb.2018 AVR-gcc V4.8.1 AVRdude V6.1 SPI-programmer USBtiny (Lady Ada) Attiny 25 Anzumerken ist dass ich verschiedene AVR Projekte in den letzten Jahren zum Laufen gebracht habe und bis vor wenigen Wochen auf diesem System lauffähigen Code generieren konnte. Sowohl der Programmer als auch das Zielsystem wurden getauscht, jedoch ohne Erfolg. Irgendwie riecht es nach einem ganz dämlichen Trivialfehler, aber ich komme einfach nicht drauf. Es wäre schön, wenn jemand dazu eine zündende Idee haben könnte. Dies ist der Minimalcode, bei dem der Fehler reproduzierbar auftritt. */ #include <stdlib.h> #include <avr/io.h> void PowerUp(void) { DDRB = (1<<PB2); //DDRB = (1<<PB2); //!!! } //++++++++ Main Program int main(void) { for (;;) { PowerUp(); PORTB |= (1<<PB2); } }
Könnte ein Problem mit dem Stack(-Pointer) sein. Die ganz kurze Funktion macht der Compiler inline (also ohne Funktionsaufruf), die längere mit "richtigem" Call benutzt Stack. Das knallt u.U. erst beim Rücksprung. Zeig mal das Disassembly...
bin/Release/TPA325xPowerManager.elf: file format elf32-avr Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000044 00000000 00000000 00000094 2**1 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .data 00000000 00800060 00000044 000000d8 2**0 CONTENTS, ALLOC, LOAD, DATA 2 .fuse 00000003 00820000 00820000 000000d8 2**0 CONTENTS, ALLOC, LOAD, DATA 3 .comment 00000011 00000000 00000000 000000db 2**0 CONTENTS, READONLY Disassembly of section .text: 00000000 <__vectors>: 0: 0e c0 rjmp .+28 ; 0x1e <__ctors_end> 2: 15 c0 rjmp .+42 ; 0x2e <__bad_interrupt> 4: 14 c0 rjmp .+40 ; 0x2e <__bad_interrupt> 6: 13 c0 rjmp .+38 ; 0x2e <__bad_interrupt> 8: 12 c0 rjmp .+36 ; 0x2e <__bad_interrupt> a: 11 c0 rjmp .+34 ; 0x2e <__bad_interrupt> c: 10 c0 rjmp .+32 ; 0x2e <__bad_interrupt> e: 0f c0 rjmp .+30 ; 0x2e <__bad_interrupt> 10: 0e c0 rjmp .+28 ; 0x2e <__bad_interrupt> 12: 0d c0 rjmp .+26 ; 0x2e <__bad_interrupt> 14: 0c c0 rjmp .+24 ; 0x2e <__bad_interrupt> 16: 0b c0 rjmp .+22 ; 0x2e <__bad_interrupt> 18: 0a c0 rjmp .+20 ; 0x2e <__bad_interrupt> 1a: 09 c0 rjmp .+18 ; 0x2e <__bad_interrupt> 1c: 08 c0 rjmp .+16 ; 0x2e <__bad_interrupt> 0000001e <__ctors_end>: 1e: 11 24 eor r1, r1 20: 1f be out 0x3f, r1 ; 63 22: cf e5 ldi r28, 0x5F ; 95 24: d2 e0 ldi r29, 0x02 ; 2 26: de bf out 0x3e, r29 ; 62 28: cd bf out 0x3d, r28 ; 61 2a: 06 d0 rcall .+12 ; 0x38 <main> 2c: 09 c0 rjmp .+18 ; 0x40 <_exit> 0000002e <__bad_interrupt>: 2e: e8 cf rjmp .-48 ; 0x0 <__vectors> 00000030 <PowerUp>: 30: 8c e0 ldi r24, 0x0C ; 12 32: 87 bb out 0x17, r24 ; 23 34: 87 bb out 0x17, r24 ; 23 36: 08 95 ret 00000038 <main>: 38: cc e0 ldi r28, 0x0C ; 12 3a: fa df rcall .-12 ; 0x30 <PowerUp> 3c: c8 bb out 0x18, r28 ; 24 3e: fd cf rjmp .-6 ; 0x3a <main+0x2> 00000040 <_exit>: 40: f8 94 cli 00000042 <__stop_program>: 42: ff cf rjmp .-2 ; 0x42 <__stop_program>
Solche Effekte kenne ich bislang nur wenn Interrupts ausgelöst werden auf nicht existente Interrupt-handler.
Es sollte auffallen, dass 1<<x niemals 2 Bits setzen kann, wie es bei 0x0C geschieht. Ergo: Compiler kaputt.
MWS schrieb: > Es sollte auffallen, dass 1<<x niemals 2 Bits setzen kann, wie es bei > 0x0C geschieht. > Ergo: Compiler kaputt. Also "Compiler kaputt" ist es doch in etwa 101% aller Fälle nicht. Insbesondere nicht bei so einem offensichtlichen Fehler. Der CPP scheint aus 1<<PB2 den Wert 0x0C zu generieren. Muss also was in den entsprechenden Header Files mit den Definitionen kaputt sein. Schau doch mal wie PB2 definiert ist.
:
Bearbeitet durch User
Und was macht PINB2 statt PB2? Edit: ok, sollte nix bringen, sind zumindest in meinem alten gcc gleich definiert. Ist schon komisch das der Compiler aus einem zweit Bits macht. Aber das richtige ist doch trotzdem dabei, nach dem disassembly müsste nur noch PB3 zusätzlich als Ausgang gesetzt werden?
ich bin nun nicht so der disassembly-Versteher. Vlt liegt der Fehler aber hier - Bildschirmausgabe vom CodeBlocks-Compiler-Lauf. Gleich in der ersten Zeile, wieso steht da an einer Stelle mmcu=attiny85, obwohl in den settings nur Attiny25 angehakt ist? In früheren Läufen hatte ich in der Tat den Attiny85 programmiert, was ja auch noch vor wenigen Wochen funktionierte. -------------- Build: Release in TPA325xPowerManager (compiler: GNU GCC Compiler for AVR)--------------- avr-gcc -mmcu=attiny85 -Wall -DF_CPU=1000000UL -Os -mmcu=attiny25 -c main.c -o obj/Release/main.o avr-g++ -o bin/Release/TPA325xPowerManager.elf obj/Release/fuse.o obj/Release/main.o -mmcu=attiny85 -Wl,-Map=bin/Release/TPA325xPowerManager.map,--cref Output file is bin/Release/TPA325xPowerManager.elf with size 1.98 KB Running project post-build steps avr-objdump -h -S bin/Release/TPA325xPowerManager.elf > bin/Release/TPA325xPowerManager.lss avr-objcopy -R .eeprom -R .fuse -R .lock -R .signature -O ihex bin/Release/TPA325xPowerManager.elf bin/Release/TPA325xPowerManager.hex avr-objcopy --no-change-warnings -j .eeprom --change-section-lma .eeprom=0 -O ihex bin/Release/TPA325xPowerManager.elf bin/Release/TPA325xPowerManager.eep avr-objcopy --no-change-warnings -j .lock --change-section-lma .lock=0 -O ihex bin/Release/TPA325xPowerManager.elf bin/Release/TPA325xPowerManager.lock avr-objcopy --no-change-warnings -j .signature --change-section-lma .signature=0 -O ihex bin/Release/TPA325xPowerManager.elf bin/Release/TPA325xPowerManager.sig avr-objcopy --no-change-warnings -j .fuse --change-section-lma .fuse=0 -O ihex bin/Release/TPA325xPowerManager.elf bin/Release/TPA325xPowerManager.fuse srec_cat bin/Release/TPA325xPowerManager.fuse -Intel -crop 0x00 0x01 -offset 0x00 -O bin/Release/TPA325xPowerManager.lfs -Intel srec_cat bin/Release/TPA325xPowerManager.fuse -Intel -crop 0x01 0x02 -offset -0x01 -O bin/Release/TPA325xPowerManager.hfs -Intel /bin/sh: 1: srec_cat: not found Process terminated with status 127 (0 minute(s), 0 second(s)) 0 error(s), 0 warning(s) (0 minute(s), 0 second(s))
mein altes AtmelStudio mit gcc 3.4 macht es richtiger:
1 | 0000002c <PowerUp>: |
2 | |
3 | #include <stdlib.h> |
4 | #include <avr/io.h> |
5 | |
6 | void PowerUp(void) { |
7 | DDRB = (1<<PB2); |
8 | 2c: 84 e0 ldi r24, 0x04 ; 4 |
9 | 2e: 87 bb out 0x17, r24 ; 23 |
10 | DDRB = (1<<PB2); //!!! |
11 | 30: 87 bb out 0x17, r24 ; 23 |
12 | 32: 08 95 ret |
13 | |
14 | 00000034 <main>: |
15 | } |
16 | //++++++++ Main Program |
17 | |
18 | int main(void) { |
19 | for (;;) { |
20 | PowerUp(); |
21 | 34: fb df rcall .-10 ; 0x2c <PowerUp> |
22 | PORTB |= (1<<PB2); |
23 | 36: c2 9a sbi 0x18, 2 ; 24 |
24 | 38: fd cf rjmp .-6 ; 0x34 <main> |
25 | |
26 | 0000003a <_exit>: |
27 | 3a: f8 94 cli |
28 | |
29 | 0000003c <__stop_program>: |
30 | 3c: ff cf rjmp .-2 ; 0x3c <__stop_program> |
wenn ich die //!!! Zeile auskommentiere wird auch nur ein out generiert.
Interessant wären tatsächlich mal die ganzen Kommandozeilen vom schlechten Fall zu sehen.
Ja, die doppelte mcu definition wird den Compiler verwirrt haben. Kenne CodeBlocks nicht, aber das muss irgendwo in den Projektsettings liegen. Evtl.
Zumindest mit 4.8.0 kann ich das nicht nachvollziehen. * Wie sieht Präcompilat (*.i) und Assembly (*.s) aus wenn -save-temps angegeben wird? * Ist sicher, dass die Dateien neu generiert werden, d.h. dass das Makefile i.O. ist? * Was ist die Ausgabe mit zusätzlich -v beim Compilieren / Linken?
:
Bearbeitet durch User
ohne das jetzt im Detail geprüft zu haben: ich vermute die falsche mcu definition führt dazu das der Stackpointer falsch initialisiert wird (tiny85 hat 512 Byte RAM, tiny24 nur 128 Bytes) und dann der Rücksprung aus PowerUp() nicht mehr im main() landet. Damit wird der Port initialisiert, aber das Bit in main nicht mehr gesetzt. Das passiert vielleicht wenn man das CodeBlocks Projekt kopiert und die mcu Einstellung verändert, dann muss die IDE ja die alte Einstellung erkennen und ändern. Das hat sie wohl nicht und den tiny25 hinzugefügt. Vielleicht korrigiert die IDE das wenn man noch andere Compilereinstellungen ändert. Aber eigentlich wollte ich mir die AVR gar nicht mehr ansehen...
Johannes S. schrieb: > ich vermute die falsche mcu definition führt dazu das der Stackpointer > falsch initialisiert wird (tiny85 hat 512 Byte RAM, tiny24 > nur 128 Bytes) Was aber nicht das 0xC für 1<<PB2 erklärt. Tatsächlich wird der Startcode für ATtiny85 verwendet:
1 | COLLECT_GCC_OPTIONS='-mmcu=attiny85' '-mmcu=attiny25' '-Os' '-save-temps' '-v' '-fverbose-asm' |
2 | collect2 version 4.8.0 20130306 (experimental) |
3 | .../avr/bin/ld -m avr25 .../avr/lib/avr25/crttn85.o ... |
4 | GNU ld (GNU Binutils) 2.23.52.20130301 |
5 | |
6 | 0000001e <__ctors_end>: |
7 | 1e: 11 24 eor r1, r1 |
8 | 20: 1f be out 0x3f, r1 ; 63 |
9 | 22: cf e5 ldi r28, 0x5F ; 95 |
10 | 24: d2 e0 ldi r29, 0x02 ; 2 |
11 | 26: de bf out 0x3e, r29 ; 62 |
12 | 28: cd bf out 0x3d, r28 ; 61 |
13 | 2a: 06 d0 rcall .+12 ; 0x38 <main> |
14 | 2c: 08 c0 rjmp .+16 ; 0x3e <_exit> |
:
Bearbeitet durch User
Pirx schrieb: > Pack mal das PowerUp() vor die For-Schleife. Ergibt immer noch kein 0x0C; immer nur 0x04.
Das 0x0c konnte ich auch mit dem alten gcc 3.4 nicht provozieren.
Bernd S. schrieb: > MWS schrieb: >> Es sollte auffallen, dass 1<<x niemals 2 Bits setzen kann, wie es bei >> 0x0C geschieht. >> Ergo: Compiler kaputt. > > Also "Compiler kaputt" ist es doch in etwa 101% aller Fälle nicht. > Insbesondere nicht bei so einem offensichtlichen Fehler. > > Der CPP scheint aus 1<<PB2 den Wert 0x0C zu generieren. Muss also was in > den entsprechenden Header Files mit den Definitionen kaputt sein. Schau > doch mal wie PB2 definiert ist. Spannender Fehler. denn 1<<x kann eigentlich nicht mehr als ein Bit gesetzt haben, egal welchen Wert x hat, also egal wie PB2 definiert ist. Tut es aber sowohl in der Funktion PowerUp als auch in der main, beide Male 0x0c Mein avr-gcc-4.9.2 macht das auch (erstmal) richtig:
1 | ldi r24,lo8(4) |
2 | out 0x17,r24 |
Der eigentliche, beobachtete Fehler scheint aber tatsächlich der falsche Startup-Code zu sein, der den Stack-Pointer falsch initialisiert. Ist auch kein Wunder, denn der Linker-Aufruf (avr-g++) bekommt nur -mmcu=attiny85 mit. Da scheint die IDE die korrekten Einstellungen noch nicht in alle Build-Schritte übertragen zu haben. Kann es sein, dass auch die Disassembly-Ausgabe alt ist und du irgendwann mal PB2 und PB3 benutzt hast? MfG, Arno
Johannes S. schrieb: > ohne das jetzt im Detail geprüft zu haben: ich vermute die falsche mcu > definition führt dazu das der Stackpointer falsch initialisiert wird > (tiny85 hat 512 Byte RAM, tiny24 nur 128 Bytes) und dann der Rücksprung > aus PowerUp() nicht mehr im main() landet. Damit wird der Port > initialisiert, aber das Bit in main nicht mehr gesetzt. > Das passiert vielleicht wenn man das CodeBlocks Projekt kopiert und die > mcu Einstellung verändert, dann muss die IDE ja die alte Einstellung > erkennen und ändern. Das hat sie wohl nicht und den tiny25 hinzugefügt. > Vielleicht korrigiert die IDE das wenn man noch andere > Compilereinstellungen ändert. > Aber eigentlich wollte ich mir die AVR gar nicht mehr ansehen... So in der Richtung denke ich auch. Ich hatte im laufenden Projekt das target geändert. Werde das Projekt neu aufsetzen, das könnte schon die Lösung sein. Dazu komme ich aber im Augenblick nicht (Gartenarbeit ist hat eben den höheren Prioritätslevel).
Für die vielen hilfreichen Beiträge möchte ich mich hier mal herzlich bedanken. Innerhalb von CodeBlocks konnte ich keine Einstellungen finden, die das falsche Target korrigiert hätten. Also habe ich ein neues Attiny25-Projekt geöffnet - und voilà - nun läuft es wieder erwartungsgemäß. Und ja, es ist für mich nachvollziehbar, dass der Code, gelinkt für den größeren RAM-Bereich des Attiny85 im Attiny25 wohl nicht funktionieren wird.
:
Bearbeitet durch User
Ist damit auch der 0x0c-Fehler beseitigt? Den finde ich noch spannender... MfG, Arno
Arno schrieb: > Ist damit auch der 0x0c-Fehler beseitigt? Den finde ich noch > spannender... > > MfG, Arno Würde mich auch interessieren. Lässt es sich bei irgendwem nachstellen wenn man den geposteten Compileraufruf an der Kommandozeile manuell nachvollzieht?
Arno schrieb: > Ist damit auch der 0x0c-Fehler beseitigt? Den finde ich noch > spannender... Das ist mit einiger Sicherheit ein Copy&Paste Fehler. Im originalen Code steht wohl einfach:
1 | DDRB = (3<<PB2); |
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.