Actualmente estamos utilizando el microcontrolador PIC32 de 32 bits. Está funcionando bien para nuestras necesidades, pero también estamos explorando otros microcontollers que pueden adaptarse mejor a nosotros + tenemos otros proyectos para los que estamos seleccionando MCU. Para ese fin, hemos seleccionado el microcontoller SAM DA basado en ARM, que es el mismo de 32 bits pero está basado en ARM (más popular que PIC32, en la industria).
Ahora para PIC32 usamos MPLAB pero para ARM cortex-M0, usaremos Atmel Studio. Usaremos lenguaje C en ambas plataformas. Lo que me preocupa es que usaremos dos microcontollers de 32 bits (de la misma compañía) pero con arquitecturas diferentes. Esto requerirá que aprendamos dos dispositivos diferentes y aumentará nuestra "curva de aprendizaje" + tiempo de entrega. Pero, por otro lado, también creo que dado que usaremos el lenguaje C en ambos casos, la curva de aprendizaje para ARM no debería ser tan escuchada y vale la pena explorar ese procesador también.
Mi pregunta principal es, ¿qué tan grande es la diferencia que hace la arquitectura cuando programamos en lenguaje C, ya que proporciona una abstracción de los componentes internos del microcontrolador? Y cuáles son las principales diferencias en MPLAP y Atmel Studio , considerando la programación en lenguaje C.
fuente
Respuestas:
Este es un tema bastante obstinado. Puedo hablar por mí mismo (AVR, ARM, MSP430).
La diferencia 1 (más significativa) está en los periféricos. Cada uno de los MCU tiene UART, SPI, temporizadores, etc. similares, solo que registrar nombres y bits son diferentes. La mayoría de las veces era el problema principal con el que tenía que lidiar al mover el código entre chips. Solución: escriba sus controladores con una API común, para que su aplicación pueda ser portátil.
La diferencia 2 es la arquitectura de la memoria. Si desea colocar constantes en flash en un AVR, debe usar atributos especiales y funciones especiales para leerlos. En el mundo ARM, simplemente desreferencia un puntero porque hay un solo espacio de direcciones (no sé qué tan pequeños lo manejan los PIC, pero supondría que están más cerca de AVR).
La diferencia 3 es la declaración de interrupción y el manejo.
avr-gcc
tiene laISR()
macro ARM solo tiene un nombre de función (como someUART_Handler (), si usa encabezados CMSIS y código de inicio). Los vectores de interrupción ARM pueden colocarse en cualquier lugar (incluida la RAM) y modificarse en tiempo de ejecución (muy útil si tiene, por ejemplo, dos protocolos UART diferentes que se pueden cambiar). AVR solo tiene la opción de usar vectores en "flash principal" o en la "sección del gestor de arranque" (por lo tanto, si desea manejar las interrupciones de manera diferente, debe usar unaif
declaración).Diferencia 4: modos de suspensión y control de potencia. Si necesita el consumo de energía más bajo, debe levantar todas las funciones de la MCU. Esto puede diferir mucho entre MCU: algunos tienen modos de ahorro de energía más burdos, otros pueden habilitar / deshabilitar periféricos individuales. Algunas MCU tienen reguladores ajustables para que pueda ejecutarlas con un voltaje más bajo a una velocidad más baja, etc. No veo una manera fácil de lograr la misma eficiencia en una MCU (digamos) con 3 modos de potencia global y otra con 7 modos de potencia y Control de reloj periférico individual.
Lo más importante al preocuparse por la portabilidad es dividir claramente su código en partes dependientes del hardware (controladores) y partes independientes del hardware (aplicación). Puede desarrollar y probar este último en una PC normal con un controlador simulado (por ejemplo, una consola en lugar de un UART). Esto me salvó muchas veces ya que el 90% del código de la aplicación se completó antes de que el hardware prototipo saliera del horno de reflujo :)
En mi opinión, lo bueno de ARM es la "monocultura": disponibilidad de muchos compiladores (gcc, Keil, IAR ... por nombrar algunos), muchos IDE gratuitos y con soporte oficial (al menos para NXP, STM32, Silicon Labs, Nórdico), muchas herramientas de depuración (SEGGER, especialmente Ozone, ULINK, OpenOCD ...) y muchos proveedores de chips (ni siquiera comenzaré a nombrarlos). El PIC32 se limita principalmente a Microchip (pero solo importa si no le gustan sus herramientas.
Cuando se trata de código C. Es el 99% igual, una
if
declaración es la misma, un bucle funciona de la misma manera. Sin embargo, debe preocuparse por el tamaño de la palabra nativa. Por ejemplo, unfor
bucle en un AVR es más rápido si lo usauint8_t
para el contador, mientras que en ARMuint32_t
es el tipo más rápido (oint32_t
). ARM tendría que verificar el desbordamiento de 8 bits cada vez que usara un tipo más pequeño.La selección de un MCU y / o proveedor en general se trata principalmente de política y logística (a menos que tenga restricciones de ingeniería muy claras, por ejemplo: alta temperatura: use MSP430 o Vorago). Incluso si la aplicación puede ejecutarse en cualquier cosa y solo el 5% del código (controladores) tiene que ser desarrollado y soportado durante la vida útil del producto , sigue siendo un costo adicional para la empresa. Todos los lugares en los que he trabajado tenían un proveedor favorito y una línea de MCU (como "elija cualquier Kinetis que desee a menos que haya una muy buena razón para elegir algo diferente"). También ayuda si tiene otras personas para pedir ayuda, por lo que, como gerente, evitaría tener un departamento de desarrollo de 5 personas donde todos usaran un chip totalmente diferente.
fuente
He usado varias MCU de cuatro fabricantes diferentes. El trabajo principal cada vez más es familiarizarse con los periféricos.
Por ejemplo, un UART en sí no es demasiado complejo y encuentro el puerto de mis controladores fácilmente. Pero la última vez que me llevó casi un día ordenar los relojes, los pines de E / S interrumpen, habilitan, etc.
El GPIO puede ser muy complejo. Bit-set, bit-clear, bit-toggle, Funciones especiales habilitadas / deshabilitadas, tri-estado. Luego, obtienes interrupciones: cualquier borde, subida, caída, nivel bajo, nivel alto, autolimpieza o no.
Luego está I2C, SPI, PWM, Timers y dos docenas más de periféricos, cada uno con su propio reloj habilitado y cada vez que los registros son diferentes con nuevos bits. Para todos ellos, lleva muchas horas leer la hoja de datos sobre cómo establecer qué bit bajo qué circunstancias.
El último fabricante tenía muchos ejemplos de código que encontré inutilizables. Todo estaba abstraído. Pero cuando lo rastreé, ¡el código pasó por seis! niveles de llamadas a funciones para establecer un bit GPIO. Agradable si tiene un procesador de 3GHz pero no en una MCU de 48MHz. Mi código al final fue una sola línea:
He intentado usar controladores más genéricos pero me he rendido. En una MCU siempre estás luchando con los ciclos espaciales y de reloj. Descubrí que la capa de abstracción es la primera en salir por la ventana si genera una forma de onda específica en una rutina de interrupción llamada a 10KHz.
Así que ahora tengo todo funcionando y planeo NO volver a cambiar a menos que sea por una muy, muy buena razón.
Todo lo anterior debe amortizarse sobre la cantidad de productos que vende y lo que ahorra. Vender un millón: ahorrar 0,10 para cambiar a un tipo diferente significa que puede gastar 100.000 en horas hombre de software. Vender 1000 solo tiene 100 para gastar.
fuente
OUTPUT_HI(n)
cual se obtendrá un código equivalente aGPIOD->bssr |= 0x400;
ifn
es una constante como 0x6A, pero llame a una subrutina simple sin
es no constante Dicho esto, la mayoría de las API de proveedores que he visto varían entre mediocres y horribles.Esto es más una opinión / comentario que una respuesta.
No desea y no debe programar en C. C ++, cuando se usa de la manera correcta , es muy superior. (OK, debo admitir que, cuando se usa de manera incorrecta, es mucho peor que C.) Eso lo limita a los chips que tienen un compilador C ++ (moderno), que es más o menos lo que es compatible con GCC, incluido AVR (con Algunas limitaciones, filo menciona los problemas de un espacio de direcciones no uniforme), pero excluye casi todos los PIC (PIC32 podría ser compatible, pero todavía no he visto ningún puerto decente).
Cuando está programando algoritmos en C / C ++, la diferencia entre las opciones que menciona es pequeña (excepto que un chip de 8 o 16 bits tendrá una grave desventaja cuando realice una gran cantidad de aritmética de 16, 32 o más bits). Cuando necesite la última onza de rendimiento, probablemente necesitará usar el ensamblador (ya sea el suyo o el código proporcionado por el proveedor o un tercero). En ese caso, es posible que desee volver a considerar el chip que seleccionó.
Cuando está codificando el hardware, puede usar alguna capa de abstracción (a menudo provista por el fabricante) o escribir la suya (según la hoja de datos y / o el código de ejemplo). Las abstracciones C existentes de IME (mbed, cmsis, ...) a menudo son funcionalmente (casi) correctas, pero fallan horriblemente en el rendimiento (verifique que los viejos pedos despotrican sobre 6 capas de indirección para una operación de configuración de pin), usabilidad y portabilidad. Quieren exponerle toda la funcionalidad del chip en particular, que en casi todos los casos no necesitará y no le importará, y bloquea su código a ese proveedor en particular (y probablemente ese chip en particular).
Esto es donde C ++ puede hacerlo mucho mejor: cuando se hace correctamente, un conjunto de pines puede atravesar 6 o más capas de abstracción (porque eso hace una mejor interfaz (¡portátil!) Y un código más corto posible), pero proporciona una interfaz que es independiente del objetivo para los casos simples , y aun así se obtiene el mismo código de máquina que escribiría en el ensamblador .
Un fragmento del estilo de codificación que uso, que puede hacerte entusiasta o alejarte con horror:
En realidad hay algunas capas más de abstracción. Sin embargo, el uso final del led, digamos que encenderlo, no muestra la complejidad o los detalles del objetivo (para una píldora azul Arduin uno o ST32, el código sería idéntico).
El compilador no se siente intimidado por todas esas capas, y debido a que no hay funciones virtuales involucradas, el optimizador ve a través de todo (algunos detalles, omitidos, como habilitar el reloj periférico):
Así es como lo habría escrito en ensamblador: SI me hubiera dado cuenta de que los registros PIO se pueden usar con compensaciones desde una base común. En este caso probablemente lo haría, pero el compilador es mucho mejor para optimizar tales cosas que yo.
Entonces, hasta donde tengo una respuesta, es: escriba una capa de abstracción para su hardware, pero hágalo en C ++ moderno (conceptos, plantillas) para que no perjudique su rendimiento. Con eso en su lugar, puede cambiar fácilmente a otro chip. Incluso puede comenzar a desarrollar en algún chip aleatorio que tenga, con el que esté familiarizado, tenga buenas herramientas de depuración, etc. y posponga la elección final hasta más tarde (cuando tenga más información sobre la memoria requerida, la velocidad de la CPU, etc.).
En mi opinión, una de las falacias del desarrollo integrado es elegir el chip primero (es una pregunta que a menudo se hace en este foro: qué chip debería elegir ... La mejor respuesta es generalmente: no importa).
(editar - respuesta a "Entonces, en cuanto al rendimiento, ¿C o C ++ estarían al mismo nivel?")
Para las mismas construcciones, C y C ++ son iguales. C ++ tiene muchas más construcciones para la abstracción (solo unas pocas: clases, plantillas, constexpr) que pueden, como cualquier herramienta, usarse para bien o para mal. Para hacer las discusiones más interesantes: no todos están de acuerdo en lo que es bueno o malo ...
fuente
Si entiendo correctamente, desea saber qué características específicas de la arquitectura de la plataforma "aparecen" en su entorno de lenguaje C, lo que hace más difícil escribir código portátil y sostenible en ambas plataformas.
C ya es bastante flexible ya que es un "ensamblador portátil". Todas las plataformas que ha seleccionado tienen compiladores GCC / comerciales disponibles que son compatibles con los estándares de lenguaje C89 y C99, lo que significa que puede ejecutar un código similar en todas las plataformas.
Hay algunas consideraciones:
Algunas plataformas / compiladores pueden ocultar esta "limitación" mejor que otras. Por ejemplo, en AVR necesita usar macros específicas para leer datos de ROM. En PIC24 / dsPIC también hay disponibles instrucciones de tblrd dedicadas. Sin embargo, algunas partes también tienen disponible la función de "visibilidad del espacio del programa" (PSVPAG) que permite mapear una página del FLASH en la RAM, haciendo que el direccionamiento de datos inmediato esté disponible sin tblrd. El compilador puede hacer esto de manera bastante efectiva.
ARM y MIPS son Von Neumann, por lo que tienen regiones de memoria para ROM, RAM y periféricos empaquetados en 1 bus. No notará ninguna diferencia entre leer datos de RAM o "ROM".
Por otro lado, un PIC24 permite que las operaciones de ALU lean y escriban datos directamente a través del direccionamiento indirecto (incluso con modificaciones de puntero ...). Esto tiene algunas características de una arquitectura similar a CISC, por lo que 1 instrucción puede hacer más trabajo. Este diseño puede conducir a núcleos de CPU más complejos, relojes más bajos, mayor consumo de energía, etc. Afortunadamente para usted, la pieza ya está diseñada. ;-)
Estas diferencias pueden significar que un PIC24 puede ser operaciones de E / S wrt "más contundentes" que un chip ARM o MIPS con reloj similar. Sin embargo, puede obtener una parte ARM / MIPS de reloj mucho más alta por las mismas restricciones de precio / paquete / diseño. Supongo que, en términos prácticos, creo que mucho de "aprender la plataforma" se está dando cuenta de lo que la arquitectura puede y no puede hacer, qué tan rápido será un conjunto de operaciones, etc.
Estas diferencias pueden ser encapsuladas de alguna manera por los controladores de dispositivo, pero al final el firmware incorporado tiene un alto nivel de acoplamiento con el hardware, por lo que a veces no se puede evitar el trabajo personalizado.
Además, si abandona los ecosistemas de Microchip / ex Atmel, es posible que las piezas ARM requieran más configuración para que funcionen. Me refiero en términos de; habilitar relojes a periféricos, luego configurar periféricos y "habilitarlos", configurar NVIC por separado, etc. Esto es solo parte de la curva de aprendizaje. Una vez que recuerde hacer todas estas cosas, en el orden correcto, escribir controladores de dispositivos para todos estos microcontroladores se sentirá bastante similar en algún momento.
fuente
Si y no. Desde la perspectiva de los programadores, lo ideal es ocultar los detalles del conjunto de instrucciones. Pero eso, en cierta medida, ya no es relevante, los periféricos, que es el objetivo de escribir el programa, no forman parte del conjunto de instrucciones. Ahora, al mismo tiempo, no puede comparar las partes flash 4096Byte en esos conjuntos de instrucciones, particularmente si se usa C, la cantidad de consumo de la memoria flash / memoria está fuertemente determinada por el conjunto de instrucciones y el compilador, algunos nunca deberían ver un compilador (tos PIC tos) debido a la cantidad de desperdicio de esos recursos que se consume al compilar. Otros consumo flash es una sobrecarga menor. El rendimiento también es un problema cuando se usa un lenguaje de alto nivel y el rendimiento es importante en las aplicaciones MCU, por lo que puede marcar la diferencia entre gastar $ 3 por placa para el mcu o $ 1.
Si se trata de facilitar la programación (al costo total del producto), debería poder descargar un paquete de desarrolladores para el mcu de modo que la arquitectura del conjunto de instrucciones sea algo que nunca verá, por lo que si esa es su principal preocupación, No es una preocupación. Todavía le cuesta dinero en cuanto al costo del producto usar estas bibliotecas, pero, el tiempo de comercialización puede ser más corto, creo que las bibliotecas tardan más tiempo / trabajo en usar que hablar directamente con los periféricos.
En pocas palabras, los conjuntos de instrucciones son la menor de sus preocupaciones, pase a problemas reales.
fuente