Author Topic: Memory controller for IS42s16160B (On-board memory for DE0 Nano)  (Read 9912 times)

0 Members and 1 Guest are viewing this topic.

Offline pigtwoTopic starter

  • Regular Contributor
  • *
  • Posts: 133
Hello everyone, I'm just wondering if anyone has written a memory controller for the on-board memory for the DE0 Nano(IS42216160B) and wouldn't mind posting their code. 

I made a memory controller for it but it doesn't seem to work so I wanted to see a reference to try to figure out what I'm doing wrong. 

Just so you guys don't think I'm just trying to get some code without writing any myself I'll post my code.  But I'm not asking anyone to look through it(I imagine that would be very painful).

I found one resource where someone did write a memory controller for it but it was in VHDL (which I don't know) and it had a lot of features that I didn't need which made it harder to read.

Code: [Select]
module Memory_Controller(
input wire Clock_50MHZ, RW, Reset, Execute,
input wire[5:0] Data_In,
input wire[10:0] Addr_In,    // In the form [A12, A11, A8-A0]

inout wire [5:0] Mem_IO,

output wire[5:0] Data_Out,
output wire[10:0] Addr_Out,
output wire Data_Ready, CS, RAS, CAS, WE, BA0, BA1, A9, A10, CKE, Ready, DQML, DQMH
);
// This is a basic memory controller for the IS42S16160B memory chip.  Which has 256 Mb of memory in 16 bit words. 
//  RW: 1 means write, 0 means read

// Symbolic mode register defintion
localparam[14:0] mode_reg = 15'b00000100010000;

// Symbolic OP-Code definition.  The OP Code is in the form [!CS, !RAS, !CAS, !WE]
localparam[3:0]
read = 4'b0101,
write = 4'b0100,
nop = 4'b0111,
activate = 4'b0011,
refresh = 4'b0001,
load_mode_reg = 4'b0000,
precharge = 4'b0010;

// Symbolic state defintions
localparam[4:0]
Start = 5'b00000,
Start_NOP = 5'b00001,
Start_Precharge = 5'b00010,
Start_Refresh = 5'b00011,
Start_Refresh_Loop = 5'b00100,
Load_Mode_Reg = 5'b00101,
Load_Mode_Reg_NOP1 = 5'b00110,
Load_Mode_Reg_NOP2 = 5'b00111,
Idle = 5'b01000,
Refresh = 5'b01001,
Refresh_NOP1 = 5'b01010,
Refresh_NOP2 = 5'b01011,
Refresh_NOP3 = 5'b01100,
Refresh_NOP4 = 5'b01101,
Activate = 5'b01110,
Activate_NOP = 5'b01111,
Read = 5'b10000,
Read_NOP1 = 5'b10001,
Read_NOP2 = 5'b10010,
Write = 5'b10011,
Write_NOP1 = 5'b10100,
Precharge = 5'b10101,
Precharge_NOP = 5'b10110;

// Internal defintions
reg[10:0] address, address_next;
reg[4:0] state, state_next;
reg[3:0] op_code, op_code_next;
reg[5:0] data_out, data_out_next, mem_io, mem_io_next;
reg[1:0] nop_count, nop_count_next;
reg[3:0] refresh_count, refresh_count_next;
reg ready, ready_next, data_ready, data_ready_next, ba0, ba0_next, ba1, ba1_next, a9, a9_next, a10, a10_next;

// FSMD register and data specifications
always @(posedge Clock_50MHZ)
begin
if(!Reset)
begin
state <= Start;
op_code <= nop;
nop_count <= 0;
refresh_count <= 0;
ready <= 0;
data_ready <= 0;
address <= 0;
ba0 <= 0;
ba1 <= 1;
a9 <= 0;
a10 <= 0;
mem_io <= 0;
data_out <= 0;
end
else
begin
state <= state_next;
op_code <= op_code_next;
nop_count <= nop_count_next;
refresh_count <= refresh_count_next;
ready <= ready_next;
data_ready <= data_ready_next;
address <= address_next;
ba0 <= ba0_next;
ba1 <= ba1_next;
a9 <= a9_next;
a10 <= a10_next;
mem_io <= mem_io_next;
data_out <= data_out_next;
end
end

// FSMD next state definitions
always @*
begin
// Define default values
state_next = state;
op_code_next = op_code;
nop_count_next = nop_count;
refresh_count_next = refresh_count;
ready_next = ready;
data_ready_next = data_ready;
address_next = address;
ba0_next = ba0;
ba1_next = ba1;
a9_next = a9;
a10_next = a10;
mem_io_next = mem_io;
data_out_next = data_out;

case(state)
// Initialization sequence
Start:
begin
data_out_next = 0;
ready_next = 0;
op_code_next = nop;
data_ready_next = 0;
refresh_count_next = 0;
mem_io_next = 0;
ba0_next = 0; // These two may need to be different but I think they can be constant. 
ba1_next = 0; //    They are essentually MSB of the address.
state_next = Start_NOP;
end

Start_NOP:
begin
op_code_next = nop;
state_next = Start_Precharge;
end

Start_Precharge:
begin
op_code_next = refresh;
nop_count_next = 0;
state_next = Start_Refresh;
end

Start_Refresh:
begin
op_code_next = nop;
nop_count_next = nop_count + 2'd1;
if(nop_count == 1) // Four nops are needed in total.  This will achive two and the other comes from the state
state_next = Start_Refresh_Loop; //    one of the state transisions later on.
else
state_next = Start_Refresh;
end

Start_Refresh_Loop:
begin
op_code_next = nop;
refresh_count_next = refresh_count + 4'd1;
if(refresh_count == 10)
state_next = Start_Precharge;
else
begin
op_code_next = load_mode_reg;
{ba1_next, ba0_next, address_next[10], address_next[9], a10_next, a9_next, address_next[8:0]} = mode_reg;
state_next = Load_Mode_Reg;
end
end

Load_Mode_Reg:
begin
op_code_next = nop;
state_next = Load_Mode_Reg_NOP1;
end

Load_Mode_Reg_NOP1:
begin
op_code_next = nop;
state_next = Load_Mode_Reg_NOP2;
end

Load_Mode_Reg_NOP2:
begin
op_code_next = nop;
refresh_count_next = 0;
a10_next = 0;
state_next = Idle;
end

// Idle
Idle:
begin
data_out_next = data_out;
ready_next = 1;
refresh_count_next = refresh_count + 4'd1;
op_code_next = nop;
if(refresh_count == 400)   //REMOVE////////// replace with frequency dependant value later
begin
op_code_next = refresh;
state_next = Refresh;
end
else if((refresh_count != 400)&&Execute)
begin
op_code_next = activate;
ready_next = 0;
data_ready_next = 0;
state_next = Activate;
end
else
begin
state_next = Idle;
end
end

// Refresh sequence
Refresh:
begin
op_code_next = nop;
state_next = Refresh_NOP1;
end

Refresh_NOP1:
begin
op_code_next = nop;
state_next = Refresh_NOP2;
end

Refresh_NOP2:
begin
op_code_next = nop;
state_next = Refresh_NOP3;
end

Refresh_NOP3:
begin
op_code_next = nop;
state_next = Refresh_NOP4;
end

Refresh_NOP4:
begin
op_code_next = nop;
state_next = Idle;
end

// Activate sequence
Activate:
begin
address_next = Addr_In;
op_code_next = nop;
state_next = Activate_NOP;
end

Activate_NOP:
begin
if(RW)     // Write
begin
op_code_next = write;
mem_io_next = Data_In;
state_next = Write;
end
else      // Read
begin
op_code_next = read;
state_next = Read;
end
end

// Write sequence
Write:
begin
op_code_next = nop;
state_next = Write_NOP1;
end

Write_NOP1:
begin
op_code_next = precharge;
state_next = Precharge;
end

// Read sequence
Read:
begin
op_code_next = nop;
state_next = Read_NOP1;
end

Read_NOP1:
begin
op_code_next = nop;
data_out_next = Mem_IO;    // ????? mem_io ?
state_next = Read_NOP2;
end

Read_NOP2:
begin
op_code_next = precharge;
data_ready_next = 1;
state_next = Precharge;
end

// Precharge sequence
Precharge:
begin
op_code_next = nop;
state_next = Precharge_NOP;
end

Precharge_NOP:
begin
op_code_next = nop;
state_next = Idle;
end

default:
state_next = Idle;
endcase
end

// Connections
assign Mem_IO = (RW) ? mem_io : 6'bz;
assign DQMH = 0;
assign DQML = 0;
assign Data_Out = data_out;
assign CS = op_code[3];
assign RAS = op_code[2];
assign CAS = op_code[1];
assign WE = op_code[0];
assign CKE = 1;         // Clock enable.  Might need a non constant value for start up.
assign BA0 = ba0;
assign BA1 = ba1;
assign A9 = a9;
assign A10 = a10; // Selects which banks to activate.  Since I'm always using the same banks, IE BA0/BA1 constant, it shouldn't matter.
assign Addr_Out = address;
assign Data_Ready = data_ready;
assign Ready = ready;

endmodule
   

I know this is a long shot but I thought I would try.

Thank you!
 

Offline Scrts

  • Frequent Contributor
  • **
  • Posts: 797
  • Country: lt
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #1 on: June 29, 2014, 08:57:51 pm »
I think there's Altera memory core for that. Why not using it?
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #2 on: June 29, 2014, 09:30:37 pm »
If you want to re-implement my SDRAM controller in Verilog to work on the DE0-Nano I'm more than happy to give you any support you need. You can find it at http://hamsterworks.co.nz/mediawiki/index.php/Simple_SDRAM_Controller.

The conversion should be pretty simple. It is all in one souce file, and my VHDL-fu is poor, with only using some special attributes to lock some registers into the I/O blocks.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #3 on: June 29, 2014, 10:17:23 pm »
If you want to re-implement my SDRAM controller in Verilog to work on the DE0-Nano I'm more than happy to give you any support you need. You can find it at http://hamsterworks.co.nz/mediawiki/index.php/Simple_SDRAM_Controller

The conversion should be pretty simple. It is all in one souce file, and my VHDL-fu is poor, with only using some special attributes to lock some registers into the I/O blocks.

Your link has an extra period I fixed it in this reply.

I could use that for my current project since I'm going to need a buffer for capturing the video data.
https://www.eevblog.com/forum/beginners/converting-15khz-analog-rgb-to-digital/msg459236/#msg459236
 

Offline marshallh

  • Supporter
  • ****
  • Posts: 1462
  • Country: us
    • retroactive
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #4 on: June 29, 2014, 10:34:59 pm »
Please post signaltap captures of your init sequence, and sample r/w/refresh sequences
Verilog tips
BGA soldering intro

11:37 <@ktemkin> c4757p: marshall has transcended communications media
11:37 <@ktemkin> He speaks protocols directly.
 

Offline marshallh

  • Supporter
  • ****
  • Posts: 1462
  • Country: us
    • retroactive
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #5 on: June 29, 2014, 10:38:11 pm »
By the way you can use a shorter notation fot the parameters/localparams:

Code: [Select]
localparam [7:0] POSSIBLE_STATE = 'h1,
                 ANOTHER_STATE = 'h2,
                 LAST_STATE = 'hFF;

Assigns the constants to the assumed bitwidth (here [7:0])

You can also put the output registers right in the module definition

Code: [Select]
output reg [15:0] data_out,
Verilog tips
BGA soldering intro

11:37 <@ktemkin> c4757p: marshall has transcended communications media
11:37 <@ktemkin> He speaks protocols directly.
 

Offline pigtwoTopic starter

  • Regular Contributor
  • *
  • Posts: 133
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #6 on: June 30, 2014, 12:11:19 am »
@Scrts I'm mostly doing it as an educational exercise.  That's probably what I'll do if I can't get it to work.

@hamster_nz Your website is actually the one resource I found that I referenced in the OP.  I just don't know VHDL so I have trouble reading it.  Your website was really helpful, it cleared up quite a few things for me previously.   Thank you!

If I could just ask you a couple of basic things about it that could really help.  If you don't remember, it's not a big deal.

I don't completely understand how DQM works.  In the datasheet it states that it should act like output enable but in all the diagrams its either 'don't care' or zero.  What did you do with it?

The datasheet says to put clock enable low during the initialization process but this seems weird to me.  What did you do with CKE during the initialization process?

Please post signaltap captures of your init sequence, and sample r/w/refresh sequences
This.  That would be awesome!

By the way you can use a shorter notation fot the parameters/localparams:

Code: [Select]
localparam [7:0] POSSIBLE_STATE = 'h1,
                 ANOTHER_STATE = 'h2,
                 LAST_STATE = 'hFF;

Assigns the constants to the assumed bitwidth (here [7:0])

You can also put the output registers right in the module definition

Code: [Select]
output reg [15:0] data_out,
Thank you, that makes that a lot less annoying. 
« Last Edit: June 30, 2014, 01:26:06 am by pigtwo »
 

Offline marshallh

  • Supporter
  • ****
  • Posts: 1462
  • Country: us
    • retroactive
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #7 on: June 30, 2014, 02:23:31 am »
DQM is an active-high mask signal. It is sampled in the same cycle as the data being written.
If DQM is 1 then the bits of its byte group will not be overwritten. The old contents in the dram array will be kept.

Since you have a DQM for each 8 bits, on a 16bit wide ram you'll have an UpperDQM and LowerDQM, for DQ[15:8], and DQ[7:0] respectively.
If you don't ever think you'll be writing less than 16 bit granularity, just tie them low.

CKE is only used in power management and is also required during INIT, but only for DDR and onwards.
For vanillla sdram you can just tie it high. In DDR1+ you need to run a few thousand clocks throgh the device before you assert CKE so the onboard DLL's can lock to it properly.
Verilog tips
BGA soldering intro

11:37 <@ktemkin> c4757p: marshall has transcended communications media
11:37 <@ktemkin> He speaks protocols directly.
 

Offline pigtwoTopic starter

  • Regular Contributor
  • *
  • Posts: 133
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #8 on: June 30, 2014, 02:40:58 am »
Thank you marshallh!  That really narrows down my trouble shooting. 

I've only done basic testing on my design.  I don't know if this is a really obvious problem or not so I thought I might mention it to see if anyone has an idea.

The problem is that whatever the last thing that was written will be the value that is read no matter what.  So if you write to address 0 the value of 2 then write to address 1 the value of 5.  Then read address 0, you would get 5, or if you read any other address you would get 5. 

My first thought was that I wasn't getting the address to the memory correctly and so all operation would happen on the same memory location but I couldn't seem to find any problems. 
 

Offline marshallh

  • Supporter
  • ****
  • Posts: 1462
  • Country: us
    • retroactive
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #9 on: June 30, 2014, 03:19:04 am »
If you are reading the last value on the bus, it means the RAM is never driving the bus. So, your init sequence crashed the ram, or you're issuign the wrong command.

On a empty dram you should read cosmic noise, it'll be an odd pattern of data that converges to either 0 or 1 the longer you have it turned on
Verilog tips
BGA soldering intro

11:37 <@ktemkin> c4757p: marshall has transcended communications media
11:37 <@ktemkin> He speaks protocols directly.
 

Offline pigtwoTopic starter

  • Regular Contributor
  • *
  • Posts: 133
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #10 on: June 30, 2014, 03:25:55 am »
Ok, that makes sense.  I was very skeptical of my initialization sequence.  I'll have to look into it.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #11 on: June 30, 2014, 10:28:38 am »
Ok, that makes sense.  I was very skeptical of my initialization sequence.  I'll have to look into it.

Yeah, it looks a little off. I've got it running in a test bench, and it doesn't look like it does what is required. From the datasheet:

The 256Mb SDRAM is initialized after the power is applied to VDD and VDDQ (simultaneously) and the clock is stable with DQM High and CKE High

A 200µs delay is required prior to issuing any command other than a COMMAND INHIBIT or a NOP. The COMMAND INHIBIT or NOP may be applied during the 200us period and should continue at least through the end of the period.

With at least one COMMAND INHIBIT or NOP command having been applied, a PRECHARGE command should be applied once the 200µs delay has been satisfied. All banks must be precharged. This will leave all banks in an idle state after which at least eight AUTO REFRESH cycles must be performed. After the AUTO REFRESH cycles are complete, the SDRAM is then ready for mode register programming.
 

My test bench holds RESET for a while, releases it then send a read every now and then (when the READY has been asserted for 19 cycles). The read sequence looks OK, with an ACTIVATE, READ and PRECHARGE sequence.

I can't see the PRECHARGE and there is only one of the eight required AUTO REFRESH cycles. :(

 The initialization sequence is very important. You have to assume that the SDRAM is in a random state - after all, somebody could have hit the reset button during the middle of transaction. The reset sequence is the only guaranteed way to get all the internal registers into a known state.


The way you have spit the address bus has me confused, with breaking out A9 and A10, so I haven't verified that the mode register is being set correctly.

Oh, and if you loop 'ready' back into 'execute' nothing gets done. Not sure if that is a design feature or not...
« Last Edit: June 30, 2014, 10:48:16 am by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline pigtwoTopic starter

  • Regular Contributor
  • *
  • Posts: 133
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #12 on: June 30, 2014, 03:18:39 pm »
Thank you, that helps a lot.  For some reason when I first learned verilog/using FPGA I skipped the test bench part, which was a mistake.  I tried to get a precharge and 10 refresh cycles in but I guess I messed up the loops.  But I didn't wait for 200 microseconds though so that needs to be added. 

I'm at work right now so I can't test anything atm but when I get home I'll try to set up a test bench of my own and fix those problems.

Quote
Oh, and if you loop 'ready' back into 'execute' nothing gets done. Not sure if that is a design feature or not...
Could you explain more, I'm not certain what you mean by this.
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #13 on: July 01, 2014, 01:56:58 am »
http://www.altera.com/products/ip/altera/ocore_sdr_sdram.html
It's a single data rate synchronous dynamic random access memory controller.
Features:
  • Burst lengths of 1, 2, 4, or 8 data words
  • CAS latency of 2 or 3 clock cycles
  • 16-bit programmable refresh counter used for automatic refresh
  • 2-chip selects for SDRAM devices
  • Supports the NOP, READA, WRITEA, AUTO_REFRESH, PRECHARGE, ACTIVATE, BURST_STOP, and LOAD_MR commands
  • Support for full-page mode operation
  • Data mask line for write operations
  • PLL to increase system performance
  • Support for data-path widths of 16, 32, and 64 bits
Available both in Verilog and VHDL, the simulation seems to be for the micron MT48LC8M16A2, but other than the ADDR is 12 bits instead of 13 bits on the Nano the rest is the same it seems.

Also hamster's VHDL is for the MT48LC4M16 and it uses 13 bits for the ADDR (but I think it should be 12 bits).
Edit: never mind I thought it was for the papilio pro SDRAM (64Mbits) but reading further on it mentions 256Mbits)

