¿Cómo se envían datos a una tira de LED cada 400 ns?

0

Quiero enviar datos a una tira de LED. Esto se debe hacer aproximadamente cada 400 (u 800 ns), dependiendo de los datos (un 0 o un 1 a ser enviado).

unsigned long  counter  = 0;

Hice una prueba con mi STM32F103C8T6 con este código en el bucle:

while (1)
{
    GPIOC->BSRR = GPIO_PIN_13; // Set GPIO
    counter++;
}

Corrí en modo de depuración, para poder verificar el valor del contador. Después de aproximadamente 10 segundos, suspendí el programa y verifiqué el valor del contador. Tenía un valor de 27822623. Esto significa que cada contador toma aproximadamente 10/27822623 = 3.5942E-07 segundos / incremento de contador, que es de 359 ns / incremento de contador.

Sin embargo, todo lo que hago aquí es configurar el pin GPIO, que es un puntero de desplazamiento, una asignación y un incremento. Y esto lleva el tiempo 'gigantesco' de 359 ns. En mi aplicación real, necesito ir al siguiente byte, verificar si es un 0 o 1, dependiendo de eso para enviar el comando anterior para configurar, o un comando de reinicio del pin (que requiere un cambio de bit adicional). ¿Cómo puedo realizar esto dentro (o en realidad alrededor de 400 ns?)

El STM32 está configurado a 72 MHz (velocidad máxima). No tengo ninguna interrupción adicional en ejecución.

¿Cómo puedo enviar datos a 400 ns manualmente?

(Intenté SPI: no lo suficientemente confiable, a veces se omiten los pulsos del reloj y los datos resultantes). Las interrupciones a través de un temporizador incluso tomarán más tiempo, ya que contiene flujo de interrupción (a través de HAL).

Actualizar

Nueva aplicación para probar mejor:

unsigned long  counter  = 0;

En main:

while (1)
{
    GPIOC->BSRR = GPIO_PIN_13; // SET
counter++;

    if (counter == 10000000)
{
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);
    counter = 0;
    }
}

Actualizar Debajo del código desensamblado (más de lo que pensaba):

152                 GPIOC->BSRR = GPIO_PIN_13; // SET
0800122e:   mov.w   r2, #8192       ; 0x2000
08001232:   ldr     r3, [pc, #36]   ; (0x8001258 <main+64>)
08001234:   str     r2, [r3, #16]
158               counter++;
08001236:   ldr     r2, [pc, #36]   ; (0x800125c <main+68>)
08001238:   ldr     r3, [r2, #0]
0800123a:   adds    r3, #1
0800123c:   str     r3, [r2, #0]
159               if (counter == 10000000)
0800123e:   ldr     r2, [pc, #32]   ; (0x8001260 <main+72>)
08001240:   cmp     r3, r2
08001242:   bne.n   0x800122e <main+22>
161                   HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);
08001244:   mov.w   r1, #16384      ; 0x4000
08001248:   ldr     r0, [pc, #12]   ; (0x8001258 <main+64>)
0800124a:   bl      0x80004e0 <HAL_GPIO_TogglePin>
162                   counter = 0;
0800124e:   movs    r2, #0
08001250:   ldr     r3, [pc, #8]    ; (0x800125c <main+68>)
08001252:   str     r2, [r3, #0]
08001254:   b.n     0x800122e <main+22>
08001256:   nop  
    
pregunta Michel Keijzers

1 respuesta

1

Este podría ser un buen momento para ver el ensamblado que generó su compilador y realmente considerar su mejora.

Es posible que su stm32 tenga una región de "banda de bits" para los registros de gpio, de modo que pueda acceder directamente a ese registro de control sin ninguna manipulación de bits directamente como dirección de bytes.

Puede hacer cosas increíblemente eficientes al no hacer una comparación manual con su byte de 0 o 1, sino mediante movimientos condicionales que dependen de ese valor; de esa manera, se pueden canalizar el valor de recuperación y la configuración del registro correcto al valor correcto. Si no lo has hecho, primero prueba diferentes banderas del compilador ( -O2 podría ser un buen comienzo) para asegurarte de que tu compilador no haga eso por ti.

    
respondido por el Marcus Müller

Lea otras preguntas en las etiquetas