至于新芯片的支持,没有一家厂家会在每一款芯片上都采用完全不同的外设,甚至不同厂家的外设都会有相似之处。更有部分外设甚至有行业标准定义(例如 USB 的 OHCI/UHCI/EHCI/XHCI 和 UART 的 16C450/16C550A 接口)轮不到厂商半点话语权。芯片开发是要有代价的,不论是从时间角度,还是金钱的角度,厂家芯片升级换代都只会更新其核心竞争力的部分,而沿用其余部分。对于单片机来说这就是提高计算性能和降低功耗,前者换核心提升工艺,后者则几乎都是工艺上下功夫,基本不会碰外设。因此任凭芯片更新换代,这几个外设如同雷打不动,我又何必担心跟不上更新换代?您也可以关注一下用户手册里面某些外设(譬如 USB OTG)的部分,会冒出来另一家公司的名字和著作权标示,这些外设是 ST 从第三方买来的。这种外设 ST 大概率连修改的权利都没有,那我更是一个驱动通吃了。
这种“直接复制过来”的拿来主义其实是学习的大敌。在学习怎么编程的时候,哪怕说以后都用固件库,第一次还是要手写一遍简单的基本外设驱动,这样才能够从软件与硬件结合的深度上领悟到外设的工作原理。另外,这些自己手写的驱动也可以累积起来作为将来应用开发的基础库。
至于开发环境,Eclipse CDT + GNU MCU Eclipse 我的感觉是后来者居上,操作便利度不亚于 Keil,同时又能跨平台,还全开源全免费没有功能限制。8051 的话 SDCC 和相关的开源 IDE 还是差了一点,所以很多人还是用的 Keil C51。STM8 情况也类似。
感觉像是在开炮,虽然我现在不怎么用Keil和IAR来开发
我怎么感觉把嵌入式软件分层,手写驱动和 GCC 工具链的使用放在一起都可以写本书了?我的输出里面还有两三本 Keil + 固件库的书呢……
我指的并不是keil还是iar这些,而是用干用寄存器兑没意思,因为我就干了这事,事后发现,真的没意思,
尽管一劳永逸,然而你会发现,这种编程方式很辛苦,因为等你真的完善好自己的库,却发现时间都浪费掉了,
如果当初把这时间花在应用上,例如如何去节省CPU时间,如何去优化架构,如何实现一个协议栈等,
例如状态机、如何去实现完美逻辑
例如操作系统、如何实现线程同步
例如想实现一个GUI,需要很多时间去思考
然而,如果把时间都干放在实现一个底层库里,跟孔乙己没啥不同。
也许你会说:GUI不是有stEmwen么,操作系统不是各种freertos各种uCos么,然而却跟我说库不是有std,hal么一个样!
最最关键的是,你这个库建立好,你得拉上很多人一起玩才能搞得起来,否则依赖关系会弄个互相排斥。同时,命名风格,操作文档,api介绍等,够一壶了吧?还有,关于IDE,其实这个没啥好纠结的, 大概是51起的头吧,其实可以用gcc,但是呢国人的动手能力其实奇差,IDE一键帮你完成的事情,为什么还要用GCC+makefile/cmake呢,就算不用cmake、makefile,你也得用eclipse、qtcreator,vstudio来连接吧?然而大多数人都把时间集中在各种应用上了,哪里还有时间跟你纠结用gcc,iar还是armcc呢,站在巨人肩膀上,才能看得更远,也许你可以成为巨人,然而时间是宝贵的。
对于您的观点,抱歉我在此强行反驳了:
1、对于库来说,不知道你说的优化具体指什么,不知道你有没有仔细看过库,如果你需要操作寄存器,其实HAL提供了寄存器的入口地址指针,你完全可以使用此指针进行外部优化,然而,虽然我不知道你说的无谓的臃肿在哪里,不过我倒是可以说说HAL,HAL提供了外设内部状态机以及可视化的error callback,在使用者使用外设出现问题,只要操作正确,必然会通过callback得到错误的地方。而且每个外设都提供了get errorcode的api。虽然我不知道你说的所谓的标准api是啥,HAL,std的本质就是为了使用对象化的接口帮助使用者去熟悉外设的使用,而不需要使用者去仔细研读操作手册里具体到每一个bit的定义,而且.c文件的一开头注释地方会有详细的step by step告诉你这个外设应该怎么使用,我相信目前所有芯片厂商提供的sdk中,比st写得好的没几个!当然我觉得你可以写出比这个更详细更好用的库,也很期待,很多人说很臃肿,其实多数是基础问题!HAL之所以在MDK上运行得慢,是因为MDK本身的链接速度优化不当,导致在编译链接HAL库的时候显得龟速,然而在IAR或者使用GCC都不会感觉到慢!
MDK的律师涵我没见过,因为我工作用的是M0,虽然其他我的照样用山寨,然而我并不是什么大公司,只是基于用户级别来说,MDK如果查到我,基本上每一个人估计也遭殃,不过,我想知道的是,MDK有没有这么强力的资源区搞死所有的个体用户?当然我不是为用翻版辩护,“我也不支持,不鼓励用翻版”。
eclipse可以,vs也不错,qt creator也不错,尽管你说得他完美无缺,在我这里他也仅仅是个IDE,我平时自己玩都喜欢用VIM+CTAGS+YOUCOMPLETE+GCC+MAKEFILE.etc,在工作中我依然会用MDK,为什么呢?同事用,难道我要走非主流路线?那如何对接工作?。
我无心说那个好,那个不好,只不过,我觉得重点其实是应该放在我们应该放的地方,如何提高自己的能力,获得更高的工资又或者利用自己的研发优势创业? 基于此,一个单片机库写得再好,你无法跟的上芯片的更新换代的速度,当然你可以反驳,反正我不会吊死在一棵树上。等你做好这系列的库,H7,H8又出了,ST官方自然有更新库的资本和义务,然而我们的重点是如何利用芯片来开发应用,而不是点灯18掌。
最后,没意思,仅仅是对于我自己而已,因为我踩过坑,而对于楼主,对于大家,其实我更鼓励去试试看,你们可以写得更好,更方便,到哪个时候,不知道你们做好的库,能不能同时兼容其它的新的芯片呢?
说到优化,我想建议您先去看看 LLVM 文档中关于编译器优化的介绍。我这里推荐您去阅读 LLVM 的文档,是因为 LLVM clang 编译器是 ARMCC v6 的基础。然后您就知道为什么我会说 HAL 和 SPL 没法优化了。如果手工优化 HAL 或 SPL 代码,那不又退回到手写驱动上了么,用 HAL 或 SPL 的目的又何在?在代码注释里面解释操作流程是我所见过最愚蠢的做法。这些文件应该已经是库了,为什么还要给一寸光阴一寸金的用户出编程练习题?
关于 MDK,我已经讲过了 MDK 的语言支持是一个大坑。ARMCC v5 的语言限制意味着我之前好几年(那时候做的 iOS,被苹果压着一定要用最新的工具和最新的语言)辛辛苦苦积累的算法模块全部报销。这还没有谈到第三方库,譬如 libopencm3 或 libusb_stm32(一个体积很小的 USB 库,不依赖 HAL 或 SPL)这些都要求 C99 甚至 C11 才能编译。至少对于我来说,换用 MDK,哪怕是 M0 或者试用版,都意味着要大量重写我已经用的很习惯的算法模块,罔论我得先去买 Windows。
至于新芯片的支持,没有一家厂家会在每一款芯片上都采用完全不同的外设,甚至不同厂家的外设都会有相似之处。更有部分外设甚至有行业标准定义(例如 USB 的 OHCI/UHCI/EHCI/XHCI 和 UART 的 16C450/16C550A 接口)轮不到厂商半点话语权。芯片开发是要有代价的,不论是从时间角度,还是金钱的角度,厂家芯片升级换代都只会更新其核心竞争力的部分,而沿用其余部分。对于单片机来说这就是提高计算性能和降低功耗,前者换核心提升工艺,后者则几乎都是工艺上下功夫,基本不会碰外设。因此任凭芯片更新换代,这几个外设如同雷打不动,我又何必担心跟不上更新换代?您也可以关注一下用户手册里面某些外设(譬如 USB OTG)的部分,会冒出来另一家公司的名字和著作权标示,这些外设是 ST 从第三方买来的。这种外设 ST 大概率连修改的权利都没有,那我更是一个驱动通吃了。
不知道您有没有注重不同平台之间的代码积累和举一反三?其实我做单片机编程到现在,几个常用驱动的基本设计在好几个平台上都是一样的,换平台一般也就是改一下寄存器名字就能用了。STM32 上我用的串口驱动还是我从 AVR 上移植过来的呢。
LLVM我就不看了,你说的SPL我不知道是什么,HAL和STD没法优化,意思是代码已经没法优化了?既然没法优化,那么是指已经是最优化的了还是说没有优化的必要了呢?也就是说,剩下的并不是HAL还是STD,而是编译器的选择了吧?既然这样,那也毫无关系啊,HAL和STD在编写上已经考虑上了GCC、ARMCC和IAR的什么鬼CC了吧,单纯换个编译器的操作并不难吧?
在代码注释里解释操作流程《这个你是不是想歪了?》我来拷贝一下HAL或者STD的开头部分吧。
估计你没有看这个吧?如果你写的库能写得这么详细,那么我举双手的支持啊,就是不知道你有没有这个时间了?而且,你居然把这个比喻成练习手册?
对于新芯片的支持,的确没有一家厂家会在每一款芯片上采用完全不同的外设,而我的意思是,你有时间每用一个新芯片都需要去看参考手册,了解寄存器到bit的程度上吗?STM32F0,STM32F1的UART的寄存器不一样你信不信呢?STM32F1的发送寄存器只有一个DR,而F0,F7等分TDR和RDR你应该知道吧?然而对于上层库,都是统一的API,而且还带UserManual给你看怎么去用这些API。你觉得去熟悉寄存器的时间比熟悉API的时间多还是少呢?
注重不同平台的代码积累举一反三?我很注重,因为我随时会更换不同的芯片(成本、产能等原因),如何举一反三?但是不管你怎么举,你这个芯片你必须要知道,芯片外设的基地址以及芯片外设的寄存器控制吧?如果你不需要,说明你666了,而对于上层API来说,你压根就不需要关注这个,因为有统一的API给你使用,你压根不需要管下面是CR是怎么配置,接受用RDR,发送用TDR,因为在上层要么send,要么receive。
你STM32的串口驱动从AVR移植过来的,我就问你,需不需要改寄存器,改寄存器之前,你需不需要看手册?而相信如果我把串口驱动从AVR移植过来后,我只需要把寄存器屏蔽,改成USART_xxxx即可,但是你用寄存器就不这么简单了,你必须要知道,从哪里开启时钟,还要去看参考手册,波特率的计算公式,还要看CR的每个bit的定义应该如何配置吧?这就是每个厂家不一样的地方了,因为外设的明明以及波特率产生方法不一致,而在上层API,你只需要调用:BaudRate = 115200即可,你说哪一个方便?哪一个开发效率高?