Build a DRAM "controller"

I know the subject of DRAM has been discussed here in the past and I know that for the smaller arduinos, it can be considered rather silly. However my interrest in DRAM and building a DRAM Controller, extends beyond the sensible.

I have been working with some older DRAM modules, specifially the M5M44256BP and a stock Arduino Uno. Its been no easy task mastering it, but Ive got it working – reading, writing and refreshing the memory. Ive also build a small circuit to combine several DRAM modules, with CS choosing the module I wish to access.

My aim would be to end with a small PCB with 2 or more DRAM modules, controlled by a single Arduino Uno (standalone chip is the goal), which controls the DRAM. Its not a very viable or even easy solution and will most likely be slow to interface with – however its a challenge, and I would like to try and build it.

I have some concerns regarding the refresh of several bytes DRAMs – I am currently handling it with interrupts in the arduino, which I enable/disable when read/write is necessary. However I am concerned that with several modules this would start to consume too much time. I have considered chip-enabling all DRAMs at once during refresh, but I suspect this might end up being simply voltage-divider, with no effect.

On the receiving end of the arduino, I am also puzzled how I am to buffer the incoming traffic, if a refresh is currently taking place, and input data start pilling up.

I am looking for pointers, as well as maybe working examples and/or semi-tech documents describing the way to go. I am aware the risk that Arduino is simply underpowered for this – and I am also very well aware, that it is not –a sane project-. But its fun :relaxed:

Any input is appreciated.

My memory - possibly faulty - tells me that it's traditional to refresh a row of all the DRAM's at once, so that it's only necessary for the controller to cycle through all the rows only once every 64 milliseconds or so. I remember that the addres went on the bus, the Row Address Strobe was asserted, and the Column Address Strobe (CAS) stayed inactive. With CAS off, the data bus was tri-stated, and nothing drove the data bus.

I can't find a datasheet for the gizmos you mention, but I'd be surprised ithey don't do something like that. If they don't, then a system with a lot of memory would be bogged down with refreshing, and it would be difficult for a customer to use a lot of the product. No manufacturer wants to make it hard for you to buy their stuff.

Hi tmd3,

The refreshing of the DRAM is not a problem - the problem I am facing is how to contruct the controller itself. which handles 2 or more DRAM blocks. Specifically the communication to and from the Controller and the CPU (MCU).

Best regards,

Can you describe your vision of how this device will work?

I can't locate a datasheet for the devices you mention. Can you post one, or post a link?

Hi TMD,

Thanks for your replies (and, sorry for my late reply).

The datasheet for the M5M4425BP is available here: http://www.bg-electronics.de/datenblaetter/Schaltkreise/M5M44256B.pdf

My idea of this device would be to have a ready-made plugin for another project. My end goal would be to have a device that takes a mix of parallel and seriel input (or mux/demux and/or SPI), a total of 11+4 signals. The first 11 of these go to the arduino; 1-2 selects DRAM block (1..4), 3-11 is for the DRAM address (9 pins). Depending of selected DRAM, CS+WE/W is set for the correct block. Address is then written to pin; and the remaining 4 datawires go directly to the selected DRAM. The same goes for reading - just reversed direction of I/O.

My problem arrises with timing. DRAM has to be refreshed a number of times every second. The more blocks, the more refresh. The DRAM is fast enough, however the Arduino isn't. Here comes my problem;

  1. if I chipselect all the DRAM; and hit all the addresses at once, I should save the most time refreshing the DRAM. However, this will (likely) be a giant voltage divider - i presume ?

  2. If i chipselect one DRAM at a time, i fear for speed. Also I fear, that any "smart solution" i make (only reserve the block being refreshed, not all four) will ultimately fail due to .. well, just - fail :slight_smile:

  3. if this device receives input while refreshing, the input will most likely be lost - or I would need some slow sync mechanism. Would would be the most prudent way to go about such possible sync problems?

In essence, the project is somewhat of a RAM-Controller. The final PCB i vision will have just the Atmega on it, some replaceable ram blocks, and a load of traces to a flat-cable-connector.

Just to re-iterate:

The M5M44256BP has 9bit x 9bit row/column. By addressing only the rows, we can refresh all the data in the columns. We can put this into an interrupt on the AtMega, every 64ms (retention time).

