Practice

Trail Camera SD Wake

A trail camera on Rowan Fell records foxes through the night. At dawn, it writes each night's photos to an SD card over SPI.

A fresh card powers up asleep in SD mode. It ignores normal SPI traffic until the host performs a fixed wake ritual.

The shipped firmware skipped that ritual and went straight to writing. The card ignored every command.

One morning, the keeper found twelve fox filenames in the directory, each with zero bytes.

Your task: build the sequencer that wakes the card. Supply its first clocks, send each command, and check each reply. Do not report ready until the card proves it can accept data.

Interface

PortDirectionTypeDescription
clk_iin1 bitSystem clock
rst_iin1 bitSynchronous reset, active high
start_iin1 bitRequest the wake ritual
miso_iin1 bitSerial data from the card
cs_n_oout1 bitCard chip select, active low and idle high
sclk_oout1 bitSerial clock, idle low
mosi_oout1 bitSerial data to the card, idle high
busy_oout1 bitHigh while the wake ritual runs
ready_oout1 bitHigh once the card is awake, then held high
error_oout1 bitWake failure, pulsed for exactly one clock

Behavior

  • While idle, cs_n_o is high, sclk_o is low, mosi_o is high, and all three status outputs are low
  • A high start_i sampled while idle is accepted, and the sequence begins on the next clock
  • busy_o is high while the sequence runs
  • Any start_i assertion while busy_o is high is ignored
  • SPI uses mode 0
  • Each SPI bit uses exactly two clk_i cycles
  • During the first cycle, sclk_o is low and mosi_o is set for the next bit
  • During the second cycle, sclk_o rises and miso_i is sampled
  • Bytes are transferred most-significant bit first
  • Begin with at least 74 complete sclk_o cycles while cs_n_o and mosi_o remain high
  • Every command is a six-byte packet: 0x40 + index, four argument bytes most-significant byte first, then its fixed CRC byte
  • Lower cs_n_o before each command and keep it low through the command and its complete response
  • After the packet, send 0xFF while polling response bytes
  • The card may return zero through eight 0xFF filler bytes before its R1 response
  • The first received byte with bit 7 low is the R1 response
  • If no R1 arrives after the permitted filler bytes, abort with an error
  • After each response, raise cs_n_o and supply eight extra clocks while sending 0xFF before the next command
  • Send CMD0 with index 0, argument 0x00000000, and CRC byte 0x95; expect R1 0x01
  • Send CMD8 with index 8, argument 0x000001AA, and CRC byte 0x87
  • CMD8 returns R1 0x01, followed by four R7 bytes
  • The last two R7 bytes must be 0x01 and 0xAA; any other echo aborts with an error
  • Begin the ACMD41 loop by sending CMD55 with index 55, argument 0x00000000, and CRC byte 0x65; expect R1 0x01
  • Then send ACMD41 with index 41, argument 0x40000000, and CRC byte 0x77
  • Repeat the complete CMD55 and ACMD41 pair while ACMD41 returns R1 0x01
  • Leave the loop when ACMD41 returns R1 0x00
  • If another pair would exceed 64 ACMD41 rounds, abort with an error
  • Send CMD58 with index 58, argument 0x00000000, and CRC byte 0xFD; expect R1 0x00
  • Capture the four OCR bytes following CMD58 without comparing them to a constant
  • After the CMD58 response, raise cs_n_o, lower busy_o, and raise ready_o
  • Once raised, ready_o stays high until reset
  • Every failure lowers busy_o, leaves ready_o low, and pulses error_o for exactly one clock
  • After the error pulse, the sequencer returns to idle
  • rst_i high at any rising edge cancels all progress and returns the interface to idle
  • Reset sets cs_n_o high, sclk_o low, mosi_o high, and busy_o, ready_o, and error_o low

What the bench checks

  • It checks reset, idle pin levels, next-clock startup, and ignored requests while busy
  • It checks mode 0 timing and at least 74 warm-up clocks with cs_n_o high
  • It checks every command byte, argument order, and fixed CRC byte
  • It checks chip-select framing and the eight extra 0xFF clocks between commands
  • It varies filler delays and checks the missing-R1 timeout
  • It checks the CMD8 echo, ACMD41 loop exit, and 64-round limit
  • It checks CMD58 completion, status behavior, error pulses, and reset during active transfers

Constraints

TIMING: everything is synchronous to clk_i; inputs are sampled on rising edges, and all outputs are registered.

SCOPE: this targets one SDHC v2 card profile with bounded response delays. CRC7 generation, CRC16, data blocks, SDSC byte addressing, and native SD mode are out of scope. The two mandated CRC constants are the only CRCs involved.

Do not add ports.

Loading editor...

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