Codificación en ensamblador para ARM (Cortex-M0 y M3): ¿es posible/práctico?

Desafortunadamente, no hay preguntas en Stack sobre ARM y ensamblador.

Mi preocupación son los dispositivos de tiempo crítico. Tomemos como ejemplo uno de mi dispositivo basado en AVR (programa compilado con GCC) que debería hacer algo hasta la interrupción INT0. Funcionaba con un oscilador interno de 8 MHz (125 ns en un ciclo de máquina), pero tardaba hasta 5 microsegundos en reaccionar ante la interrupción. Después de la investigación del código, llegué a la conclusión de que, al comienzo del servicio de interrupción, el procesador de rutina hace mucho trabajo para guardar su estado, que es casi incontrolable para los lenguajes de programación de alto nivel (como C). Si usara el ensamblador, podría, por ejemplo, lanzar un cambio de pin desde el principio y mantener el resto de los cálculos necesarios después de eso. O podría tener mucho más control sobre el uso de los registros y, por lo tanto, mucho menos tiempo para guardar esos registros.

Si fuera a ARM (que planeo hacer pronto), tendré un núcleo de procesador mucho más rápido con muchos más registros y espacio de memoria que parece prometedor. ¿Pero alguna vez podré tener algún control sobre tales procesos críticos de tiempo para obtener, por ejemplo, un tiempo de reacción dentro de, digamos, cien nanosegundos?

Cuando dice ARM, debe (especialmente cuando habla de programación en ensamblador) ser más específico. ARMV7? CortecM0? ¡hace una gran diferencia en el conjunto de instrucciones y el manejo de interrupciones! Un tiempo de reacción dentro de los 100 ns será difícil, pero podría ser posible, según el chip exacto, la frecuencia del reloj y lo que desee hacer.
@WoutervanOoijen ¡Ese es un buen punto! Corregida la pregunta.

Respuestas (3)

Es muy razonable programar ARM en ensamblador. Es una arquitectura RISC sencilla con pocas sorpresas y muchos registros. Puede mezclar C y ensamblador siempre que tenga una buena comprensión de las convenciones de llamadas.

Hay un modo especial de interrupción ARM de baja latencia llamado FIQ , que cambia algunos de los registros a un banco en hardware para que no sea necesario guardarlos en el ISR. La latencia de 100 ns para hacer algo útil seguirá siendo difícil: a 100 MHz son 10 ciclos de reloj, y FIQ tarda hasta 12 antes de ejecutar la primera instrucción.

Sí, ciertamente es posible: todo el código de inicio que usa su programa C normalmente se escribirá en ensamblador (archivos .s).

Muchas de las cosas que la gente quiere hacer con los procesadores ARM se basan en la infraestructura existente de pilas de protocolos y bibliotecas de gráficos. Si está escribiendo aplicaciones independientes, usándolas como un super 8051 o PIC, ciertamente puede usar el ensamblador para todo (o escribir sus propias pilas UDP, etc.). Puede codificar a mano las secciones críticas, por supuesto, y usar C para la mayor parte de la programación.

Observé la codificación del ensamblador central ARM7DTMI hace algún tiempo, y parecía bastante agradable trabajar con él; calculé que no tomaría más tiempo para ponerse al día que con cualquier otro procesador nuevo en ensamblador (pero de hecho estamos usando C exclusivamente con núcleos ARM: es una lengua franca muy adecuada para expertos en dominios, gente joven y programadores expertos por igual).

Tenga en cuenta que las implementaciones típicas de ARM no están tan estrechamente acopladas como los procesadores simples: hay un bus periférico que puede funcionar a una frecuencia diferente que el bus del procesador. Es posible que no pueda, por ejemplo, alternar un pin de puerto tan rápido como podría esperar de la frecuencia del reloj. Generalmente, si algo es realmente crítico en cuanto al tiempo, es mejor tener un periférico que lo maneje de forma autónoma (o usar un FPGA auxiliar).

También tenga en cuenta que, por ejemplo, juegos completos como Rollercoaster Tycoon (1 y 2) fueron codificados a mano en ensamblaje x86, posiblemente incluso más complejo que el ensamblaje ARMv5 o v6. Puede hacer más que solo un par de bucles optimizados en código ensamblador.

Este es un poco viejo, pero merece una mejor respuesta. La pregunta original era sobre la latencia de interrupción. Dado que la plataforma original es un AVR, la pieza de repuesto basada en ARM será un Cortex-M3/M4 o M0. Ambos dispositivos tienen una latencia de interrupción de 12 ciclos de instrucción como máximo. Ese es el tiempo desde el estímulo hasta la ejecución de su código.

En la práctica, llevará más tiempo hacer algo útil. Es difícil escribir en un IO en mucho menos de 3 a 5 ciclos de instrucción (cargar la dirección, cargar el valor, almacenar el valor). Más tiempo si los buses, ram o flash del dispositivo tienen latencias adicionales.

Si realmente necesita latencias en el rango de .1us, necesita periféricos o lógica personalizada en lugar de software. Si la necesidad real son tiempos de respuesta acotados/fijos, puede obtenerlos con la configuración adecuada del sistema de interrupción. Cortex-Ms tiene características que pueden reducir la latencia de interrupción a 6 ciclos en las circunstancias adecuadas (llegada tardía y encadenamiento de cola). Eso se puede desactivar si necesita una latencia fija de 12 ciclos.