Как отладить неожиданные перезагрузки в устройстве STM32? - PullRequest
11 голосов
/ 10 января 2012

Я делаю некоторые разработки на C с чипом STM32F107, и в какой-то момент устройство начало сбрасываться, когда я вызываю определенную функцию. У меня нет отладчика, и моя отладка - это простой текст через последовательный порт.

Я использовал некоторые другие микроконтроллеры, в которых мне удалось получить доступ к регистру, чтобы увидеть причину сброса, но я не могу найти эквивалент для этого устройства. Я знаю об аппаратных исключениях Cortex-M3, но я не знаю, запускается ли одно из них, так как я не могу отправить текст через usart, когда я нахожусь внутри этих обработчиков (возможно, потому что мой TX функции используют прерывания?).

Итак, я решил спросить людей с большим опытом, чем я, в этом устройстве: что обычно делается для отладки подобных ситуаций?

EDIT

Один из разработчиков активировал сторожевой таймер WWDG, и он сбрасывал аппаратное обеспечение, прежде чем я смог получить информацию от обработчиков ошибок. Это была тяжелая ошибка из-за вызова функции по указателю, указывающему на неправильное место. Тем не менее, я буду держать этот вопрос в надежде, что кто-то предоставит более подробную информацию (или материал о нем) для указания на код C из регистров, сохраненных, скажем, в Hard Fault (идея @dwelch).

Ответы [ 6 ]

11 голосов
/ 10 января 2012

Cortex M3 имеет отличные функции обработки ошибок, которые сделают вашу жизнь проще. При возникновении сбоя он автоматически объединяет несколько регистров, таких как ПК и LR, а регистры состояния сбоя сообщают вам такие вещи, как адрес сбоя шины и т. Д.

