QSPI I/O

QSPI I/O API

The following structures and functions are used for low-level QSPI I/O.

enum qspi_io_sample_edge_t

Enum type used to set which SCLK edge SIO is sampled on.

Values:

enumerator qspi_io_sample_edge_rising

Sample SIO on the rising edge

enumerator qspi_io_sample_edge_falling

Sample SIO on the falling edge

enum qspi_io_source_clock_t

Enum type used to set which of the two clock sources SCLK is derived from.

Values:

enumerator qspi_io_source_clock_ref

SCLK is derived from the 100 MHz reference clock

enumerator qspi_io_source_clock_xcore

SCLK is derived from the core clock

enum qspi_io_transfer_mode_t

Enum type used to specify whether or not nibbles should be swapped during transfers.

Values:

enumerator qspi_io_transfer_normal

Do not swap nibbles

enumerator qspi_io_transfer_nibble_swap

Swap nibbles

enum qspi_io_transaction_type_t

Enum type used to specify whether the next transaction will be a full speed QSPI transaction with dummy cycles, or a lower speed SPI read transaction without dummy cycles.

Values:

enumerator qspi_io_full_speed

The transaction will be full speed with dummy cycles

enumerator qspi_io_spi_read

The transaction will be low speed without dummy cycles

inline uint32_t qspi_io_byte_to_mosi(uint32_t x)

This function should only be called internally by qspi_io_mosi_out(). It performs the same transformation as QSPI_IO_BYTE_TO_MOSI() but also integrates the byte reversal and nibble swap performed by qspi_io_words_out().

Parameters

x – The byte to send out to MOSI.

Returns

the word to output to SIO.

inline uint32_t qspi_io_miso_to_byte(uint32_t x)

This function should only be called internally by qspi_io_miso_in().

When reading in a single byte in SPI mode, the word that is received on SIO needs to be transformed such that bit one from each nibble (which corresponds to SIO1, or MISO) is shifted into the correct bit position.

Parameters

x – The word received on SIO.

Returns

the byte received on MISO.

inline uint32_t qspi_io_nibble_swap(uint32_t word)

This function swaps the nibbles in each of the four bytes of word.

Parameters

word – The word to nibble swap.

Returns

the nibble swapped word.

inline void qspi_io_start_transaction(qspi_io_ctx_t *ctx, uint32_t first_word, size_t len, qspi_io_transaction_type_t transaction_type)

Begins a new QSPI I/O transaction by starting the clock, asserting CS, and sending out the first word which is typically a command.

Note

If more words or bytes need to be sent or received as part of this transaction, then the appropriate functions will need to be called immediately following this one. For example, qspi_io_bytes_out() then qspi_io_sio_direction_input() then qspi_io_bytes_in(). The “out” or “in” instruction in each must be executed within eight SCLK cycles of the preceding one, including the OUT instruction in qspi_io_start_transaction(). Some analysis may be necessary depending on the frequency of SCLK. These functions are all marked as inline to help keep them closer together by removing the overhead associated with function calls and to allow better optimization.

Note

It is likely not possible to follow an input with an output within a single transaction unless the frequency of SCLK is sufficiently slow. Fortunately in practice this rarely, if ever, required.

Parameters
  • ctx – Pointer to the QSPI I/O context.

  • first_word – The first word to output.

  • len – The total number of clock cycles in the transaction. CS will at some point during the transaction be setup to deassert automatically after this number of cycles.

  • transaction_type – Set to qspi_io_spi_read if the transaction will be a SPI read with no dummy cycles. This may run at a slower clock frequency in order to turn around SIO from output to input in time. Otherwise set to qspi_io_full_speed.

inline void qspi_io_bytes_out(const qspi_io_ctx_t *ctx, const qspi_io_transfer_mode_t transfer_mode, const uint8_t *data, size_t len)

Outputs a byte array to the QSPI interface. The byte array must start on a 4-byte boundary. This call must be made in time such that its OUT instruction executes within 8 SCLK cycles of the previous OUT instruction.

Parameters
  • ctx – Pointer to the QSPI I/O context.

  • transfer_mode – Can be either qspi_io_transfer_normal or qspi_io_transfer_nibble_swap. When qspi_io_transfer_nibble_swap, each byte transferred out is nibble swapped. Because the data is inherently sent out nibble swapped over the port, setting this to qspi_io_transfer_nibble_swap actually removes a nibble swap operation.

  • data – Pointer to the byte array to output. This MUST begin on a 4-byte boundary.

  • len – The number of bytes in data to output.

