【GD32F427开发板试用】三、USB转CAN功能开发与试用总结

news2024/11/15 0:13:28

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:chenjie

【GD32F427开发板试用】一、环境搭建与freertos移植
【GD32F427开发板试用】二、USB库移植与双USB CDC-ACM功能开发
【GD32F427开发板试用】三、USB转CAN功能开发与试用总结

5.CAN功能开发

GD32库的CAN部分函数跟以前ST标准库和现在ST LL库的类似,所以用ST标准库的人应该会比较熟悉。

它的demo程序在GD32F4xx\_Firmware\_Library\Examples\CAN里面,有三个demo,都差不多,直接借鉴它初始化的部分。虽然它example里面用的是F450,不过引脚是兼容的。

GD32F4系列的CAN1引脚和USB ULPI是共用的,所以USB用外部phy的时候,不要初始化CAN1的引脚,只能用一组CAN。

初始化一些参数。这里要注意,F427的总线时钟频率是50M,所以这里的波特率计算方式是50M/((sjw+bs1+bs2)*prescaler),采样率建议选稍微大一点。

配置滤波器和中断,这里选择全部都收,滤波器设置一组不过滤的参数即可。

然后定义中断接收函数。

这里进了中断就必须要用can\_message\_receive把数据收掉,不然会重复进中断。

这里笔者用了一个兵乓缓冲实现RTOS里面中断接收数据。具体实现就不说了,网上大把。

然后写个demo验证一下。

另外硬件上面要接一个收发器。由于板上没有5V的引脚,因此要选个支持3V3的,建议用TI的SN65HVD230。

这里可以评估一下CAN的性能,找个周立功的CAN盒,对着它以最快速度发送。

然后可以在调试模式下看接收了多少条

可以看到周立功的CAN盒发送的条数和开发板接收到的条数一样,可以说明CAN性能足够。

发送就比较简单,因为多数情况下发送的频率不会很高,因此也不用评估它的性能了。

6.USB-CAN 功能开发

最后一篇文章就是对本次试用的最终目标进行开发。USB-CAN,这种设备目前市面上很多,但是开源的不多,能在linux下使用的就更少了。这里笔者使用的是slcan,这个在Linux是有现成驱动的。笔者的目标是用一个USB CDC-ACM复合设备的两个ACM口,对应两路CAN,这样就可以配合上位机,实现类似周立功CAN盒两路CAN的效果。不过有一个点,如果用了USBHS的ULPI接口,那么CAN1就不可用了,而USBFS的endpoint不够,不足以支持两个USB CDC-ACM。因此要想真正实现这种效果,唯一的方法是用USBHS,不加外部PHY,开发板上面不支持这种接口,后续如果自己打板可以这样干。另外Linux下的CDC-ACM驱动不能支持复合设备。

首先要找一个工程模板来移植。canable是一个开源项目,里面就有slcan的支持,他们用的芯片是STM32F072,ST的USB库和GD的差不多,因此移植起来也简单。此工程源码在https://github.com/normaldotcom/canable-fw下。这里只需要用到它的slcan.c 和 slcan.h两个文件。把这两个文件复制到工程目录下,并添加到工程里面。

然后要修改一下头文件和函数的定义。其中slcan\_parse\_frame函数是把can接收到的数据组包为符合slcan协议的数据包,要把原本st库里面的CAN结构体定义改为GD的,另外要添加一个变量,用于标识是哪一路USB的数据/是哪一路CAN的数据。

然后在freertos下面添加两个线程,内容如下

#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"

can_receive_message_struct can0_rxmsg[50] = {0};
can_receive_message_struct can1_rxmsg[50] = {0};
int can0_rxlen = 0;
int can1_rxlen = 0;
unsigned char usb_tx_string_buf[SLCAN_MTU];
unsigned char usb_tx_string_len;

unsigned char cdc_acm_0_rx_data[64 + 1];
int cdc_acm_0_rx_len;
unsigned char cdc_acm_1_rx_data[64 + 1];
int cdc_acm_1_rx_len;

extern int get_usb_cur_state(void);

void can2usb_func(void *pvParameters)
{
    int i = 0;
    vTaskDelay(50);
    while (1) {
//        vTaskDelay(1);
        if(i++ >= 50) {
            vTaskDelay(1);
            i = 0;
        }
        
        can0_rxlen = can_recv_frames(0, can0_rxmsg, 50);
        if (can0_rxlen > 0) {
            // 处理
            for (int i = 0; i < can0_rxlen; i++) {
                usb_tx_string_len += slcan_parse_frame(0, usb_tx_string_buf + usb_tx_string_len, can0_rxmsg + i);
                if(i % 2 == 1 || i == can0_rxlen - 1) {
                    if (get_usb_cur_state() == 0) {
                        dual_cdc_acm_data_send(0, usb_tx_string_buf, usb_tx_string_len);
                    }
                    memset(usb_tx_string_buf, 0, sizeof(usb_tx_string_buf));
                    usb_tx_string_len = 0;
                }
            }
        }

        can1_rxlen = can_recv_frames(1, can1_rxmsg, 50);
        if (can1_rxlen > 0) {
            // 处理
            for (int i = 0; i < can1_rxlen; i++) {
                memset(usb_tx_string_buf, 0, sizeof(usb_tx_string_buf));
                usb_tx_string_len = slcan_parse_frame(1, usb_tx_string_buf, can1_rxmsg + i);
                if (get_usb_cur_state() == 0) {
                    dual_cdc_acm_data_send(1, usb_tx_string_buf, usb_tx_string_len);
                }
            }
        }
    }
}