Вы должны внедрить хороший обработчик ошибок (например, жесткий обработчик ошибок здесь: http://blog.frankvh.com/2011/12/07/cortex-m3-m4-hard-fault-handler/) для распечатки составленных регистров и отладки регистров состояния ошибок.

Вы должны использовать UART для печати, просто напишите свою собственную простую пользовательскую версию printf для использования из обработчика ошибок, который не зависит от прерываний. Просто запишите байты напрямую в регистр данных Uart Tx и выполните опрос для завершения байтов.

3 голосов
/ 17 февраля 2015

Помимо того, что было упомянуто об обработчиках прерываний для отладки, некоторые ST micro также имеют регистр сброса источника, который вы можете прочитать при включении питания (то есть после сброса). Для семейства M кортекса (m0 / m3 / m4) регистр RCC_CSR. http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031020.pdf

К сожалению, вы не сможете узнать, была ли специфика, например, серьезная ошибка, но она сообщит вам, сработал ли сторожевой таймер (оконный или независимый).

1 голос
/ 10 января 2012

Когда вы говорите «сброс», я думаю, что вы попадаете в вектор сброса, а не в одно из прерываний или обработчиков. Вы говорите, что он действительно сбрасывает чип и запускает ваше программное обеспечение заново, или вы говорите, что он где-то зависает? или у вас все таблицы векторов указывают на вектор сброса?

Как действовать дальше, зависит от того, что вы действительно видите, вам нужно быть более ясным или конкретным, или, возможно, вам нужна помощь в выяснении этого.

Обычно я отображаю неиспользуемые векторы в простую строку кода, которая разветвляется на себя. Позже я могу переназначить некоторые из них в реальный код.

cortex-m очень хорош тем, что вы можете указать на C-код. Если вы думаете, что получаете исключение, пусть оно указывает на подпрограмму, которая захватывает что-то, что помогает вам выяснить, в каком режиме вы находитесь, регистр ссылок может содержать эту информацию или где-то в csr, распечатываете это и идете в бесконечный цикл , Заполните неиспользуемые части таблицы векторов адресом этой универсальной функции отладки.

Оттуда вам нужно выяснить, почему вы включаете это исключение, это может быть что-то вроде неприсоединенного доступа, например. Возможно, вы сгенерировали прерывание при попытке инициализировать устройство, прежде чем полностью настроить обработчик, который знает.

измените свой вопрос, добавив больше ответов или информации, пока вы работаете с этим.

1 голос
/ 10 января 2012

Учитывая, что у вас нет отладчика, я бы посоветовал вам найти какое-нибудь периферийное устройство на микроконтроллере, чтобы помочь вам.Возможно, у вас есть светодиод, который вы можете переключить, или простой вывод GPIO, который не используется, который вы можете подключить к осциллографу.Если вы переключаете вывод GPIO достаточно медленно (не быстрее, чем 1 Гц и, возможно, медленнее, в зависимости от измерителя), вы можете использовать вольтметр вместо прицела.Поместите код, чтобы переключать светодиод или вывод GPIO в каждом из обработчиков исключений по одному, пока вы не отследите его.Если у вас есть более одного вывода GPIO, вы можете ускорить процесс.Вы также можете написать оболочку для конкретной функции, которая вызывает сброс.Функция-обертка будет отправлять список прерываний, которые активируются непосредственно перед выполнением функции прерывания.Таким образом, вам не нужно тратить время на тестирование тех, которые не включены.

Одним из преимуществ выводов GPIO в этом случае является то, что они не требуют прерывания.Лучше держаться подальше от всего, что требует прерывания (например, вашего USART в этом случае).Если сброс вызван исключением с более высоким приоритетом, ваш код отладки никогда не будет выполнен.

Также часто причиной сброса является неинициализированный указатель.Если указатель функции установлен в ноль, выполнение будет очень похоже на сброс.В этом случае код инициализации USART, вероятно, выполняется до того, как USART может полностью передать байт, что сделает USART бесполезным в качестве средства отладки в этом случае.

0 голосов
/ 09 апреля 2018

Вы можете использовать приведенный ниже код для отладки.

void HardFault_Handler(void)
{
    __asm volatile
       (
           " tst lr, #4                                                \n"
           " ite eq                                                    \n"
           " mrseq r0, msp                                             \n"
           " mrsne r0, psp                                             \n"
           " ldr r1, [r0, #24]                                         \n"
           " ldr r2, handler2_address_const                            \n"
           " bx r2                                                     \n"
           " handler2_address_const: .word prvGetRegistersFromStack    \n"
       );

  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

Также добавьте это.

void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
{
    /* These are volatile to try and prevent the compiler/linker optimising them
    away as the variables never actually get used.  If the debugger won't show the
    values of the variables, make them global my moving their declaration outside
    of this function. */
    volatile uint32_t r0;
    volatile uint32_t r1;
    volatile uint32_t r2;
    volatile uint32_t r3;
    volatile uint32_t r12;
    volatile uint32_t lr; /* Link register. */
    volatile uint32_t pc; /* Program counter. */
    volatile uint32_t psr;/* Program status register. */

    r0 = pulFaultStackAddress[ 0 ];
    r1 = pulFaultStackAddress[ 1 ];
    r2 = pulFaultStackAddress[ 2 ];
    r3 = pulFaultStackAddress[ 3 ];

    r12 = pulFaultStackAddress[ 4 ];
    lr = pulFaultStackAddress[ 5 ];
    pc = pulFaultStackAddress[ 6 ];
    psr = pulFaultStackAddress[ 7 ];

    /* When the following line is hit, the variables contain the register values. */
    for( ;; );
}

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

0 голосов
/ 07 февраля 2012

«Правильно» делать, к сожалению, непрактично с STM32.Это было бы для того, чтобы поместить большой обработчик исключений, который знает исходный код и может развернуть стек и дать вам полный стек вызовов и номер строки, которые вызывают ошибку.Это потребует добавления всей отладочной информации из вашего приложения во флэш-память STM32, и это не практично.

Существуют способы обмануть вашу IDE, чтобы иногда дать вам стек вызовов.Я бы дал подробности, но я забыл записать их, поэтому я забыл.Я думаю, что нужно вручную изменить указатель стека из одного теневого регистра в другой.

Обычно я ставлю точку останова на вектор исключений жесткого сбоя, а затем смотрю на все регистры, когда точка остановахиты.Считайте их уликами от убийства, совершенного с помощью пластиковой взрывчатки.Значения регистров дадут вам идеи.Значения регистра, начинающиеся с 0x20000000, являются адресами ОЗУ.Значения регистра, начинающиеся с 0x08000000, являются адресами Flash.Откройте дизассемблер и введите эти адреса.Вероятно, он перейдет прямо к переменной или функции в этих местах памяти.Если это не поможет, посмотрите на указатель стека.Посмотрите на ячейки памяти на указатель стека и сделайте то же самое.Я всегда находил достаточно осколков, чтобы найти функцию, где происходило исключение.

...