stm32f407-custom-drivers
A hand-written driver library for the STM32F4DISCOVERY board (STM32F407VGT6), a main application that uses it, and nine timer, PWM and UART example projects.
- Hardware and stack
-
STM32F4DISCOVERY, STM32F407VGT6 (Arm Cortex-M4F), on-board ST-LINK. C with the STM32Cube HAL, built in STM32CubeIDE and from the command line with the Arm GNU toolchain.
- C
- STM32Cube HAL
- STM32CubeIDE
- cppcheck
- GitHub Actions
- What it does
-
io: button and LED state in structs, non-blocking software debounce.adc: ADC1 + DMA five-channel scan (PA2, PA3, temperature sensor, VREFINT, VBAT), sample averaging, VDDA computed from VREFINT.circular_buffer: ISR-safe single-producer, single-consumer byte queue.uart: interrupt-driven RX and TX on two circular buffers,printf-style output.- Nine example projects: timer external clock, trigger and slave modes, input capture, output compare, PWM and UART
printf. - in progress SPI and I2C drivers.
- How it is tested
- Host-side unit tests for the hardware-independent code (
make -C tests). CI on every push and pull request: unit tests, cppcheck static analysis ofdrivers/, and Debug and Release firmware builds of all ten projects. - Configuration
-
Configured values from the repository README. These are settings, not measurements. Parameter Setting Type System clock, main application 168 MHz (HSI 16 MHz, PLL) configured USART3, PB10 TX / PB11 RX 115200 baud, 8N1 configured Button debounce 100 ms configured ADC averaging 64 samples configured - Test results
- Four host unit tests for the circular buffer: empty at start, a zero byte is valid data, 511-byte capacity with FIFO order, and wrap-around. The latest CI run on
mainpassed on : unit tests, cppcheck, and Debug and Release builds of all ten projects. - Problems found and fixed
-
- TX race: TXE is set whenever
DRis empty, so an interrupt raised for a received byte also ran the TX code whileUARTx_Write()was using the same buffer. The ISR now also checks that the TXE interrupt is enabled. - UART overrun: the HAL handler switches the RXNE interrupt off on an overrun, so reception stopped.
HAL_UART_ErrorCallback()now clears the flag and switches it back on. - Shared state between interrupts and the main loop: the circular buffer indices and the ADC DMA flag are now
volatile, and the buffer reads each index once. - Input capture: inside the callback HAL sets
Channelto the active-channel value, notTIM_CHANNEL_1, so the callback guard never matched. Fixed in the input capture and output compare examples. - Reference manual check: RM0090 limits the ETR input to a quarter of the timer clock, so the 8 MHz MCO1 signal in example 002 can lose pulses at a 16 MHz timer clock. The README documents the DIV4 prescaler as the fix.
- TX race: TXE is set whenever