STM32H733 OCTOSPI 驱动 HyperRAM 全流程:CubeMX 配置 + 内存映射 + 自测试代码

发布时间:2026/7/19 13:43:28

STM32H733 OCTOSPI 驱动 HyperRAM 全流程:CubeMX 配置 + 内存映射 + 自测试代码 前言一、OCTOSPI简介OCTOSPI是一个映射到专用AHB/AXI层的AHB/AXI从设备。HSPI是一个映射到专用AHB层的从设备。XSPI是一个映射到专用层的AXI从设备。这种映射方式使得OCTOSPI、HSPI和XSPI可以通过内存映射模式被访问就像访问内部内存一样。图1STM32H7关于OCTOSPI总线位置1.1 接口描述每个 OCTOSPI 实例均支持单路/双路/四路/八路 SPI 格式在同一总线上对单路/双路/四路/八路 SPI 进行复用可通过集成的 Octo-SPI I/O 管理器OCTOSPIIM实现。Octo-SPI接口主要使用以下线路:OCTOSPINCS线路用于芯片选择OCTOSPICLK线路用于时钟OCTOSPI_NCLK用于支持1.8VHyperBus协议OCTOSPI_DQS线路用于内存的数据同步/写屏蔽信号OCTOSPI_IO[0…7]用于数据线1.2 三种模式无论使用哪种底层协议OCTOSPI/HSPI/XSPI都可以在间接模式和内存映射模式下工作。当使用常规命令协议时OCTOSPI/HSPI/XSPI可以在自动状态轮询模式下工作。OCTOSPI 可在以下三种模式中的任意一种下运行间接模式所有操作均通过 OCTOSPI 寄存器执行间接模式用于以下情况无论HyperBus或常规命令协议• 读/写/擦除操作• 如果AHB或AXI主设备不需要自主访问 OCTOSPI/HSPI/XSPI外设在内存映射模式下可用• 所有通过OCTOSPI/HSPI/XSPI数据寄存器执行的操作使用CPU或DMA• 配置外部存储设备状态轮询模式自动状态轮询模式允许硬件完全管理内存状态寄存器的自动轮询。此功能避免了软件开销也无需执行软件轮询。在匹配时可以生成中断内存映射模式外部存储器被映射为内存系统将其视作支持读写操作的内部存储器。内存映射模式用于以下情况• 读和写操作• 使用外部内存设备就像使用内部内存一样以便任何AHB/AXI主机可以自主访问它• 从外部存储设备执行代码在内存映射模式下系统将外部内存视为内部内存。此模式允许所有AHB/AXI主机像访问内部内存一样访问外部存储设备。CPU也可以从外部内存执行代码。这个也是本文章配置的模式在内存映射模式下• OCTOSPI1可寻址空间从0x90000000到0x9FFFFFFF。• OCTOSPI2可寻址空间从0x70000000到0x7FFFFFFFb。• HSPI可寻址空间从0xA0000000到0xAFFFFFFF。• XSPI1可寻址空间从0x90000000到0x9FFFFFFF• XSPI2可寻址空间从0x70000000到0x7FFFFFFF• XSPI3可寻址空间从0x80000000到0x8FFFFFFFOCTOSPI 支持两种帧格式适用于大多数外部串行存储器例如串行 PSRAM、串行 NAND 和串行 NOR 闪存、Hyper RAM 及 Hyper flash 存储器。多芯片封装MCP可组合上述任一提及的存储器类型同样受支持• 经典帧格式包含命令、地址、交替字节、空闲周期及数据阶段• HyperBus™ 帧格式。二、HyperBUS简介HYPERBUSTM是一种低信号计数DDR接口可实现高速读写吞吐量。HyperBus 使用高速 8 位 DDR 接口来处理地址和数据。此外每个存储器件都有相应的差分时钟、读/写锁存信号和片选。HyperBus 可在同一总线上支持外部闪存和 RAM并且可配合任何具有 HyperBus 兼容外设接口的微控制器使用。HyperBus 可设置成主/从接口其中一个主机可以连接至总线上的一个或多个从存储器件。 HyperBus 闪存器件称为 HyperFlash™HyperBus DRAM 存储器件称为 HyperRAM™。2.1 HyperBUS逻辑框图图2 HyperRAM框图关于引脚描述引脚类型描述CS#主输出从输入芯片选择。总线事务以高电平到低电平跳变启动以低电平到高电平跳变终止。主设备为每个从设备配备独立的片选信号CS#。CK,CK#主输出从输入差分时钟DQ[7:0]输入\输出数据输入\输出接口RWDS输入输出读写数据选通在所有总线事务的命令/地址部分期间RWDS 为从设备输出信号用于指示是否需要额外的初始延迟。在读取数据传输期间从设备输出的数据与 RWDS 边沿对齐在写入数据传输期间从设备输入作为数据掩码使用。HIGH 需要额外延迟LOW 无需额外延迟。RESET#主输出、从输入、内部上拉硬件复位。当 Reset# 为低电平时从设备将自动初始化并返回至待机状态当 Reset# 为低电平时RWDS 和 DQ[7:0] 将被置为高阻态HIGH-Z。从设备的 Reset# 输入端包含弱上拉电阻若 Reset# 未连接则会被上拉至高电平。RWDS是一个双向信号用于指示读取传输中数据开始从HYPERRAMTM器件传输到主件的时间初始读取延迟当数据在读取传输期间从HYPERRAMT?器件传输到主件时作为源同步读取数据选通当数据开始从主件传输到HYPERRAMTM器件进行写入传输时初始写入延迟写入数据传输期间的数据屏蔽在读或写传输的CA传输部分期间RWDS充当HYPERRAMTM设备的输出以指示传输中是否需要额外的初始读取延迟。在读数据传输过程中RWDS是一种读数据选通数据值随RWDS的转换而边沿对齐。每个传输都以CS和指令地址CA信号的置位开始然后开始时钟转换以传输6个CA字节接着是初始读取延迟和读取或写入数据传输直到CS被取消置位。图3读取传输单次初始延迟计数图4 读取传输额外延迟计数图5写入传输单次初始延迟计数2.2 HyperBUS传输详情所有 HYPERRAM™ 总线传输都可以分为读或写。当时钟处于空闲状态CK 低电平且 CK# 高电平时CS# 变为低电平总线传输开始。图6指令-地址CA序列CA0、CA1、CA2定义的信息有读取或写入命令。地址空间存储空间或寄存器空间寄存器空间用于访问器件标识符ID寄存器和配置寄存器CR用于识别器件特性并确定在HYPERBUSTM扩展I/O接口上读取和写入传输的从机特定行为。命令是否使用线性或回卷突发序列。目标行和半页地址上位地址目标列半页内的单词地址低阶地址图7DQ通道和CA地址映射CA位含义CA位位名称位含义47R/W#识别该事务为读操作或写操作。R/W# 1 表示读事务R/W# 0 表示写事务。46Address space(AS)指示读取或写入事务是访问内存空间还是寄存器空间。AS 0 表示内存空间 AS 1 表示寄存器空间寄存器空间用于访问设备 ID 和配置寄存器。45Burst type指示突发数据流是线性还是环形。突发类型 0 表示环形突发突发类型 1 表示线性突发。44-16Row and upper column address目标地址的行与高位列组件系统字地址位 A31–A3。主机控制器主接口应将任何未被特定设备密度使用的高位行地址位设为 0。行数及列地址之间的地址位边界大小取决于从设备。15-3Reserved扩展预留。当前 HYPERBUS™ 设备中预留位无实际作用但为确保未来兼容性应由主机控制器主接口将其设为 0。2-0Lower column address目标地址的低位列组件。系统字地址位 A2–A0 用于选择半页内的起始字。三、使用硬件介绍3.1 HyperRAM硬件本文使用的HyperRAM硬件是 ISSI 的IS67WVH4M8FALL,主要性能HyperBus™ 低信号计数接口IS67WVH4M8FALL的命名含义IS663.0V 电压版本IS671.8V 电压版本4M8容量规格 4M × 8bit 32Mbit 4MB 字节HHyperBus 接口协议FALL / BLL封装、温度等级、驱动强度等细分参数● 1.8 V / 3.0 V 接口支持○ 单端时钟CK— 11 根总线信号○ 可选差分时钟CK, CK#— 12 根总线信号● 芯片选择CS#● 8 位数据总线DQ[7:0]● 读写数据选通RWDS○ 双向数据选通 / 屏蔽○ 所有事务起始处输出用于指示刷新延迟○ 读事务期间输出作为读数据选通● 可配置输出驱动强度● 最高200 MHz时钟频率● 双倍数据速率DDR— 每个时钟周期传输两笔数据● 数据吞吐量最高达 400 MB/s3,200 Mbps○ 可配置突发特性- 包装突发长度• 16 字节8 个时钟周期• 32 字节16 个时钟周期• 64 字节32 个时钟周期• 128 字节64 个时钟周期○ 线性突发○ 混合突发 — 一次包装突发后接线性突发性能摘要最大时钟频率1.8 V VCC/VCCQ200 MHz最大时钟频率3.0 V VCC/VCCQ200 MHz最大访问时间35 ns3.2 主控芯片主控芯片使用的是STM32H733ZGT6相关介绍网上资源较多此处省略…四、STM32CubeMX配置及说明4.1配置图Memory Type选择HyperBus(TM)将 OCTOSPI 切换为 HyperBus 协议帧格式适配 HyperRAM 器件接口复用通过 OCTOSPI I/O 管理器OCTOSPIM将 OCTOSPI1 映射到Port2端口与硬件原理图的 PF/PG 组引脚一一对应信号分配CLK单端时钟输出提供 HyperRAM 工作时钟NCLK差分互补时钟输出HyperBus 协议支持差分时钟提升高速下信号抗干扰能力NCS片选信号低电平有效每次总线事务由 CS 拉低启动DQS (RWDS)数据选通信号对应 HyperBus 的 RWDS 引脚读操作作为数据同步选通写操作作为写屏蔽Data[3:0] / Data[7:4]组成 8 位双向数据总线支持 DDR 双倍数据速率传输#### 通用参数参数配置值说明Fifo Threshold1FIFO 阈值设为 1 字节数据到达即触发传输适配小数据随机访问Dual Quad modeDisable不使用双四路模式HyperBus 为单 8 线通道Device Size22地址位宽 22bit对应2^22 4MB容量匹配 IS67WVH4M8FALL 规格Device TypeRAM外部器件类型为 RAM区别于 Flash 的擦写逻辑Chip Select High Time5片选高电平最小保持 5 个时钟周期保证两次传输间器件复位Free Running ClockDisable仅传输时输出时钟空闲时关闭以降低功耗Clock ModeLow时钟空闲电平为低匹配 HyperBus 协议时钟极性Clock Prescaler2外设时钟 2 分频200MHz 输入时钟下得到100MHz工作时钟Delay Hold Quarter CycleEnable开启 1/4 周期保持优化 DDR 模式下数据建立 / 保持时间Refresh241刷新周期配置适配 HyperRAM 自刷新需求保证数据不丢失输出速度等级VERY_HIGH非常高速CPU I-Cache / CPU D-Cache全部开启。指令缓存与数据缓存可大幅提升外部存储器访问效率内存映射模式下可直接在 HyperRAM 上运行代码、读写数据。Speculation default mode开启优化总线预取与推测访问提升连续访问性能。基地址0x90000000对应 STM32H7 系列 OCTOSPI1 内存映射起始地址区域大小4MB访问权限全权限读写支持指令读取可执行代码内存属性Cacheable可缓存允许 DCache 缓存该区域数据Bufferable可缓冲允许写缓冲合并写入提升写性能Shareable非共享单主控访问无需总线同步TEX Level 1配置为 Normal 内存类型配合缓存策略实现最高访问性能我的时钟配置五、代码生成1. 主函数****************************************************************************** * file : main.c ****************************************************************************** int main() { HyperRAM_EnableMemMapped(); /* 进入内存映射模式 */ HyperRAM_SelfTest(); /* HyperRAM 自测试 */ while (1) { } }2. HyperRAM.c/* * HyperRAM.c */ #include HyperRAM.h #include mlog.h /** * brief 进入 HyperRAM 内存映射模式 * note 调用后 HyperRAM 可通过 OCTOSPI1_BASE (0x90000000) 直接访问 */ void HyperRAM_EnableMemMapped(void) { OSPI_HyperbusCmdTypeDef s_cmd {0}; OSPI_MemoryMappedTypeDef s_mmap {0}; /* 切换到 HyperBus 内存地址空间 */ s_cmd.AddressSpace HAL_OSPI_MEMORY_ADDRESS_SPACE; s_cmd.AddressSize HAL_OSPI_ADDRESS_32_BITS; s_cmd.DQSMode HAL_OSPI_DQS_ENABLE; s_cmd.Address 0; s_cmd.NbData 1; if (HAL_OSPI_HyperbusCmd(hospi1, s_cmd, 1000) ! HAL_OK) { Error_Handler(); } /* 关闭超时计数器提升连续访问性能 */ s_mmap.TimeOutActivation HAL_OSPI_TIMEOUT_COUNTER_DISABLE; if (HAL_OSPI_MemoryMapped(hospi1, s_mmap) ! HAL_OK) { Error_Handler(); } } /* 自测试程序 */ #define HYPERRAM_BASE_ADDR 0x90000000UL #define HYPERRAM_SIZE (4UL * 1024 * 1024) /* 4MB */ /* 测试地址起始、中间、末尾附近 */ static const uint32_t test_addrs[] { 0x000000, /* 起始 */ 0x001000, /* 4KB 边界 */ HYPERRAM_SIZE / 2 - 256, /* 中间 */ HYPERRAM_SIZE - 256, /* 末尾 */ }; /** * brief HyperRAM 自测试 * note 必须在 HyperRAM_EnableMemMapped() OCTOSPI_DelayBlock_Calib() 之后调用 * 测试内容 * 1. 单字节读写 * 2. 多种数据模式0x00/0xFF/0xAA55/行走1 * 3. 多地址边界测试 * 4. 大块顺序读写 性能测量 */ void HyperRAM_SelfTest(void) { __IO uint8_t *base (__IO uint8_t *)HYPERRAM_BASE_ADDR; uint32_t pass 0, fail 0; uint32_t tick_start, tick_end; uint8_t err_cnt[4]; uint16_t fail_offset[2]; uint8_t expect_val[2], actual_val[2]; /* ---- 测试1单字节读写 ---- */ MLOG_I(HRAM, [Test1] Single byte read/write); { uint8_t err 0; base[0] 0xA5; if (base[0] ! 0xA5) err; base[1] 0x5A; if (base[1] ! 0x5A) err; base[100] 0x33; if (base[100] ! 0x33) err; err_cnt[0] err; if (err 0) { MLOG_I(HRAM, PASS); pass; } else { MLOG_I(HRAM, FAIL (errors%d), err); fail; } } /* ---- 测试2数据模式测试 ---- */ MLOG_I(HRAM, [Test2] Data pattern test (256 bytes 0x1000)); { #define PATTERN_LEN 256 uint8_t write_buf[PATTERN_LEN]; uint8_t read_buf[PATTERN_LEN]; uint8_t err 0; /* 模式: 0x00, 0xFF, 0xAA, 0x55, 行走1 */ const uint8_t patterns[] { 0x00, 0xFF, 0xAA, 0x55, 0x01, 0x80 }; const char *pattern_names[] { 0x00, 0xFF, 0xAA, 0x55, walk1_L, walk1_H }; for (uint8_t p 0; p sizeof(patterns); p) { /* 填充写入缓冲区 */ for (uint16_t i 0; i PATTERN_LEN; i) { if (patterns[p] 0x01) write_buf[i] (uint8_t)(1u (i % 8)); else if (patterns[p] 0x80) write_buf[i] (uint8_t)(0x80u (i % 8)); else write_buf[i] patterns[p]; } /* 写入 HyperRAM */ for (uint16_t i 0; i PATTERN_LEN; i) { base[0x1000 i] write_buf[i]; } /* 回读校验 */ for (uint16_t i 0; i PATTERN_LEN; i) { read_buf[i] base[0x1000 i]; if (read_buf[i] ! write_buf[i]) err; } err_cnt[1] err; if (err 0) MLOG_I(HRAM, pattern %s: PASS, pattern_names[p]); else { MLOG_I(HRAM, pattern %s: FAIL (errors%d), pattern_names[p], err); fail; } if (err 0) pass; err 0; } #undef PATTERN_LEN } /* ---- 测试3多地址边界测试 ---- */ MLOG_I(HRAM, [Test3] Address boundary test (64 bytes each)); { #define BOUNDARY_LEN 64 uint8_t err 0; for (uint8_t a 0; a sizeof(test_addrs) / sizeof(test_addrs[0]); a) { __IO uint8_t *ptr (__IO uint8_t *)(HYPERRAM_BASE_ADDR test_addrs[a]); /* 写入地址值作为数据 */ for (uint16_t i 0; i BOUNDARY_LEN; i) { ptr[i] (uint8_t)((test_addrs[a] i) 0xFF); } /* 回读校验 */ for (uint16_t i 0; i BOUNDARY_LEN; i) { if (ptr[i] ! (uint8_t)((test_addrs[a] i) 0xFF)) { fail_offset[0] i; expect_val[0] (uint8_t)((test_addrs[a] i) 0xFF); actual_val[0] ptr[i]; err; break; } } err_cnt[2] err; if (err 0) { MLOG_I(HRAM, addr0x%06lX: PASS, test_addrs[a]); pass; } else { MLOG_I(HRAM, addr0x%06lX: FAIL (offset%d expect0x%02X read0x%02X), test_addrs[a], fail_offset[0], expect_val[0], actual_val[0]); fail; } err 0; } #undef BOUNDARY_LEN } /* ---- 测试4大块顺序读写 性能测量 ---- */ MLOG_I(HRAM, [Test4] Bulk sequential R/W (1KB) timing); { #define BULK_SIZE 1024 uint8_t write_buf[BULK_SIZE]; uint8_t err 0; /* 填充递增数据 */ for (uint16_t i 0; i BULK_SIZE; i) { write_buf[i] (uint8_t)(i 0xFF); } /* 写入计时 */ tick_start HAL_GetTick(); for (uint16_t i 0; i BULK_SIZE; i) { base[0x2000 i] write_buf[i]; } tick_end HAL_GetTick(); MLOG_I(HRAM, Write 1KB: %lu ms, tick_end - tick_start); /* 回读校验 计时 */ tick_start HAL_GetTick(); for (uint16_t i 0; i BULK_SIZE; i) { if (base[0x2000 i] ! write_buf[i]) { fail_offset[1] i; expect_val[1] write_buf[i]; actual_val[1] base[0x2000 i]; err; break; } } tick_end HAL_GetTick(); MLOG_I(HRAM, Read 1KB: %lu ms, tick_end - tick_start); err_cnt[3] err; if (err 0) { MLOG_I(HRAM, PASS); pass; } else { MLOG_I(HRAM, FAIL (offset0x%03X expect0x%02X read0x%02X), 0x2000 fail_offset[1], expect_val[1], actual_val[1]); fail; } #undef BULK_SIZE } /* ---- 汇总 断电打在这里查看err_cnt的值---- */ MLOG_I(HRAM, HyperRAM Self Test DONE ); MLOG_I(HRAM, PASS: %lu, FAIL: %lu, pass, fail); if (fail 0) { MLOG_I(HRAM, *** TEST FAILED - check hardware/timing ***); } else { MLOG_I(HRAM, *** ALL TESTS PASSED ***); } }3. HyperRAM.h/* * HyperRAM.h */ #ifndef HYPERRAM_HYPERRAM_H_ #define HYPERRAM_HYPERRAM_H_ #include stm32h7xx_hal.h #include stm32h7xx_ll_delayblock.h #include octospi.h #include string.h #include main.h void HyperRAM_EnableMemMapped(void); void HyperRAM_SelfTest(void); #endif /* HYPERRAM_HYPERRAM_H_ */4. octospi.c的配置可以对照看一下/* USER CODE BEGIN Header */ /** ****************************************************************************** * file octospi.c * brief This file provides code for the configuration * of the OCTOSPI instances. ****************************************************************************** * attention * * Copyright (c) 2026 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include octospi.h /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ OSPI_HandleTypeDef hospi1; /* OCTOSPI1 init function */ void MX_OCTOSPI1_Init(void) { /* USER CODE BEGIN OCTOSPI1_Init 0 */ /* USER CODE END OCTOSPI1_Init 0 */ OSPIM_CfgTypeDef sOspiManagerCfg {0}; OSPI_HyperbusCfgTypeDef sHyperBusCfg {0}; /* USER CODE BEGIN OCTOSPI1_Init 1 */ /* USER CODE END OCTOSPI1_Init 1 */ hospi1.Instance OCTOSPI1; hospi1.Init.FifoThreshold 1; hospi1.Init.DualQuad HAL_OSPI_DUALQUAD_DISABLE; hospi1.Init.MemoryType HAL_OSPI_MEMTYPE_HYPERBUS; hospi1.Init.DeviceSize 22; hospi1.Init.ChipSelectHighTime 5; hospi1.Init.FreeRunningClock HAL_OSPI_FREERUNCLK_DISABLE; hospi1.Init.ClockMode HAL_OSPI_CLOCK_MODE_0; hospi1.Init.WrapSize HAL_OSPI_WRAP_NOT_SUPPORTED; hospi1.Init.ClockPrescaler 2; hospi1.Init.SampleShifting HAL_OSPI_SAMPLE_SHIFTING_NONE; hospi1.Init.DelayHoldQuarterCycle HAL_OSPI_DHQC_ENABLE; hospi1.Init.ChipSelectBoundary 0; hospi1.Init.DelayBlockBypass HAL_OSPI_DELAY_BLOCK_USED; hospi1.Init.MaxTran 0; hospi1.Init.Refresh 241; if (HAL_OSPI_Init(hospi1) ! HAL_OK) { Error_Handler(); } sOspiManagerCfg.ClkPort 2; sOspiManagerCfg.DQSPort 2; sOspiManagerCfg.NCSPort 2; sOspiManagerCfg.IOLowPort HAL_OSPIM_IOPORT_2_LOW; sOspiManagerCfg.IOHighPort HAL_OSPIM_IOPORT_2_HIGH; if (HAL_OSPIM_Config(hospi1, sOspiManagerCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) ! HAL_OK) { Error_Handler(); } sHyperBusCfg.RWRecoveryTime 4; sHyperBusCfg.AccessTime 4; sHyperBusCfg.WriteZeroLatency HAL_OSPI_LATENCY_ON_WRITE; sHyperBusCfg.LatencyMode HAL_OSPI_FIXED_LATENCY; if (HAL_OSPI_HyperbusCfg(hospi1, sHyperBusCfg, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) ! HAL_OK) { Error_Handler(); } /* USER CODE BEGIN OCTOSPI1_Init 2 */ /* USER CODE END OCTOSPI1_Init 2 */ } void HAL_OSPI_MspInit(OSPI_HandleTypeDef* ospiHandle) { GPIO_InitTypeDef GPIO_InitStruct {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct {0}; if(ospiHandle-InstanceOCTOSPI1) { /* USER CODE BEGIN OCTOSPI1_MspInit 0 */ /* USER CODE END OCTOSPI1_MspInit 0 */ /** Initializes the peripherals clock */ PeriphClkInitStruct.PeriphClockSelection RCC_PERIPHCLK_OSPI; PeriphClkInitStruct.PLL2.PLL2M 2; PeriphClkInitStruct.PLL2.PLL2N 32; PeriphClkInitStruct.PLL2.PLL2P 2; PeriphClkInitStruct.PLL2.PLL2Q 2; PeriphClkInitStruct.PLL2.PLL2R 2; PeriphClkInitStruct.PLL2.PLL2RGE RCC_PLL2VCIRANGE_3; PeriphClkInitStruct.PLL2.PLL2VCOSEL RCC_PLL2VCOWIDE; PeriphClkInitStruct.PLL2.PLL2FRACN 0; PeriphClkInitStruct.OspiClockSelection RCC_OSPICLKSOURCE_PLL2; if (HAL_RCCEx_PeriphCLKConfig(PeriphClkInitStruct) ! HAL_OK) { Error_Handler(); } /* OCTOSPI1 clock enable */ __HAL_RCC_OCTOSPIM_CLK_ENABLE(); __HAL_RCC_OSPI1_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); /**OCTOSPI1 GPIO Configuration PF0 ------ OCTOSPIM_P2_IO0 PF1 ------ OCTOSPIM_P2_IO1 PF2 ------ OCTOSPIM_P2_IO2 PF3 ------ OCTOSPIM_P2_IO3 PF4 ------ OCTOSPIM_P2_CLK PF5 ------ OCTOSPIM_P2_NCLK PF12 ------ OCTOSPIM_P2_DQS PG0 ------ OCTOSPIM_P2_IO4 PG1 ------ OCTOSPIM_P2_IO5 PG10 ------ OCTOSPIM_P2_IO6 PG11 ------ OCTOSPIM_P2_IO7 PG12 ------ OCTOSPIM_P2_NCS */ GPIO_InitStruct.Pin GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12; GPIO_InitStruct.Mode GPIO_MODE_AF_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate GPIO_AF9_OCTOSPIM_P2; HAL_GPIO_Init(GPIOF, GPIO_InitStruct); GPIO_InitStruct.Pin GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_11; GPIO_InitStruct.Mode GPIO_MODE_AF_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate GPIO_AF9_OCTOSPIM_P2; HAL_GPIO_Init(GPIOG, GPIO_InitStruct); GPIO_InitStruct.Pin GPIO_PIN_10|GPIO_PIN_12; GPIO_InitStruct.Mode GPIO_MODE_AF_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate GPIO_AF3_OCTOSPIM_P2; HAL_GPIO_Init(GPIOG, GPIO_InitStruct); /* OCTOSPI1 interrupt Init */ HAL_NVIC_SetPriority(OCTOSPI1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(OCTOSPI1_IRQn); /* USER CODE BEGIN OCTOSPI1_MspInit 1 */ /* USER CODE END OCTOSPI1_MspInit 1 */ } } void HAL_OSPI_MspDeInit(OSPI_HandleTypeDef* ospiHandle) { if(ospiHandle-InstanceOCTOSPI1) { /* USER CODE BEGIN OCTOSPI1_MspDeInit 0 */ /* USER CODE END OCTOSPI1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_OCTOSPIM_CLK_DISABLE(); __HAL_RCC_OSPI1_CLK_DISABLE(); /**OCTOSPI1 GPIO Configuration PF0 ------ OCTOSPIM_P2_IO0 PF1 ------ OCTOSPIM_P2_IO1 PF2 ------ OCTOSPIM_P2_IO2 PF3 ------ OCTOSPIM_P2_IO3 PF4 ------ OCTOSPIM_P2_CLK PF5 ------ OCTOSPIM_P2_NCLK PF12 ------ OCTOSPIM_P2_DQS PG0 ------ OCTOSPIM_P2_IO4 PG1 ------ OCTOSPIM_P2_IO5 PG10 ------ OCTOSPIM_P2_IO6 PG11 ------ OCTOSPIM_P2_IO7 PG12 ------ OCTOSPIM_P2_NCS */ HAL_GPIO_DeInit(GPIOF, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12); HAL_GPIO_DeInit(GPIOG, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_11 |GPIO_PIN_12); /* OCTOSPI1 interrupt Deinit */ HAL_NVIC_DisableIRQ(OCTOSPI1_IRQn); /* USER CODE BEGIN OCTOSPI1_MspDeInit 1 */ /* USER CODE END OCTOSPI1_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ /* USER CODE END 1 */

相关新闻