Можно ли во время выполнения определить, объявлен ли указатель PROGMEM?
Можно ли во время выполнения определить, указывает ли указатель на значения, введенные в PROGMEM
, или на обычные значения? Это дало бы некоторую гибкость при написании кода, который обрабатывает и то, и другое.
@Ana, 👍1
2 ответа
Лучший ответ:
Не совсем, если вы спрашиваете, можете ли вы определить (просто по его значению), находится ли 0x100 в RAM или PROGMEM. Оба являются возможными кандидатами на место в памяти.
Макрос F()
решает эту проблему, изменяя тип переменной во время компиляции, чтобы компилятор мог выбрать подходящий метод печати. Например:
Serial.println ("Hello, world");
Serial.println (F("Hello, world"));
В этом случае соответствующая функция println
выбирается компилятором во время компиляции на основе типа (одна будет const char *
, другая — __FlashStringHelper
тип).
Лучше всего придумать способ (аналогичный макросу F()
), с помощью которого можно будет принимать решение во время компиляции.
Можно ли во время выполнения определить, указывает ли указатель на значения PROGMEM или на обычные значения? Это дало бы некоторую гибкость при написании кода, который обрабатывает и то, и другое.
Микроконтроллеры AVR принадлежат Harvard Architecture. Пространства памяти данных и программ разделены. Есть также несколько областей памяти данных, например, SRAM, EEPROM, PROGMEM. Каждый из них имеет собственное адресное пространство, и для доступа к ним используются специальные инструкции.
В программном обеспечении все возможно :), поэтому можно унифицировать адресные пространства и использовать механизм времени выполнения для выполнения соответствующих операций чтения и записи. Простой метод заключается в использовании старших битов для определения адресного пространства. Например,
SRAM 0x0000..0x7fff
EEPROM 0x8000..0x8fff
PROGMEM 0x9000..0xffff
У указателей SRAM все как обычно, у указателей EEPROM есть дополнительный 0x8000, а у указателей PROGMEM дополнительный 0x9000.
Следующим шагом является написание простой функции отображения из единого адресного пространства в отдельные адресные пространства памяти. Это можно обернуть в интеллектуальный указатель C++ и/или простую иерархию классов C++.
Пример этого метода можно найти в 1) Виртуальная машина Forth для Arduino, https://github.com/mikaelpatel/ Arduino-FVM (см. https://github.com/mikaelpatel /Arduino-FVM/blob/master/src/FVM.cpp#L85), 2) командная оболочка RPN Postscript/Forth для Arduino, https://github.com/mikaelpatel/Arduino-Shell (см. https://github.com/mikaelpatel/Arduino-Shell/blob/master/Shell.h#L1059).
Ура!
PS: Интересная деталь архитектуры AVR заключается в том, что регистры 0..31 и регистры io сопоставляются с адресным пространством SRAM.
- Считывание байтов из массива PROGMEM
- Есть ли способ подключить оперативную память компьютера к Arduino?
- Последовательная печать из флэш-памяти (F() macro, PROGMEM, sprintf_P, SPTR)
- Преимущества глобальных переменных перед статическими членами класса?
- Проблема с массивом + последовательным монитором
- Локально объявленная переменная занимает глобальное переменное пространство в динамической памяти/SRAM
- Как функция/метод может определить, является ли передаваемый массив const PROGMEM (flash) или нет (RAM)?
- Очищается ли SRAM при переводе Arduino в режим sleep_mode_pwr_down?