Тут решил собирать разные методы завешивания процессора и/или его переход по прерываниям Abort, Data Abort, Prefetch Abort, Undefined Instruction и методы их устранения (если разобрался, как).
Самый частый способ завешивания программы - ошибки с указателями (неинициализированные, неправильно установленные указатели), или неправильная их интерпретация (например, имеется указатель на указатель, который был раньше обычным указателем, и не везде в программе исправлен код использования этого указателя). Другой самый частый глюк - выход за пределы массива. Такие тупые ошибки я тут не рассматриваю, поскольку они тривиальны и легко выявляются (если, конечно, программа не слишком запутанная).
Очень неприятные ошибки - те, которые трудно исправить (особенно если код чужой). Например, функция библиотеки ведет себя не так, как ожидалось, либо скомпилированный код ведет себя не так, как хотелось бы. Обычно это происходит не потому, что ошибка в библиотеке или компиляторе, а просто недостаточно знаний, как их правильно использовать (хотя бывают и исключения из этого правила). Тогда помогает поиск документации и/или тщательная её разборка. Иногда приходится экспериментировать с разными вариантами кода одного и того же алгоритма.
[Способ 1]
Тут реализована казалось бы невинная идея скопировать в буфер dspdata по нужному адресу 16-битное слово (младшая половина от 32-битного bytecnt): u8* dspdata; u32 bytecnt;
bytecnt = 135; dspdata = malloc(bytecnt); dspdata[0] = 0xA5; dspdata[1] = 0xA5; dspdata[2] = 1; //тут собственно, должно происходить копирование, а получается зависание. *(u16*)&(dspdata[3]) = (u16)(bytecnt-2);
Последняя команда, на которой ARM виснет, компилируется в следующий код: 0010D048 E1B00008 MOVS R0, R8 ;загрузим значение bytecnt, равное 135 (0x00000087), в регистр R0 0010D04C E2500002 SUBS R0, R0, #0x2 ;вычтем из R0 число 2, теперь там будет 133 (0x00000085). 0010D050 E1C700B3 STRH R0, [R7, #+3] ;запишем младшую половину R0 по адресу R7+3 (R7 у нас указывает на буфер dspdata).
На последней команде (STRH) микроконтроллер вешается (управление попадает на Abort_Handler:), причем непонятно, почему. Решить проблему удалось в обход, используя функцию memcpy.
[Способ 2]
if (crc == *(u16*)(dst->data)) { .. }
Эта конструкция может вызвать Data Abort, если адрес dst->data нечетный, например равен 0x0020D3B1. Вот в такой ассемблерный код компилируется этот оператор if, исключение Data Abort срабатывает при выполнении 3-ей строки (адрес 0x00126370): 00126368 E59F00F0 LDR R0, [PC, #+240] 0012636C E1D000B0 LDRH R0, [R0, #+0] 00126370 E1D611B1 LDRH R1, [R6, #+17] 00126374 E1500001 CMP R0, R1 00126378 1A000005 BNE ??fwupdate_routine_29
Обойти ситуацию удалось, делая побайтовую выборку u16: reccrc = dst->data[0] + (((u16)(dst->data[1]))<<8); if (crc == reccrc) { .. }
Другой пример похожей ошибки (произойдет зависание, если адрес pnt нечетный):
u8* pnt; *(u16*)pnt = tempCRC;
[Ссылки]
1. IAR EW ARM: программа вылетает в Abort_Handler. 2. IAR EW ARM: устранение ошибок компиляции. 3. IAR EW ARM: устранение ошибок с отображением регистров. 4. IAR EW ARM: применение #ifndef и #define для разрешения конфликтов включаемых файлов (#include). 5. IAR EW ARM: пути с $PROJ_DIR$ не работают, почему? |