A configuração do sistema de relógio (RCC - Reset and Clock Control) é uma etapa fundamental no desenvolvimento com microcontroladores STM32. Este guia aborda os passos e considerações para configurar o sistema utilizando os osciladores HSI (High-Speed Internal) e HSE (High-Speed External) como fontes para o PLL (Phase-Locked Loop).
Passos Gerais para Configuração do Relógio
- Resetar o controlador RCC para o estado padrão.
- Habilitar o oscilador desejado (HSE ou HSI) e aguardar sua estabilização.
- Configurar a latência de acesso à memória Flash.
- Configurar os divisores dos barramentos AHB e APB.
- Configurar a fonte e o fator multiplicador do PLL.
- Habilitar o PLL e aguardar sua estabilização.
- Comutar a fonte do sistema de relógio (SYSCLK) para a saída do PLL.
Pontos Críticos na Configuração
- Sequência Obrigatória: A configuração dos parâmetros do PLL (
PLLSRC,PLLMUL) deve ser concluída antes de habilitar o PLL. Uma vez que o PLL está habilitado, esses bits não podem ser alterados. - Preparação para Alta Velocidade: A configuração da latência da Flash e dos divisores de barramento deve ocorrer antes de comutar para uma fonte de relógio de alta frequência. Isto é crítico porque a Flash pode ter tempos de acesso mais lentos que o ciclo do CPU, e os bararmentos APB possuem limites de frequência (ex.: APB1 máximo de 36 MHz).
- Estabilidade do PLL: A comutação do SYSCLK para o PLL deve ocorrer apenas após o PLL ter atingido a estabilidade, verificando o sinalizador
PLLRDY. Comutar antes pode causar mau funcionamento do sistema.
Exemplo de Configuração Utilizando o HSE (8 MHz)
O exemplo a seguir configura um sistema de relógio de 72 MHz partindo de um cristal externo de 8 MHz, multiplicando-o por 9 via PLL.
#include "stm32f10x.h"
void ConfigurarRelogioHSE(uint32_t fator_multiplicacao)
{
volatile uint32_t contador_inicializacao = 0;
volatile uint32_t status_hse = 0;
// Reinicializa o controlador de relógio
RCC_DeInit();
// Habilita o oscilador externo
RCC_HSEConfig(RCC_HSE_ON);
// Aguarda o HSE estabilizar ou até o timeout
status_hse = RCC_WaitForHSEStartUp();
if (status_hse == SUCCESS)
{
// Configura latência da Flash para 2 ciclos de espera (para SYSCLK até 72 MHz)
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
// Configura os divisores de barramento
RCC_HCLKConfig(RCC_SYSCLK_Div1); // HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1); // PCLK2 = HCLK
RCC_PCLK1Config(RCC_HCLK_Div2); // PCLK1 = HCLK / 2 (máx. 36 MHz)
// Configura o PLL: Fonte = HSE, Fator = fator_multiplicacao
// Relógio PLL = 8 MHz * fator_multiplicacao (ex: 9 = 72 MHz)
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, fator_multiplicacao);
// Habilita o PLL
RCC_PLLCmd(ENABLE);
// Aguarda até que o PLL esteja travado e estável
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
// Espera ativa
}
// Comuta a fonte do SYSCLK para o PLL
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// Verifica se a comutação foi bem-sucedida
while (RCC_GetSYSCLKSource() != 0x08)
{
// Espera ativa
}
}
else
{
// Tratamento de erro: HSE não estabilizou.
// O sistema pode recorrer automaticamente ao HSI como fallback.
while (1)
{
// Trava a execução em caso de falha crítica.
}
}
}
Exemplo de Configuração Utilizando o HSI (8 MHz)
A lógica é análoga, mas utiliza o oscilador interno. Note que o HSI de 8 MHz é dividido por 2 internamente antes de entrar no PLL, resultando em uma frequência de referência de 4 MHz.
#include "stm32f10x.h"
void ConfigurarRelogioHSI(uint32_t fator_multiplicacao)
{
volatile uint32_t status_hsi = 0;
RCC_DeInit();
// Habilita o oscilador interno
RCC_HSICmd(ENABLE);
// Aguarda a estabilização do HSI
while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET)
{
// Espera ativa
}
status_hsi = RCC->CR & RCC_CR_HSIRDY;
if (status_hsi == RCC_CR_HSIRDY)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
// Configura o PLL: Fonte = HSI / 2, Fator = fator_multiplicacao
// Relógio PLL = (8 MHz / 2) * fator_multiplicacao (ex: 18 = 72 MHz)
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, fator_multiplicacao);
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
// Espera ativa
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08)
{
// Espera ativa
}
}
else
{
// Tratamento de erro: HSI falhou.
while (1)
{
// Trava a execução.
}
}
}