Now, the interrupt will look something like this (pseudocode)

for (i=0;i<2^9;i++)
setpins 0…8 to binary value i

since we are working with more than 8 bits, in fact its;

for(highbit=0;highbit<2;highbit++)
set pin 8 = highbit
for (i=0;i<256;i++)
setpins 0…7 to binary value i

Lets say we do it faster, in assembler, with some simple (untested code);

ldi r16, 1 ; 1 cycles
LOOP_HB: ; higherbit loop, from 1…0
out 0x05, r16 ; PORTB if i recall correctly ; 1 cycles
ldi r17, 255 ; 1 cycle
LOOP_LB: ; lowbit loop, from 255…0
out 0x0b, r17 ; PORTD 1 cycle
dec r17 ; 1 cycles
brvs LOOP_LB; ; 1/2 cycles
dec r16 ; 1 cycles
brvs LOOP_HB ; 1/2 cycles

The above (untested) code without any meddling with CAS/RAS, or chipselect, will still set us back just around 2050 cycles - or ~0.125 ms. It means, that for every 64ms, the single block of DRAM is unavailable for 0.125 ms of those - thats a whooping 0.2% of the time.

Now, multiply that with four drams, all disabling traffic when just one is updating - and even more pins to sort out CS; and the dram end up being unavailable just about 0.8% of the time.

This is why i fear for “lost communication” to the DRAM Controller.

( are my calculations correct? )

kms1980:
... a total of 11+4 signals.

That's two bits to select a single block from four blocks, 9 bits of address, and 4 bits of data. Your DRAM, though, requires 18 bits of address: 9 bits for the row address, and 9 more for the column address. With a 9-bit address, you'd have access to 512 memory locations. Instead, you have 262,144 4-bit memory locations. Maybe you only need one of these memories, instead of 4?

... if I chipselect all the DRAM; and hit all the addresses at once, I should save the most time refreshing the DRAM. However, this will (likely) be a giant voltage divider - i presume ?

Look at the timing diagram labeled, "RAS-only Refresh Cycle." You'll see that CAS is always inactive, Output enable (OE) is shown as "don't care," and the only things that matter are RAS and 9 bits of address data - the row address. The chip will refresh all 512 locations whose row address is on the address pins when RAS goes active. With CAS inactive, the data outputs are never enabled, and the data bus is tri-stated. The traditional way to implement a refresh is to put the row address on the bus, activate RAS, deactivate it after an appropriate period, and go to the next task. All of the modules should be connected to the same RAS signal, and to the same address bus, so 512 refresh cycles should refresh all the memory. I don't understand your concern about a "voltage divider." Can you clarify that concern?

if this device receives input while refreshing, the input will most likely be lost - or I would need some slow sync mechanism.

You'd be very unhappy with that result. No one wants a memory that works almost every time.

Would would be the most prudent way to go about such possible sync problems?

A straightforward way might be to let one of the controller's pins signify that the memory is available. The requesting device would then have to wait for the end of the refresh cycle to complete its transaction. No matter what, you'll need some signalling between the controller and the external device to determine when parts of the transaction are complete - things like, "I got your data," or "Data is ready."

I'm sure that there are a number of alternatives, but, without more detail on how the project is to be implemented, their usefulness is a matter of conjecture.

I'll note that your memories appear to support "CAS before RAS" refresh, and "Hidden" refresh, suggesting that the IC's maintain internal counters to step through the row addresses, and can can be kept refreshed by simply making sure that enough refresh cycles happen, without the controller keeping track of a row counter. That would certainly speed up a refresh cycle. The datasheet doesn't explicitly state that the memories have that feature. I can't figure out what else a "CAS before RAS" refresh cycle would do. We probably need a DRAM expert to chime in on this.

In essence, the project is somewhat of a RAM-Controller. The final PCB i vision will have just the Atmega on it, some replaceable ram blocks, and a load of traces to a flat-cable-connector.

It sounds like you envision a device that would:

  • Get an address from another processor
  • Get the direction - read or write,
  • Get some data for a write operation,
  • Respond with data for a read operation, and
  • Keep the memory refreshed.

