Pull to refresh

Comments 27

Интересно, а стандартные функции и библиотеки Arduino умеют пользоваться данными, размещёнными за пределами первых 32к? Например, snprintf_P и перегрузка Stream.print(const __FlashStringHelper*)
Пробовали offsetof (костыль получше)?

typedef struct {
    unsigned char array2d[2][3];
} x_t;
...
const x_t  v PROGMEM = {...};
...
unsigned char a = pgm_read_byte_far(pgm_get_far_address(v) + offsetof(x_t, array2d[i][j]));

Надо переходить на ARM, где единное 32 битное адресное пространство (если не перешли).
Вот именно, я не вижу смысла в AVR, кроме как в формате восьминогих тараканов типа ATTiny, дешевле и проще поставить STM32F0/F1, или L серию, если надо ещё и по питанию экономию полную сделать. Есть конечно запущенные случаи, где сигнальные уровни 5V, но там можно и преобразователей уровня поставить.

Или не ставить ибо у stm32 большинство ног 5v tolerant.

Вот из-за таких костылей в коде я и пересел на STM32 — никаких раздельных адресных пространств, все указатели 32 бита…
Возможно появление массивов больше 32К в 8-битном решении намекает на необходимость использования для проекта более мощного МК?
Обработка такого большого массива на 8-и битном МК возможно (зависит от Т.З.) занимает много времени. Поэтому возможно имеет смысл посмотреть в сторону увеличения разрядности.
а еще это может быть развитая менюшка, или набор констант читаемых раз в жизни, или… много всяких или. было у меня семейство приборов на сопровождении. мега2560 с почти полной пзу, а производительности хватало.
UFO just landed and posted this here
Что вы подразумеваете под «ни разу не атомарной операцией»? Что LPM, что ELPM выполняются 3 такта. Как вы перед этим заполняете регистры — другой вопрос. И почему бы вам не привести пример другого, короткого и простого макроса?
UFO just landed and posted this here
Вся эта статья возникла из-за чтения мануалов. Читаю главу 5, делаю как написано. До 32 КБ работает, потом нет. Вот что я, по-вашему, должен был делать в таком случае? Какие именно мануалы читать, если не те, что я и читал? Как не думать о 32-битной адресации, если нужные данные лежать за пределами 16-битного адресного пространства? При чём тут вообще прерывания? Откуда я мог взять смещение, которое нужно положить в «рампз»?
UFO just landed and posted this here
Вот теперь ваша мысль ясна. Я же в самом начале статьи написал, какому именно компилятору она посвящена. Ваша ветвь комментариев — точно такой же оффтоп, как и те, где рекомендуют сменить МК.
«ни разу не атомарная операция», означает в данном контексте, что для получения адреса за пределами смещения в 32к (ограниченных 15 битами регистровой пары Z), необходимо изменять RAMPZ, потому что адресация ELPM использует пару RAMPZ:Z
Аппаратные регистровые указатели у AVR — двухбайтные, X, Y, Z.
Об этом и речь. До тех пор, пока вам достаточно 2 Б (в ассемблере это регистр Z и инструкция LPM — Load Program Memory), всё хорошо. Чтобы выйти за 64 КБ (а по факту за 32), приходится использовать 3-Б аппаратные регистры, а именно RAMPZ:Z и инструкцию ELPM (Extended Load Program Memory). И вся проблема в том, что в главе 5 мануала AVR Libc об этом ни слова, хотя сам модуль pgmspace содержит всё нужное.
Об этом и речь.

речь о том что работать с 32 битными адресами при наличии только 16 битных указателей пришлось бы с гораздо большим количеством костылей. при чем всегда, а не только когда требуется выйти за пределы 32 кбайт.

хотя большие аврки уже сами по себе на костылях стоят.

0 по 0x007fffff

подскажите о каком контролере идет речь? где такие большие адреса присутствуют?

Понятия не имею, у какого микроконтроллера есть 8 МБ флеша. В серии ATmega, насколько я знаю, максимум 256 КБ; ATxmega — 392 КБ. В статье речь не о размере флеша микроконтроллера, а об адресном пространстве, выбранном разработчиками адаптированного для архитектуры AVR компилятора GCC. С практической точки зрения важно, что существую микроконтроллеры с более, чем 32 КБ флеша, а не существуют ли с 8 МБ.

вы уж извините, но что то я не могу понять кто тупит. у авр ведь разделенное адресное пространство. а то что вы пишете что-то не соответствует реальности:

"под код (ПЗУ, flash) отводятся адреса с 0 по 0x007fffff, а под данные (ОЗУ, SRAM) — с 0x00800100 по 0x0080ffff. "

я в отладке смотрю адресацию на атмега2560 и вижу там следующее.

data registers имеет адреса 0x0000 - 0x21FF

prog flash имеет адреса 0x000000 - 0x7FFF

я потратил вечер на то чтоб понять что к чему..

и у меня в атмел студио без проблем работает следующая конструкция:

pgm_read_dword_far( pgm_get_far_address(hz))

перечитав коммент понял что ошибся: prog flash имеет адреса 0x000000 - 0x3FFFF

и еще вы не упомянули такой фактор как переход к нулевому адресу без инкрементирования смещения. допустим если было 0x1FFFF и мы добавили один то станет 0x10000. не знаю еще как это прогнать в железе чтоб проверить. но в коментариях на многих англоязычных сайтах пишут что так и есть

вообщем у меня полное разочарование. я хотел создать два массива, один в оперативке, а второй в памяти програм но на границе 0x1FFFF, чтоб посмотреть что будет переписываться во второй массив во время перехода. и что я вижу. конструкция типа:

for (int x = 0; x < 399; x ++){ for (int y = 0; y < 19; y ++){ perehodreal[x][y] = pgm_read_dword_near(&(array2d[x][y])); } }

работает без проблем. а вот если мы используем дальний адрес то вываливается ошибка и ничего не компилируется.

for (int x = 0; x < 399; x ++){ for (int y = 0; y < 19; y ++){ perehodreal[x][y] = pgm_read_dword_far(pgm_get_far_address(perehod[x][y])); } }

единственный вариант что я вижу это втупую прибавлять к адрессу 4 и считывать это значение в свой массив. но как мне кажется это максимально тупо

так что скажите? есть у вас идеи по этому поводу?

Я не уверен, что понял вашу проблему, и у меня нет желания тратить время на это. Если вы пришлёте мне свой проект, может быть, я разберусь. Пока что я могу лишь предположить, что вы невнимательно читали статью. Я же написал, что pgm_get_far_address не умеет работать с элементом массива, вычисляемым во время работы; ей нужно подать определённый при компиляции указатель (другими словами, сам массив), а смещение делать вручную (через арифметику указателей. Вам знаком этот термин?). При этом я не понимаю, почему у вас работает pgm_read_dword_near; вы уверены, что данные расположены после 64 КБ?

О проблеме 0x1FFFF + 1 = 0x10000 слышу впервые; похоже, кто-то (кто? Компилятор GCC? Какая-то конструкция библиотеки AVR-libc? Отладчик Студии?) производит сложение по модулю 0x10000 (64 К) в младших 16 битах, но при этом сохраняет старшие (или всегда производит смещение на 0x10000). Также стоит помнить о том, что в микроконтроллерах AVR одни и те же вещи (например, адреса флеша) в одних местах исчисляются в байтах, а в других — в словах. Ещё я не понял, почему ваша проблема может быть решена прибавлением 4. Почему именно 4, откуда такая константа?

Sign up to leave a comment.

Articles