Ich beschäftige mich seit Längeren bereits mit ATtiny85, ATMega328 und jetzt auch mit PIC. Angefangen habe ich mit den Lernbausätzen von Franzis. Interessante Anregungen habe ich als Anfänger unter anderen bei BKainka bzw. seinem Elektronik-Labor gefunden. Er hat wohl auch den Lernbausatz ATtiny85 für Franzis entwickelt. Inzwischen sind mir die Vorteile/Unterschiede zwischen der Programmierung via Bootloader oder mittels Programmer klar. Da ich bisher nur Hochsprachen wie Bascom oder C benutzt habe, war Assembler erst einmal zweitrangig. Allerdings läuft im Mikrocontroller natürlich in Maschinensprache übersetzter Code, egal ob aus Bascom oder C. Wenn ich nun mit einem Programmer (STK500 bei ATMEL oder PICKit bei PIC) einen Controller komplett auslese, welcher mittels Bootloader über die Serielle Schnittstelle/USB programmiert wurde, finde ich natürlich im untersten Speicherbereich den Bootloader und z.B. bei PIC ab 0400hex das eigentliche Programm. Diesen Inhalt ab 0400hex könnte ich natürlich abspeichern und wieder in einen jungfreulichen Controller laden. (Configbits bzw. Fuses nicht vergessen) Will ich jetzt allerdings den Bootloader weglassen, so könnte ich doch nur den eigentlichen Maschinencode des Anwendungsprogrammes speichern, der ab 0400hex zu finden ist. Das spart Speicherplatz und reicht für fertige Geräte ja völlig aus, welche nur einmal programmiert werden sollen. Bei diesem Gedankengang kamen mir dann folgende Fragen: 1. Gibt es bei PIC/ATMEL im Assembler auch absolute Sprünge/Sprungadressen? 2. Kann ich den eigentlichen Programmcode ab 0400hex einfach an eine andere Adresse verschieben? Falls Frage 1 mit "Ja" zu beantworten ist, dann sollte Frage 2 bzw. das Verschieben nicht möglich sein. Oder sorgt der Compiler bei diesen Controllern (ATtiny85, ATMega328, PIC18F23K22) dafür, dass es keine absoluten Sprünge gibt? Sorry für die etwas akademische Frage, aber für mein Verständnis durchaus wichtig.
Die AVRs haben absolute Sprünge (jmp) bei den Modellen, bei denen der relative Sprungbefehl (rjmp) nicht für den gesamten Flash ausreicht. guggst du Datenblatt. Oliver
:
Bearbeitet durch User
Wobei ich mich gerade frage, welchen Sinn die Fragestellung für Atmel
ergibt: bei den genannten Typen (Klasse 'AVRe') befindet sich der
Bootloader doch am Ende des Flash.
PS:
Auch dies verstehe ich nicht:
> Das spart Speicherplatz ...
Welchen Vorteil soll das haben?
:
Bearbeitet durch User
Danke für den Hinweis. Das würde bedeuten, dass meine Gedanken nur bei den PICs zutreffen würden, da dort der Bootloader vorn (0 - 0400hex) liegt. Bei den Atmels würde sich ja nichts an den Adressen verändern, wenn ich nur den Maschinencode des eigentlichen Programmes abspeichere. Insofern bezieht sich meine Frage dann nur auf die PICs!
Jürgen K. schrieb: > Das spart Speicherplatz Du bekommst kein Geld zurück für nicht gebrauchtes Flash. Und auf der Festplatte sind es nur wenige hundert Bytes weniger, Flashzeit wird ebenfalls nur marginal reduziert. Jürgen K. schrieb: > 1. Gibt es bei PIC/ATMEL im Assembler auch absolute > Sprünge/Sprungadressen? Na klar. Liegt am Programmierer und Compiler ob das passiert, aber möglich sind sowohl absolute als auch relative Sprünge. Jürgen K. schrieb: > 2. Kann ich den eigentlichen Programmcode ab 0400hex einfach an eine > andere Adresse verschieben? In der Regel nicht. Es sei denn du schreibst ihn als Quellcode um. Eben als "relativ", oder an eine andere Startsadresse. Plus: Es kann sein, das der Bootloader Hardwarehürden umschifft in dem er nicht das programmiert was du meinst, will sagen: er patcht das Programm um, damit das normalerweise nicht "Bootloader-Aware" erstellte Programm "mit" läuft. Auslesen und neu Programmieren geht dann nicht, weil im zweiten Teil der Bootloader fehlt, der z.B. Sprungadressen benutzt. Aber warum sich das antun? Du kannst mit jedem Compiler oder Assembler einfach ein Programm erstellen und die Hexdatei z.B. via avrdude auch ohne Bootloader programmieren, und das tut dann auch, ohne die Sicherheitslücke Bootloader und ohne Frickelei mit Auslesen und umpatchen.
Jürgen K. schrieb: > Das würde bedeuten, dass meine Gedanken nur bei > den PICs zutreffen würden, da dort der Bootloader vorn (0 - 0400hex) > liegt. Nicht zwangsläufig. Je nach Chip ist der Bootloader oben, aber der Resetvektor wird umgepatcht. Dadurch ist der Bootloader "unsichtbar", das Programm kann mit und ohne laufen ohne das es zwei Versionen gibt. Bei deinem "BL vorne" musst du das Programm entsprechend übersetzen, was Fehleranfällig ist. Bei AVRs stimmen evtl. die Fuses nicht mit/ohne BL. Zum Glück haben die PICs das nicht, die Config steht mit im Hexfile, wenn der Programmierer kein Volldepp ist.
Bei den klassischen ATtiny/ATmega muß der Compiler nicht wissen, ob ein Bootloader benutzt wird oder nicht. Die Applikation startet immer an 0x0000. Bei den neuen AVRs muß man die Applikation verschieben, d.h. der Linker muß die Adresse der Applikation kennen. Ansonsten zeigen absolute Sprünge und Calls, die Interruptvektoren sowie konstante Daten im Flash in den Wald.
Jürgen K. schrieb: > 1. Gibt es bei PIC/ATMEL im Assembler auch absolute > Sprünge/Sprungadressen? Selbst wenn keine absoluten Sprünge / Calls verwendet werden bedeutet das noch lange nicht, dass der Code relokatibel ist. Zum Beispiel ein indirekter Funktionsaufruf: Das Problem ist die "Berechnung" der Funktionsadresse; die besteht aus dem Nehmen der absoluten Adresse der Funktion. Dito für indirekte Sprünge, etwa in if/else Dispatch-Tables, Computed Goto, Nonlocal Goto (Exceptions), etc. Eine Möglichkeit, relokatiblen Code zu realisieren ist z.B. ein ELF Loader auf dem Device, das zur Load-Zeit entsprechende RELOCs fixt. Der entstehende Code ist dann zwar nicht mehr relokatibel, spielt aber keine Rolle, weil bei erneutem Laden die Loader den Code wieder auf die gewählte Adresse anpasst. Für AVR wüsste ich nicht, dass jemand mal auch nur versucht hätte, einen ELF-Loader zu schreiben -- wäre auch nicht sonderlich sinnvoll, weil die Tools keine entsprechenden RELOCs erzeugen. Dann gibt es noch die Möglichkeit, echt relokatiblen Code zu erzeugen. Aber auch das würde Erweiterungen der Tools erfordern, etwa wie die Adresse eines Labels zu berechnen ist. Weiteres Problem ist, dass es keine absoluten Sprünge / Calls geben kann, d.h. man braucht ein Branch-Relaxing im Linker, was zB für AVR nicht umsetzbar ist.
:
Bearbeitet durch User
Johann L. schrieb: > Eine Möglichkeit, relokatiblen Code zu realisieren ist z.B. ein ELF > Loader auf dem Device, das zur Load-Zeit entsprechende RELOCs fixt. Um Himmels willen! Darf ich nochmal an das Subject erinnern? In Assembler kann man selbstverständlich relokatiblen Code schreiben. Die Frage ist, ob man das überhaupt will (bzw. braucht). Denn auch wenn man in Assembler programmiert, hat man ja den Quellcode und es kostet nur ein paar Klicks um den für eine andere Adresse zu übersetzen. Aber darum ging es dem TE ja auch nicht. Ihm geht es um die Behandlung des Maschinencodes. Und der ist im Normalfall weder relokatibel noch ist garantiert, daß er ohne den Bootloader überhaupt tut. Kommt auf den Bootloader und auf die µC-Architektur an. Speziell bei Architekturen ohne eigenen Bootloader-Support werden da Vektoren umgebogen und andere Verrenkungen gemacht. Abgesehen davon verstehe ich den Sinn hinter der Anfrage nicht. Wenn man ein Programm hat, das mit dem Bootloader tut und offensichtlich auch in den Flash paßt - warum zur Hölle würde man da den Bootloader nachträglich weglassen wollen?
Also normalerweise ist der Assembler fit genug, Programm-Adressen passend hinzubiegen. Im Flash ändern sich auch keine Adressen, oder möchtest Du einen Virus für AVR/PIC-Controller schreiben? Übrigens kann ich Dir nicht empfehlen, die PICs in Assembler zu programmieren. Ich bin genau deswegen zu den AVRs gewechselt, die einen deutlich kompletteren Registersatz und Assembler-Instructions haben, obwohl ich mit PICs angefangen habe.
Axel S. schrieb: > warum zur Hölle würde man da den Bootloader > nachträglich weglassen wollen? - Kostet Startzeit - ermöglicht Fremdflashen - Ermöglicht evtl. auslesen - Erfordert u.U. fehlenden Codeschutz Ben B. schrieb: > Übrigens kann ich Dir nicht empfehlen, die PICs in Assembler zu > programmieren. PIC-Assembler ist wesentlich einfacher als der des AVR zu verstehen, und wesentlich vorhersehbarer. Plus es entfällt dieser ganze Kram mit den Registern, alle Befehle sind gleich lang usw. usf. Und, das allerwichtigste: keine Fuses, die man manuell transportieren muss und bei denen jeder Programmer ein anderes Interface hat: Config in den Code, die Bytes landen im Hex, eine Datei in der alles steht, fertig. Aber: es ist kein "besser", es ist "anders", denn die beiden Architekturen sind wesenlich unterschiedlich. Das ist wie Mac und Windows. Irgendwie gleich, aber im Detail halt doch ganz anders. Je nachdem welche anderen Architekturen man kennt kommt man dann mit PIC oder AVR besser klar, wenn man sich die Qual des Assemblers noch antun will.
:
Bearbeitet durch User
Jens M. schrieb: > PIC-Assembler ist wesentlich einfacher als der des AVR zu verstehen, und > wesentlich vorhersehbarer. Aber erst ab PIC18 einigermaßen brauchbar. Die PIC12/16 mit Hardwarestack, segmentiertem RAM und Flash, ständiger Bankumschaltung, RETLW, DECFSZ, PCLATH sind einfach nur gruselig. Bezüglich vorhersehbar. Ich möchte nicht wissen, wieviel Entwickler da schon geflucht haben, weil nach Einfügen eines Befehls plötzlich nichts mehr ging, weil die Flashadresse einen 8Bit Überlauf hatte.
:
Bearbeitet durch User
Jens M. schrieb: > Auslesen und neu Programmieren geht dann nicht, weil im zweiten Teil der > Bootloader fehlt, der z.B. Sprungadressen benutzt. Das stimmt so nicht. Auslesen und Programmieren kann man auch direkt über die Programmierschnittstelle des Prozessors. Ein Bootloader macht das Einspielen der Anwendersoftware zwar sehr bequem, ist aber nicht unbedingt erforderlich. Wenn es ohne Bootloader nicht funktionieren würde, hätte man ein Henne-Ei-Problem beim Aufspielen des Bootloaders.
Also ich bin mit beiden Architekturen gut mit Assembler klargekommen, nur daß ich das beim AVR wie gesagt durch den großen Register- und Befehlssatz wesentlich komfortabler fand.
Jens M. schrieb: > Axel S. schrieb: >> warum zur Hölle würde man da den Bootloader >> nachträglich weglassen wollen? > > - Kostet Startzeit Wie oft startet man eine µC-Anwendung? > - ermöglicht Fremdflashen > - Ermöglicht evtl. auslesen Das Problem hat man immer und es wird durch setzen der Fuses (zumindest auf dem AVR, heißt bei PIC vermutlich anders) gelöst. > - Erfordert u.U. fehlenden Codeschutz Dieser Satz kein Sinn. Bei selbstentwickeltem Code hat man zudem immer den Quellcode. Wenn man den Bootloader nicht haben mag, übersetzt man den halt nochmal ohne Bootloader. Da frickelt man nicht mit dem Maschinencode rum. > Ben B. schrieb: >> Übrigens kann ich Dir nicht empfehlen, die PICs in Assembler zu >> programmieren. > > PIC-Assembler ist wesentlich einfacher als der des AVR zu verstehen, und > wesentlich vorhersehbarer. Nein. Weniger Befehle sind nicht besser. Wenn das so wäre, wären ja auch Whitespace oder Brainfuck beliebte Programmiersprachen. PIC Assembler ist der sicherste Weg, schnell verrückt zu werden. So wie Beulenpest und Lepra gleichzeitig. Zumindest die kleinen PICs bis PIC16. PIC18 geht einigermaßen. PIC24 ist eine reguläre µC-Architektur. Und PIC32 ist eigentlich MIPS. Mit dieser krampfhaften Umbenennerei von Architekturen tut sich Microchip IMHO keinen Gefallen. Wer einmal mit PIC16 konfrontiert war und nicht das Privileg hatte, den Compiler benutzen zu können (es gab nur einen und der kostete Geld) macht um alles was PIC heißt einen großen Bogen.
Jens M. schrieb: > PIC-Assembler ist wesentlich einfacher als der des AVR zu verstehen Vorausgesetzt vielleicht, es ist die erste Programmierumgebung, der man ausgesetzt ist, und man kennt keine andere :). Die archaische Mnemotechnik erinnert an Rechner aus grauer Vorzeit und weicht von den mittlerweile gängigen Architekturen deutlich ab.
:
Bearbeitet durch User
Axel S. schrieb: > Mit dieser krampfhaften Umbenennerei von Architekturen Der erste PIC ist von 1976. Damals waren bei den verschiedenen Architekturen die Namen und die Syntax von Befehlen noch Kraut und Rüben. Allmählich vereinheitlichte sich das jedoch, auch erkennbar an der Migration vom 8080 Stil zum Z80 Stil. Bei den PICs ist man einfach beim archaischen Schema geblieben, weshalb das heute deutlich aus der Zeit gefallen wirkt.
:
Bearbeitet durch User
Peter D. schrieb: > Die PIC12/16 mit Hardwarestack, segmentiertem RAM und Flash, ständiger > Bankumschaltung, RETLW, DECFSZ, PCLATH sind einfach nur gruselig. Och, geht. Die Register bei AVR die man nicht benutzen darf weil "das muss immer 0 sein" und so finde ich (neben den Fuses) auch absolute Designfehlentscheidungen. Wenn man's richtig macht sind PIC16 recht einfach nzu benutzen. PIC12 ist noch wesentlich einfacher, weil das ja auch nur wenig Flash hat. Bei den aufgeblasenen Typen sollte man dann wirklich schon einen 18er nehmen, aber die sind in den letzten Generationen dann auch wirklich unübersichtlich geworden. Dreistellige PIC16F sind aber leicht zu programmieren. Peter D. schrieb: > Bezüglich vorhersehbar. Ich möchte nicht wissen, wieviel Entwickler da > schon geflucht haben, weil nach Einfügen eines Befehls plötzlich nichts > mehr ging, weil die Flashadresse einen 8Bit Überlauf hatte. Jaha, das ist eine gern gefundene Falle. Ich meinte aber z.B. Taktzeiten und Speicherbedarf. Ein Befehl ist ein Wort ist ein Takt, außer bei Sprüngen. Wenn der Assembler vom Programmierer ausgetrickst wird und Flashbanks auf einmal ein Problem werden, ist das aber Layer 8. Rainer W. schrieb: > Das stimmt so nicht. Auslesen und Programmieren kann man auch direkt > über die Programmierschnittstelle des Prozessors. > Ein Bootloader macht das Einspielen der Anwendersoftware zwar sehr > bequem, ist aber nicht unbedingt erforderlich. Das stimmt sehr wohl. Es gibt bei PICs nur einen Resetvektor, und der ist nicht wie bei AVRs via Configbit/Fuse umsetzbar. Da muss (!) also ein Hinweis auf den Bootloader rein, und der wird einen Teufel tun diese Stelle mit dem zu überschreiben was er vom PC bekommt, nämlich den Start des Anwenderprogramms: dieser wird in den Bootloader selbst geschrieben, an die "Bootloader ist fertig"-Stelle. Wenn du dann das Programm "mit BL" ausliest, steht da der Start in den BL drin. Schreibst du das "ohne", fehlt der Resetvektor und der Programmstartvektor aus dem BL. Ergo: mit BL auslesen, wegeditieren und neu flashen knallt. Axel S. schrieb: > Wie oft startet man eine µC-Anwendung? Ja nu, manche Leute wundern sich wenn $Gerät nach dem Einschalten erstmal 3 Sekunden braucht bis es reagiert. $Entwickler weiß es, $Kunde ist genervt. Axel S. schrieb: > Das Problem hat man immer und es wird durch setzen der Fuses Ja eben. Ein Codeprotect kann durch den Bootloader verunmöglicht sein, und das will man u.U. nicht kommerziell ausliefern. Kann auch sein das es geht, aber das wissen wir nicht. Axel S. schrieb: > Dieser Satz kein Sinn. Dieser Satz kein Verb. ;) Lies nochmal im Zusammenhang meine Antwort drei Zeilen höher. Axel S. schrieb: > Wenn man > den Bootloader nicht haben mag, übersetzt man den halt nochmal ohne > Bootloader. Joa, das ist normal so. OP ist aber auf einem anderen Pfad unterwegs, warum auch immer. Axel S. schrieb: > PIC Assembler > ist der sicherste Weg, schnell verrückt zu werden. Och, ich komm seit ~30 Jahren bestens auf PIC Asm klar. Leicht und einfach zu verstehen, logisch nachzuvollziehen, überschaubar in der Fehlersuche. Ja, gibt bequemeres, aber viele kleine Hilfsprojekte habe ich über die Jahre mal eben auf einen PIC12F675 gehackt, keine 100 Zeilen und ein leichteres Leben. Mittlerweile mach ich es aber mit Arduinos, und das nur aus dem Grund das man da via USB live einen Update fahren kann. Wenn ich nach 10 Jahren einen Update auf einer meiner Basteleien fahre und aus einem 100-Zeilen-PIC-Programm (also auch ~100 Words Speicherbedarf) werden 100 Zeilen C, aber mit 3kB Speicherbedarf, dann tränen mir die Augen. Aber man bekommt für unbenutztes Flash ja kein Geld zurück... Axel S. schrieb: > PIC24 ist eine reguläre µC-Architektur. Und PIC32 ist eigentlich MIPS. Beides keine PICs, nur mit dem Namensschild drauf. Jeder PIC-Programmierer hasst die, und kommt auch nicht damit klar, weil die ganzen Strukturen vollkommen un-PIC-ig sind. Muss man in C machen und dann könnte man auch ARM nehmen. (prx) A. K. schrieb: > Die archaische Mnemotechnik erinnert an Rechner aus grauer Vorzeit und > weicht von den mittlerweile gängigen Architekturen deutlich ab. Ja, PICs waren ja auch eigentlich ganz anders geplant. Etwa sowas wie der Blitter im Amiga. Dann kam ein BWLer und hat gesagt "das könnte man doch auch auf dem Markt verkaufen?!"
Jens M. schrieb: > Die Register bei AVR die man nicht benutzen darf weil "das muss immer 0 > sein" Ich kenne das nur als Konvention des Compilers, nicht in der Architektur der Hardware.
Jens M. schrieb: > Dann kam ein BWLer und hat gesagt "das könnte man doch auch auf dem > Markt verkaufen?!" Tja, was soll man dazu sagen: Der BWLer hatte recht! :)
(prx) A. K. schrieb: > Ich kenne das nur als Konvention des Compilers, nicht in der Architektur > der Hardware. Das weiß ich nicht. Ich habe mal ein paar Versuche mit AVR-Asm gemacht und bin darüber gestolpert, aber eine Erklärung dafür habe ich nie gesehen. Zugegeben aber auch nicht direkt gesucht. Ich hab ein bissle C eingegeben, compiliert, mir den Code angesehen, habe geweint wie viel Kram aus den einfachsten Befehlen erzeugt wird und hab wie vom PIC gewohnt das Programm mit nur dem nötigsten zusammengestöpselt. Klein, einfach, schnell, aber unheimlich unbequem zu schreiben, weil man so wahnsinnig viele Befehle und Adressierungsarten kennen muss, nix für Anfänger.
:
Bearbeitet durch User
(prx) A. K. schrieb: > Axel S. schrieb: >> Mit dieser krampfhaften Umbenennerei von Architekturen > > Der erste PIC ist von 1976. Damals waren bei den verschiedenen > Architekturen die Namen und die Syntax von Befehlen noch Kraut und > Rüben. Ja, mag sein. Aber andere Hersteller hatten das doch deutlich besser drauf. Der Motorola 6800 ist sogar noch älter als PIC (von 1974) und da macht man sich bei der Programmierung nicht so einen Knoten ins Hirn. > Allmählich vereinheitlichte sich das jedoch, auch erkennbar an > der Migration vom 8080 Stil zum Z80 Stil. Vielleicht doch die Gnade der späten Geburt. Mein erster µP war der Z80 (als U880), später hab ich mich eingehend noch mit dem Z8 (sehr elegant) und dann mit dem 6502 (eigentlich 6510, im C64) auseinandergesetzt. Und der letztere ist ja im Prinzip eine leicht abgespeckte Variante des 6800. Man sieht natürlich die Evolution zum Z80. Viel mehr Register, Stack frei im RAM positionierbar, mehrere 16-Bit Indexregister, usw. Aber der PIC wirkt auch im Vergleich zum 6502 wie Steinzeit.
Jens M. schrieb: > Das weiß ich nicht. Aber ich. Bei RISC Architekturen ist es recht verbreitet, dass eine bestimmte Registernummer für den Wert 0 steht und ein reingeschriebener Wert verloren geht. Das vereinfacht die Implementierung. Meist ist das naheliegenderweise R0, aber in RISC-V ist es R31. GCC für AVR bildet das einfach nach. Befehle mit Konstante gibts ja nur für R16-R31 und der Wert 0 ist einfach zu wichtig.
:
Bearbeitet durch User
> Ich hab ein bissle C eingegeben, compiliert, mir den Code > angesehen, habe geweint wie viel Kram aus den einfachsten > Befehlen erzeugt wird und hab wie vom PIC gewohnt das > Programm mit nur dem nötigsten zusammengestöpselt. Das ist aber kein PIC- oder AVR-Problem, sondern das erlebt man bei allen Hochsprachen, wenn man sich das Programm nach dem Compilieren in Assembler anschaut. Gerade das macht Assembler ja so interessant, man bekommt sehr hohe Geschwindigkeit mit wenig Speicherbedarf.
>(prx) A. K. schrieb: >> Jens M. schrieb: >>> Die Register bei AVR die man nicht benutzen darf weil "das muss immer 0 >>> sein" >> >> Ich kenne das nur als Konvention des Compilers, nicht in der Architektur >> der Hardware. > > Ich habe mal ein paar Versuche mit AVR-Asm gemacht und bin darüber > gestolpert, aber eine Erklärung dafür habe ich nie gesehen. Wie gesagt, das ist eine Konvention(!) des C-Compilers. In Assembler gibt es diese Einschränkung nicht. Nur wenn man C und Assembler mischen will. Und sogar dann kann man das Zero-Register benutzen, solange man nicht in den C-Code (vom C-Compiler generierten Maschinencode) zurückkehrt. Und sei es in Form einer ISR. Aber eigentlich stellt sich das Problem nicht. Man hat ja 32 Register. Sind dann halt nur noch 31, wenn man das Zero-Register ausläßt.
Axel S. schrieb: > Z8 (sehr elegant) Aber für eng begrenzten Adressraum optimiert. Bei mehr als den grob 200 Bytes RAM war Schluss mit Lustig, und die Nachfolgearchitektur liess an Übersichtlichkeit schwer zu wünschen übrig. Dem 8051/52 ging es genauso. Sobald der ursprüngliche Adressraum überschritten wurde, wurde es hässlich. Damals peilte man solche Systeme für wenige Jahre, um danach eine neue Architektur für mehr Bedarf zu bringen. Das war MCS-96 - sehr übersichtlich für Asm-Programmierer, aber kennt die heute noch jemand?
:
Bearbeitet durch User
> Befehle mit Konstante gibts ja nur > für R16-R31 und der Wert 0 ist einfach zu wichtig. Eine der wenigen Einschränkungen beim AVR.. aber immerhin bekommt man satte 32 Register, davon 16 general purpose und die oberen 6 davon als 16-Bit-Register nutzbar. Soviel Komfort hat man beim PIC16F bei weitem nicht. Die großen ATMegas können 131 AVR-Instructions (ATMega1284), der PIC16F677 kann 35. Das will man doch nicht ...
Ben B. schrieb: > wenn man sich das Programm nach dem Compilieren in > Assembler anschaut Sich den Output eines C Compilers für 8-Bit PICs anzuschauen, ist ein Abenteuer der besonderen Art.
Ben B. schrieb: > Das will man doch nicht Befehle zu zählen ist eine brotlose Kunst. Die 8080 hat so gesehen mehr Befehle als die Z80, weil bei 8080 jeder Opcode einen eigenen Namen hat, während Z80 etliche zusammenfasst. Und MaxQ2000 hat bei geeigneter Zählweise nur einen einzigen Befehl mit zwei Adressierungsarten. :) move reg2 to reg1 move constant to reg1
:
Bearbeitet durch User
Ich weiß was Du meinst, aber bei einem Stand von 131:35 ist schon recht deutlich, welcher Kern der benutzerfreundlichere ist. Zumindest in Assembler, einem Compiler ist sowas egal.
:
Bearbeitet durch User
Dann versuche mal, den MaxQ2000 in Assembler zu programmieren. Das ist selbst mit aufgedröselter Mnemotechnik schwierig, die aus einem Opcode zig Befehle macht. :)
Ben B. schrieb: > Soviel Komfort hat man beim PIC16F bei weitem > nicht. Hab ich nie vermisst. Was mich stört sind das man ab und zu irgendwie verkehrt rum in den Befehlen ist, aber Register hab ich nie benötigt. Ben B. schrieb: > Das will man doch nicht Man braucht nicht mehr. Der AVR kann Dinge mit einem Befehl, der dann zwei Takte braucht, was der PIC in zwei Befehlen machen muss was auch zwei Takte braucht. (prx) A. K. schrieb: > Sich den Output eines C Compilers für 8-Bit PICs anzuschauen, ist ein > Abenteuer der besonderen Art. Arduino ist auch gut: Alle Variablen auf den Softwarenachgebildetenen Stack, call in die Funktion, Alle Variablen wieder runter in die Register, Rechnung ausführen, alle Ergebnise wieder zurück auf den Stack, return, alle Ergbnisse wieder runter vom Stack, weiterarbeiten. Arduino auf einer Maschine mit FRAM würde das auch in 3 Stunden kaputtschreiben. Ben B. schrieb: > bei einem Stand von 131:35 ist schon recht > deutlich, welcher Kern der benutzerfreundlichere ist. Der einfacher merkbare ;) Bitte diesen Thread nicht in eine Linux/Windows-Diskussion, äh, PIC/AVR-Diskussion abgleiten lassen. ;) Die Antwort auf OPs Frage ist in beiden Architekturen "kommt drauf an, aber wahrscheinlich nein".
Jens M. schrieb: > Bitte diesen Thread nicht in eine Linux/Windows-Diskussion, äh, > PIC/AVR-Diskussion abgleiten lassen. ;) Der hat eigentlich schon so angefangen. :)
Jens M. schrieb: > Ja eben. Ein Codeprotect kann durch den Bootloader verunmöglicht sein, > und das will man u.U. nicht kommerziell ausliefern. > Kann auch sein das es geht, aber das wissen wir nicht. Bei den AVRs hat man getrennte Lockbits für Programmer und Bootloader. Man kann also den Programmer aussperren und nur noch das Schreiben für den Bootloader erlauben. Und wenn der Bootloader kein Rücklesekommando unterstützt, ist die Applikation auslesegeschützt.
Jens M. schrieb: > Ich hab ein bissle C eingegeben, compiliert, mir den Code angesehen, > habe geweint wie viel Kram aus den einfachsten Befehlen erzeugt wird und > hab wie vom PIC gewohnt das Programm mit nur dem nötigsten > zusammengestöpselt. Dann bist Du in die Falle des zu kleinen Code getappt. C hat erstmal einen gewissen Overhead gegenüber Assembler. Aber je mehr zu tun ist, umso besser ist der Compiler, bis er dann sogar gewinnt. Der kennt viele Tricks, z.B. Register Renaming, Common subexpression elimination, wo man sich zu Fuß in Assembler einen abbrechen würde.
Jens M. schrieb: > Ich hab ein bissle C eingegeben, compiliert, mir den Code angesehen, > habe geweint wie viel Kram aus den einfachsten Befehlen erzeugt wird und > hab wie vom PIC gewohnt das Programm mit nur dem nötigsten > zusammengestöpselt. Normalerweise liegen lokale Daten von C Funktionen auf dem Stack. Vorausgesetzt das geht überhaupt. Alte PICs können das nicht und auch die PIC18 können es erst ab einer Revision der Architektur einigermassen. Bei AVR ist das an sich kein Problem, nur muss man dazu am Stackpointer rumspielen, und an dieser Stelle hat AVR Mist gebaut und dieser Mist stinkt bis heute. Andere sagen, derjenige Compiler-Hersteller, mit dem Atmel zwecks besserer Nutzbarkeit in C zusammenarbeitete, habe AVR verarscht, um einen Vorteil gegenüber dem Rest der Welt zu haben. Denn deren Compiler macht das mit zwei getrennten Stacks. Einen für Return-Adressen und einen für lokale Daten. Das geht besser. GCC hingegen macht es klassisch und als Folge davon kann der Wasserkopf am Anfang und Ende von Funktionen ziemlich hässlich aussehen.
Jens M. schrieb: > Und, das allerwichtigste: keine Fuses, die man manuell transportieren > muss und bei denen jeder Programmer ein anderes Interface hat: Config in > den Code, die Bytes landen im Hex, eine Datei in der alles steht, > fertig. Nur nebenbei: kann man beim AVR genauso haben. Aber dann üblicherweise nicht im Hex-File, sondern gleich im ELF-File. Intel-Hex braucht dort eigentlich niemand mehr (trotzdem hält es sich sehr hartnäckig). Ist halt die Frage, ob man auch wirklich bei jeder Iteration die Fuses neu flashen möchte …
Peter D. schrieb: > Und wenn der Bootloader kein Rücklesekommando > unterstützt, ist die Applikation auslesegeschützt. Könnte man theoretisch über den BL ein 2. Programm in den AVR laden, das sich dann via UART selbst ausliest? ;) Jörg W. schrieb: > Nur nebenbei: kann man beim AVR genauso haben. Aber dann üblicherweise > nicht im Hex-File, sondern gleich im ELF-File. ELF lesen viele Programmer nicht. Also: ja geht, aber nur in der Theorie. Bei PICs hingegen war es von Anfang an so das Flash, EEPROM und Config ganz normal im Adressbereich des Programmers auftauchen.
Ich glaube, die Bootloader beim AVR überschreiben immer das gesamte Programm im dafür verwendeten Flash-Bereich. Ich glaube das einzige was nicht geht ist, daß sich der Bootloader selbst überschreibt. Aber sich selbst auslesen und via UART übertragen könnte er. Aber die Controller sind da sehr vielseitig, man kann damit eigentlich allen Blödsinn machen, den man so will.
:
Bearbeitet durch User
Nebenbei. bei AVR kann ein conditional jump nur relativ sein, +-63 adressen oder so. also BREQ (-60). Bedeutet ohne absolute jumps geht gar nichts. Von einem, der auch mal einen bootloader in ASM schrieb
Bei PICs ist ein Conditional Jump immer nur ein Skip (+1 oder eben nicht). :D Da muss man auch mit umgehen können, plus das absolute Gotos immer nur einen Teil der Zeiladresse tragen können und man auf das entsprechende Latchregister achten muss, was sich wie Paging anfühlt. So hat jeder seine Vor- und Nachteile...
Pandur S. schrieb: > bei AVR kann ein conditional jump nur relativ sein Das ist bei Architekturen häufiger zu finden. Es gab aber mit z.B. 8048 und RCA 1802 ein paar Oldies, die eigentlich kein Banking hatten, aber deren kurze Sprünge die unteren 8 Bit des PC ersetzten. Von 01F8 auf 0201 ging also nicht mit kurzen Sprüngen. Das ist eigentlich nur von Vorteil, wenn man gleich Binärcode schreibt. Schon in symbolischem Assembler nervt es. Das nicht minder nervende Gegenstück war der SC/MP, der nur 8-Bit relativ springen konnte, sonst nur indirekt über Register. Wie das in Code aussieht, der ein paar KB gross ist, kann man sich ausmalen.
:
Bearbeitet durch User
Jens M. schrieb: > Könnte man theoretisch über den BL ein 2. Programm in den AVR laden, das > sich dann via UART selbst ausliest? ;) Nur wenn man sich einen speziellen Bootloader selber bastelt, der das ermöglicht. Außer bei den USB-AVRs ist ab Werk kein Bootloader drauf. Üblich schreibt ein Bootloader die Applikation an die Adresse Applikation-Start und springt dann dorthin. Auch wenn man Code hinter den belegten Bereich der Applikation schreiben könnte, gäbe es keine Instanz, die ihn aufrufen könnte.
Jens M. schrieb: > Jörg W. schrieb: >> Nur nebenbei: kann man beim AVR genauso haben. Aber dann üblicherweise >> nicht im Hex-File, sondern gleich im ELF-File. > > ELF lesen viele Programmer nicht. Also: ja geht, aber nur in der > Theorie. Geht auch in der Praxis. Alle relevanten Programmer lesen das inzwischen, insbesondere hat es schon Atmel selbst so vorgemacht damals und Microchip übernommen. AVRDUDE macht es auch. Segger ignoriert AVRs offenbar komplett (aber auch ansonsten arbeiten die viel mit ELF).
Jens M. schrieb: > Bei PICs hingegen war es von Anfang an so das Flash, EEPROM und Config > ganz normal im Adressbereich des Programmers auftauchen. Ganz am Anfang noch nicht, weil weder Flash noch EEPROM noch Config existierten. :) https://bitsavers.org/components/gi/PIC/1983_PIC_Series_Microcomputer_Data_Manual.pdf
:
Bearbeitet durch User
Jens M. schrieb: > Bei PICs ist ein Conditional Jump immer nur ein Skip (+1 oder eben > nicht). :D > Da muss man auch mit umgehen können, plus das absolute Gotos immer nur > einen Teil der Zeiladresse tragen können und man auf das entsprechende > Latchregister achten muss, was sich wie Paging anfühlt. Man kann das PCLATH weit vor dem Sprung laden, da es erst bei CALL/GOTO übernommen wird. Das macht den Quellcode nicht gerade lesbarer und kann für Überraschungen sorgen, wenn man z.B. mit einen RETI dahin zurück springt.
Peter D. schrieb: > ... > Die PIC12/16 mit Hardwarestack, segmentiertem RAM und Flash, ständiger > Bankumschaltung, RETLW, DECFSZ, PCLATH sind einfach nur gruselig. > [ ]Du hast verstanden, was 8Bit sind. [ ]Du hast verstanden, dass die (kleinen) PICs diese Umstände machen (müssen) um effektiv 13Bit Adressraum zu nutzen, trotz 8Bit Architektur. Oder hast du eine bessere Idee, wie du mit einem 8Bit Arbeitsregister 1023 Adressen nutzen kannst? Ich benutze die kleinen 12F675 heute noch für Spielereien auf der MoBa. Auch mit dem "grottigen" Assembler. Der eigentlich gar nicht grottig ist, sondern einfach nur knallhart geradeaus. Die C-Compiler für die 12Fs sind ganz große Katastrophe. habe ich einmal ausprobiert. Nie wieder.... Und trotz aller Geigeleien mit den Teilen habe ich das kByte Flash noch nie voll ausnutzen (müssen). Ok, ein serielles Display möchte ich damit nicht ansteuern, aber Schieberegister für Beleuchtungszwecke oder PWM per BitBang für Servos sind überhaupt kein Akt. Den/die PICs habe ich mir vor etlichen Jahren (Jahrzehnten?) selber beigebogen. Damals noch mit serieller Schnittstelle zum programmieren. Im Studium kam dann MSP430, Arm9 und Cortex (M3). Ging, sind halt übelst komplex und die (recht vorbildliche) Doku von Microchip zum PIC hatte verwöhnt. Danach sollte ich mal eine kurze Arbeit mit einem AVR32 machen. katastrophe. Doku/Referenzhandbuch des Kerns passt(e) überhaupt nicht zum von AVR bereitgestellten Framework und die Kommunity trug die Nase in den Wolken. Danke, nie wieder.
(prx) A. K. schrieb: > GCC hingegen macht es klassisch und als Folge davon kann der Wasserkopf > am Anfang und Ende von Funktionen ziemlich hässlich aussehen. Ich seh jetzt nicht, was man mit einem 2ten Stack einspart. Wenn Platz aufm Stack gebraucht wird, muss dieser immer noch im Prolog allokiert und im Epilog wieder freigegeben werden. Das eigentliche Problem ist ja, dass man mit den Stackpointer nicht wirklich auf den Stack zugreifen kann... außer per PUSH / POP. Wenn also eine Funktion einen Frame erfordert, dann muss man aber irgendwo in den Stack greifen, was effektiv ein Pointer-Register (Y oder Z) erfordert, samt teurer Initailisierung.
> Oder hast du eine bessere Idee, wie du mit einem > 8Bit Arbeitsregister 1023 Adressen nutzen kannst? Der AVR verwendet dafür ein 16-Bit-Register, welches aus zwei 8-Bit-Registern zusammengesetzt wird (bspw. Z in ZH:ZL bzw. R31:R30). Damit sind bis zu 64k (65.536) Adressen erreichbar.
Roland E. schrieb: > Oder hast du eine bessere Idee, wie du mit einem 8Bit Arbeitsregister > 1023 Adressen nutzen kannst? Z.B. 8051 oder AVR zeigen Dir, wie man 64kB Daten + 64kB Code linear adressieren kann. https://de.wikipedia.org/wiki/Intel_MCS-51 Es gab auch mal 8051 mit >64kB Code (AT89C51RE2: 128kB Flash). Leider ist die Fabrik abgebrannt und die Fertigung nicht wieder aufgenommen worden. Auch der P89C669 (96kB Flash) ist schon lange tot. Nur den C8051F120-GQ gibt es noch, kann aber nur bis 3,6V. https://www.digikey.de/de/products/detail/silicon-labs/C8051F120-GQ/819523
(prx) A. K. schrieb: > Bei AVR ist das an sich kein Problem, nur muss man dazu am Stackpointer > rumspielen, und an dieser Stelle hat AVR Mist gebaut und dieser Mist > stinkt bis heute. Ja, die meisten 16Bit-Register kann der AVR atomar zugreifen (Timer, ADC). Nur ausgerechnet beim SP hat man das "vergessen" und auch nicht nachgebessert.
Johann L. schrieb: > Ich seh jetzt nicht, was man mit einem 2ten Stack einspart Der erste AVR, der AT90S1200, hatte seinen Return-Stack in Hardware.
:
Bearbeitet durch User
Peter D. schrieb: > und auch nicht nachgebessert. Das hat mich seither ziemlich gewundert. So arg schwer wärs nicht gewesen. Schon ein add/sub immediate to SP hätte fast alle Fälle erledigt.
:
Bearbeitet durch User
Johann L. schrieb: > Wenn Platz > aufm Stack gebraucht wird, muss dieser immer noch im Prolog allokiert > und im Epilog wieder freigegeben werden. Wenn man ISRs in C aussen vor lässt, müssen diese Operationen nicht atomar sein, und ADIW/SBIW kamen schon mit den ersten non-AT90 hinzu.
:
Bearbeitet durch User
Man kann sich den Stackpointer nach X,Y oder Z kopieren und dann mit diesem Register arbeiten wenn man sowas wirklich braucht. Ich programmiere recht viel in Assembler und normalerweise lege ich mir den Stackpointer einmal beim Start des Controllers ans obere Ende des RAM und fasse ihn danach nie wieder an.
Ben B. schrieb: > Man kann sich den Stackpointer nach X,Y oder Z kopieren und dann mit > diesem Register arbeiten wenn man sowas wirklich braucht. Der früher übliche Framepointer, der bei anderen Architekturen heutzutage oft wegoptimiert wird. Und so macht das GCC ja auch. Aber der Transfer von XYZ zum SP ist nicht atomar und das ist bei Interrupts entscheidend. > Ich programmiere recht viel in Assembler Die Problematik bezieht sich auf C. In Assembler liegen lokale Daten selten auf dem Stack, weshalb der Prolog/Epilog-Code zur Allokation von Daten auf dem Stack entfällt.
:
Bearbeitet durch User
> Aber der Transfer von XYZ zum SP ist nicht atomar > und das ist bei Interrupts entscheidend. Das sollte eigentlich kein Problem sein, da der AVR beim Interrupt-Aufruf weitere Interrupts blockiert. Man kann SPH/SPL also in zwei Befehlen kopieren, ohne sich darum zu sorgen, daß sich SP dazwischen ändert oder auch SP verändern wenn die Interrupt-Routine aus irgendwelchen Gründen einen eigenen Stack benutzen soll. Das muss man nur logischerweise vor dem Interrupt Return wieder zurückbiegen. Der Interrupt Return hebt automatisch die Blockierung der weiteren Interrupts wieder auf, so daß die alle nacheinander abgearbeitet werden falls mehrere anstehen. Oder was wäre ein Szenario, wo das Deiner Meinung zu Problemen führt?
Ursprünglich war gedacht, den Y-Pointer als Framepointer zu reserviern, dann entfällt das Anlegen eines Stackframe. Allerdings muß man dann vorher genau abschätzen, welche Daten wo liegen sollen, sonst krachen Stackbereich und Framebereich ineinander. Legt man lokale Daten mit in den Stack, dann hat man das Problem nicht. Es kracht dann erst, wenn wirklich kein SRAM mehr frei ist. Benutzt man aber Malloc, dann muß man wieder aufteilen, wieviel SRAM der Stack und wieviel das Malloc benutzen darf. Daher wundert es mich oft, daß viele Programmierer leichtfertig Malloc benutzen, ohne das es nötig ist.
:
Bearbeitet durch User
Ben B. schrieb: > Das sollte eigentlich kein Problem sein, da der AVR beim > Interrupt-Aufruf weitere Interrupts blockiert. Es geht um den Prolog/Epilog normaler Funktionen. Darin wird SP geschrieben und das geht nur in 2 Befehlen. Wenn da ein Interrupt reinrutscht, kriegt der einen defekten Wert von SP. Typisches Szenario: Prolog: push FP FP = SP SP -= const Epilog: SP = FP oder SP += const pop FP Ist "const" recht klein, ersetzt GCC die +=/-= ggf durch ein paar PUSH/POPs oder vielleicht auch -= durch RCALL auf Folgebefehl (2-3 Bytes, je nach AVR). Das sieht dann einigermassen bizarr aus und erschliesst sich nur, wenn man das Problem kennt.
:
Bearbeitet durch User
Naja dann halt
1 | CLI |
2 | MOV R31,SPH |
3 | MOV R30,SPL |
4 | SEI |
oder so ähnlich.
Yep, so in der Art, wobei der SEI typischerweise eins vorgezogen wird, weil er erst nach dem Folgebefehl wirksam wird. Aber es kommt eben insgesamt eine Sequenz zusammen, die auf Assembler-Programmierer abschreckend wirkt.
:
Bearbeitet durch User
Hm, ein Assembler-Programmierer, der von 4 (in Worten: vier) Zeilen Quellcode abgeschreckt wird? ;) Mein längster Assembler-Quellcode ist für meine GSM-Alarmanlage, glaube das waren am Ende um die 340kB Text und mehrere tausend Zeilen (für einen ATMega1284)...
:
Bearbeitet durch User
(prx) A. K. schrieb: > Johann L. schrieb: >> Wenn Platz >> aufm Stack gebraucht wird, muss dieser immer noch im Prolog allokiert >> und im Epilog wieder freigegeben werden. > > Wenn man ISRs in C aussen vor lässt, müssen diese Operationen nicht > atomar sein, und ADIW/SBIW kamen schon mit den ersten non-AT90 hinzu. SBIW / ADIW hat aber nix mit der Atomarität einer SP-Änderung zu tun, da SBIW / ADIW auf GPRs operiert (also nicht auf SP). Außerdem wird natürlich SUBI+SBCI falls der Offset größer als 63 ist. Auf ATxmega ist das Setzen von SP dann entlich atomar realisiert. ...wie auch immer, den Zusammenhang zu 1 Stack vs. 2 Stacks sehe ich immer nich nicht. Oder worauf willst du hinaus?
Ben B. schrieb: > Hm, ein Assembler-Programmierer, der von 4 (in Worten: vier) Zeilen > Quellcode abgeschreckt wird? ;) Diese 4 Befehle sind nur eine der Prolog/Epilog-Operationen, die ich oben skizzierte. Und stell dir dann noch vor, dass ein Sparfuchs für 6 Bytes lokale Daten statt dessen rcall 0 rcall 0 reinschreibt und die arme Sau, die das liest und die Problematik nicht kennt, bloss Bahnhof versteht.
:
Bearbeitet durch User
Johann L. schrieb: > SBIW / ADIW hat aber nix mit der Atomarität einer SP-Änderung zu tun, da > SBIW / ADIW auf GPRs operiert (also nicht auf SP). Außerdem wird > natürlich SUBI+SBCI falls der Offset größer als 63 ist. Ein SBIW/ADIW auf SP wär's für viel Fälle gewesen. Kessel geflickt.
Johann L. schrieb: > ...wie auch immer, den Zusammenhang zu 1 Stack vs. 2 Stacks sehe ich > immer nich nicht. Oder worauf willst du hinaus? 2 getrennte Stacks sind notwendig, wenn der Return-Stack nicht im RAM liegt, sondern als 3 als Stack operierende separate Hardware-Register vorliegt. Siehe AT90S1200. Atmel arbeitet damals mit einem Compiler-Hersteller zusammen, weil keine Erfahrung mit dessen Vorlieben.
:
Bearbeitet durch User
> Und stell dir dann noch vor, dass ein Sparfuchs > für 6 Bytes lokale Daten statt dessen > rcall 0 > rcall 0 > reinschreibt und die arme Sau, die das liest und die > Problematik nicht kennt, bloss Bahnhof versteht. Hehe. Dazu kann ich nur sagen, wenn man auf sowas keine Lust hat, dann sollte man lieber bei C bleiben und nicht mit Assembler anfangen. Und ansonsten könnte auch ein Kommentar dahinter helfen, wo drinsteht was das macht.
Ben B. schrieb: >> Und stell dir dann noch vor, dass ein Sparfuchs >> für 6 Bytes lokale Daten statt dessen >> rcall 0 >> rcall 0 >> reinschreibt und die arme Sau, die das liest und die >> Problematik nicht kennt, bloss Bahnhof versteht. > [...]. Und ansonsten könnte auch ein Kommentar dahinter helfen, > wo drinsteht was das macht. avr-gcc macht das sogar, falls man mit -dp, -dP oder -fverbose-asm compiliert:
1 | void fun (int*); |
2 | |
3 | void bun (void) |
4 | {
|
5 | int i; |
6 | fun (&i); |
7 | }
|
Hier mit -Os -dp:
1 | bun: |
2 | push r28 ; 16 [c=4 l=1] pushqi1/0 |
3 | push r29 ; 17 [c=4 l=1] pushqi1/0 |
4 | ; SP -= 2 ; 21 [c=8 l=1] *addhi3_sp |
5 | rcall . |
6 | in r28,__SP_L__ ; 32 [c=4 l=2] *movhi/7 |
7 | in r29,__SP_H__ |
8 | /* prologue: function */ |
9 | /* frame size = 2 */ |
10 | /* stack size = 4 */ |
11 | .L__stack_usage = 4 |
12 | movw r24,r28 ; 35 [c=4 l=1] *movhi/0 |
13 | adiw r24,1 ; 15 [c=8 l=1] *addhi3_clobber/0 |
14 | rcall fun ; 6 [c=0 l=1] call_insn/1 |
15 | /* epilogue start */ |
16 | ; SP += 2 ; 27 [c=8 l=2] *addhi3_sp |
17 | pop __tmp_reg__ |
18 | pop __tmp_reg__ |
19 | pop r29 ; 28 [c=4 l=1] popqi |
20 | pop r28 ; 29 [c=4 l=1] popqi |
21 | ret ; 30 [c=0 l=1] return_from_epilogue |
:
Bearbeitet durch User
Hallo liebe Freunde, als Themenstarter bin ich begeistert wie viele Antworten ich auf meine Frage bisher erhalten habe. Auch wenn der eine oder andere etwas vom eigentlichen Thema abkommt, so liefert er dennoch für mich wichtige Aspekte. Punkte aus ihren eigenen Erfahrungen, welche mir im Fehlerfalle sicherlich ebenfalls helfen werden. Aber ich möchte nochmal auf den Kern meiner Frage zurückkommen. Vielleicht nochmal ganz kurz warum ich "nur" das eigentliche Programm ohne Bootloader in weitere Controller brennen möchte. Stellt Euch vor, ich habe z.B. eine tolle kleine Anwendung programmiert und verfüge ebenfalls über ein Programmer (STK500, Dragon bzw. PICKit 3). Da ich die Erfahrung habe, dass man mit einem Programmer nicht nur die Software deutlich schneller in den Controller bekommt, sondern auch noch selbst die Fuses/Configbits setzen oder überprüfen kann, nutze ich in der Regel lieber den Programmer. Jetzt möchte ich meine tolle Schaltung/Anwendung in 5 - 10 weitere Controller programmieren, da ich die Schaltungen an meine Freunde verschenken möchte.... Ich würde 5 - 10 neue Controller z.B. ATMega328P im Netz bestellen, von denen ich nicht weiß, wie die Fuses stehen und ob überhaupt ein Bootloader bereits drauf ist. Somit würde ich natürlich meinen Programmer nutzen wollen und an einen Bootloader überhaupt nicht mehr denken. Das gleiche entsprechend für PIC z.B. PIC18F23K22. Den eigentlichen Quelltext finde ich aus irgendeinem Grunde nicht sofort und lese lieber schnell mal einen fertigen Controller von mir aus. Extrahiere das hex-File und programmiere schnell die 5 - 10 neuen Controller..... Nun habe ich hier im Thread gelernt, dass es zumindest bei PIC18xxxxxx, bei denen der eigentliche Code erst bei 0400hex beginnt, besser nicht verschoben werden sollte (absolute Sprünge usw., was mir ja auch schon irgendwie klar war). Bei ATMEL-Bootloader würde sich an der Startadresse ja nichts ändern, da der Bootloader oberhalb liegt. Nun wäre es wohl tatsächlich besser, alles (Programm + Bootloder) auszulesen und auch komplett in die neuen Controller zu flashen. Was würde aber passieren, wenn ich bei den PICs den Bereich 0000hex - 03FFhex frei lasse, d.h. FFhex. Springt dann der Programmcounter des Controllers weiter bis er den ersten "sinnvollen" Maschinenbefehl auf 0400hex findet? Bedeutet FFhex NOP? Dann sollte ja alles funktionieren. Ich unterstelle mal, dass im Bootloader keine Tricks (Kopierschutz/Lizenzen o.ä.) programmiert sind, welche ihn unentbehrlich machen. Eine weitere Frage zu diesem Thema: Wo im AVR-Studio bzw. MPLAB lege ich denn fest, ob ein Bootloader genutzt werden soll? Ich habe bisher noch keine Stelle gefunden, wo ich das Konfigurieren könnte. Woher weiß der Compiler dass ich einen Bootloder zum Flashen einsetzen möchte? Ich denke da auch durchaus an die sogenannte Arduino-IDE. Aus allem was ich hier bisher gelesen habe, sollte zumindest bei den PICs MPLAB einen Code erzeugen, der auf die Adresse 0400hex beginnt, falls ich eine Bootloder im Controller nutze. Das bedeutet, es müsste im MPLAB konfigurierbar sein. Eine praktische Frage nebenbei: Wie könnte ich dafür sorgen, dass wenn ich einen Controller auslese, einen Hinweis finde, welches Programm/Stand ich als letztes geflasht habe? Immer wenn ich 4 Wochen lang nichts am Thema gemacht habe, habe ich völlig vergessen, was der letzte Stand im Controller war oder ob der Controller überhaupt mein "Entwicklungs"-Controller oder ein Jungfräulicher ist. Eine Idee ist, irgendwie eine laufende Nummer/Konstante (Datum Version)) mit in den Flashspeicher zu schreiben, welche ich natürlich manuell nachhalten müsste. Aber diese sonst nicht genutzte Konstante/String o.ä., sollte mir der Compiler nicht "weg"optimieren. Wie macht Ihr dass oder habt Ihr das Problem überhaupt nicht? Viele Grüße und Danke für die vielen Anregungen!
Jürgen K. schrieb: > Eine praktische Frage nebenbei: Wie könnte ich dafür sorgen, dass wenn > ich einen Controller auslese, einen Hinweis finde, welches > Programm/Stand ich als letztes geflasht habe? Vor langer langer Zeit hat man dafür Zettelchen auf die EPROMs geklebt. EPROMs sind zwar rar geworden, aber die Zettel gibts noch. :)
Beitrag #7880555 wurde vom Autor gelöscht.
Habe jetzt mal selber die KI befragt: Um den Offset für die Anwendung (Application) bei Verwendung eines Bootloaders im MPLAB X IDE mit dem XC8-Compiler festzulegen, gehst du folgendermaßen vor: Projekt-Eigenschaften öffnen: Rechtsklick auf dein Projekt im Projektnavigator → „Properties“ auswählen. XC8 Linker-Optionen auswählen: Im linken Menü unter „XC8 Global Options“ den Punkt „XC8 Linker“ auswählen. Zusätzliche Optionen einstellen: In der Kategorie „Additional options“ (Zusätzliche Optionen) das Feld für benutzerdefinierte Linker-Parameter suchen. Offset angeben: Dort trägst du den Parameter text --codeoffset=0xXXXX ein, wobei 0xXXXX für die gewünschte Startadresse der Anwendung steht, z.B. --codeoffset=0x1000 für einen Offset bei Adresse 0x1000 . Bestätigen und neu bauen: Änderungen übernehmen („Apply“/„OK“) und das Projekt neu bauen. Dadurch wird die Anwendung ab der angegebenen Adresse im Flash platziert und überschreibt nicht den Bootloader-Bereich. Der Bootloader bleibt somit im unteren Speicherbereich (z.B. ab 0x0000) erhalten, und die Anwendung startet ab dem eingestellten Offset. Hinweis: Die genaue Adresse hängt vom verwendeten Bootloader und dem reservierten Speicherbereich ab. Typische Werte sind z.B. 0x300, 0x600 oder 0x1000. So langsam bekomme ich das Gefühl: "Gut dass wir darüber geredet haben!"
:
Bearbeitet durch User
Jürgen K. schrieb: > Eine praktische Frage nebenbei: Wie könnte ich dafür sorgen, dass wenn > ich einen Controller auslese, einen Hinweis finde, welches > Programm/Stand ich als letztes geflasht habe? Man kann sich eine _version.c schreiben. Der _ sorgt dafür, daß sie als erstes gelinkt wird und so hinter der Interruptvektortabelle zu liegen kommt. PROJECT_STRING, REVISION_STRING, AUTHOR; müssen entsprechend definiert werden.
1 | const char Version[] __attribute__((used)); |
2 | const char Version[] PROGMEM = PROJECT_STRING ", " |
3 | "V:" REVISION_STRING ", " |
4 | __DATE__ "\n"; |
5 | |
6 | const char Author[] __attribute__((used)); |
7 | const char Author[] PROGMEM = AUTHOR "\n"; |
Jürgen K. schrieb: > Den > eigentlichen Quelltext finde ich aus irgendeinem Grunde nicht sofort und > lese lieber schnell mal einen fertigen Controller von mir aus. Dann solltest du an der Schlusseligkeit arbeiten... ;) Jürgen K. schrieb: > Bei ATMEL-Bootloader würde sich an der Startadresse > ja nichts ändern, da der Bootloader oberhalb liegt. Da sind aber dann die Fuses anders. Jürgen K. schrieb: > Wo im AVR-Studio bzw. MPLAB lege ich denn fest, ob ein Bootloader > genutzt werden soll? Da gibt's keinen Haken "mit Bootloader". Das legst du fest, in dem du deinen Code kennst und z.B. entsprechende Linkerscripte benutzt, oder auch einfach "org $0400". Oder, wie bei AVRs: der Bootloader ist transparent, er kann das Programm enfach so nehmen wie es kommt, es läuft so und so. Nur die Fuses müssen passend stehen. Nur den Speicher des BL darfst du nicht benutzen, aber der ist am oberen Ende, da kommt man selten hin, und wenn doch programmiert sich der BL nicht kaputt, aber dein Programm ist halt kaputt. Arduino weiß das aber und schreibt ja auch "32256 Bytes Flash", der Chip hat aber 32768. Die 512 fehlenden sind der Bootloader. Jürgen K. schrieb: > Wie könnte ich dafür sorgen, dass wenn > ich einen Controller auslese, einen Hinweis finde, welches > Programm/Stand ich als letztes geflasht habe? PICs haben dafür 4 Nibbles "ID", die man setzen kann und auch mit Protection noch auslesen. Peter D. schrieb: > Man kann sich eine _version.c schreiben. Ist das Standard-C oder nur Arduino/AVR-gcc? Geht das auch mit PIC? Aber selbst wenn: Im Hex kann man es nicht lesen, im Controller auch nicht.
Jens M. schrieb: > PICs haben dafür 4 Nibbles "ID", die man setzen kann und auch mit > Protection noch auslesen. Diese Idee finde ich interessant. Wo finde ich diese Nibbles? In den sogenannten ConfigBits?
Jens M. schrieb: > Ist das Standard-C oder nur Arduino/AVR-gcc? PROGMEM ist speziell AVR-GCC, damit die Variablen keinen SRAM belegen. Jens M. schrieb: > Im Hex kann man es nicht lesen, im Controller auch > nicht. Viele Betrachter zeigen neben dem Intel-Hex auch noch die ASCII Darstellung. Im Controller könnte man diese Variablen z.B. nach dem Einschalten auf einem LCD anzeigen oder über ein Interface ausgeben.
Ich gebe mir dank KI mal selbst die Antwort;-) ggf. auch für andere von Interesse. Die „ID“-Nibbles bei PIC-Mikrocontrollern (meist als „User ID“ oder „ID Locations“ bezeichnet) sind spezielle Speicherstellen, die zur individuellen Kennzeichnung eines Chips verwendet werden können. Sie sind unabhängig vom Programmspeicher und dienen z. B. dazu, eine Seriennummer, Versionsnummer oder einen Urheber-Hinweis im Chip zu hinterlegen. Wo findest du die User-ID-Nibbles? Die User-ID-Bereiche befinden sich typischerweise an festen Adressen im Flash-Speicher des PIC, die im jeweiligen Datenblatt des Controllers dokumentiert sind. Bei vielen PICs (z. B. PIC16, PIC18) sind diese „ID Locations“ 4 Bit breit, also ein Nibble pro Speicherstelle . Die Anzahl der User-ID-Nibbles variiert je nach PIC-Modell, häufig stehen 4 bis 8 Nibbles (also 16 bis 32 Bit) zur Verfügung. Die Adressen liegen meist direkt nach dem Programmspeicher, oft ab Adresse 0x200000 und aufwärts (bei neueren PICs), oder an anderen, im Datenblatt spezifizierten Stellen. Wie werden sie programmiert? Die User-ID-Nibbles können beim Programmieren des Chips mit dem Programmer oder über die IDE (z. B. MPLAB X) gesetzt werden. In MPLAB X kannst du sie im „Memory Views“-Fenster oder im Programmer-Dialog unter „User ID Memory“ oder „ID Locations“ eintragen. Sie werden nicht vom Programmcode überschrieben und bleiben unabhängig von Firmware-Updates erhalten, solange sie nicht gezielt gelöscht oder neu programmiert werden. Zusammengefasst: Die User-ID-Nibbles findest du bei PICs an speziellen Adressen im Flash-Speicher, meist als „ID Locations“ bezeichnet. Sie sind 4 Bit breit und werden zur individuellen Kennzeichnung genutzt. Die genaue Adresse und Anzahl entnimmst du dem Datenblatt deines PIC-Modells.
:
Bearbeitet durch User
Jürgen K. schrieb: > Jens M. schrieb: >> PICs haben dafür 4 Nibbles "ID", die man setzen kann und auch mit >> Protection noch auslesen. > > Diese Idee finde ich interessant. Wo finde ich diese Nibbles? In den > sogenannten ConfigBits? Es sind 4 x 7 Bit üblich, nach dem Programmspeicher.
Wird sowas nicht auch von neueren AVRs geboten in der User Signature Row? Hier zum Beispiel ATtiny1614/6/7 (1- Series): > 6.6 **User Row** > > In addition to the EEPROM, the ATtiny1614/1616/1617 has one extra > page of EEPROM memory that can be used for firmware settings, > the User Row (USERROW). This memory supports single byte read and > write as the normal EEPROM. The CPU can write and read this memory > as normal EEPROM and the UPDI can write and read it as a normal > EEPROM memory if the part is unlocked. The User Row can also be > written by the UPDI when the part is locked. USERROW is not > affected by a chip erase. Wobei ich es blöd finde, dass UPDI Userrow bei gelockten Devices nicht ändern kann. Wäre ein netten Feature zur Konfiguration (MAC-Adresse, I²C-Adresse, ...)
:
Bearbeitet durch User
Jürgen K. schrieb: > Wo finde ich diese Nibbles? In den > sogenannten ConfigBits? In den IDs ;) Das funktioniert so ähnlich wie die Config, wie auch immer du die einstellst. Entweder in dem Dialog, oder via Compilerbefehlen, da musst du aber dessen Hilfe fragen. Jürgen K. schrieb: > Ich gebe mir dank KI mal selbst die Antwort Viel geredet, nix gesagt. Im DaBla des Controllers und der Compilerhilfe (oder der der IDE) findest du die echte Info. Johann L. schrieb: > Wobei ich es blöd finde, dass UPDI Userrow bei gelockten Devices nicht > ändern kann. Nicht "LESEN". Oder verstehe ich Johann L. schrieb: > The User Row can also be written by the UPDI when the part is locked. falsch? Ist aber wie du sagst eher Config (MAC, Seriennummer), da nicht lesbar. PICs IDs sind extra dazu da die Software und die Version auch mit Protection identifizieren zu können.
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.