Jump to content
  • 0

How to read/write to p30 parallel flash memory on digilent genesys


Anis

Question

Hello everyone,

I am using a digilent genesys board (the board with the virtex 5 fpga). I want to save data that I read from fpga in the strataflash and then I want to read that data again form the strataflash. I have been struggling for a long time in order to read/write (even with a simple example as the one below) to the flash memory but i was not successful. It has been mentioned that a reference design on the Digilent website provides an example of driving the Flash memory in the reference manual of digilent genesys but i couldn't find it. I would appreciate any help.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

 

entity RAM_interface is
Port ( clock : in STD_LOGIC;
st_led: out std_logic_vector(7 downto 0);
clk_o: out std_logic;
addr_o : out STD_LOGIC_VECTOR (24 downto 0);
data_io : inout STD_LOGIC_VECTOR (15 downto 0);
--data_i : in STD_LOGIC_VECTOR (15 downto 0);
adv_o, ce_o, oe_o, we_o, reset_o : out STD_LOGIC);
end RAM_interface;

architecture Behavioral of RAM_interface is

begin


clk_o <= '0';

fsm: process(clock)
type states is (write_data_phase_1, write_data_phase_2, write_data_phase_3, read_data_phase_1, read_data_phase_2);
variable st : states:= write_data_phase_1;
variable cnt_v: integer:=0;
begin

if clock = '1' and clock'event then
case st is
when write_data_phase_1 =>
if cnt_v > 20 then st := write_data_phase_2; cnt_v := 0; else cnt_v := cnt_v + 1;
end if;
addr_o(24 downto 2) <= (others => '0');
addr_o(1 downto 0) <= "01";
--data_io(15 downto 0) <= x"1111";
--(adv_o, ce_o, oe_o, we_o,reset_o) <= "01110";
adv_o <= '0';
ce_o <= '1';
oe_o <= '1';
we_o <= '1';
reset_o <= '1';

when write_data_phase_2 =>
if cnt_v > 10 then st := write_data_phase_3; cnt_v := 0; else cnt_v := cnt_v + 1;
end if;
--addr_o(24 downto 2) <= (others => '0');
--addr_o(1 downto 0) <= "01";
data_io(15 downto 0) <= x"1111";
--(adv_o, ce_o, oe_o, we_o,reset_o) <= "01110";
adv_o <= '0';
ce_o <= '0';
oe_o <= '1';
we_o <= '0';
reset_o <= '1';

when write_data_phase_3 =>
if cnt_v > 0 then st := read_data_phase_1; cnt_v := 0; else cnt_v := cnt_v + 1;
end if;
--addr_o(24 downto 2) <= (others => '0');
--addr_o(1 downto 0) <= "01";
--data_io(15 downto 0) <= x"1111";
--(adv_o, ce_o, oe_o, we_o,reset_o) <= "01110";
adv_o <= '0';
ce_o <= '1';
oe_o <= '1';
we_o <= '1';
reset_o <= '1';

when read_data_phase_1 =>
if cnt_v > 1 then st := read_data_phase_2; cnt_v := 0; else cnt_v := cnt_v + 1;
end if;
addr_o(24 downto 2) <= (others => '1');
addr_o(1 downto 0) <= "00";
--(adv_o, ce_o, oe_o, we_o,reset_o) <= "00011";
adv_o <= '0';
ce_o <= '0';
oe_o <= '0';
we_o <= '1';
reset_o <= '1';
--wait_o <= '1';

when read_data_phase_2 =>
if cnt_v > 7 then st := read_data_phase_2; cnt_v := 0; else cnt_v := cnt_v + 1;
end if;
addr_o(24 downto 2) <= (others => '0');
addr_o(1 downto 0) <= "01";
--(adv_o, ce_o, oe_o, we_o,reset_o) <= "00011";
adv_o <= '0';
ce_o <= '1';
oe_o <= '1';
we_o <= '1';
reset_o <= '1';
--wait_o <= 'Z';


