当前位置: 首页 > news >正文

STM32H743的FDCAN使用方法(2):STM32CubeMX初始化代码修改

0 工具准备

1.STM32CubeMX

1 前言

本文介绍基于STM32CubeMX,修改基于STM32CubeMX生成的FDCAN初始化代码,成为我们能够正常使用的状态。

2 初始化代码修改

2.1 FDCAN初始化代码修改

typedef enum
{FDCAN_100K = 0,FDCAN_250K,FDCAN_500K,FDCAN_1M,FDCAN_2_5M,FDCAN_5M,
} FDCAN_BAUD_CFG_Type;
typedef enum
{FDCAN_NORMAL = FDCAN_MODE_NORMAL,                            /* 正常模式 */FDCAN_RESTRICTED_OPERATIO = FDCAN_MODE_RESTRICTED_OPERATION, /* 受限模式 */FDCAN_BUS_MONITORING = FDCAN_MODE_BUS_MONITORING,            /* 监控模式 */FDCAN_INTERNAL_LOOPBACK = FDCAN_MODE_INTERNAL_LOOPBACK,      /* 内部环回模式 */FDCAN_EXTERNAL_LOOPBACK = FDCAN_MODE_EXTERNAL_LOOPBACK,      /* 外部环回模式 */
} FDCAN_MODE_Type;
const fdcan_cfg_t fdCANCfg[] ={/* 输入时钟100MHz,测试100K、250K、500K、1M、2M、5M收发CAN2.0正常 */{100000, 17, 2},  /* 采样点 :90% */{250000, 17, 2},  /* 采样点 :90% */{500000, 17, 2},  /* 采样点 :90% */{1000000, 17, 2}, /* 采样点 :90% */{2500000, 17, 2}, /* 采样点 :90% */{5000000, 17, 2}, /* 采样点 :90% */
};
/*** @brief 设置FDCAN标准ID过滤器** @param id ID(0-0x7ff)* @param mask 掩码(0-0x7ff)*/
void set_fdcan_std_filter(u32 id, u32 mask)
{hfdCan2StdFilter.IdType = FDCAN_STANDARD_ID; /* 设置标准 ID *//* 用于过滤索引,如果是标准 ID,范围 0 到 127。如果是扩展 ID,范围 0 到 64 *//* 过滤索引和前面配置的过滤器个数对应,如果个数为n,则索引为0 - n-1 */hfdCan2StdFilter.FilterIndex = 0;hfdCan2StdFilter.FilterType = FDCAN_FILTER_MASK;         /* 过滤器采样屏蔽位模式 */hfdCan2StdFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; /* 如果过滤匹配,将数据保存到 Rx FIFO 0 */hfdCan2StdFilter.FilterID1 = id;                         /* 屏蔽位模式下,FilterID1 是消息 ID */hfdCan2StdFilter.FilterID2 = mask;                       /* 屏蔽位模式下,FilterID2 是消息屏蔽位 */
}/*** @brief 设置FDCAN扩展ID过滤器** @param id ID(0-0x1fffffff)* @param mask 掩码(0-0x1fffffff)*/
void set_fdcan_ext_filter(u32 id, u32 mask)
{hfdCan2ExtFilter.IdType = FDCAN_EXTENDED_ID; /* 设置扩展 ID *//* 用于过滤索引,如果是标准 ID,范围 0 到 127。如果是扩展 ID,范围 0 到 64 *//* 过滤索引和前面配置的过滤器个数对应,如果个数为n,则索引为0 - n-1 */hfdCan2ExtFilter.FilterIndex = 0;hfdCan2ExtFilter.FilterType = FDCAN_FILTER_MASK;         /* 过滤器采样屏蔽位模式 */hfdCan2ExtFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; /* 如果过滤匹配,将数据保存到 Rx FIFO 0 */hfdCan2ExtFilter.FilterID1 = id;                         /* 屏蔽位模式下,FilterID1 是消息 ID */hfdCan2ExtFilter.FilterID2 = mask;                       /* 屏蔽位模式下,FilterID2 是消息屏蔽位 */
}
/*** @brief FDCAN初始化** @param mode 模式 环回、正常等* @param fdCANBaud FDCAN波特率* @return int 0:成功 -1:失败*/
int MX_FDCAN_Init(FDCAN_MODE_Type mode, FDCAN_BAUD_CFG_Type fdCANBaud)
{HAL_StatusTypeDef ret;/* 选择FDCAN2 */hfdcan2.Instance = FDCAN2;/* 帧格式选择 *//* FDCAN_FRAME_CLASSIC:经典CAN格式(CAN2.0),最高支持1M仅支持收发CAN2.0报文*//* FDCAN_FRAME_FD_NO_BRS:不可变波特率FDCAN格式(仲裁段和数据段波特率一致),不兼容CAN2.0仲裁段和数据段的波特率一致支持收发FDCAN报文和CAN2.0报文*//* FDCAN_FRAME_FD_BRS:可变波特率FDCAN格式(仲裁段和数据段波特率可以一致),兼容CAN2.0在仲裁段使用较低波特率如500K,在数据段使用较高波特率如2M支持收发FDCAN报文和CAN2.0报文*//* 帧格式:不可变波特率 */hfdcan2.Init.FrameFormat = FDCAN_FRAME_FD_NO_BRS;/* 工作模式:自环、正常工作模式等 *//* 实测使用自环有bug,自己收不到自己发出的CAN报文 */hfdcan2.Init.Mode = mode;/* 关闭重传、发送暂停、协议错误处理 */hfdcan2.Init.AutoRetransmission = DISABLE;hfdcan2.Init.TransmitPause = DISABLE;hfdcan2.Init.ProtocolException = DISABLE;/* FDCAN分频系数 *//* CAN/FDCAN 1bit = 1Tq同步段 + 1-8Tq传播时间段 + 1-8相位缓冲段1 + 1-8相位缓冲段2 *//* CAN/FDCAN 实际使用中:1bit = 1Tq同步段 + TimeSeg1/BS1(传播时间段+相位缓冲段)+ TimeSeg2/BS2(相位缓冲段2) *//* 采样点推荐位置:85-90% 满足 (1Tq + BS1) / (1Tq + BS1 + BS2) , 建议87.5 *//* 经典CAN只需要关注仲裁阶段波特率设置,FDCAN需要设置仲裁段和数据段波特率且允许二者不一致(波特率可变)*//*选择CAN2.0或FDCAN不可变波特率,仲裁段设置的波特率就是整个CAN报文波特率选择FDCAN可变波特率,仲裁段设置的波特率是仲裁段的CAN报文波特率*/hfdcan2.Init.NominalPrescaler = FDCAN2_INPUT_CLOCK / (fdCANCfg[fdCANBaud].baud * (1 + fdCANCfg[fdCANBaud].bs1 + fdCANCfg[fdCANBaud].bs2));/* 用于动态调节Phase_Seg1和Phase_Seg2,所以不可以比Phase_Seg2和Phase_Seg2大,固定为1 */hfdcan2.Init.NominalSyncJumpWidth = 1;/* 设置位段1、位段2 */hfdcan2.Init.NominalTimeSeg1 = fdCANCfg[fdCANBaud].bs1;hfdcan2.Init.NominalTimeSeg2 = fdCANCfg[fdCANBaud].bs2;/* 只有选择FDCAN可变波特率帧格式这里的配置才作为数据段波特率 */hfdcan2.Init.DataPrescaler = FDCAN2_INPUT_CLOCK / (fdCANCfg[fdCANBaud].baud * (1 + fdCANCfg[fdCANBaud].bs1 + fdCANCfg[fdCANBaud].bs2));/* 用于动态调节Phase_Seg1和Phase_Seg2,所以不可以比Phase_Seg2和Phase_Seg2大,固定为1 */hfdcan2.Init.DataSyncJumpWidth = 1;/* 设置位段1、位段2 */hfdcan2.Init.DataTimeSeg1 = fdCANCfg[fdCANBaud].bs1;hfdcan2.Init.DataTimeSeg2 = fdCANCfg[fdCANBaud].bs2;/*FDCAN RAM偏移地址,只有一个FDCAN,偏移地址为0FDCAN1和FDCAN2共享2560个字(4Byte)*/hfdcan2.Init.MessageRAMOffset = 0;/* 标准ID过滤器个数,范围0到128 */hfdcan2.Init.StdFiltersNbr = 1;/* 标准ID过滤器个数,范围0到64 */hfdcan2.Init.ExtFiltersNbr = 1;/* RXFIFO0元素个数,范围0到64 */hfdcan2.Init.RxFifo0ElmtsNbr = 64;/* RXFIFO0每个元素数据大小 */hfdcan2.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_64;/* RXFIFO1元素个数,范围0到64 */hfdcan2.Init.RxFifo1ElmtsNbr = 0;/* RXFIFO1每个元素数据大小 */hfdcan2.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_64;/* 设置Rx Buffer元素个数,范围0-64 */hfdcan2.Init.RxBuffersNbr = 0;/* 设置RxBuffer元素中每个数据大小,范围0-64 */hfdcan2.Init.RxBufferSize = FDCAN_DATA_BYTES_64;/* Tx Event FIFO元素个数,范围0到32 */hfdcan2.Init.TxEventsNbr = 0;/* 设置专用的 Tx Buffer 元素个数,范围 0 到 32*/hfdcan2.Init.TxBuffersNbr = 0;/* 设置用于Tx FIFO/Queue 的 Tx Buffers 个数。范围 0 到 32*/hfdcan2.Init.TxFifoQueueElmtsNbr = 32;/* 设置 FIFO 模式或者 QUEUE 队列模式 */hfdcan2.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;/* 设置 Tx Element 中的数据域大小 */hfdcan2.Init.TxElmtSize = FDCAN_DATA_BYTES_8;/* 初始化FDCAN2 */if (HAL_FDCAN_Init(&hfdcan2) != HAL_OK){return -1;}/* 配置标准ID过滤器 */if (HAL_FDCAN_ConfigFilter(&hfdcan2, &hfdCan2StdFilter) != HAL_OK){return -1;}/* 配置扩展ID过滤器 */if (HAL_FDCAN_ConfigFilter(&hfdcan2, &hfdCan2ExtFilter) != HAL_OK){return -1;}/* 配置全局过滤器,配置后过滤器配置才会生效 */ret = HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_REJECT, FDCAN_REJECT,ENABLE, ENABLE);if (ret != HAL_OK){return -1;}/* 设置RxFIFO0的水印为1,接收到1个CAN报文就触发中断 */ret = HAL_FDCAN_ConfigFifoWatermark(&hfdcan2, FDCAN_CFG_RX_FIFO0, 1);if (ret != HAL_OK){return -1;}/* 激活RXFIFO0的水印通知中断 */ret = HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO0_WATERMARK, 0);if (ret != HAL_OK){return -1;}/* 启动 FDCAN */HAL_FDCAN_Start(&hfdcan2);return 0;
}

