From 9e11362e0177366e5bdf8f6c8a1ed30f6dc7564f Mon Sep 17 00:00:00 2001 From: faramire Date: Thu, 18 Apr 2024 18:44:47 +0200 Subject: [PATCH] rewrote entire SPI code --- src/SPI_master.v | 88 +++++++++++++++++++++++++++ src/SPI_wrapper.v | 141 ++++++++++++++++++++++++++++++++++++++++++++ src/stopwatch_top.v | 4 +- 3 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 src/SPI_master.v create mode 100644 src/SPI_wrapper.v diff --git a/src/SPI_master.v b/src/SPI_master.v new file mode 100644 index 0000000..28563a1 --- /dev/null +++ b/src/SPI_master.v @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 Fabio Ramirez Stern + * SPDX-License-Identifier: Apache-2.0 + */ + +module SPI_Master ( + input wire clk, + input wire res, + input wire cs_in, // CS input + input wire [15:0] word_in, // word to be sent + + output reg sck, // serial clock + output reg mosi, // MOSI + output reg report_send, // data has been sent, CS can be pulled high + output reg report_ready // ready for next transmission +); + + // FSM states + localparam IDLE = 2'b00; + localparam TRANSFER = 2'b01; + localparam DONE = 2'b10; + + reg [1:0] state; + reg [1:0] count_bit; // count through the clock cylce: negedge, hold high (sample), negedge (set) + reg [3:0] count_word; // count through the bits of the word + reg [15:0] word_out; + + + always @(posedge clk or negedge res) begin + if (!res) begin // async reset, active low + sck <= 0; + mosi <= 0; + count_bit <= 0; + count_word <= 0; + word_out <= 16'b0; + report_send <= 0; + report_ready <= 0; + state <= IDLE; + end else begin + // FSM + case(state) + + IDLE: begin + if (cs_in == 0) begin + sck <= 0; + mosi <= 0; + count_bit <= 0; + count_word <= 0; + word_out <= word_in; + report_send <= 1; + report_ready <= 1; + state <= TRANSFER; + end + end // IDLE + + TRANSFER: begin + if (count_word == 0) begin // end of word? + state <= DONE; + end + + // send out data on MOSI + if (count_bit == 0) begin + mosi <= word_out[count_word]; + /* mosi <= word_out[15]; // or shift out? + word_out <= word_out << 1; */ + count_word <= count_word - 2'b01; + + end + + // generate serial clock + if (count_bit == 1) begin + sck <= 1; + end + + count_bit <= count_bit + 2'b01; + end // TRANSFER + + DONE: begin + if (cs_in == 1) begin + state <= IDLE; + end + end // DONE + + endcase + end + end + +endmodule diff --git a/src/SPI_wrapper.v b/src/SPI_wrapper.v new file mode 100644 index 0000000..29bf37a --- /dev/null +++ b/src/SPI_wrapper.v @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024 Fabio Ramirez Stern + * SPDX-License-Identifier: Apache-2.0 + */ +`include "SPI_master.v" +module SPI_wrapper ( + input wire clk, // 1 MHz clock to run the FSM and other loops + input wire clk_div, // 100 Hz clock to trigger a time to be send out + input wire res, // reset, active low + input wire ena, + + input wire [2:0] min_X0, // minutes + input wire [3:0] min_0X, + input wire [2:0] sec_X0, // seconds + input wire [3:0] sec_0X, + input wire [3:0] ces_X0, // centiseconds (100th) + input wire [3:0] ces_0X, + + output wire Mosi, + output reg Cs, + output wire Clk_SPI +); + + // FSM + reg [1:0] state; + localparam SETUP = 2'b00; + localparam IDLE = 2'b01; + localparam TRANSFER = 2'b10; + localparam DONE = 2'b11; + + reg [15:0] word_out; + reg [2:0] digit_count; + reg [1:0] setup_count; + wire send_reported; + wire ready_reported; + + always @(posedge clk or negedge res) begin // controlling FSM + if (!res) begin // active low reset + Cs <= 1; + word_out <= 16'b0; + digit_count <= 3'b0; + state <= SETUP; + end + case(state) + + SETUP: begin // send a setup packet enabling BCD + if (res) begin + if (ready_reported == 1) begin + word_out <= 16'b0000_1001_1111_1111; // address = decode mode, data = BCD for all + Cs <= 0; + end + else if (send_reported == 1) begin // data send, Cs can be pulled high again + Cs <= 1; + state <= IDLE; + end + end + end // SETUP + + IDLE: begin + if (clk_div & ena) begin // wait for the 100Hz clock to get high + digit_count <= 3'b000; + state <= TRANSFER; + end + end // IDLE + TRANSFER: begin + + if (ready_reported == 1) begin // wait for TX ready + case(digit_count) + + 3'b000: begin // ces_0X + word_out <= {8'b0000_0001, 8'b0000_0000 | ces_0X}; // send the 16-bit word + Cs <= 0; // pull CS low to initiate send + digit_count <= 3'b001; // advance the position counter + end + + 3'b001: begin // ces_X0 + word_out <= {8'b0000_0010, 8'b0000_0000 | ces_X0}; + Cs <= 0; + digit_count <= 3'b010; + end + + 3'b010: begin // sec_0X + word_out <= {8'b0000_0011, 8'b0000_0000 | sec_0X}; + Cs <= 0; + digit_count <= 3'b011; + end + + 3'b011: begin // sec_X0 + word_out <= {8'b0000_0100, 8'b0000_0000 | sec_X0}; + Cs <= 0; + digit_count <= 3'b100; + end + + 3'b100: begin // min_0X + word_out <= {8'b0000_0101, 8'b0000_0000 | min_0X}; + Cs <= 0; + digit_count <= 3'b101; + end + + 3'b101: begin // min_X0 + word_out <= {8'b0000_0110, 8'b0000_0000 | min_X0}; + Cs <= 0; + digit_count <= 3'b110; + end + + 3'b110: begin // once send has been complete and CS is high again, switch state + state <= DONE; + end + + default:digit_count <= 3'b000; + endcase + + end else if (send_reported == 1) begin // once data has been send, pull CS high + Cs <= 1; + end + end // TRANSFER + + DONE: begin // wait for the 100 Hz clock to go low again + if (!clk_div) begin + state <= IDLE; + end + end // DONE + + default:state <= SETUP; + endcase + end + + SPI_Master SPI_Master1 ( + .clk(clk), + .res(res), + .cs_in(Cs), + .word_in(word_out), + + .report_send(send_reported), + .report_ready(ready_reported), + + .sck(clk_SPI), + .mosi(Mosi) + ); + +endmodule // SPI_wrapper diff --git a/src/stopwatch_top.v b/src/stopwatch_top.v index b6c639e..395447f 100644 --- a/src/stopwatch_top.v +++ b/src/stopwatch_top.v @@ -7,7 +7,7 @@ // ui_in [0]: reset: resets the stopwatch to 00:00:00 // ui_in [1]: speed: - +`include "SPI_wrapper.v" module tt_um_faramire_stopwatch ( input wire [7:0] ui_in, // Dedicated inputs output wire [7:0] uo_out, // Dedicated outputs @@ -82,7 +82,7 @@ module tt_um_faramire_stopwatch ( .ces_0X (ces_0X), .Mosi (uo_out[0]), // MOSI on out 0 .Cs (uo_out[1]), // CS on out 1 - .clk_SPI (uo_out[2]) // CLK on out 3 + .Clk_SPI (uo_out[2]) // CLK on out 3 ); endmodule // tt_um_faramire_stopwatch