Forum: FPGA, VHDL & Co. M25P16 Ansteuereung


von Pat R. (patrik)


Lesenswert?

Hallo Leute,
ich versuche an meine Spartan 3E StarterKit den M25P16 Speicher 
anzusteuern(lesen + schreiben) aber irgendwie will er nicht.
Ich weiss nicht, ob es an meinem Code liegt oder sonst wo.
Hat jemand von euch ein VHDL Modul geschrieben, um den M25P16 
anzusteuern?

Danke
Patrik

von Pat R. (patrik)


Lesenswert?

Ich versuche folgendes:

architecture Behavioral of M25P16 is

type rdrs_fsm_type is(rdrs_wait_for_start, rdrs_cs, rdrs_w1, rdrs_pdw1,
rdrs_w1b, rdrs_w2, rdrs_pdw2, rdrs_w2b, rdrs_w3, rdrs_pdw3, rdrs_w3b,
rdrs_w4, rdrs_pdw4, rdrs_w4b, rdrs_w5, rdrs_pdw5, rdrs_w5b, rdrs_w6,
rdrs_pdw6, rdrs_w6b, rdrs_w7, rdrs_pdw7, rdrs_w7b, rdrs_r0, rdrs_pdr0,
rdrs_r0b, rdrs_r1, rdrs_pdr1, rdrs_r1b, rdrs_r2, rdrs_pdr2, rdrs_r2b,
rdrs_r3, rdrs_pdr3, rdrs_r3b, rdrs_r4, rdrs_pdr4, rdrs_r4b, rdrs_r5,
rdrs_pdr5, rdrs_r5b, rdrs_r6, rdrs_pdr6, rdrs_r6b, rdrs_r7, rdrs_pdr7,
rdrs_r7b);
signal rdrs_fsm : rdrs_fsm_type;

CONSTANT RDID : std_logic_vector(7 downto 0) := x"9F";

begin

    process(reset, clk)
    begin
      if reset = '1' then
        rdrs_fsm <= rdrs_wait_for_start;
        clk_out <= '0';
      elsif clk = '1' and clk'event then
        case rdrs_fsm is
          when rdrs_wait_for_start =>
            if start = '1' then
              cs <= '0';
              d <= RDID(7);
              rdrs_fsm <= rdrs_cs;
            else
              cs <= '1';
              clk_out <= '0';
            end if;
          when rdrs_cs =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_w1;
          when rdrs_w1 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdw1;
          when rdrs_pdw1 =>
            d <= RDID(6);
            rdrs_fsm <= rdrs_w1b;
          when rdrs_w1b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_w2;
          when rdrs_w2 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdw2;
          when rdrs_pdw2 =>
            d <= RDID(5);
            rdrs_fsm <= rdrs_w2b;
          when rdrs_w2b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_w3;
          when rdrs_w3 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdw3;
          when rdrs_pdw3 =>
            d <= RDID(4);
            rdrs_fsm <= rdrs_w3b;
          when rdrs_w3b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_w4;
          when rdrs_w4 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdw4;
          when rdrs_pdw4 =>
            d <= RDID(3);
            rdrs_fsm <= rdrs_w4b;
          when rdrs_w4b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_w5;
          when rdrs_w5 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdw5;
          when rdrs_pdw5 =>
            d <= RDID(2);
            rdrs_fsm <= rdrs_w5b;
          when rdrs_w5b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_w6;
          when rdrs_w6 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdw6;
          when rdrs_pdw6 =>
            d <= RDID(1);
            rdrs_fsm <= rdrs_w6b;
          when rdrs_w6b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_w7;
          when rdrs_w7 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdw7;
          when rdrs_pdw7 =>
            d <= RDID(0);
            rdrs_fsm <= rdrs_w7b;
          when rdrs_w7b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_r0;
          when rdrs_r0 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdr0;
          when rdrs_pdr0 =>
            data_out(7) <= q;
            rdrs_fsm <= rdrs_r0b;
          when rdrs_r0b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_r1;
          when rdrs_r1 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdr1;
          when rdrs_pdr1 =>
            data_out(6) <= q;
            rdrs_fsm <= rdrs_r1b;
          when rdrs_r1b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_r2;
          when rdrs_r2 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdr2;
          when rdrs_pdr2 =>
            data_out(5) <= q;
            rdrs_fsm <= rdrs_r2b;
          when rdrs_r2b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_r3;
          when rdrs_r3 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdr3;
          when rdrs_pdr3 =>
            data_out(4) <= q;
            rdrs_fsm <= rdrs_r3b;
          when rdrs_r3b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_r4;
          when rdrs_r4 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdr4;
          when rdrs_pdr4 =>
            data_out(3) <= q;
            rdrs_fsm <= rdrs_r4b;
          when rdrs_r4b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_r5;
          when rdrs_r5 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdr5;
          when rdrs_pdr5 =>
            data_out(2) <= q;
            rdrs_fsm <= rdrs_r5b;
          when rdrs_r5b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_r6;
          when rdrs_r6 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdr6;
          when rdrs_pdr6 =>
            data_out(1) <= q;
            rdrs_fsm <= rdrs_r6b;
          when rdrs_r6b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_r7;
          when rdrs_r7 =>
            clk_out <= '0';
            rdrs_fsm <= rdrs_pdr7;
          when rdrs_pdr7 =>
            data_out(0) <= q;
            rdrs_fsm <= rdrs_r7b;
          when rdrs_r7b =>
            clk_out <= '1';
            rdrs_fsm <= rdrs_wait_for_start;
        end case;
      end if;
    end process;

