打印

倒垃圾:GD 全系列 MCU 的软件支持就是这副德行!

[复制链接]
12839|59
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xcvista|  楼主 | 2021-4-22 17:17 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 xcvista 于 2021-4-27 16:03 编辑

这是我有史以来见过最令人作呕的一座屎山。

Cortex-M23 核心
// gd32e23x.h
#include "gd32e23x_libopt.h"

RISC-V 核心
// gd32vf103.h
#if !defined  USE_STDPERIPH_DRIVER
#define USE_STDPERIPH_DRIVER
#endif
#ifdef USE_STDPERIPH_DRIVER
#include "gd32vf103_libopt.h"
#endif /* USE_STDPERIPH_DRIVER */

这种强制绑定所谓标准库是什么迷之操作?我是看着就火大。为什么 GD 就不能像全世界所有其他芯片厂商一样,设备头文件和标准库分离开来,让开发人员可以各取所需?

然后设备寄存器定义……
// gd32e23x_gpio.h
/* GPIOx(x=A,B,C,F) definitions */
#define GPIOA                      (GPIO_BASE + 0x00000000U)
#define GPIOB                      (GPIO_BASE + 0x00000400U)
#define GPIOC                      (GPIO_BASE + 0x00000800U)
#define GPIOF                      (GPIO_BASE + 0x00001400U)

/* registers definitions */
#define GPIO_CTL(gpiox)            REG32((gpiox) + 0x00U)    /*!< GPIO port control register */
#define GPIO_OMODE(gpiox)          REG32((gpiox) + 0x04U)    /*!< GPIO port output mode register */
#define GPIO_OSPD(gpiox)           REG32((gpiox) + 0x08U)    /*!< GPIO port output speed register */
#define GPIO_PUD(gpiox)            REG32((gpiox) + 0x0CU)    /*!< GPIO port pull-up/pull-down register */
#define GPIO_ISTAT(gpiox)          REG32((gpiox) + 0x10U)    /*!< GPIO port input status register */
#define GPIO_OCTL(gpiox)           REG32((gpiox) + 0x14U)    /*!< GPIO port output control register */
#define GPIO_BOP(gpiox)            REG32((gpiox) + 0x18U)    /*!< GPIO port bit operation register */
#define GPIO_LOCK(gpiox)           REG32((gpiox) + 0x1CU)    /*!< GPIO port configuration lock register */
#define GPIO_AFSEL0(gpiox)         REG32((gpiox) + 0x20U)    /*!< GPIO alternate function selected register 0 */
#define GPIO_AFSEL1(gpiox)         REG32((gpiox) + 0x24U)    /*!< GPIO alternate function selected register 1 */
#define GPIO_BC(gpiox)             REG32((gpiox) + 0x28U)    /*!< GPIO bit clear register */
#define GPIO_TG(gpiox)             REG32((gpiox) + 0x2CU)    /*!< GPIO port bit toggle register */

这是什么奇葩代码结构?1202 年了都不知道结构体为何物?还是说是是为了照顾汇编语言?哪怕是为了照顾汇编语言我也没看到下面有 #ifndef ASSEMBLER 之类的代码啊?

至于那个所谓的标准库么……
// gd32f23x_gpio.c
void gpio_bit_set(uint32_t gpio_periph, uint32_t pin)
{
    GPIO_BOP(gpio_periph) = (uint32_t)pin;
}

这种一行代码的函数还要单独放在 C 文件里面,而不是放到头文件里面去 inline?就算编译器知道不要为这种函数单独开帧框,一个调用一个返回都是代码量、分支预测失败风险和闪存预取队列清空的开销啊。何况在这个极端例子里面,原本无等待一条指令可以解决的事情硬生生变成了至少三条指令和好几个等待周期啊。再说了,所有这些非内连函数都要占用标识符命名空间,我之前遇到的奇葩冲突看来就是这地方出问题了。

你们要方便客户我能理解,但是这种强制绑定是什么迷之操作?然后绑定的还是一座屎山?然后好不容易提高频率挤出来的处理性能,全都被恶臭的代码给吞了。

补充:GD32 的 SVD 写的也是屎,要不然我看不惯这个头文件还有 SVDConv 重新转一个出来这条路。现在就直接变成想要用这颗芯片我要从重写/重构 SVD 开始。


使用特权

评论回复
评论
xcvista 2021-5-18 19:21 回复TA
@雨水 :我的比较标准是 SVDConv 的输出文件…… 
雨水 2021-5-18 19:16 回复TA
确实不行,感觉我去摸一摸估计都写得好点 
沙发
jiangjiayu| | 2021-4-23 19:08 | 只看该作者
我用着也是极为不习惯,真搞不懂为啥要这样改,以前好像不是的

使用特权

评论回复
板凳
xyz769| | 2021-4-23 20:17 | 只看该作者
估计厂家换人了,新来的做汇编出生的,C语言功力不够,所以只能这样了。

使用特权

评论回复
地板
汽车电子| | 2021-4-24 20:03 | 只看该作者
确实很不好,我手头上有一个用GD32F为主控的产品,现在不得不用来调试一些功能。已经确定产品打样都不用GD的,换其他品牌。

