0% found this document useful (0 votes)
3 views15 pages

SPI Module for Data Transmission

code module spi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views15 pages

SPI Module for Data Transmission

code module spi
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Module spi :

module spi (

input clk, // Clock 27 MHz

input rst_n, // Reset active low

input spi_start, // Start transmission

input [15:0] data_tx, // Data to send (2 bytes)

input miso, // Master In Slave Out

output reg [7:0] data_rx, // Data received (2nd byte)

output reg sclk, // Clock SPI (f = 27 / 8 = 3.375 MHz)

output reg mosi, // Master Out Slave In

output reg cs_n, // Chip Select (active low)

output spi_busy // Busy flag

);

reg [3:0] bit_cnt; // Bit counter (cần đủ để đếm đến 16)

reg [3:0] cnt; // Counter for sclk generation

reg [15:0] shift_reg; // Shift register

reg [1:0] state; // FSM state

reg miso_sync; // Synchronize MISO

localparam IDLE = 2'b00,

LOAD = 2'b01,

TRANSFER = 2'b10,

DONE = 2'b11;

localparam CLK_DIV_HALF = 4; // Hệ số chia / 2 (8 / 2 = 4)

assign spi_busy = (state != IDLE);

always @(posedge clk) begin

miso_sync <= miso;


end

always @(posedge clk or negedge rst_n) begin

if (!rst_n) begin

state <= IDLE;

sclk <= 0;

cs_n <= 1;

mosi <= 0;

data_rx <= 0;

bit_cnt <= 0;

cnt <= 0;

shift_reg <= 0;

end else begin

case (state)

IDLE: begin

cs_n <= 1;

sclk <= 0;

if (spi_start) begin

state <= LOAD;

shift_reg <= data_tx;

end

end

LOAD: begin

cs_n <= 0;

state <= TRANSFER;

bit_cnt <= 16;

cnt <= 0;

end

TRANSFER: begin

if (bit_cnt > 0) begin

if (cnt < CLK_DIV_HALF - 1) begin


cnt <= cnt + 1;

end else begin

cnt <= 0;

if (bit_cnt == 16) begin

mosi <= shift_reg[15];

end

sclk <= ~sclk; // Đảo trạng thái sclk mỗi CLK_DIV_HALF xung clock hệ thống

if (sclk == 1) begin // Dịch dữ liệu khi sclk lên

shift_reg <= {shift_reg[14:0], miso_sync};

bit_cnt <= bit_cnt - 1;

end

end

end else begin

state <= DONE;

sclk <= 0;

cs_n <= 1;

data_rx <= shift_reg[7:0];

end

end

DONE: begin

state <= IDLE;

end

default: state <= IDLE;

endcase

end

end

endmodule

module rc522:

module rc522 (

input clk, // 100 MHz (system clock)

input rst_n, // active low reset


input miso, // SPI MISO

output sclk, // SPI clock (3.125 MHz)

output mosi, // SPI MOSI

output cs_n, // SPI chip select (active low)

output reg rst, // RC522 reset

output reg [31:0] UID, // UID value

output reg card_OK, // card is present

output RGB1_B,

output RGB1_G,

output RGB1_R,

output RGB2_B,

output RGB2_G,

output RGB2_R

);

localparam CommandReg = 8'h01 << 1, // starts and stops command execution

ComIEnReg = 8'h02 << 1, // enable and disable interrupt request control bits

DivIEnReg = 8'h03 << 1, // enable and disable interrupt request control bits

ComIrqReg = 8'h04 << 1, // interrupt request bits

DivIrqReg = 8'h05 << 1, // interrupt request bits

ErrorReg = 8'h06 << 1, // error bits showing the error status of the last command
executed

Status1Reg = 8'h07 << 1, // communication status bits

Status2Reg = 8'h08 << 1, // receiver and transmitter status bits

FIFODataReg = 8'h09 << 1, // input and output of 64 byte FIFO buffer

FIFOLevelReg = 8'h0A << 1, // number of bytes stored in the FIFO buffer

WaterLevelReg = 8'h0B << 1, // level for FIFO underflow and overflow warning

ControlReg = 8'h0C << 1, // miscellaneous control registers

BitFramingReg = 8'h0D << 1, // adjustments for bit-oriented frames

CollReg = 8'h0E << 1, // bit position of the first bit-collision detected on the RF
interface

// 8'h0F // reserved for future use


// Page 1: Command

// 8'h10 // reserved for future use

ModeReg = 8'h11 << 1, // defines general modes for transmitting and receiving

TxModeReg = 8'h12 << 1, // defines transmission data rate and framing

RxModeReg = 8'h13 << 1, // defines reception data rate and framing

TxControlReg = 8'h14 << 1, // controls the logical behavior of the antenna driver pins
TX1 and TX2

TxASKReg = 8'h15 << 1, // controls the setting of the transmission modulation

TxSelReg = 8'h16 << 1, // selects the internal sources for the antenna driver

RxSelReg = 8'h17 << 1, // selects internal receiver settings

RxThresholdReg = 8'h18 << 1, // selects thresholds for the bit decoder

DemodReg = 8'h19 << 1, // defines demodulator settings

// 8'h1A // reserved for future use

// 8'h1B // reserved for future use

MfTxReg = 8'h1C << 1, // controls some MIFARE communication transmit


parameters

MfRxReg = 8'h1D << 1, // controls some MIFARE communication receive


parameters

// 8'h1E // reserved for future use

SerialSpeedReg = 8'h1F << 1, // selects the speed of the serial UART interface

// Page 2: Configuration

// 8'h20 // reserved for future use

CRCResultRegH = 8'h21 << 1, // shows the MSB and LSB values of the CRC calculation

CRCResultRegL = 8'h22 << 1,

// 8'h23 // reserved for future use

ModWidthReg = 8'h24 << 1, // controls the ModWidth setting?

// 8'h25 // reserved for future use

RFCfgReg = 8'h26 << 1, // configures the receiver gain

GsNReg = 8'h27 << 1, // selects the conductance of the antenna driver pins TX1
and TX2 for modulation
CWGsPReg = 8'h28 << 1, // defines the conductance of the p-driver output during
periods of no modulation

ModGsPReg = 8'h29 << 1, // defines the conductance of the p-driver output during
periods of modulation

TModeReg = 8'h2A << 1, // defines settings for the internal timer

TPrescalerReg = 8'h2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits
are in TModeReg.

TReloadRegH = 8'h2C << 1, // defines the 16-bit timer reload value

TReloadRegL = 8'h2D << 1,

TCounterValueRegH = 8'h2E << 1, // shows the 16-bit timer value

TCounterValueRegL = 8'h2F << 1,

// Page 3: Test Registers

// 8'h30 // reserved for future use

TestSel1Reg = 8'h31 << 1, // general test signal configuration

TestSel2Reg = 8'h32 << 1, // general test signal configuration

TestPinEnReg = 8'h33 << 1, // enables pin output driver on pins D1 to D7

TestPinValueReg = 8'h34 << 1, // defines the values for D1 to D7 when it is used as an


I/O bus

TestBusReg = 8'h35 << 1, // shows the status of the internal test bus

AutoTestReg = 8'h36 << 1, // controls the digital self-test

VersionReg = 8'h37 << 1, // shows the software version

AnalogTestReg = 8'h38 << 1, // controls the pins AUX1 and AUX2

TestDAC1Reg = 8'h39 << 1, // defines the test value for TestDAC1

TestDAC2Reg = 8'h3A << 1, // defines the test value for TestDAC2

TestADCReg = 8'h3B << 1; // shows the value of ADC I and Q channels

// 8'h3C // reserved for production tests

// 8'h3D // reserved for production tests

// 8'h3E // reserved for production tests

// 8'h3F // reserved for production tests

localparam PCD_Idle = 8'h00, // no action, cancels current command execution


PCD_Mem = 8'h01, // stores 25 bytes into the internal buffer

PCD_GenerateRandomID = 8'h02, // generates a 10-byte random ID number

PCD_CalcCRC = 8'h03, // activates the CRC coprocessor or performs a self-test

PCD_Transmit = 8'h04, // transmits data from the FIFO buffer

PCD_NoCmdChange = 8'h07, // no command change, can be used to modify the


CommandReg register bits without affecting the command, for example, the PowerDown bit

PCD_Receive = 8'h08, // activates the receiver circuits

PCD_Transceive = 8'h0C, // transmits data from FIFO buffer to antenna and


automatically activates the receiver after transmission

PCD_MFAuthent = 8'h0E, // performs the MIFARE standard authentication as a


reader

PCD_SoftReset = 8'h0F; // resets the MFRC522

localparam PICC_CMD_REQA = 8'h26, // REQuest command, Type A. Invites PICCs in


state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.

PICC_CMD_WUPA = 8'h52, // Wake-UP command, Type A. Invites PICCs in state


IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.

