Memory-mapped I/O lets a program talk to hardware devices by reading and writing special memory addresses. This makes hardware control simple and fast.
Memory-mapped I/O concept in Embedded C
volatile uint32_t * const DEVICE_REGISTER = (volatile uint32_t *)0x40000000; // Read value uint32_t value = *DEVICE_REGISTER; // Write value *DEVICE_REGISTER = 0x12345678;
volatile tells the compiler the value can change anytime, so it must always read from memory.
The address (like 0x40000000) is the hardware register location.
volatile uint8_t * const LED_CONTROL = (volatile uint8_t *)0x50000000; *LED_CONTROL = 0x01; // Turn on LED
volatile uint16_t * const BUTTON_STATUS = (volatile uint16_t *)0x50000010;
uint16_t status = *BUTTON_STATUS; // Read button statevolatile uint32_t * const UART_DATA = (volatile uint32_t *)0x40001000; *UART_DATA = 'A'; // Send character 'A' via UART
This program writes a value to a memory-mapped register and reads it back. It then prints the value to show how memory-mapped I/O works.
#include <stdint.h> #include <stdio.h> // Simulated hardware register address volatile uint32_t * const SIMULATED_REGISTER = (volatile uint32_t *)0x20000000; int main() { // Write a value to the hardware register *SIMULATED_REGISTER = 0xABCD1234; // Read back the value uint32_t val = *SIMULATED_REGISTER; // Print the value printf("Register value: 0x%X\n", val); return 0; }
Always use volatile for memory-mapped registers to prevent compiler optimizations that skip actual memory access.
Memory addresses must match the hardware documentation exactly.
Accessing wrong addresses can cause crashes or unexpected behavior.
Memory-mapped I/O uses special memory addresses to control hardware devices.
Use pointers with volatile to read/write hardware registers safely.
This method makes hardware control simple and fast in embedded systems.