привязка samd21, изменить базовый адрес с дефолтного
Я работаю над безопасным обновлением прошивки для своего устройства adafruitfeather m0. От моего технического директора, который написал предыдущее обновление, я понял, что либо для samd21, либо для всех рук m0 (не уверен, что именно) компилятор компилирует не относительные адреса, то есть bx 0x3000 перейдет на адрес 0x3000, а не на 0x3000 байт от моего местоположения. Моя цель — разделить flash на 4 банка:
- загрузчик (2k)
- данные пользователя
- прошивка №1
- прошивка №2 какая прошивка будет загружена, зависит от флага во флэш-памяти. я понимаю от моего предшественника, что это проблема, поскольку прошивка № 2 при загрузке в оперативную память может не работать. Я не согласен и считаю, что простые изменения в сценарии .ld должны решить эту задачу.
Мой единственный вопрос к вам, ребята, достаточно изменить адрес .ld script .text ? я знаю, что загрузчик переходит на адрес, который был определен в сценарии .ld, если он не 0xFFFFFF (если во флэш-память была записана). Мне нужно изменить сценарий .ld, чтобы он включал два раздела .text? мне нужно также определить, как они находятся в оперативной памяти? какие-нибудь примеры? намек?
Спасибо.
@codeScriber, 👍0
Обсуждение1 ответ
Типичный LD-скрипт состоит из двух разделов: один определяет области памяти ("ПАМЯТЬ"), а другой определяет, что помещать в эти области памяти ("РАЗДЕЛЫ").
Чтобы проделать дыры в существующем макете памяти, обычно достаточно просто изменить первый раздел — часть, определяющую макет мемуата. Уменьшайте и перемещайте существующие блоки памяти и вставляйте новые.
Например, у вас может быть это в данный момент:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000-0x2000 /* First 8KB used by bootloader */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
В начале прошивки уже определена дыра размером 0x2000, а скетч загружается начиная с 0x2000.
Возможно, вы захотите уменьшить и переместить его, а также добавить фрагмент "пользовательских данных". Достаточно просто пройти:
MEMORY
{
USERDATA (rx) : ORIGIN = 0x2000, LENGTH = 0x1000
FLASH (rx) : ORIGIN = 0x3000, LENGTH = 0x00040000-0x3000
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
(Я свернул часть математики, потому что это бессмысленно). Теперь область флэш-памяти (где находится скетч) была уменьшена на 0x1000 и перемещена на дополнительные 0x1000 вверх по карте памяти. Был вставлен фрагмент USERDATA, который вы можете использовать позже, если хотите.
Чтобы туда что-то вставлял скрипт компоновщика (вам не нужно ничего менять, чтобы переместить данные скетча...), вы можете определить новый раздел в более поздней части скрипта компоновщика:
.userdata :
{
KEEP(*(.userdata))
KEEP(*(.userdata.*))
} > USERDATA
Это должно поместить все, что вы поместите в раздел .userdata
(или подраздел внутри него) вашего скетча, в блок флэш-памяти USERDATA — отдельно от вашего скетча.
(sketch)
const uint8_t __attribute__((section(".userdata"), used)) data[] = { 10, 100, 123, 177, 221, 49 };
Однако, если вы планируете использовать его как EEPROM и записывать в него только код из скетча, то вам не нужно ни о чем подобном беспокоиться — просто вырежьте отверстие. Однако вы также можете указать некоторые глобальные переменные, которые помогут вам с кодом:
(linker script)
PROVIDE(userdata_start = ORIGIN(USERDATA))
PROVIDE(userdata_length = LENGTH(USERDATA))
Затем вы можете использовать их в своей программе, чтобы узнать, где находится фрагмент USERDATA и насколько он велик (идеальный вариант, если вы когда-нибудь решите его изменить — не нужно менять код, только скрипт компоновщика).
т. н. базовый ld-скрипт, по крайней мере, тот, который у меня есть, загрузчик не «дырявый» от скрипта, он является его частью, в него нельзя записать из-за использования регистра fure 4, я думаю, что он защищает первые X байтов, я думаю, 16K в ардуино по умолчанию. В любом случае сценарий ld также определяет область .text, на которую позже ссылается загрузчик, и использует volatile __asm("bx...") для перехода к этому адресу, если параллельный адрес флэш-памяти, предназначенный для скетча, имеет код и не 0xffff (что означает, что он был стерт). как скрипт «связывает» между .text на флэш-памяти и оперативной памятью?, @codeScriber
что мне нужно, так это скомпилировать скетч один раз, когда его базовая область ОЗУ определена как X и флэш-память X', и один раз, когда его база - Y на флэш-памяти и Y' в ОЗУ. опять же, как я понимаю, все адреса памяти не являются относительными., @codeScriber
Хорошая точка зрения. Существующий загрузчик не имеет понятия. Загрузчик и скрипт компоновщика должны согласовать свои действия. Если вы измените сценарий компоновщика, чтобы начать выполнение из другой области, вы также должны изменить загрузчик, чтобы перейти в эту область. Загрузчик не может ничего узнать, если вы ему не скажете., @Majenko
это само собой разумеется :) мне нужно отметить начало, как это отмечено сегодня, и заставить загрузчик иметь оба адреса или как-то обновить адрес во время обновления прошивки. я подумаю об этом позже, реальный вопрос, который, я думаю, заключается в том, скажем, я перемещаю сегмент .Text 0x4000 байт во флэш-память, нужно ли мне также перемещать его в сценарии в ОЗУ? ваш ответ ничего не говорит об оперативной памяти, просто о флэш-памяти, поэтому я не уверен., @codeScriber
Что там "перемещать" в ОЗУ? Оперативная память отделена от флэш-памяти. Перемещение вещей во флэш-памяти вообще не связано с оперативной памятью. Если вы хотите нарезать оперативную память, вы можете. Но это не имеет отношения к перемещению объектов во Flash., @Majenko
Некоторые загрузчики используют специальное место для «прыжка», отдельное от вашего скетча. Сценарий компоновщика затем "загружает" эту область с инструкцией перехода, которая отправляет ее к реальному началу кода. Таким образом, сценарий компоновщика определяет, куда программа переходит во флэш-памяти, при условии, что эта выделенная область перехода всегда одна и та же., @Majenko
Но... не проще ли было бы сохранить скетч там, где он есть, и поместить ваши пользовательские данные в *конец* флэш-памяти?, @Majenko
нет, потому что нужна область пользовательских данных, но это не худшая из моих проблем, я хочу две прошивки на одной флешке, для этого мне нужно либо иметь возможность загружаться с другого адреса, чем по умолчанию, и иметь возможность скомпилировать соответствующую программу для этого региона ИЛИ загрузите прошивку в банк 1 и заставьте сам загрузчик скопировать ее в банк 0, но если запись не удалась, все готово, чип тост, это проблема., @codeScriber
Затем вам нужно разделить флеш 50/50 с небольшим остатком для настройки. Два отдельных скрипта компоновщика, один для банка A и один для банка B. Загрузите банк A, проверьте правильность банка A, измените флаг загрузки на загрузку из банка A. Затем загрузите банк B, проверьте правильность банка B и переверните флаг загрузки. для банка B. Я думаю, загрузчик может сделать это для вас, как только загрузка будет проверена. Нужен пользовательский загрузчик, конечно. И какой-то автономный метод запоминания того, какой банк используется в настоящее время, чтобы вы скомпилировали правильную версию., @Majenko
- Как создать шестнадцатеричный файл для прошивки arduino?
- Внешняя оперативная память (23LC1024) и внешняя флэш-память (W25Q64JVSSIQ) с Sparkfun SAMD21
- Создание избыточности прошивки на Arduino Nano
- Установка Micropython на Arduino nano
- Как навсегда изменить скорость передачи данных ESP8266 (12e)?
- Можно ли отключить WiFi на ESP8266?
- Удаленная загрузка кода на плату Arduino через интернет
- Добавление пользовательской платы в среду разработки Arduino
Вы смотрели техническое описание Samd21?, @PhillyNJ
В техпаспорте подробно описано, как устроена память samd21, включая раздел загрузчика. Я понятия не имею, что вы имеете в виду под скриптом .id, какой ide вы используете? Также поищите в Google примечание к приложению samd21 AT07175. Хороший туториал по программированию загрузчика, @PhillyNJ
базовый сценарий ld показывает мне базовую структуру памяти и определяет переменные, которые позже использует загрузчик, для этого мне не нужна таблица данных. Сценарий ld, а не сценарий id — это сценарий GNU для ld (компоновщика), который определяет макет в двоичном файле, а затем во флэш-памяти и в макете памяти., @codeScriber