I2S (Inter-IC Sound)¶
-
group
group_hal_i2s
-
High level interface for interacting with the Inter-IC Sound (I2S).
The I2S protocol is a asynchronous serial interface protocol. This driver supports both transmit and receive modes of operation. The communication frequency, sample rate, word size, and channel size can all be configured.
Features
Transmit and receive functionality
Configurable data rates
Configurable channel and word size
Configurable interrupt and callback assignment from I2S events - cyhal_i2s_event_t
Quick Start
Initialize an I2S instance using the cyhal_i2s_init and provide the transmit (tx) and/or receive (rx) pins. Call cyhal_i2s_start_tx and/or cyhal_i2s_start_rx
to enable transmit and/or receive functionality as desired.
See
Snippet 1: I2S Initialization and Configuration for example initialization as transmit or receive.The sclk frequency is determined as sclk = sample_rate_hz * channel_length * 2 (multiplying by 2 for 2 channels - left and right). The input clock must be a multiple of this sclk frequency; see the implementation specific documentation for the supported multipliers.note
The clock parameter (const cyhal_clock_t *clk) is optional and can be set to NULL to generate and use an available clock resource with a default frequency.
It is possible to use either only TX functionality, only RX functionality, or both RX and TX functionality at the same time. If RX and TX are both in use, the same sample rate, channel length, word length, sclk frequency will be used for both.
Code Snippets
Snippet 1: I2S Initialization and Configuration
This snippet initializes an I2S resource for transmit or receive and assigns the pins.
Initializing as I2S transmitter
Initializing as I2S receivercyhal_i2s_t i2s; cyhal_i2s_pins_t tx_pins = { .sck = P5_1, .ws = P5_2, .data = P5_3 }; cyhal_i2s_config_t config = { .is_tx_slave = false, .is_rx_slave = false, .mclk_hz = 0, .channel_length = 32, .word_length = 32, .sample_rate_hz = 44000 }; cy_rslt_t result = cyhal_i2s_init(&i2s, &tx_pins, NULL, NC, &config, NULL); if (CY_RSLT_SUCCESS != result) { // Handle error }
cyhal_i2s_t i2s; cyhal_i2s_pins_t rx_pins = { .sck = P5_4, .ws = P5_5, .data = P5_6 }; cyhal_i2s_config_t config = { .is_tx_slave = false, .is_rx_slave = true, .mclk_hz = 0, .channel_length = 32, .word_length = 32, .sample_rate_hz = 44000 }; cy_rslt_t result = cyhal_i2s_init(&i2s, NULL, &rx_pins, NC, &config, NULL); if (CY_RSLT_SUCCESS != result) { // Handle error }
Snippet 2: I2S Transmit One-shot
This snippet shows how to transmit data using cyhal_i2s_write_async when the entire sample is available at once.
static void i2s_event_handler_transmit_one_shot(void* arg, cyhal_i2s_event_t event) { // When we registered the callback, we set 'arg' to point to the i2s object cyhal_i2s_t* i2s = (cyhal_i2s_t*)arg; if (0u != (event & CYHAL_I2S_TX_EMPTY)) { cyhal_i2s_stop_tx(i2s); } } // Data to transmit, defined e.g. an array stored in flash extern const uint32_t* i2s_tx_buffer; extern const size_t i2s_tx_buffer_len; cy_rslt_t snippet_cyhal_i2s_async_transmit_one_shot(void) { cyhal_i2s_t i2s; // Initialize the object as shown in Snippet 1 // Register a callback and set the callback argument to be a pointer to the I2S object, so that // we can easily reference it from the callback handler. cyhal_i2s_register_callback(&i2s, &i2s_event_handler_transmit_one_shot, &i2s); // Subscribe to the TX Empty event so that we can stop the interface when the transfer is // complete cyhal_i2s_enable_event(&i2s, CYHAL_I2S_TX_EMPTY, CYHAL_ISR_PRIORITY_DEFAULT, true); cy_rslt_t result = cyhal_i2s_write_async(&i2s, i2s_tx_buffer, i2s_tx_buffer_len); if (CY_RSLT_SUCCESS == result) { result = cyhal_i2s_start_tx(&i2s); } return result; }
Snippet 3: I2S Transmit Streaming
This snippet shows how to transmit data using cyhal_i2s_write_async when sample data is being continuously loaded and transmitted (e.g. streaming over the network).
// We use a dual buffer system so that one buffer can be transmitting while the other is being // filled #define BUFFER_SIZE 128u const uint32_t tx_buffer0[BUFFER_SIZE]; const uint32_t tx_buffer1[BUFFER_SIZE]; const uint32_t* active_tx_buffer; const uint32_t* next_tx_buffer; static void i2s_event_handler_transmit_streaming(void* arg, cyhal_i2s_event_t event) { // When we registered the callback, we set 'arg' to point to the i2s object cyhal_i2s_t* i2s = (cyhal_i2s_t*)arg; if (0u != (event & CYHAL_I2S_ASYNC_TX_COMPLETE)) { // Flip the active and the next tx buffers const uint32_t* temp = active_tx_buffer; active_tx_buffer = next_tx_buffer; next_tx_buffer = temp; // Start writing the next buffer while the just-freed one is repopulated cy_rslt_t result = cyhal_i2s_write_async(i2s, active_tx_buffer, BUFFER_SIZE); if (CY_RSLT_SUCCESS == result) { // Load the next set of data into next_tx_buffer } } } cy_rslt_t snippet_cyhal_i2s_async_transmit_streaming(void) { cyhal_i2s_t i2s; // Initialize the object as shown in Snippet 1 // Register a callback and set the callback argument to be a pointer to the I2S object, so that // we can easily reference it from the callback handler. cyhal_i2s_register_callback(&i2s, &i2s_event_handler_transmit_streaming, &i2s); // Subscribe to the async complete event so that we can queue up another transfer when this one // completes cyhal_i2s_enable_event(&i2s, CYHAL_I2S_ASYNC_TX_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true); // Configure asynchronous transfers to use DMA to free up the CPU during transfers cy_rslt_t result = cyhal_i2s_set_async_mode(&i2s, CYHAL_ASYNC_DMA, CYHAL_DMA_PRIORITY_DEFAULT); if (CY_RSLT_SUCCESS == result) { // Populate initial data in the two tx buffers (e.g. by streaming over the network) active_tx_buffer = tx_buffer0; next_tx_buffer = tx_buffer1; result = cyhal_i2s_write_async(&i2s, active_tx_buffer, BUFFER_SIZE); } if (CY_RSLT_SUCCESS == result) { result = cyhal_i2s_start_tx(&i2s); } return result; }
Snippet 4: I2S Receive
This snippet shows how to receive data using cyhal_i2s_read_async.
// We use a dual buffer system so that one buffer can be filling while the other is being processed #define BUFFER_SIZE 128u uint32_t rx_buffer0[BUFFER_SIZE]; uint32_t rx_buffer1[BUFFER_SIZE]; uint32_t* active_rx_buffer; uint32_t* full_rx_buffer; static void i2s_event_handler_receive(void* arg, cyhal_i2s_event_t event) { // When we registered the callback, we set 'arg' to point to the i2s object cyhal_i2s_t* i2s = (cyhal_i2s_t*)arg; if (0u != (event & CYHAL_I2S_ASYNC_RX_COMPLETE)) { // Flip the active and the next rx buffers uint32_t* temp = active_rx_buffer; active_rx_buffer = full_rx_buffer; full_rx_buffer = temp; // Start reading into the next buffer while the just-filled one is being processed cy_rslt_t result = cyhal_i2s_read_async(i2s, active_rx_buffer, BUFFER_SIZE); if (CY_RSLT_SUCCESS == result) { // Process the data in the full_rx_buffer } } } cy_rslt_t snippet_cyhal_i2s_async_receive(void) { cyhal_i2s_t i2s; // Initialize the object as shown in Snippet 1 // Register a callback and set the callback argument to be a pointer to the I2S object, so that // we can easily reference it from the callback handler. cyhal_i2s_register_callback(&i2s, &i2s_event_handler_receive, &i2s); // Subscribe to the async complete event so that we can queue up another transfer when this one // completes cyhal_i2s_enable_event(&i2s, CYHAL_I2S_ASYNC_RX_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true); // Configure asynchronous transfers to use DMA to free up the CPU during transfers cy_rslt_t result = cyhal_i2s_set_async_mode(&i2s, CYHAL_ASYNC_DMA, CYHAL_DMA_PRIORITY_DEFAULT); if (CY_RSLT_SUCCESS == result) { active_rx_buffer = rx_buffer0; full_rx_buffer = rx_buffer1; result = cyhal_i2s_read_async(&i2s, active_rx_buffer, BUFFER_SIZE); } if (CY_RSLT_SUCCESS == result) { result = cyhal_i2s_start_rx(&i2s); } return result; }
More Information
Code examples (Github)
Typedefs
-
typedef void (*
cyhal_i2s_event_callback_t
)(void *callback_arg, cyhal_i2s_event_t event)¶ Handler for I2S event callbacks.
Enums
-
enum
cyhal_i2s_event_t
¶ cyhal_i2s_event_t: I2S events.
Values:
-
enumerator
CYHAL_I2S_TX_NOT_FULL
¶ TX HW Buffer is not full.
-
enumerator
CYHAL_I2S_TX_HALF_EMPTY
¶ TX HW Buffer is half empty.
-
enumerator
CYHAL_I2S_TX_EMPTY
¶ TX HW Buffer is Empty.
-
enumerator
CYHAL_I2S_TX_OVERFLOW
¶ Attempt to write when TX HW Buffer is full.
-
enumerator
CYHAL_I2S_TX_UNDERFLOW
¶ Interface ready to transfer data but HW TX buffer is empty.
-
enumerator
CYHAL_I2S_ASYNC_TX_COMPLETE
¶ Pending async transmit is complete (but the HW buffer may still contain unsent data)
-
enumerator
CYHAL_I2S_RX_NOT_EMPTY
¶ RX HW Buffer is not Empty.
-
enumerator
CYHAL_I2S_RX_HALF_FULL
¶ RX HW Buffer is half full.
-
enumerator
CYHAL_I2S_RX_FULL
¶ RX HW Buffer is FULL.
-
enumerator
CYHAL_I2S_RX_OVERFLOW
¶ Attempt to write when RX HW Buffer is full.
-
enumerator
CYHAL_I2S_RX_UNDERFLOW
¶ Attempt to read when HW RX buffer is empty.
-
enumerator
CYHAL_I2S_ASYNC_RX_COMPLETE
¶ Pending async receive is complete.
-
enumerator
Functions
-
cy_rslt_t
cyhal_i2s_init
(cyhal_i2s_t *obj, const cyhal_i2s_pins_t *tx_pins, const cyhal_i2s_pins_t *rx_pins, cyhal_gpio_t mclk, const cyhal_i2s_config_t *config, cyhal_clock_t *clk)¶ Initialize the I2S peripheral.
It sets the default parameters for I2S peripheral, and configures its specifieds pins. If only one direction is to be used, then the pins for the other direction need not be specified (i.e. they may be set to NC). For example, if only RX is needed, tx_sck, tx_ws, and tx_sdo may all be set to NC. If one pin is specified for a direction, all pins for that direction must be specified.
- Parameters
obj – [out] Pointer to an I2S object. The caller must allocate the memory for this object but the init function will initialize its contents.
tx_pins – [in] Pins for I2S transmit. If NULL, transmit functionality will be disabled.
rx_pins – [in] Pins for I2S receive. If NULL, receive functionality will be disabled.
mclk – [in] The master clock input pin, if an external clock should be used for the I2S block. Set to NC if an internal clock source should be used.
config – [in] Initial block configuration
clk – [in] Clock source to use for this instance. If NULL, a dedicated clock divider will be allocated for this instance.
- Returns
The status of the init request
-
void
cyhal_i2s_free
(cyhal_i2s_t *obj)¶ Deinitialize the i2s object.
- Parameters
obj – [inout] The i2s object
-
cy_rslt_t
cyhal_i2s_set_sample_rate
(cyhal_i2s_t *obj, uint32_t sample_rate_hz)¶ Set the I2S sample rate.
- Parameters
obj – [in] The I2S object
sample_rate_hz – [in] Sample rate in Hz
- Returns
The status of the set sample rate request
-
cy_rslt_t
cyhal_i2s_start_tx
(cyhal_i2s_t *obj)¶ Starts transmitting data.
Transmission will continue until it is stopped by calling cyhal_i2s_stop_tx.
- Parameters
obj – [in] The I2S object
- Returns
The status of the start request.
-
cy_rslt_t
cyhal_i2s_stop_tx
(cyhal_i2s_t *obj)¶ Stops transmitting data.
This immediately terminates transmission.
- Parameters
obj – [in] The I2S object
- Returns
The status of the stop request.
-
cy_rslt_t
cyhal_i2s_clear_tx
(cyhal_i2s_t *obj)¶ Clears the tx hardware buffer.
- Parameters
obj – [in] The i2s peripheral
- Returns
The status of the clear request
-
cy_rslt_t
cyhal_i2s_start_rx
(cyhal_i2s_t *obj)¶ Starts receiving data.
Data will continue to be received until it is stopped by calling cyhal_i2s_stop_rx.
- Parameters
obj – [in] The I2S object
- Returns
The status of the start request.
-
cy_rslt_t
cyhal_i2s_stop_rx
(cyhal_i2s_t *obj)¶ Stops receiving data.
This immediately terminates data receipt.
- Parameters
obj – [in] The I2S object
- Returns
The status of the stop request.
-
cy_rslt_t
cyhal_i2s_clear_rx
(cyhal_i2s_t *obj)¶ Clears the rx hardware buffer.
- Parameters
obj – [in] The i2s peripheral
- Returns
The status of the clear request
-
cy_rslt_t
cyhal_i2s_read
(cyhal_i2s_t *obj, void *data, size_t *length)¶ Read data synchronously.
This will read the number of words specified by the length parameter, or the number of words that are currently available in the receive buffer, whichever is less, then return. The value pointed to by length will be updated to reflect the number of words that were actually read.
note
Each word will be aligned to the next largest power of 2. For example, if the word length is 16 bits, each word will consume two bytes. But if the word length is 20, each word will consume 32 bytes.
- Parameters
obj – [in] The I2S object
data – [out] The buffer for receiving
length – [inout] Number of words to (as configured in cyhal_i2s_config_t.word_length) read, updated with the number actually read
- Returns
The status of the read request
- Returns
The status of the read request
-
cy_rslt_t
cyhal_i2s_write
(cyhal_i2s_t *obj, const void *data, size_t *length)¶ Send data synchronously.
This will write either length words or until the write buffer is full, whichever is less, then return. The value pointed to by length will be updated to reflect the number of words that were actually written.
note
This function only queues data into the write buffer; it does not block until the data has all been sent out over the wire.
note
Each word will be aligned to the next largest power of 2. For example, if the word length is 16 bits, each word will consume two bytes. But if the word length is 20, each word will consume 32 bytes.
- Parameters
obj – [in] The I2S object
data – [in] The buffer for sending
length – [inout] Number of words to write (as configured in cyhal_i2s_config_t.word_length, updated with the number actually written
- Returns
The status of the write request
-
bool
cyhal_i2s_is_tx_enabled
(cyhal_i2s_t *obj)¶ Checks if the transmit functionality is enabled for the specified I2S peripheral (regardless of whether data is currently queued for transmission).
The transmit functionality can be enabled by calling cyhal_i2s_start_tx and disabled by calling cyhal_i2s_stop_tx
- Parameters
obj – [in] The I2S peripheral to check
- Returns
Whether the I2S transmit function is enabled.
-
bool
cyhal_i2s_is_tx_busy
(cyhal_i2s_t *obj)¶ Checks if the specified I2S peripheral is transmitting data, including if a pending async transfer is waiting to write more data to the transmit buffer.
- Parameters
obj – [in] The I2S peripheral to check
- Returns
Whether the I2S is still transmitting
-
bool
cyhal_i2s_is_rx_enabled
(cyhal_i2s_t *obj)¶ Checks if the receive functionality is enabled for the specified I2S peripheral (regardless of whether any unread data has been received).
The receive functionality can be enabled by calling cyhal_i2s_start_rx and disabled by calling cyhal_i2s_stop_rx
- Parameters
obj – [in] The I2S peripheral to check
- Returns
Whether the I2S receive function is enabled.
-
bool
cyhal_i2s_is_rx_busy
(cyhal_i2s_t *obj)¶ Checks if the specified I2S peripheral has received data that has not yet been read out of the hardware buffer.
This includes if an async read transfer is pending.
- Parameters
obj – [in] The I2S peripheral to check
- Returns
Whether the I2S is still transmitting
-
cy_rslt_t
cyhal_i2s_read_async
(cyhal_i2s_t *obj, void *rx, size_t rx_length)¶ Start I2S asynchronous read.
This will transfer rx_length words into the buffer pointed to by rx in the background. When the requested quantity of data has been read, the CYHAL_I2S_ASYNC_RX_COMPLETE event will be raised. See cyhal_i2s_register_callback and cyhal_i2s_enable_event.
cyhal_i2s_set_async_mode can be used to control whether this uses DMA or a CPU-driven transfer.
note
Each word will be aligned to the next largest power of 2. For example, if the word length is 16 bits, each word will consume two bytes. But if the word length is 20, each word will consume 32 bytes.
- Parameters
obj – [in] The I2S object
rx – [out] The receive buffer.
rx_length – [in] Number of words (as configured in cyhal_i2s_config_t.word_length) to read.
- Returns
The status of the read_async request
-
cy_rslt_t
cyhal_i2s_write_async
(cyhal_i2s_t *obj, const void *tx, size_t tx_length)¶ Start I2S asynchronous write.
This will transfer tx_length words into the tx buffer in the background. When the requested quantity of data has been queued in the transmit buffer, the CYHAL_I2S_ASYNC_TX_COMPLETE event will be raised. See cyhal_i2s_register_callback and cyhal_i2s_enable_event.
cyhal_i2s_set_async_mode can be used to control whether this uses DMA or a SW (CPU-driven) transfer.
note
Each word will be aligned to the next largest power of 2. For example, if the word length is 16 bits, each word will consume two bytes. But if the word length is 20, each word will consume 32 bytes.
- Parameters
obj – [in] The I2S object
tx – [in] The transmit buffer.
tx_length – [in] The number of words to transmit.
- Returns
The status of the transfer_async request
-
cy_rslt_t
cyhal_i2s_set_async_mode
(cyhal_i2s_t *obj, cyhal_async_mode_t mode, uint8_t dma_priority)¶ Set the mechanism that is used to perform I2S asynchronous transfers.
The default is SW.
warning
The effect of calling this function while an async transfer is pending is undefined.
- Parameters
obj – [in] The I2S object
mode – [in] The transfer mode
dma_priority – [in] The priority, if DMA is used. Valid values are the same as for cyhal_dma_init. If DMA is not selected, the only valid value is CYHAL_DMA_PRIORITY_DEFAULT, and no guarantees are made about prioritization.
- Returns
The status of the set mode request
-
bool
cyhal_i2s_is_read_pending
(cyhal_i2s_t *obj)¶ Checks if the specified I2S peripheral is in the process of reading data from the hardware buffer into RAM.
note
: This only checks whether there is an ongoing transfer (e.g. via cyhal_i2s_read_async) into RAM from the I2S peripheral's hardware buffer. It does not check whether unread data exists in the hardware buffer.
- Parameters
obj – [in] The I2S peripheral to check
- Returns
Whether an asynchronous read operation is still in progress
-
bool
cyhal_i2s_is_write_pending
(cyhal_i2s_t *obj)¶ Checks if the specified I2S peripheral is in the process of writing data into the hardware buffer.
note
: This only checks whether there is an ongoing transfer (e.g. via cyhal_i2s_transfer_async) from RAM into the I2S peripheral's hardware buffer. It does not check whether unwritten data exists in the hardware buffer.
- Parameters
obj – [in] The I2S peripheral to check
- Returns
Whether an asynchronous write operation is still in progress
-
cy_rslt_t
cyhal_i2s_abort_read_async
(cyhal_i2s_t *obj)¶ Abort I2S asynchronous read.
This function does not perform any validation before aborting the transfer. Any validation which is required is the responsibility of the application.
- Parameters
obj – [in] The I2S object
- Returns
The status of the abort_async_read request
-
cy_rslt_t
cyhal_i2s_abort_write_async
(cyhal_i2s_t *obj)¶ Abort I2S asynchronous write.
This function does not perform any validation before aborting the transfer. Any validation which is required is the responsibility of the application.
- Parameters
obj – [in] The I2S object
- Returns
The status of the abort_async_write request
-
void
cyhal_i2s_register_callback
(cyhal_i2s_t *obj, cyhal_i2s_event_callback_t callback, void *callback_arg)¶ Register an I2S callback handler.
This function will be called when one of the events enabled by cyhal_i2s_enable_event occurs.
- Parameters
obj – [in] The I2S object
callback – [in] The callback handler which will be invoked when the interrupt fires
callback_arg – [in] Generic argument that will be provided to the callback when called
-
void
cyhal_i2s_enable_event
(cyhal_i2s_t *obj, cyhal_i2s_event_t event, uint8_t intr_priority, bool enable)¶ Configure I2S events.
When an enabled event occurs, the function specified by cyhal_i2s_register_callback will be called.
- Parameters
obj – [in] The I2S object
event – [in] The I2S event type
intr_priority – [in] The priority for NVIC interrupt events
enable – [in] True to turn on specified events, False to turn off
-
struct
cyhal_i2s_pins_t
¶ - #include <>
Pins to use for one I2S direction.
Public Members
-
cyhal_gpio_t
sck
¶ Clock pin.
-
cyhal_gpio_t
ws
¶ Word select.
-
cyhal_gpio_t
data
¶ Data pin (sdo or sdi)
-
cyhal_gpio_t
-
struct
cyhal_i2s_config_t
¶ - #include <>
I2S Configuration.
Public Members
-
bool
is_tx_slave
¶ Configure TX to operate a slave (true) or master (false)
-
bool
is_rx_slave
¶ Configure RX to operate a slave (true) or master (false)
-
uint32_t
mclk_hz
¶ Frequency, in hertz, of the master clock if it is provided by an external pin.
If the mclk pin is not NC, this must be nonzero. If the mclk pin is NC, this must be zero.
-
uint8_t
channel_length
¶ Number of bits in each channel.
See the implementation specific documentation for supported values.
-
uint8_t
word_length
¶ Number of bits in each word.
Must be less than or equal to channel_length. If word_length < channel_length, the excess bits will be padded with 0’s.
-
uint32_t
sample_rate_hz
¶ Sample rate in Hz.
-
bool