реклама на сайте
подробности

 
 
> STM32F1xx и Fault, Не получается отловить из какого места
XGoblinX
сообщение Aug 29 2011, 11:23
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 13-12-10
Пользователь №: 61 586



Всем здравствуйте!

Есть программка на иаре. Загружаю под SWD в STM32F103.
int main( void )
{
memset(0x20000000, 0, 0xffffff);
}

Во время выполнения естественно падаю в 0xC.
Но после этого я не могу посмотреть откуда именно (с какой инструкции) он туда свалился.
Хочу для себя понять на будущее, как ловить такие вещи.
Спасибо заранее.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 13)
SII
сообщение Aug 29 2011, 11:33
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 549
Регистрация: 13-07-10
Из: Солнечногорск-7
Пользователь №: 58 414



А где пытаетесь смотреть? Адрес возврата (из которого можно восстановить адрес сбоя) при прерывании автоматически сохраняется в стеке прерванной программы.
Go to the top of the page
 
+Quote Post
XGoblinX
сообщение Aug 29 2011, 11:38
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 13-12-10
Пользователь №: 61 586



Цитата(SII @ Aug 29 2011, 11:33) *
А где пытаетесь смотреть? Адрес возврата (из которого можно восстановить адрес сбоя) при прерывании автоматически сохраняется в стеке прерванной программы.

секунду

Сообщение отредактировал XGoblinX - Aug 29 2011, 11:39
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Aug 29 2011, 11:49
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(XGoblinX @ Aug 29 2011, 13:23) *
Всем здравствуйте!

Есть программка на иаре. Загружаю под SWD в STM32F103.
int main( void )
{
memset(0x20000000, 0, 0xffffff);
}

Во время выполнения естественно падаю в 0xC.
Но после этого я не могу посмотреть откуда именно (с какой инструкции) он туда свалился.
Хочу для себя понять на будущее, как ловить такие вещи.
Спасибо заранее.


А куда это Вы разогнались с более чем 16мио байт (0xffffff) в контроллере с не более чем 64kB RAM? Пишите в непонятно куда, вылетаете в защиту.
Go to the top of the page
 
+Quote Post
XGoblinX
сообщение Aug 29 2011, 12:17
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 13-12-10
Пользователь №: 61 586



Цитата(KnightIgor @ Aug 29 2011, 11:49) *
А куда это Вы разогнались с более чем 16мио байт (0xffffff) в контроллере с не более чем 64kB RAM? Пишите в непонятно куда, вылетаете в защиту.

Это специально сделано. Чтобы выйти за область рамы.


Цитата(SII @ Aug 29 2011, 11:33) *
А где пытаетесь смотреть? Адрес возврата (из которого можно восстановить адрес сбоя) при прерывании автоматически сохраняется в стеке прерванной программы.

Не смог найти. Я смотрю стек указывает на 0x200011B0.
По этому адресу хранится 0x20fffffC.
Это явно не то.
Если имелось в виду регистр связи, то тоже не то 0xFFFFFFF9

Сообщение отредактировал XGoblinX - Aug 29 2011, 12:18
Go to the top of the page
 
+Quote Post
SII
сообщение Aug 29 2011, 13:05
Сообщение #6


Знающий
****

Группа: Свой
Сообщений: 549
Регистрация: 13-07-10
Из: Солнечногорск-7
Пользователь №: 58 414



Почитайте внимательно описание архитектуры на предмет обработки прерываний (можно и здесь глянуть). В LR находится EXC_RETURN, а отнюдь не адрес возврата. А в вершине стека _прерванного_ процесса (а не обработчика прерывания -- они могут использовать разные стеки, а могут и один) сохраняется восемь регистров, а не только адрес возврата.

В общем, учите матчасть, без неё делать нечего: это не ПК, где всю такую работу ОС сделает.
Go to the top of the page
 
+Quote Post
Aleksandr Barano...
сообщение Aug 29 2011, 18:20
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 169
Регистрация: 31-08-05
Из: New York
Пользователь №: 8 118



Если я правильно понял вопрос, есть известный способ, описанный в книжке "The Definitive Guide to the ARM Cortex-M3":
Код
void HardFaultException( void )
{
    unsigned int contr_reg;

    contr_reg = __get_CONTROL();
    if(contr_reg&2)
    {
        asm("MRS R0, PSP");
    }
    else{
        asm("MRS R0, MSP");
    }
    asm("B    (Hard_fault_handler_c)");                    //top of stack is in R0. It is passed to C-function.

  while (1)
  {

  }
}


С- handler:

Код
void Hard_fault_handler_c(unsigned long* hard_fault_args)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;

stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);

stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);

printf ("[Hard fault handler]\n");
printf ("R0 = %x\n", stacked_r0);
printf ("R1 = %x\n", stacked_r1);
printf ("R2 = %x\n", stacked_r2);
printf ("R3 = %x\n", stacked_r3);
printf ("R12 = %x\n", stacked_r12);
printf ("LR = %x\n", stacked_lr);
printf ("PC = %x\n", stacked_pc);
printf ("PSR = %x\n", stacked_psr);
  
}


