mipi_dsi_bridge_fpga/FPGA/Source/send_mipi_frame.v

326 lines
11 KiB
Verilog

/*
* File: MIPI_DSI_BRIDGE.v
* Copyright: Gaurav Singh
* website: www.circuitvalley.com
* Created on Jan 19, 2020, 1:33 AM
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* Email: gauravsingh@circuitvalley.com
************************************************************************/
module DPHY_TX_FRAME(
reset_i, //reset active high
command_i,
write_cmd_i,
clockp_fast_data_i, //fast clokc input for mipi data
clocks_fast_clk_i, //fast clock input for mipi clok
clock_slow_sync_i, //slow clock for sync
lock_chk_i, //pll lock check
fifo_almost_empty,
fifo_empty,
data_i, //mipi data input Through FIFO
fifo_read_en,
buf_clkout_lp_p_o, //mipi clock lp0 out
buf_clkout_lp_n_o, //mipi clock lp1 out
buf_dout_lp_p_o, //data lp0 out
buf_dout_lp_n_o, //data lp1 out
byte_clock_o, //byte clock out
hs_data_o, //mipi data out
hs_clock_o, //mipi clock out
finish_o // state machine finished transmitting
);
input wire write_cmd_i;
input wire [7:0]command_i;
input wire reset_i; //reset active high
input wire clockp_fast_data_i; //fast clokc input for mipi data
input wire clocks_fast_clk_i; //fast clock input for mipi clok
input wire clock_slow_sync_i; //slow clock for sync
input wire fifo_empty;
input wire fifo_almost_empty;
input wire lock_chk_i; //pll lock check
input wire [7:0]data_i; //mipi data input
output reg fifo_read_en;
output wire buf_clkout_lp_p_o; //mipi clock lp_p out
output wire buf_clkout_lp_n_o; //mipi clock lp_n out
output wire buf_dout_lp_p_o; //data lp_p out
output wire buf_dout_lp_n_o; //data lp_n out
output wire byte_clock_o; //byte clock out
output wire hs_data_o; //mipi data out
output wire hs_clock_o; //mipi clock out
output reg finish_o;
wire ddr_ready_w;
reg [7:0]command_r;
reg [9:0]rom_addr_r;
wire [7:0]rom_out;
reg rom_read_en;
reg [8:0]rom_tp_addr;
reg rom_tb_read_en;
ROM rom_inst1 (.Address(rom_addr_r), .OutClock(byte_clock_o), .OutClockEn(rom_read_en), .Reset(reset_i), .Q(rom_out));
reg data_from_rom_nfifo;
reg data_zero;
reg hs_clock_tristate_r;
reg hs_data_tristate_r;
wire write_to_fifo_w;
wire [7:0]mipi_data;
reg [7:0]mipi_data_temp;
reg clkout_lp_p_w;
reg clkout_lp_n_w;
reg dout_lp_p_w;
reg dout_lp_n_w;
DDR_MIPI ddr_mipi_inst1 ( .reset_i(reset_i),
.clkout_lp0_i(clkout_lp_p_w),
.clkout_lp1_i(clkout_lp_n_w),
.dout_lp0_i(dout_lp_p_w),
.dout_lp1_i(dout_lp_n_w),
.clock_slow_i(clock_slow_sync_i),
.data_i(mipi_data),
.clockp_fast_data_i(clockp_fast_data_i),
.clocks_fast_clk_i(clocks_fast_clk_i),
.lock_chk_i(lock_chk_i),
.tristate_data_i(hs_data_tristate_r),
.tristate_clk_i(hs_clock_tristate_r),
.byte_clock_o(byte_clock_o),
.tx_ready_o(ddr_ready_w),
.buf_clkout_lp0_o(buf_clkout_lp_p_o),
.buf_clkout_lp1_o(buf_clkout_lp_n_o),
.buf_dout_lp0_o(buf_dout_lp_p_o),
.buf_dout_lp1_o(buf_dout_lp_n_o),
.mipi_data_o(hs_data_o),
.mipi_clock_o(hs_clock_o));
parameter send_frame_state_idle = 4'h0;
parameter send_frame_state_enter_hs_clk1 = 4'h1;
parameter send_frame_state_enter_hs_clk1_wait = 4'h2;
parameter send_frame_state_enter_hs1 = 4'h3;
parameter send_frame_state_enter_hs1_wait = 4'h4;
parameter send_frame_state_enter_hs2 = 4'h5;
parameter send_frame_state_lp_wait1 = 4'h6;
parameter send_frame_state_lp_wait2 = 4'h7;
parameter send_frame_state_enable_hs = 4'h8;
parameter send_frame_state_send_preamble = 4'h9;
parameter send_frame_state_send_rom = 4'hA;
parameter send_frame_state_send_fifo = 4'hB;
parameter send_frame_state_send_crc = 4'hC;
parameter send_frame_state_finish = 4'hD;
reg [4:0]frame_state;
reg [9:0]rom_count;
reg [8:0]zeros_count;
reg [8:0]fifo_count;
reg fifo_empty_reg;
reg data_zero_reg;
reg data_from_rom_nfifo_reg;
always @(posedge reset_i or posedge byte_clock_o) //ddr module samples on falling edge of byte clock , so to align data_zero with posedge
begin
if (reset_i)
begin
data_from_rom_nfifo_reg <= 1'h0;
data_zero_reg <= 1'h0;
end
else
begin
data_zero_reg <= data_zero;
data_from_rom_nfifo_reg <= data_from_rom_nfifo;
end
end
assign mipi_data = data_zero_reg? 8'h0:(data_from_rom_nfifo_reg ? rom_out:data_i); //switch between rom or data in or zero
always @(posedge reset_i or negedge byte_clock_o)
begin
if (reset_i)
begin
frame_state <= send_frame_state_idle;
clkout_lp_p_w <= 1'b1;
clkout_lp_n_w <= 1'b1;
dout_lp_p_w <= 1'b1;
dout_lp_n_w <= 1'b1;
data_zero <= 1'b1;
hs_data_tristate_r <= 1'b1; //tristate hs data
hs_clock_tristate_r <= 1'b1; //tristate hs clock
fifo_count <= 9'h0;
fifo_read_en <= 1'b0;
finish_o <= 1'b0;
data_from_rom_nfifo <= 1'b0;
end
else
begin
case (frame_state)
send_frame_state_idle: begin //set dp low , disable clock tri state to un acitve
clkout_lp_p_w <= 1'b1;
clkout_lp_n_w <= 1'b1;
dout_lp_p_w <= 1'b1;
dout_lp_n_w <= 1'b1;
hs_data_tristate_r <= 1'b1; //tristate hs data
hs_clock_tristate_r <= 1'b1; //tristate hs clock
rom_read_en <= 1'b0;
if (write_cmd_i)
begin
finish_o <= 1'b0;
data_from_rom_nfifo <= 1'b1; //read from rom
data_zero <= 1'b1;
rom_addr_r <= command_i; //First address of rom
frame_state <= send_frame_state_enter_hs_clk1;
end
else
begin
finish_o <= 1'b1;
end
end
send_frame_state_enter_hs_clk1:begin //genrate enter hs on clk // first falling edege of byte_clk
rom_read_en <= 1'b1;
clkout_lp_p_w <= 1'b0; //pull clock_lp low
clkout_lp_n_w <= 1'b1;
frame_state <= send_frame_state_enter_hs_clk1_wait;
end
send_frame_state_enter_hs_clk1_wait:begin //to achive 50ns minimum delay between lp and ln
rom_count[7:0] <= rom_out[7:0];
rom_addr_r <= rom_addr_r + 1'b1; //increse rom address for HSByte of rom count
frame_state <= send_frame_state_enter_hs1;
end
send_frame_state_enter_hs1: begin //Third falling edege of byte_clk
rom_count[9:8] <= rom_out[1:0]; //fetch MSB rom count
rom_addr_r <= rom_addr_r + 1'b1; //increse rom address
dout_lp_p_w <= 1'b0;
dout_lp_n_w <= 1'b1;
clkout_lp_p_w <= 1'b0; //pull both clock_lp low
clkout_lp_n_w <= 1'b0;
hs_clock_tristate_r <= 1'b0; //tristate disabled hs clock
frame_state <= send_frame_state_enter_hs1_wait;
end
send_frame_state_enter_hs1_wait: begin //Fourth Falling edge of byte_clk
fifo_count[7:0] <= rom_out[7:0]; //fetch expected LSB fifo length
rom_addr_r <= rom_addr_r + 1'b1; //increse rom address
frame_state <= send_frame_state_enter_hs2;
end
send_frame_state_enter_hs2: begin //Fifth falling edege of byte_clk
fifo_count[8] <= rom_out[0]; //fetch expected MSB fifo length
dout_lp_p_w <= 1'b0;
dout_lp_n_w <= 1'b0;
frame_state <= send_frame_state_lp_wait1;
end
send_frame_state_lp_wait1: begin //6th falling edege of byte_clk, now enable data input mux tristate to be zero start send few null 4 byte
frame_state <= send_frame_state_lp_wait2;
end
send_frame_state_lp_wait2: begin //7th falling edege of byte_clk, now enable data input mux tristate to be zero start send few null 4 byte
frame_state <= send_frame_state_enable_hs;
end
send_frame_state_enable_hs: begin //8th- 12th falling edge
hs_data_tristate_r <= 1'b0; //tristate hs data
hs_clock_tristate_r <= 1'b0; //tristate hs clock
frame_state <= send_frame_state_send_preamble;
zeros_count <= 8'h4;
end
send_frame_state_send_preamble:begin //send zeros
zeros_count <= zeros_count - 1'h1;
if (!zeros_count)
begin
frame_state <= send_frame_state_send_rom;
data_zero <= 1'b0; //ROM samples addr on rising edge , by the time we get to next state correct data will be avilable
rom_addr_r <= rom_addr_r + 1'b1; //increse rom address
rom_count <= rom_count - 1'b1;
end
end
send_frame_state_send_rom: begin
rom_count <= rom_count - 1'b1;
rom_addr_r <= rom_addr_r + 1'b1; //increse rom address
if (!rom_count)
begin
if (fifo_count )
begin
data_from_rom_nfifo <= 1'b0;
fifo_count <= fifo_count - 1'h1;
//fifo_read_en <= !fifo_empty; //enable fifo right now sothat data becomes available by next falling edge of byte clock , if fifo some how empty , keep it disable
frame_state <= send_frame_state_send_fifo;
end
else
begin
data_zero <= 1'b1;
zeros_count <= 8'h5; //2 byte of crc (1byte transmits on state transition ) + 4 byte 0
frame_state <= send_frame_state_send_crc;
end
end
else
begin
if (rom_count == 9'h1 && fifo_count) // because need to get rid of first command byte off fifo
begin
fifo_read_en <= !fifo_empty; //enable fifo right now sothat data becomes available by next falling edge of byte clock , if fifo some how empty , keep it disable
end
end
end
send_frame_state_send_fifo: begin //wait till trans finish start sending fifo if not empty or skip this state on cmmand
fifo_count <= fifo_count - 1'h1;
//fifo_empty_reg <= fifo_empty; //to get last byte out of fifo
if (!fifo_count || fifo_empty)
begin
fifo_read_en <= 1'b0;
data_zero <= 1'b1;
zeros_count <= 4'h4 + fifo_count; //if any fifo_count is pending but fifo gone empty , pad it with zeros 2 byte of crc (1byte transmits on state transition ) + 4 byte 0
frame_state <= send_frame_state_send_crc;
end
end
send_frame_state_send_crc: begin //if 00 00 ff nesessry then use rom
zeros_count <= zeros_count - 1'h1;
if (!zeros_count)
begin
frame_state <= send_frame_state_finish;
end
end
send_frame_state_finish: begin
if (!write_cmd_i)
begin
frame_state <= send_frame_state_idle;
end
end
default: begin
frame_state <= send_frame_state_idle;
end
endcase
end
end
endmodule