Skip to content

Commit d3a3ab7

Browse files
Fine tune phase 1 topics contents
1 parent cd6cf15 commit d3a3ab7

File tree

10 files changed

+2032
-194
lines changed

10 files changed

+2032
-194
lines changed

Embedded_C/Assembly_Integration.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,32 @@
2222

2323
## 🎯 **Overview**
2424

25+
### Concept: Use assembly only where C cannot clearly express intent
26+
27+
Reach for inline/standalone assembly when you need exact instructions, special registers, or calling conventions C cannot provide. Keep interfaces small, stable, and documented.
28+
29+
### Why it matters in embedded
30+
- Overuse harms portability and can pessimize the optimizer.
31+
- Clear boundaries simplify review and maintenance.
32+
- Correct clobbers/constraints prevent subtle bugs.
33+
34+
### Minimal example: small leaf routine
35+
```c
36+
// C wrapper with tiny asm core (example, ARM)
37+
static inline uint32_t rbit32(uint32_t v){
38+
uint32_t out; __asm volatile ("rbit %0, %1" : "=r"(out) : "r"(v)); return out;
39+
}
40+
```
41+
42+
### Try it
43+
1. Compare compiler output for a C bit-reverse vs `rbit` intrinsic/asm.
44+
2. Validate clobber lists by enabling warnings and inspecting disassembly.
45+
46+
### Takeaways
47+
- Write assembly last, measure first.
48+
- Keep ABI boundaries clear; document register usage and side effects.
49+
- Prefer intrinsics when available—they’re easier to port and read.
50+
2551
Assembly integration is essential in embedded systems for:
2652
- **Direct hardware control** - Access to specific CPU instructions
2753
- **Performance optimization** - Hand-tuned critical code sections

Embedded_C/Bit_Manipulation.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,38 @@
2323

2424
## 🎯 **Overview**
2525

26+
### Concept: Bits are a contract with hardware and protocols
27+
28+
Bit operations must match datasheet-defined fields exactly; correctness and portability depend on using widths, masks, and shifts that are well-defined in C.
29+
30+
### Why it matters in embedded
31+
- Register fields require precise masking/shifting without UB.
32+
- Protocol packing/unpacking must respect endianness and widths.
33+
- Shifting negative or too far is undefined; rely on fixed-width types.
34+
35+
### Minimal example: safe field update
36+
```c
37+
#define REG (*(volatile uint32_t*)0x40000000u)
38+
#define MODE_Pos 4u
39+
#define MODE_Msk (0x7u << MODE_Pos) // 3-bit field
40+
41+
static inline void reg_set_mode(uint32_t mode) {
42+
mode &= 0x7u; // clamp
43+
uint32_t v = REG;
44+
v = (v & ~MODE_Msk) | (mode << MODE_Pos);
45+
REG = v;
46+
}
47+
```
48+
49+
### Try it
50+
1. Implement `get_mode()` and verify round-trip for all values 0..7.
51+
2. Pack a struct into a `uint32_t` payload; send over UART; unpack and verify.
52+
53+
### Takeaways
54+
- Use `uint*_t`, never shift signed values.
55+
- Define `*_Pos` and `*_Msk` macros or enums; avoid magic numbers.
56+
- Document endianness where on-wire vs in-memory order differs.
57+
2658
Bit manipulation is crucial in embedded systems for:
2759
- **Hardware register access** - Setting/clearing individual bits
2860
- **Memory efficiency** - Packing multiple values into single variables

Embedded_C/Compiler_Intrinsics.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@
2323

2424
## 🎯 **Overview**
2525

26+
### Concept: Intrinsics are contracts to the backend, not magic
27+
28+
They promise the compiler a specific operation; when supported, you get a single instruction, otherwise a correct fallback. Guard for architecture, and always keep a portable path.
29+
30+
### Minimal example & Try it
31+
```c
32+
// Measure vs loop implementation
33+
static inline uint32_t popcnt_loop(uint32_t v){ uint32_t c=0; while(v){c+=v&1u; v>>=1;} return c; }
34+
static inline uint32_t popcnt_intrin(uint32_t v){ return __builtin_popcount(v); }
35+
```
36+
1. Benchmark both at `-O0` and `-O2` on your target.
37+
2. Guard with `#ifdef` and provide a loop fallback to keep portability.
38+
39+
### Takeaways
40+
- Guard arch-specific intrinsics; keep fallbacks for other compilers/targets.
41+
- Intrinsics can be faster or smaller, but measure on your hardware.
42+
- Don’t conflate intrinsics with undefined behavior fixes; they don’t change language rules.
43+
2644
Compiler intrinsics are built-in functions that provide:
2745
- **Hardware-specific operations** - Direct access to CPU instructions
2846
- **Performance optimization** - Optimized implementations

