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年进入阿里一直到现在。**
**深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/257ae0e5e3303550f1a3f19d3985dd72.png)
![img](https://img-blog.csdnimg.cn/img_convert/9fbf5b4549b03a8f8a7b2460ac809821.jpeg)
![img](https://img-blog.csdnimg.cn/img_convert/8be15896309e2b1b075ac3fe881400d5.png)
![img](https://img-blog.csdnimg.cn/img_convert/a4eb21847357b0e5ca51b9230960088f.png)
![img](https://img-blog.csdnimg.cn/img_convert/13f0669ccd1dca4f5c2e6f8254f494b9.png)
![img](https://img-blog.csdnimg.cn/img_convert/0451dd0110d6393e952a6e183288e34f.png)
![](https://img-blog.csdnimg.cn/img_convert/28a7fdf5d39ae3c65e7afb1a7a1fbeba.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!
资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[**如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618654289)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**!!