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 managementand 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;

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[CSS]样式属性+元素设置

哎呀&#xff0c;好多东西&#xff0c;根本记不住&#xff0c;更多的还是边用边记吧&#xff0c;这里的代码就当使用范例&#xff0c;但其实如果可以让gpt应该会更好&#xff0c;哎学吧&#xff0c;反正记得住当然更好 文本 属性名描述word-break单词换行。取值如下&#xff1…

Java System类和Runtime类

System常见API exit:退出程序currentTimeMillis &#xff1a;获取当前的毫秒数&#xff08;1970年是c语言诞生的那一年&#xff09; 代码 System.out.println("Hello, World!"); // System.exit(0); // 退出程序 尽量别使用long currentTimeMillis System.currentTi…

计算机进制

进制 进制也就是进位制&#xff0c;是人们规定的一种进位方法对于任何一种进制—X进制&#xff0c;就表示某一位置上的数运算时是逢X进一位 十进制是逢十进一&#xff0c;十六进制是逢十六进一&#xff0c;二进制就是逢二进一&#xff0c;以此类推&#xff0c;x进制就是逢x进…

管理用户(删除指定用户)shell脚本实现

系统中删除一个用户&#xff0c;要慎之又慎。编写一个shell脚本交互式实现用户删除。代码逻辑&#xff1a; 1、获取正确用户名 2、创建函数获取正确的用户名 3、验证获取的用户名 4、确认获取的用户是否存在 5、删除属于用户的进程 6、查找属于用户的文件并输出文件报告便于后续…

600MA线性锂电池充电芯片 - YB4054DJ

描述: YB4054一款完整的单节锂离子电池充电器。其SOT23-5的封装与较少的外部元件数使得YB4054成为便携式应用的理想选择。采用了内部PMOSFET架构&#xff0c;加上防倒充电路&#xff0c;不需要外部检测电阻器和隔离二极管。热反馈可对充电电流进行自动调节&#xff0c;以便在大…

Commitizen:规范化你的 Git 提交信息

简介 在团队协作开发过程中&#xff0c;规范化的 Git 提交信息可以提高代码维护的效率&#xff0c;便于追踪和定位问题。Commitizen 是一个帮助我们规范化 Git 提交信息的工具&#xff0c;它提供了一种交互式的方式来生成符合约定格式的提交信息。 原理 Commitizen 的核心原…

面试(02)————Java基础和集合

一、Java基础知识 1、面向对象的特征 2、Java 的基本数据类型有哪些 3、JDK JRE JVM 的区别 4、重载和重写的区别 5、Java中和equals的区别 6 、String、StringBuffer、StringBuilder三者之间的区别 7、接口和抽象类的区别是什么&#xff1f; 8、反射 9、jdk1.8 的新特…

AI大模型日报#0409:Llama 3下周发布、特斯联20亿融资、Karpathy新项目

导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。标题: 120亿Stable LM 2上线即开源&#xff01;2万亿token训练&#xff0c;碾压Llama 2 70B 摘要: Stable LM 2 12B参数版本发布&#x…

vue项目中使用html2canvas 下载当前页面(动态页面宽度、高度)

老规矩先上效果图: 需求1、 只要上图红色区域的内容下载&#xff0c;就需要计算红色区域的内容的动态宽度、高度。 需求2、当前页面可视区域的内容下载&#xff0c;上传按钮下面的所有内容。 一、 安装依赖 &#xff1a;安装html2canvas插件 npm isntall html2canvas 或者…

Docker容器嵌入式开发:在Ubuntu上配置Postman和flatpak

在 Ubuntu 上配置 Postman 可以通过 Snap 命令完成&#xff0c;以下是所有命令的总结&#xff1a; sudo snap install postmansudo snap install flatpak在 Ubuntu 上配置 Postman 和 Flatpak 非常简单。以下是一些简单的步骤&#xff1a; 配置 Flatpak 安装 Flatpak&#x…