PICC_CMD_CT = 8'h88, // Cascade Tag. Not really a command, but used during
anti collision.

PICC_CMD_SEL_CL1 = 8'h93, // Anti collision/Select, Cascade Level 1

PICC_CMD_SEL_CL2 = 8'h95, // Anti collision/Select, Cascade Level 2

PICC_CMD_SEL_CL3 = 8'h97, // Anti collision/Select, Cascade Level 3

PICC_CMD_HLTA = 8'h50, // HaLT command, Type A. Instructs an ACTIVE PICC to


go to state HALT.

PICC_CMD_RATS = 8'hE0, // Request command for Answer To Reset.

// The commands used for MIFARE Classic (from


[Link] Section 9)

// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to


read/write/modify the blocks on the sector.

// The read/write commands can also be used for MIFARE Ultralight.

PICC_CMD_MF_AUTH_KEY_A = 8'h60, // Perform authentication with Key A

PICC_CMD_MF_AUTH_KEY_B = 8'h61, // Perform authentication with Key B

PICC_CMD_MF_READ = 8'h30, // Reads one 16 byte block from the authenticated


sector of the PICC. Also used for MIFARE Ultralight.
PICC_CMD_MF_WRITE = 8'hA0, // Writes one 16 byte block to the authenticated
sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.

PICC_CMD_MF_DECREMENT = 8'hC0, // Decrements the contents of a block and


stores the result in the internal data register.

PICC_CMD_MF_INCREMENT = 8'hC1, // Increments the contents of a block and stores


the result in the internal data register.

PICC_CMD_MF_RESTORE = 8'hC2, // Reads the contents of a block into the internal


data register.

PICC_CMD_MF_TRANSFER = 8'hB0, // Writes the contents of the internal data register


to a block.

// The commands used for MIFARE Ultralight (from


[Link] Section 8.6)

// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE


Ultralight.

PICC_CMD_UL_WRITE = 8'hA2; // Writes one 4 byte page to the PICC.

localparam uid_1 = 32'h2359A629; // valid card UID

localparam uid_2 = 32'hF3F3A414; // invalid card UID

reg [5:0] LED_state;

assign RGB1_B = LED_state[5];

assign RGB1_G = LED_state[4];

assign RGB1_R = LED_state[3];

assign RGB2_B = LED_state[2];

assign RGB2_G = LED_state[1];

assign RGB2_R = LED_state[0];

// SPI module instance

reg spi_start;

reg [15:0] data_tx;

wire [7:0] data_rx;

wire spi_busy;
reg new_card;

spi spi_module (

.clk (clk),

.rst_n (rst_n),

.spi_start (spi_start),

.data_tx (data_tx),

.data_rx (data_rx),

.sclk (sclk),

.mosi (mosi),

.miso (miso),

.cs_n (cs_n),

.spi_busy (spi_busy)

);

reg [31:0] cnt;

reg [2:0] cnt_2;

reg [7:0] FIFOLevelReg_Value;

reg [7:0] BCC;

// Main FSM state machine state

reg [9:0] instr_step;

// Task for SPI write operation (used in the main FSM).

task spi_write;

input [7:0] reg_addr;

input [7:0] value;

begin

spi_start <= 1;

data_tx <= {reg_addr, value};

end
endtask

// Task for SPI read operation (used in the main FSM).

task spi_read;

input [7:0] reg_addr;

begin

spi_start <= 1;

data_tx <= {reg_addr | 8'h80, 8'h00};

end

endtask

always @(posedge clk or negedge rst_n) begin

if (~rst_n) begin

instr_step <= 0;

spi_start <= 0;

rst <= 1;

UID <= 32'h00000000;

LED_state <= 6'b000000;

cnt <= 0;

cnt_2 <= 0;

new_card <= 0;

card_OK <= 0;

end else begin

if (&cnt[4:0] && spi_start) // pull spi_start down after 2^5 * 10ns = 320ns

spi_start <= 0;

if (&cnt[16:0] && ~spi_busy) begin // 1 step = 2^16 * 10ns # 1.3ms

case (instr_step)

1: rst <= 0; // Hard Reset, 1.3ms

2: rst <= 1; // wait hard reset to complete, 50ms


// initialize RC522 after reset

