STM32F103 ARM - Modificación del reloj en tiempo de ejecución - Latencia FLASH

Tengo un poco de confusión con respecto a cambiar el árbol del reloj de un STM32F103 Cortex M3 en tiempo de ejecución y espero que alguien pueda ayudarme con eso.

Estoy usando una placa de desarrollo que tiene un HSE de 8Mhz a bordo. Según la configuración predeterminada del archivo STM SPL stm32f10x_system.c, PLL (derivado de HSE) se selecciona como la fuente SYSCLK en el arranque.

Me gustaría usar PLL como fuente (derivado de HSI). Por lo que he entendido, los pasos principales son

  1. Habilitar HSI. Espera a que esté listo
  2. Establezca HSI como fuente SYSCLK. Establezca HCLK, PCLK1 y PCLK2 en consecuencia
  3. Deshabilitar PLL. Cambie su fuente a HSI y configure el multiplicador
  4. Habilitar PLL. Espere a que PLL esté listo
  5. Establezca PLL como fuente SYSCLK. establezca HCLK, PCLK1 y PCLK2 en consecuencia

Como se indicó anteriormente, escribí mi rutina llamada cuando se inicia main()

//TURN ON HSI AND SET IT AS SYSCLK SRC
RCC_HSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET){};

//SET HSI AS SYSCLK SRC. CONFIGURE HCLK, PCLK1 & PCLK2
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);

//DISABLE PLL
RCC_PLLCmd(DISABLE);

//CHANGE PLL SRC AND MULTIPLIER
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);

//ENABLE PLL
//WAIT FOR IT TO BE READY
//SET SYSCLK SRC AS PLLCLK
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){};
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

//SET HCLK = SYSCLK = 64MHZ
RCC_HCLKConfig(RCC_SYSCLK_Div1);

//SET PCLK2 = HCLK = 64MHZ
RCC_PCLK2Config(RCC_HCLK_Div1);

//SET PCLK1 = HCLK/2 = 32MHZ
RCC_PCLK1Config(RCC_HCLK_Div2);

Esto funciona bien. Luego me di cuenta de que tendría que cambiar la latencia de FLASH y mi reloj.

Así que hice esto

//SETUP THE SYSTEM CLOCK AS BELOW
//CLOCK SRC = 8MHZ HSI + PLL
//SYSCLK = 64MHZ
//HCLK = SYSCLK = 64MHZ
//PCLK2 = HCLK = 64MHZ
//PCLK1 = HCLK = 32MHZ

//TURN ON HSI AND SET IT AS SYSCLK SRC
RCC_HSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET){};

//SET HSI AS SYSCLK SRC. CONFIGURE HCLK, PCLK1 & PCLK2
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);

//SET THE FLASH LATENCY AS PER OUR CLOCK
//FASTER THE CLOCK, MORE LATENCY THE FLASH NEEDS
//000 Zero wait state, if 0  MHz < SYSCLK <= 24 MHz
//001 One wait state, if  24 MHz < SYSCLK <= 48 MHz
//010 Two wait states, if 48 MHz < SYSCLK <= 72 MHz */
FLASH_SetLatency(FLASH_Latency_0);

//DISABLE PLL
RCC_PLLCmd(DISABLE);

//CHANGE PLL SRC AND MULTIPLIER
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);

//ENABLE PLL
//WAIT FOR IT TO BE READY
//SET SYSCLK SRC AS PLLCLK
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){};
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

FLASH_SetLatency(FLASH_Latency_2);

//SET HCLK = SYSCLK = 64MHZ
RCC_HCLKConfig(RCC_SYSCLK_Div1);

//SET PCLK2 = HCLK = 64MHZ
RCC_PCLK2Config(RCC_HCLK_Div1);

//SET PCLK1 = HCLK/2 = 32MHZ
RCC_PCLK1Config(RCC_HCLK_Div2);

Esto también funciona. Entonces mis preguntas son

  1. ¿La configuración de la latencia del flash es opcional? ya que en mi caso funciono aun sin el.
  2. ¿Cuándo llama exactamente a la función FLASH_SetLatency con el nuevo estado de espera? ¿Antes de configurar el nuevo reloj o justo después?

Respuestas (2)

¿La configuración de la latencia del flash es opcional? ya que en mi caso funciono aun sin el.

No. Si no configura correctamente la latencia flash, su programa a veces puede leer datos incorrectos de la memoria flash.

¿Cuándo llama exactamente a la función FLASH_SetLatency con el nuevo estado de espera? ¿Antes de configurar el nuevo reloj o justo después?

Antes de aumentar la frecuencia del reloj del sistema o después de disminuirla.

Tener una latencia demasiado alta para el reloj del sistema es casi inofensivo: ralentizará un poco el sistema, pero eso es todo, pero tener una latencia demasiado baja puede causar fallas de funcionamiento.

Gracias. Tiene más sentido. Entendido el having latency too high is mostly harmless..bit. ¿ Puedes explicar más en Before increasing the system clock frequency, or after decreasing it..parte?
Considere: podría estar cambiando la velocidad del reloj hacia arriba o hacia abajo. Si la velocidad del reloj aumenta, es necesario aumentar la latencia del flash antes de que aumente la velocidad del reloj. Si la velocidad del reloj está disminuyendo, no puede disminuir la latencia hasta que la velocidad del reloj ya haya disminuido.
¿La configuración de latencia de Flash podría ser el problema también en esta pregunta ?

También debe agregar esta línea: SystemCoreClock = 64000000;

  • Variable SystemCoreClock: contiene el reloj central (HCLK), puede ser utilizado por la aplicación del usuario para configurar el temporizador SysTick o configurar otros parámetros.

O incluso mejor, en lugar de:

SystemCoreClock = 64000000;

llamar:

SystemCoreClockUpdate();

y calculará la variable SystemCoreClock.