Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Discussione sul trasmettitore UART

Elettronica lineare e digitale: didattica ed applicazioni

Moderatori: Foto Utenteg.schgor, Foto UtenteBrunoValente, Foto Utentecarloc, Foto UtenteDirtyDeeds, Foto UtenteIsidoroKZ

0
voti

[21] Re: Discussione sul trasmettitore UART

Messaggioda Foto Utentedadduni » 19 set 2018, 11:48

Mi sta un attimo esplodendo il cervello. Se nel codice di luxinterior quello che lui ha chiamato CLK_OUT dovesse essere un registro, per inizializzarlo "come si deve" si avrebbero bisogno di due segnali tipo ClkOutxSP e ClkOutSN (present state e next state) e di due processi, uno combinatorio che calcola il next state e uno sequenziale che aggiorna il present state al momento giusto? Ma cosi non se ne esce vivi però.....
Avatar utente
Foto Utentedadduni
1.602 1 6 12
Expert EY
Expert EY
 
Messaggi: 976
Iscritto il: 23 mag 2014, 16:26

0
voti

[22] Re: Discussione sul trasmettitore UART

Messaggioda Foto Utentedadduni » 19 set 2018, 16:14

Io da ignorante la divisione del clock la farei così. Viene un codice più complesso del tuo ma ci sono processi sequenziali e combinatori separati e lo schema rispecchia quello che avevo in mente.
L'unico fatto che non mi convince è che il contatore deve contare fino ad un certo numero, dopo del quale deve resettarsi e tenere alto l'enable per un ciclo di clock. Per fare questo confronto (che ho scritto con una uguaglianza in una if) Vivado lo sintetizza con una ROM. Bho.

clockdivider.zip
(3.7 KiB) Scaricato 15 volte
Avatar utente
Foto Utentedadduni
1.602 1 6 12
Expert EY
Expert EY
 
Messaggi: 976
Iscritto il: 23 mag 2014, 16:26

0
voti

[23] Re: Discussione sul trasmettitore UART

Messaggioda Foto Utenteluxinterior » 19 set 2018, 17:18

Ma infatti la mia procedura va riscritta alla luce di quanto avete detto.
Grazie Foto Utentedadduni stasera mi studio il tuo codice
Avatar utente
Foto Utenteluxinterior
2.279 2 4 8
Expert EY
Expert EY
 
Messaggi: 1303
Iscritto il: 6 gen 2016, 17:48

1
voti

[24] Re: Discussione sul trasmettitore UART

Messaggioda Foto Utenteboiler » 19 set 2018, 21:59

Aggiungo il resto della UART, così l'entità è completa.
Il resto delle risposte deve aspettare ancora un po', forse domani trovo un attimo.

Foto Utenteluxinterior, per sapere se devo partire da Adamo ed Eva o meno... hai seguito un corso di VLSI?

Ci ricordiamo che della UART mancavano ancora le parti combinatorie delle due FSM.

Iniziamo con quella per la trasmissione:
Codice: Seleziona tutto
  tx_fsm : process (TXbitcountxSP, TXclkcountxSP, TXshiftregxSP, TXstatexSP, TxDataxDI, TxstartxSI) is
  begin  -- process tx_fsm

    TXstatexSN    <= TXstatexSP;
    TXclkcountxSN <= TXclkcountxSP;
    TXbitcountxSN <= TXbitcountxSP;
    TXshiftregxSN <= TXshiftregxSP;

    case TXstatexSP is
      when idle =>
   TxxSO <= '1';
        if TxstartxSI = '1' then
          TXclkcountxSN <= 0;
          TXbitcountxSN <= 0;
          TXshiftregxSN <= TxDataxDI;
          TXstatexSN    <= startbit;
        end if;

      when startbit =>
        TxxSO <= '0';
        if TXclkcountxSP = CLKFREQ/BAUD-1 then
          TXstatexSN    <= data;
          TXclkcountxSN <= 0;
        else
          TXclkcountxSN <= TXclkcountxSP +1;
        end if;

      when data =>
        TxxSO         <= TXshiftregxSP(0);
        TXclkcountxSN <= TXclkcountxSP+1;
        if TXclkcountxSP = CLKFREQ/BAUD-1 and TXbitcountxSP < 8 then
          TXbitcountxSN <= TXbitcountxSP +1;
          TXclkcountxSN <= 0;
          TXshiftregxSN <= '1' & TXshiftregxSP(7 downto 1);
        elsif TXclkcountxSP = CLKFREQ/BAUD-1 and TXbitcountxSP = 8 then
          TXclkcountxSN <= 0;
          TXstatexSN    <= stopbit;
        end if;

      when stopbit =>
        TxxSO <= '1';
        if TXclkcountxSP = CLKFREQ/BAUD-1 then
          TXstatexSN    <= idle;
          TXclkcountxSN <= 0;
        else
          TXclkcountxSN <= TXclkcountxSP +1;
        end if;
       
      when others => TXstatexSN <= idle;
    end case;
   
  end process tx_fsm;


