Перемещение данных, BSS и динамической памяти во внешнюю SRAM Atmega2560

Это мой первый вопрос здесь, извините, если я что-то пропустил.

Я использую Atmega2560 в качестве основного процессора для своего проекта, но у меня заканчивается оперативная память, поэтому я подключил к нему внешнюю SRAM на 64 КБ (64 x 8). Я поискал и нашел пару проектов и библиотек, использующих внешний sram:

http://andybrown.me.uk/wk/2011/08/28/512kb-sram-expansion-for-the-arduino-mega-design/

https://hackaday.io/project/21561-arduino-mega-2560-32kb-ram-shield

Но все они используют внешнюю SRAM в качестве динамической памяти.

Я хотел бы использовать внешнюю память в качестве памяти данных, bss и кучи, оставив всю SRAM для стека.

Я нашел это в руководстве по avr-libc: https://www.nongnu.org/avr-libc/user-manual/malloc.html

Используя информацию из руководства, я изменил make-файл для загрузчика Arduino Mega здесь: C:\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\stk500v2

Ссылка на оригинальный make-файл: https://github.com/arduino/ArduinoCore-avr/blob/master/bootloaders/stk500v2/Makefile

Я изменил «EXTMEMOPTS =» на это:

EXTMEMOPTS = -Wl, --section-start,.data=0x802200, --defsym=__heap_end=0x80ffff

0x800000 — смещение для гарвардской архитектуры, 0x802200 — первый адрес для внешней памяти.

Я перекомпилирую загрузчик с новым make-файлом, но получаю следующую ошибку:

введите описание изображения здесь

Я считаю, что он жалуется, потому что адрес находится за пределами внутренней SRAM, я не смог найти способ исправить это.

Я не уверен, что не так, что мне не хватает? Также, если это будет решено, можно ли инициализировать оборудование внешней памяти (путем установки регистров XMCRA и XMCRB) в основной функции загрузчика? Если нет, то где мне это сделать?

Обновление: вот скрипт компоновщика: https://codeshare.io/aJom3K

Обновление 2: первая проблема решена; Я редактировал неправильный файл ld и после изменения правильного файла на следующий Это сработало:

DATA_REGION_ORIGIN = 0x802200;

Следующая проблема заключается в том, где инициализировать оборудование для внешней SRAM? В настоящее время я делаю это в функции __jumpMain загрузчика, которая также устанавливает регистр указателя стека. Это нормально или я должен сделать это в другом месте?

загрузчик: https://codeshare.io/5zNr1b

Обновление 3: как упоминал @Brian Drummond в частичном ответе, я изменил аргументы компоновщика на это:

EXTMEMOPTS = -Wl, --section-start,.data=0x802200, --defsym=__heap_end=0x80ffff, --defsym= DATA_REGION_ORIGIN = 0x802200

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

Для тех, кто делает что-то подобное: вам также нужно добавить аргументы для изменения DATA_REGION_LENGTH на новую длину, иначе будет использоваться только старая длина, которая в моем случае: 0xfe00.

Обновление 4: после некоторого тестирования выяснилось, что MC не использует внешнюю SRAM; после программирования с помощью нового скрипта я могу отключить SRAM, и он продолжит работать нормально. Также я проверил линии данных и адреса в SRAM, и ничего не пишется и не читается.

Итак, я вернулся к началу. Есть идеи, что не так?

