Embedded C and assembly
הוצג| English | משמעות |
|---|---|
| memory-mapped register | רשם ממוחשב במפת זיכרון |
| assembly | assembly |
Nothing between code and transistor
- A sensor node's firmware is a few thousand lines of C that write hardware registers directly. There is no operating system in between.
- So every line must map onto the machine exactly. This lesson shows how one C line becomes instructions and bus transfers.
Registers are addresses
- A memory-mapped register 存储器映射寄存器 is a hardware control word that lives at a fixed address. C reaches it through a pointer to that address.
- The pointer must be
volatile: it tells the compiler the value can change outside the program, so every read and write must really happen.
Why must a pointer to a hardware status register be volatile?
רמת קושי 1/5 · 100 מטבעות + בונוס קטן בהשלמה הראשונה היום
Without volatile the compiler may read once and reuse the value, so a loop waiting for a status bit can spin for ever.
From C to assembly
- The compiler turns C into loads, stores, arithmetic and branches. Assembly 汇编 is that same program written one machine instruction per line.
- Reading the assembly is how you check what the hardware will actually do.

Each line of assembly corresponds to one machine instruction.
רמת קושי 1/5 · 100 מטבעות + בונוס קטן בהשלמה הראשונה היום
That is what makes assembly useful for checking compiler output; one C line often becomes several instructions.
Read-modify-write
- A register is a whole word, so a single bit cannot be written on its own. To change one pin, the CPU loads the word, changes the bit and stores it back.
*GPIO_OUT |= (1u << 5);sets bit 5 and leaves the others unchanged.*GPIO_OUT = 0x20;would clear every other pin.
Which line sets bit 5 of GPIO_OUT without changing the other bits?
רמת קושי 1/5 · 100 מטבעות + בונוס קטן בהשלמה הראשונה היום
OR with a mask sets the chosen bit and keeps the rest. Plain assignment clears the others; AND with the mask clears all but bit 5.
Worked example: masks in hex
- Toggle bits 5 and 6 and clear bit 3 in one step:
(*GPIO_OUT & ~0x08) ^ 0x60. - From
0xCE:0xCE & ~0x08 = 0xC6, then0xC6 ^ 0x60 = 0xA6. Bit 3 went from 1 to 0; bits 6 and 5 went from 1, 0 to 0, 1.
GPIO_OUT holds 0xCE. After (0xCE & ~0x08) ^ 0x60, it holds
רמת קושי 1/5 · 100 מטבעות + בונוס קטן בהשלמה הראשונה היום
0xCE & ~0x08 = 0xC6 clears bit 3; 0xC6 ^ 0x60 = 0xA6 flips bits 6 and 5.
A register holds 0xFF. What is it, in decimal, after reg &= ~(1u << 7)?
רמת קושי 2/5 · 140 מטבעות + בונוס קטן בהשלמה הראשונה היום
Clearing bit 7 of 0xFF leaves 0x7F = 127.
Worked example: when does a counter wrap?
count = count + 1in a loop: a 32-bit counter wraps after $2^{32} = 4\,294\,967\,296$ steps.- At 84 MHz with a 4-instruction loop, that takes $\dfrac{2^{32} \times 4}{84 \times 10^{6}} \approx 204\,\text{s}$. Arithmetic beats waiting with a stopwatch.
A 16-bit counter increments once per microsecond. After how many milliseconds does it wrap? Give 3 decimal places.
רמת קושי 2/5 · 140 מטבעות + בונוס קטן בהשלמה הראשונה היום
$2^{16} = 65\,536$ counts at 1 µs each is 65.536 ms.
Three common slips
- Dropping
volatile. The compiler may keep the value in a CPU register and never read the hardware again. - Plain assignment for one bit.
= 0x20clears every other bit; use|=,&= ~or^=. - Assuming write order. When the hardware needs two writes in sequence, add a barrier or a read-back.
Match each operation to what it does to bit k.
רמת קושי 2/5 · 140 מטבעות + בונוס קטן בהשלמה הראשונה היום
These four idioms cover almost every register operation in a driver.
Recap
- Registers are addresses, reached through
volatilepointers. - Changing a bit is load, mask, store: read-modify-write.
- Check masks in hex on paper before trusting the hardware.