Forum: Mikrocontroller und Digitale Elektronik AVR clock prescaler (CLKPR) und gcc-Codeoptimierung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Peter-Jan P. (pjp)


Bewertung
1 lesenswert
nicht lesenswert
Da der Clock Prescaler mich die letzten zwei Tage beschäftigt hat, habe 
ich mal meine Ergebnisse zusammengetragen. Alles was ich hier schreibe, 
habe ich am attiny2313 ausprobiert, das Problem besteht aber auch bei 
anderen AVR µCs.


Um den Faktor des clock prescalers einzustellen, muss man innerhalb von 
4 Taktzyklen zweimal auf das Register CLKPR zugreifen: im ersten Zugriff 
setzt man das höchste Bit (CLKPCE) auf 1 alle anderen auf 0, im zweiten 
Zugriff stellt man den Teilungsfaktor ein. Mit avr-gcc code sieht das 
etwa so aus:
1
  CLKPR = (1<<CLKPCE);
2
  CLKPR = 1;

Sofern man Code-Optimierung benutzt (gcc Schalter -Os), funktioniert das 
auch wie erwartet, verwendet man keine Optimierung (-O0), funktioniert 
es auf einmal nicht mehr. Der Faktor des clock prescalers wird einfach 
nicht geändert. Den Grund dafür kann man im Assemblerlisting finden.
Mit Optimierung erhält man:
1
  ldi r24,lo8(-128)   ;  tmp44,
2
  out 70-32,r24   ; ,, tmp44
3
  ldi r24,lo8(1)   ;  tmp46,
4
  out 70-32,r24   ; ,, tmp46

Ohne Optimierung wird daraus:
1
  ldi r24,lo8(70)   ;  D.2172,
2
  ldi r25,hi8(70)   ;  D.2172,
3
  ldi r18,lo8(-128)   ;  tmp54,
4
  movw r30,r24   ; , D.2172
5
  st Z,r18   ; , tmp54
6
  ldi r24,lo8(70)   ;  D.2173,
7
  ldi r25,hi8(70)   ;  D.2173,
8
  ldi r18,lo8(1)   ;  tmp55,
9
  movw r30,r24   ; , D.2173
10
  st Z,r18   ; , tmp55

Man erkennt direkt, dass die Zugriffe auf das Register CLKPR (das sind 
die Zeilen mit "st Z,r18") nicht mehr innerhalb von 4 Taktzyklen 
erfolgt.

Sofern man nicht auf die Optimierung zurückgreifen möchte, lässt sich 
das Problem umgehen, indem man den Zugriff per inline assembler 
realisiert:
1
  asm volatile (
2
    "st Z,%1" "\n\t"
3
    "st Z,%2"
4
    : :
5
    "z" (&CLKPR),
6
    "r" ((uint8_t) (1<<CLKPCE)),
7
    "r" ((uint8_t) 1)  // neuer Wert für CLKPR
8
  );

von MWS (Gast)


Bewertung
-4 lesenswert
nicht lesenswert
Um solcherlei zu umschiffen, gibt's in der power.h das Makro 
clock_prescale_set(x).

Und das hättest Du jetzt leichter rausgebracht, als diesen Aufsatz hier 
zu schreiben :D

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.