void usb2can_func(void *pvParameters)
{
    vTaskDelay(20);
    while (1) {
        vTaskDelay(1);
        if (get_usb_cur_state() == 0) {
            memset(cdc_acm_0_rx_data,0,sizeof(cdc_acm_0_rx_data));
            cdc_acm_0_rx_len = dual_cdc_acm_data_receive(0, cdc_acm_0_rx_data, sizeof(cdc_acm_0_rx_data));
            if (cdc_acm_0_rx_len > 0) {
                slcan_parse_str(0, cdc_acm_0_rx_data, cdc_acm_0_rx_len);
            }
            
            memset(cdc_acm_1_rx_data,0,sizeof(cdc_acm_1_rx_data));
            cdc_acm_1_rx_len = dual_cdc_acm_data_receive(1, cdc_acm_1_rx_data, sizeof(cdc_acm_1_rx_data));
            if (cdc_acm_1_rx_len > 0) {
                slcan_parse_str(1, cdc_acm_1_rx_data, cdc_acm_1_rx_len);
            }
        }
    }
}

然后编译,下载到开发板。

Linux端,其源码在drivers/net/can/下。编译的时候,打开下面的选项

然后可以得到slcan.ko。另外还需要can-utils工具,编译之后,得到slcand,cansend,candump几个工具。

将开发板的USBHS插到Linux设备上,会出现/dev/ttyACM0设备节点。此时使用以下命令来开启Linux socketcan功能

insmod slcan.ko  
  
./slcand -o -c -s5 /dev/ttyACM0 slcan0  
  
ifconfig slcan up  
  
ifconfig slcan txqueuelen 1000

其中第一个命令中,-s5意思是指定250k波特率,对应关系如下图

然后就可以使用Linux下面标准的socketcan来进行can数据收发了。cansend是数据发送,candump是数据接收,效果如下图。

7.试用总结

最后总结一下本次试用。本次试用在GD32的库基础上,首先移植了freertos,之后在freertos下调通了USB功能和CAN功能,并在官方的CDC-ACM例程基础上开发了双CDC-ACM复合设备,最后移植了slcan,实现USB-CAN的功能。不足之处有两个,一是开发板并没有把不加外部PHY的USBHS引出来,USB ULPI接口和CAN1冲突,最终只能实现一路CAN的收发。另外一个是Linux下的USB ACM驱动并不能支持复合设备,后面可能需要使用其他的驱动来支持复合设备,比如option驱动。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/185222.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】IO流

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;C语言的输…

04 微服务调用组件Feign

JAVA 项目中如何实现接口调用&#xff1f; 1&#xff09;Httpclient HttpClient 是 Apache Jakarta Common 下的子项目&#xff0c;用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包&#xff0c;并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传统…

linux下Jenkins的安装、部署、启动(完整教程)

linux下Jenkins的安装、部署、启动(完整教程) 一、安装环境 Linux系统Centos 7 二、安装步骤 1、安装jdk8 2、安装jenkins 首先依次如下三个命令&#xff1a; 2.1 导入镜像 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.…

内网渗透之中间人欺骗攻击

ARP攻击协议简介ARP全称为Address Resolution Protocol&#xff0c;即地址解析协议&#xff0c;它是一个根据IP地址获取物理地址的TCP/IP协议&#xff0c;主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机&#xff0c;并接收返回消息&#xff0c;以此确定目标的…

手把手教你QT打包(Windows)

第一步、切换工程版本 在这一步可以直接在QT的项目页面就可以完成 在这里切换完成之后建议先运行一下&#xff0c;确保没有问题我们再进行下一步 第二步、找到对应的文件夹和编译工具进行编译 我们在使用的过成功&#xff0c;会发现点击工程中的运行就可以执行&#xff0c;但是…

MySQL详解(二)——基础 2.0

5. 完整性约束 完整性约束是为了表的数据的正确性&#xff01;如果数据不正确&#xff0c;那么一开始就不能添加到表中。 5.1 主键 当某一列添加了主键约束后&#xff0c;那么这一列的数据就不能重复出现。这样每行记录中其主键列的值就是这一行的唯一标识。例如学生的学号可…

【Linux】基础IO --- 内核级和用户级缓冲区、磁盘结构、磁盘的分治管理、block group块组剖析…

出身寒微&#xff0c;不是耻辱。能屈能伸&#xff0c;方为丈夫。 文章目录一、缓冲区&#xff08;语言级&#xff1a;IO流缓冲&#xff0c;内核级&#xff1a;块缓冲&#xff09;1.观察一个现象2.理解缓冲区存在的意义&#xff08;节省进程IO数据的时间&#xff09;3.语言级缓冲…

