Register beim Mega48 - Memory Mapped

dino03

Aktives Mitglied
27. Okt. 2008
6.760
20
38
Sprachen
  1. BascomAVR
  2. Assembler
Hallo alle,

ich hab gerade echt an meinen Programmierkünsten gezweifelt.
Ich wollte bei einem ATmega48-20PU den USART0 einstellen und der
Assembler hat sich geweigert den Code zu übersetzen. Er hat immer gemeldet
das die Register-Adressen aus dem m48def.inc "Out Of Range" sind. So eine
Grütze. Vor allem weil ich meinen Sourcecode noch mit dem Datenblatt
abgeglichen habe. Da steht nämlich folgendes drin ...


CodeBox ASM

USART_Init:
; Set baud rate
out UBRRnH, r17
out UBRRnL, r16
; Enable receiver and transmitter
ldi r16, (1<<RXENn)|(1<<TXENn)
out UCSRnB,r16
; Set frame format: 8data, 2stop bit
ldi r16, (1<<USBSn)|(3<<UCSZn0)
out UCSRnC,r16
ret


Ich sach nur: DAS BEISPIEL AUS DEM DATENBLATT KÖNNT IHR KNICKEN !
:mad: :mad: :mad: :mad:

Weiter hinten bei der Register-Summary steht nämlich folgendes ...
Code:
(0xC6) | UDR0   | USART I/O Data Register 191
(0xC5) | UBRR0H | USART Baud Rate Register High 195
(0xC4) | UBRR0L | USART Baud Rate Register Low 195
(0xC3) | Reserved | – – – – – – – –
(0xC2) | UCSR0C | UMSEL01 UMSEL00 UPM01 UPM00 USBS0 UCSZ01 /UDORD0 UCSZ00 / UCPHA0 UCPOL0 193/208
(0xC1) | UCSR0B | RXCIE0 TXCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80 192
(0xC0) | UCSR0A | RXC0 TXC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0 191
und im Anhang zu der Tabelle ...

4. When using the I/O specific commands IN and OUT, the I/O addresses 0x00 - 0x3F must be used. When addressing I/O
Registers as data space using LD and ST instructions, 0x20 must be added to these addresses. The ATmega48/88/168 is a
complex microcontroller with more peripheral units than can be supported within the 64 location reserved in Opcode for the
IN and OUT instructions. For the Extended I/O space from 0x60 - 0xFF in SRAM, only the ST/STS/STD and LD/LDS/LDD
instructions can be used.
Ihr könnt die Beispiele also beerdigen und alles mit STS/LDS umschreiben
und damit die Register wie eine Speicherstelle ansprechen. Damit haben
sich so schöne Befehle wie sbis/sbic zum Testen von einzelnen Bits in den
Registern auch erledigt. SO EINE SCH.... :mad: :banghead: :banghead:

Ich habe also das zweifelhafte Vergnügen, meine gesamten Routinen für
die USART auf Memory-Mapped umzuschreiben... Vielen Dank auch

Ach ja, das betrifft mindestens die ATmegas 48, 88, 168 und 328.
Auf jeden Fall alle extended Register.

Keinen Bock mehr. Mal sehn wann ich Lust hab da weiter zu tippen :D
Erst mal wieder abkühlen und dann wolln wir mal sehn.

Mein Problem das ich jetzt habe: Eventuell fressen programmiertechnische
Klimmzüge die zusätzlichen 4MHz Taktfrequenz (20MHz Quarz) wieder auf.
Da werde ich wohl einiges an Gehirnschmalz investieren müssen. Pech ist es
auch, das es beim Speicherzugriff mit "Data Direct With Displacement" nur
6Bit lange Distanzen gibt, die man zum Y- oder Z-Register addieren
lassen kann. Das wird ein Spaß! :eek:

Gruß
Dino
 
Hi Dino,

ich hoffe du hast dich inzwischen wieder etwas beruhigt ;) Wenn nicht, dann hilft vielleicht :cheers: Aber dann erst wieder morgen programmieren, gell :D.

Das mit der unterschiedlichen IO-Register-Adressierung bei verschiedenen Mikrocontrollern ist schon ziemlich nervig, so ist der Assemblercode nicht immer kompatibel und man muss daran "rumbiegen". Und ausgerechnet wurden dann genau die Register, die man gerade benötigt in den höheren IO-Bereich gelegt ... und dann nutzt man bei denen noch Bitadressierung :banghead:

Die Assembler-Programmierer müssen da halt leider durch :rolleyes:

Schönen Abend noch,
Dirk
 
Hi Dirk,

ich hoffe du hast dich inzwischen wieder etwas beruhigt ;) Wenn nicht, dann hilft vielleicht :cheers: Aber dann erst wieder morgen programmieren, gell :D.
Der Dampf ist wieder runter :D
Nen kühles Bier hab ich aber leider nicht mehr :(
Und ne ganze Flasche Wein köpfen ist mir zu viel ;) Aber danach
merkt man bestimmt nix mehr :D

