A production-grade, modular open-source C hardware library and educational reference suite targeting the STM32F100 (ARM Cortex-M3) microcontroller family (e.g., STM32VLDISCOVERY board, STM32F100RB/CB Value Line).
- Modular Architecture: Clean separation of Driver Headers (
include/), Implementations (src/), System & Startup Files (system/), and Modular Examples (examples/). - Bare-Metal Drivers: Hand-crafted peripheral abstractions for:
- RCC: Reset and Clock Control & Peripheral Clock Gating
- GPIO: Pin configuration (
CRL/CRH), atomic pin operations (BSRR/BRR), state toggles & reads - USART: Polled transmission & Interrupt-driven RX/TX with a lock-free Circular Ring Buffer
- SysTick: ARM Cortex-M core timer for sub-millisecond precision (
delay_ms(),millis()) - TIM3 PWM: General-purpose timer duty cycle modulation for LED breathing/dimming
- EXTI Interrupts: Hardware pin interrupts (PA0 Button mapped to
EXTI0_IRQHandler) - ADC1: 12-bit Analog-to-Digital single-channel voltage sampling
- Dual-Execution Support: Compiles both locally on Host Machines (CLI Simulation mode via
gcc/clang) and natively for Bare-Metal ARM Cortex-M3 targets (arm-none-eabi-gcc).
Hardware-programming-C/
├── README.md # Master open-source repository documentation
├── Makefile # Multi-target build script
├── LICENSE # Apache 2.0 Open Source License
├── include/ # Driver Header Interfaces
│ ├── stm32f100_map.h # Master Register Maps & Physical Address definitions
│ ├── stm32f100_rcc.h # Reset & Clock Control API
│ ├── stm32f100_gpio.h # GPIO Driver API (CRL/CRH, BSRR/BRR)
│ ├── stm32f100_usart.h # USART API & Lock-Free Ring Buffer
│ ├── stm32f100_systick.h # SysTick 1ms Timekeeping API
│ ├── stm32f100_timer.h # TIM3 Hardware PWM API
│ ├── stm32f100_exti.h # External Pin Interrupt API
│ └── stm32f100_adc.h # ADC1 12-Bit Voltage Sampling API
├── src/ # Core Driver Implementations
│ ├── stm32f100_rcc.c # APB1/APB2 clock enablement
│ ├── stm32f100_gpio.c # Pin configuration & atomic manipulation
│ ├── stm32f100_usart.c # Serial stream & ring buffer routines
│ ├── stm32f100_systick.c # SysTick tick generator & precision delays
│ ├── stm32f100_timer.c # Timer prescaler & PWM compare setup
│ ├── stm32f100_exti.c # AFIO line mapping & EXTI line triggers
│ └── stm32f100_adc.c # ADC conversion sequence setup
├── system/ # Bare-Metal ARM System & Linker Files
│ ├── startup_stm32f100.c # Vector Table & Reset_Handler (.data / .bss initialization)
│ ├── stm32f100.ld # Linker Script (128KB Flash @ 0x08000000, 8KB RAM @ 0x20000000)
│ └── host_sim.c # Host CLI simulation register storage
└── examples/ # Modular Educational Reference Examples
├── 00_hello_world/ # GPIO LED Blink & USART Serial Transmission
├── 01_systick_delay/ # Non-blocking SysTick Timekeeping (`millis()`)
├── 02_gpio_interrupt_exti/ # Hardware Pin Interrupt (`EXTI0_IRQHandler`)
├── 03_usart_interrupt_ringbuf/ # Interrupt-Driven Serial RX/TX with Circular Buffer
├── 04_timer_pwm_dimmer/ # TIM3 Hardware PWM LED Breathing/Dimming
└── 05_adc_potentiometer/ # ADC1 12-Bit Analog Voltage Sampling
To compile and execute all 6 modular reference examples directly on your host machine:
# Build and run all modular examples
make run
# Clean build binaries
make cleanTo build bare-metal .elf binaries and raw .bin images for physical STM32F100 hardware targets using arm-none-eabi-gcc:
make armGenerates target binary images in the repository root:
bin_arm_00_hello_world.binbin_arm_01_systick_delay.binbin_arm_02_gpio_interrupt_exti.binbin_arm_03_usart_interrupt_ringbuf.binbin_arm_04_timer_pwm_dimmer.binbin_arm_05_adc_potentiometer.bin
/* Configure PC9 as General Purpose Output Push-Pull 2MHz */
gpio_config_pin(GPIOC, 9, GPIO_MODE_OUTPUT_PP_2MHZ);
/* Atomic Pin Set / Reset using BSRR and BRR */
gpio_write_pin(GPIOC, 9, true); /* High (LED ON) */
gpio_write_pin(GPIOC, 9, false); /* Low (LED OFF) */
gpio_toggle_pin(GPIOC, 9); /* Toggle ODR bit *//* Initialize 1ms tick generator @ 8MHz System Clock */
systick_init(8000000);
/* Non-blocking timing check */
if ((millis() - last_time) >= 250) {
last_time = millis();
gpio_toggle_pin(GPIOC, 9);
}
/* Blocking millisecond delay */
delay_ms(100);/* Initialize USART1 with Interrupt RX & Ring Buffer @ 115200 Baud */
usart1_init_interrupt(115200, 8000000);
/* Send string */
usart1_send_string("Hello, STM32F100!\r\n");
/* Read bytes from circular ring buffer */
uint8_t byte;
if (ring_buffer_get(&g_usart1_rx_ringbuf, &byte)) {
/* Process incoming character */
}/* Configure TIM3 Channel 4 for 1 kHz PWM output on PC9 */
timer3_init_pwm(1000, 8000000);
timer3_start();
/* Set Duty Cycle (0% to 100%) */
timer3_set_duty_cycle(4, 75);/* Map PA0 (User Button) to EXTI Line 0 on Rising Edge */
exti_config_pin(EXTI_PORT_A, 0, EXTI_TRIGGER_RISING);
/* Interrupt Handler */
void EXTI0_IRQHandler(void) {
if (exti_is_pending(0)) {
exti_clear_pending(0);
/* Handle pin interrupt */
}
}/* Initialize 12-bit ADC1 on PA1 (Channel 1) */
adc1_init();
/* Read 12-bit value (0..4095) */
uint16_t raw_adc = adc1_read_channel(1);
uint32_t millivolts = (raw_adc * 3300UL) / 4095UL;When booting on target hardware, the ARM Cortex-M3 core reads physical memory starting at 0x08000000:
Memory Address Vector Content
-----------------------------------------------------------
0x08000000 Initial Stack Pointer (_estack = 0x20002000)
0x08000004 Reset_Handler Pointer
0x08000008 NMI_Handler Pointer
0x0800000C HardFault_Handler Pointer
... ...
0x0800003C SysTick_Handler Pointer
0x08000058 EXTI0_IRQHandler Pointer
0x080000D4 USART1_IRQHandler Pointer
Distributed under the Apache License 2.0. See LICENSE for full details.