Forum: Compiler & IDEs ATtiny10 mit avr-gcc Compiler


von Martin (Gast)


Lesenswert?

Hallo,

ich möchte den ATtiny10 verwenden, da dieser sehr klein
und für meine Anwendung ausreichend ist.

Ich habe mir die aktuellste Version von AVR Studio und
der AVR Toolchain installiert und habe nun folgendes Problem.

Der Compiler gibt keine Fehler aus und die Toolchain erzeugt mir eine 
hex- File die auch auf dem µC Platz hat.

Nach dem Überspielen macht dieser aber nichts.

In einigen Beiträgen zu diesem µC in verschiedenen Foren habe ich 
herausgefunden, dass dieser gar nicht zum C- Compilieren geht, da dieser 
keinen RAM besitzt.

Stimmt dies immer noch, da der ATtiny10 ja in der avr-libc unterstütz 
wird?

Was muss ich machen, damit mein C- Code auch auf dem Controller richtig 
ausgeführt wird?

Vielen Dank im Voraus,
schöne Grüße,
Martin

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Martin schrieb:

> Nach dem Überspielen macht dieser aber nichts.

Das ist nicht unnormal. ;-)  An dieser Stelle beginnt üblicherweise
der wichtigste Schritt der Programmierung: das Debuggen.

> In einigen Beiträgen zu diesem µC in verschiedenen Foren habe ich
> herausgefunden, dass dieser gar nicht zum C- Compilieren geht, da dieser
> keinen RAM besitzt.

Das ist Quatsch.  Ein ATtiny10 hat sehr wohl SRAM, siehe Datenblatt.

> Stimmt dies immer noch, da der ATtiny10 ja in der avr-libc unterstütz
> wird?

Von der avr-libc wird er nun eher nicht unterstützt.  Es gibt
lediglich ein IO-Headerfile, damit man auf die Portregister
zugreifen kann.

> Was muss ich machen, damit mein C- Code auch auf dem Controller richtig
> ausgeführt wird?

Debuggen. ;-)

Nun ja, sagen wir mal so: die Wahrscheinlichkeit, dass die Toolchain
an dieser Stelle noch Bugs hat, ist gegeben.  Die Unterstützung für
ATtiny10 & Co. wurde von Atmel eigens für die AVR-Tools (die wohl
Bestandteil von AVR Studio 5 sind, so wie ich das sehe) gezimmert,
damit gibt es für diesen Teil bislang noch nicht sehr viele Leute,
die das getestet haben.  Wenn du ein Problem mit deinem eigenen
Sourcecode ausschließen kannst, dann solltest du dich an den Atmel-
Support wenden.  So viel Flash-ROM ist das ja nicht, du solltest also
schon in der Lage sein, im disassemblierten Code nachzuvollziehen,
ob der Maschinencode zu deinem C-Code passt oder nicht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Was ich bisher vom ATtiny10-Support in avr-gcc gesehen habe (bzw. im 
Atmel-Branch von avr-gcc) sieht nicht sonderlich vertrauenserweckend 
aus.

Sch mal in den erzeugten Assemblercode rein, ob der vernünftig aussieht. 
Ansonsten wäre es auch angebracht, ein grep über den erzeugten Assembler 
(zB mit -save-temps) oder ein Disassembly laufen zu lassen, ab nicht 
Register < r16 verwendet werden. Die Register werden m.W. einfach auf 
Register+16 gemappt, was zwar keine Fehler beim Übersetzen gibt, aber 
logischerweise zu unsinnigem Code führt.

Ausserdem dürfen r16 (was _tmp_reg_ wird) und r17 (was _zero_reg_ 
wird) nirgends im Code auftauchen, ausser im Dateistart des jeweiligen 
s-Files.

Wie gesagt, die Atmel-Patches für den Tiny10-Support sehen incht so aus, 
als wären die schon für den praktischen Einsatz tauglich.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:

> Wie gesagt, die Atmel-Patches für den Tiny10-Support sehen incht so aus,
> als wären die schon für den praktischen Einsatz tauglich.

Und wie auch schon gesagt: Supportanfragen dafür bitte an die Adresse
richten, die im AVR Studio genannt ist.  Das Ganze ist derzeit ein rein
privater Atmel-Hack.

