CYGPKG_DEVS_DISK_MMC — eCos Support for MMC, SD, SDHC and SDIO media Cards


This package provides a disk device driver for two commercial flash memory card standards: MultiMedia Cards (MMC), and Secure Digital (SD) cards, including the high-capacity SDHC variant. The package also provides some (non-disk) basic SD I/O (SDIO) card support.

The MMC card implementation is intended to allow operation with memory cards compliant with the MultiMediaCard Standard version 2, as published by the MultiMediaCard Association. The SD implementation is intended to allow operation with cards compliant with the SD Physical Layer Specification version 2, as published by the SD Card Association.

This package evolved from an MMC-only implementation and as such the naming of certain aspects such as the CDL package name reflects that heritage. Any identifiers which reference MMC usually refer to either MMC or SD cards unless otherwise noted. Similarly, the package provides (limited) support for SDIO cards which do NOT require the presence of the CYGPKG_IO_DISK infrastructure and do not present as disk (memory) devices.

An MMC/SD card provides non-volatile storage in a small footprint (24mm * 32mm * 1.4mm), and weighing less than 2 grams. Typical card sizes are 128MB to 2GB, with an upper limit of 4GB for MMC and SDv1; and 32GB for SDHC cards in SDv2. It should be noted that these sizes are measured in millions of bytes, not 2^20. This driver provides support for 4GB MMC and SDv1 cards, although in practice, the FAT16 filesystem layout on such cards is unusual and may not be supported by a filesystem implementation using this driver. This problem should not occur with cards of size 2GB and less, or with SDHC cards.

At the hardware level there are two ways of accessing an MMC card. The first it to use a custom interface frequently known as either an an MCI (Multimedia Card Interface, although this allows supports for SD as well) or an MMC/SD bus. The second interface is via connection to an SPI bus. A card will detect the interface in use at run-time. The custom MCI interface allows for better performance but requires additional hardware. SPI peripheral support is more readily available on many existing CPUs. At this time, the SPI bus mode of interface does not support SD or SDIO cards in this driver.

Theoretically an MMC/SD memory card can be used with any file system. In practice all cards are formatted for PC compatibility, with a partition table in the first block and a single FAT file system on the rest of the card. The SPI mode driver always checks the format of the MMC card and will only allow access to a card if it is formatted this way. The MCI card bus driver can adapt to a card with no partition table as long as it contains a FAT filesystem starting from the first block. This non-standard format can sometimes be created by Windows when reformatting a corrupted card. This ability is controlled by the CYGSEM_IO_DISK_DETECT_FAT_BOOT CDL configuration option in the generic disk device driver package CYGPKG_IO_DISK.

Card Insertion and Removal

An MMC or SD socket allows cards to be removed and inserted at any time. It is a common feature for such sockets to contain a contact allowing the presence of cards to be detected. On some hardware that signal is routed to the processor allowing it to be sampled, usually connected as a GPIO signal or to an interrupt line (or to a GPIO interrupt if available).

In such cases, the MMC/SD bus driver layer in this package is able to be informed by the hardware MMC/SD bus driver of whether cards are present or not, and if possible, can be informed by an event callback that a card has just been inserted or removed. The SPI mode driver in this package does not yet support this feature.

