This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| en:multiasm:piot:chapter_4_8 [2025/05/31 09:51] – marcin | en:multiasm:piot:chapter_4_8 [2026/01/19 12:46] (current) – marcin | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Best Practices on Structural Programming ====== | ||
| + | |||
| + | Modular Programming: | ||
| + | |||
| + | ** Impact of AVR Architecture Variations on Modular Programming ** | ||
| + | |||
| + | Although AVR microcontrollers share a common 8‑bit RISC architecture, | ||
| + | |||
| + | **1. Differences in Register Addresses ** | ||
| + | |||
| + | AVR devices frequently place hardware registers at different memory addresses. | ||
| + | Examples: | ||
| + | * ATmega328P and ATmega32 have similar peripherals but located at different I/O addresses. | ||
| + | * Larger devices such as ATmega128 or ATmega2560 introduce extended I/O space, shifting many registers to higher addresses. | ||
| + | |||
| + | **Programming Implications** | ||
| + | |||
| + | Hard‑coding register addresses or device‑specific constants inside logic modules makes the code non‑portable.To avoid this: | ||
| + | * Always use symbolic register names from `< | ||
| + | * Keep hardware‑dependent definitions in separate configuration files. | ||
| + | * Avoid embedding numeric addresses directly in application logic. This ensures that the same module can be compiled for different AVR models without modification. | ||
| + | |||
| + | ---- | ||
| + | |||
| + | **2. Differences in Peripheral Availability** | ||
| + | |||
| + | Not all AVR microcontrollers include the same set of peripherals: | ||
| + | * Some have one USART, others have four. | ||
| + | * Some include 16‑bit timers, others only 8‑bit. | ||
| + | * Some have ADC, SPI, TWI, or analog comparators, | ||
| + | |||
| + | **Programming Implications** | ||
| + | |||
| + | Modules that depend on specific peripherals must be written with flexibility in mind. Recommended practices include: | ||
| + | * Using conditional compilation (`#ifdef`, `#if defined(...)`). | ||
| + | * Creating abstraction layers that hide hardware differences. | ||
| + | * Designing modules so they can operate even when certain peripherals are unavailable. This approach allows the same codebase to support multiple AVR families. | ||
| + | |||
| + | ---- | ||
| + | |||
| + | **3. Differences in Interrupt Vector Layout** | ||
| + | |||
| + | AVR devices differ in: | ||
| + | * number of interrupt sources, | ||
| + | * order of interrupt vectors, | ||
| + | * naming of interrupt handlers. | ||
| + | |||
| + | **Programming Implications** | ||
| + | |||
| + | Interrupt‑driven modules must rely on symbolic ISR names rather than fixed vector numbers. | ||
| + | Example:Vis mindreKodeblokk er utvidet | ||
| + | ISR(TIMER1_COMPA_vect) | ||
| + | |||
| + | This ensures that the correct interrupt is used regardless of the device’s vector table layout. | ||
| + | |||
| + | ---- | ||
| + | |||
| + | **4. Differences in Memory Size and Addressing** | ||
| + | |||
| + | Larger AVR devices (e.g., ATmega128, ATmega2560) require extended addressing mechanisms: | ||
| + | |||
| + | * RAMPX, RAMPY, RAMPZ, RAMPD for data memory beyond 64 KB | ||
| + | * EIND for program memory beyond 128 KB | ||
| + | * ELPM instead of LPM for reading from extended Flash | ||
| + | |||
| + | **Programming Implications** | ||
| + | |||
| + | Modules accessing program memory or large data structures must: | ||
| + | |||
| + | * use the correct load instructions (*LPM* vs *ELPM*), | ||
| + | * handle extended addressing registers, | ||
| + | * avoid assumptions about pointer size or memory layout. | ||
| + | |||
| + | This highlights the importance of isolating memory‑related operations into dedicated modules. | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==How Modular Programming Helps Manage AVR Differences== | ||
| + | |||
| + | A well‑structured modular design allows hardware‑dependent code to be isolated from application logic. | ||
| + | This is typically achieved through the following layering: | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ** 1. Hardware Abstraction Layer (HAL) *** | ||
| + | |||
| + | HAL provides a unified interface to peripherals, | ||
| + | |||
| + | Example functions: | ||
| + | |||
| + | * `uart_init()` | ||
| + | * `uart_send()` | ||
| + | * `uart_receive()` | ||
| + | |||
| + | Internally, HAL uses different registers depending on the device, but the application code remains unchanged. | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ** 2. Device‑Specific Configuration Modules ** | ||
| + | |||
| + | These modules contain: | ||
| + | |||
| + | * clock settings, | ||
| + | * timer configurations, | ||
| + | * peripheral initialization. | ||
| + | |||
| + | By placing these in separate files, it becomes easy to adapt the project to a new AVR model. | ||
| + | |||
| + | ---- | ||
| + | |||
| + | **3. Reusable High‑Level Modules ** | ||
| + | |||
| + | These modules remain independent of hardware details and include: | ||
| + | |||
| + | * communication protocols, | ||
| + | * algorithms, | ||
| + | * state machines. | ||
| + | |||
| + | Such modules can be reused across many different AVRs. | ||
| + | |||
| + | ---- | ||
| + | |||
| + | **Summary** | ||
| + | |||
| + | Differences between AVR models—register locations, peripheral availability, | ||
| + | Modular programming provides a robust framework for handling these variations by separating hardware‑specific code from application logic. | ||
| + | |||
| + | This ensures: | ||
| + | |||
| + | * portability, | ||
| + | * easier maintenance, | ||
| + | * reusability across different AVR families. | ||