How to Use Pointer to Register in Embedded C: Simple Guide
In Embedded C, you use a
pointer to access a hardware register by assigning the register's memory address to a pointer variable declared as volatile. This lets you read or write the register directly through the pointer, ensuring the compiler does not optimize away these accesses.Syntax
To use a pointer to a hardware register, declare a volatile pointer to the register's address. The volatile keyword tells the compiler the value can change anytime, so it must not optimize access.
Example parts:
volatile: prevents compiler optimizationsuint32_t *: pointer to a 32-bit unsigned register0x40021000: example register address= (volatile uint32_t *)0x40021000;: cast address to pointer type
c
volatile uint32_t *reg_ptr = (volatile uint32_t *)0x40021000;Example
This example shows how to write a value to a hardware register and then read it back using a pointer. It simulates a register at a fixed memory address.
c
#include <stdint.h> #include <stdio.h> // Simulate hardware register memory uint32_t simulated_register = 0; int main() { // Pointer to the simulated register address volatile uint32_t *reg_ptr = &simulated_register; // Write a value to the register *reg_ptr = 0xABCD1234; // Read the value back uint32_t value = *reg_ptr; printf("Register value: 0x%X\n", value); return 0; }
Output
Register value: 0xABCD1234
Common Pitfalls
Common mistakes when using pointers to registers include:
- Not using
volatile, causing the compiler to optimize away register reads/writes. - Using incorrect pointer types or sizes, leading to wrong data access.
- Forgetting to cast the register address to the correct pointer type.
- Accessing invalid memory addresses causing crashes.
Always verify the register address and use volatile to ensure proper hardware access.
c
/* Wrong: Missing volatile - compiler may optimize away access */ uint32_t *reg_ptr_wrong = (uint32_t *)0x40021000; *reg_ptr_wrong = 0x01; // May not actually write to hardware /* Correct: Use volatile to prevent optimization */ volatile uint32_t *reg_ptr_right = (volatile uint32_t *)0x40021000; *reg_ptr_right = 0x01; // Guaranteed write to hardware
Quick Reference
| Concept | Description | Example |
|---|---|---|
| volatile | Prevents compiler optimization on register access | volatile uint32_t *reg_ptr; |
| Pointer cast | Cast address to pointer type for correct access | (volatile uint32_t *)0x40021000 |
| Dereference | Read or write register via pointer | *reg_ptr = 0x01; |
| Address | Use correct hardware register address | 0x40021000 |
Key Takeaways
Always declare register pointers as volatile to prevent compiler optimizations.
Cast the hardware register address to the correct pointer type before use.
Use pointers to read from and write to hardware registers directly.
Verify register addresses carefully to avoid invalid memory access.
Dereference the pointer to access the register value safely.