Ich bin zwar der erste, der einen Controller prinzipiell eher in C
programmieren würde, aber gerade angesichts der Kleinheit und
Einfachheit würde ich für meinen Bedarf bei ATtiny10 & Co. wohl von
diesem Grundsatz abgehen und den Code wirklich mal gleich im
Assembler zimmern.

von Rolf Magnus (Gast)


Lesenswert?

Jörg Wunsch schrieb:
>> In einigen Beiträgen zu diesem µC in verschiedenen Foren habe ich
>> herausgefunden, dass dieser gar nicht zum C- Compilieren geht, da dieser
>> keinen RAM besitzt.
>
> Das ist Quatsch.  Ein ATtiny10 hat sehr wohl SRAM, siehe Datenblatt.

Es gab früher schon mal einen AVR namens ATtiny10, der tatsächlich kein 
SRAM hatte. Das war im Prinzip ein Tiny11 mit nur einmal beschreibbarem 
Programmspeicher. In alten Versionen des Tiny11/12-Datenblatts war der 
noch mit dokumentiert. Eine kurze Suche hat folgendes erbracht: 
http://avr.hw.cz/pdf/attiny_10_11_12.pdf

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf Magnus schrieb:

>> Das ist Quatsch.  Ein ATtiny10 hat sehr wohl SRAM, siehe Datenblatt.
>
> Es gab früher schon mal einen AVR namens ATtiny10, der tatsächlich kein
> SRAM hatte.

Wobei es den wohl nie wirklich gab (im Gegensatz zu ATtiny11/12),
aber ich kannte den Namen davon auch noch.  Naja, Škoda verkauft ja
nun auch wieder einen Felicia, den sie schon mal in den 1950er
gebaut haben …

von Martin (Gast)


Lesenswert?

Hallo,

vielen Dank für Eure Antworten.

Ich habe nun mal AVR Studio 5 installiert und ein neues
Projekt mit dem ATtiny10 aufgesetzt.

Ich habe ein einfaches Programm geschrieben, dass lediglich den
PB0 ein und mit einem delay ausschaltet.

AVR Studio 5 installiert gleichzeitig auch eine AVR Toolchain mit,
die ich nun auch verwende.
Ich habe mein WINAVR und die alte Toolchain von AVR Studio 4 
deinstalliert und die nötige Path- File umgeschrieben.

Im Debug- Mode mit dem AVR Simulator gibt es die Möglichkeit zu 
disassemblieren.
Dort wird zwar kein R16 verwendet, aber R17.
Beim Debuggen läuft immer die gleiche Schleife ab. Deshalb wird auch
der programmierte µC nichts schalten.

Der Assembler Code schaut demnach nicht nach einem richtigen Code aus!

Was könnte ich noch machen, damit ich den ATtiny10 richtig in C 
programmieren kann?

Schöne Grüße,
Martin

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Martin schrieb:

> Der Assembler Code schaut demnach nicht nach einem richtigen Code aus!

So viel kann's nicht sein, und geheim kann das bisschen Blinken einer
LED wohl auch nicht sein, also warum postest du nicht den generierten
Code mal?  Kannst auch das ELF-File als Anhang senden, dann muss ich
mich nicht mit dem blöden AVR-Studio-Disassembler rumärgern, dessen
wichtigstes es zu sein scheint, hinter jeden Opcode NOP noch dahinter
zu schreiben, dass da "no operation" passiert.

> Was könnte ich noch machen, damit ich den ATtiny10 richtig in C
> programmieren kann?

. dir deinen eigenen C-Compiler schreiben
. Atmel auf den Wecker gehen, bis sie die Bugs im Compiler reparieren,
  die sie da reingebaut haben
. vielleicht doch die paar Zeilen gleich in Assembler schreiben
  (OK, entspricht natürlich nicht deinen Anforderung, wollte es
  trotzdem nochmal erwähnt haben)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wie sieht den der erzeugte Assembler aus? Die Ausgabe erfolgt mit 
-save-temps und macht ein s-File. Zusätzlich kannst du noch 
-fverbose-asm -dp angeben, so daß zusätzliche Informationen enthalten 
sind.

