你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

为什么不常见不用固件库或 HAL 的 STM32 新手教程?

[复制链接]
maxtch 提问时间:2017-12-9 22:38 /
我个人做嵌入式编程到现在,感觉 ST 的固件库和 HAL(特别是 Cube HAL)并不好用:接口复杂难于理解,代码臃肿无法优化。然而为什么大多数的教程依然是以固件库或 HAL 为中心的?类似的,为什么教程基本上都只用 Keil 开发环境,偶尔有 IAR,但几乎从不考虑免费的 GCC 开源工具链?
收藏 1 评论52 发布时间:2017-12-9 22:38

举报

52个回答
任风吹吹 回答时间:2017-12-12 14:52:11
本帖最后由 任风吹吹 于 2017-12-12 15:00 编辑
Inc_brza 发表于 2017-12-12 10:00
LLVM我就不看了,你说的SPL我不知道是什么,HAL和STD没法优化,意思是代码已经没法优化了?既然没法优化, ...

哥们,我举双手给你点赞!
讨论来讨论去大家都忽视了问题的本质,时间才是问题的关键。
不管你的寄存器方法写得有多好,效率有多高,这些问题你得考虑:
1> 维护问题。肯定有BUG对吧?那么谁了维护?还是你吗?万一哪天你离职了,公司还说谁可以维护你写的代码?对于公司来说维护成本哪个高?
2> 移植问题,跨平台问题,假设哪天公司产品升级,想从F1换成F4,那么F4的相同外设和F1一样吗?寄存器有哪些差异?之前写的寄存器版本代码还能用吗?从公司的角度出发,那个成本要低?
3> 效率问题。SPL效率高,好吧,算吧,寄存器比HAL效率高?OK,我承认,HAL比SPL效率低?好吧,算吧,但你要知道,LL的效率>=SPL库,而LL与HAL完美兼容!LL很多接口都是基于宏定义,基本相当于直接操作寄存器,跟你所说的效率问题相差不大,但那个更有优势,你自己的代码不能保障,别人不敢用,但官方的LL无论可移植性和可维护性都比你的强,效率上,你敢确定你写的比ST官方的好?再说了,代码效率问题和MCU本省新能是相对的好吧?你犯得着用汇编写PC端软件吗? 你犯得着为F7/F4用寄存器方式来写应用代码吗?从低到高,HAL,SPL,LL可以灵活选择好吧?
4> IDE问题,KEIL编译那是KEIL本身的问题,IAR就没有这个问题,收费方面AC6免费,至于你一定要在LInux这种OS用,好吧,eclipse+插件方式也可以支持。但问题的本质是,这里是开发MCU好吧,不是开发PC端软件,犯得着为了一个MCU上跑的软件非得弄个LInux开发环境来开发吗?非Linux开发环境我还不开心了,典型的脑袋被门夹了!
5> 关于库文档说明问题,你们居然不知道每个HAL库下载包内就已经包含一个CHM帮助文件,里面就有各个HAL接口函数的说明!别拿无知当荣耀好不?库内各种使用DEMO已经各个头文件的注释居然还不能满足你?我只能说明你已经中毒微软太深,一定要弄个类似微软的MSDN这种文档摆在你面前才叫满意,尽管其他各种CHM,DEMO,comment一概无视,任性!牛!
6> 看完以上内容,你还要坚持说,哥就是不爽库开发模式,哥就是想自己动手,从底层一点一滴的来.这只能说面你具有成为大咖的潜质,等你功成名就之时,媳妇早跟别人跑喽。太牛了,果然是英雄!

综述概之,会充分利用各种资源,灵活变通才叫叼!累死的往往是做最底层的!
Inc_brza 回答时间:2017-12-12 10:00:57
本帖最后由 Inc_brza 于 2017-12-12 10:06 编辑
maxtch 发表于 2017-12-12 03:25
说到优化,我想建议您先去看看 LLVM 文档中关于编译器优化的介绍。我这里推荐您去阅读 LLVM 的文档,是因 ...

