hello! I'm Ryosu, a new engineer on the Lattice team.

 

Last time, we examined what kind of signals are used for SPI communication and what their waveforms are.

 

This time, I would like to actually perform RTL design for SPI communication in Verilog-HDL!

 

For those of you who are visiting this blog for the first time, let me give you a brief overview of this blog.

In this blog, I will introduce the process of making a temperature sensor that controls 7 segments with FPGA.

(If you're interested, I'll attach links to other episodes below, so please take a look!)

Consider an SPI communication module

Last time, I was able to understand what kind of waveform should be sent by investigating SPI communication.

 

From this time onwards, we will actually do the RTL design, but first of all, I would like to consider the configuration of the entire module!

  

Please check the following easy-to-use FPGAfor information on the used to realize this specification this time!

Overall configuration of SPI communication module

When considering the configuration of the entire SPI communication module, we will divide the functions.

 

The functions of the SPI module created this time are roughly divided into four as shown in the table below. Also, although it is rough, I tried to imagine the overall composition!

Module name explanation
spi_state control the state
counter Count 16bit and wait time
spi_tx Send command to temperature sensor
spi_rx Receive output from temperature sensor

 

Try it now! I think that is important, but when debugging later, don't forget "What was the intention of the design?"

From the general framework, I would like to think of it as the role in the TOP module → the role (function) in each module → the syntax required in each module.

The roles in the TOP module are roughly the four shown in the table above.

 

The spi_state module is the most important module for realizing this SPI communication.

A module that controls the state of the SPI.

The counter module, as the name suggests, is a module that counts when necessary.

 

The spi_tx/rx module looks at the state of spi_state to determine transmission/reception.

 

The RESET of each module is common, and the input clock is the 2.08MHz output from the internal oscillator.

Use a 500kHz clock divided by 1/4 using Clock Devieder. (Internal Oscillators and Deviders are also explained in later chapters.)

Consider the details of each module

From here, I would like to perform the detailed design of each module.

 

We will think about what roles and syntax are necessary to reproduce waveforms!

spi_state module details

First, the spi_sate module.

This spi_state module is a module that controls the state of SPI communication. Break down the operation of SPI communication so that one operation is in one state.
Since other modules operate according to each decomposed state, this module becomes the core of SPI communication.

  

It's like a human brain!

For example, state 1 is the state that forces CS = Low.
State 2 is broken down into one action, like the state sending a command to the temperature sensor.

 

As a caution, if you make it too detailed, the source code will become long, which may cause mistakes and make debugging difficult.
So, this time, I decided to divide it by the fineness of 1 state for 1 operation.

 

The detailed functions and states of spi_state.v are summarized below.

 

 

Is it okay to have several states with the same state and different transition conditions? I think you need to think a little
This time, I would like to proceed with the design with this state and transition conditions.

 

This state machine module implements the following three functions:

 

① State management

 
(2) Flag output that tells the state of each state

 
③SCLK output

 

In this article, the source code of each module is published!

If you are interested, click it and it will be displayed in another window.

(I would appreciate it if you could take a look at the source code that the amateurs thought with all their might.)

 

  

I will explain the points for realizing the function of this spi_state module.

① State management

→ State management is performed using the CASE statement. Each state is parameterized to facilitate debugging, and the state (CASE) advances under certain conditions.

If there is an error or if it has reached the final state, it will move to the first state.

The state I created has a lot of overlapping states, so maybe it can be simplified a little more? I think. . .


(2) Flag output that tells the state of each state

The →flag uses the selector syntax as an enable signal. High output when certain conditions are met, and low output otherwise.

 
③SCLK output

→SCLK outputs High/Low using a counter circuit. Runs the counter and outputs SCLK when in a certain state.

Details of the counter module

Next is the counter module.

 

This module counts SCLK 16 clocks and Wait 250ms.

 

The detailed functions of counter.v are as follows.

