IAR EW ARM: программа вылетает в Abort_Handler |
![]() |
Добавил(а) microsin |
Обычно Abort Handler срабатывает, когда произошло некорректное обращение к данным (чтение или запись) - программа попыталась что-то сделать с данными по адресу, который не существует. При этом срабатывает исключение Data Abort, которое заставляет процессор ARM перейти по фиксированному адресу 0x00000010, где, в свою очередь, стоит безусловный переход в обработчик Abort_Handler. Например, по адресу 0x00000010 может быть команда LDR PC, [PC, #+20], загружающая в счетчик команд адрес из таблицы векторов переходов по исключению (адрес находится по смещению +20 относительно текущего счетчика команд. Назовем этот адрес меткой Abort Handler:). По этому месту компилятор ставит тупое зацикливание: При срабатывании Abort Handler можно посмотреть, откуда это произошло (какой код вызвал ошибку). Для этого нужно в отладчике остановить выполнение программы (курсор текущего местоположения окна Disassembler должен показывать на Abort_Handler), и посмотреть содержимое регистра LR (Link Register - в нем сохраняется содержимое программного счетчика при вызове подпрограмм) - в нем будет находится адрес, где сработало исключение Data Abort. Несмотря на то, что есть такое удобное средство, чтобы выявить источник ошибки, иногда разобраться в ошибке бывает нелегко, особенно если она возникает случайно или в том месте, где работает чужой код. У меня такое произошло в обработчике прерывания, обслуживающее прерывание по изменению уровня на ножках ввода/вывода. Этот обработчик я взял из примеров IAR, так как там было очень удобно сделана обработка изменения уровней на отдельных ножках - для каждой ножки можно назначить свой обработчик. Вот код, который у меня вызывал Data Abort (pio_it.c): // Check PIO controller status // Check all sources // Source if configured on PIOA pSources[i].handler(pSources[i].pPin); Ошибка происходила случайно, и локализовать её обычными средствами не удавалось. Причина была в переполнении массива static InterruptSource pSources[MAX_INTERRUPT_SOURCES] (pio_it.c). У меня при задании нового источника прерывания количество прерываний numSources превышало MAX_INTERRUPT_SOURCES (стало 8, а MAX_INTERRUPT_SOURCES было равно 7), и происходило обращение к переменной вне массива (if (pSources[i].pPin->id == id)), что и вызывало Data Abort. Макрос ASSERT, который проверял переполнение массива при инициализации, я отключил, поэтому процессор не выдавал ошибки переполнения массива. Увеличил константу MAX_INTERRUPT_SOURCES до 8, и все встало на свои места. [Общая схема - как ловить ошибки при зависании Abort_Handler] 1. В отладчике нужно посмотреть содержимое LR (адрес) - оттуда произошло зависание. [Ссылки] 1. Как повесить ARM AT91SAM7X256 |