Forum: Mikrocontroller und Digitale Elektronik Organisation von AVR-Projekten


von Jan Schirrmacher (Gast)


Lesenswert?

Hallo liebe Mitstreiter,

habe vor ein paar Wochen mit diesem kommodigem AVR-Assembler begonnen 
und erwecke nun einige Hardwarekomponenten (die üblichen Verdächtigen) 
zum Leben.

Aus der Hochsprachenprogrammierung habe ich noch die dumme Angewohnheit 
meinen Code auf Wiederverwendbarkeit und schlanke Schnittstellen zu 
trimmen, sodass ich keine Monolithen bekomme und nie mit Codekopieren 
arbeiten muss.
Das ist in Assembler gar nicht so leicht, insbesondere wenn kein 
Betriebsystem und damit keine Speicherverwaltung vorhanden ist wie auf 
meinen ATmega-Systemen.

Wenn ich nun Assembler-Dateien, z.B. für UART-Zugriff und 
Display-Ansteuerung für Wiederverwendbarkeit gestalte, habe ich 
Schwierigkeiten und erhoffe hier ein paar Hinweise von Euch zur 
Gestaltung von Projekten mit mehreren Dateien.

Beispiel: ich habe Basisroutinen zur Ringpufferverwaltung auf die die 
UART-Routinen aufbauen (ich arbeite mit blockierendem Senden und 
gepuffertem Empfang). Die UART-Routinen sollen wiederum im Hauptprogramm 
verwendet werden, welches aber möglicherweise selber auch 
Ringpufferroutinen verwendet. In C und C++ und ähnlichen bindet jedes 
"Modul" das ein, was es benötigt und Präprozessor oder ein anderer 
Mechanismus verhindert doppeltes Kompilieren.

Im Moment muss ich immer auf die Reihenfolge der includes von 
asm-Dateien achten und teilweise deren defs in eigene .inc-Dateien 
auslagern, damit ich diese .inc-Dateien oben im Hauptprogramm und die 
asm-Dateien weiter unten einbinden kann.

Gibt es dazu Hinweise und Verfahren, die sich bewährt haben, vielleicht 
ähnliche Krücken wie in C mit #ifndef MEINEDATEI_H usw.?

Grüße, Dank und viel Spaß

von Sven P. (Gast)


Lesenswert?

Nunja, wenn ich bisher ein Projekt in Assembler aufgesetzt habe, dann 
meistens immer aus dem Grund, das letzte Bisschen Geschwindigkeit und 
Rechenzeit herauszunehmen.
Allein daher wars dann eben schon unpraktisch, 'generische' Module zu 
schreiben und wieder Tempo zu verschenken.

Kurzun: Meistens immer ein langes ASM-Listing :->

von Purzel H. (hacky)


Lesenswert?

Man kann mit include dateien arbeiten... {$include mymath.asm} oder so.

von Assemblerfreak (Gast)


Lesenswert?

Jan Schirrmacher schrieb:
> Wenn ich nun Assembler-Dateien, z.B. für UART-Zugriff und
> Display-Ansteuerung für Wiederverwendbarkeit gestalte, habe ich
> Schwierigkeiten und erhoffe hier ein paar Hinweise von Euch zur
> Gestaltung von Projekten mit mehreren Dateien.

Schau Dir mal amforth (amforth.sf.net) an, dort werden einige viele
Assemblersourcen nach Bedarf zusammengestellt. Die Schnittstelle 
zwischen
den Modulen ist relativ einfach als Stack ausgebildet. Wiederverwendung
und austauschbare Module sind ebenfalls an Bord.

von Rolf Magnus (Gast)


Lesenswert?

Wenn du in C genau das kannst, was du willst, warum schreibst du deine 
Programme dann stattdessen in Assembler?

von O. D. (odbs)


Lesenswert?

Warum wird immer wie selbstverständlich die Annahme gemacht, daß man 
seine Code-Module von vornherein möglichst generisch gestalten und auf 
Wiederverwendbarkeit trimmen sollte? Steht das in irgendwelchen 
Lehrbüchern, die nicht hinterfragt werden?

Ich halte das für einen großen Irrtum und einen Hauptgrund für 
aufgeblasene, fehlerträchtige und ineffiziente Software.

