|
LPC2888, Data Abort exception, при выполнении кода из Flash |
|
|
|
Jan 10 2011, 07:27
|

Участник

Группа: Участник
Сообщений: 66
Регистрация: 6-11-09
Из: г. Омск
Пользователь №: 53 464

|
Прежде всего позлорадствую. Я не удивлен подобного рода проблемой, потому как мне и моим коллегам эта модель сразу дико не понравилась. Она особенная в семействе LPC2000, эдакий уродец. Все его отличия только отрицательные (они в полной мере описаны в этом аппноуте), единственный плюс это энергопотребление, по которому он и был выбран (не нами, естественно). Проблема возникла, когда размер проекта достиг порядка 2000 строк кода. Причем "охват" использования ресурсов МК небольшой: прерывания не используются, код линейный, из периферии используется только GPIO, LCD контроллер, ну и CGU для тактирования последнего. Компилятор GCC (Yagarto). Оптимизация кода отключена. Отлаживаю J-Link'ом (через GDB Server), драйвера и прошивка последние. Cache и memory remap не используются, в j-linke также отключено всяческое кеширование. Из RAM код выполняется замечательно, но из Flash вдруг где-то посередине (на дисплее половина интерфейса уже отрисовалась) процессор вываливается в Data Abort. Причем происходит это даже не в какой то ответсвенный момент работы с регистрами периферии или еще чего-то там, а в в процессе выполнения безобидной функции. Вот она: Код 10401878 <_Z14get_menu_childP18menu_item_header_th>: menu_item_header_t* get_menu_child(menu_item_header_t* menu, uint8_t i) { 10401878: e52db004 push {fp}; (str fp, [sp, #-4]!) 1040187c: e28db000 add fp, sp, #0 10401880: e24dd00c sub sp, sp, #12 10401884: e50b0008 str r0, [fp, #-8] 10401888: e1a03001 mov r3, r1 1040188c: e54b3009 strb r3, [fp, #-9] return (menu_item_header_t *)((uint8_t *)(menu) + *((uint16_t *)((uint8_t *)(menu) + sizeof(menu_item_header_t) + 2*(i)))); 10401890: e51b2008 ldr r2, [fp, #-8] 10401894: e55b3009 ldrb r3, [fp, #-9] 10401898: e2833001 add r3, r3, #1 1040189c: e1a03083 lsl r3, r3, #1 104018a0: e0823003 add r3, r2, r3 104018a4: e1d330b0 ldrh r3, [r3] <--- выполнение этой инструкции приводит к возникновению data abort exception 104018a8: e51b2008 ldr r2, [fp, #-8] 104018ac: e0823003 add r3, r2, r3 } 104018b0: e1a00003 mov r0, r3 104018b4: e28bd000 add sp, fp, #0 104018b8: e8bd0800 pop {fp} 104018bc: e12fff1e bx lr Я поставил брикпойнт на эту инструкцию. В регистре R3 на этот момент находится вполне валидный адрес из области flash. Просматриваю память по этому адресу, все шикарно читается, значение показывает то самое, которое и должно быть там (это значение я узнал, выполнив до этого код в RAM'е). Ну что делать ? Наверно, надо как-то вмешаться, возможно я сброшу какой-нить там кеш или конвейр комманд своим действием. Беру и меняю адрес в R3 на другой произвольно взятый из области flash. Делаю шаг, все равно вываливается, ну и ладно, чуда не произошло. Начинаю все сначала, и на этот раз меняю его на адрес из RAM. Вуаля, инструкция выполняется успешно ! Но мне то надо, чтобы код выполнялся так, как он написан. И пришлось мне оказать помощь процу, взяв выполнение инструкции "ldrh r3, [r3]" на себя, раз уж он не справляется, благо это меня не сильно обременило, потому как эта функция всего два раза вызывается. Итак, что я сделал. Проц останавливается про брикпоинту на этой инструкции. Я ручками беру адрес из R3, по этому адресу из памяти запрашиваю значение, запихиваю это значение в R3, в регистр PC запихиваю значение 0x104018a8 (перепрыгиваю через злосчастную инструкцию), говорю отладчику продолжить выполнять код дальше. Остановка происходит на втором вызове, я повторяю те же действия. В результате код выполняется до конца, на дисплее тот же результат, какой был при выполнении из RAM. Какие есть соображения по этому поводу ? P.S. За startup-код и линкер-скрипты ручаюсь. P.S.2. Я портировал код на IAR, и то же самое повторилось в этой же функции, но уже при выполнении из RAM.
Сообщение отредактировал artymen - Jan 10 2011, 07:32
--------------------
"Сознание своего несовершенства приближает к совершенству" Гёте
|
|
|
|
|
 |