This module realizes the function to rotate the counter depending on the state of the enable signal from spi_state (when the enable signal is High).

 

The count is sent to spi_state, and when it counts up to a certain number, the state of spi_state transitions, and at the same time the enable signal becomes Low.

 

The counter is reset when the enable signal goes low.

spi_tx module details

This spi_tx.v is a module that sends commands to the temperature sensor.

 

Detailed functions of spi_tx.v are as follows.

This module implements the following three functions. In addition, it operates by the enable signal of the spi_state module.

  

(1) Set the command in the register in the state before sending

  

(2) Operate the shift register circuit in the transmission state

 

(3) Perform parallel-to-serial conversion and send a command to the temperature sensor

 

How to write a shift register? At first glance it seems difficult, but it is surprisingly easy to describe!

I will explain the points to realize the function of this module.

 

(1) Set the command in the register in the state before sending

→Use the register to set your intended command or ALL 0/1.

(2) Operate the shift register circuit in the transmission state

(3) Perform parallel-to-serial conversion and send a command to the temperature sensor

→Could you check the source code?

The data set in the previous state can be parallel-to-serial converted with a shift register with a single line description like "addr[15:1] <= addr[14:0];"!

 

The description of the state machine module was pretty messy, so I'm impressed that I can write it cleanly this time. .

spi_rx module details

This spi_rx.v will be the module that receives the output data from the temperature sensor.

 

The detailed functions of spi_rx.v are as follows!

This module implements the following three functions. In addition, it operates by the enable signal of the spi_state module.

 

(1) Operate the shift register in the state of receiving data

 

②Once all the data is received, confirm the data

 

(3) Send data to the next module

 

Unlike the previous spi_tx module, serial-parallel conversion is performed next. It's also easy to write!

 

I will explain the points to realize the function of this module.

 

(1) Operate the shift register in the state of receiving data

→ The description of parallel-serial conversion and the description method are slightly different, but I was able to write this in one line!

②Once all the data is received, confirm the data

(3) Send data to the next module

→ After receiving the data, store it in the storage register and pass the data to the next module.

spi_top module details

Finally, we have the top module!

The top module connects four modules: spi_state.v, counter.v, spi_rx.v, and spi_tx.v.

The image is an image of packing each small box in a big box.

This is called hierarchical design.

 

Hierarchical design has the effect of making the code easier to see and easier to debug.

Call each of the four modules and write to the top module.

This is called instantiation.


Also, write to the top module to call the internal oscillator and the clock developer.

The top module achieves three functions.

(1) Instantiate each module

 

(2) Call Clock Provider

 

(3) Call internal oscillator

I will explain the points to realize the functions of the top module.

(1) Instantiate each module

→ Here, each module is connected by wire. It's a simple description, but I'm going to write it carefully because I'm going to make a mistake in the description.

 

(2) Call Clock Provider

→ Lattice FPGA can be called by RTL description. This time, we divide the frequency by 1/4 and write it in various setting RTL.

 

(3) Call internal oscillator

→Similarly, call the module to output 2.08MHz.

However, since the internal oscillator has an accuracy of ±5%, it is recommended to input an external clock if more accuracy is required.

This time, I designed SPI communication with RTL.

As an impression,

 

At first glance, it was fun because I could see the combination of syntax when I disassembled the communication that seemed complicated at first glance!

 

It was fun, but what is Verilog? I started designing from there, so it took me 4 days! smile

 

Next time, we will simulate using Model Sim Lattice Eddtion, and if there is no problem, we would like to check with the actual machine!

 

See you next time! See ya!

About the Lattice FPGA Getting Started Blog

 

Throughout the article, we are making a module that converts the temperature (SPI communication) acquired by the temperature sensor inside the FPGA and displays it on the 7-segment LED display!

 

If you are interested in "What is this newcomer making?"

 

I would be happy if you could check the module production process and the whole picture from the page below!