I'm going to use the VHDL version from that altera code for both the IS42s16160B and the MT41J64M16JT-15E on the BeMicro CV board.
« Last Edit: July 01, 2014, 04:31:34 am by miguelvp »
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #14 on: July 01, 2014, 03:05:49 am »
Quote
Oh, and if you loop 'ready' back into 'execute' nothing gets done. Not sure if that is a design feature or not...
Could you explain more, I'm not certain what you mean by this.

I was trying to see how back-to-back access looked, so I did something along the lines of

An async assigment so that execute would be asserted whenever your controller asserted "ready"
  execute <= ready;

and then in a clocked process
   if ready = '1' then
    rw <= not rw;
  end if;

It was attempting to send alternating read/writes as fast as the controller could support it. Nothing happend. :(
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline miguelvp

  • Super Contributor
  • ***
  • Posts: 5550
  • Country: us
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #15 on: July 01, 2014, 06:56:15 pm »
@hamster

You should have linked this page instead:

http://hamsterworks.co.nz/mediawiki/index.php/SDRAM_Memory_Controller

I'm so using it.
 

Offline pigtwoTopic starter

  • Regular Contributor
  • *
  • Posts: 133
Re: Memory controller for IS42s16160B (On-board memory for DE0 Nano)
« Reply #16 on: July 01, 2014, 07:05:16 pm »
@hamster That's definitely a bug there's probably a lot more.  What program do you use to make test benches?
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf