用户工具

站点工具


icore4tx_14

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
icore4tx_14 [2020/07/28 15:29]
fmj
icore4tx_14 [2022/04/02 11:58] (当前版本)
sean
行 2: 行 2:
 |技术支持电话|**0379-69926675-801**||| |技术支持电话|**0379-69926675-801**|||
 |技术支持邮件|Gingko@vip.163.com||| |技术支持邮件|Gingko@vip.163.com|||
-|技术论坛|http://​www.eeschool.org||| 
 ^  版本 ​ ^  日期 ​ ^  作者 ​ ^  修改内容 ​ ^ ^  版本 ​ ^  日期 ​ ^  作者 ​ ^  修改内容 ​ ^
 |  V1.0  |  2020-07-28 ​ |  gingko ​ |  初次建立 ​ |  |  V1.0  |  2020-07-28 ​ |  gingko ​ |  初次建立 ​ | 
行 10: 行 9:
 \\ \\
  
-=====STM32CubeMX教程十——QSPI通信实验 =====+=====STM32CubeMX教程十——SDRAM实验 =====
 \\ \\
 \\ \\
行 16: 行 15:
  
 1.在主界面选择File-->​New Project ​  ​或者直接点击ACCEE TO MCU SELECTOR。  ​ 1.在主界面选择File-->​New Project ​  ​或者直接点击ACCEE TO MCU SELECTOR。  ​
-{{ :icore4tx:icore4tx_cube_13_1.png?direct |}} +{{ :icore4tx:icore4tx_cube_14_1.png?direct |}}
 2.出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置在搜索栏的下面,提供的各 ​ 种查找方式,可以选择芯片内核,型号,等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。 2.出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置在搜索栏的下面,提供的各 ​ 种查找方式,可以选择芯片内核,型号,等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。
-{{ :icore4tx:icore4tx_cube_13_2.png?direct |}} +{{ :icore4tx:icore4tx_cube_14_2.png?direct |}}
 3.配置RCC,使用外部时钟源。 3.配置RCC,使用外部时钟源。
-{{ :icore4tx:icore4tx_cube_13_3.png?direct |}} +{{ :icore4tx:icore4tx_cube_14_3.png?direct |}}
 4.时基源选择SysTick。 4.时基源选择SysTick。
-{{ :icore4tx:icore4tx_cube_13_4.png?direct |}} +{{ :icore4tx:icore4tx_cube_14_4.png?direct |}}
 5.将PA10,​PB7,​PB8设置为GPIO_Output。 5.将PA10,​PB7,​PB8设置为GPIO_Output。
-{{ :icore4tx:icore4tx_cube_13_5.png?direct |}} +{{ :icore4tx:icore4tx_cube_14_5.png?direct |}}
 6.引脚模式配置。 6.引脚模式配置。
-{{ :icore4tx:icore4tx_cube_13_6.png?direct |}}  +{{ :icore4tx:icore4tx_cube_14_6.png?direct |}} 
-{{ :icore4tx:icore4tx_cube_13_7.png?direct |}}  +{{ :icore4tx:icore4tx_cube_14_7.png?direct |}} 
-7.设置串口。 +7.设置串口。 
-{{ :icore4tx:icore4tx_cube_13_8.png?direct |}}  +{{ :icore4tx:icore4tx_cube_14_8.png?direct |}} 
-8.在NVIC Settings一栏使能接收中断。 +8.配置FMC 
-{{ :icore4tx:icore4tx_cube_13_9.png?direct |}}  +{{ :icore4tx:icore4tx_cube_14_9.png?direct |}} 
-9.配置QUADSPI。 +9.在 NVIC Settings 一栏使能接收中断。 
-{{ :icore4tx:icore4tx_cube_13_10.png?direct |}} +{{ :icore4tx:icore4tx_cube_14_10.png?direct |}}
 10.时钟源设置,选择外部高速时钟源,配置为最大主频。 10.时钟源设置,选择外部高速时钟源,配置为最大主频。
-{{ :icore4tx:icore4tx_cube_13_11.png?​direct |}}  +{{ :icore4tx:icore4tx_cube_14_11.png?direct |}} 
-{{ :​icore4tx:​icore4tx_cube_13_12.png?direct |}}  +11.工程文件的设置,​ 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可IDE我们使用的是MDK V5.27。 
-11.工程文件的设置,​ 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可 ​ IDE我们使用的是 MDK V5.27。 +{{ :icore4tx:icore4tx_cube_14_12.png?direct |}}
-{{ :icore4tx:icore4tx_cube_13_13.png?direct |}} +
 12.点击Code Generator,进行进一步配置。 12.点击Code Generator,进行进一步配置。
-{{ :icore4tx:icore4tx_cube_13_14.png?direct |}} +{{ :icore4tx:icore4tx_cube_14_13.png?direct |}}
   * **Copy all used libraries into the project folder**   * **Copy all used libraries into the project folder**
   * **将HAL库的所有.C和.H都复制到所建工程中**   * **将HAL库的所有.C和.H都复制到所建工程中**
行 54: 行 52:
     * 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径     * 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径
   * 自行选择方式即可   * 自行选择方式即可
-13.然后点击GENERATE CODE  创建工程。 +13.然后点击GENERATE CODE创建工程。 
-{{ :icore4tx:icore4tx_cube_13_15.png?direct |}} +{{ :icore4tx:icore4tx_cube_14_14.png?direct |}} 
 创建成功,打开工程。 创建成功,打开工程。
 \\ \\
 \\ \\