Das mit der unterschiedlichen IO-Register-Adressierung bei verschiedenen Mikrocontrollern ist schon ziemlich nervig, so ist der Assemblercode nicht immer kompatibel und man muss daran "rumbiegen". Und ausgerechnet wurden dann genau die Register, die man gerade benötigt in den höheren IO-Bereich gelegt ... und dann nutzt man bei denen noch Bitadressierung :banghead:
Wenn die Beispiele im Datenblatt wenigstens stimmen würden, dann wäre
ich schon glücklicher gewesen. :(

Die Assembler-Programmierer müssen da halt leider durch :rolleyes:
Dafür rennt es aber immer noch schneller als nen Bascom oder C Programm :D
Ich hab da im Forum mal nen Schnipsel von Markus oder Thomas oder wem
auch immer gesehen. Da waren mehr POPs und PUSHs drin als eigentlicher
Nutz-Code :D Da ist selbst ein hingestricktes Assembler-Programm ja noch
schneller :cool:

Da werde ich wohl so viel wie möglich auf Interrupts auslagern müssen um nicht so
viel Status-Polls durchführen zu müssen.

Gruß
Dino
 
Hallo Oskar,

ja aber so wie ich das verstanden habe geht es in deinem Beitrag um das "Problem", dass man das Bit URSEL ändern muss, um entweder auf UCSRC oder UBRRH zugreifen zu können.

Befinden sich Register im oberen Adressbereich, müssen diese entsprechend durch lds, sts adressiert werden. in, out sbic usw. funktioniert hier nicht mehr, das ändert auch ein anderes Include-File nicht?!

Grüße,
Dirk
 
Hi Oskar,

Hallo @d...
schau mal hier:
U(S)ART wird hier erklärt:
Ist nicht einfach.......
Weil was verdreht wird...aber schau mal selbst:
http://www.avr-praxis.de/forum/showthread.php?t=178
Thread vom 22.09.2009 runterscrollen.
Da ist genau Dein Problem und der Lösungsansatz beschrieben.
Schön wärs, wenn es so einfach wär ;)
Bei mir läuft der USART ja auf nem ATmega32 ohne Probleme in Assembler.
Die Include-Datei ist bei mir auch korrekt. Aber wie ich in der Include nachgesehen
habe, da waren hinter den Adress-Definitionen für die Register des USARTs
Einträge, das die Register nicht IO-Mapped sondern Memory-Mapped sind.
Daher kann ich nicht mehr die Befehle OUT, IN, SBIC, SBIS, ... für den
IO-Bereich verwenden so wie ich es im Mega32 gemacht habe. Ich muß jetzt
alle Routinen umschreiben.
Wenn ich jetzt ein Register setzen will müßte das ungefähr so aussehen ...


CodeBox ASM

ldi r16,0x80 ; Wert für das Register UBRRH in r16 laden
sts UBRR0H,r16 ; Wert in die Memory-Zelle von UBRR0H schreiben

Es geht also nur mit STS, LDS, LDD, ... (den SRAM-Befehlen)
Damit habe ich aber leider auch keinen direkten Zugriff mehr auf die Bits.
Ich müßte erst mit LDS die SRAM-Zelle lesen, dann den Inhalt in einem
temporären Register (z.B. r16) bearbeiten und dann mit STS wieder in
die entsprechende SRAM-Zelle des Funktions-Registers zurückschreiben.

Das Problem: Die Memory-Befehle verbrauchen nicht einen Taktzyklus
sondern mindestens 2 Taktzyklen. Wenn ich also viele Memory-Operationen
machen muß bleiben von meinen 20MHz Prozessortakt effektiv evtl nur
noch 15MHz übrig.

Ich hab extra den Mega48 genommen, weil der statt der üblichen 16MHz
nen 20MHz-Quarz verkraftet. Und bei nem Analyzer für I2C oder 1-Wire
brauch ich alles was drin ist um die Daten einzulesen und zu verarbeiten.

Wenn man sich das Datenblatt ansieht (Register-Summary) dann sind da
die Adressen der Port-Register (DDRB, PORTB, ...) auch IO-Mapped
(Adresse nicht in Klammern) und Memory-Mapped (Adresse in Klammern).
Die Register, die für die TIMER und USART zuständig sind liegen aber
zum größten Teil oder vollständig im extended Bereich. Und da ist es
wegen der Abwärtskompatibilität alles nur noch Memory-Mapped.
Dadurch kann ich keine Befehle verwenden, die in einem Takt-Zyklus
direkt Bits aus den Registern abfragen können. Ich muß immer den Umweg
über ein Register (r0..r31) gehen und die SRAM-Operationen fressen noch
zusätzliche Performance.

