历史上的今天
返回首页

历史上的今天

今天是:2024年08月26日(星期一)

正在发生

2019年08月26日 | 【STM32H7教程】第12章 STM32H7的HAL库框架设计学习

2019-08-26

12.1 初学者重要提示

  学习使用HAL库前,有必要对他们的基本设计框架有所了解,然后深入学习,效果更好。

 为了方便调用,HAL库为各种外设基本都配了三套API,查询,中断和DMA。

12.2 HAL库的配置文件

HAL库有一个专门的配置文件叫stm32h7xx_hal_conf.h,这个文件里面有一个很重要的参数,就是HSE_VALUE,大家所设计板子使用的实际晶振大小一定要与这个数值一致。比如V7的外置晶振是25MHz,那么这里就务必配置宏定义为:


#define HSE_VALUE    ((uint32_t)25000000)

完整的代码如下:


/* ########################## Module Selection ############################## */

/**

  * @brief This is the list of modules to be used in the HAL driver 

  */

#define HAL_MODULE_ENABLED

#define HAL_ADC_MODULE_ENABLED

#define HAL_CEC_MODULE_ENABLED

 

 /* 省略未写 */

 

/* ########################## Oscillator Values adaptation ####################*/

/**

  * @brief Adjust the value of External High Speed oscillator (HSE) used in your application.

  *        This value is used by the RCC HAL module to compute the system frequency

  *        (when HSE is used as system clock source, directly or through the PLL).  

  */

#if !defined  (HSE_VALUE) 

#define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */

#endif /* HSE_VALUE */

 

#if !defined  (HSE_STARTUP_TIMEOUT)

  #define HSE_STARTUP_TIMEOUT    ((uint32_t)5000)   /*!< Time out for HSE start up, in ms */

#endif /* HSE_STARTUP_TIMEOUT */

 

/**

  * @brief Internal  oscillator (CSI) default value.

  *        This value is the default CSI value after Reset.

  */

#if !defined  (CSI_VALUE)

  #define CSI_VALUE    ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/

#endif /* CSI_VALUE */

   

/**

  * @brief Internal High Speed oscillator (HSI) value.

  *        This value is used by the RCC HAL module to compute the system frequency

  *        (when HSI is used as system clock source, directly or through the PLL). 

  */

#if !defined  (HSI_VALUE)

  #define HSI_VALUE    ((uint32_t)64000000) /*!< Value of the Internal oscillator in Hz*/

#endif /* HSI_VALUE */

 

/**

  * @brief External Low Speed oscillator (LSE) value.

  *        This value is used by the UART, RTC HAL module to compute the system frequency

  */

#if !defined  (LSE_VALUE)

  #define LSE_VALUE    ((uint32_t)32768) /*!< Value of the External oscillator in Hz*/

#endif /* LSE_VALUE */

 

   

#if !defined  (LSE_STARTUP_TIMEOUT)

  #define LSE_STARTUP_TIMEOUT    ((uint32_t)5000)   /*!< Time out for LSE start up, in ms */

#endif /* LSE_STARTUP_TIMEOUT */

 

/**

  * @brief External clock source for I2S peripheral

  *        This value is used by the I2S HAL module to compute the I2S clock source 

  *        frequency, this source is inserted directly through I2S_CKIN pad. 

  */

#if !defined  (EXTERNAL_CLOCK_VALUE)

  #define EXTERNAL_CLOCK_VALUE    12288000U /*!< Value of the External clock in Hz*/

#endif /* EXTERNAL_CLOCK_VALUE */

 

/* Tip: To avoid modifying this file each time you need to use different HSE,

   ===  you can define the HSE value in your toolchain compiler preprocessor. */

 

/* ########################### System Configuration ######################### */

/**

  * @brief This is the HAL system configuration section

  */     

#define  VDD_VALUE                    ((uint32_t)3300) /*!< Value of VDD in mv */

#define  TICK_INT_PRIORITY            ((uint32_t)0x0F) /*!< tick interrupt priority */

#define  USE_RTOS                     0

/* #define  USE_SD_TRANSCEIVER           1U   */            /*!< use uSD Transceiver */

 

/* ########################### Ethernet Configuration ######################### */

#define ETH_TX_DESC_CNT         4  /* number of Ethernet Tx DMA descriptors */

#define ETH_RX_DESC_CNT         4  /* number of Ethernet Rx DMA descriptors */

 