LLVM我就不看了,你说的SPL我不知道是什么,HAL和STD没法优化,意思是代码已经没法优化了?既然没法优化,那么是指已经是最优化的了还是说没有优化的必要了呢?也就是说,剩下的并不是HAL还是STD,而是编译器的选择了吧?既然这样,那也毫无关系啊,HAL和STD在编写上已经考虑上了GCC、ARMCC和IAR的什么鬼CC了吧,单纯换个编译器的操作并不难吧?
在代码注释里解释操作流程《这个你是不是想歪了?》我来拷贝一下HAL或者STD的开头部分吧。
  1. /**
  2.   ******************************************************************************
  3.   * @file    stm32f7xx_hal_uart.c
  4.   * @author  MCD Application Team
  5.   * @version V1.2.2
  6.   * @date    14-April-2017
  7.   * @brief   UART HAL module driver.
  8.   *          This file provides firmware functions to manage the following
  9.   *          functionalities of the Universal Asynchronous Receiver Transmitter (UART) peripheral:
  10.   *           + Initialization and de-initialization functions
  11.   *           + IO operation functions
  12.   *           + Peripheral Control functions
  13.   *           + Peripheral State and Errors functions
  14.   *
  15.   @verbatim
  16.   ==============================================================================
  17.                         ##### How to use this driver #####
  18.   ==============================================================================
  19.   [..]
  20.     The UART HAL driver can be used as follows:

  21.     (#) Declare a UART_HandleTypeDef handle structure.

  22.     (#) Initialize the UART low level resources by implementing the HAL_UART_MspInit() API:
  23.         (##) Enable the USARTx interface clock.
  24.         (##) UART pins configuration:
  25.             (+++) Enable the clock for the UART GPIOs.
  26.             (+++) Configure these UART pins as alternate function pull-up.
  27.         (##) NVIC configuration if you need to use interrupt process (HAL_UART_Transmit_IT()
  28.              and HAL_UART_Receive_IT() APIs):
  29.             (+++) Configure the USARTx interrupt priority.
  30.             (+++) Enable the NVIC USART IRQ handle.
  31.         (##) DMA Configuration if you need to use DMA process (HAL_UART_Transmit_DMA()
  32.              and HAL_UART_Receive_DMA() APIs):
  33.             (+++) Declare a DMA handle structure for the Tx/Rx stream.
  34.             (+++) Enable the DMAx interface clock.
  35.             (+++) Configure the declared DMA handle structure with the required
  36.                   Tx/Rx parameters.
  37.             (+++) Configure the DMA Tx/Rx Stream.
  38.             (+++) Associate the initialized DMA handle to the UART DMA Tx/Rx handle.
  39.             (+++) Configure the priority and enable the NVIC for the transfer complete
  40.                   interrupt on the DMA Tx/Rx Stream.

  41.     (#) Program the Baud Rate, Word Length, Stop Bit, Parity, Hardware
  42.         flow control and Mode(Receiver/Transmitter) in the Init structure.

  43.     (#) For the UART asynchronous mode, initialize the UART registers by calling
  44.         the HAL_UART_Init() API.

  45.     (#) For the UART Half duplex mode, initialize the UART registers by calling
  46.         the HAL_HalfDuplex_Init() API.

  47.     (#) For the LIN mode, initialize the UART registers by calling the HAL_LIN_Init() API.

  48.     (#) For the Multi-Processor mode, initialize the UART registers by calling
  49.         the HAL_MultiProcessor_Init() API.

  50.      [..]
  51.        (@) The specific UART interrupts (Transmission complete interrupt,
  52.             RXNE interrupt and Error Interrupts) will be managed using the macros
  53.             __HAL_UART_ENABLE_IT() and __HAL_UART_DISABLE_IT() inside the transmit
  54.             and receive process.

  55.      [..]
  56.        (@) These APIs (HAL_UART_Init() and HAL_HalfDuplex_Init()) configure also the
  57.             low level Hardware GPIO, CLOCK, CORTEX...etc) by calling the customized
  58.             HAL_UART_MspInit() API.

  59.      [..]
  60.         Three operation modes are available within this driver :

  61.      *** Polling mode IO operation ***
  62.      =================================
  63.      [..]
  64.        (+) Send an amount of data in blocking mode using HAL_UART_Transmit()
  65.        (+) Receive an amount of data in blocking mode using HAL_UART_Receive()

  66.      *** Interrupt mode IO operation ***
  67.      ===================================
  68.      [..]
  69.        (+) Send an amount of data in non blocking mode using HAL_UART_Transmit_IT()
  70.        (+) At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can
  71.             add his own code by customization of function pointer HAL_UART_TxCpltCallback
  72.        (+) Receive an amount of data in non blocking mode using HAL_UART_Receive_IT()
  73.        (+) At reception end of transfer HAL_UART_RxCpltCallback is executed and user can
  74.             add his own code by customization of function pointer HAL_UART_RxCpltCallback
  75.        (+) In case of transfer Error, HAL_UART_ErrorCallback() function is executed and user can
  76.             add his own code by customization of function pointer HAL_UART_ErrorCallback

  77.      *** DMA mode IO operation ***
  78.      ==============================
  79.      [..]
  80.        (+) Send an amount of data in non blocking mode (DMA) using HAL_UART_Transmit_DMA()
  81.        (+) At transmission end of half transfer HAL_UART_TxHalfCpltCallback is executed and user can
  82.             add his own code by customization of function pointer HAL_UART_TxHalfCpltCallback
  83.        (+) At transmission end of transfer HAL_UART_TxCpltCallback is executed and user can
  84.             add his own code by customization of function pointer HAL_UART_TxCpltCallback
  85.        (+) Receive an amount of data in non blocking mode (DMA) using HAL_UART_Receive_DMA()
  86.        (+) At reception end of half transfer HAL_UART_RxHalfCpltCallback is executed and user can
  87.             add his own code by customization of function pointer HAL_UART_RxHalfCpltCallback
  88.        (+) At reception end of transfer HAL_UART_RxCpltCallback is executed and user can
  89.             add his own code by customization of function pointer HAL_UART_RxCpltCallback
  90.        (+) In case of transfer Error, HAL_UART_ErrorCallback() function is executed and user can
  91.             add his own code by customization of function pointer HAL_UART_ErrorCallback
  92.        (+) Pause the DMA Transfer using HAL_UART_DMAPause()
  93.        (+) Resume the DMA Transfer using HAL_UART_DMAResume()
  94.        (+) Stop the DMA Transfer using HAL_UART_DMAStop()

  95.      *** UART HAL driver macros list ***
  96.      =============================================
  97.      [..]
  98.        Below the list of most used macros in UART HAL driver.

  99.       (+) __HAL_UART_ENABLE: Enable the UART peripheral
  100.       (+) __HAL_UART_DISABLE: Disable the UART peripheral
  101.       (+) __HAL_UART_GET_FLAG : Check whether the specified UART flag is set or not
  102.       (+) __HAL_UART_CLEAR_IT : Clears the specified UART ISR flag
  103.       (+) __HAL_UART_ENABLE_IT: Enable the specified UART interrupt
  104.       (+) __HAL_UART_DISABLE_IT: Disable the specified UART interrupt
  105.       (+) __HAL_UART_GET_IT_SOURCE: Check whether the specified UART interrupt has occurred or not

  106.      [..]
  107.        (@) You can refer to the UART HAL driver header file for more useful macros
复制代码

估计你没有看这个吧?如果你写的库能写得这么详细,那么我举双手的支持啊,就是不知道你有没有这个时间了?而且,你居然把这个比喻成练习手册?
对于新芯片的支持,的确没有一家厂家会在每一款芯片上采用完全不同的外设,而我的意思是,你有时间每用一个新芯片都需要去看参考手册,了解寄存器到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即可,你说哪一个方便?哪一个开发效率高?
maxtch 回答时间:2017-12-9 23:30:45

你指的是什么东西没意思?ST 的固件库已经被我在原帖里面数落过了。我在开发实践中也被 HAL 给咬过。结果 LightSwitchUSB 芯片太小没法用 HAL USB 被迫找第三方,DAP42 就直接跳过 HAL 纯手写了。另外如果你有正版 Keil 或 IAR,我有兴趣看看正版授权书长什么样。
maxtch 回答时间:2017-12-9 23:17:06
anywill 发表于 2017-12-9 22:43
楼主系统的开帖讲讲吧!

好的,什么时候我来讲讲不用 HAL 直接捅寄存器做 STM32 编程,顺道兜售一下我的纯开源 STM32 开发板。呵呵……用什么芯片好呢?我现在设计的纯开源开发板不太好直接做演示,只有 GPIO、USB 和串口有接东西,更多的是兼容 Arduino。
anywill 回答时间:2017-12-9 22:43:23
楼主系统的开帖讲讲吧!
Inc_brza 回答时间:2017-12-9 23:26:48
maxtch 发表于 2017-12-9 23:17
好的,什么时候我来讲讲不用 HAL 直接捅寄存器做 STM32 编程,顺道兜售一下我的纯开源 STM32 开发板。呵 ...

没意思
黑皮男 回答时间:2017-12-10 08:14:18
本帖最后由 黑皮男 于 2017-12-10 08:19 编辑

官方已经做好的库,可能会开销大一下,不用那么在意寄存器的配置,相对来说用起来会简单很多。并且针对新手,上来就整寄存器,当然就懵了。我也不怎么用HAL库开发,代码确实臃肿,不过有LL库可以使用。我也一直尝试GCC来开发,目标也是用纯gcc+makefile搭建一个适合自己的代码框架的平台,不过目前仅仅是自己玩。虽然公司的平台是GCC+eclipse+cmake来搭建的,但需要有个很牛的老大来搭建平台,包括编译脚本的编写。项目中还是IAR或MDK的交互性更好,虽然好多用盗版的。
奏奏奏 回答时间:2017-12-10 13:23:29
黑皮男 发表于 2017-12-10 08:14
官方已经做好的库,可能会开销大一下,不用那么在意寄存器的配置,相对来说用起来会简单很多。并且针对新手 ...

用ST官方的AC6开发就挺好的,免费的
maxtch 回答时间:2017-12-10 15:10:31
本帖最后由 maxtch 于 2017-12-10 15:11 编辑
黑皮男 发表于 2017-12-10 08:14
官方已经做好的库,可能会开销大一下,不用那么在意寄存器的配置,相对来说用起来会简单很多。并且针对新手 ...

但是 ST 的库操作起来和寄存器有什么两样?很多新手被吓到的原因是不会做系统分割,如果把驱动层和应用层分割开来就没那么吓人了。Eclipse 有一个 GNU MCU Eclipse 的插件,可以生成正确的编译脚本,不需要大牛来弄了。IAR 还好一点,MDK 的语言特性支持(C99 和 C11)是个渣渣,至少我个人是用不惯。而且这两个东西不跨平台,如果电脑上没有 Windows 就没法用了。(我的几台电脑分别运行 macOS 和 Ubuntu Linux)
maxtch 回答时间:2017-12-10 15:13:07
奏奏奏 发表于 2017-12-10 13:23
用ST官方的AC6开发就挺好的,免费的

Ac6 用起来还是有点碍手碍脚,而且默认生成的代码有点多。Eclipse CDT + GNU MCU Eclipse 我在用的时候都是从空白项目开始的。
黑皮男 回答时间:2017-12-10 17:31:27
maxtch 发表于 2017-12-10 15:10
但是 ST 的库操作起来和寄存器有什么两样?很多新手被吓到的原因是不会做系统分割,如果把驱动层和应用层 ...

我也很赞同楼主的想法,软件分层的思想在开发的过程中会带来很多便利。固件库提供了很多例程,很多时候直接复制过来就能用,即使不能直接用,也可以做个参考,稍作修改就能用,这个还是比较方便的。至于这个开发环境的问题,估计是个时间的问题,免费好用的GCC工具链出来的应该没有Keil或是IAR那么早,当年学51的时候上的都是Keil。不想Keil那么根深蒂固。感觉Keil用的是最多的。
maxtch 回答时间:2017-12-10 17:54:38
黑皮男 发表于 2017-12-10 17:31
我也很赞同楼主的想法,软件分层的思想在开发的过程中会带来很多便利。固件库提供了很多例程,很多时候直 ...

这种“直接复制过来”的拿来主义其实是学习的大敌。在学习怎么编程的时候,哪怕说以后都用固件库,第一次还是要手写一遍简单的基本外设驱动,这样才能够从软件与硬件结合的深度上领悟到外设的工作原理。另外,这些自己手写的驱动也可以累积起来作为将来应用开发的基础库。

至于开发环境,Eclipse CDT + GNU MCU Eclipse 我的感觉是后来者居上,操作便利度不亚于 Keil,同时又能跨平台,还全开源全免费没有功能限制。8051 的话 SDCC 和相关的开源 IDE 还是差了一点,所以很多人还是用的 Keil C51。STM8 情况也类似。
黑皮男 回答时间:2017-12-10 18:15:43
黑皮男 发表于 2017-12-10 17:31
我也很赞同楼主的想法,软件分层的思想在开发的过程中会带来很多便利。固件库提供了很多例程,很多时候直 ...

感觉像是在开炮,虽然我现在不怎么用Keil和IAR来开发。我是很赞同软件分层和GCC这样的工具链中的在项目中的应用,只不过这个现象是这样存在的。也希望楼主可以开贴讲一讲软件分层相关的经验,目前感觉比较好的是rt-thread的软件架构比较好,但是还是感觉代码占用代码空间过大。
maxtch 回答时间:2017-12-11 02:36:59
黑皮男 发表于 2017-12-10 18:15
感觉像是在开炮,虽然我现在不怎么用Keil和IAR来开发。我是很赞同软件分层和GCC这样的工具链中的在项 ...

我怎么感觉把嵌入式软件分层,手写驱动和 GCC 工具链的使用放在一起都可以写本书了?我的输出里面还有两三本 Keil + 固件库的书呢……
Inc_brza 回答时间:2017-12-11 19:28:14
本帖最后由 Inc_brza 于 2017-12-11 19:36 编辑
maxtch 发表于 2017-12-9 23:30
你指的是什么东西没意思?ST 的固件库已经被我在原帖里面数落过了。我在开发实践中也被 HAL 给咬过。结果 ...

我指的并不是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呢,站在巨人肩膀上,才能看得更远,也许你可以成为巨人,然而时间是宝贵的。
Inc_brza 回答时间:2017-12-11 19:38:32
同时,如果楼主的侧重点是模块化,接口化,对象化,那我就真的支持了!
1234下一页

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版