Прежде всего позлорадствую. Я не удивлен подобного рода проблемой, потому как мне и моим коллегам эта модель сразу дико не понравилась. Она особенная в семействе 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