OpenHarmony实战开发-如何实现一个小鸟避障游戏。

介绍 本示例用于验证OpenHarmony提供的Stage模型&#xff0c;Canvas组件做小游戏的能效是否符合预期&#xff0c;以及验证资源调度子系统的API接口是否符合后台规范运行的预期。 效果预览 使用说明 1.点击ConnectService按钮&#xff0c;创建一个ServiceAbility并连接。 2.…

数据的属性与相似性

目录 一、数据集的结构&#xff08;一&#xff09;二维表&#xff08;二&#xff09;数据矩阵 二、属性的类型&#xff08;一&#xff09;连续属性&#xff08;二&#xff09;离散属性&#xff08;三&#xff09;分类属性&#xff08;四&#xff09;二元属性&#xff08;五&…

【图论】图的存储--链式前向星存图法以及深度优先遍历图

图的存储 介绍 无向图-就是一种特殊的有向图-> 只用考虑有向图的存储即可 有向图 邻接矩阵邻接表 邻接表 存储结构: (为每一个点开了一个单链表,存储这个点可以到达哪个点) 1:3->4->null2:1->4->null3:4->null4:null 插入一条新的边 比如要插一条边&am…

Go语言不能常量取址!?

题如下图 在软件开发中&#xff0c;常量是一种重要的编程元素&#xff0c;它们在程序中起到固定值的作用被大量使用 Go语言中的常量取址 在 Go 语言中&#xff0c;常量是无法被取址的。这意味着我们不能使用取址操作符 & 来获取常量的地址。例如&#xff1a; const a …

vue3移动端H5 瀑布流显示列表

以上效果 是之前发送的改进版 waterList <template><view class"pro-cons" v-if"data.length"><view class"cons-left"><template v-for"(item, index) in data"><template v-if"(index 1) % 2 1…

scala代码中报Cannot resolve symbol %

1、问题复现 2、解决 &#xff08;1&#xff09; &#xff08;2&#xff09; &#xff08;3&#xff09;检查返回类型&#xff0c;应该是Int 我之前用的&#xff08;.var&#xff09;自动生成返回值&#xff0c;他生成的类型是[Range.Inclusive]&#xff0c;这个类型是scala …

Spring-IoC 基于xml管理

现大多使用注解方式&#xff0c;xml方式并不简洁&#xff0c;本文仅记录xml用作基础学习。 0、前提 首先在父项目的pom.xml中配置好依赖们。然后子模块也可以使用这些依赖。 在resource目录下创建Spring的xml文件&#xff0c;名称无要求&#xff0c;本文使用bean.xml。文件最…

vmware 一打开虚拟机就蓝屏重启

按照正常步骤安装完镜像后&#xff0c;点击 开启此虚拟机 &#xff0c;直接出现下图所示蓝屏&#xff0c;然后重启。 解决的办法是通过修改 启用或关闭windows功能 里的选项&#xff0c;如下图&#xff0c;勾选上 Windows虚拟机监控程序平台 和 虚拟机平台 两项。然后重启电脑…

海外仓的出入库流程有什么痛点?位像素海外仓系统怎么提高出入库效率?

随着跨境电商的蓬勃发展&#xff0c;海外仓是其中不可或缺的一个关键环节。而货物的出库与入库则是海外仓管理中的一个核心业务流程&#xff0c;它的运作效率直接影响到整个跨境物流的效率和客户体验。今天&#xff0c;让我们具体来看一看关于海外仓出入库的流程&#xff0c;其…

Transformer详解和知识点总结

目录 1. 注意力机制1.1 注意力评分函数1.2 多头注意力&#xff08;Multi-head self-attention&#xff09; 2. Layer norm3. 模型结构4. Attention在Transformer中三种形式的应用 论文&#xff1a;https://arxiv.org/abs/1706.03762 李沐B站视频&#xff1a;https://www.bilibi…