Ärgerlich ist auch, das man z.B. nicht das Y- oder Z-Registerpaar mit 0x0000
laden kann und dann mit Displacement arbeiten kann. Dafür müßte man
8Bit zu dem Wert in dem Registerpaar addieren können. Die entsprechenden
Befehle verkraften aber nur 6Bit und das reicht leider nicht aus um den vollen
extended Bereich zu überstreichen. Also kann ich die Register im extended
Bereich nur mit absoluter SRAM-Adressierung ansprechen.

Die Adressierungsarten sind in der Befehlserklärung von ATMEL vorne recht
gut abgebildet.

Na mal sehen. Wenn es läuft, kann ich den Sourcecode ja mal hier reinstellen.
Dann habt ihr was zum diskutieren :D :D

- - - - - - - Änderung - - - - -
Ich hab mir gerade nochmal Gedanken gemacht. ...
Wenn ich ein Bit in einem Register ändern möchte dann kostet mich das 5 Taktzyklen
(Memory laden, Bit ändern, Memory zurückschreiben) gegenüber 1 Taktzyklus bei
IO-Mapped Registern :mad:
Der ATmega8 ist aber zum Glück Pinkompatibel zum ATmega48. Leider hat er
nicht diese schönen PinChangeInterrupts :( Das müßte ich dann entweder über ne
Zusatzschaltung auf INT0/INT1 bringen oder über Polling. Polling frißt mir aber auch
wieder Performance. :(

Gruß
Dino
 
Zugriffzeiten auf dseg

Hallo @dino...
die Zugriffzeiten auf das .dseg sind auch noch doppelt so lang, wie auf das .cseg, das hatte ich mir für die Erreichung möglichst großer Verzögerungszeiten zunutze gemacht. (Hierbei wird ja mit jeder "Nanosekunde" schon beim Laden gefeilscht.)
OK.
Erst im Deklarationsteil die Adressen im SRAM per .BYTE-Anweisung reservieren, im "Hauptprogramm" über ein Label (laden-dseg zum Beispiel)
die Ladevorgänge über nur ein und dasselbe Temporärregister (r16 bis r32, besser weniger, weil evtl. sonst schon bei Verwendung nur eines "Pointers" eine "Doppelbelegungs"-Warnung beim Assemblieren kommt,) nun den Bereichen zuordnen mit "sts", hinterher in der Zeitschleife zunächst dann wieder mit "lds" "umladen" auf irgendein oder, falls nötig mehrere "temps" auf das .cseg.

Hier wird dann deutlich, daß damit zwar Temporärregister gespart werden können, das aber auf Kosten des Umfanges des Codes und, wie gesagt, der Zugriffszeit geht.

Daß bei bestimmten MCUs das Konfigurieren einiger doch wichtiger Register nur über die SRAM-"Geschichte" läuft, ist mir neu.
Da diese Register doch eigentlich nicht dauernd geändert werden, also die "Config" z.B. des U(S)ARTs einmal am Anfang gemacht wird,
dürfte das doch für das eigentliche Programm hinterher kaum eine Rolle spielen.

Auch ist an der "Architektur" wohl noch etwas nachträglich geändert worden, wenn ich mir z.B. die Memory-Adressbereiche des ATMega8535 ansehe.

Es wurde wohl bewußt auch das UBBRH nach vorne geschoben, dann erst sollte das UBBRL beschrieben werden, anders als beim Einrichten des Stacks wohl, weil man normalerweise keine so großen Baudratenteilerwerte braucht, so daß diese Werte nicht volle 16 Bit beanspruchen würden. (Es sei denn, man arbeitet vielleicht mit 75 Baud oder mit einer hohen Taktfrequenz.) Damit ist dann im UBBRH noch etwas "Luft".

Deswegen wohl - aus nachträglicher "Architektur"-Akrobatik heraus - auch der "Umweg" des Ansprechens eines U(S)ART Registers über ein Bit eines anderen.

Das sind dann - wenn ich das Datenblatt richtig interpretiert hatte - sogenannte "atomic" Ladevorgänge, die unmittelbar innerhalb bestimmter Taktzyklen erfolgen sollten.

Zur Sicherheit hatte ich den U(S)ART-Ladevorgang nochmals im besagten Programmbeispiel dahintergeschrieben, um definierte Verhältnisse zu schaffen.


Gruß von Oskar01
 
Ein UART-Beispiel für den ATmega168 mit Memory-Mapped Registern

Hallo ,

ich hab mal ein wenig mit Google gesucht und folgendes gefunden ...

http://www.mikekohn.net/micro/atmel_rs232.php

Da ist unten auf der Seite ein kleines Stück Assembler-Code für
den ATmega168 in dem die Register Memory-Mapped angesprochen
werden. Genau das was ich gesucht habe ;) Das werde ich die
nächstem Tage mal für meine Zwecke anpassen. Die Prozzis
ATmega48,88,168 sind vom Register-Mapping ja glücklicherweise
identisch. :)

Es geht vorran - alles wird gut :D :D

Dann wird erst mal mit polling gearbeitet und dann der UART langsam
auf Interrupts umgestellt.

Gruß
Dino
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)