在ARM MDK和STM32Cube中如何选择驱动库:CMSIS Driver、SPL、HAL、LL

阅读本专栏其他文章,有助于理解本文。👆

文章目录

  • 一、开发库选择
  • 1.1 概述
  • 1.2 CMSIS pack
  • 1.3 SPL库
  • 1.4 HAL 库
  • 1.5 LL库
  • 1.6 寄存器开发
  • 二、代码对比
  • 2.1 使用寄存器
  • 2.2 使用CMSIS库
  • 2.3 使用SPL库
  • 2.4 使用HAL库
  • 2.5 使用LL库
  • 2.6 使用RTOS
  • 三、如何在软件中选择不同的库
  • 3.1 ARM MDK
  • 3.2 STM32Cube IDE
  • 一、开发库选择

    1.1 概述

    STM32开发相关的库有很多,它们都是为了方便开发者使用STM32微控制器而提供的软件工具。根据不同的功能和层次,可以将它们分为以下几类:

    1. CMSIS库(准确来说是CMSIS pack)Cortex Microcontroller Software Interface Standard)是ARM公司推出的一种标准化的微控制器软件接口,它定义了一些通用的数据类型、寄存器访问、中断处理、内核功能等,方便开发者使用Cortex-M内核的各种功能。CMSIS库还包括了一些中间件组件,如RTOS、DSP、Driver、Pack、SVD、DAP和NN等,提供了丰富的软件功能。CMSIS库不是HAL库,也不是标准库,它是一种与厂商(比如ST公司)无关的软件层,可以在不同的微控制器上使用。

    2. HAL库Hardware Abstraction Layer硬件抽象层)是ST公司推出的一种硬件抽象层库,它提供了一套统一、简洁、易用的API函数接口,方便开发者使用STM32的各种外设功能。HAL库支持STM32全系列产品,具有可移植性、易用性和可靠性等优点。HAL库还提供了一些中间件组件,如RTOS,USB,TCP/IP和图形等,可以快速实现复杂的功能。

    3. 标准库Standard Peripheral Libraries)是ST公司为STM32微控制器提供的一种固件函数包,它封装了STM32所有外设的寄存器操作和中断处理,提供了一套统一、简洁、易用的API函数接口,方便开发者使用STM32的各种外设功能。标准库支持STM32全系列产品,具有可移植性、易用性和可靠性等优点。不过,ST官方已经不再更新STM32标准固件库,而是力推新的固件库:HAL库。

    4. LL库(Low-Layer,底层)是ST公司最近(也不是最近,六七年了)新增的一种底层库,它与HAL库捆绑发布,文档也是和HAL文档在一起的。 LL库更接近硬件层,对需要复杂上层协议栈的外设不适用,直接操作寄存器。LL库可以独立使用,也可以和HAL库结合使用。

    5. 其他第三方或开源库:除了ST公司提供的官方库外,还有许多第三方或开源的软件库可以用于STM32开发,如FreeRTOS、uCOS、FatFs、LwIP等。这些软件库通常提供了一些特定领域或功能的解决方案,如实时操作系统、文件系统、网络协议等。

    很显然,CMSISI库(主要是CORE)是最基本的,HAL、SPL、LL(STM32)都是基于CMSIS CORE进一步进行设计和开发的,旨在降低开发难度。

    我们通常的、简单的开发形式有:HAL库开发、LL库开发、SPL库开发、第三方库开发。


    插一嘴:

    一般,如果你使用正点原子的开发板进行学习或开发,就会看到他们的相关资料。你会看到:《xxx开发指南HAL库版本Vx.x》、《xxx开发指南固件库版本Vx.x》、《xxx开发指南寄存器版本Vx.x》。

    这里说明一下:正点原子一些资料里面的“固件库”、“标准库”、“库函数”,这些名词一般都指的是:STM32 的 Standard Peripheral Library (SPL):标准外设库(或SPL库中的函数)。

    (具体的看资料内部描述即可)

    实际上,固件库不单单指的是SPL库,固件库是指由芯片厂商提供的针对特定芯片或系列芯片的软件包,它包含了对芯片外设的驱动函数、示例代码、中间件和实用工具等。固件库的目的是为了简化开发者对底层硬件的访问和操作,提供一个统一的、易于使用的编程接口。所以:LL库、HAL库、SPL库都是固件库。所以,当您看到HAL固件库这样类似的名词时应当理解其就是HAL库。

    总之,注意一下,正点原子的一些资料可能把SPL库叫做固件库或标准库。


    1.2 CMSIS pack

    CMSIS (Cortex Microcontroller Software Interface Standard) 是 ARM 公司为其 Cortex-M 系列微控制器定义的一套软件接口标准。这套标准旨在简化微控制器的软件开发,使得开发者可以更容易地开发跨不同 Cortex-M 处理器系列和供应商的嵌入式应用程序。

    提示: 阅读本专栏其他文章,学习相关知识点。

    CMSIS pack主要由以下几部分组成:

  • CMSIS-CORE:提供了Cortex-M处理器的核心功能接口,包括NVIC、SysTick等。它还定义了处理器的寄存器访问、中断向量和中断函数名称。

  • CMSIS-DSP:一个为Cortex-M处理器优化的数字信号处理库,提供了丰富的DSP函数,如FFT、滤波器、矩阵运算等。

  • CMSIS-RTOS:为实时操作系统提供了一个标准的API接口,使得开发者可以轻松地在不同的RTOS之间切换。

  • CMSIS-Driver:定义了一套标准的外设驱动接口,如UART、SPI、I2C等。

  • CMSIS-SVD:系统查看描述,提供了一个描述微控制器外设的XML格式。

  • CMSIS-Pack:定义了一个用于软件组件、设备和板卡的描述、交付和安装的标准。

  • 1

    这里的Standard Middleware(标准中间件),提供了一组更高级别的软件组件,用于实现常见的嵌入式系统功能。比如RTOS、USB、文件系统等等。

    CMSIS是ARM为Cortex-M系列MCU提供的标准API,而各个使用该内核的芯片厂商(比如NXP、ST、intel),通常会在这些接口的基础上进一步开发适用于自家芯片的 开发库,比如ST的HAL、LL、SPL库。

    CMSIS的优势

  • 跨平台:由于CMSIS是为Cortex-M系列微控制器定义的标准,因此开发者可以轻松地将代码从一个Cortex-M处理器迁移到另一个处理器,而无需进行大量的代码修改。

  • 高效性:CMSIS库中的许多函数都经过了优化,以充分利用Cortex-M处理器的特性,如SIMD指令。

  • 易于使用:CMSIS提供了清晰、一致的API,使得开发者可以快速上手并开始开发。

  • 强大的生态系统:许多第三方供应商和RTOS提供了对CMSIS的支持,这使得开发者可以轻松地集成各种软件组件和工具。


  • 通常在进行STM32开发时,不会直接使用CMSIS 的API,而是使用基于CMSISI的HAL库或者SPL库,它们提供了更高级的抽象、更易用的API、更丰富的文档、更好的IDE支持等等。

    使用CMSIS库可以获得更精细粒度的控制、更强大额性能,在以下场景中,可能会直接使用CMISIS库:

    1. DSP开发,CMSIS-DSP已经为Cortex-M系列微控制器进行了优化。对于需要高性能计算的应用,直接使用这些函数可能会更有效。
    2. 如果开发者希望他们的代码能够在不同的Cortex-M微控制器之间移植,那么直接使用CMSIS库会更有意义,因为它提供了一个标准化的接口。
    3. 使用RTOS。

    1.3 SPL库

    STM32的SPL(Standard Peripheral Libraries),即标准外设库,是STMicroelectronics为其STM32系列Cortex-M微控制器提供的软件开发库。它为STM32微控制器上的各种外设提供了C语言的函数API,帮助开发者简化硬件配置和使用。

    STM32的SPL主要由以下几部分组成:

  • 外设驱动:为STM32微控制器上的各种外设(如GPIO、UART、SPI、I2C、ADC、TIM等)提供了驱动函数。

  • CMSIS支持:SPL包括对CMSIS库的支持,特别是CMSIS-CORE部分,为开发者提供了对Cortex-M核心功能的访问。

  • 系统配置:包括系统时钟、中断和其他基础配置的函数。

  • 工具链文件:如启动文件、链接脚本等,这些文件为特定的工具链(如GCC、Keil、IAR等)提供了支持。

  • 示例代码:STMicroelectronics通常会提供一些示例代码,展示如何使用SPL来开发应用程序。

  • STM32 SPL 应用程序的文件描述:

    文件名 描述
    STM32 SPL
    stm32yyxx_conf.h 外设驱动程序的配置文件。用户可以通过使用模板启用或禁用外设头文件包含。此文件还可用于在编译固件库驱动程序之前启用或禁用库运行时失败,通过预处理器定义USE_FULL_ASSERT
    stm32yyxx_ppp.h PPP外设的头文件
    stm32yyxx_ppp.c 用C语言编写的PPP外设的驱动源代码文件
    stm32yyxx_it.h 包含所有中断处理程序原型的头文件
    stm32yyxx_it.c 包含Cortex-Mx异常的中断服务例程(ISR)的模板源文件。用户可以为使用的外设添加额外的ISRs(有关可用的外设中断处理程序的名称,请参考startup_stm32yyxx.s)
    CMSIS
    stm32yyxx.h CMSIS Cortex-Mx STM32yyxx 设备外设访问层头文件。这是应用程序员在源代码中使用的唯一包含文件
    system_stm32yyxx.h CMSIS Cortex-Mx STM32yyxx 设备外设访问层系统头文件
    system_stm32yyxx.c CMSIS Cortex-Mx STM32yyxx 设备外设访问层系统源文件

    2

    SPL的优势:

  • 简化开发:STM32的SPL为微控制器的外设提供了高级的抽象,使得开发者不需要深入了解硬件细节就可以配置和使用外设。

  • 跨设备兼容性:由于SPL为STM32系列的微控制器提供了统一的API,因此开发者可以更容易地在同一系列的不同微控制器之间移植代码。

  • 供应商支持:使用SPL意味着可以获得STMicroelectronics的支持,包括文档、示例代码和可能的固件更新。

  • SPL的局限性:

  • 性能:由于SPL提供了高级的抽象,某些操作可能不如直接访问硬件寄存器那么快。

  • 灵活性:虽然SPL为大多数常见的用例提供了支持,但对于一些特定的、非标准的需求,直接使用CMSIS或其他方法可能会更合适。

  • 更新和维护STMicroelectronics已经开始推广其HAL(硬件抽象层)库,并逐渐减少对SPL的支持。因此,新的STM32产品可能不再支持SPL,或者SPL可能不再获得更新。

  • 1.4 HAL 库

    HAL(Hardware Abstraction Layer),即硬件抽象层,是STMicroelectronics为其STM32系列微控制器提供的一个新的软件开发框架。与SPL(标准外设库)相比,HAL提供了更高级的抽象和更多的功能,旨在简化和加速STM32微控制器的开发过程。

    STM32的HAL库主要由以下几部分组成:

  • 外设驱动:为STM32微控制器上的各种外设(如GPIO、UART、SPI、I2C、ADC、TIM等)提供了驱动函数。

  • 中间件支持:HAL库包括对各种中间件的支持,如USB、TCP/IP、文件系统等。

  • 系统配置:提供了系统时钟、电源模式、中断和其他基础配置的函数。

  • 回调机制:HAL库使用了回调函数的机制,允许开发者在特定的事件(如数据接收完成)发生时执行自定义的代码。

  • 错误处理:HAL库提供了错误处理和检查机制,帮助开发者识别和处理可能的错误。

  • HAL库的优势:

  • 模块化和可重用性:HAL库的设计使得开发者可以轻松地重用代码,特别是在不同的STM32微控制器之间。

  • 跨设备兼容性:由于HAL为STM32系列的微控制器提供了统一的API,因此开发者可以更容易地在同一系列的不同微控制器之间移植代码。

  • 集成开发环境(IDE)支持:STMicroelectronics提供了STM32CubeMX工具,该工具可以自动生成HAL库的初始化代码,进一步简化了开发过程。

  • 持续更新和维护:与SPL相比,HAL库获得了更多的更新和维护,以支持新的STM32产品和功能。

  • HAL库的局限性:

  • 学习曲线:对于习惯于使用SPL或直接访问硬件寄存器的开发者来说,HAL库可能需要一些时间来熟悉。

  • 性能考虑:虽然HAL库为开发者提供了很多便利,但它的高级抽象可能会导致某些操作的性能略有下降。

  • 1.5 LL库

    STM32的LL库((Low Layer))是STM32Cube库的一部分,旨在为STM32外设提供一个简化的API集,同时保持最大的灵活性。LL库是一个更接近硬件的编程接口,与HAL(硬件抽象层)库相比,它提供了更低的抽象级别。

    主要特点:

    1. 性能:由于LL库提供了更接近硬件的API,因此它通常比HAL库更快,尤其是在中断处理程序中。

    2. 简单性:LL库的API设计得更简单,更直接,使得代码更容易阅读和维护。

    3. 灵活性:LL库提供了对STM32外设的完全控制,允许开发人员更好地优化其应用程序。

    4. 与HAL的互操作性:LL库可以与HAL库一起使用,这意味着开发人员可以在同一个项目中混合使用两者,根据需要选择最佳的库。

    LL库的组成:

  • 外设初始化:LL库提供了初始化外设的功能,这些功能通常比HAL库提供的功能更简单,更直接。

  • 外设控制:LL库提供了一组函数,允许开发人员直接控制STM32外设,而无需经过任何中间抽象。

  • 中断处理:与HAL库相比,LL库提供了更简单、更直接的中断处理函数。

  • 使用LL库的优点:

    1. 代码大小:由于LL库提供了更少的抽象,因此生成的代码通常比使用HAL库的代码更小。

    2. 执行速度:LL库的函数通常比HAL库的函数执行得更快,因为它们提供了更少的抽象。

    3. 更好的控制:LL库允许开发人员更直接地控制STM32外设,这可以提供更好的性能和更低的功耗。

    STM32Cube库的组成如下:(STMicroelectronics为其STM32微控制器系列提供的一个全面的软件开发工具集)

    1. HAL (Hardware Abstraction Layer):这是STM32Cube的核心部分,提供了一套完整的外设驱动程序,用于STM32系列的微控制器。这些驱动程序提供了一个高级的API,使开发人员能够轻松地访问STM32的各种功能。

    2. LL (Low Layer):这是一个更接近硬件的驱动程序集,为那些需要更高性能或更低级访问的应用程序提供了一个选择。

    3. Middleware:STM32Cube还包含了一些中间件组件,如USB库、TCP/IP堆栈、文件系统、RTOS接口等。

    4. CMSIS (Cortex Microcontroller Software Interface Standard):这是ARM定义的一个标准,用于开发Cortex-M微控制器的应用程序。STM32Cube包含了CMSIS核心和设备头文件。

    5. Utilities:这些是一些实用程序和工具,如数据结构、数学函数、图形界面库等。

    6. Examples and Templates:STM32Cube为STM32的各种开发板提供了大量的示例代码和模板,帮助开发人员快速入门。

    7. Configuration Tool:STM32CubeMX是一个图形工具,允许用户图形化地配置STM32微控制器的外设,并自动生成初始化代码。

    1.6 寄存器开发

    STM32寄存器开发是一种直接操作STM32微控制器内部的寄存器来控制外设的开发方式,它可以充分利用STM32的性能和灵活性,但也需要对寄存器的功能和地址有深入的了解。

    STM32寄存器开发的优点是:

  • 可以实现最高效的代码执行,无需调用库函数或中间件。
  • 可以实现最灵活的外设配置,无需受限于库函数或中间件的参数。
  • 可以实现最低层次的硬件控制,无需考虑库函数或中间件的兼容性。
  • STM32寄存器开发的缺点是:

  • 需要对寄存器的功能和地址有深入的了解,否则容易出错或造成冲突。
  • 需要编写大量的代码,否则难以实现复杂的功能或逻辑。
  • 需要手动管理内存和堆栈,否则容易出现溢出或泄漏。
  • 有时候,直接使用寄存器进行开发也称作“裸机开发”。但裸机开发有时候也指不使用操作系统的开发。

    二、代码对比

    一个简单功能的实现:点亮一个 LED。以下是使用不同 STM32 开发库实现此功能的代码示例(主要部分):

    2.1 使用寄存器

    直接操作STM32的硬件寄存器来配置和控制GPIO。

    #define GPIOB_BASE 0x40020400
    #define GPIOB_MODER ( *(volatile uint32_t*)(GPIOB_BASE) )
    #define GPIOB_ODR   ( *(volatile uint32_t*)(GPIOB_BASE + 0x14) )
    
    int main(void) {
        // 设置PB0为输出模式
        GPIOB_MODER |= (1 << 0);
        
        while(1) {
            GPIOB_ODR |= (1 << 0);  // 点亮LED
        }
    }
    

    2.2 使用CMSIS库

    使用CMSIS定义的结构和宏来操作寄存器。

    #include "stm32f4xx.h"
    
    int main(void) {
        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;  // 使能GPIOB时钟
        GPIOB->MODER |= GPIO_MODER_MODER0_0;  // 设置PB0为输出模式
        
        while(1) {
            GPIOB->ODR |= GPIO_ODR_OD0;  // 点亮LED
        }
    }
    

    2.3 使用SPL库

    使用STM32标准外设库函数。

    #include "stm32f4xx_gpio.h"
    #include "stm32f4xx_rcc.h"
    
    int main(void) {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
    
        while(1) {
            GPIO_SetBits(GPIOB, GPIO_Pin_0);  // 点亮LED
        }
    }
    

    2.4 使用HAL库

    使用STM32硬件抽象层函数。

    #include "stm32f4xx_hal.h"
    
    GPIO_InitTypeDef GPIO_InitStructure;
    
    int main(void) {
        __HAL_RCC_GPIOB_CLK_ENABLE();
    
        GPIO_InitStructure.Pin = GPIO_PIN_0;
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStructure.Pull = GPIO_NOPULL;
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
    
        while(1) {
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);  // 点亮LED
        }
    }
    

    2.5 使用LL库

    使用STM32低层库函数。

    #include "stm32f4xx_ll_gpio.h"
    #include "stm32f4xx_ll_bus.h"
    
    int main(void) {
        LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
    
        LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_0, LL_GPIO_MODE_OUTPUT);
    
        while(1) {
            LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_0);  // 点亮LED
        }
    }
    

    2.6 使用RTOS

    使用实时操作系统(如FreeRTOS)来控制LED。

    #include "FreeRTOS.h"
    #include "task.h"
    #include "stm32f4xx_hal.h"
    
    void LedTask(void *pvParameters) {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        __HAL_RCC_GPIOB_CLK_ENABLE();
    
        GPIO_InitStructure.Pin = GPIO_PIN_0;
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_InitStructure.Pull = GPIO_NOPULL;
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
    
        while(1) {
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);  // 点亮LED
            vTaskDelay(1000);  // 延时1秒
        }
    }
    
    int main(void) {
        xTaskCreate(LedTask, "LED", 128, NULL, 1, NULL);
        vTaskStartScheduler();
    }
    

    三、如何在软件中选择不同的库

    3.1 ARM MDK

    如何新建工程、安装pack以及MDK的各个功能,我前面的文章有详细介绍。

    假设我们使用的外设是GPIO。

    再次回顾这张图:

    现在打开MDK的RTE管理器,我们就很清楚的知道,无论使用SPL还是使用HAL库,都必须要选择下图CMSIS下的CORE。因为这些库都是基于CMSIS CORE(提供了访问和控制MCU的核心API)进行进一步开发的。

    上面这些选项(software component),与你安装的pack有关,不一定都是这些内容,其作用分别是(当然你看后面的Description也是一样的):

    大类 是什么 有什么用
    Board Support 与特定开发板相关的驱动和配置文件。 提供了开发板特有的硬件接口和初始化代码,如 LED、按钮、LCD 显示等的驱动。
    CMSIS ARM 提供的一组与硬件无关的接口。 提供了一种标准化的方法来访问 Cortex-M 内核(这是STM32使用的内核)的特性,如 NVIC、系统时钟等。
    CMSIS Driver CMSIS 的一部分,提供了一组标准的设备驱动接口。 允许以一种与硬件无关的方式编写代码,以控制各种外设,如 UART、SPI、I2C 等。
    Compiler 包含了编译器特定的设置和库。 用于优化代码和提供编译器特定的内联汇编、宏等。
    Device 特定于微控制器(如 STM32F1)的驱动和配置文件。 提供了访问和控制特定微控制器硬件的必要代码和接口。
    File System 提供了文件系统的实现。 允许在嵌入式系统中使用如 FAT、NFS 等文件系统,通常用于 SD 卡或内部存储的数据管理。
    Graphics 包含了图形用户界面(GUI)和显示驱动。 提供了创建图形界面的工具和库,如按钮、滑块、文本框等。
    Network 包含了网络协议栈和相关的服务。 允许嵌入式系统通过 Ethernet、Wi-Fi 等进行网络通信,支持如 TCP/IP、HTTP、MQTT 等协议。
    USB 包含了 USB 通信的驱动和库。 提供了实现 USB 主机或设备功能的必要接口和代码,如 USB HID、USB Mass Storage 等。

    CMSIS Driver 提供了cortex M3 MCU外设控制的API,我们使用的STM32芯片,既然使用了这个内核,那么我们肯定是可以使用CMSIS Driver下面的API进行开发的,但这些API并不是针对STM32芯片的,是通用API,所以你要使用这些API进行开发的话,需要仔细阅读具体芯片的数据手册才行。

    因此,推荐使用各个厂商的API,它们会对具体的芯片信号进行适配、优化,开发起来更加便捷。

    当你安装芯片对应的pack后,该芯片在MDK中支持的库就会显示在Device目录下面,根据需要,选择相关外设的API即可。

    注意: 由于历史原因,MDK中,STM32 F1系列的芯片只有SPL这一个库,而F4这种比较新的芯片就支持SPL、HAL、LL库了。(当然,并不是说F1系列不支持HAL库,只是MDK的RTE不提供这个选项,你可以去STM32Cube开发,或者从MX复制过来)。

    F4:

    再补充一点:有的库对C语言标准是有要求的,MDK可能默认设置的是c90,你手动换成新一点的标准就行了。

    3.2 STM32Cube IDE

    STM32Cube主要使用HAL和LL库。

    在STM32Cube MX中选择即可,默认就是HAL。每个外设都可以单独指定(如果你比较熟练,且对性能有较高的要求)

    集成于STM32Cube IDE的STM32Cube MX可能没有保存之类的按钮,使用快捷键ctrl s就行了。单独安装的STM32Cube MX更方便与其他IDE和工具链一起使用。


    1. Keil官方:https://www.keil.com/pack/doc/CMSIS_Dev/General/html/index.html ↩︎

    2. ST官方:https://www.st.com/resource/en/application_note/an5044-stm32-standard-peripheral-library-to-stm32cube-lowlayer-migration-stmicroelectronics.pdf ↩︎

    物联沃分享整理
    物联沃-IOTWORD物联网 » 在ARM MDK和STM32Cube中如何选择驱动库:CMSIS Driver、SPL、HAL、LL

    发表评论