-===== 实验十QSPI通信实验——读写测试SPI FLASH =====+===== 实验十SDRAM实验——读写测试SDRAM =====
  
 ==== 一、 实验目的与意义 ==== ==== 一、 实验目的与意义 ====
-  - 了解STM32 ​QSPI结构。 +  - 了解STM32 ​SDRAM结构。 
-  - 了解STM32 ​QSPI特征。 +  - 了解STM32 ​SDRAM特征。 
-  - 掌握QSPI的使用方法。 +  - 掌握SDRAM的使用方法。 
-  - 掌握STM32 HAL库中QSPI属性的配置方法。 +  - 掌握STM32 HAL库中SDRAM属性的配置方法。 
-  - 掌握KEILMDK 集成开发环境使用方法。+  - 掌握KEILMDK集成开发环境使用方法。
 ==== 二、 实验设备及平台 ==== ==== 二、 实验设备及平台 ====
   - iCore4TX 双核心板[[https://​item.taobao.com/​item.htm?​spm=a1z10.1-c-s.w4004-22598974120.3.29da532fLkazHH&​id=614919247574|点击购买]]。   - iCore4TX 双核心板[[https://​item.taobao.com/​item.htm?​spm=a1z10.1-c-s.w4004-22598974120.3.29da532fLkazHH&​id=614919247574|点击购买]]。
行 75: 行 73:
   - 装有WIN XP(及更高版本)系统的计算机。   - 装有WIN XP(及更高版本)系统的计算机。
 ==== 三、 实验原理 ==== ==== 三、 实验原理 ====
-=== 1.QSPI简介 === +=== 1.SDRAM简介 === 
- +  * 同步动态随机存取内存(synchronous dynamic random-access memory简称 SDRAM)有一个同步接口动态随机存取内存(DRAM)。通常 DRAM 是有一个异步接口的,这样它可以随时响控制输入的变化而 SDRAM 有一个同步接口,响应控制输入前会等待一个时钟信号,这样就能和计算机系统总线同步。时钟被用来驱动一个有限状态机,对进入的指令进行管线(Pipeline)操作。这使得 SDRAM 与没有同步接口的异 DRAM(asynchronousDRAM)相比可以有一个更复杂的操作模式。管线意味着芯片可以在处理完之前的指令前,接受一个新的指令个写入管线中写入命令在另一个指令执行完之后可以立刻执行,而不需要等待数据写入存储队列的时间在一个读取的流水线中,需要的数据在读取指令发出之后固定数量的时钟频率后到达,而这个等待的过程可以发出其它附加指令。 
-  * QSPI是Queued SPI的简写,是Motorola公司推出SPI接口的扩展比SPI用更加广泛。在SPI协议基础上Motorola公司其功能进行了增强增加了队列传输机制推出了队列串行外围口协议(即QSPI协议)QSPI是种专用通信接口连接单、双或四(条数据线)SPI Flash存储介质 +  * SDRAM 是多 Bank 结构,例如在一个具有两个 Bank 的 SDRAM 的模组中,其中一个Bank 在进行预充电期,另一个 Bank 却马上可以被读取,这样当进行一次读取后,又马上去读取已经预充电 Bank 的数据时,就无需等待而是可以直读取了,这也就大大提高了的访问速度。为了实现这个功能,SDRAM 需要增加对多个 Bank 的管理,实现控制其中的 Bank 进预充电。在一个具有 2 个以上 Bank 的 SDRAM 中,一般会多一根叫做 BAn的引脚,用来实现在多个 Bank 之间的选择。 
-  * 该接口可以在以下三种模式下工作: +  * SDRAM 具有多种工作模式,内操作是一个复杂的状态机。SDRAM ​件的引脚分为以下几类。 
-  * **① 间接模式**:使用QSPI寄存器全部操作。 +  * (1)控制信号:包括片选、钟、时钟使能、行列地址选择、读有效及数据有效。 
-  * **② 状态轮询模式**:周期性读取外Flash状态寄存,而且标志位置1时会产生中断(如擦除或烧完成,会产生中断)。 +  * (2)地址信号时分复用引脚,根据行列地址选择引脚,控制输入的地址为行地址或列地址。 
-  * **③ 内存映射模式**外部Flash映射到微控制地址空间,从而系统将其视作内部存储器。 +  * (3)数据信号:向引脚受数据有效控制。 
-  * 采用闪存模式时同时访问两个Quad-SPI Flash,吞吐量容量均提高二倍。 +  * SDRAM的所有操作都步于钟。根据时钟上升沿控制管脚地址输入的状态,以产生多种输入命令:​模式寄存器设置命令、激活命令、预充命令、读命令写命令带预充的读命、带预充的写命令、自动刷新命令自我刷新命令、突发停命令、空操作命令根据输入命令,SDRAM状态内部状态间转移内部状态包括模式寄存器设置状态、激活状态、预充状态、写状态、读状态、预充读状态、预充写状态、自动刷新状态及自我刷新状态。 
-=== 2.QSPI命令序列 === +  * SDRAM 支持操作命令有初始化配置、预充电、行激活、操作、写操作、自动刷新、自刷新等。所有的操作命令通过控制线 CS#​、RAS#​、CAS#​、WE#​和地址线、体选地址BA输入 
-  * QUADSPI通过命令与Flash通信,每条命令包括指令、地址交替字节空指和数据这五个阶段,任一阶段均可跳过,但至少要包含指令、地址交替字节或数据阶段之一nCS在每条指开始前下降,在每条指令完成后再次上升如图为QSPI四线模式的读命令时序。 +=== 2.W9825G6JB命令表 === 
-{{ :icore4tx:icore4tx_arm_hal_13_1.png?direct |}} +{{ :icore4tx:icore4tx_arm_hal_14_1.png?direct |}} 
-== (1) 指令阶段 ​== +=== 3.FMC简介 === 
- +  * STM32H750使用FMC外设来管理扩展的器,FMC是Flexible Memory Controller缩写译为变存储控制器以用于驱动包括 SRAM、SDRAM、NOR FLASH以及NAND FLSAH类型的器。 
-  * 这一阶段,将在QUADSPI_CCR[7:​0]寄存器的INSTRUCTION字段中配置的一条8位指令发送到Flash指定待执行操作类型。尽管大多数 Flash从IO0/​SO信号(单线 SPI 模式)只能以一次1位的方式接收指令但指令阶段选择一次发送2位(在双线SPI模式中通过IO0/​IO1)或一次发送4位(在四线SPI模式中通过IO0/​IO1/​IO2/​IO3)通过 QUADSPI_CCR[9:​8]寄存器中的IMODE[1:​0]字段进行配置。 +  * FMC 有 6 个存储区域每个区域支持 256MB 的寻空间。 
-  * 若IMODE = 00则跳过指令阶段,命令序列从地阶段(如果存在)开始 +  * (1) 存储区域 1 可连接多达 ​个 NOR Flash 或 PSRAM 设备储区域被划分为如4个NOR/​PSRAM子区域带4个专用片选信号:储区域 1 NOR/PSRAM 1、储区域 ​NOR/PSRAM 2存储区域 1 NOR/PSRAM 3、存储区域 1 NOR/​PSRAM ​4。 
-== (2) 地址阶段 == +  * (2) 储区域 2 用于 SDRAM 件,具体是 SDRAM 存储区域 ​还是 SDRAM 存储区域 2 取决于 BMAP 位配置。 
- +  * (3) 存储区域 3 用于连接 NAND Flash 器件此空间的 MPU 特性必须通过软件重新配置中。 
-  * 在地址阶段,将1-4字节发送到Flash,指示操作地址待发送的地址字节数在QUADSPI_CCR[13:​12]寄器的ADSIZE[1:​0]字段中进行配置。在间接模式和自动轮询模式下,待发送的地址字节在QUADSPI_AR寄器的ADDRESS[31:​0]中指定在内映射模式下,则通过 AHB(来自于 Cortex ® 或 DMA)直接给出地址。地址阶段可一次发送位(在单线SPI模式中通过SO)2位(在双线SPI模式中通过IO0/IO1)或4位(在四线 SPI 模式中通过 IO0/​IO1/​IO2/​IO3)这可通过QUADSPI_CCR[11:​10]寄存器中的ADMODE[1:​0]字段进行配置。 +  * (4) 存储区域 5 和 6 用于连接 SDRAM 器件每个存储区域 1 个器件)。 
-  * 若ADMODE = 00,则跳过地址阶段,命令序列直接进入下一阶段(如果存在)。 +  * 对于每个存储区域,所要使用的存储器类型由用户应用程序通过配置寄存器配置。 
-== (3) 交换字节阶段 == +  * 本实验使用 FMC 控制 SDRAM。启动时必须通用户应用程对用于连接 FMC SDRAM 控制器与外部 SDRAM 设备的 SDRAM I/O 引脚行配置程序未使用的 SDRAM 控制器 I/O 引脚可用于其它用途。 
- +  * FMC 的存储区域如图所示: 
-  * 在交替字节阶段,将1-4字节发送到Flash,一般用于控制操作模式待发送交替字节数在QUADSPI_CCR[17:​16]寄存器的ABSIZE[1:​0]字段中进行配置。待发送的字节在QUADSPI_ABR寄存器中指定。 +{{ :​icore4tx:​icore4tx_arm_hal_14_2.png?​direct |}} 
-  * 交替字节阶段可一次发送1位(在单线 SPI 模式中通过 SO)、2位(在双线SPI模式中通过 IO0/​IO1)或4在四线SPI模式中通IO0/​IO1/​IO2/​IO3)。可通过QUADSPI_CCR[15:​14]寄存器中的ABMODE[1:​0]字段进行配置。 +  * FMC 框图如下: 
-  * 若ABMODE = 00则跳交替字节阶段,命令列直接进入下一阶段(如果存在)交替字节阶段存在仅需发送单个半字节而不是一个全字节的情况,比如采双线模式并且仅使用两个周期发送交替字节时。在这种情况下,固件四线模式(ABMODE ​11)并发送一字节,方法是ALTERNATE的位731”(IO3 保持高电平)且6和2置“0”(IO2 ​线保持低电平)时,半字节的高 ​放在ALTERNATE位 4:3低 2位放在位1和0例如,如果半字节2 ​(0010通过IO0/​IO1发送则ALTERNATE 应设置0x8A (1000_1010)。 +{{ :​icore4tx:​icore4tx_arm_hal_14_3.png?​direct |}} 
-== (4) 空指令周期阶段 ​== +=== 4.SDRAM的地址映射 === 
- +  * 两可用的 SDRAM 存储区域如图: 
-  * 在空指令周期阶段,给定1-31个周期内不发送或接收任何数据,目的是当采用更高的时钟频率时,给Flash留出准备数据阶段的时间。这一阶段中给定的周期数在QUADSPI_CCR[22:​18]寄存器的DCYC[4:​0]字段中指定。在SDR和DDR模式下,持续间被指定为一定个数的全时钟周期。若DCYC为零,则跳过空指令周期阶段,命令列直接进入数据阶段(如果在)。空指周期阶段的操作模式由DMODE确定。为确保数据信号从输出模式转变为输入模式足够的“周转”时间使用双线四线模式从Flash接收数据时,至少需要指定一个空指令周期 +{{ :​icore4tx:​icore4tx_arm_hal_14_4.png?​direct |}} 
-== (5) 数据阶段 == +  * 下表显示了 13 和 11 位列配的 SDRAM 映射。 
- +{{ :​icore4tx:​icore4tx_arm_hal_14_5.png?​direct |}} 
-  * 在数据阶段,从Flash接收或向其送任意量的字节。 +  * (1) 连接 16 存储器时, FMC 内部使用 ADDR[11:​1]内部地址线进行外部寻址连接32 位存储器时,FMC 内部使用 ADDR[12:2]地址线进行外部寻址。无论外部储器宽度是多少FMC_A[0]都必须连接到外部储器地址 A[0] 
-  * 在间接模式和自动轮询模式下,待发送/​接收的字节数在QUADSPI_DLR寄存器中指定。在接写入模式下,发送到Flash的数据必须写入QUADSPI_DR寄存器。在间接读取模式下,通过读取QUADSPI_DR寄存器获得从 Flash 接收的数据。在内映射模式下,读取的数据通过AHB直接发送回Cortex或DMA。数据阶段可一次发送/​接收1位(在单线SPI ​模式中通过SO)、2位(在双线 SPI 模式中通过IO0/​IO1)或4位(在四线SPI模式中通过IO0/​IO1/​IO2/​IO3)。这可通过QUADSPI_CCR[15:​14] ​寄存器ABMODE[1:​0]字段进行配置。若DMODE = 00,则跳过数据阶段,命令序列在拉高nCS立即完成。这一配置仅可用于仅间接写入模式+  * (2不支持 AutoPrecharge。FMC_A[10]必须连接到外部存储器地址 A[10]但始终低电平。 
 +=== 5.SDRAM 控制寄存器 === 
 +  * 控制 SDRAM 有 FMC_SDCR1/​FMC_SDCR2 控制寄存器、FMC_SDTR1/​FMC_SDTR2时序器、FMC_SDCMR 命令模式寄存器以及FMC_SDRTR 刷新时器寄存器其中控制寄存器及时序寄存器各有 2 个分别对应于 SDRAM 存储区域 1 存储区域 2 的配置。 
 +  * FMC_SDCR 控制寄存器配置 SDCLK 的同步时钟频率、突读使能、写保护、CAS延迟、行列地址位以及数据总线宽度等。 
 +  * FMC_SDTR 时序寄存器用于配置 SDRAM 访问时的各种时延迟,如 TRP 行预充电延迟、TMRD 加载模式寄存器激活延迟等 
 +  * FMC_SDCMR 命令模式寄存器用于储要发送到 SDRAM 模式寄存器的配置,以及要向 SDRAM 芯片发送的命令。 
 +  * FMC_SDRTR 刷新定器寄存器用于配置 ​SDRAM 的自动刷新周期 
 +=== 6.原理图 === 
 +{{ :​icore4tx:​icore4tx_arm_hal_14_6.png?​direct |}}
 ==== 四、 实验程序 ==== ==== 四、 实验程序 ====
- 
 === 1.主函数 === === 1.主函数 ===
 <code c> <code c>
-int main(void) ​  +int main(void) 
-{  ​ +{ 
-    ​int i;   +  int i,j
-    int temp;   +  HAL_Init();​ 
-    unsigned char write_buffer[4096]; ​  +  i2c.initialize();​ 
-    unsigned char read_buffer[4096]; ​  +  ​axp152.initialize();​ 
-    ​HAL_Init(); ​  +  ​axp152.set_dcdc1(3500);//​[ARM & FPGA] 
- +  axp152.set_dcdc2(1200);//​[FPGA INT] 
-    SystemClock_Config(); ​  +  axp152.set_dcdc3(3300);//​[DCOUT3] 
-    ​i2c.initialize();  ​ +  axp152.set_dcdc4(3300);//​[DCOUT4] 
-    ​axp152.initialize();  ​ +  axp152.set_aldo1(3300);//​[BK3] 
-    ​axp152.set_dcdc1(3500);//​[ARM & FPGA] +  axp152.set_aldo2(3300);//​[ALDOOUT2] 
-    axp152.set_dcdc2(1200);//​[FPGA INT] +  axp152.set_dldo1(3300);//​[BK0] 
-    axp152.set_dcdc3(3300);//​[DCOUT3] +  axp152.set_dldo2(3300);//​[BK1] 
-    axp152.set_dcdc4(3300);//​[DCOUT4] +  HAL_Delay(200);​ 
- +  ​SystemClock_Config();​ 
-    ​axp152.set_aldo1(3300);//​[BK3] +  MX_GPIO_Init();​ 
-    axp152.set_aldo2(3300);//​[ALDOOUT2] +  ​MX_USART2_UART_Init();​ 
-    axp152.set_dldo1(3300);//​[BK0] +  MX_FMC_Init(); 
-    axp152.set_dldo2(3300);//​[BK1] +  BSP_SDRAM_Init(); 
-    HAL_Delay(200);​ +  ​usart2.initialize(115200);​ 
-   +  ​usart2.printf("​\x0c"​);​ //清屏 
-    MX_GPIO_Init();  ​ +  usart2.printf("​\033[1;​32;​40m"​);​ //​设置终端字体为绿色 
-    ​MX_USART2_UART_Init();  ​ +  usart2.printf("​Hello,​I am iCore4TX!\r\n\r\n"​);​ 
-    MX_QUADSPI_Init();  ​ +  ​//向 SDRAM 中写入 0x0000~0xFFFF 并读取校验 
-    BSP_QSPI_Init();  ​ +  for(j = 0; j < 256; j++){ 
-    ​usart2.initialize(115200);  ​ +    for(i = 0;i < 65536;i++){ 
-    ​usart2.printf("​\x0c"​); ​                      ​//清屏 +      write_sdram((65536 * j + i),i)
-    usart2.printf("​\033[1;​32;​40m"​); ​             //​设置终端字体为绿色  +    } 
-    usart2.printf("​Hello,​I am iCore4TX!\r\n\r\n"​); ​        ​ +  } 
-    temp = BSP_QSPI_FLASH_ReadID(); ​  +  for(j = 0; j < 256; j ++){ 
-    ​usart2.printf("FLASH ID: 0x%X\r\n",​temp);  ​ +    for(i = 0;i < 65536;i++){ 
-   ​for(i = 0;i < 4096;i ++){      ​ +      if(i != read_sdram((65536 * j + i))){ 
-        write_buffer[i] = % 256  +         ​usart2.printf("​SDRAM ERROR!\r\n"​);​ 
-        read_buffer[i] = 0;  ​ +         ​while(1){ //​测试失败 LED 灯闪烁 
-    }   +            LED_ON; 
-    ​BSP_QSPI_Write(write_buffer,​0,4096) //​写数据 +            HAL_Delay(500);​ 
-    BSP_QSPI_Read(read_buffer,​0,​4096);     //​读数据 +            LED_OFF
-    for(i = 0;i < 4096;i ++){     ​ +            ​HAL_Delay(500);​ 
-        if(read_buffer[i!= write_buffer[i]){   +  ​} 
-            usart2.printf("​FLASH ERROR!\r\n"​); ​  +  usart2.printf("​SDRAM TEST OK!\r\n"​);​ 
-            while(1); ​  +  ​HAL_Delay(1000);​ 
-        ​}  ​ +  LED_ON; //​测试成功 LED 灯常亮 
-    ​} ​  +  ​while (1) 
-    usart2.printf("​FLASH TEST OK!\r\n"​); ​      +  
-    while (1)   +  ​} 
-      ​ +            
-    ​} ​  +      
-  +
 </​code>​ </​code>​
    
-=== 2.QSPI初始化函数 === +=== 2.SDRAM 初始化函数 ===
-初始化好QSPI外设后,还要初始化初始化QSPI存储器,需要先复位存储器,使能写操作,配置状态寄存器才可进行数据读写操作。+
 <code c> <code c>
-uint8_t ​BSP_QSPI_Init(void) ​  +uint8_t ​BSP_SDRAM_Init(void) 
-  +
-  ​QSPIHandle.Instance ​QUADSPI  +  ​static uint8_t sdramstatus ​SDRAM_OK
-  /* 调用DeInit函数重置驱动程序 ​*/   +  /* SDRAM 驱动配置 ​*/ 
-  ​if (HAL_QSPI_DeInit(&​QSPIHandle) !HAL_OK)  ​ +  ​sdramHandle.Instance ​FMC_SDRAM_DEVICE;​ 
-  ​{   +  ​Timing.LoadToActiveDelay = 2
-    return QSPI_ERROR  +  ​Timing.ExitSelfRefreshDelay = 7; 
-  ​}  ​ +  ​Timing.SelfRefreshTime = 4; 
-  ​/* 系统级初始化 */   +  Timing.RowCycleDelay = 7; 
-  ​BSP_QSPI_MspInit(&​QSPIHandle,​ NULL)  +  ​Timing.WriteRecoveryTime = 2
-  ​/*  QSPI初始化 */  ​ +  ​Timing.RPDelay = 2; 
-  ​/* 时钟预分频器设置为1,因此QSPI时钟240MHz /(1 + 1)= 120MHz */  +  ​Timing.RCDDelay ​2; 
-  ​QSPIHandle.Init.ClockPrescaler ​    1  +  ​sdramHandle.Init.SDBank ​FMC_SDRAM_BANK1
-  ​QSPIHandle.Init.FifoThreshold ​     ​POSITION_VAL(W25Q64_FLASH_SIZE) - 1  +  ​sdramHandle.Init.ColumnBitsNumber ​FMC_SDRAM_COLUMN_BITS_NUM_9
-  ​QSPIHandle.Init.SampleShifting ​    QSPI_SAMPLE_SHIFTING_NONE  +  ​sdramHandle.Init.RowBitsNumber ​FMC_SDRAM_ROW_BITS_NUM_13
-  ​QSPIHandle.Init.FlashSize ​         ​POSITION_VAL(W25Q64_FLASH_SIZE) - 1  +  ​sdramHandle.Init.MemoryDataWidth ​SDRAM_MEMORY_WIDTH
-  ​QSPIHandle.Init.ChipSelectHighTime ​QSPI_CS_HIGH_TIME_6_CYCLE  +  ​sdramHandle.Init.InternalBankNumber ​FMC_SDRAM_INTERN_BANKS_NUM_4
-  ​QSPIHandle.Init.ClockMode ​         ​QSPI_CLOCK_MODE_0;   +  ​sdramHandle.Init.CASLatency ​FMC_SDRAM_CAS_LATENCY_3; 
-  ​QSPIHandle.Init.FlashID ​           ​QSPI_FLASH_ID_1;   +  sdramHandle.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;​ 
-  ​QSPIHandle.Init.DualFlash ​         ​QSPI_DUALFLASH_DISABLE;   +  ​sdramHandle.Init.SDClockPeriod ​SDCLOCK_PERIOD; 
-  if (HAL_QSPI_Init(&QSPIHandle) != HAL_OK) ​  +  sdramHandle.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;​ 
-  {   +  ​sdramHandle.Init.ReadPipeDelay ​FMC_SDRAM_RPIPE_DELAY_1; 
-    ​return QSPI_ERROR  +  /* SDRAM 控制器初始化 */ 
-  }   +  BSP_SDRAM_MspInit(&​sdramHandle,​ NULL); 
-  ​return QSPI_OK  +  if(HAL_SDRAM_Init(&sdramHandle,​ &Timing) != HAL_OK) 
-}   +  { 
 +    ​sdramstatus = SDRAM_ERROR
 +  } 
 +  else 
 +  ​
 +    /* SDRAM 初始化顺序 */ 
 +    BSP_SDRAM_Initialization_sequence(REFRESH_COUNT)
 +  } 
 +  return sdramstatus;​ 
 +}
 </​code> ​ </​code> ​
-=== 3.QSPI读函数 === +=== 3.SDRAM 函数 ===
-要从存取器中读取数据,首先要用一个指针指向读回来的数据,并确定数据的首地址,数据大小,通过库函数HAL_QSPI_Command发送配置命令,然后调用库函数HAL_QSPI_Receive接收数据,最后等待操作完成,代码如下:+
 <code c> <code c>
-uint8_t BSP_QSPI_Read(uint8_t* pDatauint32_t ReadAddr, uint32_t Size  +#define write_sdram(offset,data) *(volatile unsigned short int *)(SDRAM_DEVICE_ADDR + (offset << 1)) = data 
-{   +#define read_sdram(offset) *(volatile unsigned short int *)(SDRAM_DEVICE_ADDR + (offset << 1))
-  QSPI_CommandTypeDef s_command; ​  +
-  /初始化读取命令 ​*/   +
-  s_command.InstructionMode ​  = QSPI_INSTRUCTION_1_LINE; ​  +
-  s_command.Instruction ​      = QUAD_OUT_FAST_READ_CMD; ​  +
-  s_command.AddressMode ​      = QSPI_ADDRESS_1_LINE; ​  +
-  s_command.AddressSize ​      = QSPI_ADDRESS_24_BITS; ​  +
-  s_command.Address ​          = ReadAddr; ​  +
-  s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; ​  +
-  s_command.DataMode ​         = QSPI_DATA_4_LINES; ​  +
-  s_command.DummyCycles ​      = W25Q64_DUMMY_CYCLES_READ_QUAD; ​  +
-  s_command.NbData ​           = Size;   +
-  s_command.DdrMode ​          = QSPI_DDR_MODE_DISABLE; ​  +
-  s_command.DdrHoldHalfCycle ​ = QSPI_DDR_HHC_ANALOG_DELAY; ​  +
-  s_command.SIOOMode ​         = QSPI_SIOO_INST_EVERY_CMD; ​     +
-  /* 配置命令 */   +
-  if (HAL_QSPI_Command(&​QSPIHandle,​ &​s_command,​ HAL_QPSI_TIMEOUT_DEFAULT_VALUE!HAL_OK  +
-  {   +
-    return QSPI_ERROR; ​  +
-  }   +
-  /数据接收 ​*/   +
-  if (HAL_QSPI_Receive(&​QSPIHandle,​ pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE!= HAL_OK  +
-  {   +
-    return QSPI_ERROR; ​  +
-  }   +
-  return QSPI_OK; ​  +
-}   +
 </​code> ​ </​code> ​
-pData:指向要取的数据的指针 +定义 SDRAM 读写函数
-ReadAddr:读取起始地址 +
-Size:要读取的数据大小 +
-=== 4.QSPI写函数 ​=== +
- +
-要从存取器中写入数据,首先要用一个指针指向写入的数据,并确定数据的首地址,数据大小,根据写入地址及大小判断存储器的页面,然后通过库函数HAL_QSPI_Command发送配置命令,再调用库函数HAL_QSPI_Transmit逐页写入数据,最后等待操作完成。代码如下:+
 <code c> <code c>
-uint8_t ​BSP_QSPI_Write(uint8_t* pData, ​uint32_t WriteAddr, uint32_t Size) +uint8_t ​BSP_SDRAM_ReadData(uint32_t uwStartAddress,​ uint32_t ​*pData, 
-{   +uint32_t ​uwDataSize
-  QSPI_CommandTypeDef s_command; ​  +
-  ​uint32_t ​end_addr, current_size,​ current_addr; ​  +  if(HAL_SDRAM_Read_32b(&sdramHandle,​ (uint32_t ​*)uwStartAddress, pData, ​uwDataSize) != HAL_OK) 
-  /* 计算写地址和页面末尾之间的大小 */   +  { 
-  current_size = W25Q64_PAGE_SIZE - (WriteAddr % W25Q64_PAGE_SIZE);  ​ +    return ​SDRAM_ERROR; 
-  /* 检查数据大小是否小于页面中的剩余位置*/ ​  +  } 
-  if (current_size > Size)   +  ​else 
-  ​  +  ​{ 
-    ​current_size = Size;   +    return ​SDRAM_OK
-  }   +  } 
-  /* 初始化地址变量 */   +}
-  current_addr = WriteAddr; ​  +
-  end_addr = WriteAddr + Size;   +
-  /* 初始化程序命令 */   +
-  s_command.InstructionMode ​  = QSPI_INSTRUCTION_1_LINE; ​  +
-  s_command.Instruction ​      = QUAD_IN_FAST_PROG_CMD; ​  +
-  s_command.AddressMode ​      = QSPI_ADDRESS_1_LINE; ​  +
-  s_command.AddressSize ​      = QSPI_ADDRESS_24_BITS; ​  +
-  s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; ​  +
-  s_command.DataMode ​         = QSPI_DATA_4_LINES; ​  +
-  s_command.DummyCycles ​      = 0;   +
-  s_command.DdrMode ​          = QSPI_DDR_MODE_DISABLE; ​  +
-  s_command.DdrHoldHalfCycle ​ = QSPI_DDR_HHC_ANALOG_DELAY; ​  +
-  s_command.SIOOMode ​         = QSPI_SIOO_INST_EVERY_CMD; ​  +
-  /* 逐页执行写入*/ ​  +
-  do   +
-  {   +
-    s_command.Address = current_addr; ​  +
-    s_command.NbData ​ = current_size; ​  +
-    /* 启用写操作 */   +
-    ​if (QSPI_WriteEnable(&QSPIHandle) != QSPI_OK) ​  +
-    {   +
-      return QSPI_ERROR; ​  +
-    }   +
-     /配置命令 */   +
-    if (HAL_QSPI_Command(&​QSPIHandle,​ &​s_command,​ HAL_QPSI_TIMEOUT_DEFAULT_VALUE!= HAL_OK) ​  +
-    {   +
-      return QSPI_ERROR; ​  +
-    }   +
-    /* 传输数据 */   +
-    if (HAL_QSPI_Transmit(&​QSPIHandle, pData, ​HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) ​  +
-    ​{   +
-      ​return ​QSPI_ERROR;  ​ +
-    ​  +
-    /* 配置自动轮询模式以等待程序结束 */   +
-    if (QSPI_AutoPollingMemReady(&​QSPIHandle,​ HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) ​  +
-    ​{   +
-      ​return ​QSPI_ERROR  +
-    }   +
-      /* 为下一页编程更新地址和变量大小 */   +
-    current_addr += current_size; ​  +
-    pData += current_size; ​  +
-    current_size = ((current_addr + W25Q64_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q64_PAGE_SIZE;  ​ +
-  } while (current_addr < end_addr); ​  +
-  return QSPI_OK;  ​ +
-  +
 </​code> ​ </​code> ​
-pData:指向要写入的数据的指针 +函数功能:在轮询模式下从 SDRAM 存储器中读取大量数据。 
-ReadAddr写入起始地址 +uwStartAddress:读取起始地址。 
-Size:要写入的数据大小 +pData:指向要读取的数据的指针 
-=== 5.QSPI_CommandTypeDe通信配置命令结构体 ===+uwDataSize从存储器读取的数据大小
 <code c> <code c>
-typedef struct  ​ +uint8_t BSP_SDRAM_WriteData(uint32_t uwStartAddress,​ uint32_t *pData,​uint32_t uwDataSize) 
-  +
-  uint32_t ​Instruction; ​       /设置通信指令,指定要发送到外部 SPI 设备的指令。仅可在 BUSY 0 时修改该字段*/ ​  +  ​if(HAL_SDRAM_Write_32b(&​sdramHandle,​ (uint32_t *)uwStartAddress,​ pData, uwDataSize) !HAL_OK) 
-  ​uint32_t Address           /* 指定要发送到外部 Flash 的地址,BUSY = 0 或 FMODE = 11(内存映射模式)时,忽略写入该字段在双闪存模式下,由于地址终为偶地址,ADDRESS[0] 自动保持为“0” */  ​ +  
-  ​uint32_t AlternateBytes; ​    /​* ​在地址后立即发送到外部 SPI 设备可选数据,仅可在 BUSY = 0 时修改该字段。*  +    return SDRAM_ERROR;​ 
-  ​uint32_t AddressSize       /* 定义地址长度,可以是8位,16位,24位或者32位 */   +  ​
-uint32_t AlternateBytesSize;​ /* 定义交替字节长度,可以是8位,16位,24位或者32位 */   +  else 
-  ​uint32_t DummyCycles       /* 定义空指令阶段持续时间,在 SDR 和 DDR 模式下,它定 CLK 周期数 (0-31*  +  { 
-  ​uint32_t InstructionMode   /* 定义指令阶段的操作模式,00:无指令;01:单线传输指令;10:双线传输指令;11:四线传输指令*/   +    return SDRAM_OK; 
-  ​uint32_t AddressMode; ​       ​/* 定义地址阶段的操作模式,00:无地址;01:单线传输地址;10:双线传输地址;11:四线传输地址*/   +  } 
-  ​uint32_t AlternateByteMode;  ​/* 定义交替字节阶段的操作模式00:无交替字节;01:单线传输交替字节;10:双线传输交替字节;11:四线传输交替字节 */   +
-  ​uint32_t DataMode          /* 定义数据阶段的操作模式,00:无数据;01:单线传输数据;10:双线传输数据;11:四线传输数据。该字段还定义空指令阶段的操作模式 */   +</code>  
-  ​uint32_t NbData            /* 设置数据长度,在间接模式和状态轮询模式下待检索的数据数量(值 + 1)。对状态轮询模式应使用不大于 3 的值(表示 4 字节)*/ ​  +功能介绍:在轮询模式大量数据写入 ​SDRAM 存储器 
-  ​uint32_t DdrMode           /* 为地址、交替字节和数据阶段设置 DDR 模式,0:禁止 DDR 模式;1:使能 DDR 模式 */   +uwStartAddress:写入起始地址 
-  ​uint32_t DdrHoldHalfCycle; ​  /* 设置DDR 模式下数据输出延迟 1/4 个 QUADSPI 输出钟周期,0:使用模拟延迟来延迟数据输出;1:数据输出延迟 1/4 个 QUADSPI 输出时钟周期。仅在 DDR 模式下激活*/   +pData:写入数据的指针。 
-  ​uint32_t SIOOMode          /* 设置仅发送指令一次模式,IMODE ​00 时,该位不起作用。0:在每个事务中发送指令;1:仅为第一条命令发送指令 */   +uwDataSize:向存储器写入的数据大小 
-}QSPI_CommandTypeDef;   +<code c> 
 +uint8_t BSP_SDRAM_Sendcmd(FMC_SDRAM_CommandTypeDef ​*SdramCmd) 
 +
 +  if(HAL_SDRAM_SendCommand(&​sdramHandle,​ SdramCmd, SDRAM_TIMEOUT) != HAL_OK) 
 +  ​
 +    return SDRAM_ERROR; 
 +  } 
 +  ​else 
 +  ​
 +    return SDRAM_OK; 
 +  } 
 +
 +</code>  
 +功能介绍:向 SDRAM bank 发送命令。 
 +SdramCmd:向 SDRAM 命结构的指针 
 +=== 4.FMC初始化函数 === 
 +<code c> 
 +void MX_FMC_Init(void) 
 +//​本实验中我们只用到了 FMC 的引脚,时序配置使用官方提供的 SDRAM 驱动 
 +  ​FMC_SDRAM_TimingTypeDef SdramTiming = {0}; 
 +  ​/* 执行 SDRAM1 存储器初始化序列 ​*/ 
 +  hsdram1.Instance = FMC_SDRAM_DEVICE;​ 
 +  /* hsdram1 初始化 ​*/ 
 +  hsdram1.Init.SDBank = FMC_SDRAM_BANK1;​ 
 +  ​hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_8; 
 +  hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;​ 
 +  hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;​ 
 +  ​hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; 
 +  hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_1;​ 
 +  ​hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; 
 +  hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_DISABLE;​ 
 +  ​hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE; 
 +  hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;​ 
 +  /* Sdram 序 */ 
 +  SdramTiming.LoadToActiveDelay = 16; 
 +  ​SdramTiming.ExitSelfRefreshDelay = 16; 
 +  SdramTiming.SelfRefreshTime ​16; 
 +  SdramTiming.RowCycleDelay = 16; 
 +  ​SdramTiming.WriteRecoveryTime = 16; 
 +  SdramTiming.RPDelay = 16; 
 +  ​SdramTiming.RCDDelay = 16; 
 +  if (HAL_SDRAM_Init(&​hsdram1,​ &​SdramTiming) != HAL_OK) 
 +  { 
 +    Error_Handler( ); 
 +  } 
 +}
 </​code> ​ </​code> ​
 +
 ==== 五、 实验步骤 ==== ==== 五、 实验步骤 ====
  
行 324: 行 300:
   - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。   - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。
 ==== 六、 实验现象 ==== ==== 六、 实验现象 ====
-读写测试成功,在终端显示出“FLASH TEST OK!”。测试失败,在终端显示“FLASH ERROR!” +SDRAM 读写测试成功,LED 常亮,并在终端显示出“SDRAM TEST OK!”。测试失败 ​LED 灯闪烁在终端显示“SDRAM ERROR!” 
-{{ :icore4tx:icore4tx_arm_hal_13_2.png?direct |}}+{{ :icore4tx:icore4tx_arm_hal_14_7.png?direct |}}
  
icore4tx_14.1595921342.txt.gz · 最后更改: 2020/07/28 15:29 由 fmj