1 /*
2  * Copyright (c) 2015 - 2020, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  *    contributors may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef NRFX_I2S_H__
33 #define NRFX_I2S_H__
34 
35 #include <nrfx.h>
36 #include <hal/nrf_i2s.h>
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /**
43  * @defgroup nrfx_i2s I2S driver
44  * @{
45  * @ingroup nrf_i2s
46  * @brief   Inter-IC Sound (I2S) peripheral driver.
47  */
48 
49 /**
50  * @brief This value can be provided instead of a pin number for the signals
51  *        SDOUT, SDIN, and MCK to specify that a given signal is not used
52  *        and therefore does not need to be connected to a pin.
53  */
54 #define NRFX_I2S_PIN_NOT_USED  0xFF
55 
56 /** @brief I2S driver configuration structure. */
57 typedef struct
58 {
59     uint8_t sck_pin;      ///< SCK pin number.
60     uint8_t lrck_pin;     ///< LRCK pin number.
61     uint8_t mck_pin;      ///< MCK pin number.
62                           /**< Optional. Use @ref NRFX_I2S_PIN_NOT_USED
63                            *   if this signal is not needed. */
64     uint8_t sdout_pin;    ///< SDOUT pin number.
65                           /**< Optional. Use @ref NRFX_I2S_PIN_NOT_USED
66                            *   if this signal is not needed. */
67     uint8_t sdin_pin;     ///< SDIN pin number.
68                           /**< Optional. Use @ref NRFX_I2S_PIN_NOT_USED
69                            *   if this signal is not needed. */
70     uint8_t irq_priority; ///< Interrupt priority.
71 
72     nrf_i2s_mode_t     mode;          ///< Mode of operation.
73     nrf_i2s_format_t   format;        ///< Frame format.
74     nrf_i2s_align_t    alignment;     ///< Alignment of sample within a frame.
75     nrf_i2s_swidth_t   sample_width;  ///< Sample width.
76     nrf_i2s_channels_t channels;      ///< Enabled channels.
77     nrf_i2s_mck_t      mck_setup;     ///< Master clock setup.
78     nrf_i2s_ratio_t    ratio;         ///< MCK/LRCK ratio.
79 #if NRF_I2S_HAS_CLKCONFIG
80     nrf_i2s_clksrc_t   clksrc;        ///< Clock source selection.
81     bool               enable_bypass; ///< Bypass clock generator. MCK will be equal to source input.
82 #endif
83 } nrfx_i2s_config_t;
84 
85 /** @brief I2S driver buffers structure. */
86 typedef struct
87 {
88     uint32_t       * p_rx_buffer; ///< Pointer to the buffer for received data.
89     uint32_t const * p_tx_buffer; ///< Pointer to the buffer with data to be sent.
90 } nrfx_i2s_buffers_t;
91 
92 #if NRF_I2S_HAS_CLKCONFIG || defined(__NRFX_DOXYGEN__)
93     /** @brief I2S additional clock source configuration. */
94     #define NRF_I2S_DEFAULT_EXTENDED_CLKSRC_CONFIG \
95         .clksrc        = NRF_I2S_CLKSRC_PCLK32M,   \
96         .enable_bypass = false,
97 #else
98     #define NRF_I2S_DEFAULT_EXTENDED_CLKSRC_CONFIG
99 #endif
100 /**
101  * @brief I2S driver default configuration.
102  *
103  * This configuration sets up I2S with the following options:
104  * - master mode
105  * - i2s data format
106  * - left alignment
107  * - sample width 16 bit
108  * - left channel enabled
109  * - MCK frequency 4 MHz
110  * - LRCK frequency 125 kHz
111  *
112  * @param[in] _pin_sck   SCK pin number.
113  * @param[in] _pin_lrck  LRCK pin number.
114  * @param[in] _pin_mck   MCK pin number.
115  * @param[in] _pin_sdout SDOUT pin number.
116  * @param[in] _pin_sdin  SDIN pin number.
117  */
118 #define NRFX_I2S_DEFAULT_CONFIG(_pin_sck, _pin_lrck, _pin_mck, _pin_sdout, _pin_sdin)   \
119 {                                                                                       \
120     .sck_pin      = _pin_sck,                                                           \
121     .lrck_pin     = _pin_lrck,                                                          \
122     .mck_pin      = _pin_mck,                                                           \
123     .sdout_pin    = _pin_sdout,                                                         \
124     .sdin_pin     = _pin_sdin,                                                          \
125     .irq_priority = NRFX_I2S_DEFAULT_CONFIG_IRQ_PRIORITY,                               \
126     .mode         = NRF_I2S_MODE_MASTER,                                                \
127     .format       = NRF_I2S_FORMAT_I2S,                                                 \
128     .alignment    = NRF_I2S_ALIGN_LEFT,                                                 \
129     .sample_width = NRF_I2S_SWIDTH_16BIT,                                               \
130     .channels     = NRF_I2S_CHANNELS_LEFT,                                              \
131     .mck_setup    = NRF_I2S_MCK_32MDIV8,                                                \
132     .ratio        = NRF_I2S_RATIO_32X,                                                  \
133     NRF_I2S_DEFAULT_EXTENDED_CLKSRC_CONFIG                                              \
134 }
135 
136 #define NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED (1UL << 0)
137     /**< The application must provide buffers that are to be used in the next
138      *   part of the transfer. A call to @ref nrfx_i2s_next_buffers_set must
139      *   be done before the currently used buffers are completely processed
140      *   (that is, the time remaining for supplying the next buffers depends on
141      *   the used size of the buffers). */
142 
143 #define NRFX_I2S_STATUS_TRANSFER_STOPPED    (1UL << 1)
144     /**< The I2S peripheral has been stopped and all buffers that were passed
145      *   to the driver have been released. */
146 
147 /**
148  * @brief I2S driver data handler type.
149  *
150  * A data handling function of this type must be specified during the initialization
151  * of the driver. The driver will call this function when it finishes using
152  * buffers passed to it by the application, and when it needs to be provided
153  * with buffers for the next part of the transfer.
154  *
155  * @note The @c p_released pointer passed to this function is temporary and
156  *       will be invalid after the function returns, hence it cannot be stored
157  *       and used later. If needed, the pointed content (that is, buffers pointers)
158  *       must be copied instead.
159  *
160  * @param[in] p_released  Pointer to a structure with pointers to buffers
161  *                        passed previously to the driver that will no longer
162  *                        be accessed by it (they can be now safely released or
163  *                        used for another purpose, in particular for a next
164  *                        part of the transfer).
165  *                        This pointer will be NULL if the application did not
166  *                        supply the buffers for the next part of the transfer
167  *                        (via a call to @ref nrfx_i2s_next_buffers_set) since
168  *                        the previous time the data handler signaled such need.
169  *                        This means that data corruption occurred (the previous
170  *                        buffers are used for the second time) and no buffers
171  *                        can be released at the moment.
172  *                        Both pointers in this structure are NULL when the
173  *                        handler is called for the first time after a transfer
174  *                        is started, because no data has been transferred yet
175  *                        at this point. In all successive calls, the pointers
176  *                        specify what has been sent (TX) and what has been
177  *                        received (RX) in the part of the transfer that has
178  *                        just been completed (provided that a given direction
179  *                        is enabled, see @ref nrfx_i2s_start).
180  *                        @note Since the peripheral is stopped asynchronously,
181  *                              buffers that are released after the call to
182  *                              @ref nrfx_i2s_stop are not used entirely.
183  *                              In this case, only a part (if any) of the TX
184  *                              buffer has been actually transmitted and only
185  *                              a part (if any) of the RX buffer is filled with
186  *                              received data.
187  * @param[in] status  Bit field describing the current status of the transfer.
188  *                    It can be 0 or a combination of the following flags:
189  *                    - @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED
190  *                    - @ref NRFX_I2S_STATUS_TRANSFER_STOPPED
191  */
192 typedef void (* nrfx_i2s_data_handler_t)(nrfx_i2s_buffers_t const * p_released,
193                                          uint32_t                   status);
194 
195 /**
196  * @brief Function for initializing the I2S driver.
197  *
198  * @param[in] p_config Pointer to the structure with the initial configuration.
199  * @param[in] handler  Data handler provided by the user. Must not be NULL.
200  *
201  * @retval NRFX_SUCCESS             Initialization was successful.
202  * @retval NRFX_ERROR_INVALID_STATE The driver was already initialized.
203  * @retval NRFX_ERROR_INVALID_PARAM The requested combination of configuration
204  *                                  options is not allowed by the I2S peripheral.
205  */
206 nrfx_err_t nrfx_i2s_init(nrfx_i2s_config_t const * p_config,
207                          nrfx_i2s_data_handler_t   handler);
208 
209 /** @brief Function for uninitializing the I2S driver. */
210 void nrfx_i2s_uninit(void);
211 
212 /**
213  * @brief Function for starting the continuous I2S transfer.
214  *
215  * The I2S data transfer can be performed in one of three modes: RX (reception)
216  * only, TX (transmission) only, or in both directions simultaneously.
217  * The mode is selected by specifying a proper buffer for a given direction
218  * in the call to this function or by passing NULL instead if this direction
219  * is to be disabled.
220  *
221  * The length of the buffer (which is a common value for RX and TX if both
222  * directions are enabled) is specified in 32-bit words. One 32-bit memory
223  * word can either contain four 8-bit samples, two 16-bit samples, or one
224  * right-aligned 24-bit sample sign-extended to a 32-bit value.
225  * For a detailed memory mapping for different supported configurations,
226  * see the Product Specification.
227  *
228  * @note Peripherals using EasyDMA (including I2S) require the transfer buffers
229  *       to be placed in the Data RAM region. If this condition is not met,
230  *       this function will fail with the error code NRFX_ERROR_INVALID_ADDR.
231  *
232  * @param[in] p_initial_buffers Pointer to a structure specifying the buffers
233  *                              to be used in the initial part of the transfer
234  *                              (buffers for all consecutive parts are provided
235  *                              through the data handler).
236  * @param[in] buffer_size       Size of the buffers (in 32-bit words).
237  *                              Must not be 0.
238  * @param[in] flags             Transfer options (0 for default settings).
239  *                              Currently, no additional flags are available.
240  *
241  * @retval NRFX_SUCCESS             The operation was successful.
242  * @retval NRFX_ERROR_INVALID_STATE Transfer was already started or
243  *                                  the driver has not been initialized.
244  * @retval NRFX_ERROR_INVALID_ADDR  The provided buffers are not placed
245  *                                  in the Data RAM region.
246  */
247 nrfx_err_t nrfx_i2s_start(nrfx_i2s_buffers_t const * p_initial_buffers,
248                           uint16_t                   buffer_size,
249                           uint8_t                    flags);
250 
251 /**
252  * @brief Function for supplying the buffers to be used in the next part of
253  *        the transfer.
254  *
255  * The application must call this function when the data handler receives
256  * @ref NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED in the @c status parameter.
257  * The call can be done immediately from the data handler function or later,
258  * but it has to be done before the I2S peripheral finishes processing the
259  * buffers supplied previously. Otherwise, data corruption will occur.
260  *
261  * @param[in] p_buffers Pointer to a structure specifying the buffers
262  *                      to be used in the upcoming part of the transfer.
263  *
264  * @retval NRFX_SUCCESS             If the operation was successful.
265  * @retval NRFX_ERROR_INVALID_STATE If the buffers were already supplied or
266  *                                  the peripheral is currently being stopped.
267  *
268  * @sa nrfx_i2s_data_handler_t
269  */
270 nrfx_err_t nrfx_i2s_next_buffers_set(nrfx_i2s_buffers_t const * p_buffers);
271 
272 /** @brief Function for stopping the I2S transfer. */
273 void nrfx_i2s_stop(void);
274 
275 /** @} */
276 
277 
278 void nrfx_i2s_irq_handler(void);
279 
280 
281 #ifdef __cplusplus
282 }
283 #endif
284 
285 #endif // NRFX_I2S_H__
286 
287