Wat isn Dampfmaschin - Die Innereien eines Atmels ...

dino03

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

ich hab mal wieder Lust zum schreiben ;)
Da manche blutigen Newbies mit der Digitaltechnik und vor allem mit den Innereien des Mikrocontrollers so ihre Probleme haben werde ich mal ein paar Grundlagen vermitteln.

Die Links in diesem Beitrag verweisen auf die entsprechenden Quellen.

Also wat isn Dampfmaschin (frei nach der Feuerzangenbowle ;) - Pfeiffer mit 3 F - 1 vor dem EI und 2 hinter dem EI :D )

Wenn man früher mal mit nem Z80-Prozessor gearbeitet hat, dann kennt man das schon alles. Aber in der heutigen Zeit wird da meist ganz oberflächlich drüber weggearbeitet und ganz schnell irgendwas Java-mäßiges verzapft.



=== Die Architekturen ===

Fangen wir mal mit Rechnerarchitekturen an ... Da gibt es zwei unterschiedliche ...

1.) Die Von-Neumann-Architektur
Memory - Speicherwerk speichert sowohl Programme als auch Daten, welche für das Rechenwerk zugänglich sind.
...
Der von-Neumann-Flaschenhals der von-Neumann-Architektur bezeichnet den Sachverhalt, dass das Verbindungssystem (Daten- und Befehls-Bus) zum Engpass zwischen dem Prozessor und dem Speicher wird.

2.) Die Harvard-Architektur
Der Befehlsspeicher ist physisch vom Datenspeicher getrennt und beide werden über getrennte Busse angesteuert.
...
Ebenso basieren die Mikrocontroller der AVR-Reihe von Atmel auf der Harvard-Architektur.



=== internes Speichergedöns ===

Wir haben es also mit der Harvard-Architektur zu tun. Das merkt man auch schon beim internen Aufbau des Prozessors. Das Flash mit dem ausführbaren Programmcode und das SRAM bzw EEPROM für die zu verarbeitenden Daten.

AVR-Speicher.png
Ein kleiner Überblick aus dem Datenblatt

Der Flash-Speicher beinhaltet also nur das Programm und Tabellen/Konstanten, die für die Programmausführung benötigt werden. Er wird bei der Programmierung beschrieben und ist im normalen Betrieb nicht veränderbar.

Im SRAM werden die Daten abgelegt, die beim Programmablauf anfallen. Also zB für Berechnungen, Rücksprungadressen bei Unterprogrammaufrufen, usw. Kurz gesagt - alles was sich dauernd verändert.

Das EEPROM ist ein Mittelding zwischen SRAM und Flash (ganz grob). Es enthält Daten die bei der Programmausführung benötigt werden, hält aber den Speicherinhalt auch ohne Strom und kann während des normalen Betriebes verändert werden (aber auch beim Programmiervorgang). Hier werden zB Kallibrierdaten (zB für Meß-Sensoren), Log-Daten (GPS-Logger) und anderes abgelegt was man auch ohne Strom behalten möchte.


Was ist nun im Ruhezustand in den Speichern los ...

Wenn man einen neuen Atmel hat, dann sind im Flash und im EEPROM alle Bits mit 1 besetzt (also 0xFF(hex) oder 255 (dezimal) oder 0b11111111 (binär) ). Das hat mit dem Aufbau der Speicherstellen zu tun. Beim Löschvorgang werden Elektronen von der isoliert angebrachten Steuerelektrode des Speichertransistors entfernt. Damit ist dann dieses Bit auf 1. Beim Programmieren wird bei den Bits die 0 durch aufbringen (tunneln durch die Isolierschicht) von Elektronen erzeugt. Man kann beim Programmieren keine Einsen schreiben. Dafür müßte man also wieder löschen (beim Flash ganze Speicherseiten und beim EEPROM ganze Bytes). Aus dem Grund sieht man also bei neuen Atmels im Flash und EEPROM die ganzen 0xFF.

Das SRAM hat dagegen keinen definierten Zustand. Wenn man den Strom einschaltet, dann sind die Bits der Speicherstellen zufällig mit Einsen und Nullen besetzt. Das Bitmuster kann sich auch jedes mal ändern. Aus diesem Grund sollte man auch Variablen in einem Programm vor der ersten Benutzung auf einen definierten Anfangswert setzen. Einen Reset überlebt der Inhalt der SRAM-Zellen, einen Spannungsausfall jedoch nicht.