使用特权

评论回复
5
EtherWalker| | 2021-4-25 17:10 | 只看该作者
虽然楼主言辞有点激烈,但确实代表了很大一部分开发者的心声

使用特权

评论回复
6
xcvista|  楼主 | 2021-4-27 15:59 | 只看该作者
xyz769 发表于 2021-4-23 20:17
估计厂家换人了,新来的做汇编出生的,C语言功力不够,所以只能这样了。

喜欢用汇编的话你好歹把下面 C 函数原型部分 #ifndef 了,这样我在编译汇编代码的时候可以直接用这些头文件。

使用特权

评论回复
7
xcvista|  楼主 | 2021-4-27 16:02 | 只看该作者
GD32 的 SVD 写的也是屎,要不然我看不惯这个头文件还有 SVDConv 重新转一个出来这条路。现在就直接变成想要用这颗芯片我要从重写/重构 SVD 开始。

使用特权

评论回复
8
xcvista|  楼主 | 2021-4-27 16:07 | 只看该作者
汽车电子 发表于 2021-4-24 20:03
确实很不好,我手头上有一个用GD32F为主控的产品,现在不得不用来调试一些功能。已经确定产品打样都不用GD ...

问题是现在能兼容我常用的开源公版平台的 RISC-V 和 Cortex-M23/M33 核心的芯片基本就只有 GD 在做啊,对于我的学术用途没得选啊。(ST、Microchip 也都有 Cortex-M23/M33 产品,但都拿货困难。)

使用特权

评论回复
9
imdx| | 2021-4-27 20:03 | 只看该作者
库又不是必须的,不爽自己改就是了,源代码都给了。
寄存器定义不是只有ST一种,这种寄存器定义方式习惯了其实也挺好的,方便使用寄存器的客户使用,基本只用他们头文件。
GD的库更新得确实很慢,反馈了bug也得不到修复,只能靠自己。

使用特权

评论回复
10
xcvista|  楼主 | 2021-4-27 21:06 | 只看该作者
本帖最后由 xcvista 于 2021-4-27 21:07 编辑
imdx 发表于 2021-4-27 20:03
库又不是必须的,不爽自己改就是了,源代码都给了。
寄存器定义不是只有ST一种,这种寄存器定义方式习惯了 ...

我不是说 ST 的寄存器是好事情,那个只不过是 CMSIS 标准格式,你可以看看 SVDConv 输出是怎样的。GD 玩了一种非标准的。

不爽自己改,但是这么多外设改到猴年马月?我现在所能想的就是找一个靠谱的 XML 编辑器帮 GD 修 SVD 文件,然后用 SVDConv 去生成标准的头文件。(我这里基本已经淘汰 printf 调试,替代的 JTAG 调试严重依赖 SVD,而 GD 的渣渣 SVD 我连调试用都困难。我现在就连 LPC2103 这种 ARM7 的芯片都在用 SVD 了。)

使用特权

评论回复
11
imdx| | 2021-4-27 22:31 | 只看该作者
xcvista 发表于 2021-4-27 21:06
我不是说 ST 的寄存器是好事情,那个只不过是 CMSIS 标准格式,你可以看看 SVDConv 输出是怎样的。GD 玩了 ...

我这里SWD/JTAG基本都不用,都是串口调试。寄存器也是串口直接查看,所以没啥影响。

使用特权

评论回复
12
xcvista|  楼主 | 2021-4-27 22:39 | 只看该作者
imdx 发表于 2021-4-27 22:31
我这里SWD/JTAG基本都不用,都是串口调试。寄存器也是串口直接查看,所以没啥影响。 ...

串口调试有扰乱时序的风险。JTAG/SWD 调试的时候是可以配置成让外设全都一起暂停配合调试,有些时序敏感的 bug 可以直接调。同时串口调试占芯片容量。

使用特权

评论回复
13
imdx| | 2021-4-28 08:02 | 只看该作者
xcvista 发表于 2021-4-27 22:39
串口调试有扰乱时序的风险。JTAG/SWD 调试的时候是可以配置成让外设全都一起暂停配合调试,有些时序敏感的 ...

我的SWD/JTAG接口IO都当作实际IO用掉了,设计良好的串口调试代码不存在你说的问题。当然缺点就是占用芯片容量,所以我使用的MCU基本都要64kB起。
偶尔有必须用SWD接口的问题,直接换到开发板上测试就行了,这种情况极少,基本可以忽略。

使用特权

评论回复
14
xcvista|  楼主 | 2021-4-28 08:13 | 只看该作者
本帖最后由 xcvista 于 2021-4-28 08:20 编辑
imdx 发表于 2021-4-28 08:02
我的SWD/JTAG接口IO都当作实际IO用掉了,设计良好的串口调试代码不存在你说的问题。当然缺点就是占用芯片 ...

以后如果你要调试 STM32WB 或 LPC54114 这种多核心的芯片的时候,时序问题就会多很多了。

另外,我现在很喜欢用的 STM32F042F4P6,只有 16kB ROM 和 20 个管脚却支持 USB。这种芯片基本都必须用 SWD 调试了,串口就算没有被 USB CDC 功能吃掉,也没有多少空间去放串口 monitor 了。