r17 ist prinzipiell ok; die Frage ist jedoch wie das Register 
verwendet wird. Nach avr-gcc ABI hat dieses Register ausserhalb einer 
insn immer den Wert 0 zu enthalten.

Ist das .set von __zero_reg__ am Anfang des Assemblers ok? 
Wird __zero_reg__ im Startup-Code genullt? Verwendet der Startup-Code 
ungültiger Register? Den Startup-Code siehst du im Disassembly des 
gelinkten elf.

Ändert sich der Code, wenn du zusätzlich die avr-gcc-Schalter
-ffixed-2
-ffixed-3
...
-ffixed-17

angibst?

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

hatte leider gestern keine Zeit mich weiter mit diesem Problem zu 
befassen.

Nun habe ich aber mal ein s- File erstellen lassen.

Anbei findet Ihr die erzeugten Files, mit den temp- files.

Ich kann leider nicht wirklich erkennen, ob dabei ein fehlerhafter Code 
generiert wird, da ich normalerweise nicht mit dem Compiler selbst 
arbeite, sondern diesen nur benutze...

Also vorab mal wieder vielen Dank fürs Posten...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Der erzeugte Assemblercode entspricht durchaus deinem C-Code.

Den Fehler hättest du genauso gut auf einem anderen Controller als
einen ATtiny10 bekommen ... schau dir nochmal genau an, wie du
versuchst, das Portpin wieder auf 0 zu setzen.

von Martin (Gast)


Angehängte Dateien:

Lesenswert?

Ach ja...

Ich habe eine Tilde vergessen.

Dies ist nun ausgebessert und nun funktioniert der einfache Code auf dem 
µC. Somit habe ich bei diesem Code keine Probleme mehr.

Daraufhin wollte ich einen Timer starten lassen und die TOF - Interrupt- 
Routine bearbeiten.
Der Timer wird im Fast-PWM Mode gestartet und ich will in der ISR das
OCR0A umschreiben um den Duty- Cycle zu ändern.

Dazu habe ich globale Variablen verwendet!

Dabei hat der Code auf dem µC NICHT funktioniert.
Ich habe mir wieder den Disassembly angesehen.
Das Problem, das nun auftritt ist, dass die globalen Variablen beim 
Compilieren falsch realisiert werden.

Ich kann aber leider im Assemblercode keinen Fehler erkennen, außer dass 
vor dem LDS und dem STS Befehl Fragzeichen stehen.
Den Befehl STS und LDS gibt es laut Datenblatt schon.

Anbei habe ich wieder die Files gestellt, die erstellt wurden.

Am Ausgang liegt zwar ein Rechteck an, aber der Duty-Cycle wird nicht 
verändert.

Könnt Ihr einen Fehler erkennen?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Ja, das sieht "vergurkt" aus und wäre schon einen Bugreport an den
Atmel-Support wert.  Register r24 wird einerseits als lokale Variable
(für iTimerTemp) benutzt, andererseits aber in vielen IO-Operationen
als scratch register.  Wenn das auf iTimer am Ende zurückgeschrieben
wird, steht da natürlich nichts sinnvolles mehr drin.

Noch ein paar Anmerkungen zum C-Code:
1
//Globale Variablen zum Gebrauch in ISR
2
volatile uint8_t iTimer=0;
3
volatile uint8_t iRichtung=0;

Nicht jede Variable, die in einer ISR benutzt wird, muss man
"volatile" machen.  Diese hier werden nur in der ISR benutzt, und
normale Variablen hätte es getan (die man sinnvollerweise als
"static" deklariert, um die Sichtbarkeit einzuschränken).

Dann kann man sich den ganzen Firlefanz mit iTimerTemp etc. sparen
und das Cachen in Registern dem Compiler überlassen.

Globale und statische Variablen muss man nicht mit 0 initialisieren,
dies wird bereits durch den C-Standard abgesichert.
1
  GTCCR |= (1 << TSM);

Würde ich weglassen, wenn man nicht wirklich eine derartige taktgenaue
Synchronisation (wogegen denn eigentlich?) braucht.
1
  TCCR0A |= (1 << WGM00);
2
  TCCR0A &= ~(1<< WGM01);
3
  TCCR0B |= (1 << WGM02);
