How to Write a (GPIO_reg.h) File for STM32F401 GPIO
Introduction
When you’re
working close to the hardware, you need a way to talk to registers without
memorizing their hex addresses. That’s where the reg.h file comes
in!!! a small header that connects register addresses from the datasheet to
something you can use in C.
1. Where to Start
Everything begins with the reference manual for the
STM32F401. Two places in it matter the most:
- Memory map → gives
you the starting address for each peripheral.
- Peripheral section → shows
the registers, their offsets, and their bit fields.
Examples:
[1] GPIO Driver (Step 1, Get the Base Address)
·
GPIOA Base address: 0x40020000
·
GPIOB Base address: 0x40020400
·
GPIOC Base address: 0x40020800
·
Registers:
- MODER: 0x00
- OTYPER: 0x04
- OSPEEDR: 0x08
- PUDR: 0x0C
- IDR: 0x10
- ODR: 0x14
- BSRR: 0x18
- LCKR: 0x1C
- AFRL: 0x20
- AFRH: 0x24
2. Build the Struct
In C, we can make a struct that lines up exactly with the hardware
layout.
typedef
struct
{
u32 MODER; // 0x00
u32 OTYPER; // 0x04
u32 OSPEEDR; // 0x08
u32 PUPDR; // 0x0C
u32 IDR; // 0x10
u32 ODR; // 0x14
u32 BSRR; // 0x18
u32 LCKR; // 0x1C
u32 AFRL; // 0x20
u32
AFRH; // 0x24
}
GPIO_MemoryMap_t;
- The order must match the manual — even
unused spots need to be accounted for.
3. Base Addresses
#define
GPIOA_BASE_ADDRESS 0x40020000
#define
GPIOB_BASE_ADDRESS 0x40020400
#define
GPIOC_BASE_ADDRESS 0x40020800
4. Pointers to the Struct
We link the address to the struct type:
#define
GPIOA ((volatile GPIO_MemoryMap_t*) (GPIOA_BASE_ADDRESS))
#define
GPIOB ((volatile GPIO_MemoryMap_t*) (GPIOB_BASE_ADDRESS))
#define
GPIOC ((volatile GPIO_MemoryMap_t*) (GPIOC_BASE_ADDRESS))
volatile tells the
compiler this value can change outside the program (e.g., hardware writes to
it)
Now to access any register you can do it as simple as possible:
GPIOA
-> ODR
5. Same Steps for Any
Peripheral
The process doesn’t change for USART, SPI, I2C, NVIC, or anything
else:
- Get base address.
- List registers and offsets.
- Make struct in correct order.
- Add reserved spaces if needed.
- Define pointer macros.
6. Things That Break Your Code
- Wrong register order →
every value read/written is
off.
- Skipping volatile → compiler might remove your register
access.
- Wrong base address → you’re
talking to the wrong hardware block.
- Forgetting reserved spots → struct
alignment goes wrong.
7. Wrap-Up
Once you understand this, you can make a reg.h for anything on the
STM32F401.
The idea is always the same:
- Look up base address.
- Copy the register layout.
- Turn it into a struct.
- Point a macro at it.


Comments
Post a Comment