Embedded_C/Memory_Mapped_IO.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,38 @@
1717

1818
## 🎯 Overview
1919

20+
### Concept: Typed volatile views over fixed addresses
21+
22+
Treat peripheral registers as `volatile` objects at known addresses with precise widths. Use minimal, typed accessors and avoid accidental non-volatile aliases.
23+
24+
### Why it matters in embedded
25+
- Prevents the compiler from eliding or reordering critical I/O operations.
26+
- Clarifies intent (read-only status vs write-only command registers).
27+
- Eases review and static analysis.
28+
29+
### Minimal example
30+
```c
31+
typedef struct {
32+
volatile uint32_t CTRL;
33+
volatile const uint32_t STAT; // read-only
34+
volatile uint32_t DATA;
35+
} periph_t;
36+
37+
#define PERIPH ((periph_t*)0x40010000u)
38+
39+
static inline void periph_enable(void) { PERIPH->CTRL |= 1u; }
40+
static inline uint32_t periph_ready(void) { return (PERIPH->STAT & 1u) != 0u; }
41+
```
42+
43+
### Try it
44+
1. Intentionally drop `volatile` and compile with `-O2`; show hoisted loads or removed writes.
45+
2. Add a memory barrier where required by the architecture (e.g., after enabling clocks) and measure behavior.
46+
47+
### Takeaways
48+
- Always access registers through `volatile`-qualified types/pointers.
49+
- Be explicit about read-only/write-only semantics via `const` on `volatile` fields.
50+
- Consider memory barriers for ordering on platforms that require them.
51+
2052
Memory-mapped I/O allows direct access to hardware registers through memory addresses, enabling efficient communication with peripherals. This technique is fundamental in embedded systems for controlling hardware without dedicated I/O instructions.
2153
2254
## 🔧 Memory-Mapped I/O Basics

Embedded_C/Memory_Models.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@
2222

2323
## 🎯 **Overview**
2424

25+
### Concept: Sections map to cost at startup and at runtime
26+
27+
Know which data ends up in Flash vs RAM and what the startup code must zero or copy. Use the map file to make footprint visible and deliberate.
28+
29+
### Why it matters in embedded
30+
- `.data` increases Flash (init image) and RAM (runtime) and costs boot copy time.
31+
- `.bss` increases RAM and costs boot zeroing time.
32+
- `const` moves to ROM (`.rodata`), reducing RAM.
33+
34+
### Try it
35+
1. Build with a map file; identify largest contributors to `.data` and `.bss`.
36+
2. Move large tables to `static const` and observe `.rodata` vs `.data` changes.
37+
38+
### Takeaways
39+
- Prefer `static const` for lookup tables.
40+
- Avoid large automatic arrays on the stack; use static storage or pools.
41+
- For freestanding targets, keep startup work small to reduce boot latency.
42+
2543
Understanding memory models is crucial for embedded systems programming. Memory layout, segmentation, and access patterns directly impact performance, reliability, and security of embedded applications.
2644

2745
### **Key Concepts for Embedded Development**

Embedded_C/Pointers_Memory_Addresses.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020

2121
## 🎯 Overview
2222

