STM32 H7系列学习笔记

这篇具有很好参考价值的文章主要介绍了STM32 H7系列学习笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

必备的API知识

第 1 步:系统上电复位,进入启动文件 startup_stm32h743xx.s,在这个文件里面执行复位中断服务程序。

  • 在复位中断服务程序里面执行函数 SystemInit,在system_stm32h7xx.c 里面。*
  • 之后是调用编译器封装好的函数,比如用于 MDK 的启动文件是调__main,最终进入到 main函数*

第 2 步:进入到 main 函数就可以开始用户应用程序编程了。在这个函数里面要做几个重要的初始化,依次是:

  • MPU 初始化,需要用到库文件
    stm32h7xx_hal_cortex.c 和stm32h7xx_hal_cortex.h。
  • Cache 初始化,需要用到 core_cm7.h 文件。
  • HAL 库初始化函数 HAL_Init,需要用到文件 stm32h7xx_hal.c。
  • 系统时钟初始化,需要用到库文件 stm32h7xx_hal_rcc.c。

函数 HAL_Init()

HAL_StatusTypeDef HAL_Init(void)
{
/* 设置中断优先级分组 */
 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
 /* 使用滴答定时器做为默认时基,配置为 1ms 滴答,另外系统上电后默认使用的 HIS 时钟 */
 if(HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
 {
 return HAL_ERROR;
 }
  /* 初始化底层硬件 */
 HAL_MspInit();
 /* 返回函数状态 */
 return HAL_OK;
}

此函数用于初始化 HAL 库,此函数主要实现如下功能:

  • 设置 NVIC 优先级分组是 4。
  • 设置滴答定时器的每 1ms 中断一次。
  • HAL 库不像之前的标准库,在系统启动函数 SystemInit 里面做了 RCC 初始化,HAL 库是没有做的,
    所以进入到 main 函数后,系统还在用内部高速时钟 HSI,对于 H7 来说,HSI 主频是 64MHz。
  • 函数 HAL_Init 里面调用的 HAL_MspInit 一般在文件 stm32h7xx_hal_msp.c 里面做具体实现,主要
    用于底层初始化。当前此函数也在文件 stm32h7xx_hal.c 里面,只是做了弱定义。

源文件 sttm32h7xx_hal_rcc.c

这个文件主要是实现内部和外部时钟(HSE、HSI、LSE、CSI、LSI、HSI48、PLL、CSS、MCO)以
及总线时钟(SYSCLK、AHB3、 AHB1、AHB2、AHB4、APB3、APB1L、APB1H、APB2、 APB4)的配置。
系统上电复位后,用户需要完成以下工作:
⚫选择用于驱动系统时钟的时钟源。
⚫ 配置系统时钟频率和 Flash 设置。
⚫ 配置分频器。
⚫ 使能外设时钟。
⚫ 配置外设时钟源,部分外设的时钟可以不来自系统时钟,此时通过配置寄存器 RCC_D1CCIPR、
RCC_D2CCIP1R、RCC_D2CCIP2R 和 RCC_D3CCIPR 实现

函数 HALRCCClockConfig()

RCC_ClkInitTypeDef RCC_ClkInitStruct;
HAL_StatusTypeDef ret = HAL_OK;

/* 
 选择 PLL 的输出作为系统时钟
 配置 RCC_CLOCKTYPE_SYSCLK 系统时钟
 配置 RCC_CLOCKTYPE_HCLK 时钟,对应 AHB1,AHB2,AHB3 和 AHB4 总线
 配置 RCC_CLOCKTYPE_PCLK1 时钟,对应 APB1 总线
 配置 RCC_CLOCKTYPE_PCLK2 时钟,对应 APB2 总线
 配置 RCC_CLOCKTYPE_D1PCLK1 时钟,对应 APB3 总线
 配置 RCC_CLOCKTYPE_D3PCLK1 时钟,对应 APB4 总线 
 */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 |
RCC_CLOCKTYPE_PCLK1 | \
RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; 
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; 
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; 
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; 
/* 此函数会更新 SystemCoreClock,并重新配置 HAL_InitTick */
ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
if(ret != HAL_OK)
{
 Error_Handler(__FILE__, __LINE__);
}

源文件 sttm32h7xx_hal_cortex.c

这个库文件主要功能是 NVIC,MPU 和 Systick 的配置。此文件有个臃肿的地方,里面的 API 其实就
是将 ARM 的 CMSIS 库各种 API 重新封装了一遍。这么做的好处是保证了 HAL 的 API 都是以字母 HAL
开头。

MPU 单元

MPU 可以将 memory map 内存映射区分为多个具有一定访问规则的区域,通过这些规则可以实现
如下功能:
◆ 防止不受信任的应用程序访问受保护的内存区域。
◆ 防止用户应用程序破坏操作系统使用的数据。
◆ 通过阻止任务访问其它任务的数据区。
◆ 允许将内存区域定义为只读,以便保护重要数据。
◆ 检测意外的内存访问。
简单的说就是内存保护、外设保护和代码访问保护

MPU 可以配置保护 16 个内存区域(这 16 个内存域是独立配置的),每个区域最小要求 256 字节,
每个区域还可以配置为 8 个子区域。由于子区域一般都相同大小,这样每个子区域的大小就是 32 字节,正好跟 Cache 的 Cache Line 大小一样。
MPU 可以配置的 16 个内存区的序号范围是 0 到 15,还有默认区 default region,也叫作背景区,序号-1。由于这些内存区可以嵌套和重叠,所以这些区域在嵌套或者重叠的时候有个优先级的问题。序号15 的优先级最高,以此递减,序号-1,即背景区的优先级最低。这些优先级是固定的。下面通过一个具体的实例帮助大家理解。如下所示共有 7 个区,背景区和序号 0-5 的区。内存区 4 跟内存区 0 和 1 有重叠部分,那么重叠部分将按照内存区 4 的配置规则执行;内存区 5 被完全包含在内存区3 里面,那么这部分内存区将按照内存区 5 的配置规则执行。

函数 HAL_MPU_ConfigRegion()

== 函数原型:==

void HAL_MPU_ConfigRegion(MPU_Region_InitTypeDef *MPU_Init)
{
 /* 部分省略未写 */
 /* Set the Region number */
 MPU->RNR = MPU_Init->Number;
 if ((MPU_Init->Enable) != RESET)
 {
 /* 部分省略未写 */
 MPU->RBAR = MPU_Init->BaseAddress;
 MPU->RASR = ((uint32_t)MPU_Init->DisableExec << MPU_RASR_XN_Pos) |
 ((uint32_t)MPU_Init->AccessPermission << MPU_RASR_AP_Pos) |
 ((uint32_t)MPU_Init->TypeExtField << MPU_RASR_TEX_Pos) |
 ((uint32_t)MPU_Init->IsShareable << MPU_RASR_S_Pos) |
 ((uint32_t)MPU_Init->IsCacheable << MPU_RASR_C_Pos) |
 ((uint32_t)MPU_Init->IsBufferable << MPU_RASR_B_Pos) |
 ((uint32_t)MPU_Init->SubRegionDisable << MPU_RASR_SRD_Pos) |
 ((uint32_t)MPU_Init->Size << MPU_RASR_SIZE_Pos) |
 ((uint32_t)MPU_Init->Enable << MPU_RASR_ENABLE_Pos);
 }
 else
 {
 MPU->RBAR = 0x00;
 MPU->RASR = 0x00;
 }
}

函数参数
此函数的形参是一个 MPU_Region_InitTypeDef 类型的结构体变量,定义如下:

typedef struct
{
 uint8_t Enable; 
 uint8_t Number; 
 uint32_t BaseAddress; 
 uint8_t Size; 
 uint8_t SubRegionDisable; 
 uint8_t TypeExtField; 
 uint8_t AccessPermission; 
 uint8_t DisableExec; 
 uint8_t IsShareable; 
 uint8_t IsCacheable; 
 uint8_t IsBufferable; 
}MPU_Region_InitTypeDef;

STM32H7 的 Cache

当前芯片厂商出的 M7 内核芯片基本都做了一级 Cache 支持,Cache 又分数据缓存 D-Cache 和指令
缓冲 I-Cache,STM32H7 的数据缓存和指令缓存大小都是 16KB。对于指令缓冲,用户不用管,这里主
要说的是数据缓存 D-Cache。以 STM32H7 为例,主频是 400MHz,除了 TCM 和 Cache 以 400MHz
工作,其它 AXI SRAM,SRAM1,SRAM2 等都是以 200MHz 工作。数据缓存 D-Cache 就是解决 CPU
加速访问 SRAM。
STM32 H7系列学习笔记,STM32,stm32,笔记,嵌入式硬件

如果每次 CPU 要读写 SRAM 区的数据,都能够在 Cache 里面进行,自然是最好的,实现了 200MHz
到 400MHz 的飞跃,实际是做不到的,因为数据 Cache 只有 16KB 大小,总有用完的时候。
对于使能了 Cache 的 SRAM 区,要分读写两种情况考虑。

读操作:

如果 CPU 要读取的 SRAM 区数据在 Cache 中已经加载好,这就叫读命中(Cache hit),如果 Cache
里面没有怎么办,这就是所谓的读 Cache Miss。

写操作:

如果 CPU 要写的 SRAM 区数据在 Cache 中已经开辟了对应的区域(专业词汇叫 Cache Line,以 32
字节为单位),这就叫写命中(Cache hit),如果 Cache 里面没有开辟对应的区域怎么办,这就是所谓的写 Cache Miss。

总结:

  1. Cortex-M7 内核的 L1 Cache 由多行内存区组成,每行有 32 字节,每行都配有一个地址标签。数据
    缓冲 DCache 是每 4 行为一组,称为 4-way set associative。而指令缓冲区 ICache 是 2 行为一组,
    这样节省地址标签,不用每个行都标记一个地址。
  2. 对于读操作,只有在第 1 次访问指定地址时才会加载到 Cache,而写操作的话,可以直接写到内存中
    (write-through 模式)或者放到 Cache 里面,后面再写入(write-back 模式)。
  3. 如果采用的是 Write back,Cache line 会被标为 dirty,等到此行被 evicted 时,才会执行实际的写
    操作,将 Cache Line 里面的数据写入到相应的存储区。
  4. Cache 命中是访问的地址落在了给定的 Cache Line 里面,所以硬件需要做少量的地址比较工作,以
    检查此地址是否被缓存。如果命中了,将用于缓存读操作或者写操作。如果没有命中,则分配和标记
    新行,填充新的读写操作。如果所有行都分配完毕了,Cache 控制器将支持 eviction 操作。根据 Cache
    Line 替换算法,一行将被清除 Clean,无效化 Invalid 或者重新配置。数据缓存和指令缓存是采用的
    伪随机替换算法。
  5. Cache 支持的 4 种基本操作,使能,禁止,清空和无效化。Clean 清空操作是将 Cache Line 中标记
    为 dirty 的数据写入到内存里面,而无效化 Invalid 是将 Cache Line 标记为无效,即删除操作。

面对繁冗复杂的 Cache 配置,推荐方式和安全隐患解决办法

◆ 推荐使用 128KB 的 TCM 作为主 RAM 区,其它的专门用于大缓冲和 DMA 操作等。
◆ Cache 问题主要是 CPU 和 DMA 都操作这个缓冲区时容易出现,使用时要注意。
◆ Cache 配置的选择,优先考虑的是 WB,然后是 WT 和关闭 Cache,其中 WB 和 WT 的使用中可以
配合 ARM 提供的函数解决上面说到的隐患问题(见本章 24.6 小节)。但不是万能的,在不起作用的
时候,直接暴力选择函数 SCB_CleanInvlaidateDCache 解决。关于这个问题,在分别配置以太网
MAC 的描述符缓冲区,发送缓冲区和接收缓冲区时尤其突出。

Cache 的相关函数

CMSIS 软件包的 core_cm7.h 文件为 Cache 的配置提供了 11 个函数:
◆ SCB_EnableICache
◆ SCB_DisableICache
◆ SCB_InvalidateICache
◆ SCB_EnableDCache
◆ SCB_DisableDCache
◆ SCB_InvalidateDCache
◆ SCB_CleanDCache
◆ SCB_CleanInvalidateDCache
◆ SCB_InvalidateDCache_by_Addr
◆ SCB_CleanDCache_by_Addr
◆ SCB_CleanInvalidateDCache_by_Addr
其中前三个函数是指令 Cache,比较容易掌握。重点是后面几个数据 Cache 函数。由于函数 SCB_CleanInvalidateDCache,SCB_CleanDCache 和 SCB_InvalidateDCache是对整个 Cache 的操作,所以比最后的三个函数 SCB_InvalidateDCache_by_Addr,SCB_CleanDCache_by_Addr 和 SCB_CleanInvalidateDCache_by_Addr 要耗时,当然,如果用户操作的存储器超过了数据 Cache 的大小,即 16KB,那么就跟前三个函数没有区别了。

STM32H7 的 TCM,SRAM 等五块内存基础知识

◆ TCM : Tightly-Coupled Memory 紧密耦合内存 。ITCM 用于指令,DTCM 用于数据,特点是跟内
核速度一样,而片上 RAM 的速度基本都达不到这个速度。
STM32 H7系列学习笔记,STM32,stm32,笔记,嵌入式硬件
◆ ITCM 和 DTCM
这两个是直连 CPU 的。
◆ D1 Domain
D1 域中的各个外设是挂在 64 位 AXI 总线组成 67 的矩阵上。
⚫ 6 个从接口端 ASIB1 到 ASIB6
外接的主控是 LTDC,DMA2D,MDMA,SDMMC1,AXIM 和 D2-to-D1 AHB 总线。
⚫ 7 个主接口端 AMIB1 到 AMIB7
外接的从设备是 AHB3 总线,Flash A,Flash B,FMC 总线,QSPI 和 AXI SRAM。另外 AHB3
也是由 AXI 总线分支出来的,然后再由 AHB3 分支出 APB3 总线。
◆ D2 Domain
D2 域的各个外设是挂在 32 位 AHB 总线组成 10
9 的矩阵上。
⚫ 10 个从接口
外接的主控是 D1-to-D2 AHB 总线,AHBP 总线,DMA1,DMA2,Ethernet MAC,SDMMC2,
USB HS1 和 USB HS2。
⚫ 9 个主接口
外接的从设备是 SRAM1,SRMA2,SRAM3,AHB1,AHB2,APB1,APB2,D2-to-D1 AHB
总线和 D2-to-D3 AHB 总线。
◆ D3 Domain
D3 域的各个外设是挂在 32 位 AHB 总线组成 3*2 的矩阵上。
⚫ 3 个从接口
外接的主控 D1-to-D3 AHB 总线,D2-to-D3 AHB 总线和 BDMA。
⚫ 2 个主接口
外接的从设备是 AHB4,SRAM4 和 Bckp SRAM。另外 AHB4 也是这个总线矩阵分支出来的,
然后再由 AHB4 分支出 APB4 总线

各块 RAM 特性

TCM 区

TCM : Tightly-Coupled Memory 紧密耦合内存 。ITCM 用于运行指令,也就是程序代码,DTCM
用于数据存取,特点是跟内核速度一样,而片上 RAM 的速度基本都达不到这个速度,所以有降频处
理。
速度:400MHz。
DTCM 地址:0x2000 0000,大小 128KB。
ITCM 地址:0x0000 0000,大小 64KB。

AXI SRAM 区

位于 D1 域,数据带宽是 64bit,挂在 AXI 总线上。除了 D3 域中的 BDMB 主控不能访问,其它都可
以访问此 RAM 区。
速度:200MHz。
地址:0x2400 0000,大小 512KB。
用途:用途不限,可以用于用户应用数据存储或者 LCD 显存。

SRAM1,SRAM2 和 SRAM3 区

位于 D2 域,数据带宽是 32bit,挂在AHB 总线上。除了 D3域中的 BDMB主控不能访问这三块SRAM,
其它都可以访问这几个 RAM 区。
速度:200MHz。
SRAM1:地址 0x3000 0000,大小 128KB,用途不限,可用于 D2 域中的 DMA 缓冲,也可以当
D1 域断电后用于运行程序代码。
SRAM2:地址 0x3002 0000,大小 128KB,用途不限,可用于 D2 域中的 DMA 缓冲,也可以用于
用户数据存取。
SRAM3:地址 0x3004 0000,大小 32KB,用途不限,主要用于以太网和 USB 的缓冲。

SRAM4 区

位于 D3 域,数据带宽是 32bit,挂在 AHB 总线上,大部分主控都能访这块 SRAM 区。
速度:200MHz。
地址:0x3800 0000,大小 64KB。
用途:用途不限,可以用于 D3 域中的 DMA 缓冲,也可以当 D1 和 D2 域进入 DStandby 待机方式
后,继续保存用户数据。

Backup SRAM 区

备份 RAM 区,位于 D3 域,数据带宽是 32bit,挂在 AHB 总线上,大部分主控都能访问这块 SRAM
区。
速度:200MHz。
地址:0x3880 0000,大小 4KB。
用途:用途不限,主要用于系统进入低功耗模式后,继续保存数据(Vbat 引脚外接电池)。

串口的 HAL 库用法

串口的 HAL 库用法其实就是几个结构体变量成员的配置和使用,然后配置 GPIO、时钟,并根据需要
配置 NVIC、中断和 DMA。
HAL 库在 USART_TypeDef 的基础上封装了一个结构体 UART_HandleTypeDef,定义如下:

typedef struct
{
 USART_TypeDef *Instance; /*!< UART registers base address */
 UART_InitTypeDef Init; /*!< UART communication parameters */
 UART_AdvFeatureInitTypeDef AdvancedInit; /*!< UART Advanced Features initialization parameters */
 uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
 uint16_t TxXferSize; /*!< UART Tx Transfer size */
 __IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
 uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
 uint16_t RxXferSize; /*!< UART Rx Transfer size */
 __IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
 uint16_t Mask; /*!< UART Rx RDR register mask */
 DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
 DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
 HAL_LockTypeDef Lock; /*!< Locking object */
 __IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
 and also related to Tx operations.
 This parameter can be a value of @ref HAL_UART_StateTypeDef */
 __IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations.
 This parameter can be a value of @ref HAL_UART_StateTypeDef */
 __IO uint32_t ErrorCode; /*!< UART Error code */
}UART_HandleTypeDef;

UART_InitTypeDef 结构体的定义如下:

typedef struct
{
 uint32_t BaudRate; /* 波特率 */
 uint32_t WordLength; /* 数据位长度 */
 uint32_t StopBits; /* 停止位 */ 
 uint32_t Parity; /* 奇偶校验位 */ 
 uint32_t Mode; /* 发送模式和接收模式使能 */ 
 uint32_t HwFlowCtl; /* 硬件流控制 */ 
 uint32_t OverSampling; /* 过采样,可以选择 8 倍和 16 倍过采样 */ 
 uint32_t Prescaler; /* 串口分频 */ 
 uint32_t FIFOMode; /* 串口 FIFO 使能 */ 
 uint32_t TXFIFOThreshold; /* 发送 FIFO 的阀值 */ 
 uint32_t RXFIFOThreshold; /* 接收 FIFO 的阀值 */ 
}UART_InitTypeDef;

UART_AdvFeatureInitTypeDef AdvancedInit(这个参数用于配置串口的高级特性)具体支持的功能参数如下:

typedef struct
{
 uint32_t AdvFeatureInit; /* 初始化的高级特性类别 */
 uint32_t TxPinLevelInvert; /* Tx 引脚电平翻转 */
 uint32_t RxPinLevelInvert; /* Rx 引脚电平翻转 */
 uint32_t DataInvert; /* 数据逻辑电平翻转 */
 uint32_t Swap; /* Tx 和 Rx 引脚交换 */
 uint32_t OverrunDisable; /* 接收超时检测禁止 */
 uint32_t DMADisableonRxError; /* 接收出错,禁止 DMA */
 uint32_t AutoBaudRateEnable; /* 自适应波特率使能 */
 uint32_t AutoBaudRateMode; /* 自适应波特率的四种检测模式选择 */
 uint32_t MSBFirst; /* 发送或者接收数据时,高位在前 */
} UART_AdvFeatureInitTypeDef;

示例

配置串口参数,其实就是配置结构体 UART_HandleTypeDef 的成员。比如下面配置为波特率 115200,8个数据位,无奇偶校验,1 个停止位。

UART_HandleTypeDef UartHandle;
/* USART3 工作在 UART 模式 */
/* 配置如下:
 - 数据位 = 8 Bits
 - 停止位 = 1 bit
 - 奇偶校验位 = 无
 - 波特率 = 115200bsp
 - 硬件流控制 (RTS 和 CTS 信号) */
UartHandle.Instance = USART3;
UartHandle.Init.BaudRate = 115200;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if(HAL_UART_Init(&UartHandle) != HAL_OK)
{
Error_Handler();
}

串口外设的基本参数配置完毕后还不能使用,还需要配置 GPIO、时钟、中断等参数,比如下面配置
串口 1,使用引脚 PA9 和 PA10。

/* 串口 1 的 GPIO PA9, PA10 */
#define USART1_CLK_ENABLE()			 __HAL_RCC_USART1_CLK_ENABLE()
#define USART1_TX_GPIO_CLK_ENABLE()	 __HAL_RCC_GPIOA_CLK_ENABLE()
#define USART1_TX_GPIO_PORT 	GPIOA
#define USART1_TX_PIN 			GPIO_PIN_9
#define USART1_TX_AF 			GPIO_AF7_USART1
/*
*********************************************************************************************************
* 函 数 名: InitHardUart
* 功能说明: 配置串口的硬件参数和底层
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void InitHardUart(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
#if UART1_FIFO_EN == 1 /* 串口 1 */
/* 使能 GPIO TX/RX 时钟 */
USART1_TX_GPIO_CLK_ENABLE();
USART1_RX_GPIO_CLK_ENABLE();
/* 使能 USARTx 时钟 */
USART1_CLK_ENABLE();
/* 配置 TX 引脚 */
GPIO_InitStruct.Pin = USART1_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = USART1_TX_AF;
HAL_GPIO_Init(USART1_TX_GPIO_PORT, &GPIO_InitStruct);
/* 配置 RX 引脚 */
GPIO_InitStruct.Pin = USART1_RX_PIN;
GPIO_InitStruct.Alternate = USART1_RX_AF;
HAL_GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStruct);
/* 配置 NVIC the NVIC for UART */ 
HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART1_IRQn);
 
