Исключение HardFault (настраиваемое исключение приоритета для HardFault) - PullRequest
1 голос
/ 20 апреля 2019

содержимое стека Я написал простую процедуру прерывания ввода-вывода для проверки вывода ввода-вывода в кору ARM m4 (cm408F). Код ниже и очень простой и заполняет таблицу векторов (также включает в себя прагма слабые и другие вещи).

Я запускаю прерывание, устанавливая соответствующие биты в NVIC_ISER0 и NVIC_ISPR0. В момент возникновения прерывания процессор выдает мне следующее исключение при сбое и зацикливается на загрузочном ПЗУ L1.

Процессор превратил исключение настраиваемого приоритета в HardFault. Инструкция выполнена с недопустимым полем EPSR.T или EPSR.IT (CFSR.INVSTATE). Исключение произошло при ПК = 0xffffffff, LR = 0x0

В окне стека вызовов я вижу:

__iar_systems$$modulde + 0x1451

Может ли это помочь?

Я также добавил цикл while (1) для HardFault_Handler. Таким образом, если процессор фактически утверждает HardFault_Handler, он должен идти в этот бесконечный цикл, но он никогда не идет туда. Не имеет значения, какое прерывание активировано (через NVIC_ISER0 и NVIC_ISPR0), возникает та же проблема (при получении прерывания оно скачет и застревает в цикле в строке загрузочного ПЗУ L1: 1452!).

Я прикрепил снимок стека, как только прерывание поднято. Прежде чем поднять прерывание я изменился содержимое R12 и R0-R3 (0x1238 .... 0x1234), чтобы лучше реализовать их в стеке. Как я сказал когда прерывание поднято, программа никогда не возвращается, поэтому я приостановил его и посмотрел на стек (прикрепленная картинка). Кажется, что первый толчок в порядке; мы видим, что xPSR, ПК, LR, R12, R0-R3 все сложены правильно (FPU отключен). Но во втором толкании в стек ПК равен нулю (LR в порядке)! Я предполагаю, что это показывает проблему. ПК не должен быть нулевым. Почему он не возвращается из прерывания, нажав правильный адрес обратного адреса на ПК. Я думаю третий толчок в стек является результатом этой проблемы.

До прерывания: SP = 0x2005FFF0 После прерывания: SP = 0x2005FFA4

............................

// My code is very simple as follows.    
// main.c
#include <intrinsics.h>

int main()
{



  int k1=123; 
  k1=k1+2*k1;


  while(1)
  {
    k1=k1;
  }

  return 0;
}

// =========================================

// my_int_Routines.c

void PINT0_BLOCK_Int_Handler(void)
{
    while(1)
  {
     asm("nop");
  }

}

void PINT1_BLOCK_Int_Handler(void)
{
    while(1)
  {
    asm("nop");
  }

}

void PINT2_BLOCK_Int_Handler(void)
{
    while(1)
  {
        asm("nop");
  }

}

void PINT3_BLOCK_Int_Handler(void)
{
    while(1)
  {
    asm("nop");
  }

}

void PINT4_BLOCK_Int_Handler(void)
{
    while(1)
  {
    asm("nop");
  }

}

// =====================================

// my_startup.c
// This is ARM standard cstartup.c in IAR folder. I only added the relevant lines 
// (marked as Reza)

/**************************************************
 *
 * This file contains an interrupt vector for Cortex-M written in C.
 * The actual interrupt functions must be provided by the application developer.
 *
 * Copyright 2007-2017 IAR Systems AB.
 *
 * $Revision: 112610 $
 *
 **************************************************/

#pragma language=extended
#pragma segment="CSTACK"

extern void __iar_program_start( void );

extern void NMI_Handler( void );
extern void HardFault_Handler( void );
extern void MemManage_Handler( void );
extern void BusFault_Handler( void );
extern void UsageFault_Handler( void );
extern void SVC_Handler( void );
extern void DebugMon_Handler( void );
extern void PendSV_Handler( void );
extern void SysTick_Handler( void );

extern void   PINT0_BLOCK_Int_Handler(void);  //  18  Pin Interrupt Block  Reza
extern void   PINT1_BLOCK_Int_Handler(void);  //  19  Pin Interrupt Block  Reza
extern void   PINT2_BLOCK_Int_Handler(void);  //  20  Pin Interrupt Block  Reza
extern void   PINT3_BLOCK_Int_Handler(void);  //  21  Pin Interrupt Block  Reza
extern void   PINT4_BLOCK_Int_Handler(void);  //  22  Pin Interrupt Block  Reza

