Имеется функция, которой передается некий указатель.
Можно ли узнать где находятся данные по этому указателю: в ОЗУ или в PROGMEM, чтобы соответствующим образом их обработать?
Или нужно писать отдельные функции для каждого из случаев?
В общем случае можно.
Указатель - это адрес. Диапазоны адресов для памяти и для прогмем разные.
Ты что-то сильно неправильно делаешь, если тебе вообще такое понадобилось.
нет, они пересекаются
как это?
Адресное пространство одно. Никогда нельзя сказать точно лежит ли переменная с адресом 0x100 в RAM или во FLASH. Даже компилятор не знает, считая все обращения к переменным, как обращение к ОЗУ. Иначе библиотека progmem.h была бы не нужна
Для AVR это не всегда верно !
uint8_t ram[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
const uint8_t PROGMEM flash[] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
};
void setup () {
Serial.begin(9600);
Serial.println("Start");
Serial.print(ram[0]);
Serial.print(' ');
Serial.println((uint16_t)&ram[0]);
Serial.print(pgm_read_byte(&flash[152]));
Serial.print(' ');
Serial.println((uint16_t)&flash[152]);
// TODO: put your setup code here, to run once:
}
void loop() {
// TODO: put your main code here, to run repeatedly:
}
Start
1 256
2 256
Это может сработать - если заранее отодвинуть данные в PROGMEM на величину объёма RAM. Но следующая версия компилятора может всё обрушить !
Пространства как раз разные !
TC надо делать что то типа этого -
https://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/st7735-160-na-128-podsvetka-barakhlit?page=4#comment-666572
Компилятор сам разберется какую из функций вызвать в зависимости от того что вы в неё передадите.
надо что-то почитать об этом…
Это на ББ, ARM, … можно по адресу понять где что лежит - одно адресное пространство …
Для AVR с Гарвардской архитектурой всё иначе -
“…Как и подавляющее большинство современных 8-разрядных микроконтроллеров, AVR является типичным представителем архитектуры Гарвардского типа. Память программ и память данных в нем отделены друг от друга и находятся в различных адресных пространствах…”
Я так делаю для AVR:
#define FSH_P(p) (reinterpret_cast<const __FlashStringHelper *>(p))
const char messageRAM[] = "I'm in RAM";
const char messageProgmem[] PROGMEM = "I'm in PROGMEM";
Serial.println(messageRAM);
Serial.println(FSH_P(messageProgmem));
я имел ввиду, что адрес может быть один, а пространства, конечно, разные.
Спасибо. Оно.
Еще один вопросик имеется:
Размещаю строку в PROGMEM так:
const PROGMEM char inits1[]=“Initializing SD card.”;
strlen(inits1) показывает правильное значение
но если я передаю эту строку (т.е. указатель) в функцию, то в самой функции
void StringOut(const char *S) {
Serial.println(strlen(S));
...
strlen() показывает какой-то бред.
Судя по всему strlen() думает что строка находится в ОЗУ
Как можно решить эту проблему?
Что-то сомнения берут, как он разберется
В АВР константный массив тоже лежит в РАМ, если его принудительно в ПРОГМЕМ не запихнуть.
копируется в RAM при старте
Массивы констант из RAM надо передавать так:
writebuff (uint8_t*)ram_const, sizeof(ram_const));
Пример
uint8_t ram[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
const uint8_t PROGMEM flash[] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2
};
const uint8_t ram_const[] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
void print_buff(uint8_t buffer[], uint8_t count) {
Serial.print("0x");
Serial.print((uint16_t)&buffer[0], HEX);
Serial.print(" in RAM ");
while (count--) {
Serial.print(buffer++[0]);
}
Serial.println();
}
void print_buff(const uint8_t buffer[], uint8_t count) {
Serial.print("0x");
Serial.print((uint16_t)&buffer[0], HEX);
Serial.print(" in FLASH ");
while (count--) {
Serial.print(pgm_read_byte(buffer++));
}
Serial.println();
}
void setup () {
Serial.begin(9600);
Serial.println("Start");
print_buff(ram, sizeof(ram));
print_buff(flash + 152, sizeof(flash) - 152);
print_buff((uint8_t*)ram_const, sizeof(ram_const));
// TODO: put your setup code here, to run once:
}
void loop() {
// TODO: put your main code here, to run repeatedly:
}
Блин. Понял… И прикол в том что я пытался так делать, ибо помнил что где-то читал об этом, но компилятор ругался. И только сейчас дошло, что это си-шная case sensitive, к которой до сих пор не могу привыкнуть.
Спасибо!
Чуть выше вам же привели пример для строк:
Не только для строк. Таким образом Arduino IDE разводит по сторонам RAM const и PROGMEM const. Неплохой приём, как мне думается.
Скорее наоборот: всегда лежит в PROGMEM, и по умолчанию еще и копируется в RAM.
Откуда вообще в RAM могут появиться константные строки, как не из PROGMEM?