Hallo zusammen,
ich habe hier eine Frage zur Projektorganisation/Speicherung der
SW-Teile. Ich weiß nicht, wie ich das in der titelzeile ausdrücken soll.
Ich habe eine Directory, unter der ich für jedes meiner kleinen
(Bastel-)Projekte Subdirektoreies angelegt habe, unter denen dann der
jeweilige Projektbaum (gemäß Atmel Studio 6.2) zu finden ist.
Viele der einzelnen Sourcefiles, z.B. für die TFT-Ansteuerung, z.B.
TFT.C, TFT.H werden in vielen meiner Projekte verwendet. Nun möchte ich
diese "Standardroutinen" unter einer getrennten directory, z.B. mit
Namen "pool", ablegen.
Soweit, sogut, wenn ich eine solche Datzei nun im Studio als Sourfce
hinzufüge, damit ich die Datei ggf. ändern/erweitern kann Nur speichert
Atmel Studio diese geänderte Datei nicht unter "pool" zurück sondern
unter "src" im jeweiligen Projekt.
Nun ja, ich könnte diese Dateien in "main" o.ä. includieren, nur dann
wäre ein einfaches Ändern der Datei nicht möglich und müßte extern
erfolgen.
Kennt jemand für mein "Problem" einen Lösungsweg? Oder bin ich nur zu
blöde, kann ja auch sein.. :-)
Hanns-Jürgen M. schrieb:> Kennt jemand für mein "Problem" einen Lösungsweg?
Meines Wissens nach kann man in Atmel Studio Sourcen direkt
als Datei oder "gepointert" als Datei-Link im Projet einbinden.
Mit Datei-Link wärst du womöglich da wo du hin willst?
Hanns-Jürgen M. schrieb:> (gemäß Atmel Studio 6.2)
Auf jeden Fall würde ich von dem buggy und zähem 6.2 auf 7.x
wechseln.
@Och nöö
Danke für den Tip, ich werde mal suchen.
Update auf Studio Vers. 7. hatte ich mal durchgeführt, aber das ist
leider auf meinem anderen unter XP laufenden Rechner nicht möglich. Und
denn kann ich nicht auf 7 updaten, da Win7 für wichtige ältere Hardware
keine Treiber hat. Und somit bleibt aus Kompatiblitätsgründen nur die
Version 6.2 übrig. Bugs sind mir dort bislang noch nicht aufgefallen,
nur Probs mit der Toolchain, aber auch diese ließen sich umschiffen.
Hanns-Jürgen M. schrieb:> leider auf meinem anderen unter XP laufenden Rechner nicht möglich.
Ist mir auch so ergangen.
Seitdem liegt Atmel Studio nutzlos "in der Ecke", auch wenn ich
mittlerweile auch Win 7 habe.
Ich wollte Atmel-ARM machen, aber nachdem Atmel einem die Gangart
in der Entwicklungsumgebung nicht leicht machte (man denke nur
an das ganze .NET Gerödele) ist der Sprung zu STM32 gaaaaanz
schmerzlos vonstatten gegangen - dank der vielseitigen Möglich-
keiten einer Entwicklungsumgebung.
Hallo Hanns-Jürgen M.,
das Problem kenn ich auch. Alles, was in einem Projekt verwendet wird,
ist dort auch im Verzeichnis gespeichert. Einerseits ist das gut, aber
... wenn dann man eine Library ändert, muss man diese wieder extra
speichern für weitere Verwendung. Ich hatte mal das ASF-Framework
verwendet, da war das dann genauso.
Vor Jahren hatte ich dann AVR32 uCs mit dem AVR32-Studio verwendet, was
auch gut lief, aber da war das Speichern ähnlich. Das AVR32-Studio wird
schon seit langem nicht mehr unterstützt. Und dann musste ich
zwangsweise auf Atmel Studio umsteigen, was auf älteren PCs dank .NET
auch nicht gut läuft. Also ich finde persönlich die IDE auch echt
schrecklich, obwohl das ASF Framework durchaus brauchbar ist, wenn man
verstanden hat, wie diese aufgebaut ist und genutzt wird. Da bleibt mal
abzuwarten wie sich das jetzt mit Microship ändern wird.
Ich habe auch die uC-Familie und die IDE gewechselt.
Thomas O. schrieb:> geht das nicht mit .include C:\Pool\...
Ja, das geht, aber genau das wollte ich verhindern.
Ich habe da ggf. eine Lösung gefunden, muß das aber noch austestetn, ob
es grundsätzlich brauchbar ist..
Hanns-Jürgen M. schrieb:> Nun möchte ich> diese "Standardroutinen" unter einer getrennten directory, z.B. mit> Namen "pool", ablegen.
Laß so etwas lieber sein. Deine Quelltexte mögen ja von einem zum
anderen Projekt so ziemlich gleich sein, insbesondere dann, wenn du
immer nur den gleichen Chip-Typ verwendest, aber dennoch: Laß alles, was
du nicht mit #include <xxxxx> einbindest, in deinem Projekt-Verzeichnis,
denn dadurch hältst du dein Projekt in sich konsistent. Das ist
wichtiger, als du es derzeit vielleicht meinst.
Ich selber bin ein großer Freund von weitgehend flach organisierten
Projekt-Verzeichnissen, also derart, daß alles, was zum eigentlichen
Übersetzen benötigt wird, in einem einzigen Verzeichnis drinsteht.
Speicherplatz ist bei heutigen Festplatten ja kein Thema mehr.
W.S.
@W.S.
Nun, Deine Begründung ist richtig... in Teilen.
Ich nehme mal ein Beispiel, Das File DCF.C diene zur DCF-Decodierung und
wird in fast allen meinen Projekten verwendet.
Nun habe ich kürzlich die Routinen etwas verändert, ohne dabei die
Schnittstellen zu verändern. Wenn ich nun dieses File nicht im Pool
habe, dann muß ich es manuell in jede Projekt-Directory reinkopieren.
Und das ist nicht nur mühseelig, sondern könnte, falls eine
Projektdirectory übersehen wird, zu bösen zeitrauzbenden Bugs führen.
Ein anders Beispiel wäre eine Font-Datei, die ich ggf. erweitert habe.
du könntest das AVR-Studio über eine Batchdatei starten in der du vor
dem eigentlichen Start deine Pool Dateien mit den anderen Projektordnern
vergleichst und ggf. aktualisieren läßt.
glaube das war robocopy mit dem man solche Syncronisierungsaufgaben per
Kommandozeilenaufruf (bzw. dann eben in die Batchdatei aufnehem)
erledigen kann.
@Thomas O et altera
von einem Start mittels einer Batchdatei halte ichm, unter Windoof, eher
gar nichts. Falls da etwas schiefläuft und Atmel Studio beendet wird,
ohnen die Dateien zurück zu kopieren ist alles am A...., wenn man dann
nicht manuell eingreift.
Unter DOS verwende ich Batch-Dateien, dort ist es eher kein Problem.
(Alter IAR Compiler für HC11 und 6809 SW, ja ja, ich weiß, Schnee von
vorvorgestern)
Ich habe nun eine einigermaßen brauchbare Lösung gefunden, die auf
#includes beruht. Ich wollte das eigentlich nicht, aber okay.
Im ersten Schritt lege ich in der directory (Beisoielname) "POOL" die
Standardroutinen (.c und .h Files) ab.
Projektbezogen sind sie in der Projektdirectory nicht mehr zu finden,
auch aus dem Makefile werden sie entfernt.
Dazu lege ich projektbezogen einen c-Datei POOLFILES.C und eine
Headerdartei POOLFILES.C an. Die POOLFILES.C wird im Makefile als zu
kompilierende und zu linkende datei eingetragen.
Die POOLFILES.C enthält nun projektbezogen die benötigten C-Dateien als
INCLUDES:
Desweiteren wird eine Headerdaei POLLFILES.H angelegt, die die im
Projekt benötigten Headerdateien der Pool-Sources beinhaltet. Diese
Datei ind in die projekt-Surcefiles zu includieren.
Hanns-Jürgen M. schrieb:> Die POOLFILES.C enthält nun projektbezogen die benötigten C-Dateien als> INCLUDES:
Man includiert eigentlich keine .c Dateien. Man kompiliert sie separat
und linkt sie dazu.
Bernd K. schrieb:> Hanns-Jürgen M. schrieb:>> Die POOLFILES.C enthält nun projektbezogen die benötigten C-Dateien als>> INCLUDES:>> Man includiert eigentlich keine .c Dateien. Man kompiliert sie separat> und linkt sie dazu.
Das ist mir bekannt, aber solange die "POOL"-Routinen nicht nicht
endgültig fixiert sind und gelegentliche Ergänzungen oder Korrekturen
macht das weniger Sinn.
Außerdem sind einige Sourcecodes dabei, die variabel, d.h. "bedingt"
kompiliert werden, und das geht IMHO mit Libs eher weniger. ????
Hanns-Jürgen M. schrieb:> Bernd K. schrieb:>> Hanns-Jürgen M. schrieb:>>> Die POOLFILES.C enthält nun projektbezogen die benötigten C-Dateien als>>> INCLUDES:>>>> Man includiert eigentlich keine .c Dateien. Man kompiliert sie separat>> und linkt sie dazu.>> Das ist mir bekannt, aber solange die "POOL"-Routinen nicht nicht> endgültig fixiert sind und gelegentliche Ergänzungen oder Korrekturen> macht das weniger Sinn.
wieso? Du musst doch nur dafür sorgen daß die für die IDE als zum
Projekt zugehörig betrachtet werden, egal wo sie liegen.
Wenn die IDE das partout nicht akzeptiert daß das in einem anderen
Ordner ist dann mach doch einfach Symlinks oder Hardlinks zu den
entsprechenden Dateien, dann sehen die für die IDE und für das
Buildsystem so aus als lägen die direkt in Deinem Projekt, obwohl sie
eigentlich woanders liegen. Alter Trick, haben wir schon vor 30 Jahren
so gemacht und Windows kann das jetzt neuerdings (endlich) auch.
> Außerdem sind einige Sourcecodes dabei, die variabel, d.h. "bedingt"> kompiliert werden, und das geht IMHO mit Libs eher weniger. ????
Ich spreche nicht von Libraries.
Ich spreche von einzeln zu kompilierenden c Dateien. Jede Datei des
Projekts wird einzeln für sich kompiliert zu jeweils einer .o Datei und
am Schluss werden alle .o Dateien zu einer .elf gelinkt. Und aus dem
.elf wird dann in einem weiteren Schritt noch das .hex zum Flashen
erzeugt.
Die wirklich saubere Lösung wäre allerdings diesen "Pool" in ein eigenes
git repo zu stecken und in den Repositories der jeweiligen Anwendungen
einen Klon dieses Repositories als git submodule einzubinden, dann
kann man es bei einzelnen Projekten auch auf eine bestimmte Revision
festnageln falls neuere Versionen der Pool-Dateien für ein bestimmtes
Projekt inkompatibel geworden sind.
Eine andere Möglichkeit ist, "Standardroutinen" in eine eigene
Bibliothek zu packen, die dann zu den Projekten dazugelinkt wird. So
mache ich das zumindest. Aus Fonts, CRC-Tabellen etc. erstelle ich
Assembler-Sourcen, die praktisch nur aus .byte Zeilen bestehen. Wenn ich
jetzt irgendwo (z.B) glcd_text("Hello World"); aufrufe, dann sorgt
letztendlich der Linker dafür, dass die Tabelle automatisch mit in den
Code wandert.
Joerg W. schrieb:> Eine andere Möglichkeit ist, "Standardroutinen" in eine eigene> Bibliothek zu packen, die dann zu den Projekten dazugelinkt wird.
Das ist leider nicht immer so einfach bei µC-Projekten.
Beispiel: lcd.c:
1
#include"lcd-config.h"
In lcd-config.h wird dann die Verkabelung des LCDs definiert, welche
durchaus von Projekt zu Projekt verschieden sein kann. Da nützt mir ein
bereits kompiliertes lcd.o oder ein lib-lcd.a herzlich wenig.
Ich habe auch die Erfahrung gemacht, dass Kopieren des Sources
suboptimal ist. Baut man im Verlaufe des Projektes B eine Verbesserung
in lcd.c ein, hat Projekt A erstmal nichts davon.
Deshalb arbeite ich so, dass ich ein Verzeichnis ../lib benutze, in
welchem der wiederverwendbare Code als Quelltext landet. In den meisten
IDEs kann man auch Quellcode außerhalb des Projektordners hinzufügen.
Wenn das nicht geht, hilft zur Not der Include-Trick. Aber schön ist
anders.
Frank M. schrieb:> Ich habe auch die Erfahrung gemacht, dass Kopieren des Sources> suboptimal ist. Baut man im Verlaufe des Projektes B eine Verbesserung> in lcd.c ein, hat Projekt A erstmal nichts davon.
Doch, es hat sehr viel davon, nämlich daß es immer noch läuft.
Ich speichere daher allen Lib-Code immer lokal im jeweiligen Projekt.
Ansonsten passiert es sehr leicht, wenn man alten Code anfassen muß, daß
nichts mehr funktioniert, weil die Lib inzwischen "verbessert" wurde und
damit inkompatibel zu alten Projekten ist.
Bernd K. schrieb:> Die wirklich saubere Lösung wäre allerdings diesen "Pool" in ein eigenes> git repo zu stecken und in den Repositories der jeweiligen Anwendungen> einen Klon dieses Repositories als git submodule einzubinden, dann> kann man es bei einzelnen Projekten auch auf eine bestimmte Revision> festnageln falls neuere Versionen der Pool-Dateien für ein bestimmtes> Projekt inkompatibel geworden sind.
Danke für den Hinweis. Nur ich habe davon wirklich keine Ahnung. Ich
habe jetzt mal nach "GIT PEPO" gegoogelt, um überhaupt zu erfahren, was
das ist..
Ich meine, daß dies auch der richtige Weg wäre, aber ich betreibe alles
nur noch als Hobby (ich bin auch ursprünglich kein SW-Mann) und scheue
mich (noch) davor, mich in dieses neue Thema einzuarbeiten. Ob das dann
überhaupt mit ATMEL Studio 6.2 unter Windoof zusammenfunzt, weiß ich
nicht (??).
Viele Grüße, Yogy
Peter D. schrieb:> Frank M. schrieb:>> Ich habe auch die Erfahrung gemacht, dass Kopieren des Sources>> suboptimal ist. Baut man im Verlaufe des Projektes B eine Verbesserung>> in lcd.c ein, hat Projekt A erstmal nichts davon.>> Doch, es hat sehr viel davon, nämlich daß es immer noch läuft.> Ich speichere daher allen Lib-Code immer lokal im jeweiligen Projekt.> Ansonsten passiert es sehr leicht, wenn man alten Code anfassen muß, daß> nichts mehr funktioniert, weil die Lib inzwischen "verbessert" wurde und> damit inkompatibel zu alten Projekten ist.
Auch irgendwie richtig. Ich für meinen teil sichere jedes Projekt, an
dem ich arbeite, und künftig auch den POOL, täglich unter einem eigenen
Namen, z.B. POOL_2018_03_19 auf dem Sicherungsmedium. Damit kann ich
beleiebig zurückgehen.
Der Hinweis vom UKW-Moderator bringt es auf den Punkt, warum ich sources
einbinden will, ich hatte das unter dem Begrief "bedingte Kompilierung"
zusammengefaßt.
Peter D. schrieb:> Ansonsten passiert es sehr leicht, wenn man alten Code anfassen muß, daß> nichts mehr funktioniert, weil die Lib inzwischen "verbessert" wurde und> damit inkompatibel zu alten Projekten ist.
Das ist die typische Angst, das etwas bei einer Aenderung kaputt gehen
koennte, weshalb man eher dazu neigt nichts zu aendern, obwohl man etwas
aendern will/sollte.
Diese Angst vergeht ganz schnell, wenn man ordentliche Softwaretests
hat, angefangen bei Unittests.
"Ich aender das nicht, weil dann was kaputt gehen koennte" ist nur eine
Ausrede, um schlechten Code zu rechtfertigen.
Und von einem Modul 23 verschiedene Versionen, an 65 verschiedenen Orten
zu haben, macht das ganze nicht besser. Denn dann musst du in jedem
Projekt immer wissen, warum sich Funktion X in diesem Projekt
moeglicherweise leicht anders verhaelt, als in einem anderen Projekt.
Mal ehrlich:
Die Zeiten mit haendischem Kopieren und Umbenennen sind schon lange
vorbei. Wer glaubt das dieses Vorgehen auch nur irgendwelche Vorteile
gegenueber einer Versionsverwaltung wie Git, SVN, etc. hat, der moege
mal bitte ueber seinen Tellerrand gucken.
Faengt doch schon bei einem kleinen Bugfix an. Projekt auschecken, bug
fixen, einchecken, und schon haben alle Projekte nach einer
aktualisierung, die von diesem Projekt abhaengen, auch den Bugfix.
Denselben Bug in 10 Projekten fixen zu muessen, nur weil man das immer
alles von Hand hin und her kopiert, und dann vermutlich auch noch an 1
oder 2 Stellen das fixen vergessen... klar, kann man machen, hat am Ende
aber nur Nachteile.
Alleine die Moeglichkeit sehen zu koennen, wann man was wo geaendert
hat. Ganz ohne das man da haendisch irgendeine Textdatei pflegen muss
(was man doch nicht macht, wegen 'keine lust' oder 'mach ich spaeter').
Und anbieter wie z.B. GitLab
https://about.gitlab.com/
kosten nicht mal was. Selbst private Repos sind kostenlos.
Die Verkabelung des LCD habe ich (für mich) dahingehend gelöst, dass
sowohl die Datenleitungen als auch die Steuerleitungen jeweils innerhalb
eines Ports liegen müssen. Bis jetzt bin ich damit gut zurechtgekommen.
Bei der Initialisierung gebe ich die Portpins mit an, z.B:
init_glcd128a(PORT_A,PORT_C,0,1,2,3);
wobei das "a" hinter "glcd128" in dem Fall für ein monochromes 128x64
Display mit 2 Low-aktiven CS Leitungen steht. Dieser Teil ist eigentlich
"dumm", denn er stellt nur einen 1K großen Framebuffer bereit. Mittels
einer Routine "serve_glcd128a()", die in den Tick-Interrupt mit
eingebunden wird, werden jeweils 8x8 Pixel zum LCD übertragen. Und die
eigentlichen LCD-Routinen wie Zeichen ausgeben oder Linien zeichnen sind
völlig unabhängig von der angeschlossenen Hardware, da sie nur auf den
Framebuffer zugreifen. Und ganz unten drunter liegen generische PORT-IO
Routinen, damit das Ganze auch controllerunabhängig ist.
Wenn ich jetzt ein neues LCD mit exotischer Ansteuerung habe, dann
schreibe ich nur den Lowlevel-Teil neu und bin fertig. Wenn dann alles
funktioniert, wandert der Code mit in die Bibliothek und ist danach auch
für alle anderen Controller verfügbar. Und mit einem Script erzeuge ich
aus den ganzen C-Datein in der library eine Header-Datei mit den
Funktionsprototypen.
Joerg W. schrieb:> Die Verkabelung des LCD habe ich (für mich) dahingehend gelöst, dass> sowohl die Datenleitungen als auch die Steuerleitungen jeweils innerhalb> eines Ports liegen müssen. Bis jetzt bin ich damit gut zurechtgekommen.> Bei der Initialisierung gebe ich die Portpins mit an, z.B:>
Nun, wenn ich "normale" LCD-Module verwende, dann gibt es 2 x 16, 4 x 20
oder auch 1 x 16 Module, die ich je nach HW Seriell über SPI oder über
I2C oder 4-bit parallel oder 8 bit parallel ansteuere. Und die Ports
ändern sich jenachdem welche (Arduino-)HW ich verwende. Hierzu nutze ich
#define-Anweisungen. Bei den TFTs ist es noch schlimmer, da muß noch
zwischen den TFT-Controllern unterschieden werden.
Aber es führen immer viele Wege nach Rom (oder so ähnlich).
Yogy
> und schon haben alle Projekte nach einer> aktualisierung, die von diesem Projekt abhaengen, auch den Bugfix.
Das kann einem auch zum Verhängnis werden, wenn nämlich das Programm
selbst schon den Bugfix enthält. Wenn z.B. in der Bibliotheksroutine ein
Vorzeichenfehler ist. Da die bisherigen Projekte ja laufen, hatte man
dort halt das Ergebnis der Routine addiert statt subtrahiert. Mit der
gefixten Routine werden sämtliche bestehenden Projekte, wenn man sie neu
baut, nicht mehr richtig funktionieren. Natürlich nur, soweit sie die
einst fehlerhafte Routine nutzen.
Gut, mit Vorzeichen ist es mir noch nicht passiert, aber mit Endianess.
Nachdem ich die Routine (wegen STM32) für Little-Endian gefixt hatte,
funktionierten die Projekte für PowerPC µC nicht mehr, da die Big-Endian
sind. Letztendlich habe ich die Routine wieder "zurückgestellt" und eine
neue universelle erstellt, die etwas anders heisst und beide varianten
richtig behandelt. Das ist auch die, welche weiter gepflegt wird und
wenn ich ein altes Projekt mal wieder anfasse, stelle ich den Aufruf
(wenn ich dran denke) gleich mit um.
Ähnlich ist es auch, wenn man z.B. einen weiteren Parameter für die
Routine braucht oder sich die Bedeutung eines Parameters ändert. Hier
ist es meiner Meinung nach viel besser, eine neue Routine zu erstellen
anstelle an der alten herumzustricken. Letztendlich sorgt ja der Linker
dafür, dass nur das eingebunden wird, was auch gebraucht wird.
Kaj G. schrieb:> Diese Angst vergeht ganz schnell, wenn man ordentliche Softwaretests> hat, angefangen bei Unittests.
Zeig mir mal deinen Unit-Test für die Ansteuerung eines LCD-Displays ;-)
ich halte auch wenig davon, Korrekturen automatisiert auf Projekte zu
verteilen. Ich mach das nur, wenn ich das jeweilige Projekt auch
anfasse. Ansonsten kommen bei einem jahrealten projekt beim ersten
SCM-Update viele Änderungen, und ich weiss erstmal nicht wie mir
geschieht.
Ich habe mir da (auch in anderen Bereichen) eine spezielle Methodik
zurechtgelegt: Im SCM (Subversion in meinem Fall) gibt es einen
speziellen bereich, der "common code" enthält. Dieser bereich ist für
sich alleine weder compilier- noch lauffähig; aber über Skripte kann ich
automatisiert prüfen, inwieweit der common-code mit dem aktuellen
Projekt übereinstimmt (wobei es zwei Fälle gibt: common ist aktueller,
oder Projekt ist aktueller, auf die man dann auch unterschiedlich
reagieren will)
Oft ist es so, dass ich in einem Projekt common-code
erweitere/ändere/optimiere, dieser muss sich aber erst über ein paar
Tage/Wochen/Monate "bewähren", und ich will auf keinen Fall dass dieser
bereits in andere Projekte einfliesst.
Kaj G. schrieb:> Diese Angst vergeht ganz schnell, wenn man ordentliche Softwaretests> hat, angefangen bei Unittests.
In der idealen Welt sieht für Dich alles so schön einfach aus.
Aber selbst die großen Programmierbuden schleppen Bugs oft lange mit,
ohne sie zu entdecken. Und wenn man sie dann entdeckt, kann niemand
sagen, wie sich der Bugfix oder die Erweiterungen auf alten Code
auswirkt.
Ich hatte zu oft das Problem, daß alter Code dann nicht mehr läuft und
davon schlichtweg die Nase voll. Genau deshalb bin ich auf lokale Kopien
zurück gekehrt.
> Zeig mir mal deinen Unit-Test für die Ansteuerung eines LCD-Displays ;-)
Ich war zwar nicht gemeint, aber ich lade mal meinen oder zumindest
einen Teil davon hoch. Dazu gehört natürlich immer noch ein board.h in
dem sämtliche Einstellungen für das konkrete Controllerboard stehen. Auf
praktisch allen (Test-)Boards habe ich eine rote+grüne LED zwecks
Debugging, hier würde z.B. die rote LED leuchten, wenn der Controller
zuwenig RAM hat (würde z.B. beim ATMega8 oder kleineren HCS08
passieren).
Letztendlich werden ein Quadrat, ein ausgefülltes Quadrat, zwei schräge
Linien und ein invertierter Text angezeigt. Und nebenbei bewegt sich ein
kleines Sprite durch die Gegend...
Insgesamt habe ich derzeit 41 Tests und die müssen bei jeder neuen
Bibliotheksversion zumindest ohne Fehler compilieren, mit externer
Hardware teste ich eigentlich nur neue Bibliotheksfunktionen.
Peter D. schrieb:> Ich hatte zu oft das Problem, daß alter Code dann nicht mehr läuft und> davon schlichtweg die Nase voll. Genau deshalb bin ich auf lokale Kopien> zurück gekehrt.
... kenne ich auch und macht sinn für mich!
an svm kommt man trotzdem nicht mehr vorbei, selbst im hobbybereich.
weil auch hier gibt es oft viele projekte und zahllose sw module mit
entsprechenden abhängigkeiten.
ich nutze und empfehle mercurial mit gui TortoiseHg. das ist auch im
context des explorer integriert und ansonsten einfach zu verstehen und
zu benutzen.
mt
Peter D. schrieb:> In der idealen Welt sieht für Dich alles so schön einfach aus.
Nein tut es nicht.
Peter D. schrieb:> Aber selbst die großen Programmierbuden schleppen Bugs oft lange mit,> ohne sie zu entdecken. Und wenn man sie dann entdeckt, kann niemand> sagen, wie sich der Bugfix oder die Erweiterungen auf alten Code> auswirkt.
Richtig. Weil auch grosse Softwarefirmen das Testing viel zu oft
straeflich vernachlaessigen, weil es ja Zeit kostet. Sollte man mal
gegenrechnen was es kostet die Software ordentlich zu entwickeln und mit
tests auszustatten (TDD/BDD) und was das Suchen und Beheben von Bugs
kostet.
Unittests sind nicht die Loesung auf alles, richtig. Wenn man aber Tests
hat, dann ist die Angst etwas kaputt zu machen, weil man etwas aendert,
deutlich geringer. Die Tests (sofern sie gut sind) sagen dir doch, ob
nach der Aenderung noch alles so funktioniert wie vorher.
Kaj G. schrieb:> TDD/BDD
Ja, eh. In der "großen" Welt. Hier gehts um uC.
Wenn ich weiter oben gefragt hatte, wie ein Unit-Test eines LCD-Treibers
aussieht, dann meinte ich primär automatisierte Tests. Un diese sind
aufgrund der Hardware-Nähe eines uC halt bissel kompliziert aufzusetzen.
Joerg W. schrieb:> mit externer Hardware teste ich eigentlich nur neue Bibliotheksfunktionen.
Was die Unit Tests in der weiteren Evolution eigentlich ad absurdum
führt.
Das muß nicht unbedingt sein. Denn wenn ich z.B. Funktionen wie einen
neuen SPI-Flash oder CRC-Berechnung hinzufüge, muss ich nicht die ganzen
anderen Funktionen testen, die z.B. nur von Port-I/O abhängig sind. Wenn
ich natürlich an einer Funktion herumschraube, die relativ "tief" liegt,
also z.B. Port-I/O, muss ich natürlich die darüberliegenden Funtionen
testen. Anfangs wollte ich das eigentlich gar nicht so hierarchisch
aufziehen, aber nachdem ich z.B. Port-I/O auf fast allen Plattformen in
ASM realisiert habe, ist der Overhead gar nicht mehr so schlimm.
Wichtiger sind mir die Tests allerdings bei neuen Controllerfamilien,
weil ich damit schnell grundlegende Funktionalitäten testen und auch
bewerten kann.
Sog. Highlevel-Funktionen wie z.B. LCD oder SD-Karte dürfen bei mir dazu
weder voneinander noch von der darunterliegenden Hardware abhängig sein
(nur von darunter liegenden Bilbliotheksfunktionen). Sie liegen in einem
zenralen Verzeichnis und werden nur per Symlink in die
Sourceverzeichnisse der Bibliotheken eingebunden. Das erspart schon mal
jede Menge Testaufwand, weil ich erstmal nur auf einer Plattform testen
muss. Anders geht es auch gar nicht, denn ich betreibe das privat in
meiner "Freizeit". Und die besteht u.a. aus der täglichen Pendelei mit
der S-Bahn, wo größere Aufbauten eher unpraktisch sind.
Joerg W. schrieb:> aber nachdem ich z.B. Port-I/O auf fast allen Plattformen in> ASM realisiert habe,
Um Gottes Willen, warum denn das? War Dir langweilig? Und lässt sich das
manuelle ASM Gedöns dann überhaupt noch von der LTO vernünftig inlinen
(nur für den Fall daß es Dir tatsächlich um Performance ging und nicht
nur um den Spaß an der Tüftelarbeit)?
Der erste Punkt, ich lerne dabei. Wie der Controller funktioniert, was
der Compiler für ASM-Code generiert...
Mein Ziel war, dass z.B. set_portpin_output(PORT_A,3) überall "gleich"
funktioniert, ähnlich wie beim Arduino. Und das mit möglichst wenigen
Befehlen.
Und so ist die Konstante PORT_A z.B. beim AVR ein (char) Tabellenoffset,
der zeigt, wo die Adressen von PORTA,DDRA und PINA liegen, beim STM32
(unsigned long) die absolute Adresse von GPIOA. Außerdem kann man durch
geschicktes Verschieben und Maskieren des Wertes auch gleich die
notwendige Maske für RCC_APB2ENR berechnen. Die PowerPC Controller
dagegen haben für jeden Pin ein extra Konfigurationsregister, dort habe
ich dann auch keinen ASM-Code verwendet. Hier ist die Konstante PORT_A
einfach nur ein Offset (Port-Nr. * 16) und der C-Code für die Funktion
lautet in dem Fall
1
voidset_portpin_output(intport,intpin)
2
{
3
SIU.PCR[port+pin].REG=0x204;
4
}
Das ist ein Aufwand, den man sich aber nur einmal machem muss. LTO
funktioniert meines Wissens nach nicht oder nur eingeschränkt mit
dazugelinkten Bibliotheken.
Joerg W. schrieb:> Mein Ziel war, dass z.B. set_portpin_output(PORT_A,3) überall "gleich"> funktioniert, ähnlich wie beim Arduino. Und das mit möglichst wenigen> Befehlen.
Ich hab mir für jeden der handvoll Controller mit denen ich
hauptsächlich unterwegs bin jeweils ein Python script geschrieben das
mir ein gpio.h generiert.
Meine Pins werden dann zum Beispiel so definiert:
Inhalt von gpio.py
Das ganze in mein Makefile eingebaut, sobald ich die .py ändere baut er
ein neues .h
gpio_mkv11 kann ich leider nicht rausrücken, die Rechte gehören mir
nicht allein, ist aber auch nicht sonderlich aufwendig. Es enthält noch
ein paar Tabellen um bei Bedarf auch defines für den ADC Kanal oder
Timerkanal des pins auszuspucken oder generiert automatisch code um NMI
abzuschalten wenn ich den entsprechenden Pin verwende und solche
Kleinigkeiten.
Nur so als Anregung.
Alles was man nicht vernünftig als Makro hinschreiben kann lass ich
mittlerweile mittels Python generieren. hat auch den Vorteil daß beim
Debuggen echter Code in einer echten Quelldatei zur Verfügung steht.