zHz00 Untitled

суббота, 14 декабря 2019
23:59 Смещение на полвагона
В общем, я про такое слышал, но глазами увидел впервые.

Был проект на микроконтроллере STM32F4. Перенёс на STM32F0 (упрощённая модель). Не весь, конечно, только нужные части. Не запускается. Хардфолт.

Копание в ассемблере показало, что хардфолт происходит при косвенной адресации по адресу, который вполне обычен. Он расположен в доступной области и по нему есть данные. Единственная особенность адреса -- он был нечётным!

Это был адрес начала "сегмента данных". Программа занимала 17189 байт, поэтому данные-инициализаторы располагались начиная с адреса 0x08004325. Чтобы заставить расположить программу данные начиная с чётного адреса, мне пришлось вручную поправить скрипт линковщика (у меня это arm-gcc-link.ld), написав там в начале сегмента данных .=ALIGN(4) (что означат: выровнять текущий адрес по границе 4-байтных слов). Я на всякий случай решил выровнять сразу по 4 байта, а не по 2.

После этого всё заработало. То есть, младшая модель микроконтроллера не умеет работать с данными по нечётным адресам. Это не нонсенс. Современные и мощные контроллеры/процессоры, естественно, работают с данными по любым адресам. Но это не получается само собой. В них встроен специальный блок, который прозрачно для пользователя считывает два слова, равных разрядности процессора, с адресами до и после нужного, а потом склеивает из них конечное число. Получается немного медленнее.

А в этой модели микроконтроллера блок нечётных адресов вырезали.

Вообще-то, среда разработки (у меня это заброшенный разработчиками CooCox IDE) должна знать о таких вещах, коли уж она при задании целевого микроконтроллера автоматически подставляет его размеры RAM и REM ROM -- и правильно указывает нужные диапазоны адресов. Но в этот раз она не знала.

@темы: Программирование, Борьба с техникой

URL
Блин, а...
вот штука то откапалась в жж: "Лет 20 тому назад жу...
М-да... а Пряник служит в Каспийске... Куда мир кати...
Алекс, а можешь сделать мне вот так? http://mylife.yuga...
Так хочется опять посплавляться...
Это я http://www.dirty.ru/users/777 Current music: ...

15.12.2019 в 04:28

15.12.2019 в 04:28
выравниванием начала сегмента данных дело в общем случае не решится
а вдруг в сегменте данных у тебя идёт сначала байт, а потом слово? и тогда слово получится по нечётному адресу
нужно автоматическое выравнивание всех переменных в сегменте данных (вставкой нулевых байт где нужно),
но такое выравнивание может раздуть данные, что может противоречить ожиданиям программиста
как ни крути, но незаметно для программиста, автоматически, этот вопрос не решить
ты должен знать все особенности МК

помню БК-0010-01, она 16-битная
там младший бит адреса просто игнорировался, когда адресуется слово, и считывалось всегда слово по чётному адресу
всё-таки генерировать ошибку при нечётном адресе было бы более правильным поведением, чем замалчивать
URL

15.12.2019 в 13:29

15.12.2019 в 13:29
CD_Eater, про выравнивание всех переменных ты прав. Но пока я не нагуглил, как это сделать. Раздувание не проблема, т.к. в проекте задача элементарная -- памяти хватит. Сейчас я по крайней мере знаю о такой особенности МК, поэтому в случае возникновения глюков буду сразу догадываться, куда копать.

>>ты должен знать все особенности МК

Разве такие люди существуют? Это надо много лет работать только с одной моделью -- и пилить на ней разные (!) штуки. А на практике такого не бывает.

Я под PIC32 писал. Старший коллега составил рыбу прошивки на низком уровне (он гораздо лучше всё знает), а я стал писать логику на высоком. И обнаружил невообразимый глюк -- у переменных были совершенно не те значения, что надо (точных примеров не помню, но приколы были уровня a=2+2, а в переменной 5986). При этом ветвление программы основывалось на неправильных значениях, т.е. это были не проблемы отладчика. Старший коллега понятия не имел, с чем это могло быть связано. Я перенёс объявления переменных в начало функции и всё заработало. С чем это было связано -- не знаю до сих пор. Я с тех пор написал большой шмат кода под этот МК и больше таких глюков не видел, где бы я переменные не объявлял. Проблем с нечётными адресами вроде как у этого МК нет.

>>помню БК-0010-01

Да ты зубр. Я могу похвастаться только МК-52. При этом добрался я до него только в 2000-е. Я тогда в школе учился.

>>всё-таки генерировать ошибку при нечётном адресе было бы более правильным поведением, чем замалчивать

Да.
URL

15.12.2019 в 13:55

15.12.2019 в 13:55
Но пока я не нагуглил, как это сделать.
ты на си пишешь?
тогда
pragma DATA_ALIGN
pragma pack
URL

15.12.2019 в 14:02

15.12.2019 в 14:02
CD_Eater, на си.
1. Прагма пэк работает только на структуры!
2. Про прагму дата-алигнед никогда не слышал. На первый взгляд не гуглится.
3. В gcc есть __attribute__(aligned), но его надо задавать для каждой нужной переменной. Я думаю, придётся идти этим путём.
URL

15.12.2019 в 14:34

15.12.2019 в 14:34
3) да, для каждой
но можно сделать свой
#define WORD ...,
чтобы писать просто
WORD x;
URL

15.12.2019 в 14:35

15.12.2019 в 14:35
1) да, только на структуры
но __attribute__(aligned) не работает внутри определения структуры
URL

15.12.2019 в 14:40

15.12.2019 в 14:40
кстати, в локальных переменных (в стеке) тоже будет такая проблема (на твоём мк push может запушить 1 байт?)
но pragma DATA_ALIGN работает только со статическими переменными
URL

15.12.2019 в 22:15

15.12.2019 в 22:15
CD_Eater,

>>#define WORD ...,
чтобы писать просто
WORD x;

Можно, но это плоховато, поскольку скрывает важную часть в определении. Впрочем, возможно я так и сделаю.

>>но __attribute__(aligned) не работает внутри определения структуры

А для этого есть прагма пэк

>>кстати, в локальных переменных (в стеке) тоже будет такая проблема (на твоём мк push может запушить 1 байт?)

Думаю, с локальными переменными проблемы не будет, т.к. пуш поддерживает только один размер данных. Вроде бы. Надо уточнить.

Спасибо за консультацию.
URL
Добавить комментарий

Расширенная форма

Подписаться на новые комментарии