=== Die ALU - das Herz ===

Soviel erst einmal zu den Speicherbereichen im Atmel Mikrocontroller.
Jetzt weiter im Text mit dem Herz von allem. Der ALU (Arithmetisch Logische Einheit). Leider ist das bei Wikipedia nur sparsam erklärt. Darum mach ich das mal etwas länger ... :D

Also in der ALU läuft - kurz gesagt - die gesamte Datenverarbeitung ab. Sie berechnet (Addition, Subtraktion, Multiplikation, ...), vergleicht (Größer, Kleiner, Gleich, ...) und führt logische Operationen aus (AND, OR, NOT, XOR, ...). Ohne sie wäre der Atmel nur ein bischen Speicher mit nem Zähler dran.

Um Daten für diese Operationen zwischenzuspeichern stehen ihr die Register zur Seite. Beim Atmel sind diese Register ein Teil des SRAM. Das müssen sie aber nicht unbedingt sein. Weil das SRAM aber mit auf dem Prozessorchip sitzt hat sich das hier angeboten (Platz sparen und Aufbau einfacher machen).

AVR-ALU.png
Ein Bildausschnitt aus dem Datenblatt

Sie besitzt also zwei Eingangszweige wo die Daten eingefüttert werden und einen Ausgang wo die Daten nach der Verarbeitung wieder herauspurzeln. An die Eingangszweige werden je nach verwendeten Befehl die gewünschten Register angesetzt, die die zu verarbeitenden Daten enthalten. Wenn die Verarbeitung durchgeführt wurde landet das Ergebnis meist wieder in einem der Register, die die Eingangsdaten geliefert haben. Zusätzliche Informationen landen im Statusregister (Ergebnis war Null, Es gab einen Übertrag, Ergebnis war negativ, ...).

Die Informationen, die im Statusregister landen können bei einem bedingten Sprung im Programm verwendet werden. Zum Beispiel : springe wenn das Ergebnis Null war , oder : springe wenn es negativ war , oder : springe wenn es nicht Null war, ...

Wenn man einen Vergleich macht, werden eigentlich nur beide Eingangswerte voneinander abgezogen und wenn das Ergebnis Null ist, dann sind die Werte gleich. Bei negativ war das eine größer und bei nicht Null und nicht negativ war das andere größer. Das ist das ganze Geheimnis.



=== Die Steuerung ===

Was läuft eigentlich bei so einer Abarbeitung des Befehls ab ?

Wenn man den Strom anschaltet, dann setzt die Reset-Logik zuerst mal die internen Zähler des CPU-Kerns auf einen definierten Anfangszustand. Am wichtigsten ist hier der Programm-Counter (PC). Das ist eigentlich nur ein Zähler, der die Speicherstellen in Flash adressiert, die als Befehl abgearbeitet werden sollen.

Er fängt also im Normalfall bei der Flash-Zelle 0x0000 an den ersten Befehl in das Befehlsregister zu laden. Der Dekoder zerlegt den Befehlscode dann und gibt die Teile an die entsprechenden Einheiten in der Ablaufsteuerung weiter. Die Ablaufsteuerung sagt dann was intern alles passieren soll (Register in die ALU laden, springen, Register mit Wert laden, ... usw).

Die Befehle aus dem Flash werden stumpf und ohne nachdenken nacheinander geladen. Das heißt - wenn man irgendwo eine Tabelle im Flash hat und da reinspringt, dann werden diese Werte einfach als Befehle interpretiert. Woher soll der Prozessor auch wissen das es eine Tabelle ist ... :D Den Murks macht immer der vor der Tastatur ;) Der Prozessor führt das nur eins nach dem anderen aus. Ein Arbeiter ohne Hirn sozusagen. Die Intelligenz entsteht erst durch die richtige Anordnung der Befehle im Flash und das ist die Arbeit des Programmierers.

Wenn man jetzt einen Sprung ausführt, dann wird einfach die Adresse, die im Sprungbefehl mit eingebaut ist, in den Progammzähler geladen. Und schon gehts an einer anderen Speicherstelle im Flash mit der Befehlsausführung weiter.

