Wir verwenden derzeit einen 32-Bit-PIC32-Mikrocontroller. Es funktioniert gut für unsere Bedürfnisse, aber wir untersuchen auch andere Mikrocontroller, die besser zu uns passen. Wir haben andere Projekte, für die wir MCU auswählen. Zu diesem Zweck haben wir einen ARM-basierten SAM DA- Mikrocontroller ausgewählt, der 32-Bit-basiert, aber ARM-basiert ist (populärer als PIC32 - branchenweit).
Jetzt verwenden wir für PIC32 MPLAB, aber für ARM cortex-M0 verwenden wir Atmel Studio. Wir werden C-Sprache auf beiden Plattformen verwenden. Was mich betrifft, ist, dass wir zwei 32-Bit-Mikrocontroller (von derselben Firma) verwenden, aber unterschiedliche Architekturen haben. Dies erfordert das Erlernen von zwei verschiedenen Geräten und erhöht unsere "Lernkurve" + Lieferzeit. Andererseits denke ich auch, da wir in beiden Fällen C-Language verwenden werden, sollte die Lernkurve für ARM nicht so gehört werden, und es lohnt sich, auch diesen Prozessor zu untersuchen.
Meine Hauptfrage ist, wie groß der Unterschied ist, den die Architektur beim Programmieren in C-Language macht, da sie eine Abstraktion der Interna des Mikrocontrollers bietet. Und was sind die Hauptunterschiede zwischen MPLAP und Atmel Studio in Bezug auf die Programmierung in C-Sprache?
quelle
Antworten:
Dies ist ein ziemlich einfühlsames Thema. Ich kann für mich selbst sprechen (AVR, ARM, MSP430).
Unterschied 1 (am signifikantesten) liegt in den Peripheriegeräten. Jede der MCUs hat ähnliche UART, SPI, Timer usw. - nur Registernamen und Bits sind unterschiedlich. Die meiste Zeit war es das Hauptproblem, mit dem ich mich befassen musste, wenn ich Code zwischen Chips verschob. Lösung: Schreiben Sie Ihre Treiber mit einer gemeinsamen API, damit Ihre Anwendung portabel ist.
Unterschied 2 ist die Speicherarchitektur. Wenn Sie Konstanten in Flash auf einem AVR platzieren möchten, müssen Sie spezielle Attribute und spezielle Funktionen verwenden, um sie zu lesen. In der ARM-Welt dereferenzieren Sie nur einen Zeiger, weil es einen einzelnen Adressraum gibt (ich weiß nicht, wie kleine PICs damit umgehen, würde aber annehmen, dass sie näher am AVR liegen).
Unterschied 3 ist die Interrupt-Deklaration und -Handhabung.
avr-gcc
hat dasISR()
Makro. ARM hat nur einen Funktionsnamen (wie someUART_Handler () - wenn Sie CMSIS-Header und Startcode verwenden). ARM-Interrupt-Vektoren können überall platziert werden (einschließlich RAM) und zur Laufzeit geändert werden (sehr praktisch, wenn Sie beispielsweise zwei verschiedene UART-Protokolle haben, die umgeschaltet werden können). AVR hat nur die Möglichkeit, Vektoren entweder im "Haupt-Flash" oder im "Bootloader-Bereich" zu verwenden (wenn Sie Interrupts also anders behandeln möchten, müssen Sie eineif
Anweisung verwenden).Unterschied 4 - Schlafmodi und Leistungsregelung. Wenn Sie den geringsten Stromverbrauch benötigen, müssen Sie alle Funktionen der MCU nutzen. Dies kann zwischen den MCUs sehr unterschiedlich sein - einige haben gröbere Energiesparmodi, andere können einzelne Peripheriegeräte aktivieren / deaktivieren. Einige MCUs haben einstellbare Regler, so dass Sie sie mit niedrigerer Spannung bei langsamerer Geschwindigkeit usw. betreiben können. Ich sehe keinen einfachen Weg, um den gleichen Wirkungsgrad auf einer MCU (sagen wir) mit 3 globalen Leistungsmodi und einem anderen mit 7 Leistungsmodi und zu erzielen individuelle periphere Taktsteuerung.
Das Wichtigste bei der Portabilität ist die klare Aufteilung Ihres Codes in hardwareabhängige (Treiber) und hardwareunabhängige (Anwendungs-) Teile. Sie können letzteres auf einem normalen PC mit einem Mock-Treiber (z. B. Konsole anstelle eines UART) entwickeln und testen. Dies hat mich viele Male gerettet, da 90% des Anwendungscodes vollständig waren, bevor die Prototyp-Hardware aus dem Reflow-Ofen kam :)
Meiner Meinung nach ist das Gute an ARM die "Monokultur" - Verfügbarkeit vieler Compiler (gcc, Keil, IAR ... um nur einige zu nennen), vieler kostenloser und offiziell unterstützter IDEs (zumindest für NXP, STM32, Silicon Labs, Nordic), viele Debug-Tools (SEGGER - insbesondere Ozone, ULINK, OpenOCD ...) und viele Chiphersteller (ich werde sie nicht einmal benennen). Der PIC32 ist größtenteils auf Microchip beschränkt (aber es ist nur wichtig, wenn Sie die Werkzeuge nicht mögen.
Wenn es um C-Code geht. Es ist zu 99% gleich, eine
if
Anweisung ist gleich, eine Schleife funktioniert genauso. Sie sollten sich jedoch um die native Wortgröße kümmern. Beispielsweise ist einefor
Schleife auf einem AVR am schnellsten, wenn Sie sieuint8_t
für den Zähler verwenden, während auf ARMuint32_t
der schnellste Typ (oderint32_t
) ist. ARM müsste jedes Mal auf 8-Bit-Überlauf prüfen, wenn Sie einen kleineren Typ verwenden.Bei der Auswahl einer MCU und / oder eines Anbieters im Allgemeinen geht es hauptsächlich um Politik und Logistik (es sei denn, Sie haben sehr klare technische Einschränkungen, zum Beispiel: Hochtemperatur - verwenden Sie MSP430 oder Vorago). Selbst wenn die Anwendung auf irgendetwas ausgeführt werden kann und nur 5% des Codes (Treibers) über die Produktlebensdauer entwickelt und unterstützt werden müssen, sind dies immer noch zusätzliche Kosten für das Unternehmen. Alle Orte, an denen ich gearbeitet habe, hatten einen bevorzugten Anbieter und eine MCU-Linie (wie "Wählen Sie einen beliebigen Kinetis aus, es sei denn, es gibt einen sehr guten Grund, etwas anderes zu wählen"). Es ist auch hilfreich, wenn andere Personen um Hilfe bitten müssen. Als Manager würde ich es vermeiden, eine 5-köpfige Entwicklungsabteilung zu haben, in der jeder einen völlig anderen Chip verwendet.
quelle
Ich habe mehrere MCUs von vier verschiedenen Herstellern verwendet. Die Hauptaufgabe besteht jedes Mal darin, sich mit den Peripheriegeräten vertraut zu machen.
Zum Beispiel ist ein UART selbst nicht zu komplex und ich finde meinen Treiberport leicht. Aber das letzte Mal, als ich fast einen Tag brauchte, um die Uhren, E / A-Pins zu unterbrechen, zu aktivieren usw. zu sortieren.
Das GPIO kann sehr komplex sein. Bit gesetzt, Bit gelöscht, Bit umgeschaltet, Sonderfunktionen aktivieren / deaktivieren, Tri-State. Als nächstes erhalten Sie Interrupts: Any-Edge, Rise, Fall, Level-Low, Level-High, Self Clearing oder nicht.
Dann gibt es I2C, SPI, PWM, Timer und zwei Dutzend weitere Arten von Peripheriegeräten mit jeweils eigenen Taktfreigaben und jedes Mal, wenn sich die Register mit neuen Bits unterscheiden. Für all diese dauert es viele, viele Stunden, das Datenblatt zu lesen, wie unter welchen Umständen welches Bit gesetzt wird.
Der letzte Hersteller hatte viele Codebeispiele, die ich als unbrauchbar empfand. Alles wurde abstrahiert. Aber als ich es aufgespürt habe, hat der Code sechs durchlaufen ! Ebenen von Funktionsaufrufen zum Setzen eines GPIO-Bits. Schön, wenn Sie einen 3-GHz-Prozessor haben, aber keine MCU mit 48 MHz. Mein Code am Ende war eine einzelne Zeile:
Ich habe versucht, allgemeinere Treiber zu verwenden, aber ich habe aufgegeben. Auf einer MCU haben Sie immer Probleme mit Platz- und Taktzyklen. Ich fand heraus, dass die Abstraktionsschicht die erste ist, die aus dem Fenster geht, wenn Sie eine bestimmte Wellenform in einer Interruptroutine erzeugen, die bei 10 kHz aufgerufen wird.
Jetzt funktioniert also alles und ich plane, NICHT wieder zu wechseln, es sei denn aus einem sehr, sehr guten Grund.
Alle oben genannten Punkte müssen über die Anzahl der von Ihnen verkauften Produkte und die Einsparungen abgeschrieben werden. Eine Million verkaufen: Wenn Sie 0,10 sparen, um zu einem anderen Typ zu wechseln, können Sie 100.000 für Software-Arbeitsstunden ausgeben. Wenn Sie 1000 verkaufen, müssen Sie nur 100 ausgeben.
quelle
OUTPUT_HI(n)
das Code erhalten wird, derGPIOD->bssr |= 0x400;
if entspricht, wennn
eine Konstante wie 0x6A ist, aber eine einfache Subroutine aufruft, wennn
is nicht konstant. Abgesehen davon bewegen sich die meisten Anbieter-APIs, die ich gesehen habe, zwischen mittelmäßig und schrecklich.Dies ist eher eine Meinung / ein Kommentar als eine Antwort.
Sie wollen und sollten nicht in C. programmieren. C ++ ist bei richtiger Verwendung weit überlegen. (OK, ich muss zugeben, wenn es falsch verwendet wird, ist es weitaus schlimmer als C.) Das beschränkt Sie auf Chips, die einen (modernen) C ++ - Compiler haben, der ungefähr alles ist, was von GCC unterstützt wird, einschließlich AVR (mit Bei einigen Einschränkungen erwähnt Filo die Probleme eines ungleichmäßigen Adressraums, schließt jedoch fast alle PICs aus (PIC32 könnte unterstützt werden, aber ich habe noch keinen anständigen Port gesehen).
Wenn Sie Algorithmen in C / C ++ programmieren, ist der Unterschied zwischen den von Ihnen erwähnten Auswahlmöglichkeiten gering (mit der Ausnahme, dass ein 8- oder 16-Bit-Chip einen schwerwiegenden Nachteil hat, wenn Sie viel 16-, 32- oder höhere Bit-Arithmetik ausführen). Wenn Sie die letzte Unze Leistung benötigen, müssen Sie wahrscheinlich Assembler verwenden (entweder Ihren eigenen oder den vom Anbieter oder einem Dritten bereitgestellten Code). In diesem Fall möchten Sie möglicherweise den von Ihnen ausgewählten Chip erneut berücksichtigen.
Wenn Sie auf die Hardware codieren, können Sie entweder eine Abstraktionsschicht (häufig vom Hersteller bereitgestellt) verwenden oder eine eigene schreiben (basierend auf dem Datenblatt und / oder dem Beispielcode). IME-vorhandene C-Abstraktionen (mbed, cmsis, ...) sind häufig funktional (fast) korrekt, versagen jedoch in Bezug auf Leistung (überprüfen Sie, ob oldfarts etwa 6 Indirektionsebenen für eine Pin-Set-Operation enthält), Benutzerfreundlichkeit und Portabilität. Sie möchten Ihnen alle Funktionen des jeweiligen Chips zur Verfügung stellen, die Sie in fast allen Fällen nicht benötigen und sich nicht darum kümmern, und sie sperren Ihren Code für diesen bestimmten Anbieter (und wahrscheinlich für diesen bestimmten Chip).
Hier kann C ++ viel besser: Wenn es richtig gemacht wird, kann ein Pin-Set 6 oder mehr Abstraktionsschichten durchlaufen (da dies eine bessere (tragbare!) Schnittstelle und kürzeren Code ermöglicht) und dennoch eine Schnittstelle bereitstellen, die zielunabhängig ist für die einfachen Fälle und führen immer noch zu demselben Maschinencode, den Sie in Assembler schreiben würden .
Ein Ausschnitt aus dem von mir verwendeten Codierungsstil, der Sie entweder begeistern oder sich entsetzt abwenden kann:
In Wirklichkeit gibt es noch einige weitere Abstraktionsebenen. Die endgültige Verwendung der LED, sagen wir zum Einschalten, zeigt jedoch nicht die Komplexität oder die Details des Ziels (für ein Arduin Uno oder eine blaue ST32-Pille wäre der Code identisch).
Der Compiler lässt sich von all diesen Ebenen nicht einschüchtern, und da keine virtuellen Funktionen beteiligt sind, sieht der Optimierer alles durch (einige Details wurden weggelassen, z. B. das Aktivieren der Peripherietakt):
So hätte ich es in Assembler geschrieben - WENN ich erkannt hätte, dass die PIO-Register mit Offsets von einer gemeinsamen Basis verwendet werden können. In diesem Fall würde ich wahrscheinlich, aber der Compiler kann solche Dinge weitaus besser optimieren als ich.
Soweit ich eine Antwort habe, lautet diese: Schreiben Sie eine Abstraktionsschicht für Ihre Hardware, aber tun Sie dies in modernem C ++ (Konzepte, Vorlagen), damit Ihre Leistung nicht beeinträchtigt wird. Mit dieser Funktion können Sie problemlos zu einem anderen Chip wechseln. Sie können sogar mit der Entwicklung auf einem zufälligen Chip beginnen, den Sie herumliegen, mit dem Sie vertraut sind, für den Sie gute Debugging-Tools haben usw. und die endgültige Auswahl auf später verschieben (wenn Sie weitere Informationen über den erforderlichen Speicher, die CPU-Geschwindigkeit usw. haben).
IMO ist eine der Falschheiten der eingebetteten Entwicklung die Auswahl des Chips zuerst (es ist eine Frage, die in diesem Forum häufig gestellt wird: Für welchen Chip soll ich mich entscheiden ... Die beste Antwort ist im Allgemeinen: Es spielt keine Rolle.)
(Bearbeiten - Antwort auf "In Bezug auf die Leistung wäre C oder C ++ also auf dem gleichen Niveau?")
Für dieselben Konstrukte sind C und C ++ identisch. C ++ hat viel mehr Konstrukte für die Abstraktion (nur einige: Klassen, Vorlagen, constexpr), die wie jedes Tool zum Guten oder zum Schlechten verwendet werden können. Um die Diskussionen interessanter zu gestalten: Nicht alle sind sich einig, was gut oder schlecht ist ...
quelle
Wenn ich das richtig verstehe, möchten Sie wissen, welche architekturspezifischen Funktionen der Plattform in Ihrer C-Sprachumgebung "auftauchen", was es schwieriger macht, wartbaren, portablen Code auf beiden Plattformen zu schreiben.
C ist bereits sehr flexibel, da es sich um einen "tragbaren Assembler" handelt. Für alle von Ihnen ausgewählten Plattformen stehen GCC- / kommerzielle Compiler zur Verfügung, die die Sprachstandards C89 und C99 unterstützen. Dies bedeutet, dass Sie auf allen Plattformen ähnlichen Code ausführen können.
Es gibt einige Überlegungen:
Einige Plattformen / Compiler können diese "Einschränkung" besser verbergen als andere. Bei AVR müssen Sie beispielsweise bestimmte Makros verwenden, um ROM-Daten zu lesen. Auf PIC24 / dsPIC stehen auch spezielle tblrd-Anweisungen zur Verfügung. Darüber hinaus ist in einigen Teilen jedoch auch die Funktion "Programmbereichssichtbarkeit" (PSVPAG) verfügbar, mit der eine Seite des FLASH dem RAM zugeordnet werden kann, sodass eine sofortige Datenadressierung ohne tblrd verfügbar ist. Der Compiler kann dies sehr effektiv tun.
ARM und MIPS sind Von Neumann, wodurch Speicherbereiche für ROM, RAM und Peripheriegeräte auf 1 Bus gepackt sind. Sie werden keinen Unterschied zwischen dem Lesen von Daten aus dem RAM oder "ROM" bemerken.
Andererseits ermöglicht ein PIC24 ALU-Operationen, Daten direkt über indirekte Adressierung zu lesen und zu schreiben (auch bei Zeigermodifikationen ..). Dies hat einige Eigenschaften einer CISC-ähnlichen Architektur, sodass 1 Befehl mehr Arbeit leisten kann. Dieses Design kann zu komplexeren CPU-Kernen, niedrigeren Takten, höherem Stromverbrauch usw. führen. Zum Glück ist das Teil bereits entworfen. ;-);
Diese Unterschiede können bedeuten, dass ein PIC24 für E / A-Operationen "druckvoller" sein kann als ein ähnlich getakteter ARM- oder MIPS-Chip. Möglicherweise erhalten Sie jedoch ein viel höheres ARM / MIPS-Teil für den gleichen Preis, das gleiche Paket und das gleiche Design. Ich denke, aus praktischen Gründen denke ich, dass viel "Lernen der Plattform" in den Griff bekommt, was die Architektur kann und was nicht, wie schnell einige Operationen sein werden usw.
Diese Unterschiede können durch Gerätetreiber etwas gekapselt werden, aber letztendlich hat die eingebettete Firmware einen hohen Grad an Kopplung mit der Hardware, so dass benutzerdefinierte Arbeiten manchmal nicht vermieden werden können.
Wenn Sie die Ökosysteme von Microchip / Ex-Atmel verlassen, müssen Sie möglicherweise feststellen, dass ARM-Teile mehr Setup erfordern, um sie zum Laufen zu bringen. Ich meine in Bezug auf; Aktivieren von Uhren für Peripheriegeräte, anschließendes Konfigurieren und "Aktivieren" von Peripheriegeräten, separates Einrichten von NVIC usw. Dies ist nur ein Teil der Lernkurve. Wenn Sie daran denken, all diese Dinge in der richtigen Reihenfolge zu tun, wird sich das Schreiben von Gerätetreibern für all diese Mikrocontroller irgendwann ziemlich ähnlich anfühlen.
quelle
Ja und nein. Aus Sicht des Programmierers verbergen Sie idealerweise die Details des Befehlssatzes. Aber das ist zum Teil schon nicht relevant. Die Peripheriegeräte, auf die sich das Programm bezieht, sind nicht Teil des Befehlssatzes. Gleichzeitig können Sie nicht nur 4096Byte-Flash-Teile über diese Befehlssätze hinweg vergleichen, insbesondere wenn Sie C verwenden. Der Verbrauch des Flashs / Speichers wird stark vom Befehlssatz und vom Compiler bestimmt. Einige sollten niemals einen Compiler sehen (Husten-PIC) Husten) aufgrund dessen, wie viel Abfall dieser Ressourcen beim Kompilieren verbraucht wird. Andere Flash-Verbrauch ist ein geringerer Overhead. Die Leistung ist auch ein Problem bei der Verwendung einer Hochsprache und Leistungsaspekte in MCU-Anwendungen. Daher kann es einen Unterschied machen, ob Sie 3 US-Dollar pro Board für das MCU oder 1 US-Dollar ausgeben.
Wenn es darum geht, die Programmierung zu vereinfachen (zu den Gesamtkosten des Produkts), sollten Sie in der Lage sein, ein Entwicklerpaket für das mcu herunterzuladen, sodass die Befehlssatzarchitektur etwas ist, das Sie nie sehen. Wenn dies Ihr Hauptanliegen ist, ist dies der Fall ist kein Problem. Die Verwendung dieser Bibliotheken kostet Sie immer noch Geld, was die Kosten des Produkts angeht. Da die Markteinführungszeit jedoch möglicherweise kürzer ist, benötigen die Bibliotheken mehr Zeit / Arbeit als die direkte Kommunikation mit den Peripheriegeräten.
Unterm Strich sind die Befehlssätze die geringste Sorge. Fahren Sie mit echten Problemen fort.
quelle