He puesto toda la configuración del reloj en su estado predeterminado, por lo que un oscilador interno funciona a 8 mhz. Tengo un ciclo de retardo usando 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 de la siguiente manera:
// 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 esperaba. Pero cuando cambio los estados de espera para flash de 0 a 1, mi bucle tarda 833 milisegundos en lugar de 500 milisegundos, o una pérdida de rendimiento del 66% aproximadamente.
Cuando uso GDB para depurar, puedo ver que el registro FLASH_ACR tiene un contenido que 0b0011 0000
significa que el búfer de captación previa está habilitado y tiene un estado 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 hacer or'ing, 0b001
obtengo el resultado esperado de 0b0011 0001
volver 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 búsqueda 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.
Estoy usando una placa NUCLEO-F303RE , que usa un STM32F103RE.
El búfer de caché en STM32F303RE tiene solo 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í, I-cache podría ayudarlo, pero como veo, no hay I-cache en esta MCU.
Es preferible utilizar 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 proviene de un reloj (frecuencia) independiente del reloj de la MCU, la rutina de retardo será prácticamente independiente en su comportamiento de la frecuencia de la MCU y/o los parámetros de acceso Flash.
rdtsc
hak8or