23+
### Concept: Addresses, objects, and aliasing
24+
25+
A pointer is just an address; correctness depends on the lifetime and effective type of the object it points to. Hardware access requires `volatile`; high-performance memory access benefits from no-aliasing assumptions.
26+
27+
### Minimal example
28+
```c
29+
extern uint32_t sensor_value;
30+
void update(volatile uint32_t* reg, uint32_t v){ *reg = v; }
31+
32+
// Aliasing pitfall: compiler may assume *a and *b don't alias unless told
33+
void add_buffers(uint16_t* restrict a, const uint16_t* restrict b, size_t n){
34+
for(size_t i=0;i<n;i++) a[i]+=b[i];
35+
}
36+
```
37+
38+
### Takeaways
39+
- Use `volatile` for memory-mapped registers and ISR-shared flags.
40+
- Be mindful of strict aliasing; stick to the same effective type or `memcpy`.
41+
- Prefer `restrict` only when you can prove non-aliasing.
42+
2343
Pointers are fundamental to embedded programming, enabling direct memory access, hardware register manipulation, and efficient data structures. Understanding pointers is crucial for low-level programming and hardware interaction.
2444
2545
### Key Concepts for Embedded Development

Embedded_C/Structure_Alignment.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,30 @@
2222

2323
## 🎯 **Overview**
2424

25+
### Concept: Layout trades size for speed and safety
26+
27+
Field order and alignment determine padding, access efficiency, and sometimes correctness for hardware overlays. Optimize for fewer accesses and aligned loads/stores; avoid `packed` unless absolutely necessary.
28+
29+
### Why it matters in embedded
30+
- Misaligned access can fault or incur penalties on some MCUs.
31+
- Register overlays require exact widths and `volatile` access.
32+
- Packing to save bytes can increase access cycles or break HW requirements.
33+
34+
### Minimal example
35+
```c
36+
typedef struct { uint8_t a; uint32_t b; uint8_t c; } poor_t; // likely 12B
37+
typedef struct { uint32_t b; uint8_t a, c; } better_t; // likely 8B
38+
```
39+
40+
### Try it
41+
1. Compare `sizeof(poor_t)` vs `better_t`; inspect the map to see cumulative RAM impact.
42+
2. Benchmark a tight loop that reads/writes these structures to see aligned vs misaligned effects.
43+
44+
### Takeaways
45+
- Reorder fields to minimize padding and align to natural sizes.
46+
- Avoid `__attribute__((packed))` for HW registers; use explicit `uint*_t` fields and document reserved bits.
47+
- For on-wire protocol structs, serialize/deserialize explicitly to avoid ABI/layout surprises.
48+
2549
Structure alignment is critical in embedded systems for:
2650
- **Memory efficiency** - Minimizing wasted memory space
2751
- **Performance optimization** - Aligned access is faster

Embedded_C/Type_Qualifiers.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,41 @@
2020

2121
## 🎯 **Overview**
2222

23+
### Concept: Tell the compiler the truth about how data changes
24+
25+
Think of qualifiers as contracts:
26+
- `const`: intent is read-only at this access point
27+
- `volatile`: value may change outside the compiler’s view (hardware/ISR)
28+
- `restrict`: this pointer is the only way to access the referenced object
29+
30+
### Why it matters in embedded
31+
- Correct `volatile` prevents the compiler from caching HW register values.
32+
- `const` enables placement in ROM and better optimization.
33+
- `restrict` allows the compiler to vectorize/memcpy efficiently in hot paths.
34+
35+
### Minimal examples
36+
```c
37+
// Read-only lookup table likely in Flash
38+
static const uint16_t lut[] = {1,2,3,4};
39+
40+
// Memory-mapped I/O register
41+
#define GPIOA_ODR (*(volatile uint32_t*)0x40020014u)
42+
43+
// Non-aliasing buffers (improves copy performance)
44+
void copy_fast(uint8_t * restrict dst, const uint8_t * restrict src, size_t n);
45+
```
46+
47+
### Try it
48+
1. Remove `volatile` from a polled status register read and compile with `-O2`; inspect assembly to see hoisted loads.
49+
2. Add/Remove `restrict` on a memset/memcpy-like loop and measure on target.
50+
51+
### Takeaways
52+
- `volatile` is about visibility, not atomicity or ordering.
53+
- `const` expresses intent and may change placement; don’t cast it away to write.
54+
- Use `restrict` only when you can prove no aliasing.
55+
56+
> Platform note: For I/O ordering on some MCUs/SoCs, pair volatile accesses with memory barriers when required by the architecture.
57+
2358
Type qualifiers in C provide important hints to the compiler about how variables should be treated:
2459
- **const** - Indicates read-only data
2560
- **volatile** - Indicates data that can change unexpectedly

0 commit comments

Comments
 (0)