Git Product home page Git Product logo

sdspi's Introduction

SD-Card controller

This repository contains two Verilog hardware RTL controllers for handling SD cards from an FPGA. The first and older controller handles SD cards via their (optional) SPI interface. The second and newer controller works using the SDIO interface. This second controller has also been demonstrated to handle eMMC cards as well.

SPI-based controller

The SDSPI controller exports an SD card controller interface from internal to an FPGA to the rest of the FPGA core, while taking care of the lower level details internal to the interface. Unlike the SDIO controller in this respository, this controller focuses on the SPI interface of the SD Card. While this is a slower interface, the SPI interface is necessary to access the card when using a XuLA2 board (for which it was originally written), or in general any time the full 9--bit, bi--directional interface to the SD card has not been implemented. Further, for those who are die--hard Verilog authors, this core is written in Verilog as opposed to the XESS provided demonstration SD Card controller found on GitHub, which was written in VHDL. For those who are not such die--hard Verilog authors, this controller provides a lower level interface to the card than these other controllers. Whereas the XESS controller will automatically start up the card and interact with it, this controller requires external software to be used when interacting with the card. This makes this SDSPI controller both more versatile, in the face of potential changes to the card interface, but also less turn-key.

While this core was written for the purpose of being used with the ZipCPU, as enhanced by the Wishbone DMA controller used by the ZipCPU, nothing in this core prevents it from being used with any other architecture that supports the 32-bit Wishbone interface of this core.

This core has been written as a wishbone slave, not a master. Using the core together with a separate master, such as a CPU or a DMA controller, only makes sense. This design choice, however, also restricts the core from being able to use the multiple block write or multiple block read commands, restricting it to single block read and write commands alone.

Status: The SDSPI IP is silicon proven. It is no longer under active development. It has been used successfully in several FPGA projects. The components of this IP have formal proofs, which they are known to pass. A Verilator C++ model also exists which can fairly faithfully represent an SD card's SPI interface. A software library also exists which can act as a back end when using the FATFS library.

For more information, please consult the SDSPI user guide.

SDIO

This repository also contains a second and newer SD card controller, designed to exploit both the full SDIO protocol and the 8b EMMC protocol--either with or without data strobes. This controller has been tested against both SDIO and eMMC chips, with the differences between the two types of chips handled by software.

The interface to this controller is roughly the same as that of the SDSPI controller, although there are enough significant differences to warrant a separate user guide.

The controller is designed to support IO modes all the way up to the HS400 mode used by eMMC. HS400 is an eMMC DDR mode based off of a 200MHz IO clock, using a data strobe pin on return. Also supported are an SDR mode using a 200MHz clock, DDR and SDR modes using a 100MHz clock, as well as both DDR and SDR support for integer divisions of the 100MHz clock, starting with a 50MHz clock and going all the way down to 100kHz. This is all based upon a nominal 100MHz system clock, together with a 400MHz clock for SERDES support. For designs without 8:1 and 1:8 SERDES IO components, 100MHz and slower clocks are still supported, depending upon whether or not DDR I/O components are available. Both open-drain and push-pull IOs are supported, and the front end can switch between the two as necessary based upon options within a PHY configuration register. No support is planned for any of the UHS-II protocols.

Both Wishbone and AXI-Lite interfaces are supported.

Status: The SDIO controller has now been silicon proven. It is currently working successfully in its first FPGA project, where it is being used to control both an SD card as well as an eMMC chip. Many of the components of this IP have formal proofs, which they are known to pass.

Notably missing among the component proofs is a proof of the front end. The front end's verification depends upon integrated simulation testing.

Both Verilog and C++ models have been built which can be used to test this controller in simulation, although only the Verilog SDIO and eMMC models have been tested to date.

For more information, please consult the SDIO user guide.

Roadmap and TODO items

