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。
在这里插入图片描述

如果每次 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 的速度基本都达不到这个速度。
在这里插入图片描述
◆ 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。
在这里插入图片描述
对应到实际芯片框图上就是下面这样(DE 发送使能,D 是发送数据端,RE 是接收使能,R 是接收数据端)
在这里插入图片描述
当用户在 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 时钟选择

在这里插入图片描述

FMC地址区域

FMC 总线可操作的地址范围 0x60000000 到 0xDFFFFFFF。
在这里插入图片描述
与 F1 和 F4 不同,H7 系列的 FMC 总线接口支持重映射,也就是可以设置这几块存储器的位置。
在这里插入图片描述
◆ 对于 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 一样进行读写了,使用
比较方便。
在这里插入图片描述

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

FMC_NORSRAM_TimingTypeDef

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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/533776.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java基础入门--第十一章--JDBC(Java Database Connection)Java数据库连接

JDBC 11.1 什么是JDBC11.1.1 JDBC概述11.1.2 JDBC驱动程序 11.2 JDBC的常用API11.3 JDBC编程11.3.1 JDBC 编程步骤11.3.2 实现第一个JDBC程序 我的MySQL的root密码: root 11.1 什么是JDBC 11.1.1 JDBC概述 JDBC的全称是Java数据库连接&#xff08;Java Database Connectivit…

为什么用核心板与底板模式开发智能产品?小米SU7坐舱域控制器PCB设计的新选择

随着科技的飞速发展&#xff0c;智能产品市场的竞争日益激烈。如何在最短的时间内&#xff0c;以最低的成本&#xff0c;打造出性能卓越的产品&#xff0c;成为了各大企业面临的重要课题。近日&#xff0c;小米SU7智能汽车的发布为我们提供了一个全新的视角——通过核心板与底板…

算法:多重背包问题dp

文章目录 一、多重背包问题特点1.1、多重背包问题的特征1.2、解决多重背包问题的基本方法典型例题&#xff1a;AcWing——多重背包问题I 1.3、二进制优化1.3.1、二进制优化的思想1.3.2、多重背包问题的二进制优化 一、多重背包问题特点 多重背包问题是背包问题的又一变种&…

钢条切割问题:动态规划算法的典型应用

一、引言 在工业生产和物流管理中&#xff0c;钢条切割问题是一个常见的优化问题。企业在购买长钢条并将其切割为短钢条出售时&#xff0c;往往面临着如何切割以最大化利润的问题。这个问题不仅关系到企业的成本控制和利润最大化&#xff0c;也涉及到资源的有效利用和生产效率…

QA:缺少VC运行时库导致VisualBox和XShell运行出错

前言 启动软件时&#xff0c;特别是绿色版软件&#xff0c;有时会遇到“缺少xxx.dll文件”&#xff0c;导致软件启动失败。 注&#xff1a;xxx.dll是动态链接库&#xff08;DLL&#xff09;文件&#xff0c;包含了程序运行所需的函数和资源。 内容 象上面这种类型的错误&…

漫画|数据工程师面试常见问题之数据倾斜

话说&#xff0c;闹钟一响&#xff0c;现实照进梦想&#xff0c;又是李大虎面试找工作的一天。 李大虎心里一直有个想法&#xff0c;如果一天睡20个小时&#xff0c;然后这20个小时全做美梦&#xff0c;醒来的4个小时用来吃喝拉撒&#xff0c;这样岂不就和那些富二代一样了&am…

AI应用实战2:使用scikit-learn进行回归任务实战

代码仓库在gitlab&#xff0c;本博客对应于02文件夹。 1.问题分析 在此篇博客中我们来对回归任务进行实战演练&#xff0c;背景是直播带货平台的业绩预测。第一步&#xff0c;就是分析问题。 问题痛点&#xff1a; 在直播带货平台上&#xff0c;由于市场环境多变、用户行为复…

【网站项目】校园二手交易平台小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Python爬虫网络实践:去哪儿旅游数据爬取指南

Python爬虫网络实践&#xff1a;去哪儿旅游数据爬取指南 在这个博客中&#xff0c;我们将探索如何使用 Python 来进行网络数据抓取&#xff0c;并以抓取旅游数据为例进行演示。我们将通过一个简单的示例来说明如何利用 Python 中的常用库进行网页抓取&#xff0c;从而获取旅游…

ABAP 增强篇