inline void qspi_io_words_out(const qspi_io_ctx_t *ctx, const qspi_io_transfer_mode_t transfer_mode, const uint32_t *data, size_t len)

Outputs a word array to the QSPI interface. This call must be made in time such that its OUT instruction executes within 8 SCLK cycles of the previous OUT instruction.

Parameters
  • ctx – Pointer to the QSPI I/O context.

  • transfer_mode – Can be either qspi_io_transfer_normal or qspi_io_transfer_nibble_swap. When qspi_io_transfer_nibble_swap, each byte transferred out is nibble swapped. Because the data is inherently sent out nibble swapped over the port, setting this to qspi_io_transfer_nibble_swap actually removes a nibble swap operation.

  • data – Pointer to the word array to output.

  • len – The number of words in data to output.

inline void qspi_io_mosi_out(const qspi_io_ctx_t *ctx, const qspi_io_transfer_mode_t transfer_mode, const uint8_t *data, size_t len)

Outputs a byte array to the QSPI interface over the single data line MOSI (SIO0). This call must be made in time such that its OUT instruction executes within 8 SCLK cycles of the previous OUT instruction.

Parameters
  • ctx – Pointer to the QSPI I/O context.

  • transfer_mode – Can be either qspi_io_transfer_normal or qspi_io_transfer_nibble_swap. When qspi_io_transfer_nibble_swap, each byte transferred out is nibble swapped.

  • data – Pointer to the byte array to output.

  • len – The number of words in data to output.

inline void qspi_io_sio_direction_input(qspi_io_ctx_t *ctx)

This must be called to change the direction of SIO from output to input before calling either qspi_io_bytes_in() or qspi_io_words_in(). This call must be made in time such that the call to port_set_buffered() completes before the sample edge of SCLK shifts in the first nibble of the next data word to be read. This also will setup CS to deassert at the end of the transaction while waiting for the previous output to complete.

Note

This is probably the most fragile function. Ensure that the port direction is turned around on time, and that the subsequent read IN instruction executes on time, by inspecting a VCD trace with both ports and instructions.

Parameters

ctx – Pointer to the QSPI I/O context.

inline void qspi_io_bytes_in(const qspi_io_ctx_t *ctx, const qspi_io_transfer_mode_t transfer_mode, uint8_t *data, uint32_t start_time, size_t len)

Inputs a byte array from the QSPI interface. The byte array must start on a 4-byte boundary. qspi_io_sio_direction_input() must have been called previously. This call must be made in time such that its IN instruction executes before start_time.

Note

The number of bytes input may be any number. However, if it is NOT a multiple of four, then this likely will need to be the last call in the transaction. This is because the shorter length of the last input chunk plus the extra overhead required to deal with the sub-word accesses will not allow subsequent I/O to keep up unless the SCLK frequency is significantly slower than the core clock.

Parameters
  • ctx – Pointer to the QSPI I/O context.

  • transfer_mode – Can be either qspi_io_transfer_normal or qspi_io_transfer_nibble_swap. When qspi_io_transfer_nibble_swap, each byte transferred in is nibble swapped. Because the data is inherently received nibble swapped over the port, setting this to qspi_io_transfer_nibble_swap actually removes a nibble swap operation.

  • data – Pointer to the byte array to save the received data to. This MUST begin on a 4-byte boundary.

  • start_time – The port time, relative to the beginning of the transfer, at which to input the first group of four bytes. This must line up with the last nibble of the fourth byte. If len is less than four, then it must line up with the last nibble of the last byte.

  • len – The number of bytes to input.

inline void qspi_io_words_in(const qspi_io_ctx_t *ctx, const qspi_io_transfer_mode_t transfer_mode, uint32_t *data, uint32_t start_time, size_t len)

Inputs a word array from the QSPI interface. qspi_io_sio_direction_input() must have been called previously. This call must be made in time such that its IN instruction executes before start_time.