Although the initial RTL has both been fully drafted and successfully hardware tested, this project is far from finished. Several key steps remain before this controller will be a completed product:

  • Multi-block: Multiple block commands have been demonstrated in simulation for the SDIO model. While eMMC multiblock support exists, it hasn't yet been tested, and will likely fail.

    Multiblock commands form the basis for the DMA's operation.

  • OPT_DMA: An optional DMA is now available, and passing tests in silicon.

    Only the Wishbone version of the DMA controller exists at present. Although some components exist in my wb2axip repository which could support an AXI DMA, these components have neither been integrated nor tested as part of this design.

    Since the eMMC model doesn't yet support the multi-block commands required by the DMA, DMA simulation testing has been limited to the SDIO model.

  • STREAM DMA: At customer request, hooks now exist for an (optional) stream DMA interface. This interface will accept an AXI stream input, and/or an AXI stream output. Data present on the AXI stream input may then be written directly to the device. Reads from the device may also produce data at the output stream. At present, the stream inputs must be a minimum of 32bits, and a power of two in width. The stream outputs must either be 32bits or the full bus width. No provision exist for stream data less than a word in size.

    This interface will need to be tested together with the pending hardware tests for the DMA.

  • C++ Model: An early Verilator C++ model of an SDIO component has been drafted. It needs to be finished and tested. No C++ eMMC model exists at present, nor is any data strobe support is planned.

  • SW Testing: Control software has been written, and has been used to demonstrate both SDIO and EMMC performance. This software is designed to work with the FATFS library.

    An integrated test bench exists for testing this software from a ZipCPU, it just hasn't (yet) been tested. Because this integrated test bench will require integration with an external project (i.e. the ZipCPU, further work is on hold pending a decision on how to integrate multiple dissimilar design components together for this purpose.

  • AXI Support: A version exists in the dev branch that supports an AXI-Lite interface.

  • eMMC Boot mode: No plan exists to support eMMC boot mode (at present). This decision will likely be revisited in the future.

    Boot mode may require support for eMMC CRC tokens, which aren't (yet) supported. These are 8'bit return values, indicating whether or not a page has been read or written and passes its CRC check.

    Some (untested) support exists for boot mode in the eMMC model.

Logic usage

Current logic usage is being tracked for iCE40 and Xilinx 6-LUT devices in the usage.txt file in the RTL/ directory.

Commercial Applications

Should you find the GPLv3 license insufficient for your needs, other licenses may be purchased from Gisselquist Technology, LLC.

sdspi's People

Contributors

foobar2016 avatar mjoergen avatar zipcpu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sdspi's Issues

Stuck in startup_hold in llsdspi.v

There seems to be an issue caused by line 185 in in llsdspi.v where the logic means that it will never escape the existing condition.

The code below is always true during startup_hold
if (startup_hold || byte_accepted) begin r_clk_counter <= i_speed; r_z_counter <= (i_speed == 0); end

which means the next block
else if (!r_z_counter) begin r_clk_counter <= (r_clk_counter - 1); r_z_counter <= (r_clk_counter == 1); end
never gets executed and therefore no clocks are issued to clear the startup_counter

I had to replace the code at line 185 with
if ((startup_hold || byte_accepted) && r_z_counter) begin r_clk_counter <= i_speed; r_z_counter <= (i_speed == 0); end
to stop this block being executed after r_z_counter was set to zero.

It might be a problem with my implementation of the interface but it seems compliant and I'm not sure that the interface signals could influence this particular code block

Interested in PR for sdspisim multi-block read support?

I've used sdspisim to test and develop an SD card SPI controller for a personal project, and found it super helpful, but wanted to support multi-block reads, so I added it into sdspisim.

If you'd be interested in merging something along those lines, I'm happy to take the time to clean up my patch and submit it.

SPI initiation sequence

Some cards can't seem to operate in SPI mode correctly without toggling the SCLK pin for 74 times or more directly before sending a CMD0. The core doesn't comply with this requirement, causing unpredictable behavior in some generic cards.

OPT_SERDES=1 fails implementation

Implementation with OPT_SERDES=1 fails with error "multiple driver nets". The issue is that o_mine is assigned twice in xsdserdes8x.v. After removing the second assigment on line 188 implementation succeeds but timing fails.

