Using DDR2 as a big FIFO - Page 1
Forum section: electronics / general

author: voltsandjolts
author_rank: Unknown
timestamp: March 12, 2021, 06:07:45 pm
content: I have done some basic FPGA stuff but attempting to go up a gear and use a DDR2 SDRAM on an existing board I have.I want to use the SDRAM as a big FIFO.Writing and reading will only use the max burst size of 16 bytes.Writing and reading will be done at different times, i.e. write say 64MB then sometime later read back that data.There are 8 banks on the device I have.I'm wondering what is the best strategy for the contoller and what (if any) simplifications the above requirements allow.Would writing the first page in each bank, then the second page in each bank and so on be a reasonable approach, rather than filling up one bank at a time?Any thoughts?

author: asmi
author_rank: Super Contributor
timestamp: March 12, 2021, 08:52:21 pm
content: If your controller is smart enough to take advantage of DDR2's request pipelining capability, you can do consecutive reads and writes with no breaks between them (see attachment for example, taken from Micron's DDR2 datasheet). You will still have to close rows for refresh and reopen them after refresh is completed, but if your application's accesses are sequential (and it sounds like they are), open/close will only need to happen once between consecutive refreshes. Also since refresh time is not a hard wall, you can adjust refresh intervals to align them with page boundaries (there is no harm is sending refreshes more often that you need to - there is only an upper bound), and this way you will be opening a new row after every refresh - this might make design simpler because you won't have to keep track of time after last refresh separately and handle breaks in the flow when the time will come to issue a refresh.And this is why a specialized controller optimized for your design's access patterns, can be significantly more efficient at bandwidth utilization that a generic one-size-fits-all one, while simultaneously consuming significantly less logic resources.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 13, 2021, 05:17:35 pm
content: It takes time to activate a row and it takes time to deactivate (precharge) it. If you want an efficient algorithm, you need to make sure that while you're activating/precharging rows in one bank, you read/write data in the other bank.To achieve this, the best way is to rotate banks - you read a chunk of memory (16 bytes may be too small, so you may need to increase the size) from bank 0. While you're doing this, bank 1 is activating. The next access will be to bank 1. During this access, bank 0 is precharging while bank 2 is activating. And so on.

author: BrianHG
author_rank: Super Contributor
timestamp: March 13, 2021, 11:10:39 pm
content: Even with the efficient bank rotation, there is a small penalty, even within the same bank, for goring from read to write of 1-2CLK, while there is a huge one going from a write to a read. Your best bet is to make the DDR2 2x-3x as fast as you need with simple smart bank management, setting up that smaller internal FPGA FIFO to smooth out those breaks.Another solution is if your FIFO always has a huge difference between in and out, you may choose the position of your banking so that you are always reading from a set of banks while writing in another. Hence, 2 important wildly different sections of rows activated at the same time.Refresh will always kick you in the ass as you must -precharge all banks- first, then refresh, then back to the activate row...

author: NorthGuy
author_rank: Super Contributor
timestamp: March 14, 2021, 01:02:52 am
content: Quote from: BrianHG on March 13, 2021, 11:10:39 pmThis is largely irrelevant since the OP doesn't need switching direction often:Quote from: voltsandjolts on March 12, 2021, 06:07:45 pmQuote from: BrianHG on March 13, 2021, 11:10:39 pmYou can avoid automatic refresh, which is done for all banks simultaneously, and do your own refresh only the bank(s) which is currently unused. All you need to do is to make sure than each row of every bank is activated at least once every 64 ms. This is not very hard to do.

author: voltsandjolts
author_rank: Unknown
timestamp: March 14, 2021, 10:33:30 am
content: Thanks to all for the input, very helpful.Essentially I want to write data into the 'FIFO' quite fast, say 200MBytes/sec, or whatever I can get.Once writing has completed, I just need a leisurely read to transfer to PC for analysis.So, the time to switch between write and read is not important.Also, read speed is not important.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 14, 2021, 12:50:55 pm
content: Quote from: voltsandjolts on March 14, 2021, 10:33:30 am8-bit chip running at minimum 200 MHz speed will give you 400 MBytes/sec, or 1 GBytes/sec at 500 MHz. Or you can take a 16-bit chip which will go up to 2 GBytes/sec.So, you're already in the situation which BrianHG suggested - the memory bandwidth is several times higher than your needs.

author: BrianHG
author_rank: Super Contributor
timestamp: March 15, 2021, 12:29:19 am
content: Go for 16bit, 200MHz. Makes timing easier to achieve on the IOs of even poor designs.

author: voltsandjolts
author_rank: Unknown
timestamp: March 15, 2021, 10:06:16 am
content: OK 200MHz 16bit it is, drinks on me if I get any faster.The PCB has no trace length matching, so may have to wind it back, we'll see.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 15, 2021, 02:48:32 pm
content: Quote from: voltsandjolts on March 14, 2021, 10:33:30 amThis is one of the best scenarios then! You don't need interleaved reads and writes, and you'll only access consecutive addresses.200 MBytes/s in both directions should be pretty straightforward to get without anything sophisticated. A basic controller will do!With a 16-bit data bus in DDR mode, that's a mere 50 MHz. Now account for some controller overhead, but with your DDR2 memory clocked at 100 MHz, you should have no problem whatsoever, and that's still a frequency low enough that signal integrity shouldn't be a big problem and you could use a pretty modest FPGA.

author: mattselectronics
author_rank: Contributor
timestamp: March 15, 2021, 02:52:39 pm
content: I would recommend to add decently sized FIFOs in FPGA memory blocks (M10K for Cyclone V for example) at the input and the output of your FIFO.You can then write a statemachine that starts a read or write burst according to the fill-level of the in and out FIFO.You could even add a bypass to the DDR memory, if there is not much data to be stored to reduce latency.

author: technix
author_rank: Super Contributor
timestamp: April 30, 2021, 06:39:02 am
content: I'd propose an out-of-the-box idea: get rid of the big FIFO entirely and switch to some fast I/O standards that can carry all your data as it is being generated. What I mean is PCIe and USB 3.0. USB 3.0 has 5Gb/s or around 500MB/s after overhead. PCIe 2.0 x4 can do more than 1GB/s.PCIe can even do bus mastering, which allows your FPGA to commandeer host DDR4 memory.