SylixOS 基于AT91SAM9X25的CAN总线传输流程解析

  1. 概述

    本文档是在AT91SAM9X25平台上进行SylixOS CAN总线驱动开发时,对CAN总线底层传输流程的解析。

    适用于正在学习CAN总线驱动的技术工程师。

     

  2. 技术实现

    CAN总线的传输流程可以分成两个部分:

    一部分是CAN总线的发送流程,主要工作是将准备发送的数据填充到对应的寄存器,并使能开始传输位和邮箱中断位;另一部分是CAN总线的中断处理流程,主要工作是对触发中断的中断源进行判断,并对不同的中断进行相关处理。

  3. CAN总线的发送流程

    AT91SAM9X25平台上,CAN总线发送流程如图 21所示。在填写数据的帧ID时,必须要将邮箱设置为禁用模式。正常情况下,当我们将数据填充完成,开始发送数据时,就可以在总线上测到我们发送的数据。这里使能的邮箱中断是传输完成中断。

    21 CAN总线的发送流程图

    具体的代码实现如程序清单 21所示。

    程序清单 21 CAN总线的传输函数

    /*********************************************************************************************************
    ** 函数名称: __canTransmit
    ** 功能描述: CAN的传输
    ** 输    入: pChannel     通道对象
    **           pcanFrame    can帧结构体指针
    ** 输    出:
    ** 返    回: LW_FALSE     传输出错
    **           LW_TRUE      传输成功
    *********************************************************************************************************/
    static INT  __canTransmit (__PCAN_CHANNEL  pChannel,
                               CAN_FRAME      *pcanFrame)
    {
        UINT uiRegMid;
        UINT uiRegMcr;
    
        if (pcanFrame->CAN_bExtId) {                                        /*  如果是扩展帧                */
            uiRegMid = (pcanFrame->CAN_uiId & CAN_EFF_MASK) | CAN_MID_MIDE;
        } else {                                                            /*  如果是标准帧                */
            uiRegMid = (pcanFrame->CAN_uiId & CAN_SFF_MASK) << CAN_MID_MIDVA_SHIFT;
        }
        uiRegMcr = (pcanFrame->CAN_bRtr & 1 ? CAN_MCR_MRTR : 0)  |
                    (pcanFrame->CAN_ucLen << CAN_MSR_MDLC_SHIFT) |
                    CAN_MCR_MTCR;
    
        writel((MB_MODE_DISABLED) | SET_PRIO_IS_0,                          /*  写ID时,将邮箱设为禁用模式  */
               REG_CAN_MMR(CHANNEL, MB_TX));
        writel(uiRegMid, REG_CAN_MID(CHANNEL, MB_TX));                      /*  将ID写到对应寄存器          */
        writel((MB_MODE_TX) | SET_PRIO_IS_0,                                /*  设置为TX模式                */
               REG_CAN_MMR(CHANNEL, MB_TX));
    
        if (!(readl(REG_CAN_MSR(CHANNEL, MB_TX)) & CAN_MSR_MRDY)) {
            printk("TX Mailbox is busy!\n");
            return (LW_FALSE);
        }
    
        if (pcanFrame->CAN_ucLen > 0) {                                     /*  如果有数据                  */
            UINT uiDataL;
            uiDataL  = pcanFrame->CAN_ucData[0] << 0;
            uiDataL += pcanFrame->CAN_ucData[1] << 8;
            uiDataL += pcanFrame->CAN_ucData[2] << 16;
            uiDataL += pcanFrame->CAN_ucData[3] << 24;
            writel(uiDataL, REG_CAN_MDL(CHANNEL, MB_TX));                   /*  填充数据寄存器              */
        }
        if (pcanFrame->CAN_ucLen > 3) {                                     /*  超过4个字节数据             */
            UINT uiDataH;
            uiDataH  = pcanFrame->CAN_ucData[4] << 0;
            uiDataH += pcanFrame->CAN_ucData[5] << 8;
            uiDataH += pcanFrame->CAN_ucData[6] << 16;
            uiDataH += pcanFrame->CAN_ucData[7] << 24;
            writel(uiDataH, REG_CAN_MDH(CHANNEL, MB_TX));                   /*  填充数据寄存器              */
        }
    
        writel(uiRegMcr, REG_CAN_MCR(CHANNEL, MB_TX));                      /*  触发传输                    */
        writel((1 << MB_TX), REG_CAN_IER(CHANNEL));                         /*  使能发送邮箱中断            */
    
        return (LW_TRUE);
    }

    
    
     

  4. CAN总线的中断处理流程

    CAN总线的中断处理流程如图 22所示。在AT91SAM9X25平台上,读状态寄存器(REG_CAN_SR)就可以清除中断标志位。通过对状态寄存器和中断屏蔽寄存器的比较,可以判断出是哪一种中断,并进行相应的处理。

    22 CAN总线的中断处理流程图

    具体代码实现如程序清单 22所示。

     

    程序清单 22 CAN总线的中断处理函数

    /*********************************************************************************************************
    ** 函数名称: __canIrq
    ** 功能描述: 中断服务函数
    ** 输  入  : pCanchan         通道对象
    **           ulVector         中断向量号
    ** 输  出  : LW_IRQ_HANDLED   系统中断返回值
    **           LW_IRQ_NONE      系统中断返回值
    *********************************************************************************************************/
    static irqreturn_t __canIrq (__PCAN_CHANNEL  pChannel, ULONG  ulVector)
    {
        UINT  uiRegSr;
        UINT  uiRegImr;
        UINT  uiRxOrErr;
    
        uiRegSr  = readl(REG_CAN_SR(CHANNEL));                              /*  清除中断标志位              */
        uiRegImr = readl(REG_CAN_IMR(CHANNEL));
        uiRegSr &= uiRegImr;
        if (!uiRegSr) {
            goto exit;
        }
    
        /*
         *  Rx和错误中断
         */
        uiRxOrErr = ((1 << MB_RX)                                           /*  RX和错误中断的中断位        */
                     | AT91_IRQ_ERR_FRAME);
        if (uiRegSr & uiRxOrErr) {
            if (uiRegSr & (1 << MB_RX)) {
                __canReadMsg(pChannel);
            } else {
                _DebugFormat(__PRINTMESSAGE_LEVEL, "__canIrq: Frame error!\r\n");
                readl(REG_CAN_SR(CHANNEL));                                 /*  清除错误中断标志位          */
                return (LW_IRQ_NONE);
            }
        }
    
        /*
         *  Tx中断
         */
        if (uiRegSr & (AT91_MB_MASK(MAILBOXES_NUM) & (~AT91_MB_MASK(MB_TX)))) {
            writel(1 << MB_TX, REG_CAN_IDR(CHANNEL));                       /*  禁用发送邮箱的中断          */
        }
    
    exit:
        return (LW_IRQ_HANDLED);
    }
    

     

  5. 免责声明

    内部交流文档,仅针对AT91SAM9X25相关平台,若发现相关错误或者建议,请及时联系文档创建者进行修订和更新。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值