commonjs vs ES module in Node.js

在现代软件开发中&#xff0c;模块将软件代码组织成独立的块&#xff0c;这些块共同构成了更大、更复杂的应用程序。 在浏览器 JavaScript 生态系统中&#xff0c;JavaScript 模块的使用依赖于import和export语句&#xff1b;这些语句分别加载和导出 EMCAScript 模块&#xff…

Java SSM (springboot+mybatis)美食菜谱分享平台系统设计和实现以及论文报告

Java SSM (springbootmybatis)美食菜谱分享平台系统设计和实现以及论文报告 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收…

DNS的解析,查询,调度原理是什么?什么是DNS劫持,污染?如何监控?

DNS的核心工作就是将域名翻译成计算机IP地址, 它是基于UDP协议实现的&#xff0c;本文将具体阐述DNS相关的概念&#xff0c;解析&#xff0c;调度原理&#xff08;负载均衡和区域调度&#xff09;等DNS相关的所有知识点DNS简介域名系统并不像电话号码通讯录那么简单&#xff0c…

LeetCode 91. 解码方法 120. 三角形最小路径和 97. 交错字符串 131. 分割回文串 132. 分割回文串 II

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 欢迎来到茶色岛岛屿&#xff0c;本文带来的是LeetCode 91. 解码方法 120. 三角形最小路径和 97. 交错字符串 131. 分割回文串 132. 分割回文串 II &#x1f332;&#x1f332;&#x1f434;&#x1f434; 91. 解码方法…

意图识别和文本分类(六)

一、分类的目的和分类的方法 目标 能够说出项目中进行文本的目的能够说出意图识别的方法能够说出常见的分类的方法 1.1 文本分类的目的 回顾之前的流程&#xff0c;我们可以发现文本分类的目的就是为了进行意图识别 在当前我们的项目的下&#xff0c;我们只有两种意图需要被…

算法刷题打卡第75天:合并两个链表

合并两个链表 难度&#xff1a;中等 给你两个链表 list1 和 list2 &#xff0c;它们包含的元素分别为 n 个和 m 个。 请你将 list1 中下标从 a 到 b 的全部节点都删除&#xff0c;并将 list2 接在被删除节点的位置。 下图中蓝色边和节点展示了操作后的结果&#xff1a; 请你…

php debug yasd手记

yasd 调试器 v0.2.5 版本发布&#xff0c;支持 PHP8 以及在 IDE 中使用调试 - 知乎 GitHub - swoole/yasd: Yet Another Swoole Debugger 安装 yasd 在编译安装之前你需要安装boost库。 macOS&#xff1a; brew install boostUbuntu&#xff1a; apt-get install libboos…

Python编程 装饰器

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;b网络豆的主页​​​​​​ 目录 前言 一.函数 1.装饰器引入 &#xff08;1&#xff09;时间模块 封装函数&am…

软件测试简历没有邀约,为什么?8类细节通通告诉你(附赠高薪简历)

求职不顺&#xff0c;没有邀约&#xff0c;大概率是你的简历出现了问题。本篇文章列出高薪简历应该注意的细节&#xff0c;合计36处&#xff0c;涉及简历的八大组成部分。现在就讲。一、简历样式要求&#xff08;3点要求&#xff09;1、简历格式&#xff0c;推荐使用PDF格式的简…

shopee、lazada跨境电商产品定位和快速获取流量来源是什么?

曹哥首先说的是产品的定位的思路 当确定好具体的经营类目后&#xff0c;就需要去给店铺的商品进行架构分类&#xff0c;一般分为3类&#xff0c;分为爆款&#xff0c;引流款&#xff0c;利润款 关于爆款主要指那些流量高&#xff0c;转化率高&#xff0c;销量高&#xff0c;但…

51单片机学习笔记-9蜂鸣器

9 蜂鸣器 [toc] 注&#xff1a;笔记主要参考B站江科大自化协教学视频“51单片机入门教程-2020版 程序全程纯手打 从零开始入门”。 注&#xff1a;工程及代码文件放在了本人的Github仓库。 9.1 蜂鸣器简介 蜂鸣器 是一种将电信号转换为声音信号的器件&#xff0c;常用来产生…

Hystrix工作步骤说明以及服务监控hystrixDashboard

目录 一、步骤说明和流程解析 二、服务监控hystrixDashboard 官网&#xff1a;How it Works Netflix/Hystrix Wiki GitHub 一、步骤说明和流程解析 1 创建 HystrixCommand&#xff08;用在依赖的服务返回单个操作结果的时候&#xff09; 或 HystrixObserableCommand&am…

threadLocal的分享

问题描述&#xff1a;1、书城首页的书明明是广告解锁的&#xff0c;但是没有free标识&#xff0c;经过多次接口请求得出结论&#xff0c;相同的请求参数&#xff0c;有时会展示出free标识&#xff0c;有时不会展示free标识问题分析&#xff1a;1、长时间分析也没有得出结论&…