├── assets └── dist_pc_polar.png ├── src ├── cross_domain.v ├── pulse_cross_domain.v ├── clock_divider.v ├── clock_detection.v ├── clock_divider_w_divisor_in.v ├── pulse_widener.v ├── counter_ms.v ├── delay.v ├── reset_timer.v ├── clock_divider_two_phase.v ├── auxilary_functions.v ├── register_file_address_space.v ├── spi_slave.v ├── multicycle_generator.v ├── ppi_generator.v ├── ad9826_serial_controller.v ├── sensor_serial_controller.v ├── tof_board.ucf ├── ad9826_data_controller.v ├── top.v ├── tb_main.v ├── sensor_intf.v ├── main.v ├── register_file.v ├── spi_slave.vhd └── spi_master.vhd ├── README.md └── LICENSE /assets/dist_pc_polar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmitrii-khizbullin/tof-driver/HEAD/assets/dist_pc_polar.png -------------------------------------------------------------------------------- /src/cross_domain.v: -------------------------------------------------------------------------------- 1 | module cross_domain( 2 | input clk_dst, 3 | input in, 4 | output reg out 5 | ); 6 | 7 | reg int1 = 0, int2 = 0; 8 | always @(posedge clk_dst) begin 9 | int1 <= in; 10 | int2 <= int1; 11 | out <= int2; 12 | end 13 | 14 | endmodule 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Verilog/FPGA driver of TOF camera for Blackfin DSP ## 2 | 3 | Dmitrii Khizbullin, 2013-2014 4 | 5 | TOF (Time-of-Flight) sensor used: PMD Technologies 19k-S3 160x120 [datasheet](https://www.pmdtec.com/html/pdf/pmdPhotonICs_19k_S3.pdf). 6 | 7 | An example of a captured point cloud: 8 | 9 | ![TOF point cloud](assets/dist_pc_polar.png) 10 | 11 | -------------------------------------------------------------------------------- /src/pulse_cross_domain.v: -------------------------------------------------------------------------------- 1 | module pulse_cross_domain( 2 | input in_clk, 3 | input in_pulse, 4 | 5 | input out_clk, 6 | output reg out_pulse = 0 7 | ); 8 | 9 | reg ff = 0; 10 | always @(posedge in_clk) 11 | if (in_pulse) 12 | ff <= ~ff; 13 | 14 | reg r1 = 0; 15 | reg r2 = 0; 16 | reg r3 = 0; 17 | always @(posedge out_clk) begin 18 | r1 <= ff; 19 | r2 <= r1; 20 | r3 <= r2; 21 | end 22 | 23 | always @(posedge out_clk) 24 | out_pulse <= r2 ^ r3; // catch both rising an falling edges 25 | 26 | endmodule 27 | -------------------------------------------------------------------------------- /src/clock_divider.v: -------------------------------------------------------------------------------- 1 | module clock_divider 2 | ( 3 | input clk_in, 4 | input rst, 5 | output reg clk_out 6 | ); 7 | 8 | `include "auxilary_functions.v" 9 | 10 | parameter divisor = 10; 11 | 12 | reg [base2(divisor)-1:0] cnt = 0; 13 | 14 | always @(posedge clk_in) begin 15 | if (rst) begin 16 | cnt <= 0; 17 | clk_out <= 0; 18 | end 19 | else begin 20 | if (cnt >= divisor-1) begin 21 | cnt <= 0; 22 | end 23 | else begin 24 | cnt <= cnt + 1; 25 | end 26 | 27 | clk_out <= (cnt >= divisor/2); 28 | end 29 | end 30 | 31 | endmodule 32 | -------------------------------------------------------------------------------- /src/clock_detection.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module posedge_detection(signal, clk, posedge_signal); 4 | input signal; 5 | input clk; 6 | output posedge_signal; 7 | 8 | reg l1,l2; 9 | 10 | always @* 11 | l1 <= signal; 12 | 13 | always @(posedge clk) 14 | l2 <= l1; 15 | 16 | assign posedge_signal = (l1 && !l2); 17 | 18 | endmodule 19 | 20 | 21 | module negedge_detection(signal, clk, negedge_signal); 22 | input signal; 23 | input clk; 24 | output negedge_signal; 25 | 26 | reg l1,l2; 27 | 28 | always @* 29 | l1 <= signal; 30 | 31 | always @(posedge clk) 32 | l2 <= l1; 33 | 34 | assign negedge_signal = (!l1 && l2); 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /src/clock_divider_w_divisor_in.v: -------------------------------------------------------------------------------- 1 | module clock_divider_w_divisor_in 2 | #( 3 | parameter DIVISOR_BITS = 8 4 | ) 5 | ( 6 | input clk_in, 7 | input rst, 8 | input [DIVISOR_BITS-1:0] divisor, 9 | output reg clk_out 10 | ); 11 | 12 | `include "auxilary_functions.v" 13 | 14 | reg [DIVISOR_BITS-1:0] cnt = 0; 15 | 16 | always @(posedge clk_in) begin 17 | if (rst) begin 18 | cnt <= 0; 19 | clk_out <= 0; 20 | end 21 | else begin 22 | if (cnt >= divisor-1) begin 23 | cnt <= 0; 24 | end 25 | else begin 26 | cnt <= cnt + 1; 27 | end 28 | 29 | clk_out <= (cnt >= divisor/2); 30 | end 31 | end 32 | 33 | endmodule 34 | -------------------------------------------------------------------------------- /src/pulse_widener.v: -------------------------------------------------------------------------------- 1 | module pulse_widener 2 | #( 3 | parameter PERIOD = 100 4 | ) 5 | ( 6 | input clk_i, 7 | input rst, 8 | input pulse_i, 9 | output reg out_o = 0 10 | ); 11 | 12 | `include "auxilary_functions.v" 13 | 14 | reg [base2(PERIOD)-1:0] cnt = 0; 15 | 16 | wire test = (pulse_i === 1); 17 | 18 | always @(posedge clk_i) begin 19 | if (rst) begin 20 | cnt <= 0; 21 | out_o <= 0; 22 | end 23 | else begin 24 | if (test) begin 25 | cnt <= PERIOD-1; 26 | end 27 | else begin 28 | if (cnt > 0) begin 29 | cnt <= cnt - 1; 30 | end 31 | end 32 | 33 | out_o <= (cnt > 0); 34 | end 35 | end 36 | 37 | endmodule 38 | -------------------------------------------------------------------------------- /src/counter_ms.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module counter_ms 4 | ( 5 | input clk, 6 | input rst, 7 | input [17:0] clocks_in_ms, 8 | output reg [31:0] time_ms, 9 | output reg pulse_ms 10 | ); 11 | 12 | reg [17:0] cnt_ms; 13 | 14 | always @(posedge clk) 15 | if(rst) 16 | begin 17 | cnt_ms <= 0; 18 | time_ms <= 0; 19 | pulse_ms <= 0; 20 | end 21 | else 22 | if(cnt_ms >= clocks_in_ms) 23 | begin 24 | cnt_ms <= 1; 25 | time_ms <= time_ms + 1; 26 | pulse_ms <= 1; 27 | end 28 | else 29 | begin 30 | cnt_ms <= cnt_ms + 1; 31 | pulse_ms <= 0; 32 | end 33 | 34 | endmodule 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Dmitrii Khizbullin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/delay.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module delay_reg( data_in, we, clk, data_out ); 4 | parameter DELAY = 1; 5 | parameter WIDTH = 1; 6 | input [WIDTH-1:0] data_in; 7 | input clk; 8 | input we; 9 | output [WIDTH-1:0] data_out; 10 | 11 | genvar i; 12 | generate 13 | for (i=0; i < WIDTH; i=i+1) 14 | begin: DELAY_REG 15 | delay1 #( .DELAY(DELAY) ) delay_reg_unit 16 | ( 17 | .data_in(data_in[i]), 18 | .we(we), 19 | .clk(clk), 20 | .data_out(data_out[i]) 21 | ); 22 | end 23 | endgenerate 24 | 25 | endmodule 26 | 27 | 28 | module delay1( data_in, we, clk, data_out); 29 | parameter DELAY = 1; 30 | 31 | input data_in; 32 | input we; 33 | input clk; 34 | output data_out; 35 | 36 | reg [DELAY-1:0] shift_reg; 37 | 38 | always @(posedge clk) 39 | if(we) 40 | shift_reg <= { data_in, shift_reg[DELAY-1:1] }; 41 | 42 | assign data_out = shift_reg[0]; 43 | 44 | initial begin 45 | shift_reg <= 0; 46 | end 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /src/reset_timer.v: -------------------------------------------------------------------------------- 1 | module reset_timer( 2 | input clk, 3 | input rst_in, 4 | output reg rst_out = 1'b1 5 | ); 6 | 7 | `include "auxilary_functions.v" 8 | 9 | parameter use_rst_in = 0; 10 | parameter ticks = 100000; 11 | 12 | reg [clogb2(ticks)-1:0] cnt = 0; 13 | reg rst_n = 1'b0; 14 | 15 | generate 16 | if (use_rst_in) begin 17 | always @(posedge clk or posedge rst_in) begin 18 | if (rst_in) begin 19 | cnt <= 0; 20 | rst_n <= 1'b0; 21 | end 22 | else begin 23 | if (!(&cnt)) begin 24 | cnt <= cnt + 1; 25 | rst_n <= 1'b0; 26 | end 27 | else begin 28 | rst_n <= 1'b1; 29 | end 30 | end 31 | end 32 | end 33 | else begin 34 | always @(posedge clk) begin 35 | if (!(&cnt)) begin 36 | cnt <= cnt + 1; 37 | rst_n <= 1'b0; 38 | end 39 | else begin 40 | rst_n <= 1'b1; 41 | end 42 | end 43 | end 44 | endgenerate 45 | 46 | always @(posedge clk) 47 | rst_out <= !rst_n; 48 | 49 | endmodule 50 | -------------------------------------------------------------------------------- /src/clock_divider_two_phase.v: -------------------------------------------------------------------------------- 1 | module clock_divider_two_phase 2 | #( 3 | parameter DIVISOR_BITS = 8 4 | ) 5 | ( 6 | input clk_in, 7 | input rst, 8 | input [DIVISOR_BITS-1:0] divisor, 9 | input [DIVISOR_BITS-1:0] phase, 10 | output reg clk_out, 11 | output reg clk_out_phased 12 | ); 13 | 14 | `include "auxilary_functions.v" 15 | 16 | reg [DIVISOR_BITS-1:0] cnt = 0; 17 | reg [DIVISOR_BITS-1:0] cnt_unphased = 0; 18 | reg [DIVISOR_BITS-1:0] cnt_phased = 0; 19 | 20 | wire [DIVISOR_BITS-1+1:0] cnt_phased_unbounded = {1'b0, cnt} + {1'b0, phase}; 21 | 22 | always @(posedge clk_in) begin 23 | if (rst) begin 24 | cnt <= 0; 25 | cnt_unphased <= 0; 26 | cnt_phased <= 0; 27 | clk_out <= 0; 28 | clk_out_phased <= 0; 29 | end 30 | else begin 31 | if (cnt >= divisor-1) begin 32 | cnt <= 0; 33 | end 34 | else begin 35 | cnt <= cnt + 1; 36 | end 37 | 38 | cnt_unphased <= cnt; 39 | if (cnt_phased_unbounded >= divisor) begin 40 | cnt_phased <= cnt_phased_unbounded - divisor; 41 | end 42 | else begin 43 | cnt_phased <= cnt_phased_unbounded; 44 | end 45 | 46 | clk_out <= (cnt_unphased >= divisor/2); 47 | clk_out_phased <= (cnt_phased >= divisor/2); 48 | end 49 | end 50 | 51 | endmodule 52 | -------------------------------------------------------------------------------- /src/auxilary_functions.v: -------------------------------------------------------------------------------- 1 | // **************************************************************************** 2 | // Auxilary functions 3 | // **************************************************************************** 4 | 5 | // Ceiling of base-2 logarithm 6 | function automatic integer clogb2; 7 | input [31:0] value; 8 | reg [31:0] v; 9 | integer result; 10 | begin 11 | v = value; 12 | for (result = 0; v > 0; result = result + 1) begin 13 | v = v >> 1; 14 | end 15 | clogb2 = result; 16 | end 17 | endfunction 18 | 19 | // Number of bits to represent at least n values 20 | function automatic integer base2; 21 | input integer n; 22 | begin 23 | base2 = clogb2(n-1); 24 | end 25 | endfunction 26 | 27 | function automatic integer max; 28 | input integer v1; 29 | input integer v2; 30 | begin 31 | max = (v1 > v2) ? v1 : v2; 32 | end 33 | endfunction 34 | 35 | function automatic integer min; 36 | input integer v1; 37 | input integer v2; 38 | begin 39 | min = (v1 < v2) ? v1 : v2; 40 | end 41 | endfunction 42 | 43 | function automatic integer pow; 44 | input integer v; 45 | input integer gr; 46 | integer i, acc; 47 | begin 48 | acc = 1; 49 | for (i = 0; i < gr; i = i + 1) begin 50 | acc = acc * v; 51 | end 52 | pow = acc; 53 | end 54 | endfunction 55 | 56 | function automatic integer pow2; 57 | input integer gr; 58 | integer i, acc; 59 | begin 60 | acc = 1; 61 | for (i = 0; i < gr; i = i + 1) begin 62 | acc = acc * 2; 63 | end 64 | pow2 = acc; 65 | end 66 | endfunction 67 | 68 | -------------------------------------------------------------------------------- /src/register_file_address_space.v: -------------------------------------------------------------------------------- 1 | localparam [6:0] ADDRESS_DEBUG_0 = 7'h40; 2 | localparam [6:0] ADDRESS_DEBUG_1 = 7'h41; 3 | localparam [6:0] ADDRESS_DEBUG_2 = 7'h42; 4 | localparam [6:0] ADDRESS_DEBUG_3 = 7'h43; 5 | localparam [6:0] ADDRESS_DEBUG_4 = 7'h44; 6 | localparam [6:0] ADDRESS_DEBUG_5 = 7'h45; 7 | localparam [6:0] ADDRESS_DEBUG_6 = 7'h46; 8 | localparam [6:0] ADDRESS_DEBUG_7 = 7'h47; 9 | 10 | localparam [6:0] ADDRESS_START_CYCLE = 7'h50; 11 | localparam [6:0] ADDRESS_CYCLE_FINISHED = 7'h51; 12 | localparam [6:0] ADDRESS_INTEGRATION_TIME_0 = 7'h52; 13 | localparam [6:0] ADDRESS_INTEGRATION_TIME_1 = 7'h53; 14 | localparam [6:0] ADDRESS_INTEGRATION_TIME_2 = 7'h54; 15 | localparam [6:0] ADDRESS_OVERRIDE_ENABLE_ROI = 7'h55; 16 | localparam [6:0] ADDRESS_ENABLE_CYCLE_EMULATION = 7'h56; 17 | localparam [6:0] ADDRESS_ADC_CTRL = 7'h57; 18 | 19 | localparam [6:0] ADDRESS_SNS_ADDR = 7'h68; 20 | localparam [6:0] ADDRESS_SNS_VALUE = 7'h69; 21 | localparam [6:0] ADDRESS_SNS_BUSY = 7'h6A; 22 | localparam [6:0] ADDRESS_SNS_ACQUIRE = 7'h6B; 23 | localparam [6:0] ADDRESS_MUX_CE_A_ND = 7'h6C; 24 | 25 | localparam [6:0] ADDRESS_CFG_REGISTER = 7'h71; 26 | 27 | localparam [6:0] ADDRESS_ADC_ADDR = 7'h72; 28 | localparam [6:0] ADDRESS_ADC_VALUE = 7'h73; 29 | localparam [6:0] ADDRESS_ADC_BUSY = 7'h74; 30 | localparam [6:0] ADDRESS_ADC_ACQUIRE = 7'h75; 31 | localparam [6:0] ADDRESS_ADC_VALUE_HIGHER_BYTE = 7'h76; 32 | 33 | localparam [6:0] ADDRESS_MODSEL_DIVISOR = 7'h78; 34 | localparam [6:0] ADDRESS_MODLED_PHASE = 7'h79; 35 | localparam [6:0] ADDRESS_MODLED_PHASE_1 = 7'h7A; 36 | localparam [6:0] ADDRESS_MODLED_PHASE_2 = 7'h7B; 37 | localparam [6:0] ADDRESS_MODLED_PHASE_3 = 7'h7C; 38 | localparam [6:0] ADDRESS_MULTICYCLE_MODE = 7'h7D; 39 | 40 | localparam [0:0] RF_WRITE_BIT = 1'b1; 41 | localparam [0:0] RF_READ_BIT = 1'b0; 42 | -------------------------------------------------------------------------------- /src/spi_slave.v: -------------------------------------------------------------------------------- 1 | // SPI slave 2 | // CPOL = 0, CPHA = 0, most significant bit first 3 | 4 | module spi_slave 5 | ( 6 | // System 7 | input clk, 8 | input rst, 9 | 10 | // SPI interface 11 | input spi_SCK, 12 | input spi_MOSI, 13 | input spi_CSN, 14 | 15 | output reg parallel_start_of_message, 16 | output reg parallel_end_of_message, 17 | output reg [7:0] parallel_data, 18 | output reg parallel_data_valid, 19 | 20 | output reg corrupt_byte 21 | ); 22 | 23 | wire CSN; 24 | wire MOSI; 25 | wire SCK; 26 | 27 | delay_reg #(.DELAY(3), .WIDTH(3)) d1 28 | ( 29 | .data_in({spi_CSN, spi_MOSI, spi_SCK}), 30 | .we(1'b1), 31 | .clk(clk), 32 | .data_out({CSN, MOSI, SCK}) 33 | ); 34 | 35 | wire CSN_pe; 36 | posedge_detection CSN_pe_i(.signal(CSN), .clk(clk), .posedge_signal(CSN_pe)); 37 | wire CSN_ne; 38 | negedge_detection CSN_ne_i(.signal(CSN), .clk(clk), .negedge_signal(CSN_ne)); 39 | wire SCK_pe; 40 | posedge_detection SCK_pe_i(.signal(SCK), .clk(clk), .posedge_signal(SCK_pe)); 41 | 42 | reg [7:0] byte; 43 | reg [2:0] bit; 44 | 45 | always @(posedge clk) begin 46 | if (rst) begin 47 | parallel_data <= 8'b0; 48 | parallel_start_of_message <= 1'b0; 49 | parallel_end_of_message <= 1'b0; 50 | byte <= 8'b0; 51 | parallel_data_valid <= 1'b0; 52 | corrupt_byte <= 1'b0; 53 | bit <= 0; 54 | end 55 | else begin 56 | parallel_start_of_message <= 1'b0; 57 | parallel_end_of_message <= 1'b0; 58 | parallel_data_valid <= 1'b0; 59 | 60 | if (CSN_ne) begin 61 | parallel_start_of_message <= 1'b1; 62 | bit <= 0; 63 | corrupt_byte <= 1'b0; 64 | byte <= 8'b0; 65 | end 66 | else if (CSN_pe) begin 67 | parallel_end_of_message <= 1'b1; 68 | if (bit != 0) begin 69 | corrupt_byte <= 1'b1; 70 | end 71 | byte <= 8'b0; 72 | parallel_data <= 8'b0; 73 | end 74 | else begin 75 | if (!CSN) begin 76 | if (SCK_pe) begin 77 | byte[7-bit] <= MOSI; 78 | bit <= bit + 1; // no need to process overflow 79 | if (bit == 3'd7) begin 80 | parallel_data <= {byte[7:1], MOSI}; 81 | parallel_data_valid <= 1'b1; 82 | end 83 | end 84 | end 85 | end 86 | end 87 | end 88 | 89 | endmodule 90 | -------------------------------------------------------------------------------- /src/multicycle_generator.v: -------------------------------------------------------------------------------- 1 | module multicycle_generator( 2 | input clk_i, 3 | input rst_i, 4 | 5 | input is_multicycle_i, 6 | input start_multicycle_i, 7 | output reg start_sycle_o, 8 | input ppi_frame_valid_i, 9 | input cycle_finished_i, 10 | output reg multicycle_finished_o, 11 | 12 | input [7:0] modsel_phase_i, // also modsel_phase_0_i 13 | input [7:0] modsel_phase_1_i, 14 | input [7:0] modsel_phase_2_i, 15 | input [7:0] modsel_phase_3_i, 16 | output reg [7:0] modsel_phase_o 17 | ); 18 | 19 | `include "auxilary_functions.v" 20 | 21 | localparam NUM_CYCLES = 4; 22 | reg [base2(NUM_CYCLES)-1:0] cnt; 23 | 24 | localparam ST_IDLE = 0; 25 | localparam ST_CYCLES_START = 1; 26 | localparam ST_CYCLES_WAIT_MODSEL = 2; 27 | localparam ST_CYCLES_WAIT_FINISHED = 3; 28 | reg [1:0] st; 29 | 30 | reg [base2(NUM_CYCLES)-1:0] last_cycle; 31 | 32 | always @(posedge clk_i) begin 33 | if (rst_i) begin 34 | start_sycle_o <= 0; 35 | multicycle_finished_o <= 1; 36 | cnt <= 0; 37 | st <= ST_IDLE; 38 | end 39 | else begin 40 | start_sycle_o <= 0; 41 | 42 | case (st) 43 | ST_IDLE: begin 44 | if (start_multicycle_i) begin 45 | multicycle_finished_o <= 0; 46 | st <= ST_CYCLES_START; 47 | cnt <= 0; 48 | end 49 | end 50 | ST_CYCLES_START: begin 51 | start_sycle_o <= 1; 52 | st <= ST_CYCLES_WAIT_MODSEL; 53 | end 54 | ST_CYCLES_WAIT_MODSEL: begin 55 | if (ppi_frame_valid_i) begin 56 | st <= ST_CYCLES_WAIT_FINISHED; 57 | end 58 | end 59 | ST_CYCLES_WAIT_FINISHED: begin 60 | last_cycle = is_multicycle_i ? NUM_CYCLES-1 : 0; 61 | 62 | if (cycle_finished_i) begin 63 | if (cnt >= last_cycle) begin 64 | st <= ST_IDLE; 65 | multicycle_finished_o <= 1; 66 | cnt <= 0; 67 | end 68 | else begin 69 | st <= ST_CYCLES_START; 70 | cnt <= cnt + 1; 71 | end 72 | end 73 | end 74 | default: begin 75 | st <= ST_IDLE; 76 | end 77 | endcase 78 | end 79 | end 80 | 81 | always @(posedge clk_i) begin 82 | modsel_phase_o <= 83 | is_multicycle_i ? ( 84 | (cnt == 0) ? modsel_phase_i : 85 | (cnt == 1) ? modsel_phase_1_i : 86 | (cnt == 2) ? modsel_phase_2_i : 87 | modsel_phase_3_i) : 88 | modsel_phase_i; 89 | end 90 | 91 | endmodule 92 | -------------------------------------------------------------------------------- /src/ppi_generator.v: -------------------------------------------------------------------------------- 1 | module ppi_generator 2 | ( 3 | input clk_ppi, 4 | input rst, 5 | 6 | input start, 7 | output reg ready = 0, 8 | 9 | output [15:0] ppi_data, 10 | output ppi_fs1, 11 | output ppi_fs2, 12 | output ppi_fs3 13 | ); 14 | 15 | `include "auxilary_functions.v" 16 | 17 | localparam FRAME_WIDTH = 162; 18 | localparam FRAME_HEIGHT = 120; 19 | localparam HBI = 10; 20 | localparam VBI = 2; 21 | 22 | localparam ST_IDLE = 0; 23 | localparam ST_GENERATE = 1; 24 | reg [0:0] st = ST_IDLE; 25 | 26 | reg [base2(FRAME_WIDTH)-1:0] cnt_w = 0; 27 | reg [base2(FRAME_HEIGHT)-1:0] cnt_h = 0; 28 | reg horz_blank = 0; 29 | 30 | localparam NO_DATA = 16'hFFFF; 31 | reg [15:0] data = NO_DATA; 32 | reg line_valid = 0; 33 | reg frame_valid = 0; 34 | 35 | wire [15:0] common_counter = cnt_h * FRAME_WIDTH + cnt_w; 36 | 37 | always @(posedge clk_ppi) begin 38 | if (rst) begin 39 | st <= ST_IDLE; 40 | cnt_w <= 0; 41 | cnt_h <= 0; 42 | data <= NO_DATA; 43 | line_valid <= 0; 44 | frame_valid <= 0; 45 | horz_blank <= 0; 46 | end 47 | else begin 48 | case (st) 49 | ST_IDLE: begin 50 | if (start) begin 51 | st <= ST_GENERATE; 52 | end 53 | 54 | cnt_w <= 0; 55 | cnt_h <= 0; 56 | data <= NO_DATA; 57 | line_valid <= 0; 58 | frame_valid <= 0; 59 | horz_blank <= 0; 60 | end 61 | ST_GENERATE: begin 62 | if (horz_blank) begin 63 | line_valid <= 0; 64 | data <= NO_DATA; 65 | 66 | if (cnt_w >= HBI-1) begin 67 | horz_blank <= 0; 68 | cnt_w <= 0; 69 | 70 | if (cnt_h >= FRAME_HEIGHT-1) begin 71 | cnt_h <= 0; 72 | st <= ST_IDLE; 73 | end 74 | else begin 75 | cnt_h <= cnt_h + 1; 76 | end 77 | end 78 | else begin 79 | cnt_w <= cnt_w + 1; 80 | end 81 | end 82 | else begin 83 | line_valid <= 1; 84 | data <= common_counter; 85 | 86 | if (cnt_w >= FRAME_WIDTH-1) begin 87 | horz_blank <= 1; 88 | cnt_w <= 0; 89 | end 90 | else begin 91 | cnt_w <= cnt_w + 1; 92 | end 93 | end 94 | 95 | frame_valid <= 1; 96 | end 97 | endcase 98 | end 99 | end 100 | 101 | assign ppi_data = data; 102 | assign ppi_fs1 = line_valid; 103 | assign ppi_fs2 = frame_valid; 104 | assign ppi_fs3 = 0; 105 | 106 | always @(posedge clk_ppi) 107 | ready <= (st == ST_IDLE); 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /src/ad9826_serial_controller.v: -------------------------------------------------------------------------------- 1 | module ad9826_serial_controller 2 | ( 3 | input clk, 4 | input rst, 5 | 6 | output sdata_o, 7 | input sdata_i, 8 | output reg sdata_oen_o, 9 | output sclk_o, 10 | output sload_o, 11 | 12 | input [2:0] address_i, 13 | input [8:0] write_data_i, // 9-bit 14 | input write_valid_i, 15 | input read_start_i, 16 | output reg [8:0] read_data_o, // 9-bit 17 | output reg busy_o 18 | ); 19 | 20 | reg rd_nwr = 0; 21 | 22 | wire di_req; 23 | reg [15:0] di; 24 | reg wren; 25 | wire wr_ack; 26 | wire do_valid; 27 | wire [15:0] do; 28 | 29 | localparam [0:0] write_bit = 1'b0; 30 | localparam [0:0] read_bit = 1'b1; 31 | 32 | always @(posedge clk) begin 33 | if (rst) begin 34 | wren <= 0; 35 | busy_o <= 0; 36 | read_data_o <= 'b0; 37 | rd_nwr <= 0; 38 | di <= 'b0; 39 | end 40 | else begin 41 | wren <= 0; 42 | 43 | if (busy_o) begin 44 | if (do_valid) begin 45 | busy_o <= 0; 46 | 47 | if (rd_nwr) begin 48 | read_data_o <= do[8:0]; 49 | end 50 | end 51 | end 52 | else begin 53 | if (write_valid_i) begin 54 | rd_nwr <= 0; 55 | di <= {write_bit, address_i, 3'b0, write_data_i}; 56 | wren <= 1; 57 | busy_o <= 1; 58 | end 59 | else if (read_start_i) begin 60 | rd_nwr <= 1; 61 | di <= {read_bit, address_i, 3'b0, 9'b0}; 62 | wren <= 1; 63 | busy_o <= 1; 64 | end 65 | end 66 | end 67 | end 68 | 69 | wire [7:0] state_dbg; 70 | 71 | spi_master #( 72 | .N(16), // 32bit serial word length is default 73 | .CPOL(0), // SPI mode selection (mode 0 default) 74 | .CPHA(0), // CPOL = clock polarity, CPHA = clock phase. 75 | .PREFETCH(2), // prefetch lookahead cycles 76 | .SPI_2X_CLK_DIV(/*10*/50) // for a 100MHz sclk_i, yields a 5MHz SCK 77 | ) 78 | spi_master ( 79 | .sclk_i(clk), // high-speed serial interface system clock 80 | .pclk_i(clk), // high-speed parallel interface system clock 81 | .rst_i(rst), // reset core 82 | 83 | //// serial interface //// 84 | .spi_ssel_o(sload_o), // spi bus slave select line 85 | .spi_sck_o (sclk_o), // spi bus sck 86 | .spi_mosi_o(sdata_o), // spi bus mosi output 87 | .spi_miso_i(sdata_i), // spi bus spi_miso_i input 88 | 89 | //// parallel interface //// 90 | .di_req_o (di_req), // preload lookahead data request line 91 | .di_i (di), // parallel data in (clocked on rising spi_clk after last bit) 92 | .wren_i (wren), // user data write enable, starts transmission when interface is idle 93 | .wr_ack_o (wr_ack), // write acknowledge 94 | .do_valid_o(do_valid), // do_o data valid signal, valid during one spi_clk rising edge. 95 | .do_o (do), // parallel output (clocked on rising spi_clk after last bit) 96 | 97 | .sck_ena_o(), 98 | .sck_ena_ce_o(), 99 | .do_transfer_o(), 100 | .wren_o(), 101 | .rx_bit_reg_o(), 102 | .state_dbg_o(state_dbg), 103 | .core_clk_o(), 104 | .core_n_clk_o(), 105 | .core_ce_o(), 106 | .core_n_ce_o(), 107 | .sh_reg_dbg_o() 108 | ); 109 | 110 | always @(posedge clk) 111 | sdata_oen_o <= rd_nwr ? ((state_dbg > 8'h0B) || (state_dbg == 8'h00)) : 1'b1; 112 | 113 | endmodule 114 | -------------------------------------------------------------------------------- /src/sensor_serial_controller.v: -------------------------------------------------------------------------------- 1 | module sensor_serial_controller 2 | ( 3 | input clk, 4 | input rst, 5 | 6 | output ce_a_o, 7 | output ce_d_o, 8 | output sclk_o, 9 | input sdi_i , 10 | output sdo_o , 11 | 12 | input [6:0] address_i, 13 | input [7:0] write_data_i, 14 | input write_valid_i, 15 | input read_start_i, 16 | output reg [7:0] read_data_o, 17 | output reg busy_o, 18 | input mux_ce_a_nd_i 19 | ); 20 | 21 | reg rd_nwr = 0; 22 | 23 | wire di_req; 24 | reg [15:0] di; 25 | reg wren; 26 | wire wr_ack; 27 | wire do_valid; 28 | wire [15:0] do; 29 | 30 | localparam [0:0] write_bit = 1'b1; 31 | localparam [0:0] read_bit = 1'b0; 32 | 33 | always @(posedge clk) begin 34 | if (rst) begin 35 | wren <= 0; 36 | busy_o <= 0; 37 | read_data_o <= 'b0; 38 | rd_nwr <= 0; 39 | di <= 'b0; 40 | end 41 | else begin 42 | wren <= 0; 43 | 44 | if (busy_o) begin 45 | if (do_valid) begin 46 | busy_o <= 0; 47 | 48 | if (rd_nwr) begin 49 | read_data_o <= do[7:0]; 50 | end 51 | end 52 | end 53 | else begin 54 | if (write_valid_i) begin 55 | rd_nwr <= 0; 56 | di <= {write_bit, address_i, write_data_i}; 57 | wren <= 1; 58 | busy_o <= 1; 59 | end 60 | else if (read_start_i) begin 61 | rd_nwr <= 1; 62 | di <= {read_bit, address_i, 8'b0}; 63 | wren <= 1; 64 | busy_o <= 1; 65 | end 66 | end 67 | end 68 | end 69 | 70 | wire [7:0] state_dbg; 71 | 72 | wire sload; 73 | 74 | spi_master #( 75 | .N(16), // 32bit serial word length is default 76 | .CPOL(0), // SPI mode selection (mode 0 default) 77 | .CPHA(1), // CPOL = clock polarity, CPHA = clock phase. 78 | .PREFETCH(2), // prefetch lookahead cycles 79 | .SPI_2X_CLK_DIV(/*10*/50) // for a 100MHz sclk_i, yields a 5MHz SCK 80 | ) 81 | spi_master ( 82 | .sclk_i(clk), // high-speed serial interface system clock 83 | .pclk_i(clk), // high-speed parallel interface system clock 84 | .rst_i(rst), // reset core 85 | 86 | //// serial interface //// 87 | .spi_ssel_o(sload), // spi bus slave select line 88 | .spi_sck_o (sclk_o), // spi bus sck 89 | .spi_mosi_o(sdo_o), // spi bus mosi output 90 | .spi_miso_i(sdi_i), // spi bus spi_miso_i input 91 | 92 | //// parallel interface //// 93 | .di_req_o (di_req), // preload lookahead data request line 94 | .di_i (di), // parallel data in (clocked on rising spi_clk after last bit) 95 | .wren_i (wren), // user data write enable, starts transmission when interface is idle 96 | .wr_ack_o (wr_ack), // write acknowledge 97 | .do_valid_o(do_valid), // do_o data valid signal, valid during one spi_clk rising edge. 98 | .do_o (do), // parallel output (clocked on rising spi_clk after last bit) 99 | 100 | .sck_ena_o(), 101 | .sck_ena_ce_o(), 102 | .do_transfer_o(), 103 | .wren_o(), 104 | .rx_bit_reg_o(), 105 | .state_dbg_o(state_dbg), 106 | .core_clk_o(), 107 | .core_n_clk_o(), 108 | .core_ce_o(), 109 | .core_n_ce_o(), 110 | .sh_reg_dbg_o() 111 | ); 112 | 113 | assign ce_a_o = mux_ce_a_nd_i ? (~sload) : 1'b0; 114 | assign ce_d_o = mux_ce_a_nd_i ? 1'b0 : (~sload); 115 | 116 | endmodule 117 | -------------------------------------------------------------------------------- /src/tof_board.ucf: -------------------------------------------------------------------------------- 1 | #NET "clk_100_mhz" TNM_NET = "TNM_clk_100_mhz"; 2 | #TIMESPEC "TS_clk_100_mhz" = PERIOD "TNM_clk_100_mhz" 100 MHz HIGH 50 %; 3 | #NET "clk_10_mhz" TNM_NET = "TNM_clk_10_mhz"; 4 | #TIMESPEC "TS_clk_10_mhz" = PERIOD "TNM_clk_10_mhz" 10 MHz HIGH 50 %; 5 | 6 | #NET "CLK" TNM_NET = "clk_net"; 7 | #TIMESPEC "TS_clk_net" = PERIOD "clk_net" 10 ns; 8 | 9 | #PIN "sclk_gen/clkout1_buf.O" CLOCK_DEDICATED_ROUTE = FALSE; 10 | 11 | # misc 12 | NET "RESET" LOC = "J11" | IOSTANDARD = LVCMOS33; 13 | #NET "RESET" IOSTANDARD = LVCMOS33; 14 | NET "MOD_LED" LOC = "T14" | IOSTANDARD = LVCMOS33; 15 | 16 | #NET "pad_net_name" IOSTANDARD=iostandard_name; 17 | #NET "MAIN_CLOCK_IN" IOSTANDARD = LVCMOS33; 18 | 19 | # 200 MHZ clock 20 | NET "CLK_S3AN_N" LOC = "D8" | IOSTANDARD = LVDS_33; 21 | NET "CLK_S3AN_P" LOC = "C8" | IOSTANDARD = LVDS_33; 22 | 23 | # ADC 24 | NET "ADC2_D[0]" LOC = "A13" | IOSTANDARD = LVCMOS33; 25 | NET "ADC2_D[1]" LOC = "B12" | IOSTANDARD = LVCMOS33; 26 | NET "ADC2_D[2]" LOC = "A12" | IOSTANDARD = LVCMOS33; 27 | NET "ADC2_D[3]" LOC = "A11" | IOSTANDARD = LVCMOS33; 28 | NET "ADC2_D[4]" LOC = "C11" | IOSTANDARD = LVCMOS33; 29 | NET "ADC2_D[5]" LOC = "A10" | IOSTANDARD = LVCMOS33; 30 | NET "ADC2_D[6]" LOC = "B10" | IOSTANDARD = LVCMOS33; 31 | NET "ADC2_D[7]" LOC = "D10" | IOSTANDARD = LVCMOS33; 32 | NET "ADC2_SCLK2" LOC = "A6" | IOSTANDARD = LVCMOS33; 33 | NET "ADC2_SCLK1" LOC = "A5" | IOSTANDARD = LVCMOS33; 34 | NET "ADC2_CCLK2" LOC = "B6" | IOSTANDARD = LVCMOS33; 35 | NET "SLOAD_ADC2" LOC = "A14" | IOSTANDARD = LVCMOS33; 36 | NET "SCLK_ADC" LOC = "B14" | IOSTANDARD = LVCMOS33; 37 | NET "SDATA_ADC" LOC = "B15" | IOSTANDARD = LVCMOS33; 38 | 39 | # Sensor 40 | NET "SEL_SR" LOC = "C1" | IOSTANDARD = LVCMOS33; 41 | NET "CLK_C" LOC = "C2" | IOSTANDARD = LVCMOS33; 42 | NET "START_C" LOC = "D3" | IOSTANDARD = LVCMOS33; 43 | NET "START_ROI" LOC = "E1" | IOSTANDARD = LVCMOS33; 44 | NET "HOLD" LOC = "D1" | IOSTANDARD = LVCMOS33; 45 | NET "ENABLE_ROI" LOC = "E2" | IOSTANDARD = LVCMOS33; 46 | NET "CLEAR_R" LOC = "F3" | IOSTANDARD = LVCMOS33; 47 | NET "CLK_ROI" LOC = "G1" | IOSTANDARD = LVCMOS33; 48 | NET "CLK_R" LOC = "F1" | IOSTANDARD = LVCMOS33; 49 | NET "START_R" LOC = "H1" | IOSTANDARD = LVCMOS33; 50 | NET "END_R" LOC = "G2" | IOSTANDARD = LVCMOS33; 51 | NET "CLEAR_C" LOC = "J3" | IOSTANDARD = LVCMOS33; 52 | NET "RESET_CCD" LOC = "R5" | IOSTANDARD = LVCMOS33; 53 | NET "END_C" LOC = "T6" | IOSTANDARD = LVCMOS33; 54 | NET "G_RESET" LOC = "T5" | IOSTANDARD = LVCMOS33; 55 | NET "ADC_CTRL" LOC = "T7" | IOSTANDARD = LVCMOS33; 56 | NET "MODSEL" LOC = "R9" | IOSTANDARD = LVCMOS33; 57 | # 58 | NET "CCD_CE_A" LOC = "T10" | IOSTANDARD = LVCMOS33; 59 | NET "CCD_CE_D" LOC = "R7" | IOSTANDARD = LVCMOS33; 60 | NET "CCD_SCLK" LOC = "T9" | IOSTANDARD = LVCMOS33; 61 | NET "CCD_SDI" LOC = "T8" | IOSTANDARD = LVCMOS33; 62 | NET "CCD_SDO" LOC = "P8" | IOSTANDARD = LVCMOS33; 63 | 64 | # SPI to Blackfin 65 | NET "SPI_SEL_S3AN" LOC = "P15" | IOSTANDARD = LVCMOS33 | PULLUP; 66 | NET "SPISCK_S3AN" LOC = "J14" | IOSTANDARD = LVCMOS33; 67 | NET "SPIMISOS_3AN" LOC = "P13" | IOSTANDARD = LVCMOS33; 68 | NET "SPIMOSIS3AN" LOC = "R14" | IOSTANDARD = LVCMOS33; 69 | 70 | # PPI 71 | NET "PPICLK" LOC = "M16" | IOSTANDARD = LVCMOS33; 72 | NET "PPIFS1" LOC = "N16" | IOSTANDARD = LVCMOS33; 73 | NET "PPIFS2" LOC = "P16" | IOSTANDARD = LVCMOS33; 74 | NET "PPIFS3" LOC = "N14" | IOSTANDARD = LVCMOS33; 75 | NET "PPID[0]" LOC = "M15" | IOSTANDARD = LVCMOS33; 76 | NET "PPID[1]" LOC = "L16" | IOSTANDARD = LVCMOS33; 77 | NET "PPID[2]" LOC = "K16" | IOSTANDARD = LVCMOS33; 78 | NET "PPID[3]" LOC = "K15" | IOSTANDARD = LVCMOS33; 79 | NET "PPID[4]" LOC = "G16" | IOSTANDARD = LVCMOS33; 80 | NET "PPID[5]" LOC = "H16" | IOSTANDARD = LVCMOS33; 81 | NET "PPID[6]" LOC = "F16" | IOSTANDARD = LVCMOS33; 82 | NET "PPID[7]" LOC = "F15" | IOSTANDARD = LVCMOS33; 83 | NET "PPID[8]" LOC = "D14" | IOSTANDARD = LVCMOS33; 84 | NET "PPID[9]" LOC = "C15" | IOSTANDARD = LVCMOS33; 85 | NET "PPID[10]" LOC = "E16" | IOSTANDARD = LVCMOS33; 86 | NET "PPID[11]" LOC = "D16" | IOSTANDARD = LVCMOS33; 87 | NET "PPID[12]" LOC = "D15" | IOSTANDARD = LVCMOS33; 88 | NET "PPID[13]" LOC = "C16" | IOSTANDARD = LVCMOS33; 89 | NET "PPID[14]" LOC = "J16" | IOSTANDARD = LVCMOS33; 90 | NET "PPID[15]" LOC = "H15" | IOSTANDARD = LVCMOS33; 91 | 92 | # Test points 93 | NET "TP[13]" LOC = "P9" | IOSTANDARD = LVCMOS33; 94 | NET "TP[14]" LOC = "J1" | IOSTANDARD = LVCMOS33; 95 | NET "TP[15]" LOC = "J2" | IOSTANDARD = LVCMOS33; 96 | NET "TP[16]" LOC = "K1" | IOSTANDARD = LVCMOS33; 97 | NET "TP[17]" LOC = "K3" | IOSTANDARD = LVCMOS33; 98 | NET "TP[18]" LOC = "L2" | IOSTANDARD = LVCMOS33; 99 | NET "TP[19]" LOC = "L1" | IOSTANDARD = LVCMOS33; 100 | NET "TP[20]" LOC = "L4" | IOSTANDARD = LVCMOS33; 101 | NET "TP[21]" LOC = "N1" | IOSTANDARD = LVCMOS33; 102 | NET "TP[22]" LOC = "M1" | IOSTANDARD = LVCMOS33; 103 | NET "TP[23]" LOC = "P1" | IOSTANDARD = LVCMOS33; 104 | NET "TP[24]" LOC = "N2" | IOSTANDARD = LVCMOS33; 105 | NET "TP[25]" LOC = "R1" | IOSTANDARD = LVCMOS33; 106 | -------------------------------------------------------------------------------- /src/ad9826_data_controller.v: -------------------------------------------------------------------------------- 1 | module ad9826_data_controller 2 | ( 3 | input clk_adc_i, // about 30 MHz 4 | input rst_i, 5 | 6 | input sns_enable_roi_i, 7 | input sns_clk_roi_i, 8 | 9 | input [7:0] adc_data_i, 10 | output reg adc_sclk2_o = 1'b0, // about 2.5 MHz, 1/12 fill 11 | output adc_sclk1_o, // = 0 12 | output reg adc_cclk_o = 1'b0, // about 7.5 MHz 13 | 14 | output reg [15:0] ppi_data_o, 15 | output ppi_fs1_o, 16 | output ppi_fs2_o, 17 | output ppi_fs3_o, 18 | output reg ppi_clk_o = 1'b0 19 | ); 20 | 21 | // 3-channel SHA mode 22 | 23 | localparam NUM_PHASES = 12; 24 | reg [3:0] phase; 25 | 26 | reg sns_clk_roi_prev = 1'b1; 27 | always @(posedge clk_adc_i) begin 28 | sns_clk_roi_prev <= sns_clk_roi_i; 29 | end 30 | wire sns_clk_roi_posedge = sns_clk_roi_i & (~sns_clk_roi_prev); 31 | 32 | always @(posedge clk_adc_i) begin 33 | if (rst_i) begin 34 | phase <= 0; 35 | end 36 | else begin 37 | if (sns_clk_roi_posedge) begin 38 | phase <= 1; 39 | end 40 | else begin 41 | if (phase >= NUM_PHASES-1) phase <= 0; 42 | else phase <= phase + 1; 43 | end 44 | end 45 | end 46 | 47 | reg generating_frame = 0; 48 | reg line_valid; 49 | reg frame_valid; 50 | 51 | localparam NUM_IDX_COL = 54+1; // ceil(160/3)=54 52 | localparam NUM_IDX_ROW = 120; 53 | 54 | reg [6:0] idx_col; 55 | reg [6:0] idx_row; 56 | reg [7:0] high_byte; 57 | reg sns_enable_roi_prev; 58 | 59 | always @(posedge clk_adc_i) begin 60 | if (rst_i) begin 61 | adc_cclk_o <= 0; 62 | adc_sclk2_o <= 0; 63 | ppi_clk_o <= 0; 64 | high_byte <= 0; 65 | ppi_data_o <= 0; 66 | generating_frame <= 0; 67 | idx_row <= 0; 68 | idx_col <= 0; 69 | line_valid <= 0; 70 | frame_valid <= 0; 71 | sns_enable_roi_prev <= 0; 72 | end 73 | else begin 74 | if ((phase % 4) == 1) begin 75 | adc_cclk_o <= 0; 76 | end 77 | if ((phase % 4) == 3) begin 78 | adc_cclk_o <= 1; 79 | end 80 | adc_sclk2_o <= (phase == NUM_PHASES-2); // 10 81 | 82 | if ((phase % 4) == 1) begin 83 | ppi_clk_o <= 0; 84 | end 85 | if ((phase % 4) == 3) begin 86 | ppi_clk_o <= 1; 87 | end 88 | 89 | if (generating_frame) begin 90 | if (phase == 1) begin 91 | high_byte <= adc_data_i; 92 | end 93 | if (phase == 3) begin 94 | ppi_data_o <= {high_byte, adc_data_i}; 95 | end 96 | if (phase == 5) begin 97 | high_byte <= adc_data_i; 98 | end 99 | if (phase == 7) begin 100 | ppi_data_o <= {high_byte, adc_data_i}; 101 | end 102 | if (phase == 9) begin 103 | high_byte <= adc_data_i; 104 | end 105 | if (phase == 11) begin 106 | ppi_data_o <= {high_byte, adc_data_i}; 107 | end 108 | end 109 | else begin 110 | ppi_data_o <= 0; 111 | end 112 | 113 | if (phase == 11) begin 114 | sns_enable_roi_prev <= sns_enable_roi_i; 115 | 116 | if (sns_enable_roi_i && !sns_enable_roi_prev) begin 117 | generating_frame <= 1; 118 | end 119 | 120 | if (generating_frame) begin 121 | if (idx_col > 0) begin 122 | line_valid <= 1; 123 | end 124 | else begin 125 | line_valid <= 0; 126 | end 127 | 128 | frame_valid <= 1; 129 | 130 | if (idx_col >= NUM_IDX_COL-1) begin 131 | idx_col <= 0; 132 | 133 | if (idx_row >= NUM_IDX_ROW-1) begin 134 | idx_row <= 0; 135 | idx_col <= 0; 136 | line_valid <= 0; 137 | frame_valid <= 0; 138 | generating_frame <= 0; 139 | end 140 | else begin 141 | idx_row <= idx_row + 1; 142 | end 143 | end 144 | else begin 145 | idx_col <= idx_col + 1; 146 | end 147 | end 148 | end 149 | end 150 | end 151 | 152 | assign adc_sclk1_o = 0; 153 | 154 | assign ppi_fs1_o = line_valid; 155 | assign ppi_fs2_o = frame_valid; 156 | assign ppi_fs3_o = 0; 157 | 158 | endmodule 159 | -------------------------------------------------------------------------------- /src/top.v: -------------------------------------------------------------------------------- 1 | module top 2 | ( 3 | // misc 4 | input RESET, 5 | output MOD_LED, 6 | 7 | // 156.--- mhz clock 8 | input CLK_S3AN_N, 9 | input CLK_S3AN_P, 10 | 11 | // SPI to Blackfin 12 | input SPI_SEL_S3AN, 13 | input SPISCK_S3AN, 14 | output SPIMISOS_3AN, 15 | input SPIMOSIS3AN, 16 | 17 | // CCD 18 | // ROI readout 19 | output START_ROI, 20 | input ENABLE_ROI, 21 | output CLK_ROI, 22 | // some other readout 23 | output CLK_C, 24 | output START_C, 25 | output CLEAR_R, 26 | output CLK_R, 27 | output START_R, 28 | input END_R, 29 | output CLEAR_C, 30 | input END_C, 31 | // control 32 | output SEL_SR, 33 | output HOLD, 34 | output RESET_CCD, // reset_1 35 | output G_RESET, // global_reset 36 | output ADC_CTRL, 37 | output MODSEL, 38 | 39 | output CCD_CE_A, 40 | output CCD_CE_D, 41 | output CCD_SCLK, 42 | output CCD_SDI, 43 | input CCD_SDO, 44 | 45 | // ADC 46 | input [7:0] ADC2_D, 47 | output ADC2_SCLK2, 48 | output ADC2_SCLK1, 49 | output ADC2_CCLK2, 50 | output SLOAD_ADC2, 51 | output SCLK_ADC, 52 | inout SDATA_ADC, 53 | 54 | // PPI 55 | output PPICLK, 56 | output PPIFS1, 57 | output PPIFS2, 58 | output PPIFS3, 59 | output [15:0] PPID, 60 | 61 | // Test points 62 | output reg [25:13] TP 63 | ); 64 | 65 | wire clk_sys; 66 | // pll 104.--- mhz 67 | sys_clk_gen sys_clk_gen ( 68 | .CLKIN_N_IN(CLK_S3AN_N), 69 | .CLKIN_P_IN(CLK_S3AN_P), 70 | .RST_IN(1'b0), 71 | .CLKFX_OUT(clk_sys), 72 | .CLKIN_IBUFGDS_OUT(), 73 | .CLK0_OUT(), 74 | .LOCKED_OUT(clk_sys_locked) 75 | ); 76 | 77 | 78 | /*wire clk_ppi; 79 | // pll to 10.4 mhz 80 | ppi_clk_gen ppi_clk_gen ( 81 | .CLKIN_IN(clk_sys), 82 | .RST_IN(1'b0), 83 | .CLKFX_OUT(clk_ppi), 84 | .CLK0_OUT(), 85 | .LOCKED_OUT(clk_ppi_locked) 86 | );*/ 87 | 88 | 89 | wire clk_adc; 90 | // pll to 31.2 mhz 91 | adc_clk_gen adc_clk_gen ( 92 | .CLKIN_IN(clk_sys), 93 | .RST_IN(1'b0), 94 | .CLKFX_OUT(clk_adc), 95 | .CLK0_OUT(), 96 | .LOCKED_OUT(clk_adc_locked) 97 | ); 98 | 99 | 100 | wire rst_by_timer; 101 | reset_timer #( 102 | .use_rst_in(0), 103 | .ticks(100000) 104 | ) 105 | reset_timer ( 106 | .clk(clk_sys), 107 | .rst_in(0), 108 | .rst_out(rst_by_timer) 109 | ); 110 | wire rst = (!clk_sys_locked) || (!clk_adc_locked) || rst_by_timer; 111 | 112 | wire start; 113 | wire [7:0] cfg_register; 114 | 115 | wire adc_sdata_o; 116 | wire adc_sdata_oen_o; 117 | assign SDATA_ADC = adc_sdata_oen_o ? adc_sdata_o : 1'bz; 118 | 119 | wire spi_masking; 120 | reset_timer #( 121 | .use_rst_in(0), 122 | .ticks(100000000*5) 123 | ) 124 | spi_masking_timer ( 125 | .clk(clk_sys), 126 | .rst_in(0), 127 | .rst_out(spi_masking) 128 | ); 129 | wire spi_SCK; 130 | wire spi_MOSI; 131 | wire spi_MISO; 132 | wire spi_CSN; 133 | assign spi_SCK = spi_masking ? 1'b0 : SPISCK_S3AN; 134 | assign spi_MOSI = spi_masking ? 1'b0 : SPIMOSIS3AN; 135 | assign SPIMISOS_3AN = spi_masking ? 1'bz : (spi_CSN == 1'b1) ? 1'bz : spi_MISO; 136 | assign spi_CSN = spi_masking ? 1'b1 : SPI_SEL_S3AN; 137 | 138 | main main 139 | ( 140 | .clk_sys(clk_sys), 141 | .clk_adc(clk_adc), 142 | .rst(rst), 143 | 144 | // Blackfin SPI interface 145 | .cpu_spi_SCK (spi_SCK), 146 | .cpu_spi_MOSI(spi_MOSI), 147 | .cpu_spi_MISO(spi_MISO), 148 | .cpu_spi_CSN (spi_CSN), 149 | 150 | .sns_start_roi_o (START_ROI), 151 | .sns_enable_roi_i(ENABLE_ROI), 152 | .sns_clk_roi_o (CLK_ROI), 153 | .sns_hold_o (HOLD), 154 | .sns_reset_1_o (RESET_CCD), // reset_1 155 | .sns_sel_sr_o (SEL_SR), 156 | .sns_modsel_o (MODSEL), 157 | .sns_modled_o (MOD_LED), 158 | 159 | .sns_cfg_ce_a_o(CCD_CE_A), 160 | .sns_cfg_ce_d_o(CCD_CE_D), 161 | .sns_cfg_sclk_o(CCD_SCLK), 162 | .sns_cfg_sdi_i (CCD_SDO ), // connect vice versa 163 | .sns_cfg_sdo_o (CCD_SDI ), 164 | 165 | // ADC 166 | .adc_cfg_sdata_o (adc_sdata_o), 167 | .adc_cfg_sdata_i (SDATA_ADC), 168 | .adc_cfg_sdata_oen_o(adc_sdata_oen_o), 169 | .adc_cfg_sclk_o (SCLK_ADC), 170 | .adc_cfg_sload_o (SLOAD_ADC2), 171 | 172 | .adc_data (ADC2_D ), 173 | .adc_sclk2(ADC2_SCLK2), 174 | .adc_sclk1(ADC2_SCLK1), 175 | .adc_cclk (ADC2_CCLK2), 176 | 177 | // PPI 178 | .ppi_data(PPID), 179 | .ppi_fs1(PPIFS1), 180 | .ppi_fs2(PPIFS2), 181 | .ppi_fs3(PPIFS3), 182 | .ppi_clk(PPICLK), 183 | 184 | .adc_ctrl(ADC_CTRL), 185 | .start(start), 186 | .cfg_register(cfg_register) 187 | ); 188 | 189 | 190 | assign G_RESET = 1'b0; // global_reset 191 | //assign ADC_CTRL = 1'b0; 192 | 193 | assign CLK_C = 1'b0; 194 | assign START_C = 1'b0; 195 | assign CLEAR_R = 1'b0; 196 | assign CLK_R = 1'b0; 197 | assign START_R = 1'b0; 198 | assign CLEAR_C = 1'b0; 199 | 200 | /* 201 | //`define PERMANENT_PPI_CLK 202 | `define PP_CLK_DISABLED_OUT_VALUE_1 203 | 204 | `ifdef PERMANENT_PPI_CLK 205 | assign PPICLK = clk_ppi; 206 | `else 207 | `ifdef PP_CLK_DISABLED_OUT_VALUE_1 208 | BUFGCE_1 209 | `else 210 | BUFGCE 211 | `endif 212 | clk_ppi_en 213 | ( 214 | .I(clk_ppi), 215 | .O(PPICLK), 216 | .CE(ppi_enable_clock) 217 | ); 218 | `endif 219 | */ 220 | 221 | always @(*) begin 222 | TP <= 'bz; 223 | 224 | TP[13] <= cfg_register[3] ? cfg_register[2] : 1'bz; // P9 225 | TP[14] <= cfg_register[1] ? cfg_register[0] : 1'bz; // J1 226 | 227 | TP[15] <= start; 228 | TP[16] <= 0; //start_ppi; 229 | TP[17] <= clk_sys_locked; 230 | TP[18] <= rst_by_timer; 231 | TP[19] <= rst; 232 | TP[20] <= adc_sdata_o; 233 | TP[21] <= adc_sdata_oen_o; 234 | TP[22] <= 0; 235 | end 236 | 237 | 238 | endmodule 239 | -------------------------------------------------------------------------------- /src/tb_main.v: -------------------------------------------------------------------------------- 1 | `timescale 1 ns/1 ps 2 | 3 | module tb(); 4 | 5 | `include "register_file_address_space.v" 6 | 7 | reg clk_sys = 1; 8 | reg clk_adc = 1; 9 | reg rst = 1; 10 | 11 | always #5 clk_sys = ~clk_sys; // 100 MHz 12 | //always #17 clk_adc = ~clk_adc; // 30 MHz 13 | always #8 clk_adc = ~clk_adc; // 60 MHz 14 | 15 | initial #200 rst = 0; 16 | 17 | wire spi_SCK; 18 | wire spi_MOSI; 19 | wire spi_MISO; 20 | wire spi_CSN; 21 | 22 | wire di_req; 23 | reg [15:0] di = 16'hXXXX; 24 | reg wren = 0; 25 | wire wr_ack; 26 | wire do_valid; 27 | wire [15:0] do; 28 | 29 | initial begin 30 | @(negedge rst); 31 | #1; 32 | repeat (10) @(posedge clk_sys); 33 | 34 | //di = {1'b1, 7'h71, 8'h55}; 35 | //wren = 1; 36 | @(posedge clk_sys); 37 | di = 16'hXXXX; 38 | wren = 0; 39 | 40 | /* 41 | repeat (2) begin 42 | repeat (500) @(posedge clk_sys); 43 | 44 | di = {RF_READ_BIT, ADDRESS_CFG_REGISTER, 8'h12}; 45 | wren = 1; 46 | @(posedge clk_sys); 47 | wren = 0; 48 | end 49 | */ 50 | 51 | /* 52 | // --------------- ADC ------------------- 53 | repeat (500) @(posedge clk_sys); 54 | di = {RF_WRITE_BIT, ADDRESS_ADC_ADDR, 8'h01}; 55 | wren = 1; 56 | @(posedge clk_sys); 57 | wren = 0; 58 | 59 | repeat (500) @(posedge clk_sys); 60 | di = {RF_WRITE_BIT, ADDRESS_ADC_VALUE, 8'hAA}; 61 | wren = 1; 62 | @(posedge clk_sys); 63 | wren = 0; 64 | 65 | repeat (8) begin 66 | repeat (500) @(posedge clk_sys); 67 | 68 | di = {RF_READ_BIT, ADDRESS_ADC_BUSY, 8'h00}; 69 | wren = 1; 70 | @(posedge clk_sys); 71 | wren = 0; 72 | end 73 | 74 | repeat (500) @(posedge clk_sys); 75 | di = {RF_WRITE_BIT, ADDRESS_ADC_VALUE_HIGHER_BYTE, 8'hFF}; 76 | wren = 1; 77 | @(posedge clk_sys); 78 | wren = 0; 79 | 80 | repeat (500) @(posedge clk_sys); 81 | di = {RF_WRITE_BIT, ADDRESS_ADC_VALUE, 8'hBB}; 82 | wren = 1; 83 | @(posedge clk_sys); 84 | wren = 0; 85 | 86 | repeat (8) begin 87 | repeat (500) @(posedge clk_sys); 88 | 89 | di = {RF_READ_BIT, ADDRESS_ADC_BUSY, 8'h00}; 90 | wren = 1; 91 | @(posedge clk_sys); 92 | wren = 0; 93 | end 94 | 95 | repeat (500) @(posedge clk_sys); 96 | di = {RF_WRITE_BIT, ADDRESS_ADC_ACQUIRE, 8'h01}; 97 | wren = 1; 98 | @(posedge clk_sys); 99 | wren = 0; 100 | 101 | repeat (8) begin 102 | repeat (500) @(posedge clk_sys); 103 | 104 | di = {RF_READ_BIT, ADDRESS_ADC_BUSY, 8'h00}; 105 | wren = 1; 106 | @(posedge clk_sys); 107 | wren = 0; 108 | end 109 | 110 | repeat (2) begin 111 | repeat (500) @(posedge clk_sys); 112 | di = {RF_READ_BIT, ADDRESS_ADC_VALUE_HIGHER_BYTE, 8'h00}; 113 | wren = 1; 114 | @(posedge clk_sys); 115 | wren = 0; 116 | end 117 | 118 | repeat (2) begin 119 | repeat (500) @(posedge clk_sys); 120 | di = {RF_READ_BIT, ADDRESS_ADC_VALUE, 8'h00}; 121 | wren = 1; 122 | @(posedge clk_sys); 123 | wren = 0; 124 | end 125 | // --------------- end ADC ------------------- 126 | */ 127 | 128 | /* 129 | // --------------- Sensor ------------------- 130 | repeat (500) @(posedge clk_sys); 131 | di = {RF_WRITE_BIT, ADDRESS_SNS_ADDR, 8'h01}; 132 | wren = 1; 133 | @(posedge clk_sys); 134 | wren = 0; 135 | 136 | repeat (500) @(posedge clk_sys); 137 | di = {RF_WRITE_BIT, ADDRESS_SNS_VALUE, 8'hAA}; 138 | wren = 1; 139 | @(posedge clk_sys); 140 | wren = 0; 141 | 142 | repeat (8) begin 143 | repeat (500) @(posedge clk_sys); 144 | 145 | di = {RF_READ_BIT, ADDRESS_SNS_BUSY, 8'h00}; 146 | wren = 1; 147 | @(posedge clk_sys); 148 | wren = 0; 149 | end 150 | 151 | repeat (8) begin 152 | repeat (500) @(posedge clk_sys); 153 | 154 | di = {RF_READ_BIT, ADDRESS_SNS_BUSY, 8'h00}; 155 | wren = 1; 156 | @(posedge clk_sys); 157 | wren = 0; 158 | end 159 | 160 | repeat (500) @(posedge clk_sys); 161 | di = {RF_WRITE_BIT, ADDRESS_SNS_ACQUIRE, 8'h01}; 162 | wren = 1; 163 | @(posedge clk_sys); 164 | wren = 0; 165 | 166 | repeat (8) begin 167 | repeat (500) @(posedge clk_sys); 168 | 169 | di = {RF_READ_BIT, ADDRESS_SNS_BUSY, 8'h00}; 170 | wren = 1; 171 | @(posedge clk_sys); 172 | wren = 0; 173 | end 174 | 175 | repeat (2) begin 176 | repeat (500) @(posedge clk_sys); 177 | di = {RF_READ_BIT, ADDRESS_SNS_VALUE, 8'h00}; 178 | wren = 1; 179 | @(posedge clk_sys); 180 | wren = 0; 181 | end 182 | // --------------- end Sensor ------------------- 183 | */ 184 | 185 | //repeat (500) @(posedge clk_sys); 186 | //di = {RF_WRITE_BIT, ADDRESS_ENABLE_CYCLE_EMULATION, 8'h01}; 187 | //wren = 1; 188 | //@(posedge clk_sys); 189 | //wren = 0; 190 | 191 | //repeat (2) begin 192 | // repeat (500) @(posedge clk_sys); 193 | // di = {RF_READ_BIT, ADDRESS_OVERRIDE_ENABLE_ROI, 8'h00}; 194 | // wren = 1; 195 | // @(posedge clk_sys); 196 | // wren = 0; 197 | //end 198 | 199 | repeat (500) @(posedge clk_sys); 200 | di = {RF_WRITE_BIT, ADDRESS_MODLED_PHASE, 8'h01}; 201 | wren = 1; 202 | @(posedge clk_sys); 203 | wren = 0; 204 | 205 | //repeat (500) @(posedge clk_sys); 206 | //di = {RF_WRITE_BIT, ADDRESS_MODLED_PHASE_1, 8'h02}; 207 | //wren = 1; 208 | //@(posedge clk_sys); 209 | //wren = 0; 210 | // 211 | //repeat (500) @(posedge clk_sys); 212 | //di = {RF_WRITE_BIT, ADDRESS_MODLED_PHASE_2, 8'h03}; 213 | //wren = 1; 214 | //@(posedge clk_sys); 215 | //wren = 0; 216 | // 217 | //repeat (500) @(posedge clk_sys); 218 | //di = {RF_WRITE_BIT, ADDRESS_MODLED_PHASE_3, 8'h04}; 219 | //wren = 1; 220 | //@(posedge clk_sys); 221 | //wren = 0; 222 | // 223 | //repeat (500) @(posedge clk_sys); 224 | //di = {RF_WRITE_BIT, ADDRESS_MULTICYCLE_MODE, 8'h01}; 225 | //wren = 1; 226 | //@(posedge clk_sys); 227 | //wren = 0; 228 | 229 | repeat (500) @(posedge clk_sys); 230 | di = {RF_WRITE_BIT, ADDRESS_START_CYCLE, 8'h01}; 231 | wren = 1; 232 | @(posedge clk_sys); 233 | wren = 0; 234 | 235 | //#4000000; 236 | // 237 | //repeat (500) @(posedge clk_sys); 238 | //di = {RF_WRITE_BIT, ADDRESS_START_CYCLE, 8'h01}; 239 | //wren = 1; 240 | //@(posedge clk_sys); 241 | //wren = 0; 242 | 243 | end 244 | 245 | spi_master #( 246 | .N(16), // 32bit serial word length is default 247 | .CPOL(1), // SPI mode selection (mode 0 default) 248 | .CPHA(1), // CPOL = clock polarity, CPHA = clock phase. 249 | .PREFETCH(2), // prefetch lookahead cycles 250 | .SPI_2X_CLK_DIV(5) // for a 100MHz sclk_i, yields a 10MHz SCK 251 | ) 252 | spi_master ( 253 | .sclk_i(clk_sys), // high-speed serial interface system clock 254 | .pclk_i(clk_sys), // high-speed parallel interface system clock 255 | .rst_i(rst), // reset core 256 | 257 | //// serial interface //// 258 | .spi_ssel_o(spi_CSN), // spi bus slave select line 259 | .spi_sck_o(spi_SCK), // spi bus sck 260 | .spi_mosi_o(spi_MOSI), // spi bus mosi output 261 | .spi_miso_i(spi_MISO), // spi bus spi_miso_i input 262 | 263 | //// parallel interface //// 264 | .di_req_o(di_req), // preload lookahead data request line 265 | .di_i(di), // parallel data in (clocked on rising spi_clk after last bit) 266 | .wren_i(wren), // user data write enable, starts transmission when interface is idle 267 | .wr_ack_o(wr_ack), // write acknowledge 268 | .do_valid_o(do_valid), // do_o data valid signal, valid during one spi_clk rising edge. 269 | .do_o(do), // parallel output (clocked on rising spi_clk after last bit) 270 | 271 | .sck_ena_o(), 272 | .sck_ena_ce_o(), 273 | .do_transfer_o(), 274 | .wren_o(), 275 | .rx_bit_reg_o(), 276 | .state_dbg_o(), 277 | .core_clk_o(), 278 | .core_n_clk_o(), 279 | .core_ce_o(), 280 | .core_n_ce_o(), 281 | .sh_reg_dbg_o() 282 | ); 283 | 284 | wire [15:0] PPID; 285 | wire PPIFS1; 286 | wire PPIFS2; 287 | wire PPIFS3; 288 | //wire ppi_enable_clock; 289 | wire ppi_clk; 290 | 291 | wire sns_start_roi; 292 | reg sns_enable_roi = 1'b0; 293 | wire sns_clk_roi; 294 | wire sns_hold; 295 | wire sns_reset_ccd; 296 | wire sns_sel_sr; 297 | wire sns_modsel; 298 | wire sns_modled; 299 | 300 | wire sns_ce_a; 301 | wire sns_ce_d; 302 | wire sns_sclk; 303 | reg sns_sdi = 1; 304 | wire sns_sdo; 305 | 306 | wire adc_sdata_i; 307 | reg adc_sdata_o = 1; 308 | wire adc_sdata_oen; 309 | wire adc_sclk; 310 | wire adc_sload; 311 | 312 | reg [7:0] adc_data; 313 | always @(posedge clk_adc) adc_data <= $random; 314 | wire adc_sclk2; 315 | wire adc_sclk1; 316 | wire adc_cclk; 317 | 318 | main main 319 | ( 320 | .clk_sys(clk_sys), 321 | .clk_adc(clk_adc), 322 | .rst(rst), 323 | 324 | // Blackfin SPI interface 325 | .cpu_spi_SCK (spi_SCK), 326 | .cpu_spi_MOSI(spi_MOSI), 327 | .cpu_spi_MISO(spi_MISO), 328 | .cpu_spi_CSN (spi_CSN), 329 | 330 | .sns_start_roi_o (sns_start_roi), 331 | .sns_enable_roi_i(sns_enable_roi), 332 | .sns_clk_roi_o (sns_clk_roi), 333 | .sns_hold_o (sns_hold), 334 | .sns_reset_1_o (sns_reset_ccd), // reset_1 335 | .sns_sel_sr_o (sns_sel_sr), 336 | .sns_modsel_o (sns_modsel), 337 | .sns_modled_o (sns_modled), 338 | 339 | .sns_cfg_ce_a_o(sns_ce_a), 340 | .sns_cfg_ce_d_o(sns_ce_d), 341 | .sns_cfg_sclk_o(sns_sclk), 342 | .sns_cfg_sdi_i (sns_sdi ), 343 | .sns_cfg_sdo_o (sns_sdo ), 344 | 345 | // ADC 346 | .adc_cfg_sdata_o (adc_sdata_i), 347 | .adc_cfg_sdata_i (adc_sdata_o), 348 | .adc_cfg_sdata_oen_o(adc_sdata_oen), 349 | .adc_cfg_sclk_o (adc_sclk), 350 | .adc_cfg_sload_o (adc_sload), 351 | 352 | .adc_data (adc_data), 353 | .adc_sclk2(adc_sclk2), 354 | .adc_sclk1(adc_sclk1), 355 | .adc_cclk (adc_cclk), 356 | 357 | // PPI 358 | .ppi_data(PPID), 359 | .ppi_fs1 (PPIFS1), 360 | .ppi_fs2 (PPIFS2), 361 | .ppi_fs3 (PPIFS3), 362 | .ppi_clk (ppi_clk), 363 | 364 | .adc_ctrl(), 365 | .start(), 366 | .cfg_register() 367 | ); 368 | 369 | //initial sns_enable_roi = #100 1'b1; 370 | 371 | always begin 372 | @(posedge sns_start_roi); 373 | #10000; 374 | sns_enable_roi = 1; 375 | //#(2692800+400*100); 376 | #(2692800/2-400*1000); 377 | sns_enable_roi = 0; 378 | #1; 379 | end 380 | 381 | 382 | endmodule 383 | -------------------------------------------------------------------------------- /src/sensor_intf.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module sensor_intf( 4 | clk_i, 5 | rst_i, 6 | 7 | start_i, 8 | autostart_i, 9 | ready_o, 10 | 11 | t_pxlrst_i, 12 | t_rsthold_i, 13 | t_intprep_i, 14 | t_intprep2_i, 15 | t_inthold_i, 16 | t_inthold2_i, 17 | t_rdoprep_i, 18 | t_rdohold_i, 19 | t_roiclk_i, 20 | t_int_numclocks_i, 21 | 22 | sns_reset_1_o, 23 | sns_hold_o, 24 | sns_modsel_en_o, 25 | 26 | sns_start_roi_o, 27 | sns_enable_roi_i, 28 | sns_clk_roi_o, 29 | sns_sel_sr_o, 30 | 31 | ppi_frame_valid_i, 32 | 33 | deb_state_o, 34 | deb_fsm_cnt_o, 35 | deb_fsm_cnt_en_o 36 | ); 37 | 38 | // Bit with of timing parameters 39 | localparam integer TIMING_PARAMS_WIDTH = 12; 40 | 41 | // Master clock 42 | input clk_i; 43 | // Master reset 44 | input rst_i; 45 | 46 | // Start integration-readout cycle. Makes sense only when circuit is ready. 47 | input start_i; 48 | // Autostart signal. 49 | input autostart_i; 50 | // Ready to start signal. 51 | output ready_o; 52 | 53 | // Pixel reset duration (with reset_1 = 1 and hold = 0) 54 | input [TIMING_PARAMS_WIDTH-1:0] t_pxlrst_i; // t23 = 2us 55 | // Hold duration after reset (with reset_1 = 1 and hold = 1) 56 | input [TIMING_PARAMS_WIDTH-1:0] t_rsthold_i; // t25 = 1us 57 | // Prepare duration before integration (with reset_1 = 0 and hold = 1) 58 | input [TIMING_PARAMS_WIDTH-1:0] t_intprep_i; // t26 = 1us 59 | // Prepare duration before integration (with reset_1 = 0 and hold = 0) 60 | input [TIMING_PARAMS_WIDTH-1:0] t_intprep2_i; // t28 = 1us 61 | // Hold duration after integration (with reset_1 = 0 and hold = 0) 62 | input [TIMING_PARAMS_WIDTH-1:0] t_inthold_i; // t29 = 1us 63 | // Hold duration after integration (with reset_1 = 0 and hold = 1) 64 | input [TIMING_PARAMS_WIDTH-1:0] t_inthold2_i; // t24 = 1us 65 | // Prepare duration before readout (with reset_1 = 1 and hold = 1) 66 | input [TIMING_PARAMS_WIDTH-1:0] t_rdoprep_i; // t27 = 1us 67 | // Hold duration after integration (dmitryh:readout) (with reset_1 = 1 and hold = 1) 68 | input [TIMING_PARAMS_WIDTH-1:0] t_rdohold_i; // t31 = 10 us 69 | // ROI Clock period. 70 | input [TIMING_PARAMS_WIDTH-1:0] t_roiclk_i; 71 | // Number of modsel pulses. 72 | input [24-1:0] t_int_numclocks_i; 73 | 74 | // Sensor modulation signals 75 | output sns_reset_1_o; 76 | output sns_hold_o; 77 | output reg sns_modsel_en_o = 0; 78 | 79 | // Sensor ROI (Region of Interest) readout signals 80 | output sns_start_roi_o; 81 | input sns_enable_roi_i; 82 | output sns_clk_roi_o; 83 | output sns_sel_sr_o; 84 | 85 | input ppi_frame_valid_i; 86 | 87 | output [3:0] deb_state_o; 88 | output [24-1:0] deb_fsm_cnt_o; 89 | output deb_fsm_cnt_en_o; 90 | 91 | 92 | //`define STATE_RESET 11'b00000000001 93 | //`define STATE_READY 11'b00000000010 94 | //`define STATE_RESET_DONE 11'b00000000100 95 | //`define STATE_INT_PREPARE 11'b00000001000 96 | //`define STATE_INT_PREPARE2 11'b00000010000 97 | //`define STATE_INTEGRATION 11'b00000100000 98 | //`define STATE_INT_HOLD 11'b00001000000 99 | //`define STATE_INT_HOLD2 11'b00010000000 100 | //`define STATE_RDO_PREPARE 11'b00100000000 101 | //`define STATE_READOUT 11'b01000000000 102 | //`define STATE_RDO_HOLD 11'b10000000000 103 | `define STATE_RESET 4'd0 104 | `define STATE_READY 4'd1 105 | `define STATE_RESET_DONE 4'd2 106 | `define STATE_INT_PREPARE 4'd3 107 | `define STATE_INT_PREPARE2 4'd4 108 | `define STATE_INTEGRATION 4'd5 109 | `define STATE_INT_HOLD 4'd6 110 | `define STATE_INT_HOLD2 4'd7 111 | `define STATE_RDO_PREPARE 4'd8 112 | `define STATE_READOUT 4'd9 113 | `define STATE_RDO_HOLD 4'd10 114 | 115 | //reg [10:0] i_state; 116 | reg [3:0] i_state; 117 | assign deb_state_o = i_state; 118 | 119 | reg [24-1:0] i_fsm_cnt_load_value; 120 | 121 | reg [24-1:0] i_fsm_cnt; 122 | assign deb_fsm_cnt_o = i_fsm_cnt; 123 | reg i_fsm_cnt_en; 124 | assign deb_fsm_cnt_en_o = i_fsm_cnt_en; 125 | // Timing generator for fsm delays 126 | always @(posedge clk_i) begin 127 | if (rst_i) 128 | i_fsm_cnt <= {TIMING_PARAMS_WIDTH{1'b0}}; 129 | else if (!i_fsm_cnt_en) 130 | i_fsm_cnt <= i_fsm_cnt_load_value; 131 | else 132 | if (i_fsm_cnt > {TIMING_PARAMS_WIDTH{1'b0}}) begin 133 | i_fsm_cnt <= i_fsm_cnt - 1'b1; 134 | end 135 | end 136 | 137 | //assign i_fsm_cnt_done = i_fsm_cnt[TIMING_PARAMS_WIDTH-1];//(i_fsm_cnt == {TIMING_PARAMS_WIDTH{1'b0}}); 138 | wire i_fsm_cnt_zero = (i_fsm_cnt == {TIMING_PARAMS_WIDTH{1'b0}}); 139 | reg i_fsm_cnt_zero_prev = 0; 140 | always @(posedge clk_i) 141 | i_fsm_cnt_zero_prev <= i_fsm_cnt_zero; 142 | wire i_fsm_cnt_done = i_fsm_cnt_zero && !i_fsm_cnt_zero_prev; 143 | 144 | 145 | wire i_rdo_done; 146 | reg i_sns_reset_1, i_sns_hold; 147 | 148 | // Main FSM 149 | assign ready_o = (i_state == `STATE_READY); 150 | 151 | always @(posedge clk_i) begin 152 | 153 | 154 | if (rst_i) begin 155 | 156 | i_state <= `STATE_RESET; 157 | i_fsm_cnt_load_value <= t_pxlrst_i; 158 | i_fsm_cnt_en <= 1'b0; 159 | i_sns_reset_1 <= 1'b1; 160 | i_sns_hold <= 1'b0; 161 | 162 | end else if (i_state == `STATE_RESET) begin // 0 163 | 164 | i_fsm_cnt_en <= 1'b1; 165 | i_sns_reset_1 <= 1'b1; 166 | i_sns_hold <= 1'b0; 167 | 168 | if (i_fsm_cnt_done) begin 169 | i_state <= `STATE_READY; 170 | i_fsm_cnt_en <= 1'b0; 171 | i_sns_reset_1 <= 1'b1; 172 | i_sns_hold <= 1'b0; 173 | end 174 | 175 | end else if (i_state == `STATE_READY) begin // 1 176 | 177 | i_fsm_cnt_en <= 1'b0; 178 | i_sns_reset_1 <= 1'b1; 179 | i_sns_hold <= 1'b0; 180 | 181 | if (start_i | autostart_i) begin 182 | i_state <= `STATE_RESET_DONE; 183 | i_fsm_cnt_load_value <= t_rsthold_i; 184 | i_fsm_cnt_en <= 1'b0; 185 | i_sns_reset_1 <= 1'b1; 186 | i_sns_hold <= 1'b1; 187 | end 188 | 189 | end else if (i_state == `STATE_RESET_DONE) begin // 2 190 | 191 | i_fsm_cnt_en <= 1'b1; 192 | i_sns_reset_1 <= 1'b1; 193 | i_sns_hold <= 1'b1; 194 | 195 | if (i_fsm_cnt_done) begin 196 | i_state <= `STATE_INT_PREPARE; 197 | i_fsm_cnt_load_value <= t_intprep_i; 198 | i_fsm_cnt_en <= 1'b0; 199 | i_sns_reset_1 <= 1'b0; 200 | i_sns_hold <= 1'b1; 201 | end 202 | 203 | 204 | end else if (i_state == `STATE_INT_PREPARE) begin // 3 205 | 206 | i_fsm_cnt_en <= 1'b1; 207 | i_sns_reset_1 <= 1'b0; 208 | i_sns_hold <= 1'b1; 209 | 210 | if (i_fsm_cnt_done) begin 211 | i_state <= `STATE_INT_PREPARE2; 212 | i_fsm_cnt_load_value <= t_intprep2_i; 213 | i_fsm_cnt_en <= 1'b0; 214 | i_sns_reset_1 <= 1'b0; 215 | i_sns_hold <= 1'b0; 216 | end 217 | 218 | end else if (i_state == `STATE_INT_PREPARE2) begin // 4 219 | 220 | i_fsm_cnt_en <= 1'b1; 221 | i_sns_reset_1 <= 1'b0; 222 | i_sns_hold <= 1'b0; 223 | 224 | if (i_fsm_cnt_done) begin 225 | i_state <= `STATE_INTEGRATION; 226 | i_fsm_cnt_load_value <= t_int_numclocks_i; 227 | i_fsm_cnt_en <= 1'b0; 228 | i_sns_reset_1 <= 1'b0; 229 | i_sns_hold <= 1'b0; 230 | end 231 | 232 | end else if (i_state == `STATE_INTEGRATION) begin // 5 233 | 234 | i_fsm_cnt_en <= 1'b1; 235 | i_sns_reset_1 <= 1'b0; 236 | i_sns_hold <= 1'b0; 237 | 238 | if (i_fsm_cnt_done) begin 239 | i_state <= `STATE_INT_HOLD; 240 | i_fsm_cnt_load_value <= t_inthold_i; 241 | i_fsm_cnt_en <= 1'b0; 242 | i_sns_reset_1 <= 1'b0; 243 | i_sns_hold <= 1'b0; 244 | end 245 | 246 | end else if (i_state == `STATE_INT_HOLD) begin // 6 247 | 248 | i_fsm_cnt_en <= 1'b1; 249 | i_sns_reset_1 <= 1'b0; 250 | i_sns_hold <= 1'b0; 251 | 252 | if (i_fsm_cnt_done) begin 253 | i_state <= `STATE_INT_HOLD2; 254 | i_fsm_cnt_load_value <= t_inthold2_i; 255 | i_fsm_cnt_en <= 1'b0; 256 | i_sns_reset_1 <= 1'b0; 257 | i_sns_hold <= 1'b1; 258 | end 259 | 260 | end else if (i_state == `STATE_INT_HOLD2) begin // 7 261 | 262 | i_fsm_cnt_en <= 1'b1; 263 | i_sns_reset_1 <= 1'b0; 264 | i_sns_hold <= 1'b1; 265 | 266 | if (i_fsm_cnt_done) begin 267 | i_state <= `STATE_RDO_PREPARE; 268 | i_fsm_cnt_load_value <= t_rdoprep_i; 269 | i_fsm_cnt_en <= 1'b0; 270 | i_sns_reset_1 <= 1'b1; 271 | i_sns_hold <= 1'b1; 272 | end 273 | 274 | end else if (i_state == `STATE_RDO_PREPARE) begin // 8 275 | 276 | i_fsm_cnt_en <= 1'b1; 277 | i_sns_reset_1 <= 1'b1; 278 | i_sns_hold <= 1'b1; 279 | 280 | if (i_fsm_cnt_done) begin 281 | i_state <= `STATE_READOUT; 282 | i_fsm_cnt_en <= 1'b0; 283 | i_sns_reset_1 <= 1'b1; 284 | i_sns_hold <= 1'b1; 285 | end 286 | 287 | end else if (i_state == `STATE_READOUT) begin // 9 288 | 289 | i_fsm_cnt_en <= 1'b0; 290 | i_sns_reset_1 <= 1'b1; 291 | i_sns_hold <= 1'b1; 292 | 293 | if (i_rdo_done) begin 294 | i_state <= `STATE_RDO_HOLD; 295 | i_fsm_cnt_load_value <= t_rdohold_i; 296 | i_fsm_cnt_en <= 1'b0; 297 | i_sns_reset_1 <= 1'b1; 298 | i_sns_hold <= 1'b1; 299 | end 300 | 301 | end else if (i_state == `STATE_RDO_HOLD) begin // 10 302 | 303 | i_fsm_cnt_en <= 1'b1; 304 | i_sns_reset_1 <= 1'b1; 305 | i_sns_hold <= 1'b1; 306 | 307 | if (i_fsm_cnt_done) begin 308 | i_state <= `STATE_RESET; 309 | i_fsm_cnt_load_value <= t_pxlrst_i; 310 | i_fsm_cnt_en <= 1'b0; 311 | i_sns_reset_1 <= 1'b1; 312 | i_sns_hold <= 1'b0; 313 | end 314 | 315 | end 316 | end 317 | 318 | assign sns_reset_1_o = i_sns_reset_1; 319 | assign sns_hold_o = i_sns_hold; 320 | 321 | 322 | // Integration process 323 | 324 | always @(posedge clk_i) begin 325 | sns_modsel_en_o <= (i_state == `STATE_INTEGRATION); 326 | end 327 | 328 | // Readout process 329 | 330 | reg [TIMING_PARAMS_WIDTH-1:0] i_roi_clk_fdcntr; 331 | reg i_roi_clk; 332 | wire i_roi_clk_t, i_roi_clk_re, i_roi_clk_fe; 333 | 334 | always @(posedge clk_i) begin 335 | if (rst_i || i_roi_clk_t) 336 | i_roi_clk_fdcntr <= t_roiclk_i-1; 337 | else 338 | i_roi_clk_fdcntr <= i_roi_clk_fdcntr - 1'b1; 339 | 340 | if (rst_i) 341 | i_roi_clk <= 1'b0; 342 | else if (i_roi_clk_t) 343 | i_roi_clk <= !i_roi_clk; 344 | end 345 | assign i_roi_clk_t = (i_roi_clk_fdcntr == {TIMING_PARAMS_WIDTH{1'b0}}); 346 | assign i_roi_clk_fe = (i_roi_clk_t && i_roi_clk); 347 | assign i_roi_clk_re = (i_roi_clk_t && !i_roi_clk); 348 | 349 | reg i_roi_start, i_roi_cycle; 350 | reg [1:0] i_roi_enable; 351 | wire i_rdo_start; 352 | 353 | assign i_rdo_start = (i_state == `STATE_READOUT && i_roi_clk_fe && !i_roi_cycle); 354 | 355 | wire composite_frame_valid = sns_enable_roi_i | ppi_frame_valid_i; 356 | 357 | always @(posedge clk_i) begin 358 | 359 | if (i_state != `STATE_READOUT) 360 | i_roi_cycle <= 1'b0; 361 | else if (i_roi_clk_fe && !i_roi_cycle) 362 | i_roi_cycle <= 1'b1; 363 | 364 | if (rst_i || (i_roi_start && i_roi_clk_fe)) 365 | i_roi_start <= 1'b0; 366 | else if (i_rdo_start) 367 | i_roi_start <= 1'b1; 368 | 369 | if (i_roi_clk_re) 370 | i_roi_enable[1:0] <= {i_roi_enable[0], composite_frame_valid}; 371 | end 372 | 373 | assign i_rdo_done = ((i_state == `STATE_READOUT) && (i_roi_enable == 2'b10)); 374 | 375 | assign sns_start_roi_o = i_roi_start; 376 | assign sns_clk_roi_o = i_roi_clk; 377 | assign sns_sel_sr_o = 1'b0; 378 | 379 | 380 | endmodule 381 | -------------------------------------------------------------------------------- /src/main.v: -------------------------------------------------------------------------------- 1 | module main 2 | ( 3 | input clk_sys, 4 | input clk_adc, 5 | input rst, 6 | 7 | // SPI interface 8 | input cpu_spi_SCK, 9 | input cpu_spi_MOSI, 10 | output cpu_spi_MISO, 11 | input cpu_spi_CSN, 12 | 13 | // Sensor 14 | output sns_start_roi_o, 15 | input sns_enable_roi_i, 16 | output sns_clk_roi_o, 17 | output sns_hold_o, 18 | output sns_reset_1_o, 19 | output sns_sel_sr_o, 20 | output sns_modsel_o, 21 | output sns_modled_o, 22 | 23 | output sns_cfg_ce_a_o, 24 | output sns_cfg_ce_d_o, 25 | output sns_cfg_sclk_o, 26 | input sns_cfg_sdi_i, 27 | output sns_cfg_sdo_o, 28 | 29 | // ADC 30 | output adc_cfg_sdata_o, 31 | input adc_cfg_sdata_i, 32 | output adc_cfg_sdata_oen_o, 33 | output adc_cfg_sclk_o, 34 | output adc_cfg_sload_o, 35 | 36 | input [7:0] adc_data, 37 | output adc_sclk2, 38 | output adc_sclk1, 39 | output adc_cclk, 40 | 41 | // PPI 42 | output reg [15:0] ppi_data, 43 | output reg ppi_fs1, 44 | output reg ppi_fs2, 45 | output reg ppi_fs3, 46 | output ppi_clk, 47 | 48 | // Debug 49 | output adc_ctrl, 50 | output start, 51 | output [7:0] cfg_register 52 | ); 53 | 54 | `define SPI 55 | `ifdef SPI 56 | wire cpu_di_req; 57 | wire [15:0] cpu_di; 58 | wire cpu_wren; 59 | wire cpu_wr_ack; 60 | wire cpu_do_valid; 61 | wire [15:0] cpu_do; 62 | 63 | spi_slave #( 64 | .N(16), // 32bit serial word length is default 65 | .CPOL(1), // SPI mode selection (mode 0 default) 66 | .CPHA(1), // CPOL = clock polarity, CPHA = clock phase. 67 | .PREFETCH(2) // prefetch lookahead cycles 68 | ) 69 | spi_slave( 70 | .clk_i(clk_sys), // internal interface clock (clocks di/do registers) 71 | .spi_ssel_i(cpu_spi_CSN), // spi bus slave select line 72 | .spi_sck_i(cpu_spi_SCK), // spi bus sck clock (clocks the shift register core) 73 | .spi_mosi_i(cpu_spi_MOSI), // spi bus mosi input 74 | .spi_miso_o(cpu_spi_MISO), // spi bus spi_miso_o output 75 | .di_req_o(cpu_di_req), // preload lookahead data request line 76 | .di_i(cpu_di), // parallel load data in (clocked in on rising edge of clk_i) 77 | .wren_i(cpu_wren), // user data write enable 78 | .wr_ack_o(cpu_wr_ack), // write acknowledge 79 | .do_valid_o(cpu_do_valid), // do_o data valid strobe, valid during one clk_i rising edge. 80 | .do_o(cpu_do), // parallel output (clocked out on falling clk_i) 81 | 82 | .do_transfer_o(), 83 | .wren_o(), 84 | .rx_bit_next_o(), 85 | .state_dbg_o(), 86 | .sh_reg_dbg_o() 87 | ); 88 | assign start = cpu_do_valid; 89 | 90 | `else 91 | counter_ms counter_ms 92 | ( 93 | .clk(clk_sys), 94 | .rst(rst), 95 | .clocks_in_ms(18'd100_000_000), 96 | .time_ms(), 97 | .pulse_ms(start) 98 | ); 99 | `endif 100 | 101 | 102 | wire [2:0] adc_p_address; 103 | wire [8:0] adc_p_write_data; 104 | wire adc_p_write_valid; 105 | wire adc_p_read_start; 106 | wire [8:0] adc_p_read_data; 107 | wire adc_p_busy; 108 | 109 | wire [6:0] sns_p_address; 110 | wire [7:0] sns_p_write_data; 111 | wire sns_p_write_valid; 112 | wire sns_p_read_start; 113 | wire [7:0] sns_p_read_data; 114 | wire sns_p_busy; 115 | wire sns_p_mux_ce_a_nd; 116 | 117 | wire [7:0] modsel_divisor; 118 | wire [7:0] modsel_phase; 119 | wire start_multicycle; 120 | wire [23:0] integration_time; 121 | wire multicycle_finished; 122 | wire override_sns_enable_roi; 123 | wire switch_to_cycle_emulation; 124 | wire is_multicycle; 125 | wire [7:0] modsel_phase_1; 126 | wire [7:0] modsel_phase_2; 127 | wire [7:0] modsel_phase_3; 128 | 129 | wire [3:0] deb_state; 130 | wire [23:0] deb_fsm_cnt; 131 | wire deb_fsm_cnt_en; 132 | 133 | register_file register_file 134 | ( 135 | .clk_i(clk_sys), 136 | .rst_i(rst), 137 | 138 | .cpu_din_i(cpu_do), 139 | .cpu_din_we_i(cpu_do_valid), 140 | 141 | .cpu_dout_o(cpu_di), 142 | .cpu_dout_valid_o(cpu_wren), 143 | .cpu_dout_ack_i(cpu_wr_ack), 144 | 145 | .adc_p_address_o (adc_p_address ), 146 | .adc_p_write_data_o (adc_p_write_data ), 147 | .adc_p_write_valid_o(adc_p_write_valid), 148 | .adc_p_read_start_o (adc_p_read_start ), 149 | .adc_p_read_data_i (adc_p_read_data ), 150 | .adc_p_busy_i (adc_p_busy ), 151 | 152 | .sns_p_address_o (sns_p_address ), 153 | .sns_p_write_data_o (sns_p_write_data ), 154 | .sns_p_write_valid_o(sns_p_write_valid), 155 | .sns_p_read_start_o (sns_p_read_start ), 156 | .sns_p_read_data_i (sns_p_read_data ), 157 | .sns_p_busy_i (sns_p_busy ), 158 | .sns_p_mux_ce_a_nd_o(sns_p_mux_ce_a_nd), 159 | 160 | .cfg_register_o (cfg_register ), 161 | .start_cycle_o (start_multicycle ), 162 | .modsel_divisor_o (modsel_divisor ), 163 | .modsel_phase_o (modsel_phase ), 164 | .integration_time_o (integration_time ), 165 | .cycle_finished_i (multicycle_finished ), 166 | .override_sns_enable_roi_o (override_sns_enable_roi ), 167 | .switch_to_cycle_emulation_o(switch_to_cycle_emulation), 168 | .adc_ctrl_o (adc_ctrl), 169 | .is_multicycle_o (is_multicycle), 170 | .modsel_phase_1_o (modsel_phase_1), 171 | .modsel_phase_2_o (modsel_phase_2), 172 | .modsel_phase_3_o (modsel_phase_3), 173 | 174 | .debug_0_i({4'b0, deb_state}), 175 | .debug_1_i(deb_fsm_cnt[0+:8]), 176 | .debug_2_i(deb_fsm_cnt[8+:8]), 177 | .debug_3_i(deb_fsm_cnt[16+:8]), 178 | .debug_4_i({7'b0, deb_fsm_cnt_en}), 179 | .debug_5_i(8'b0), 180 | .debug_6_i(8'b0), 181 | .debug_7_i(8'b0) 182 | ); 183 | 184 | 185 | ad9826_serial_controller ad9826_serial_controller 186 | ( 187 | .clk(clk_sys), 188 | .rst(rst), 189 | 190 | .sdata_o (adc_cfg_sdata_o ), 191 | .sdata_i (adc_cfg_sdata_i ), 192 | .sdata_oen_o(adc_cfg_sdata_oen_o), 193 | .sclk_o (adc_cfg_sclk_o ), 194 | .sload_o (adc_cfg_sload_o ), 195 | 196 | .address_i (adc_p_address ), 197 | .write_data_i (adc_p_write_data ), 198 | .write_valid_i(adc_p_write_valid), 199 | .read_start_i (adc_p_read_start ), 200 | .read_data_o (adc_p_read_data ), 201 | .busy_o (adc_p_busy ) 202 | ); 203 | 204 | 205 | sensor_serial_controller sensor_serial_controller 206 | ( 207 | .clk(clk_sys), 208 | .rst(rst), 209 | 210 | .ce_a_o(sns_cfg_ce_a_o), 211 | .ce_d_o(sns_cfg_ce_d_o), 212 | .sclk_o(sns_cfg_sclk_o), 213 | .sdi_i (sns_cfg_sdi_i ), 214 | .sdo_o (sns_cfg_sdo_o ), 215 | 216 | .address_i (sns_p_address ), 217 | .write_data_i (sns_p_write_data ), 218 | .write_valid_i(sns_p_write_valid), 219 | .read_start_i (sns_p_read_start ), 220 | .read_data_o (sns_p_read_data ), 221 | .busy_o (sns_p_busy ), 222 | .mux_ce_a_nd_i(sns_p_mux_ce_a_nd) 223 | ); 224 | 225 | 226 | wire sns_modsel_en; 227 | wire [7:0] modsel_phase_multicycle; 228 | clock_divider_two_phase #( 229 | .DIVISOR_BITS(8) 230 | ) 231 | modsel_clk_gen ( 232 | .clk_in(clk_sys), 233 | .rst(rst || (!sns_modsel_en)), 234 | .divisor(modsel_divisor), 235 | .phase(modsel_phase_multicycle), 236 | .clk_out(sns_modsel_o), 237 | .clk_out_phased(sns_modled_o) 238 | ); 239 | 240 | wire start_multicycle_pulse; 241 | posedge_detection front_of_start( 242 | .signal(start_multicycle), 243 | .clk(clk_sys), 244 | .posedge_signal(start_multicycle_pulse) 245 | ); 246 | 247 | wire start_cycle; 248 | wire cycle_finished_sys; 249 | wire ppi_frame_valid_sys; 250 | multicycle_generator multicycle_generator( 251 | .clk_i(clk_sys), 252 | .rst_i(rst), 253 | 254 | .is_multicycle_i(is_multicycle), 255 | .start_multicycle_i(start_multicycle_pulse), 256 | .start_sycle_o(start_cycle), 257 | .ppi_frame_valid_i(ppi_frame_valid_sys), // required to the chain: start -> something in between -> finished 258 | .cycle_finished_i(cycle_finished_sys), 259 | .multicycle_finished_o(multicycle_finished), 260 | 261 | .modsel_phase_i(modsel_phase), 262 | .modsel_phase_1_i(modsel_phase_1), 263 | .modsel_phase_2_i(modsel_phase_2), 264 | .modsel_phase_3_i(modsel_phase_3), 265 | .modsel_phase_o(modsel_phase_multicycle) 266 | ); 267 | 268 | 269 | wire start_ppi; 270 | pulse_cross_domain pulse_cross_domain( 271 | .in_clk(clk_sys), 272 | .in_pulse(start_cycle), 273 | .out_clk(ppi_clk), 274 | .out_pulse(start_ppi) 275 | ); 276 | 277 | wire enable_roi_emulation; 278 | pulse_widener #( 279 | .PERIOD(100) 280 | ) 281 | pw ( 282 | .clk_i(ppi_clk), 283 | .rst(rst), 284 | .pulse_i(start_ppi), 285 | .out_o(enable_roi_emulation) 286 | ); 287 | 288 | localparam integer clk_adc_freq_mhz = 30; 289 | localparam [11:0] t_pxlrst = clk_adc_freq_mhz * 2.0; 290 | localparam [11:0] t_rsthold = clk_adc_freq_mhz * 1.0; 291 | localparam [11:0] t_intprep = clk_adc_freq_mhz * 1.0; 292 | localparam [11:0] t_intprep2 = clk_adc_freq_mhz * 1.0; 293 | localparam [11:0] t_inthold = clk_adc_freq_mhz * 1.0; 294 | localparam [11:0] t_inthold2 = clk_adc_freq_mhz * 1.0; 295 | localparam [11:0] t_rdoprep = clk_adc_freq_mhz * 1.0; 296 | localparam [11:0] t_rdohold = clk_adc_freq_mhz * 10.0; 297 | //localparam integer t_int_numclocks_i = clk_adc_freq_mhz * 20.0; // 50 us integration time 298 | 299 | wire start_sensor = switch_to_cycle_emulation ? 1'b0 : 300 | override_sns_enable_roi ? 1'b0 : start_ppi; 301 | wire ready_sensor; 302 | wire ppi_frame_valid; 303 | 304 | sensor_intf sensor_intf 305 | ( 306 | .clk_i(clk_adc), 307 | .rst_i(rst), 308 | 309 | .start_i(start_sensor), 310 | .autostart_i(1'b0), 311 | .ready_o(ready_sensor), 312 | 313 | .t_pxlrst_i (t_pxlrst), 314 | .t_rsthold_i (t_rsthold), 315 | .t_intprep_i (t_intprep), 316 | .t_intprep2_i(t_intprep2), 317 | .t_inthold_i (t_inthold), 318 | .t_inthold2_i(t_inthold2), 319 | .t_rdoprep_i (t_rdoprep), 320 | .t_rdohold_i (t_rdohold), 321 | .t_roiclk_i (12'd6), 322 | .t_int_numclocks_i(integration_time), // t_int_numclocks_i 323 | 324 | .sns_reset_1_o (sns_reset_1_o), 325 | .sns_hold_o (sns_hold_o), 326 | .sns_modsel_en_o (sns_modsel_en), 327 | .sns_start_roi_o (sns_start_roi_o), 328 | .sns_enable_roi_i(sns_enable_roi_i), 329 | .sns_clk_roi_o (sns_clk_roi_o), 330 | .sns_sel_sr_o (sns_sel_sr_o), 331 | 332 | // required to check that both sns_enable_roi_i and real_ppi_fs2 finished to start new cycle 333 | .ppi_frame_valid_i(ppi_frame_valid), 334 | 335 | .deb_state_o(deb_state), 336 | .deb_fsm_cnt_o(deb_fsm_cnt), 337 | .deb_fsm_cnt_en_o(deb_fsm_cnt_en) 338 | ); 339 | 340 | wire [15:0] real_ppi_data; 341 | wire real_ppi_fs1 ; 342 | wire real_ppi_fs2 ; 343 | wire real_ppi_fs3 ; 344 | wire sns_enable_roi = override_sns_enable_roi ? enable_roi_emulation : sns_enable_roi_i; 345 | ad9826_data_controller ad9826_data_controller 346 | ( 347 | .clk_adc_i(clk_adc), 348 | .rst_i(rst), 349 | 350 | .sns_enable_roi_i(sns_enable_roi), 351 | .sns_clk_roi_i(sns_clk_roi_o), // correct 352 | 353 | .adc_data_i(adc_data), 354 | .adc_sclk2_o(adc_sclk2), 355 | .adc_sclk1_o(adc_sclk1), 356 | .adc_cclk_o(adc_cclk), 357 | 358 | .ppi_data_o(real_ppi_data), 359 | .ppi_fs1_o (real_ppi_fs1 ), 360 | .ppi_fs2_o (real_ppi_fs2 ), 361 | .ppi_fs3_o (real_ppi_fs3 ), 362 | .ppi_clk_o (ppi_clk ) 363 | ); 364 | 365 | wire [15:0] generator_ppi_data; 366 | wire generator_ppi_fs1; 367 | wire generator_ppi_fs2; 368 | wire generator_ppi_fs3; 369 | 370 | wire start_generator = switch_to_cycle_emulation ? start_ppi : 1'b0; 371 | wire ready_generator; 372 | ppi_generator ppi_generator 373 | ( 374 | .clk_ppi(ppi_clk), 375 | .rst(rst), 376 | 377 | .start(start_generator), 378 | .ready(ready_generator), 379 | 380 | .ppi_data(generator_ppi_data), 381 | .ppi_fs1 (generator_ppi_fs1), 382 | .ppi_fs2 (generator_ppi_fs2), 383 | .ppi_fs3 (generator_ppi_fs3) 384 | ); 385 | 386 | 387 | always @(*) begin 388 | if (switch_to_cycle_emulation) begin 389 | ppi_data <= generator_ppi_data; 390 | ppi_fs1 <= generator_ppi_fs1; 391 | ppi_fs2 <= generator_ppi_fs2; 392 | ppi_fs3 <= generator_ppi_fs3; 393 | end 394 | else begin 395 | ppi_data <= real_ppi_data; 396 | ppi_fs1 <= real_ppi_fs1; 397 | ppi_fs2 <= real_ppi_fs2; 398 | ppi_fs3 <= real_ppi_fs3; 399 | end 400 | end 401 | 402 | assign ppi_frame_valid = ppi_fs2; 403 | 404 | wire cycle_finished = switch_to_cycle_emulation ? ready_generator : ready_sensor; 405 | 406 | cross_domain finished_ppi_to_sys( 407 | .clk_dst(clk_sys), 408 | .in(cycle_finished), 409 | .out(cycle_finished_sys) 410 | ); 411 | 412 | cross_domain frame_valid_ppi_to_sys( 413 | .clk_dst(clk_sys), 414 | .in(ppi_frame_valid), 415 | .out(ppi_frame_valid_sys) 416 | ); 417 | 418 | endmodule 419 | -------------------------------------------------------------------------------- /src/register_file.v: -------------------------------------------------------------------------------- 1 | module register_file 2 | ( 3 | input clk_i, 4 | input rst_i, 5 | 6 | input [15:0] cpu_din_i, 7 | input cpu_din_we_i, 8 | 9 | output reg [15:0] cpu_dout_o, 10 | output reg cpu_dout_valid_o, 11 | input cpu_dout_ack_i, 12 | 13 | output reg [2:0] adc_p_address_o, 14 | output reg [8:0] adc_p_write_data_o, 15 | output reg adc_p_write_valid_o, 16 | output reg adc_p_read_start_o, 17 | input [8:0] adc_p_read_data_i, 18 | input adc_p_busy_i, 19 | 20 | output reg [6:0] sns_p_address_o, 21 | output reg [7:0] sns_p_write_data_o, 22 | output reg sns_p_write_valid_o, 23 | output reg sns_p_read_start_o, 24 | input [7:0] sns_p_read_data_i, 25 | input sns_p_busy_i, 26 | output reg sns_p_mux_ce_a_nd_o, 27 | 28 | output reg [7:0] cfg_register_o, 29 | output start_cycle_o, 30 | output reg [7:0] modsel_divisor_o, 31 | output reg [7:0] modsel_phase_o, 32 | output reg [23:0] integration_time_o, 33 | input cycle_finished_i, 34 | output reg override_sns_enable_roi_o, 35 | output reg switch_to_cycle_emulation_o, 36 | output reg adc_ctrl_o, 37 | output reg is_multicycle_o, 38 | output reg [7:0] modsel_phase_1_o, 39 | output reg [7:0] modsel_phase_2_o, 40 | output reg [7:0] modsel_phase_3_o, 41 | 42 | input [7:0] debug_0_i, 43 | input [7:0] debug_1_i, 44 | input [7:0] debug_2_i, 45 | input [7:0] debug_3_i, 46 | input [7:0] debug_4_i, 47 | input [7:0] debug_5_i, 48 | input [7:0] debug_6_i, 49 | input [7:0] debug_7_i 50 | ); 51 | 52 | `include "register_file_address_space.v" 53 | 54 | localparam [0:0] write_bit = RF_WRITE_BIT; 55 | localparam [0:0] read_bit = RF_READ_BIT; 56 | 57 | reg cpu_din_we_prev = 0; 58 | always @(posedge clk_i) 59 | cpu_din_we_prev <= cpu_din_we_i; 60 | wire cpu_din_we = cpu_din_we_i & (~cpu_din_we_prev); 61 | 62 | wire wr_nrd_comb = cpu_din_we ? cpu_din_i[15] : 0; 63 | wire [6:0] address_comb = cpu_din_we ? cpu_din_i[8+:7] : 0; 64 | wire [7:0] data_in_comb = cpu_din_we ? cpu_din_i[0+:8] : 0; 65 | 66 | reg adc_higher_byte_written = 0; // for ADC 67 | reg start_cycle_int = 0; 68 | 69 | always @(posedge clk_i) begin 70 | if (rst_i) begin 71 | cpu_dout_o <= 16'd0; 72 | cpu_dout_valid_o <= 0; 73 | 74 | cfg_register_o <= 0; 75 | modsel_divisor_o <= 6; 76 | modsel_phase_o <= 0; 77 | modsel_phase_1_o <= 0; 78 | modsel_phase_2_o <= 0; 79 | modsel_phase_3_o <= 0; 80 | integration_time_o <= 24'd1500; 81 | override_sns_enable_roi_o <= 0; 82 | switch_to_cycle_emulation_o <= 0; 83 | start_cycle_int <= 0; 84 | adc_ctrl_o <= 0; 85 | is_multicycle_o <= 0; 86 | 87 | adc_p_address_o <= 3'b0; 88 | adc_p_write_data_o <= 9'b0; 89 | adc_p_write_valid_o <= 1'b0; 90 | adc_p_read_start_o <= 1'b0; 91 | adc_higher_byte_written <= 0; 92 | 93 | sns_p_address_o <= 7'b0; 94 | sns_p_write_data_o <= 8'b0; 95 | sns_p_write_valid_o <= 1'b0; 96 | sns_p_read_start_o <= 1'b0; 97 | sns_p_mux_ce_a_nd_o <= 1'b1; 98 | end 99 | else begin 100 | // defaults 101 | cpu_dout_o <= 16'd0; 102 | cpu_dout_valid_o <= 0; 103 | adc_p_write_valid_o <= 0; 104 | adc_p_read_start_o <= 0; 105 | sns_p_write_valid_o <= 0; 106 | sns_p_read_start_o <= 0; 107 | start_cycle_int <= 0; // pulse 108 | 109 | if (cpu_din_we) begin 110 | case (address_comb) 111 | ADDRESS_CFG_REGISTER: begin 112 | if (wr_nrd_comb) begin 113 | cfg_register_o <= data_in_comb[0+:8]; 114 | end 115 | else begin 116 | cpu_dout_o <= {read_bit, address_comb, cfg_register_o}; 117 | cpu_dout_valid_o <= 1; 118 | end 119 | end 120 | ADDRESS_MODSEL_DIVISOR: begin 121 | if (wr_nrd_comb) begin 122 | modsel_divisor_o <= data_in_comb[0+:8]; 123 | end 124 | else begin 125 | cpu_dout_o <= {read_bit, address_comb, modsel_divisor_o}; 126 | cpu_dout_valid_o <= 1; 127 | end 128 | end 129 | ADDRESS_MODLED_PHASE: begin 130 | if (wr_nrd_comb) begin 131 | modsel_phase_o <= data_in_comb[0+:8]; 132 | end 133 | else begin 134 | cpu_dout_o <= {read_bit, address_comb, modsel_phase_o}; 135 | cpu_dout_valid_o <= 1; 136 | end 137 | end 138 | ADDRESS_MODLED_PHASE_1: begin 139 | if (wr_nrd_comb) begin 140 | modsel_phase_1_o <= data_in_comb[0+:8]; 141 | end 142 | else begin 143 | cpu_dout_o <= {read_bit, address_comb, modsel_phase_1_o}; 144 | cpu_dout_valid_o <= 1; 145 | end 146 | end 147 | ADDRESS_MODLED_PHASE_2: begin 148 | if (wr_nrd_comb) begin 149 | modsel_phase_2_o <= data_in_comb[0+:8]; 150 | end 151 | else begin 152 | cpu_dout_o <= {read_bit, address_comb, modsel_phase_2_o}; 153 | cpu_dout_valid_o <= 1; 154 | end 155 | end 156 | ADDRESS_MODLED_PHASE_3: begin 157 | if (wr_nrd_comb) begin 158 | modsel_phase_3_o <= data_in_comb[0+:8]; 159 | end 160 | else begin 161 | cpu_dout_o <= {read_bit, address_comb, modsel_phase_3_o}; 162 | cpu_dout_valid_o <= 1; 163 | end 164 | end 165 | ADDRESS_START_CYCLE: begin 166 | if (wr_nrd_comb) begin 167 | start_cycle_int <= 1; // pulse 168 | end 169 | end 170 | ADDRESS_CYCLE_FINISHED: begin 171 | if (wr_nrd_comb) begin 172 | // do nothing 173 | end 174 | else begin 175 | cpu_dout_o <= {read_bit, address_comb, 7'b0, cycle_finished_i}; 176 | cpu_dout_valid_o <= 1; 177 | end 178 | end 179 | ADDRESS_INTEGRATION_TIME_0: begin 180 | if (wr_nrd_comb) begin 181 | integration_time_o[0+:8] <= data_in_comb[0+:8]; 182 | end 183 | else begin 184 | cpu_dout_o <= {read_bit, address_comb, integration_time_o[0+:8]}; 185 | cpu_dout_valid_o <= 1; 186 | end 187 | end 188 | ADDRESS_INTEGRATION_TIME_1: begin 189 | if (wr_nrd_comb) begin 190 | integration_time_o[8+:8] <= data_in_comb[0+:8]; 191 | end 192 | else begin 193 | cpu_dout_o <= {read_bit, address_comb, integration_time_o[8+:8]}; 194 | cpu_dout_valid_o <= 1; 195 | end 196 | end 197 | ADDRESS_INTEGRATION_TIME_2: begin 198 | if (wr_nrd_comb) begin 199 | integration_time_o[16+:8] <= data_in_comb[0+:8]; 200 | end 201 | else begin 202 | cpu_dout_o <= {read_bit, address_comb, integration_time_o[16+:8]}; 203 | cpu_dout_valid_o <= 1; 204 | end 205 | end 206 | ADDRESS_OVERRIDE_ENABLE_ROI: begin 207 | if (wr_nrd_comb) begin 208 | override_sns_enable_roi_o <= data_in_comb[0]; 209 | end 210 | else begin 211 | cpu_dout_o <= {read_bit, address_comb, 7'b0, override_sns_enable_roi_o}; 212 | cpu_dout_valid_o <= 1; 213 | end 214 | end 215 | ADDRESS_ENABLE_CYCLE_EMULATION: begin 216 | if (wr_nrd_comb) begin 217 | switch_to_cycle_emulation_o <= data_in_comb[0]; 218 | end 219 | else begin 220 | cpu_dout_o <= {read_bit, address_comb, 7'b0, switch_to_cycle_emulation_o}; 221 | cpu_dout_valid_o <= 1; 222 | end 223 | end 224 | 225 | // ----------------------------- ADC --------------------------------- 226 | ADDRESS_ADC_ADDR: begin 227 | if (wr_nrd_comb) begin 228 | adc_p_address_o <= data_in_comb[0+:3]; 229 | end 230 | else begin 231 | cpu_dout_o <= {read_bit, address_comb, 5'b0, adc_p_address_o}; 232 | cpu_dout_valid_o <= 1; 233 | end 234 | end 235 | ADDRESS_ADC_VALUE: begin 236 | if (wr_nrd_comb) begin 237 | if (adc_higher_byte_written) begin 238 | adc_p_write_data_o[0+:8] <= data_in_comb[0+:8]; // do not overwrite higher byte (1 bit) 239 | end 240 | else begin 241 | adc_p_write_data_o <= {1'b0, data_in_comb[0+:8]}; // force higher byte to 0 242 | end 243 | adc_higher_byte_written <= 0; 244 | adc_p_write_valid_o <= 1; 245 | end 246 | else begin 247 | cpu_dout_o <= {read_bit, address_comb, adc_p_read_data_i[0+:8]}; 248 | cpu_dout_valid_o <= 1; 249 | end 250 | end 251 | ADDRESS_ADC_VALUE_HIGHER_BYTE: begin 252 | if (wr_nrd_comb) begin 253 | adc_p_write_data_o[8] <= data_in_comb[0]; 254 | adc_higher_byte_written <= 1; 255 | end 256 | else begin 257 | cpu_dout_o <= {read_bit, address_comb, {7'b0, adc_p_read_data_i[8]}}; 258 | cpu_dout_valid_o <= 1; 259 | end 260 | end 261 | ADDRESS_ADC_BUSY: begin 262 | if (wr_nrd_comb) begin 263 | // do nothing 264 | end 265 | else begin 266 | cpu_dout_o <= {read_bit, address_comb, 7'b0, adc_p_busy_i}; 267 | cpu_dout_valid_o <= 1; 268 | end 269 | end 270 | ADDRESS_ADC_ACQUIRE: begin 271 | adc_p_read_start_o <= 1; 272 | end 273 | // ----------------------------- end ADC --------------------------------- 274 | 275 | // ----------------------------- Sensor --------------------------------- 276 | ADDRESS_SNS_ADDR: begin 277 | if (wr_nrd_comb) begin 278 | sns_p_address_o <= data_in_comb[0+:7]; 279 | end 280 | else begin 281 | cpu_dout_o <= {read_bit, address_comb, 1'b0, sns_p_address_o}; 282 | cpu_dout_valid_o <= 1; 283 | end 284 | end 285 | ADDRESS_SNS_VALUE: begin 286 | if (wr_nrd_comb) begin 287 | sns_p_write_data_o <= data_in_comb[0+:8]; 288 | sns_p_write_valid_o <= 1; 289 | end 290 | else begin 291 | cpu_dout_o <= {read_bit, address_comb, sns_p_read_data_i[0+:8]}; 292 | cpu_dout_valid_o <= 1; 293 | end 294 | end 295 | ADDRESS_SNS_BUSY: begin 296 | if (wr_nrd_comb) begin 297 | // do nothing 298 | end 299 | else begin 300 | cpu_dout_o <= {read_bit, address_comb, 7'b0, sns_p_busy_i}; 301 | cpu_dout_valid_o <= 1; 302 | end 303 | end 304 | ADDRESS_SNS_ACQUIRE: begin 305 | sns_p_read_start_o <= 1; 306 | end 307 | ADDRESS_MUX_CE_A_ND: begin 308 | if (wr_nrd_comb) begin 309 | sns_p_mux_ce_a_nd_o <= data_in_comb[0]; 310 | end 311 | else begin 312 | cpu_dout_o <= {read_bit, address_comb, 7'b0, sns_p_mux_ce_a_nd_o}; 313 | cpu_dout_valid_o <= 1; 314 | end 315 | end 316 | // ----------------------------- end Sensor --------------------------------- 317 | 318 | ADDRESS_DEBUG_0: begin 319 | if (!wr_nrd_comb) begin 320 | cpu_dout_o <= {read_bit, address_comb, debug_0_i}; 321 | cpu_dout_valid_o <= 1; 322 | end 323 | end 324 | ADDRESS_DEBUG_1: begin 325 | if (!wr_nrd_comb) begin 326 | cpu_dout_o <= {read_bit, address_comb, debug_1_i}; 327 | cpu_dout_valid_o <= 1; 328 | end 329 | end 330 | ADDRESS_DEBUG_2: begin 331 | if (!wr_nrd_comb) begin 332 | cpu_dout_o <= {read_bit, address_comb, debug_2_i}; 333 | cpu_dout_valid_o <= 1; 334 | end 335 | end 336 | ADDRESS_DEBUG_3: begin 337 | if (!wr_nrd_comb) begin 338 | cpu_dout_o <= {read_bit, address_comb, debug_3_i}; 339 | cpu_dout_valid_o <= 1; 340 | end 341 | end 342 | ADDRESS_DEBUG_4: begin 343 | if (!wr_nrd_comb) begin 344 | cpu_dout_o <= {read_bit, address_comb, debug_4_i}; 345 | cpu_dout_valid_o <= 1; 346 | end 347 | end 348 | ADDRESS_DEBUG_5: begin 349 | if (!wr_nrd_comb) begin 350 | cpu_dout_o <= {read_bit, address_comb, debug_5_i}; 351 | cpu_dout_valid_o <= 1; 352 | end 353 | end 354 | ADDRESS_DEBUG_6: begin 355 | if (!wr_nrd_comb) begin 356 | cpu_dout_o <= {read_bit, address_comb, debug_6_i}; 357 | cpu_dout_valid_o <= 1; 358 | end 359 | end 360 | ADDRESS_DEBUG_7: begin 361 | if (!wr_nrd_comb) begin 362 | cpu_dout_o <= {read_bit, address_comb, debug_7_i}; 363 | cpu_dout_valid_o <= 1; 364 | end 365 | end 366 | 367 | ADDRESS_ADC_CTRL: begin 368 | if (wr_nrd_comb) begin 369 | adc_ctrl_o <= data_in_comb[0]; 370 | end 371 | else begin 372 | cpu_dout_o <= {read_bit, address_comb, 7'b0, adc_ctrl_o}; 373 | cpu_dout_valid_o <= 1; 374 | end 375 | end 376 | 377 | ADDRESS_MULTICYCLE_MODE: begin 378 | if (wr_nrd_comb) begin 379 | is_multicycle_o <= data_in_comb[0]; 380 | end 381 | else begin 382 | cpu_dout_o <= {read_bit, address_comb, 7'b0, is_multicycle_o}; 383 | cpu_dout_valid_o <= 1; 384 | end 385 | end 386 | 387 | default: begin 388 | // do nothing 389 | end 390 | endcase 391 | end 392 | end 393 | end 394 | 395 | posedge_detection front_of_start( 396 | .signal(start_cycle_int), 397 | .clk(clk_i), 398 | .posedge_signal(start_cycle_o) 399 | ); 400 | 401 | endmodule 402 | -------------------------------------------------------------------------------- /src/spi_slave.vhd: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------------- 2 | -- Author: Jonny Doin, jdoin@opencores.org 3 | -- 4 | -- Create Date: 15:36:20 05/15/2011 5 | -- Module Name: SPI_SLAVE - RTL 6 | -- Project Name: SPI INTERFACE 7 | -- Target Devices: Spartan-6 8 | -- Tool versions: ISE 13.1 9 | -- Description: 10 | -- 11 | -- This block is the SPI slave interface, implemented in one single entity. 12 | -- All internal core operations are synchronous to the external SPI clock, and follows the general SPI de-facto standard. 13 | -- The parallel read/write interface is synchronous to a supplied system master clock, 'clk_i'. 14 | -- Synchronization for the parallel ports is provided by input data request and write enable lines, and output data valid line. 15 | -- Fully pipelined cross-clock circuitry guarantees that no setup artifacts occur on the buffers that are accessed by the two 16 | -- clock domains. 17 | -- 18 | -- The block is very simple to use, and has parallel inputs and outputs that behave like a synchronous memory i/o. 19 | -- It is parameterizable via generics for the data width ('N'), SPI mode (CPHA and CPOL), and lookahead prefetch 20 | -- signaling ('PREFETCH'). 21 | -- 22 | -- PARALLEL WRITE INTERFACE 23 | -- The parallel interface has a input port 'di_i' and an output port 'do_o'. 24 | -- Parallel load is controlled using 3 signals: 'di_i', 'di_req_o' and 'wren_i'. 25 | -- When the core needs input data, a look ahead data request strobe , 'di_req_o' is pulsed 'PREFETCH' 'spi_sck_i' 26 | -- cycles in advance to synchronize a user pipelined memory or fifo to present the next input data at 'di_i' 27 | -- in time to have continuous clock at the spi bus, to allow back-to-back continuous load. 28 | -- The data request strobe on 'di_req_o' is 2 'clk_i' clock cycles long. 29 | -- The write to 'di_i' must occur at most one 'spi_sck_i' cycle before actual load to the core shift register, to avoid 30 | -- race conditions at the register transfer. 31 | -- The user circuit places data at the 'di_i' port and strobes the 'wren_i' line for one rising edge of 'clk_i'. 32 | -- For a pipelined sync RAM, a PREFETCH of 3 cycles allows an address generator to present the new adress to the RAM in one 33 | -- cycle, and the RAM to respond in one more cycle, in time for 'di_i' to be latched by the interface one clock before transfer. 34 | -- If the user sequencer needs a different value for PREFETCH, the generic can be altered at instantiation time. 35 | -- The 'wren_i' write enable strobe must be valid at least one setup time before the rising edge of the last clock cycle, 36 | -- if continuous transmission is intended. 37 | -- When the interface is idle ('spi_ssel_i' is HIGH), the top bit of the latched 'di_i' port is presented at port 'spi_miso_o'. 38 | -- 39 | -- PARALLEL WRITE PIPELINED SEQUENCE 40 | -- ================================= 41 | -- __ __ __ __ __ __ __ 42 | -- clk_i __/ \__/ \__/ \__/ \__/ \__/ \__/ \... -- parallel interface clock 43 | -- ___________ 44 | -- di_req_o ________/ \_____________________... -- 'di_req_o' asserted on rising edge of 'clk_i' 45 | -- ______________ ___________________________... 46 | -- di_i __old_data____X______new_data_____________... -- user circuit loads data on 'di_i' at next 'clk_i' rising edge 47 | -- ________ 48 | -- wren_i __________________________/ \______... -- 'wren_i' enables latch on rising edge of 'clk_i' 49 | -- 50 | -- 51 | -- PARALLEL READ INTERFACE 52 | -- An internal buffer is used to copy the internal shift register data to drive the 'do_o' port. When a complete 53 | -- word is received, the core shift register is transferred to the buffer, at the rising edge of the spi clock, 'spi_sck_i'. 54 | -- The signal 'do_valid_o' is strobed 3 'clk_i' clocks after, to directly drive a synchronous memory or fifo write enable. 55 | -- 'do_valid_o' is synchronous to the parallel interface clock, and changes only on rising edges of 'clk_i'. 56 | -- When the interface is idle, data at the 'do_o' port holds the last word received. 57 | -- 58 | -- PARALLEL READ PIPELINED SEQUENCE 59 | -- ================================ 60 | -- ______ ______ ______ ______ 61 | -- clk_spi_i ___/ bit1 \______/ bitN \______/bitN-1\______/bitN-2\__... -- spi base clock 62 | -- __ __ __ __ __ __ __ __ __ 63 | -- clk_i __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_... -- parallel interface clock 64 | -- _________________ _____________________________________... -- 1) received data is transferred to 'do_buffer_reg' 65 | -- do_o __old_data_______X__________new_data___________________... -- after last bit received, at next shift clock. 66 | -- ____________ 67 | -- do_valid_o ________________________________/ \_________... -- 2) 'do_valid_o' strobed for 2 'clk_i' cycles 68 | -- -- on the 3rd 'clk_i' rising edge. 69 | -- 70 | -- 71 | -- This design was originally targeted to a Spartan-6 platform, synthesized with XST and normal constraints. 72 | -- 73 | ------------------------------ COPYRIGHT NOTICE ----------------------------------------------------------------------- 74 | -- 75 | -- This file is part of the SPI MASTER/SLAVE INTERFACE project http://opencores.org/project,spi_master_slave 76 | -- 77 | -- Author(s): Jonny Doin, jdoin@opencores.org, jonnydoin@gmail.com 78 | -- 79 | -- Copyright (C) 2011 Jonny Doin 80 | -- ----------------------------- 81 | -- 82 | -- This source file may be used and distributed without restriction provided that this copyright statement is not 83 | -- removed from the file and that any derivative work contains the original copyright notice and the associated 84 | -- disclaimer. 85 | -- 86 | -- This source file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 87 | -- General Public License as published by the Free Software Foundation; either version 2.1 of the License, or 88 | -- (at your option) any later version. 89 | -- 90 | -- This source is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 91 | -- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 92 | -- details. 93 | -- 94 | -- You should have received a copy of the GNU Lesser General Public License along with this source; if not, download 95 | -- it from http://www.gnu.org/licenses/lgpl.txt 96 | -- 97 | ------------------------------ REVISION HISTORY ----------------------------------------------------------------------- 98 | -- 99 | -- 2011/05/15 v0.10.0050 [JD] created the slave logic, with 2 clock domains, from SPI_MASTER module. 100 | -- 2011/05/15 v0.15.0055 [JD] fixed logic for starting state when CPHA='1'. 101 | -- 2011/05/17 v0.80.0049 [JD] added explicit clock synchronization circuitry across clock boundaries. 102 | -- 2011/05/18 v0.95.0050 [JD] clock generation circuitry, with generators for all-rising-edge clock core. 103 | -- 2011/06/05 v0.96.0053 [JD] changed async clear to sync resets. 104 | -- 2011/06/07 v0.97.0065 [JD] added cross-clock buffers, fixed fsm async glitches. 105 | -- 2011/06/09 v0.97.0068 [JD] reduced control sets (resets, CE, presets) to the absolute minimum to operate, to reduce 106 | -- synthesis LUT overhead in Spartan-6 architecture. 107 | -- 2011/06/11 v0.97.0075 [JD] redesigned all parallel data interfacing ports, and implemented cross-clock strobe logic. 108 | -- 2011/06/12 v0.97.0079 [JD] implemented wr_ack and di_req logic for state 0, and eliminated unnecessary registers reset. 109 | -- 2011/06/17 v0.97.0079 [JD] implemented wr_ack and di_req logic for state 0, and eliminated unnecessary registers reset. 110 | -- 2011/07/16 v1.11.0080 [JD] verified both spi_master and spi_slave in loopback at 50MHz SPI clock. 111 | -- 2011/07/29 v2.00.0110 [JD] FIX: CPHA bugs: 112 | -- - redesigned core clocking to address all CPOL and CPHA configurations. 113 | -- - added CHANGE_EDGE to the FSM register transfer logic, to have MISO change at opposite 114 | -- clock phases from SHIFT_EDGE. 115 | -- Removed global signal setting at the FSM, implementing exhaustive explicit signal attributions 116 | -- for each state, to avoid reported inference problems in some synthesis engines. 117 | -- Streamlined port names and indentation blocks. 118 | -- 2011/08/01 v2.01.0115 [JD] Adjusted 'do_valid_o' pulse width to be 2 'clk_i', as in the master core. 119 | -- Simulated in iSim with the master core for continuous transmission mode. 120 | -- 2011/08/02 v2.02.0120 [JD] Added mux for MISO at reset state, to output di(N-1) at start. This fixed a bug in first bit. 121 | -- The master and slave cores were verified in FPGA with continuous transmission, for all SPI modes. 122 | -- 2011/08/04 v2.02.0121 [JD] Changed minor comment bugs in the combinatorial fsm logic. 123 | -- 2011/08/08 v2.02.0122 [JD] FIX: continuous transfer mode bug. When wren_i is not strobed prior to state 1 (last bit), the 124 | -- sequencer goes to state 0, and then to state 'N' again. This produces a wrong bit-shift for received 125 | -- data. The fix consists in engaging continuous transfer regardless of the user strobing write enable, and 126 | -- sequencing from state 1 to N as long as the master clock is present. If the user does not write new 127 | -- data, the last data word is repeated. 128 | -- 2011/08/08 v2.02.0123 [JD] ISSUE: continuous transfer mode bug, for ignored 'di_req' cycles. Instead of repeating the last data word, 129 | -- the slave will send (others => '0') instead. 130 | -- 2011/08/28 v2.02.0126 [JD] ISSUE: the miso_o MUX that preloads tx_bit when slave is desselected will glitch for CPHA='1'. 131 | -- FIX: added a registered drive for the MUX select that will transfer the tx_reg only after the first tx_reg update. 132 | -- 133 | ----------------------------------------------------------------------------------------------------------------------- 134 | -- TODO 135 | -- ==== 136 | -- 137 | ----------------------------------------------------------------------------------------------------------------------- 138 | library ieee; 139 | use ieee.std_logic_1164.all; 140 | use ieee.numeric_std.all; 141 | use ieee.std_logic_unsigned.all; 142 | 143 | entity spi_slave is 144 | Generic ( 145 | N : positive := 32; -- 32bit serial word length is default 146 | CPOL : std_logic := '0'; -- SPI mode selection (mode 0 default) 147 | CPHA : std_logic := '0'; -- CPOL = clock polarity, CPHA = clock phase. 148 | PREFETCH : positive := 3); -- prefetch lookahead cycles 149 | Port ( 150 | clk_i : in std_logic := 'X'; -- internal interface clock (clocks di/do registers) 151 | spi_ssel_i : in std_logic := 'X'; -- spi bus slave select line 152 | spi_sck_i : in std_logic := 'X'; -- spi bus sck clock (clocks the shift register core) 153 | spi_mosi_i : in std_logic := 'X'; -- spi bus mosi input 154 | spi_miso_o : out std_logic := 'X'; -- spi bus spi_miso_o output 155 | di_req_o : out std_logic; -- preload lookahead data request line 156 | di_i : in std_logic_vector (N-1 downto 0) := (others => 'X'); -- parallel load data in (clocked in on rising edge of clk_i) 157 | wren_i : in std_logic := 'X'; -- user data write enable 158 | wr_ack_o : out std_logic; -- write acknowledge 159 | do_valid_o : out std_logic; -- do_o data valid strobe, valid during one clk_i rising edge. 160 | do_o : out std_logic_vector (N-1 downto 0); -- parallel output (clocked out on falling clk_i) 161 | --- debug ports: can be removed for the application circuit --- 162 | do_transfer_o : out std_logic; -- debug: internal transfer driver 163 | wren_o : out std_logic; -- debug: internal state of the wren_i pulse stretcher 164 | rx_bit_next_o : out std_logic; -- debug: internal rx bit 165 | state_dbg_o : out std_logic_vector (3 downto 0); -- debug: internal state register 166 | sh_reg_dbg_o : out std_logic_vector (N-1 downto 0) -- debug: internal shift register 167 | ); 168 | end spi_slave; 169 | 170 | --================================================================================================================ 171 | -- SYNTHESIS CONSIDERATIONS 172 | -- ======================== 173 | -- There are several output ports that are used to simulate and verify the core operation. 174 | -- Do not map any signals to the unused ports, and the synthesis tool will remove the related interfacing 175 | -- circuitry. 176 | -- The same is valid for the transmit and receive ports. If the receive ports are not mapped, the 177 | -- synthesis tool will remove the receive logic from the generated circuitry. 178 | -- Alternatively, you can remove these ports and related circuitry once the core is verified and 179 | -- integrated to your circuit. 180 | --================================================================================================================ 181 | 182 | architecture rtl of spi_slave is 183 | -- constants to control FlipFlop synthesis 184 | constant SHIFT_EDGE : std_logic := (CPOL xnor CPHA); -- MOSI data is captured and shifted at this SCK edge 185 | constant CHANGE_EDGE : std_logic := (CPOL xor CPHA); -- MISO data is updated at this SCK edge 186 | 187 | ------------------------------------------------------------------------------------------ 188 | -- GLOBAL RESET: 189 | -- all signals are initialized to zero at GSR (global set/reset) by giving explicit 190 | -- initialization values at declaration. This is needed for all Xilinx FPGAs, and 191 | -- especially for the Spartan-6 and newer CLB architectures, where a local reset can 192 | -- reduce the usability of the slice registers, due to the need to share the control 193 | -- set (RESET/PRESET, CLOCK ENABLE and CLOCK) by all 8 registers in a slice. 194 | -- By using GSR for the initialization, and reducing RESET local init to the really 195 | -- essential, the model achieves better LUT/FF packing and CLB usability. 196 | ------------------------------------------------------------------------------------------ 197 | -- internal state signals for register and combinatorial stages 198 | signal state_next : natural range N downto 0 := 0; -- state 0 is idle state 199 | signal state_reg : natural range N downto 0 := 0; -- state 0 is idle state 200 | -- shifter signals for register and combinatorial stages 201 | signal sh_next : std_logic_vector (N-1 downto 0); 202 | signal sh_reg : std_logic_vector (N-1 downto 0); 203 | -- mosi and miso connections 204 | signal rx_bit_next : std_logic; -- sample of MOSI input 205 | signal tx_bit_next : std_logic; 206 | signal tx_bit_reg : std_logic; -- drives MISO during sequential logic 207 | signal preload_miso : std_logic; -- controls the MISO MUX 208 | -- buffered di_i data signals for register and combinatorial stages 209 | signal di_reg : std_logic_vector (N-1 downto 0); 210 | -- internal wren_i stretcher for fsm combinatorial stage 211 | signal wren : std_logic; 212 | signal wr_ack_next : std_logic := '0'; 213 | signal wr_ack_reg : std_logic := '0'; 214 | -- buffered do_o data signals for register and combinatorial stages 215 | signal do_buffer_next : std_logic_vector (N-1 downto 0); 216 | signal do_buffer_reg : std_logic_vector (N-1 downto 0); 217 | -- internal signal to flag transfer to do_buffer_reg 218 | signal do_transfer_next : std_logic := '0'; 219 | signal do_transfer_reg : std_logic := '0'; 220 | -- internal input data request signal 221 | signal di_req_next : std_logic := '0'; 222 | signal di_req_reg : std_logic := '0'; 223 | -- cross-clock do_valid_o logic 224 | signal do_valid_next : std_logic := '0'; 225 | signal do_valid_A : std_logic := '0'; 226 | signal do_valid_B : std_logic := '0'; 227 | signal do_valid_C : std_logic := '0'; 228 | signal do_valid_D : std_logic := '0'; 229 | signal do_valid_o_reg : std_logic := '0'; 230 | -- cross-clock di_req_o logic 231 | signal di_req_o_next : std_logic := '0'; 232 | signal di_req_o_A : std_logic := '0'; 233 | signal di_req_o_B : std_logic := '0'; 234 | signal di_req_o_C : std_logic := '0'; 235 | signal di_req_o_D : std_logic := '0'; 236 | signal di_req_o_reg : std_logic := '0'; 237 | begin 238 | --============================================================================================= 239 | -- GENERICS CONSTRAINTS CHECKING 240 | --============================================================================================= 241 | -- minimum word width is 8 bits 242 | assert N >= 8 243 | report "Generic parameter 'N' error: SPI shift register size needs to be 8 bits minimum" 244 | severity FAILURE; 245 | assert N = 16 246 | report "DMITRY" 247 | severity FAILURE; 248 | -- maximum prefetch lookahead check 249 | assert PREFETCH <= N-5 250 | report "Generic parameter 'PREFETCH' error: lookahead count out of range, needs to be N-5 maximum" 251 | severity FAILURE; 252 | assert PREFETCH = 2 253 | report "DMITRY" 254 | severity FAILURE; 255 | 256 | --============================================================================================= 257 | -- GENERATE BLOCKS 258 | --============================================================================================= 259 | 260 | --============================================================================================= 261 | -- DATA INPUTS 262 | --============================================================================================= 263 | -- connect rx bit input 264 | rx_bit_proc : rx_bit_next <= spi_mosi_i; 265 | 266 | --============================================================================================= 267 | -- CROSS-CLOCK PIPELINE TRANSFER LOGIC 268 | --============================================================================================= 269 | -- do_valid_o and di_req_o strobe output logic 270 | -- this is a delayed pulse generator with a ripple-transfer FFD pipeline, that generates a 271 | -- fixed-length delayed pulse for the output flags, at the parallel clock domain 272 | out_transfer_proc : process ( clk_i, do_transfer_reg, di_req_reg, 273 | do_valid_A, do_valid_B, do_valid_D, 274 | di_req_o_A, di_req_o_B, di_req_o_D) is 275 | begin 276 | if clk_i'event and clk_i = '1' then -- clock at parallel port clock 277 | -- do_transfer_reg -> do_valid_o_reg 278 | do_valid_A <= do_transfer_reg; -- the input signal must be at least 2 clocks long 279 | do_valid_B <= do_valid_A; -- feed it to a ripple chain of FFDs 280 | do_valid_C <= do_valid_B; 281 | do_valid_D <= do_valid_C; 282 | do_valid_o_reg <= do_valid_next; -- registered output pulse 283 | -------------------------------- 284 | -- di_req_reg -> di_req_o_reg 285 | di_req_o_A <= di_req_reg; -- the input signal must be at least 2 clocks long 286 | di_req_o_B <= di_req_o_A; -- feed it to a ripple chain of FFDs 287 | di_req_o_C <= di_req_o_B; 288 | di_req_o_D <= di_req_o_C; 289 | di_req_o_reg <= di_req_o_next; -- registered output pulse 290 | end if; 291 | -- generate a 2-clocks pulse at the 3rd clock cycle 292 | do_valid_next <= do_valid_A and do_valid_B and not do_valid_D; 293 | di_req_o_next <= di_req_o_A and di_req_o_B and not di_req_o_D; 294 | end process out_transfer_proc; 295 | -- parallel load input registers: data register and write enable 296 | in_transfer_proc: process (clk_i, wren_i, wr_ack_reg) is 297 | begin 298 | -- registered data input, input register with clock enable 299 | if clk_i'event and clk_i = '1' then 300 | if wren_i = '1' then 301 | di_reg <= di_i; -- parallel data input buffer register 302 | end if; 303 | end if; 304 | -- stretch wren pulse to be detected by spi fsm (ffd with sync preset and sync reset) 305 | if clk_i'event and clk_i = '1' then 306 | if wren_i = '1' then -- wren_i is the sync preset for wren 307 | wren <= '1'; 308 | elsif wr_ack_reg = '1' then -- wr_ack is the sync reset for wren 309 | wren <= '0'; 310 | end if; 311 | end if; 312 | end process in_transfer_proc; 313 | 314 | --============================================================================================= 315 | -- REGISTER TRANSFER PROCESSES 316 | --============================================================================================= 317 | -- fsm state and data registers change on spi SHIFT_EDGE 318 | core_reg_proc : process (spi_sck_i, spi_ssel_i) is 319 | begin 320 | -- FFD registers clocked on SHIFT edge and cleared on idle (spi_ssel_i = 1) 321 | -- state fsm register (fdr) 322 | if spi_ssel_i = '1' then -- async clr 323 | state_reg <= 0; -- state falls back to idle when slave not selected 324 | elsif spi_sck_i'event and spi_sck_i = SHIFT_EDGE then -- on SHIFT edge, update state register 325 | state_reg <= state_next; -- core fsm changes state with spi SHIFT clock 326 | end if; 327 | -- FFD registers clocked on SHIFT edge 328 | -- rtl core registers (fd) 329 | if spi_sck_i'event and spi_sck_i = SHIFT_EDGE then -- on fsm state change, update all core registers 330 | sh_reg <= sh_next; -- core shift register 331 | do_buffer_reg <= do_buffer_next; -- registered data output 332 | do_transfer_reg <= do_transfer_next; -- cross-clock transfer flag 333 | di_req_reg <= di_req_next; -- input data request 334 | wr_ack_reg <= wr_ack_next; -- wren ack for data load synchronization 335 | end if; 336 | -- FFD registers clocked on CHANGE edge and cleared on idle (spi_ssel_i = 1) 337 | -- miso MUX preload control register (fdp) 338 | if spi_ssel_i = '1' then -- async preset 339 | preload_miso <= '1'; -- miso MUX sees top bit of parallel input when slave not selected 340 | elsif spi_sck_i'event and spi_sck_i = CHANGE_EDGE then -- on CHANGE edge, change to tx_reg output 341 | preload_miso <= spi_ssel_i; -- miso MUX sees tx_bit_reg when it is driven by SCK 342 | end if; 343 | -- FFD registers clocked on CHANGE edge 344 | -- tx_bit register (fd) 345 | if spi_sck_i'event and spi_sck_i = CHANGE_EDGE then 346 | tx_bit_reg <= tx_bit_next; -- update MISO driver from the MSb 347 | end if; 348 | end process core_reg_proc; 349 | 350 | --============================================================================================= 351 | -- COMBINATORIAL LOGIC PROCESSES 352 | --============================================================================================= 353 | -- state and datapath combinatorial logic 354 | core_combi_proc : process ( sh_reg, sh_next, state_reg, tx_bit_reg, rx_bit_next, do_buffer_reg, 355 | do_transfer_reg, di_reg, di_req_reg, wren, wr_ack_reg) is 356 | begin 357 | -- all output signals are assigned to (avoid latches) 358 | sh_next <= sh_reg; -- shift register 359 | tx_bit_next <= tx_bit_reg; -- MISO driver 360 | do_buffer_next <= do_buffer_reg; -- output data buffer 361 | do_transfer_next <= do_transfer_reg; -- output data flag 362 | wr_ack_next <= wr_ack_reg; -- write enable acknowledge 363 | di_req_next <= di_req_reg; -- data input request 364 | state_next <= state_reg; -- fsm control state 365 | case state_reg is 366 | 367 | when (16) => -- deassert 'di_rdy' and stretch do_valid 368 | wr_ack_next <= '0'; -- acknowledge data in transfer 369 | di_req_next <= '0'; -- prefetch data request: deassert when shifting data 370 | tx_bit_next <= sh_reg(N-1); -- output next MSbit 371 | sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits 372 | sh_next(0) <= rx_bit_next; -- shift in rx bit into LSb 373 | state_next <= state_reg - 1; -- update next state at each sck pulse 374 | 375 | when (16-1) downto (2+3) => -- remove 'do_transfer' and shift bits 376 | do_transfer_next <= '0'; -- reset 'do_valid' transfer signal 377 | di_req_next <= '0'; -- prefetch data request: deassert when shifting data 378 | wr_ack_next <= '0'; -- remove data load ack for all but the load stages 379 | tx_bit_next <= sh_reg(N-1); -- output next MSbit 380 | sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits 381 | sh_next(0) <= rx_bit_next; -- shift in rx bit into LSb 382 | state_next <= state_reg - 1; -- update next state at each sck pulse 383 | 384 | when (2+2) downto 3 => -- raise prefetch 'di_req_o' signal 385 | di_req_next <= '1'; -- request data in advance to allow for pipeline delays 386 | wr_ack_next <= '0'; -- remove data load ack for all but the load stages 387 | tx_bit_next <= sh_reg(N-1); -- output next MSbit 388 | sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits 389 | sh_next(0) <= rx_bit_next; -- shift in rx bit into LSb 390 | state_next <= state_reg - 1; -- update next state at each sck pulse 391 | 392 | when 2 => -- transfer received data to do_buffer_reg on next cycle 393 | di_req_next <= '1'; -- request data in advance to allow for pipeline delays 394 | wr_ack_next <= '0'; -- remove data load ack for all but the load stages 395 | tx_bit_next <= sh_reg(N-1); -- output next MSbit 396 | sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits 397 | sh_next(0) <= rx_bit_next; -- shift in rx bit into LSb 398 | do_transfer_next <= '1'; -- signal transfer to do_buffer on next cycle 399 | do_buffer_next <= sh_next; -- get next data directly into rx buffer 400 | state_next <= state_reg - 1; -- update next state at each sck pulse 401 | 402 | when 1 => -- transfer rx data to do_buffer and restart if new data is written 403 | sh_next(0) <= rx_bit_next; -- shift in rx bit into LSb 404 | di_req_next <= '0'; -- prefetch data request: deassert when shifting data 405 | state_next <= N; -- next state is top bit of new data 406 | if wren = '1' then -- load tx register if valid data present at di_reg 407 | wr_ack_next <= '1'; -- acknowledge data in transfer 408 | sh_next(N-1 downto 1) <= di_reg(N-2 downto 0); -- shift inner bits 409 | tx_bit_next <= di_reg(N-1); -- first output bit comes from the MSb of parallel data 410 | else 411 | wr_ack_next <= '0'; -- no data reload for continuous transfer mode 412 | sh_next(N-1 downto 1) <= (others => '0'); -- clear transmit shift register 413 | tx_bit_next <= '0'; -- send ZERO 414 | end if; 415 | 416 | when 0 => -- idle state: start and end of transmission 417 | sh_next(0) <= rx_bit_next; -- shift in rx bit into LSb 418 | sh_next(N-1 downto 1) <= di_reg(N-2 downto 0); -- shift inner bits 419 | tx_bit_next <= di_reg(N-1); -- first output bit comes from the MSb of parallel data 420 | wr_ack_next <= '1'; -- acknowledge data in transfer 421 | di_req_next <= '0'; -- prefetch data request: deassert when shifting data 422 | do_transfer_next <= '0'; -- clear signal transfer to do_buffer 423 | state_next <= N; -- next state is top bit of new data 424 | 425 | when others => 426 | state_next <= 0; -- safe state 427 | 428 | end case; 429 | end process core_combi_proc; 430 | 431 | --============================================================================================= 432 | -- OUTPUT LOGIC PROCESSES 433 | --============================================================================================= 434 | -- data output processes 435 | do_o_proc : do_o <= do_buffer_reg; -- do_o always available 436 | do_valid_o_proc: do_valid_o <= do_valid_o_reg; -- copy registered do_valid_o to output 437 | di_req_o_proc: di_req_o <= di_req_o_reg; -- copy registered di_req_o to output 438 | wr_ack_o_proc: wr_ack_o <= wr_ack_reg; -- copy registered wr_ack_o to output 439 | 440 | ----------------------------------------------------------------------------------------------- 441 | -- MISO driver process: preload top bit of parallel data to MOSI at reset 442 | ----------------------------------------------------------------------------------------------- 443 | -- this is a MUX that selects the combinatorial next tx bit at reset, and the registered tx bit 444 | -- at sequential operation. The mux gives us a preload of the first bit, simplifying the shifter logic. 445 | spi_miso_o_proc: process (preload_miso, tx_bit_reg, di_reg) is 446 | begin 447 | if preload_miso = '1' then 448 | spi_miso_o <= di_reg(N-1); -- copy top bit of parallel data at reset 449 | else 450 | spi_miso_o <= tx_bit_reg; -- copy top bit of shifter at sequential operation 451 | end if; 452 | end process spi_miso_o_proc; 453 | 454 | --============================================================================================= 455 | -- DEBUG LOGIC PROCESSES 456 | --============================================================================================= 457 | -- these signals are useful for verification, and can be deleted after debug. 458 | do_transfer_proc: do_transfer_o <= do_transfer_reg; 459 | state_debug_proc: state_dbg_o <= std_logic_vector(to_unsigned(state_reg, 4)); -- export internal state to debug 460 | rx_bit_next_proc: rx_bit_next_o <= rx_bit_next; 461 | wren_o_proc: wren_o <= wren; 462 | sh_reg_debug_proc: sh_reg_dbg_o <= sh_reg; -- export sh_reg to debug 463 | end architecture rtl; 464 | 465 | -------------------------------------------------------------------------------- /src/spi_master.vhd: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------------------------------------- 2 | -- Author: Jonny Doin, jdoin@opencores.org, jonnydoin@gmail.com 3 | -- 4 | -- Create Date: 12:18:12 04/25/2011 5 | -- Module Name: SPI_MASTER - RTL 6 | -- Project Name: SPI MASTER / SLAVE INTERFACE 7 | -- Target Devices: Spartan-6 8 | -- Tool versions: ISE 13.1 9 | -- Description: 10 | -- 11 | -- This block is the SPI master interface, implemented in one single entity. 12 | -- All internal core operations are synchronous to the 'sclk_i', and a spi base clock is generated by dividing sclk_i downto 13 | -- a frequency that is 2x the spi SCK line frequency. The divider value is passed as a generic parameter during instantiation. 14 | -- All parallel i/o interface operations are synchronous to the 'pclk_i' high speed clock, that can be asynchronous to the serial 15 | -- 'sclk_i' clock. 16 | -- For optimized use of longlines, connect 'sclk_i' and 'pclk_i' to the same global clock line. 17 | -- Fully pipelined cross-clock circuitry guarantees that no setup artifacts occur on the buffers that are accessed by the two 18 | -- clock domains. 19 | -- The block is very simple to use, and has parallel inputs and outputs that behave like a synchronous memory i/o. 20 | -- It is parameterizable via generics for the data width ('N'), SPI mode (CPHA and CPOL), lookahead prefetch signaling 21 | -- ('PREFETCH'), and spi base clock division from sclk_i ('SPI_2X_CLK_DIV'). 22 | -- 23 | -- SPI CLOCK GENERATION 24 | -- ==================== 25 | -- 26 | -- The clock generation for the SPI SCK is derived from the high-speed 'sclk_i' clock. The core divides this reference 27 | -- clock to form the SPI base clock, by the 'SPI_2X_CLK_DIV' generic parameter. The user must set the divider value for the 28 | -- SPI_2X clock, which is 2x the desired SCK frequency. 29 | -- All registers in the core are clocked by the high-speed clocks, and clock enables are used to run the FSM and other logic 30 | -- at lower rates. This architecture preserves FPGA clock resources like global clock buffers, and avoids path delays caused 31 | -- by combinatorial clock dividers outputs. 32 | -- The core has async clock domain circuitry to handle asynchronous clocks for the SPI and parallel interfaces. 33 | -- 34 | -- PARALLEL WRITE INTERFACE 35 | -- ======================== 36 | -- The parallel interface has an input port 'di_i' and an output port 'do_o'. 37 | -- Parallel load is controlled using 3 signals: 'di_i', 'di_req_o' and 'wren_i'. 'di_req_o' is a look ahead data request line, 38 | -- that is set 'PREFETCH' clock cycles in advance to synchronize a pipelined memory or fifo to present the 39 | -- next input data at 'di_i' in time to have continuous clock at the spi bus, to allow back-to-back continuous load. 40 | -- For a pipelined sync RAM, a PREFETCH of 2 cycles allows an address generator to present the new adress to the RAM in one 41 | -- cycle, and the RAM to respond in one more cycle, in time for 'di_i' to be latched by the shifter. 42 | -- If the user sequencer needs a different value for PREFETCH, the generic can be altered at instantiation time. 43 | -- The 'wren_i' write enable strobe must be valid at least one setup time before the rising edge of the last SPI clock cycle, 44 | -- if continuous transmission is intended. If 'wren_i' is not valid 2 SPI clock cycles after the last transmitted bit, the interface 45 | -- enters idle state and deasserts SSEL. 46 | -- When the interface is idle, 'wren_i' write strobe loads the data and starts transmission. 'di_req_o' will strobe when entering 47 | -- idle state, if a previously loaded data has already been transferred. 48 | -- 49 | -- PARALLEL WRITE SEQUENCE 50 | -- ======================= 51 | -- __ __ __ __ __ __ __ 52 | -- pclk_i __/ \__/ \__/ \__/ \__/ \__/ \__/ \... -- parallel interface clock 53 | -- ___________ 54 | -- di_req_o ________/ \_____________________... -- 'di_req_o' asserted on rising edge of 'pclk_i' 55 | -- ______________ ___________________________... 56 | -- di_i __old_data____X______new_data_____________... -- user circuit loads data on 'di_i' at next 'pclk_i' rising edge 57 | -- _______ 58 | -- wren_i __________________________/ \_______... -- user strobes 'wren_i' for one cycle of 'pclk_i' 59 | -- 60 | -- 61 | -- PARALLEL READ INTERFACE 62 | -- ======================= 63 | -- An internal buffer is used to copy the internal shift register data to drive the 'do_o' port. When a complete word is received, 64 | -- the core shift register is transferred to the buffer, at the rising edge of the spi clock, 'spi_clk'. 65 | -- The signal 'do_valid_o' is set one 'spi_clk' clock after, to directly drive a synchronous memory or fifo write enable. 66 | -- 'do_valid_o' is synchronous to the parallel interface clock, and changes only on rising edges of 'pclk_i'. 67 | -- When the interface is idle, data at the 'do_o' port holds the last word received. 68 | -- 69 | -- PARALLEL READ SEQUENCE 70 | -- ====================== 71 | -- ______ ______ ______ ______ 72 | -- spi_clk bit1 \______/ bitN \______/bitN-1\______/bitN-2\__... -- internal spi 2x base clock 73 | -- _ __ __ __ __ __ __ __ __ 74 | -- pclk_i \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_... -- parallel interface clock (may be async to sclk_i) 75 | -- _____________ _____________________________________... -- 1) rx data is transferred to 'do_buffer_reg' 76 | -- do_o ___old_data__X__________new_data___________________... -- after last rx bit, at rising 'spi_clk'. 77 | -- ____________ 78 | -- do_valid_o ____________________________/ \_________... -- 2) 'do_valid_o' strobed for 2 'pclk_i' cycles 79 | -- -- on the 3rd 'pclk_i' rising edge. 80 | -- 81 | -- 82 | -- The propagation delay of spi_sck_o and spi_mosi_o, referred to the internal clock, is balanced by similar path delays, 83 | -- but the sampling delay of spi_miso_i imposes a setup time referred to the sck signal that limits the high frequency 84 | -- of the interface, for full duplex operation. 85 | -- 86 | -- This design was originally targeted to a Spartan-6 platform, synthesized with XST and normal constraints. 87 | -- The VHDL dialect used is VHDL'93, accepted largely by all synthesis tools. 88 | -- 89 | ------------------------------ COPYRIGHT NOTICE ----------------------------------------------------------------------- 90 | -- 91 | -- This file is part of the SPI MASTER/SLAVE INTERFACE project http://opencores.org/project,spi_master_slave 92 | -- 93 | -- Author(s): Jonny Doin, jdoin@opencores.org, jonnydoin@gmail.com 94 | -- 95 | -- Copyright (C) 2011 Jonny Doin 96 | -- ----------------------------- 97 | -- 98 | -- This source file may be used and distributed without restriction provided that this copyright statement is not 99 | -- removed from the file and that any derivative work contains the original copyright notice and the associated 100 | -- disclaimer. 101 | -- 102 | -- This source file is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser 103 | -- General Public License as published by the Free Software Foundation; either version 2.1 of the License, or 104 | -- (at your option) any later version. 105 | -- 106 | -- This source is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 107 | -- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 108 | -- details. 109 | -- 110 | -- You should have received a copy of the GNU Lesser General Public License along with this source; if not, download 111 | -- it from http://www.gnu.org/licenses/lgpl.txt 112 | -- 113 | ------------------------------ REVISION HISTORY ----------------------------------------------------------------------- 114 | -- 115 | -- 2011/04/28 v0.01.0010 [JD] shifter implemented as a sequential process. timing problems and async issues in synthesis. 116 | -- 2011/05/01 v0.01.0030 [JD] changed original shifter design to a fully pipelined RTL fsmd. solved all synthesis issues. 117 | -- 2011/05/05 v0.01.0034 [JD] added an internal buffer register for rx_data, to allow greater liberty in data load/store. 118 | -- 2011/05/08 v0.10.0038 [JD] increased one state to have SSEL start one cycle before SCK. Implemented full CPOL/CPHA 119 | -- logic, based on generics, and do_valid_o signal. 120 | -- 2011/05/13 v0.20.0045 [JD] streamlined signal names, added PREFETCH parameter, added assertions. 121 | -- 2011/05/17 v0.80.0049 [JD] added explicit clock synchronization circuitry across clock boundaries. 122 | -- 2011/05/18 v0.95.0050 [JD] clock generation circuitry, with generators for all-rising-edge clock core. 123 | -- 2011/06/05 v0.96.0053 [JD] changed async clear to sync resets. 124 | -- 2011/06/07 v0.97.0065 [JD] added cross-clock buffers, fixed fsm async glitches. 125 | -- 2011/06/09 v0.97.0068 [JD] reduced control sets (resets, CE, presets) to the absolute minimum to operate, to reduce 126 | -- synthesis LUT overhead in Spartan-6 architecture. 127 | -- 2011/06/11 v0.97.0075 [JD] redesigned all parallel data interfacing ports, and implemented cross-clock strobe logic. 128 | -- 2011/06/12 v0.97.0079 [JD] streamlined wr_ack for all cases and eliminated unnecessary register resets. 129 | -- 2011/06/14 v0.97.0083 [JD] (bug CPHA effect) : redesigned SCK output circuit. 130 | -- (minor bug) : removed fsm registers from (not rst_i) chip enable. 131 | -- 2011/06/15 v0.97.0086 [JD] removed master MISO input register, to relax MISO data setup time (to get higher speed). 132 | -- 2011/07/09 v1.00.0095 [JD] changed all clocking scheme to use a single high-speed clock with clock enables to control lower 133 | -- frequency sequential circuits, to preserve clocking resources and avoid path delay glitches. 134 | -- 2011/07/10 v1.00.0098 [JD] implemented SCK clock divider circuit to generate spi clock directly from system clock. 135 | -- 2011/07/10 v1.10.0075 [JD] verified spi_master_slave in silicon at 50MHz, 25MHz, 16.666MHz, 12.5MHz, 10MHz, 8.333MHz, 136 | -- 7.1428MHz, 6.25MHz, 1MHz and 500kHz. The core proved very robust at all tested frequencies. 137 | -- 2011/07/16 v1.11.0080 [JD] verified both spi_master and spi_slave in loopback at 50MHz SPI clock. 138 | -- 2011/07/17 v1.11.0080 [JD] BUG: CPOL='1', CPHA='1' @50MHz causes MOSI to be shifted one bit earlier. 139 | -- BUG: CPOL='0', CPHA='1' causes SCK to have one extra pulse with one sclk_i width at the end. 140 | -- 2011/07/18 v1.12.0105 [JD] CHG: spi sck output register changed to remove glitch at last clock when CPHA='1'. 141 | -- for CPHA='1', max spi clock is 25MHz. for CPHA= '0', max spi clock is >50MHz. 142 | -- 2011/07/24 v1.13.0125 [JD] FIX: 'sck_ena_ce' is on half-cycle advanced to 'fsm_ce', elliminating CPHA='1' glitches. 143 | -- Core verified for all CPOL, CPHA at up to 50MHz, simulates to over 100MHz. 144 | -- 2011/07/29 v1.14.0130 [JD] Removed global signal setting at the FSM, implementing exhaustive explicit signal attributions 145 | -- for each state, to avoid reported inference problems in some synthesis engines. 146 | -- Streamlined port names and indentation blocks. 147 | -- 2011/08/01 v1.15.0135 [JD] Fixed latch inference for spi_mosi_o driver at the fsm. 148 | -- The master and slave cores were verified in FPGA with continuous transmission, for all SPI modes. 149 | -- 2011/08/04 v1.15.0136 [JD] Fixed assertions (PREFETCH >= 1) and minor comment bugs. 150 | -- 151 | ----------------------------------------------------------------------------------------------------------------------- 152 | -- TODO 153 | -- ==== 154 | -- 155 | ----------------------------------------------------------------------------------------------------------------------- 156 | library ieee; 157 | use ieee.std_logic_1164.all; 158 | use ieee.numeric_std.all; 159 | use ieee.std_logic_unsigned.all; 160 | 161 | --================================================================================================================ 162 | -- SYNTHESIS CONSIDERATIONS 163 | -- ======================== 164 | -- There are several output ports that are used to simulate and verify the core operation. 165 | -- Do not map any signals to the unused ports, and the synthesis tool will remove the related interfacing 166 | -- circuitry. 167 | -- The same is valid for the transmit and receive ports. If the receive ports are not mapped, the 168 | -- synthesis tool will remove the receive logic from the generated circuitry. 169 | -- Alternatively, you can remove these ports and related circuitry once the core is verified and 170 | -- integrated to your circuit. 171 | --================================================================================================================ 172 | 173 | entity spi_master is 174 | Generic ( 175 | N : positive := 32; -- 32bit serial word length is default 176 | CPOL : std_logic := '0'; -- SPI mode selection (mode 0 default) 177 | CPHA : std_logic := '0'; -- CPOL = clock polarity, CPHA = clock phase. 178 | PREFETCH : positive := 2; -- prefetch lookahead cycles 179 | SPI_2X_CLK_DIV : positive := 5); -- for a 100MHz sclk_i, yields a 10MHz SCK 180 | Port ( 181 | sclk_i : in std_logic := 'X'; -- high-speed serial interface system clock 182 | pclk_i : in std_logic := 'X'; -- high-speed parallel interface system clock 183 | rst_i : in std_logic := 'X'; -- reset core 184 | ---- serial interface ---- 185 | spi_ssel_o : out std_logic; -- spi bus slave select line 186 | spi_sck_o : out std_logic; -- spi bus sck 187 | spi_mosi_o : out std_logic; -- spi bus mosi output 188 | spi_miso_i : in std_logic := 'X'; -- spi bus spi_miso_i input 189 | ---- parallel interface ---- 190 | di_req_o : out std_logic; -- preload lookahead data request line 191 | di_i : in std_logic_vector (N-1 downto 0) := (others => 'X'); -- parallel data in (clocked on rising spi_clk after last bit) 192 | wren_i : in std_logic := 'X'; -- user data write enable, starts transmission when interface is idle 193 | wr_ack_o : out std_logic; -- write acknowledge 194 | do_valid_o : out std_logic; -- do_o data valid signal, valid during one spi_clk rising edge. 195 | do_o : out std_logic_vector (N-1 downto 0); -- parallel output (clocked on rising spi_clk after last bit) 196 | --- debug ports: can be removed or left unconnected for the application circuit --- 197 | sck_ena_o : out std_logic; -- debug: internal sck enable signal 198 | sck_ena_ce_o : out std_logic; -- debug: internal sck clock enable signal 199 | do_transfer_o : out std_logic; -- debug: internal transfer driver 200 | wren_o : out std_logic; -- debug: internal state of the wren_i pulse stretcher 201 | rx_bit_reg_o : out std_logic; -- debug: internal rx bit 202 | state_dbg_o : out std_logic_vector (7 downto 0); -- debug: internal state register 203 | core_clk_o : out std_logic; 204 | core_n_clk_o : out std_logic; 205 | core_ce_o : out std_logic; 206 | core_n_ce_o : out std_logic; 207 | sh_reg_dbg_o : out std_logic_vector (N-1 downto 0) -- debug: internal shift register 208 | ); 209 | end spi_master; 210 | 211 | --================================================================================================================ 212 | -- this architecture is a pipelined register-transfer description. 213 | -- all signals are clocked at the rising edge of the system clock 'sclk_i'. 214 | --================================================================================================================ 215 | architecture rtl of spi_master is 216 | -- core clocks, generated from 'sclk_i': initialized at GSR to differential values 217 | signal core_clk : std_logic := '0'; -- continuous core clock, positive logic 218 | signal core_n_clk : std_logic := '1'; -- continuous core clock, negative logic 219 | signal core_ce : std_logic := '0'; -- core clock enable, positive logic 220 | signal core_n_ce : std_logic := '1'; -- core clock enable, negative logic 221 | -- spi bus clock, generated from the CPOL selected core clock polarity 222 | signal spi_2x_ce : std_logic := '1'; -- spi_2x clock enable 223 | signal spi_clk : std_logic := '0'; -- spi bus output clock 224 | signal spi_clk_reg : std_logic; -- output pipeline delay for spi sck (do NOT global initialize) 225 | --signal spi_clk_reg : std_logic := '0'; -- output pipeline delay for spi sck (do NOT global initialize) 226 | -- core fsm clock enables 227 | signal fsm_ce : std_logic := '1'; -- fsm clock enable 228 | signal sck_ena_ce : std_logic := '1'; -- SCK clock enable 229 | signal samp_ce : std_logic := '1'; -- data sampling clock enable 230 | -- 231 | -- GLOBAL RESET: 232 | -- all signals are initialized to zero at GSR (global set/reset) by giving explicit 233 | -- initialization values at declaration. This is needed for all Xilinx FPGAs, and 234 | -- especially for the Spartan-6 and newer CLB architectures, where a async reset can 235 | -- reduce the usability of the slice registers, due to the need to share the control 236 | -- set (RESET/PRESET, CLOCK ENABLE and CLOCK) by all 8 registers in a slice. 237 | -- By using GSR for the initialization, and reducing async RESET local init to the bare 238 | -- essential, the model achieves better LUT/FF packing and CLB usability. 239 | -- 240 | -- internal state signals for register and combinatorial stages 241 | signal state_next : natural range N+1 downto 0 := 0; 242 | signal state_reg : natural range N+1 downto 0 := 0; 243 | -- shifter signals for register and combinatorial stages 244 | signal sh_next : std_logic_vector (N-1 downto 0); 245 | signal sh_reg : std_logic_vector (N-1 downto 0); 246 | -- input bit sampled buffer 247 | signal rx_bit_reg : std_logic := '0'; 248 | -- buffered di_i data signals for register and combinatorial stages 249 | signal di_reg : std_logic_vector (N-1 downto 0); 250 | -- internal wren_i stretcher for fsm combinatorial stage 251 | signal wren : std_logic; 252 | signal wr_ack_next : std_logic := '0'; 253 | signal wr_ack_reg : std_logic := '0'; 254 | -- internal SSEL enable control signals 255 | signal ssel_ena_next : std_logic := '0'; 256 | signal ssel_ena_reg : std_logic := '0'; 257 | -- internal SCK enable control signals 258 | signal sck_ena_next : std_logic; 259 | signal sck_ena_reg : std_logic; 260 | -- buffered do_o data signals for register and combinatorial stages 261 | signal do_buffer_next : std_logic_vector (N-1 downto 0); 262 | signal do_buffer_reg : std_logic_vector (N-1 downto 0); 263 | -- internal signal to flag transfer to do_buffer_reg 264 | signal do_transfer_next : std_logic := '0'; 265 | signal do_transfer_reg : std_logic := '0'; 266 | -- internal input data request signal 267 | signal di_req_next : std_logic := '0'; 268 | signal di_req_reg : std_logic := '0'; 269 | -- cross-clock do_transfer_reg -> do_valid_o_reg pipeline 270 | signal do_valid_A : std_logic := '0'; 271 | signal do_valid_B : std_logic := '0'; 272 | signal do_valid_C : std_logic := '0'; 273 | signal do_valid_D : std_logic := '0'; 274 | signal do_valid_next : std_logic := '0'; 275 | signal do_valid_o_reg : std_logic := '0'; 276 | -- cross-clock di_req_reg -> di_req_o_reg pipeline 277 | signal di_req_o_A : std_logic := '0'; 278 | signal di_req_o_B : std_logic := '0'; 279 | signal di_req_o_C : std_logic := '0'; 280 | signal di_req_o_D : std_logic := '0'; 281 | signal di_req_o_next : std_logic := '1'; 282 | signal di_req_o_reg : std_logic := '1'; 283 | begin 284 | --============================================================================================= 285 | -- GENERICS CONSTRAINTS CHECKING 286 | --============================================================================================= 287 | -- minimum word width is 8 bits 288 | assert N >= 8 289 | report "Generic parameter 'N' (shift register size) needs to be 8 bits minimum" 290 | severity FAILURE; 291 | assert N = 16 292 | report "DMITRY" 293 | severity FAILURE; 294 | -- minimum prefetch lookahead check 295 | assert PREFETCH >= 1 296 | report "Generic parameter 'PREFETCH' (lookahead count) needs to be 1 minimum" 297 | severity FAILURE; 298 | assert PREFETCH = 2 299 | report "DMITRY" 300 | severity FAILURE; 301 | -- maximum prefetch lookahead check 302 | assert PREFETCH <= N-5 303 | report "Generic parameter 'PREFETCH' (lookahead count) out of range, needs to be N-5 maximum" 304 | severity FAILURE; 305 | -- SPI_2X_CLK_DIV clock divider value must not be zero 306 | assert SPI_2X_CLK_DIV > 0 307 | report "Generic parameter 'SPI_2X_CLK_DIV' must not be zero" 308 | severity FAILURE; 309 | 310 | --============================================================================================= 311 | -- CLOCK GENERATION 312 | --============================================================================================= 313 | -- In order to preserve global clocking resources, the core clocking scheme is completely based 314 | -- on using clock enables to process the serial high-speed clock at lower rates for the core fsm, 315 | -- the spi clock generator and the input sampling clock. 316 | -- The clock generation block derives 2 continuous antiphase signals from the 2x spi base clock 317 | -- for the core clocking. 318 | -- The 2 clock phases are generated by separate and synchronous FFs, and should have only 319 | -- differential interconnect delay skew. 320 | -- Clock enable signals are generated with the same phase as the 2 core clocks, and these clock 321 | -- enables are used to control clocking of all internal synchronous circuitry. 322 | -- The clock enable phase is selected for serial input sampling, fsm clocking, and spi SCK output, 323 | -- based on the configuration of CPOL and CPHA. 324 | -- Each phase is selected so that all the registers can be clocked with a rising edge on all SPI 325 | -- modes, by a single high-speed global clock, preserving clock resources and clock to data skew. 326 | ----------------------------------------------------------------------------------------------- 327 | -- generate the 2x spi base clock enable from the serial high-speed input clock 328 | spi_2x_ce_gen_proc: process (sclk_i) is 329 | variable clk_cnt : integer range SPI_2X_CLK_DIV-1 downto 0 := 0; 330 | begin 331 | if sclk_i'event and sclk_i = '1' then 332 | if clk_cnt = SPI_2X_CLK_DIV-1 then 333 | spi_2x_ce <= '1'; 334 | clk_cnt := 0; 335 | else 336 | spi_2x_ce <= '0'; 337 | clk_cnt := clk_cnt + 1; 338 | end if; 339 | end if; 340 | end process spi_2x_ce_gen_proc; 341 | ----------------------------------------------------------------------------------------------- 342 | -- generate the core antiphase clocks and clock enables from the 2x base CE. 343 | core_clock_gen_proc : process (sclk_i) is 344 | begin 345 | if sclk_i'event and sclk_i = '1' then 346 | if spi_2x_ce = '1' then 347 | -- generate the 2 antiphase core clocks 348 | core_clk <= core_n_clk; 349 | core_n_clk <= not core_n_clk; 350 | -- generate the 2 phase core clock enables 351 | core_ce <= core_n_clk; 352 | core_n_ce <= not core_n_clk; 353 | else 354 | core_ce <= '0'; 355 | core_n_ce <= '0'; 356 | end if; 357 | end if; 358 | end process core_clock_gen_proc; 359 | 360 | --============================================================================================= 361 | -- GENERATE BLOCKS 362 | --============================================================================================= 363 | -- spi clk generator: generate spi_clk from core_clk depending on CPOL 364 | spi_sck_cpol_0_proc: if CPOL = '0' generate 365 | begin 366 | spi_clk <= core_clk; -- for CPOL=0, spi clk has idle LOW 367 | end generate; 368 | 369 | spi_sck_cpol_1_proc: if CPOL = '1' generate 370 | begin 371 | spi_clk <= core_n_clk; -- for CPOL=1, spi clk has idle HIGH 372 | end generate; 373 | ----------------------------------------------------------------------------------------------- 374 | -- Sampling clock enable generation: generate 'samp_ce' from 'core_ce' or 'core_n_ce' depending on CPHA 375 | -- always sample data at the half-cycle of the fsm update cell 376 | samp_ce_cpha_0_proc: if CPHA = '0' generate 377 | begin 378 | samp_ce <= core_ce; 379 | end generate; 380 | 381 | samp_ce_cpha_1_proc: if CPHA = '1' generate 382 | begin 383 | samp_ce <= core_n_ce; 384 | end generate; 385 | ----------------------------------------------------------------------------------------------- 386 | -- FSM clock enable generation: generate 'fsm_ce' from core_ce or core_n_ce depending on CPHA 387 | fsm_ce_cpha_0_proc: if CPHA = '0' generate 388 | begin 389 | fsm_ce <= core_n_ce; -- for CPHA=0, latch registers at rising edge of negative core clock enable 390 | end generate; 391 | 392 | fsm_ce_cpha_1_proc: if CPHA = '1' generate 393 | begin 394 | fsm_ce <= core_ce; -- for CPHA=1, latch registers at rising edge of positive core clock enable 395 | end generate; 396 | ----------------------------------------------------------------------------------------------- 397 | -- sck enable control: control sck advance phase for CPHA='1' relative to fsm clock 398 | sck_ena_ce <= core_n_ce; -- for CPHA=1, SCK is advanced one-half cycle 399 | 400 | --============================================================================================= 401 | -- REGISTERED INPUTS 402 | --============================================================================================= 403 | -- rx bit flop: capture rx bit after SAMPLE edge of sck 404 | rx_bit_proc : process (sclk_i, spi_miso_i) is 405 | begin 406 | if sclk_i'event and sclk_i = '1' then 407 | if samp_ce = '1' then 408 | rx_bit_reg <= spi_miso_i; 409 | end if; 410 | end if; 411 | end process rx_bit_proc; 412 | 413 | --============================================================================================= 414 | -- CROSS-CLOCK PIPELINE TRANSFER LOGIC 415 | --============================================================================================= 416 | -- do_valid_o and di_req_o strobe output logic 417 | -- this is a delayed pulse generator with a ripple-transfer FFD pipeline, that generates a 418 | -- fixed-length delayed pulse for the output flags, at the parallel clock domain 419 | out_transfer_proc : process ( pclk_i, do_transfer_reg, di_req_reg, 420 | do_valid_A, do_valid_B, do_valid_D, 421 | di_req_o_A, di_req_o_B, di_req_o_D ) is 422 | begin 423 | if pclk_i'event and pclk_i = '1' then -- clock at parallel port clock 424 | -- do_transfer_reg -> do_valid_o_reg 425 | do_valid_A <= do_transfer_reg; -- the input signal must be at least 2 clocks long 426 | do_valid_B <= do_valid_A; -- feed it to a ripple chain of FFDs 427 | do_valid_C <= do_valid_B; 428 | do_valid_D <= do_valid_C; 429 | do_valid_o_reg <= do_valid_next; -- registered output pulse 430 | -------------------------------- 431 | -- di_req_reg -> di_req_o_reg 432 | di_req_o_A <= di_req_reg; -- the input signal must be at least 2 clocks long 433 | di_req_o_B <= di_req_o_A; -- feed it to a ripple chain of FFDs 434 | di_req_o_C <= di_req_o_B; 435 | di_req_o_D <= di_req_o_C; 436 | di_req_o_reg <= di_req_o_next; -- registered output pulse 437 | end if; 438 | -- generate a 2-clocks pulse at the 3rd clock cycle 439 | do_valid_next <= do_valid_A and do_valid_B and not do_valid_D; 440 | di_req_o_next <= di_req_o_A and di_req_o_B and not di_req_o_D; 441 | end process out_transfer_proc; 442 | -- parallel load input registers: data register and write enable 443 | in_transfer_proc: process ( pclk_i, wren_i, wr_ack_reg ) is 444 | begin 445 | -- registered data input, input register with clock enable 446 | if pclk_i'event and pclk_i = '1' then 447 | if wren_i = '1' then 448 | di_reg <= di_i; -- parallel data input buffer register 449 | end if; 450 | end if; 451 | -- stretch wren pulse to be detected by spi fsm (ffd with sync preset and sync reset) 452 | if pclk_i'event and pclk_i = '1' then 453 | if wren_i = '1' then -- wren_i is the sync preset for wren 454 | wren <= '1'; 455 | elsif wr_ack_reg = '1' then -- wr_ack is the sync reset for wren 456 | wren <= '0'; 457 | end if; 458 | end if; 459 | end process in_transfer_proc; 460 | 461 | --============================================================================================= 462 | -- REGISTER TRANSFER PROCESSES 463 | --============================================================================================= 464 | -- fsm state and data registers: synchronous to the spi base reference clock 465 | core_reg_proc : process (sclk_i) is 466 | begin 467 | -- FF registers clocked on rising edge and cleared on sync rst_i 468 | if sclk_i'event and sclk_i = '1' then 469 | if rst_i = '1' then -- sync reset 470 | state_reg <= 0; -- only provide local reset for the state machine 471 | elsif fsm_ce = '1' then -- fsm_ce is clock enable for the fsm 472 | state_reg <= state_next; -- state register 473 | end if; 474 | end if; 475 | -- FF registers clocked synchronous to the fsm state 476 | if sclk_i'event and sclk_i = '1' then 477 | if fsm_ce = '1' then 478 | sh_reg <= sh_next; -- shift register 479 | ssel_ena_reg <= ssel_ena_next; -- spi select enable 480 | do_buffer_reg <= do_buffer_next; -- registered output data buffer 481 | do_transfer_reg <= do_transfer_next; -- output data transferred to buffer 482 | di_req_reg <= di_req_next; -- input data request 483 | wr_ack_reg <= wr_ack_next; -- write acknowledge for data load synchronization 484 | end if; 485 | end if; 486 | -- FF registers clocked one-half cycle earlier than the fsm state 487 | if sclk_i'event and sclk_i = '1' then 488 | if sck_ena_ce = '1' then 489 | sck_ena_reg <= sck_ena_next; -- spi clock enable: look ahead logic 490 | end if; 491 | end if; 492 | end process core_reg_proc; 493 | 494 | --============================================================================================= 495 | -- COMBINATORIAL LOGIC PROCESSES 496 | --============================================================================================= 497 | -- state and datapath combinatorial logic 498 | core_combi_proc : process ( sh_reg, state_reg, rx_bit_reg, ssel_ena_reg, sck_ena_reg, do_buffer_reg, 499 | do_transfer_reg, wr_ack_reg, di_req_reg, di_reg, wren ) is 500 | begin 501 | sh_next <= sh_reg; -- all output signals are assigned to (avoid latches) 502 | ssel_ena_next <= ssel_ena_reg; -- controls the slave select line 503 | sck_ena_next <= sck_ena_reg; -- controls the clock enable of spi sck line 504 | do_buffer_next <= do_buffer_reg; -- output data buffer 505 | do_transfer_next <= do_transfer_reg; -- output data flag 506 | wr_ack_next <= wr_ack_reg; -- write acknowledge 507 | di_req_next <= di_req_reg; -- prefetch data request 508 | spi_mosi_o <= sh_reg(N-1); -- default to avoid latch inference 509 | state_next <= state_reg; -- next state 510 | case state_reg is 511 | 512 | when (16+1) => -- this state is to enable SSEL before SCK 513 | spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb 514 | ssel_ena_next <= '1'; -- tx in progress: will assert SSEL 515 | sck_ena_next <= '1'; -- enable SCK on next cycle (stays off on first SSEL clock cycle) 516 | di_req_next <= '0'; -- prefetch data request: deassert when shifting data 517 | wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages 518 | state_next <= state_reg - 1; -- update next state at each sck pulse 519 | 520 | when (16) => -- deassert 'di_rdy' and stretch do_valid 521 | spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb 522 | di_req_next <= '0'; -- prefetch data request: deassert when shifting data 523 | sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits 524 | sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb 525 | wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages 526 | state_next <= state_reg - 1; -- update next state at each sck pulse 527 | 528 | when (16-1) downto (2+3) => -- remove 'do_transfer' and shift bits 529 | spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb 530 | di_req_next <= '0'; -- prefetch data request: deassert when shifting data 531 | do_transfer_next <= '0'; -- reset 'do_valid' transfer signal 532 | sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits 533 | sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb 534 | wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages 535 | state_next <= state_reg - 1; -- update next state at each sck pulse 536 | 537 | when (2+2) downto 2 => -- raise prefetch 'di_req_o' signal 538 | spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb 539 | di_req_next <= '1'; -- request data in advance to allow for pipeline delays 540 | sh_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift inner bits 541 | sh_next(0) <= rx_bit_reg; -- shift in rx bit into LSb 542 | wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages 543 | state_next <= state_reg - 1; -- update next state at each sck pulse 544 | 545 | when 1 => -- transfer rx data to do_buffer and restart if new data is written 546 | spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb 547 | di_req_next <= '1'; -- request data in advance to allow for pipeline delays 548 | do_buffer_next(N-1 downto 1) <= sh_reg(N-2 downto 0); -- shift rx data directly into rx buffer 549 | do_buffer_next(0) <= rx_bit_reg; -- shift last rx bit into rx buffer 550 | do_transfer_next <= '1'; -- signal transfer to do_buffer 551 | if wren = '1' then -- load tx register if valid data present at di_i 552 | state_next <= N; -- next state is top bit of new data 553 | sh_next <= di_reg; -- load parallel data from di_reg into shifter 554 | sck_ena_next <= '1'; -- SCK enabled 555 | wr_ack_next <= '1'; -- acknowledge data in transfer 556 | else 557 | sck_ena_next <= '0'; -- SCK disabled: tx empty, no data to send 558 | wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages 559 | state_next <= state_reg - 1; -- update next state at each sck pulse 560 | end if; 561 | 562 | when 0 => -- idle state: start and end of transmission 563 | di_req_next <= '1'; -- will request data if shifter empty 564 | sck_ena_next <= '0'; -- SCK disabled: tx empty, no data to send 565 | if wren = '1' then -- load tx register if valid data present at di_i 566 | spi_mosi_o <= di_reg(N-1); -- special case: shift out first tx bit from the MSb (look ahead) 567 | ssel_ena_next <= '1'; -- enable interface SSEL 568 | state_next <= N+1; -- start from idle: let one cycle for SSEL settling 569 | sh_next <= di_reg; -- load bits from di_reg into shifter 570 | wr_ack_next <= '1'; -- acknowledge data in transfer 571 | else 572 | spi_mosi_o <= sh_reg(N-1); -- shift out tx bit from the MSb 573 | ssel_ena_next <= '0'; -- deassert SSEL: interface is idle 574 | wr_ack_next <= '0'; -- remove write acknowledge for all but the load stages 575 | state_next <= 0; -- when idle, keep this state 576 | end if; 577 | 578 | when others => 579 | state_next <= 0; -- state 0 is safe state 580 | end case; 581 | end process core_combi_proc; 582 | 583 | --============================================================================================= 584 | -- OUTPUT LOGIC PROCESSES 585 | --============================================================================================= 586 | -- data output processes 587 | spi_ssel_o_proc: spi_ssel_o <= not ssel_ena_reg; -- active-low slave select line 588 | do_o_proc: do_o <= do_buffer_reg; -- parallel data out 589 | do_valid_o_proc: do_valid_o <= do_valid_o_reg; -- data out valid 590 | di_req_o_proc: di_req_o <= di_req_o_reg; -- input data request for next cycle 591 | wr_ack_o_proc: wr_ack_o <= wr_ack_reg; -- write acknowledge 592 | ----------------------------------------------------------------------------------------------- 593 | -- SCK out logic: pipeline phase compensation for the SCK line 594 | ----------------------------------------------------------------------------------------------- 595 | -- This is a MUX with an output register. 596 | -- The register gives us a pipeline delay for the SCK line, pairing with the state machine moore 597 | -- output pipeline delay for the MOSI line, and thus enabling higher SCK frequency. 598 | spi_sck_o_gen_proc : process (sclk_i, sck_ena_reg, spi_clk, spi_clk_reg) is 599 | begin 600 | if sclk_i'event and sclk_i = '1' then 601 | if sck_ena_reg = '1' then 602 | spi_clk_reg <= spi_clk; -- copy the selected clock polarity 603 | else 604 | spi_clk_reg <= CPOL; -- when clock disabled, set to idle polarity 605 | end if; 606 | end if; 607 | spi_sck_o <= spi_clk_reg; -- connect register to output 608 | end process spi_sck_o_gen_proc; 609 | 610 | --============================================================================================= 611 | -- DEBUG LOGIC PROCESSES 612 | --============================================================================================= 613 | -- these signals are useful for verification, and can be deleted after debug. 614 | do_transfer_proc: do_transfer_o <= do_transfer_reg; 615 | state_dbg_proc: state_dbg_o <= std_logic_vector(to_unsigned(state_reg, 8)); 616 | rx_bit_reg_proc: rx_bit_reg_o <= rx_bit_reg; 617 | wren_o_proc: wren_o <= wren; 618 | sh_reg_dbg_proc: sh_reg_dbg_o <= sh_reg; 619 | core_clk_o_proc: core_clk_o <= core_clk; 620 | core_n_clk_o_proc: core_n_clk_o <= core_n_clk; 621 | core_ce_o_proc: core_ce_o <= core_ce; 622 | core_n_ce_o_proc: core_n_ce_o <= core_n_ce; 623 | sck_ena_o_proc: sck_ena_o <= sck_ena_reg; 624 | sck_ena_ce_o_proc: sck_ena_ce_o <= sck_ena_ce; 625 | 626 | end architecture rtl; 627 | 628 | --------------------------------------------------------------------------------