/* 配置波特率、奇偶校验 */
bsp_SetUartParam(USART1, UART1_BAUD, UART_PARITY_NONE, UART_MODE_TX_RX);
SET_BIT(USART1->ICR, USART_ICR_TCCF); /* 清除 TC 发送完成标志 */
SET_BIT(USART1->RQR, USART_RQR_RXFRQ); /* 清除 RXNE 接收标志 */
SET_BIT(USART1->CR1, USART_CR1_RXNEIE);/* 使能 PE. RX 接受中断 */
#endif
}

串口的状态标志清除问题

__HAL_USART_GET_FLAG 函数。这个函数用来检查 USART 标志位是否被设置。

/** @brief Check whether the specified USART flag is set or not.
 * @param __HANDLE__: specifies the USART Handle
 * @param __FLAG__: specifies the flag to check.
 * This parameter can be one of the following values:
 * @arg USART_FLAG_TXFT: TXFIFO threshold flag
 * @arg USART_FLAG_RXFT: RXFIFO threshold flag
 * @arg USART_FLAG_RXFF: RXFIFO Full flag
 * @arg USART_FLAG_TXFE: TXFIFO Empty flag
 * @arg USART_FLAG_REACK: Receive enable ackowledge flag
* @arg USART_FLAG_TEACK: Transmit enable ackowledge flag
 * @arg USART_FLAG_BUSY: Busy flag
 * @arg USART_FLAG_TXE: Transmit data register empty flag
 * @arg USART_FLAG_TC: Transmission Complete flag
 * @arg USART_FLAG_RXNE: Receive data register not empty flag
 * @arg USART_FLAG_IDLE: Idle Line detection flag
 * @arg USART_FLAG_ORE: OverRun Error flag
 * @arg USART_FLAG_UDR: UnderRun Error flag
 * @arg USART_FLAG_NE: Noise Error flag
 * @arg USART_FLAG_FE: Framing Error flag
 * @arg USART_FLAG_PE: Parity Error flag
 * @retval The new state of __FLAG__ (TRUE or FALSE).
 */
