This section describes the API between the FLASH IO library the FLASH device drivers.
The flash_info
structure is used by both
the FLASH IO library and the device driver.
struct flash_info { int block_size; // Assuming fixed size "blocks" int blocks; // Number of blocks int buffer_size; // Size of write buffer (only defined for some devices) unsigned long block_mask; void *start, *end; // Address range int init; // FLASH API initialised _printf *pf; // printf like function for diagnostics }; |
block_mask is used internally in the FLASH IO library. It contains a mask which can be used to turn an arbitrary address in flash to the base address of the block which contains the address.
There exists one global instance of this structure with the name
flash_info
. All calls into the device driver
makes use of this global structure to maintain state.
The FLASH IO library will call the following function to initialize the device driver:
externC int flash_hwr_init(void); |
The device driver should probe the hardware to see if the FLASH
devices exist. If it does it should fill in start, end,
blocks and block_size.
If the FLASH contains a write buffer
the size of this should be placed in buffer_size
. On successful probing the function should return
FLASH_ERR_OK. When things go wrong it can be
assumed that pf
points to a printf like
function for outputting error messages.
FLASH devices can be queried to return there manufacture ID, size etc. This function allows this information to be returned.
int flash_query(unsigned char *data); |
The caller must know the size of data to be returned and provide
an appropriately sized buffer pointed to be parameter
data
. This function is generally used by
flash_hwr_init()
.
So that the FLASH IO layer can erase a block of FLASH the following function should be provided.
int flash_erase_block(volatile flash_t *block, unsigned int block_size); |
The following function must be provided so that data can be written into the FLASH.
int flash_program_buf(volatile flash_t *addr, flash_t *data, int len, unsigned long block_mask, int buffer_size); |
The device will only be asked to program data in one block of the flash. The FLASH IO layer will break longer user requests into a smaller writes.
Some FLASH devices are not memory mapped so it is not possible to read there contents directly. The following function read a region of FLASH.
int flash_read_buf(volatile flash_t* addr, flash_t* data, int len); |
As with writing to the flash, the FLASH IO layer will break longer user requests for data into a number of reads which are at maximum one block in size.
A device which cannot be read directy should set
CYGSEM_IO_FLASH_READ_INDIRECT so that the IO layer
makes use of the flash_read_buf()
function.
Some flash devices allow blocks to be locked so that they cannot be written to. The device driver should provide the following functions to manipulate these locks.
int flash_lock_block(volatile flash_t *block); int flash_unlock_block(volatile flash_t *block, int block_size, int blocks); |
These functions are only used if CYGHWR_IO_FLASH_BLOCK_LOCKING
The functions flash_erase_block(),
flash_program_buf(), flash_read_buf(), flash_lock_block() and
flash_unlock_block()
return an error code which is specific
to the flash device. To map this into a FLASH IO error code, the
driver should provide the following function:
int flash_hwr_map_error(int err); |
Although a general function, the device driver is expected to
provide the implementation of the function
flash_code_overlaps()
.
The FLASH IO layer will manipulate the caches as required. The device drivers do not need to enable/disable caches when performing operations of the FLASH.
Device drivers should keep all chatter to a minimum when
CYGSEM_IO_FLASH_CHATTER is not defined. All output
should use the print function in the pf
in
flash_info
and not
diag_printf()
Device driver functions which manipulate the state of the flash so that it cannot be read from for program execute need to ensure there code is placed into RAM. The linker will do this if the appropriate attribute is added to the function. e.g:
int flash_program_buf(volatile flash_t *addr, flash_t *data, int len, unsigned long block_mask, int buffer_size) __attribute__ ((section (".2ram.flash_program_buf"))); |