Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1751298
  • 博文数量: 100
  • 博客积分: 10122
  • 博客等级: 上将
  • 技术积分: 4092
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-04 20:28
文章分类

全部博文(100)

文章存档

2010年(2)

2009年(28)

2008年(70)

我的朋友

分类:

2009-02-04 08:11:34

Author : Miao ZhiCheng
Date : Tuesday, February 03 2009

MSCAN(Motorola Scalable Controller Area Network) IP Core 被很多 CAN 控制器所使用。 但由于文档缘故,编写他的中断例程特别是发送中断的处理很困扰人。 这里以 的 为例,把我编写该驱动的过程分享一下。 本文对于其他MSNCAN-based 的 CAN 控制器也可适用, 不过寄存器名以MSCAN的 data-sheet 为准。

接收中断、 超限(Overrun)中断 和 CSC(CAN State Change) 中断

这些中断由 RIER 寄存器打开和关闭。 在控制器离开初始化模式后(通过设置 CTL0)设置RIER为0x7F即可:

        dev_outb(dev, CAN16Z029_RIER, 0x7F);

在中断例程中,这些中断比较好处理: 各中断都会在 RFLG 中相应位上置位, 再该为上重新写入 1 即响应并结束了该中断的等待状态, 代码片段:
    /* received buffer, RXF*/
if (rflg & 0x01) {
CAN_Package_st stCANPkg;

/* decode the package */
DecodePackage(dev, &stCANPkg);
HALCAN_AppRxSignal(pstHALCANObj, &stCANPkg);

dev_outb(dev, CAN16Z029_RFLG, 0x01);
ret = EVENT_HANDLED;
}

/* rx overrun, OVR */
if (rflg & 0x02) {
kprintf("CAN%d OVR\n", pstData->nCANID);
dev_outb(dev, CAN16Z029_RFLG, 0x02);
ret = EVENT_HANDLED;
}

/* status change, CSC */
if (rflg & 0x40) {
kprintf("CAN%d CSCIF\n", pstData->nCANID);
dev_outb(dev, CAN16Z029_RFLG, 0x40);
ret = EVENT_HANDLED;
}
发送中断

这是困扰很多人的地方, 可归咎于 MSNCAN 本身的文档并没有提供详细的例程。 MSCAN 提供三个内部待发送包缓存, 通过 BSEL 寄存器, 驱动每次只能选择其中一个进行操作。 驱动在载入了ID,DATA以及传输优先级寄存器 TXBPR 后,通过清除 TFLG 相应位(设置1), 通知控制器该缓存已就绪。 控制器取出三个缓存中就绪的并且优先级量最小的发送到网络中。发射完毕后设置 TFLG 寄存器,通知驱动发送已完毕。 如果驱动设置了相应的 TIER,那么这个发送完毕事件会出发一个等待的中断。

难点在于,1、如果没有更多包发送了,怎样清除这个等待的中断? 2、如果还有包发送,怎样设置这些寄存器3、如何正确使用 TXBPR 使发送顺序对于程序遵循FIFO 顺序

对于问题一,正确的方法是,如果有包发送,则打开 TIER 位,没有了便关闭。

对于问题二,顺序则很奇怪,在设置任何发送缓存寄存器前,先要关闭 TIER 位,设置完毕后再打开。 如果不这么做,则会收到一个多余的中断(没有任何事件发生)。 这点是最值得注意的地方。

代码片段:
                /* Disable Interrupt when setting tx registers */
tier &= ~nTxFlag;
dev_outb(dev, CAN16Z029_TIER, tier);

/* Set tx registers */
dev_outb(dev, CAN16Z029_BSEL, nTxFlag);
EncodePackage(dev, &stPkg);
dev_outb(dev, CAN16Z029_TXBPR, unPrioNext);

/* Enable Transmit */
dev_outb(dev, CAN16Z029_TFLG, nTxFlag);

/* Enable Interrupt */
tier |= nTxFlag;
dev_outb(dev, CAN16Z029_TIER, tier);

对于问题三,有很多种方法,注意点是:
1. 找出当前最大的有效(传输缓存发送等待中)发送缓存的优先级,加1后分配给下一个待发送的包
2. 当最大优先级到255最大值时,发送被缓存到驱动缓存中,等下次发送中断后再发出
3. 在中断例程中处理这些数据避免可重入问题

因为属于关键算法,具体这里就不给出了。

希望这些能给各自系统编写 MSCAN 驱动的人以一定帮助。

阅读(2186) | 评论(0) | 转发(0) |
0

上一篇:The Reader

下一篇:me on TV

给主人留下些什么吧!~~