All'inizio assegno i valori correnti alle variabili, così che se non cambia nulla (restiamo nello stesso stato della FSM) non devo esplicitamente riassegnare il valore.

Dopodiché viene il case-statement che ha un when per ogni stato, piú uno di default alla fine. Questo default è importante per risolvere possibili problemi dati da stati inesistenti al reset o indotti da una botta di ESD.

Stato idle
Viene dato un 1 in uscita. Se il segnale di controllo richiede una trasmissione, vengono resettati i counters e l'interfaccia dati viene campionata nello shift register. Il prossimo stato è startbit.

Stato startbit
In uscita abbiamo uno 0.
Se il clock-counter arriva alla durata in clock di un bit (frequenza/baudrate-1), allora il prossimo stato è data, altrimenti restiamo dove siamo e incrementiemo il counter.

Stato data
In uscita abbiamo l'LSB dello shift-register.
Il clock-counter viene incrementato.
Se il counter indica che la durata in di un bit è finita, abbiamo due possibilità:
- se il bit non era l'ultimo (indicato dal bit-counter), allora incrementiamo questo counter, resettiamo il clock-counter e shiftiamo di uno lo shift-register. Restiamo in questo stato così che il tutto si ripeta per il prossimo bit.
- se il bit era l'ultimo, allora resettiamo solo il clock-counter e il prossimo stato è stopbit.

Stato stopbit
È identico a startbit, solo che diamo uno 0 in uscita e passiamo poi a idle.

Se per qualche motivo finiamo nello stato di default, al prossimo clock passiamo a idle.

Codice: Seleziona tutto
  rx_fsm : process (RXbitcountxSP, RXclkcountxSP, RXshiftregxSP, RXstatexSP, RxxSI) is
  begin  -- process rx_fsm

    RXstatexSN    <= RXstatexSP;
    RXclkcountxSN <= RXclkcountxSP;
    RXbitcountxSN <= RXbitcountxSP;
    RXshiftregxSN <= RXshiftregxSP;

    case RXstatexSP is

      when idle =>
        if RxxSI = '0' then
          RXstatexSN    <= startbit;
          RXclkcountxSN <= 0;
          RXbitcountxSN <= 0;
          RXshiftregxSN <= (others => '0');
        end if;

      when startbit =>
        if RXclkcountxSP = CLKFREQ/BAUD-1 then
          RXclkcountxSN <= 0;
          RXstatexSN    <= data;
        else
          RXclkcountxSN <= RXclkcountxSP+1;
        end if;

      when data =>
        if RXclkcountxSP = (CLKFREQ/BAUD)/2 then
          RXshiftregxSN <= RxxSI & RXshiftregxSP(7 downto 1);
          RXbitcountxSN <= RXbitcountxSP +1;
          RXclkcountxSN <= RXclkcountxSP +1;
        elsif RXclkcountxSP = CLKFREQ/BAUD-1 and RXbitcountxSP < 8 then
          RXclkcountxSN <= 0;
        elsif RXclkcountxSP = CLKFREQ/BAUD-1 and RXbitcountxSP = 8 then
          RXclkcountxSN <= 0;
          RXstatexSN    <= stopbit;
        else
          RXclkcountxSN <= RXclkcountxSP + 1;
        end if;

      when stopbit =>
        if RXclkcountxSP = (CLKFREQ/BAUD)/4 then
          RXclkcountxSN <= 0;
          RXstatexSN    <= idle;
        else
          RXclkcountxSN <= RXclkcountxSP+1;
        end if;

      when others => RXstatexSN <= idle;
                     
    end case;
   
  end process rx_fsm;


È molto simile, la differenza principale sta nello stato "data" dove ci interessa il punto a metà della durata del bit ((CLKFREQ/BAUD)/2) nel quale prendiamo il valore presente in ingresso e lo memorizziamo nello shift-register di ricezione.

Abbiamo quindi la struttura completa che ha questo aspetto:

Codice: Seleziona tutto
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;

