rt-thread CAN驱动框架_rt-thread can hdr_bank

本文详细解释了RT-Can库中关于消息列表管理、硬件过滤器配置、open流程(包括RX/FXFIFO初始化)以及接收流程(包括过滤器配置和接收ISR)的过程,着重展示了如何根据硬件过滤器配置决定消息的挂载位置。
摘要由CSDN通过智能技术生成

rt_can_msg_list

list :list指针。通过该变量,将msg_list挂载到freelist或uselist
hdrlist :hdrlist指针。如果当前接收的msg的hdr值所对应的硬件过滤器已使能(可参考过滤器配置),则该msg不仅会挂载到uselist链表,同时也会挂载到所对应硬件过滤器的list链表,如上图中的msg0/1,不仅挂载在uselist链表,同时也挂载在hdr0的list链表。如果当前接收的msg的hdr值所对应的硬件过滤器未使能,则该msg只会加入到uselist链表,而不会加入到硬件过滤器的链表,如上图中的msg2。

rt_can_filter_item

硬件过滤器配置项描述结构体
id :该过滤器需要过滤的id
ide :该过滤器是过滤标准帧还是扩展帧
rtr :该过滤器是过滤数据帧还是远程帧
hdr_bank :该过滤器编号

rt_can_filter_config

硬件过滤器配置描述结构体
count :该config包含几个硬件过滤器
actived :是否激活硬件过滤器
items :指向硬件过滤器数组的指针,数组中可能包含多个硬件过滤器配置,每个数组元素对应一个硬件过滤器的配置

rt_can_hdr

connected :指示该硬件过滤器是否连接。若硬件过滤器配置项rt_can_filter_item中的hdr_bank为-1,则在设置时不会将contected置1
msgs :该硬件过滤器接收了多少个msg
filter :硬件过滤器配置项。在设置硬件过滤器时,会从rt_can_filter_config中复制到该filter
list :用于挂载该硬件过滤器接收到的msg

2.open流程

static rt\_err\_t rt\_can\_open(struct rt\_device \*dev, rt\_uint16\_t oflag)
{
	if (can->can_rx == RT_NULL)
    {
        if (oflag & RT_DEVICE_FLAG_INT_RX)
        {
            int i = 0;
            struct rt\_can\_rx\_fifo \*rx_fifo;
			//为 rx\_fifo 分配空间,RTT默认分配16个 rt\_can\_msg\_list,即可接收16个CAN消息。
			//16个CAN消息的存储空间在 struct rt\_can\_rx\_fifo 结构体后面
            rx_fifo = (struct rt\_can\_rx\_fifo \*) rt\_malloc(sizeof(struct rt\_can\_rx\_fifo) +
                      can->config.msgboxsz \* sizeof(struct rt\_can\_msg\_list));
            RT\_ASSERT(rx_fifo != RT_NULL);
			//获取第一个struct rt\_can\_msg\_list的地址,并将16个struct rt\_can\_msg\_list清0
            rx_fifo->buffer = (struct rt\_can\_msg\_list \*)(rx_fifo + 1);
            rt\_memset(rx_fifo->buffer, 0, can->config.msgboxsz \* sizeof(struct rt\_can\_msg\_list));
            //初始化freelist和uselist
            rt\_list\_init(&rx_fifo->freelist);
            rt\_list\_init(&rx_fifo->uselist);
            //设置freenumbers初始值,RTT默认配置为16
            rx_fifo->freenumbers = can->config.msgboxsz;
            for (i = 0;  i < can->config.msgboxsz; i++)
            {
            	//将struct rt\_can\_msg\_list加入到freelist链表
                rt\_list\_insert\_before(&rx_fifo->freelist, &rx_fifo->buffer[i].list);
#ifdef RT\_CAN\_USING\_HDR
				//初始化struct rt\_can\_msg\_list的hdrlist
                rt\_list\_init(&rx_fifo->buffer[i].hdrlist);
                rx_fifo->buffer[i].owner = RT_NULL;
#endif
            }
            //将rx\_fifo赋值给can\_rx
            can->can_rx = rx_fifo;
        }
    }

	if (can->can_tx == RT_NULL)
    {
        if (oflag & RT_DEVICE_FLAG_INT_TX)
        {
            int i = 0;
            struct rt\_can\_tx\_fifo \*tx_fifo;
			//为tx\_fifo分配空间
            tx_fifo = (struct rt\_can\_tx\_fifo \*) rt\_malloc(sizeof(struct rt\_can\_tx\_fifo) +
                      can->config.sndboxnumber \* sizeof(struct rt\_can\_sndbxinx\_list));
            RT\_ASSERT(tx_fifo != RT_NULL);

            tx_fifo->buffer = (struct rt\_can\_sndbxinx\_list \*)(tx_fifo + 1);
            rt\_memset(tx_fifo->buffer, 0,
                    can->config.sndboxnumber \* sizeof(struct rt\_can\_sndbxinx\_list));
            rt\_list\_init(&tx_fifo->freelist);
            for (i = 0;  i < can->config.sndboxnumber; i++)
            {
                rt\_list\_insert\_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list);
                rt\_completion\_init(&(tx_fifo->buffer[i].completion));
                tx_fifo->buffer[i].result = RT_CAN_SND_RESULT_OK;
            }

            rt\_sprintf(tmpname, "%stl", dev->parent.name);
            //初始化信号量sem,RTT默认配置can->config.sndboxnumber为1,即sem初始值为1
            rt\_sem\_init(&(tx_fifo->sem), tmpname, can->config.sndboxnumber, RT_IPC_FLAG_FIFO);
            can->can_tx = tx_fifo;
        }
    }
	//初始化硬件过滤器
	if (can->hdr == RT_NULL)
    {
        int i = 0;
        struct rt\_can\_hdr \*phdr;
		//为硬件过滤器分配空间
        phdr = (struct rt\_can\_hdr \*) rt\_malloc(can->config.maxhdr \* sizeof(struct rt\_can\_hdr));
        RT\_ASSERT(phdr != RT_NULL);
        rt\_memset(phdr, 0, can->config.maxhdr \* sizeof(struct rt\_can\_hdr));
        for (i = 0;  i < can->config.maxhdr; i++)
        {
        	//初始化硬件过滤器的list链表
            rt\_list\_init(&phdr[i].list);
        }

        can->hdr = phdr;
    }
}

