Это мой первый вопрос здесь, извините, если я что-то пропустил.
Я использую 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, и ничего не пишется и не читается.
Итак, я вернулся к началу. Есть идеи, что не так?
TL; DR Это не будет работать так, как вы хотите, потому что Atmega2560 не имеет интерфейса внешней памяти.
Когда вы создаете переменную, которая сохраняется во [внутренней] SRAM, ALU процессора может получить эту переменную, потому что ALU и SRAM подключены к одной и той же шине внутренней памяти. На процессорах более высокого класса (например, STM32F756) у вас иногда есть выделенное периферийное устройство интерфейса внешней памяти, которое может, например, подключаться к SRAM, DRAM, SDRAMS и т. д. Эти периферийные устройства являются особыми, поскольку они преобразуют протокол шины внутренней памяти. процессора во внешний аппаратный интерфейс, необходимый для загрузки/сохранения данных во внешнюю микросхему памяти.
Простая [r] аналогия такова: ваш ATmega2560 имеет периферийное устройство SPI. Когда вы настраиваете его как мастер SPI и записываете что-то в регистр данных SPI, периферийное устройство автоматически синхронизирует биты на шину без дальнейшего вмешательства ЦП. Вы преобразовали доступ к памяти (запись регистра данных) в физический протокол.
И наоборот, вы можете написать код, который будет вручную шевелить контакты ввода-вывода для достижения того же аппаратного результата, что и периферийное устройство SPI. Это имеет ряд ограничений, главное из которых заключается в том, что вам нужно вручную распаковать байт данных и установить контакты в соответствующее время вручную (через код). Должно быть очевидно, что этот код под капотом выполняет много операций чтения и записи памяти, и у вас больше нет автоматического преобразования «запись в регистр данных, тактовые биты», как с выделенным периферийным устройством SPI.
То, что вы пытаетесь реализовать с вашей внешней SRAM и скриптом компоновщика, не сработает, потому что, что касается микроконтроллера и компоновщика, этого адресного пространства просто не существует, и нет аппаратного периферийного устройства, которое может преобразовывать инструкции шины. в сигналы внешней памяти. Проекты, которые вы связали, просто используют программный уровень для ручного управления контактами ввода-вывода для связи с внешней SRAM (также известной как бит-бэнг).
Изменить, чтобы добавить: вы все равно можете полностью использовать внешнюю SRAM, просто она не будет автоматической. Вам понадобится программная библиотека, чтобы заставить ее работать, и вам придется явно хранить/загружать данные через какой-либо API. Если у вас заканчивается SRAM и ваша программа не может быть связана, вам не повезло. Есть несколько чрезвычайно хакерских способов обойти это, но я не рекомендую их. Вместо этого либо уменьшите требования к памяти вашего приложения, пока его нельзя будет связать, либо переключитесь на более мощный микроконтроллер. Я бы порекомендовал последнее и сказал бы избавиться от внешней памяти, потому что даже на процессоре с интерфейсом внешней памяти добавление внешней памяти серьезно увеличивает стоимость, сложность и время.
Частичный ответ:
Глядя на файл .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 может дать дополнительную информацию, показывающую, что происходит на самом деле...
пользователь_1818839
Пит В.
Оли
Оли
пользователь_1818839
__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800200;
кажется, не согласен с.data=802200
в командной строке. Может быть, вам нужно установить__DATA_REGION_ORIGIN__
аргументы компоновщика?Оли
Лундин
Оли
Ха-Лайла ха-Зех
__attribute__ ((section (".init3"))