用户工具

站点工具


sdram实验_读写sdram

差别

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

到此差别页面的链接

后一修订版
前一修订版
sdram实验_读写sdram [2019/12/21 11:20]
zhangzheng 创建
sdram实验_读写sdram [2022/03/22 10:26] (当前版本)
sean
行 1: 行 1:
-[[http://www.cnblogs.com/xiaomagee/p/7614102.html]]+|  **银杏科技有限公司旗下技术文档发布平台** ​ |||| 
 +|技术支持电话|**0379-69926675-801**||| 
 +|技术支持邮件|Gingko@vip.163.com||| 
 +^  版本 ​ ^  日期 ​ ^  作者 ​ ^  修改内容 ​ ^ 
 +|  V1.0  |  2020-07-12 ​ |  gingko ​ |  初次建立 ​ |  
 + 
 +===== 实验三十七:SDRAM实验——读写SDRAM ===== 
 + 
 +==== 一、 实验目的与意义 ==== 
 + 
 +  - 了解STM32 SDRAM结构。 
 +  - 了解STM32 SDRAM特征。 
 +  - 掌握SDRAM的使用方法。 
 +  - 掌握STM32 HAL库中SDRAM属性的配置方法。 
 +  - 掌握KEILMDK 集成开发环境使用方法。 
 +==== 二、 实验设备及平台 ==== 
 + 
 +  - iCore4 双核心板[[https://item.taobao.com/item.htm?​spm=a1z10.1-c-s.w4004-22598974120.15.5923532fsFrHiE&​id=551864196684|点击购买]]。 
 +  - JLINK(或相同功能)仿真器[[https:​//item.taobao.com/​item.htm?​id=554869837940|点击购买]]。 
 +  - Micro USB线缆。 
 +  - Keil MDK 开发平台。 
 +  - STM32CubeMX开发平台。 
 +  - 装有WIN XP(及更高版本)系统的计算机。 
 +==== 三、 实验原理 ==== 
 + 
 +=== 1、SDRAM简介 === 
 + 
 +  * SDRAM,英文名是:Synchronous Dynamic Random Access Memory,即同步动态随机存储器,相较于SRAM(静态存储器),SDRAM具有:容量大和价格便宜的特点。STM32F767支持SDRAM,因此,我们可以外挂SDRAM,从而大大降低外扩内存的成本。 
 +  * 同步动态随机存取内存(SDRAM)是有一个同步接口的动态随机存取内存(DRAM)。通常DRAM是有一个异步接口的,这样它可以随时响应控制输入的变化。而SDRAM有一个同步接口,在响应控制输入前会等待一个时钟信号,这样就能和计算机的系统总线同步。时钟被用来驱动一个有限状态机,对进入的指令进行管线(Pipeline)操作。这使得SDRAM与没有同步接口的异DRAM(asynchronous DRAM)相比,可以有一个更复杂的操作模式。管线意味着芯片可以在处理完之前的指令前,接受一个新的指令。在一个写入的管线中,写入命令在另一个指令执行完之后可以立刻执行,而不需要等待数据写入存储队列的时间。在一个读取的流水线中,需要的数据在读取指令发出之后固定数量的时钟频率后到达,而这个等待的过程可以发出其它附加指令。 
 +  * SDRAM是多Bank结构,例如在一个具有两个Bank的SDRAM的模组中,其中一个Bank在进行预充电期间,另一个Bank却马上可以被读取,这样当进行一次读取后,又马上去读取已经预充电Bank的数据时,就无需等待而是可以直接读取了,这也就大大提高了存储器的访问速度。为了实现这个功能,SDRAM需要增加对多个Bank的管理,实现控制其中的Bank进行预充电。在一个具有2个以上Bank的SDRAM中,一般会多一根叫做BAn的引脚,用来实现在多个Bank之间的选择。 
 +  * SDRAM具有多种工作模式,内部操作是一个复杂的状态机。SDRAM器件的引脚分为以下几类。 
 +    * (1)控制信号:包括片选、时钟、时钟使能、行列地址选择、读写有效及数据有效。 
 +    * (2)地址信号:时分复用引脚,根据行列地址选择引脚,控制输入的地址为行地址或列地址。 
 +    * (3)数据信号:双向引脚,受数据有效控制。 
 +  * SDRAM的所有操作都同步于时钟。根据时钟上升沿控制管脚和地址输入的状态,可以产生多种输入命令:​ 
 +    * 模式寄存器设置命令 
 +    * 激活命令 
 +    * 预充命令 
 +    * 读命令 
 +    * 写命令 
 +    * 带预充的读命令 
 +    * 带预充的写命令 
 +    * 自动刷新命令 
 +    * 自我刷新命令 
 +    * 突发停命令 
 +    * 空操作命令 
 +  * 根据输入命令,SDRAM状态在内部状态间转移。内部状态包括模式寄存器设置状态、激活状态、预充状态、写状态、读状态、预充读状态、预充写状态、自动刷新状态及自我刷新状态。 
 +  * SDRAM支持的操作命令有初始化配置、预充电、行激活、读操作、写操作、自动刷新、自刷新等。所有的操作命令通过控制线CS#​、RAS#​、CAS#​、WE#​和地址线、体选地址BA输入。 
 +=== 2、SDRAM信号线 === 
 + 
 +  * SDRAM的信号线如图所示: 
 +{{ :​icore4:​icore4_arm_hal_37_1.png?​direct&​750 |}}  
 +=== 3、SDRAM存储单元 === 
 + 
 +  * SDRAM的存储单元(称之为:BANK)是以阵列的形式排列的,每个存储单元的结构示意图,如图所示: 
 +{{ :​icore4:​icore4_arm_hal_37_2.png?​direct&​600 |}}   
 +  * 对于这个存储阵列,我们可以将其看成是一个表格,只需要给定行地址和列地址,就可以确定其唯一位置,这就是SDRAM寻址的基本原理。而一个SDRAM芯片内部,一般又有4个这样的存储单元(BANK),所以,在SDRAM内部寻址的时候,先指定BANK号和行地址,然后再指定列地址,就可以查找到目标地址。 
 +  * SDRAM的存储结构示意图,如图下所示,寻址的时候,首先RAS信号为低电平,选通行地址,地址线A0~A12所表示的地址,会被传输并锁存到行地址译码器里面,最为行地址,同时BANK地址线上面的BS0,BS1所表示的BANK地址,也会被锁存,选中对应的BANK,然后,CAS信号为低电平,选通列地址,地址线A0~A12所表示的地址,会被传输并锁存到列地址译码器里面,作为列地址,这样,就完成了一次寻址。 
 +{{ :​icore4:​icore4_arm_hal_37_3.png?​direct |}}   
 +=== 4、数据传输 === 
 + 
 +  * 在完成寻址以后,数据线DQ0~DQ15上面的数据会通过数据控制逻辑写入(或读出)存储阵列。特别注意:因为SDRAM的位宽,可以达到32位,也就是最多有32条数据线,在实际使用的时候,我们可能会以:8位、16位、24位和32位等宽度来读写数据,这样的话,并不是每条数据线,都会被使用到,未被用到的数据线上面的数据,必须被忽略,这个时候就需要用到数据掩码(DQM)线来控制了,每一个数据掩码线,对应8个位的数据,低电平表示对应数据位有效,高电平表示对应数据位无效。 
 +  * SDRAM的驱动需要用到一些命令,常用的命令如图所示: 
 +{{ :​icore4:​icore4_arm_hal_37_4.png?​direct |}}  
 +=== 5、原理图 === 
 +{{ :​icore4:​icore4_arm_hal_37_5.png?​direct |}}  
 +==== 四、 实验程序 ==== 
 + 
 +=== 1、主函数 === 
 +<code c> 
 +int main(void) 
 +
 +  int i,j; 
 +  /* MCU 配置*/ 
 +  /* 重置所有外设,​ 初始化Flash 接口和Systick. */ 
 +  HAL_Init();​ 
 +  /* 系统时钟配置 */ 
 +  SystemClock_Config();​ 
 +  /* 初始化所有已配置的外设 */ 
 +  MX_GPIO_Init();​ 
 +    //​SDRAM初始化 
 +  BSP_SDRAM_Init(); ​       
 +  LED_BLUE_ON;​ 
 +  //​向SDRAM中写入0x5555并读取校验 
 +  for(i = 0;i < SDRAM_SIZE;​i++){  
 +      write_sdram(i,​0x5555);​ 
 +    } 
 +    for(i = 0;i < SDRAM_SIZE;​i++){ 
 +        if(0x5555 != read_sdram(i)){ 
 +            while(1){ 
 +                LED_RED_ON;​ 
 +                HAL_Delay(500);​ 
 +                LED_RED_OFF;​ 
 +                HAL_Delay(500);​ 
 +            } 
 +        } 
 +    } 
 +    //​向SDRAM中写入0xAAAA并读取校验 
 +    for(i = 0;i < SDRAM_SIZE;​i++){  
 +        write_sdram(i,​0xAAAA);​ 
 +    } 
 +    for(i = 0;i < SDRAM_SIZE;​i++){ 
 +        if(0xAAAA != read_sdram(i)){ 
 +            while(1){ 
 +                LED_RED_ON;​ 
 +                HAL_Delay(500);​ 
 +                LED_RED_OFF;​ 
 +                HAL_Delay(500);​ 
 +            } 
 +        } 
 +    }    
 +    //​向SDRAM中写入0x0000~0xFFFF并读取校验 
 +    for(j = 0; j < 256; j++){ 
 +        for(i = 0;i < 65536;​i++){ 
 +            write_sdram((65536 * j + i),i); 
 +        } 
 +    } 
 +    for(j = 0; j < 256; j ++){ 
 +        for(i = 0;i < 65536;​i++){ 
 +            if(i != read_sdram((65536 * j + i))){ 
 +                while(1){ 
 +                    LED_RED_ON;​ 
 +                    HAL_Delay(500);​ 
 +                    LED_RED_OFF;​ 
 +                    HAL_Delay(500);​ 
 +                } 
 +            } 
 +        } 
 +    }    
 + 
 +    //​测试成功 
 +    LED_BLUE_OFF;​ 
 +    LED_GREEN_ON;​ 
 +  while (1) 
 +  { 
 +  } 
 +
 + 
 +</​code>​ 
 +=== 2、SDRAM初始化 === 
 +<code c> 
 +uint8_t BSP_SDRAM_Init(void) 
 +{  
 +  static uint8_t sdramstatus = SDRAM_ERROR;​ 
 +  /* SDRAM设备配置 */ 
 +  /* SDRAM时钟频率为100Mhz的定时配置(系统时钟最高为200Mhz) */ 
 +  Timing.LoadToActiveDelay ​   = 2; 
 +  Timing.ExitSelfRefreshDelay = 7; 
 +  Timing.SelfRefreshTime ​     = 4; 
 +  Timing.RowCycleDelay ​       = 7; 
 +  Timing.WriteRecoveryTime ​   = 2; 
 +  Timing.RPDelay ​             = 2; 
 +  Timing.RCDDelay ​            = 2; 
 +   
 +  sdramHandle.Init.SDBank ​            = FMC_SDRAM_BANK1;​ 
 +  sdramHandle.Init.ColumnBitsNumber ​  = FMC_SDRAM_COLUMN_BITS_NUM_9;​ 
 +  sdramHandle.Init.RowBitsNumber ​     = FMC_SDRAM_ROW_BITS_NUM_13;​ 
 +  sdramHandle.Init.MemoryDataWidth ​   = SDRAM_MEMORY_WIDTH;​ 
 +  sdramHandle.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;​ 
 +  sdramHandle.Init.CASLatency ​        = FMC_SDRAM_CAS_LATENCY_3;​ 
 +  sdramHandle.Init.WriteProtection ​   = FMC_SDRAM_WRITE_PROTECTION_DISABLE;​ 
 +  sdramHandle.Init.SDClockPeriod ​     = SDCLOCK_PERIOD;​ 
 +  sdramHandle.Init.ReadBurst ​         = FMC_SDRAM_RBURST_ENABLE;​ 
 +  sdramHandle.Init.ReadPipeDelay ​     = FMC_SDRAM_RPIPE_DELAY_1;​ 
 +  /* SDRAM控制器初始化 */ 
 +  BSP_SDRAM_MspInit(&​sdramHandle,​ NULL); /* __weak函数可以被应用程序重写*/​ 
 +  if(HAL_SDRAM_Init(&​sdramHandle,​ &​Timing) != HAL_OK) 
 +  { 
 +    sdramstatus = SDRAM_ERROR;​ 
 +  } 
 +  else 
 +  { 
 +    sdramstatus = SDRAM_OK; 
 +  } 
 +  /* SDRAM初始化顺序 */ 
 +  BSP_SDRAM_Initialization_sequence(REFRESH_COUNT);​ 
 +  return sdramstatus;​ 
 +
 +  
 +  
 +</​code>​ 
 +=== 3、SDRAM读写函数 === 
 +<code c> 
 +#define SDRAM_SIZE SDRAM_DEVICE_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)) 
 + 
 +</​code>​ 
 +==== 五、 实验步骤 ==== 
 + 
 +  - 把仿真器与iCore4的SWD调试口相连(直接相连或者通过转接器相连); 
 +  - 把iCore4通过Micro USB线与计算机相连,为iCore4供电; 
 +  - 打开Keil MDK 开发环境,并打开本实验工程; 
 +  - 烧写程序到iCore4上; 
 +  - 也可以进入Debug模式,单步运行或设置断点验证程序逻辑。 
 +==== 六、 实验现象 ==== 
 + 
 +  * 上电即开始读写SDRAM测试,测试过程中,蓝色LED点亮,如果出现错误,红色LED闪烁,测试成功,绿色LED点亮。 
sdram实验_读写sdram.1576898456.txt.gz · 最后更改: 2019/12/21 11:20 由 zhangzheng