Mecanismo de Callback na HAL: Exemplo Completo com UART em STM32

Este exemplo detalha o fluxo completo de um callback de conclusão de transmissão UART utilizando a HAL (Hardware Abstraction Layer) do STM32, desde a inicialização até a ativação do callback. O código base é gerado pelo CubeMX, com acréscimos de comentários explicativos.

Inicialização de Hardware (Geração CubeMX)

No arquivo main.c, a rotina de inicialização gerada pelo CubeMX inclui:


// Inicialização do clock do sistema, GPIO, UART, etc.
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);

int main(void) {
 HAL_Init();
 SystemClock_Config();
 MX_GPIO_Init();
 MX_USART2_UART_Init();  // Inicializa UART2
 // ... outros códigos
}
 

Configuração da UART (Parâmetros Essenciais)

Dentro de MX_USART2_UART_Init(), os parâmetros da UART são definidos. A função HAL_UART_MspInit é chamada implicitamente:


UART_HandleTypeDef huart2;

void MX_USART2_UART_Init(void) {
 huart2.Instance = USART2;
 huart2.Init.BaudRate = 115200;
 huart2.Init.WordLength = UART_WORDLENGTH_8B;
 huart2.Init.StopBits = UART_STOPBITS_1;
 huart2.Init.Parity = UART_PARITY_NONE;
 huart2.Init.Mode = UART_MODE_TX_RX;
 huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
 // Chama a inicialização da HAL para a UART, que por sua vez chama HAL_UART_MspInit()
 HAL_UART_Init(&huart2);
}
 

Sobrescrita da Função de Callback pelo Usuário

No arquivo de código do usuário (e.g., main.c), a função de callback definida como __weak, HAL_UART_TxCpltCallback, é sobrescrita:


// Sobrescreve a função de callback de conclusão de transmissão UART
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
 // Verifica qual instância da UART gerou o callback
 if (huart->Instance == USART2) {
   HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); // Operação personalizada: inverte o estado do LED
   printf("Transmissao UART concluida!\\r\\n");
 }
}
 

Início da Transmissão UART (Acionando o Callback)

Na função main(), a transmissão UART é iniciada no modo de interrupção:


uint8_t txData[] = "Ola, STM32 HAL Callback!\r\n";

int main(void) {
 // ... código de inicialização ...

 // Inicia a transmissão UART no modo de interrupção
 HAL_UART_Transmit_IT(&huart2, txData, sizeof(txData) - 1);

 while (1) {
   // O loop principal pode executar outras tarefas
 }
}
 

Acionamento da Interrupção e Fluxo do Callback

Cadeia completa de acionamento:

  1. Início da Transmissão: HAL_UART_Transmit_IT() inicia a transmissão e habilita a interrupção de conclusão de transmissão (TCIE) da UART.

  2. Interrupção de Hardware: Ao concluir a transmissão do último byte, o hardware aciona o vetor de interrupção USART2_IRQHandler.

  3. Processamento pela HAL: ```

    // Definição da rotina de tratamento de interrupção em stm32xx_it.c void USART2_IRQHandler(void) { // A HAL processa a interrupção da UART de forma unificada HAL_UART_IRQHandler(&huart2); }

  4. Chamada do Callback: Dentro de HAL_UART_IRQHandler(), ao detectar a flag de conclusão de transmissão (TC), a HAL chama automaticamente HAL_UART_TxCpltCallback().

Pontos Chave

  • Callbacks com Definição Fraca (__weak): A HAL fornece implemnetações padrão como __weak void HAL_UART_TxCpltCallback(...), que o usuário pode sobrescrever para adicionar sua lógica personalizada.
  • Identificação do Periférico: Dentro da função de callback, é crucial verificar huart->Instance para distinguir qual periférico (e.g., USART1, USART2) originou o evento, especialmente em sistemas com múltiplas UARTs.
  • Configuração de Interrupção: A função HAL_UART_Init(), através de HAL_UART_MspInit(), é responsável por configurar o NVIC (prioridade e habilitação da interrupção) para o periférico UART correspondente.
  • Sem Registro Explícito: O usuário simplesmente sobrescreve a função de callback; não é necessário registrar pontieros de função explicitamente.

Comportamento em Execução

  • Condição de Acionamento: O callback é executado após a conclusão bem-sucedida da transmissão pela UART (o último byte é enviado pelo registrador de deslocamento).
  • Lógica do Usuário: Neste exemplo, a lógica personalizada inverte o estado de um LED e exibe uma mensagem na saída serial.
  • Natureza Assíncrona: O loop principal while(1) não precisa verificar o status da transmissão, permitindo operações não bloqueantes e otimização do uso do processador.

Comparação com Caso Sem Sobrescrita de Callback

  • Se o usuário não sobrescrever HAL_UART_TxCpltCallback, a função padrão (fraca), que é vazia, será executada sem realizar nanhuma ação.
  • Para implementar lógica personalizada em resposta a eventos de transmissão, o usuário deve obrigatoriamente sobrescrever a função de callback. A vantagem é que a HAL cuida dos detalhes de baixo nível, como a limpeza de flags de interrupção.

Fluxo de Trabalho Geral dos Callbacks na HAL

  1. Inicialização do Periférico: A configuração do hardware é realizada, geralmente via código gerado pelo CubeMX.
  2. Implementação do Callback: O usuário define a lógica de resposta para eventos específicos sobrescrevendo as funções de callback apropriadas.
  3. Início de Operações Assíncronas: Funções como HAL_UART_Transmit_IT() são chamadas para iniciar operações que podem ser concluídas posteriormente.
  4. Acionamento Automático do Callback: O sistema de interrupção e a HAL orquestram a chamada da função de callback do usuário quando o evento correspondente ocorre.

Este mecanismo permite desacoplar a lógica de hardware das rotinas de aplicação, simplificando o desenvolvimento e a manutenção do código.

Tags: STM32 HAL UART Callback Interrupção

Publicado em 8-10 21:37