Ответов
|
Jan 11 2011, 05:07
|

Участник

Группа: Участник
Сообщений: 66
Регистрация: 6-11-09
Из: г. Омск
Пользователь №: 53 464

|
Нет, не должен ! Вот хотя бы одна объективная причина (а их немало в эмбеддед кодинге, я думаю). Памяти в МК мало, поэтому я напрямую работаю с файлом шрифта, загруженным во флеш при программировании. А все внутренние структуры шрифта упакованы, а таблицы 8битные нечетного размера и т.д., то есть выравнивания никакого и в помине нету. Я пыхтел, разрабатывая свой собственный ультракомпактный формат шрифта, чтобы запихать его в мизерную память. И что в итоге получилось ? Капризный компилятор, видите ли, забил на проверку выравнивания. Ему, видите ли, вломы было разбить 16-битный доступ на два 8-битных. И теперь я должен переделывать формат файла, выравнивая данные в нем, то есть переделывать и усложнять код генератора шрифта, да еще и размер файла увеличивать ! И все для того, чтобы программа заработала конкретно на LPC2888. А, к примеру, на LPC2106 она уже будет не так работать. Согласитесь, это бред. Разработчики gcc, я думаю, согласились, и предусмотрели это, введя опции -m(no-)short-load-bytes, однако позже концепция была переделана в -m(no-)alignment-traps. Но мне несказанно повезло с текущей сборкой Yagarto. Версия gcc как раз пришлась ровно на этот перелом. В ней нету ни первой (уже устаревшей) опции, и новой (еще не появившейся) опции  UPDATE: Похоже ни той, ни другой опции больше вообще нету и не будет. Замечательно, что тут еще сказать.
Сообщение отредактировал artymen - Jan 11 2011, 05:24
--------------------
"Сознание своего несовершенства приближает к совершенству" Гёте
|
|
|
|
|
Jan 11 2011, 06:44
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(artymen @ Jan 11 2011, 11:07)  Нет, не должен ! Вот хотя бы одна объективная причина (а их немало в эмбеддед кодинге, я думаю). Памяти в МК мало, поэтому я напрямую работаю с файлом шрифта, загруженным во флеш при программировании. А все внутренние структуры шрифта упакованы, а таблицы 8битные нечетного размера и т.д., то есть выравнивания никакого и в помине нету. Я пыхтел, разрабатывая свой собственный ультракомпактный формат шрифта, чтобы запихать его в мизерную память. И что в итоге получилось ? ... А вот с пакованными структурами вообще надо быть очень осторожным. Компилятор генерит специальный код для доступа к полям таких структур, обращааясь к ним побайтно (к стати тут интересный момент, пакуешь структуры, чтобы сэкономить память, но из-за специфической кодогенерации объём всё равно растёт). И стоит только где-нибудь в сишном коде свалиться к обращениям по нетипизированным указателям к этим полям дата аборты полезут, как клопы из-зо всех щелей. Поэтому программист на С ОБЯЗАН отслеживать все подобные моменты в своём коде. НЕ ВЫКРУЧИВАТЬ РУКИ компилятору преобразованием типов и адресной арифметикой при работе с пакованными типами и уж точно потом не жаловаться на кривизну компилятора, если не соблюдает этих элементарных правил. Всё вышеописанное справедливо для GCC, IAR а также ARM7, CortexM3, AVR32. То что на собственной шкуре испытал. З.Ы. К стати когда то над моим постом, о том что внутри memcpy происходит дата аборт, достопочтимые гуру просто надругались. Мы докопали тему и нашли когда именно в gсс могут пойти дата аборты из memcpy. Без опции no-builtin-memcpy компимлятор не вставлял свою функцию memcpy, а каждый раз генерировал новый код, где если нет явных указаний на пакованность типов, может возникать обращение по невыровненным адресам. Цитата(artymen @ Jan 11 2011, 12:20)  Просто я всего-навсего говорю о том, что компилятору следует не только предупреждать, но и проявлять инициативу, а именно разбить 16-битный доступ на два 8-битных. Собственно говоря компилятор так и делает когда необходимо, например при пакованных структурах. А если структура обыкновенная, то компилятор СПРАВЕДЛИВО считает, что всё находится по выровненным адресам и делает чтение\запись с максимальной возможной разрядностью. И вообще баги надо начинать искать со своего кода, а не огульно обвинять компилятор в том что программа не работает.  То что код работал из RAM, судя по всему простая случайность.
|
|
|
|
Сообщений в этой теме
artymen LPC2888, Data Abort exception Jan 10 2011, 07:27 Chameleon Выравнивание? Чему равен младший бит регистра R3 в... Jan 10 2011, 09:52 artymen Ну точно ! Сейчас прочитал, что архитектура тр... Jan 11 2011, 01:27 aaarrr Цитата(artymen @ Jan 11 2011, 07:27) Он д... Jan 11 2011, 02:00 artymen А чей же ? Неужто это я должен заботиться об архит... Jan 11 2011, 02:45 aaarrr Цитата(artymen @ Jan 11 2011, 08:45) Неуж... Jan 11 2011, 03:30 IgorKossak artymen, не кипятитесь. Послушайте ещё раз и внима... Jan 11 2011, 05:40 artymen Я прекрасно это понимаю. И, как я сейчас выяснил, ... Jan 11 2011, 06:20 IgorKossak QUOTE (artymen @ Jan 11 2011, 11:20) ... ... Jan 11 2011, 06:34  sonycman Цитата(IgorKossak @ Jan 11 2011, 12:34) Т... Jan 11 2011, 07:22 artymen Эх... Значит проблема у меня на уровне системного ... Jan 11 2011, 07:40 GetSmart Цитата(artymen @ Jan 11 2011, 15:40) Хоро... Jan 11 2011, 08:04 sergeeff Цитата(artymen @ Jan 11 2011, 14:40) Ошиб... Jan 11 2011, 08:17 xelax Цитата(artymen @ Jan 11 2011, 13:40) Там ... Jan 11 2011, 11:24 artymen Вот я уже и начал менять. Походу ничего другого мн... Jan 11 2011, 08:28 GetSmart Цитата(artymen @ Jan 11 2011, 16:28) А по... Jan 11 2011, 08:33 artymen Ну тогда я не понимаю, что вы имеете в виду под ... Jan 11 2011, 10:15 GetSmart Цитата(artymen @ Jan 11 2011, 18:15) Ну т... Jan 11 2011, 15:06  xelax Цитата(GetSmart @ Jan 11 2011, 21:06) А е... Jan 12 2011, 04:29 artymen Хм, классно. Выходит, IAR рулит И все же во мне т... Jan 12 2011, 00:54 artymen Ну елки палки ! Выровнял я свои данные. Теперь... Jan 12 2011, 05:03 GetSmart Цитата(artymen @ Jan 12 2011, 13:03) Ну е... Jan 12 2011, 05:41  sergeeff Цитата(GetSmart @ Jan 12 2011, 12:41) В у... Jan 12 2011, 06:43   xelax Цитата(sergeeff @ Jan 12 2011, 12:43) Вов... Jan 12 2011, 09:34 artymen Все, победил ! Всем спасибо. Теперь буду зн... Jan 12 2011, 06:07
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|