为了便于使用,这里为FDCAN初始化函数增加了模式、波特率2个形参。所有的配置全部有详细注释,可以参考注释进行配置。

2.2 增加FDCAN的RXFIFO0接收回调函数

/*** @brief FDCAN的RXFIFO0接收回调** @param hfdcan FDCAN句柄* @param RxFifo0ITs RXFIFO0状态*/
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{FDCAN_RxHeaderTypeDef rxHeader;uint8_t rxData[64];if (hfdcan == &hfdcan2){if ((RxFifo0ITs & FDCAN_IT_RX_FIFO0_WATERMARK) != RESET){/* 轮询RX FIFO,直到无数据可读 */for (;;){if (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0){/* 从 RX FIFO0 读取数据 */HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rxHeader, rxData);add_fdcan_recv_msg(&rxHeader, rxData);}else{break;}}}}
}

2.3 增加FDCAN的发送函数

/*** @brief 发送CAN/FDCAN报文** @param buff 数据* @param len 长度* @return int 0-成功 -1-失败*/
int fdcan_send(u8 *buff, u8 len)
{int timeout = 0;HAL_StatusTypeDef ret;/* 初始化FDCAN发送参数 */fdCANSendCfg.Identifier = 0x147;                      /* 设置消息的ID */fdCANSendCfg.IdType = FDCAN_STANDARD_ID;              /* 标准ID */fdCANSendCfg.TxFrameType = FDCAN_DATA_FRAME;          /* 数据帧 */fdCANSendCfg.ErrorStateIndicator = FDCAN_ESI_ACTIVE;  /* 设置错误状态指示 */fdCANSendCfg.BitRateSwitch = FDCAN_BRS_OFF;           /* 关闭可变波特率 */fdCANSendCfg.FDFormat = FDCAN_CLASSIC_CAN;            /* FDCAN格式 */fdCANSendCfg.TxEventFifoControl = FDCAN_NO_TX_EVENTS; /* 用于发送事件 FIFO 控制, 不存储 */fdCANSendCfg.MessageMarker = 0;                       /* 用于复制到 TX EVENT FIFO 的消息 Maker 来识别消息状态(检查消息是否发送成功等),范围0到0xFF */fdCANSendCfg.DataLength = (uint32_t)len << 16;        /* 发送数据长度 *//* 等待TX FIFO可用 */while (HAL_FDCAN_GetTxFifoFreeLevel(&hfdcan2) == 0){HAL_Delay(1);timeout++;if (timeout > 100){return -1;}}/* 添加数据到 TX FIFO */ret = HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &fdCANSendCfg, buff);if (ret != HAL_OK){return -1;}add_fdcan_send_msg(&fdCANSendCfg, buff);return 0;
}

