Forum: FPGA, VHDL & Co. Hilfe bei VHDL für Schieberegister mit einigen Extras


von noips (Gast)


Lesenswert?

Hallo zusammen,

ich will mit einem CPLD von Lattice ein Schieberegister realisieren. Der 
soll bei der Kombination '101' an Eingängen SS0, SS1, und SS2 aktiv 
werden, also bei fallender SCLK-Flanke die Daten an SDI einlesen und 
wenn die Kombination '101' weg ist (also gerade bei diesem Ereignis) 
sollen die Daten ausgewertet und abhängig davon, bestimmte Ausgänge 
gesetzt werden. Die Simulation mit Active-HDL bringt gewünschtes 
Verhalten, der CPLD will aber nicht, wenn ich ihn mit dem daraus 
erzeugten File programmiere. Könntet ihr bitte drüberschauen und wenn 
was auffällt, was nicht OK ist, mir einen Hinweis geben.

Danke schon mal!
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.std_logic_arith.all;
4
use ieee.std_logic_unsigned.all;
5
--use WORK.types.all;
6
7
entity gain_logic is
8
  generic (--CONFIG_par  : integer := 1;
9
       DATA_LENGTH : integer := 16);
10
       --SS_NUMBER   : integer := SS_NUMBER;
11
       --SPI_NUMBER  : integer := SPI_NUMBER);
12
13
  port (
14
15
    SS0      : in std_logic;
16
    SS1      : in std_logic;
17
    SS2      : in std_logic;
18
    SCLK    : in std_logic;
19
    SDI      : in std_logic;
20
    SLV_NR    : in std_logic_vector(3 downto 0);
21
    
22
    CONVST    : out std_logic;
23
    CS1      : out std_logic;
24
    CS2      : out std_logic;
25
    Gain_1    : out std_logic_vector(2 downto 0);
26
    Gain_2    : out std_logic_vector(2 downto 0);
27
    Gain_3    : out std_logic_vector(2 downto 0);
28
    Gain_4    : out std_logic_vector(2 downto 0);
29
    Gain_5    : out std_logic_vector(2 downto 0);
30
    Gain_6    : out std_logic_vector(2 downto 0);
31
    Gain_7    : out std_logic_vector(2 downto 0);
32
    Gain_8    : out std_logic_vector(2 downto 0)
33
    );
34
end;
35
36
architecture rtl of gain_logic is
37
38
  signal data_in    : std_logic_vector(DATA_LENGTH-1 downto 0) := X"0000";
39
  signal SS_vec    : std_logic_vector(2 downto 0);
40
  signal SS      : std_logic;
41
  -- type gain_array is array (1 to 8) of std_logic_vector(2 downto 0);
42
  -- signal gain_ar_s  : gain_array;
43
  signal chan_nr    : std_logic_vector(2 downto 0) := "000";
44
  signal gain      : std_logic_vector(2 downto 0) := "000";
45
  signal slave_nr    : std_logic_vector(3 downto 0) := "0000";
46
                                                     
47
  signal gain_1_s    : std_logic_vector(2 downto 0) := "000";
48
  signal gain_2_s    : std_logic_vector(2 downto 0) := "000";
49
  signal gain_3_s    : std_logic_vector(2 downto 0) := "000";
50
  signal gain_4_s    : std_logic_vector(2 downto 0) := "000";
51
  signal gain_5_s    : std_logic_vector(2 downto 0) := "000";
52
  signal gain_6_s    : std_logic_vector(2 downto 0) := "000";
53
  signal gain_7_s    : std_logic_vector(2 downto 0) := "000";
54
  signal gain_8_s    : std_logic_vector(2 downto 0) := "000";
55
56
  
57
begin
58
  
59
  SS <= not(SS2 and not SS1 and SS0);
60
  CS2 <= SS;
61
  
62
  SS_vec <= SS2 & SS1 & SS0;            --      15      |     |     |            0
63
  slave_nr <= data_in(15 downto 12);    --      |x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|x|
64
  chan_nr  <= data_in(11 downto 9);     --      |       |     |     |            
65
  gain     <= data_in(8 downto 6);      --      |slave  |chan.|gain |
66
                                        --      |nr.    |nr.  |     |
67
  Gain_1  <= gain_1_s;
68
  Gain_2  <= gain_2_s;
69
  Gain_3  <= gain_3_s;
70
  Gain_4  <= gain_4_s;
71
  Gain_5  <= gain_5_s;
72
  Gain_6  <= gain_6_s;
73
  Gain_7  <= gain_7_s;
74
  Gain_8  <= gain_8_s;
75
  
76
  
77
  process (SS_vec, SCLK, SS, chan_nr, slave_nr) begin
