电子说
一.准备
基于RT-Thread Studio
1.1安装BSP包
注意GNU工具链版本
1.2 芯片资料
1.3FSP
1.4代码仓库
1.5创建工程
菜单栏
文件->新建->RT-Thread项目
设置如下
接上串口P205 P206
115200-8-N-1
二.CAN模块硬件部分介绍
TP5设置了一个测试点,可以测试Vref的VDD/2的电压,辅助确认芯片是否正常。
R76 R77构成了120欧终端电阻,C67起到滤波作用,这个电容不能大,否则影响高速时信号边沿,导致边沿变迟缓可能导致采样错误。
RS用于Slope-Control控制输入,默认接GND即High-Speed模式。
三.CAN模块介绍
参考《Renesas RA6M3 Group User’s Manual: Hardware》的《37. Controller Area Network (CAN) Module》
3.1特征
支持ISO11898-1 标准和扩展帧
支持最高1 Mbps
32个消息邮箱:每一个都可以独立配置为接收或发送;或者24个配置为接受或发送,剩余的8个配置为4级收发FIFO。
支持数据帧和远程帧接收,可配置只接收标准帧或者扩展帧或者混合帧,可配置单次接收模式,可配置溢出时数据是保存还是丢弃,每个邮箱可单独配置接收完成中断使能。
4个邮箱共用一个,一共8个接收过滤器,每个邮箱可单独使能过滤。
支持数据帧和远程帧发送,可配置只发送标准帧或者扩展帧或者混合帧,可配置单次发送模式,广播功能,优先级可由ID或者邮箱序号决定,支持发送中止且有中止完成标志,每个邮箱可单独配置接发送成中断使能。
从总线断开状态恢复的模式转换可选择为:1.符合ISO11898-1规范2.总线断开进入时自动进入CAN停止模式3.总线断开完成时自动进入CAN停止模式4.通过软件进入CAN停止模式5.通过软件转换到错误活动状态。
监控CAN总线错误,包括填充错误、格式错误、ACK错误、15位CRC错误、位错误和ACK分隔符错误。检测到错误状态的转换,包括错误警告、被动错误、总线关闭进入和总线关闭恢复。支持读取错误计数器。
使用16位计数器的时间戳功能,可选择1位、2位、4位和8位时间周期的参考时钟
支持五种中断源:接收完成、发送完成、接收FIFO、发送FIFO和错误中断。
停止CAN时钟以降低功耗。
三个软件支持单元:接收过滤器;邮箱搜索支持,包括接收邮箱搜索、发送邮箱搜索和邮件丢失搜索;通道搜索支持。
时钟源来自PCLKB 或 CANMCLK
可用于评估的三种测试模式:仅听模式;自检模式0(外部环回);自检模式1(内部环回)。
可以设置模块停止状态以降低功耗.
3.2框图
3.3操作模式
CAN模块的操作模式包括:CAN复位模式,CAN停止模式,CAN操作模式,CAN睡眠模式。状态切换如下图:
3.4时序设置
时序设置很重要
时钟源
CAN模块有一个CAN时钟发生器,可通过BCR寄存器中的CCLKS和BRP[9:0]位进行设置。图显示了CAN时钟发生器的框图
CCLKS选择时钟源来自与PCLKB还是EXTAL
BPR设置时钟分频最后得到fCANCLK
3.5时序设置
3.6中断
四.CAN驱动介绍
4.1添加CAN驱动
按如下设置并保存,也可以使用env设置
添加的代码位置如下
4.2使能硬件CAN
右键点击工程,打开env环境
4.3测试代码
CANboardSConscript下添加
if GetDepend(['RT_USING_CAN']):
src += Glob('ports/can_test.c')
刷新scons配置
添加的测试代码如下
该代码使用can0,创建接收线程接收can数据,接收到后打印信息,同时导出命令can_sample,执行一次命令发送一帧CAN数据。
五.回环测试
rt_device_open后添加一行,设置为回环模式
rt_device_control(can_dev,RT_CAN_CMD_SET_MODE,RT_CAN_MODE_LOOPBACK);
编译运行,help可以看到对应的命令can_sample
六.问题
can_sample can0
只能执行一次
static rt_device_t can_dev = NULL;
设置只有未初始化才初始化
if(can_dev == NULL)
{
if (argc == 2)
{
rt_strncpy(can_name, argv[1], RT_NAME_MAX);
}
else
{
rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
}
can_dev = rt_device_find(can_name);
if (!can_dev)
{
rt_kprintf("find %s failed!n", can_name);
return RT_ERROR;
}
rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
RT_ASSERT(res == RT_EOK);
rt_device_control(can_dev,RT_CAN_CMD_SET_MODE,RT_CAN_MODE_LOOPBACK);
thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
rt_kprintf("create can_rx thread failed!n");
}
}
这样就可以反复进行can_sample测试
七.CAN驱动分析
7.1测试代码
boardportscan_test.c
见前面的测试
7.2硬件抽象层
librariesHAL_Driversdrv_can.c drv_can.h
导出了初始化函数,启动时自动根据链接脚本放置的位置调用该函数
INIT_BOARD_EXPORT(rt_hw_can_init);
通过接口
result = rt_hw_can_register(&can_obj[i].can_dev, can_obj[i].config->name, can_obj[i].can_dev.ops, RT_NULL);
注册几个关键的数据结构
重点是如下结构体,即操作底层硬件的接口,驱动层即通过注册的该opt结构进行底层硬件操作
const struct rt_can_ops ra_can_ops =
{
.configure = ra_can_configure,
.control = ra_can_control,
.sendmsg = ra_can_sendmsg,
.recvmsg = ra_can_recvmsg
};
librariesHAL_Driversconfigra2l1can_config.h中的
#if defined(BSP_USING_CAN0)
#ifndef CAN0_CONFIG
#define CAN0_CONFIG
{
.name = "can0",
.num_of_mailboxs = CAN_NO_OF_MAILBOXES_g_can0,
.p_api_ctrl = &g_can0_ctrl,
.p_cfg = &g_can0_cfg,
}
#endif /* CAN0_CONFIG /
#endif / BSP_USING_CAN0 */
则定义的芯片相关的操作数据结构和设备名字。
7.3组件层
rt-threadcomponentsdriverscancan.c
导出了命令
MSH_CMD_EXPORT_ALIAS(cmd_canstat, canstat, stat can device status);
rt_hw_can_register注册以下接口,即组件设备的驱动API
device- >init = rt_can_init;
device- >open = rt_can_open;
device- >close = rt_can_close;
device- >read = rt_can_read;
device- >write = rt_can_write;
device->control = rt_can_control;
7.4设备层
更通用的设备层通过设备名找到设备句柄
rt_device_find
设备打开等操作时rt_device_open通过设备句柄调用组件层的API,
rt_can_open等,而组件层调用硬件抽象层的接口,硬件抽象层再调用IC的固件库实现硬件操作。
八.总结
得益于RT_Thread比较好的设备驱动框架,设备驱动的扩展非常方便,直接配置IC固件库,实现硬件抽象层即可,组件层和设备层驱动都是通用的。
全部0条评论
快来发表一下你的评论吧 !