Necesito tener pausa programable con la mayor precisión posible. Para lograr esto tengo el siguiente código GCC:
void delay(unsigned char d){
volatile unsigned char i=d;
while(i>0) i--;
}
Que se compila a:
1cc: 89 81 ldd r24, Y+1 ; 0x01
1ce: 81 50 subi r24, 0x01 ; 1
1d0: 89 83 std Y+1, r24 ; 0x01
1d2: 89 81 ldd r24, Y+1 ; 0x01
1d4: 81 11 cpse r24, r1
1d6: fa cf rjmp .-12 ; 0x1cc <__vector_1+0x2c>
(Estoy mostrando solo el código del núcleo del bucle). Esto lleva al hecho de que la precisión es de 7 ciclos lo cual no es muy aceptable. Sin embargo, veo que el compilador no hizo su trabajo lo más rápido posible: si la i
variable fuera registro r24, ahorraré 3 operaciones y el código sería casi el doble de rápido.
Entonces, ¿cómo puedo decirle al compilador que quiero que esta variable esté en un registro?
PD. Consideraría hacer una pausa con un número programable en nop
's. Pero no puedo imaginar cómo se puede lograr esto. AVR no tiene instrucciones para bifurcarse a la dirección calculada. Por lo que sé, no se puede acceder directamente a la pila en AVR (si pudiera, podría enviar el valor necesario a la pila y ejecutar la ret
instrucción para saltar a la dirección del programa necesaria; también es un trabajo complicado, pero sería al menos considerable).
ACTUALIZAR Después de cambiar volatile
a register
palabra clave (como se describió en una de las respuestas), obtuve el siguiente código:
14e: 81 50 subi r24, 0x01 ; 1
150: f1 f7 brne .-4 ; 0x14e <__vector_6+0x1c>
Así que reduje el ciclo de 7 a 2 ciclos. Lo cual es mucho mejor de lo que podía esperar.
No declare su variable como volatile
. Eso prácticamente obliga al compilador a usar una ubicación de memoria y acceder a ella en cada iteración del ciclo. Utilice register
en su lugar.
La forma convencional de lograr lo que desea es codificar a mano la subrutina de retardo en el lenguaje ensamblador nativo. Casi todos los conjuntos de herramientas de desarrollo que son compiladores de C tendrán la capacidad de incluir módulos de lenguaje ensamblador en la compilación.
Un truco común utilizado por programadores experimentados es construir primero la rutina de retardo en código C como lo ha hecho. Luego, al mirar el código de máquina compilado, obtiene una plantilla de cómo escribir la misma rutina en código ensamblador y luego le permite optimizar las secciones críticas. La ventaja de este enfoque es que el compilador "le muestra cómo" configurar la entrada y salida a/desde la subrutina para que sea compatible con la llamada desde el código C principal.
david tweed
volatile
? Eso prácticamente obliga al compilador a usar una ubicación de memoria y acceder a ella en cada iteración de bucle. Pruebaregister
en su lugar.romano matveev
volatile
evitar que el compilador "optimizara" el código parecía no hacer nada. ¿Escribirías una respuesta que pudiera votar y aceptar?David