78
   if SS_vec = "101" then
79
    if (falling_edge(SCLK)) then
80
      data_in <= data_in(DATA_LENGTH-2 downto 0) & SDI;
81
    end if;
82
   end if;
83
   if (rising_edge(SS)) then
84
    if (slave_nr = SLV_NR) then
85
      case chan_nr is
86
        when "000"     => gain_1_s <= gain;
87
        when "001"     => gain_2_s <= gain;
88
        when "010"     => gain_3_s <= gain;
89
        when "011"     => gain_4_s <= gain;
90
        when "100"     => gain_5_s <= gain;
91
        when "101"     => gain_6_s <= gain;
92
        when "110"     => gain_7_s <= gain;
93
        when "111"     => gain_8_s <= gain;
94
        --when others    => gain_1_s <= "000";
95
      end case;
96
    end if;
97
   end if;
98
  end process;
99
100
end rtl;

von Der Besucher (Gast)


Lesenswert?

if SS_vec = "101" then
    if (falling_edge(SCLK)) then
      data_in <= data_in(DATA_LENGTH-2 downto 0) & SDI;
    end if;
   end if;

Vertausche mal die beide Abfragen. Vielleichts gehts dann.

Der Besucher

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


Lesenswert?

Der Besucher schrieb:
> Vertausche mal die beide Abfragen. Vielleichts gehts dann.
Daran liegts nicht. Die Synthesetools erkennen heutzutage den etwas 
seltsam geschriebenen Clock-Enable:
http://www.lothar-miller.de/s9y/categories/6-Clock-Enable

noips schrieb:
> der CPLD will aber nicht, wenn ich ihn mit dem daraus
> erzeugten File programmiere.
Wundert mich, dass dir die Synthese da nicht auf die Finger klopft:
1
    if (falling_edge(SCLK)) then
2
      data_in <= data_in(DATA_LENGTH-2 downto 0) & SDI;
3
    end if;
4
   end if;
5
   if (rising_edge(SS)) then
6
     if (slave_nr = SLV_NR) then
Das ist nur unübersichtlich, wenn du alles in einen Prozess reinstopfst. 
Trenn doch wenigstens die beiden Takte auf:
http://www.lothar-miller.de/s9y/categories/26-SPI-Slave

Lass dir doch mal den RTL-Plan anzeigen, dann siehst du ja, ob in etwa 
das rauskommt, was du willst...

noips schrieb:
> der CPLD will aber nicht,
Und was will er nicht?

von noips (Gast)


Lesenswert?

Lothar Miller schrieb:
> Und was will er nicht?

An den Ausgängen Gain_x sind LEDs geschaltet. Wenn ich Daten in den CPLD 
schreibe, sollten sie ja an den LEDs sichtbar sein, es ist aber keine 
Reaktion zu sehen.

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


Lesenswert?

Jetzt seh ichs gerade:
1
  SS <= not(SS2 and not SS1 and SS0);
2
3
     if (rising_edge(SS)) then
Das ist ein absolutes No-Go! Man verwendet nicht eine kombinatorische 
Verknüpfung als Taktsignal. Stichwort: Glitches.

Probier dein Design doch mal mit einem einzigen SS-Signal aus. Und dann 
überleg dir, warum das bei SPI so üblich ist...

von noips (Gast)


Lesenswert?

Lothar Miller schrieb:
> Probier dein Design doch mal mit einem einzigen SS-Signal aus.

Hm, ich habe aber nur 3 SS-Leitungen und benutze sie für mehrere Sachen. 
Wenn ich eine SS-Leitung für Schieberegister nehme, dann reichen die mir 
nicht, so muss ich Kombinationen verwenden.

Kurz gesagt, genau bei dem Ereignis, wenn "SS2 & SS1 & SS0" ungleich 
"101" wird, wollte ich was machen. Früher hatte ich das so in VHDL:
1
if SS_vec'event and SS_vec /= "101" then

wobei SS_vec gleich "SS2 & SS1 & SS0" ist. In Simulation ging es, das 
Synthese-Tool weigert sich aber das zu akzeptieren, deswegen bin ich den 
Umweg gegangen mit der Verknüpfung der Signale SS1 bis SS3 zu SS und mit 
Flankenauswertung an SS.

Kann man es den gar nicht so machen, wie ich es mir vorgestellt habe?

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


Lesenswert?

noips schrieb:
> Hm, ich habe aber nur 3 SS-Leitungen und benutze sie für mehrere Sachen.
> Wenn ich eine SS-Leitung für Schieberegister nehme, dann reichen die mir
> nicht, so muss ich Kombinationen verwenden.
Es wird aber einfach nicht zuverlässig gehen. Wenn du deine SS z.B. von 
"111" nach "000" umschaltest, dann kann das gut so aussehen:
SS
0     11111111000000
1     11111000000000
2     11111110000000
Und damit sieht dein interner SS so aus:
      11111001111111
Und du hast deine steigende Flanke, obwohl dein CPLD nicht selektiert 
war.

Das geht auch mit beliebigen anderen Bitkombinationen:
0     00001111111111
1     11111000000000
2     11111110000000
SSint 11111001111111

> Kann man es den gar nicht so machen, wie ich es mir vorgestellt habe?
Man kann schon. Es kann auch gehen. Aber Murks bleibt Murks.

von noips (Gast)


Lesenswert?

Lothar Miller schrieb:
> Probier dein Design doch mal mit einem einzigen SS-Signal aus. Und dann
> überleg dir, warum das bei SPI so üblich ist...

Das mit den Glitches ist einleuchtend, aber ich denke, das ist nur dann 
kritisch, wenn man die "Flanke" eines zusammengestzten SS-Signals nutzen 
will. Wenn der Pegel (im Gegensazt zu Flanke) des Signals zur 
Unterscheidung genutzt wird (z.B. zur Aktivierung des Schieberegisters), 
so ist das doch nicht kritisch, vorausgesetzt, man wartet lange genug, 
bis sich alle Signalbestandteile "eingependelt" haben und taktet erst 
dann Daten ein. Dann werde ich diesen Umweg gehen müssen.

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


Lesenswert?

noips schrieb:
> Wenn der Pegel (im Gegensazt zu Flanke) des Signals zur Unterscheidung
> genutzt wird (z.B. zur Aktivierung des Schieberegisters)
Es wird nicht besser, wenn du statt Flipflops Latches nimmst, denn auch 
ein Latch reagiert unschön auf Glitches. Zeichne es dir einfach mal auf.

Ich würde einfach mal in Richtung Daisy-Chain gehen, und nicht alle 
SPI-Devices parallel anschließen, sondern hintereinander. Dann würde 
im Extremfall sogar 1 SS ausreichen...

von noips (Gast)


Lesenswert?

Ich weiß noch, dass wir im Studium zum Anschließen mehrerer 
Speicherbausteine am Datenbus eines Prozessors aus den oberen 
Adressleitungen mit Kombinatorik die Chip-Selects für einzelne 
Speicherbausteine erzeugt haben und das galt als gängige Praxis. Solange 
man mit dem Schreiben von Daten etwas wartet ist es doch nicht kritisch, 
wenn ein Baustein beim Wechseln des Zustandes von inaktiv zu aktiv paar 
mal zwischen den beiden Zuständen pendelt bevor er engültig aktiv ist. 
Hauptsache, dass der sicher aktiv ist, wenn Daten kommen. Oder wo siehst 
du genau das Problem?

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


Lesenswert?

noips schrieb:
> Oder wo siehst du genau das Problem?
Dass du Birnen und Rüben verwechselst: bei dem beschriebenen Bus war die 
Select-Leitung nur eine "abgekürzte" Schreibweise für einen 
Adressbereich und hatte wie die Adressleitungen für sich selber keine 
Funktion. Erst mit RD# oder WR# zusammen wurde dieses kombinatorisch 
erzeugte Signal ausgewertet. Und zu diesem Zeitpunkt konnte man sicher 
sein, dass das Signal stabil und irgendwelche Glitches, die da beim 
Umschalten sicher noch drauf waren, verschwunden waren.

Aber du verwendest dieses Signal jetzt direkt für eine Aktion: die 
Datenübernahme aus dem Schieberegister. Dir können die Glitches also 
nie&nimmer egal sein, weil die Datenübernahme-Hardware immer aktiv ist 
und auf jede Flanke reagieren wird.

Und das ist der grundlegende Unterschied zwischen damals und jetzt.


Und wie gesagt solltest du dich bei solchen augenscheinlich genialen 
Ideen immer fragen: Warum ist da noch keiner draufgekommen?

von noips (Gast)


Lesenswert?

OK, endlich geschnallt! Vielen Dank!

von Falk B. (falk)


Lesenswert?

Siehe Glitch

von noips (Gast)


Lesenswert?

Bitte verzeiht mir meine Hartnäckigkeit, aber ich möchte alle 
einfacheren Wege wirklich ausgeschlossen wissen, bevor ich anfange 
meinen Konzept aufwendig umzuändern. Ich habe viele Slaves auf längere 
Distanz mit differentieller Übertragung und jeder neue SS-Signal sind 2 
Adern mehr (als Folge größere Stecker, mehr Platz auf Leiterplatte, 
dickere Kabel). Ich sehe da noch eine folgende Möglichkeit:

