FLASH device API

This section describes the API between the FLASH IO library the FLASH device drivers.

The flash_info structure

The flash_infostructure 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.

Initializing the device driver

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.

Querying the FLASH

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().

Erasing a block of FLASH

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);

Programming a region of FLASH

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.

Reading a region from FLASH

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.

Locking and unlocking FLASH blocks

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

Mapping FLASH error codes to FLASH IO error codes

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);

Determining if code is in FLASH

Although a general function, the device driver is expected to provide the implementation of the function flash_code_overlaps().

Implementation Notes

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")));