STM32 CMSIS标准和标准库函数文件详解

 

CMSIS各个层级

CMSIS标准层次结构定义了Cortex-M处理器核心与软件之间的接口。这种结构包含多个关键层次,每个层次提供不同的功能和抽象,以便开发者能够有效地编写嵌入式软件。以下是CMSIS标准层次结构的详细说明:

(1) Core层

Core层是CMSIS的核心组成部分,它提供了与Cortex-M处理器内核相关的功能。在这个层次中,有几个关键的模块:

  • NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器):这是处理器内核的中断控制器,负责管理中断请求和处理的优先级。

  • SCB(System Control Block,系统控制块):SCB提供了关键的系统控制功能,包括系统时钟的控制、系统异常处理、CPU状态等。

  • SysTick:SysTick定时器为实现操作系统调度和其他定时任务提供计时器。

  • MPU(Memory Protection Unit,内存保护单元):MPU是一种硬件机制,可用于保护内存区域,限制访问权限和执行权限。

  • (2) DSP库层

    DSP库层提供数字信号处理函数和算法,如FFT、滤波器、向量运算等。这些函数和算法可用于音频、图像处理等应用。CMSIS DSP库使用C语言实现,并经过了针对Cortex-M处理器的优化。

    (3) RTOS层

    RTOS层提供实时操作系统(RTOS)的API,例如任务管理、信号量、队列等。这些API可用于构建嵌入式系统中的多任务应用程序。CMSIS RTOS API基于C语言实现,并支持多种RTOS内核。

    (4) Device层

    Device层提供与特定设备相关的功能,例如GPIO、UART、SPI等。每个设备都有自己的设备头文件和寄存器映射。这个层次由芯片厂商提供,因此不同的芯片可能会有不同的设备层接口。

    (5) Startup文件

    Startup文件提供了启动代码,包括复位向量、中断向量表等。每个芯片厂商都会提供特定的Startup文件,因为不同的芯片可能需要不同的启动流程和初始化。

    (6) 编译器层

    编译器层是CMSIS库的最底层,它包括以下内容:

  • 数据类型定义:定义了通用的数据类型,例如 uint32_t、int16_t、float 等。这样的定义能够在不同的编译器和处理器上保持一致,提高了代码的可移植性。

  • 编译器指令定义:定义了一些编译器相关的指令和语法,例如 __asm、__inline、__packed 等。这些指令能够使代码更加高效和可靠。

  • 内联汇编:内联汇编函数允许程序员在C/C++代码中嵌入汇编指令,以实现特定的功能。

  • 编译器特定的实现:为不同的编译器提供了特定的实现代码,以确保代码能够在不同编译器上编译和运行。

  • 编译器层是CMSIS库的基础,为上层的库层和应用层提供了与编译器相关的接口和实现支持。整个CMSIS标准层次结构通过这些层次的组合,为开发者提供了一种有效的方式来利用Cortex-M处理器核心的功能,并在嵌入式系统中开发高效的软件。

    STM32 CMSIS层次结构与核心支持文件

    在STM32开发中,CMSIS标准层次结构是核心文件体系的一部分,它提供了与Cortex-M处理器核心及片上外设的接口。在CoreSupport文件夹中,我们可以找到两个关键文件:core_cm3.ccore_cm3.h。这些文件在开发过程中扮演着重要角色。

    core_cm3.h

    core_cm3.h 是CMSIS中的核心头文件之一,它实现了与内核相关的寄存器映射,与外设头文件(如stm32f10x.h)相对应。这个头文件定义了一些关键数据类型和常量,为开发者提供了一种在不同处理器平台上保持一致性的方式。这在实现可移植性时尤为重要。

    core_cm3.h 中,还包含了 ANSI C 标准库头文件 stdint.h,这是一个独立于特定处理器的文件,类似于熟知的 stdio.h 文件。它主要定义了一些最小宽度的整数类型,如 int_fast8_tint_fast16_t 等。这些类型的定义屏蔽了不同芯片平台上整数位宽的差异,从而提高了代码的可移植性。这在编写跨平台嵌入式应用程序时非常有用。

    system_stm32f10x.c

    system_stm32f10x.c 文件实现了STM32的时钟配置,主要操作片上的RCC(Reset and Clock Control)外设。在系统上电后,启动文件中的复位函数会调用 SystemInit 函数,而这个函数就在 system_stm32f10x.c 文件中定义。通过这个函数,系统的时钟会被初始化为默认值,例如可能设置为72MHz。如果需要重新配置系统时钟,可以参考这个函数进行修改,但出于库的维护性考虑,最好不要直接修改这个文件中的函数。

    STM32F10x_StdPeriph_Driver

    STM32F10x_StdPeriph_Driver 文件夹包含了针对STM32F10x系列微控制器提供的标准外设库,这是ST公司为了方便开发者使用STM32F10x系列微控制器的外设功能而提供的软件包。

    STM32F10x_StdPeriph_Driver 文件夹中,有两个关键子文件夹:inc(include的缩写)和 src(source的缩写)。这些文件提供了针对片上外设的驱动源代码和相应的外设头文件。src 文件夹包含了每个外设驱动的源代码,而 inc 文件夹则包含了相应的外设头文件。这些文件是ST标准库的主要组成部分,提供了对不同外设的驱动和配置。

     

    这两个文件夹中,还有一个很特别的 **misc.c 文件**,这个文件提供了外设对内核中的 NVIC(中断向量控制器) 的访问函数,在配置中断时,我们必须把这个文件添加到工程中。

    stm32f10x_it.c文件

        这个文件包含了中断处理函数的实现。当一个外部事件(如定时器计数器满、串口接收数据等)触发了一个中断,系统就会执行相应的中断处理函数来响应这个事件。这个文件中包含了这些处理函数的实现,例如 TIMx_IRQHandler、USARTx_IRQHandler等。这些函数中会根据具体的事件类型执行相应的操作,例如清除中断标志位、读取接收数据等等。

    system_stm32f10x.c文件

        这个文件包含了系统初始化函数的实现。在系统启动时,需要进行一些基本的初始化操作,例如配置系统时钟、启用外设时钟、设置中断向量表等等。这些操作会在系统初始化函数中完成。这个文件中的函数主要有SystemInit、SystemCoreClockUpdate等。其中,SystemInit函数会在启动时自动执行,用于进行最基本的系统初始化;SystemCoreClockUpdate函数则用于更新系统时钟频率,以便应对系统时钟频率改变的情况。

    stm32f10x_conf.h文件

        stm32f10x_conf.h:这个文件被包含进 stm32f10x.h 文件。当我们使用固件库编程的时候,如果需要某个外设的驱动库,就需要包含该外设的头文件: stm32f10x_ppp.h,包含一个还好,如果是用了多外设,就需要包含多个头文件,这不仅影响代码美观也不好管理,现我们用一个头文件stm32f10x_conf.h 把这些外设的头文件都包含在里面,让这个配置头文件统一管理这些外设的头文件,我们在应用程序中只需要包含这个配置头文件即可,我们又知道这个头文件在stm32f10x.h 的最后被包含,所以最终我们只需要包含 stm32f10x.h 这个头文件即可,非常方便。默认情况下是所以头文件都被包含,没有被注释掉。我们也可以把不要的都注释掉,只留下需要使用的即可。

    stm32f10x_conf.h 这个文件还可配置是否使用“断言”编译选项

    #ifdef USE_FULL_ASSERT 
    /** 
    * @brief The assert_param macro is used for function's parameters check. 
    * @param expr: If expr is false, it calls assert_failed function which reports 
    * the name of the source file and the source line number of the call 
    * that failed. If expr is true, it returns no value. 
    * @retval None 
    */ 
    #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__)) 
    /* Exported functions ------------------------------------------------------- */ 
    void assert_failed(uint8_t* file, uint32_t line);
    #else
    #define assert_param(expr) ((void)0) 
    #endif /* USE_FULL_ASSERT */
    关于断言:

    编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设,可以将断言看作是异常处理的一种高级形式。断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真。可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言,而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新启用断言。 —来自百度百科

    有这么一个数组和函数:

    int Array[5] = {0xA1, 0xB2, 0xC3, 0xD4, 0xE5};
    
    int Fun(char i)
    {
        return Array[i];
    }
    
    1234567
    

    如果我们函数中不加Assert断言语句,你觉得直接调用这个函数会有风险吗?

    假如这么调用:

    int a;
    
    a = Fun(8);
    
    1234
    

    很明显,就这么调用,会出错,且我们不容易发现错误在哪里。

    但是,假如添加有Assert断言语句,错误就能一下找出来。

    在 ST 标准库的函数中,一般会包含输入参数检查,即上述代码中的“assertparam”宏,当参数不符合要求时,会调用“assertfailed”函数,这个函数默认是空的。实际开发中使用断言时,先通过定义 USEFULLASSERT 宏来使能断言,然后定义“assertfailed”函数,通常我们会让它调用 printf 函数输出错误说明。使能断言后,程序运行时会检查函数的输入参数,当软件经过测试,可发布时,会取消 USEFULL_ASSERT 宏来去掉断言功能,使程序全速运行。

    image.png

    image.png

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 CMSIS标准和标准库函数文件详解

    发表评论