Wie ich es verstanden habe, braucht es einer einzigen sauberen Flanke 
auf Slave-Select, damit die Daten aus dem SPI-Schieberegister, die 
vollständig eingetaktet wurden, sauber in einen, sagen wir mal, 
parallelen Ausgangsregister übernommen werden. In meiner Vorstellung 
sollte folgendes funktionieren können:

Zur Aktivierung des Schieberegisters nimmt man ein mit Kombinatorik 
verknüpftes Signal und beginnt mit der Datenübertragung nur dann , wenn 
alle Glitches sicher vorbei sind. Zur Übernahme der Daten nimmt man aber 
nur eines von diesen mehreren SS-Signalen (aus denen sich das Signal zur 
Aktivierung bildet) von dem man sicher weiß, dass es eine Flanke 
enthält.

Nach diesem Schema:

                 Nr. des gerade    Übernahme bei
SS2  SS1  SS0    aktiven Slaves    steig. Flanke auf
---------------------------------------------------------
 1    1    1         ---              ----
 1    1    0          1                SS0
 1    0    1          2                SS1
 1    0    0          3              SS0 oder SS1
 0    1    1          4                SS2
 0    1    0          5              SS2 oder SS0
 0    0    1          6              SS2 oder SS1
 0    0    0          7              SS2 oder SS1 oder SS0


Auf diese Weise liest immer nur der gerade aktive Slave die Daten auf 
SDI ein. Die Daten aus dem Schieberegister in den Ausgangsregister 
werden gleichzeitig bei mehreren Slaves übernommen (bei allen die mit 
dem gleichen SS-Signal getrigert sind), aber wenn die Daten im 
Schieberegister sich nicht geändert haben (wenn der Slave inaktiv war), 
ändern sich die Zustände an den parallelen Ausgängen nicht. Das sollte 
zuverlässig funktionieren.


Lothar Miller schrieb:
> Und wie gesagt solltest du dich bei solchen augenscheinlich genialen
> Ideen immer fragen: Warum ist da noch keiner draufgekommen?

Bitte versteht mich richtig, ich behaupte hier nicht, ich finde die 
Lösung eines Problems, welches Scharen von Entwicklern in Jahrzenhnten 
vor mir nicht lösen konnten. Es kann ja sein, dass Lösungen möglich sind 
und schon mehrfach gefunden sind und funktionieren, nur ich weiß nichts 
davon, sonst würde ich ja sofort Gebrauch davon machen.

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


Lesenswert?

noips schrieb:
> Das sollte zuverlässig funktionieren.
Richtig, das hört sich hinreichend komplex an und ausreichend weit von 
der ursprünglichen SPI Spec weg, so dass es funktionieren sollte...  ;-)


Ich könnte mir aber noch was anderes vorstellen:
Jeder SPI-Slave hat eine Adresse (z.B. über DIP-Schalter einstellbar). 
Es werden mit einem CS immer alle selektiert und alle hängen parallel 
mit Din sowie Dout zusammen. Die ersten (z.B. 8) übertragenen Bits 
enthalten die Adresse, und eine Logik im Slave vergleicht diese Bits mit 
der eigenen Adresse. Wenn die beiden zusammenpassen, geht die 
eigentliche SPI-Übertragung mit dem selektierten Slave los...
So könnte man mit 1 SS und 8 Bit insgesamt 256 Slaves adressieren.

von Falk B. (falk)


Lesenswert?

@  noips (Gast)

>Wie ich es verstanden habe, braucht es einer einzigen sauberen Flanke
>auf Slave-Select,

Nö, in deiner Schaltung. WOHER die kommt, ist zweitrangig.

>Zur Aktivierung des Schieberegisters nimmt man ein mit Kombinatorik
>verknüpftes Signal und beginnt mit der Datenübertragung nur dann , wenn
>alle Glitches sicher vorbei sind.

Ja, z.B. indem man aus n Leitungen einen 1 aus N Dekoder baut, der das 
Chiüp Select dekodiert. Dier wird als CE (clock enable) genutzt.

> Zur Übernahme der Daten nimmt man aber
>nur eines von diesen mehreren SS-Signalen (aus denen sich das Signal zur
>Aktivierung bildet) von dem man sicher weiß, dass es eine Flanke
>enthält.

Kann man machen.

>Nach diesem Schema:

Kann man auch einfacher darstellen. 2 Bit adresse, 1 Bit Chip Select für 
alle. Wenn gleich die Bezeichung dann irreführend ist. Strobe, Store 
oder Sync trifft es eher.

>ändern sich die Zustände an den parallelen Ausgängen nicht. Das sollte
>zuverlässig funktionieren.

Ja.

MFG
Falk

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.