SDRAM控制器

简介: 笔记

1.SDRAM简介


简介:SDRAM为同步动态随机存储内存,同步指的是时钟与外部输入的时钟保持一致,也就是与外部共用一个时钟;动态指的是每个时间段内,都要进行一次刷新操作,否则里面的数据会丢失,这也是由存储特性决定的;随机指的是数据存储地址可由我们自己任意指定。

bank与地址: 在SDRAM中,有多个bank,每个bank都有自己的行列地址,相互独立,在读写的时候,我们需要指定那个bank的那行,那列进行读写,其中行列地址线是共用的,下面会具体的说明

命令:我认为SDRAM是响应式的,对任何SDRAM的操作都要给出对应的命令,否则是无法得到想要的结果的。

数据: SDRAM输入输出的数据线是共用的

本文章使用的SDRAM是黑金AX4010上的


2. SDRAM的操作流程


上电延时,然后初始化

进入仲裁状态机,优先执行刷新请求,读写请求的优先级可自行决定

ps:是不是感觉挺简单的٩(๑>◡<๑)۶


3. SDRAM 初始化


找到说明文档,查阅初始化时序图

2.png


CKE为SDRAM使能线,在整个运行过程中,一直为高即可


COMMAND,command是由4根线共同组成的,分别是:CS,RAS,CAS,WE,在手册的可以方便的找到不同的命令,其4根线上高低电平分别是怎样的


DQM为掩码,设置dqm的值,在读写sdram时,可以只对数据的高八位或者低八位或者十六位都感兴趣,一般一直设为00,即十六位都感兴趣


A 为行列地址线,row地址时,A全部有效,col地址时,其第九位有效


BA 为bank,指定对那个bank进行操作


DQ: 为sdram的数据线


从时序图可以看到,上电后,我们需要延时最少100us,然后给个NOP命令,一般为了稳定,都会延时200us;在NOP命令后,然后再给PRECHARGE(预充电)命令,此时需要指定bank,如果A10为高的话,就是对所有的bank,如果A10为低的话,就按照BA指定的来,一般设置A10为高,后面的一些延时和对应的命令按照时序图来即可


直接来到LOAD Mode Register这个命令,此时需要指定A的值,不同的A值,在后面对SDMRA的操作会不同,阅读手册可知


A0,A1,A2:控制突发长度,给一个读写命令,我可以连续读写多少个数据,我设置的是000,突发长度为1,我认为这样便于书写程序


A3: 读写是连续的,还是随机的,仅对突发长度不为1时有效;读写的需要给定地址,也就是说写入的第一个数据的地址是以给定的,如果突发长度不为1的话,后面的数据的地址是在给定地址的基础上依次加一,还是说是随机的。


A4,A5,A6:仅对读数据有效,给了读命令后,在接下来的几个周期内,数据才会出来,俗称潜伏期


其他位就不作介绍了,都为0即可,


至此SDRAM的初始化就完成了

3.png

4. SDRAM的写


老规矩,先查阅手册,找到时序图,可惜没有我想要的完整的,那分开吧,

激活命令,激活对应的row地址和bank

延时两个周期

写命令,指定对应的col行地址和数据(A10最好为0,不然给一个命令后,又得给激活命令,重复1,2步骤)

如果想继续写,写数据达到突发长度后,然后继续再给一个写命令和新的col地址

如果不想写了,写数据达到突发长度后,给一个PRECHARGE命令,然后就写完成了。

ps : 此步骤只是写SDRAM的一种,我认为是最简单,也是比较高效的一种

可以参考下面的写时序,与我说的,只是A10给定的值不同,可以看出,如果A10给1了的话,它会自动进行一个PRECHARGE操作,而为0的话,则需要我们自己给定,以结束这次的写操作。

4.png

5. SDRAM读和刷新


SDRAM的读与SDRAM的写基本上一样,同样刷新操作更简单,大家可以按照读时序图自己琢磨,下面给出对应的时序图

5.png6.png

6. 注意事项


1. 读写的时候,A10的值是非常值得关注的。
2. 读时,何时接收数据;写时,何时获取数据。
3. 仲裁模块的书写,确保读写数据后,没有超过刷新周期,这里可以用读写速度换取稳定性


7. 异步FIFO


最后来介绍一下异步FIFO的实现,我们都知道FIFO是一种先进先出的一种结构,可以说是很简单的,但是设计起来还是有点难度的,难点如下


1. 由于使用的是同一块内存,如何做到读与写如何不冲突
2. 如何判断是否写满了,以及是否为空
3. 如何计算FIFO里面读写的数据量


接下来,我还是结合代码来说明吧


1. 读写

curr表示当前读写的地址,next表示下一次的读写地址只需要合理地对next地址进行更新即可做到合理性


reg[8:0]  curr_read_ptr,next_read_ptr;    //读指针
reg[8:0]  curr_write_ptr,next_write_ptr;    //写指针


对读地址进行更新,可以看到,只要不为空的时候,我们就可以一直更新next读地址的值,同样,只要没有写满的时候,就可以一直更新next写地址的值。


