搜索
bottom↓
回复: 18

STM32被函数:memcpy 坑了,查了一天。大家来看看。

[复制链接]

出590入992汤圆

发表于 2024-4-19 21:13:31 | 显示全部楼层 |阅读模式
本帖最后由 SUPER_CRJ 于 2024-4-19 22:37 编辑

如题。
具体是这样的,我之前项目全都是keil做的。现在新项目就移植到:embedded Studio。
于是把之前的Keil项目移植过来。
芯片用的是:STM32G474型号,用了里面的CAN FD功能。
代码上关于CAN FD代码几乎没有改。
但是:CAN FD发送数据就是和写入的不一样。

最终:查了一天,定位在:把变量复制到CAN FD的RAM里面的时候:用的memcpy函数:memcpy( (void *)&CANFD1_RAM->txBufferElement[0].T0all, &txElement.T0all,sizeof(_MSGRAM_TX_BUFFER_ELEMENT));
1:keil应该是32bit复制。
2:embedded Studio是8bit,就是单字节复制。
3:CAN FD的RAM手册表明:访问必须用32bit访问。

最终找到了这个问题。

最后问问大家:embedded Studio中的如何让:memcpy函数按照32bit进行复制?

出0入0汤圆

发表于 2024-4-19 21:15:33 来自手机 | 显示全部楼层
是sizeof获取的长度不一样吗

出590入992汤圆

 楼主| 发表于 2024-4-19 21:23:34 | 显示全部楼层
fenglove 发表于 2024-4-19 21:15
是sizeof获取的长度不一样吗
(引用自2楼)

不是的,就是:CANFD的RAM里面就是不能用字节进行写,必须每次都写一个word。
而memcpy拷贝的时候是:一个字节一个字节拷贝的。最后出问题了。

出0入42汤圆

发表于 2024-4-19 21:32:29 来自手机 | 显示全部楼层
不用memcpy,自己写。比如转成uint32逐个赋值,你输入肯定整word的

出0入1209汤圆

发表于 2024-4-19 21:41:09 | 显示全部楼层
本帖最后由 kitten 于 2024-4-19 21:52 编辑

keil里也是按照字节复制呀,memcpy根本不管数据类型,直接按照内存地址进行复制的。memcpy不背这个锅。大概率是因为你没做word对齐,起始地址以及字节数量等检查一下

出0入1209汤圆

发表于 2024-4-19 21:48:43 | 显示全部楼层
利用memcpy不区分数据类型的特性可以干很多事情,这也是C语言的灵活之处。楼主你别折腾memcpy函数了,写个for循环,直接数组赋值完事。

出0入0汤圆

发表于 2024-4-19 22:09:31 来自手机 | 显示全部楼层
我也感觉不memcpy的问题,人家应该都是字节复制,因为长度参数的单位就是字节

出590入992汤圆

 楼主| 发表于 2024-4-19 22:35:46 | 显示全部楼层
kitten 发表于 2024-4-19 21:41
keil里也是按照字节复制呀,memcpy根本不管数据类型,直接按照内存地址进行复制的。memcpy不背这个锅。大概 ...
(引用自5楼)

100%确定。
地址全部8字节对齐。地址无重叠。整个结构体:72字节。
调试模式查看:源内存和目标内存。使用后:SES明显不对。KEIL全部正确。
keil调用的是:__aeabi_memcpy4。SES调用的是:__aeabi_memcpy8。

另外:这个目标地址明确表明,只能32bit访问。所以肯定就是:memcpy出的问题。但是SES用的:__aeabi_memcpy8好像是要8字节对齐。但是上面的也是8字节对齐。
实测:如果按照8bit写入,剩下的24bit都会变成一样的值。而SES,出现了几个一样的值。所以100%确定。

汇编我看不懂,我截图上来:
你也看看:



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2024-4-19 22:59:48 | 显示全部楼层
SUPER_CRJ 发表于 2024-4-19 22:35
100%确定。
地址全部8字节对齐。地址无重叠。整个结构体:72字节。
调试模式查看:源内存和目标内存。使 ...
(引用自8楼)

这个SES确实是按字节复制的。KEIL的memcpy函数如果地址对齐的话按照32位复制

出0入8汤圆

