QSPI Flash RTOS Driver

This driver can be used to instantiate and control a Quad SPI flash I/O interface on xcore in an RTOS application.

Initialization API

The following structures and functions are used to initialize and start a QSPI flash driver instance.

typedef struct rtos_qspi_flash_struct rtos_qspi_flash_t

Typedef to the RTOS QSPI flash driver instance struct.

void rtos_qspi_flash_start(rtos_qspi_flash_t *ctx, unsigned priority)

Starts an RTOS QSPI flash driver instance. This must only be called by the tile that owns the driver instance. It may be called either before or after starting the RTOS, but must be called before any of the core QSPI flash driver functions are called with this instance.

rtos_qspi_flash_init() must be called on this QSPI flash driver instance prior to calling this.

Parameters
  • ctx – A pointer to the QSPI flash driver instance to start.

  • priority – The priority of the task that gets created by the driver to handle the QSPI flash interface.

void rtos_qspi_flash_init(rtos_qspi_flash_t *ctx, xclock_t clock_block, port_t cs_port, port_t sclk_port, port_t sio_port, qspi_io_source_clock_t source_clock, int full_speed_clk_divisor, uint32_t full_speed_sclk_sample_delay, qspi_io_sample_edge_t full_speed_sclk_sample_edge, uint32_t full_speed_sio_pad_delay, int spi_read_clk_divisor, uint32_t spi_read_sclk_sample_delay, qspi_io_sample_edge_t spi_read_sclk_sample_edge, uint32_t spi_read_sio_pad_delay, qspi_flash_page_program_cmd_t quad_page_program_cmd)

Initializes an RTOS QSPI flash driver instance. This must only be called by the tile that owns the driver instance. It may be called either before or after starting the RTOS, but must be called before calling rtos_qspi_flash_start() or any of the core QSPI flash driver functions with this instance.

Parameters
  • ctx – A pointer to the QSPI flash driver instance to initialize.

  • clock_block – The clock block to use for the qspi_io interface.

  • cs_port – The chip select port. MUST be a 1-bit port.

  • sclk_port – The SCLK port. MUST be a 1-bit port.

  • sio_port – The SIO port. MUST be a 4-bit port.

  • source_clock – The source clock to use for the QSPI I/O interface. Must be either qspi_io_source_clock_ref or qspi_io_source_clock_xcore.

  • full_speed_clk_divisor – The divisor to use for QSPI reads and writes as well as SPI writes. The frequency of SCLK will be set to: (F_src) / (2 * full_speed_clk_divisor) Where F_src is the frequency of the source clock specified by source_clock.

  • full_speed_sclk_sample_delay – Number of SCLK cycles to delay the sampling of SIO on input during a full speed transaction. Usually either 0 or 1 depending on the SCLK frequency.

  • full_speed_sclk_sample_edge – The SCLK edge to sample the SIO input on during a full speed transaction. May be either qspi_io_sample_edge_rising or qspi_io_sample_edge_falling.

  • full_speed_sio_pad_delay – Number of core clock cycles to delay sampling the SIO pads during a full speed transaction. This allows for more fine grained adjustment of sampling time. The value may be between 0 and 5.

  • spi_read_clk_divisor – The divisor to use for the clock when performing a SPI read. This may need to be slower than the clock used for writes and QSPI reads. This is because a small handful of instructions must execute to turn the SIO port around from output to input and they must execute within a single SCLK period during a SPI read. QSPI reads have dummy cycles where these instructions may execute which allows for a higher clock frequency. The frequency of SCLK will be set to: (F_src) / (2 * spi_read_clk_divisor) Where F_src is the frequency of the source clock specified by source_clock.

  • spi_read_sclk_sample_delay – Number of SCLK cycles to delay the sampling of SIO on input during a SPI read transaction. Usually either 0 or 1 depending on the SCLK frequency.

  • spi_read_sclk_sample_edge – The SCLK edge to sample the SIO input on during a SPI read transaction. May be either qspi_io_sample_edge_rising or qspi_io_sample_edge_falling.

  • spi_read_sio_pad_delay – Number of core clock cycles to delay sampling the SIO pads during a SPI read transaction. This allows for more fine grained adjustment of sampling time. The value may be between 0 and 5.

  • quad_page_program_cmd – The command that will be sent when rtos_qspi_flash_write() is called if quad_page_program_enable is true. This should be a value returned by the QSPI_IO_BYTE_TO_MOSI() macro.

RTOS_QSPI_FLASH_READ_CHUNK_SIZE
struct rtos_qspi_flash_struct
#include <rtos_qspi_flash.h>