#define __HAL_USART_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->ISR & (__FLAG__)) == (__FLAG__))

USART 标志是需要软件主动清零的。清零有两种方式:一种是调用__HAL_USART_CLEAR_FLAG 函数,另一种是操作相关寄存器后自动清零。

/** @brief Clear the specified USART pending flag.
 * @param __HANDLE__: specifies the USART Handle.
 * @param __FLAG__: specifies the flag to check.
 * This parameter can be any combination of the following values:
 * @arg USART_FLAG_TXFT: TXFIFO threshold flag
 * @arg USART_FLAG_RXFT: RXFIFO threshold flag
 * @arg USART_FLAG_RXFF: RXFIFO Full flag
 * @arg USART_FLAG_TXFE: TXFIFO Empty flag
 * @arg USART_FLAG_REACK: Receive enable ackowledge flag
 * @arg USART_FLAG_TEACK: Transmit enable ackowledge flag
 * @arg USART_FLAG_WUF: Wake up from stop mode flag
 * @arg USART_FLAG_RWU: Receiver wake up flag (is the USART in mute mode)
 * @arg USART_FLAG_SBKF: Send Break flag
 * @arg USART_FLAG_CMF: Character match flag
 * @arg USART_FLAG_BUSY: Busy flag
 * @arg USART_FLAG_ABRF: Auto Baud rate detection flag
 * @arg USART_FLAG_ABRE: Auto Baud rate detection error flag
 * @arg USART_FLAG_RTOF: Receiver timeout flag
 * @arg USART_FLAG_LBD: LIN Break detection flag
 * @arg USART_FLAG_TXE: Transmit data register empty flag
 * @arg USART_FLAG_TC: Transmission Complete flag
 * * @arg USART_FLAG_RXNE: Receive data register not empty flag
 * @arg USART_FLAG_IDLE: Idle Line detection flag
 * @arg USART_FLAG_ORE: OverRun Error flag
 * @arg USART_FLAG_NE: Noise Error flag
 * @arg USART_FLAG_FE: Framing Error flag
 * @arg USART_FLAG_PE: Parity Error flag
 * @retval The new state of __FLAG__ (TRUE or FALSE).
 */
