Cortex M0의 CMSIS에서 인터럽트 핸들러는 어떻게 구현됩니까?


9

LPC1114 키트가 있습니다. 지난 며칠 동안 Cortex M0의 CMSIS 구현을 파헤쳐 서 어떻게 수행되는지 확인했습니다. 지금까지 각 레지스터가 어떻게 매핑되고 어떻게 액세스 할 수 있는지 이해했습니다. 그러나 여전히 인터럽트가 어떻게 구현되는지 모르겠습니다. CMSIS의 인터럽트에 대해 내가 아는 것은 시작 파일에 언급 된 인터럽트 핸들러 이름이 있다는 것입니다. 시작 파일에서 언급 한 것과 동일한 이름의 C 함수를 작성하여 자체 처리기를 작성할 수 있습니다. 나를 혼란스럽게하는 것은 사용자 안내서에서 모든 GPIO를 외부 인터럽트 소스로 사용할 수 있다는 것입니다. 그러나 시작 파일에는 4 개의 PIO 인터럽트 만 언급되어 있습니다. 그러니 내게 말해:

  1. 다른 GPIO에 대한 외부 인터럽트 처리기를 어떻게 구현할 수 있습니까?
  2. CMSIS에서 인터럽트 테이블은 어디에 매핑됩니까?
  3. NVIC와 AVR / PIC의 인터럽트 구현의 주요 차이점은 무엇입니까? (NVIC를 제외하고 플래시의 어느 곳에서나 매핑 할 수 있음)

답변:


14

다음 정보는 Igor의 탁월한 답변에 추가됩니다.

C 프로그래밍 관점에서 인터럽트 핸들러는 cr_startup_xxx.c 파일 (예 : LPC1343의 cr_startup_lpc13.c 파일)에 정의되어 있습니다. 가능한 모든 인터럽트 핸들러는 WEAK 별명으로 정의됩니다. 인터럽트 소스에 대해 자신의 XXX_Handler ()를 정의하지 않으면이 파일에 정의 된 기본 인터럽트 핸들러 함수가 사용됩니다. 링커는 cr_startup_xxx.c의 인터럽트 벡터 테이블과 함께 최종 바이너리에 포함 할 함수를 정렬합니다.

포트의 GPIO 인터럽트 예제는 gpio.c 데모 파일에 나와 있습니다. GPIO 포트 당 NVIC에 하나의 인터럽트 입력이 있습니다. 포트의 각 개별 비트를 활성화 / 비활성화하여 해당 포트에서 인터럽트를 생성 할 수 있습니다. 예를 들어 포트 PIO1_4 및 PIO1_5에서 인터럽트가 필요한 경우 GPIO0IE에서 개별 PIO1_4 및 PIO1_5 인터럽트 비트를 활성화합니다. PIOINT0_Handler () 인터럽트 핸들러 함수가 실행되면 GPIO0RIS 레지스터를 읽고 인터럽트를 적절히 처리하여 보류중인 PIO1_4 또는 PIO1_5 (또는 둘 다) 인터럽트를 결정하는 것은 사용자의 몫입니다.


10