文章目录 ABAP 增强篇第一代增强-基于源码增强用户出口子程序所能使用的数据变量VA01增强示例 第二代&#xff1a;基于函数出口增强&#xff08;FUNCTION&#xff09;SMOD与COMD查找出口函数出口对象激活&#xff08;SMOD&#xff09;增强详细说明文档示例&#xff1a;通过出口…

vulhub靶场shiro系列漏洞复现CVE-2010-3863、CVE-2016-4437(shiro550)、CVE-2020-1957、shiro721

目录 shiro简介 shiro漏洞成因 shiro550 shiro721 利用过程 CVE-2010-3863&#xff08;未授权访问&#xff09; 简介 CVE-2016-4437(shiro550) 简介 CVE-2020-1957&#xff08;未授权访问&#xff09; 漏洞影响 简介 url处理过程 shiro721 影响版本 简介 利用 …

2024全国现代流通经济创新大会暨城郊大仓基地高质量建设论坛日程发布

2024年4月19日 中国平谷 建设城郊大仓基地 创新现代流通经济 一、大会开幕式&主论坛 时间&#xff1a;9:00-12:00 地点&#xff1a;博物馆一楼 报告厅 主持人&#xff1a;中国商业联合会商贸物流与供应链分会会长干为 08:30-09:00 大会入场&宣传片视频 09:00-0…

iOS 启动速度优化

启动耗时&#xff1a;点击App后到首帧显示耗费的时间。 阶段分析&#xff1a;premain、postmain&#xff0c;也就是main函数执行前和main函数执行后。 耗时检测&#xff1a;Instrument->App Launch Premain 减少动态库数量&#xff1a;启动时程序会加载动态库&#xff0c;…

Acrobat Pro DC 2021---PDF编辑与管理,打造高效PDF工作流程 含Mac+win

Acrobat Pro DC 2021包括全面的PDF编辑、OCR识别、多种输出格式转换以及强大的文件安全性保护。用户可轻松编辑、合并、转换PDF文件&#xff0c;同时支持将扫描文档转换为可编辑的PDF。可将PDF转换为Word、Excel、PowerPoint等格式&#xff0c;提高工作效率。 Mac电脑&#xf…

vue的 blob文件下载文件时,后端自定义异常,并返回json错误提示信息,前端捕获信息并展示给用户

1.后端返回的json数据结构为&#xff1a; {"message":"下载失败&#xff0c;下载文件不存在&#xff0c;请联系管理员处理&#xff01;","code":500} 2.vue 请求后台接口返回的 Blob数据 3.问题出现的原因是&#xff0c;正常其他数据列表接口&…

2024/4/2—力扣—连续数列

代码实现&#xff1a; 思路&#xff1a;最大子数组和 解法一&#xff1a;动态规划 #define max(a, b) ((a) > (b) ? (a) : (b))int maxSubArray(int* nums, int numsSize) {if (numsSize 0) { // 特殊情况return 0;}int dp[numsSize];dp[0] nums[0];int result dp[0];fo…

阿里云云效CI/CD配置

1.NODEJS项目流水线配置(vue举例) nodejs构建配置 官方教程 注意:下图的dist是vue项目打包目录名称,根据实际名称配置 # input your command here cnpm cache clean --force cnpm install cnpm run build 主机部署配置 rm -rf /home/vipcardmall/frontend/ mkdir -p /home/…

海山数据库(He3DB)原理剖析:浅析OLAP数据库计算引擎中的统计信息

背景&#xff1a; 统计信息在计算引擎的优化器模块中经常被提及&#xff0c;尤其是在基于成本成本优化&#xff08;CBO&#xff09;框架中统计信息发挥着至关重要的作用。CBO旨在通过评估执行查询的可能方法&#xff0c;并选择最有效的执行计划来提高查询性能。而统计信息则提…

传统企业如何实现数字化转型?

传统企业实现数字化转型是一个系统性工程&#xff0c;涉及到企业战略、技术应用、组织结构、业务流程、人才培养等多个方面。以下是一些关键步骤和策略&#xff1a; 1、明确转型目标和战略&#xff1a;首先&#xff0c;企业需要明确数字化转型的目标&#xff0c;这通常是为了提…

48-基于腾讯云EKS的容器化部署实战

准备工作 在部署IAM应用之前&#xff0c;我们需要做以下准备工作&#xff1a; 开通腾讯云容器服务镜像仓库。安装并配置Docker。准备一个Kubernetes集群。 开通腾讯云容器服务镜像仓库 在Kubernetes集群中部署IAM应用&#xff0c;需要从镜像仓库下载指定的IAM镜像&#xff…