【问题标题】:How to get flash address of global variable in Arduino如何在Arduino中获取全局变量的闪存地址
【发布时间】:2018-12-09 10:17:11
【问题描述】:

我的 Arduino(例如 ATmega328P)中有一个静态全局变量,它与任何其他静态非 PROGMEM 存储一样,在启动后自动加载到 SRAM。我将其设置为默认值,该默认值替换为setup() 中 EEPROM 中的存储值。我想提供将变量重置为其原始默认值的功能,而无需在我的代码中再次定义该值。
例如,是否可以通过pgm_read_byte() 获取 Arduino 中静态全局变量的闪存地址以将其原始数据从闪存加载到 SRAM?如果有,怎么做?

附:所讨论的静态全局变量是一个相当大的结构。重新定义它是不可能的。

【问题讨论】:

    标签: c arduino avr atmega


    【解决方案1】:

    可以通过将常量数据声明为PROGMEM 来使其可寻址。由于 AVR 程序存储器在单独的地址空间中组织为 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  ................
    [...]
    

    【讨论】:

    • 好主意。我没有想到对 SRAM 部分使用未初始化的全局变量。没错,这样你只有一次在闪存中和一次在 SRAM 中的 1000 字节,而不是两次在闪存中。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-28
    • 2010-10-12
    相关资源
    最近更新 更多