--------------------
ASB
Go to the top of the page
 
+Quote Post
XGoblinX
сообщение Aug 30 2011, 05:03
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 13-12-10
Пользователь №: 61 586



Цитата(Aleksandr Baranov @ Aug 29 2011, 18:20) *
...

Спасибо огромное! Работает метод!

Всем спасибо за ответы!
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jun 14 2012, 10:02
Сообщение #9


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Ребята, стал попадать в обработчик хард-фолта с таким вот состоянием (получено вышеуказанным способ).

Цитата
R0 : 0x8005a80
R1 : 0x000008
R2 : 0x40011000
R3 : 0x000004
R12 : 0x000002
LR : 0x8005671
PC : 0x800567a
PSR : 0x81005000
BFAR: 0xe000ed38
CFSR: 0x000400
HFSR: 0x40000000
DFSR: 0x000001
AFSR: 00000000


Как это раскрутить чтобы понять причину фолта. С чего начать?
Я правильно понимаю что в РС содержится указатель на адрес кода, который выполнялся в момент фолта?


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
andrewlekar
сообщение Jun 14 2012, 11:13
Сообщение #10


Знающий
****

Группа: Участник
Сообщений: 837
Регистрация: 8-02-07
Пользователь №: 25 163



По идее да. Смотрите в map файле, что за функция находится по этому адресу (должна быть чуть раньше указанного адреса).
Go to the top of the page
 
+Quote Post
brag
сообщение Jun 14 2012, 11:46
Сообщение #11


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



Цитата
Ребята стал попадать в обработчик хард-фолта с таким вот состоянием.

В LR у Вас явно не то, что должно быть, обработчик видимо у Вас кривой.

Адрес возврата и другую информацию отлавливаю так. верный вариант по задумке разработчика armv7m
Код
eHardFault
    mov r0,#0
    mov r1,lr
    mov r2,sp; always MSP in exception handler
    mrs r3,PSP
    bl printfault
    b .

void printfault(U32 flt,U32 lr,U32 *msp,U32 *psp){
    U32 retaddr;

    // analyze EXC_RETURN
    if((lr&0x0F)==1||(lr&0x0F)==9){
        retaddr=msp[6];
    }else if((lr&0x0F)==0x0D){
        retaddr=psp[6];
    }else ra=0xFFFFFFFF;

   // print
    switch(flt){
    case ...:
              }
}

В месте с адресом возврата нужно печатать CFSR, BFAR и HFSR.

Что касается отлова места, от куда растут ноги... Во первых надо внимательно прочитать описание на вышеприведенные регистры CFSR, BFAR, HFSR - информации про fault там не мало.
Обычно, если занесло не туда(на пример при переполнении буффера в стеке), то исключениия могут быть следующие
1. UsageFault - попали на существующую память, но дело дошло до некорректной инструкции.
2. BusFault - попали на недоступную для выполнения кода память
В обеих случаях адрес возврата может быть не тот,что нам интересно. Для начала нужно это проверить, посмотрев в дизассемблер вашего реального КОДА - если там этого адреса нету - значит он не тот. В таком случаи дальше уже стандартного метода нету.
Если баг вылазит сразу, то и поймать место легко - стевим бряк на выходы с функций и смотрим куда попадает.
Если не очень сразу - в дебаггерах есть трассировка вызовов и переходов. Натрейсить многомегабайтный лог и потом искать в обратном порядке последнюю запланированную инструкцию(так, которая есть в вашем КОДЕ).

Если баг вылазит очень редко (на пример, раз в неделю) и весь код вы уже перечесали на предмет переполнений и indirect-вызовов - тут надо хорошенько напрячь мозги и прокурить документацию.

У меня была ситуация с PendSV, SVC обработчиками.
Код
ePendSV
; push LR(EXC_RETURN),R11-R4 to PSP, save PSP
    mrs r0,PSP
    stmdb r0!,{r4-r11,lr}
    
    ...save context....
              ... get new context....
    
; restore LR(EXC_RETURN),R11-R4 from new PSP, set new PSP, return
    ldmia r0!,{r4-r11,lr}
    msr PSP,r0
    bx lr

void eSVCall(void){
    U32 a0,a1,a2,a3,svc,*psp;
    
    psp=(U32*)__get_PSP();
    a0=psp[0];a1=psp[1];a2=psp[2];a3=psp[3]; // get arguments from user stack
    svc=psp[4]; // get service call ID from user stack
    
              a=service(svc,a0,a1,a2,a3);
    
    psp[0]=a0; // save return value (r0) to user stack
}


используем это дело так:
Код
         mov r0,...; arg1
         mov r1,...; arg2
         mov r12,#1; SVC ID
         svc 0
; now r0 has return value

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

Вроде все гуд, НО!
Прочитав фразу "Because SVCall and PendSV have the same execution priority they cannot preempt each other" из refмануала на armv7m так и сделал - назначил обеим обработчикам одинаковый приоритет и был уверен, что все сделал правильно. Хотя в моем случаи это было неверно.