typedef void( *intfunc )( void );
typedef union { intfunc __fun; void * __ptr; } intvec_elem;

// The vector table is normally located at address 0.
// When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
// If you need to define interrupt service routines,
// make a copy of this file and include it in your project.
// The name "__vector_table" has special meaning for C-SPY, which
// is where to find the SP start value.
// If vector table is not located at address 0, the user has to initialize
// the  NVIC vector table register (VTOR) before using interrupts.


#pragma location = ".intvec"
const intvec_elem __vector_table[] =
{
  { .__ptr = __sfe( "CSTACK" ) },
  __iar_program_start,

  NMI_Handler,
  HardFault_Handler,
  MemManage_Handler,
  BusFault_Handler,
  UsageFault_Handler,
  0,
  0,
  0,
  0,
  SVC_Handler,
  DebugMon_Handler,
  0,
  PendSV_Handler,
  SysTick_Handler,
// *******  Reza (all zeros below)
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0,
  0, 
  PINT0_BLOCK_Int_Handler,  //  18   Pin Interrupt Block  Reza
  PINT1_BLOCK_Int_Handler,  //  19  Pin Interrupt Block   Reza
  PINT2_BLOCK_Int_Handler,  //  20  Pin Interrupt Block   Reza
  PINT3_BLOCK_Int_Handler,  //  21  Pin Interrupt Block   Reza
  PINT4_BLOCK_Int_Handler  //   22  Pin Interrupt Block   Reza
};

#pragma call_graph_root = "interrupt"
__weak void NMI_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void HardFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void MemManage_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void BusFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void UsageFault_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void SVC_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void DebugMon_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PendSV_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void SysTick_Handler( void ) { while (1) {} }
// ======================  Reza
#pragma call_graph_root = "interrupt"
__weak void PINT0_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT1_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT2_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT3_BLOCK_Int_Handler( void ) { while (1) {} }
#pragma call_graph_root = "interrupt"
__weak void PINT4_BLOCK_Int_Handler( void ) { while (1) {} }

void __cmain( void );
__weak void __iar_init_core( void );
__weak void __iar_init_vfp( void );

#pragma required=__vector_table
void __iar_program_start( void )
{
  __iar_init_core();
  __iar_init_vfp();
  __cmain();
}

Ответы [ 2 ]

0 голосов
/ 05 мая 2019

Я имею в виду спецификацию, http://infocenter.arm.com/help/topic/com.arm.doc.ddi0439b/DDI0439B_cortex_m4_r0p0_trm.pdf

Здесь упоминается, что расположение таблицы векторов по умолчанию - 0x00000000, это должно быть упомянуто в регистре VTOR.Если этот регистр не изменен, то после получения прерывания ЦП прочитает адрес памяти LOC1: 0x00000000 + некоторое смещение, соответствующее номеру прерывания, и перейдет к LOC1.

Теперь я предполагаю, что ISRнеправильно расположен, а LOC1 установлен неправильно, вместо этого он содержит некоторое значение мусора 0x00001452.Теперь процессор читает и переходит в это место.

Я думаю, что вы можете решить эту проблему,

Конфигурируя компоновщик таким образом, что ISR находится в правильном месте, а LOC1 заполняетсяправильное значение. Также вам может понадобиться настроить регистр VTOR с некоторым настраиваемым значением.

0 голосов
/ 26 апреля 2019

В Cortex-M ПК фактически не может быть 0xffffffff, в регистре есть только физически биты [31: 1].Когда вы наблюдаете выполнение, которое, по-видимому, находится по адресу 0xfffffffe, это адрес «LOCKUP», который является архитектурным состоянием прямой блокировки (будучи недопустимым адресом выборки, он заставляет ПК использовать адрес блокировки, который является недопустимым адресом выборки).

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

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

Первоечтобы выяснить, к чему относятся эти составленные значения ПК в вашем коде, и где это относится к тому, что вы пытаетесь запустить ISR.Может быть, ваш main () уже вернулся (он ничего не делает), и этот 0x1452 является UNDEF.У цепочки инструментов есть 3 варианта: «после main ()», «Зацикливаться навсегда», сбой или просто выполнять произвольные инструкции.Если вы не разберете / не пройдете по изображению, это не будет очевидным.

...