本文档是在AT91SAM9X25平台上进行SylixOS CAN总线驱动开发时,对CAN总线底层传输流程的解析。
适用于正在学习CAN总线驱动的技术工程师。
CAN总线的传输流程可以分成两个部分:
一部分是CAN总线的发送流程,主要工作是将准备发送的数据填充到对应的寄存器,并使能开始传输位和邮箱中断位;另一部分是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) | AT91_MID_MIDE;/* 扩展帧ID */ } else { uiRegMid = (pcanFrame->CAN_uiId & CAN_SFF_MASK) << 18; /* 标准帧ID */ } uiRegMcr = (pcanFrame->CAN_bRtr & 1 ? AT91_MCR_MRTR : 0) | (pcanFrame->CAN_ucLen << 16) | AT91_MCR_MTCR; writel((MB_MODE_DISABLED << 24) | SET_PRIO_IS_0, /* 写ID时,将邮箱设为禁用模式 */ REG_CAN_MMR(CHANNEL, MB_TX)); writel(uiRegMid, REG_CAN_MID(CHANNEL, MB_TX)); /* 将ID写到对应寄存器 */ writel((MB_MODE_TX << 24) | SET_PRIO_IS_0, /* 设置为TX模式 */ REG_CAN_MMR(CHANNEL, MB_TX)); if (!(readl(REG_CAN_MSR(CHANNEL, MB_TX)) & AT91_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) { 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)); /* This triggers transmission */ writel((1 << MB_TX), REG_CAN_IER(CHANNEL)); /* 使能发送邮箱中断 */ return (LW_TRUE); }
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); }
内部交流文档,仅针对AT91SAM9X25相关平台,若发现相关错误或者建议,请及时联系文档创建者进行修订和更新。
SylixOS 基于AT91SAM9X25的CAN总线传输流程解析
原文地址:http://12558316.blog.51cto.com/12548316/1925839