Skip to content

Alfredosavi/stm32-semihosting-example

Repository files navigation

SEMIHOSTING EXAMPLE - STM32

Este projeto é uma POC (Prova de Conceito) para demonstrar o uso de semihosting em microcontroladores ARM usando a plataforma STM32CubeIDE (versão 1.19.0).
Para este exemplo, foi utilizada a placa NUCLEO-F446RE, mas o guia pode ser utilizado para outras famílias ARM da ST.

O objetivo do projeto é mostrar:

  • A configuração necessária para habilitar semihosting;
  • Exemplos de leitura e escrita de arquivos no host PC via semihosting;
  • Uso de printf() para logging no console do host.

⚠️ AVISO: Este recurso de semihosting destina-se apenas a testes e depuração. Como depende do debugger, pode travar o programa e reduzir significativamente o desempenho. Use com cautela.


O que é Semihosting?

Semihosting é um mecanismo que permite que um microcontrolador ARM envie solicitações de entrada e saída para um computador host rodando o depurador.
Isso possibilita que funções da biblioteca C, como printf() e scanf(), usem a tela e o teclado do host, sem depender de periféricos físicos no MCU.

É especialmente útil durante o desenvolvimento, quando o hardware pode não possuir todos os recursos de entrada/saída do sistema final.
O semihosting é implementado por instruções especiais (ex.: BKPT ou SVC) que geram exceções. O depurador intercepta essas chamadas e realiza a operação no host.

Geralmente, o semihosting é invocado internamente por funções da biblioteca C, mas também pode ser chamado diretamente pela aplicação.

Referência: ARM Semihosting Documentation


Etapas de configuração

Antes de iniciar, certifique-se de ter um projeto CubeIDE criado e com build sem erros.

Para habilitar semihosting, são necessários três ajustes principais, cada um acompanhado de imagem ilustrativa:

1️⃣ Ignorar o arquivo syscalls.c

No projeto padrão do STM32CubeIDE, as funções de sistema (_write, _read, _open, _close, _lseek) estão implementadas em syscalls.c.
Para semihosting, essas funções serão sobrescritas pela biblioteca rdimon, portanto é necessário excluir syscalls.c do build:

  • Clique com o botão direito no arquivo syscalls.c;
  • Vá em Resource Configurations → Exclude from Build;
  • Marque Debug e Release e confirme.

⚠️ Por que é necessário?
O arquivo syscalls.c padrão tenta acessar periféricos inexistentes (UART, filesystem do MCU).
Removê-lo evita conflitos, permitindo que o semihosting (via rdimon) implemente _write, _read, _open, _fclose, etc., corretamente.

exclude build exclude build

2️⃣ Incluir a biblioteca rdimon

O rdimon implementa a interface de semihosting para o linker. Para habilitar:

  • Vá em Propriedades → C/C++ Build → Settings → MCU/MPU GCC Linker → Miscellaneous;

  • No campo Other flags, adicione:

    -specs=rdimon.specs -lc -lrdimon

Isso indica ao linker que a aplicação deve usar a biblioteca de semihosting e sobrescrever as funções padrão de I/O.

linker configuration


3️⃣ Configuração do depurador

Para habilitar o semihosting corretamente durante a depuração, siga os passos abaixo:

  1. Selecionar o depurador ST-LINK (OpenOCD)
    • Abra Run → Debug Configurations → Debugger;
    • Escolha ST-LINK (OpenOCD) como depurador.

debugger configuration

  1. Adicionar comando de inicialização para semihosting
    • Na mesma janela, vá para a aba Startup;

    • No campo Initialization Commands, adicione o comando e aplique as alterações:

      monitor arm semihosting enable

Esse comando instrui o GDB a habilitar o semihosting durante toda a sessão de depuração, permitindo que funções como printf() e fopen() interajam com o host PC.

debugger configuration


Sobre o exemplo

Este firmware demonstra o uso do semihosting para comunicação entre o MCU e o PC host, permitindo que o microcontrolador interaja diretamente com o sistema de arquivos do computador durante a execução.

O projeto realiza as seguintes operações:

  • Utiliza printf() para enviar mensagens ao console do host;
  • Lê um arquivo de texto localizado no PC host e carrega seu conteúdo na RAM do MCU;
  • Grava um novo arquivo de texto no PC host, utilizando dados armazenados na flash do MCU.

Tudo isso é feito de forma transparente, sem necessidade de interfaces físicas de comunicação adicionais — apenas com o semihosting habilitado durante o debug.

⚠️ Importante:
Antes de executar este exemplo, é necessário configurar corretamente a macro ROOT_PATH
com o caminho absoluto da pasta raiz do seu projeto no PC host.

Exemplo:

#define ROOT_PATH "C:/Users/SeuUsuario/Projects/semihosting-example/"

Isso garante que o firmware consiga localizar e abrir/gravar o arquivo de texto durante a execução.

Abaixo está a saída esperada no console do CubeIDE durante a execução: Console

📖 Função read_file()

Esta função demonstra como o MCU, utilizando semihosting, pode abrir e ler um arquivo de texto armazenado no PC host. Ela tenta abrir o arquivo definido em NAME_FILE_READ, lê seu conteúdo linha por linha e exibe tudo no console por meio de printf().

Se o arquivo não for encontrado, a função mostra uma mensagem de erro e interrompe a execução para facilitar o debug.

📖 Função write_file()

Esta função demonstra como o MCU, por meio do semihosting, é capaz de criar e escrever um arquivo de texto diretamente no PC host. O arquivo definido em NAME_FILE_WRITE é aberto (ou criado, caso não exista) e recebe os dados armazenados no array data[]. Após a conclusão da escrita, o arquivo pode ser encontrado na pasta Output — especificada pela macro NAME_DIR_WRITE — dentro do diretório raiz do projeto.

About

Prova de conceito demonstrando o uso de semihosting em microcontroladores ARM.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages