GD32双路CAN踩坑记录

GD32双路CAN踩坑记录

目录

  • GD32双路CAN踩坑记录
    • 1 问题描述
    • 2 原因分析
    • 3 解决办法
    • 4 CAN配置参考代码

1 问题描述

GD32的CAN1无法进入接收中断,收不到数据。
注:MCU使用的是GD32E50x,其他型号不确定是否一样,本文只以GD32E50x举例说明。

2 原因分析

GD32的CAN过滤器总共有28个,通过过滤器控制寄存器(CAN_FCTL)打开或关闭,具体如下:

在这里插入图片描述

其中问题就出现在上图的HBC1F上面,CAN0使用的是过滤器编号0到编号(HBC1F-1),CAN1使用的是过滤器编号(HBC1F)到27,而这个默认值是0xE(14),也就是说CAN0默认使用的是编号为0-13的过滤器,CAN1默认使用的是编号为0-27的过滤器,因此,在初始化CAN1的时候,过滤器编号要在这个范围内才能被正确使用,否则是接收不到CAN数据的。

3 解决办法

1、使用编号为15-28的过滤器
2、通过修改CAN_FCTL寄存器的HBC1F,调整过滤器编号的分配
其中GD32固件库有封装函数可以修改HBC1F,函数原形如下:

/*!
    \brief      set CAN1 fliter start bank number
    \param[in]  start_bank: CAN1 start bank number
                only one parameter can be selected which is shown as below:
      \arg        (1..27)
    \param[out] none
    \retval     none
*/
void can1_filter_start_bank(uint8_t start_bank)
{
    /* filter lock disable */
    CAN_FCTL(CAN0) |= CAN_FCTL_FLD;
    /* set CAN1 filter start number */
    CAN_FCTL(CAN0) &= ~(uint32_t)CAN_FCTL_HBC1F;
    CAN_FCTL(CAN0) |= FCTL_HBC1F(start_bank);
    /* filter lock enable */
    CAN_FCTL(CAN0) &= ~CAN_FCTL_FLD;
}

4 CAN配置参考代码

#include "main.h"
#include "stdio.h"

can_trasnmit_message_struct can0_tx_message;
can_trasnmit_message_struct can1_tx_message;
can_receive_message_struct can0_rx_message;
can_receive_message_struct can1_rx_message;

void can0_gpio_config(void)
{
    /* enable CAN0 clock */
    rcu_periph_clock_enable(RCU_CAN0);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_AF);
    /* configure CAN0 GPIO */
    gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP, ENABLE);
}

void can0_config(void)
{
    can_parameter_struct can_parameter;
    can_fdframe_struct can_fd_parameter;
    can_fd_tdc_struct can_fd_tdc_parameter;
    can_filter_parameter_struct can_filter;

    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
    /* initialize CAN register */
    can_deinit(CAN0);

#if 1  // CAN配置
    /* initialize CAN parameters */
    can_parameter.time_triggered = DISABLE;
    can_parameter.auto_bus_off_recovery = DISABLE;
    can_parameter.auto_wake_up = DISABLE;
    can_parameter.auto_retrans = DISABLE;
    can_parameter.rec_fifo_overwrite = DISABLE;
    can_parameter.trans_fifo_order = DISABLE;
    can_parameter.working_mode = CAN_NORMAL_MODE;
    /* CAN波特率 = 时钟频率 / 分频系数 / (1 + TSG1 + TSG2) */
    /* 仲裁段波特率 = 90M / 9 / (1 + 7 + 2) = 1M */
    /* configure CAN baud rate 1MBps, sample point at 80% */
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;  // TSG1
    can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;  // TSG2
    can_parameter.prescaler = 9U;                   // 分频系数
    /* initialize CAN */
    can_init(CAN0, &can_parameter);
#else  // CANFD配置
    /* initialize CAN parameters */
    can_parameter.time_triggered = DISABLE;
    can_parameter.auto_bus_off_recovery = DISABLE;
    can_parameter.auto_wake_up = DISABLE;
    can_parameter.auto_retrans = ENABLE;
    can_parameter.rec_fifo_overwrite = ENABLE;
    can_parameter.trans_fifo_order = ENABLE;
    can_parameter.working_mode = CAN_NORMAL_MODE;
    /* baudrate 1Mbps, sample piont at 80% */
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;
    can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;
    can_parameter.prescaler = 9U;
    /* initialize CAN */
    can_init(CAN0, &can_parameter);

    can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter);
    can_fd_parameter.fd_frame = ENABLE;
    can_fd_parameter.excp_event_detect = ENABLE;
    can_fd_parameter.delay_compensation = ENABLE;
    can_fd_tdc_parameter.tdc_filter = 0x04U;
    can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET;
    can_fd_tdc_parameter.tdc_offset = 0x04U;
    can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter;
    can_fd_parameter.iso_bosch = CAN_FDMOD_ISO;
    can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE;
    /* CAN波特率 = 时钟频率 / 分频系数 / (1 + TSG1 + TSG2) */
    /* 数据段波特率 = 90M / 3 / (1 + 4 + 1) = 5M */
    can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ;
    can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_4TQ;  // TSG1
    can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ;  // TSG2
    /* CAN-FD data segement prescaler should be the same as non-data segement prescaler */
    can_fd_parameter.data_prescaler = 3;                    // 分频系数
    /* initialize CAN-FD */
    can_fd_init(CAN0, &can_fd_parameter);
#endif

    /* initialize filter */
    /* configure filter mode */
    can_filter.filter_mode = CAN_FILTERMODE_MASK;
    can_filter.filter_bits = CAN_FILTERBITS_32BIT;
    /* configure filter ID */
    can_filter.filter_list_high = 0x0000U;
    can_filter.filter_list_low = 0x0000U;
    /* configure filter mask */
    can_filter.filter_mask_high = 0x0000U;
    can_filter.filter_mask_low = 0x0000U;
    /* select receiver fifo */
    can_filter.filter_fifo_number = CAN_FIFO0;
    can_filter.filter_number = 0U;
    can_filter.filter_enable = ENABLE;
    can_filter_init(CAN0, &can_filter);
    /* configure CAN0 NVIC */
    nvic_irq_enable(CAN0_RX0_IRQn, 0U, 0U);

    /* enable can receive FIFO0 not empty interrupt */
    can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
}

int can0_send_message(void)
{
    uint8_t i;
    uint16_t id = 1;

    can0_tx_message.tx_sfid = id;
    can0_tx_message.fd_flag = 0;
    can0_tx_message.fd_brs = 0;
    can0_tx_message.fd_esi = 0;
    can0_tx_message.tx_dlen = 8;
    for(i = 0; i < 8; i++) 
    {
        can0_tx_message.tx_data[i] = i;
    }
#if 0
    printf("\r\n can0 transmit data(id: 0x%x): ", can0_tx_message.tx_sfid);
    for(i = 0U; i < can0_tx_message.tx_dlen; i++) 
    {
        printf(" %02x", can0_tx_message.tx_data[i]);
    }
#endif
    /* transmit message */
    if(can_message_transmit(CAN0, &can0_tx_message) != CAN_NOMAILBOX)
    {
        return 1;
    }

    return 0;
}

void CAN0_RX0_IRQHandler(void)
{
    /* check the receive message */
    can_message_receive(CAN0, CAN_FIFO0, &can0_rx_message);
    LOG("\r\n can0 receive(id=0x%X) data: ", can0_rx_message.rx_sfid);
    for(int i = 0U; i < can0_rx_message.rx_dlen; i++) 
    {
        LOG(" %02x", can0_rx_message.rx_data[i]);
    }
}

void can1_gpio_config(void)
{
    /* enable CAN1 clock */
    rcu_periph_clock_enable(RCU_CAN1);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_AF);
    /* configure CAN1 GPIO */
    gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_pin_remap_config(GPIO_CAN1_REMAP, ENABLE);
}

void can1_config(void)
{
    can_parameter_struct can_parameter;
    can_fdframe_struct can_fd_parameter;
    can_fd_tdc_struct can_fd_tdc_parameter;
    can_filter_parameter_struct can_filter;

    can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
    /* initialize CAN register */
    can_deinit(CAN1);

    /* initialize CAN parameters */
    can_parameter.time_triggered = DISABLE;
    can_parameter.auto_bus_off_recovery = DISABLE;
    can_parameter.auto_wake_up = DISABLE;
    can_parameter.auto_retrans = ENABLE;                 // TODO 自动重传是否需要使能
    can_parameter.rec_fifo_overwrite = ENABLE;   
    can_parameter.trans_fifo_order = ENABLE;
    can_parameter.working_mode = CAN_NORMAL_MODE;
    /* CAN波特率 = 时钟频率 / 分频系数 / (1 + TSG1 + TSG2) */
    /* 仲裁段波特率 = 90M / 9 / (1 + 7 + 2) = 1M */
    /* baudrate 1Mbps, sample piont at 80% */
    can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
    can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;  // TSG1
    can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;  // TSG2
    can_parameter.prescaler = 9U;                   // 分频系数
    /* initialize CAN */
    can_init(CAN1, &can_parameter);

    can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter);
    can_fd_parameter.fd_frame = ENABLE;
    can_fd_parameter.excp_event_detect = ENABLE;
    can_fd_parameter.delay_compensation = ENABLE;
    can_fd_tdc_parameter.tdc_filter = 0x04U;
    can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET;
    can_fd_tdc_parameter.tdc_offset = 0x04U;
    can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter;
    can_fd_parameter.iso_bosch = CAN_FDMOD_ISO;
    can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE;
    /* CAN波特率 = 时钟频率 / 分频系数 / (1 + TSG1 + TSG2) */
    /* 数据段波特率 = 90M / 3 / (1 + 4 + 1) = 5M */
    can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ;
    can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_4TQ;  // TSG1
    can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ;  // TSG2
    /* CAN-FD data segement prescaler should be the same as non-data segement prescaler */
    can_fd_parameter.data_prescaler = 3;                    // 分频系数
    /* initialize CAN-FD */
    can_fd_init(CAN1, &can_fd_parameter);

    /* initialize filter */
    /* configure filter mode */
    can_filter.filter_mode = CAN_FILTERMODE_MASK;
    can_filter.filter_bits = CAN_FILTERBITS_32BIT;
    /* configure filter ID */
    can_filter.filter_list_high = 0x0000U;
    can_filter.filter_list_low = 0x0000U;
    /* configure filter mask */
    can_filter.filter_mask_high = 0x0000U;
    can_filter.filter_mask_low = 0x0000U;
    /* select receiver fifo */
    can_filter.filter_fifo_number = CAN_FIFO1;  
    can_filter.filter_number = 15U;  // CAN_FCTL默认定义了CAN0和CAN1过滤器序号的分配数量,CAN0使用0-13序号,CAN1使用14-27,可以通过can1_filter_start_bank()修改
    can_filter.filter_enable = ENABLE;
    can_filter_init(CAN1, &can_filter);

    /* configure CAN1 NVIC */
    nvic_irq_enable(CAN1_RX1_IRQn, 1U, 1U);

    /* enable can receive FIFO0 not empty interrupt */
    can_interrupt_enable(CAN1, CAN_INTEN_RFNEIE1);
}

int can1_send_message(void)
{
    uint8_t i;
    uint16_t id = 2;

    can1_tx_message.tx_sfid = id;
    can1_tx_message.fd_flag = 1;
    can1_tx_message.fd_brs = 1;
    can1_tx_message.fd_esi = 0;
    can1_tx_message.tx_dlen = 8;
    for(i = 0; i < 8; i++) 
    {
        can1_tx_message.tx_data[i] = i;
    }
#if 0
    printf("\r\n can1 transmit data(id: 0x%x): ", can1_tx_message.tx_sfid);
    for(i = 0U; i < can1_tx_message.tx_dlen; i++) 
    {
        printf(" %02x", can1_tx_message.tx_data[i]);
    }
#endif
    /* transmit message */
    if(can_message_transmit(CAN1, &can1_tx_message) != CAN_NOMAILBOX)
    {
        return 1;
    }
    return 0;
}

void CAN1_RX1_IRQHandler(void)
{
    /* check the receive message */
    can_message_receive(CAN1, CAN_FIFO1, &can1_rx_message);
    printf("\r\n can1 receive(id=0x%X) data: ", can1_rx_message.rx_sfid);
    for(int i = 0U; i < can1_rx_message.rx_dlen; i++) 
    {
        printf(" %02x", can1_rx_message.rx_data[i]);
    }
}

void can_user_init(void)
{
    // CAN0 init
    can0_gpio_config();
    can0_config();
    /* initialize can0 transmit message */
    can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &can0_tx_message);
    /* initialize can0 receive message */
    can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &can0_rx_message);

    // CAN1 init
    can1_gpio_config();
    can1_config();
    /* initialize can1 transmit message */
    can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &can1_tx_message);
    /* initialize can1 receive message */
    can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &can1_rx_message);

    printf("can init success\r\n");
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue项目-三级联动的路由跳转与传参

三级联动组件的路由的跳转与传参 三级联动&#xff0c;用户可以点击的&#xff1a;一级分类、二级分类和三级分类 以商城项目为例&#xff0c;Home模块跳转到Search模块&#xff0c;以及会把用户选中的产品&#xff08;产品名字、产品ID&#xff09;在路由跳转的时候&#xff…

Q*算法深度猜猜:从Q-learning优化到智能决策

Q*算法深度猜猜&#xff1a;从Q-learning优化到智能决策 引言 在强化学习&#xff08;Reinforcement Learning&#xff09;中&#xff0c;Q-learning算法作为一种无模型的学习方法&#xff0c;被广泛应用于解决各种决策优化问题。然而&#xff0c;尽管Q-learning在许多场景下…

基于ssm+vue+uniapp的医院挂号预约系统小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

Matlab处理H5文件