Struct representing an RTOS QSPI flash driver instance.

The members in this struct should not be accessed directly.

Core API

The following functions are the core QSPI flash driver functions that are used after it has been initialized and started.

inline void rtos_qspi_flash_lock(rtos_qspi_flash_t *ctx)

Obtains a lock for exclusive access to the QSPI flash. This allows a thread to perform a sequence of operations (such as read, modify, erase, write) without the risk of another thread issuing a command in the middle of the sequence and corrupting the data in the flash.

If only a single atomic operation needs to be performed, such as a read, it is not necessary to call this to obtain the lock first. Each individual operation obtains and releases the lock automatically so that they cannot run while another thread has the lock.

The lock MUST be released when it is no longer needed by calling rtos_qspi_flash_unlock().

Parameters

ctx – A pointer to the QSPI flash driver instance to lock.

inline void rtos_qspi_flash_unlock(rtos_qspi_flash_t *ctx)

Releases a lock for exclusive access to the QSPI flash. The lock must have already been obtained by calling rtos_qspi_flash_lock().

Parameters

ctx – A pointer to the QSPI flash driver instance to unlock.

inline void rtos_qspi_flash_read(rtos_qspi_flash_t *ctx, uint8_t *data, unsigned address, size_t len)

This reads data from the flash in quad I/O mode. All four lines are used to send the address and to read the data.

Parameters
  • ctx – A pointer to the QSPI flash driver instance to use.

  • data – Pointer to the buffer to save the read data to.

  • address – The byte address in the flash to begin reading at. Only bits 23:0 contain the address. Bits 31:24 are actually transmitted to the flash during the first two dummy cycles following the three address bytes. Some flashes read the SIO lines during these first two dummy cycles to enable certain features, so this might be useful for some applications.

  • len – The number of bytes to read and save to data.

int rtos_qspi_flash_read_ll(rtos_qspi_flash_t *ctx, uint8_t *data, unsigned address, size_t len)

This is a lower level version of rtos_qspi_flash_read() that is safe to call from within ISRs. If a task currently own the flash lock, or if another core is actively doing a read with this function, then the read will not be performed and an error returned. It is up to the application to determine what it should do in this situation and to avoid a potential deadlock.

Note

It is not possible to call this from a task that currently owns the flash lock taken with rtos_qspi_flash_lock(). In general it is not advisable to call this from an RTOS task unless the small amount of overhead time that is introduced by rtos_qspi_flash_read() is unacceptable.

Parameters
  • ctx – A pointer to the QSPI flash driver instance to use.

  • data – Pointer to the buffer to save the read data to.

  • address – The byte address in the flash to begin reading at. Only bits 23:0 contain the address. Bits 31:24 are actually transmitted to the flash during the first two dummy cycles following the three address bytes. Some flashes read the SIO lines during these first two dummy cycles to enable certain features, so this might be useful for some applications.

  • len – The number of bytes to read and save to data.

Returns

  • 0 – if the flash was available and the read operation was performed.

  • -1 – if the flash was unavailable and the read could not be performed.

inline void rtos_qspi_flash_write(rtos_qspi_flash_t *ctx, const uint8_t *data, unsigned address, size_t len)

This writes data to the QSPI flash. If the data spans multiple pages then multiple page program commands will be issued. If ctx->quad_page_program_enable is true, then the command in ctx->quad_page_program_cmd is sent and all four SIO lines are used to send the address and data. Otherwise, the standard page program command is sent and only SIO0 (MOSI) is used to send the address and data.

The driver handles sending the write enable command, as well as waiting for the write to complete.

This function may return before the write operation is complete, as the actual write operation is queued and executed by a thread created by the driver.

Note

this function does NOT erase the flash first. Erase operations must be explicitly requested by the application.

Parameters
  • ctx – A pointer to the QSPI flash driver instance to use.

  • data – Pointer to the data to write to the flash.

  • address – The byte address in the flash to begin writing at. Only bits 23:0 contain the address. The byte in bits 31:24 is not sent.

  • len – The number of bytes to write to the flash.

inline void rtos_qspi_flash_erase(rtos_qspi_flash_t *ctx, unsigned address, size_t len)

This erases data from the QSPI flash. If the address range to erase spans multiple sectors, then all of these sectors will be erased by issuing multiple erase commands.

The driver handles sending the write enable command, as well as waiting for the write to complete.

This function may return before the write operation is complete, as the actual erase operation is queued and executed by a thread created by the driver.

