Nous utilisons actuellement un microcontrôleur PIC32 32 bits. Cela fonctionne bien pour nos besoins, mais nous explorons également d'autres microcontrôleurs qui peuvent mieux nous adapter + nous avons d'autres projets pour lesquels nous sélectionnons MCU. À cet effet, nous avons sélectionné le microcontrôleur SAM DA basé sur ARM, qui est le même 32 bits mais est basé sur ARM (plus populaire que PIC32 - en termes d'industrie).
Maintenant, pour PIC32, nous utilisons MPLAB mais pour ARM cortex-M0, nous utiliserons Atmel Studio. Nous utiliserons le langage C sur les deux plates-formes. Ce qui me préoccupe, c'est que nous utiliserons deux microcontrôleurs 32 bits (de la même entreprise) mais avec des architectures différentes. Cela nous obligera à apprendre deux appareils différents et augmentera notre "courbe d'apprentissage" + le délai de livraison. Mais d'un autre côté, je pense également que puisque nous utiliserons le langage C dans les deux cas, la courbe d'apprentissage pour ARM ne devrait pas être aussi entendue et cela vaut la peine d'explorer ce processeur également.
Ma question principale est de savoir quelle différence l'architecture fait lorsque nous programmons en langage C car elle fournit une abstraction des internes du microcontrôleur. Et quelles sont les principales différences entre MPLAP et Atmel Studio , compte tenu de la programmation en langage C.
la source
Réponses:
C'est tout à fait un sujet d'opinion. Je peux parler pour moi (AVR, ARM, MSP430).
La différence 1 (la plus significative) concerne les périphériques. Chacun des MCU a des UART, SPI, temporisateurs, etc. similaires - les noms de registre et les bits sont différents. La plupart du temps, c'était le principal problème avec lequel je devais faire face lors du déplacement de code entre puces. Solution: écrivez vos pilotes avec une API commune, afin que votre application puisse être portable.
La différence 2 est l'architecture de la mémoire. Si vous souhaitez placer des constantes en flash sur un AVR, vous devez utiliser des attributs spéciaux et des fonctions spéciales pour les lire. Dans le monde ARM, vous déréférencez simplement un pointeur car il n'y a qu'un seul espace d'adressage (je ne sais pas comment les petits PIC le gèrent, mais supposeraient qu'ils sont plus proches d'AVR).
La différence 3 est la déclaration et la gestion des interruptions.
avr-gcc
a laISR()
macro. ARM a juste un nom de fonction (comme someUART_Handler () - si vous utilisez des en-têtes CMSIS et du code de démarrage). Les vecteurs d'interruption ARM peuvent être placés n'importe où (y compris la RAM) et modifiés au moment de l'exécution (très pratique si vous avez par exemple deux protocoles UART différents qui peuvent être commutés). AVR n'a que la possibilité d'utiliser des vecteurs soit dans "flash principal" soit dans la "section du chargeur de démarrage" (donc si vous voulez gérer les interruptions différemment, vous devez utiliser uneif
instruction).Différence 4 - modes de veille et contrôle de l'alimentation. Si vous avez besoin de la plus faible consommation d'énergie, vous devez niveler toutes les fonctionnalités du MCU. Cela peut différer considérablement entre les MCU - certains ont des modes d'économie d'énergie plus grossiers, certains peuvent activer / désactiver des périphériques individuels. Certains MCU ont des régulateurs réglables afin que vous puissiez les faire fonctionner avec une tension inférieure à une vitesse plus lente, etc. Je ne vois pas de moyen facile d'obtenir la même efficacité sur un MCU (disons) avec 3 modes de puissance globale et un autre avec 7 modes de puissance contrôle individuel de l'horloge périphérique.
La chose la plus importante lorsque vous vous souciez de la portabilité est de diviser clairement votre code en parties dépendantes du matériel (pilotes) et indépendantes du matériel (application). Vous pouvez développer et tester ce dernier sur un PC ordinaire avec un faux pilote (par exemple une console au lieu d'un UART). Cela m'a sauvé plusieurs fois car 90% du code d'application était terminé avant que le matériel prototype ne sorte du four de refusion :)
À mon avis, la bonne chose à propos d'ARM est la "monoculture" - la disponibilité de nombreux compilateurs (gcc, Keil, IAR ... pour n'en nommer que quelques-uns), de nombreux IDE gratuits et officiellement pris en charge (au moins pour NXP, STM32, Silicon Labs, Nordic), de nombreux outils de débogage (SEGGER - en particulier Ozone, ULINK, OpenOCD ...) et de nombreux fournisseurs de puces (je ne vais même pas commencer à les nommer). Le PIC32 est principalement limité à Microchip (mais cela n'a d'importance que si vous n'aimez pas leurs outils.
En ce qui concerne le code C. C'est 99% pareil, une
if
déclaration est la même, une boucle fonctionne de la même manière. Cependant, vous devez vous soucier de la taille du mot natif. Par exemple, unefor
boucle sur un AVR est la plus rapide si vous utilisezuint8_t
pour le compteur, tandis que sur ARMuint32_t
est le type le plus rapide (ouint32_t
). ARM devra vérifier chaque fois le débordement de 8 bits si vous utilisez un type plus petit.La sélection d'un MCU et / ou d'un fournisseur en général concerne principalement la politique et la logistique (sauf si vous avez des contraintes d'ingénierie très claires, par exemple: haute température - utilisez MSP430 ou Vorago). Même si l'application peut fonctionner sur n'importe quoi et que seulement 5% du code (pilotes) doit être développé et pris en charge pendant la durée de vie du produit - c'est toujours un coût supplémentaire pour l'entreprise. Tous les endroits où j'ai travaillé avaient un fournisseur préféré et une gamme de microcontrôleurs (comme "choisissez les Kinetis que vous voulez, sauf s'il y a une très bonne raison de choisir quelque chose de différent"). Cela aide également si vous avez d'autres personnes pour demander de l'aide, donc en tant que responsable, j'éviterais d'avoir un service de développement de 5 personnes où tout le monde utilise une puce totalement différente.
la source
J'ai utilisé plusieurs MCU de quatre fabricants différents. Le travail principal à chaque fois est de se familiariser avec les périphériques.
Par exemple, un UART lui-même n'est pas trop complexe et je trouve facilement le port de mes pilotes. Mais la dernière fois, il m'a fallu presque un jour pour régler les horloges, les broches d'E / S, les activer, etc.
Le GPIO peut être très complexe. Bit-set, bit-clear, bit-toggle, Activation / désactivation des fonctions spéciales, trois états. Ensuite, vous obtenez des interruptions: n'importe quel bord, montée, chute, niveau bas, niveau haut, auto-compensation ou non.
Ensuite, il y a I2C, SPI, PWM, Timers et deux douzaines de types de périphériques supplémentaires chacun avec leur propre horloge active et chaque fois que les registres sont différents avec de nouveaux bits. Pour tous ceux-ci, il faut de nombreuses heures à lire la fiche technique pour définir quel bit dans quelles circonstances.
Le dernier fabricant avait beaucoup d'exemples de code que j'ai trouvé inutilisables. Tout était abstrait. Mais quand je l'ai retrouvé, le code est passé par six! niveaux d'appels de fonction pour définir un bit GPIO. Bien si vous avez un processeur 3GHz mais pas sur un MCU de 48MHz. Mon code à la fin était une seule ligne:
J'ai essayé d'utiliser des pilotes plus génériques mais j'ai abandonné. Sur un MCU, vous êtes toujours aux prises avec des cycles d'espace et d'horloge. J'ai trouvé que la couche d'abstraction est la première à sortir de la fenêtre si vous générez une forme d'onde spécifique dans une routine d'interruption appelée à 10 KHz.
Alors maintenant, tout fonctionne et je prévois de ne PAS changer à nouveau, sauf pour une très, très bonne raison.
Tout ce qui précède doit être amorti sur le nombre de produits que vous vendez et sur ce que vous économisez. Vendre un million: économiser 0,10 pour passer à un autre type signifie que vous pouvez dépenser 100 000 heures logicielles. En vendant 1000, vous n'en avez que 100 à dépenser.
la source
OUTPUT_HI(n)
laquelle donnera un code équivalent àGPIOD->bssr |= 0x400;
ifn
est une constante comme 0x6A, mais appelez un sous-programme simple ifn
is pas constant. Cela dit, la plupart des API des fournisseurs que j'ai vues varient entre médiocres et horribles.Il s'agit plus d'une opinion / d'un commentaire que d'une réponse.
Vous ne voulez pas et ne devriez pas programmer en C. C ++, lorsqu'il est utilisé de la bonne façon , est de loin supérieur. (OK, je dois admettre que lorsqu'il est utilisé de manière incorrecte, il est bien pire que C.) Cela vous limite aux puces qui ont un compilateur C ++ (moderne), qui est à peu près tout ce qui est pris en charge par GCC, y compris AVR (avec certaines limitations, filo mentionne les problèmes d'un espace d'adressage non uniforme), mais en excluant presque tous les PIC (PIC32 pourrait être pris en charge, mais je n'ai pas encore vu de port décent).
Lorsque vous programmez des algorithmes en C / C ++, la différence entre les choix que vous mentionnez est faible (sauf qu'une puce de 8 ou 16 bits sera fortement désavantagée lorsque vous effectuez beaucoup d'arithmétique de 16, 32 bits ou plus). Lorsque vous avez besoin de la dernière once de performances, vous devrez probablement utiliser l'assembleur (le vôtre ou le code fourni par le fournisseur ou un tiers). Dans ce cas, vous voudrez peut-être reconsidérer la puce que vous avez sélectionnée.
Lorsque vous codez pour le matériel, vous pouvez utiliser une couche d'abstraction (souvent fournie par le fabricant) ou écrire la vôtre (sur la base de la fiche technique et / ou d'un exemple de code). Les abstractions C existantes d'IME (mbed, cmsis, ...) sont souvent fonctionnellement (presque) correctes, mais échouent horriblement en termes de performances (vérifiez les oldfarts rant environ 6 couches d'indirection pour une opération de jeu de broches), l'utilisabilité et la portabilité. Ils veulent vous exposer toutes les fonctionnalités de la puce particulière, dont dans presque tous les cas vous n'aurez pas besoin et ne vous souciez pas, et cela verrouille votre code à ce fournisseur particulier (et probablement à cette puce particulière).
C'est là que le C ++ peut faire beaucoup mieux: lorsqu'il est fait correctement, un ensemble de broches peut traverser 6 couches d'abstraction ou plus (car cela rend une meilleure interface (portable!) Et un code plus court possible), tout en fournissant une interface indépendante de la cible pour les cas simples , et donnent toujours le même code machine que vous écririez dans l'assembleur .
Un extrait du style de codage que j'utilise, qui peut vous rendre enthousiaste ou vous détourner d'horreur:
En réalité, il existe d'autres couches d'abstraction. Pourtant, l'utilisation finale de la led, disons pour l'allumer, ne montre pas la complexité ou les détails de la cible (pour une arduin uno ou une pilule bleue ST32 le code serait identique).
Le compilateur n'est pas intimidé par toutes ces couches, et comme aucune fonction virtuelle n'est impliquée, l'optimiseur voit tout (certains détails, omis, comme l'activation de l'horloge périphérique):
C'est ainsi que je l'aurais écrit en assembleur - SI j'avais réalisé que les registres PIO peuvent être utilisés avec des décalages à partir d'une base commune. Dans ce cas, je le ferais probablement, mais le compilateur est bien meilleur pour optimiser de telles choses que moi.
Donc, pour autant que j'ai une réponse, c'est: écrivez une couche d'abstraction pour votre matériel, mais faites-le en C ++ moderne (concepts, modèles) afin que cela ne nuise pas à vos performances. Avec cela en place, vous pouvez facilement passer à une autre puce. Vous pouvez même commencer à développer sur une puce aléatoire que vous avez en place, que vous connaissez, avez de bons outils de débogage, etc. et reporter le choix final à plus tard (lorsque vous aurez plus d'informations sur la mémoire requise, la vitesse du processeur, etc.).
IMO, l'une des failles du développement intégré est de choisir d'abord la puce (c'est une question souvent posée sur ce forum: pour quelle puce dois-je choisir ... La meilleure réponse est généralement: cela n'a pas d'importance.)
(edit - réponse à "Donc, en termes de performances, C ou C ++ serait au même niveau?")
Pour les mêmes constructions, C et C ++ sont identiques. C ++ a beaucoup plus de constructions pour l'abstraction (juste quelques-unes: classes, modèles, constexpr) qui peuvent, comme tout outil, être utilisées pour le bien ou pour le mal. Pour rendre les discussions plus intéressantes: tout le monde n'est pas d'accord sur ce qui est bon ou mauvais ...
la source
Si je comprends bien, vous voulez savoir quelles fonctionnalités spécifiques à l'architecture de la plate-forme "apparaissent" dans votre environnement de langage C, ce qui rend plus difficile l'écriture de code portable maintenable sur les deux plates-formes.
C est déjà assez flexible dans la mesure où il s'agit d'un "assembleur portable". Toutes les plateformes que vous avez sélectionnées ont des compilateurs GCC / commerciaux disponibles qui prennent en charge les normes de langage C89 et C99, ce qui signifie que vous pouvez exécuter un code similaire sur toutes les plateformes.
Il y a quelques considérations:
Certaines plates-formes / compilateurs peuvent mieux masquer cette "limitation" que d'autres. Par exemple, sur AVR, vous devez utiliser des macros spécifiques pour lire les données ROM. Sur PIC24 / dsPIC, il existe également des instuctions tblrd dédiées. Cependant, certaines parties disposent également de la fonctionnalité "visibilité de l'espace programme" (PSVPAG) qui permet de mapper une page du FLASH dans la RAM, rendant l'adressage immédiat des données disponible sans tblrd. Le compilateur peut le faire assez efficacement.
ARM et MIPS sont Von Neumann, ont ainsi des régions de mémoire pour ROM, RAM et périphériques regroupés sur 1 bus. Vous ne remarquerez aucune différence entre la lecture des données de la RAM ou de la "ROM".
D'un autre côté, un PIC24 permet aux opérations ALU de lire et d'écrire des données directement via l'adressage indirect (même avec des modifications de pointeur ..). Cela a certaines caractéristiques d'une architecture de type CISC, donc 1 instruction peut faire plus de travail. Cette conception peut entraîner des cœurs de processeur plus complexes, des horloges plus faibles, une consommation d'énergie plus élevée, etc. Heureusement pour vous, la pièce est déjà conçue. ;-)
Ces différences peuvent signifier qu'un PIC24 peut être "plus percutant" par rapport aux opérations d'E / S qu'une puce ARM ou MIPS à horloge similaire. Cependant, vous pouvez obtenir une pièce ARM / MIPS d'horloge beaucoup plus élevée pour les mêmes contraintes de prix / emballage / conception. Je suppose que pour des termes pratiques, je pense que beaucoup d '"apprentissage de la plate-forme" consiste à comprendre ce que l'architecture peut et ne peut pas faire, la rapidité de quelques opérations, etc.
Ces différences peuvent être quelque peu encapsulées par les pilotes de périphérique, mais au final, le micrologiciel intégré a un niveau élevé de couplage avec le matériel, de sorte que le travail personnalisé ne peut parfois pas être évité.
De plus, si vous quittez les écosystèmes de Microchip / ancien Atmel, vous constaterez peut-être que les pièces ARM nécessitent plus de configuration pour les faire fonctionner. Je veux dire en termes de; activer les horloges sur les périphériques, puis configurer les périphériques et les "activer", configurer NVIC séparément, etc. Ceci n'est qu'une partie de la courbe d'apprentissage. Une fois que vous vous souvenez de faire toutes ces choses, dans le bon ordre, l'écriture des pilotes de périphérique pour tous ces microcontrôleurs se sentira assez similaire à un moment donné.
la source
Oui et non. Du point de vue des programmeurs, vous cachez idéalement les détails du jeu d'instructions. Mais cela n'est pas dans une certaine mesure déjà pertinent les périphériques qui est tout l'intérêt d'écrire le programme ne font pas partie du jeu d'instructions. Maintenant, en même temps, vous ne pouvez pas comparer les pièces flash de 4096 octets à travers ces jeux d'instructions, en particulier si vous utilisez C, la quantité de consommation du flash / de la mémoire est fortement déterminée par le jeu d'instructions et le compilateur, certains ne devraient jamais voir un compilateur (toux PIC toux) en raison de la quantité de gaspillage de ces ressources consommée par la compilation. Pour d'autres, la consommation de flash est une surcharge. Les performances sont également un problème lors de l'utilisation d'un langage de haut niveau et les questions de performances dans les applications MCU, elles peuvent donc faire la différence entre dépenser 3 $ par carte pour le mcu ou 1 $.
S'il s'agit de faciliter la programmation (au coût global du produit), vous devriez pouvoir télécharger un package de développement pour le mcu de telle sorte que l'architecture du jeu d'instructions soit quelque chose que vous ne voyez jamais, donc si c'est votre principale préoccupation, il n'est pas une préoccupation. L'utilisation de ces bibliothèques vous coûte toujours de l'argent en ce qui concerne le coût du produit, mais le temps de mise sur le marché peut être plus court, je trouve que les bibliothèques prennent plus de temps / travail à utiliser que de parler directement aux périphériques.
En conclusion, les ensembles d'instructions sont le moindre de vos soucis, passez à de vrais problèmes.
la source