2014-09-10 3 views
2

IAR Embedded Workbench IDE를 사용하는 NXP LPC1788 마이크로 컨트롤러 용 애플리케이션을 개발 중입니다. 요구 사항 중 하나는 가능한 빨리 CAN1 포트에서 CAN 메시지를 수신하는 것입니다. 내 문제는 인터럽트를 처리하기 위해 마이크로 컨트롤러 ~ 30 마이크로 초 밖에 걸리지 않는 것처럼 보이지만 CAN IRQ를 한 번 호출 한 후부터 다음에 시작할 때까지 약 270 마이크로 초의 지연이있는 것으로 보입니다.CAN IRQ가 LPC1788 마이크로 컨트롤러에 대해 호출되는 속도를 어떻게 향상시킬 수 있습니까?

이 인터럽트 외에도 CAN 및 USB 메시지를 수신 한 50 마이크로 초마다 정기적 인 타이머 인터럽트를 예약했습니다. 그러나이 인터럽트 루틴은 처리 할 CAN 또는 USB 메시지가 없으면 약 3 마이크로 초가 걸리고 약 80 마이크로 초 밖에 걸리지 않습니다.

이 때문에 나는 왜 CAN IRQ가 매 270 마이크로 초보다 빠르게 발사 할 수 없는지 궁금해하며이를 해결하기 위해 무엇을 할 수 있는지 궁금합니다.

USB 인터럽트는 CAN 메시지보다 훨씬 드물게 USB 메시지가 도착하기 때문에 성능에 거의 영향을 미치지 않으며,이 인터럽트가 실행되지 않아도이 문제가 발생한다고 판단했습니다.

현재 내 응용 프로그램은 ~ 300 us의 평균 inter-arrival 시간을 가진 CAN 메시지를 처리 ​​할 수있는 것 같습니다 (1 ms 간격으로 생성 된 3 개의 메시지와 ~ 500,000 개의 메시지가 처리되고 0 % 드롭 율로 테스트 됨) .

void CAN_IRQHandler(void) 
{ 
    ITM_EVENT32_WITH_PC(1, 0xAAAAAAAA); 

#if CAN_SOURCE_PORT == CAN_PORT_1 
    if(LPC_CAN1->SR & 0x1 /* RBS */) 
    { 
    CAN_ReceiveMsg(CAN_1, &recMessage); 
    COMMS_NotifyCANMessageReceived(); 
    CAN_SetCommand(CAN_1, CAN_CMR_RRB); 
    } 
#else 
    if(LPC_CAN2->SR & 0x1) 
    { 
    CAN_ReceiveMsg(CAN_2, &recMessage); 
    COMMS_NotifyCANMessageReceived(); 
    CAN_SetCommand(CAN_2, CAN_CMR_RRB); 
    } 
#endif 

    ITM_EVENT32_WITH_PC(1, 0xBBBBBBBB); 
} 

COMMS_NotifyCANMessageReceived 코드 : 이것은 CAN의 IRQ 코드