Bei einem Unterprogrammaufruf sieht das ähnlich aus wie bei einem Sprung. Die Adresse des neuen Befehls wird in den PC geladen. Vorher wird aber die alte Adresse gesichert. Dafür hat man den Stack (Stapel). Der Stack wird vom Stackpointer (SP) verwaltet. Der Stack ist eigentlich nur ein Bereich, den man am Anfang seines Programmes im SRAM definiert. Unser Stapel ist aber nicht so aufgebaut wie ein Stapel auf dem Tisch sondern hängt sozusagen an der Decke. Wenn man etwas auf unseren Stapel packt, dann klebt man sozusagen ein Post-It an die Decke auf die bereits existierenden. Er wächst also von der Decke nach unten. Aus dem Grund zeigt der Stack-Pointer auch am Anfang auf die höchste SRAM-Adresse. Wenn man jetzt ein Unterprogramm aufruft, dann wird also die alte Adresse auf den Stack gelegt und der SP wandert um die enstsprechenden Speicherzellen nach unten (gegen 0x0000 des SRAM-Bereichs). Wenn man jetzt das Unterprogramm mit einem Return wieder verläßt, dann wird diese alte Adresse von Stack wieder zurückgeholt und die CPU macht an der Stelle weiter, an der sie vorher ins Unterprogramm gesprungen ist.


Das war also erst einmal "des Pudels Kern" :D - Das Innerste des Prozessors.

Das dranhängende Gebamsel (UART, SPI, Timer, ...) und Interrupts kommt dann später.
Wobei die Interrupts davon wohl als erstes erklärt werden.
 
Ein wenig Digitalkram ...

Jetzt gehts mit Digitalkram weiter.

=== Logikpegel, Flanken und Ausgänge ===

Zuerst mal ein wenig Logik-Kram ... die Pegel usw ... ich erkläre dabei den Normalzustand.

Wenn man eine Speicherstelle / einen Ausgang auf 0 setzt dann liegt dieser Ausgang auf GND (0V). Diesen Logikpegel nennt man auch Low oder L-Pegel.

Bei einer 1 hat man also genau das gegenteilige Ergebnis. Der Ausgang ist auf Vcc (der positiven Betriebsspannnung). Also auf +5V oder +3,3V oder so. Dieser Logikpegel nennt sich dann auch High oder H-Pegel. Soviel erst einmal ganz zu Anfang.


Jetzt zu den Flanken eines Signals. Es gibt zwei verschiedene Flanken ...

1.) positive Flanke (steigende Flanke) __---
Also der Pegel wechselt von Low nach High (oder von 0 auf 1). Die Ausgangsspannung steigt also.

2.) negative Flanke (fallende Flanke) ---__
hier wechselt der Pegel von High nach Low (oder 1 auf 0). Also sinkt hier die Ausgangsspannung.


Damit kennen wir jetzt also High-Pegel, Low-Pegel, positive Flanken und negative Flanken.


Jetzt gibt es auch noch Glitches :D Das sind eigentlich nix anderes als Störungen im normalen Signal. Es handelt sich hierbei um sehr kurze Impulse (Nanosekunden-Bereich oder kürzer) die durch Umschaltereignisse und Laufzeiten in den Gattern eines Bausteins entstehen. Sie sind unerwünscht und können einen bei der Fehlersuche in den Wahnsinn treiben. ;) Bei Logikanalysatoren gibt es dafür extra eine Erkennung damit man sie überhaupt erfassen kann. Bei den Atmels werden sie durch Zwischenspeicher an den Eingängen eliminiert. Aus dem Grund werden die Eingangspegel auch nicht sofort erkannt sondern immer um 1-2 CPU-Takte später.


Einen hab ich aber noch. Den Z-Pegel oder auch hochohmigen Ausgang (TriState).
Wenn man einen TriState-Ausgang hat, dann kann er ganz normal Low und High-Pegel abgeben aber er kann auch hochohmig geschaltet werden. Damit kann man diese Ausgänge zu einem Bus zusammenschalten. Das hat den Grund, weil sonst zusammengeschaltete Ausgänge mit Low und High-Pegel einen Kurzschluß verursachen können (GND und +5V) und sich in Rauch auflösen.


Und wenn wir schon dabei sind ... es gibt noch den OpenCollector-Ausgang.
Da besitzen die Ausgänge keine Gegentakt-Endstufe, die nach Vcc und GND schalten kann sondern nur den Transistor nach GND. Diese Ausgänge kann man auch gefahrlos zu einem Bus zusammenschalten. Ein Beispiel bildet hier der 1-Wire-Bus. Er braucht aber für einen definierten High-Pegel (+5V) noch einen Pull-Up-Widerstand der die Leitung nach Vcc (+5V) ziehen kann. Die Ausgänge können ja nur nach GND schalten.



