avr-g++ 13.3.0在ATmega4809中传递const char数组参数异常问题
问题结论:这是avr-gcc 13.3.0针对ATmega4809的编译器/链接器问题,而非代码问题
核心原因分析
- ATmega4809属于AVR-DA系列,采用哈佛架构,程序存储器(Flash)与SRAM是独立的地址空间。
const字符串默认被编译器放到Flash的.rodata段,但代码中使用的ld r24, Z是SRAM读取指令,无法正确访问Flash中的数据,导致读到随机垃圾值。 - 而ATmega328p是AVR经典系列,编译器默认会把
.rodata段内容复制到SRAM的.data段,因此ld指令能正常读取字符串,这就是两个平台表现不同的根本原因。
反汇编验证细节
.rodata段的61 62 63 00是"abc\0"的正确ASCII值,但汇编器将其解析为ori等指令,说明该地址属于Flash空间;主函数传递的0x414c是Flash地址,函数中用Z寄存器指向该地址后执行ld指令,实际访问的是SRAM的对应地址,自然读不到正确字符。- 函数
f中对比r24和0x61('a'的ASCII)时,r24的值是SRAM随机内容,因此判断为false,触发PC1引脚LED闪烁。
临时解决方案
- 强制放入.data段:如你已经尝试的,用
__attribute__((section(".data")))将const字符串放到SRAM,让ld指令能正确读取:void f(const char str[]) { // ...原有逻辑 } int main() { PORTC.DIR |= PIN0_bm | PIN1_bm; static const char str[] __attribute__((section(".data"))) = "abc"; while (1) { f(str); } } - 使用PROGMEM手动访问Flash:利用AVR的
PROGMEM属性和pgm_read_byte函数读取Flash中的字符串:#include <avr/io.h> #include <util/delay.h> #include <avr/pgmspace.h> void f(const char* str) { if (pgm_read_byte(str) == 'a') { PORTC.OUT |= PIN0_bm; _delay_ms(500); PORTC.OUT &= ~PIN0_bm; _delay_ms(500); } else { PORTC.OUT |= PIN1_bm; _delay_ms(500); PORTC.OUT &= ~PIN1_bm; _delay_ms(500); } } int main() { PORTC.DIR |= PIN0_bm | PIN1_bm; while (1) { f(PSTR("abc")); } }
编译器问题的佐证
针对AVR-DA系列,avr-gcc应该自动识别.rodata段在Flash中,并生成lpm(Load Program Memory)指令来访问,或者在链接阶段处理地址映射。13.3.0版本显然没有正确处理这一平台特性,导致代码生成错误。
内容的提问来源于stack exchange,提问作者Antonio
相关产品推荐
相关产品推荐

