Neste terceiro artigo da série criaremos um arquivo Makefile para automatizar o processo de compilação e geração do binário necessário para a programação da placa. Além disso, utilizaremos o OpenOCD para realizar a gravação do binário diretamente na Franzininho C0.
Criação arquivo MAKE para compilação
Na estrutura do seu projeto crie um arquivo “Makefile”.
Neste arquivo, adicione os seguintes comandos:
firmware.elf: src/main.o src/startup_stm32c011xx.o src/system_stm32c0xx.o
arm-none-eabi-gcc \
src/main.o \
src/startup_stm32c011xx.o \
src/system_stm32c0xx.o \
-specs=nosys.specs \
-T STM32C011F6PX_FLASH.ld \
-mcpu=cortex-m0 \
-mthumb \
-o build/firmware.elf \
-g
src/main.o: src/main.c
arm-none-eabi-gcc \
src/main.c \
-specs=nosys.specs \
-Istm/CMSIS/Device/ST/STM32C0xx/Include \
-Istm/CMSIS/Include \
-Istm/STM32C0xx_HAL_Driver/Inc \
-Istm/STM32C0xx_HAL_Driver/Src \
-DSTM32C011xx \
-mcpu=cortex-m0 \
-mthumb \
-Os \
-o src/main.o \
-g -c
src/startup_stm32c011xx.o: src/startup_stm32c011xx.s
arm-none-eabi-gcc \
src/startup_stm32c011xx.s \
-specs=nosys.specs \
-Istm/CMSIS/Device/ST/STM32C0xx/Include \
-Istm/CMSIS/Include \
-Istm/STM32C0xx_HAL_Driver/Inc \
-Istm/STM32C0xx_HAL_Driver/Src \
-DSTM32C011xx \
-mcpu=cortex-m0 \
-mthumb \
-Os \
-o src/startup_stm32c011xx.0 \
-g -c
src/system_stm32c0xx.o: src/system_stm32c0xx.c
arm-none-eabi-gcc \
src/system_stm32c0xx.c \
-specs=nosys.specs \
-Istm/CMSIS/Device/ST/STM32C0xx/Include \
-Istm/CMSIS/Include \
-Istm/STM32C0xx_HAL_Driver/Inc \
-Istm/STM32C0xx_HAL_Driver/Src \
-DSTM32C011xx \
-mcpu=cortex-m0 \
-mthumb \
-Os \
-o src/system_stm32c0xx.0 \
-g -c
clean:
rm -f firmware.elf firmware.bin src/*.o
Neste Makefile estamos definindo os passos para compilar individualmente cada componente (main, startup, e system), transformá-los em arquivos objeto e finalmente linká-los em um binário .elf, que pode ser gravado na memória do microcontrolador. Para gerar o elf digite no terminal:
makeApós esse comando, o arquivo .elf será salvo na pasta build.
Apesar do nosso Makefile estar funcional ele não segue boas práticas, visto que está repetindo muitos comandos. Podemos modificá-lo utilizando variáveis e regras genéricas para simplificar e generalizar o processo de compilação. Substitua os comandos do arquivo Makefile por:
# Compilador e linker
CC := arm-none-eabi-gcc
# Flags de compilação
CFLAGS := -mcpu=cortex-m0 -mthumb -Os -g -DSTM32C011xx \
-Istm/CMSIS/Device/ST/STM32C0xx/Include \
-Istm/CMSIS/Include -specs=nosys.specs
LDFLAGS := -mcpu=cortex-m0 -mthumb -T STM32C011F6PX_FLASH.ld -specs=nosys.specs
# Diretórios
SRC_DIR := src
BUILD_DIR := build
OBJ_DIR := $(BUILD_DIR)/obj
# Arquivos
SRCS := $(wildcard $(SRC_DIR)/*.c $(SRC_DIR)/*.s)
OBJS := $(patsubst $(SRC_DIR)/%.c,$(OBJ_DIR)/%.o,$(patsubst $(SRC_DIR)/%.s,$(OBJ_DIR)/%.o,$(SRCS)))
TARGET := $(BUILD_DIR)/firmware.elf
# Regras
all: $(TARGET)
# Geração do ELF
$(TARGET): $(OBJS)
@mkdir -p $(BUILD_DIR)
$(CC) $(OBJS) $(LDFLAGS) -o $@
# Regras para objetos
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
@mkdir -p $(OBJ_DIR)
$(CC) $(CFLAGS) -c $< -o $@
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s
@mkdir -p $(OBJ_DIR)
$(CC) $(CFLAGS) -c $< -o $@
# Limpeza
clean:
rm -rf $(BUILD_DIR)
.PHONY: all clean
Neste novo Makefile temos:
1. Variáveis
- CC: Define o compilador utilizado, neste caso, o arm-none-eabi-gcc.
- CFLAGS: Contém as flags de compilação, incluindo:
- -mcpu=cortex-m0 e -mthumb: Configuram a arquitetura e o conjunto de instruções.
- -Os: Otimização para reduzir o tamanho do código.
- -g: Adiciona informações de depuração.
- -DSTM32C011xx: Define uma macro para identificar o microcontrolador.
- -I…: Inclui os diretórios de cabeçalhos.
- LDFLAGS: Flags específicas para o linkador, como o script de link (-T STM32C011F6PX_FLASH.ld).
- SRC_DIR, BUILD_DIR, OBJ_DIR: Diretórios organizando o código-fonte, os objetos compilados e a saída final.
2. Listas de arquivos
- SRCS: Busca automaticamente todos os arquivos .c e .s no diretório src.
- OBJS: Gera a lista de arquivos objeto (.o) correspondente aos arquivos fonte.
3. Regras
- all: $(TARGET): Gera o firmware final (firmware.elf).
- Junta todos os arquivos objeto ($(OBJS)) para criar o binário ELF.
- Cria o diretório de saída ($(BUILD_DIR)) se não existir.
- Usa padrões (%.o) para compilar arquivos fonte (.c e .s) em objetos.
- clean: Remove o diretório de compilação ($(BUILD_DIR)), apagando os arquivos gerados.
Quando você digitar make no terminal, os arquivos serão gerados.
make
Dicas:
Após a geração do arquivo elf você usar os seguintes comandos:
- Para gerar tamanho do binário:
arm-none-eabi-size build/firmware.elf
- Para gerar mapeamento detalhado:
arm-none-eabi-gcc -Wl,-Map=firmware.map -o build/firmware.elfGravação na Franzininho C0 usando OpenOCD
Com o ST-Link conectado à Franzininho C0 e devidamente reconhecido pelo WSL, siga os passos abaixo para realizar a gravação do firmware:

- Instale ferramenta st-link
sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa sudo apt update sudo apt install stlink-tools- Digite o seguinte comando no terminal do Ubuntu:
sudo nano /etc/udev/rules.d/99-stlink.rulesEsse comando abrirá um arquivo para regra personalizada.
- No arquivo aberto adicione a regra, substituindo o idVendor e idProduct pelos valores exibidos no comando lsusb
SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", MODE="0666"
Substitua 0483 e 374b pelos valores específicos exibidos no seu sistema. Para sair do arquivo, pressione CTRL+X e, em seguida, confirme com Y que deseja salvar alterações feitas.
- Crie um arquivo de configuração stm32c011f6.cfg e insira os comandos
ource [find interface/stlink.cfg]
transport select hla_swd
set CHIPNAME stm32c011f6
source [find target/stm32c0x.cfg]
reset_config srst_only
- Inicie o Openocd, digitando no terminal o seguinte:
sudo openocd -f interface/stlink.cfg -f target/stm32c0x.cfgA saída deve ser algo semelhante

- Mantenha este terminal ativo. Em seguida, abra outro terminal e execute o comando:
telnet localhost 4444
Se o comando não funcionar, tente instalar o telnet com sudo apt install telnet.
- No prompt do Telnet (após conectar), use o comando abaixo para gravar o arquivo ELF na memória da placa. Certifique-se de ajustar o caminho conforme a localização do seu arquivo:
program /home/grazi/hello-world/build/firmware.elf verify resetSubstitua /home/grazi/hello-world/build/firmware.elf pelo caminho completo onde o arquivo ELF está salvo no seu sistema.

Funcionamento
Desafio
Adapte o código para também piscar o LED conectado ao pino PB7. Após realizar a modificação, recompilhe o projeto para gerar o novo arquivo .elf e, em seguida, grave-o na placa.
Conclusão
Nesta série “Programando Franzininho C0 na Unha Sem o Ecossistema STM32Cube”, dividida em três partes, você aprendeu do zero como desenvolver um sistema capaz de gravar códigos no microcontrolador e a escrever códigos acessando diretamente os registradores com o auxílio das macros do CMSIS. Utilizamos ferramentas como OpenOCD, Make, CMSIS e a GNU ARM Embedded Toolchain para criar um fluxo completo e funcional.
O projeto completo está disponível aqui: https://github.com/Graziele-Rodrigues/blink_stm32c0_com_cmsis