以上代码和CAN调试器在100K、250K、500K、1M下测试100万次收发正常。在内部回环、外部回环下无法收到FDCAN自己发出的报文,怀疑是HAL库bug,本文使用的HAL库版本如下:

STM32Cube FW_H7 V1.11.0

此外,发现在高速接收CAN报文时,如果stm32H743主频被设置为480MHz则会丢掉几乎所有包,而主频设置为400MHz则能够正常接收。建议即使是v版本(支持最高480MHz)的stm32H743也将主频设置为400MHz,设置为400MHz之后发热量和稳定性都会有所提升,没必要为了区区80MHz的提升牺牲稳定性。
如果你也遇到了和我一样的问题,欢迎留言交流!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 判断变量是否为数组的几种方法
  • 音视频及H264/H256编码相关原理
  • 关于Broken pipe异常的一点学习记录
  • 【小沐学GIS】GDAL库安装和使用(C++、Python)
  • 没有括号的字符串四则运算
  • android 水平居中对齐并举例
  • wordpress教程视频 wordpress教程网盘 wordpress教程推荐wordpress教程网
  • ERC314协议
  • 3.每日LeetCode-爬楼梯(Go,Java,Python)
  • SpringCloud系列(23)--手写实现负载轮询算法
  • 使用paddlepaddle框架构建ViT用于CIFAR10图像分类
  • 基于Vue2与3版本的Element UI与Element Plus入门
  • 【蓝桥杯选拔赛真题76】python找出元素 第十四届青少年组蓝桥杯python选拔赛真题 算法思维真题解析
  • LeetCode/NowCoder-链表经典算法OJ练习3
  • 使用elementUI的form表单校验时,错误提示位置异常解决方法
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • [译]Python中的类属性与实例属性的区别
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • JAVA SE 6 GC调优笔记
  • jdbc就是这么简单
  • JS题目及答案整理
  • JWT究竟是什么呢?
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • vue 配置sass、scss全局变量
  • 如何实现 font-size 的响应式
  • 如何优雅地使用 Sublime Text
  • 设计模式(12)迭代器模式(讲解+应用)
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • 优秀架构师必须掌握的架构思维
  • MyCAT水平分库
  • ## 1.3.Git命令
  • (+4)2.2UML建模图
  • (2024.6.23)最新版MAVEN的安装和配置教程(超详细)
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (蓝桥杯每日一题)love
  • (七)理解angular中的module和injector,即依赖注入
  • (转)jQuery 基础
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)Mysql的优化设置
  • .NET C# 操作Neo4j图数据库
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .NET连接数据库方式
  • .Net转前端开发-启航篇,如何定制博客园主题
  • @angular/cli项目构建--http(2)
  • @cacheable 是否缓存成功_Spring Cache缓存注解
  • @RequestMapping-占位符映射
  • @Transient注解
  • @Value获取值和@ConfigurationProperties获取值用法及比较(springboot)
  • [ vulhub漏洞复现篇 ] Django SQL注入漏洞复现 CVE-2021-35042
  • [.net] 如何在mail的加入正文显示图片
  • [4]CUDA中的向量计算与并行通信模式
  • [ACL2022] Text Smoothing: 一种在文本分类任务上的数据增强方法
  • [ACTF2020 新生赛]Include
  • [AI StoryDiffusion] 创造神奇故事,AI漫画大乱斗!
  • [BUUCTF]-Reverse:reverse3解析