end Behavioral;



Das ist nichts anderes, als den Befehl 0x9F zum Speicher zu schicken und 
damit das ID auszulesen. Ich bekomme aber nur Müll. Der Speicher an sich 
funktioniert, die Applikation 'Picoblaze SPI FLASH Programmer' vom 
Xilinx funktioniert einwandfrei. Wenn ich mir die Doku zu dieser 
Anwendung anschaue, dann macht mein Code das selbe(bzw. ich weiss nicht 
bei welcher Flanke ich anfangen soll zu lesen, aber das würde die Bits 
im Ergebniss nur um eine Stelle verschieben) aber es geht nicht :(

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> dann macht mein Code das selbe
hast du das Design schon mal simuliert?

> bzw. ich weiss nicht bei welcher Flanke ich anfangen soll zu lesen
Dazu gibt es das Datenblatt.

Du kannst immer 2 deiner Zustände zusammenfassen, weil bei SPI nicht 
zwischen den Flanken vom Takt etwas passiert, sondern wegen (und 
damit an) den Flanken vom Takt.
SPI ist nichts anderes als gekoppelte Schieberegister.

Dein Code:
1
          when rdrs_pdw1 =>
2
            d <= RDID(6);
3
            rdrs_fsm <= rdrs_w1b;
4
          when rdrs_w1b =>
5
            clk_out <= '1';
6
            rdrs_fsm <= rdrs_w2;
7
          when rdrs_w2 =>
8
            clk_out <= '0';
9
            rdrs_fsm <= rdrs_pdw2;
10
          when rdrs_pdw2 =>
11
            d <= RDID(5);
12
            rdrs_fsm <= rdrs_w2b;
13
          when rdrs_w2b =>
14
            clk_out <= '1';
15
            rdrs_fsm <= rdrs_w3;
16
          when rdrs_w3 =>
17
            clk_out <= '0';
18
            rdrs_fsm <= rdrs_pdw3;

Kompakter:
1
          when rdrs_w1 =>
2
            clk_out <= '0';   -- gleichzeitig mit fallender Flanke
3
            d <= RDID(6);     -- Daten ändern
4
            rdrs_fsm <= rdrs_w1b;
5
          when rdrs_w1b =>
6
            clk_out <= '1';
7
            rdrs_fsm <= rdrs_w2;
8
          when rdrs_w2 =>
9
            clk_out <= '0';
10
            d <= RDID(5);
11
            rdrs_fsm <= rdrs_w2b;
12
          when rdrs_w2b =>
13
            clk_out <= '1';
14
            rdrs_fsm <= rdrs_w3;
15
          when rdrs_w3 =>
16
            clk_out <= '0';
17
            d <= RDID(4);
18
          :
19
          :
20
          when rdrs_r2 =>
21
            clk_out <= '0';
22
            rdrs_fsm <= rdrs_pdr2;
23
          when rdrs_pdr2 =>
24
            clk_out <= '1';
25
            data_out(5) <= q;     -- mit der steigenden Flanke
26
            rdrs_fsm <= rdrs_r3;  -- die Daten einlesen
27
          when rdrs_r3 =>
28
            clk_out <= '0';
29
            rdrs_fsm <= rdrs_pdr3;
30
          when rdrs_pdr3 =>
31
            clk_out <= '1';
32
            data_out(4) <= q;
33
            rdrs_fsm <= rdrs_r4;
34
          when rdrs_r4 =>
35
            clk_out <= '0';
36
            rdrs_fsm <= rdrs_pdr4;

Aber solche Copy-Paste-Statemachines sind Käse. Nicht skalierbar, voller 
Tippfehler (sag bloß nicht, da sei keiner dringewesen ;-) usw.

Du solltest vorher überlegen, was du eigentlich brauchst.
Für SPI: ein Schieberegister, nicht einen Multiplexer.

von Pat R. (patrik)


Lesenswert?

Ursprünglich habe ich das so gehabt wie du es vorgeschlagen hast. Dann 
habe ich mir das 'Picoblaze SPI FLASH Programmer' Beispiel angeschaut, 
und sie machen es so, dass die Daten gesetzt/gelesen werden, und dann 
generieren sie eine High-Low Flanke auf Clock signal. Um sicher zu 
gehen, habe ich das auch so implementiert, kein Erfolg. Simuliert habe 
ich das auch, bekomme genau das was im Datenblatt steht.
Ich glaube langsam, der Fehler liegt nicht im Quellcode. Der SPI Bus auf 
dem Board wird mit anderen Bausteinen geteilt. Diese muss man 
'deaktivieren' damit man auf den Flash ansteuern kann. Das habe ich zwar 
gemacht, aber möglicherweise nicht richtig. Ich glaube, ich kaufe mir 
einen solchen Speicher und versuche ihn so anzusteuern denn ich habe 
keine Idee mehr :(

patrik

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> 'Picoblaze SPI FLASH Programmer' Beispiel angeschaut,
> und sie machen es so, dass die Daten gesetzt/gelesen werden,
> und dann generieren sie eine High-Low Flanke auf Clock signal.
Ja, klar. Dort ist es reine Software, deshalb wird es sequentiell 
gemacht.

> Der SPI Bus auf dem Board wird mit anderen Bausteinen geteilt.
> Diese muss man 'deaktivieren' damit man auf den Flash ansteuern kann.
Die anderen Bausteine müssen natürlich alle deselektiert (inaktiv) sein. 
sonst gehts schief. Üblicherweise also auf den SS# eine '1' legen.

Hast du schon mal am Bus und den anderen Bausteinen gemessen?
Die Hardware ist ok, mit dem Picoblaze gehts ja.

von Pat R. (patrik)


Lesenswert?

Ich habe es nun an Oszi angeschlossen. Der Speicher bekommt das richtige 
Signal, liefert aus das richtige, aber eben High sind keine 3.3V sondern 
nur irgendwie 1.3V. Irgendetwas stört das MISO Signal. Ich habe die 
Constraints-Datei von dem 'Picoblaze SPI FLASH Programmer' Beispiel 
genommen, mit meiner verglichen und die Signale gemessen, alles gleich. 
Keine Idee mehr.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Ich habe es nun an Oszi angeschlossen. Der Speicher bekommt das
> richtige Signal, liefert aus das richtige, aber eben High sind
> keine 3.3V sondern nur irgendwie 1.3V.
> Irgendetwas stört das MISO Signal.
Buskonflikt. Zwei Teilnehmer sind auf dem Bus, eine Pattsituation.

Sind tatsächlich alle anderen SPI-Busteilnehmer korrekt deselektiert?
Ist dein FPGA-Pin q als Eingang definiert (nicht z.B. inout)?

von Pat R. (patrik)


Lesenswert?

Hallo Leute,
habe nun das Projekt wieder ausgegraben und nach langem Suchen 
festgestellt, dass das tatsächlich ein Buskonflikt war und zwar mit dem 
Platform Flash PROM. Der Signal FPGA_INIT_B muss auf 0 stehen, und nicht 
auf 1 wie es in der Doku auf Seite 102 steht. Naja, hoffe jemandem 
geholfen zu haben :-)

Grüsse
Patrik

von Gast (Gast)


Lesenswert?

Wow lustig :) Die letzte Antwort war genau vor einem Jahr -2 Tage :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.