AVR Studio --> External-Dependencies --> "iom???.h" --> "iomxx0_1.h"
Wenn man sich von oben nach unten im Code durchwühlt, trifft man im low level Bereich auf Code wie diesen:
Jetzt die Frage:Code:inline void MotorSpeed (unsigned char left_speed, unsigned char right_speed) { OCR1A = left_speed; OCR1B = right_speed; } inline void MotorDir (unsigned char left_dir, unsigned char right_dir) { PORTD = (PORTD &~ ((1 << PD4) | (1 << PD5))) | left_dir; PORTB = (PORTB &~ ((1 << PB4) | (1 << PB5))) | right_dir; }
Woher kennt der Compiler die Definition der Variablen OCR1A, OCR1B, PORTB, PORTD, PB4, PB5, PD4, PD5 ? Ich habe in den Files der Lib 2.70 gesucht aber nirgends etwas gefunden.
AVR Studio --> External-Dependencies --> "iom???.h" --> "iomxx0_1.h"
Diese Definitionen werden mit dem Compiler geliefert und liegen daher in dessen Verzeichnis.
Hi,bei mir ist <WinAVR_ROOT> = c:\WinAVR.Zitat von ehenkes
In asuro.h:In <WinAVR_ROOT>\avr\include\avr\io.h:Code:... #define ASURO_H #include <avr/io.h> ...Und in <WinAVR_ROOT>\avr\include\avr\iom8.h findest Du ALLES ...Code:... #elif defined (__AVR_ATmega8__) # include <avr/iom8.h> ...
Klasse Spurensuche! Jetzt fehlen mir nur noch diese ...
_SFR_IO16
_SFR_IO8
z. B. aus
#define OCR1A _SFR_IO16(0x2A)
#define OCR1B _SFR_IO16(0x2
#define PORTB _SFR_IO8(0x1
#define PORTD _SFR_IO8(0x12)
... dann wäre die Kette komplett.
Ich habe es via google gefunden: in sfr_defs.h
Kann dies bitte jemand erläutern? Wann muss ich __SFR_OFFSET als 0 setzen anstelle 0x20?Code:#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET) #define _SFR_IO16(io_addr) ((io_addr) + __SFR_OFFSET) #ifndef __SFR_OFFSET /* Define as 0 before including this file for compatibility with old asm sources that don't subtract __SFR_OFFSET from symbolic I/O addresses. */ #define __SFR_OFFSET 0x20 #endif
Das hängt mit der internen Architektur des AVRs zusammen. Es gibt zwei Methoden, die Hardware-Konfigurations-Register (SFRs) anzusprechen, und deswegen hat jedes SFR auch zwei Adressen. Schau dir mal in Datenbaltt die Registerübersicht an. Für PORTB steht dort z:b. 0x18 (0x3. Beide Adressen bezeichnen dasselbe Register, aber unter Verwendung der beiden Zugriffsmethoden:
die erste ist direkter Zugiff auf die Register mit speziellen Befehlen (IN/OUT). Dabei wird kein Offset benötigt. DIe Adresse von PORTB ist hier also 0x18. Mit "OUT 0x18, r16" wird daher der Inhalt von Register 16 auf PORTB ausgegeben.
Als zweite Möglichkeit werden die Register quasi ins RAM gespiegelt, haben also jedes eine eigene Speicheradresse. Da in den ersten 32 Bytes des RAMs aber schon die Multifunktionsregister leigen, fangen die SFRs erst bei 0x0020 an. Der eigentliche RAM beginnt übrigens erst bei 0x0060, weil davor halt die SFRs liegen.
"STS 0x38, r16" würde wiederum Register 16 auf PORTB ausgeben.
EDIT: stimmt wohl doch nicht!
Der C-Compiler bevorzugt grundsätzlich die zweite Methode und braucht daher den Offset.
Ich hoffe das war korrekt so, hab lange kein ASM mehr geschrieben (da muss man sowas mitunter beachten. Wenn du also neugierig bist, wie der AVR wirklich funktioniert, solltest du dich etwas mit ASM beschäftigen).
Danke, das ist sehr verständlich erklärt. Jetzt bleibt nur noch die offene Frage: Warum verwendet der C-Compiler die Methode via RAM? ... oder anders gefragt: kann ich den C-Compiler zwingen, direkt auf die Register (ohne Spiegelung ins RAM) zuzugreifen?
Da hab ich wohl falsch vermutet. Hab mir grad mal nen .hex disassembliert. Es wird doch IN/OUT verwendet.
Es gibt aber bei den größeren AVRs mit vielen Funktionen auch SFRs, die sich nur als RAM ansprechen lassen. Dafür wird der Offset auf jeden Fall benötigt.
Lesezeichen