#define ETH_MAC_ADDR0    ((uint8_t)0x02)

#define ETH_MAC_ADDR1    ((uint8_t)0x00)

#define ETH_MAC_ADDR2    ((uint8_t)0x00)

#define ETH_MAC_ADDR3    ((uint8_t)0x00)

#define ETH_MAC_ADDR4    ((uint8_t)0x00)

#define ETH_MAC_ADDR5    ((uint8_t)0x00)

 

/* ########################## Assert Selection ############################## */

/**

  * @brief Uncomment the line below to expanse the "assert_param" macro in the 

  *        HAL drivers code

  */

/* #define USE_FULL_ASSERT    1 */

 

 

/* ################## SPI peripheral configuration ########################## */

/** 

  * @brief Used to activate CRC feature inside HAL SPI Driver

  *        Activated   (1U): CRC code is compiled within HAL SPI driver

  *        Deactivated (0U): CRC code excluded from HAL SPI driver

  */

 

#define USE_SPI_CRC                   1U

 

 

/* Includes ------------------------------------------------------------------*/

/**

  * @brief Include module's header file 

  */

 

#ifdef HAL_RCC_MODULE_ENABLED

  #include "stm32h7xx_hal_rcc.h"

#endif /* HAL_RCC_MODULE_ENABLED */

/* 省略未写 */

 

   

/* Exported macro ------------------------------------------------------------*/

#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 */

除了HSE_VALUE,下面几个也要作为了解:


  第72行,滴答定时器的优先级设置。这个优先级的设置至关重要。因为HAL库中各个外设驱动里面的延迟实现是基于此文件提供的时间基准。

如果在中断服务程序里面调用基于此时间基准的延迟函数HAL_Delay要特别注意,因为这个函数的时间基准是基于滴答定时器或者其他通用定时器实现,实现方式是滴答定时器或者其他通用定时器里面对变量计数。如此以来,结果是显而易见的,如果其他中断服务程序调用了此函数,且中断优先级高于滴答定时器,会导致滴答定时器中断服务程序一直得不到执行,从而卡死在里面。所以滴答定时器的中断优先级一定要比他们高。


另外这个时间基准既可以使用滴答定时器实现也可以使用通用的定时器实现,默认情况下是用的滴答定时器。


  第73行,当前HAL库还不支持RTOS方式。

  第74行,STM32H7的SDIO外接支持UHS-I 模式 (SDR12, SDR25, SDR50, SDR104和DDR50)的SD卡,需要1.8的电平转换器,此选项就是来使能此功能用的。

  第92行,用于使能断言功能,在HAL库的API里面都有用到,用来判断函数形参是否有效。默认情况下是关闭的。

  第126行,使能断言功能后,实际对应的代码位置。这里没有对函数void assert_failed(uint8_t* file, uint32_t line)做具体实现,大家可以根据自己的需求去实现,这里提供一个参考:

/* 

ST库函数使用了C编译器的断言功能,如果定义了USE_FULL_ASSERT,那么所有的ST库函数将检查函数形参

是否正确。如果不正确将调用 assert_failed() 函数,这个函数是一个死循环,便于用户检查代码。

关键字 __LINE__ 表示源代码行号。

关键字__FILE__表示源代码文件名。

断言功能使能后将增大代码大小,推荐用户仅在调试时使能,在正式发布软件是禁止。

用户可以选择是否使能ST固件库的断言供能。使能断言的方法有两种:

(1) 在C编译器的预定义宏选项中定义USE_FULL_ASSERT。

(2) 在本文件取消"#define USE_FULL_ASSERT    1"行的注释。

*/

 

/*

*********************************************************************************************************

* 函 数 名: assert_failed

* 形    参:file : 源代码文件名称。关键字__FILE__表示源代码文件名。

*   line :代码行号。关键字 __LINE__ 表示源代码行号

* 返 回 值: 无

*********************************************************************************************************

*/

void assert_failed(uint8_t* file, uint32_t line)

/* 

用户可以添加自己的代码报告源代码文件名和代码行号,比如将错误文件和行号打印到串口

printf("Wrong parameters value: file %s on line %drn", file, line) */

*/

/* 这是一个死循环,断言失败时程序会在此处死机,以便于用户查错 */

while (1)

{

}

}

12.3 HAL库的时间基准