还有一些板子我做了 JTAG 全板自检,一个四线制 JTAG 接口接了不止一个芯片(譬如 STM32F103 + XC3S500E + XCF04S + ATMEGA128A)

使用特权

评论回复
15
imdx| | 2021-4-28 22:11 | 只看该作者
本帖最后由 imdx 于 2021-4-28 22:14 编辑
xcvista 发表于 2021-4-28 08:13
以后如果你要调试 STM32WB 或 LPC54114 这种多核心的芯片的时候,时序问题就会多很多了。

另外,我现在很 ...

16kB器件根本没法用,用USB的bootloader自身就要16kB了。当然不用bootloader的话16kB凑合能用一下。
简单应用32kB还可以,要想用着舒服,还是得64kB起。四线JTAG很久很久都不用了,2线SWD少接2根线方便太多了。我做的gdlink连JTAG都没有留出来,客户也觉得没什么不方便的,JTAG还有多少人用可见一斑。
Cortex-M我没有用过多核芯片,不过TI的28035是双核的,带一个CLA协处理器,用串口没有感到什么不方便的。

使用特权

评论回复
16
xcvista|  楼主 | 2021-4-29 08:20 | 只看该作者
imdx 发表于 2021-4-28 22:11
16kB器件根本没法用,用USB的bootloader自身就要16kB了。当然不用bootloader的话16kB凑合能用一下。
简单 ...

STM32F042F4P6 有内置 ROM bootloader,因此说完全可以不用自己写 bootloader。16kB 对我来说至少可以塞进一个 CMSIS-DAP 调试器固件。

四线 JTAG 我现在依然很常用,特别是涉及到多个芯片的场合,以及 MCU 和其它类型芯片混合设置的场合。

使用特权

评论回复
17
imdx| | 2021-4-29 09:40 | 只看该作者
xcvista 发表于 2021-4-29 08:20
STM32F042F4P6 有内置 ROM bootloader,因此说完全可以不用自己写 bootloader。16kB 对我来说至少可以塞 ...

调试功能是一个设计良好固件必备的功能,代价是多占一些FLASH空间,这个是完全值得的。
我这里MCU内置的bootloader只是用来写入自己的bootloader的,内置的bootloader功能太简陋了,开发板上写入一次可以,用在产品中完全不行。
无论是四线JTAG还是两线的SWD,占用宝贵的IO口,在低管脚器件上尤其明显,很多时候我都当普通IO用了。

使用特权

评论回复
18
xcvista|  楼主 | 2021-4-29 11:17 | 只看该作者
本帖最后由 xcvista 于 2021-4-29 11:21 编辑
imdx 发表于 2021-4-29 09:40
调试功能是一个设计良好固件必备的功能,代价是多占一些FLASH空间,这个是完全值得的。
我这里MCU内置的b ...

我这里已经有用 STM32F042F4P6 这个只有 16kB Flash,据说是世界上最便宜的 USB ARM 单片机实现的 SWD+串口 CMSIS-DAP 了,近段时间我甚至在研究用沁恒 CH554 来做更便宜的 SWD+串口 CMSIS-DAP,以及在上述 STM32 CMSIS-DAP 上增加四线制 JTAG。当我嵌入 USB Hub 和仿真器的成本和嵌入 USB 串口芯片差不多的时候,串口调试的价值直接跌落谷底。在我这里产品在应用程序 USB 口前面有嵌入的 SL2.1 USB Hub 和仿真器是常见现象。

在我这里固件本身永远不会设置专门调试功能,所有调试任务都是通过 JTAG/SWD 和电脑端没有 strip 过的 ELF 文件来实现的。如果产品级别上因故需要设计自调试功能,那就整合一个上述廉价仿真器进去。

在我这里对于 90% 情况来说,片内 bootloader 已经足够了(其实也都不怎么用,刷固件都是用的 SWD/JTAG)因此除非是某些芯片不能从用户程序转入而使用场景又必须要设置可以从用户程序转入的 bootloader,或者存在特殊需求还不能直接嵌入仿真器,我已经不再占用的 Flash 空间来放自己的 bootloader 了。

专用调试串口和 SWD 一样占两个 I/O,还要占用片内可以用于其他目的的硬件资源,以及依赖预设的时钟树来维持波特率。SWD 则是专用调试模块,不依赖系统时钟,甚至可以用来救砖,而且有 GDB、SystemView 等标准调试软件的支持。

使用特权

评论回复
19
aple0807| | 2021-4-29 16:50 | 只看该作者
一开始确实不太习惯,不过也有它的好处,这种寄存器定义方式比结构体执行效率高,代码量相对较小。

使用特权

评论回复
20
xcvista|  楼主 | 2021-4-29 18:55 | 只看该作者
aple0807 发表于 2021-4-29 16:50
一开始确实不太习惯,不过也有它的好处,这种寄存器定义方式比结构体执行效率高,代码量相对较小。 ...

我这里用 GCC,最低的 -Og 优化等级下这种方式和结构体方式代码量完全一样。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

42

主题

631

帖子

3

粉丝