50: spi_write (TxModeReg, 8'h00); // reset transmit baud rates 106kBd

51: spi_write (RxModeReg, 8'h00); // reset receive baud rates 106kBd

52: spi_write (ModWidthReg, 8'h26); // reset ModWidthReg

53: spi_write (TModeReg, 8'h80); // setup timeout

54: spi_write (TPrescalerReg, 8'hA9);

55: spi_write (TReloadRegH, 8'h03);

56: spi_write (TReloadRegL, 8'hE8);

57: spi_write (TxASKReg, 8'h40); // default 0x00. Force a 100% ASK


modulation

58: spi_write (ModeReg, 8'h3D); // default 0x3F. Set the preset value for the
CRC coprocessor for the CalcCRC command to 0x6363

59: spi_read (TxControlReg);

60: spi_write (TxControlReg, 8'h03 | data_rx); // enable the antenna driver pins TX1
and TX2 (they were disabled by the reset)

// check if new card is present

62: spi_write (CommandReg, PCD_Idle); // stop any active command

63: spi_write (ComIrqReg, 8'h7F); // clear all 7 interrupt request bits

64: spi_write (FIFOLevelReg, 8'h80); // flush the FIFO buffer

65: spi_write (FIFODataReg, PICC_CMD_REQA); // send REQA command

66: spi_write (BitFramingReg, 8'h07); // bit adjustments: 7 bit frame

67: spi_write (CommandReg, PCD_Transceive); // start the transceive command

68: spi_write (BitFramingReg, 8'h87); // StartSend = 1, start the transmission of


data

// read ComIrqReg to check if card has responded

70: spi_read (ComIrqReg); // read the ComIrqReg

71: if (data_rx[5]) // ComIrqReg[5]: RxIRq -> set if received data is


detected

new_card <= 1;
// send SELECT command to the card

73: spi_write (FIFOLevelReg, 8'h80); // flush the FIFO buffer

74: spi_write (FIFODataReg, PICC_CMD_SEL_CL1); // send SELECT command: 0x93,


0x20

75: spi_write (FIFODataReg, 8'h20);

76: spi_write (BitFramingReg, 8'h00); // reset bit adjustments

77: spi_write (CommandReg, PCD_Transceive); // start the transceive command

78: spi_write (BitFramingReg, 8'h80); // StartSend = 1, start the transmission of


data

// read UID and BCC.

// RFID card will response with 5 bytes: UID_0, UID_1, UID_2, UID_3, BCC (saved in FIFO
buffer)

// BCC = UID_0 ^ UID_1 ^ UID_2 ^ UID_3 (for error checking)

83: spi_read (FIFOLevelReg);

84: FIFOLevelReg_Value <= data_rx;

85: spi_read (FIFODataReg);

86: UID[31:24] <= data_rx;

87: spi_read (FIFODataReg);

88: UID[23:16] <= data_rx;

89: spi_read (FIFODataReg);

90: UID[15:8] <= data_rx;

91: spi_read (FIFODataReg);

92: UID[7:0] <= data_rx;

93: spi_read (FIFODataReg);

94: BCC <= data_rx;

95: new_card <= 0;

// check if UID is correct

96: if ((FIFOLevelReg_Value == 5) && (BCC == (UID[31:24] ^ UID[23:16] ^ UID[15:8] ^


UID[7:0])))

card_OK <= 1;
97: card_OK <= 0;

// flash LEDs

98: LED_state <= (UID == uid_1) ? 6'b111000 : (UID == uid_2) ? 6'b000111 : 6'b000000;

500:LED_state <= 6'b000000;

endcase

// FSM state transitions

if (instr_step == 72 && ~new_card) begin

cnt_2 <= cnt_2 + 1;

if (cnt_2 == 5) begin

cnt_2 <= 0;

instr_step <= 62;

end else

instr_step <= 70;

end else if (instr_step == 501)

instr_step <= 62;

else

instr_step <= instr_step + 1;

end

cnt <= cnt + 1;

end

end

endmodule

module top :

module top(

input clk,

input rst_n,
input miso,

output sclk,

output mosi,

output cs_n,

output rst,

output RGB1_B,

output RGB1_G,

output RGB1_R,

output RGB2_B,

output RGB2_G,

output RGB2_R

);

wire card_OK;

wire [31:0] UID;

rc522 rc522_inst(

.clk (clk),

.rst_n (rst_n),

.miso (miso),

.sclk (sclk),

.mosi (mosi),

.cs_n (cs_n),

.rst (rst),

.UID (UID),

.card_OK (card_OK),

.RGB1_B (RGB1_B),

.RGB1_G (RGB1_G),

.RGB1_R (RGB1_R),

.RGB2_B (RGB2_B),

.RGB2_G (RGB2_G),
.RGB2_R (RGB2_R)

);

endmodule

You might also like