This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| en:multiasm:exercisesbook:arduinouno [2026/05/03 19:37] – [Use Serial Port for Tracing] ktokarz | en:multiasm:exercisesbook:arduinouno [2026/05/04 14:55] (current) – [Function Call Standards] ktokarz | ||
|---|---|---|---|
| Line 24: | Line 24: | ||
| ===== Memory Map ===== | ===== Memory Map ===== | ||
| - | Location of the code (Flash) and data (SRAM) is assigned to the addressing space. It also impacts source code construction in assembler. The following image presents the ATMega328P memory map. When using fully manual memory control, e.g., when the source code does not use '' | + | Location of the code (Flash) and data (SRAM) is assigned to the addressing space. It also impacts source code construction in assembler. The following image presents the ATMega328P memory map. When using fully manual memory control, e.g., when the source code does not use '' |
| <figure arduinomemorymap> | <figure arduinomemorymap> | ||
| - | {{: | + | {{: |
| < | < | ||
| </ | </ | ||
| Line 33: | Line 33: | ||
| Source code needs to use explicit declarations to tell the GCC-AVR toolkit how to handle the contents: whether it is code or data, whether the variable is read-only, whether it should be stored across updates, and so on. There are two possible approaches to is: one is to use declarations (' | Source code needs to use explicit declarations to tell the GCC-AVR toolkit how to handle the contents: whether it is code or data, whether the variable is read-only, whether it should be stored across updates, and so on. There are two possible approaches to is: one is to use declarations (' | ||
| There are five '' | There are five '' | ||
| - | Each of them does the job of '' | ||
| <table arduinomemorysections> | <table arduinomemorysections> | ||
| Line 44: | Line 43: | ||
| | **.eeprom** | Long-term storage | EEPROM | No | | | **.eeprom** | Long-term storage | EEPROM | No | | ||
| </ | </ | ||
| - | + | The AVR GCC compiler uses virtual addresses to distinguish the nature of objects; thus, each section (corresponding to a kind of memory) has a separate virtual address | |
| - | We mentioned before | + | |
| - | It is, because Flash, EEPROM, and SRAM all start at 0x0000 (see figure {{ref> | + | |
| For this reason, the way the AVR-GCC toolchain (assembler and linker) handles Harvard Architecture in Arduino Uno (ATMega328P) is the use of virtual memory offsets: '' | For this reason, the way the AVR-GCC toolchain (assembler and linker) handles Harvard Architecture in Arduino Uno (ATMega328P) is the use of virtual memory offsets: '' | ||
| <table arduinomemoryblocks> | <table arduinomemoryblocks> | ||
| < | < | ||
| - | ^ Memory Type ^ GCC Internal Offset ^ Hardware Address ^ | + | ^ Memory Type |
| - | | Flash | %%0x000000%% | %%0x0000%% | | + | | Flash |
| - | | SRAM | %%0x800000%% | %%0x0000%% | | + | | SRAM (Registers and I/ |
| - | | SRAM (Internal) | %%0x800100%% | %%0x0100%% | | + | | SRAM (Internal) |
| - | | EEPROM | %%0x810000%% | %%0x0000%% | | + | | EEPROM |
| </ | </ | ||
| - | <note tip>In some of the following chapters, we sometimes present a " | + | <note tip>In some of the following chapters, we sometimes present a " |
| - | To summarise briefly, the most common scenario is that the code is intended to land in Flash memory, while variables are in SRAM. Appropriate '.org' | + | To summarise briefly, the most common scenario is that the code is intended to land in Flash memory, while variables are in SRAM. Appropriate |
| - | It is possible to write code without using sections, but that makes the code unnecessarily complicated. Whenever you use variable declarations, | + | It is possible to write code without using sections, but that makes the code unnecessarily complicated. Whenever you use variable declarations, |
| The sample code below declares a 16-bit value named ' | The sample code below declares a 16-bit value named ' | ||
| Line 71: | Line 68: | ||
| .org 0x100 ; Set SRAM start address manually | .org 0x100 ; Set SRAM start address manually | ||
| analogue_value: | analogue_value: | ||
| - | .skip 2 ; 16-bit variable | + | .skip 2 ; 16-bit variable |
| .section .text | .section .text | ||
| Line 90: | Line 87: | ||
| </ | </ | ||
| - | <note warning> | + | <note warning> |
| ===== GPIO and Ports ===== | ===== GPIO and Ports ===== | ||
| Line 107: | Line 104: | ||
| </ | </ | ||
| - | <note tip>Some GPIOs have extra features (as presented | + | <note tip>Some GPIOs have extra features (as presented |
| - | **IO Registers **\\ | + | **I/O Registers **\\ |
| Each Port has assigned three 8-bit registers (there are 9 in total then): | Each Port has assigned three 8-bit registers (there are 9 in total then): | ||
| * DDRx (Data Direction Register): there are 3 of those registers, one per Port (B, C, D): DDRB, DDRC and DDRD. This registers configures GPIO as Input (0) or Output (1). Configuration is done "per bit", so it is equivalent to controlling each GPIO individually. | * DDRx (Data Direction Register): there are 3 of those registers, one per Port (B, C, D): DDRB, DDRC and DDRD. This registers configures GPIO as Input (0) or Output (1). Configuration is done "per bit", so it is equivalent to controlling each GPIO individually. | ||
| Line 178: | Line 175: | ||
| A common scenario for manual control of the GPIO pin is to first set either the GPIO is input or output (using the correct DDRx register), then either set ('' | A common scenario for manual control of the GPIO pin is to first set either the GPIO is input or output (using the correct DDRx register), then either set ('' | ||
| - | <note tip>'' | + | <note tip>'' |
| Line 412: | Line 409: | ||
| </ | </ | ||
| - | The function is called when interrupt INT0 (on the falling edge of GPIO 2) occurs, and it simply toggles PB5 (GPIO 13, built-in LED). This is a trick in AVR that simplifies code: the classical read-> | + | The function is called when interrupt INT0 (on the falling edge of GPIO 2) occurs, and it simply toggles PB5 (GPIO 13, built-in LED). This is a trick in AVR that simplifies code: the classical read-> |
| <code asm> | <code asm> | ||
| ; --- Interrupt Service Routine --- | ; --- Interrupt Service Routine --- | ||
| Line 467: | Line 464: | ||
| sts UBRR0L, r16 | sts UBRR0L, r16 | ||
| </ | </ | ||
| - | The 103 value is loaded into the '' | + | The 103 value is loaded into the '' |
| <figure usartprescaller> | <figure usartprescaller> | ||
| {{: | {{: | ||
| - | < | + | < |
| </ | </ | ||
| Where **Fcpu** is 16MHz for regular Arduino Uno (AtMega 328P). Note that this calculation yields ~9615 bps, not exactly 9600 bps. A tolerance of up to 2% is acceptable (here, it is 0.16%). | Where **Fcpu** is 16MHz for regular Arduino Uno (AtMega 328P). Note that this calculation yields ~9615 bps, not exactly 9600 bps. A tolerance of up to 2% is acceptable (here, it is 0.16%). | ||
| - | Next step is to enable UART: | + | Next step is to configure frame format (8 bits, no parity, 1 stop bit, shortly 8N1 - the most common case): |
| <code asm> | <code asm> | ||
| - | ldi r16, (1 << | + | ldi r18, (1<<UCSZ01) | (1<< |
| - | sts UCSR0B, r16 | + | sts UCSR0C, r18 |
| </ | </ | ||
| - | and configure frame format (8 bits, no parity, 1 stop bit, shortly 8N1 - the most common case): | + | |
| + | and enable | ||
| <code asm> | <code asm> | ||
| ldi r16, (1 << TXEN0) | ldi r16, (1 << TXEN0) | ||
| sts UCSR0B, r16 | sts UCSR0B, r16 | ||
| </ | </ | ||
| - | Now it is time to send the string to the transmitter, | + | |
| + | Now it is time to send the string to the transmitter, | ||
| <code asm> | <code asm> | ||
| main: | main: | ||
| Line 531: | Line 530: | ||
| <table arduinotimerprescalers> | <table arduinotimerprescalers> | ||
| - | < | + | < |
| ^ Prescaler ^ Frequency ^ Period (Tick Speed) ^ | ^ Prescaler ^ Frequency ^ Period (Tick Speed) ^ | ||
| | 1 | 16 MHz | 0.0625 µs | | | 1 | 16 MHz | 0.0625 µs | | ||
| Line 579: | Line 578: | ||
| ** The Notification **\\ | ** The Notification **\\ | ||
| - | These registers are to control the timer-based interrupt notification system. We do not use interrupts for PWM; therefore, this description is omitted. | + | These registers are to control the timer-based interrupt notification system. We do not use interrupts for PWM, but they are necessary for handling timer-based tasks. |
| <table arduinothemanagertimer> | <table arduinothemanagertimer> | ||
| Line 937: | Line 936: | ||
| .section .data | .section .data | ||
| .org 0x0100 | .org 0x0100 | ||
| - | adc_storage: | + | adc_storage: |
| </ | </ | ||
| Line 965: | Line 964: | ||
| Start conversion by setting the ADSC bit (6) of ADSCRA to 1. | Start conversion by setting the ADSC bit (6) of ADSCRA to 1. | ||
| - | ADC requires some time to read the value and complete the conversion | + | ADC requires some time to complete the conversion; thus, when the result |
| Here, we do not use any interrupts, just dummy pulling. | Here, we do not use any interrupts, just dummy pulling. | ||
| <code asm> | <code asm> | ||
| Line 1001: | Line 1000: | ||
| ** Speed vs Quality ** | ** Speed vs Quality ** | ||
| - | ADC converts an analogue value to its digital representation using a capacitor. Charging and discharging of the capacitor require time and depend on the impedance of the analogue signal' | + | ADC converts an analogue value to its digital representation using a method called successive approximation, |
| <table arduinoadcprescaler> | <table arduinoadcprescaler> | ||
| Line 1044: | Line 1043: | ||
| <figure avrarduinocallingconventions> | <figure avrarduinocallingconventions> | ||
| - | {{: | + | {{: |
| < | < | ||
| </ | </ | ||
| Line 1111: | Line 1110: | ||
| .section .data | .section .data | ||
| ; 1. Declaration of a buffer for a string in RAM | ; 1. Declaration of a buffer for a string in RAM | ||
| - | my_string_buffer: | + | my_string_buffer: |
| .section .text | .section .text | ||
| Line 1198: | Line 1197: | ||
| To use a string (e.g. constant) that is stored in Flash, convert this line: | To use a string (e.g. constant) that is stored in Flash, convert this line: | ||
| '' | '' | ||
| - | <note important> | + | <note important> |
| ** Delay (in ms) **\\ | ** Delay (in ms) **\\ | ||