#define __HAL_USART_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->ICR = (__FLAG__))

RS485 的基础知识

关于 RS485 的逻辑状态,不同厂家的芯片的定义可能不同,但不影响正常的数据收发,这里以 TI 的
为例做个说明,TI 的定义方式如下:
A 表示非反向输出 non-inverting output,B 表示反向输出 inverting output。
当 VA > VB 的时候表示逻辑状态 0,被称为 ON。
当 VA < VB 的时候表示逻辑状态 1,被称为 OFF。
STM32 H7系列学习笔记,STM32,stm32,笔记,嵌入式硬件
对应到实际芯片框图上就是下面这样(DE 发送使能,D 是发送数据端,RE 是接收使能,R 是接收数据端)
STM32 H7系列学习笔记,STM32,stm32,笔记,嵌入式硬件
当用户在 D(Driver)引脚输入逻辑高电平时,将在 485 总线上实现逻辑状态 0,即 ON 状态。接收端 R
(Receiver)将收到逻辑高电平。
当用户在 D(Driver)引脚输入逻辑低电平时,将在 485 总线上实现逻辑状态 1,即 OFF 状态。接收端 R
(Receiver)将收到逻辑低电平。

FMC 基础知识

FMC 的几个关键知识点放在开头说:
◆ STM32H7 的 FMC 总线是挂载 64 位带宽的 AXI 总线上,F1,F4 和 F7 是挂在 32 位总线上。
◆ 使用 FMC,可以用来外挂 NOR/PSRAM 型存储器,SRAM 型存储器,NAND 型存储器,SDRAM
存储器等,从而可以用来驱动 AD7606,OLED,DM9000 等并行控制设备。
◆ 支持 8 位,16 位和 32 位总线带宽控制。
◆ 每个片选下的存储器空间配置都是独立的,有专门的寄存器,互不影响。