=== Zahlensysteme ===

In der Computerei werden verschieden Zahlensysteme verwendet. Je nach Geschmack und Anwendungsfall wird bunt zwischen ihnen hin und ver gewechselt. Es werden hauptsächlich folgende verwendet ...

- Binärsystem/Dualsystem ( 0+1 ... Darstellung 0b10010110, 0b00111010, ... ) also Prefix 0b
- Dezimalsystem ( 0-9 ... Darstellung 255, 243, 14, ...) ohne Prefix
- Hexadezimalsystem ( 0-9A-F ... Darstellung 0xFF, 0x45, 0x3A, ...) mit Prefix 0x
- Octalsystem ( 0-7 ... Darstellung 034, 075, 03, ... ) mit führender Null (0)

Es ist einem Prozessor absolut egal mit welchem Zahlensystem man ihn füttert, da er intern sowieso Binär mit Bits arbeitet.

Dann gibt es noch die Länge einer Binär-Zahl ...

- Bit (nur eine Zelle)
- Nibble (4 Bit)
- Byte (8 Bit oder 2 Nibble)
- Word/Wort (16 Bit oder 2 Byte oder 4 Nibble)
- Doubleword/Doppelwort (32 Bit oder ...)
- Longword/Langwort (64 Bit oder ...)

Ein Prozessor arbeitet immer mit Integerzahlen (also Ganzzahlen). Die Vorzeichen und Fließkommazahlen sind lediglich Definitionen, wie welches Bit dieses Speicherinhalts verwendet werden soll. So gibt es zB für negative Zahlen das Zweierkomplement. Dadurch kann man in 8 Bit (einem Byte) die Zahlen von -128 bis +127 darstellen. Ohne diese Definition wären es 0 bis 255.

Jetzt etwas für Leute die meinen, die CPU wüßte was sie da im Register hat ... :D

folgende Darstellungen sind in der CPU absolut identisch ...

0b10011010 (binär)
-102 (Dezimal Zweierkomplement)
154 (Dezimal Integer)
0x9A (hexadezimal)
0232 (octal)
š (ASCII-Zeichen - je nach Zeichentabelle)

es sind lediglich andere Darstellungen des selben Inhalts im Byte.



=== Gatter und FlipFlops ===

Jetzt kommt wieder etwas Hardware ...

Gatter gibt es für jede logische Operation mit verschieden vielen Eingängen. Die Basis bilden dabei AND (UND), OR (ODER), XOR (Exclusiv Oder), NOT (Nicht / Inverter).

Ich möchte hier jetzt nicht unbedingt jede Logiktabelle aufführen. Dafür gibt es schon genug Seiten, die voll davon sind ...

eine kleine will ich aber doch machen :D


CodeBox Logik

B A | AND OR XOR NOT(A) NAND NOR
----------------------------------
0 0 | 0 0 0 1 1 1
0 1 | 0 1 1 0 1 0
1 0 | 0 1 1 1 1 0
1 1 | 1 1 0 0 0 0




FlipFlops sind eigentlich nichts anderes als Speicher. Es gibt flankengetriggerte und impulsgetriggerte. Die flankengetriggerten übernehmen bei einer Flanke am Takteingang den Pegel am Dateneingang und bei einem impulsgetriggerten wird der Pegel am Dateneingang so lange übernommen, wie der Takteingang auf entsprechendem Pegel ist. Da es aber auch positive und negative Flanken und L und H-Pegel gibt (wie bereits gelernt) gibt es damit auch vier verschiedene Triggermöglichkeiten.

Der Takt-Eingang T nennt sich manchmal auch CLK oder CK (Clock).

- Triggerung über L-Pegel
So lange wie der Takteingang auf L ist wird der Pegel auf dem Dateneingang übernommen. Bei H am Takt bleibt der letzte Zustand gespeichert.


CodeBox Logik

T D | Q
--------------
0 0 | 0 Bei Low an T wird der Pegel an D übernommen
0 1 | 1
1 x | n bei High an T bleibt der letzte Inhalt gespeichert. Egal was jetzt an D anliegt


- Triggerung über H-Pegel
identisch wie bei L nur das hier der Pegel am Daten-Eingang bei L-Pegel übernommen wird.


CodeBox Logik

