PIC32 vs dsPIC vs ARM vs AVR, spielt die Architektur eine Rolle, wenn wir sowieso in C-Sprache programmieren? [geschlossen]


10

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?


2
Wenn die Dinge mit dem PIC32 funktionieren, wozu sollte man dann wechseln? Auch wenn der Code vollständig portiert ist (nicht), gibt es immer noch die neue Toolkette und IDE, an die man sich gewöhnen muss. Was ist der Sinn? Aus religiösen Gründen zu wechseln oder "ARM-basiert" (oder irgendetwas anderes) zu sein, ist dumm. Sie müssen einen guten Grund haben, aber Sie haben uns keinen gezeigt.
Olin Lathrop

Ich habe nicht nach einem Wechsel gefragt. Ich habe darüber gesprochen, eine andere Architektur für andere Projekte zu wählen, da wir an mehreren Projekten arbeiten. Es gibt Raum für Verbesserungen in unserem bestehenden Design. Der Hauptpunkt war die Lernkurve und die Herausforderungen bei der gleichzeitigen Arbeit mit zwei verschiedenen Architekturen.
Ingenieur

Eine Sache, die ich gefunden habe, dass Atmel Studio überlegenes Timing bietet als MPLAB Youtube Video
Ingenieur

Antworten:


20

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-gcchat das ISR()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 eine ifAnweisung 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 ifAnweisung ist gleich, eine Schleife funktioniert genauso. Sie sollten sich jedoch um die native Wortgröße kümmern. Beispielsweise ist eine forSchleife auf einem AVR am schnellsten, wenn Sie sie uint8_tfür den Zähler verwenden, während auf ARM uint32_tder schnellste Typ (oder int32_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.


3
„AVR ist am schnellsten, wenn Sie uint8_t für den Zähler verwenden, während uint32_t auf ARM der schnellste Typ (oder int32_t) ist. ARM müsste jedes Mal auf 8-Bit-Überlauf prüfen, wenn Sie einen kleineren Typ verwenden würden. “ Sie können uint_fast8_t verwenden, wenn Sie nur mindestens 8 Bit benötigen.
Michael

@Michael - sicher können Sie die _fast-Typen verwenden, aber Sie können sich nicht auf das Überlaufverhalten verlassen. In meinem gcc's stdint.h habe ich "typedef unsigned int uint_fast8_t", was im Grunde ein uint32_t ist :)
filo

Der Versuch, eine API zu schreiben, die effizient, universell und vollständig ist, ist schwierig, da verschiedene Plattformen unterschiedliche Fähigkeiten haben. Die CPU ist wahrscheinlich weniger wichtig als die Peripheriegeräte und die mit ihnen getroffenen Entwurfsentscheidungen. Beispielsweise können bei einigen Geräten verschiedene Peripheriegeräte jederzeit in höchstens wenigen Mikrosekunden neu konfiguriert werden, während bei anderen Geräten möglicherweise mehrere Schritte über Hunderte von Mikrosekunden oder sogar Millisekunden verteilt sind. Eine API-Funktion, die für das vorherige Muster vorgesehen ist, kann innerhalb einer Interrupt-Serviceroutine verwendet werden, die mit 10.000 Hz ausgeführt wird, aber ...
Supercat

... konnte eine solche Verwendung auf Plattformen nicht unterstützen, bei denen der Betrieb über Hunderte von Mikrosekunden verteilt werden müsste. Ich weiß nicht, warum Hardware-Designer nicht sehr bemüht zu sein scheinen, die API-Semantik "Schnelle Operation zu jeder Zeit" zu unterstützen, aber viele verwenden ein Modell, das einzelne Operationen synchronisiert, anstatt anzugeben, ob z. B. eine Anfrage an sie gestellt wurde Schalten Sie ein Gerät ein und der Code erkennt, dass es nicht eingeschaltet sein muss. Der Code muss warten, bis sich das Gerät einschaltet, bevor er die Anforderung zum Ausschalten ausgeben kann. Die reibungslose Handhabung in einer API führt zu erheblichen Komplikationen.
Supercat

11

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:

GPIO->set_output = bit.

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.


1
Persönlich bleibe ich deshalb beim Assembler. Schöne Binärdatei, keine Abstraktion.
Ian Bland

Der Präprozessor von C kann ziemlich gut mit Dingen umgehen, insbesondere wenn er mit __builtin_constant intrinsics kombiniert wird. Wenn man Konstanten für jedes E / A-Bit des Formulars definiert (Portnummer * 32 + Bitnummer), ist es möglich, ein Makro zu schreiben, für OUTPUT_HI(n)das Code erhalten wird, der GPIOD->bssr |= 0x400;if entspricht, wenn neine Konstante wie 0x6A ist, aber eine einfache Subroutine aufruft, wenn nis nicht konstant. Abgesehen davon bewegen sich die meisten Anbieter-APIs, die ich gesehen habe, zwischen mittelmäßig und schrecklich.
Supercat

8

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:

// GPIO part of a HAL for atsam3xa
enum class _port { a = 0x400E0E00U, . . . };

template< _port P, uint32_t pin >
struct _pin_in_out_base : _pin_in_out_root {

   static void direction_set_direct( pin_direction d ){
      ( ( d == pin_direction::input )
         ? ((Pio*)P)->PIO_ODR : ((Pio*)P)->PIO_OER )  = ( 0x1U << pin );
   }

   static void set_direct( bool v ){
      ( v ? ((Pio*)P)->PIO_SODR : ((Pio*)P)->PIO_CODR )  = ( 0x1U << pin );    
   }
};

// a general GPIO needs some boilerplate functionality
template< _port P, uint32_t pin >
using _pin_in_out = _box_creator< _pin_in_out_base< P, pin > >;

// an Arduino Due has an on-board led, and (suppose) it is active low
using _led = _pin_in_out< _port::b, 27 >;
using led  = invert< pin_out< _led > >;

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

target::led::init();
target::led::set( 1 );

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

 mov.w  r2, #134217728  ; 0x8000000
 ldr    r3, [pc, #24]   
 str    r2, [r3, #16]
 str    r2, [r3, #48]   

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 ...


In Bezug auf die Leistung wäre C oder C ++ also auf dem gleichen Niveau? Ich würde denken, dass C ++ mehr Überlastung haben wird. Auf jeden Fall haben Sie mich in die richtige Richtung gelenkt, C ++ ist der richtige Weg, nicht C.
Ingenieur

C ++ - Vorlagen erzwingen einen Polymorphismus zur Kompilierungszeit, der hinsichtlich der Leistung keine (oder sogar negative) Kosten verursachen kann, da der Code für jeden spezifischen Anwendungsfall kompiliert wird. Dies eignet sich jedoch am besten für die Zielgeschwindigkeit (O3 für GCC). Laufzeitpolymorphismus kann wie virtuelle Funktionen eine viel größere Strafe erleiden, obwohl er möglicherweise einfacher zu warten und in einigen Fällen gut genug ist.
Hans

1
Sie behaupten, dass C ++ besser ist, aber dann verwenden Sie Casts im C-Stil. Zum Schämen.
JAB

@JAB Ich habe nie viel für die neuen Casts empfunden, aber ich werde es versuchen. Meine derzeitige Priorität liegt jedoch in anderen Teilen dieser Bibliothek. Das eigentliche Problem ist natürlich, dass ich die Zeiger nicht als Vorlagenparameter übergeben konnte.
Wouter van Ooijen

@Hans my cto-Stil (Compile Time Objects) hat einen eher engen Anwendungsfall (in der Nähe der Hardware, bekannte Situation zur Kompilierungszeit). Er ist eher ein C-Killer als ein Ersatz für die traditionelle Verwendung von virtuellem OO. Ein nützlicher Beifang ist, dass das Fehlen einer Indirektion die Berechnung der Stapelgröße ermöglicht.
Wouter van Ooijen

4

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 Architekturen sind Von Neumann (ARM, MIPS), andere sind Harvard. Die Hauptbeschränkungen treten auf, wenn Ihr C-Programm Daten aus dem ROM lesen muss, z. B. um Zeichenfolgen zu drucken, Daten als "const" oder ähnlich definiert haben.

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.

  • Wenn Sie unter C tauchen und sich die generierten Anweisungen für bestimmte Operationen ansehen, werden Sie einige große Unterschiede in Bezug auf E / A feststellen. ARM und MIPS sind RISC- Load-Store-Registerarchitekturen . Dies bedeutet, dass der Datenzugriff auf den Speicherbus MOV-Anweisungen durchlaufen muss. Dies bedeutet auch, dass jede Änderung eines Peripheriewerts zu einer RMW-Operation (Read-Modify-Write) führt. Es gibt einige ARM-Teile, die Bit-Banding unterstützen und die Set / Clr-Bit-Register im E / A-Peripherieraum zuordnen. Sie müssen diesen Zugriff jedoch selbst codieren.

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.

  • Peripheriegeräte, Uhrenverwaltung usw. unterscheiden sich je nach Teilefamilie. Genau genommen wird sich dies auch innerhalb des ARM-Ökosystems zwischen Anbietern ändern, mit Ausnahme einiger Cortex m-gebundener Peripheriegeräte wie NVIC und SysTick.

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.

  • Versuchen Sie auch, Bibliotheken wie stdint.h, stdbool.h usw. zu verwenden, wenn Sie dies noch nicht getan haben. Diese Ganzzahltypen machen die Breiten explizit, wodurch das Codeverhalten zwischen den Plattformen am vorhersehbarsten ist. Dies kann die Verwendung von 32-Bit-Ganzzahlen auf einem 8-Bit-AVR bedeuten. Aber wenn Ihr Code es braucht, soll es so sein.

3

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.