Olen kirjoittanut UART-moduulin Verilogiin. Käyttämällä kyseistä moduulia saan tietoja tietokoneelta UART: n kautta ja lähetän sitten tiedot takaisin tämän UART-moduulin kautta. Latasin sen FPGA: hun testausta varten. Se toimii moitteettomasti riippumatta siitä, kuinka monta merkkiä lähetän alla olevalla koodilla (itse asiassa et ehkä tarvitse TX-tilaa, mutta laitan täyden koodin selvitykseen):
-moduuli uart_transceiver
# (parametri [15: 0] CLK_PERIOD = 434) // 50000000/115200
(
syöttö sys_rst,
syöte sys_clk,
tulo uart_rx,
lähtö reg uart_tx,
// syötteen [15: 0] jakaja,
lähtö reg [7: 0] rx_data,
lähtö reg rx_err,
tuotos [1: 0] state_uart,
lähtö [7: 0] kellon melkein8,
tuotos [7: 0] kello_hyvin8,
syöte [7: 0] tx_data,
syöttö tx_wr,
lähtö reg rx_busy,
lähtö reg rx_done,
lähtö reg tx_busy
);
reg [1: 0] tila_tx, tila_rx;
// ------------------------------------------------ -----------------
// UART RX -logiikka
// ------------------------------------------------ -----------------
reg [3: 0] rx_bitcount;
reg [15: 0] clk_luku_rx = 16'h0001;
reg [7: 0] rx_reg;
reg rx1;
määritä state_uart = state_rx;
// määritä kellonlähde8 = clk_luku_rx [7: 0];
// määritä kellon_lähin8 = clk_luku_rx [15: 8];
parametri IDLERX = 2'd0,
TAKESTART = 2 'd1,
TAKE8BITS = 2'd2,
TAKESTOP = 2'd3;
parametri [15: 0] FIRST_CHECK = CLK_PERIOD / 2;
aina @ (posedge sys_clk) alkaa
jos (sys_rst) alkaa
state_rx < = IDLERX;
rx_err < = 1'b0;
rx_done < = 1'b0;
loppu alkaa
tapaus (state_rx)
IDLERX: aloita
rx_bitcount < = 4'd0;
rx_busy < = 1'b0;
jos (uart_rx == 1'b0 && rx_err! = 1'b1) alkaa
clk_luku_rx < = 16'h0001;
state_rx < = TAKESTART;
loppuun
loppuun
// Ota yksi käynnistyssignaali ja tarkista, onko se 0
TAKESTART: aloita
rx_busy < = 1'b1;
rx_done < = 1'b0;
clk_luku_rx < = clk_luku_rx + 16'h0001;
jos (clk_luku_rx == FIRST_CHECK)
alkaa
rx1 < = uart_rx;
// clk_count_rx < = clk_count_rx + 16'd1;
loppuun
if (clk_luku_rx == CLK_PERIOD && rx1! = 1'b0)
alkaa
rx_err < = 1'b1;
state_rx < = IDLERX;
loppuun
muuten jos (clk_count_rx == CLK_PERIOD && rx1 == 1'b0)
alkaa
clk_luku_rx < = 16'h0001;
state_rx < = TAKE8BITS;
loppuun
loppuun
// Ota 8 bittiä dataa, mutta ole varovainen ja odota 1 CLK_PERIOD kutakin bittiä kohti
TAKE8BITS: aloita
if (rx_bitcount < 4'd8)
alkaa
clk_luku_rx < = clk_luku_rx + 16'h0001;
jos (clk_luku_rx == FIRST_CHECK)
alkaa
rx1 < = uart_rx;
loppuun
else if (clk_luku_rx == CLK_PERIOD)
alkaa
clk_luku_rx < = 16'h0001;
rx_reg < = {rx1, rx_reg [7: 1]};
rx_bitcount < = rx_bitcount + 1'b1;
loppuun
loppuun
muu
alkaa
clk_luku_rx < = 16'h0001;
state_rx < = TAKESTOP;
loppuun
loppuun
// Ota yksi pysäytysbitti viimeisessä CLK_PERIOD
TAKESTOP: aloita
clk_luku_rx < = clk_luku_rx + 16'h0001;
jos (clk_luku_rx == FIRST_CHECK)
alkaa
rx1 < = uart_rx;
loppuun
muuten jos (clk_count_rx == CLK_PERIOD && rx1! = 1'b1)
alkaa
rx_err < = 1'b1;
state_rx < = IDLERX;
loppuun
muuten jos (clk_count_rx == CLK_PERIOD && rx1 == 1'b1)
alkaa
rx_data < = rx_reg;
rx_done < = 1'b1;
clk_luku_rx < = 16'h0001;
state_rx < = IDLERX;
loppuun
else if (clk_luku_rx > CLK_PERIOD)
alkaa
rx_err < = 1'b1;
state_rx < = IDLERX;
loppuun
loppuun
pääkotelo
loppuun
loppuun
// ------------------------------------------------ -----------------
// UART TX -logiikka
// ------------------------------------------------ -----------------
parametri IDLE = 2'd0,
SENDSTART = 2 d1,
SEND8BITS = 2'd2,
LÄHETYS = 2 d3;
reg [3: 0] tx_bitcount;
reg [15: 0] clk_määrä;
reg [7: 0] tx_reg;
aina @ (posedge sys_clk) alkaa
jos (sys_rst) alkaa
state_tx < = IDLE;
loppu alkaa
tapaus (state_tx)
IDLE: aloita
uart_tx < = 1'b1;
// tx_reg < = tx_data;
clk_luku < = 16'd0;
tx_bitcount < = 4'd0;
tx_busy < = 1'b0;
jos (tx_wr) alkaa
tx_reg < = tx_data;
state_tx < = LÄHETÄ;
loppuun
loppuun
// Lähetä yksi aloitussignaali yhdelle CLK_PERIODille
LÄHETÄ: aloita
tx_busy < = 1'b1;
uart_tx < = 1'b0;
jos (clk_count == CLK_PERIOD) alkaa
clk_luku < = 16'd0;
// tx_reg < = tx_data;
state_tx < = LÄHETTÄ 8BITS;
loppu alkaa
clk_luku < = clk_luku + 16'd1;
loppuun
loppuun
// Lähetä 8 bittiä tietoja, mutta ole varovainen ja odota 1 CLK_PERIOD kutakin bittiä kohti
SEND8BITS: aloita
jos (tx_bitcount == 4'd0) alkaa
tx_bitcount < = tx_bitcount + 4'd1;
uart_tx < = tx_reg [0];
tx_reg < = {1'b0, tx_reg [7: 1]};
loppuun
jos (clk_count == CLK_PERIOD) alkaa
clk_luku < = 16'd0;
jos (tx_bitcount < 4'd8) alkaa
tx_bitcount < = tx_bitcount + 4'd1;
uart_tx < = tx_reg [0];
tx_reg < = {1'b0, tx_reg [7: 1]};
loppuun
muuten alkaa
clk_luku < = 16'd0;
state_tx < = LÄHETÄ;
loppuun
loppuun
muuten alkaa
clk_luku < = clk_luku + 16'd1;
loppuun
loppuun
// Lähetä yksi pysäytysbitti yhdelle CLK_PERIODille
LÄHETÄ: aloita
uart_tx < = 1'b1;
jos (clk_count == CLK_PERIOD) alkaa
clk_luku < = 16'd0;
tx_busy < = 1'b0;
state_tx < = IDLE;
loppu alkaa
clk_luku < = clk_luku + 16'd1;
loppuun
loppuun
pääkotelo
loppuun
loppuun
endmoduuli
Jos kuitenkin poistan viimeisen muutakin lohkoa alla olevasta TAKESTOP-tilasta, koodi lakkaa toimimasta, kun se on toiminut hyvin joidenkin satunnaismerkkien kohdalla, ja juuttuu TAKESTOP-tilaan. Kun sovellan sys_rst, se toimii jälleen joillekin hahmoille ja jumittuu sitten samassa TAKESTOP-tilassa. Mielenkiintoista on, että kun tämä muu lohko sijoitetaan ja koodi toimii moitteettomasti, se ei koskaan anna tätä muuta jos. Tiesin sen, koska muuten se olisi jumissa IDLERX-tilassa, koska rx_err olisi 1:
else if (clk_count_rx > CLK_PERIOD)
alkaa
rx_err < = 1'b1;
state_rx < = IDLERX;
loppuun
Olen vihainen tällaisista ongelmista. Sen sijaan, että lisättäisit tämän muun if-lohkon, ongelma häviää myös, kun määritän clk_count_rx-lähdön poistamalla kommentin näistä kahdesta rivistä yllä olevasta täydestä koodikoodista:
määritä clock_least8 = clk_count_rx [7: 0];
määritä kellon eniten8 = clk_luku_rx [15: 8];
Toisin sanoen tilakoneeni ei toimi hyvin ja vakaana, jos en määritä rekisteriä lähdölle, vaikka en käytä tätä lähtöä. Tätä on tapahtunut vielä pari kertaa erilaisissa Verilog-projekteissani.
Kysymys, kuinka tällaiset merkityksettömät muutokset voivat korjata koodini? Mikä minussa on vikana? Asia ei näytä loogiselta. Teenkö rakenteellisen käsitteellisen virheen ja tämä muutos näyttää korjaavan sen jotenkin? En tiedä. Käytän Quartus 16.1: tä Cyclone V GX Starter Boardin kanssa.
Muuten tämä on toimiva UART-moduuli, ja kuka tahansa on tervetullut käyttämään sitä. Olen varmasti hyvin iloinen siitä, kuka auttaa minua tässä asiassa.