For a write operation, that's 23 bits - 1 bit for read/write, 18 for address, and 4 for data. For a read, it's 19 bits in, and 4 bits out. If you're contemplating a serial interface, then it will take time to receive the address and data information. Transactions will likely be slow enough to make it feasible for the controller refresh memory as its primary task, to be interrupted by access requests.

kms1980:
We can put this into an interrupt on the AtMega, every 64ms (retention time).

I can't find any evidence in the datasheet that the memory wants a 64 millisecond refresh. It looks like it wants each row to be refreshed every 8 milliseconds. The first page shows this text:

512 refresh cycles/8 ms

The 4th page of the datasheet lists a "refresh cycle time" of 8 ms. I don't find either of those notations to be overwhelmingly clear, but they seem to be the only thing in the datasheet that describes a required refresh rate. I think the canonical refresh time is 8 ms for these memories.

... that's a whooping 0.2% of the time.

I can't speak from experience, but the Wikipedia article entitled, "memory refresh," claims that

... refresh overhead occupied up to 10% of chip time in earlier DRAMs, in modern chips this fraction is less than 1%

So, it looks like 0.2% is pretty good.

Now, multiply that with four drams ... and the dram end up being unavailable just about 0.8% of the time.

I think that you can refresh all the modules together. With this memory, it looks like you just have to refresh 512 rows, no matter how many columns you have.

I get the feeling that you haven't put any hardware together yet for this project, and haven't yet performed any tests. Is that correct?

[Edit: add this] You might want to read the Wikipedia articles on DRAM and "Memory Refresh" before you go much further.

tmd3:
That's two bits to select a single block from four blocks, 9 bits of address, and 4 bits of data. Your DRAM, though, requires 18 bits of address: 9 bits for the row address, and 9 more for the column address. With a 9-bit address, you'd have access to 512 memory locations. Instead, you have 262,144 4-bit memory locations. Maybe you only need one of these memories, instead of 4?

You send 9 bits of rows, toggle pins, then send 9 bits of column - same physical 9 pins. For refresh (and i was speaking strictly RAS-refresh) you send 9 rows.

tmd3:
Look at the timing diagram labeled, "RAS-only Refresh Cycle." You'll see that CAS is always inactive, Output enable (OE) is shown as "don't care," and the only things that matter are RAS and 9 bits of address data - the row address. The chip will refresh all 512 locations whose row address is on the address pins when RAS goes active. With CAS inactive, the data outputs are never enabled, and the data bus is tri-stated. The traditional way to implement a refresh is to put the row address on the bus, activate RAS, deactivate it after an appropriate period, and go to the next task. All of the modules should be connected to the same RAS signal, and to the same address bus, so 512 refresh cycles should refresh all the memory. I don't understand your concern about a "voltage divider." Can you clarify that concern?

I am more or less concerned, that four modules, would "divide the voltage", to be too low, for any actual signal to pass through, or that that values being refreshed would have a different resistance, depending on the module and its contents (like, how much needed to be refreshed).