发表于 2024-4-19 23:24:10 来自手机 | 显示全部楼层
楼主,memcpy是对两个记忆体地址一字节一字节拷贝不用地址对齐,你出错可能是用memcpy来做struct to structure的拷贝时,struct原型没有宣告byte packing的情况下,编译器对struct的element地址做alignment而导致拷贝后的数据不是在预计的位置上

出0入1209汤圆

发表于 2024-4-19 23:34:51 | 显示全部楼层
SUPER_CRJ 发表于 2024-4-19 22:35
100%确定。
地址全部8字节对齐。地址无重叠。整个结构体:72字节。
调试模式查看:源内存和目标内存。使 ...
(引用自8楼)

其实你已经找到答案了。keil帮你优化了memcpy函数,恰好你做了字节对齐,恰好keil使用的是4字节也就是32bit复制,歪打正着没出问题。SES则优化太猛了,直接按照8字节拷贝。   另外keil下是否勾选MicroLib出来的效果也不同。ANSI C标准库memcpy就是按照字节拷贝的。所以安全的办法还是不使用memecpy,采用直接赋值才安全。

出0入442汤圆

发表于 2024-4-19 23:35:47 | 显示全部楼层
modbus 发表于 2024-4-19 22:59
这个SES确实是按字节复制的。KEIL的memcpy函数如果地址对齐的话按照32位复制 ...
(引用自9楼)


哈哈,strb,ldrb。确实是字节。

库做过优化。gcc是标准string实现,如果要实现dword复制,则需要自己改libgcc库实现。

出0入18汤圆

发表于 2024-4-20 10:46:06 | 显示全部楼层
本帖最后由 fcm32 于 2024-4-20 10:52 编辑

SES应该还是不十分完善,或是某些小的差异。

一个例子程序,用了sprintf,keil里没有问题,SES就是结果不对。调试了一下,传给sprintf的参数,时、分、秒其内容是正确的,输出就是错的。

/* Display time Format : hh:mm:ss */
  sprintf((char*)showtime,"%02d:%02d:%02d",stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);

showtime执行结果是:2d:2d:2d

破案了:

要在Printf Width/Precision Supported选项设为Yes,默认为No

出1310入193汤圆

发表于 2024-4-20 10:50:14 | 显示全部楼层
本帖最后由 lb0857 于 2024-4-20 10:51 编辑

11l  正解

有疑问:  安全的办法还是不使用memecpy,采用直接赋值才安全
这个原则是平时少使用memecpy吧

出300入477汤圆

发表于 2024-4-20 10:56:46 来自手机 | 显示全部楼层
要求必须按32位操作的寄存器,你就不该用memcpy,应该自己写个专门按32位读写的函数,那个函数里面还得用个32位的volatile变量做操作,防止聪明的编译器给你优化成每次64位或者每次8位了。。。
没人给你保证memcpy按每次多少位操作。

出590入992汤圆

 楼主| 发表于 2024-4-20 13:18:52 来自手机 | 显示全部楼层
kitten 发表于 2024-4-19 23:34
其实你已经找到答案了。keil帮你优化了memcpy函数,恰好你做了字节对齐,恰好keil使用的是4字节也就是32b ...
(引用自11楼)

是的,这下知道了。

出130入20汤圆

发表于 2024-4-20 13:21:23 | 显示全部楼层
我一般都宁可for循环自己写赋值。memcpy,malloc之类的能不用就不用

出1310入193汤圆

发表于 2024-4-20 14:49:30 | 显示全部楼层
shuiluo2 发表于 2024-4-20 13:21
我一般都宁可for循环自己写赋值。memcpy,malloc之类的能不用就不用 ...
(引用自17楼)

的确哈
memcpy运用中存在的缺陷,即memcpy不能拷贝目的地址(dest)和源地址(src)内存空间有重合的部分,
更为确切的说应该是当目的地址大于源地址的时候,
不能够有重合部分,
否则源地址重合部分数据会发生错误

出0入362汤圆

发表于 2024-4-23 12:33:00 | 显示全部楼层
lb0857 发表于 2024-4-20 14:49
的确哈
memcpy运用中存在的缺陷,即memcpy不能拷贝目的地址(dest)和源地址(src)内存空间有重合的部分 ...
(引用自18楼)

这种情况用memmove啊, 实现方式有的是另外开辟空间中转一次, 有的是倒过来从后往前复制.

不过, 有些库里的memcpy其实就是memmove的别名
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-3 03:34

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表