FMC 时钟选择

STM32 H7系列学习笔记,STM32,stm32,笔记,嵌入式硬件

FMC地址区域

FMC 总线可操作的地址范围 0x60000000 到 0xDFFFFFFF。
STM32 H7系列学习笔记,STM32,stm32,笔记,嵌入式硬件
与 F1 和 F4 不同,H7 系列的 FMC 总线接口支持重映射,也就是可以设置这几块存储器的位置。
STM32 H7系列学习笔记,STM32,stm32,笔记,嵌入式硬件
◆ 对于 NOR/PSRAM/SRAM 块区。
这个块区用到的地方最多,像 NAND 和 SDRAM 块区基本只能接 NAND 和 SDRAM,而
NOR/PSRAM/SRAM 区就不同了,除了能接这几种类型的存储器,还可以外接 DM9000,SDRAM,OLED,AD7606 等总线外设。这个块区有 4 路片选,分别是 FMC_NE1,FMC_NE2,FMC_NE3 和 FMC_NE4,这几个片选在芯片上都有对应的引脚,每个片选可以管理 64MB 的访问空间,这个是由 FMC 引出的 26路地址线 FMC_A[0:25]决定的,2^26 = 64MB。
⚫ FMC_NE1:首地址 0x6000 0000,可以管理的地址范围 0x6000 0000 到 0x63FF FFFF。
⚫ FMC_NE2:首地址 0x6400 0000,可以管理的地址范围 0x6400 0000 到 0x67FF FFFF。
⚫ FMC_NE3:首地址 0x6800 0000,可以管理的地址范围 0x6800 0000 到 0x6BFF FFFF。
⚫ FMC_NE4:首地址 0x6C00 0000,可以管理的地址范围 0x6C00 0000 到 0x6FFF FFFF。

