/* * Copyright (c) 2025, Nicolas Sauzede * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Simple SPI Master wrapper for Darkriscv */ `timescale 1ns / 1ps //`include "../rtl/config.vh" // See spi_master doc for 3-wire support, and divider coefficient configuration. // // SPI registers // Only 16 (1 byte data) and 24 (2 bytes data) bits SPI transfers are supported // BE // W 0011 command,data // R 0001 data // R 1000 STATUS // W 1111 00,command,datalo,datahi // R 0011 datalo,datahi // R 1111 STATUS,00,datalo,datahi // Where STATUS is: {6'b0, spi_ready, spi_busy} and can be polled for SPI transfer completion. // // Special reserved 32 bit write to trigger spi_master internal configuration // W 1111 (refer to spi_master documentation) // // Examples below are for STMicro LIS3DH sensor SPI target. // // - One byte transfer: // To read a single byte at address 0x0f (WHO_AM_I), initiate a 16 bits write: // *((volatile short *)SPI_MMADDR) = 0x8f00; // 8f is addr with RnW=1, 00 is 8-bit resp placeholder // Followed by a 8 bits read: // char who_am_i = *((volatile char *)SPI_MMADDR) & 0xff; // // To write a single byte at address eg: 0x20 (CTRL_REG1), initiate a 16 bits write: // *((volatile short *)SPI_MMADDR) = 0x2077; // 20 is addr, 77 is 8-bit data to write // // - Two bytes access (with automatic address increment): // To read two bytes starting at address eg: 0x28 (OUT_X_L), initiate a 32 bits write: // *((volatile int *)SPI_MMADDR) = 0x00e80000; // e8 is addr with RnW=1 & MnS=1, 0000 is 16-bit resp placeholder // Followed by: // -- a 16 bits read: // short swapped_out_x = *((volatile short *)SPI_MMADDR); // Note that the returned value is byte-swapped: 0xLOHI module darkspi #(parameter integer DIV_COEF = 0) ( input CLK, // clock input RES, // reset input RD, // bus read input WR, // bus write input [ 3:0] BE, // byte enable input [31:0] DATAI, // data input output [31:0] DATAO, // data output output IRQ, // interrupt req output CSN, // SPI CSN output (active LOW) output SCK, // SPI clock output inout MOSI, // SPI master data output, slave data input; or SDI/O (3-wire mode) input MISO, // SPI master data input, slave data output `ifdef SIMULATION output reg ESIMREQ = 0, input ESIMACK, `endif output [3:0] DEBUG // osc debug ); reg [31:0] spi_mosi_data = 0; wire [31:0] spi_miso_data; reg [4:0] spi_nbits = 0; reg spi_request = 0; wire spi_ready; wire [7:0] status; reg spi_busy = 0; assign status = {6'b0, spi_ready & ~WR & ~spi_request, spi_busy}; assign DATAO = {status, spi_miso_data[23:16], spi_miso_data[15:8], spi_miso_data[7:0]}; assign IRQ = 0; // assign IRQ = spi_ready; always @(posedge CLK) begin if (RES) begin spi_mosi_data <= 0; spi_nbits <= 0; spi_request <= 0; spi_busy <= 0; end else begin if (spi_ready) begin spi_busy <= 0; end if (WR) begin spi_request <= 1; spi_busy <= 1; if (BE == 4'b1111) begin spi_mosi_data <= DATAI; if (DATAI[31:24] == 8'b0) begin spi_nbits <= 5'd23; // 24 bits end else begin spi_nbits <= 5'd0; // 32 bits internal config end end else if (BE == 4'b0011) begin spi_nbits <= 5'd15; // 16 bits spi_mosi_data <= DATAI[15:0]; end else begin spi_request <= 0; // ignore any other writes end end else begin spi_request <= 0; //spi_nbits <= 0; end end end spi_master #(.DIV_COEF(DIV_COEF)) spi_master1 ( .clk_in(CLK), .nrst(~RES), .spi_sck(SCK), .spi_mosi(MOSI), .spi_miso(MISO), .spi_csn(CSN), .mosi_data(spi_mosi_data), .miso_data(spi_miso_data), .nbits(spi_nbits), .request(spi_request), .ready(spi_ready) ); assign DEBUG = 0; endmodule