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_PDM_H__
35 #define NRFX_PDM_H__
36
37 #include <nrfx.h>
38 #include <haly/nrfy_pdm.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_PDM) && defined(NRFX_PDM_ENABLED) && !defined(NRFX_PDM0_ENABLED)
46 #define NRFX_PDM0_ENABLED 1
47 #endif
48
49 /**
50 * @defgroup nrfx_pdm PDM driver
51 * @{
52 * @ingroup nrf_pdm
53 * @brief Pulse Density Modulation (PDM) peripheral driver.
54 */
55
56 /** @brief Data structure of the Pulse Density Modulation (PDM) driver instance. */
57 typedef struct
58 {
59 NRF_PDM_Type * p_reg; ///< Pointer to a structure containing PDM registers.
60 uint8_t drv_inst_idx; ///< Index of the driver instance. For internal use only.
61 } nrfx_pdm_t;
62
63 #ifndef __NRFX_DOXYGEN__
64 enum {
65 /* List all enabled driver instances (in the format NRFX_\<instance_name\>_INST_IDX). */
66 NRFX_INSTANCE_ENUM_LIST(PDM)
67 NRFX_PDM_ENABLED_COUNT
68 };
69 #endif
70
71 /** @brief Macro for creating an instance of the PDM driver. */
72 #define NRFX_PDM_INSTANCE(id) \
73 { \
74 .p_reg = NRFX_CONCAT(NRF_, PDM, id), \
75 .drv_inst_idx = NRFX_CONCAT(NRFX_PDM, id, _INST_IDX), \
76 }
77
78 /** @brief Maximum supported PDM buffer size. */
79 #define NRFX_PDM_MAX_BUFFER_SIZE 32767
80
81 /** @brief PDM error type. */
82 typedef enum
83 {
84 NRFX_PDM_NO_ERROR = 0, ///< No error.
85 NRFX_PDM_ERROR_OVERFLOW = 1 ///< Overflow error.
86 } nrfx_pdm_error_t;
87
88 /** @brief PDM event structure. */
89 typedef struct
90 {
91 bool buffer_requested; ///< Buffer request flag.
92 int16_t * buffer_released; ///< Pointer to the released buffer. Can be NULL.
93 nrfx_pdm_error_t error; ///< Error type.
94 } nrfx_pdm_evt_t;
95
96 /** @brief PDM interface driver configuration structure. */
97 typedef struct
98 {
99 nrf_pdm_mode_t mode; ///< Interface operation mode.
100 nrf_pdm_edge_t edge; ///< Sampling mode.
101 uint32_t clk_pin; ///< CLK pin number.
102 uint32_t din_pin; ///< DIN pin number.
103 #if NRF_PDM_HAS_PDMCLKCTRL
104 nrf_pdm_freq_t clock_freq; ///< Clock frequency.
105 #elif NRF_PDM_HAS_PRESCALER
106 uint32_t prescaler; ///< Prescaler divisor.
107 #endif
108 nrf_pdm_gain_t gain_l; ///< Left channel gain.
109 nrf_pdm_gain_t gain_r; ///< Right channel gain.
110 uint8_t interrupt_priority; ///< Interrupt priority.
111 #if NRF_PDM_HAS_RATIO_CONFIG
112 nrf_pdm_ratio_t ratio; ///< Ratio between PDM_CLK and output sample rate.
113 #endif
114 #if NRF_PDM_HAS_MCLKCONFIG
115 nrf_pdm_mclksrc_t mclksrc; ///< Master clock source selection.
116 #endif
117 bool skip_gpio_cfg; ///< Skip GPIO configuration of pins.
118 /**< When set to true, the driver does not modify
119 * any GPIO parameters of the used pins. Those
120 * parameters are supposed to be configured
121 * externally before the driver is initialized. */
122 bool skip_psel_cfg; ///< Skip pin selection configuration.
123 /**< When set to true, the driver does not modify
124 * pin select registers in the peripheral.
125 * Those registers are supposed to be set up
126 * externally before the driver is initialized.
127 * @note When both GPIO configuration and pin
128 * selection are to be skipped, the structure
129 * fields that specify pins can be omitted,
130 * as they are ignored anyway. */
131 } nrfx_pdm_config_t;
132
133 /**
134 * @brief PDM driver default configuration.
135 *
136 * This configuration sets up PDM with the following options:
137 * - mono mode
138 * - data sampled on the clock falling edge
139 * - frequency: 1.032 MHz
140 * - standard gain
141 *
142 * @param[in] _pin_clk CLK output pin.
143 * @param[in] _pin_din DIN input pin.
144 */
145 #define NRFX_PDM_DEFAULT_CONFIG(_pin_clk, _pin_din) \
146 { \
147 .mode = NRF_PDM_MODE_MONO, \
148 .edge = NRF_PDM_EDGE_LEFTFALLING, \
149 .clk_pin = _pin_clk, \
150 .din_pin = _pin_din, \
151 NRFX_COND_CODE_1(NRF_PDM_HAS_PDMCLKCTRL, \
152 (.clock_freq = NRF_PDM_FREQ_1032K,), ()) \
153 NRFX_COND_CODE_1(NRF_PDM_HAS_PRESCALER, \
154 (.prescaler = 4,), ()) \
155 .gain_l = NRF_PDM_GAIN_DEFAULT, \
156 .gain_r = NRF_PDM_GAIN_DEFAULT, \
157 .interrupt_priority = NRFX_PDM_DEFAULT_CONFIG_IRQ_PRIORITY, \
158 NRFX_COND_CODE_1(NRF_PDM_HAS_RATIO_CONFIG, \
159 (.ratio = NRF_PDM_RATIO_64X,), ()) \
160 NRFX_COND_CODE_1(NRF_PDM_HAS_MCLKCONFIG, \
161 (.mclksrc = NRF_PDM_MCLKSRC_PCLK32M,), ()) \
162 }
163
164 /**
165 * @brief Macro returning PDM interrupt handler.
166 *
167 * @param[in] idx PDM index.
168 *
169 * @return Interrupt handler.
170 */
171 #define NRFX_PDM_INST_HANDLER_GET(idx) NRFX_CONCAT_3(nrfx_pdm_, idx, _irq_handler)
172
173 /**
174 * @brief Handler for the PDM interface ready events.
175 *
176 * This event handler is called on a buffer request, an error or when a buffer
177 * is full and ready to be processed.
178 *
179 * @param[in] p_evt Pointer to the PDM event structure.
180 */
181 typedef void (*nrfx_pdm_event_handler_t)(nrfx_pdm_evt_t const * p_evt);
182
183 #if NRFX_API_VER_AT_LEAST(3, 7, 0) || defined(__NRFX_DOXYGEN__)
184
185 /**
186 * @brief Function for initializing the PDM driver instance.
187 *
188 * @param[in] p_instance Pointer to the driver instance structure.
189 * @param[in] p_config Pointer to the structure with the initial configuration.
190 * @param[in] event_handler Event handler provided by the user. Cannot be NULL.
191 *
192 * @retval NRFX_SUCCESS Initialization was successful.
193 * @retval NRFX_ERROR_ALREADY The driver is already initialized.
194 * @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
195 * Deprecated - use @ref NRFX_ERROR_ALREADY instead.
196 * @retval NRFX_ERROR_INVALID_PARAM Invalid configuration was specified.
197 */
198 nrfx_err_t nrfx_pdm_init(nrfx_pdm_t const * p_instance,
199 nrfx_pdm_config_t const * p_config,
200 nrfx_pdm_event_handler_t event_handler);
201
202 /**
203 * @brief Function for reconfiguring the PDM driver instance.
204 *
205 * @param[in] p_instance Pointer to the driver instance structure.
206 * @param[in] p_config Pointer to the structure with the configuration.
207 *
208 * @retval NRFX_SUCCESS Reconfiguration was successful.
209 * @retval NRFX_ERROR_BUSY There is ongoing sampling and driver cannot be reconfigured.
210 * @retval NRFX_ERROR_INVALID_STATE The driver is not initialized.
211 * @retval NRFX_ERROR_INVALID_PARAM Invalid configuration was specified.
212 */
213 nrfx_err_t nrfx_pdm_reconfigure(nrfx_pdm_t const * p_instance,
214 nrfx_pdm_config_t const * p_config);
215
216 /**
217 * @brief Function for uninitializing the PDM driver instance.
218 *
219 * @param[in] p_instance Pointer to the driver instance structure.
220 *
221 * This function stops PDM sampling, if it is in progress.
222 */
223 void nrfx_pdm_uninit(nrfx_pdm_t const * p_instance);
224
225 /**
226 * @brief Function for checking if the PDM driver instance is initialized.
227 *
228 * @param[in] p_instance Pointer to the driver instance structure.
229 *
230 * @retval true Interface is already initialized.
231 * @retval false Interface is not initialized.
232 */
233 bool nrfx_pdm_init_check(nrfx_pdm_t const * p_instance);
234
235 /**
236 * @brief Function for getting the address of a PDM driver instance task.
237 *
238 * @param[in] p_instance Pointer to the driver instance structure.
239 * @param[in] task Task.
240 *
241 * @return Task address.
242 */
243 NRFX_STATIC_INLINE uint32_t nrfx_pdm_task_address_get(nrfx_pdm_t const * p_instance,
244 nrf_pdm_task_t task);
245
246 /**
247 * @brief Function for getting the state of the PDM drivers instance.
248 *
249 * @param[in] p_instance Pointer to the driver instance structure.
250 *
251 * @retval true The PDM interface is enabled.
252 * @retval false The PDM interface is disabled.
253 */
254 NRFX_STATIC_INLINE bool nrfx_pdm_enable_check(nrfx_pdm_t const * p_instance);
255
256 /**
257 * @brief Function for starting the PDM sampling.
258 *
259 * @param[in] p_instance Pointer to the driver instance structure.
260 *
261 * @retval NRFX_SUCCESS Sampling was started successfully or was already in progress.
262 * @retval NRFX_ERROR_BUSY Previous start/stop operation is in progress.
263 */
264 nrfx_err_t nrfx_pdm_start(nrfx_pdm_t const * p_instance);
265
266 /**
267 * @brief Function for stopping the PDM sampling.
268 *
269 * When this function is called, the PDM driver instance is stopped after finishing
270 * the current frame.
271 * The event handler function might be called once more after calling this function.
272 *
273 * @param[in] p_instance Pointer to the driver instance structure.
274 *
275 * @retval NRFX_SUCCESS Sampling was stopped successfully or was already stopped before.
276 * @retval NRFX_ERROR_BUSY Previous start/stop operation is in progress.
277 */
278 nrfx_err_t nrfx_pdm_stop(nrfx_pdm_t const * p_instance);
279
280 /**
281 * @brief Function for supplying the sample buffer.
282 *
283 * Call this function after every buffer request event.
284 *
285 * @param[in] p_instance Pointer to the driver instance structure.
286 * @param[in] buffer Pointer to the receive buffer. Cannot be NULL.
287 * @param[in] buffer_length Length of the receive buffer in 16-bit words.
288 *
289 * @retval NRFX_SUCCESS The buffer was applied successfully.
290 * @retval NRFX_ERROR_BUSY The buffer was already supplied or the peripheral is currently being stopped.
291 * @retval NRFX_ERROR_INVALID_STATE The driver was not initialized.
292 * @retval NRFX_ERROR_INVALID_PARAM Invalid parameters were provided.
293 */
294 nrfx_err_t nrfx_pdm_buffer_set(nrfx_pdm_t const * p_instance,
295 int16_t * buffer,
296 uint16_t buffer_length);
297
298 #ifndef NRFX_DECLARE_ONLY
nrfx_pdm_task_address_get(nrfx_pdm_t const * p_instance,nrf_pdm_task_t task)299 NRFX_STATIC_INLINE uint32_t nrfx_pdm_task_address_get(nrfx_pdm_t const * p_instance,
300 nrf_pdm_task_t task)
301 {
302 return nrf_pdm_task_address_get(p_instance->p_reg, task);
303 }
304
nrfx_pdm_enable_check(nrfx_pdm_t const * p_instance)305 NRFX_STATIC_INLINE bool nrfx_pdm_enable_check(nrfx_pdm_t const * p_instance)
306 {
307 return nrf_pdm_enable_check(p_instance->p_reg);
308 }
309 #endif // NRFX_DECLARE_ONLY
310
311 #else
312
313 #if !defined(NRF_PDM_INDEX)
314 /* Choose the instance to use in case of using deprecated single-instance driver variant. */
315 #if defined(NRF_PDM130)
316 #define NRF_PDM_INDEX 130
317 #elif defined(NRF_PDM21)
318 #define NRF_PDM_INDEX 21
319 #elif defined(NRF_PDM20)
320 #define NRF_PDM_INDEX 20
321 #else
322 #define NRF_PDM_INDEX 0
323 #endif
324 #endif
325
326 /**
327 * @brief Function for initializing the PDM interface.
328 *
329 * @param[in] p_config Pointer to the structure with the initial configuration.
330 * @param[in] event_handler Event handler provided by the user. Cannot be NULL.
331 *
332 * @retval NRFX_SUCCESS Initialization was successful.
333 * @retval NRFX_ERROR_ALREADY The driver is already initialized.
334 * @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
335 * Deprecated - use @ref NRFX_ERROR_ALREADY instead.
336 * @retval NRFX_ERROR_INVALID_PARAM Invalid configuration was specified.
337 */
338 nrfx_err_t nrfx_pdm_init(nrfx_pdm_config_t const * p_config,
339 nrfx_pdm_event_handler_t event_handler);
340
341 /**
342 * @brief Function for reconfiguring the PDM interface.
343 *
344 * @param[in] p_config Pointer to the structure with the configuration.
345 *
346 * @retval NRFX_SUCCESS Reconfiguration was successful.
347 * @retval NRFX_ERROR_BUSY There is ongoing sampling and driver cannot be reconfigured.
348 * @retval NRFX_ERROR_INVALID_STATE The driver is not initialized.
349 * @retval NRFX_ERROR_INVALID_PARAM Invalid configuration was specified.
350 */
351 nrfx_err_t nrfx_pdm_reconfigure(nrfx_pdm_config_t const * p_config);
352
353 /**
354 * @brief Function for uninitializing the PDM interface.
355 *
356 * This function stops PDM sampling, if it is in progress.
357 */
358 void nrfx_pdm_uninit(void);
359
360 /**
361 * @brief Function for checking if the PDM interface is initialized.
362 *
363 * @retval true Interface is already initialized.
364 * @retval false Interface is not initialized.
365 */
366 bool nrfx_pdm_init_check(void);
367
368 /**
369 * @brief Function for getting the address of a PDM interface task.
370 *
371 * @param[in] task Task.
372 *
373 * @return Task address.
374 */
375 NRFX_STATIC_INLINE uint32_t nrfx_pdm_task_address_get(nrf_pdm_task_t task);
376
377 /**
378 * @brief Function for getting the state of the PDM interface.
379 *
380 * @retval true The PDM interface is enabled.
381 * @retval false The PDM interface is disabled.
382 */
383 NRFX_STATIC_INLINE bool nrfx_pdm_enable_check(void);
384
385 /**
386 * @brief Function for starting the PDM sampling.
387 *
388 * @retval NRFX_SUCCESS Sampling was started successfully or was already in progress.
389 * @retval NRFX_ERROR_BUSY Previous start/stop operation is in progress.
390 */
391 nrfx_err_t nrfx_pdm_start(void);
392
393 /**
394 * @brief Function for stopping the PDM sampling.
395 *
396 * When this function is called, the PDM interface is stopped after finishing
397 * the current frame.
398 * The event handler function might be called once more after calling this function.
399 *
400 * @retval NRFX_SUCCESS Sampling was stopped successfully or was already stopped before.
401 * @retval NRFX_ERROR_BUSY Previous start/stop operation is in progress.
402 */
403 nrfx_err_t nrfx_pdm_stop(void);
404
405 /**
406 * @brief Function for supplying the sample buffer.
407 *
408 * Call this function after every buffer request event.
409 *
410 * @param[in] buffer Pointer to the receive buffer. Cannot be NULL.
411 * @param[in] buffer_length Length of the receive buffer in 16-bit words.
412 *
413 * @retval NRFX_SUCCESS The buffer was applied successfully.
414 * @retval NRFX_ERROR_BUSY The buffer was already supplied or the peripheral is currently being stopped.
415 * @retval NRFX_ERROR_INVALID_STATE The driver was not initialized.
416 * @retval NRFX_ERROR_INVALID_PARAM Invalid parameters were provided.
417 */
418 nrfx_err_t nrfx_pdm_buffer_set(int16_t * buffer, uint16_t buffer_length);
419
420 #ifndef NRFX_DECLARE_ONLY
nrfx_pdm_task_address_get(nrf_pdm_task_t task)421 NRFX_STATIC_INLINE uint32_t nrfx_pdm_task_address_get(nrf_pdm_task_t task)
422 {
423 return nrf_pdm_task_address_get(NRF_PDM0, task);
424 }
425
nrfx_pdm_enable_check(void)426 NRFX_STATIC_INLINE bool nrfx_pdm_enable_check(void)
427 {
428 return nrf_pdm_enable_check(NRF_PDM0);
429 }
430 #endif // NRFX_DECLARE_ONLY
431
432 void nrfx_pdm_irq_handler(void);
433
434 #endif // NRFX_API_VER_AT_LEAST(3, 7, 0) || defined(__NRFX_DOXYGEN__)
435
436 /** @} */
437
438 /*
439 * Declare interrupt handlers for all enabled driver instances in the following format:
440 * nrfx_\<periph_name\>_\<idx\>_irq_handler (for example, nrfx_pdm_0_irq_handler).
441 *
442 * A specific interrupt handler for the driver instance can be retrieved by using
443 * the NRFX_PDM_INST_HANDLER_GET macro.
444 *
445 * Here is a sample of using the NRFX_PDM_INST_HANDLER_GET macro to map an interrupt handler
446 * in a Zephyr application:
447 *
448 * IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_PDM_INST_GET(\<instance_index\>)), \<priority\>,
449 * NRFX_PDM_INST_HANDLER_GET(\<instance_index\>), 0, 0);
450 */
451 NRFX_INSTANCE_IRQ_HANDLERS_DECLARE(PDM, pdm)
452
453 #ifdef __cplusplus
454 }
455 #endif
456
457 #endif // NRFX_PDM_H__
458