entity uart is
 
  generic (CLKFREQ : integer := 5000000;
           BAUD    : integer := 57600);

  port (RxxSI      : in  std_logic;
        TxxSO      : out std_logic;
        RxDataxDO  : out std_logic_vector (7 downto 0);
        TxDataxDI  : in  std_logic_vector (7 downto 0);
        RxbusyxSO  : out std_logic;
        TxbusyxSO  : out std_logic;
   TxstartxSI : in  std_logic;
        ClkxC      : in  std_logic;
        RstxRBI    : in  std_logic);

end uart;

architecture Behavioral of uart is

  type state is (idle, startbit, data, stopbit);
  signal RXstatexSP, RXstatexSN, TXstatexSP, TXstatexSN : state;

  signal RXshiftregxSN, RXshiftregxSP : std_logic_vector (7 downto 0);
  signal RXbitcountxSN, RXbitcountxSP : integer range 0 to 8;
  signal RXclkcountxSN, RXclkcountxSP : integer range 0 to (CLKFREQ/BAUD)-1;

  signal TXshiftregxSN, TXshiftregxSP : std_logic_vector (7 downto 0);
  signal TXbitcountxSN, TXbitcountxSP : integer range 0 to 8;
  signal TXclkcountxSN, TXclkcountxSP : integer range 0 to (CLKFREQ/BAUD)-1;

begin

  TxbusyxSO <= '0' when TXstatexSP = idle else '1';
  RxbusyxSO <= '0' when RXstatexSP = idle else '1';
  RxDataxDO <= RXshiftregxSP;

  tx_fsm : process (TXbitcountxSP, TXclkcountxSP, TXshiftregxSP, TXstatexSP, TxDataxDI, TxstartxSI) is
  begin  -- process tx_fsm

    TXstatexSN    <= TXstatexSP;
    TXclkcountxSN <= TXclkcountxSP;
    TXbitcountxSN <= TXbitcountxSP;
    TXshiftregxSN <= TXshiftregxSP;

    case TXstatexSP is
      when idle =>
   TxxSO <= '1';
        if TxstartxSI = '1' then
          TXclkcountxSN <= 0;
          TXbitcountxSN <= 0;
          TXshiftregxSN <= TxDataxDI;
          TXstatexSN    <= startbit;
        end if;

      when startbit =>
        TxxSO <= '0';
        if TXclkcountxSP = CLKFREQ/BAUD-1 then
          TXstatexSN    <= data;
          TXclkcountxSN <= 0;
        else
          TXclkcountxSN <= TXclkcountxSP +1;
        end if;

      when data =>
        TxxSO         <= TXshiftregxSP(0);
        TXclkcountxSN <= TXclkcountxSP+1;
        if TXclkcountxSP = CLKFREQ/BAUD-1 and TXbitcountxSP < 8 then
          TXbitcountxSN <= TXbitcountxSP +1;
          TXclkcountxSN <= 0;
          TXshiftregxSN <= '1' & TXshiftregxSP(7 downto 1);
        elsif TXclkcountxSP = CLKFREQ/BAUD-1 and TXbitcountxSP = 8 then
          TXclkcountxSN <= 0;
          TXstatexSN    <= stopbit;
        end if;

      when stopbit =>
        TxxSO <= '1';
        if TXclkcountxSP = CLKFREQ/BAUD-1 then
          TXstatexSN    <= idle;
          TXclkcountxSN <= 0;
        else
          TXclkcountxSN <= TXclkcountxSP +1;
        end if;
       
      when others => TXstatexSN <= idle;
    end case;
   
  end process tx_fsm;


  rx_fsm : process (RXbitcountxSP, RXclkcountxSP, RXshiftregxSP, RXstatexSP, RxxSI) is
  begin  -- process rx_fsm

    RXstatexSN    <= RXstatexSP;
    RXclkcountxSN <= RXclkcountxSP;
    RXbitcountxSN <= RXbitcountxSP;
    RXshiftregxSN <= RXshiftregxSP;

    case RXstatexSP is

      when idle =>
        if RxxSI = '0' then
          RXstatexSN    <= startbit;
          RXclkcountxSN <= 0;
          RXbitcountxSN <= 0;
          RXshiftregxSN <= (others => '0');
        end if;

      when startbit =>
        if RXclkcountxSP = CLKFREQ/BAUD-1 then
          RXclkcountxSN <= 0;
          RXstatexSN    <= data;
        else
          RXclkcountxSN <= RXclkcountxSP+1;
        end if;

      when data =>
        if RXclkcountxSP = (CLKFREQ/BAUD)/2 then
          RXshiftregxSN <= RxxSI & RXshiftregxSP(7 downto 1);
          RXbitcountxSN <= RXbitcountxSP +1;
          RXclkcountxSN <= RXclkcountxSP +1;
        elsif RXclkcountxSP = CLKFREQ/BAUD-1 and RXbitcountxSP < 8 then
          RXclkcountxSN <= 0;
        elsif RXclkcountxSP = CLKFREQ/BAUD-1 and RXbitcountxSP = 8 then
          RXclkcountxSN <= 0;
          RXstatexSN    <= stopbit;
        else
          RXclkcountxSN <= RXclkcountxSP + 1;
        end if;

      when stopbit =>
        if RXclkcountxSP = (CLKFREQ/BAUD)/4 then
          RXclkcountxSN <= 0;
          RXstatexSN    <= idle;
        else
          RXclkcountxSN <= RXclkcountxSP+1;
        end if;

      when others => RXstatexSN <= idle;
                     
    end case;
   
  end process rx_fsm;


  fsm_mem : process (ClkxC, RstxRBI) is
  begin  -- process fsm_mem
    if RstxRBI = '0' then                   -- asynchronous reset (active low)
      RXstatexSP    <= idle;
      RXclkcountxSP <= 0;
      RXbitcountxSP <= 0;
      RXshiftregxSP <= (others => '0');
      TXstatexSP    <= idle;
      TXclkcountxSP <= 0;
      TXbitcountxSP <= 0;
      TXshiftregxSP <= (others => '0');
      
    elsif ClkxC'event and ClkxC = '1' then  -- rising clock edge
      RXstatexSP    <= RXstatexSN;
      RXclkcountxSP <= RXclkcountxSN;
      RXbitcountxSP <= RXbitcountxSN;
      RXshiftregxSP <= RXshiftregxSN;
      TXstatexSP    <= TXstatexSN;
      TXclkcountxSP <= TXclkcountxSN;
      TXbitcountxSP <= TXbitcountxSN;
      TXshiftregxSP <= TXshiftregxSN;
    end if;
  end process fsm_mem;