when others =>
addr_o(24 downto 2) <= (others => '0');
addr_o(1 downto 0) <= "00";
--(adv_o, ce_o, oe_o, we_o,reset_o) <= "00011";
adv_o <= '1';
ce_o <= '1';
oe_o <= '1';
we_o <= '1';
reset_o <= '1';
--wait_o <= 'Z';

end case;
end if;
end process;

st_led <= data_io(7 downto 0);

end Behavioral;

 

and this is the constraint file:

NET  "st_led[0]"                                LOC = "AG8" ;          #Bank 22
NET  "st_led[1]"                                LOC = "AH8" ;          #Bank 22
NET  "st_led[2]"                                LOC = "AH9" ;          #Bank 22
NET  "st_led[3]"                                LOC = "AG10" ;          #Bank 22
NET  "st_led[4]"                                LOC = "AH10" ;          #Bank 22
NET  "st_led[5]"                                LOC = "AG11" ;          #Bank 22
NET  "st_led[6]"                                LOC = "AF11" ;          #Bank 22
NET  "st_led[7]"                                LOC = "AE11" ;          #Bank 22


NET  "clock"                               LOC = "AG18" ;          #Bank 22

NET  "ce_o"                                LOC = "AE14" ;          #Bank 22
NET  "oe_o"                                LOC = "AF14" ;          #Bank 22
NET  "we_o"                                LOC = "AF20" ;          #Bank 22
NET  "clk_o"                               LOC = "AG21" ;          #Bank 22
NET  "reset_o"                             LOC = "AG17" ;          #Bank 22
#NET  "wait_o"                              LOC = "AH18" ;          #Bank 22
NET  "adv_o"                               LOC = "AF21" ;          #Bank 22              
              
NET  "addr_o[0]"                                LOC = "K12" ;          #Bank 22
NET  "addr_o[1]"                                LOC = "K13" ;          #Bank 22
NET  "addr_o[2]"                                LOC = "H23" ;          #Bank 22
NET  "addr_o[3]"                                LOC = "G23" ;          #Bank 22
NET  "addr_o[4]"                                LOC = "H12" ;          #Bank 22
NET  "addr_o[5]"                                LOC = "J12" ;          #Bank 22
NET  "addr_o[6]"                                LOC = "K22" ;          #Bank 22
NET  "addr_o[7]"                                LOC = "K23" ;          #Bank 22
NET  "addr_o[8]"                                LOC = "K14" ;          #Bank 22
NET  "addr_o[9]"                                LOC = "L14" ;          #Bank 22
NET  "addr_o[10]"                                LOC = "H22" ;          #Bank 22
NET  "addr_o[11]"                                LOC = "G22" ;          #Bank 22
NET  "addr_o[12]"                                LOC = "J15" ;          #Bank 22
NET  "addr_o[13]"                                LOC = "K16" ;          #Bank 22
NET  "addr_o[14]"                                LOC = "K21" ;          #Bank 22
NET  "addr_o[15]"                                LOC = "J22" ;          #Bank 22    
NET  "addr_o[16]"                                LOC = "L16" ;          #Bank 22
NET  "addr_o[17]"                                LOC = "L15" ;          #Bank 22
NET  "addr_o[18]"                                LOC = "L20" ;          #Bank 22
NET  "addr_o[19]"                                LOC = "L21" ;          #Bank 22
NET  "addr_o[20]"                                LOC = "AE23" ;          #Bank 22
NET  "addr_o[21]"                                LOC = "AE22" ;          #Bank 22
NET  "addr_o[22]"                                LOC = "AG12" ;          #Bank 22
NET  "addr_o[23]"                                LOC = "AF13" ;          #Bank 22
NET  "addr_o[24]"                                LOC = "AG23" ;          #Bank 22

