1 /* 2 * Copyright (c) 2015 - 2025, Nordic Semiconductor ASA 3 * All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, this 11 * list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the copyright holder nor the names of its 18 * contributors may be used to endorse or promote products derived from this 19 * software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #ifndef NRFX_I2S_H__ 35 #define NRFX_I2S_H__ 36 37 #include <nrfx.h> 38 #include <haly/nrfy_i2s.h> 39 40 #ifdef __cplusplus 41 extern "C" { 42 #endif 43 44 /* On devices with single instance (with no id) use instance 0. */ 45 #if defined(NRF_I2S) && defined(NRFX_I2S_ENABLED) && !defined(NRFX_I2S0_ENABLED) 46 #define NRFX_I2S0_ENABLED 1 47 #endif 48 49 /** 50 * @defgroup nrfx_i2s I2S driver 51 * @{ 52 * @ingroup nrf_i2s 53 * @brief Inter-IC Sound (I2S) peripheral driver. 54 */ 55 56 /** @brief I2S driver configuration structure. */ 57 typedef struct 58 { 59 uint32_t sck_pin; ///< SCK pin number. 60 uint32_t lrck_pin; ///< LRCK pin number. 61 uint32_t mck_pin; ///< MCK pin number. 62 /**< Optional. Use @ref NRF_I2S_PIN_NOT_CONNECTED 63 * if this signal is not needed. */ 64 uint32_t sdout_pin; ///< SDOUT pin number. 65 /**< Optional. Use @ref NRF_I2S_PIN_NOT_CONNECTED 66 * if this signal is not needed. */ 67 uint32_t sdin_pin; ///< SDIN pin number. 68 /**< Optional. Use @ref NRF_I2S_PIN_NOT_CONNECTED 69 * if this signal is not needed. */ 70 uint8_t irq_priority; ///< Interrupt priority. 71 nrf_i2s_mode_t mode; ///< Mode of operation (master or slave). 72 nrf_i2s_format_t format; ///< I2S frame format. 73 nrf_i2s_align_t alignment; ///< Alignment of sample within a frame. 74 nrf_i2s_swidth_t sample_width; ///< Sample width. 75 nrf_i2s_channels_t channels; ///< Enabled channels. 76 nrf_i2s_mck_t mck_setup; ///< Master clock generator setup. 77 nrf_i2s_ratio_t ratio; ///< MCK/LRCK ratio. 78 #if NRF_I2S_HAS_CLKCONFIG 79 nrf_i2s_clksrc_t clksrc; ///< Clock source selection. 80 bool enable_bypass; ///< Bypass clock generator. MCK will be equal to source input. 81 #endif 82 bool skip_gpio_cfg; ///< Skip GPIO configuration of pins. 83 /**< When set to true, the driver does not modify 84 * any GPIO parameters of the used pins. Those 85 * parameters are supposed to be configured 86 * externally before the driver is initialized. */ 87 bool skip_psel_cfg; ///< Skip pin selection configuration. 88 /**< When set to true, the driver does not modify 89 * pin select registers in the peripheral. 90 * Those registers are supposed to be set up 91 * externally before the driver is initialized. 92 * @note When both GPIO configuration and pin 93 * selection are to be skipped, the structure 94 * fields that specify pins can be omitted, 95 * as they are ignored anyway. */ 96 } nrfx_i2s_config_t; 97 98 #if NRFX_API_VER_AT_LEAST(3, 3, 0) || defined(__NRFX_DOXYGEN__) 99 /** @brief I2S driver buffers structure. */ 100 typedef nrfy_i2s_xfer_desc_t nrfx_i2s_buffers_t; 101 #else 102 typedef nrfy_i2s_buffers_t nrfx_i2s_buffers_t; 103 #endif 104 105 /** @brief I2S driver instance structure. */ 106 typedef struct 107 { 108 NRF_I2S_Type * p_reg; ///< Pointer to a structure with I2S registers. 109 uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only. 110 } nrfx_i2s_t; 111 112 /** @brief Macro for creating an I2S driver instance. */ 113 #define NRFX_I2S_INSTANCE(id) \ 114 { \ 115 .p_reg = NRFX_CONCAT(NRF_, I2S, id), \ 116 .drv_inst_idx = NRFX_CONCAT(NRFX_I2S, id, _INST_IDX), \ 117 } 118 119 #ifndef __NRFX_DOXYGEN__ 120 enum { 121 /* List all enabled driver instances (in the format NRFX_\<instance_name\>_INST_IDX). */ 122 NRFX_INSTANCE_ENUM_LIST(I2S) 123 NRFX_I2S_ENABLED_COUNT 124 }; 125 #endif 126 127 /** 128 * @brief I2S driver default configuration. 129 * 130 * This configuration sets up I2S with the following options: 131 * - master mode 132 * - i2s data format 133 * - left alignment 134 * - sample width 16 bit 135 * - left channel enabled 136 * - MCK frequency 4 MHz 137 * - LRCK frequency 125 kHz 138 * 139 * @param[in] _pin_sck SCK pin number. 140 * @param[in] _pin_lrck LRCK pin number. 141 * @param[in] _pin_mck MCK pin number. 142 * @param[in] _pin_sdout SDOUT pin number. 143 * @param[in] _pin_sdin SDIN pin number. 144 */ 145 #define NRFX_I2S_DEFAULT_CONFIG(_pin_sck, _pin_lrck, _pin_mck, _pin_sdout, _pin_sdin) \ 146 { \ 147 .sck_pin = _pin_sck, \ 148 .lrck_pin = _pin_lrck, \ 149 .mck_pin = _pin_mck, \ 150 .sdout_pin = _pin_sdout, \ 151 .sdin_pin = _pin_sdin, \ 152 .irq_priority = NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY, \ 153 .mode = NRF_I2S_MODE_MASTER, \ 154 .format = NRF_I2S_FORMAT_I2S, \ 155 .alignment = NRF_I2S_ALIGN_LEFT, \ 156 .sample_width = NRF_I2S_SWIDTH_16BIT, \ 157 .channels = NRF_I2S_CHANNELS_LEFT, \ 158 .mck_setup = NRF_I2S_MCK_32MDIV8, \ 159 .ratio = NRF_I2S_RATIO_32X, \ 160 NRFX_COND_CODE_1(NRF_I2S_HAS_CLKCONFIG, \ 161 (.clksrc = NRF_I2S_CLKSRC_PCLK32M, \ 162 .enable_bypass = false,), \ 163 ()) \ 164 } 165 166 #define NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED (1UL << 0) 167 /**< The application must provide buffers that are to be used in the next 168 * part of the transfer. A call to @ref nrfx_i2s_next_buffers_set must 169 * be done before the currently used buffers are completely processed 170 * (that is, the time remaining for supplying the next buffers depends on 171 * the used size of the buffers). */ 172 173 #define NRFX_I2S_STATUS_TRANSFER_STOPPED (1UL << 1) 174 /**< The I2S peripheral has been stopped and all buffers that were passed 175 * to the driver have been released. */ 176 177 /** 178 * @brief I2S driver data handler type. 179 * 180 * A data handling function of this type must be specified during the initialization 181 * of the driver. The driver will call this function when it finishes using 182 * buffers passed to it by the application, and when it needs to be provided 183 * with buffers for the next part of the transfer. 184 * 185 * @note The @c p_released pointer passed to this function is temporary and 186 * will be invalid after the function returns, hence it cannot be stored 187 * and used later. If needed, the pointed content (that is, buffers pointers) 188 * must be copied instead. 189 * 190 * @param[in] p_released Pointer to a structure with pointers to buffers 191 * passed previously to the driver that will no longer 192 * be accessed by it (they can be now safely released or 193 * used for another purpose, in particular for a next 194 * part of the transfer). 195 * This pointer will be NULL if the application did not 196 * supply the buffers for the next part of the transfer 197 * (via a call to @ref nrfx_i2s_next_buffers_set) since 198 * the previous time the data handler signaled such need. 199 * This means that data corruption occurred (the previous 200 * buffers are used for the second time) and no buffers 201 * can be released at the moment. 202 * Both pointers in this structure are NULL when the 203 * handler is called for the first time after a transfer 204 * is started, because no data has been transferred yet 205 * at this point. In all successive calls, the pointers 206 * specify what has been sent (TX) and what has been 207 * received (RX) in the part of the transfer that has 208 * just been completed (provided that a given direction 209 * is enabled, see @ref nrfx_i2s_start). 210 * @note Since the peripheral is stopped asynchronously, 211 * buffers that are released after the call to 212 * @ref nrfx_i2s_stop are not used entirely. 213 * In this case, only a part (if any) of the TX 214 * buffer has been actually transmitted and only 215 * a part (if any) of the RX buffer is filled with 216 * received data. 217 * @param[in] status Bit field describing the current status of the transfer. 218 * It can be 0 or a combination of the following flags: 219 * - @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED 220 * - @ref NRFX_I2S_STATUS_TRANSFER_STOPPED 221 */ 222 typedef void (* nrfx_i2s_data_handler_t)(nrfx_i2s_buffers_t const * p_released, 223 uint32_t status); 224 225 /** 226 * @brief Function for initializing the I2S driver. 227 * 228 * @param[in] p_instance Pointer to the driver instance structure. 229 * @param[in] p_config Pointer to the structure with the initial configuration. 230 * @param[in] handler Data handler provided by the user. Must not be NULL. 231 * 232 * @retval NRFX_SUCCESS Initialization was successful. 233 * @retval NRFX_ERROR_ALREADY The driver is already initialized. 234 * @retval NRFX_ERROR_INVALID_STATE The driver is already initialized. 235 * Deprecated - use @ref NRFX_ERROR_ALREADY instead. 236 * @retval NRFX_ERROR_INVALID_PARAM The requested combination of configuration 237 * options is not allowed by the I2S peripheral. 238 */ 239 nrfx_err_t nrfx_i2s_init(nrfx_i2s_t const * p_instance, 240 nrfx_i2s_config_t const * p_config, 241 nrfx_i2s_data_handler_t handler); 242 243 /** 244 * @brief Function for uninitializing the I2S driver. 245 * 246 * @param[in] p_instance Pointer to the driver instance structure. 247 */ 248 void nrfx_i2s_uninit(nrfx_i2s_t const * p_instance); 249 250 /** 251 * @brief Function for checking if the I2S driver instance is initialized. 252 * 253 * @param[in] p_instance Pointer to the driver instance structure. 254 * 255 * @retval true Instance is already initialized. 256 * @retval false Instance is not initialized. 257 */ 258 bool nrfx_i2s_init_check(nrfx_i2s_t const * p_instance); 259 260 #if NRFX_API_VER_AT_LEAST(3, 3, 0) || defined(__NRFX_DOXYGEN__) 261 /** 262 * @brief Function for starting the continuous I2S transfer. 263 * 264 * The I2S data transfer can be performed in one of three modes: RX (reception) 265 * only, TX (transmission) only, or in both directions simultaneously. 266 * The mode is selected by specifying a proper buffer for a given direction 267 * in the call to this function or by passing NULL instead if this direction 268 * is to be disabled. 269 * 270 * The length of the buffer (which is a common value for RX and TX if both 271 * directions are enabled) is specified in 32-bit words. One 32-bit memory 272 * word can either contain four 8-bit samples, two 16-bit samples, or one 273 * right-aligned 24-bit sample sign-extended to a 32-bit value. 274 * For a detailed memory mapping for different supported configurations, 275 * see the Product Specification. 276 * 277 * @note Peripherals using EasyDMA (including I2S) require the transfer buffers 278 * to be placed in the Data RAM region. If this condition is not met, 279 * this function will fail with the error code NRFX_ERROR_INVALID_ADDR. 280 * 281 * @param[in] p_instance Pointer to the driver instance structure. 282 * @param[in] p_initial_buffers Pointer to a structure specifying the buffers 283 * to be used in the initial part of the transfer 284 * (buffers for all consecutive parts are provided 285 * through the data handler). 286 * @param[in] flags Transfer options (0 for default settings). 287 * Currently, no additional flags are available. 288 * 289 * @retval NRFX_SUCCESS The operation was successful. 290 * @retval NRFX_ERROR_INVALID_STATE Transfer was already started or 291 * the driver has not been initialized. 292 * @retval NRFX_ERROR_INVALID_ADDR The provided buffers are not placed 293 * in the Data RAM region. 294 */ 295 nrfx_err_t nrfx_i2s_start(nrfx_i2s_t const * p_instance, 296 nrfx_i2s_buffers_t const * p_initial_buffers, 297 uint8_t flags); 298 #else 299 /** 300 * @brief Function for starting the continuous I2S transfer. 301 * 302 * The I2S data transfer can be performed in one of three modes: RX (reception) 303 * only, TX (transmission) only, or in both directions simultaneously. 304 * The mode is selected by specifying a proper buffer for a given direction 305 * in the call to this function or by passing NULL instead if this direction 306 * is to be disabled. 307 * 308 * The length of the buffer (which is a common value for RX and TX if both 309 * directions are enabled) is specified in 32-bit words. One 32-bit memory 310 * word can either contain four 8-bit samples, two 16-bit samples, or one 311 * right-aligned 24-bit sample sign-extended to a 32-bit value. 312 * For a detailed memory mapping for different supported configurations, 313 * see the Product Specification. 314 * 315 * @note Peripherals using EasyDMA (including I2S) require the transfer buffers 316 * to be placed in the Data RAM region. If this condition is not met, 317 * this function will fail with the error code NRFX_ERROR_INVALID_ADDR. 318 * 319 * @param[in] p_instance Pointer to the driver instance structure. 320 * @param[in] p_initial_buffers Pointer to a structure specifying the buffers 321 * to be used in the initial part of the transfer 322 * (buffers for all consecutive parts are provided 323 * through the data handler). 324 * @param[in] buffer_size Size of the buffers (in 32-bit words). 325 * Must not be 0. 326 * @param[in] flags Transfer options (0 for default settings). 327 * Currently, no additional flags are available. 328 * 329 * @retval NRFX_SUCCESS The operation was successful. 330 * @retval NRFX_ERROR_INVALID_STATE Transfer was already started or 331 * the driver has not been initialized. 332 * @retval NRFX_ERROR_INVALID_ADDR The provided buffers are not placed 333 * in the Data RAM region. 334 */ 335 nrfx_err_t nrfx_i2s_start(nrfx_i2s_t const * p_instance, 336 nrfx_i2s_buffers_t const * p_initial_buffers, 337 uint16_t buffer_size, 338 uint8_t flags); 339 #endif 340 341 /** 342 * @brief Function for supplying the buffers to be used in the next part of 343 * the transfer. 344 * 345 * The application must call this function when the data handler receives 346 * @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED in the @c status parameter. 347 * The call can be done immediately from the data handler function or later, 348 * but it has to be done before the I2S peripheral finishes processing the 349 * buffers supplied previously. Otherwise, data corruption will occur. 350 * 351 * @param[in] p_instance Pointer to the driver instance structure. 352 * @param[in] p_buffers Pointer to a structure specifying the buffers 353 * to be used in the upcoming part of the transfer. 354 * 355 * @retval NRFX_SUCCESS If the operation was successful. 356 * @retval NRFX_ERROR_INVALID_STATE If the buffers were already supplied or 357 * the peripheral is currently being stopped. 358 * 359 * @sa nrfx_i2s_data_handler_t 360 */ 361 nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_t const * p_instance, 362 nrfx_i2s_buffers_t const * p_buffers); 363 364 /** 365 * @brief Function for stopping the I2S transfer. 366 * 367 * @param[in] p_instance Pointer to the driver instance structure. 368 */ 369 void nrfx_i2s_stop(nrfx_i2s_t const * p_instance); 370 371 /** @} */ 372 373 /* 374 * Declare interrupt handlers for all enabled driver instances in the following format: 375 * nrfx_\<periph_name\>_\<idx\>_irq_handler (for example, nrfx_i2s_0_irq_handler). 376 * 377 * A specific interrupt handler for the driver instance can be retrieved by using 378 * the NRFX_I2S_INST_HANDLER_GET macro. 379 * 380 * Here is a sample of using the NRFX_I2S_INST_HANDLER_GET macro to map an interrupt handler 381 * in a Zephyr application: 382 * 383 * IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_I2S_INST_GET(\<instance_index\>)), \<priority\>, 384 * NRFX_I2S_INST_HANDLER_GET(\<instance_index\>), 0, 0); 385 */ 386 NRFX_INSTANCE_IRQ_HANDLERS_DECLARE(I2S, i2s) 387 388 #ifdef __cplusplus 389 } 390 #endif 391 392 #endif // NRFX_I2S_H__ 393 394