NOR/PSRAM/SRAM 时序控制

F103 和 F407 仅支持 16 位总线访问,等到 F429,H7 已经支持 32 位总线访问。以驱动 SRAM 为例,
需要用到下面的数据,地址和控制引脚。配置完毕后,就可以像使用内部 SRAM 一样进行读写了,使用
比较方便。
STM32 H7系列学习笔记,STM32,stm32,笔记,嵌入式硬件

NOR/PSARM/SRAM 时序配置结构体

FMC_NORSRAM_TimingTypeDef文章来源地址https://www.toymoban.com/news/detail-847697.html

typedef struct
{
 uint32_t AddressSetupTime; //此参数用于设置地址建立时间,单位 FMC 时钟周期个数,范围 0 -15。同步 NOR Flash 用不到此参
数。
 uint32_t AddressHoldTime; //此参数用于设置地址持续时间,单位 FMC 时钟周期个数,范围 1 -15。同步 NOR Flash 用不到此参
数。
 uint32_t DataSetupTime; //此参数用于设置数据建立时间,单位 FMC 时钟周期个数,范围 1 -255。用于 SRAM,异步多路复用
 uint32_t BusTurnAroundDuration; //此参数用于设置总线 TurnAround(总线周转阶段)持续时间,单位 FMC 时钟周期个数,范围 0 -15。仅用于多路复用 NOR Flash。
 uint32_t CLKDivision; //此参数用于设置时钟分频,范围 2 -16,仅用于同步器件。
 uint32_t DataLatency; //对于使能了读/写突发模式的同步访问,此参数定义了读写首个数据前要发送给存储器的时钟周期个数。
 	//操作 CRAM,此参数必须为 0。
	//异步 NOR/PSRAM/SRAM 器件用不到此参数。
	//使能了同步突发模式的 NOR Flash,此参数的范围是 2 – 17,单位 FMC 时钟周期个数。 
 uint32_t AccessMode; //用于设置 FMC 的访问模式
}FMC_NORSRAM_TimingTypeDef;

