Practice

Hive Scale Sampler

A bee farm weighs every hive to catch swarms early. When a swarm leaves, half the bees go with it, and the hive gets lighter within the hour. The scale under each hive feeds a 12-bit ADC, and the ADC talks SPI.

The old readout board sampled the data line one clock too late, just after the ADC had already shifted it. Every bit landed one place too high, so the logged weight came out doubled. Hive 7 swarmed in June. The chart showed a fat, thriving colony, and nobody opened the lid until the honey was gone.

Your task: build the SPI master that reads one sample from the ADC. Wait in idle until start_i pulses. Then pull cs_n_o low, run sclk_o at 1/4 of the system clock rate, and capture miso_i on each rising sclk_o edge. The ADC sends 2 null bits, then the 12 data bits, highest bit first. Put the reading on sample_o, pulse valid_o for 1 cycle, and go back to idle.

Interface

PortDirectionTypeDescription
clk_iin1 bitSystem clock
rst_iin1 bitSynchronous reset (active high)
start_iin1 bitRequest one reading (one-cycle pulse)
miso_iin1 bitSerial data from the ADC
cs_n_oout1 bitADC chip select (active low)
sclk_oout1 bitSerial clock to the ADC (idles low)
sample_oout12-bit vectorLast completed reading, held
valid_oout1 bitReading complete (one-cycle pulse)

Behavior

  • When idle, cs_n_o is high, sclk_o is low, and valid_o is low
  • While idle, start_i high at a rising clock edge begins a read: cs_n_o falls on that same edge
  • Cycle numbering: cycle 0 is the first full cycle with cs_n_o low
  • sclk_o divides the system clock by 4: in each group of 4 cycles from cycle 0, it is low for 2 cycles, then high for 2
  • The first sclk_o rising edge lands at cycle 2; the rest follow every 4 cycles, 14 rising edges in total
  • cs_n_o stays low for cycles 0 through 55: exactly 14 sclk_o periods
  • The ADC updates miso_i after each sclk_o falling edge; the master captures miso_i on each sclk_o rising edge
  • The first 2 captured bits are null bits, driven 0 by the ADC; the reading does not include them
  • The next 12 captured bits are the reading, bit 11 first, bit 0 last
  • At cycle 56 the read ends: cs_n_o returns high, sclk_o is low, valid_o is high, and sample_o presents the new reading
  • valid_o is high for exactly 1 cycle per read
  • sample_o holds between reads and while a read is in progress; reset clears it to 0
  • start_i pulses while cs_n_o is low are ignored
  • A start_i pulse on the cycle right after valid_o begins a new read
  • rst_i high at a rising clock edge cancels any read: cs_n_o high, sclk_o low, valid_o low, sample_o cleared

What the bench checks

  • The testbench models the ADC: it loads a known code when cs_n_o falls and shifts it out on sclk_o falling edges
  • The testbench checks cs_n_o, sclk_o, and valid_o against the fixed timeline on every cycle of every read
  • The testbench compares sample_o to the loaded code after each read, using codes that expose shifted or reversed bits
  • The testbench drives miso_i high whenever cs_n_o is high
  • The testbench pulses start_i in the middle of one read and checks that no second read starts after it
  • The testbench pulses start_i on the last cycle with cs_n_o low and checks that no new read follows
  • The testbench starts one read on the cycle right after valid_o and expects a normal read
  • The testbench asserts rst_i in the middle of one read and checks the outputs return to idle on the next cycle
  • The testbench checks sample_o on every cycle of every read: it must hold the previous reading until the read completes
  • The testbench checks that sample_o holds its value between reads

Constraints

TIMING: everything is synchronous to clk_i; all outputs are registered.

SCOPE: this models the SPI master side of one fixed read: 2 null bits, then 12 data bits at a quarter-rate clock. The scale, the ADC's analog side, and the logging are out of scope.

Do not add ports.

Loading editor...

Click Run to execute your code. Output will appear here.