1 /* 2 * Copyright (c) 2015 - 2023, 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 /** @brief I2S driver buffers structure. */ 99 typedef nrfy_i2s_buffers_t nrfx_i2s_buffers_t; 100 101 /** @brief I2S driver instance structure. */ 102 typedef struct 103 { 104 NRF_I2S_Type * p_reg; ///< Pointer to a structure with I2S registers. 105 uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only. 106 } nrfx_i2s_t; 107 108 /** @brief Macro for creating an I2S driver instance. */ 109 #define NRFX_I2S_INSTANCE(id) \ 110 { \ 111 .p_reg = NRF_I2S##id , \ 112 .drv_inst_idx = NRFX_CONCAT_3(NRFX_I2S, id, _INST_IDX), \ 113 } 114 115 #ifndef __NRFX_DOXYGEN__ 116 enum { 117 /* List all enabled driver instances (in the format NRFX_\<instance_name\>_INST_IDX). */ 118 NRFX_INSTANCE_ENUM_LIST(I2S) 119 NRFX_I2S_ENABLED_COUNT 120 }; 121 #endif 122 123 /** 124 * @brief I2S driver default configuration. 125 * 126 * This configuration sets up I2S with the following options: 127 * - master mode 128 * - i2s data format 129 * - left alignment 130 * - sample width 16 bit 131 * - left channel enabled 132 * - MCK frequency 4 MHz 133 * - LRCK frequency 125 kHz 134 * 135 * @param[in] _pin_sck SCK pin number. 136 * @param[in] _pin_lrck LRCK pin number. 137 * @param[in] _pin_mck MCK pin number. 138 * @param[in] _pin_sdout SDOUT pin number. 139 * @param[in] _pin_sdin SDIN pin number. 140 */ 141 #define NRFX_I2S_DEFAULT_CONFIG(_pin_sck, _pin_lrck, _pin_mck, _pin_sdout, _pin_sdin) \ 142 { \ 143 .sck_pin = _pin_sck, \ 144 .lrck_pin = _pin_lrck, \ 145 .mck_pin = _pin_mck, \ 146 .sdout_pin = _pin_sdout, \ 147 .sdin_pin = _pin_sdin, \ 148 .irq_priority = NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY, \ 149 .mode = NRF_I2S_MODE_MASTER, \ 150 .format = NRF_I2S_FORMAT_I2S, \ 151 .alignment = NRF_I2S_ALIGN_LEFT, \ 152 .sample_width = NRF_I2S_SWIDTH_16BIT, \ 153 .channels = NRF_I2S_CHANNELS_LEFT, \ 154 .mck_setup = NRF_I2S_MCK_32MDIV8, \ 155 .ratio = NRF_I2S_RATIO_32X, \ 156 NRFX_COND_CODE_1(NRF_I2S_HAS_CLKCONFIG, \ 157 (.clksrc = NRF_I2S_CLKSRC_PCLK32M, \ 158 .enable_bypass = false,), \ 159 ()) \ 160 } 161 162 #define NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED (1UL << 0) 163 /**< The application must provide buffers that are to be used in the next 164 * part of the transfer. A call to @ref nrfx_i2s_next_buffers_set must 165 * be done before the currently used buffers are completely processed 166 * (that is, the time remaining for supplying the next buffers depends on 167 * the used size of the buffers). */ 168 169 #define NRFX_I2S_STATUS_TRANSFER_STOPPED (1UL << 1) 170 /**< The I2S peripheral has been stopped and all buffers that were passed 171 * to the driver have been released. */ 172 173 /** 174 * @brief I2S driver data handler type. 175 * 176 * A data handling function of this type must be specified during the initialization 177 * of the driver. The driver will call this function when it finishes using 178 * buffers passed to it by the application, and when it needs to be provided 179 * with buffers for the next part of the transfer. 180 * 181 * @note The @c p_released pointer passed to this function is temporary and 182 * will be invalid after the function returns, hence it cannot be stored 183 * and used later. If needed, the pointed content (that is, buffers pointers) 184 * must be copied instead. 185 * 186 * @param[in] p_released Pointer to a structure with pointers to buffers 187 * passed previously to the driver that will no longer 188 * be accessed by it (they can be now safely released or 189 * used for another purpose, in particular for a next 190 * part of the transfer). 191 * This pointer will be NULL if the application did not 192 * supply the buffers for the next part of the transfer 193 * (via a call to @ref nrfx_i2s_next_buffers_set) since 194 * the previous time the data handler signaled such need. 195 * This means that data corruption occurred (the previous 196 * buffers are used for the second time) and no buffers 197 * can be released at the moment. 198 * Both pointers in this structure are NULL when the 199 * handler is called for the first time after a transfer 200 * is started, because no data has been transferred yet 201 * at this point. In all successive calls, the pointers 202 * specify what has been sent (TX) and what has been 203 * received (RX) in the part of the transfer that has 204 * just been completed (provided that a given direction 205 * is enabled, see @ref nrfx_i2s_start). 206 * @note Since the peripheral is stopped asynchronously, 207 * buffers that are released after the call to 208 * @ref nrfx_i2s_stop are not used entirely. 209 * In this case, only a part (if any) of the TX 210 * buffer has been actually transmitted and only 211 * a part (if any) of the RX buffer is filled with 212 * received data. 213 * @param[in] status Bit field describing the current status of the transfer. 214 * It can be 0 or a combination of the following flags: 215 * - @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED 216 * - @ref NRFX_I2S_STATUS_TRANSFER_STOPPED 217 */ 218 typedef void (* nrfx_i2s_data_handler_t)(nrfx_i2s_buffers_t const * p_released, 219 uint32_t status); 220 221 /** 222 * @brief Function for initializing the I2S driver. 223 * 224 * @param[in] p_instance Pointer to the driver instance structure. 225 * @param[in] p_config Pointer to the structure with the initial configuration. 226 * @param[in] handler Data handler provided by the user. Must not be NULL. 227 * 228 * @retval NRFX_SUCCESS Initialization was successful. 229 * @retval NRFX_ERROR_INVALID_STATE The driver was already initialized. 230 * @retval NRFX_ERROR_INVALID_PARAM The requested combination of configuration 231 * options is not allowed by the I2S peripheral. 232 */ 233 nrfx_err_t nrfx_i2s_init(nrfx_i2s_t const * p_instance, 234 nrfx_i2s_config_t const * p_config, 235 nrfx_i2s_data_handler_t handler); 236 237 /** 238 * @brief Function for uninitializing the I2S driver. 239 * 240 * @param[in] p_instance Pointer to the driver instance structure. 241 */ 242 void nrfx_i2s_uninit(nrfx_i2s_t const * p_instance); 243 244 /** 245 * @brief Function for starting the continuous I2S transfer. 246 * 247 * The I2S data transfer can be performed in one of three modes: RX (reception) 248 * only, TX (transmission) only, or in both directions simultaneously. 249 * The mode is selected by specifying a proper buffer for a given direction 250 * in the call to this function or by passing NULL instead if this direction 251 * is to be disabled. 252 * 253 * The length of the buffer (which is a common value for RX and TX if both 254 * directions are enabled) is specified in 32-bit words. One 32-bit memory 255 * word can either contain four 8-bit samples, two 16-bit samples, or one 256 * right-aligned 24-bit sample sign-extended to a 32-bit value. 257 * For a detailed memory mapping for different supported configurations, 258 * see the Product Specification. 259 * 260 * @note Peripherals using EasyDMA (including I2S) require the transfer buffers 261 * to be placed in the Data RAM region. If this condition is not met, 262 * this function will fail with the error code NRFX_ERROR_INVALID_ADDR. 263 * 264 * @param[in] p_instance Pointer to the driver instance structure. 265 * @param[in] p_initial_buffers Pointer to a structure specifying the buffers 266 * to be used in the initial part of the transfer 267 * (buffers for all consecutive parts are provided 268 * through the data handler). 269 * @param[in] buffer_size Size of the buffers (in 32-bit words). 270 * Must not be 0. 271 * @param[in] flags Transfer options (0 for default settings). 272 * Currently, no additional flags are available. 273 * 274 * @retval NRFX_SUCCESS The operation was successful. 275 * @retval NRFX_ERROR_INVALID_STATE Transfer was already started or 276 * the driver has not been initialized. 277 * @retval NRFX_ERROR_INVALID_ADDR The provided buffers are not placed 278 * in the Data RAM region. 279 */ 280 nrfx_err_t nrfx_i2s_start(nrfx_i2s_t const * p_instance, 281 nrfx_i2s_buffers_t const * p_initial_buffers, 282 uint16_t buffer_size, 283 uint8_t flags); 284 285 /** 286 * @brief Function for supplying the buffers to be used in the next part of 287 * the transfer. 288 * 289 * The application must call this function when the data handler receives 290 * @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED in the @c status parameter. 291 * The call can be done immediately from the data handler function or later, 292 * but it has to be done before the I2S peripheral finishes processing the 293 * buffers supplied previously. Otherwise, data corruption will occur. 294 * 295 * @param[in] p_instance Pointer to the driver instance structure. 296 * @param[in] p_buffers Pointer to a structure specifying the buffers 297 * to be used in the upcoming part of the transfer. 298 * 299 * @retval NRFX_SUCCESS If the operation was successful. 300 * @retval NRFX_ERROR_INVALID_STATE If the buffers were already supplied or 301 * the peripheral is currently being stopped. 302 * 303 * @sa nrfx_i2s_data_handler_t 304 */ 305 nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_t const * p_instance, 306 nrfx_i2s_buffers_t const * p_buffers); 307 308 /** 309 * @brief Function for stopping the I2S transfer. 310 * 311 * @param[in] p_instance Pointer to the driver instance structure. 312 */ 313 void nrfx_i2s_stop(nrfx_i2s_t const * p_instance); 314 315 /** @} */ 316 317 /* 318 * Declare interrupt handlers for all enabled driver instances in the following format: 319 * nrfx_\<periph_name\>_\<idx\>_irq_handler (for example, nrfx_i2s_0_irq_handler). 320 * 321 * A specific interrupt handler for the driver instance can be retrieved by using 322 * the NRFX_I2S_INST_HANDLER_GET macro. 323 * 324 * Here is a sample of using the NRFX_I2S_INST_HANDLER_GET macro to directly map 325 * an interrupt handler in a Zephyr application: 326 * 327 * IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_I2S_INST_GET(\<instance_index\>)), \<priority\>, 328 * NRFX_I2S_INST_HANDLER_GET(\<instance_index\>), 0); 329 */ 330 NRFX_INSTANCE_IRQ_HANDLERS_DECLARE(I2S, i2s) 331 332 #ifdef __cplusplus 333 } 334 #endif 335 336 #endif // NRFX_I2S_H__ 337 338