NET  "data_io[0]"                                LOC = "AD19" ;          #Bank 22
NET  "data_io[1]"                                LOC = "AE19" ;          #Bank 22
NET  "data_io[2]"                                LOC = "AE17" ;          #Bank 22
NET  "data_io[3]"                                LOC = "AF16" ;          #Bank 22
NET  "data_io[4]"                                LOC = "AD20" ;          #Bank 22
NET  "data_io[5]"                                LOC = "AE21" ;          #Bank 22
NET  "data_io[6]"                                LOC = "AE16" ;          #Bank 22
NET  "data_io[7]"                                LOC = "AF15" ;          #Bank 22
NET  "data_io[8]"                                LOC = "AH13" ;          #Bank 22
NET  "data_io[9]"                                LOC = "AH14" ;          #Bank 22
NET  "data_io[10]"                                LOC = "AH19" ;          #Bank 22
NET  "data_io[11]"                                LOC = "AH20" ;          #Bank 22
NET  "data_io[12]"                                LOC = "AG13" ;          #Bank 22
NET  "data_io[13]"                                LOC = "AH12" ;          #Bank 22
NET  "data_io[14]"                                LOC = "AH22" ;          #Bank 22
NET  "data_io[15]"                                LOC = "AG22" ;          #Bank 22    

 

Link to comment
Share on other sites

13 answers to this question

Recommended Posts

1st, I'm not Digilent.

2nd, I'm not sure I could debug your code from here.  Sorry.

Do you have the specification sheet for the strataflash?  I managed to get one for the device I was working with a while back by googling the part number.

3rd, I don't own a strataflash.  I was going to purchase the 3E development board at one time, and built all the RTL I thought I would need to support it, but given that I didn't buy the board, I don't know if any of the RTL I built would've truly worked.  I did manage to write a thorough testbench for the flash and Verilog to control the testbench, so I'm pretty confident that I was close to getting it to work.

4th, the approach I'm about to share did work for me on SPI flash--which I have gotten to work.

So, with all of the above caveats aside ...

Here's what has been successful for me: 1) I often write a simulator for the flash as my first step.  Some people call this a test-bench, although since I've been using Verilator as my build language, my "simulator"/testbenches are all built in C++ and they are fully functional. (I can even load my simulated flash with whatever I want initially, so that I can know the read works before the write.)  Building this required the specification sheet for the flash, and walking through that spec sheet over and over.  2) I then work my Verilog code against the simulator until it works.

For example, as I recall, the strataflash I was looking at had several different read modes and you had to carefully control and select which mode the device was in.  You could read various things from the device including status registers, ID fields, all in addition to the actual memory of the device.  By using my "simulator", I always knew what mode the flash was in versus what mode I wanted it to be in.  I could then guarantee all the transitions happened when I needed them to and so on.  For example, can you read the status register from the strataflash?  It might tell you what you are doing wrong.

Writing to a flash is much more complicated than writing to a memory.  You do know that you need to erase the flash first before you can write to it?  Erasing turns all the bits to '1's, writes selectively turn '1's to '0's.  Erases only work on blocks, so on and so forth.  It's really quite complicated.  You should become very familiar with the specification. 

I guess what I'm saying is, your code above looks a bit too simplistic.  Take a good long hard at the specification sheet.  Work your simulation hard.  Then, when all else is still failing, place some kind of scope on your interaction so that you can see what is going on in order to debug it.

Hope this helps,

Dan

 

Link to comment
Share on other sites

Thank you Dan for your reply.

