Entendiendo esta rutina AVR ASM

0

Esta es una versión abreviada de WS2812 LED control rutina . He eliminado todos los no-ops por motivos de legibilidad aquí. ¿Alguien puede explicar el papel de la instrucción de rama (brne) hacia el final de la rutina?

 asm volatile(
    "       ldi   %0,8  \n\t"
    "loop%=:            \n\t"
    "       out   %2,%3 \n\t"    //  '1' [01] '0' [01] - re  "       sbrs  %1,7  \n\t"    //  '1' [03] '0' [02]
    "       out   %2,%4 \n\t"    //  '1' [--] '0' [03] - fe-low
    "       lsl   %1    \n\t"    //  '1' [04] '0' [04]  "       out   %2,%4 \n\t"    //  '1' [+1] '0' [+1] - fe-high
    "       dec   %0    \n\t"    //  '1' [+2] '0' [+2]
    "       brne  loop%=\n\t"    //  '1' [+3] '0' [+4]
    :   "=&d" (ctr)
    :   "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
    );  
    
pregunta Adam Lee

1 respuesta

1

La variable %0 ( ctr en la función circundante) cuenta el número de bits en el byte que se está transmitiendo. La rama hace que la rutina se repita hasta que se hayan procesado los 8 bits de %1 ( curbyte ).

Parece que puedes haber eliminado más que solo no-ops. Debe haber al menos una rama basada en el valor de un bit en %1 que selecciona una de las dos rutas a través del cuerpo del bucle. Las instrucciones out alternan un pin de salida alto y bajo para crear la forma de onda PWM que requiere el WS2812, y los no ops controlan la sincronización relativa de los períodos alto y bajo.

Ah, sí. Mirando el código original, tiene:

asm volatile(
"       ldi   %0,8  \n\t"
"loop%=:            \n\t"
"       out   %2,%3 \n\t"    //  '1' [01] '0' [01] - re
[ variable number of NOPs based on w1_nops ]
"       sbrs  %1,7  \n\t"    //  '1' [03] '0' [02]
"       out   %2,%4 \n\t"    //  '1' [--] '0' [03] - fe-low
"       lsl   %1    \n\t"    //  '1' [04] '0' [04]
[ variable number of NOPs based on w2_nops ]
"       out   %2,%4 \n\t"    //  '1' [+1] '0' [+1] - fe-high
[ variable number of NOPs based on w3_nops ]
"       dec   %0    \n\t"    //  '1' [+2] '0' [+2]
"       brne  loop%=\n\t"    //  '1' [+3] '0' [+4]
:   "=&d" (ctr)
:   "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
);

El pin se establece alto al principio del bucle. La instrucción sbrs (¿Omitir si se establece el bit en el registro?) Determina si el pin se establece bajo después del período w1_nops , o no hasta después del período w2_nops también. El total de w1_nops + w2_nops + w3_nops (más las instrucciones que se muestran aquí) determina el período total de cada bit.

    
respondido por el Dave Tweed

Lea otras preguntas en las etiquetas