SD cards are easily interfaceable with FPGAs. They come in different sizes (standard, mini and micro) but electrically they all work the same way. Let's focus on micro-SD cards since they are conveniently small and popular nowadays.

Micro-SD cards have 8 pins. First the power connection goes on pins 4 and 6.

Then, you need between three and six connections to FPGA pins depending on the mode of operation you decide to use.

SPI模式

In SPI mode, the DI/DO lines are unidirectional. That means:

  • No pull-up necessary on DI/DO
  • Commands (and sectors data when you do a sector write) are sent to the DI pin
  • Response (and sectors data when you do a sector read) are received from the DO pin

The SPI mode is often used in microcontroller systems. With an FPGA, we migh be better served with the…

SD modes

In SD modes, the CMD/DATx lines are bidirectional. That means:

  • Pull-ups are required on CMD/DATx (FPGAs can usually provide them internally)
  • Commands/response are sent/received on the CMD pin
  • Sectors data (for sector read and writes) are sent/received from the DATx pins

So for example, we need these connections in SD one-bit mode:

协议

SD cards work with a command/response scheme. For example, command “17” allows reading one sector (512 bytes) of the card memory. All communication is synchronous to a clock provided by the host (FPGA in our case). The clock should run below 400KHz at startup and can go faster after some card initialization.

All commands and most responses are 48bits long (6 bytes). Sector data come in multiples of 512 bytes. For example, here's a simple code that allows sending commands to the SD card.

// we use the Xylo-E FX2 FIFO2 as data source for "commanding" an SD card
// the SD card is used in one-bit SD mode
 
// first we are going to drive the SD card at a much slower speed than the FPGA itself
// let's create a "shift" signal that is asserted once every 64 clock periods
reg [5:0] cnt=0;  always @(posedge clk) cnt <= cnt+1;
reg shift=0;  always @(posedge clk) shift <= &cnt;
 
// now we serialize every byte we get from the FIFO2
reg [2:0] cntbit=0;
reg shifting=0;
reg [7:0] data=0;
always @(posedge clk) if(shift) shifting <= shifting ? ~(&cntbit & ~FIFO2_data_available) : FIFO2_data_available;
always @(posedge clk) if(shift & shifting) cntbit <= cntbit+1;
always @(posedge clk) if(shift) data <= (FIFO2_data_available & (~shifting | &cntbit)) ? FIFO_DATAIN : {data[6:0],1'b0};
assign FIFO_RD = shift & (~shifting | &cntbit);
 
// and send the serial data to the SD card
assign SD_CLK = cnt[5];
assign SD_CMD = shifting ? data[7] : 1'bZ;

Some commands have no reply, while some other will issue a response on the SD_DAT line. For example, to initialize the card, we start with a CMD0 followed by CMD8:

  • CMD0 “GOIDLESTATE”
  • CMD8 “SENDIFCOND”, response expected

相关资源