The 25LC256 SPI EEPROM needs some management, if you plan to write data to it. It's described in this app note. At startup, it's read-only. You need to enable write functionality and remove write protect. Once that's done, you can use the write functionality.
This is the sequence:
I need to send the 8 bit write-enable, then the 16 bit no-protection. Both should be wrapped inside a ~CS envelope.
I'm implementing the EEPROM VHDL as a state machine. Init at startup, then read, then wait for data and write. Once data is received and written, back to read. Because I'm managing the ~CS myself via bitbanging*, I'd like to keep each SPI sentence (a section wrapped inside a ~CS) as a state. So I split the init state in two:
- initialise Write Enable
- initialise No Protection
* The SPI module I selected doesn't support CS hold. It will hold CS low until the requested data size is sent. But that's a fixed size. The EEPROM has requirements to hold the CS until a activity is completed. In my case, that can be 1 byte for the WREN instruction, 2 bytes to write to a register, or 4 bytes to read/write data: instruction, 2 byte address, data. To get support for CS hold, I can:
I chose the 3rd option. |
My state machine will look like this:
- init WREN, then next
- init NOPROT, then next
- READ data from address, then next
- wait for data and WRITE to address, then 3
Here's the design. I tried to implement 1 and 2. The others just contain comments of what I think they 'll need to do:
architecture Behavioral of eeprom is TYPE FSM IS(init_wren, init_noprot, accept, read); --state machine SIGNAL state : FSM; SIGNAL step : integer range 0 to 5; begin PROCESS(clk, reset_n) BEGIN IF(reset_n = '0') THEN --reset everything state <= init_wren; step <= 0; bitbang_cs_n <= '1'; start <= '0'; ELSIF(rising_edge(clk)) THEN case state is when init_wren => -- init eeprom, enable writing if (step = 0) then -- send WREN cmd bitbang_cs_n <= '0'; step <= 1; -- next step data_out <= "00000110"; -- WREN (0x06) start <= '1'; elsif (step = 1) then -- wait for ack from spi if (busy = '1') then -- wait for spi buzy step <= 2; end if; elsif (step = 2) then -- finalise WREN if not (busy = '1') then -- wait until spi no longer buzy -- finished start <= '0'; state <= init_noprot; step <= 0; bitbang_cs_n <= '1'; end if; end if; when init_noprot => -- init eeprom, no write protect if (step = 0) then -- write status register (0x01) bitbang_cs_n <= '0'; step <= 1; -- next step data_out <= "00000001"; -- WRSR (0x01) start <= '1'; elsif (step = 1) then -- wait for ack from spi if (busy = '1') then -- wait for spi buzy step <= 2; end if; elsif (step = 2) then -- finalise WRSR if not (busy = '1') then -- wait until spi no longer buzy -- finished start <= '0'; step <= 3; end if; elsif (step = 3) then -- finalise WRSR step <= 4; -- next step data_out <= "00000000"; -- NOPROT (0x00) start <= '1'; elsif (step = 4) then -- wait for ack from spi if (busy = '1') then -- wait for spi buzy step <= 5; end if; elsif (step = 5) then -- finalise NOPROT if not (busy = '1') then -- wait until spi no longer buzy -- finished start <= '0'; state <= read; step <= 0; bitbang_cs_n <= '1'; end if; end if; when read => -- todo read from address -- todo READ cmd -- todo send address -- todo receive data -- finished state <= accept; step <= 0; WHEN accept => IF not (data_in (3 downto 0) = "0000") THEN -- todo write to address -- todo WRITE cmd -- todo send address -- todo send data -- finished state <= read; step <= 0; END IF; END CASE; END IF; END PROCESS; end Behavioral;
I think I'll have an issue with my CS bitbanging, as currently implemented. The state machine runs on a fast clock. The time between setting CS high and back low, between states, may be too short for the 25LC256. I know how to deal with that, but want to see if it's a real issue first.
edit: this works. See the comments below for the steps from fail to success...
checkpoints:
- CS low
- send 0x06
- CS high
- min 350 ns before next step: 9 µs (I check this specifically, because I'm bitbanging this signal. All others controlled bt the SPI IP).
- CS low
- send 0x01
- send 0x00
- CS high