Insofern schließe ich mich meinen Vorrednern an, gerade wenn es um 
Assembler-Programmierung geht. ASM-Codeschnipsel sind per definitionem 
weder portabel noch generisch. Was nicht heißt, daß man nicht aus einem 
alten Projekt bewährte Codesequenzen in ein neues kopieren und dort 
anpassen sollte.

von Sven P. (Gast)


Lesenswert?

Ist doch meine Rede.

von spess53 (Gast)


Angehängte Dateien:

Lesenswert?

Hi

Hier mal mein Ansatz am Beispiel Dog-Grafik-LCDs.

Für die ASM-LIB existiert eine Konfigurations-Datei in der alle 
notwendigen Konstanten festgelegt und die verwendeten Unterprogramme 
freigeschaltet werden. Diese wird in das Projektverzeichnis kopiert, 
konfiguriert und am Anfang des Hauptprogramms mit include eingebunden. 
Die ASM-Datei befindet sich in einen anderen Verzeichnis, das mit 
'Additonal include path' für den Assembler sichtbar ist.

MfG Spess

von Jan Schirrmacher (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Wenn du in C genau das kannst, was du willst, warum schreibst du deine
> Programme dann stattdessen in Assembler?

ooch, ich finde maschinennahe Sachen sehen in Assembler besser aus. 
Beispielsweise sind die verschiedenen Bitroll-Befehle kaum unterstützt. 
Außerddem kann man in Assembler sehr wohl strukturiert programmieren. 
Das hängt aber ein wenig an einer eventuell vorhandenen 
Betriebsystemstruktur ab. Habe solche Systeme in jungen Jahren 
entwickelt.

Aber hauptsächlich finde ich AVR so schön Back-To-The-Roots. Da passt 
eben Assembler. Aber dein Einwand ist natürlich prinzipiell berechtigt.

von Jan Schirrmacher (Gast)


Lesenswert?

Oliver Döring schrieb:
> Warum wird immer wie selbstverständlich die Annahme gemacht, daß man
> seine Code-Module von vornherein möglichst generisch gestalten und auf
> Wiederverwendbarkeit trimmen sollte? Steht das in irgendwelchen
> Lehrbüchern, die nicht hinterfragt werden?
>
> Ich halte das für einen großen Irrtum und einen Hauptgrund für
> aufgeblasene, fehlerträchtige und ineffiziente Software.

Das steht sehr wohl in Lehrbüchern drin. Und Assembler ist nicht 
gleichbedeutend mit Unstrukturiert. Die Strukturen sind eben bloß nicht 
portierbar.

von Ronny (Gast)


Lesenswert?

Dein Problem rührt einfach daher, dass der AVR Assembler nur ein recht 
einfacher Assembler ist. Mit dem AVR-GCC kann man sehr wohl mehrere 
Module getrennt assemblieren und dann zu einem einzigem ELF oder HEX 
zusammen linken.

Symbole kann man dann in einem Modul (glaub per 'public') auch nach 
aussen sichtbar machen und von wo anders her aufrufen. Schau dir am 
besten mal die Man-Pages zum AVR-GCC an.

Einziger Stolperstein ist hier, dass der Linker immer noch den 
Einsprungpunkt in der C-Startup Funktion vermutet. Aber das liess sich 
auch deaktivieren, müsste nochmal nachschauen wo das war.

Wenn man meist auf dem selben AVR arbeitet, kann es schon Sinn machen 
die gut optimierten Assembler Routinen in ein Modul zu schieben und dann 
per #define abhängig vom konkret verwendeten AVR festzulegen welcher 
Code erzeugt wird. Mit jedem neuem AVR wächst dann das Modul-Listing 
eben etwas.

Gruß,

Ronny

von horst (Gast)


Lesenswert?

> Warum wird immer wie selbstverständlich die Annahme gemacht, daß man
> seine Code-Module von vornherein möglichst generisch gestalten und auf
> Wiederverwendbarkeit trimmen sollte? Steht das in irgendwelchen
> Lehrbüchern, die nicht hinterfragt werden?

Na endlich spricht das mal jemand an! Die meisten Projekte haben nämlich 
immer wieder etwas andere Anforderungen an das konkrete Modul. Da fährt 
man einfach dreimal besser, wenn man den Code kopiert und nicht bloss 
einbindet. Insbesondere treten so in alten Projekten nicht plötzlich 
Bugs aufgrund von Änderungen in den Bibliotheken auf.

Natürlich, wenn man am Anfang die Module perfekt durchplant und sehr 
flexibel gestaltet, dann sollten weder Änderungen an den Bibliotheken 
noch Kompatibilitätsprobleme mit älteren Projekten auftreten. Aber jeder 
hier kennt die Grenzen von Vorausplanung (und -sehung) sowie 
Bugfreiheit.

Und Assemblerprojekte zu modularisieren ist sowieso ein Widerspruch in 
sich - wer heute auf Mikrocontrollern in Assembler programmiert, der 
will ja gerade maximale Effizienz und/oder exakt vorhersehbares 
Zeitverhalten. Das beisst sich aber mit generischen Schnittstellen ganz 
gewaltig.

von Markus M. (adrock)


Lesenswert?

Hi,

kann auch nur WinAVR empfehlen, arbeitet mit AVR Studio zusammen (wenn 
man das denn will) und man kann ASM und C kombinieren.

In meinem aktuellen Projekt (12x12 LED-Matrix mit Software PWM und 
diversen auf dem AVR selbst berechneten Effekten) habe ich im C-Programm 
mehr die Steuerfunktionen und Berechnungen.

Im ASM Teil habe ich die Sachen, die oft aufgerufen werden und Schleifen 
beinhalten (PWM, kopieren von Speicherbereichen, Linien zeichnen etc.).

Zwangsweise ergeben sich zum C-Programm entsprechende Schnittstellen die 
auch ein paar Zyklen kosten (Register auf Stack sichern etc.), auch habe 
ich einige Programmteile ziemlich allgemein gehalten bzw. paramtrierbar 
gemacht.

Aber ich schätze alles in allem dürfte der Vorteil durch direkten 
ASM-Code noch min. Faktor 2 sein was auf einem µC schon einiges 
ausmacht.

Ciao...
Markus

von GefährlichesHalbwissen (Gast)


Lesenswert?

Markus M. schrieb:
> kann auch nur WinAVR empfehlen, arbeitet mit AVR Studio zusammen (wenn
> man das denn will) und man kann ASM und C kombinieren.

Sehr gut, so langsam wird mir der Hintergrund klarer. Der AVR-Assembler 
des AVR-Studio arbeitet ohne Linker (da er eh keinen Code zu relozieren 
hat) und daher funktioniert Modularisierung auf Linker-Ebene sowieso 
nicht.

habe mich auch schon gefragt, wie man dann C und Assembler mischen kann 
(ausser inlne Assembler) ohne Linker. Aber der Hinweis mit WinAVR ist 
interessant in diesem Zusammenhang, da ich über kurz oder lang die 
Gurken auch mal in C programmieren werde.

Dann auch für die Hinweise der anderen Poster. Die Diskussion über den 
Sinn des Assemblerprogrammierens ist berechtigt und ich sehe auch das 
Problem der Codeanpassung, z.B. an andere Port-Konfigurationen, das 
strukturiert nur aufwändig zu realisieren ist.

Wahrscheinlich denke ich zu softwarelastig. Mir ist gerade eingefallen, 
dass die AVRs recht billig sind und daher eine Modularisierung auf 
Hardwareebene ebenfalls in Frage kommt. So könnte ich mein LCD-Modul 
einfach mit einem ATTiny ausstatten und ein simples SPI-Interface 
implementieren mit einem eigenen Softwareprotokoll und schon wäre die 
Sache einfacher in andere Projekte zu integrieren.

Haach. Das bringt schon Spaß mit diesen kleinen Chips.

von Peter D. (peda)


Lesenswert?

Ich finde modulare Programmierung schon sehr sinnvoll.
Z.B. beim LCD möchte ich mir nicht vorschreiben lassen, welche Pins ich 
nehmen soll, da man dann oft die Spezialfunktionen (UART, PWM, ADC, ...) 
verliert.
Da nehme ich einfach nen Universalcode für beliebige Pins:
http://www.mikrocontroller.net/attachment/30300/lcd_drv.zip

Auch wird durch die Modularisierung die Programmierung deutlich leichter 
und fehlersicherer.
Ein einmal entwickelter Modul wird benutzt und gut is.


Programme über 2kB möchte ich aber nicht mehr in Assembler proggen 
müssen, das ist mir deutlich zu aufwendig.
C-Compiler sind garnicht so schlecht, etwa 5..20% Overhead bezüglich 
Größe und Geschwindigkeit ist doch kein großer Nachteil.
Die 5..20% gelten aber nur für erfahrene Assemblerprogramierer. 
Assembleranfänger erreichen oft das Gegenteil, d.h. größeren und 
langsameren Code als der C-Compiler.

Was nützt es, einige Befehle einzusparen um damit bezogen auf das 
Gesamtprogramm 0,1% CPU-Last weniger zu haben. Es ist einfach nur 
vergeudete Arbeitszeit.


Peter

von Rene B. (themason) Benutzerseite


Lesenswert?

@oliver

>Ich halte das für einen großen Irrtum und einen Hauptgrund für
>aufgeblasene, fehlerträchtige und ineffiziente Software.

Das Stimmt so nicht ganz. Aufgeblasene Software hat man doch ohnehin 
meist "nur" auf dem PC, wo es eben nicht auf ein Megabyte genau ankommt. 
Beim AVR hat man eben aber kein Megabyte. Und ich behaupte mal das wenn 
man sich die Schnittstellen seiner Module vernünftig zurechtlegt dann 
spart man doppelt und dreifache Arbeit, selbst wenn es etwas mehr Code 
kostet.
Und wie Peter schon erwähnte, bei großen Projekten ist Assembler einfach 
zu aufwendig, selbst wenn man dann vllt ein paar Prozent eingespart hat.
Zumal hat man bei Assembler eben nicht die Möglichkeit den Code für 
einen anderen Prozessor (bzw andere Prozessorfamilie) einzusetzen und 
muß dann wirklich alles neu schreiben.
Assembler ist dann eine Alternative, wenns auf jeden Taktzyklus oder 
jedes Byte ankommt.

von Gastino G. (gastino)


Lesenswert?

Oliver Döring schrieb:
> Warum wird immer wie selbstverständlich die Annahme gemacht, daß man
> seine Code-Module von vornherein möglichst generisch gestalten und auf
> Wiederverwendbarkeit trimmen sollte? Steht das in irgendwelchen
> Lehrbüchern, die nicht hinterfragt werden?

Das zeichnet einfach die Entwickler aus, die etwas weiter als bis zum 
aktuellen Projekt denken. ;)
Wiederverwendbarer Code spart nicht nur Arbeitszeit, er sorgt auch für 
bessere getestete Software und - was immer wieder vergessen wird - er 
ist oft deutlich besser strukturiert und damit besser wartbarer. 
Außerdem macht sich der Entwickler vorher eher Gedanken über einen 
sinnvollen Aufbau.

> Ich halte das für einen großen Irrtum und einen Hauptgrund für
> aufgeblasene, fehlerträchtige und ineffiziente Software.

Nö. Aufgeblasen und fehlerträchig wird es erst, wenn der Entwickler 
nicht verstanden hat, wie weit die Wiederverwendbarkeit sinnvoll 
getrieben werden kann. Und auch dann, wenn sich der Entwickler keinerlei 
Gedanken um Wiederverwendbarkeit macht und einfach drauflos 
programmiert.

Ich versuche meinen Code auch immer so zu strukturieren und die 
Schnittstellen von Funktionen so zu gestalten, dass ich die auf 
möglichst vielseitige Art in verschiedenen Projekten nutzen kann.
Der Code ist deswegen kein bisschen aufgeblasen.

von spess53 (Gast)


Lesenswert?

Hi

>C-Compiler sind garnicht so schlecht, etwa 5..20% Overhead bezüglich
>Größe und Geschwindigkeit ist doch kein großer Nachteil

Ich habe hier noch keinen disassemblierten C-Code gesehen der diese 
Bedingung erfüllt hätte.

>Programme über 2kB möchte ich aber nicht mehr in Assembler proggen
>müssen, das ist mir deutlich zu aufwendig.

Wenn du davon 1,5k aus der Schublade holen kannst, kein Problem.

>Zumal hat man bei Assembler eben nicht die Möglichkeit den Code für
>einen anderen Prozessor (bzw andere Prozessorfamilie) einzusetzen und
>muß dann wirklich alles neu schreiben.

Das hat sich auch erledigt, wenn du in C auf irgendwelche IO-Register 
zugreifst.

MfG Spess

von Rene B. (themason) Benutzerseite


Lesenswert?

>Das hat sich auch erledigt, wenn du in C auf irgendwelche IO-Register
>zugreifst.

Wenn der Code wiederverwendbar werden soll benutzt man i.d.R. Makros die 
man bei Wiederverwendung innerhalb der selben Prozessorfamilie einfach 
nur anpasst.

Beispiel 7-Segmentanzeige :

#define LED7_DATA_PORT  PORTA
#define LED7_DATA_DDR   DDRA
#define LED7_STRB_PORT  PORTD
#define LED7_STRB_DDR   DDRD
#define LED7_STRB_PIN   4
#define LED7_SIZE       3
#define LED7_STRB_MASK  0x70


#define LED7_DATA_INIT  LED7_DATA_DDR  = 0xff;
#define LED7_STRB_INIT  LED7_STRB_DDR |= LED7_STRB_MASK;

#define LED7_STRB(x)    LED7_STRB_PORT = \
                          (LED7_STRB_PORT & ~LED7_STRB_MASK) | \
                          (1 << (LED7_STRB_PIN + (x)))