Note

The smallest amount of data that can be erased is a 4k sector. This means that data outside the address range specified by address and len will be erased if the address range does not both begin and end at 4k sector boundaries.

Parameters
  • ctx – A pointer to the QSPI flash driver instance to use.

  • address – The byte address to begin erasing. This does not need to begin at a sector boundary, but if it does not, note that the entire sector that contains this address will still be erased.

  • len – The minimum number of bytes to erase. If address + len - 1 does not correspond to the last address within a sector, note that the entire sector that contains this address will still be erased.

inline size_t rtos_qspi_flash_size_get(rtos_qspi_flash_t *qspi_flash_ctx)

This gets the size in bytes of the flash chip.

Parameters

A – pointer to the QSPI flash driver instance to query.

Returns

the size in bytes of the flash chip.

inline size_t rtos_qspi_flash_page_size_get(rtos_qspi_flash_t *qspi_flash_ctx)

This gets the size in bytes of each page in the flash chip.

Parameters

A – pointer to the QSPI flash driver instance to query.

Returns

the size in bytes of the flash page.

inline size_t rtos_qspi_flash_page_count_get(rtos_qspi_flash_t *qspi_flash_ctx)

This gets the number of pages in the flash chip.

Parameters

A – pointer to the QSPI flash driver instance to query.

Returns

the number of pages in the flash chip.

inline size_t rtos_qspi_flash_sector_size_get(rtos_qspi_flash_t *qspi_flash_ctx)

This gets the sector size of the flash chip

Parameters

A – pointer to the QSPI flash driver instance to query.

Returns

the size in bytes of the smallest sector

RPC Initialization API

The following functions may be used to share a QSPI flash driver instance with other xcore tiles. Tiles that the driver instance is shared with may call any of the core functions listed above.

void rtos_qspi_flash_rpc_client_init(rtos_qspi_flash_t *qspi_flash_ctx, rtos_driver_rpc_t *rpc_config, rtos_intertile_t *host_intertile_ctx)

Initializes an RTOS QSPI flash driver instance on a client tile. This allows a tile that does not own the actual driver instance to use a driver instance on another tile. This will be called instead of rtos_qspi_flash_init(). The host tile that owns the actual instance must simultaneously call rtos_qspi_flash_rpc_host_init().

Parameters
  • qspi_flash_ctx – A pointer to the QSPI flash driver instance to initialize.

  • rpc_config – A pointer to an RPC config struct. This must have the same scope as qspi_flash_ctx.

  • host_intertile_ctx – A pointer to the intertile driver instance to use for performing the communication between the client and host tiles. This must have the same scope as qspi_flash_ctx.

void rtos_qspi_flash_rpc_host_init(rtos_qspi_flash_t *qspi_flash_ctx, rtos_driver_rpc_t *rpc_config, rtos_intertile_t *client_intertile_ctx[], size_t remote_client_count)

Performs additional initialization on a QSPI flash driver instance to allow client tiles to use the QSPI flash driver instance. Each client tile that will use this instance must simultaneously call rtos_qspi_flash_rpc_client_init().

Parameters
  • qspi_flash_ctx – A pointer to the QSPI flash driver instance to share with clients.

  • rpc_config – A pointer to an RPC config struct. This must have the same scope as qspi_flash_ctx.

  • client_intertile_ctx – An array of pointers to the intertile driver instances to use for performing the communication between the host tile and each client tile. This must have the same scope as qspi_flash_ctx.

  • remote_client_count – The number of client tiles to share this driver instance with.

void rtos_qspi_flash_rpc_config(rtos_qspi_flash_t *qspi_flash_ctx, unsigned intertile_port, unsigned host_task_priority)

Configures the RPC for a QSPI flash driver instance. This must be called by both the host tile and all client tiles.

On the client tiles this must be called after calling rtos_qspi_flash_rpc_client_init(). After calling this, the client tile may immediately begin to call the core QSPI flash functions on this driver instance. It does not need to wait for the host to call rtos_qspi_flash_start().

On the host tile this must be called both after calling rtos_qspi_flash_rpc_host_init() and before calling rtos_qspi_flash_start().

Parameters
  • qspi_flash_ctx – A pointer to the QSPI flash driver instance to configure the RPC for.

  • intertile_port – The port number on the intertile channel to use for transferring the RPC requests and responses for this driver instance. This port must not be shared by any other functions. The port must be the same for the host and all its clients.

  • host_task_priority – The priority to use for the task on the host tile that handles RPC requests from the clients.