SergeyVas 1 May 9, 2015 Posted May 9, 2015 · Report post Хочу попробовать запустить spi slave на циклоне. Поискал в сети готовые исходники, примеров много для этого интерфейса не знаю с какого начать, подскажите пожалуйста ссылку на проверенный пример, который вам понравился )) Quote Share this post Link to post Share on other sites More sharing options...
Maverick_ 17 May 9, 2015 Posted May 9, 2015 · Report post Хочу попробовать запустить spi slave на циклоне. Поискал в сети готовые исходники, примеров много для этого интерфейса не знаю с какого начать, подскажите пожалуйста ссылку на проверенный пример, который вам понравился )) `timescale 1ns/1ns `define CLOCK_PHASE 0 `define CLOCK_POLARITY 0 module spi_slave #( parameter SHIFT_DIRECTION = 0, parameter DATA_LENGTH = 8 // changed from 32 to 8 ) ( //Back end device interfacet CSn, DATA_IN, //8 bit width - changed from 32 bits WR_RD, DATA_OUT, //8 bit width - changed from 32 bits TX_RDY, RX_RDY, TX_ERR, RX_ERR, CLK_I, RST_I, //spi interface MISO_SLAVE, MOSI_SLAVE, CSn_SLAVE, SCLK_SLAVE ); //back end device interface input CSn; input [7:0] DATA_IN; //8 bit width - changed from 32 bits input WR_RD; output [7:0] DATA_OUT; //8 bit width - changed from 32 bits output TX_RDY; output RX_RDY; output TX_ERR; output RX_ERR; input CLK_I; input RST_I; //spi interface output MISO_SLAVE; input MOSI_SLAVE; input CSn_SLAVE; input SCLK_SLAVE; parameter UDLY = 1; //register access reg MISO_SLAVE; reg [7:0] latch_s_data; //8 bit width - changed from 32 bits reg [DATA_LENGTH-1:0] reg_rxdata; reg [DATA_LENGTH-1:0] reg_txdata; reg [DATA_LENGTH-1:0] rx_shift_data; reg reg_toe; reg reg_roe; reg reg_trdy; reg reg_rrdy; reg tx_done; reg rx_done; reg rx_done_flip1; reg rx_done_flip2; reg rx_done_flip3; reg tx_done_flip1; reg tx_done_flip2; reg tx_done_flip3; reg [5:0] rx_data_cnt; reg [5:0] tx_data_cnt; assign TX_RDY=reg_trdy; assign RX_RDY=reg_rrdy; assign TX_ERR=reg_toe; assign RX_ERR=reg_roe; assign DATA_OUT=reg_rxdata; always @(posedge CLK_I or posedge RST_I) if(RST_I) latch_s_data <= #UDLY 32'h0; else if (!WR_RD && !CSn && reg_trdy) latch_s_data <= #UDLY DATA_IN; //Receive Data Register always @(posedge CLK_I or posedge RST_I) if(RST_I) reg_rxdata <= #UDLY 'h0; else if (rx_done_flip1 && !rx_done_flip2) reg_rxdata <= #UDLY rx_shift_data; //Transmit Data Register always @(posedge CLK_I or posedge RST_I) if(RST_I) reg_txdata <= #UDLY 'h0; else //if (!WR_RD && !CSn && reg_trdy) reg_txdata <= #UDLY latch_s_data; //-----------------------------For Rx data, //-----------------sample at posedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 0 `ifdef CLOCK_POLARITY `ifdef CLOCK_PHASE always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_shift_data <= #UDLY 'h0; else if (!CSn_SLAVE) if (SHIFT_DIRECTION) rx_shift_data <= #UDLY {MOSI_SLAVE,rx_shift_data[DATA_LENGTH-1:1]}; else rx_shift_data <= #UDLY {rx_shift_data,MOSI_SLAVE}; always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_data_cnt <= #UDLY 'h0; else if (rx_data_cnt == DATA_LENGTH - 1) rx_data_cnt <= #UDLY 'h0; else if (!CSn_SLAVE) rx_data_cnt <= #UDLY rx_data_cnt + 1; always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_done <= #UDLY 1'b0; else if (rx_data_cnt == DATA_LENGTH - 1) rx_done <= #UDLY 1'b1; else rx_done <= #UDLY 1'b0; //-----------------sample at negedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 1 `else //For Rx data, sample at negedge when CLOCK_PHASE is 1 always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_shift_data <= #UDLY 'h0; else if (!CSn_SLAVE) if (SHIFT_DIRECTION) rx_shift_data <= #UDLY {MOSI_SLAVE,rx_shift_data[DATA_LENGTH-1:1]}; else rx_shift_data <= #UDLY {rx_shift_data,MOSI_SLAVE}; always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_data_cnt <= #UDLY 'h0; else if (rx_data_cnt == DATA_LENGTH - 1) rx_data_cnt <= #UDLY 'h0; else if (!CSn_SLAVE) rx_data_cnt <= #UDLY rx_data_cnt + 1; always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_done <= #UDLY 1'b0; else if (rx_data_cnt == DATA_LENGTH - 1) rx_done <= #UDLY 1'b1; else rx_done <= #UDLY 1'b0; //end `endif //-----------------sample at negedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 0 `else `ifdef CLOCK_PHASE always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_shift_data <= #UDLY 'h0; else if (!CSn_SLAVE) if (SHIFT_DIRECTION) rx_shift_data <= #UDLY {MOSI_SLAVE,rx_shift_data[DATA_LENGTH-1:1]}; else rx_shift_data <= #UDLY {rx_shift_data,MOSI_SLAVE}; always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_data_cnt <= #UDLY 'h0; else if (rx_data_cnt == DATA_LENGTH - 1) rx_data_cnt <= #UDLY 'h0; else if (!CSn_SLAVE) rx_data_cnt <= #UDLY rx_data_cnt + 1; always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_done <= #UDLY 1'b0; else if (rx_data_cnt == DATA_LENGTH - 1) rx_done <= #UDLY 1'b1; else rx_done <= #UDLY 1'b0; //-----------------sample at posedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 1 `else //For Rx data, sample at negedge when CLOCK_PHASE is 1 always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_shift_data <= #UDLY 'h0; else if (!CSn_SLAVE) if (SHIFT_DIRECTION) rx_shift_data <= #UDLY {MOSI_SLAVE,rx_shift_data[DATA_LENGTH-1:1]}; else rx_shift_data <= #UDLY {rx_shift_data,MOSI_SLAVE}; always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_data_cnt <= #UDLY 'h0; else if (rx_data_cnt == DATA_LENGTH - 1) rx_data_cnt <= #UDLY 'h0; else if (!CSn_SLAVE) rx_data_cnt <= #UDLY rx_data_cnt + 1; always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) rx_done <= #UDLY 1'b0; else if (rx_data_cnt == DATA_LENGTH - 1) rx_done <= #UDLY 1'b1; else rx_done <= #UDLY 1'b0; //end `endif `endif always @(posedge CLK_I or posedge RST_I) if (RST_I) begin rx_done_flip1 <= #UDLY 1'b0; rx_done_flip2 <= #UDLY 1'b0; rx_done_flip3 <= #UDLY 1'b0; end else begin rx_done_flip1 <= #UDLY rx_done; rx_done_flip2 <= #UDLY rx_done_flip1; rx_done_flip3 <= #UDLY rx_done_flip2; end always @(posedge CLK_I or posedge RST_I) if (RST_I) reg_rrdy <= #UDLY 1'b0; else if (rx_done_flip2 && !rx_done_flip3) reg_rrdy <= #UDLY 1'b1; else if (WR_RD && !CSn) reg_rrdy <= #UDLY 1'b0; always @(posedge CLK_I or posedge RST_I) if (RST_I) reg_roe <= #UDLY 1'b0; else if (rx_done_flip2 && !rx_done_flip3 && reg_rrdy) reg_roe <= #UDLY 1'b1; else if (WR_RD && !CSn) reg_roe <= #UDLY 1'b0; //--------------------For Tx data, //-----------------------------------update at negedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 0 `ifdef CLOCK_POLARITY `ifdef CLOCK_PHASE //always @(*) always @(reg_txdata or tx_data_cnt or CSn_SLAVE ) if (!CSn_SLAVE) MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] : reg_txdata[DATA_LENGTH-tx_data_cnt-1]; else MISO_SLAVE<=1'bz; always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) tx_data_cnt <= #UDLY 'h0; else if (tx_data_cnt == DATA_LENGTH - 1) tx_data_cnt <= #UDLY 'h0; else if (!CSn_SLAVE) tx_data_cnt <= #UDLY tx_data_cnt + 1; always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) tx_done <= #UDLY 1'b0; else if (tx_data_cnt == DATA_LENGTH - 1) tx_done <= #UDLY 1'b1; else tx_done <= #UDLY 1'b0; //-----------------------------------update at posedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 1 `else //always @(posedge SCLK_SLAVE or posedge RST_I) // if (RST_I) // MISO_SLAVE <= #UDLY 1'b0; // else // MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] : // reg_txdata[DATA_LENGTH-tx_data_cnt-1]; always @(posedge SCLK_SLAVE) if (!CSn_SLAVE) MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] : reg_txdata[DATA_LENGTH-tx_data_cnt-1]; else MISO_SLAVE<=1'bz; always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) tx_data_cnt <= #UDLY 'h0; else if (tx_data_cnt == DATA_LENGTH - 1) tx_data_cnt <= #UDLY 'h0; else if (!CSn_SLAVE) tx_data_cnt <= #UDLY tx_data_cnt + 1; always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) tx_done <= #UDLY 1'b0; else if (tx_data_cnt == DATA_LENGTH - 1) tx_done <= #UDLY 1'b1; else tx_done <= #UDLY 1'b0; `endif //-----------------------------------update at posedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 0 `else `ifdef CLOCK_PHASE //always @(*) always @(reg_txdata or tx_data_cnt or CSn_SLAVE ) if (!CSn_SLAVE) MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] : reg_txdata[DATA_LENGTH-tx_data_cnt-1]; else MISO_SLAVE<=1'bz; always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) tx_data_cnt <= #UDLY 'h0; else if (tx_data_cnt == DATA_LENGTH - 1) tx_data_cnt <= #UDLY 'h0; else if (!CSn_SLAVE) tx_data_cnt <= #UDLY tx_data_cnt + 1; always @(posedge SCLK_SLAVE or posedge RST_I) if (RST_I) tx_done <= #UDLY 1'b0; else if (tx_data_cnt == DATA_LENGTH - 1) tx_done <= #UDLY 1'b1; else tx_done <= #UDLY 1'b0; //-----------------------------------update at negedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 1 `else // always @(negedge SCLK_SLAVE or posedge RST_I) // if (RST_I) // MISO_SLAVE <= #UDLY 1'b0; // else // MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] : // reg_txdata[DATA_LENGTH-tx_data_cnt-1]; always @(negedge SCLK_SLAVE) if (!CSn_SLAVE) MISO_SLAVE <= #UDLY SHIFT_DIRECTION ? reg_txdata[tx_data_cnt] : reg_txdata[DATA_LENGTH-tx_data_cnt-1]; else MISO_SLAVE<=1'bz; always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) tx_data_cnt <= #UDLY 'h0; else if (tx_data_cnt == DATA_LENGTH - 1) tx_data_cnt <= #UDLY 'h0; else if (!CSn_SLAVE) tx_data_cnt <= #UDLY tx_data_cnt + 1; always @(negedge SCLK_SLAVE or posedge RST_I) if (RST_I) tx_done <= #UDLY 1'b0; else if (tx_data_cnt == DATA_LENGTH - 1) tx_done <= #UDLY 1'b1; else tx_done <= #UDLY 1'b0; `endif `endif always @(posedge CLK_I or posedge RST_I) if (RST_I) begin tx_done_flip1 <= #UDLY 1'b0; tx_done_flip2 <= #UDLY 1'b0; tx_done_flip3 <= #UDLY 1'b0; end else begin tx_done_flip1 <= #UDLY tx_done; tx_done_flip2 <= #UDLY tx_done_flip1; tx_done_flip3 <= #UDLY tx_done_flip2; end always @(posedge CLK_I or posedge RST_I) if (RST_I) reg_trdy <= #UDLY 1'b1; else if (!WR_RD && !CSn) reg_trdy <= #UDLY 1'b0; else if (tx_done_flip2 && !tx_done_flip3) reg_trdy <= #UDLY 1'b1; always @(posedge CLK_I or posedge RST_I) if(RST_I) reg_toe <= #UDLY 1'b0; else if(!reg_trdy && !WR_RD && !CSn) reg_toe <= #UDLY 1'b1; else if(!WR_RD && !CSn) reg_toe <= #UDLY 1'b0; endmodule тестбенч: `timescale 1ns/1ps module spi_speripheral_tb; wire clk,rst; wire mosi,csn_spi,sclk; wire csn,wr_rd; wire [7:0] data_out; wire miso; wire tx_rdy,rx_rdy,tx_err,rx_err; wire [7:0] data_in; spi_master spi_master( .sclk_master(sclk), .csn_master(csn_spi), .mosi_master(mosi), .miso_master(miso) ); spi_slave spi_slave ( //slave port .CSn(csn), .DATA_IN(data_in), //8 bit width - changed from 32 bits .WR_RD(wr_rd), .DATA_OUT(data_out), //8 bit width - changed from 32 bits .TX_RDY(tx_rdy), .RX_RDY(rx_rdy), .TX_ERR(tx_err), .RX_ERR(rx_err), //spi interface .MISO_SLAVE(miso), .MOSI_SLAVE(mosi), .CSn_SLAVE(csn_spi), .SCLK_SLAVE(sclk), //system clock and reset .CLK_I(clk), .RST_I(rst) ); back_end_device back_end_device( .CSn(csn), .DATA_IN(data_out), .WR_RD(wr_rd), .DATA_OUT(data_in), .TX_RDY(tx_rdy), .RX_RDY(rx_rdy), .TX_ERR(tx_err), .RX_ERR(rx_err), .CLK(clk), .RST(rst) ); endmodule `timescale 1ns/1ps module spi_master( sclk_master, csn_master, mosi_master, miso_master ); parameter CLOCK_PHASE = 0; parameter CLOCK_POLARITY = 0; parameter sclk_cycle= 40; parameter SHIFT_DIRECTION = 0; parameter DATA_LENGTH = 8; // changed from 32 to 8 output sclk_master; output csn_master; output mosi_master; input miso_master; reg sclk_master; reg csn_master; reg mosi_master; reg [7:0] master_data_in; reg [7:0] master_data_out; reg [2:0] cnt; initial begin if(CLOCK_POLARITY) sclk_master<=#1 1'b1; else sclk_master<=#1 1'b0; csn_master<=1'b1; master_data_in<=8'h00; master_data_out<=8'h00; cnt<=3'h0; mosi_master<=1'b0; #306; spi_master_operation(8'h73); #100; spi_master_operation(8'h43); #104; spi_master_operation(8'h19); #100 spi_master_operation(8'h55); #100 spi_master_operation(8'haa); #100 $stop; end task spi_master_operation; input [7:0] data_out; integer i; begin $display($time,"ns: SPI master sends data %h",data_out); master_data_out=data_out; csn_master<=1'b0; if(!CLOCK_POLARITY) begin if(!CLOCK_PHASE) begin cnt<=3'h0; for (i = 7; i >= 0; i = i - 1) begin mosi_master<=SHIFT_DIRECTION ? master_data_out[cnt]:master_data_out[DATA_LENGTH-cnt-1]; #sclk_cycle; sclk_master<=#1 1'b1; master_data_in<={master_data_in[6:0],miso_master}; #sclk_cycle; sclk_master<=#1 1'b0; // at the falling edge of SCLK. cnt=cnt+1; end #2; csn_master<=1'b1; end else begin cnt<=3'h0; for (i = 7; i >= 0; i = i - 1) begin #sclk_cycle; sclk_master<=1'b1; // at the raising edge of SCLK. mosi_master<=SHIFT_DIRECTION ? master_data_out[cnt]:master_data_out[DATA_LENGTH-cnt-1]; cnt<=cnt+1; #sclk_cycle; sclk_master<=1'b0; master_data_in<={master_data_in[6:0],miso_master}; end #2; csn_master<=1'b1; end end else begin if(!CLOCK_PHASE) begin cnt<=3'h0; for (i = 7; i >= 0; i = i - 1) begin mosi_master<=SHIFT_DIRECTION ? master_data_out[cnt]:master_data_out[DATA_LENGTH-cnt-1]; #sclk_cycle; sclk_master<=1'b0; master_data_in<={master_data_in[6:0],miso_master}; #sclk_cycle; sclk_master<=1'b1; // at the raising edge of SCLK. cnt=cnt+1; end #2; csn_master<=1'b1; end else begin cnt<=3'h0; for (i = 7; i >= 0; i = i - 1) begin #sclk_cycle; sclk_master<=1'b0; // at the falling edge of SCLK. mosi_master<=SHIFT_DIRECTION ? master_data_out[cnt]:master_data_out[DATA_LENGTH-cnt-1]; cnt<=cnt+1; #sclk_cycle; sclk_master<=1'b1; master_data_in<={master_data_in[6:0],miso_master}; end #2; csn_master<=1'b1; end end $display($time,"ns: SPI master receive data %h",master_data_in); end endtask endmodule `timescale 1ns/1ps module back_end_device( CSn, DATA_IN, WR_RD, DATA_OUT, TX_RDY, RX_RDY, TX_ERR, RX_ERR, CLK, RST ); output CLK; output RST; output CSn; input [7:0] DATA_IN; output WR_RD; output [7:0] DATA_OUT; input TX_RDY; input RX_RDY; input TX_ERR; input RX_ERR; parameter clk_cycle= 10; reg CLK; reg RST; reg CSn; reg WR_RD; reg [7:0] DATA_OUT; integer i; always #(clk_cycle/2) CLK = ~CLK; initial begin RST<=1'b0; CLK<= 1'b0; CSn<=1'b1; WR_RD<=1'b1; DATA_OUT<=8'h00; i=0; #2; RST<=1'b1; #200; RST<=1'b0; while(i<3) begin @(posedge CLK) if(RX_RDY || TX_RDY) begin if(TX_RDY) begin CSn<=#1 1'b0; WR_RD<=#1 1'b0; DATA_OUT=#1 $random % 60; i=i+1; $display($time,"ns: Back end device send data %h",DATA_OUT); @(posedge CLK) CSn<=#1 1'b1; WR_RD<=#1 1'b1; end else if(RX_RDY) begin CSn<=#1 1'b0; WR_RD<=#1 1'b1; $display($time,"ns: Back end device receive data %h",DATA_IN); @(posedge CLK) CSn<=#1 1'b1; WR_RD<=#1 1'b1; end end end @(posedge CLK) CSn<=#1 1'b0; WR_RD<=#1 1'b0; DATA_OUT=#1 $random % 60; $display($time,"ns: Back end device send data %h",DATA_OUT); @(posedge CLK) CSn<=#1 1'b1; WR_RD<=#1 1'b1; end endmodule //--------------------------------EOF----------------------------------------- module BI_DIR (O,I0,IO,OE); input I0,OE; inout IO; output O; supply0 GND; supply1 VCC; reg IO0, O0; wire IO1; parameter PULL = "Off"; parameter OUTOPEN = "Off"; //assign O=O0; buf INSXQ1 (O,O0); //assign IO = IO0; //buf INSXQ2 (IO,IO0); //assign IO1 = IO; buf INSXQ3 (IO1,IO); bufif1 INSXQ2 (IO,IO0,OE); always @(IO1) begin if (PULL == "Off") case(IO1) 1'b0: O0 = 1'b0; 1'b1: O0 = 1'b1; 1'bz: O0 = 1'bx; 1'bx: O0 = 1'bx; endcase else if (PULL == "Up") case(IO1) 1'b0: O0 = 1'b0; 1'b1: O0 = 1'b1; 1'bz: O0 = 1'b1; endcase else if (PULL == "Down") case(IO1) 1'b0: O0 = 1'b0; 1'b1: O0 = 1'b1; 1'bz: O0 = 1'b0; endcase else if (PULL == "Hold") case(IO1) 1'b0: O0 = 1'b0; 1'b1: O0 = 1'b1; 1'bz: O0 = O0; endcase end always @(OE or I0) begin if (OE == 1'b0) IO0 = 1'bz; else if (OE == 1'b1) if (OUTOPEN == "Off") case(I0) 1'b0: IO0 = 1'b0; 1'b1: IO0 = 1'b1; 1'bz: IO0 = 1'bx; 1'bx: IO0 = 1'bx; endcase else if (OUTOPEN == "Drain" || OUTOPEN == "Collect") begin if (I0 == 1'b0) IO0 = 1'b0; else if (I0 == 1'b1) begin if (PULL == "Off") IO0 = 1'bz; else if (PULL == "Up") IO0 = 1'b1; else if (PULL == "Down") IO0 = 1'b0; else if (PULL == "Hold") IO0 = IO0; else IO0 = 1'bz; end else IO0 = 1'bx; end end specify (I0 => IO) = 0:0:0, 0:0:0; (OE => IO) = 0:0:0, 0:0:0; (IO => O) = 0:0:0, 0:0:0; endspecify endmodule PS могу поделиться описанием на VHDL... Quote Share this post Link to post Share on other sites More sharing options...
SergeyVas 1 May 10, 2015 Posted May 10, 2015 · Report post Благодарю за код, давайте если не жалко )). Есть какие отличия ? На верилоге вроде компактнее получается код, конечно у меня опыта не много поэтому утверждать не буду. Сейчас попробую протестировать на stm32f407 ep3c5e результат напишу. Значок решетка что означает? Немного не по теме, случайно не знаете в квартусе 13,1 есть автоформатирование кода ? Quote Share this post Link to post Share on other sites More sharing options...
Maverick_ 17 May 10, 2015 Posted May 10, 2015 · Report post Благодарю за код, давайте если не жалко )). Есть какие отличия ? описание на VHDL - функциональных отличий нет по сравнению с описанием на verilog. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity spi_slave is generic (DATA_LENGTH : integer:=8; SHIFT_DIRECTION: std_logic := '0'; CLOCK_POLARITY:std_logic:='0'; CLOCK_PHASE:std_logic:='0'); port ( CSn : in std_logic; DATA_IN : in std_logic_vector(7 downto 0); WR_RD : in std_logic; DATA_OUT : out std_logic_vector(7 downto 0); TX_RDY : out std_logic; RX_RDY : out std_logic; TX_ERR : out std_logic; RX_ERR : out std_logic; CLK_I : in std_logic; RST_I : in std_logic; MISO_SLAVE : out std_logic; MOSI_SLAVE : in std_logic; CSn_SLAVE : in std_logic; SCLK_SLAVE : in std_logic ); end; architecture arch of spi_slave is constant UDLY:time:=1 ns; signal latch_s_data:std_logic_vector(7 downto 0); signal reg_rxdata:std_logic_vector(DATA_LENGTH-1 downto 0); signal reg_txdata:std_logic_vector(DATA_LENGTH-1 downto 0); signal rx_shift_data:std_logic_vector(DATA_LENGTH-1 downto 0); signal reg_toe:std_logic; signal reg_roe:std_logic; signal reg_trdy:std_logic; signal reg_rrdy:std_logic; signal tx_done:std_logic; signal rx_done:std_logic; signal rx_done_flip1:std_logic; signal rx_done_flip2:std_logic; signal rx_done_flip3:std_logic; signal tx_done_flip1:std_logic; signal tx_done_flip2:std_logic; signal tx_done_flip3:std_logic; signal rx_data_cnt:std_logic_vector(5 downto 0); signal tx_data_cnt:std_logic_vector(5 downto 0); begin TX_RDY<=reg_trdy; RX_RDY<=reg_rrdy; TX_ERR<=reg_toe; RX_ERR<=reg_roe; DATA_OUT<=reg_rxdata; process(CLK_I,RST_I) begin if(RST_I='1') then latch_s_data <= (others => '0'); elsif rising_edge(CLK_I) then if (WR_RD='0' and CSn='0' and reg_trdy='1') then latch_s_data <=DATA_IN; end if; end if; end process; --Receive Data Register process(CLK_I,RST_I) begin if(RST_I='1') then reg_rxdata <=(others => '0'); elsif rising_edge(CLK_I) then if (rx_done_flip1='1' and rx_done_flip2='0') then reg_rxdata <= rx_shift_data; end if; end if; end process; --Transmit Data Register process(CLK_I,RST_I) begin if(RST_I='1') then reg_txdata <= (others => '0'); elsif rising_edge(CLK_I) then reg_txdata <= latch_s_data; end if; end process; -------------------------------For Rx data, -------------------sample at posedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 0 u1: if CLOCK_POLARITY='0' and CLOCK_PHASE='0' generate process(SCLK_SLAVE,RST_I) begin if (RST_I='1') then rx_shift_data <= (others => '0'); elsif rising_edge(SCLK_SLAVE) then if (CSn_SLAVE='0') then if (SHIFT_DIRECTION='1') then rx_shift_data <= MOSI_SLAVE & rx_shift_data(DATA_LENGTH-1 downto 1); else rx_shift_data <= rx_shift_data(DATA_LENGTH-2 downto 0) & MOSI_SLAVE; end if; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_data_cnt <= (others => '0'); elsif rising_edge(SCLK_SLAVE) then if (rx_data_cnt = DATA_LENGTH - 1) then rx_data_cnt <=(others => '0'); elsif (CSn_SLAVE='0') then rx_data_cnt <=rx_data_cnt + 1; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_done <= '0'; elsif rising_edge(SCLK_SLAVE) then if (rx_data_cnt = DATA_LENGTH - 1) then rx_done <= '1'; else rx_done <= '0'; end if; end if; end process; end generate; -------------------sample at negedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 1 u2: if CLOCK_POLARITY='0' and CLOCK_PHASE='1' generate --For Rx data, sample at negedge when CLOCK_PHASE is 1 process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_shift_data <= (others => '0'); elsif falling_edge(SCLK_SLAVE) then if (CSn_SLAVE='0') then if (SHIFT_DIRECTION='1') then rx_shift_data <= MOSI_SLAVE & rx_shift_data(DATA_LENGTH-1 downto 1); else rx_shift_data <= rx_shift_data(DATA_LENGTH-2 downto 0) & MOSI_SLAVE; end if; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_data_cnt <= (others => '0'); elsif falling_edge(SCLK_SLAVE) then if (rx_data_cnt = DATA_LENGTH - 1) then rx_data_cnt <=(others => '0'); elsif (CSn_SLAVE='0') then rx_data_cnt <=rx_data_cnt + 1; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_done <= '0'; elsif falling_edge(SCLK_SLAVE) then if (rx_data_cnt = DATA_LENGTH - 1) then rx_done <= '1'; else rx_done <= '0'; end if; end if; end process; end generate; -------------------sample at negedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 0 u3:if CLOCK_POLARITY='1' and CLOCK_PHASE='0' generate process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_shift_data <= (others => '0'); elsif falling_edge(SCLK_SLAVE) then if (CSn_SLAVE='0') then if (SHIFT_DIRECTION='1') then rx_shift_data <= MOSI_SLAVE & rx_shift_data(DATA_LENGTH-1 downto 1); else rx_shift_data <= rx_shift_data(DATA_LENGTH-2 downto 0) & MOSI_SLAVE; end if; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_data_cnt <= (others => '0'); elsif falling_edge(SCLK_SLAVE) then if (rx_data_cnt = DATA_LENGTH - 1) then rx_data_cnt <=(others => '0'); elsif (CSn_SLAVE='0') then rx_data_cnt <=rx_data_cnt + 1; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_done <= '0'; elsif falling_edge(SCLK_SLAVE) then if (rx_data_cnt = DATA_LENGTH - 1) then rx_done <= '1'; else rx_done <= '0'; end if; end if; end process; end generate; -------------------sample at posedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 1 u4: if CLOCK_POLARITY='1' and CLOCK_PHASE='1' generate --For Rx data, sample at negedge when CLOCK_PHASE is 1 process(SCLK_SLAVE,RST_I) begin if (RST_I='1') then rx_shift_data <= (others => '0'); elsif rising_edge(SCLK_SLAVE) then if (CSn_SLAVE='0') then if (SHIFT_DIRECTION='1') then rx_shift_data <= MOSI_SLAVE & rx_shift_data(DATA_LENGTH-1 downto 1); else rx_shift_data <= rx_shift_data(DATA_LENGTH-2 downto 0) & MOSI_SLAVE; end if; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_data_cnt <= (others => '0'); elsif rising_edge(SCLK_SLAVE) then if (rx_data_cnt = DATA_LENGTH - 1) then rx_data_cnt <=(others => '0'); elsif (CSn_SLAVE='0') then rx_data_cnt <=rx_data_cnt + 1; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then rx_done <= '0'; elsif rising_edge(SCLK_SLAVE) then if (rx_data_cnt = DATA_LENGTH - 1) then rx_done <= '1'; else rx_done <= '0'; end if; end if; end process; end generate; process(CLK_I,RST_I) begin if (RST_I='1') then rx_done_flip1 <= '0'; rx_done_flip2 <= '0'; rx_done_flip3 <= '0'; elsif rising_edge(CLK_I) then rx_done_flip1 <= rx_done; rx_done_flip2 <= rx_done_flip1; rx_done_flip3 <= rx_done_flip2; end if; end process; process(CLK_I,RST_I) begin if (RST_I='1') then reg_rrdy <= '0'; elsif rising_edge(CLK_I) then if (rx_done_flip2='1' and rx_done_flip3='0') then reg_rrdy <= '1'; elsif (WR_RD='1' and CSn='0') then reg_rrdy <= '0'; end if; end if; end process; process(CLK_I,RST_I) begin if (RST_I='1') then reg_roe <= '0'; elsif rising_edge(CLK_I) then if (rx_done_flip2='1' and rx_done_flip3='0' and reg_rrdy='1') then reg_roe <= '1'; elsif (WR_RD='1' and CSn='0') then reg_roe <= '0'; end if; end if; end process; ----------------------For Tx data, -------------------------------------update at negedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 0 u11: if CLOCK_POLARITY='0' and CLOCK_PHASE='0' generate process(reg_txdata,tx_data_cnt,CSn_SLAVE ) begin if (CSn_SLAVE='0') then if(SHIFT_DIRECTION='1') then MISO_SLAVE <= reg_txdata(conv_integer(tx_data_cnt)); else MISO_SLAVE <= reg_txdata(conv_integer(DATA_LENGTH-tx_data_cnt-1)); end if; else MISO_SLAVE<='Z'; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then tx_data_cnt <= (others => '0'); elsif falling_edge(SCLK_SLAVE) then if (tx_data_cnt = DATA_LENGTH - 1) then tx_data_cnt <= (others => '0'); elsif (CSn_SLAVE='0') then tx_data_cnt <= tx_data_cnt + 1; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then tx_done <='0'; elsif falling_edge(SCLK_SLAVE) then if (tx_data_cnt = DATA_LENGTH - 1) then tx_done <= '1'; else tx_done <= '0'; end if; end if; end process; end generate; -------------------------------------update at posedge when CLOCK_POLARITY=0 and CLOCK_PHASE is 1 u22: if CLOCK_POLARITY='0' and CLOCK_PHASE='1' generate process (SCLK_SLAVE) begin if rising_edge(CLK_I) then if (CSn_SLAVE='0') then if(SHIFT_DIRECTION='1') then MISO_SLAVE <= reg_txdata(conv_integer(tx_data_cnt)); else MISO_SLAVE <= reg_txdata(conv_integer(DATA_LENGTH-tx_data_cnt-1)); end if; else MISO_SLAVE<='Z'; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then tx_data_cnt <= (others => '0'); elsif rising_edge(SCLK_SLAVE) then if (tx_data_cnt = DATA_LENGTH - 1) then tx_data_cnt <= (others => '0'); elsif (CSn_SLAVE='0') then tx_data_cnt <= tx_data_cnt + 1; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then tx_done <= '0'; elsif rising_edge(SCLK_SLAVE) then if (tx_data_cnt = DATA_LENGTH - 1) then tx_done <= '1'; else tx_done <= '0'; end if; end if; end process; end generate; -------------------------------------update at posedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 0 u33: if CLOCK_POLARITY='1' and CLOCK_PHASE='0' generate process(reg_txdata,tx_data_cnt,CSn_SLAVE ) begin if (CSn_SLAVE='0') then if(SHIFT_DIRECTION='1') then MISO_SLAVE <= reg_txdata(conv_integer(tx_data_cnt)); else MISO_SLAVE <= reg_txdata(conv_integer(DATA_LENGTH-tx_data_cnt-1)); end if; else MISO_SLAVE<='Z'; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then tx_data_cnt <= (others => '0'); elsif rising_edge(SCLK_SLAVE) then if (tx_data_cnt = DATA_LENGTH - 1) then tx_data_cnt <= (others => '0'); elsif (CSn_SLAVE='0') then tx_data_cnt <= tx_data_cnt + 1; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then tx_done <= '0'; elsif rising_edge(SCLK_SLAVE) then if (tx_data_cnt = DATA_LENGTH - 1) then tx_done <= '1'; else tx_done <= '0'; end if; end if; end process; end generate; -------------------------------------update at negedge when CLOCK_POLARITY=1 and CLOCK_PHASE is 1 u44: if CLOCK_POLARITY='1' and CLOCK_PHASE='1' generate process (SCLK_SLAVE) begin if falling_edge(CLK_I) then if (CSn_SLAVE='0') then if(SHIFT_DIRECTION='1') then MISO_SLAVE <= reg_txdata(conv_integer(tx_data_cnt)); else MISO_SLAVE <= reg_txdata(conv_integer(DATA_LENGTH-tx_data_cnt-1)); end if; else MISO_SLAVE<='Z'; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then tx_data_cnt <= (others => '0'); elsif falling_edge(SCLK_SLAVE) then if (tx_data_cnt = DATA_LENGTH - 1) then tx_data_cnt <= (others => '0'); elsif (CSn_SLAVE='0') then tx_data_cnt <= tx_data_cnt + 1; end if; end if; end process; process(SCLK_SLAVE ,RST_I) begin if (RST_I='1') then tx_done <='0'; elsif falling_edge(SCLK_SLAVE) then if (tx_data_cnt = DATA_LENGTH - 1) then tx_done <= '1'; else tx_done <= '0'; end if; end if; end process; end generate; process(CLK_I,RST_I) begin if (RST_I='1') then tx_done_flip1 <= '0'; tx_done_flip2 <= '0'; tx_done_flip3 <= '0'; elsif rising_edge(CLK_I) then tx_done_flip1 <= tx_done; tx_done_flip2 <= tx_done_flip1; tx_done_flip3 <= tx_done_flip2; end if; end process; process(CLK_I,RST_I) begin if (RST_I='1') then reg_roe <= '0'; elsif rising_edge(CLK_I) then if (rx_done_flip2='1' and rx_done_flip3='0' and reg_rrdy='1') then reg_roe <= '1'; elsif (WR_RD='1' and CSn='0') then reg_roe <= '0'; end if; end if; end process; process(CLK_I,RST_I) begin if (RST_I='1') then reg_trdy <= '1'; elsif rising_edge(CLK_I) then if (WR_RD='0' and CSn='0') then reg_trdy <= '0'; elsif (tx_done_flip2='1' and tx_done_flip3='0') then reg_trdy <= '1'; end if; end if; end process; process(CLK_I,RST_I) begin if (RST_I='1') then reg_toe <= '0'; elsif rising_edge(CLK_I) then if(reg_trdy='0' and WR_RD='0' and CSn='0') then reg_toe <= '1'; elsif(WR_RD='0' and CSn='0') then reg_toe <= '0'; end if; end if; end process; end arch; тестбенч: library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity spi_master is port( sclk_master: out std_logic; csn_master: out std_logic; mosi_master: out std_logic; miso_master: in std_logic ); end; architecture arch_spi_master of spi_master is constant CLOCK_PHASE:std_logic:='0'; constant CLOCK_POLARITY:std_logic:='0'; constant SHIFT_DIRECTION:std_logic:='0'; constant DATA_LENGTH:integer:= 8; --signal master_data_in:std_logic_vector(7 downto 0); --signal master_data_out:std_logic_vector(7 downto 0); -- --signal cnt:std_logic_vector(2 downto 0); signal sclk_master_tmp: std_logic; signal csn_master_tmp: std_logic; signal mosi_master_tmp: std_logic; function slv4_xcha (inp: STD_LOGIC_VECTOR(3 downto 0)) return CHARACTER is variable result: character; begin case inp is when "0000" => result := '0'; when "0001" => result := '1'; when "0010" => result := '2'; when "0011" => result := '3'; when "0100" => result := '4'; when "0101" => result := '5'; when "0110" => result := '6'; when "0111" => result := '7'; when "1000" => result := '8'; when "1001" => result := '9'; when "1010" => result := 'a'; when "1011" => result := 'b'; when "1100" => result := 'c'; when "1101" => result := 'd'; when "1110" => result := 'e'; when "1111" => result := 'f'; when others => result := 'x'; end case; return result; end; function slv8_xstr (inp: STD_LOGIC_VECTOR(7 downto 0)) return STRING is variable result : string (1 to 2); begin result := slv4_xcha(inp(7 downto 4)) & slv4_xcha(inp(3 downto 0)); return result; end; procedure spi_master_operation (signal sclk_master_tmp : out std_logic; signal csn_master_tmp: out std_logic; signal mosi_master_tmp: out std_logic; signal miso_master: in std_logic; constant data_out:in STD_LOGIC_VECTOR(7 downto 0); constant CLOCK_PHASE : in std_logic; constant CLOCK_POLARITY : in std_logic; constant SHIFT_DIRECTION : in std_logic; constant DATA_LENGTH : in integer ) is variable master_data_in:std_logic_vector(7 downto 0):=(others => '0'); variable master_data_out:std_logic_vector(7 downto 0):=(others => '0'); variable cnt:integer; variable i:integer; variable sclk_cycle:time:=40 ns; begin csn_master_tmp<='1'; mosi_master_tmp<='0'; report "SPI master sends data " & slv8_xstr(data_out); master_data_out:=data_out; csn_master_tmp<='0'; if(CLOCK_POLARITY='0') then if(CLOCK_PHASE='0') then cnt:=0; for i in 7 downto 0 loop if(SHIFT_DIRECTION='1') then mosi_master_tmp<=master_data_out(cnt); else mosi_master_tmp<=master_data_out(DATA_LENGTH-cnt-1); end if; wait for sclk_cycle; sclk_master_tmp<='1'; master_data_in:=(master_data_in(6 downto 0) & miso_master); wait for sclk_cycle; sclk_master_tmp<='0'; cnt:=cnt+1; end loop; wait for 2 ns; csn_master_tmp<='1'; else cnt:=0; for i in 7 downto 0 loop wait for sclk_cycle; sclk_master_tmp<='1'; if(SHIFT_DIRECTION='1') then mosi_master_tmp<=master_data_out(cnt); else mosi_master_tmp<=master_data_out(DATA_LENGTH-cnt-1); end if; cnt:=cnt+1; wait for sclk_cycle; sclk_master_tmp<='0'; master_data_in:=(master_data_in(6 downto 0) & miso_master); end loop; wait for 2 ns; csn_master_tmp<='1'; end if; else if(CLOCK_PHASE='0') then cnt:=0; for i in 7 downto 0 loop if(SHIFT_DIRECTION='1') then mosi_master_tmp<=master_data_out(cnt); else mosi_master_tmp<=master_data_out(DATA_LENGTH-cnt-1); end if; wait for sclk_cycle; sclk_master_tmp<='0'; master_data_in:=(master_data_in(6 downto 0) & miso_master); wait for sclk_cycle; sclk_master_tmp<='1'; cnt:=cnt+1; end loop; wait for 2 ns; csn_master_tmp<='1'; else cnt:=0; for i in 7 downto 0 loop wait for sclk_cycle; sclk_master_tmp<='0'; if(SHIFT_DIRECTION='1') then mosi_master_tmp<=master_data_out(cnt); else mosi_master_tmp<=master_data_out(DATA_LENGTH-cnt-1); end if; cnt:=cnt+1; wait for sclk_cycle; sclk_master_tmp<='1'; master_data_in:=(master_data_in(6 downto 0) & miso_master); end loop; wait for 2 ns; csn_master_tmp<='1'; end if; end if; report "SPI master receive data " & slv8_xstr(master_data_in); end; begin sclk_master<=sclk_master_tmp; csn_master<=csn_master_tmp; mosi_master<=mosi_master_tmp; initial: process begin --wait for 1 ns; if(CLOCK_POLARITY='1') then sclk_master_tmp<='1' after 1 ns; else sclk_master_tmp<='0'; end if; wait for 306 ns; spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master, "01110011",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH); wait for 100 ns; spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master, "01000011",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH); wait for 104 ns; spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master, "00011001",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH); wait for 100 ns; spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master, "01010101",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH); wait for 100 ns; spi_master_operation(sclk_master_tmp,csn_master_tmp,mosi_master_tmp,miso_master, "10101010",CLOCK_PHASE,CLOCK_POLARITY,SHIFT_DIRECTION,DATA_LENGTH); wait for 100 ns; wait; end process; end arch_spi_master; ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity back_end_device is port( CSn: out std_logic; DATA_IN:in STD_LOGIC_VECTOR(7 downto 0); WR_RD: out std_logic; DATA_OUT:out STD_LOGIC_VECTOR(7 downto 0); TX_RDY: in std_logic; RX_RDY: in std_logic; TX_ERR: in std_logic; RX_ERR: in std_logic; CLK: out std_logic; RST: out std_logic ); end; architecture arch_back_end_device of back_end_device is constant clk_cycle:time:=5 ns; signal clk_temp:std_logic; signal data_out_temp:STD_LOGIC_VECTOR(7 downto 0); signal i:integer:=0; function slv4_xcha_r (inp: STD_LOGIC_VECTOR(3 downto 0)) return CHARACTER is variable result: character; begin case inp is when "0000" => result := '0'; when "0001" => result := '1'; when "0010" => result := '2'; when "0011" => result := '3'; when "0100" => result := '4'; when "0101" => result := '5'; when "0110" => result := '6'; when "0111" => result := '7'; when "1000" => result := '8'; when "1001" => result := '9'; when "1010" => result := 'a'; when "1011" => result := 'b'; when "1100" => result := 'c'; when "1101" => result := 'd'; when "1110" => result := 'e'; when "1111" => result := 'f'; when others => result := 'x'; end case; return result; end; function slv8_xstr_r (inp: STD_LOGIC_VECTOR(7 downto 0)) return STRING is variable result : string (1 to 2); begin result := slv4_xcha_r(inp(7 downto 4)) & slv4_xcha_r(inp(3 downto 0)); return result; end; begin clk_gen:process begin clk_temp<='0'; wait for clk_cycle; loop clk_temp<=not clk_temp; wait for clk_cycle; end loop; end process; CLK<=clk_temp; DATA_OUT<=data_out_temp; initial: process begin RST<='0'; CSn<='1'; WR_RD<='1'; data_out_temp<=(others => '0'); wait for 2 ns; RST<='1'; wait for 202 ns; RST<='0'; while(i<3) loop wait until clk_temp'event and clk_temp = '1'; if(RX_RDY='1' or TX_RDY='1') then if(TX_RDY='1') then CSn<='0' after 1 ns; WR_RD<='0' after 1 ns; if(i=0) then data_out_temp<="00001000" after 1 ns; elsif(i=1) then data_out_temp<="11101101" after 1 ns; elsif(i=2) then data_out_temp<="11011001" after 1 ns; end if; i<=i+1; wait for 1 ns; report "Back end device send data " & slv8_xstr_r(data_out_temp); wait until clk_temp'event and clk_temp = '1'; CSn<='1' after 1 ns; WR_RD<='1' after 1 ns; elsif(RX_RDY='1') then CSn<='0' after 1 ns; WR_RD<='1' after 1 ns; report "Back end device receive data " & slv8_xstr_r(DATA_IN); wait until clk_temp'event and clk_temp = '1'; CSn<='1' after 1 ns; WR_RD<='1' after 1 ns; end if; end if; end loop; while(i=3) loop wait until clk_temp'event and clk_temp = '1'; CSn<='0' after 1 ns; WR_RD<='0' after 1 ns; data_out_temp<="11100011" after 1 ns; wait for 1 ns; report "Back end device send data " & slv8_xstr_r(data_out_temp); wait until clk_temp'event and clk_temp = '1'; CSn<='1' after 1 ns; WR_RD<='1' after 1 ns; i<=4; end loop; wait for 2500 ns; --wait; end process; end arch_back_end_device; ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity spi_speripheral_tb is end spi_speripheral_tb; architecture arch_spi_speripheral_tb of spi_speripheral_tb is component spi_slave is --generic (DATA_LENGTH : integer:=8; -- SHIFT_DIRECTION: std_logic := '0'; -- CLOCK_POLARITY:std_logic:='0'; -- CLOCK_PHASE:std_logic:='0'); port ( CSn : in std_logic; DATA_IN : in std_logic_vector(7 downto 0); WR_RD : in std_logic; DATA_OUT : out std_logic_vector(7 downto 0); TX_RDY : out std_logic; RX_RDY : out std_logic; TX_ERR : out std_logic; RX_ERR : out std_logic; CLK_I : in std_logic; RST_I : in std_logic; MISO_SLAVE : out std_logic; MOSI_SLAVE : in std_logic; CSn_SLAVE : in std_logic; SCLK_SLAVE : in std_logic ); end component; component spi_master is port( sclk_master: out std_logic; csn_master: out std_logic; mosi_master: out std_logic; miso_master: in std_logic ); end component; component back_end_device is port( CSn: out std_logic; DATA_IN: in std_logic_vector(7 downto 0); WR_RD: out std_logic; DATA_OUT: out std_logic_vector(7 downto 0); TX_RDY: in std_logic; RX_RDY: in std_logic; TX_ERR: in std_logic; RX_ERR: in std_logic; CLK: out std_logic; RST: out std_logic ); end component; signal clk,rst:std_logic; signal mosi,csn_spi,sclk:std_logic; signal csn,wr_rd:std_logic; signal data_out:std_logic_vector(7 downto 0); signal miso:std_logic; signal tx_rdy,rx_rdy,tx_err,rx_err:std_logic; signal data_in:std_logic_vector(7 downto 0); begin spi_master_uut: spi_master port map( sclk_master=>sclk, csn_master=>csn_spi, mosi_master=>mosi, miso_master=>miso ); spi_slave_uut: spi_slave port map ( CSn=>csn, DATA_IN=>data_in, WR_RD=>wr_rd, DATA_OUT=>data_out, TX_RDY=>tx_rdy, RX_RDY=>rx_rdy, TX_ERR=>tx_err, RX_ERR=>rx_err, MISO_SLAVE=>miso, MOSI_SLAVE=>mosi, CSn_SLAVE=>csn_spi, SCLK_SLAVE=>sclk, CLK_I=>clk, RST_I=>rst ); back_end_device_uut: back_end_device port map( CSn=>csn, DATA_IN=>data_out, WR_RD=>wr_rd, DATA_OUT=>data_in, TX_RDY=>tx_rdy, RX_RDY=>rx_rdy, TX_ERR=>tx_err, RX_ERR=>rx_err, CLK=>clk, RST=>rst ); end arch_spi_speripheral_tb; Значок решетка что означает? #100; (verilog) = wait for 100 ns; (vhdl) PS у меня это описание работало в "железе" PS PS Мне не жалко, в надежде, что когда мне что-то понадобиться, то тоже люди тоже откликнуться и помогут... Quote Share this post Link to post Share on other sites More sharing options...
SergeyVas 1 May 10, 2015 Posted May 10, 2015 · Report post Благодарю вас. Эта задержка синтезируется или это только для симулятора? Quote Share this post Link to post Share on other sites More sharing options...
Maverick_ 17 May 10, 2015 Posted May 10, 2015 · Report post Благодарю вас. Эта задержка синтезируется или это только для симулятора? только для симулятора Quote Share this post Link to post Share on other sites More sharing options...
SergeyVas 1 May 10, 2015 Posted May 10, 2015 · Report post Понятно. Попробовал сразу все заработало)). Частоту подал на clck_in 200Мгц , правильно ? spi_slave spi_uc(csn,datain,wr_rd,dataout,tx_rdy,rx_rdy,tx_err,rx_err,CLOCK,RESET,SDOUT_UC,SD I_UC,CS_UC,SCLCK_UC); //--------------------------------------------------------------------------// //--------------------------------------------------------------------------// always@(posedge CLOCK ) begin if(RESET == 1) begin rxtxrdwr <= 8'd0; adressreg <= 8'd0; getadres <= 1'b0; csn <= 1'b1; wr_rd <= 1'b1; for(initdatafor = 0; initdatafor < 8'd255;initdatafor = initdatafor + 8'd1) begin dataINuc[initdatafor] <= 8'd0; dataOUTuc[initdatafor] <= 8'd0; end end else begin if(CS_UC == 1) begin getadres <= 1'b0; end if(tx_rdy || rx_rdy) begin if(tx_rdy) begin csn<= 1'b0; wr_rd<= 1'b0; rxtxrdwr <= 8'd1; if(getadres == 1) begin datain <= 20;//dataOUTuc[adressreg]; end else begin datain <= 8'd0; end end else if(rx_rdy) begin csn<= 1'b0; wr_rd<= 1'b1; rxtxrdwr <= 8'd2; if(getadres == 0) begin getadres <= 1'b1; adressreg <= dataout; end else begin dataINuc[adressreg] <= dataout; end end end else begin if(rxtxrdwr == 1)begin csn<= 1'b1; wr_rd<= 1'b1; rxtxrdwr <= 8'd0; end else if(rxtxrdwr == 2)begin csn<= 1'b1; wr_rd<= 1'b1; rxtxrdwr <= 8'd0; end end end end //--------------------------------------------------------------------------// Единственное почему то последний байт не доходит например отправляю с плис 20 в мк приходит 10 и тд. Микроконтроллер вначале пробовал с mems датчиком что бы проверить правильность настройки spi интерфейса в микроконтроллере. Quote Share this post Link to post Share on other sites More sharing options...
Maverick_ 17 May 10, 2015 Posted May 10, 2015 · Report post Единственное почему то последний байт не доходит например отправляю с плис 20 в мк приходит 10 и тд. Микроконтроллер вначале пробовал с mems датчиком что бы проверить правильность настройки spi интерфейса в микроконтроллере. режимы работы SPI в мк и в плис должны совпадать. совпадают? Для обозначения режимов работы интерфейса SPI принято следующее соглашений: режим 1 (CPOL = 0, CPHA = 0); режим 2 (CPOL = 0, CPHA = 1); режим 3 (CPOL = 1, CPHA = 0); режим 4 (CPOL = 1, CPHA = 1). Quote Share this post Link to post Share on other sites More sharing options...
SergeyVas 1 May 10, 2015 Posted May 10, 2015 · Report post Да совпадают RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); SPI_I2S_DeInit(SPI1); SPI_InitTypeDef spi1; SPI_StructInit(&spi1); spi1.SPI_Direction = SPI_Direction_2Lines_FullDuplex; spi1.SPI_Mode = SPI_Mode_Master; spi1.SPI_DataSize = SPI_DataSize_8b; spi1.SPI_CPOL = SPI_CPOL_Low; spi1.SPI_CPHA = SPI_CPHA_1Edge; spi1.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; spi1.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; spi1.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &spi1); SPI_Cmd(SPI1, ENABLE); SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set); Сделал осциллограмму если правильно смотрю из плис уходит 00001010 = 10 а должно быть 00010100. Дико извиняюсь, я напортачил не правильно настроил, все работает отлично. нужно было объявить это `define CLOCK_POLARITY `define CLOCK_PHASE Это настройки spi в stm32f407 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); SPI_I2S_DeInit(SPI1); SPI_InitTypeDef spi1; SPI_StructInit(&spi1); spi1.SPI_Direction = SPI_Direction_2Lines_FullDuplex; spi1.SPI_Mode = SPI_Mode_Master; spi1.SPI_DataSize = SPI_DataSize_8b; spi1.SPI_CPOL = SPI_CPOL_Low; spi1.SPI_CPHA = SPI_CPHA_1Edge; spi1.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; spi1.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; spi1.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &spi1); SPI_Cmd(SPI1, ENABLE); SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set); большое спасибо за помощь.)) Quote Share this post Link to post Share on other sites More sharing options...
johan 0 May 10, 2015 Posted May 10, 2015 · Report post только для симулятора Где-то читал (или сам сделал выводы :) ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика. Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ). Quote Share this post Link to post Share on other sites More sharing options...
Maverick_ 17 May 10, 2015 Posted May 10, 2015 · Report post Где-то читал (или сам сделал выводы :) ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика. Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ). а что оно дает для синтезатора? Quote Share this post Link to post Share on other sites More sharing options...
SergeyVas 1 May 10, 2015 Posted May 10, 2015 · Report post Можно как то синтезировать задержку? Иногда очень нужна, делаю либо сдвигом клока либо внешними цепочками. Quote Share this post Link to post Share on other sites More sharing options...
johan 0 May 10, 2015 Posted May 10, 2015 · Report post а что оно дает для синтезатора? Разумеется, ничего :) Или смысл только в том, что бы видеть в симуляции времянки более красивые и приближенные к реальности (появления значения на выходе триггера) "позже", чем edge клока? Или есть еще какие-то тонкости? :rolleyes: Можно как то синтезировать задержку? Иногда очень нужна, делаю либо сдвигом клока либо внешними цепочками. А для каких целей вам надо синтезировать задержку? Вы синхронный дизайн планируете делать? Quote Share this post Link to post Share on other sites More sharing options...
nepoch 0 May 20, 2015 Posted May 20, 2015 (edited) · Report post Где-то читал (или сам сделал выводы :) ), что трюк с #1 в чистом RTL-коде это не самая интуитивная/хорошая практика. Однако, ребята с opencores в низскоскоростных протоколах очень любят такое делать (например, I2C ). Зачем Вам задержка, если надо, чтобы у Вас часть проекта сработало через определенное время, используйте счетчик, это идеальный вариант Edited May 20, 2015 by Nepoch Quote Share this post Link to post Share on other sites More sharing options...
krux 9 May 20, 2015 Posted May 20, 2015 · Report post #1 сильно помогает "старой гвардии", привыкшей работать с такими конструкциями, во время симуляции видеть причинно-следственные связи, не заглядывая в код, а догадываясь по названиям сигналов. тем, кто учился писать RTL без #1 - его наличие/отсутствие не помогает никак, может только сбивает с толку. Quote Share this post Link to post Share on other sites More sharing options...