3.接收流程

3.1.过滤器配置

CAN框架通过struct rt_can_filter_item配置每个硬件过滤器的具体配置:需要过滤的ID,是否是扩展帧/远程帧,以及配置硬件过滤器的hdr_bank(即硬件过滤器号)。框架支持配置多个硬件过滤器,多个硬件过滤器统一通过struct rt_can_filter_config进行管理。设置硬件过滤器通过rt_device_control接口配置。配置过程如下:

case RT_CAN_CMD_SET_FILTER:
		//调用芯片硬件底层驱动,将过滤器配置设置到寄存器
        res = can->ops->control(can, cmd, args);

        if (pfilter->actived)
        {
        	//通过while循环逐个设置硬件过滤器
            while (count)
            {
            	//如果hdr == -1或hdr >= can->config.maxhdr,则直接开始下一次循环
                if (pitem->hdr_bank >= can->config.maxhdr || pitem->hdr_bank < 0)
                {
                    count--;
                    pitem++;
                    continue;
                }
                level = rt\_hw\_interrupt\_disable();
                //contected为0,则进行配置
                if (!can->hdr[pitem->hdr_bank].connected)
                {
                    rt\_hw\_interrupt\_enable(level);
                    //将硬件过滤器的配置复制到can->hdr[].filter
                    rt\_memcpy(&can->hdr[pitem->hdr_bank].filter, pitem,
                              sizeof(struct rt\_can\_filter\_item));
                    level = rt\_hw\_interrupt\_disable();
                    //将contected赋值为1
                    can->hdr[pitem->hdr_bank].connected = 1;
                    can->hdr[pitem->hdr_bank].msgs = 0;
                    rt\_list\_init(&can->hdr[pitem->hdr_bank].list);
                }
                rt\_hw\_interrupt\_enable(level);

                count--;
                pitem++;
            }
        }

由上述配置流程可知,CAN模块可以配置多个硬件过滤器(最大可配置硬件过滤器数量不超过can->config.maxhdr)。只有在rt_can_filter_item配置项中hdr_bank不等于-1,且小于can->config.maxhdr时,才会初始化硬件过滤器的list链表,在接收到msg时,才会把该msg也加入到硬件过滤器的list链表。否则,接收的msg只会加入到uselist链表。

3.2.接收isr

rt_hw_can_isr
{
	case RT_CAN_EVENT_RX_IND:
		/\* 调用底层驱动,接收CAN消息 \*/
		can->ops->recvmsg(can, &tmpmsg, no);
		
		/\* 接收消息数自增 \*/
		can->status.rcvpkg++;
        can->status.rcvchange = 1;

		if (!rt\_list\_isempty(&rx_fifo->freelist)) /\* freelist 链表不为空,即有空闲的 struct rt\_can\_msg\_list \*/
		{
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/074b336e75ee48d5075045c55b2930ee.png)

![img](https://img-blog.csdnimg.cn/img_convert/f499232cbb1be5b4fc04924332dbfe20.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/0118002e1afc597f65ecc33bd3981abd.png)

 **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

![img](https://img-blog.csdnimg.cn/img_convert/bfacf6496aa6e3906972400637c0a588.png)

![img](https://img-blog.csdnimg.cn/img_convert/4e35300d4acbd05f1732eaa38ea26720.png)

 

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**

<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />



# 最后

**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**

**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**

!! (备注:嵌入式)**

<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />



# 最后

**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**

**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**

**[更多资料点击此处获qu!!](https://bbs.csdn.net/topics/618376385)**
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值