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 clock. In the designed SPI Controller we shift the data on negative edge of the clock so that the data is available to the peripheral for sampling at the immediate rising edge of the SPI clock. Hence we go with CPOL 0 and CPHA 0.
RTL design and testbench are done in Verilog.
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.
##### 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.
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. I randomly chose 2Mhz here.
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.
State transitions happen sequentially on every negedge
of SPI Clock. Only in case of state transition from shift_state
to idle_state
, the design keeps counting the number of bits that are still remaining in the shift register that needs to be shifted on to the serial line. Once the count reaches 0, we shift the 0th bit, assert done and transit to idle_state
.
idle_state
:
1. Pull chipselect high
2. Transit to load_state
load_state
:
1. reset output done signal to 0.
2. load bitcount tracking register to max. number of bits to be shifted-> 4'hF
3. load shift_reg with 8-bit control and 8-bit data bytes.
start_state
:
1. chipselect is pulled low
2. shift MSB from the shift_reg on to MOSI line. Like stated earlier, we shift the bit on negedge
so that the peripheral can already sample it on the next immediate occurring posedge
of the sclk.
3. shift_reg is left shifted by 1-bit as MSB has already been placed on MOSI.
4. bitcount counter is decremented by 1.
5. transit to shift_state.
shift_state
:
1. Keep shifting until the rest of the 15 bits in the shift_reg are shifted on to the MOSI line.
2. keep decrementing bitcount tracking register.
3. Assert output signal done and Transit to idle_state after all the bits have been shifted.
##### 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
Please log in or sign up to comment.