STM32 인터럽트 벡터표의 내용을 바꾸는 대신코드

10539 단어 코드 세그먼트
최근에는 또 다른 프로젝트를 인수해 STM32를 사용했다.듣자니 이 코드는 대신이 쓴 것이라고 한다.나는 대충 보았는데, 구름 속에 안개 속에 매우 많은 신기들이 있었다.너무 많은 코드가 나를 놀라게 했는데 놀랍게도 이렇게 코드를 쓸 수 있었다. 놀랍게도 이것은 너무 어렵고 깊이 써서 내가 욕하고 싶을 정도로 이해하기 어려웠다.보고 싶은 말이 너무 많으니 오늘은 조금만 놓고 나눠보고 대신의 소동을 참배해 봅시다.
우리는 인터럽트 서비스 함수부터 시작해서 코드에 인터럽트 벡터를 어떻게 배치하는지 살펴보자.
ISR(USART2_IRQn)
{
  uint8 data;
  uint32 _if=USART2->ISR;

잘못 보지 않았습니다. 이것이 바로 서비스 중단 함수의 이름입니다.이 ISR가 뭔지 추적해 봅시다.헤더 파일에는 다음과 같은 정의가 있다.보시면 ISR(USART2 IRQn)는void ISR 와 같습니다.NAME(USART2_IRQn)(void),ISR_NAME는 과 동일합니다.ISR_NAME,__ISR_NAME는 과 동일합니다.ISR_##A.이것이 마지막 매크로 정의입니다. 매크로를 연결하는 것입니다.
#ifndef ISR_NAME
#define ISR_NAME(A)       __ISR_NAME(A)
#define __ISR_NAME(A)     __ISR_##A
#endif

#ifndef ISR_Extern
#define ISR_Extern(A)     ISR(A)
#endif

#ifndef ISR_Implement
#define ISR_Implement(A)  ISR(A)
#endif

#ifndef ISR_Define
#define ISR_Define(A)     ISR(A)
#endif

#ifndef ISR
#define ISR(A)  void ISR_NAME(A)(void)
#endif

층층이 거대한 정의를 통해ISR(USART2 IRQn)은voidISR_USART2_IRQn(void).STM32를 자주 사용하는 우리는 직렬 인터럽트 함수는 일반적으로 이 USART2 라는 것을 안다IRQHandler, 위에 그게 아니에요.그럼 서비스 중단 함수에서 위에 있는 함수를 호출한 거 아닐까요?나는 전체 프로젝트 범위 내에서 USART2를 검색했다.IRQHandler, 이 함수를 찾을 수 없습니다.
프로젝트 파일에서 한 차례의 검색을 거쳐 나는 문제의 답안을 찾았다.나는 원본 파일에서 이러한 그룹의 정의를 찾았다.root는 이 그룹이 다른 파일에 사용되었든 안 사용되었든 간에 컴파일러가 컴파일된 파일에 강제로 컴파일된다는 뜻입니다. @". intvec"는 컴파일러에게 이 그룹을 컴파일해서. intvec 섹션에 놓는 것을 알려 줍니다. 이. intvec 섹션은 인터럽트 벡터표가 저장된 곳을 인터럽트 벡터로 덮어쓰는 것입니다. 이 섹션에는 인터럽트 벡터표가 층층이 정의되어 있습니다.
__root const intvec_elem __vector_table[] @".intvec"=
{
  
  //======================================================================
  //  CM3    /      (     )
  ISR_VAL_2_15_FILL_IN_VECT_TAB(_Deault_Handler),  
  
  //======================================================================
  //    ,      
  [0].ptr          = (uint32)__sfe( "CSTACK" ) - 32 ,
  [1].handler      = __iar_program_start,
  
  //CM3    /   
  ISR_VAL_IN_VECT_TAB(NonMaskableInt_IRQn,_Deault_Handler),
  //ISR_VAL_IN_VECT_TAB(HardFault_IRQn,_Deault_Handler),    
  ISR_VAL_IN_VECT_TAB(MemoryManagement_IRQn,_Deault_Handler),
  ISR_VAL_IN_VECT_TAB(BusFault_IRQn,_Deault_Handler),              
  ISR_VAL_IN_VECT_TAB(UsageFault_IRQn,_Deault_Handler),     
  ISR_VAL_IN_VECT_TAB(SVCall_IRQn,_Deault_Handler),          
  ISR_VAL_IN_VECT_TAB(DebugMonitor_IRQn,_Deault_Handler),    
  ISR_VAL_IN_VECT_TAB(PendSV_IRQn,ISR_NAME(PendSV_IRQn)),                
  ISR_VAL_IN_VECT_TAB(SysTick_IRQn,ISR_NAME(SysTick_IRQn)),
  
  //==============================================================================
  //      
#if defined(STM32F10X_LD)   //0-42
  ISR_VAL_FILL_43_IN_VECT_TAB(_Deault_Handler),  
  
#elif defined(STM32F10X_LD_VL)   //0-55
  ISR_VAL_FILL_56_IN_VECT_TAB(_Deault_Handler), 
  
#elif defined(STM32F10X_MD)   //0-42
  ISR_VAL_FILL_43_IN_VECT_TAB(_Deault_Handler), 
  
#elif defined(STM32F10X_MD_VL)   //0-55
  ISR_VAL_FILL_56_IN_VECT_TAB(_Deault_Handler), 
  
#elif defined(STM32F10X_HD)   //0-59
  ISR_VAL_FILL_60_IN_VECT_TAB(_Deault_Handler), 
  
#elif defined(STM32F10X_HD_VL)   //0-60
  ISR_VAL_FILL_61_IN_VECT_TAB(_Deault_Handler), 
  
#elif defined(STM32F10X_XL)   //0-59
  ISR_VAL_FILL_60_IN_VECT_TAB(_Deault_Handler), 
  
#elif defined(STM32F10X_CL)   //0-67
  ISR_VAL_FILL_68_IN_VECT_TAB(_Deault_Handler), 
  
#else 
#warning "unkown type!"
  
#endif
  
  
  //======================================================================  
  //STM32   
  ISR_IN_VECT_TAB(USART1_IRQn), 
  ISR_IN_VECT_TAB(USART2_IRQn),
  ISR_IN_VECT_TAB(TIM3_IRQn), 
  
//  ISR_IN_VECT_TAB(USB_HP_CAN1_TX_IRQn),
//  ISR_IN_VECT_TAB(USB_LP_CAN1_RX0_IRQn),
//  ISR_IN_VECT_TAB(SDIO_IRQn),
//  ISR_IN_VECT_TAB(SD_SDIO_DMA_IRQn),
//  ISR_IN_VECT_TAB(USBWakeUp_IRQn),
  
};

우선 수조의 유형을 살펴보자.intvec_elem.연합체 유형은 함수 바늘일 수도 있고 32자리의 성형수일 수도 있다.함수 포인터의 유형을 볼 수 있습니다. 서비스 중단 함수와 마찬가지로 매개 변수가 없고 되돌아오지 않습니다.
typedef void  ( vector_handler_t )( void );
typedef union { vector_handler_t * handler; uint32 ptr; } intvec_elem;

우리는 수조에 이런 두 마디가 있다는 것을 볼 수 있는데 이것은 우리가 M3 내핵에 대한 인식에 부합된다.벡터 테이블 앞의 네 바이트는 창고 끝 주소입니다.sfe는 IAR의 어셈블리 문법으로 CSTACK 단락의 마지막 주소로 가는 것을 의미한다.벡터 테이블에 이어서 저장된 것은 벡터를 복원하는 주소이다.여기 코드가 라고 적혀있어요.iar_program_start 이건 IAR와 관련이 있을 거예요. 추적이 안 돼요.
  //======================================================================
  //    ,      
  [0].ptr          = (uint32)__sfe( "CSTACK" ) - 32 ,
  [1].handler      = __iar_program_start,

우리는 이어서 수조 안의 매크로 정의를 보았다.일단 ISR...VAL_2_15_FILL_IN_VECT_TAB
  //  CM3    /      (     )
  ISR_VAL_2_15_FILL_IN_VECT_TAB(_Deault_Handler),  

매크로 정의는 다음과 같습니다.
#define ISR_VAL_2_15_FILL_IN_VECT_TAB(A)\
[2].handler  = A,\
[3].handler  = A,\
[4].handler  = A,\
[5].handler  = A,\
[6].handler  = A,\
[7].handler  = A,\
[8].handler  = A,\
[9].handler  = A,\
[10].handler  = A,\
[11].handler  = A,\
[12].handler  = A,\
[13].handler  = A,\
[14].handler  = A,\
[15].handler  = A

수조에 이런 조작이 있을 수 있다???나도 놀랐다. 네가 아래와 같이 수조를 정의하는 것과 같다.소동 조작은 여태껏 만난 적이 없다.
typedef union{
  uint32_t reg;
  uint8_t buff[4];
}un_test_t;
un_test_t test[] = {
  [0].reg = 0,
  [1].reg = 1,
};

_Deault_Handler의 정의는 다음과 같다. 디버깅을 할 때 창고와 레지스터의 수요를 고려해야 한다.보아하니 대신이 M3 내핵 처리 함수를 뛰어넘을 때 창고의 조작을 손금 보듯 잘 알고 있어 탄복하고 탄복한다
#if VECT_DEBUG==1
typedef struct
{
  uint32 _r0;
  uint32 _r1;
  uint32 _r2;
  uint32 _r3;
  uint32 _r12;
  uint32 _lr;
  uint32 _pc;
  uint32 _xpsr;
}__irq_reg_t;

__root volatile __irq_reg_t __irq_reg;
#endif

#define   _Deault_Handler ((void (*)(void))&__Deault_Handler)

__task void __Deault_Handler(void)
{
  
#if VECT_DEBUG==1  
  uint32 *sp=(uint32 *)__get_MSP();
  
  for(int i=0;i

전면 ISRVAL_2_15_FILL_IN_VECT_TAB 이 매크로는defaulthandler.startup을 뒤져서 기본 인터럽트 벡터표를 보면 2에서 15가 시스템 인터럽트 벡터라는 것을 알 수 있습니다.
다시 데이터 속의 매크로를 내려다보면 또 하나의 끼워 넣은 매크로가 나를 너무 피곤하게 본다.Bus Falut 같은...IRQn, 브레이크 벡터 번호,
 //CM3    /   
  ISR_VAL_IN_VECT_TAB(NonMaskableInt_IRQn,_Deault_Handler),
  //ISR_VAL_IN_VECT_TAB(HardFault_IRQn,_Deault_Handler),    
  ISR_VAL_IN_VECT_TAB(MemoryManagement_IRQn,_Deault_Handler),
  ISR_VAL_IN_VECT_TAB(BusFault_IRQn,_Deault_Handler),              
  ISR_VAL_IN_VECT_TAB(UsageFault_IRQn,_Deault_Handler),     
  ISR_VAL_IN_VECT_TAB(SVCall_IRQn,_Deault_Handler),          
  ISR_VAL_IN_VECT_TAB(DebugMonitor_IRQn,_Deault_Handler),    
  ISR_VAL_IN_VECT_TAB(PendSV_IRQn,ISR_NAME(PendSV_IRQn)),                
  ISR_VAL_IN_VECT_TAB(SysTick_IRQn,ISR_NAME(SysTick_IRQn)),
#define ISR_IN_VECT_N16_TAB(A)            [(A)+16].handler  = ISR_NAME(A)
#define ISR_VAL_IN_VECT_N16_TAB(A,B)      [(A)+16].handler  = B
#define ISR_IN_VECT_TAB(A)                ISR_IN_VECT_N16_TAB(A)
#define ISR_VAL_IN_VECT_TAB(A,B)          ISR_VAL_IN_VECT_N16_TAB(A,B)

우리는 M3 내핵의 중단 벡터 번호의 마이너스를 한 부 붙여서 보면 다음과 같다.매크로에 16을 추가했기 때문에 이 부분의 내부 핵 단계의 중단은 중단 벡터표에 정확하게 넣을 수 있다.NonMaskableInt_IRQn에 16을 더하면 2가 된다.
typedef enum IRQn
{
/******  Cortex-M3 Processor Exceptions Numbers ***************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                             */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M3 Memory Management Interrupt              */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M3 Bus Fault Interrupt                      */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M3 Usage Fault Interrupt                    */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M3 SV Call Interrupt                       */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M3 Debug Monitor Interrupt                 */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M3 Pend SV Interrupt                       */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M3 System Tick Interrupt                   */

/******  STM32 specific Interrupt Numbers *********************************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                            */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt            */
  TAMPER_IRQn                 = 2,      /*!< Tamper Interrupt               

잠깐만, 방금 우리 ISRVAL_2_15_FILL_IN_VECT_TAB 홍리, 2에서 15에 값을 매겼잖아. 어떻게 여기서 2에서 15의 내용에 값을 매길 수 있겠어. 아래와 같고 수조에 이런 조작이 있을 수 있잖아.나는 정말 탄복한다. 지금까지 이런 수조의 정의를 본 적이 없다.
typedef union{
  uint32_t reg;
  uint8_t buff[4];
}un_test_t;
un_test_t test[] = {
  [0].reg = 0,
  [0].reg = 1,
};

그 다음에 MCU의 용량에 따라 조건컴파일을 했습니다. 그중 하나를 보겠습니다.
ISR_VAL_FILL_43_IN_VECT_TAB(_Deault_Handler), 

추적해 보면 이 단락이 비교적 길어서 나는 몇 마디만 붙이면 된다.내가 눈을 좀 비비면 눈이 좀 침침해진다.사십삼은 사십삼과 사십이를 정의했고, 사십이는 사십이와 사십일을 정의했다...접룡이요...위와 같이 수조 인덱스를 통해 수조의 구성원을 정의하는 것이 아니라 정의값을 직접 쓰는 것이다.
#define ISR_VAL_FILL_43_IN_VECT_TAB(A)    A,ISR_VAL_FILL_42_IN_VECT_TAB(A)
#define ISR_VAL_FILL_42_IN_VECT_TAB(A)    A,ISR_VAL_FILL_41_IN_VECT_TAB(A)
#define ISR_VAL_FILL_41_IN_VECT_TAB(A)    A,ISR_VAL_FILL_40_IN_VECT_TAB(A)

#define ISR_VAL_FILL_40_IN_VECT_TAB(A)    A,ISR_VAL_FILL_39_IN_VECT_TAB(A)
...
#define ISR_VAL_FILL_1_IN_VECT_TAB(A)    A

이렇게 쓰는 것이 아니겠는가. 오 마이 갓. 나는 이미 나의 C언어가 체육 선생님께서 가르쳐 주신 것인지 의심하고 있다. 이것은 분명히 수조인데 나는 이런 조작을 전혀 본 적이 없다.

typedef union{
  uint32_t reg;
  uint8_t buff[4];
}un_test_t;
un_test_t test[] = {
  [0].reg = 0,
  [0].reg = 1,
  52,
};

배열의 마지막
  //======================================================================  
  //STM32   
  ISR_IN_VECT_TAB(USART1_IRQn), 
  ISR_IN_VECT_TAB(USART2_IRQn),
  ISR_IN_VECT_TAB(TIM3_IRQn), 

익숙한 ISR 을 보는 추적 매크로의 정의NAME이야, 이것이 바로 우리가 처음에 본 그 거대한 것 아니야.원래 그 직렬의 인터럽트 서비스 함수는 인터럽트 벡터표에 쓰여 있었다. 
#define ISR_IN_VECT_N16_TAB(A)            [(A)+16].handler  = ISR_NAME(A)
#define ISR_VAL_IN_VECT_N16_TAB(A,B)      [(A)+16].handler  = B
#define ISR_IN_VECT_TAB(A)                ISR_IN_VECT_N16_TAB(A)
#define ISR_VAL_IN_VECT_TAB(A,B)          ISR_VAL_IN_VECT_N16_TAB(A,B)

이 신묘한 조작을 보고 나니 내 머리가 멍해졌다.잠시 말이 막혀서, 강요하는 것이 좋을지, 아니면 어리석은 것이 좋을지 모르겠다.
인터럽트 벡터에 대한 재작성은 훌륭하지 않다고 할 수 없다.그러나 이 층층의 매크로 정의, 매크로 연결은 코드를 보는 사람들을 괴롭힌다.코드 안에 도처에 이런 층층이 매크로 정의가 있으니, 시간을 내서 내가 다시 한 편을 공유할게.

좋은 웹페이지 즐겨찾기