Bird
Raised Fist0
VHDLprogramming~10 mins

SPI master controller in VHDL - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - SPI master controller
Start
↓
Idle: Wait for start signal
↓
Load data to shift register
↓
Set clock low
↓
For each bit in data
↓
Set MOSI to current bit
↓
Toggle SCLK high
↓
Read MISO if needed
↓
Toggle SCLK low
↓
Shift data left
↓
All bits sent?
Yes↓
Set CS high to end
↓
Done
The SPI master controller waits for a start signal, loads data, then sends bits one by one by toggling the clock and setting MOSI, finally ending the transmission.
Execution Sample
VHDL
process(clk)
begin
  if rising_edge(clk) then
    if start = '1' then
      cs <= '0'; -- activate slave
      shift_reg <= data_in;
      bit_cnt <= 7;
    elsif bit_cnt >= 0 then
      sclk <= not sclk;
      if sclk = '1' then
        mosi <= shift_reg(bit_cnt);
        bit_cnt <= bit_cnt - 1;
      end if;
    else
      cs <= '1'; -- deactivate slave
    end if;
  end if;
end process;
This VHDL process sends 8 bits over SPI by toggling the clock and shifting bits out on MOSI.
Execution Table
Stepstartcsbit_cntsclkmosishift_regAction
11070Udata_inStart signal detected, CS low, load data_in to shift_reg, bit_cnt=7
200711data_inToggle sclk high (clock rising edge), output bit 7 on MOSI
300601data_inToggle sclk low
400611data_inToggle sclk high (clock rising edge), output bit 6 on MOSI
500500data_inToggle sclk low
600510data_inToggle sclk high (clock rising edge), output bit 5 on MOSI
700401data_inToggle sclk low
800411data_inToggle sclk high (clock rising edge), output bit 4 on MOSI
900300data_inToggle sclk low
1000310data_inToggle sclk high (clock rising edge), output bit 3 on MOSI
1100201data_inToggle sclk low
1200211data_inToggle sclk high (clock rising edge), output bit 2 on MOSI
1300100data_inToggle sclk low
1400110data_inToggle sclk high (clock rising edge), output bit 1 on MOSI
1500001data_inToggle sclk low
1600011data_inToggle sclk high (clock rising edge), output bit 0 on MOSI
1700-100data_inToggle sclk low
1801-100data_inAll bits sent, CS high to deactivate slave
1901-100data_inIdle, waiting for next start
💡 bit_cnt < 0 means all bits sent, CS set high to end transmission
Variable Tracker
VariableStartAfter 1After 2After 3After 4After 5After 6After 7After 8After 9After 10After 11After 12After 13After 14After 15After 16After 17Final
start0100000000000000000
cs1000000000000000011
bit_cnt77766554433221100-1-1
sclk0010101010101010100
mosiUU11100110011001100
shift_regdata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_indata_in
Key Moments - 3 Insights
Why does MOSI only update when sclk is low, not high?
MOSI updates on the rising edge of sclk (when sclk = '1') to ensure data is stable before the clock falling edge triggers the slave to read it, as shown in execution_table rows where mosi changes only at sclk=1.
Why does bit_cnt decrement only when sclk is low?
bit_cnt decrements after sending each bit on MOSI at sclk=1, so the controller knows which bit to send next, as seen in execution_table where bit_cnt changes after sclk toggles high.
What happens when bit_cnt becomes -1?
When bit_cnt < 0, it means all bits have been sent, so CS is set high to deactivate the slave, ending the transmission (execution_table step 18).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 2. What is the value of MOSI?
A1
B0
CU (undefined)
DNot set yet
💡 Hint
Check the MOSI column at step 2 in the execution_table.
At which step does bit_cnt first decrement from 7 to 6?
AStep 2
BStep 5
CStep 4
DStep 3
💡 Hint
Look at the bit_cnt column changes between steps 2, 3, and 4 in the execution_table.
If start stays '0' after step 1, what happens to CS at step 18?
ACS remains low (0)
BCS goes high (1)
CCS toggles rapidly
DCS is undefined
💡 Hint
Refer to execution_table step 18 where bit_cnt < 0 causes CS to go high.
Concept Snapshot
SPI Master Controller in VHDL:
- Wait for start signal
- Set CS low to select slave
- Load data into shift register
- For each bit:
  - Set MOSI to current bit on sclk rising edge
  - Toggle sclk to clock data out
- After all bits sent, set CS high to end
- Repeat on next start
Full Transcript
This visual execution trace shows how an SPI master controller in VHDL works step-by-step. It starts by waiting for a start signal. When start is detected, the controller sets the chip select (CS) line low to activate the slave device and loads the data to send into a shift register. Then, it sends each bit one by one by toggling the serial clock (sclk). On the rising edge of sclk, the controller sets the MOSI line to the current bit from the shift register and decrements the bit counter. This process repeats until all bits are sent. Finally, the controller sets CS high to deactivate the slave and waits for the next start signal. The execution table tracks all variable changes per step, helping beginners see exactly how the signals change over time. Key moments clarify why MOSI updates on sclk high and what happens when all bits are sent. The quiz questions test understanding of these steps.

Practice

(1/5)
1. What is the primary role of the SPI master controller in VHDL designs?
easy
A. To convert SPI signals into parallel data only
B. To act as a slave device responding to SPI commands
C. To generate random data for SPI devices
D. To control the clock, chip select, and data lines for SPI communication

Solution

  1. Step 1: Understand SPI roles

    The SPI master controls communication timing and signals like clock and chip select.
  2. Step 2: Identify controller function

    The master sends and receives data by managing these lines, unlike a slave which only responds.
  3. Final Answer:

    To control the clock, chip select, and data lines for SPI communication -> Option D
  4. Quick Check:

    SPI master controls clock, chip select, data lines [OK]
Hint: Master controls clock and chip select lines [OK]
Common Mistakes:
  • Confusing master with slave device
  • Thinking master only sends data without control
  • Assuming master generates random data
2. Which VHDL statement correctly declares a 8-bit shift register signal for SPI data?
easy
A. signal shift_reg : integer range 0 to 255;
B. signal shift_reg : std_logic_vector(7 downto 0);
C. signal shift_reg : std_logic;
D. signal shift_reg : bit_vector(0 to 7);

Solution

  1. Step 1: Identify correct data type for shift register

    Shift registers for SPI data use std_logic_vector for bit-wise operations.
  2. Step 2: Check syntax and range

    std_logic_vector(7 downto 0) correctly defines 8 bits from MSB to LSB.
  3. Final Answer:

    signal shift_reg : std_logic_vector(7 downto 0); -> Option B
  4. Quick Check:

    Use std_logic_vector(7 downto 0) for 8-bit register [OK]
Hint: Use std_logic_vector with downto for bit vectors [OK]
Common Mistakes:
  • Using integer instead of bit vector
  • Using bit_vector which is less common
  • Declaring single bit instead of vector
3. Given this VHDL process snippet for SPI clock generation:
process(clk)
begin
  if rising_edge(clk) then
    if clk_div = 1 then
      spi_clk <= not spi_clk;
      clk_div <= 0;
    else
      clk_div <= clk_div + 1;
    end if;
  end if;
end process;

What is the frequency relationship between spi_clk and clk?
medium
A. spi_clk frequency equals clk frequency
B. spi_clk frequency is double clk frequency
C. spi_clk frequency is half of clk frequency
D. spi_clk frequency is unrelated to clk frequency

Solution

  1. Step 1: Analyze clock division logic

    clk_div toggles spi_clk every 2 rising edges of clk, flipping spi_clk once per two clk cycles.
  2. Step 2: Determine frequency ratio

    Since spi_clk toggles every 2 clk cycles, its frequency is half of clk frequency.
  3. Final Answer:

    spi_clk frequency is half of clk frequency -> Option C
  4. Quick Check:

    spi_clk toggles every 2 clk cycles = half frequency [OK]
Hint: Toggle output every 2 input cycles halves frequency [OK]
Common Mistakes:
  • Assuming frequencies are equal
  • Thinking frequency doubles
  • Ignoring clk_div counter effect
4. Identify the error in this SPI master controller state machine snippet:
type state_type is (IDLE, LOAD, TRANSFER);
signal state : state_type := IDLE;

process(clk)
begin
  if rising_edge(clk) then
    case state is
      when IDLE =>
        if start = '1' then
          state <= LOAD;
        end if;
      when LOAD =>
        state <= TRANSFER;
      when TRANSFER =>
        if bit_count = 8 then
          state <= IDLE;
        end if;
    end case;
  end if;
end process;
medium
A. bit_count is not reset, causing TRANSFER to never end
B. Missing default case in state machine
C. start signal is not checked in TRANSFER state
D. State transitions are missing LOAD to IDLE path

Solution

  1. Step 1: Check state transitions and counters

    TRANSFER state depends on bit_count reaching 8 to return to IDLE.
  2. Step 2: Identify missing reset of bit_count

    If bit_count is never reset to 0, it may never reach 8, so TRANSFER state loops indefinitely.
  3. Final Answer:

    bit_count is not reset, causing TRANSFER to never end -> Option A
  4. Quick Check:

    bit_count reset missing = infinite TRANSFER [OK]
Hint: Always reset counters to avoid infinite states [OK]
Common Mistakes:
  • Ignoring counter reset logic
  • Expecting default case is mandatory
  • Confusing start signal usage
5. You want to extend an SPI master controller to support variable data widths (4 to 16 bits). Which VHDL approach best handles this requirement?
hard
A. Use a generic parameter for data width and adjust shift register size accordingly
B. Hardcode shift register to 16 bits and ignore unused bits
C. Create separate modules for each data width and select at compile time
D. Use integer counters only without shift registers

Solution

  1. Step 1: Understand variable data width needs

    Supporting 4 to 16 bits requires flexible register size and control logic.
  2. Step 2: Use generics for flexibility

    Generics allow parameterizing data width at compile time, adjusting shift register size dynamically.
  3. Step 3: Evaluate other options

    Hardcoding wastes resources; separate modules increase complexity; counters alone can't shift data.
  4. Final Answer:

    Use a generic parameter for data width and adjust shift register size accordingly -> Option A
  5. Quick Check:

    Generics enable flexible data width in VHDL [OK]
Hint: Use generics to set data width flexibly [OK]
Common Mistakes:
  • Hardcoding fixed sizes wastes resources
  • Creating many modules complicates design
  • Ignoring shift register role in data transfer
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard