Cambiar la latencia del flash de 0 a 1, incluso con la recuperación previa activada habilitada en STM32

3

He puesto toda la configuración del reloj a su estado predeterminado, por lo que un oscilador interno está funcionando a 8 mhz. Tengo un bucle de retardo utilizando el ensamblaje en línea de la siguiente manera:

// Delay a certain number of cycles using glorious inline assembly.
void delay(uint32_t time) {
    asm volatile(
        "mov r4, #3                \n" // Divide time by three since the loop is
        "udiv %[time], %[time], r4 \n" // 3x too slow.
        "loop:                     \n"
        "subs %[time], %[time], #1 \n" // 1 cycle
        "bne loop                  \n" // 1 cycle if not take, 2 if taken.
        : [time] "+l" (time)           // Put rw input variable time in r0..r7.
                                       // Make it rw and as output so we don't clobber
        :                              // Time is both input and output.
        : "r4", "cc"                   // We are clobbering r4 and condition code flags.
    );
}

y una rutina GPIO como sigue:

// Blink the led with a period of 1 second.
while (1) {
    // Set LED pin.
    GPIOA_BSRR = 1 << LED_PIN;
    delay(second_cycles / 2);

    // Reset LED pin
    GPIOA_BSRR = 1 << (LED_PIN + 16);
    delay(second_cycles / 2);
}

Cuando se ejecuta sin estados de espera, todo está bien y funciona como se espera. Pero cuando cambio los estados de espera para flash de 0 a 1, mi bucle toma 833 milisegundos en lugar de 500 milisegundos, o una pérdida del rendimiento del 66% aproximadamente.

Cuando uso GDB para depurar, puedo ver que el registro FLASH_ACR tiene el contenido de 0b0011 0000 , lo que significa que el búfer de captación previa está habilitado y tiene un estado de habilitado, con 0 estados de espera para flash. Además, el búfer de captación previa debe habilitarse en el reinicio según la hoja de datos. Cuando escribo en el registro al hacerlo con 0b001 obtengo el resultado esperado de 0b0011 0001 después de leerlo nuevamente. Esto se hace haciendo lo siguiente:

// Change the flash wait states to 1.
volatile uint32_t foo1 = FLASH_ACR;
FLASH_ACR = FLASH_ACR | (0b001 << 0);
volatile uint32_t foo2 = FLASH_ACR;

Curiosamente, habilitar o deshabilitar el búfer de captación previa con un estado de espera 1 no hace ninguna diferencia en mi bucle, lo que no parece tener sentido.

Y aquí está la sección relevante de la hoja de datos

Estoyusandouna placa NUCLEO-F303RE , que utiliza un STM32F103RE.

    
pregunta hak8or

1 respuesta

1

El búfer de caché en STM32F303RE solo tiene 8 bytes (64 bits), por lo tanto, si su código de ciclo tiene más de 8 bytes, no tendrá efecto porque el búfer se reescribe cada ciclo una y otra vez. Aquí, el I-cache podría ayudarlo, pero como veo, no hay I-cache en este MCU.

Es preferible usar un temporizador que provenga de un reloj siempre constante, como 32.768 kHz u otra oscilación, para contar los retrasos. Su MCU implementa muchos temporizadores y el RTC, intente usar uno.

void delay(unsigned timertickstowait)
{
  unsigned time0 = get_current_timer_ticks_count();
  while( (unsigned)(get_current_timer_ticks_count() - time0) < timertickstowait )
    { /* do nothing */ }
  return;
}

Si el temporizador que utiliza se obtiene de un reloj (frecuencia) independiente del reloj de MCU, la rutina de demora será prácticamente independiente en su comportamiento de la frecuencia de MCU y / o los parámetros de acceso a Flash.

    
respondido por el asndre

Lea otras preguntas en las etiquetas