mikrocontroller.net

Forum: FPGA, VHDL & Co. UART Transmitter, FSM


Autor: Daniel -------- (root)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Mein UART Transmitter will irgendwie nicht recht.
Nach mehrmaligen Wieder/Wieder/Wieder-Drüberschauen
finde meinen Fehler nicht. Deswegen stelle ich es hierein
damit frische Köpfe sich an anschauen ...
Wer welche Teile auch immer kritisieren möchte, möge es auch tun :)

In der Simulation klappt alles wie soll.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

-- transmission 'least significant bit first'

entity transmitter is
    generic(freq: integer := 100e6;
    baud: integer := 115200;
    nticks: integer := 16;
    databits: integer := 8;    -- allowed values 5-8
    paritybit: integer := 0;   
                -- 0 = no parity, 1 = odd, 2 = even
    stopbits: integer := 2);   -- only full, 1 or 2
    port(clk: in std_logic;
    reset: in std_logic;
    tx: out std_logic;
    done: out std_logic;
    busy: out std_logic;
    data: in std_logic_vector(databits-1 downto 0);
    take_data_pulse: in std_logic);
end entity;

architecture behaviour of transmitter is

    constant oversample_freq: integer := baud * nticks;
    constant n: integer := freq / oversample_freq;

    type fsm is (idle, start_transmit, 
                data_transmit, parity_transmit, 
                stop_transmit, done_pulse);
    signal state_reg, state_next: fsm := idle;
    
    signal count_reg, count_next: integer range 0 to n := 0;
    signal data_reg, data_next: std_logic_vector(databits-1 downto 0);
    
    signal dbits_reg, dbits_next: integer range 0 to databits := 0;
    signal sbits_reg, sbits_next: integer range 0 to stopbits := 0;
    
    signal even_parity, odd_parity: std_logic := '0';

begin

    update: process(clk, reset)
    begin
    if reset = '1' then
      state_reg <= idle;
      count_reg <= 0;
      data_reg <= (others => '0');
      dbits_reg <= 0;
      sbits_reg <= 0;
    elsif rising_edge(clk) then
      state_reg <= state_next;
      count_reg <= count_next;
      data_reg <= data_next;
      dbits_reg <= dbits_next;
      sbits_reg <= sbits_next;
    end if;
    end process;
    
    logic: process(state_reg, take_data_pulse, 
                    count_reg, dbits_reg, sbits_reg,
                    data_reg, even_parity, odd_parity)
    begin
    tx <= '0';
    busy <= '1';
    done <= '0';
    state_next <= state_reg;
    data_next <= data_reg;
    sbits_next <= sbits_reg;
    dbits_next <= dbits_reg;
    count_next <= count_reg;
    case state_reg is
      when idle =>
        tx <= '1';
        busy <= '0';
        count_next <= 0;
        if take_data_pulse = '1' then
          data_next <= data;
          sbits_next <= 0;
          dbits_next <= 0;
          state_next <= start_transmit;
        end if;
      when start_transmit => 
        tx <= '0';
        count_next <= count_reg + 1;
        if count_reg = n-1 then
          count_next <= 0;
          state_next <= data_transmit;
        end if;
      when data_transmit => 
        count_next <= count_reg + 1;
        tx <= data_reg(dbits_reg);
        if count_reg = n-1 then
          count_next <= 0;
          dbits_next <= dbits_reg + 1;
          if dbits_reg = databits-1 then
            if paritybit = 0 then
              state_next <= stop_transmit;
            else
              state_next <= parity_transmit;
            end if;
          end if;
        end if;
      when parity_transmit => 
        tx <= '0';
        count_next <= count_reg + 1;
        if count_reg = n-1 then
          count_next <= 0;
          state_next <= stop_transmit;
        end if;
        if paritybit = 1 then  -- should be made odd
          if even_parity = '1' then
            tx <= '1';
          else
            tx <= '0';
          end if;
        else      -- should be made even
          if even_parity = '1' then
            tx <= '0';
          else
            tx <= '1';
          end if;
        end if;
      when stop_transmit => 
        tx <= '1';
        count_next <= count_reg + 1;
        if count_reg = n-1 then
          count_next <= 0;
          sbits_next <= sbits_reg + 1;
          if sbits_reg = stopbits-1 then
            state_next <= done_pulse;
          end if;
        end if;
      when done_pulse => 
        tx <= '1';
        busy <= '0';
        done <= '1';
        state_next <= idle;
    end case;
    end process;
    
    parity: process(data_reg)
    variable even: std_logic;
  begin
    even := '1';
    for i in data_reg'range loop
      if data_reg(i) = '1' then
      even := not even;
      end if;
    end loop;
    even_parity <= even;
    odd_parity <= not even;
    end process;

end architecture;


Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du diesen Code simulierst, kann alles moegliche passieren, das sich 
in der Wirklichkeit ganz anders verhaelt - die sensitivity list ist bei 
weitem nicht vollstaendig.

Autor: Daniel (root) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
    logic: process(state_reg, take_data_pulse, 
                    count_reg, dbits_reg, sbits_reg,
                    data_reg, even_parity, odd_parity)


hmm .. sieht für mich vollständig aus. Alles worauf ich
lesend zugreife steht da.

Du hast mich auf die Frage gebracht ob generic Werte
auch in die sens. Liste reinsollen oder nicht. So wie
paritybit. Ich denke aber nicht, weil es eine Konstante ist.
Genauso wie n.

Autor: Peter A. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
probier es mal mit
 logic : process( count_reg, data, data_reg, dbits_reg, even_parity,
                   sbits_reg, state_reg, take_data_pulse)

und nein, deine generics muessen nicht in die sen liste, da die als 
konstanten behandelt werden.

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel (root) schrieb:
>
> hmm .. sieht für mich vollständig aus. Alles worauf ich
> lesend zugreife steht da.

z.B. data fehlt noch.

> Du hast mich auf die Frage gebracht ob generic Werte
> auch in die sens. Liste reinsollen oder nicht. So wie
> paritybit. Ich denke aber nicht, weil es eine Konstante ist.
> Genauso wie n.

Wie Peter schreibt, generics und Konstanten muessen nicht in die Liste.

Autor: Daniel (root) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke! tatsächlich data habe ich übersehen
in dem vorliegenden Fall hat es aber nichts ausgemacht, da auf
data nur in einem Taktzyklus zugegriffen wird, geschützt in if ...
im nächsten Zyklus ist FSM schon im anderen state und dann ist es
auch egal ob data sich ändert.

ich habe den Fehler gefunden!
wie immer sucht man erst woanders :)
es ist ein denkfehler gewesen
constant n: integer := freq / baud;

so sollte es ein. Die Überabtastung spielt nur im receiver eine Rolle
und denn habe ich zuerst geschrieben.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.