Parameters
  • ctx – Pointer to the QSPI I/O context.

  • transfer_mode – Can be either qspi_io_transfer_normal or qspi_io_transfer_nibble_swap. When qspi_io_transfer_nibble_swap, each byte transferred in is nibble swapped. Because the data is inherently received nibble swapped over the port, setting this to qspi_io_transfer_nibble_swap actually removes a nibble swap operation.

  • data – Pointer to the word array to save the received data to.

  • start_time – The time, relative to the beginning of the transfer, at which to input the first word. This must line up with the last nibble of the first word.

  • len – The number of words to input.

inline void qspi_io_miso_in(const qspi_io_ctx_t *ctx, const qspi_io_transfer_mode_t transfer_mode, uint8_t *data, uint32_t start_time, size_t len)

Inputs a byte array from the QSPI interface over the single data line MISO (SIO1). qspi_io_sio_direction_input() must have been called previously. This call must be made in time such that its IN instruction executes before start_time.

Parameters
  • ctx – Pointer to the QSPI I/O context.

  • transfer_mode – Can be either qspi_io_transfer_normal or qspi_io_transfer_nibble_swap. When qspi_io_transfer_nibble_swap, each byte transferred in is nibble swapped.

  • data – Pointer to the byte array to save the received data to.

  • start_time – The time, relative to the beginning of the transfer, at which to input the first byte. This must line up with the last bit of the first byte.

  • len – The number of words to input.

inline void qspi_io_miso_poll(const qspi_io_ctx_t *ctx, const uint8_t mask, const uint8_t val, uint32_t start_time)

Polls the SPI interface by repeatedly receiving a byte over MISO until a specified condition is met. For each time the received byte does not meet the condition, the deassertion of CS is extended by eight SCLK cycles. qspi_io_sio_direction_input() must have been called previously. This call must be made in time such that its IN instruction executes before start_time.

Parameters
  • ctx – Pointer to the QSPI I/O context.

  • mask – The bitmask to apply to the received byte before comparing it to val;

  • val – The value that the received byte, masked with mask, must match before returning.

  • start_time – The time, relative to the beginning of the transfer, at which to input the first byte. This must line up with the last bit of the first byte.

inline void qspi_io_end_transaction(const qspi_io_ctx_t *ctx)

This sets up CS to deassert at the end of the transaction if it has not already, waits for the current QSPI transaction to complete, and then stops SCLK.

Parameters

ctx – Pointer to the QSPI I/O context.

void qspi_io_deinit(const qspi_io_ctx_t *ctx)

This disables and frees the clock block and all the ports associated with the QSPI I/O interface.

Parameters

ctx – Pointer to the QSPI I/O context. This should have been previously initialized with qspi_io_init().

void qspi_io_init(const qspi_io_ctx_t *ctx, qspi_io_source_clock_t source_clock)

This sets up the clock block and all the ports associated with the QSPI I/O interface. This must be called first prior to any other QSPI I/O function.

Parameters
  • ctx – Pointer to the QSPI I/O context. This must be initialized with the clock block and ports to use.

  • source_clock – Set to qspi_io_source_clock_ref to use the 100 MHz reference clock as the source for SCLK. Set to qspi_io_source_clock_xcore to use the xcore clock.

QSPI_IO_BYTE_TO_MOSI(x)

This macro may be used when sending out bytes that are only transmitted over the single data line MOSI (SIO0). The returned word should be transmitted using either qspi_io_start_transaction() or qspi_io_words_out(). Typically the byte argument to this macro is a constant known at compile time, like commands, as the compiler can perform this computation at compile time. For arrays of data, it may be more appropriate to use qspi_io_mosi_out() which more efficiently computes this transformation at run time on the fly.

When writing a single byte out in SPI mode, the byte needs to be transformed such that each nibble in the word that is sent out on SIO contains one bit from the byte in bit 0 (which corresponds to SIO0, or MOSI).

Parameters
  • x – The byte to send out to MOSI.

QSPI_IO_SETC_PAD_DELAY(n)
QSPI_IO_RESOURCE_SETCI(res, c)
QSPI_IO_RESOURCE_SETC(res, r)
QSPI_IO_SETSR(c)
QSPI_IO_CLRSR(c)
struct qspi_io_ctx_t
#include <qspi_io.h>

The context structure that must be passed to each of the qspi_io functions. Several of the members in this structure must be set by the application prior to calling either qspi_io_init() or qspi_io_start_transaction().