Its a walkthrough how the RTL design for SPI Master controller is put up to be able to speak to AD7303 8-bit DAC peripheral.
PMOD DA1 which hosts two DACs has been used in this project.
AD7303 samples the serial data on the rising edge of the SPI clock. SPI polarity and phase are chosen to be CPOL 0 and CPHA 0.
RTL design and testbench are done in Verilog HDL.
Reading through the textbook "Verilog By Example" by Blaine C. Readler and lectures from Prof. Adi Teman, I am convinced that designing a FSM probably offers more clean and modular way to structure the HDL design, that could later be easier to debug, maintain and enhance. Its a two-block FSM as explained in the lecture from Prof. Teman. I highly recommend watching it to appreciate the beauty of separating the sequential and the combinatorial parts of the FSM.
Like in the lecture, the sequential block is designated for the state register and the combinational part to calculate the outputs and the next_state.
##### Design:
In brief the implemented SPI Controller is just a shift register that keeps shifting each bit from a 16-bit register on to the serial line MOSI, MSB first. The FSM is clocked by the high speed FPGA Clock. SPI Clock is NOT a free-running clock but rather it is generated by the FSM itself. The snippet can be found here.
// Generate SCLK based on the clock counter
always @(posedge clk) begin
if (!nreset) sclk <= 1'b0;
else if (state_cur != IDLE && (clk_counter == PRESCALER)) sclk <= ~sclk;
else if (state_cur == IDLE) sclk <= 1'b0; //keep SCLK low in IDLE state
else sclk <= sclk; //expliciting- hold SCLK state
end
We also make sure that the shift_reg shifts the MSB onto the MOSI line at the middle of (SCLK == LOW). For this we need to a burst pulse at this location to time it.
// “one-shot” when the counter ends. A pulse at the SCLK rising edge
wire sclk_rise = (clk_counter == PRESCALER);
// “one-shot” halfway through. A pulse at the half the PRESCALER.
wire sclk_fall = (clk_counter == (PRESCALER>>1));
SPI Clock: CMOD S7 has an on-board 12MHz crystal oscillator that could be used in FPGA designs. I have used a clock divider of 6 to derive 2MHz SPI Clock. AD7303 can have clock frequencies as high as 30MHz.
Note: The recently committed RTL uses a PRESCALER 49 to derive 2MHz SPI clock from 100MHz FPGA Clock as I tested it on Basys3 board. If you still want to use a CMOD S7, the PRESCALER can be adjusted to 6.
The FMS comprises of four states as shown below. In the RTL Design we declare them as parameters that would eventually work as 'case' statements.
parameter IDLE = 2'b00;
parameter CS_LOW = 2'b01;
parameter SHIFT = 2'b10;
parameter CS_HIGH = 2'b11;
State register state_cur takes the value of state_nxt on every rising edge of the FPGA clock.
state_nxt is computed in the combinatorial always @* block as per the timing requirements from the AD7303 datasheet.
##### Note:
The control register is taken as 0x00. This configuration shall keep both the DACs active, loads the data byte that we shifted into the shift registers of both DACs. Therefore we shall see the same output voltage on both the DACs.
The data register is handled as a parameter and given a value of 0x7F.
This shall produce an output analog voltage of
2*3.3V*(127/256) = 1.63V
A simple testbench has been written to test this unit. I have used iverilog and gtkwave for testing this in simulation.
I then created a Vivado project to synthesize, implement, generate bitstream and configure the FPGA on CMOD-S7.
Analog Discovery (legacy) was quite handy to verify both the transmitted digital data and converted analog voltage by the PMOD DA1 module.
Transmitted MOSI data:
DAC output from PMOD DA1:
The design has been tested with different data values to check for the correctness of analog output voltages.
The oscillations in the output voltage can be minimized by connecting a filter capacitor at the DAC output.
HW Setup:
The design shall further be extended to make data byte as input vector so that this RTL module can take it as input from application it goes into.
The similar can be done with control byte as well based on the application needs.
Please let me know you thoughts and thank you.
Comments