如何在Arduino中获取全局变量的flash地址
How to get flash address of global variable in Arduino
我的 Arduino(例如 ATmega328P)中有一个静态全局变量,它与任何其他静态非 PROGMEM 存储一样,在启动后自动加载到 SRAM。我将其设置为默认值,该值由 setup()
中 EEPROM 中的存储值替换。我想提供将变量重置为其原始默认值的功能,而无需在我的代码中再次定义该值。
例如,是否可以通过 pgm_read_byte()
获取 Arduino 中静态全局变量的闪存地址以将其原始数据从闪存加载到 SRAM?如果可以,怎么做?
P.S。所讨论的静态全局变量是一个相当大的结构。重新定义它是不可能的。
可以通过将常量数据声明为 PROGMEM
来使其可寻址。由于 AVR 程序存储器被组织为单独地址 space 中的 16 位字,因此必须使用 special functions 进行读取。
#include <assert.h>
#include <string.h> // memcpy
#include <avr/pgmspace.h> // AVR PROGMEM, memcpy_P
#define SIZE 1000
struct large { // arbitrary large data structure
unsigned char data[SIZE];
};
struct large l; // global variable (in SRAM)
const struct large l_default PROGMEM = { // default value (in PROGMEM)
{ 0xaa, 0xab, 0x0ac, 0xad, 0xae, 0xaf }
};
void setup(void) // load values from EEPROM
{
memset(&l, 1, SIZE); // simulate reading from real EEPROM
}
int main(void)
{
setup(); // initialize from EEPROM
assert(l.data[0] == 1);
memcpy_P(l.data, &l_default, SIZE); // reset to defaults (from PROGMEM)
assert(l.data[0] == 0xaa);
return 0;
}
确认上述示例的大小符合预期:Program
中的默认数据有 1000 个额外字节,全局变量 Data
中总共有 1000 个字节。
$ avr-size -C -x main.bin
AVR Memory Usage
----------------
Device: Unknown
Program: 1252 bytes
(.text + .data + .bootloader)
Data: 1000 bytes
(.data + .bss + .noinit)
默认数据(从 aaabacadaeaf
开始到 994 个零继续)已被放置在中断向量之后的程序存储器中。它可以在运行时通过 pgm_read_
函数族访问。
$ avr-objdump -s main.bin
main.bin: file format elf32-avr
Contents of section .text:
0000 0c942802 0c943a02 0c943a02 0c943a02 ..(...:...:...:.
0010 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0020 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0030 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0040 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0050 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0060 0c943a02 0c943a02 aaabacad aeaf0000 ..:...:.........
0070 00000000 00000000 00000000 00000000 ................
0080 00000000 00000000 00000000 00000000 ................
0090 00000000 00000000 00000000 00000000 ................
[...]
我的 Arduino(例如 ATmega328P)中有一个静态全局变量,它与任何其他静态非 PROGMEM 存储一样,在启动后自动加载到 SRAM。我将其设置为默认值,该值由 setup()
中 EEPROM 中的存储值替换。我想提供将变量重置为其原始默认值的功能,而无需在我的代码中再次定义该值。
例如,是否可以通过 pgm_read_byte()
获取 Arduino 中静态全局变量的闪存地址以将其原始数据从闪存加载到 SRAM?如果可以,怎么做?
P.S。所讨论的静态全局变量是一个相当大的结构。重新定义它是不可能的。
可以通过将常量数据声明为 PROGMEM
来使其可寻址。由于 AVR 程序存储器被组织为单独地址 space 中的 16 位字,因此必须使用 special functions 进行读取。
#include <assert.h>
#include <string.h> // memcpy
#include <avr/pgmspace.h> // AVR PROGMEM, memcpy_P
#define SIZE 1000
struct large { // arbitrary large data structure
unsigned char data[SIZE];
};
struct large l; // global variable (in SRAM)
const struct large l_default PROGMEM = { // default value (in PROGMEM)
{ 0xaa, 0xab, 0x0ac, 0xad, 0xae, 0xaf }
};
void setup(void) // load values from EEPROM
{
memset(&l, 1, SIZE); // simulate reading from real EEPROM
}
int main(void)
{
setup(); // initialize from EEPROM
assert(l.data[0] == 1);
memcpy_P(l.data, &l_default, SIZE); // reset to defaults (from PROGMEM)
assert(l.data[0] == 0xaa);
return 0;
}
确认上述示例的大小符合预期:Program
中的默认数据有 1000 个额外字节,全局变量 Data
中总共有 1000 个字节。
$ avr-size -C -x main.bin
AVR Memory Usage
----------------
Device: Unknown
Program: 1252 bytes
(.text + .data + .bootloader)
Data: 1000 bytes
(.data + .bss + .noinit)
默认数据(从 aaabacadaeaf
开始到 994 个零继续)已被放置在中断向量之后的程序存储器中。它可以在运行时通过 pgm_read_
函数族访问。
$ avr-objdump -s main.bin
main.bin: file format elf32-avr
Contents of section .text:
0000 0c942802 0c943a02 0c943a02 0c943a02 ..(...:...:...:.
0010 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0020 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0030 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0040 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0050 0c943a02 0c943a02 0c943a02 0c943a02 ..:...:...:...:.
0060 0c943a02 0c943a02 aaabacad aeaf0000 ..:...:.........
0070 00000000 00000000 00000000 00000000 ................
0080 00000000 00000000 00000000 00000000 ................
0090 00000000 00000000 00000000 00000000 ................
[...]