diff --git a/FRAM_Speicher/FRAM_Speicher-Modell.pdf b/FRAM_Speicher/FRAM_Speicher-Modell.pdf new file mode 100644 index 0000000..e7b896a Binary files /dev/null and b/FRAM_Speicher/FRAM_Speicher-Modell.pdf differ diff --git a/FRAM_Speicher/SPI_FRAM_Module.sv b/FRAM_Speicher/SPI_FRAM_Module.sv new file mode 100644 index 0000000..80e5dbd --- /dev/null +++ b/FRAM_Speicher/SPI_FRAM_Module.sv @@ -0,0 +1,180 @@ +module SPI_FRAM_Module( + input wire SI, + output wire SO, + input reg SCK, + input reg nCS, + output reg [7:0] opcode, //contains the command which controls the FRAM + output reg [23:0] addr, //contains current address that the memory is reading/writing + reg [7:0] mem_data [1023:0], //contains the memory data + reg [7:0] stat_reg, //stat_reg Bit 0 is 1 while waking up from Hibernate + reg hibernate); //if true, memory is in hibernation + + reg [2:0] bitcnt_rcv; //counts the bits of the current byte when reading from SPI + reg [2:0] bitcnt_snd; //counts sent bits for the current sent byte when writing to SPI + reg [2:0] bitcnt_mem_write; //counts bits written to memory for the current received byte + reg byte_received; //gets high when a full byte is received + reg [7:0] byte_data_received; //contains the data of last received byte + reg [3:0] byte_count; //counts the bytes of one message; is reset when a new message starts + reg [7:0] byte_data_sent; //contains the sent byte after transmission + reg send_data; //is set by opcode commands Read status register and Read memory when writing to SPI + reg write_to_memory; ////is set by opcode WRITE, when high, incoming Bits from SI are written to the memory at a specific address. + integer i; //countdown variable for status register read + + + initial begin //values are set to startup values of FRAM + opcode = 8'h00; + stat_reg = 8'b00100000; + addr = 24'h000000; + byte_count = 4'b0000; + byte_data_sent = 8'h00; + bitcnt_rcv = 3'b000; + bitcnt_snd = 3'b111; + bitcnt_mem_write = 3'b111; + byte_received = 1'b0; + byte_data_received = 8'b00000000; + send_data = 0; + write_to_memory = 0; + i = 8; + hibernate = 0; + $readmemh("memory.txt", mem_data); //initializes the memory with the contents of memory.txt + end + + //receive incoming Bits and organize them bytewise + always @(posedge SCK) begin + if (bitcnt_rcv == 3'b111) begin + byte_count <= byte_count + 4'b0001; + end + bitcnt_rcv <= bitcnt_rcv + 3'b001; + byte_data_received <= {byte_data_received[6:0], SI}; + + //when opcode WRÍTE is executed, the incoming bytes are written to memory + if (write_to_memory == 1 && nCS == 0) begin + mem_data[addr][bitcnt_mem_write+3'b001] = byte_data_received[0]; + + if(bitcnt_mem_write == 3'b000) begin + addr <= addr + 1; + bitcnt_mem_write <= 3'b111; + end + bitcnt_mem_write <= bitcnt_mem_write - 1; + end + end + always @(posedge SCK) byte_received <= (nCS == 0) && (bitcnt_rcv==3'b111); + + //TRANSMISSION + //Read out memory and write to SPI, starts at addr + always @(negedge SCK) begin + if(send_data == 1 && nCS == 0) + begin + byte_data_sent <= {byte_data_sent[6:0], mem_data[addr][bitcnt_snd]}; + bitcnt_snd <= bitcnt_snd - 1; + if (bitcnt_snd == 3'b000) begin + addr <= addr + 1; + bitcnt_snd <= 3'b111; + end + end + //write status register to SO when opcode RDSR is sent + else if (opcode == 8'h05 && nCS == 0 && i > 0) begin + byte_data_sent <= {byte_data_sent[6:0], stat_reg[i-1]}; + i = i - 1; + end + end + assign SO = byte_data_sent[0]; // MSB of the transmission is the lsb of byte_data_sent + + + +//the following block resets counters when a message has finished + always @ (posedge nCS) begin + if (opcode == 8'h06) begin //When WLEN opcode is executed, nCS needs to be reset. + //Since the message is not finished, no counters should be reset when executing WLEN + end + else if (opcode == 8'hb9 && nCS == 1) hibernate = 1; //When hibernation opcode 8'hb9 is sent, the device goes into hibernation + else begin + byte_count = 8'h00; + bitcnt_rcv = 3'b000; + bitcnt_snd = 3'b111; + bitcnt_mem_write = 3'b111; + byte_data_received = 8'h00; + end + send_data = 0; //disables sending data + write_to_memory = 0; // disables writing to memory + stat_reg[1] = 0; //reset WEL when writing to memory has finished + end + + //reset hibernate + always @ (negedge nCS) hibernate = 0; +//when a byte is received the FRAM-model reacts dependent on the number of bytes received in the current nCS low state, i. e. in one message. + + always @ (posedge byte_received) begin + case (byte_count) + //Byte 1 of message + 4'h1: begin //counting starts at 1, not 0. + case (byte_data_received) + 8'h03: //READ Op-code + opcode = 8'h03; + 8'h06: begin //WREN Op-Code + opcode = 8'h06; + #25; //wait one clock for nCS to get low + if (nCS == 1) stat_reg [1] = 1; //Set WEL Bit in Status Register after one clock cycle + end + //READ STATUS REGISTER Op-Code + 8'h05: opcode = 8'h05; + //HIBERNATE Op-Code + 8'hb9: begin + opcode = 8'hb9; + end + endcase + end + //Byte 2 of message + 4'h2: begin + case (byte_data_received) + //WRITE + 8'h02: //WRITE Op-code, only if WREN op-code was executed, WRITE Op-code is permitted. + if (opcode == 8'h06) opcode = 8'h02; + default: + //READ - get highest address byte + if (opcode == 8'h03) //upper four bits are not used and are always 0 + //the address is shifted in from right to left. Byte_data_received is the highest byte of the address + addr <= {4'b0000, 12'h000, byte_data_received}; + endcase + end + //Byte 3 of message + 4'h3: begin + case (byte_data_received) + default: + //READ - get middle address byte + if (opcode == 8'h03) //if opcode is read, the byte_data_received + //is the next byte of the address, followed by 1 byte + addr <= {4'b0000, 4'b0000, addr[7:0], byte_data_received}; + //WRITE - get highest address byte + else if (opcode == 8'h02 && stat_reg[1] == 1'b1) + addr <= {4'b0000, 12'h000, byte_data_received}; + endcase + end + //Byte 4 of message + 4'h4: begin + case (byte_data_received) + default: + //READ - get the lowest byte of the address + if (opcode == 8'h03) begin + addr <= {addr[15:0], byte_data_received}; + send_data = 1; //sets the flag which starts sending every bit out of SO at memory address "addr". + end + //WRITE - get middle address byte + else if (opcode == 8'h02 && stat_reg[1] == 1'b1) + addr <= {4'b000, 4'b0000, addr[7:0], byte_data_received}; + endcase + end + //Byte 5 of message + 4'h5: begin + case (byte_data_received) + default: + //WRITE - get lowest address byte and enable write_to_memory, the following bytes are data. + if (opcode == 8'h02 && stat_reg[1] == 1'b1) begin + addr <= {addr[15:0], byte_data_received}; + write_to_memory = 1; //set write to memory and wait one clock + end + endcase + end + endcase + end +endmodule \ No newline at end of file diff --git a/FRAM_Speicher/SPI_FRAM_tb.sv b/FRAM_Speicher/SPI_FRAM_tb.sv new file mode 100644 index 0000000..19a91bb --- /dev/null +++ b/FRAM_Speicher/SPI_FRAM_tb.sv @@ -0,0 +1,223 @@ +//This testbench verifies all implemented functions of the Module "SPI-FRAM-Module". That contains Read/Write to memory, Status register read and Hibernation. + +`timescale 1us/1ns + +module SPI_FRAM_tb; + reg SI, SO; //init all registers that are connected to the identical named ports of the FRAM-Module. + reg SCK, nCS; + reg [7:0] opcode; + reg [7:0] mem_data [1023:0] ; + reg [23:0] addr; //3 Byte Memory Address for test only the lower 13 are used (2^13 = 8192) + reg [7:0] stat_reg; + reg hibernate; + SPI_FRAM_Module dut(.nCS(nCS), .SCK(SCK), .SI(SI), .SO(SO), .opcode(opcode), .addr(addr), .mem_data(mem_data),. stat_reg(stat_reg), .hibernate(hibernate)); + + + initial begin //values are set to startup values of FRAM + nCS = 1'b1; + SCK = 1'b0; + end + + //generate 40MHz clock + always @(nCS) begin + while (nCS == 0) #12.5 SCK = ~SCK; + if (nCS == 1) SCK = 0; + end + + initial begin + $dumpfile("dump.vcd"); + $dumpvars; + + SI = 0; + nCS = 0; + + //TEST READ MEMORY + // Sends 8'b00000011 as Read Opcode + SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 1; + #25 SI = 1; + #25; assert (opcode == 8'h03); + + //first byte (only the highest 4 bits are used) of 20-Bit address + SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + + //second Byte of 20-Bit address + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + //third byte of address + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 1; + #25 SI = 1; + + //read one Byte (200clocks/25 clocks per bit = 8 bit) + #25 assert (addr == 24'h000003); //check address + //check for correct writing to SPI out of memory + #25 assert (SO == 0); + #25 assert (SO == 0); + #25 assert (SO == 1); + #25 assert (SO == 1); + #25 assert (SO == 0); + #25 assert (SO == 0); + #25 assert (SO == 1); + #25 assert (SO == 1); + + //Message is finished, so nCS is not active + nCS = 1; + #50 nCS = 0; //enable nCS after 50 clock cycles for next test + + //TEST WRITE MEMORY + //send WREN opcode to set WEL bit + SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 1; + #25 SI = 1; + #25 SI = 0; + + //to set WEL-bit, nCS needs to be high (inactive) + #25 nCS = 1; + #25 assert (opcode == 8'h06); //check if the WREN-opcode was recognized + #25 nCS = 0; + assert (stat_reg[1] == 1'b1); //check if WEL-Bit is set + + //after stat_reg is set, the next opcode WRITE can be received + SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 1; + #25 SI = 0; + #25 assert (opcode == 8'h02); + //the next 3 following Bytes are the address. the upper 4 Bits are cut off. + //Highest Byte 1 + SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + //second address Byte + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + //third address Byte + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 1; + #25 SI = 0; + #25 assert (addr == 24'h000002); + + //the following SI is written to the memory at the address "addr" + //one Byte is written + assert (mem_data[24'h000002] == 8'hFF); //check data at addr before to see difference after writing to it + SI = 0; + #25 SI = 1; + #25 SI = 1; + #25 SI = 1; + #25 SI = 0; + #25 SI = 0; + #25 SI = 1; + #25 SI = 0; + //Message is finished, so nCS is not active + #12.5 nCS = 1; + + #50 nCS = 0; //enable nCS after 50 clock cycles for next test + assert (mem_data[24'h000002] == 8'h72); //check if the operation wrote the correct data to the correct address; 8'h72 is used because it is not symmetrical and the first and last bit are 0. Since the memory (see memory.txt) has 8'hFF written to all other bytes it is easily recognized if a 0 was accidentally written elsewhere. +assert (mem_data[24'h000001] == 8'hFF); + + //test to see if write accidentally wrote in the next memory byte + assert (mem_data[24'h000003] == 8'h33); + + + //test opcode read status register + SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 0; + #25 SI = 1; + #25 SI = 0; + #25 SI = 1; + + #25 assert (opcode == 8'h05); + + //Test correct writing to SPI of status register (stat_reg = 8'h20) + #25 assert (SO == 0); + #25 assert (SO == 0); + #25 assert (SO == 1); + #25 assert (SO == 0); + #25 assert (SO == 0); + #25 assert (SO == 0); + #25 assert (SO == 0); + #25 assert (SO == 0); + + + assert (stat_reg == 8'h20); + + //Message is finished, so nCS is not active + #50 nCS = 1; + + #25 nCS = 0; //enable nCS and SCK after 50 clock cycles for next test + + + + //TEST HIBERNATE MODE + //send opcode + SI = 1; + #25 SI = 0; + #25 SI = 1; + #25 SI = 1; + #25 SI = 1; + #25 SI = 0; + #25 SI = 0; + #25 SI = 1; + #25 assert (opcode == 8'hb9); + + + //Message is finished, so nCS is not active + //hibernate is set on the rising edge of nCS and reset at the falling edge of nCS + nCS = 1; + #25 assert (hibernate == 1); + #500 nCS = 0; //enable nCS and SCK after 50 clock cycles for next test + #25 assert (hibernate == 0); + + end +endmodule \ No newline at end of file diff --git a/FRAM_Speicher/memory.txt b/FRAM_Speicher/memory.txt new file mode 100644 index 0000000..8ffe6b7 --- /dev/null +++ b/FRAM_Speicher/memory.txt @@ -0,0 +1,1024 @@ +FF +FF +FF +33 +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF +FF \ No newline at end of file