#define LED7_DATA(x)    LED7_DATA_PORT = (x)

void v7SegInit (void);
void v7SegDoTimer (void);
void v7SegSet (char cSeg, unsigend char cDigits);


So ähnlich könnte ein 7-Segment-Modul-Header aussehen.
Der eigentliche Quellcode lässt sich für alle Prozessoren der selben 
Familie verwenden. Außerdem kann man durch Anpassung der Makros 
LED7_DATA und LED7_STRB die Anzeige auch über einen I2C Bus, ein 
Schieberegister oder dergleichen für den Anschluß realisieren.

Wenn das ganze z.b. für einen ARM7 portiert werden soll, passt man 
einfach nur die Makros LED7_DATA, LED7_DATA_INIT, LED7_STRB und 
LED7_STRB_INIT an.

Bei komplexeren Sachen die die direkte Hardware des Prozessors betreffen 
wie z.b. UART, I2C, SPI muß das Modul neugeschrieben werden.
Aber bei Verwendung der gleichen Software-Schnittstellen kann darauf 
basierende Hardware (z.b. LCD via SPI oder I2C EEProm) bei 
entsprechender Kapselung (meist) ohne weiteres angesprochen werden.

Alle weiteren Software-Module die nichts mit der Hardware zu tun haben, 
Middleware, Tools und Ablaufsteuerungen lassen sich fast gänzlich ohne 
Anpassungen portieren, dadurch das da eben keine Registerzugriffe 
gemacht werden.

von spess53 (Gast)


Lesenswert?

Hi
>Wenn der Code wiederverwendbar werden soll benutzt man i.d.R. Makros die
>man bei Wiederverwendung innerhalb der selben Prozessorfamilie einfach
>nur anpasst.

Geht in Assembler ebenso. Sieh dir mal meinen ersten Anhang vom 17.1. 
an. Das Problem ist, das viele die Möglichkeiten des 
Assemblers/Preprozessors nicht nutzen oder gar nicht kennen.

MfG Spess

von Peter D. (peda)


Lesenswert?

spess53 schrieb:
> Ich habe hier noch keinen disassemblierten C-Code gesehen der diese
> Bedingung erfüllt hätte.

Nimm einfach mal das oben erwähnte LCD-Beispiel und versuch es 
einzudampfen.
Ich kann Dir auch das Assemblerlisting erzeugen (mit eingeschalteter 
Optimierung).

Es gibt natürlich viele C-Programme, die aufgebläht sind.
Sehr oft sieht man z.B. daß gedankenlos int genommen wird, obwohl 
uint8_t ausreicht. Klar, daß sich dann der Code verdoppeln muß, wenn man 
16Bit auf nem 8Bitter macht.


Peter


P.S.:
Hast Du ein schönes Assemblermacro, was es auch gestattet, Portpins 
bequem als Bitvariablen zu definieren. D.h. Bitnummmer und Adresse in 
einem Namen abzulegen?
Das gefällt mir am GCC sehr, hat mir auch am Keil C51 schon gut 
gefallen.

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.