포인트 1과 2는 구현상의 세부 사항이며 아키텍처 제한이 아닙니다.

  1. 더 큰 NXP 칩 (예 : LPC17xx)에는 자체 인터럽트 핸들러가있는 전용 인터럽트 핀 (EINTn)이 있습니다. 나머지 GPIO는 하나의 공통 인터럽트 (EINT3)를 사용해야합니다. 그런 다음 인터럽트 상태 레지스터를 폴링하여 어떤 핀이 인터럽트를 트리거했는지 확인할 수 있습니다.
  2. LPC11xx에 익숙하지 않지만 GPIO 포트 당 하나의 인터럽트가있는 것 같습니다 . 특정 핀을 파악하려면 상태 레지스터를 다시 확인해야합니다. 웨이크 업 소스 역할을 할 수있는 최대 12 개의 핀이 있습니다. 일반적인 인터럽트로 하이재킹 할 수 있는지 잘 모르겠습니다 (예 : 휴면 상태에서만 트리거 될 수 있음).
  3. 기본 핸들러 테이블은 주소 0 (플래시)에 있습니다. 첫 번째 항목은 SP 레지스터의 재설정 값이고, 두 번째 항목은 재설정 벡터이며 나머지는 다른 예외 및 인터럽트 벡터입니다. 첫 번째 두 가지 (NMI 및 HardFault와 같은)는 ARM에 의해 수정되고 나머지는 칩에 따라 다릅니다. 런타임에 벡터를 변경해야하는 경우 벡터를 RAM에 다시 매핑 할 수 있습니다 (먼저 테이블을 복사해야 함). LPC11xx에서 리 맵핑은 SRAM의 시작 (0x10000000)으로 고정되며 다른 칩이 더 유연 할 수 있습니다.
  4. NVIC는 효율적인 인터럽트 처리를 위해 최적화되었습니다.
    • 각 인터럽트에 대해 프로그램 가능 우선 순위 레벨 0-3. 우선 순위가 높은 인터럽트는 우선 순위가 낮은 인터럽트를 우선합니다 (중첩). 우선 순위가 높은 인터럽트가 완료되면 우선 순위가 낮은 우선 순위의 실행이 재개됩니다.
    • 인터럽트 진입시 프로세서 상태의 자동 스태킹; 이를 통해 C에서 직접 인터럽트 처리기를 작성할 수 있으며 어셈블리 래퍼가 필요하지 않습니다.
    • tail-chaining : 상태를 팝핑하고 다시 푸시하는 대신 다음 보류중인 인터럽트가 즉시 처리됩니다.
    • 늦게 도착 : 프로세서 상태를 스태킹하는 동안 우선 순위가 높은 인터럽트가 도착하면 이전에 보류중인 인터럽트 대신 즉시 실행됩니다.

PIC에 익숙하기 때문에이 애플리케이션 노트를 살펴보십시오. PIC 마이크로 컨트롤러에서 Cortex-M3으로 마이그레이션

M3에 관한 것이지만 대부분의 포인트가 M0에도 적용됩니다.


8

Austin과 Igor의 답변은 충분히 자세합니다. 그러나 다른 방법으로 대답하고 싶습니다. 아마 도움이 될 수 있습니다.

LPC11xx (Cortex-M0)는 GPIO 핀에 대해 4 가지 레벨을 가지며 GPIO0.0에서 GPIO0.n까지의 모든 핀은 동일한 인터럽트 번호를 공유하며 GPIO3.0에서 GPIO3.m의 모든 핀은 동일한 인터럽트 번호를 공유합니다.

LPC11xx에서 GPIO 인터럽트를 초기화하는 6 가지 단계가 있습니다

  1. 핀 연결 블록 레지스터를 수정하여 핀 기능을 설정하십시오.
  2. GPIO 데이터 방향 레지스터를 수정하여 핀 방향을 설정하십시오 (기본값은 입력 됨).
  3. 각 개별 핀에 대한 인터럽트를 설정하려면 GPIO 인터럽트 마스크 레지스터 GPIOnIE로 이동하여 비트 (핀에 해당) 논리 1을 설정해야합니다.
  4. GPIO 인터럽트 감지 레지스터 GPIOnIBE 및 GPIOnIS를 수정하여 상승 에지 또는 하강 에지에 대한 인터럽트를 설정하십시오.
  5. CMSIS 기능을 사용하여 Nested Vectored Interrupt Control에서 PIO_0 / PIO_1 / PIO_2 / PIO_3 인터럽트 소스를 활성화하십시오.
  6. CMSIS 기능을 사용하여 인터럽트 우선 순위를 설정하십시오.

코드 구현. 두 가지 기능이 필요합니다. 하나는 위의 6 단계를 초기화하고 두 번째는 인터럽트 처리기이며 시작 코드 startup_LPC11xx.s파일에 정의 된 처리기와 이름이 같아야 합니다. 이름은에서 PIOINT0_IRQHandler까지 PIOINT3_IRQHandler입니다. 다른 이름을 사용하는 경우 시작 파일에서 이름을 변경해야합니다.

/*Init the GPIO pin for interrupt control */
void GPIO_Init(){
    LPC_IOCON-> =..              //Pin configuration register
    LPC_GPIO1->FIODIR = ...      //GPIO Data direction register
    LPC_GPIO1->FIOMASK = ..      //GPIO Data mask register - choose  the right pin
    LPC_GPIO1->GPIOnIE = ..      //Set up falling or rising edge 
    NVIC_EnableIRQ(PIO_1);       //Call API to enable interrupt in NVIC
    NVIC_SetPriority(PriorityN); //Set priority if needed
}


/*Must have the same name as listed in start-up file startup_LPC11xx.s */
void PIOINT1_IRQHandler(void){
   //Do something here
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.