概述
本文档是在AT91SAM9X25平台上进行SylixOS CAN总线驱动开发时,对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) | 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);
}
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!rn");
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);
}
上一篇:ATMEL AT91SAM9X25 平台的开发流程
下一篇:01-AT91SAM9X25初识
推荐阅读最新更新时间:2024-11-10 15:39