gpt4 book ai didi

c - 如何提高 LPC1788 微 Controller 调用 CAN IRQ 的速率?

转载 作者:太空宇宙 更新时间:2023-11-03 23:49:02 25 4
gpt4 key购买 nike

我正在使用 IAR Embedded Workbench IDE 为 NXP LPC1788 微 Controller 开发应用程序,其中一项要求是尽快从 CAN1 端口接收 CAN 消息。我的问题是,在 CAN IRQ 的一次调用开始和下一次调用开始之间似乎有大约 270 微秒的延迟,尽管微 Controller 似乎只需要大约 30 微秒来处理中断。

除了这个中断之外,我还安排了每 50 微秒一次的定期定时器中断,它处理接收到的 CAN 和 USB 消息。但是,如果没有要处理的 CAN 或 USB 消息,此中断例程需要大约 3 微秒,如果有,则只需要大约 80 微秒。

因此,我想知道为什么 CAN IRQ 不能比每 270 微秒更快地触发一次,以及我可以做些什么来解决这个问题。

USB 中断对性能的影响可以忽略不计,因为 USB 消息比 CAN 消息到达的频率低得多,而且我确定即使从未触发此中断也会出现此问题。

目前,我的应用程序似乎能够处理平均到达间隔时间约为 300 微秒的 CAN 消息(针对以 1 毫秒间隔生成的 3 条消息进行测试,处理了约 500,000 条消息,丢弃率为 0%)。

此代码初始化 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:

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 IRQ 代码:

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代码:

void COMMS_NotifyCANMessageReceived()
{
COMMS_BUFFER_T commsBuffer;

#if MAX_MSG_QUEUE_LENGTH > 0
uint32_t length;

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

if(length >= MAX_MSG_QUEUE_LENGTH)
{
ITM_EVENT32_WITH_PC(2, 0x43214321);
return;
}
#endif

commsBuffer.flags = COMMS_MODE_CAN;

COMMS_GetData(&commsBuffer);

LIST_AcquireLock(canMessageList);
LIST_AddItem(canMessageList, &commsBuffer);
LIST_ReleaseLock(canMessageList);
}

这是我的定时器中断代码,每 50 微秒触发一次:

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);
}

以下是运行应用程序时典型事件日志的摘录,消息之间的平均到达间隔时间为 200 微秒:

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

地点:

  • 0xAAAAAAAA 表示 CAN IRQ 的开始。
  • 0xBBBBBBBB表示CAN IRQ结束。
  • 0x88888888 表示 CAN 报文将在定时器 IRQ 内由 interpretMessage 处理。
  • 0x99999999 表示我们已经从 interpretMessage 返回。

您可以看到,尽管消息每 200 微秒到达一次,但 CAN IRQ 仅每约 270 微秒为它们提供服务。这会导致接收队列不断增加,直到最终消息开始被丢弃。

如有任何帮助,我们将不胜感激。

编辑 1

也许我还应该提到,我已将我的 CAN 外围设备编程为以 500 kBaud 的速率运行。此外,我的应用程序涉及回显接收到的 CAN 消息,因此到达端口 1 的任何消息都会在端口 2 上重新传输。

编辑 2

CAN 和 TIMER_0 中断例程具有相同的优先级:

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

编辑 3

我可以确认问题仍然存在,即使我禁用定时器中断并让 CAN IRQ 只将接收到的 CAN 消息复制到 RAM 并释放接收,中断之间的 ~270 us 间隔几乎/没有变化缓冲区。

最佳答案

我是个傻子。在 500 kBaud 下,传输具有 11 位标准标识符和最大填充位的 CAN 消息需要 271 us。我的代码中没有明显的问题,瓶颈只是 CAN 消息在总线上传输的速度有多快。

关于c - 如何提高 LPC1788 微 Controller 调用 CAN IRQ 的速率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25759955/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com