If using the MMC/SD bus driver with appropriate hardware and driver support, the MMC/SD bus driver layer in this package can plug into the removeable media support offered by the generic disk driver layer (CYGPKG_IO_DISK) if the configuration option CYGFUN_DEVS_DISK_MMCSD_BUS_REMOVABLE_MEDIA_SUPPORT is enabled. This option may only be enabled if a hardware driver indicates that support is available. This facility allows for event notification when a card is inserted or removed from the socket. This information can be used directly by the application using the disk package APIs (see that package's documentation), or to allow use of, for example, the automounter support provided in the File I/O package (CYGPKG_IO_FILEIO).

If card detection by an interrupt is not possible, or if using the SPI bus driver, then the only time the device driver will detect removal events is when the next I/O operation happens. At that point, the operation will fail, typically with an error code such as ENODEV, ETIMEDOUT or possible EIO. It is left to higher-level code to recover from this error - the MMC/SD driver is unable to do anything since the card has gone. In the case of the eCosPro implementation of the FAT filesystem, it has been made robust to such events such that it will always be able to force an unmount using the umount_force function instead of the standard umount function.

Without card detection by interrupt, use of the automounter is not possible, therefore expected usage is that application code will explicitly mount the card before attempting any file I/O.

Irrespective of card detection abilities, it is expected that the application will umount the card before it is removed. Until unmounted, the system is likely to keep some disk blocks cached, for performance reasons. If the card is removed before the umount then it may end up with a corrupted file system. Application design to inform users of when it is safe to remove card media, and regular uses of the standard sync function will reduce the risk of file system corruption.

If card detection support is available, but is only pollable, rather than being connected to an interrupt, then this has limited benefits other than to accelerate the process of determining whether a card has been removed, which otherwise necessitate attempting operations and waiting for potential timeouts. In a future revision of this driver it may become possible to use a polling thread to check periodically for whether cards have been inserted or removed.

Write Protection and Security

The MMC and SD specifications allow cards to be write-protected in software. The current device driver does not yet make it possible to mark a card as write-protected, however it does respect the setting, and on mounting such a card will mark it internally as read-only. Any attempt to write to the card will fail with the error EROFS.

SD cards additionally feature a write-protect or 'lock' switch to indicate that cards must not be written to. This is not a physical protection however - instead it is expected that the lock switch position is detected by a contact in the socket, and it is for software to sample the state of that contact to determine whether the card is write-protected. Therefore the lock switch may not be respected if either the hardware or hardware driver does not support sampling the lock switch position from the socket. If sampling is supported however, the MMC/SD bus driver will respect that and mark the card internally as read-only.

SD (and to a lesser extent MMC) support other security features such as password protection and encryption. This driver does not yet support these features.

Configuration Options

CYGPKG_DEVS_DISK_MMC is a hardware package which should get loaded automatically when you configure for a suitable eCos target platform. In this case suitable means that the hardware either:

  1. has an MMC/SD socket connected to an SPI bus, that an SPI bus driver package exists and is also automatically loaded, and that the platform HAL provides information on how the card is connected to the SPI bus; or
  2. has an MMC/SD socket connected to a custom MCI interface's card bus and a driver package for the MCI exists and is also automatically loaded, or exists in the HAL.

For memory card support the package depends on support from the generic disk package CYGPKG_IO_DISK. That will not be loaded automatically: the presence of an MMC/SD socket on the board does not mean that the application has any need for a file system. Hence by default CYGPKG_DEVS_DISK_MMC will be inactive and will not contribute any code or data to the application's memory footprint. To activate the driver it will be necessary to add one or more packages to the configuration using ecosconfig add or the graphical configuration tool: the generic disk support CYGPKG_IO_DISK; usually a file system, CYGPKG_FS_FAT; support for the file I/O API CYGPKG_IO_FILEIO; and possibly additional support packages that may be needed by the file system, for example CYGPKG_LINUX_COMPAT for FAT. Depending on the template used to create the initial configuration some of these may be loaded already.

For non-memory SDIO cards it is possible for the package to be used without the disk I/O infrastructure. This is controlled by the CYGFUN_DEVS_DISK_MMCSD_SDIO option, which is available when the target platform indicates that it implements the relevant SDIO support. This allows for embedded (non-removable) SDIO device support on platforms without incurring the cost of including the unnecessary disk I/O code.

SPI mode operation configuration

The package provides two main configuration options when using the SPI mode of operation. CYGDAT_DEVS_DISK_MMC_SPI_DISK0_NAME specifies the name of the raw disk device, for example /dev/mmcdisk0. Allowing for partition tables that makes /dev/mmcdisk0/1 the first argument that shoul be passed to a mount call. If the hardware has multiple disk devices then each one will need a unique name. CYGIMP_DEVS_DISK_MMC_SPI_POLLED controls whether the SPI bus will be accessed in interrupt-driven or polled mode. It will default to interrupt-driven if the application is multi-threaded, which is assumed to be the case if the kernel is present. If the kernel is absent, for example in a RedBoot configuration, then the driver will default to polled mode. With some hardware polled mode may significantly increase disk throughput even in a multi-threaded application, but will consume cpu cycles that could be used by other threads.

MMC/SD card bus mode operation configuration

When using an MMC/SD card bus, there a number of CDL configuration settings to be aware of within this driver.

This CDL interface indicates the number of sockets capable of being supported by the MMC/SD card bus driver. It is usually implemented by either a hardware device driver or the platform HAL. At the present time there can only be 1 socket supported. This limitation is intended to be lifted in the future.
This option is present to allow SD card support to be disabled. SD card support is considered a superset of MMC support, and therefore it is not possible to disable MMC card support. If SD cards are not to be used, this option can be disabled to reduce code and memory footprints, along with slightly faster execution.
This option is present to allow SDIO card support to be enabled for targets that do not require memory MMC/SD card disk support. It is enabled by default when the target platform/variant indicates the requirement, and is not normally an option the user should need to manually configure.
Device name for the MMC/SD disk 0 device (CYGDAT_DEVS_DISK_MMCSD_BUS_DISK0_NAME)
This is the name of the raw disk or SDIO device. For disks it provides the prefix used for the separate disk device strings which are passed to the mount call. For example, a setting of /dev/mmcsd0/ would allow the first partition on the card to be accessed as /dev/mmcsd0/1, the second as /dev/mmcsd0/2, etc. /dev/mmcsd0/0 is a special device name used to access the entire device (including the partition table if present. Furthermore, the /dev/mmcsd0 device can be used for registering disk insertion/removal events with the disk layer. Consult the disk package documentation for details. The setting of this configuration option must end with a slash character ('/').
Hardware drivers support card detection (CYGINT_DEVS_DISK_MMCSD_BUS_CARD_DETECTION)
This CDL interface is implemented by a hardware device driver or platform HAL to indicate that it is able to report the presence or absence of cards.
This option is used to determine whether the MMC/SD bus layer will plug into the generic disk package's removeable media support, i.e. allowing notification of insertion or removal of cards. There is no point enabling this option without hardware and driver support, so it is not possible to enable it if CYGINT_DEVS_DISK_MMCSD_BUS_CARD_DETECTION has not been implemented. Some code can be saved if this option is disabled.
Detailed debugging output is possible via the diagnostic console. By default there is no debugging output, but setting this option to 1 or 2 will provide increased verbosity of debugging output.

Certain MMC/SD bus device drivers may provide support for multi-sector I/O. But if you are using the FAT filesystem, it will not take advantage of this facility unless you make a configuration change within the FAT filesystem package (CYGPKG_FS_FAT). You may increase the value of the "FAT block cache block size" (CYGNUM_FS_FAT_BLOCK_CACHE_BLOCKSIZE) to a higher power of two, in order to increase the number of sectors read or written in a chunk by the filesystem. This will cause multi-sector I/O to be employed within this driver. It has been noticed that certain models of SD cards (including some made by brand-name manufacturers like Sandisk and Kingston) perform disproportionately poorly if only using single block I/O; therefore we recommend that where possible you do adjust this option to a higher value (e.g. 16384). Note that memory usage will go up proportionately unless you also reduce the "FAT block cache memory size" (CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE), which you may wish to do depending on your memory requirements.

Additional SPI Mode Functionality

When using the SPI mode to access MMC cards, the disk driver package exports a variable cyg_mmc_spi_polled. This defaults to true or false depending on the configuration option CYGIMP_DEVS_DISK_MMC_SPI_POLLED. If the default mode is interrupt-driven then file I/O, including mount operations, are only allowed when the scheduler has started and interrupts have been enabled. Any attempts at file I/O earlier during system initialization, for example inside a C++ static constructor, will lock up. If it is necessary to perform file I/O at this time then the driver can be temporarily switched to polling mode before the I/O operation by setting cyg_mmc_spi_polled, and clearing it again after the I/O. Alternatively the default mode can be changed to polling by editing the configuration, and then the main() thread can change the mode to interrupt-driven once the scheduler has started.

Porting to New Hardware

SPI mode

Assuming that the MMC connector is hooked up to a standard SPI bus and that there is already an eCos SPI bus driver, porting the MMC disk driver package should be straightforward. Some other package, usually the platform HAL, should provide a cyg_spi_device structure cyg_spi_mmc_dev0. That structure contains the information needed by this package to interact with the MMC card via the usual SPI interface, for example how to activate the appropriate chip select. The platform HAL should also implement the CDL interface CYGINT_DEVS_DISK_MMC_SPI_CONNECTORS.

When defining cyg_spi_mmc_dev0 special care must be taken with the chip select. The MMC protocol is transaction-oriented. For example a read operation involves an initial command sent to the card, then a reply, then the actual data, and finally a checksum. The card's chip select must be kept asserted for the entire operation, and there can be no interactions with other devices on the same SPI bus during this time.

Optionally the platform HAL may define a macro HAL_MMC_SPI_INIT which will be invoked during a mount operation. This can take any hardware-specific actions that may be necessary, for example manipulating GPIO pins. Usually no such macro is needed because the hardware is set up during platform initialization.

On some targets there may be additional hardware to detect events such as card insertion or removal, but there is no support for exploiting such hardware at present.

Only a single MMC socket is supported. Given the nature of SPI buses there is a problem if the MMC socket is hooked up via an expansion connector rather than being attached to the main board. The platform HAL would not know about the socket so would not implement the CDL interface CYGINT_DEVS_DISK_MMC_SPI_CONNECTORS, and the ecos.db target entry would not include CYGPKG_DEVS_DISK_MMC. Because this is a hardware package it cannot easily be added by hand. Instead this scenario would require some editing of the existing platform HAL and target entry.

Card bus mode

Creating a hardware driver for accessing a card connected via a card bus requires a large amount of detailed description closely related to the specific code definitions. Therefore comprehensive descriptions of functionality has been provided in the mmcsd_bus.h header file in the include directory of this package. Drivers should include this file, although before doing so they must define the C preprocessor macro __MMCSD_DRIVER_PRIVATE in order to obtain definitions private to card bus drivers.

It is appropriate to provide a high-level overview of the porting process however. A driver package must implement the CDL interface CYGINT_DEVS_DISK_MMCSD_BUS_CONNECTORS to indicate the presence of a socket driven as a card bus. It may also implement CYGINT_DEVS_DISK_MMCSD_BUS_CARD_DETECTION if appropriate.

The driver in this package accesses the hardware driver through the abstraction of the card bus. This is done by instantiating a bus object using the CYG_MMCSD_BUS macro. This takes as arguments an opaque word of private data which may be useful to the hardware driver for identifying this bus or for any relevant bus state, and it also takes a function callback list. The CYG_MMCSD_BUS instantiation must exist in a module which is always included in the program image. This is usually performed when building the package by including it in the libextras.a library (which is converted to extras.o in the eCos build process and forcibly included in the program image that way).

This function callback list must be instantiated using the CYG_MMCSD_BUS_FUNS macro. This provides a table identifying driver functions to: initialise the bus at system startup time; (re-)initialise the socket when attempting to access a card in it for the first time; shutting down a socket to conserve power; doing specialised configuration options; preparing to select a card in a socket; sending a command to a card; and transferring data blocks to or from a card. At this point the byte and stream operations may be left as NULL and are only present for potential future expansion. Details on the purpose and arguments to these functions can be found in mmcsd_bus.h.

If the hardware and driver is capable of reporting card insertion/removal events, then notification of insertion or removal can be performed by calling the MMCSD_CARD_DETECT_EVENT() macro to register this with the MMC/SD layer, which will perform any further processing required. It must be called in DSR or thread context, not ISR context.

SDIO Support

Due to the undefined nature of SDIO card features, the package (currently) provides basic initialisation and device access support. Custom drivers will be needed to support specific SDIO cards or embedded devices. A simple API is exposed to allow the underlying SD commands to be passed to the SDIO card compliant with the SD Specifications Part E1 SDIO Simplified Specification Version 3.00 document as published by the SD Card Association.

A custom driver will reference the SDIO card via an I/O handle obtained via a call to the cyg_io_lookup() function. This handle can be used to perform MMC/SD bus driver “config” calls as well as perform SD operations via the SDIO specific functions exposed by this package. Currently two SDIO specific functions are available.

Cyg_ErrNo cyg_sdio_transaction_direct(cyg_io_handle_t handle,
                                      cyg_uint32      cmd,
                                      cyg_uint32      arg,
                                      cyg_uint32 *response);

The function above can be used to send card control commands (e.g. CMD0, CMD5, etc.) or the SDIO single register read/write CMD52 whereas the function below is an interface to the specific SDIO block data transfer CMD53 support.

Cyg_ErrNo cyg_sdio_transaction_extended(cyg_io_handle_t handle,
                                        cyg_uint32      arg,
                                        cyg_uint32      *response,
                                        cyg_bool        read,
                                        cyg_uint32      block_length,
                                        cyg_uint32      block_count,
                                        cyg_uint8 *buf);
  1. The current SDIO implementation is limited to platforms that define the HAL_MMCSD_PLF_SDIO_INIT_EARLY_EXIT macro since the detection of MMC/SD-vs-SDIO (and combo) cards during card specific initialisation has not yet been implemented.
  2. It is currently the responsibility for the custom SDIO device driver to perform card initialisation (CMD0, CMD5, et-al) via the exposed cyg_sdio_transaction_direct() API.