Tengo muchos años de experiencia con núcleos de 8 bits de varios fabricantes, a saber, 8051, PIC y AVR, y ahora tengo un Cortex M0 para averiguarlo. Específicamente este , pero espero que podamos ser más generales que eso.
Está resultando ser un poco más de lo que esperaba, con múltiples documentos que describen diferentes partes del sistema en diferentes niveles de detalle y ninguno que haya visto realmente para conectarlo todo. Esto se compara con tener una hoja de datos que explica todo. Entiendo que tengo mucho más material para documentar en primer lugar, pero el cambio de formato me está dando vueltas.
El sitio web anterior tiene un documento que es una buena descripción general de cada subsistema y periférico de forma aislada, y otro que describe cada registro en detalle, y tengo todo el código fuente de su SDK, incluidos los archivos de encabezado y algunos ejemplos complejos, pero aún veo nada que describa cómo se conecta todo.
¿Hay un tutorial conciso de la arquitectura Cortex que explique la función de las cosas que los controladores más pequeños simplemente no tienen, como varias capas de buses desde la CPU hasta los periféricos, cada uno con su propio temporizador de vigilancia, y cómo se conectan entre sí?
He trabajado en AVR y MCU basados en ARM Cortex-M3/M4/R4. Creo que puedo ofrecer algunos consejos generales. Esto supondrá que está programando en C, no en ensamblaje.
La CPU es en realidad la parte fácil. Los tipos de datos básicos de C tendrán diferentes tamaños, pero de todos modos está usando uint8/16/32_t, ¿verdad? :-) Y ahora todos los tipos de enteros deberían ser razonablemente rápidos, siendo los de 32 bits (int) los más rápidos. Probablemente no tenga una FPU, así que continúe evitando flotantes y dobles.
Primero, trabaje en su comprensión de la arquitectura a nivel del sistema. Esto significa E/S, sincronización, memoria, reinicios e interrupciones. Además, debe acostumbrarse a la idea de los periféricos mapeados en memoria. En AVR puede evitar pensar en eso porque los registros tienen nombres únicos con variables globales únicas definidas para ellos. En sistemas más complejos, es común referirse a los registros por una dirección base y un desplazamiento. Todo se reduce a la aritmética de punteros. Si no se siente cómodo con los punteros, comience a aprender ahora.
Para los IO, descubra cómo se maneja el muxing periférico. ¿Hay un control mux central para seleccionar qué pines son señales periféricas y cuáles son GPIO? ¿O configura los pines en modo periférico usando los registros periféricos? Y, por supuesto, necesitará saber cómo configurar GPIO como entradas y salidas, y habilitar el modo de drenaje abierto y pull-ups/downs. Las interrupciones externas suelen caer también en esta categoría. Los GPIO son bastante genéricos, por lo que su experiencia debería serle útil aquí.
El reloj se reduce a algunas cosas. Comienza con una fuente de reloj, típicamente un cristal o un oscilador RC interno. Esto se utiliza para crear uno o más dominios de reloj a nivel de sistema. Los chips de mayor velocidad usarán un PLL, que puede considerar como un multiplicador de frecuencia. También habrá divisores de reloj en varios puntos. Las cosas clave a considerar son cuál debería ser la frecuencia de reloj de su CPU y qué tasas de bits necesita para sus periféricos de comunicación. Por lo general, esto es bastante flexible. Cuando esté más avanzado, puede aprender cosas como los modos de bajo consumo, que generalmente se basan en la sincronización del reloj.
Memoria significa flash y RAM. Si tiene suficiente RAM, a menudo es más rápido mantener su programa allí durante el desarrollo inicial para que no tenga que programar el flash una y otra vez. El gran problema aquí es la gestión de la memoria. Su proveedor debe proporcionar ejemplos de secuencias de comandos de vinculación, pero es posible que deba asignar más memoria al código, las constantes, las variables globales o la pila, según la naturaleza de su programa. Los temas más avanzados incluyen seguridad de código y programación flash en tiempo de ejecución.
Los reinicios son bastante sencillos. Por lo general, solo tiene que buscar el temporizador de vigilancia, que puede estar habilitado de forma predeterminada. Los reinicios son más importantes durante la depuración cuando ejecuta el mismo código una y otra vez. Es fácil pasar por alto un error debido a problemas de secuenciación de esa manera.
Hay dos cosas que debe saber acerca de las interrupciones: cómo habilitarlas y deshabilitarlas, y cómo configurar los vectores de interrupción. AVR-GCC hace esto último por usted con las macros ISR(), pero en otras arquitecturas es posible que deba escribir una dirección de función en un registro manualmente.
Los periféricos del microcontrolador suelen ser independientes entre sí, por lo que puede aprenderlos uno a la vez. Puede ser útil elegir un periférico y usarlo para aprender parte de las cosas a nivel del sistema. Los periféricos de comunicación y los PWM son buenos para el reloj y las E/S, y los temporizadores son buenos para las interrupciones.
No se deje intimidar por el nivel de complejidad. Esos microcontroladores "básicos" ya le han enseñado mucho de lo que necesita saber. Por favor, hágamelo saber si necesita que le aclare algo.
int
/ int_leastN_T
para variables de pila.int_fastN_t
tipos, no int_leastN_t
tipos.int16_t
será a menudo tan rápido como int32_t
para los valores almacenados en la memoria, pero el estándar requiere que en las plataformas donde int
es de 17 bits o más, int16_t x=32767; x+=2;
debe establecerse x
en -32767, lo que requiere con frecuencia instrucciones de extensión de signo, incluso si el código nunca haga uso del comportamiento de envoltura.x+=2
, sería legal usar instrucciones para tipos de 16 bits, porque el compilador puede asumir que el valor no se ajustará y, por lo tanto, usarlo no cambiaría el comportamiento observable. Pero creo que ARM no tiene una instrucción ADD de 16 bits que lo haga posible. (Podría estar equivocado, mi conocimiento sobre el conjunto de instrucciones ARM no es tan bueno).int
el especificado como convertir el valor a un tipo sin signo del mismo tamaño y luego convertirlo a un entero con signo. Si el valor está dentro del rango especificado para el tipo de entero con signo, el resultado está definido por la implementación en lugar de indefinido. Creo que es una tontería que en la mayoría de las plataformas de 32 bits, dado int16_t i; uint16_t u;
, la instrucción i*=i;
se define para todos los valores de i
, pero u*=u;
no se define para todos los valores de u
, pero no escribí las reglas.int16_t
, pero otorgando a los compiladores la libertad adicional de que si un valor fuera de rango se almacena en una variable de ese tipo, un compilador podría tener las lecturas de la variable arrojan arbitrariamente cualquier valor congruente con el valor almacenado mod 65536, aunque se requerirían conversiones para truncar al rango -32768..32767 ; por el contrario, requeriría que si el resultado de un operador aditivo, multiplicativo o de desplazamiento a la izquierda se convierte o se coacciona a un tipo sin signo más pequeño que int
...uint16_t
valores desencadene un Comportamiento indefinido en los casos en que el resultado se volverá a asignar a uint16_t
.Es útil recordar que ARM posee la propiedad intelectual del microprocesador, pero en realidad no fabrica las piezas. En su lugar, los fabricantes obtienen licencias de las diversas versiones de procesadores ARM y producen sus propias piezas únicas con combinaciones individuales de características y periféricos.
Dicho esto, si es nuevo en la arquitectura, probablemente tenga sentido comenzar con la documentación de ARM que es, esencialmente, la documentación básica para todos esos microprocesadores.
Por ejemplo, el Cortex-M0 se describe en el sitio web de ARM .
También hay una lista de libros relacionados con ARM que satisface una amplia variedad de necesidades e intereses.
Finalmente, están las hojas de datos del fabricante específico. Para el M0, Cypress, NXP y STMicroelectronics son solo tres de los muchos fabricantes de piezas reales basadas en Cortex-M0.
(Y no, no trabajo para ARM y nunca lo he hecho).
Una gran diferencia es el uso de bibliotecas proporcionadas por proveedores. Para los PIC, Atmels, etc., la mayoría de los desarrolladores no utilizaron mucho las bibliotecas básicas (para gpio, temporizadores, adc, etc.). En mi experiencia, la gente (como máximo) los usaría como guías al escribir su propio código.
Sin embargo, con ARM, casi siempre se usan las bibliotecas. Existe un estándar, "CMSIS", que se recomienda seguir a los fabricantes. Debe hacerse. Ayuda en la portabilidad del código (entre diferentes ARM y entre fabricantes) y brinda un método "estandarizado" para estructurar su código. La gente se acostumbra a ver y comprender las funciones de la biblioteca.
Seguro que hay algunos desarrolladores que acceden a los registros directamente, pero son los atípicos :)
Para responder a su pregunta, me resultó muy útil leer la documentación de la Biblioteca. ST tiene un código bien desarrollado, con un gran archivo de ayuda creado por Doxygen. Puede ver cuáles son todas las opciones para cada módulo de hardware.
Para usar GPIO como ejemplo, la función de inicialización maneja:
Al mirar las opciones, puede ver lo que es posible. Y, por supuesto, ¡aprenderá cómo pasar estas opciones a la función Init!
Bien, ahora que dije eso, veo que su ARM específico no tiene bibliotecas compatibles con CMSIS. En cambio, tienen su SDK patentado disponible para descargar. Comenzaría a buscar a través de sus documentos SDK.
Si no está casado con este producto específico, podría recomendarle que busque un proveedor diferente con bibliotecas más compatibles. Vas a subir una curva de aprendizaje de todos modos, por lo que también podrías hacer que tu inversión sea más portátil...
¡Los ARM son divertidos! No he mirado atrás.
Buen momento para moverse; los 8 bits se están muriendo rápidamente; cuando puede comprar una placa de $ 5 con (por ejemplo) un STM32F103 que es un microcontrolador ARM de 32 bits bastante capaz (¡incluso con USB!), No hay duda de que los tiempos han cambiado.
Ya ha recibido algunas respuestas excelentes, pero principalmente diría "olvídese del ensamblaje" y casi "olvídese de preocuparse por cómo funciona la CPU a un nivel bajo". (una optimización específica o para la depuración), pero los núcleos ARM ejecutan el código C excepcionalmente bien (por diseño) y rara vez necesita aventurarse profundamente en las tripas.
Esto significa que pasará una cierta cantidad de tiempo golpeándose la cabeza contra los problemas con los compiladores (y especialmente los vinculadores y los archivos MAKE) vomitando errores oscuros, pero todos son superables.
Las entrañas de cómo funcionan los ARM (es decir, los libros de CPU ARM) son densos y no muy interesantes hasta el día en que realmente necesita optimizar (y se sorprenderá de la poca frecuencia que tiene cuando tiene registros de 32 bits y su PLL). d El reloj de la CPU está en la región de 100 MHz).
El conjunto de instrucciones ARM de la "vieja escuela" es mucho más fácil de leer y desensamblar que el mucho más nuevo "Thumb2", que es lo que se encuentra en la mayoría de los ARM de nivel de microcontrolador modernos (Cortex), pero nuevamente las entrañas de las instrucciones en lenguaje ensamblador en su mayoría se desvanecen en el fondo; si tiene el conjunto de herramientas correcto (especialmente un depurador de nivel de fuente decente con puntos de interrupción/paso único, etc.), simplemente no le importa demasiado que sea ARM en absoluto.
Una vez que esté en el mundo de los registros de 32 bits y los anchos de bus de datos de 32 bits y todo lo que siempre quiso disponible en el chip, nunca más querrá volver a una CPU de 8 bits; básicamente, a menudo no hay penalización por "tomarlo con calma" y escribir código para que sea legible más que eficiente.
Sin embargo... periféricos... sí y AHÍ ESTÁ el problema.
Seguro que obtienes un montón de cosas con las que jugar en los MCU modernos, y muchas de ellas son cosas bastante elegantes; a menudo encuentra un mundo de sofisticación mucho, mucho más allá de los periféricos en chip AVR, PIC y 8051.
¿Un temporizador programable? ¡No, toma ocho! DMA? ¿Qué tal 12 canales con prioridad programable y modo ráfaga y modo encadenado y recarga automática y... y... y...
¿I2C? ¿I2S? ¿Docenas de opciones de muxing de pines? ¿Quince formas diferentes de reprogramar el flash en chip? ¡Seguro!
A menudo se siente como si hubiera pasado de la hambruna a la fiesta con los periféricos y es común que haya trozos enteros de un chip que admirará pero que apenas usará (por lo tanto, sincronización del reloj).
La cantidad de hardware en el chip (y las variaciones en la línea de chips de un solo proveedor) es hoy en día bastante alucinante. Por supuesto, un proveedor de chips tenderá a reutilizar los bloques de IP, por lo que una vez que se familiarice con una determinada marca, se volverá más fácil, pero "la mierda se volvió loca hoy en día".
En todo caso, los periféricos y sus interacciones (y DMA e interrupciones y asignación de bus y y y...) son TAN complejos (y, en ocasiones, no exactamente como se describe en las hojas de datos) que los ingenieros con frecuencia tienen una gama favorita de MCU ARM y tienden a querer quedarse con él simplemente porque están familiarizados con los periféricos y las herramientas de desarrollo.
Buenas bibliotecas y herramientas de desarrollo (es decir, un ciclo rápido de compilación y depuración con un depurador adecuado) y un gran conjunto de proyectos de código de ejemplo en funcionamiento son absolutamente cruciales para su elección de ARM MCU hoy en día. Parece que la mayoría de los proveedores ahora tienen placas de evaluación extremadamente baratas (
Como estoy seguro de que habrás notado, una vez que superas el nivel del microcontrolador con ARM y llegas al nivel de SOC (por ejemplo, SOC de estilo Raspberry Pi/etc), las reglas cambian por completo y se trata de qué tipo de Linux estás usando. correr, porque, con muy pocas excepciones, estarías ladrando como un loco si intentaras cualquier otra cosa.
Básicamente; independientemente de la CPU que (puede) haber sido preseleccionada para usted en este concierto, cómprese un puñado de placas de evaluación basadas en Cortex súper baratas de algunos proveedores diferentes (TI, STM, Freescale y más vienen a la mente) y tenga un truco con el código de muestra proporcionado.
Último consejo; una vez que encuentre la página o tres en la hoja de datos que describe las opciones de pin-muxing para el chip de número de pieza exacto con el que está trabajando, es posible que desee imprimirlo y pegarlo en la pared. Descubrir tarde en un proyecto que cierta combinación de periféricos es imposible debido a la muxación de pines no es divertido y, a veces, esa información está tan oculta que juraría que están tratando de ocultarla :-)
También vengo de AVR y ahora generalmente me quedo con STM32 (Cortex-M). Esto es lo que recomiendo para empezar, y refleja mis propias dificultades cuando comencé:
Obtenga una placa con un depurador, o al menos un conector JTAG (y luego compre un depurador JTAG). Hay muchos baratos, y ahorrarás mucho tiempo usándolos.
Consigue un buen IDE con todo incluido. Solía recomendar CooCox CoIDE hace mucho tiempo. Desde entonces, ha detenido y reiniciado el desarrollo, por lo que no estoy seguro de cómo está ahora. "Un buen IDE" le permite hacer que el LED Hello World básico parpadee en poco tiempo.
"Un buen IDE" debería configurar los encabezados CMSIS del fabricante. Estos son básicamente los mapas de registro que permiten una escritura más fácil de los programas C/C++, con nombres de variables en lugar de números simples y punteros.
Intente utilizar las bibliotecas de periféricos del fabricante, si no necesita el mejor rendimiento absoluto. En realidad no lo haces por ahora, ya que estás aprendiendo. Si luego descubre que necesita exprimir más, busque en el código de la biblioteca para ver cómo hace qué. Lo bueno de las bibliotecas también es que generalmente te permiten usar muchos chips diferentes del mismo fabricante con el mismo código.
A diferencia de AVR, los chips ARM comienzan con los periféricos deshabilitados. Primero debe habilitarlos. Una buena biblioteca de periféricos tendrá ejemplos sobre cómo usar los periféricos correctamente, y puede obtener más información de la hoja de datos del dispositivo. Por lo tanto, recuerde habilitar los relojes y periféricos antes de usarlos. Sí, incluso los puertos de E/S se consideran periféricos.
Codifica a medida que aprendes. No intentes asimilar todo a la vez, ya que es bastante complejo. Comenzaría aprendiendo el árbol del reloj (autobuses APB, AHB, etc.) y cómo interactúan los relojes y los divisores de reloj. Luego buscaría dónde almacena el IDE los scripts del enlazador y el código de inicio para su dispositivo. La secuencia de comandos del enlazador es más o menos cómo organiza la memoria (dónde está la RAM, la memoria flash, la tabla de vectores ISR, etc.). El script de inicio configura su programa (cosas como copiar inicializadores de variables globales de flash a RAM). Algunos IDE tienen scripts de inicio en ASM y otros en C. A veces puede buscar otro en Google, en el idioma que prefiera.
Ponga en marcha el depurador lo antes posible. Es bastante común cometer un error al principio, al hacer algunas cosas (generalmente la inicialización del hardware) en un orden diferente al que debería. Esto a veces desencadena una excepción de ISR que lo coloca en while(1);
un bucle infinito (implementación predeterminada para ese ISR) que detiene su programa y es difícil de rastrear incluso con un depurador. Imagínese sin un depurador.
Hablando de un depurador, intente poner en marcha el UART también, luego use un adaptador serial-USB para leer eso. printf()
la depuración siempre es útil :-)
No he trabajado mucho en 8051, AVR o PIC. Pero recientemente comencé a buscar en la línea de procesadores ARM Cortex MX. Por lo tanto, no puedo decirle mucho sobre la transición desde 8051, AVR o PIC, pero sobre todo desde el punto de vista de un principiante.
El procesador ARM®Cortex™-M4 se basa en la arquitectura Harvard, por lo que tiene buses de datos e instrucciones separados. A continuación se muestra una imagen de alto nivel.
Esta semana, representantes de NXP visitarán nuestras instalaciones. Verificaré con ellos los recursos de NXP ARM-Cortex Mx y los publicaré aquí. Freescale tiene un microcontrolador (MCU) de 32 bits de bajo consumo Kinetis basado en núcleos ARM® Cortex®-M . Entiendo que también tienen guías similares para aprender a usar procesadores ARM. Desafortunadamente no los he investigado.
Referencias:
DigitalNinja
aarond
aarond
Ronan Paixão