Дело в том, что в armv7m есть такая вероятность, что PendSV и SVCall одновременно могут висеть в ожидании, а если они имеют одинаковый приоритет, то порядок их выполнения неопределен, тк там есть механизмы Late arrival preemption, Tail-chaining и конвеер. Подробно можно почитать в ARM DDI0403D

Теперь, если исключение PendSV наступит в момент, когда иснтрукция svc уже в конвеере, но пока само исключение SVCall еще не сгенерировано, мы попадаем в обработчик PendSV, которий в итоге перезапишет значение PSP и выйдет. Далее по tail-chain выполнится уже SVCall, который будет уже обращатся к чужому стеку... Баг вылазит довольно редко, с интервалом от нескольких часов, до недели а то и больше. И вылазит он не в виде fault-a, а в виде вызова исключения(зачастую успешным) с неправильными аргументами или значением возврата.программа вроде работает, но не так, как надо. я очень долго не мог этот баг выудить... Недели копания в дебагере, чтения документации, анализа кода... И все практически напрасно. Помогло только чтение документации + симуляция поведения проца в голове..
Зато решение оказалось просто смешное - поднять приоритет SVCall sm.gif Это даст гарантию, что SVCall всегда будет выполнено до PendSV. и глюка уже не будет.

Заставить PendSV и SVCall одновременно висеть в Pending state легко: Запускаем таймер, частоту задть по максимуму, чтобы вероятность поднять. в таймере делаем PENDSVSET. Теперь если прерывание таймера вытеснит SVCall до старта самого обработчика SVCall(тоесть SVCall все еще в pending-state), выполнится обработчик таймера, установит PendSV тоже в pending-state. Все, при выходе с обработчика таймера при равном приоритете PendSV и SVCall может выполнится любая из них,порядок неопределен.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jun 14 2012, 12:04
Сообщение #12


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Огромное спасибо за столь исчерпывающие рекомендации!
Причиной фолта была бага в коде (приведение const* к не_const*).

А с кривостью обработчика фолта хотелось бы разобраться.
Выкладываю свой вариант заточенный под keil. Комментарии приветствуются!
CODE

#pragma pack(push, 4)
typedef struct
{
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t psr;
} stacked_regs_t;
#pragma pack(pop)

//=============================================================================
// This is called from the HardFault_HandlerAsm with a pointer the Fault stack as the parameter.
// We can then read the values from the stack and place them into local variables for ease of reading.
//=============================================================================
void hard_fault_debug_print(stacked_regs_t* stack) // prints 8 regs saved on the stack and so on
{
dprintf("\n\nHard fault:\n");
dprintf("R0 : %#08lx\n", stack->r0);
dprintf("R1 : %#08lx\n", stack->r1);
dprintf("R2 : %#08lx\n", stack->r2);
dprintf("R3 : %#08lx\n", stack->r3);
dprintf("R12 : %#08lx\n", stack->r12);
dprintf("LR : %#08lx\n", stack->lr);
dprintf("PC : %#08lx\n", stack->pc);
dprintf("PSR : %#08lx\n", stack->psr);
dprintf("BFAR: %#08lx\n", *((volatile uint32_t*)0xE000ED38));
dprintf("CFSR: %#08lx\n", *((volatile uint32_t*)0xE000ED28));
dprintf("HFSR: %#08lx\n", *((volatile uint32_t*)0xE000ED2C));
dprintf("DFSR: %#08lx\n", *((volatile uint32_t*)0xE000ED30));
dprintf("AFSR: %#08lx\n", *((volatile uint32_t*)0xE000ED3C));
}



//=============================================================================
// Alternative Hard Fault handler to help debug the reason for a fault.
// To use, edit the vector table to reference this function in the HardFault vector
// This code is suitable for Cortex-M3 and Cortex-M0 cores
//=============================================================================
__asm void HardFault_Handler(void) // __irq __attribute__((naked))
{
EXPORT HardFault_Handler

IMPORT hard_fault_debug_print

movs r0, #(1<<2)
mov r1, lr
tst r0, r1
beq do_msp
mrs r0, psp
B (hard_fault_debug_print)
B .
do_msp
mrs r0, msp
B (hard_fault_debug_print)
B .
}


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
brag
сообщение Jun 14 2012, 12:10
Сообщение #13


Профессионал
*****

Группа: Свой
Сообщений: 1 047
Регистрация: 2-12-06
Из: Kyiv, Ukraine
Пользователь №: 23 046



У Вас по ходу LR выводился из стека, а я думал то LR из исключения(который EXC_RETURN).
LR из стека, к стати тоже можно использовать для нахождения адресса! Если адресс в этом LR похож на правду(а в PC не похожsm.gif - загляните в него и поставьте туда бряк, а далее пошаговое выполнение.
Так что все верно у Вас с обработчиком.

Ну и можно не поленится, расписать немного сами эти BFAR,CFSR,HFSR регистры, чтобы сразу выводило название ошибки, не надо будет постоянно бегать в документацию.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jun 14 2012, 17:17
Сообщение #14


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Спасибо! Отличная мысль!


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 20:21
Рейтинг@Mail.ru


Страница сгенерированна за 0.01502 секунд с 7
ELECTRONIX ©2004-2016