1.读取h5文件 filenamexxx.h5; h5disp(filename) 2.h5文件保存为mat文件 读取 HDF5 文件中的数据 % 指定 HDF5 文件的路径 filename xxx.h5;% 读取 HDF5 文件中的各个数据集 A241_P h5read(filename, /A241_P); A241_W h5read(filename, /A241_W); A242_P h5read(filen…

Ps:首选项 - 性能

Ps菜单&#xff1a;编辑/首选项 Edit/Preferences 快捷键&#xff1a;Ctrl K Photoshop 首选项中的“性能” Performance选项卡允许用户通过调整内存使用、GPU 设置、高速缓存设置以及多线程处理等选项&#xff0c;来优化 Photoshop 的性能。这对于处理大文件、复杂图像或需要…

【NOI-题解】1137 - 纯粹素数1258 - 求一个三位数1140 - 亲密数对1149 - 回文数个数

文章目录 一、前言二、问题问题&#xff1a;1137 - 纯粹素数问题&#xff1a;1258 - 求一个三位数问题&#xff1a;1140 - 亲密数对问题&#xff1a;1149 - 回文数个数 三、感谢 一、前言 欢迎关注本专栏《C从零基础到信奥赛入门级&#xff08;CSP-J&#xff09;》 本章节主要…

二进制安装php

下载php二进制包&#xff1a; 官网地址&#xff1a;https://www.php.net/releases/ PHP: Releaseshttps://www.php.net/releases/在里边可以选择自己要下载的包进行下载&#xff1b; 下载完成后进行解压&#xff1a; tar xvzf php-7.3.12.tar.gz 解压后 进入目录进行预编…

学习yolo+Java+opencv简单案例(三)

主要内容&#xff1a;车牌检测识别&#xff08;什么颜色的车牌&#xff0c;车牌号&#xff09; 模型作用&#xff1a;车牌检测&#xff0c;车牌识别 文章的最后附上我的源码地址。 学习还可以参考我前两篇博客&#xff1a; 学习yoloJavaopencv简单案例&#xff08;一&#xff0…

Cobalt Strike 4.8 用户指南-第二节-用户界面

2.1、概述 Cobalt Strike用户界面分为两部分。界面顶部显示会话或目标的可视化。界面底部显示与你交互的每个 Cobalt Strike 功能或会话的选项卡。可以单击这两个部分之间的区域并根据自己的喜好调整它们的大小。 # 2.2、工具栏 顶部的工具栏提供对常见 Cobalt Strike功能的快…

C/C++实现蓝屏2.0

&#x1f680;欢迎互三&#x1f449;&#xff1a;程序猿方梓燚 &#x1f48e;&#x1f48e; &#x1f680;关注博主&#xff0c;后期持续更新系列文章 &#x1f680;如果有错误感谢请大家批评指出&#xff0c;及时修改 &#x1f680;感谢大家点赞&#x1f44d;收藏⭐评论✍ 前…

LeetCode合并两个有序链表

题目描述&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2&#xff1a; 输入&#xff1a;l1 [], l2…

chromedriver下载地址大全(包括124.*后)以及替换exe后仍显示版本不匹配的问题

Chrome for Testing availability CNPM Binaries Mirror 若已经更新了系统环境变量里的chromdriver路径下的exe&#xff0c;仍显示版本不匹配&#xff1a; 则在cmd界面输入 chromedriver 会跳出version verison与刚刚下载好的exe不匹配&#xff0c;则再输入&#xff1a; w…

http连接未释放导致生产故障

凌晨4点运维老大收到报警&#xff08;公司官网页面超时&#xff0c;上次故障因为运维修改nginx导致官网域名下某些接口不可用后&#xff0c;运维在2台nginx服务器上放了检测程序&#xff0c;检测官网页面&#xff09;&#xff0c;运维自己先看了看服务器相关配置&#xff0c;后…

小区物业维修管理系统/小区居民报修系统

摘要 小区物业维修是物业公司的核心&#xff0c;是必不可少的一个部分。在物业公司的整个服务行业中&#xff0c;业主担负着最重要的角色。为满足如今日益复杂的管理需求&#xff0c;各类小区物业维修管理系统也在不断改进。本课题所设计的小区物业维修管理系统&#xff0c;使用…

IPC进程间通信方式及网络通信

一、IPC进程间通信方式 1.共享内存&#xff08;最高效的进程间通信方式&#xff09; 其允许两个或多个进程共享一个给定的存储区&#xff0c;这一段存储区可以被两个或以上的进程映射至自己的地址空间中&#xff0c;一个进程写入共享内存的信息&#xff0c;可以被其他使用这个…

“面试宝典:高频算法题目详解与总结”

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

每日掌握一个科研插图·2D密度图|24-08-21

小罗碎碎念 在统计学和数据可视化领域&#xff0c;探索两个定量变量之间的关系是一种常见的需求。为了更深入地理解这种关系&#xff0c;我们可以使用多种图形表示方法&#xff0c;这些方法在本质上是对传统图形的扩展和变体。 散点图&#xff1a;这是最基本的图形&#xff0c…

图算法-贪心策略-最小生成树(prim)和最短路径(dijkstra)

参考来源&#xff1a;和感谢 1.代码随想录 (programmercarl.com) 2.【图-最小生成树-Prim(普里姆)算法和Kruskal(克鲁斯卡尔)算法】https://www.bilibili.com/video/BV1wG411z79G?vd_source0ddb24a02523448baa69b0b871ab50f7 3.【图-最短路径-Dijkstra(迪杰斯特拉)算法】ht…

Vue3学习笔记之插槽

目录 前言 一、基础 (一) 默认插槽 (二) 具名插槽 (三) 作用域插槽 (四) 动态插槽 二、实战案例 前言 插槽&#xff08;Slots&#xff09;&#xff1f; 插槽可以实现父组件自定义内容传递给子组件展示&#xff0c;相当于一块画板&#xff0c;画板就是我们的子组件&…

RabbitMQ发布订阅模式Publish/Subscribe详解

订阅模式Publish/Subscribe 基于API的方式1.使用AmqpAdmin定制消息发送组件2.消息发送者发送消息3.消息消费者接收消息 基于配置类的方式基于注解的方式总结 SpringBoot整合RabbitMQ中间件实现消息服务&#xff0c;主要围绕3个部分的工作进行展开&#xff1a;定制中间件、消息发…