Reputation: 651
The following code doesn't work in ATmega4809
:
#include <avr/io.h>
#include <util/delay.h>
void f(const char str[])
{
if (str[0] == 'a'){ // <-- here is the problem!!! The program thinks str[0] != 'a'
PORTC.OUT |= PIN0_bm;
_delay_ms(500);
PORTC.OUT &= ~PIN0_bm;
_delay_ms(500);
} else { // blink a led in pin PC1
PORTC.OUT |= PIN1_bm;
_delay_ms(500);
PORTC.OUT &= ~PIN1_bm;
_delay_ms(500);
}
}
int main()
{
PORTC.DIR |= PIN0_bm; // init pin PC0
PORTC.DIR |= PIN1_bm; // init pin PC1
while (1) { f("abc"); }
}
When I pass a const char array
to a function (in the code when I pass str
to function f
) the value of the string is wrong (in this case, the value of str[0]
it's not 'a' but a different char). To implement a minimal program to show the problem I'm using 2 leds: if str[0]
is 'a' (the right value) one led blinks; if it is not, other led blinks. The problem is that the wrong led blinks.
I detect this problem in a different program that compile and work fine with atmega328p
but has this weird behavior with atmega4809
(of 40 pins).
What am I doing wrong? It is a compiler problem?
================
I am compiling it with avr-g++ 13.3.0:
avr-g++ -Os -std=c++23 -Wall -pedantic -funsigned-char -funsigned-bitfields -fshort-enums -ffunction-sections -fdata-sections -save-temps -fverbose-asm -DMCU=atmega4809 -DF_CPU=2666667UL -mmcu=atmega4809 -c -o test.o test.cpp
I'm using the atmega4809
of 40 pins. I know that I have to initialize pins PB[5:0]
and PC[7:6]
and I do it in my program. I don't show the init
function in the previous code because the program behaves the same calling that init
function or not.
============
I'm not used to read assembler, but here (I think) is the relevant asm code:
The string "abc"
:
.LC0:
.string "abc"
.section .text.startup.main,"ax",@progbits
The call of f("abc")
:
ldi r24,lo8(.LC0) ; ,
ldi r25,hi8(.LC0) ; ,
call _Z1fPKc ;
and the if
of f
function:
.section .text._Z1fPKc,"ax",@progbits
.global _Z1fPKc
.type _Z1fPKc, @function
_Z1fPKc:
.L__stack_usage = 0
; main.cpp:43: if (str[0] == 'a'){
movw r30,r24 ; , tmp62
ld r24,Z ; *str_9(D), *str_9(D)
cpi r24,lo8(97) ; *str_9(D),
brne .L3 ; ,
// blink PC0
// ...
==========
EDIT: Adding the result of avr-objdump -D test.elf
(relevant parts, only):
Disassembly of section .rodata:
0000414c <_end-0x7fe6b4>:
414c: 61 62 ori r22, 0x21 ; 33
414e: 63 00 .word 0x0063 ; ????
Why avr-objdump
writes those signs: ????
<-- is this the problem?
Call of f
in main
:
13e: 8c e4 ldi r24, 0x4C ; 76
140: 91 e4 ldi r25, 0x41 ; 65
142: 0e 94 5c 00 call 0xb8 ; 0xb8 <_Z1fPKc>
Function f
(till if
...):
000000b8 <_Z1fPKc>:
b8: fc 01 movw r30, r24
ba: 80 81 ld r24, Z
bc: 81 36 cpi r24, 0x61 ; 97
=========
EDIT2: I've written the same program in atmega328p
and it works fine. The difference in the result of avr-objdump -D
between atmega328p
and atmega4809
is that in the case of atmega328p
the "abc" string is store in the .data
section, while in the case of atmega4809
it stores it in the .rodata
section.
==========
EDIT3: The problem is with the .rodata
section.
If I change the code using a variable str
:
const char str[] = "abc";
and then call f(str)
the program doesn't work, but if I force to write str
into the .data
section:
const char str[] __attribute__((section(".data"))) = "abc";
the progam works.
Is this a problem with avr-gcc 13.3.0?
Upvotes: 3
Views: 79
Reputation: 3983
The problem is with the
.rodata
section. [...] but if I force to write str into the.data
section [...] the progam works. Is this a problem with avr-gcc 13.3.0?
No. With almost certainty, you forgot to upload the .rodata
section to the ATmega4809. Notice that avrxmega3 devices see program memory in the RAM address space, and hence .rodata
is not a part of .data
.
Guessing further, you are brewing an Intel Hex file to flash with avrdude
or similar. Just flash the ELF file will prevent such headaches, since ELF knows what's part of flash memory.
To see what I mean, you can disassemble the ATmega4809 ELF file like:
$ avr-objdump -h -d -S -r -j .text -j .data -j .rodata -j .eeprom <file>.elf
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 0000001c 00802800 00000176 0000022a 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .text 00000172 00000000 00000000 000000b4 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rodata 00000004 00004172 00000172 00000226 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
...
Notice there is a dedicated .rodata
output section. It is required since VMAs must be at an offset of 0x4000 after the LMAs, which would not be the case if .rodata
input sections were allocated to the .text
output section
Upvotes: 1