Understanding bxCAN Interrupt requests (IRQs)
bxCAN 인터럽트가 발생하는 경우
- 송신 이벤트(Tx Events)
- 메시지 전송 요청이 완료될 때 (Mailbox 0, 1, 2)
- 수신 이벤트(Rx Events)
- RX FIFO 0에 새로운 프레임이 수신될 때
- RX FIFO 1에 새로운 프레임이 수신될 때
- 상태 변화(Status Change Events)
- CAN 버스 상태 변화 (Bus-off, 오류 발생 등)
- 오류 발생(Error Events)
- 수신/송신 오류 증가
- FIFO 오버런(overrun) 발생
- Bus-off 상태로 전환
bxCAN 인터럽트 벡터 개수
- bxCAN1: 4개의 인터럽트 벡터(IRQ)
- bxCAN2: 4개의 인터럽트 벡터(IRQ)
- 총 8개의 IRQ가 CAN1 및 CAN2에 할당됨
bxCAN 인터럽트 발생 원인 및 처리 방식
① 송신 인터럽트 (Transmit Interrupt)
- Mailbox 0, 1, 2에서 메시지 전송 완료 시 발생
- 관련 레지스터: CAN_TSR (Transmit Status Register)
- RQCP0 (Request Completed for Mailbox 0) 비트가 1이 되면 인터럽트 발생
② RX FIFO 0 인터럽트 (Receive FIFO 0 Interrupt)
- FIFO 0에 새로운 메시지가 들어오면 발생
- 관련 레지스터: CAN_RF0R (Receive FIFO 0 Register)
- FMP0 (FIFO Message Pending) 비트가 1 이상이면 인터럽트 발생
- FIFO가 가득 차거나(FULL0 비트) 오버런 발생(FOVR0 비트) 시 인터럽트 발생
③ RX FIFO 1 인터럽트 (Receive FIFO 1 Interrupt)
- RX FIFO 0과 동일한 방식으로 동작 (FIFO 1 사용)
④ 상태 변화 및 오류 인터럽트 (Status Change & Error Interrupt)
- ESR (Error Status Register)에 의해 감지됨
- 주요 원인:
- EWGF (Error Warning Flag): 오류 카운터가 일정 값(96) 이상 증가하면 경고 발생
- BOFF (Bus-off 상태): 전송 오류(TEC)가 255를 초과하면 노드가 Bus-off 상태가 되어 통신 불가
- WKUI (Wakeup Interrupt): Sleep Mode에서 Start of Frame(SOF) 감지 시 발생
Bus-off 상태 및 복구
- Bus-off란?
- 송신 오류(TEC)가 255를 초과하면 노드가 Bus-off 상태로 전환
- Bus-off 상태에서는 송·수신이 불가능하며, CAN 버스로부터 차단
- Bus-off 복구 방법
- 자동 복구 (Auto Bus-Off Management, ABOM) 활성화
- ABOM 비트를 1로 설정하면 자동 복구 가능
- 128개의 연속적인 Recessive(1) 비트를 감지하면 자동 복구됨
- 소프트웨어를 통한 복구
- CAN_Init()을 다시 호출하여 CAN 컨트롤러를 초기화 모드 → 정상 모드로 전환
- 자동 복구 (Auto Bus-Off Management, ABOM) 활성화
WKUI - Wakeup Interrupt)
- CAN 컨트롤러가 Sleep Mode에 있을 때, Start of Frame(SOF)이 감지되면 발생
- CAN RX 엔진이 활성화되어 있어야 감지
IRQs Exercise
IRQ 활성화 (msp.c)
void HAL_CAN_MspInit(CAN_HandleTypeDef *hcan)
{
GPIO_InitTypeDef gpio_can1;
__HAL_RCC_CAN1_CLK_ENABLE();
gpio_can1.Pin = GPIO_PIN_11 | GPIO_PIN_12;
gpio_can1.Mode = GPIO_MODE_AF_PP;
gpio_can1.Pull = GPIO_NOPULL;
gpio_can1.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_can1.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init(GPIOA, &gpio_can1);
HAL_NVIC_SetPendingIRQ(CAN1_TX_IRQn, 15, 0);
HAL_NVIC_SetPendingIRQ(CAN1_RX0_IRQn, 15, 0);
HAL_NVIC_SetPendingIRQ(CAN1_RX1_IRQn, 15, 0);
HAL_NVIC_SetPendingIRQ(CAN1_SCE_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
HAL_NVIC_EnableIRQ(CAN1_SCE_IRQn);
}
인터럽트 서비스 루틴(ISR) 구현 (it.c)
void CAN1_TX_IRQHandler(void)
{
HAL_CAN_IRQHandler(&hcan1);
}
void CAN1_RX0_IRQHandler(void)
{
HAL_CAN_IRQHandler(&hcan1);
}
void CAN1_RX1_IRQHandler(void)
{
HAL_CAN_IRQHandler(&hcan1);
}
void CAN1_SCE_IRQHandler(void)
{
HAL_CAN_IRQHandler(&hcan1);
}
Callback function Implementation
CAN 하드웨어에서 인터럽트를 활성화하려면 메인함수에서 activate notification API 호출
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_TX_MAILBOX_EMPTY | CAN_IT_RX_FIFO0_MSG_PENDING | CAN_IT_BUSOFF)
Callback 함수를 모두 구현하고, 인터럽트 모드이므로 Rx 함수는 제거
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan)
{
char msg[50];
sprintf(msg, "Message Transmitted\r\n");
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan)
{
char msg[50];
sprintf(msg, "Message Transmitted\r\n");
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan)
{
char msg[50];
sprintf(msg, "Message Transmitted\r\n");
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
CAN_RxHeaderTypeDef RxHeader;
uint8_t message[5];
char msg[50];
//while(HAL_CAN_GetRxFifoFillLevel(&hcan1, CAN_RX_FIFO0));
if(HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, message)!= HAL_OK) Error_handler();
sprintf(msg, "Message Received %s\r\n", message);
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan)
{
char msg[50];
sprintf(msg, "CAN Error Detected!\r\n");
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
반응형