как выглядит файл .ld?
не хочется об этом говорить, но если ваша прошивка требует динамического распределения памяти и внешней SRAM, возможно, AtMega не подходит для этой работы.
Вот файл скрипта компоновщика: codeshare.io/aJom3K
@PeteW Я знаю, что настаиваю на этом, и в будущем я перейду к вооружению, но я хочу сначала решить эту проблему.
__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800200;кажется, не согласен с .data=802200в командной строке. Может быть, вам нужно установить __DATA_REGION_ORIGIN__аргументы компоновщика?
@BrianDrummond Большое спасибо, я все это время менял не тот файл ld. После того, как вы упомянули об этом, я понял это. Я удалил условие и изменил файл ld на это: DATA_REGION_ORIGIN = 0x802200; и это решило проблему. Но я не уверен, где он был определен изначально, поскольку, если я позволю условию быть там, это даст мне ту же ошибку.
Зачем тебе куча на 8-битке и почему нельзя просто удалить ее, чтобы освободить память? Он просто сидит в вашей оперативной памяти, занимая место без уважительной причины.
@Lundin Меня не волнует куча, и она не используется, приведенные выше аргументы компоновщика - это просто тест. Моя главная цель состояла в том, чтобы переместить .data и .bss во внешнюю SRAM.
Возможно, попробуйте инициализировать XMCRA в разделе init3 с помощью__attribute__ ((section (".init3"))

Ответы (2)

TL; DR Это не будет работать так, как вы хотите, потому что Atmega2560 не имеет интерфейса внешней памяти.

Когда вы создаете переменную, которая сохраняется во [внутренней] SRAM, ALU процессора может получить эту переменную, потому что ALU и SRAM подключены к одной и той же шине внутренней памяти. На процессорах более высокого класса (например, STM32F756) у вас иногда есть выделенное периферийное устройство интерфейса внешней памяти, которое может, например, подключаться к SRAM, DRAM, SDRAMS и т. д. Эти периферийные устройства являются особыми, поскольку они преобразуют протокол шины внутренней памяти. процессора во внешний аппаратный интерфейс, необходимый для загрузки/сохранения данных во внешнюю микросхему памяти.

Простая [r] аналогия такова: ваш ATmega2560 имеет периферийное устройство SPI. Когда вы настраиваете его как мастер SPI и записываете что-то в регистр данных SPI, периферийное устройство автоматически синхронизирует биты на шину без дальнейшего вмешательства ЦП. Вы преобразовали доступ к памяти (запись регистра данных) в физический протокол.

И наоборот, вы можете написать код, который будет вручную шевелить контакты ввода-вывода для достижения того же аппаратного результата, что и периферийное устройство SPI. Это имеет ряд ограничений, главное из которых заключается в том, что вам нужно вручную распаковать байт данных и установить контакты в соответствующее время вручную (через код). Должно быть очевидно, что этот код под капотом выполняет много операций чтения и записи памяти, и у вас больше нет автоматического преобразования «запись в регистр данных, тактовые биты», как с выделенным периферийным устройством SPI.

То, что вы пытаетесь реализовать с вашей внешней SRAM и скриптом компоновщика, не сработает, потому что, что касается микроконтроллера и компоновщика, этого адресного пространства просто не существует, и нет аппаратного периферийного устройства, которое может преобразовывать инструкции шины. в сигналы внешней памяти. Проекты, которые вы связали, просто используют программный уровень для ручного управления контактами ввода-вывода для связи с внешней SRAM (также известной как бит-бэнг).

Изменить, чтобы добавить: вы все равно можете полностью использовать внешнюю SRAM, просто она не будет автоматической. Вам понадобится программная библиотека, чтобы заставить ее работать, и вам придется явно хранить/загружать данные через какой-либо API. Если у вас заканчивается SRAM и ваша программа не может быть связана, вам не повезло. Есть несколько чрезвычайно хакерских способов обойти это, но я не рекомендую их. Вместо этого либо уменьшите требования к памяти вашего приложения, пока его нельзя будет связать, либо переключитесь на более мощный микроконтроллер. Я бы порекомендовал последнее и сказал бы избавиться от внешней памяти, потому что даже на процессоре с интерфейсом внешней памяти добавление внешней памяти серьезно увеличивает стоимость, сложность и время.

Спасибо за разъяснение, меня смутило техническое описание интерфейса XMEM (интерфейс внешней памяти) и того, как он обрабатывает все автоматически, а документация AVR-LIBC показала, что это возможно; система, над которой я работаю, — это всего лишь прототип, и я обновлю ее до ARM, поскольку, как вы упомянули, она намного эффективнее и проще.

Частичный ответ:

Глядя на файл .ld (скрипт компоновщика), мы видим

__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800200;

что, кажется, не согласуется с вашим желанием .data=802200в командной строке. Вы можете проследить путь от __DATA_REGION_ORIGIN__до .dataв самом скрипте .ld.

Что предполагает, что вы можете установить __DATA_REGION_ORIGIN__в аргументах компоновщика (в ldкомандной строке), и (если установлено) оно переопределит значение, 0x800200указанное в сценарии .ld.

Или отредактируйте выражение в скрипте компоновщика. Простое редактирование значения должно работать (в моем понимании), но, по-видимому, что-то еще (но ЧТО?) в процессе ldпредоставляет значение, которое переопределяет значение сценария. Я чувствую, что процесс .ld излишне неясен, и я не претендую на полное его понимание.

В качестве обходного пути можно удалить условное выражение, оставив только значение, но вы должны быть осторожны с «неофициальными» изменениями в сценариях сборки, поскольку они, как правило, позже вызывают проблемы с обслуживанием.

Добавление -vк команде ld может дать дополнительную информацию, показывающую, что происходит на самом деле...

В этом ответе упускается из виду тот факт, что ATMega2560 не имеет средств для отображения внешних SRAM памяти, и никакие действия компоновщика-скрипта не исправят это. Во всяком случае, это просто разорвет связь, и ничего не будет работать.