T D | Q
--------------
1 0 | 0 Bei High an T wird der Pegel an D übernommen
1 1 | 1
0 x | n bei Low an T bleibt der letzte Inhalt gespeichert. Egal was jetzt an D anliegt


- Triggerung über positive Flanke
mit einer positiven Flanke (L->H) am Takteingang wird der Pegel am Dateneingang in das FlipFlop übernommen und gespeichert.


CodeBox Logik

T D | Q
--------------
0 x | n ein Low oder High-Pegel an T ändert nichts am gespeicherten Inhalt
1 x | n
_- 0 | 0 bei einer steigenden Flanke an T wird der Pegel an D übernommen
_- 1 | 1


- Triggerung über negative Flanke
und hier wird mit einer negativen Flanke der Dateneingang übernommen.


CodeBox Logik

T D | Q
--------------
0 x | n ein Low oder High-Pegel an T ändert nichts am gespeicherten Inhalt
1 x | n
-_ 0 | 0 bei einer fallenden Flanke an T wird der Pegel an D übernommen
-_ 1 | 1



das sollte erst mal genug Bit-Gepopel sein ... ;)
 
Dateikram und anderes Zeugs ...

Jetzt will ich mal ein wenig zu den Dateien erzählen, die da beim Compilieren eine Rolle spielen ...

Es gibt ja immer mal wieder Fragen wegen diesen .hex-Dateien usw ...

Also hier einmal die Entstehungsgeschichte ...
Als erstes das Assembler-Listing ...


CodeBox ASM

; ---------------------------------------
; Test-Projekt: blinkende LED an Port PB0
; ---------------------------------------
;
.include "m8535def.inc" ;Definitionsdatei laden
.cseg ;Beginn eines Code-Segmentes
.org 0 ;Startadresse=0
;
start: ldi r16,low(ramend)
ldi r17,high(ramend)
out spl,r16 ;Stackpointer auf
out sph,r17 ;RAM-Ende setzen
ldi r16,0b00000001 ;PortB: PB0 auf Ausgang
out ddrb,r16 ;setzen
clr r16 ;Anfangswert setzen
;
loop: out portb,r16 ;Daten an PortB ausgeben
rcall wait ;Warteschleife aufrufen
inc r16 ;Datenwert erhöhen
rjmp loop ;Schleife neu beginnen
;
; Warteschleife (ungefähr 500ms)
;
wait: ldi r19,5 ;r19, r18 und r17
clr r18 ;ergeben zusammen
clr r17 ;einen 3-Byte-Zähler
wait1: dec r17 ;niedrigstes Byte -1
brne wait1 ;0 erreicht? nein -> Schleife
dec r18 ;mittleres Byte -1
brne wait1 ;0 erreicht? nein -> Schleife
dec r19 ;höchstes Byte -1
brne wait1 ;0 erreicht? nein -> Schleife
ret ;Schleifenende, Rückkehr

Aus dieser Text-Datei (dem Quellcode) macht das AVR-Studio folgendes ...


CodeBox HEX

:020000020000FC
:100000000FE512E00DBF1EBF01E007BB002708BBD4
:1000100002D00395FCCF35E0222711271A95F1F77E
:0A0020002A95E1F73A95D1F708950B
:00000001FF

Das ist diese ominöse .hex-Datei. Das ist eigentlich nichts anderes als eine
reine Text-Datei in der die Binärdaten für das Flash als Hex-Werte drinstehen.
Das ganze nennt sich "Intel-Hex-Format".
Jetzt zerleg ich es mal so wie auf Wikipedia ...

: 02 - 0000 - 02 - 0000 - FC
: 10 - 0000 - 00 - 0F E5 12 E0 0D BF 1E BF 01 E0 07 BB 00 27 08 BB - D4
: 10 - 0010 - 00 - 02 D0 03 95 FC CF 35 E0 22 27 11 27 1A 95 F1 F7 - 7E
: 0A - 0020 - 00 - 2A 95 E1 F7 3A 95 D1 F7 08 95 - 0B
: 00 - 0000 - 01 - FF

Also 42 Bytes ab der Adresse 0x0000 für das Flash des Atmel.

So viel zu den Ausgabedaten des Compilers (ob jetzt Bascom, C oder Assembler).
 
Hi,

dass es ja keiner wagt, hier zu meckern - DER muss uns erhalten bleiben...;):D


Grüsse,

Michael
 

Ü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)