All of the functions described here are declared in the header file <cyg/nand/nand.h>, which should be included by all users of the NAND library.
Note: Most of the functions in the library are declared as returning int. Unless otherwise stated, all functions return 0 for success, or a negative eCos error code if something went wrong.
NAND devices are identified to the library by name. In many cases there will be only one, commonly named onboard, but this flexibility allows for easy expansion later without cross-device confusion.
Note: The naming of NAND devices is set up by the code that instantiates their drivers. Normally this is done by the platform HAL port.
__externC int cyg_nand_lookup(const char *devname, cyg_nand_device **dev_o); |
On success, *dev_o will be set up to point to a
cyg_nand_device struct. On failure, it will not; a return
code of -ENOENT signifies that the requested device
name was not found.
Applications will hardly, if ever, need to access the cyg_nand_device structs directly. The following members and convenience macros are most likely to be of relevance:
struct _cyg_nand_device_t {
...
cyg_nand_printf pf; // Diagnostic printf-like function for this device to use. May be changed at runtime.
...
size_t page_bits; // log2 of no of regular bytes per page
size_t spare_per_page; // OOB area size in bytes
size_t block_page_bits; // log2 of no of pages per eraseblock
size_t blockcount_bits; // log2 of number of blocks
size_t chipsize_log; // log2 of total chip size in BYTES.
...
};
#define CYG_NAND_BYTES_PER_PAGE(dev) (1<<(dev)->page_bits)
#define CYG_NAND_SPARE_PER_PAGE(dev) ((dev)->spare_per_page)
#define CYG_NAND_PAGES_PER_BLOCK(dev) (1<<(dev)->block_page_bits)
#define CYG_NAND_BLOCKCOUNT(dev) (1<<(dev)->blockcount_bits)
#define CYG_NAND_PAGECOUNT(dev) (NAND_BLOCKCOUNT(dev) * NAND_PAGES_PER_BLOCK(dev))
#define CYG_NAND_CHIPSIZE(dev) (1<<(dev)->chipsize_log)
#define CYG_NAND_APPSPARE_PER_PAGE(dev) ((dev)->oob->app_size)
|
NAND devices are arranged as a series of pages and eraseblocks. The eCos NAND library numbers pages and eraseblocks sequentially, both starting at 0 and continuing until the end of the chip. For example, eraseblock 0 might contain pages 0 through 63; eraseblock 1, pages 64 through 127; and so on.
| Caution |
This numbering scheme is independent of the device's addressing scheme. Take care, particularly when erasing blocks; some devices and some applications effectively express the location to erase as a page number (or, in NAND-speak, as the row address to erase from). |
| Warning |
Most NAND chip manufacturers document restrictions on the order in which pages may be written to their device. Typically, individual pages within an eraseblock must be written in sequential order starting from the first, and random-order writes are prohibited or unspecified. The eCos NAND library does not attempt to police such restrictions; if at all unsure, check the spec sheet for the part. You have been warned! |
NAND devices are widely considered to be arranged as one or more partitions, and the eCos NAND library supports this. However, there is no universal scheme for partition sizes to be supplied to the driver, unlike hard drives which encode a partition table into their first sector. Partition arrangements are often implicitly hardcoded, such as by byte address within the device, though they could be encoded in a "partition table", user-set, or even variable under software control by some esoteric rules. Therefore, every device driver is responsible for configuring its partition information as appropriate for the device, and this might for example appear as CDL options.
Tip: Be sure to read the notes associated with the device driver to understand how partitions are set up; if no notes are provided, look in its
devinitcode.
After a NAND device has been initialised, its device struct contains
a list of partitions. These are numbered from 0 and may go up to
CYGNUM_NAND_MAX_PARTITIONS-1. Before an
application can use the NAND device, it must obtain a partition
context (pointer) with the following call:
__externC cyg_nand_partition* cyg_nand_get_partition(cyg_nand_device *dev, unsigned partno); |
Note: This call returns a pointer to the partition struct, not an error code. If the given partition number is inactive or invalid, it returns NULL.
Every page on the NAND array has a small number of "spare" bytes associated with it. These are used by the NAND library to store the page's ECC; whatever is left over may be used by the application for whatever purposes may suit it.
Every page has CYG_NAND_APPSPARE_PER_PAGE(dev)
bytes of spare area available to the application. (This amount is implicit
from the driver configuration and cannot change during the lifetime of
a device.)
Note: Application spare bytes are not subject to the ECC. When reading the spare area data, you must be prepared to cope with the consequences of the (unlikely) event of a bit drop-out or other failure.
Now, finally, given a cyg_nand_partition*, your application can make use of the NAND array with the following functions:
__externC int cyg_nand_read_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, void * dest, size_t size, void * spare, size_t spare_size); |
Reads a single page and its spare area. The data read from the chip will be automatically ECC-checked and repaired if necessary. Parameters are as follows:
- ctx
The partition that data is to be read from.
- page
The page to be read, numbered from the start of the partition.. As a double-check, the library will refuse the operation with
-ENOENTif this address is not within partition ctx.Note: This was changed in application interface v2; earlier page and block addresses were device-relative.
- dest
Where to put the data. May be NULL, in which case the page data is not read.
- size
The maximum amount of data to read. (In any event, no more than a single page will be read, but if your application knows it doesn't need the whole page, you can place a cap here.)
- spare
Where to store the application data read from the spare area. This may be NULL if spare data is not required.
- spare_size
The maximum number of bytes to read from the spare area. This will not be more than
CYG_NAND_APPSPARE_PER_PAGE(dev)bytes.An error response of
-EIOmeans that a multiple-bit I/O error has occurred in the page data, which the ECC could not repair. The library stores the data read from the device in *dest and *spare on a best-effort basis; it should not be relied upon. The application should take steps to salvage what it can and erase the block as soon as possible.
__externC int cyg_nand_write_page(cyg_nand_partition *ctx, cyg_nand_page_addr page, const void * src, size_t size, const void * spare, size_t spare_size); |
Writes a single page and its spare area. The ECC will be computed and stored automatically. Parameters are as follows:
- ctx
The partition that data is to be written to.
- page
The page to be written, numbered from the start of the partition. As a double-check, the library will refuse the operation with
-ENOENTif this address is not within partition ctx.- src
Where to read the data from. May be NULL, in which case the page data is not written.
- size
The amount of data to write. (In any event, no more than a single page will be written.)
- spare
Where to read the data to go into the spare area; it will automatically be packed around the ECC as necessary. Again, this may be NULL if spare data is not required.
- spare_size
The number of bytes to write to the spare area. This should not be larger than
CYG_NAND_APPSPARE_PER_PAGE(dev); if it is, only that many bytes will be stored.An error response of
-EIOmeans that the page write failed. The application should copy out any data it wishes to keep from the rest of the eraseblock, then callcyg_nand_bbt_markbad()to put the block beyond use.
__externC int cyg_nand_erase_block(cyg_nand_partition *ctx, cyg_nand_block_addr blk); |
- ctx
The partition that data is to be erased from.
- blk
The block to be erased, numbered from the start of the partition. As a double-check, the library will refuse the operation with
-ENOENTif this address is not within partition ctx.An error response of
-EIOmeans that the block erase failed. In this case, the library automatically marks the block as bad, and the application need take no further action.
The following common error returns may be encountered when manipulating the NAND array using the above functions:
-EIOThe operation could not be completed due to an I/O error. This may require the application to take further action; check the details provided above for the call you have just made.
-ENOENTThe page or block address was not valid for the given partition.
-EINVALThe page (block) address was (within) a block that is marked bad.
The following functions are provided to allow applications to interact with the Bad Block Table:
typedef enum {
CYG_NAND_BBT_OK=0,
CYG_NAND_BBT_WORNBAD=1,
CYG_NAND_BBT_RESERVED=2,
CYG_NAND_BBT_FACTORY_BAD=3
} cyg_nand_bbt_status_t;
__externC int cyg_nand_bbt_query(cyg_nand_partition *ctx, cyg_nand_block_addr blk);
__externC int cyg_nand_bbt_markbad(cyg_nand_partition *ctx, cyg_nand_block_addr blk); |
To determine the status of an eraseblock, use
cyg_nand_bbt_query; this returns an enum from
cyg_nand_bbt_status_t or a negative eCos error code. All
blocks which return a non-0 enum value are considered inaccessible by
applications.
Occasionally, it is necessary for applications to mark a block
as bad. This most commonly happens when a write operation fails
(see the Section called Writing data above). To do this, call
cyg_nand_bbt_markbad; the return is 0 for success,
or a negative eCos error code. As with other calls, blocks
are numbered from 0 at the start of the partition, and internally
translated for the device as appropriate.
Both of these calls may foreseeably return
-ENOENT if the given block address was not valid,
or -EIO if something awful happened with the on-chip
bad block table.