end Behavioral;


Non è sicuramente l'unico modo di generare una UART. Né per quel che riguarda l'architettura, né per quel che riguarda la sintassi.
Ho messo l'accento sulla sintassi, perché questo modo di "scrivere" porta ad un risultato che si comporta esattamente allo stesso modo indipendentemente dalla toolchain e dal target.

Nella fattispecie questo esatto codice l'ho implementato su una CPLD Altera, su due FPGA di famiglie diverse Xilinx e su un ASIC con librerie Faraday Logic. Funziona su tutti i target e l'unica cosa che ho dovuto adattare sono i due generics (baudrate e frequenza di clock).

Boiler
Avatar utente
Foto Utenteboiler
14,4k 4 7 13
G.Master EY
G.Master EY
 
Messaggi: 2461
Iscritto il: 9 nov 2011, 12:27

0
voti

[25] Re: Discussione sul trasmettitore UART

Messaggioda Foto Utentedadduni » 23 set 2018, 9:51

Salve, ripesco questa discussione per due motivi:
Uno "bastardamente" è per mettere pressione psicologica a boiler così che possiamo strappargli un altro po di informazioni preziose :twisted: :twisted:
L'altra è per chiedere cosa ne pensa Foto Utenteboiler se scrivessi un altro articoletto in cui confronto il codice del trasmittente scritto da me nel primo articolo (sbagliato) e lo confrontassi con uno corretto che ho scritto imparando dal suo, da quello che ha detto e da "the design warrior's guide".
Mi piacerebbe far vedere le criticità del primo codice e che risultato da in sintetizzazione, e confrontarlo prima con il mio codice corretto e poi magari anche con il tuo (solo trasmettitore) così da far vedere le differenze e in qualche modo "aggiustare" il primo articolo.
Che ne pensi?
Davide
Avatar utente
Foto Utentedadduni
1.602 1 6 12
Expert EY
Expert EY
 
Messaggi: 976
Iscritto il: 23 mag 2014, 16:26

1
voti

[26] Re: Discussione sul trasmettitore UART

Messaggioda Foto Utenteboiler » 24 set 2018, 13:00

dadduni ha scritto:Che ne pensi?


Scrivi, scrivi! :ok:

Boiler
Avatar utente
Foto Utenteboiler
14,4k 4 7 13
G.Master EY
G.Master EY
 
Messaggi: 2461
Iscritto il: 9 nov 2011, 12:27

Precedente

Torna a Elettronica generale

Chi c’è in linea

Visitano il forum: Google Adsense [Bot] e 23 ospiti