Ive done it, build it (with two blocks), and it works. Thats just not the same as it keeps working, if there was a logic problem here :slight_smile: Im not really all that into the lower parts of signaling (25+ years coding, but only 6 months hardware building - its still pretty new to me that stuff isn't just 0 or 1, but can have a raising/falling edge .. )

tmd3:
You'd be very unhappy with that result. No one wants a memory that works almost every time.

Yes that is actually what i meant, the need for a controller. If the main arduino just access, as I do now, the ram directly - no problem. But thats not what i want.

tmd3:
A straightforward way might be to let one of the controller's pins signify that the memory is available. The requesting device would then have to wait for the end of the refresh cycle to complete its transaction. No matter what, you'll need some signalling between the controller and the external device to determine when parts of the transaction are complete - things like, "I got your data," or "Data is ready."

Yes exactly. That is what i invision.

tmd3:
I'll note that your memories appear to support "CAS before RAS" refresh, and "Hidden" refresh, suggesting that the IC's maintain internal counters to step through the row addresses, and can can be kept refreshed by simply making sure that enough refresh cycles happen, without the controller keeping track of a row counter. That would certainly speed up a refresh cycle. The datasheet doesn't explicitly state that the memories have that feature. I can't figure out what else a "CAS before RAS" refresh cycle would do. We probably need a DRAM expert to chime in on this.

I have always used the Burst-refresh mechanism, refresh everything at once - and only with Ras-only method. Cas-Before-Ras is smart, you drop CAS and RAS, just toggling it over and over - the internal counter will move to next address automatically. Its like burst mode. I haven't been able to really wrap my head around how to use Hiddden refresh yet.

tmd3:
It sounds like you envision a device that would:

(my edits)

  • Controller ready state = 1 pin
  • Get the direction - read or write, = 1 pin
  • Get an address from another processor = 9 pins + number of ram pins (2 pins for 4 blocks) - you let R/W-pin go up&down to switch from row to column, signal up/down with controller ready state pin that its accepted - kinda like the DRAM does
  • Get/write some data for a write/read operation, = 4-8 pins, depending on the ram

17-21 parallel pins. Or very few, in seriel/SPI.

tmd3:
For a write operation, that's 23 bits - 1 bit for read/write, 18 for address, and 4 for data. For a read, it's 19 bits in, and 4 bits out. If you're contemplating a serial interface, then it will take time to receive the address and data information. Transactions will likely be slow enough to make it feasible for the controller refresh memory as its primary task, to be interrupted by access requests.

Yes. Thats actually all i imagine it is. A passthrough, that keeps the memory refreshed.

tmd3:
I can't find any evidence in the datasheet that the memory wants a 64 millisecond refresh. It looks like it wants each row to be refreshed every 8 milliseconds. The first page shows this text:The 4th page of the datasheet lists a "refresh cycle time" of 8 ms. I don't find either of those notations to be overwhelmingly clear, but they seem to be the only thing in the datasheet that describes a required refresh rate. I think the canonical refresh time is 8 ms for these memories. I can't speak from experience, but the Wikipedia article entitled, "memory refresh," claims thatSo, it looks like 0.2% is pretty good.

You can usually, in my experience, stretch the refresh times. Ive read a paper on it somewhere (where i have forgotten, it was "on the internet") that usually a lot of time and energy can be saved by stretching out the refreshes - and it usually works as well.

tmd3:
I think that you can refresh all the modules together. With this memory, it looks like you just have to refresh 512 rows, no matter how many columns you have.

Yes, its a regular RAS-refresh.

tmd3:
I get the feeling that you haven't put any hardware together yet for this project, and haven't yet performed any tests. Is that correct?

Actually I have. At the moment, two ram blocks and the arduino, connected via a serial-parrallel interface. Data is refreshed fine, but I have been concerned that adding more would ruin the "refresh all at once" method. My problem is to "finalise" it. To move the program-logic out of the arduino that uses the dram, and convert that Arduino into a controller, as to be used by other arduinos. I cannot wrap my head around how im supposed to buffer the incoming data or prevent fails.

Perhaps I should just build the darn thing to store and read one byte at a time. Each time wait for ready state, each time, send data and receive it - one byte. Then later, expand that to burst mode.

tmd3:
[Edit: add this] You might want to read the Wikipedia articles on DRAM and "Memory Refresh" before you go much further.

Im already refreshing the ram. But thanks :slight_smile:

I am sorry Im giving of the wipe I haven't put the hardware together - since this is a new field for me, its also harder for me to identify where the potential problems are. I am therefore prone for XYProblems, but try my best to communicate what I see as the actual problem without too much hazzle.

Thanks for your reply, comments and time - very much appreciated !

I'm glad to hear that you've made working hardware. Your first post suggested as much, but I began to get confused through later posts.

Let's look at your concern about multiple modules on the bus. It sounds like you're concerned about having so many DRAM modules attached to your Arduino outputs that the Arduino can't supply enough current for all the DRAM inputs. Am I understanding you correctly?

The actual refresh times depend steeply on the temperature - the quoted refresh time is what's
needed for every cell in the device to work reliably at the top of its temperature range.

Many cells will last a lot longer, and all cells will last a lot longer at room temperature (perhaps
a second even).

At cryogenic temperatures the storage time becomes long enough for DRAM to resemble
non-volatile memory!!