It seems that writing to the strata flash is more complicated than what I thought. I was trying to write/read to/from it as if it is a memory by controlling the signals as described in the datasheet (page 22) (you can find it by googling the device number pc28f512p30t85...sorry I couldn't attach it since the file is bigger than what is allowed). I was doing this based on the few examples that I found on the net where their approaches were so simplistic, reads and writes are executed by controlling mainly the signals CE (chip enable), OE (output enable) and WE (write enable). I am really confused now, I don't know how to send commands to the strata flash and how to erase the memory or how exactly to proceed to reads and writes. The data sheet is not so clear on how doing that (or maybe I didn't get it well) and also there are no explicit examples from which we can learn how to use the strata flash as a simple memory. So any help would be appreciated. 

Thanks again Dan,

Anis 

Link to comment
Share on other sites

Don't forget to

1. Set the configuration register

2. Study the timing diagrams, and make certain you remain within limits.  These will often really help you understand what's going on as well.  "Often", not always ...

Good luck!

Dan

Link to comment
Share on other sites

Dear all,

i am also struggling with the same issue.i tried it on two kits.KC705 as well as Sparten3 starter kits.no success.

datasheet does not explain all the steps properly.

there is no step wise help available.

i tried to do read/write with different combination.look like device not responding.plz help.

Link to comment
Share on other sites

@csdwi,

If you don't understand the data sheet, then it's hard to draw the conclusion that the device isn't responding ...

But, let's back up. Flash isn't like memory that gets written in one cycle and then read again later.  To capture this, most flash memories discuss being "erased" and "programmed" rather than being written.  An "erase" cycle will turn a whole section of your flash memory to all '1's.  A programming cycle will turn some of those '1's back to '0's.  (The data sheet for the strataflash calls this a "write", but it's really not like your normal memory write at all.)  All of this takes time, and that time will seem like an eternity when compared to how long it takes to do the rest of your board's logic.

Now, let's back up and look at the strataflash on the Spartan 3E starter kit.  Judging by the schematic, it's a 28F256J3-TSOP56.  You can find the data sheet for that here.  Page 24 discusses the "block erase" operation.  Initiating a block erase takes "two cycle"s, meaning you need to send two separate and consecutive words to the flash to get it to erase.  Judging by page 40 of the flash data sheet, this erase operation may take anywhere between 1 and 5 seconds.  That's *really* slow when compared to the rest of anything you are doing with your FPGA.  It's also the *only* way to turn zero bits to one's.

If you back up in the datasheet, pages 17-18 discuss all of the various commands that can be given to the flash.  You'll want to place the device into the read array mode before most of what you wish to do.  However, when you want to change things, you'll need to exit that mode, issue a sector erase command, wait for it to complete, then "write to buffer", then "word/byte program" and again wait for that to complete.

Just remember ... a flash doesn't act like a normal memory.  You can almost access it like a normal ROM, but you will need to erase/program it to get it to contain the data you want.

Dan

Link to comment
Share on other sites

6 hours ago, D@n said:

@csdwi,

If you don't understand the data sheet, then it's hard to draw the conclusion that the device isn't responding ...

But, let's back up. Flash isn't like memory that gets written in one cycle and then read again later.  To capture this, most flash memories discuss being "erased" and "programmed" rather than being written.  An "erase" cycle will turn a whole section of your flash memory to all '1's.  A programming cycle will turn some of those '1's back to '0's.  (The data sheet for the strataflash calls this a "write", but it's really not like your normal memory write at all.)  All of this takes time, and that time will seem like an eternity when compared to how long it takes to do the rest of your board's logic.

Now, let's back up and look at the strataflash on the Spartan 3E starter kit.  Judging by the schematic, it's a 28F256J3-TSOP56.  You can find the data sheet for that here.  Page 24 discusses the "block erase" operation.  Initiating a block erase takes "two cycle"s, meaning you need to send two separate and consecutive words to the flash to get it to erase.  Judging by page 40 of the flash data sheet, this erase operation may take anywhere between 1 and 5 seconds.  That's *really* slow when compared to the rest of anything you are doing with your FPGA.  It's also the *only* way to turn zero bits to one's.

If you back up in the datasheet, pages 17-18 discuss all of the various commands that can be given to the flash.  You'll want to place the device into the read array mode before most of what you wish to do.  However, when you want to change things, you'll need to exit that mode, issue a sector erase command, wait for it to complete, then "write to buffer", then "word/byte program" and again wait for that to complete.

Just remember ... a flash doesn't act like a normal memory.  You can almost access it like a normal ROM, but you will need to erase/program it to get it to contain the data you want.

Dan

Dear Mr D@n

Thanks for ur quick reply.

I am new to this.so please avoid if i ask you stupid question.

First of all,i tried to read the device identifier register like device id vendor id etc.to read location 0x000000,i initiated write commind(0x90 with adress).then i simply initiated read command to read the content at the same location.nothing coming out.

For this operation,do we need to do sector  erase for this operation also?

 

 

Link to comment
Share on other sites

@csdwi,

To set any bits from 0 to 1, you will need to do a sector erase.  That will set the value of every bit within the sector to one.  To set a '1' bit to zero, you'll need to do a write-buffer command followed by a program command.  Expect this to take a while.

After any command, but before reading from the device, you need to issue a "Read Array" command.

Reading a vendor and/or device ID, and then verifying that they match the data sheet is a good way to begin.

Dan

Link to comment
Share on other sites

@csdwi,

Sorry, I don't have the strataflash, neither have I built any drivers for it.  I think there's a driver on opencores, but I also think its a read-only driver.  What I'm trying to say is that I'm not about to have any insights reading through your code (other than the fact that you are using an unreliable asynchronous reset--don't do that, check for your reset on the positive edge of the clock).

Let's see I understand correctly.  Your problem is 1) that your design doesn't work, 2) you don't know why not, 3) you've stared at your code over and over and 4) you are stuck.  Don't get me wrong, I'm not making fun of you our your situation--I'm trying to help.  This is a very common problem.  Many individuals, much like you, write in to the Digilent forum's with this same basic problem.  I like to say they are stuck in FPGA Hell.  The typical student ends up in FPGA Hell when they use the student's design process (pasted below).

student-design-process.thumb.png.2d6f9aad30bc61abe987876a40feba25.png

I discuss this problem on a blog I've been building at zipcpu.com.  I've also been working on developing and presenting a way out of that situation on the blog.  (You'll have to pardon if the solutions are all in Verilog ... :D )

The basic solution to your problem is twofold: first, simulate your design with a simulated flash driver (You may need to build the simulation).  You can find an example of the code I use to do that here, although it works for a QSPI flash and not a parallel flash.  (You can find copies of that code in other distributions of mine, in case OpenCores isn't responding well to  you.  Building component simulations is just so-useful/valuable, that I tend to reuse them a lot.)  You might struggle with this step, though, since you are struggling to understand what the flash data sheet is describing.  Trust me, I've been there.  This leads to the second component of the solution: you need to get a trace of your logic out of the FPGA, and you'll need that trace to include both the commands you are issuing as well as the responses from the flash.  Then, you'll need to take your trace and compare it against the timing diagrams on the flash data sheet.

If I understand correctly, Xilinx provides a ChipScope for this purpose.  I've never used it, but I'm sure others on this forum have.

There's no reason why you need a proprietary program to do this.

  • There's an open source logic probe posted on OpenCores that you can use.
  • I use my own Wishbone Scope.  Since it depends upon the pre-existence of a wishbone bus, I've been working through the design process and the steps necessary to implement your own serial-port controlled bus within an FPGA.  You can read about it on zipcpu.com.  As of yesterday's post on zipcpu.com, I've described how you can build a simulated bus that you can read and write from using serial port commands, and so you can read a trace back from your wishbone scope.  Indeed, yesterday's post goes even farther, to the point of describing how the whole test infrastructure can be simulated without needing an FPGA.  I expect to move forward with that design to provide controls whereby you might enable and read from that scope from host software, but I'm not there yet.  (I've got the software, debugged it yesterday, it works ... I just haven't written the post to accompany it yet.)  I've also got the software necessary to turn that scope's output into a VCD file that you can view with an open source tool like GTKWave, but again ... I haven't posted a discussion of how to do it yet.
  • You could also build your own.  It's not that hard to do.  These sorts of scopes and traces are examples of really simple logic (easier than the flash to work with).  Getting the trigger to line up with the data took some work, but it's quite doable.  There's no rocket science involved.

While most of my instructions are based upon a Linux host platform, I also have cygwin instructions for getting the open source tools I use installed on a machine running windows.  I'm holding them back, though, waiting for a Windows volunteer to test them before I post them.

While I realize this response wasn't what you were asking for, I hope it helps.  Feel free to keep writing though until you get unstuck.  I'll do my best to help, but I don't have the hardware you are working with.

Dan

 

 

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...