Timing report
Name Slack Levels High Fanout From To Total Delay Logic Delay Net Delay Requirement Source Clock Destination Clock Exception Clock Uncertainty
Path 221 -1.01 2 3 ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.cmd_serdes/GEN_BIDIRECTIONAL.u_iserdes/CLKDIV ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.cmd_serdes/u_oserdes/T1 2.23 0.74 1.49 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21
Path 222 -0.58 1 3 ps/sdio_top_0/U0/u_sdio/u_txframe/ck_data_reg[13]/C ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.GEN_WIDE_DATIO[5].io_serdes/u_oserdes/T1 1.81 0.48 1.33 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21
Path 223 -0.50 1 41 ps/sdio_top_0/U0/u_sdio/u_txframe/ck_valid_reg/C ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.GEN_WIDE_DATIO[1].io_serdes/u_oserdes/T1 1.73 0.63 1.10 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21
Path 224 -0.44 1 41 ps/sdio_top_0/U0/u_sdio/u_txframe/ck_valid_reg/C ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.GEN_WIDE_DATIO[2].io_serdes/u_oserdes/T1 1.67 0.63 1.04 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21
Path 225 -0.41 1 41 ps/sdio_top_0/U0/u_sdio/u_txframe/ck_valid_reg/C ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.GEN_WIDE_DATIO[4].io_serdes/u_oserdes/T1 1.64 0.63 1.01 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21
Path 226 -0.40 1 41 ps/sdio_top_0/U0/u_sdio/u_txframe/ck_valid_reg/C ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.GEN_WIDE_DATIO[6].io_serdes/u_oserdes/T1 1.63 0.63 1.00 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21
Path 227 -0.37 1 41 ps/sdio_top_0/U0/u_sdio/u_txframe/ck_valid_reg/C ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.GEN_WIDE_DATIO[7].io_serdes/u_oserdes/T1 1.60 0.63 0.97 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21
Path 228 -0.30 1 10 ps/sdio_top_0/U0/u_sdio/u_control/o_pp_data_reg/C ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.GEN_WIDE_DATIO[3].io_serdes/u_oserdes/T1 1.53 0.54 0.99 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21
Path 229 -0.29 1 10 ps/sdio_top_0/U0/u_sdio/u_control/o_pp_data_reg/C ps/sdio_top_0/U0/u_sdfrontend/GEN_WIDE_IO.GEN_WIDE_DATIO[0].io_serdes/u_oserdes/T1 1.53 0.54 0.99 2.50 clk_out1_ps_block_clk_wiz_0_0 clk_out2_ps_block_clk_wiz_0_0 0.21

Testing it with failed timing, initialization and CSD reading succeeds but bus width determination fails sometimes. When bus width determination succeeds reading and writing single blocks works with enough time after write. Busy workaround of reading o_debug doesn't work since it's all zeroes when using serdes option.

EMMC write issue

I have a Zynq 7020 board with 8-bit EMMC connected to PL pins. I have configured sdio with AXI bus, OPT_DMA=0, OPT_DDR=0, and OPT_SERDES=0. Software is configured with EMMCMULTI=0. AXI clock speed is 100 MHz, EMMC clock speed is 25 MHz and the bus is 8-bits.

EMMC reads seem to be working fine, but I'm having issues with EMMC writes. 1st block write succeeds, but reading back the written block reads 512 0xfe bytes and fails with SDIO_ERR and SDIO_RXERR bits set.

Calling emmc_get_r1(dev) after the 1st block write has finished reports:

CMD13:   SEND_STATUS
  Cmd:     0001010d
  Data:    00000e00
  PHY:     c9003803
EMMC R1 Decode:  00000e00
  STATE: prg

prg state makes sense since write function doesn't wait for write to finish. Read succeeds if there is enough delay before read to make sure that previous write has completed. The issue seems to be that emmc_write and emmc_read start even if DAT0 is pulled low and the device is busy.

However, just adding a while loop that checks for SDIO_CARDBUSY bit at the start doesn't seem to solve the issue. From the o_debug port I can see that DAT0 = '0', but CARDBUSY bit is not set. When I add a busy loop on o_debug(0) bit at the start of emmc_read_block and emmc_write_block reads and writes work fine.

Below is ILA capture of the end of the write:

sdio_ila

It seems that DAT0 takes a while to be pulled down and I guess CARBUSY bit is not set correctly.

char array cast to unsigned array in sdcard.c assumes big endian CPU

In sdcard.c functions sdcard_read(), sdcard_write(), sdcard_read_csd() and sdcard_read_cid(), the passed in char* buffer gets cast to unsigned*, for convenient access to/from sd_fifo[0]. This will only work as intended on a big endian platform. On little endian platforms an endian byte swap is needed.

I also suspect there will be issues if the passed in char* is not word aligned. I haven't verified that though.

eMMC read & write block issue

I tried to write & read a eMMC sector but the result was wrong. It seems that it is because in emmc_write_block and emmc_read_block functions, the phy value is not written back to the IP register.

C++ undefined behavior

At autotest_tb.cpp:218, this function with return type unsigned does not have a return value. This is undefined behavior of C++. When using g++ 10.2 and -O1, it will be optimized to an infinite loop and trigger an assertion later.

Add "return r;" to the end of the function can solve the problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.