Forum: FPGA, VHDL & Co. VHDL Einsteiger: State-Machine?


von Simon K. (simon) Benutzerseite


Lesenswert?

Hallo,
Ich bräuchte mal etwas Hilfe zur "best practice". Ich habe eine H-Brücke 
an einen CPLD angeschlossen, den ich in VHDL programmiere.
Mein VHDL-Modul hat nun die folgende Portdefinition:
1
entity BridgeDriver is
2
    Port (
3
        ENABLE   : in  STD_LOGIC;
4
        IN_CLOCK : in  STD_LOGIC;
5
        OUT_BLI  : out STD_LOGIC;
6
        OUT_BHI   : out STD_LOGIC;
7
        OUT_ALI   : out STD_LOGIC;
8
        OUT_AHI  : out STD_LOGIC
9
    );
10
end BridgeDriver;

Jetzt will ich, nach einer steigenden Flanke von ENABLE einen bestimmten 
Ablauf haben. Also gewissermaßen eine Statemachine, die bei jeder 
steigenden Flanke von IN_CLOCK folgende Stati durchläuft:
- Alle OUT_XXX auf '0' setzen. (H-Brücke hochohmig)
- OUT_BLI und OUT_ALI auf '1' setzen. (Bootstrap Kondensatoren laden)
- Normale Funktion (z.B. togglen o.ä.)

Wie mache ich das jetzt am sinnvollsten in VHDL?
Zwei Prozesse für jeweils ENABLE und IN_CLOCK? Den aktuellen Zustand der 
Statemachine als Variable speichern?

von voodoofrei (Gast)


Lesenswert?


von Simon K. (simon) Benutzerseite


Lesenswert?

Das sieht schon sehr gut aus. Das führ ich mir mal zu Gemüte. Merci!

von Simon K. (simon) Benutzerseite


Angehängte Dateien:

Lesenswert?

Sehr schön. Also das folgende funktioniert schon direkt:
1
architecture Behavioral of BridgeDriver is
2
    type State_t is (Off, Start, Charge, Enabled, Running);
3
    signal State : State_t := Start;
4
    
5
    signal ALI : STD_LOGIC := '0';
6
    signal AHI : STD_LOGIC := '0';
7
    signal BLI : STD_LOGIC := '0';
8
    signal BHI : STD_LOGIC := '0';
9
    
10
begin
11
    process(IN_CLOCK, State)
12
    begin
13
        if rising_edge(IN_CLOCK) then
14
            case State is 
15
                when Start =>   ALI <= '0';
16
                                AHI <= '0';
17
                                BLI <= '0';
18
                                BHI <= '0';
19
                                State <= Charge;
20
                                        
21
                when Charge =>  ALI <= '1';
22
                                BLI <= '1';
23
                                State <= Enabled;
24
                
25
                when Enabled => ALI <= '0';
26
                                AHI <= '1';
27
                                State <= Running;
28
                                        
29
                when Running => ALI <= not ALI;
30
                                AHI <= not AHI;
31
32
                when others =>                                        
33
            end case;
34
        end if;
35
    end process;
36
    
37
    OUT_ALI <= ALI;
38
    OUT_AHI <= AHI;
39
    OUT_BLI <= BLI;
40
    OUT_BHI <= BHI;
41
        
42
end Behavioral;

Jetzt möchte ich aber in meinem CPLD asynchrone Logik entwickeln. Das 
heißt ich möchte jetzt, dass die Ausgänge asynchron verändert werden 
können. Das ganze soll ein Chopper-Stromgregler werden.

- Bei Taktbeginn (rising_edge von IN_CLOCK) sollen die Ausgänge gesetzt 
werden.
- Bei einem "Komparator-Interrupt" sollen die Ausgänge zurückgesetzt 
werden.

Ich dachte nun eigentlich, dass die Signale ALI, AHI, BLI, BHI intern 
als Flipflops realisiert werden (können). Und zwar ein solches FF, was 
asynchron gesetzt oder zurückgesetzt werden kann. Das Prinzipschaltbild 
ist mal im Anhang angehängt (Datenblatt L297).
Wenn ich allerdings einen zweiten Prozess machen möchte, der die Signale 
entsprechend zurücksetzt, dann beschwert sich VHDL darüber, dass die 
"Signals connected to multiple drivers".
1
    process(IN_COMP, State)
2
    begin
3
        if rising_edge(IN_COMP) then
4
            case State is
5
                when Enabled => ALI <= '1';
6
                                AHI <= '0';
7
                
8
                when others =>
9
            end case;
10
        end if;
11
    end process;

Ich bin ein Hardware Mensch und bin gerade etwas empört, dass man als 
Hardware Mensch erst wieder auf Software ebene "hochgehen" muss um 
Hardware zu definieren ;-) Sprich, ich weiß, wie die Hardware aussehen 
muss und muss jetzt einen Weg finden das korrekt in Software zu 
beschreiben.

von berndl (Gast)


Lesenswert?

Simon K. schrieb:
> Ich bin ein Hardware Mensch und bin gerade etwas empört, dass man als
> Hardware Mensch erst wieder auf Software ebene "hochgehen" muss um
> Hardware zu definieren ;-) Sprich, ich weiß, wie die Hardware aussehen
> muss und muss jetzt einen Weg finden das korrekt in Software zu
> beschreiben.