到了这里,关于STM32 H7系列学习笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 嵌入式学习笔记——STM32的USART相关寄存器介绍及其配置

    上一篇中,对串口做了个概述,主要是介绍了串口通信的特征,异步串行全双工通信,然后就是结合串口的框图梳理了一下STM32中USART的配置流程以及发送接收数据的流程,本文将接着上篇的内容,对串口的寄存器做个介绍,然后实现一个简单的收发实验。 根据之前GPIO的经验

    2024年02月05日
    浏览(54)
  • 蓝桥杯嵌入式CT117E-M4学习笔记02-STM32G431RBT6芯片学习

    首先学习了解一下蓝桥杯嵌入式CT117E-M4开发板的主控芯片STM32G431RBT6,本文仅为个人学习成果总结,如有错误,恳请指正。 上图为STM32CubeMX选型界面,如图可以看出STM32G431RBT6具有以下特点和硬件集成。 采用Cortex-M4 32位RISC核心架构,工作频率最高可达170Mhz。 128kBytes的FLASH,32

    2023年04月09日
    浏览(59)
  • STM32 H7系列学习笔记

    第 1 步:系统上电复位,进入启动文件 startup_stm32h743xx.s,在这个文件里面执行复位中断服务程序。 在复位中断服务程序里面执行函数 SystemInit,在system_stm32h7xx.c 里面。* 之后是调用编译器封装好的函数,比如用于 MDK 的启动文件是调__main,最终进入到 main函数* 第 2 步:进入到

    2024年04月11日
    浏览(37)
  • STM32串口通信详解(嵌入式学习)

    时钟信号在电子领域中是指用于同步和定时电路操作的周期性信号。它在数字系统和通信系统中起着至关重要的作用,用于协调各个组件之间的数据传输和操作。 时钟信号有以下几个重要的方面: 频率:时钟信号的频率是指单位时间内信号周期的数量。它通常以赫兹(Hz)为

    2024年02月09日
    浏览(67)
  • STM32的时钟系统(嵌入式学习)

    时钟是指用于计量和同步时间的装置或系统。时钟是嵌入式系统的脉搏,处理器内核在时钟驱动下完成指令执行,状态变换等动作,外设部件在时钟的驱动下完成各种工作,例如:串口数据的发送、AD转换、定时器计数等。因此时钟对于计算机系统是至关重要的,通常时钟系

    2024年02月16日
    浏览(47)
  • STM32的中断系统详解(嵌入式学习)

    中断是处理器中的一种机制,用于响应和处理突发事件或紧急事件。当发生中断时,当前正在执行的程序会被暂时中止,处理器会跳转到中断处理程序(也称为中断服务例程),对中断事件进行处理。处理完中断后,处理器再返回到被中断的程序继续执行。 中断可以分为内部

    2024年02月12日
    浏览(69)
  • 嵌入式开发--STM32G4系列片上FLASH的读写

    这个玩意吧,说起来很简单,就是几行代码的事,但楞是折腾了我大半天时间才搞定。原因后面说,先看代码吧: 读操作很简单,以32位方式读取的时候是这样的: 需要注意的是,当以32位方式读取时,地址需要是4的整数倍,即32位。 8位或16位方式类似操作即可 需要注意的

    2024年01月18日
    浏览(68)
  • STM32开发环境搭建&工程创建(嵌入式学习)

    简介 STM32CubeMX是STMicroelectronics公司提供的一款集成开发环境(IDE)工具,用于快速配置和初始化STM32微控制器系列的软件工程。它提供了图形化界面和交互式工具,使开发者能够轻松地生成STM32微控制器的初始化代码和配置文件。 STM32CubeMX具有以下主要功能和特点: 微控制器

    2024年02月11日
    浏览(66)
  • 嵌入式学习stm32基础知识(期末复习)

    1. 计算机的体系架构 冯诺依曼架构 ​ 在完整的计算机系统中,包含五个部分,储存器,运算器,控制器输入设备和输出设备。 改进的冯诺依曼架构 改进型架构的各模块的高速数据交换中心利用储存器这个大容量,极大的提高了效率。 哈佛架构 ​ 哈佛结构数据空间和地址

    2024年02月07日
    浏览(65)
  • STM32的定时器详解(嵌入式学习)

    想要了解STM32的时钟系统 点击这里跳转——》STM32的时钟系统(嵌入式学习) 建议先看看时钟树如何配置 点击这里跳转——》STM32的时钟树配置(嵌入式学习) 跳转——》STM32的时钟基础详解(嵌入式学习) 跳跳转——》STM32的时钟源详解(嵌入式学习) SysTick又称滴答定时

    2024年02月13日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包