0
0
Power-electronicsHow-ToBeginner · 3 min read

How to Read Modify Write Register in Embedded C

To read, modify, and write a hardware register in embedded C, first read the register value using a pointer to the register address, then change the bits you want using bitwise operations, and finally write the new value back to the register using the same pointer. Use volatile pointers to ensure the compiler does not optimize away these hardware accesses.
📐

Syntax

Use a volatile pointer to the register address to read and write the register. Use bitwise operators to modify specific bits without affecting others.

  • volatile uint32_t *REG = (volatile uint32_t *)0xADDRESS; — pointer to register
  • uint32_t val = *REG; — read register value
  • val |= MASK; — set bits
  • val &= ~MASK; — clear bits
  • *REG = val; — write back modified value
c
volatile uint32_t *REG = (volatile uint32_t *)0x40021000; // example address
uint32_t val = *REG;           // read register
val |= 0x01;                  // set bit 0
val &= ~0x02;                 // clear bit 1
*REG = val;                   // write back
💻

Example

This example shows how to read a 32-bit register, set bit 3, clear bit 2, and write the new value back safely.

c
#include <stdint.h>
#include <stdio.h>

// Simulate a hardware register as a global variable
volatile uint32_t REGISTER = 0x0A; // initial value 00001010b

int main() {
    volatile uint32_t *reg = &REGISTER;
    uint32_t val = *reg;           // read register

    val |= (1 << 3);               // set bit 3 (bit counting from 0)
    val &= ~(1 << 2);              // clear bit 2

    *reg = val;                   // write back

    printf("Register value after modify: 0x%X\n", *reg);
    return 0;
}
Output
Register value after modify: 0x12
⚠️

Common Pitfalls

Common mistakes include:

  • Not using volatile, causing the compiler to optimize away register reads/writes.
  • Overwriting the entire register without preserving other bits.
  • Using incorrect bit masks or shifts.

Always read the register first, modify only the bits you want, then write back.

c
/* Wrong way: overwrites all bits, losing other settings */
*REG = 0x01; // sets bit 0 but clears others

/* Right way: read-modify-write preserves other bits */
uint32_t val = *REG;
val |= 0x01; // set bit 0
*REG = val;
📊

Quick Reference

StepActionCode Example
1Declare volatile pointer to registervolatile uint32_t *REG = (volatile uint32_t *)0xADDRESS;
2Read current register valueuint32_t val = *REG;
3Modify bits using bitwise operatorsval |= MASK; // set bits val &= ~MASK; // clear bits
4Write modified value back*REG = val;

Key Takeaways

Always use volatile pointers to access hardware registers to prevent compiler optimizations.
Use read-modify-write to change only specific bits without affecting others.
Use bitwise OR (|) to set bits and bitwise AND with NOT (&~) to clear bits.
Never overwrite the whole register unless you intend to reset all bits.
Test your code on real hardware or simulators to verify register changes.