Wenn du HW-Mensch bist, dann wuerdest du aber bestimmt nicht 2 
Gatterausgaenge zusammenloeten und erwarten, dass das ganze noch 
funktioniert! Genau das machst du aber, wenn du an mehreren Stellen dem 
Signal etwas zuweist.
Wie wuerdest du das in HW loesen? Richtig, 2 Logiksignale die ueber 
einen Multiplexer verknuepft das endgueltige Signal ergeben.
Oder in VHDL/Verilog halt die ganzen Zuweisungen in einen Prozess 
schreiben, die HDLs bauen dir dann schon deinen Multiplexer.

PS: Wenn du das Signal IN_COMP auch noch mit deiner Clock sauber 
eintaktest (in 2 FFs) dann kannst du in deinem Prozess auch mit der 
Clock arbeiten und verwendest dann halt 'das letzte FF' deines 
IN_COMP_SR (Schieberegister).

von Simon K. (simon) Benutzerseite


Lesenswert?

berndl schrieb:
> Simon K. schrieb:
>> Ich bin ein Hardware Mensch und bin gerade etwas empört, dass man als
>> Hardware Mensch erst wieder auf Software ebene "hochgehen" muss um
>> Hardware zu definieren ;-) Sprich, ich weiß, wie die Hardware aussehen
>> muss und muss jetzt einen Weg finden das korrekt in Software zu
>> beschreiben.
>
> Wenn du HW-Mensch bist, dann wuerdest du aber bestimmt nicht 2
> Gatterausgaenge zusammenloeten und erwarten, dass das ganze noch
> funktioniert! Genau das machst du aber, wenn du an mehreren Stellen dem
> Signal etwas zuweist.
> Wie wuerdest du das in HW loesen? Richtig, 2 Logiksignale die ueber
> einen Multiplexer verknuepft das endgueltige Signal ergeben.
Nein, wie schon erwähnt und wie auch in Bildform angehangen möchte ich 
an der Stelle ein Flipflop haben. Ein Prozess setzt den Ausgang, der 
andere setzt ihn zurück.
DAS möchte ich machen. Und da ich meine öfter schon mal gelesen zu 
haben, dass Signale in Flipflops synthetisiert werden, dachte ich, dass 
das der richtige Weg ist.

> PS: Wenn du das Signal IN_COMP auch noch mit deiner Clock sauber
> eintaktest (in 2 FFs) dann kannst du in deinem Prozess auch mit der
> Clock arbeiten und verwendest dann halt 'das letzte FF' deines
> IN_COMP_SR (Schieberegister).
Ich möchte kein synchrones Design haben. Ich habe einen Choppertakt mit 
~30kHz. Der Komparatoreingang muss asynchron verarbeitet werden.

von Simon K. (simon) Benutzerseite


Lesenswert?

Ok. Typischer Fall von RTFM bzw. Lehrbuch ;-)
Flipflop mit Asynchronem Reset innerhalb eines Prozesses. So gehts:
1
    process(IN_CLOCK, IN_COMP, State)
2
    begin
3
        if IN_COMP = '1' then
4
            case State is
5
                when Enabled => ALI <= '1';
6
                                AHI <= '0';
7
                when others =>
8
            end case;
9
        elsif rising_edge(IN_CLOCK) then
10
            case State is 
11
                -- Give Gate Drivers some time to enable bridge
12
                when Start =>   ALI <= '0';
13
                                AHI <= '0';
14
                                BLI <= '0';
15
                                BHI <= '0';
16
                                State <= Charge;
17
                
18
                -- Charge bootstrap capacitors
19
                when Charge =>  ALI <= '1';
20
                                BLI <= '1';
21
                                State <= Enabled;
22
                
23
                when Enabled => ALI <= '0';
24
                                AHI <= '1';
25
                when others =>                                        
26
            end case;
27
        end if;
28
        
29
        OUT_ALI <= ALI;
30
        OUT_AHI <= AHI;
31
        OUT_BLI <= BLI;
32
        OUT_BHI <= BHI;
33
    
34
    end process;

Angenommen ich würde noch eine Flankenerkennung an IN_COMP wollen. Wie 
würde man da vorgehen? Oder geht das nicht?

von voodoofrei (Gast)


Lesenswert?

IN_COMP aus der Sensitivity-List nehmen!


1
Signal IN_COMP_H: std_logic;
2
3
if reset = '1' then
4
IN_COMP_H <= '0';
5
elsif rising_edge(IN_CLOCK) then
6
     IN_COMP_H <= IN_COMP;
7
     if(IN_COMP_H = '0' and IN_COMP = '1')
8
------- Flanke erkannt

von Simon K. (simon) Benutzerseite


Lesenswert?

Ich bin mir ziemlich sicher, dass damit wieder versucht wird IN_COMP auf 
den Choppertakt einzusynchronisieren.
Das ist in diesem Falle nicht möglich!

Der Choppertakt hat ~30kHz. Aber der Komparatorinterrupt kommt zwischen 
zwei Choppertakt-Flanken.
Der Choppertakt bestromt den Motor, der Komparator soll dafür sorgen, 
dass die Bestromung aufhört.

Aber mit dem asynchronen Reset funktioniert es jetzt gut.

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.