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