This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F280049C: 三板间的CAN通信

Part Number: TMS320F280049C


我的功能是主控板通过CANA下发查询命令查询另外两块板的电流和电压,然后通过CANB发送到显示面板上,我遇到的问题是:我的主控板的通信没有出过问题,但是我两个副板总会有一个(比较随机有时是1号有时是2号)突然无法通信,我用仿真器加断点发现它已经无法触发CAN的中断了。

查询的频率是在一个由ECAP产生的1Khz的中断中发布查询,而且两块板之间是轮询查的中断第一次查1号板,第二次查2号板这样循环

三个板子我用的是同一套代码

初始化程序:

//初始化函数
void HAL_setupCAN()
{
    //配置IO 30、31引脚
    GPIO_setPinConfig(CANRXA_GPIO_CFG);
    GPIO_setPinConfig(CANTXA_GPIO_CFG);
    GPIO_setPinConfig(CANRXB_GPIO_CFG);
    GPIO_setPinConfig(CANTXB_GPIO_CFG);
    // 初始化CAN控制器
    CAN_initModule(CANA_BASE);
    CAN_initModule(CANB_BASE);
    // 设置CAN,使用CANA,系统时钟,波特率500KHz,位时序20Tq
    CAN_setBitRate(CANA_BASE, DEVICE_SYSCLK_FREQ, 1000000, 20);
    CAN_setBitRate(CANB_BASE, DEVICE_SYSCLK_FREQ, 500000, 20);
    // 使能CAN中断
    CAN_enableInterrupt(CANA_BASE, CAN_INT_ERROR|CAN_INT_STATUS|CAN_INT_IE0);
    CAN_enableInterrupt(CANB_BASE, CAN_INT_ERROR|CAN_INT_STATUS|CAN_INT_IE0);
//    CAN_enableInterrupt(CANA_BASE, CAN_INT_STATUS|CAN_INT_IE0);
//    CAN_enableInterrupt(CANB_BASE, CAN_INT_STATUS|CAN_INT_IE0);

    CAN_enableRetry(CANA_BASE);
    CAN_enableRetry(CANB_BASE);
    // 配置CANA0中断
    Interrupt_register(INT_CANA0, &canAISR);//wait replenish
    Interrupt_register(INT_CANB0, &canISR);
    // 使能CANA0中断
    Interrupt_enable(INT_CANA0);
    Interrupt_enable(INT_CANB0);
    CAN_enableGlobalInterrupt(CANA_BASE, CAN_GLOBAL_INT_CANINT0);
    CAN_enableGlobalInterrupt(CANB_BASE, CAN_GLOBAL_INT_CANINT0);
    //
    // Initialize the transmit message object used for sending CAN messages.
    // Message Object Parameters:
    //      Message Object ID Number: 邮箱ID
    //      Message Identifier: CAN_ID
    //      Message Frame: 数标准格式
    //      Message Type: 非远程发送
    //      Message ID Mask: 无消息拓展
    //      Message Object Flags: 发送中断标志位使能
    //      Message Data Length: 数据长度8字节
    //
    CAN_setupMessageObject(CANA_BASE, TX_MSG_OBJ_ID, CAN_ID, CAN_MSG_FRAME_STD,
                           CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_TX_INT_ENABLE,
                           Can_DATA_LENGTH);
    CAN_setupMessageObject(CANB_BASE, TX_MSG_OBJ_ID, CAN_ID, CAN_MSG_FRAME_STD,
                           CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_TX_INT_ENABLE,
                           Can_DATA_LENGTH);
    //
    // Initialize the receive message object used for receiving CAN messages.
    // Message Object Parameters:
    //      Message Object ID Number: 邮箱ID
    //      Message Identifier: CAN_ID
    //      Message Frame: 数据标准格式
    //      Message Type: 非远程接收
    //      Message ID Mask: 无消息拓展
    //      Message Object Flags: 接收中断使能
    //      Message Data Length: 8 Bytes
    //
    CAN_setupMessageObject(CANA_BASE, RX_MSG_OBJ_ID, CAN_ID, CAN_MSG_FRAME_STD,
                           CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_RX_INT_ENABLE,
                           Can_DATA_LENGTH);
    CAN_setupMessageObject(CANB_BASE, RX_MSG_OBJ_ID, CAN_ID, CAN_MSG_FRAME_STD,
                           CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_RX_INT_ENABLE,
                           Can_DATA_LENGTH);

    // 启动CAN模块
    CAN_startModule(CANA_BASE);
    CAN_startModule(CANB_BASE);
}

中断程序:

// 中断处理函数
interrupt void canISR(void)
{
    uint32_t status;
    // 读取CAN中断状态,获得中断标志位
    status = CAN_getInterruptCause(CANB_BASE);
    if(status == CAN_INT_INT0ID_STATUS)
    {
        // 读取控制器状态。这将返回一个状态错误位字段,该字段可以指示各种错误。
        // 为了简单起见,本例中没有进行错误处理。
        // 有关错误状态位的详细信息,请参考API文档。
        // 读取此状态的行为将清除中断。
        status = CAN_getStatus(CANB_BASE);
        // 检查是否发生错误。
        if (((status & ~(CAN_STATUS_TXOK | CAN_STATUS_RXOK)) != 7)
                && ((status & ~(CAN_STATUS_TXOK | CAN_STATUS_RXOK)) != 0))
        {    // Set a flag to indicate some errors may have occurred.
            CAN_clearInterruptStatus(CANB_BASE,CAN_INT_INT0ID_STATUS);
            CAN_clearInterruptStatus(CANB_BASE, TX_MSG_OBJ_ID);
            CAN_clearInterruptStatus(CANB_BASE, RX_MSG_OBJ_ID);
        }
    }
    else if (status == TX_MSG_OBJ_ID) // 为发送中断
    {
        // 到达这一点意味着TX中断发生
        // 并且消息TX已经完成
        // 清除中断标志
        CAN_clearInterruptStatus(CANB_BASE, TX_MSG_OBJ_ID);
    }

    else if (status == RX_MSG_OBJ_ID) // 为接收中断
    {
        CAN_List_FLAG[CAN_List_Num] = 1;//改变队列标志位
        // 获取接收到的信息
        CAN_readMessage(CANB_BASE, RX_MSG_OBJ_ID, CanMsgData[CAN_List_Num]);
        // 队列计数+1
        CAN_List_Num++;
        if(CAN_List_Num >= CAN_DATA_LIST)
            CAN_List_Num = 0;

        // 到达这一点意味着RX中断发生在消息对象2上,消息RX完成了。
        // 清除消息对象中断。
        CAN_clearInterruptStatus(CANB_BASE, RX_MSG_OBJ_ID);

    }

    else  { // 如果意外的事情导致中断,这将处理它。
        CAN_clearInterruptStatus(CANB_BASE, RX_MSG_OBJ_ID);
        CAN_clearInterruptStatus(CANB_BASE, TX_MSG_OBJ_ID);
    }

    // 清除CAN中断线路的全局中断标志
    CAN_clearGlobalInterruptStatus(CANB_BASE, CAN_GLOBAL_INT_CANINT0);

    // 这个位于第9组的中断
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}
interrupt void canAISR(void)
{
    uint32_t status;
    // 读取CAN中断状态,获得中断标志位
    status = CAN_getInterruptCause(CANA_BASE);
    if(status == CAN_INT_INT0ID_STATUS)
    {
        // 读取控制器状态。这将返回一个状态错误位字段,该字段可以指示各种错误。
        // 为了简单起见,本例中没有进行错误处理。
        // 有关错误状态位的详细信息,请参考API文档。
        // 读取此状态的行为将清除中断。
        status = CAN_getStatus(CANA_BASE);
        // 检查是否发生错误。
        if (((status & ~(CAN_STATUS_TXOK | CAN_STATUS_RXOK)) != 7)
                && ((status & ~(CAN_STATUS_TXOK | CAN_STATUS_RXOK)) != 0))
        {    // Set a flag to indicate some errors may have occurred.
            CAN_clearInterruptStatus(CANA_BASE,CAN_INT_INT0ID_STATUS);
        }
    }
    else if (status == TX_MSG_OBJ_ID) // 为发送中断
    {
        // 到达这一点意味着TX中断发生
        // 并且消息TX已经完成
        // 清除中断标志
        CAN_clearInterruptStatus(CANA_BASE, TX_MSG_OBJ_ID);
    }

    else if (status == RX_MSG_OBJ_ID) // 为接收中断
    {
        CANA_List_FLAG[CANA_List_Num] = 1;//改变队列标志位
        // 获取接收到的信息
        CAN_readMessage(CANA_BASE, RX_MSG_OBJ_ID, CanAMsgData[CANA_List_Num]);
        // 队列计数+1
        CANA_List_Num++;
        if(CANA_List_Num >= CAN_DATA_LIST)
            CANA_List_Num = 0;

        // 到达这一点意味着RX中断发生在消息对象2上,消息RX完成了。
        // 清除消息对象中断。
        CAN_clearInterruptStatus(CANA_BASE, RX_MSG_OBJ_ID);

    }

    else  { // 如果意外的事情导致中断,这将处理它。
        CAN_clearInterruptStatus(CANA_BASE, RX_MSG_OBJ_ID);
        CAN_clearInterruptStatus(CANA_BASE, TX_MSG_OBJ_ID);
    }

    // 清除CAN中断线路的全局中断标志
    CAN_clearGlobalInterruptStatus(CANA_BASE, CAN_GLOBAL_INT_CANINT0);

    // 这个位于第9组的中断
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

我在TI的例程中没有看到具体的CAN错误处理,我有看到他有查询错误,但是最多就是记录出错次数,想问一下如果遇到这种出错的正常你们是怎么做的?

  • 您好,我们已收到您的问题并升级到英文论坛寻求帮助,由于明天假期,我们可能无法及时将回复转达给您,您可以自行查看以下链接来获取最新进展:

    e2e.ti.com/.../tms320f280049c-can-communication-between-3-boards

  • 您好,

    很明显由于3个节点之间的通信没问题,那么硬件是没有问题的。应该是您代码间歇性的问题。 很抱歉我们无法帮忙debug此类问题。 唯一可以给出的建议是去除代码中的所有其他内容,仅保留 CAN 部分并测试通信。 然后您可以逐步将模块添加到您的代码中,来识别问题在哪里。

  • 虽然不确定是不是这个问题造成的,但我在初始化添加了

    CAN_enableAutoBusOn(CANA_BASE);//当出现总线关闭的情况时,能够自动重启
    CAN_enableAutoBusOn(CANB_BASE);//当出现总线关闭的情况时,能够自动重启
    CAN_setAutoBusOnTime(CANA_BASE,100);//1MS
    CAN_setAutoBusOnTime(CANB_BASE,100);//1MS

    这段话后好像就没有再出现这种情况了

  • 应该还是有问题存在,只是你让CAN总线自动重启了。

    1、不需要定时发送查询帧,只需要另外两块板定时将你需要的信息发到CAN总线上就可以,主控板按照协议进行解析

    2、你的目前主控板板发送CAN报文的频率太快了(1ms一帧),你放到10ms或者20模式试试,把上面添加的代码屏蔽掉应该也可以