void CANHandlerRun() 
{ 
    // Enter reset mode. 
    LPC_CAN1->MOD |= 0x1; 
    LPC_CAN2->MOD |= 0x1; 

#if CAN_SOURCE_PORT == CAN_PORT_1 
    SFF_GPR_Table[0].controller1 = SFF_GPR_Table[0].controller2 = CAN1_CTRL; 
    SFF_GPR_Table[0].disable1 = SFF_GPR_Table[0].disable2 = MSG_ENABLE; 
    SFF_GPR_Table[0].lowerID = 0x0; 
    SFF_GPR_Table[0].upperID = 0x7FF; 
#else 
    SFF_GPR_Table[0].controller1 = SFF_GPR_Table[0].controller2 = CAN2_CTRL; 
    SFF_GPR_Table[0].disable1 = SFF_GPR_Table[0].disable2 = MSG_ENABLE; 
    SFF_GPR_Table[0].lowerID = 0x0; 
    SFF_GPR_Table[0].upperID = 0x7FF; 
#endif 

    AFTable.FullCAN_Sec = NULL; 
    AFTable.FC_NumEntry = 0; 

    AFTable.SFF_Sec = NULL; 
    AFTable.SFF_NumEntry = 0; 

    AFTable.SFF_GPR_Sec = &SFF_GPR_Table[0]; 
    AFTable.SFF_GPR_NumEntry = 1; 

    AFTable.EFF_Sec = NULL; 
    AFTable.EFF_NumEntry = 0; 

    AFTable.EFF_GPR_Sec = NULL; 
    AFTable.EFF_GPR_NumEntry = 0; 

    if(CAN_SetupAFLUT(&AFTable) != CAN_OK) printf("AFLUT error\n"); 

    LPC_CANAF->AFMR = 0; 

    // Re-enter normal operational mode. 
    LPC_CAN1->MOD &= ~0x1; 
    LPC_CAN2->MOD &= ~0x1; 

    // Enable interrupts on transmitting and receiving messages. 
#if CAN_SOURCE_PORT == CAN_PORT_1 
    LPC_CAN1->IER |= 0x1; /* RIE */ 
    LPC_CAN1->IER |= (1 << 8); /* IDIE */ 
#else 
    LPC_CAN2->IER |= 0x1; 
    LPC_CAN2->IER |= (1 << 8); 
#endif 

    NVIC_EnableIRQ(CAN_IRQn); 
} 

: 이것은 CAN를 실행하는 데 사용되는

void CANHandlerInit() 
{ 
    // Configure CAN pins. 
    PINSEL_ConfigPin(0, 0, 1); // RD1. 
    PINSEL_ConfigPin(0, 1, 1); // TD1. 
    PINSEL_ConfigPin(0, 4, 2); // RD2. 
    PINSEL_ConfigPin(0, 5, 2); // TD2. 

    CAN_Init(CAN_1, CAN_BAUD_RATE); 
    CAN_Init(CAN_2, CAN_BAUD_RATE); 

    //printf("CAN Handler initialised\n"); 
} 

:

이 코드는 CAN을 초기화한다 :

우리 (200)의 메시지의 평균 간 도착 시간에 응용 프로그램을 실행하는 동안 다음
void TIMER0_IRQHandler(void) 
{ 
    uint32_t canMessageCount, usbMessageCount; 

    if(TIM_GetIntStatus(LPC_TIM0, TIM_MR0_INT) == SET) 
    { 
    //ITM_EVENT32_WITH_PC(4, 0); 

    LIST_AcquireLock(canMessageList); 
    canMessageCount = LIST_GetLength(canMessageList); 
    LIST_ReleaseLock(canMessageList); 

    LIST_AcquireLock(usbMessageList); 
    usbMessageCount = LIST_GetLength(usbMessageList); 
    LIST_ReleaseLock(usbMessageList); 

    if(canMessageList != NULL && canMessageCount > 0) 
    { 
     LIST_AcquireLock(canMessageList); 

     if(!LIST_PopAtIndex(canMessageList, 0, &outCommsBuffer)) 
     { 
     LIST_ReleaseLock(canMessageList); 
     goto TIMER_IRQ_END; 
     } 

     LIST_ReleaseLock(canMessageList); 

     ITM_EVENT32_WITH_PC(4, 0x88888888); 
     interpretMessage(outCommsBuffer); 
     ITM_EVENT32_WITH_PC(4, 0x99999999); 
    } 
    else if(usbMessageList != NULL && usbMessageCount > 0) 
    { 
     LIST_AcquireLock(usbMessageList); 

     if(!LIST_PopAtIndex(usbMessageList, 0, &outCommsBuffer)) 
     { 
     LIST_ReleaseLock(usbMessageList); 
     goto TIMER_IRQ_END; 
     } 

     LIST_ReleaseLock(usbMessageList); 

     ITM_EVENT32_WITH_PC(4, 0xCCCCCCCC); 
     interpretMessage(outCommsBuffer); 
     ITM_EVENT32_WITH_PC(4, 0xDDDDDDDD); 
    } 

    //ITM_EVENT32_WITH_PC(4, 1); 
    } 

TIMER_IRQ_END: 
    TIM_ClearIntPending(LPC_TIM0, TIM_MR0_INT); 
} 

전형적인 이벤트 로그의 발췌 한 것입니다 :

이 688,는 매 50 마이크로 초 트리거 내 타이머 인터럽트 코드입니다 :

  • 0xAAAAAAAA가 시작 O를 나타냅니다

    4s 718164.69 us  0x00005E82 0xAAAAAAAA    
    4s 718175.27 us  0x00005EC4 0xBBBBBBBB    
    4s 718197.10 us  0x000056C4    0x88888888 
    4s 718216.50 us  0x00005700    0x99999999 
    4s 718438.69 us  0x00005E82 0xAAAAAAAA    
    4s 718449.40 us  0x00005EC4 0xBBBBBBBB    
    4s 718456.42 us  0x000056C4    0x88888888 
    4s 718476.56 us  0x00005700    0x99999999 
    4s 718707.04 us  0x00005E82 0xAAAAAAAA    
    4s 718717.54 us  0x00005EC4 0xBBBBBBBB    
    4s 718747.15 us  0x000056C4    0x88888888 
    4s 718768.00 us  0x000056C4    0x99999999 
    

    f CAN IRQ.

  • 0xBBBBBBBB은 CAN IRQ의 끝을 나타냅니다.
  • 0x88888888은 CAN 메시지가 타이머 IRQ 내에서 interpretMessage으로 처리 될 예정임을 나타냅니다.
  • 0x99999999interpretMessage에서 반환되었음을 나타냅니다.

메시지가 200 us마다 도착하더라도 CAN IRQ는 매 270 us마다 서비스를 수행하고 있습니다. 이로 인해 결국 메시지가 떨어지기 시작할 때까지 수신 대기열이 쌓입니다.

도움을 주시면 감사하겠습니다.

EDIT 1

나는 아마 또한 내가 내 CAN 주변 장치 500kBaud의의 속도로 작동하는 프로그램이 있음을 언급해야한다. 또한, 내 애플리케이션 메시지를 이미 수신 반향 포함하므로 1 번 포트에 도착하는 모든 메시지는 포트에 다시 전송된다 2.

EDIT 2

캔과 TIMER_0 루틴은 동일한 우선 순위가 인터럽트 :

NVIC_SetPriority(USB_IRQn, 1); 
NVIC_SetPriority(CAN_IRQn, 1); 
NVIC_SetPriority(TIMER0_IRQn, 1); 

EDIT 3

문제가 남아 있고 ~ 270 우리에게 조금/변화가 interva가 없다는 것을 나는 확인할 수

l 타이머 인터럽트를 비활성화하고 CAN IRQ에 아무것도하지 않고 수신 된 CAN 메시지를 RAM으로 복사하고 수신 버퍼를 해제 할 때도 인터럽트 사이에.

+1

인터럽트 속도는 CAN 버스 전송 속도에 의해서만 결정됩니다. 네가 잘못 할 수있는 유일한 일은 분명히 문제가 아니라 계속 따라 잡고있는 것이 아니라는 것이다. –

+0

@HansPassant 감사합니다. 전송 속도에 따라 예상되는 인터럽트 속도를 계산하는 방법이 있습니까? 내 보오는 500,000이며,이를 위해 CAN 주변 장치를 12 MHz로 설정했습니다. 따라서 각 틱은 약 83 나노초이므로 각 인터럽트 사이에 ~ 3000 틱이 필요합니다 (270 마이크로 초 지연을 판단). – Tagc

+1

@HansPassant 미안하지만, 난 그냥 피비린내 나는 멍청이야. 500kBaud에서 표준 (11 비트) ID 및 최대 스터프 비트가 전송되는 CAN 메시지의 경우 271 us가 소요됩니다. 니가 지금 무슨 뜻인지 이해해. – Tagc

답변

1

나는 바보입니다. 500kBaud에서 11 비트 표준 식별자와 최대 스터프 비트가 전송되는 CAN 메시지의 경우 271 us가 소요됩니다. 내 코드에는 명백한 문제가 없습니다. 병목 현상은 버스에서 CAN 메시지가 얼마나 빨리 전송 될 수 있는지입니다.