4
  TCCR0B &= ~(1<< WGM03);

Du initialisiert die Register, da ist es sinnvoller, gleich die
kompletten Registerwerte zu beschreiben, statt jedes Bit einzeln zu
befummeln.  Auf dokumentierte Resetwerte darfst du dich ansonsten auch
verlassen, d. h. "TCCR0A &= ~(1<< WGM01);" ist garantiert eine
sinnlose Operation (das Bit war bereits 0).
1
      OCR0A++;
2
      if (OCR0A >= 240) //...

Da du den Timer mit einer 8-bit-PWM betreibst, kommst du besser, wenn
du nur mit OCR0AL rechnest, denn der high-Teil der 16-bit-Operation
ist immer 0 (was der Compiler aber nicht wissen kann/darf).

1
    if(iRichtung_temp)//Soll nach oben gezählt werden?
2
    {    
3
    /* ... */
4
    else if(!iRichtung_temp) //Soll nach unten gezählt werden?

Was soll es denn beim "else" sonst noch sein wenn nicht gleich 0?
1
void Start_Timer(void)

Diese Funktion wird direkt nach Init() aufgerufen, hätte man auch
zusammenlegen können.  Insbesonder hätte man sie beide "static" machen
sollen, dann hätte der Compiler gewusst, dass sie nicht von außen
gerufen werden kann, und hätte den Code entsprechend gleich in main()
fallenlassen.
1
    for(;;){
2
    asm volatile ("nop"); //Hauptschleife soll nichts ausführen...
3
    }

Dazu braucht man keinen NOP, eine leere Anweisung tut's auch.
Sinnvoller ist es aber, ein sleep_mode() da reinzusetzen, dann spart
man noch ein wenig Strom.  Zugegebenermaßen beim ATtiny10 und nur 128
kHz Takt nicht mehr nennenswert (der verbraucht ja ohnehin schon fast
nur Leckstrom), aber man kann es sich zum Prinzip machen, am Ende der
Hauptschleife schlafen zu gehen.

von MWS (Gast)


Lesenswert?

És würde alles funktionieren, d.h. Timer läuft, PWM auch, ISR löst aus. 
Jedoch scheint der ATTiny10 für LDS/STS einen anderen Opcode zu 
benötigen, welcher der GCC nicht richtig übersetzt.

Dazu ein paar Zeilen in ASM im AVR-Studio 4 compiliert, es handelt sich 
um mit Fragezeichen markierten Befehle:
1
LDS   R24,   0x40
2
LDS   R18,   0x41
3
STS   0x41,  R18
4
STS   0x40,  R24

Daraus erzeugt der Compiler:
1
A180        LDS       R24,0x40
2
A121        LDS       R18,0x41       
3
A921        STS       0x41,R18
4
A980        STS       0x40,R24
Dieser Code simuliert auch richtig, während es der per GCC erzeugte Code 
für diese Befehle nicht macht.

Zum Vergleich, Original-ASM:
1
 80 91 40 00          ???LDS R24,0x0040
2
 20 91 41 00          ???LDS R18,0x0041
3
 80 93 40 00          ???STS 0x0040,R24
4
 20 93 41 00          ???STS 0x0041,R18

von Martin (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Ja, das sieht "vergurkt" aus und wäre schon einen Bugreport an den
>
> Atmel-Support wert.  Register r24 wird einerseits als lokale Variable
>
> (für iTimerTemp) benutzt, andererseits aber in vielen IO-Operationen
>
> als scratch register.  Wenn das auf iTimer am Ende zurückgeschrieben
>
> wird, steht da natürlich nichts sinnvolles mehr drin.

Vielen Dank fürs Ansehen!
Wie sieht so ein Bug Report aus?
Ich habe so etwas noch nie gemacht...
Leider werde ich diesen µC noch nicht in C programmieren können, oder?
Ich kann ja noch nicht davon ausgehen, dass das was ich in C schreibe,
auch wirklich vom µC dann ausgeführt wird.
Und ob dies mit den globalen Variablen das einzige ist, weis ich ja auch 
noch nicht!

Jörg Wunsch schrieb:
> Nicht jede Variable, die in einer ISR benutzt wird, muss man
>
> "volatile" machen.  Diese hier werden nur in der ISR benutzt, und
>
> normale Variablen hätte es getan (die man sinnvollerweise als
>
> "static" deklariert, um die Sichtbarkeit einzuschränken).


Bei diesem Beispiel gebe ich dir recht...

Die globalen Variablen hätten in diesem Fall auch ohne "volatile" 
funktioniert.
Dann hätte sich der Compiler wesentlich leichter getan.

Das mit dem GTTCR habe ich nur laut Datenblatt so gemacht.

Jörg Wunsch schrieb:
> Diese Funktion wird direkt nach Init() aufgerufen, hätte man auch
>
> zusammenlegen können.  Insbesonder hätte man sie beide "static" machen
>
> sollen, dann hätte der Compiler gewusst, dass sie nicht von außen
>
> gerufen werden kann, und hätte den Code entsprechend gleich in main()
>
> fallenlassen.

Was passiert dann wenn ich die static- Funktion 2x aufrufe. Bei static 
kopiert ja der Pre-Prozessor die Funktion in die main- Funktion um 
Sprungbefehle weg zu lassen, oder sehe ich das falsch?
Wird die Funktion dann 2x in den Code kopiert, oder wird eine 
Sprunganweisung geschrieben?

Das NOP in der Endlosschleife habe ich sicherheitshalber hingeschrieben, 
damit der Compiler evtl. die Schleife nicht weg optimiert.

von MWS (Gast)


Lesenswert?

http://www.atmel.com/dyn/resources/prod_documents/doc8127.pdf
S. 93 LDS (16-bit) & S. 148 STS (16-bit)

von 1gast (Gast)


Lesenswert?

Martin schrieb:
> Was passiert dann wenn ich die static- Funktion 2x aufrufe. Bei static
> kopiert ja der Pre-Prozessor die Funktion in die main- Funktion um
> Sprungbefehle weg zu lassen, oder sehe ich das falsch?
Der Präprozessor hat da nichts zu suchen! Die genaue Erklärung überlasse 
ich aber lieber Jörg Wunsch, der hat mehr Ahnung davon.

von MWS (Gast)


Lesenswert?

Hmm, irgendetwas lief hier falsch...
Instruction Set:
http://www.atmel.com/atmel/acrobat/doc0856.pdf
Dort S. 96 & S. 151

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

MWS schrieb:
> És würde alles funktionieren, d.h. Timer läuft, PWM auch, ISR löst aus.
> Jedoch scheint der ATTiny10 für LDS/STS einen anderen Opcode zu
> benötigen, welcher der GCC nicht richtig übersetzt.

Genauer gesagt, der Assembler assembliert es nicht korrekt.

Das ist aber auch reichlich fies: sie haben die Befehle LDS und STS
für den ATtiny10 (& Verwandte) letztlich überladen mit einem völlig
anderen Opcode, nur die Namen der Befehle sind gleich.  Die Befehle
im ATtiny10 fallen dadurch auf, dass sie nur 16 Bit groß sind und
nur einen Takt brauchen, aber die einzige Bemerkung, die darauf hin
deutet ist:

Note: Registers r0..r15 are remapped to r16..r31.

Ein separater Opcode wäre weiß Gott angebracht gewesen.

von MWS (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Genauer gesagt, der Assembler assembliert es nicht korrekt.

Oder so.

> Das ist aber auch reichlich fies: sie haben die Befehle LDS und STS
> für den ATtiny10 (& Verwandte) letztlich überladen mit einem völlig
> anderen Opcode, nur die Namen der Befehle sind gleich.

Den Mangel an Info im ATiny10 DB fand ich auch eigenartig, kein einziger 
Hinweis auf LDS/STS. Wenn man dann noch ein älteres Instruction Set 
Manual da hat, kommt man erst über Umwege auf den Trichter, daß es da 
noch was Anderes geben muss.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Martin schrieb:
> Wie sieht so ein Bug Report aus?

Einfach eine Mail, in der du die beiden gezeigten Probleme erklärst,
und der du am besten deinen Beispielcode beilegst.  Die Support-
Mailadresse müsstest du irgendwo beim Installieren der AVR Toolchain
gesagt bekommen haben.

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
Noch kein Account? Hier anmelden.