====== SDcard management module ====== This page is about modules to read and write data to SDcards. All the modules are actually based on a single module that makes it possible to perform low level accesses, the SDcard_raw_access_v2 module. These modules have been tested with a large pannel of SD / SDHC cards. Testing on SDXC cards is still lacking. These modules are provided //as is// for HDL lab sessions at ENSEIRB-MATMECA. They are the property of ENSEIRB-MATMECA. Use them at your own (SDcard, data and legal) risks. There should be no problem using them for education purpose. If using them for research purpose, please contact the author for acknowledgement / authorship policy. For commercial use, please contact the author or the lawyer's office of ENSEIRB-MATMECA/INP. ===== Features ===== The different modules of this page are designed to take full access to the SDcards, therefore, it is not possible to mix the different behaviors. * [[#raw_access]] : Full R/W access to the SDcard data * [[#readstream]] : Read only access, data is provided as a continuous stream * [[#writestream]] : write only, module stores data on the SDcard as a continuous stream ---- ===== Raw Access ===== Data on a SDcard is split in 512-byte blocks. The SDcard module makes it possible to tranfer data between the SDcard and local buffers (on the FPGA). The number of local buffers is configurable depending on the application need. Default is 4 512-bytes buffers identified by a 2-bit value. The SDcard block is identified by a 32-bit value. To access SDcard data, users should then transfer them from the SDcard to a local buffer, then read the local buffer as a standard memory. To write to the SDcard, users should first write data to a local buffer, then transfer this local buffer to the SDcard. {{ :en202:sdcard_raw_access_symbol.png?direct&750 |}} ({{ :en202:sdcard_raw_access_symbol.vsd | figure source }}) The //blocks// output of the module provides the number of 512-byte blocks actually available on the card. Therefore, all operations must be performed on blocks numbered from //0// to //blocks - 1//. Any data equal or above //blocks// will result in an error and operations being ignored. When the card has not finished the initialization process, the //blocks// output it set to //0// since no block is available yet. After reset, powerup or configuration, the SDcard is being initialized. During this time, the //busy// output is set, even if no operation was ordered. User must wait for the //busy// output to be cleared to perform any operation Reading and writing data to buffers is performed like any RAM access. The actual RAM access is computed from //loc_buffer// and //address//. Data in the buffers can be 8, 16, 32 or 64 bits wide (refered as /n/ on the symbol schematic). Therefore, as blocks always contain 512 bytes, data address in the block is respectively 9, 8, 7 or 6 bits wide (refered as 9-i on the symbol schematic) ==== SDcard operations ==== Simple read, write or erase operations are performed as described on the following diagram. For a write operation, the content of the buffer //TR_buffer// will transfered to the block number //SD_block// on the SDcard. For a read operation, data from block //SD_block// on the SDcard will be transfer to the buffer //TR_buffer// on the FPGA. For ersae operation, no buffer ID is required, the block //SD_block// on the SDcard will be erased. Note that on SDcards, erase does not necessarilly means 'reset' or zeroed. The actual value of an erased block is technology dependant. In all cases, the operation is actually finished when //busy// returns to 0. {{ :en202:sdcard_rawop_diagram.png?direct&600 |}} ({{ :en202:sdcard_rawop_diagram.svg | figure source }}) While an operation is being performed, it is still possible to read/write data on buffers. So it is possible to work on a buffer while transferring another one. There is no buffer access limitation, so it is technically possible to modify a buffer during its transfer to the SDcard. Such behavior is strongly discouraged because there is no mean to identify atomic data transfers with the SDcard. On the other hand, it is perfectly safe to read data in a buffer which is being saved on the SDcard. To improve performance, it is possible to use multiple commands. Data are then written or read in a burst and the SDcard requires much less time to perform the transfer operation to memory blocks. The timing diagram below represent how to use the optional //multiple// input. Note that //multiple// MUST remain high during the whole transfer, otherwise, the module considers the burst is interrupted. Each time a new block is transfered, its value is internally increased by one, so it is not necessary to provide a new block value anymore. It is always necessary to provide a local buffer value to indicate the target buffer of the operation. If //multiple// is released when no operation is being performed (//busy// = '0'), the module needs to perform SDcard operations to close the transfer, therefore, the //busy// output will be active for some time and the module will not respond to eventual new commands. While performing operations, the modules does not constantly poll //multiple//, therefore, if //multiple// is released then reasserted while //busy// is set, there is no way to actually know whether the burst has been interrupted or not. {{ :en202:sdcard_rawmultop_diagram.png?direct&780 |}} ({{ :en202:sdcard_rawmultop_diagram.svg | figure source }}) To perform multiple block erase, the procedure is a bit different and is shown on the following diagram. It is only necessary to provide the first and last SD block to erase. So the module returns in idle state after the second call to erase whatever the value of //multiple// may be. {{ :en202:sdcard_rawmulerase_diagram.png?direct&700 |}} ({{ :en202:sdcard_rawmulerase_diagram.svg | figure source }}) ==== Module Generics ==== The //SDcard_raw_access_v2// module provides a set of generics to improve its flexibility. All these parameters have a default value that gives the best warranty to minimize design effort. * **//CLK_FREQ_HZ//** : This is the main clock frequency. This value is used to provide the best clock speed for data transfers. SDcard clock is performed by a state machine, not a DCM, to avoid specific hardware references and improve portability of the module. Transfers are performed at the highest possible frequency lower or equal to 25MHz for v1.00 SDcards and 50MHz for more recent SDcards (including SDHC and SDXC). The system clock frequencies that provide the best transfer performance are then multiples of 100MHz . * **//HIGH_SPEED_IF//** : allows or prevent using the 50MHz clock frequency when the SDcard supports that speed. 50MHz transfer clock might be problematic for data integrity because of connectors impedance, particularly when using the PmodSD with extension wires. Although there should not be problems with internal slots (like that of the Nexys4 board) this value is set to //False// by default to limit eventual problems. * **//WORD_SIZE_PW2//** : defines the data width of the buffers values 0, 1, 2 and 3 respectively code 8bits, 16bits, 32bits and 64bits. Although module's limit is 2048 bits, the design refuses more than 64 bits to limit hardware resource consumption. Default value is 0 (8bits data transfers). As data buffers are always 512 bytes, their address size is affected by this parameter. For example, if data width is set to 32bits, buffer address will only be 7 bits wide (128 addresses x 4 bytes = 512) * **//BUFFER_NUM_PW2//** : specifies the number of 512byte data buffers to handle within the module. This value makes it possible to get a proper balance between access flexibility and hardware resource consumption. The value actually codes for a power of 2, so 1, 2, 3, 4, 5, 6, 7 and 8 respectively mean 2, 4, 8, 16, 32, 64, 128 and 256 internal buffers. The default value is 2, meaning 4 buffers and requires a RAMB18k block for implementation. As modern FPGA are no able to infer smaller block RAMs, this value is the best compromise to limit resources. * **//PARAMETER_BUFFERING//** : (Deprecated) set for compatibility with previous version. This parameter makes it possible to remove a local copy of inputs and gain some hardware resources. It has been deprecated because the hardware architecture made those local copies necessary. Therefore, the only input which is influenced by this parameter is //loc_buffer// which corresponds to 2 FlipFlops in the default configuration. This gain is considered negligible. * **//FILENAME//** : (ignored) This parameter is used to define a filename that performs the content of a virtual SDcard for simulation model of this module. It is only present here to provide compatibility with the simulation model. The simulation model itself has not yet been released because it is not 100% equivalent to this module yet. * **//LITTLE_ENDIAN//** : In the case of data width higher than 8 bits, tells if data on the SDcard should be considered big endian (False) of little endian (True). Computer standard is getting more and more attached to little endian, so this is the default value. ==== Error Codes ==== The module provides an //err_code// output to identify eventual issues wile using the SDcard. Messages that have the Warning or Error status are only output during one clock cycle. To catch them, user should poll bit 2 and 3. A //1x// code means error, //01// code means warning and //00// is for standard info. ^ //err_code// ^ Status ^ Identifier ^ meaning ^ | 0000 | Info | NO_ERROR | Everything is working properly | | 0001 | Info | WRITE_PROTECTED | If used, the SD_WP line indicates that the //write protect// lock has been set on the SDcard. Although it is still technically possible, the module will refuse to modify the content of the SDcard. | | 0100 | WARNING | RETRY_AFTER_BAD_CRC | A data transfer failed to match CRC checks, the transfer is being retried. This Warning is a sign that the link to the SDcard is not reliable enough to achieve good performance. Automatic retries are still not implemented. | | 0101 | WARNING | MULT_OP_CANCELLED | A multiple block read or write has just been cancelled. This warning can be safely ignored if this is intentionnal | | 0110 | WARNING | CMD23_TIMEOUT | SDcard did not respond to command 23. This generally means that we have a SDHC card v2.01 or older. This command is used to improve data transfers. The conclusion to draw from this warning is unfirtunately SDcard dependant. In some cases SDcards can achieve good performance without this command, there are also some SDcards whose performance are not influenced by this command. | 1000 | ERROR | NO_CARD | There is no SDcard in the slot. (//SD_CD// = '1') | | 1001 | ERROR | INVALID_CARD | A card has been detected in the slot, but it seems that it is not a fully operational SDcard | | 1010 | ERROR | INVALID_DATA_BLOCK | An operation has been requested on a data block that does not physically exist on the SDcard (//SD_block// too high) | | 1011 | ERROR | WRITE_ERROR_FROM_CARD | The SDcard reported an internal write error. The module is not advanced enough to provide more information | | 1100 | ERROR | INCONSISTENT_CSD | Configuration information retreived from the SDcard is not coherent. Checks are not extensive, so erroneous SDcards might still no trigger this error | | 1101 | ERROR | TOO_MANY_CRC_RETRIES | The module failed to recover from a CRC error. There is high probability that the I/O lines between the FPGA and the SDcard slod do not have a good impedance or bandwidth. Future version might have a management of trandfer retries. | | 1110 | ERROR | CARD_RESP_TIMEOUT | SDcard does not respond to a requested command. There is high probability that the card has been removed from its slot and NO_OR_INVALID_CARD should occur soon. | | 1111 | ERROR | NO_W_ON_WP_CARD | The SDcard is write protected by its mechanical switch and a write or erase operation has been requested. The module refused the operation. | ==== Resource requirements ==== * 1 18kb Block RAM * 2 ^ (BUFFER_NUM_PW2 - 2) * ?? slices (please contribute) ==== limitations ==== * Local buffers can't be accessed independently * transfers are only perform by 512-byte blocks whereas (non SDHC/SDXC) SDcards can address byte level accesses ==== Warning ==== * operation times are unpredictable, this is because of the nature of SDcards themselves. * **DO NOT TRUST** the comercial SDcard capacity, which is a rough (overestimated) value of the actual number of blocks. Actual block number will always be 5 to 8% lower. ==== Known Bugs ==== * The module is still not fully finished, and some CRC/integrity check are not performed on non critical operations. There is neither transfer restart if a block transmission fails during multiple transfers. * The module seems to provide a different behavior when inserting an SDcard for the first time after reset and after the other insertions... This issue hasn't been digged yet and might actually be the consequence of the characterization architecture. * to be fully compliant with specs, first instructions should be performed at 400kHz, but they are actually performed at 25MHz. It seems that this constraint comes for backwards compatibility with MMC cards, so there sould be no consequence but users should keep this in mind if a Card is not detected/initialized properly ---- ===== Readstream ===== This module is designed to provide a stream from the content of the SDcard. It is to be used as a frontend to the //SDcard_raw_access_v2// module, and therefore will present the same eventual bugs/limitations. This module was developped using //SDcard_raw_access_v2// v2.0.2. {{ :en202:sdcard_readstream_symbol.png?direct&750 |}} ({{ :en202:sdcard_readstream_symbol.vsd | figure source }}) Data is available on //data_out// when //data_empty_n// signal is set. If both //data_read// and //data_empty_n// are set, the module considers that data has been retreived/processed and outpouts the next data word on //data_out// if available. If not, //data_empty_n// is reset and //data_out// content is not meaningful. The diagram below represent the evolution of the signal for 4 data reads in different conditions. The clock edges at which the module considers that data is read are overlined in red. {{ :en202:fifo_out_diagram.png?direct&650 |}} ({{ :en202:fifo_out_diagram.svg | figure source }}) ==== Module Generics ==== As the //SDcard_raw_access_v2// module on which it relies, the SDcard_writestream module can be configured to match several use cases. * **//CLK_FREQ_HZ//** : This is the main clock frequency. This value is used to provide the best clock speed for data transfers. SDcard clock is performed by a state machine, not a DCM, to avoid specific hardware references and improve portability of the module. Transfers are performed at the highest possible frequency lower or equal to 25MHz for v1.00 SDcards and 50MHz for more recent SDcards (including SDHC and SDXC). The system clock frequencies that provide the best transfer performance are then multiples of 100MHz . * **//HIGH_SPEED_IF//** : allows or prevent using the 50MHz clock frequency when the SDcard supports that speed. 50MHz transfer clock might be problematic for data integrity because of connectors impedance, particularly when using the PmodSD with extension wires. Although there should not be problems with internal slots (like that of the Nexys4 board) this value is set to //False// by default to limit eventual problems. * **//WORD_SIZE_PW2//** : defines the data width of the buffers values 0, 1, 2 and 3 respectively code 8bits, 16bits, 32bits and 64bits. Although module's limit is 2048 bits, the design refuses more than 64 bits to limit hardware resource consumption. Default value is 0 (8bits data transfers). * **//LITTLE_ENDIAN//** : In the case of data width higher than 8 bits, tells if data on the SDcard should be considered big endian (False) of little endian (True). Computer standard is getting more and more attached to little endian, so this is the default value. ==== Warning ==== * The module has an internal 2kBytes buffer which is designed to use minimal RAM resources. Because of SDcard technology, realtime applications should use an additionnal buffer of 15ms (roughly). Although this value is not a warranty to get proper real-time behavior, it is likely to work well in 99% of the cases. This buffer is not included in the module to allow a wider implementation choice to the developper. The real-time performance is SDcard dependant. ==== Error Codes ==== The //sd_error// output is asserted during one clock cycle if an error occurs. It is then possible to retreive the error code on the //debug// output. Otherwise, //debug// contains messages that help monitor data. Most of these messages come from the //SDcard_raw_access_v2// module. ^ //debug// ^ Status ^ Identifier ^ meaning ^ | 000000 | Info | NOTHING_TO_SAY | Everything is working properly | | 000001 | Info | END_OF_CARD | The module has reached the end of the SDcard. Data will not be accepted anymore. | | 100000 | ERROR | NO_CARD | No SDcard has been detected in the slot (//SD_CD// = '1') | | 100001 | ERROR | INVALID_CARD | The initialization sequence was not able to establish a connexion with the SDcard. | | 100100 | ERROR | INCONSISTENT_CSD | Configuration information retreived from the SDcard is not coherent. The module will not accept data. Checks are not extensive, so erroneous SDcards might still no trigger this error. | | 100101 | ERROR | TOO_MANY_CRC_RETRIES | The module failed to recover from a CRC error. There is high probability that the I/O lines between the FPGA and the SDcard slod do not have a good impedance or bandwidth. Waiting for //SDcard_raw_access_v2//'s lazy developper to handle retry management | | 100110 | ERROR | CARD_RESP_TIMEOUT | SDcard does not respond to a requested command. There is high probability that the card has been removed from its slot. | ==== Known bugs ==== * the module does not check error messages, if things go wrong, it may output erroneous data ---- ===== Writestream ===== This module is designed to receive a stream of data and store it directly on the SDcard. It is to be used as a frontend to the //SDcard_raw_access_v2// module, and therefore will present the same eventual bugs/limitations. This module was developped using //SDcard_raw_access_v2// v2.0.2. {{ :en202:sdcard_writestream_symbol.png?direct&750 |}} ({{ :en202:sdcard_writestream_symbol.vsd | figure source }}) Data is considered written at the rising edge of clk if //data_write// and //data_full_n// signals are both set. The diagram below represent the evolution of the signal for 4 data writes in different conditions. The clock edges at which data is actually accepted by the module are overlined in red. {{ :en202:fifo_in_diagram.png?direct&600 |}} ({{ :en202:fifo_in_diagram.svg | figure source }}) if asserted, the //final_flush// input generates a data flush to the SDcard. This is usefull if there is less than 512 bytes remaining in the buffer. SDcards working with 512byte blocks, the last data block will be filled with random data from the previous buffers. During this operation, //data_full_n// is cleared to indicate that the module is not ready to accept new data. Once the operation is performed, //data_full_n// is set again. User may remove the SDcard safely. ==== Module Generics ==== As the //SDcard_raw_access_v2// module on which it relies, the SDcard_writestream module can be configured to match several use cases. * **//CLK_FREQ_HZ//** : This is the main clock frequency. This value is used to provide the best clock speed for data transfers. SDcard clock is performed by a state machine, not a DCM, to avoid specific hardware references and improve portability of the module. Transfers are performed at the highest possible frequency lower or equal to 25MHz for v1.00 SDcards and 50MHz for more recent SDcards (including SDHC and SDXC). The system clock frequencies that provide the best transfer performance are then multiples of 100MHz . * **//HIGH_SPEED_IF//** : allows or prevent using the 50MHz clock frequency when the SDcard supports that speed. 50MHz transfer clock might be problematic for data integrity because of connectors impedance, particularly when using the PmodSD with extension wires. Although there should not be problems with internal slots (like that of the Nexys4 board) this value is set to //False// by default to limit eventual problems. * **//WORD_SIZE_PW2//** : defines the data width of the buffers values 0, 1, 2 and 3 respectively code 8bits, 16bits, 32bits and 64bits. Although module's limit is 2048 bits, the design refuses more than 64 bits to limit hardware resource consumption. Default value is 0 (8bits data transfers). * **//LITTLE_ENDIAN//** : In the case of data width higher than 8 bits, tells if data on the SDcard should be considered big endian (False) of little endian (True). Computer standard is getting more and more attached to little endian, so this is the default value. * **//PRE_ERASE//** : To improve write performance, the SDcard is erase at insertion which leaves no room for mistake tolerance. setting this value to //False// will not perform that erase procedure. It will reduce performance but add some security for final user's data. ==== Warning ==== * For performance reasons, the module first erases all the content of the SDcard before any data writing. So inserting an SDcard in a slot controlled by this module will systematically and definitively erase all its content. * The module has an internal 2kBytes buffer which is designed to use minimal RAM resources. Because of SDcard technology, realtime applications should use an additionnal buffer of 20ms (roughly). Although this value is not a warranty to get proper real-time behavior, it is likely to work well in 99% of the cases. This buffer is not included in the module to allow a wider implementation choice to the developper. The real-time performance is SDcard dependant. ==== Error Codes ==== The //sd_error// output is asserted during one clock cycle if an error occurs. It is then possible to retreive the error code on the //debug// output. Otherwise, //debug// contains messages that help monitor data. Most of these messages come from the //SDcard_raw_access_v2// module. ^ //debug// ^ Status ^ Identifier ^ meaning ^ | 000000 | Info | NOTHING_TO_SAY | Everything is working properly | | 000001 | Info | END_OF_CARD | The module has reached the end of the SDcard. Data will not be accepted anymore. | | 000010 | Info | INIT | SDcard initialization pending | | 100000 | ERROR | NO_CARD | No SDcard is inserted in the slot. (//SD_CD// = '1') | | 100001 | ERROR | INVALID_CARD | The initialization sequence was not able to establish a connexion with the SDcard. | | 100011 | ERROR | WRITE_ERROR_FROM_CARD | The SDcard reported an internal write error. The //SDcard_raw_access_v2// module is not advanced enough to provide more information and this module is not able to handle it. | | 100100 | ERROR | INCONSISTENT_CSD | Configuration information retreived from the SDcard is not coherent. The module will not accept data. Checks are not extensive, so erroneous SDcards might still no trigger this error. | | 100101 | ERROR | TOO_MANY_CRC_RETRIES | The module failed to recover from a CRC error. There is high probability that the I/O lines between the FPGA and the SDcard slod do not have a good impedance or bandwidth. Waiting for //SDcard_raw_access_v2//'s lazy developper to handle retry management | | 100110 | ERROR | CARD_RESP_TIMEOUT | SDcard does not respond to a requested command. There is high probability that the card has been removed from its slot. | | 100111 | ERROR | WRITE_PROTECTED | The SDcard is write protected by its mechanical switch. No data will be accepted for storage | ==== Known Bugs ==== * The //SDcard_writestream// module does not forward warning messages from lower PHY layer * No Error checking is performed, if things go wrong and the //debug// output is not monitored, there is no warranty that storage is performed correctly. * when card has been totally filled, the END_OF_CARD message occurs too late, data has been accepted in buffer and there is no room to store it anymore. The exact amount of lost data actually depends on the input data rate.