diff --git a/FPGA_Firmware/Source/src/camera_controller.v b/FPGA_Firmware/Source/src/camera_controller.v index 570c225..13b90f2 100644 --- a/FPGA_Firmware/Source/src/camera_controller.v +++ b/FPGA_Firmware/Source/src/camera_controller.v @@ -43,7 +43,7 @@ begin if (state_time_counter == 0) begin - camera_state <= camera_state + (camera_state != state_idle); //go to next state if state is not equal to state_active + camera_state <= camera_state + (camera_state != state_idle); //go to next state if state is not equal to state_idle case(camera_state) state_reset: diff --git a/FPGA_Firmware/Source/src/mipi_csi_16_nx.v b/FPGA_Firmware/Source/src/mipi_csi_16_nx.v index 9279802..133a137 100644 --- a/FPGA_Firmware/Source/src/mipi_csi_16_nx.v +++ b/FPGA_Firmware/Source/src/mipi_csi_16_nx.v @@ -17,7 +17,7 @@ Takes MIPI Clock and 4 Data lane as input convert into Parallel YUV output Ouputs 32bit YUV data with Frame sync, lsync and pixel clock */ -module mipi_csi_16_nx( //reset_in, +module mipi_csi_16_nx( reset_in, mipi_clk_p_in, mipi_clk_n_in, mipi_data_p_in, @@ -32,15 +32,27 @@ module mipi_csi_16_nx( //reset_in, pclk_o, //data output on pos edge , should be latching into receiver on negedge data_o, fsync_o, //active high - lsync_o //active high + lsync_o, //active high + //these pins may or many not be needed depeding on hardware config + cam_ctrl_in, //control camera control input from host + cam_pwr_en_o, //enable camera power + cam_reset_o, //camera reset to camera + cam_xmaster_o //camera master or slave ); parameter MIPI_LANES = 2; //number of mipi lanes with camera. Only 2 or 4 parameter MIPI_GEAR = 8; //deserializer gearing ratio. Only 8 or 16 -parameter MIPI_PIXEL_PER_CLOCK = 2; // number of pixels pipeline process in one clock cycle. With 2 Lanes and Gear 8 only 2 or 4, With 4 Lanes only 4 or 8 +parameter MIPI_PIXEL_PER_CLOCK = 2; // number of pixels pipeline process in one clock cycle. With 2 Lanes and Gear 8 only 2 or 4 with gear 16 only 4 , With 4 Lanes only 4 or 8 parameter MAX_PIXEL_WIDTH = 12; //max pixel width , 14bit (RAW14) , IMX219 has 10bit while IMX477 has 12bit and IMX294 has 14bit -//input reset_in; +parameter FRAME_DETECT = 1; //if 1 MIPI start frame packet will be detected and used as frame sync rather than mipi_clk_lp , used for sensor whoes clock does not go into lp while frame sync is inactive + +//this should never be active unless testing +parameter SAMPLE_GENERATOR = 0; //if 1 a ROM based sample generator will be activated for testing, Sample generator uses 2 ROM lines as that is what mipimum needed to an image with correct enough colors, ROM file are first.rom and second.rom + +input reset_in; +input cam_ctrl_in; + input mipi_clk_p_in; input mipi_clk_n_in; input [MIPI_LANES-1:0]mipi_data_p_in; @@ -50,6 +62,10 @@ input mipi_clk_n_in1; input [MIPI_LANES-1:0]mipi_data_p_in1; input [MIPI_LANES-1:0]mipi_data_n_in1; +output cam_pwr_en_o; +output cam_reset_o; +output cam_xmaster_o; + output pclk_o; output [31:0]data_o; output fsync_o; @@ -70,14 +86,15 @@ wire is_decoded_valid; wire is_raw_line_valid; wire is_unpacked_valid; wire is_rgb_valid; +wire is_rgb_corrected_valid; wire is_yuv_valid; wire is_yuv_line_valid; wire mipi_out_clk; wire [31 :0]mipi_data_raw_hw; wire [31 :0]mipi_data_raw; -//wire [((MIPI_LANES * MIPI_GEAR) - 1) :0]mipi_data_raw_hw; -//wire [((MIPI_LANES * MIPI_GEAR) - 1) :0]mipi_data_raw; + + wire [((MIPI_LANES * MIPI_GEAR) - 1) :0]byte_aligned; wire [((MIPI_LANES * MIPI_GEAR) - 1) :0]lane_aligned; wire [((MIPI_LANES * MIPI_GEAR) - 1) :0]decoded_data; @@ -85,35 +102,23 @@ wire [2:0]packet_type; wire [15:0]packet_length; wire [((MAX_PIXEL_WIDTH * MIPI_PIXEL_PER_CLOCK ) - 1 ):0]unpacked_data; wire [((MAX_PIXEL_WIDTH * MIPI_PIXEL_PER_CLOCK * 3) - 1 ):0]rgb_data; +wire [((MAX_PIXEL_WIDTH * MIPI_PIXEL_PER_CLOCK * 3) - 1 ):0]rgb_corrected; wire [((MIPI_PIXEL_PER_CLOCK * 8 * 2 ) - 1 ):0]yuv_data; -//wire frame_sync_in; +wire line_reset; +wire frame_sync; +wire [1:0] sync_pulse; -wire hf_clk; int_osc int_osc_ins1(.hf_out_en_i(1'b1), .hf_clk_out_o(mipi_out_clk), .lf_clk_out_o(osc_clk)); -wire ready; -wire [15:0]debug_16; -wire [7:0]debug_aligner; -//&& (byte_aligned[23:16] == 8'hb8 ) && (byte_aligned[39:32] == 8'hb8 ) && (byte_aligned[55:48] == 8'hb8 ) -wire line_reset; -wire [1:0] sync_pulse; - -//assign data_o = mipi_data_raw_hw; -//assign mipi_out_clk = ; //yellow -//assign lsync_o = !frame_sync; //green -//assign fsync_o = mipi_out_clk & out_lsync ; //orange -//assign data_o[1] = is_yuv_valid; //blue -//assign data_o[3] = out_lsync; -//assign data_o = {3'b111,1'b1, yuv_line_valid , is_yuv_valid, lsync_o & mipi_out_clk, is_yuv_valid & mipi_byte_clock , 3'b0, lane_aligned[7:0] == 8'hB8, is_lane_aligned_valid, is_decoded_valid & mipi_byte_clock, is_decoded_valid, mipi_byte_clock, 3'b0, debug_16[10:6], 2'b0, debug_16[5:0]}; -//wirere [15:0]debug_word; -//assign debug_16 = {packet_length[15:2]}; - +//Lattice FPGA Engineering sample chip does not allow manual PHY pin assignment* for PHY and our hardware uses PHY1 rather than PHY0, this instance with go to PHY0 while our actual instance will go to PHY 1 +//*Lattice Does allow manual pin assignment but when you assign manually PHY will not work at all. Appears to be ES chip bug. +//As i am using Lattice ES chips i need to use Radiant 2.0 , DPHY IP has been changed a little with Radiant 3.1 dphy_dummy mipi_csi_phy_inst0(.sync_clk_i(osc_clk), .sync_rst_i(1'b0), .lmmi_clk_i(1'b0), @@ -126,9 +131,9 @@ dphy_dummy mipi_csi_phy_inst0(.sync_clk_i(osc_clk), .lmmi_rdata_o(), .lmmi_rdata_valid_o(), .hs_rx_en_i(1'b1), - //.hs_rx_clk_en_i(1'b1), //new - //.hs_rx_data_en_i(1'b1), //new - //.hs_data_des_en_i(1'b1), //new + //.hs_rx_clk_en_i(1'b1), + //.hs_rx_data_en_i(1'b1), + //.hs_data_des_en_i(1'b1), .hs_rx_data_o(dummy_out), //.hs_rx_data_sy nc_o(), .lp_rx_en_i(1'b1), @@ -178,7 +183,7 @@ csi_dphy mipi_csi_phy_inst1(.sync_clk_i(osc_clk), .ready_o()) ; /* -generate +generate //if hardware mipi lane n does not match to FPGA PHY lane n then adjust here because Lattice ES chip does not allow manual pin assigment if ( (MIPI_GEAR == 16) && (MIPI_LANES == 4)) begin assign mipi_data_raw = {mipi_data_raw_hw[15:0], mipi_data_raw_hw[31:16], mipi_data_raw_hw[63:48] ,mipi_data_raw_hw[47:32]}; //If schematic lane 0 may not connected PHY lane 0 , May need to swap here because its not possible to do before PHY IP, because Radiant auto assign PHY ports @@ -200,32 +205,81 @@ endgenerate */ assign mipi_data_raw = mipi_data_raw_hw; +camera_controller camera_controller_ins0( .sclk_i(osc_clk), + .reset_i(reset_in), + .cam_ctrl_in(cam_ctrl_in), + .cam_pwr_en_o(cam_pwr_en_o), + .cam_reset_o(cam_reset_o), + .cam_xmaster_o(cam_xmaster_o) + ); -line_reset_generator line_reset_generator_ins1(.clk_i(mipi_byte_clock), + +line_reset_generator line_reset_generator_ins0(.clk_i(mipi_byte_clock), .lp_data_i(lp_rx_data_p[0]), .line_reset_o(line_reset)); -assign frame_sync = lp_rx_clk_p; -genvar i; + + generate - for (i = 0;i < MIPI_LANES; i = i +1) begin +genvar i; + + if (SAMPLE_GENERATOR) + begin + wire dummy_byte_valid; //sample generator should neve be active unless debugging + assign is_byte_valid = {dummy_byte_valid,dummy_byte_valid}; + sample_generator sample_generator_ins( .framesync_i(frame_sync), + .clk_i(mipi_byte_clock), + .reset_i(line_reset), + .byte_o(byte_aligned), + .byte_valid_o(dummy_byte_valid)); - mipi_csi_rx_byte_aligner #(.MIPI_GEAR(MIPI_GEAR))mipi_rx_byte_aligner_0( .clk_i(mipi_byte_clock), + end + else + begin + for (i = 0;i < MIPI_LANES; i = i +1) + begin + + mipi_csi_rx_byte_aligner #(.MIPI_GEAR(MIPI_GEAR))mipi_rx_byte_aligner_0(.clk_i(mipi_byte_clock), .reset_i(line_reset), .byte_i(mipi_data_raw[(MIPI_GEAR * i) +: MIPI_GEAR]), .byte_o( byte_aligned[(MIPI_GEAR * i) +: MIPI_GEAR]), .byte_valid_o(is_byte_valid[i])); + end + end - endgenerate +generate + +if (FRAME_DETECT) +begin + frame_detector #(.MIPI_GEAR(MIPI_GEAR)) frame_detector_ins0( .reset_i(reset_in), + .clk_i(mipi_byte_clock), + .data_valid_i(is_byte_valid[0]), + .data_lane0_i(byte_aligned[0 +: MIPI_GEAR]), + .detected_frame_sync_o(frame_sync)); + +end +else +begin + assign frame_sync = lp_rx_clk_p; +end + +endgenerate + + + mipi_csi_rx_lane_aligner #(.MIPI_GEAR(MIPI_GEAR), .MIPI_LANES(MIPI_LANES))mipi_rx_lane_aligner( .clk_i(mipi_byte_clock), .reset_i(line_reset), .bytes_valid_i(is_byte_valid), .byte_i(byte_aligned), .lane_valid_o(is_lane_aligned_valid), .lane_byte_o(lane_aligned)); + + + + generate if ( (MIPI_GEAR == 16) && (MIPI_LANES == 4)) @@ -236,8 +290,7 @@ generate .output_valid_o(is_decoded_valid), .data_o(decoded_data), .packet_length_o(), - .packet_type_o(packet_type), - .debug_o()); + .packet_type_o(packet_type)); mipi_csi_rx_raw_depacker_16b4lane #(.PIXEL_WIDTH(MAX_PIXEL_WIDTH)) mipi_csi_rx_raw_depacker_0( .clk_i(mipi_byte_clock), .data_valid_i(is_decoded_valid), @@ -256,8 +309,7 @@ generate .output_valid_o(is_decoded_valid), .data_o(decoded_data), .packet_length_o(), - .packet_type_o(packet_type), - .debug_o()); + .packet_type_o(packet_type)); @@ -278,8 +330,7 @@ generate .output_valid_o(is_decoded_valid), .data_o(decoded_data), .packet_length_o(), - .packet_type_o(packet_type), - .debug_o()); + .packet_type_o(packet_type)); mipi_csi_rx_raw_depacker_8b4lane #(.PIXEL_WIDTH(MAX_PIXEL_WIDTH)) mipi_csi_rx_raw_depacker_0( .clk_i(mipi_byte_clock), .data_valid_i(is_decoded_valid), @@ -300,8 +351,7 @@ generate .output_valid_o(is_decoded_valid), .data_o(decoded_data), .packet_length_o(), - .packet_type_o(packet_type), - .debug_o()); + .packet_type_o(packet_type)); if (( MIPI_PIXEL_PER_CLOCK == 4) ) @@ -340,6 +390,25 @@ debayer_filter #(.PIXEL_WIDTH(MAX_PIXEL_WIDTH), .PIXEL_PER_CLK(MIPI_PIXEL_PER_CL .data_valid_i(is_unpacked_valid), .output_o(rgb_data), .output_valid_o(is_rgb_valid)); +/* +color_correction_matrix #(.PIXEL_WIDTH(MAX_PIXEL_WIDTH), .PIXEL_PER_CLK(MIPI_PIXEL_PER_CLOCK))color_correction_matrix_0( + .clk_i(mipi_byte_clock), + .reset_i(frame_sync), + .line_valid_i(is_raw_line_valid), + .data_i(rgb_data), + .data_valid_i(is_rgb_valid), + .output_o(rgb_corrected), + .output_valid_o(is_rgb_corrected_valid)); + + +rgb_to_yuv #(.PIXEL_WIDTH(MAX_PIXEL_WIDTH), .PIXEL_PER_CLK(MIPI_PIXEL_PER_CLOCK))rgb_to_yuv_0( .clk_i(mipi_byte_clock), + .rgb_i(rgb_corrected), + .rgb_valid_i(is_rgb_corrected_valid), + .line_valid_i(is_raw_line_valid), + .yuv_o(yuv_data), + .yuv_valid_o(is_yuv_valid), + .yuv_line_o(yuv_line_valid)); +*/ rgb_to_yuv #(.PIXEL_WIDTH(MAX_PIXEL_WIDTH), .PIXEL_PER_CLK(MIPI_PIXEL_PER_CLOCK))rgb_to_yuv_0( .clk_i(mipi_byte_clock), .rgb_i(rgb_data), @@ -348,7 +417,7 @@ rgb_to_yuv #(.PIXEL_WIDTH(MAX_PIXEL_WIDTH), .PIXEL_PER_CLK(MIPI_PIXEL_PER_CLOCK) .yuv_o(yuv_data), .yuv_valid_o(is_yuv_valid), .yuv_line_o(yuv_line_valid)); - + //wire line_wire; output_reformatter #(.PIXEL_PER_CLK(MIPI_PIXEL_PER_CLOCK))out_reformatter_0( .clk_i(mipi_byte_clock), .line_sync_i(yuv_line_valid), @@ -362,5 +431,5 @@ output_reformatter #(.PIXEL_PER_CLK(MIPI_PIXEL_PER_CLOCK))out_reformatter_0( .cl assign pclk_o = mipi_out_clk; //output clock always available assign fsync_o = !frame_sync; //activate fsync Active high -//assign lsync_o = line_wire & mipi_out_clk; +//assign lsync_o = is_yuv_valid; endmodule \ No newline at end of file