always@(posedge rclk or negedge rst)
begin
  if(rst == 1'b0)
  next_read_ptr <= 'd1;
  else if(r_en == 1'b1)
  if(r_empty == 1'b0)
    if(next_read_ptr == 'd511)
    next_read_ptr <= 'd0;
    else
    next_read_ptr <= next_read_ptr + 1'b1;
  else
    next_read_ptr <= next_read_ptr;
  else
  next_read_ptr <= next_read_ptr;
end


2. 判断是否为空和满

满和空其实很好判断,只要当下一个写的地址等于当前读的地址,即可判断为满,

空也是如此,当下一个读的地址等于当前写的地址,即为空,还要考虑初始情况,next_read等于next_write的时候也是为空的


assign  w_full  = (next_write_ptr == curr_read_ptr ) ? 1'b1 : 1'b0; 
assign  r_empty = ( next_read_ptr == curr_write_ptr || (next_read_ptr == next_write_ptr)) ? 1'b1 : 1'b0;


3. 计算FIFO里面的数据量

FIFO里面的数据量其实读写地址的差值,但是当写的地址在读的地址后面的时候,又不仅仅是差值了,而是数据总长度减去这个差值了。


always@(posedge rclk or negedge rst)
begin
  if(rst == 1'b0)
  data_count <= 'd0;
  else if(curr_read_ptr >= curr_write_ptr && next_read_ptr != next_write_ptr)
  data_count <= 'd511 - curr_read_ptr + curr_write_ptr;
  else
  data_count <= curr_write_ptr - curr_read_ptr;
end


最后给出我自己实现的SDRAM_FIFO控制器,其中包括sdram_pluse仿真模块,以及testbench;FIFO没有调用IP核,利用SDRAM和FIFO将sdram封装成一个可以方便实用的异步sdram_fifo.

欢迎大家下载学习,写的很通俗易懂。下载地址.


公众号:FPGA之旅


目录
相关文章
|
2月前
|
测试技术 Perl
【ZYNQ】ZYNQ7000 UART 控制器及驱动应用示例
【ZYNQ】ZYNQ7000 UART 控制器及驱动应用示例
HIMA-H4135 992413502模块控制器处理器驱动器
HIMA-H4135 992413502模块控制器处理器驱动器
|
2月前
|
芯片 索引
可编程中断控制器
可编程中断控制器
164 0
|
10月前
|
Linux 索引
RISC-V SiFive U54内核——CLINT中断控制器
RISC-V SiFive U54内核——CLINT中断控制器
|
11月前
|
异构计算 SoC 内存技术
深入理解AMBA总线(九)AHB2SRAM设计
深入理解AMBA总线(九)AHB2SRAM设计
452 0
|
12月前
|
Linux 索引
中断控制器(GIC)(上)
中断控制器(GIC)
353 0
|
12月前
|
Linux
中断控制器(GIC)(下)
中断控制器(GIC)(下)
135 0
Linux驱动分析之SPI控制器
之前对SPI驱动的整体架构做了介绍,现在来分析具体的驱动程序。之前说过,SPI驱动分为设备驱动和控制器驱动。先来分析控制器驱动。我们以RockChip的控制器来作为分析。
UART子系统(一)初识
UART子系统(一)初识
125 0
UART子系统(一)初识

热门文章

最新文章

  • 1
    流量控制系统,用正则表达式提取汉字
    25
  • 2
    Redis09-----List类型,有序,元素可以重复,插入和删除快,查询速度一般,一般保存一些有顺序的数据,如朋友圈点赞列表,评论列表等,LPUSH user 1 2 3可以一个一个推
    26
  • 3
    Redis08命令-Hash类型,也叫散列,其中value是一个无序字典,类似于java的HashMap结构,Hash结构可以将对象中的每个字段独立存储,可以针对每字段做CRUD
    25
  • 4
    Redis07命令-String类型字符串,不管是哪种格式,底层都是字节数组形式存储的,最大空间不超过512m,SET添加,MSET批量添加,INCRBY age 2可以,MSET,INCRSETEX
    27
  • 5
    S外部函数可以访问函数内部的变量的闭包-闭包最简单的用不了,闭包是内层函数+外层函数的变量,简称为函数套函数,外部函数可以访问函数内部的变量,存在函数套函数
    23
  • 6
    Redis06-Redis常用的命令,模糊的搜索查询往往会对服务器产生很大的压力,MSET k1 v1 k2 v2 k3 v3 添加,DEL是删除的意思,EXISTS age 可以用来查询是否有存在1
    30
  • 7
    Redis05数据结构介绍,数据结构介绍,官方网站中看到
    21
  • 8
    JS字符串数据类型转换,字符串如何转成变量,+号只要有一个是字符串,就会把另外一个转成字符串,- * / 都会把数据转成数字类型,数字型控制台是蓝色,字符型控制台是黑色,
    19
  • 9
    JS数组操作---删除,arr.pop()方法从数组中删除最后一个元素,并返回该元素的值,arr.shift() 删除第一个值,arr.splice()方法,删除指定元素,arr.splice,从第一
    19
  • 10
    定义好变量,${age}模版字符串,对象可以放null,检验数据类型console.log(typeof str)
    19