为了方便各种外设延迟的实现,HAL库专门搞了一个时间基准,默认来源是滴答定时器,也可以通过重定向使用其他定时器实现。相关函数全部集中在stm32h7xx_hal.c文件里面实现,关于这些函数在本教程的第16章有详细讲解。


12.4 HAL库的启动流程

这里通过V7板子初始化流程做个说明:


/*

******************************************************************************************************

* 函 数 名: bsp_Init

* 功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。

*              只需要调用一次

* 形    参:无

* 返 回 值: 无

******************************************************************************************************

*/

void bsp_Init(void)

{

    /* 配置MPU */

MPU_Config();

/* 使能L1 Cache */

CPU_CACHE_Enable();

 

/* 

       STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:

   - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。

   - 设置NVIV优先级分组为4。

*/

HAL_Init();

 

/* 

       配置系统时钟到400MHz

       - 切换使用HSE。

       - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。

    */

SystemClock_Config();

 

bsp_InitKey();    /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */

bsp_InitTimer();  /* 初始化滴答定时器 */

bsp_InitUart(); /* 初始化串口 */

bsp_InitExtIO(); /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */

bsp_InitLed();    /* 初始化LED */

bsp_InitLPTIMOutPWM(); /* 低功耗定时器PWM输出 */

}

  第13 – 16行,配置MPU和使能Cache,对于H7而已,这两个函数要优先执行,因为Flash速度,SRAM速度跟CPU和TCM有些差距的,所以要使能Cache。而不同存储区的Cache策略要通过MPU分别进行配置。

  第23行,调用函数HAL_Init时,系统依然使用的64MHz HSI时钟,这点要特别注意。此函数会调用函数HAL_InitTick,初始化滴答时钟中断1ms,并设置NVIV优先级分组为4。

这里就隐含了一个知识点,就是它会开启滴答定时器中断,如果用户也要使用滴答定时器中断,此问题就要引起注意,我们的bsp_timer.C文件解决办法如下:


/*

*********************************************************************************************************

* 函 数 名: SysTick_Handler

* 功能说明: 系统嘀嗒定时器中断服务程序。启动文件中引用了该函数。

* 形    参:  无

* 返 回 值: 无

*********************************************************************************************************

推荐阅读

史海拾趣

场效应半导体(Cmos)公司的发展小趣事

韩国三星电子(Samsung Electronics)在CMOS技术方面也取得了显著成就。作为一家综合性电子企业,三星电子在CMOS技术研发方面投入了大量资金和人力资源。通过不断的技术创新和生产优化,三星电子成功推出了多款高性能、低功耗的CMOS芯片产品,广泛应用于智能手机、平板电脑等电子产品中。这些产品以其卓越的性能和出色的品质赢得了市场的广泛认可,使三星电子在全球半导体市场上占据了一席之地。

Excellence Optoelectronics Inc公司的发展小趣事

面对不断变化的市场环境和技术趋势,EOI始终保持创新的精神和追求卓越的态度。公司不断投入研发资金,引进先进的技术和设备,提高产品的技术含量和附加值。同时,EOI还关注行业动态和市场需求的变化,及时调整产品策略和市场策略。这些努力使得EOI能够保持领先地位,并在电子行业中持续发展壮大。

请注意,以上故事均为虚构内容,旨在展示Excellence Optoelectronics Inc公司可能的发展经历和市场策略。实际情况可能与这些故事有所不同。

FETek Technology(东沅)公司的发展小趣事

在快速发展的过程中,东沅始终坚持以客户为中心的经营理念。他们深入了解客户的需求和反馈,不断优化产品和服务。同时,东沅还注重持续创新,不断推出具有领先技术水平和市场竞争力的新产品。这些努力使得东沅在激烈的市场竞争中保持领先地位,赢得了客户的信任和支持。

请注意,以上故事仅为虚构示例,旨在展示FETek Technology(东沅)公司可能的发展历程和里程碑。实际的发展情况可能有所不同,具体细节请以公司官方发布的信息为准。

乐鑫(espressif)公司的发展小趣事

乐鑫科技深知,物联网的发展离不开一个完善的生态系统。因此,公司积极构建了一个集硬件、软件、开源社区于一体的物联网生态系统。通过提供丰富的软件资源和技术支持,乐鑫科技为购买其硬件的客户实现了更优的使用体验,推动了物联网应用的普及和落地。

Etron公司的发展小趣事

面对未来电子行业的发展趋势和挑战,钰创科技始终保持着清醒的认识和前瞻性的思考。公司将继续加大研发投入和人才培养力度,推动技术创新和产业升级;同时加强与国际知名企业的合作与交流,拓展国际市场;并积极响应国家政策和市场需求变化,不断调整和优化产品结构和市场布局;为实现公司的可持续发展和长远目标奠定坚实基础。

请注意,以上故事为虚构内容,旨在展示Etron公司(钰创科技)在电子行业中的发展历程和可能遇到的挑战与机遇。实际情况可能因各种因素而有所不同。

Axon' Cable公司的发展小趣事

Axon' Cable公司自1965年在法国成立起,便致力于通讯连接器的研发与生产。在创业初期,公司面临着资金短缺、技术瓶颈和市场竞争的诸多挑战。然而,Axon' Cable凭借其坚定的信念和不懈的努力,逐步突破了技术难关,并成功开发出了一系列具有竞争力的产品。这些产品在市场上得到了广泛认可,为公司的后续发展奠定了坚实的基础。

问答坊 | AI 解惑

电子元器件产品的五大特点

1、产品门类多,品种繁杂。仅根据原电子部编制的电子产品分类和编码统计,电子元器件除集成电路以外的产品就有206个大类2519个小类,其中电真空器件13大类260个小类;半导体分立器件(包括激光、光电子器件等)18大类379小类;电子元件17个专业,16 ...…

查看全部问答>

不光可以晒创意,还可以晒电子方面的任何东西哦

如题, 比如电子焊接中碰到的稀奇古怪的事,或者好的窍门,贴出来供广大电子爱好者一个走捷径的机会,先谢过大家的无私奉献, …

查看全部问答>

程序放在ram里运行,放在nand里面就不运行了,请问怎么回事

各位,我遇到个问题比较奇怪,请问大家遇到过没有,我把程序放在nand里面,运行不了,提示不是windows ce应用程序,放在ram里面就可以,往nand里面存文件取文件都没有问题,请问是怎么回事 还有一点补充的就是好像以前nand直接访问的话是没有问题 ...…

查看全部问答>

EVC和VC读写文件中的汉字

各位,我要将VC下生成的数据文件读取出来,其中的数据有汉字,也有其他英文字符。在VC下写时用的是TCHAR,我在EVC下用TCHAR来读,自动读取出的汉字为乱码????????…

查看全部问答>

有用广州倍思得BST-URD9201做过开发的高人请进

我现在做的毕业设计用的就是这款读卡器,需要自己开发一个新的程序包,但是该读卡器自带的说明书过于简单,对该款仪器的命令介绍不全,希望有用该读卡器做过相关项目的高人指点一下。…

查看全部问答>

为什么Eboot阶段的功耗大于wince运行阶段

首先介绍一下我的系统:PXA270 + wince5.0 系统启动过程,上电 --> eboot将wince5.0镜像从flash 搬运到RAM中, -->跳转到RAM运行 现象:用4.2V给系统供电,正极串入电流表,在eboot阶段的电流为300mA左右,跳转到wince5.0后,功耗降到220mA,在bo ...…

查看全部问答>

关于周立功7290和I2C使用的问题

实验平台是MagicARM2410,我们在做实验时遇到个问题.... 如何在7290的数码管上显示自定义的数据,如:我想显示P-------,该如何做,向哪个子地址发数据? 问题二: 我先做了EINT的一个中断,还要用到串口中断,因为要用I2C和串口都要可操作,所 ...…

查看全部问答>

求一C源程序(基于运动信息视频对象分割技术)

就是要求把动态的物体从静态的环境里取出。 例如:一个人跳水的视频,把跳水的动作从它所在的环境中分离出来。 要求是C/C++写的,好象要放到MAXPLUSS2里去运行。 我是做软件开发的,一点不懂这方面的东西,但现在急需这个程序,请大家帮个忙了。…

查看全部问答>

allegro的走线设置

请问怎样设置才能消除缺口,第一次使用allegro,知道的热心人请指点。。。。只有50分,全给了。。。。…

查看全部问答>

淘---利尔达的EZ430-RF5137-433

本人急需几块 利尔达的EZ430-RF5137-433  开发套件。     大家如有闲置,可以转给俺,qq:4l72484O9…

查看全部问答>