xref: /nrf52832-nimble/nordic/nrfx/drivers/src/nrfx_pdm.c (revision 150812a83cab50279bd772ef6db1bfaf255f2c5b)
1 /*
2  * Copyright (c) 2015 - 2018, 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 #include <nrfx.h>
33 
34 #if NRFX_CHECK(NRFX_PDM_ENABLED)
35 
36 #include <nrfx_pdm.h>
37 #include <hal/nrf_gpio.h>
38 
39 #define NRFX_LOG_MODULE PDM
40 #include <nrfx_log.h>
41 
42 #define EVT_TO_STR(event)                                       \
43     (event == NRF_PDM_EVENT_STARTED ? "NRF_PDM_EVENT_STARTED" : \
44     (event == NRF_PDM_EVENT_STOPPED ? "NRF_PDM_EVENT_STOPPED" : \
45     (event == NRF_PDM_EVENT_END     ? "NRF_PDM_EVENT_END"     : \
46                                       "UNKNOWN EVENT")))
47 
48 
49 /** @brief PDM interface status. */
50 typedef enum
51 {
52     NRFX_PDM_STATE_IDLE,
53     NRFX_PDM_STATE_RUNNING,
54     NRFX_PDM_STATE_STARTING,
55     NRFX_PDM_STATE_STOPPING
56 } nrfx_pdm_state_t;
57 
58 /** @brief PDM interface control block.*/
59 typedef struct
60 {
61     nrfx_pdm_event_handler_t  event_handler;    ///< Event handler function pointer.
62     int16_t *                 buff_address[2];  ///< Sample buffers.
63     uint16_t                  buff_length[2];   ///< Length of the sample buffers.
64     nrfx_drv_state_t          drv_state;        ///< Driver state.
65     volatile nrfx_pdm_state_t op_state;         ///< PDM peripheral operation state.
66     uint8_t                   active_buffer;    ///< Number of currently active buffer.
67     uint8_t                   error;            ///< Driver error flag.
68     volatile uint8_t          irq_buff_request; ///< Request the next buffer in the ISR.
69 } nrfx_pdm_cb_t;
70 
71 static nrfx_pdm_cb_t m_cb;
72 
73 
nrfx_pdm_irq_handler(void)74 void nrfx_pdm_irq_handler(void)
75 {
76     if (nrf_pdm_event_check(NRF_PDM_EVENT_STARTED))
77     {
78         nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED);
79         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_PDM_EVENT_STARTED));
80 
81         uint8_t finished_buffer = m_cb.active_buffer;
82 
83         // Check if the next buffer was set before.
84         uint8_t next_buffer = (~m_cb.active_buffer) & 0x01;
85         if (m_cb.buff_address[next_buffer] ||
86             m_cb.op_state == NRFX_PDM_STATE_STARTING)
87         {
88             nrfx_pdm_evt_t evt;
89             evt.error = NRFX_PDM_NO_ERROR;
90             m_cb.error = 0;
91 
92             // Release the full buffer if ready and request the next one.
93             if (m_cb.op_state == NRFX_PDM_STATE_STARTING)
94             {
95                 evt.buffer_released = 0;
96                 m_cb.op_state = NRFX_PDM_STATE_RUNNING;
97             }
98             else
99             {
100                 evt.buffer_released = m_cb.buff_address[finished_buffer];
101                 m_cb.buff_address[finished_buffer] = 0;
102                 m_cb.active_buffer = next_buffer;
103             }
104             evt.buffer_requested = true;
105             m_cb.event_handler(&evt);
106         }
107         else
108         {
109             // No next buffer available. Report an error.
110             // Do not request the new buffer as it was already done.
111             if (m_cb.error == 0)
112             {
113                 nrfx_pdm_evt_t const evt = {
114                     .buffer_requested = false,
115                     .buffer_released  = NULL,
116                     .error = NRFX_PDM_ERROR_OVERFLOW
117                 };
118                 m_cb.error = 1;
119                 m_cb.event_handler(&evt);
120             }
121         }
122 
123         if (m_cb.op_state == NRFX_PDM_STATE_STARTING)
124         {
125             m_cb.op_state = NRFX_PDM_STATE_RUNNING;
126         }
127     }
128     else if (nrf_pdm_event_check(NRF_PDM_EVENT_STOPPED))
129     {
130         nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED);
131         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_PDM_EVENT_STOPPED));
132         nrf_pdm_disable();
133         m_cb.op_state = NRFX_PDM_STATE_IDLE;
134 
135         // Release the buffers.
136         nrfx_pdm_evt_t evt;
137         evt.error = NRFX_PDM_NO_ERROR;
138         evt.buffer_requested = false;
139         if (m_cb.buff_address[m_cb.active_buffer])
140         {
141             evt.buffer_released = m_cb.buff_address[m_cb.active_buffer];
142             m_cb.buff_address[m_cb.active_buffer] = 0;
143             m_cb.event_handler(&evt);
144         }
145 
146         uint8_t second_buffer = (~m_cb.active_buffer) & 0x01;
147         if (m_cb.buff_address[second_buffer])
148         {
149             evt.buffer_released = m_cb.buff_address[second_buffer];
150             m_cb.buff_address[second_buffer] = 0;
151             m_cb.event_handler(&evt);
152         }
153         m_cb.active_buffer = 0;
154     }
155 
156     if (m_cb.irq_buff_request)
157     {
158         nrfx_pdm_evt_t const evt =
159         {
160             .buffer_requested = true,
161             .buffer_released  = NULL,
162             .error = NRFX_PDM_NO_ERROR,
163         };
164         m_cb.irq_buff_request = 0;
165         m_cb.event_handler(&evt);
166     }
167 }
168 
169 
nrfx_pdm_init(nrfx_pdm_config_t const * p_config,nrfx_pdm_event_handler_t event_handler)170 nrfx_err_t nrfx_pdm_init(nrfx_pdm_config_t const * p_config,
171                          nrfx_pdm_event_handler_t  event_handler)
172 {
173     NRFX_ASSERT(p_config);
174     NRFX_ASSERT(event_handler);
175     nrfx_err_t err_code;
176 
177     if (m_cb.drv_state != NRFX_DRV_STATE_UNINITIALIZED)
178     {
179         err_code = NRFX_ERROR_INVALID_STATE;
180         NRFX_LOG_WARNING("Function: %s, error code: %s.",
181                          __func__,
182                          NRFX_LOG_ERROR_STRING_GET(err_code));
183         return err_code;
184     }
185 
186     if (p_config->gain_l > NRF_PDM_GAIN_MAXIMUM ||
187         p_config->gain_r > NRF_PDM_GAIN_MAXIMUM)
188     {
189         err_code = NRFX_ERROR_INVALID_PARAM;
190         NRFX_LOG_WARNING("Function: %s, error code: %s.",
191                          __func__,
192                          NRFX_LOG_ERROR_STRING_GET(err_code));
193         return err_code;
194     }
195 
196     m_cb.buff_address[0] = 0;
197     m_cb.buff_address[1] = 0;
198     m_cb.active_buffer = 0;
199     m_cb.error = 0;
200     m_cb.event_handler = event_handler;
201     m_cb.op_state = NRFX_PDM_STATE_IDLE;
202 
203     nrf_pdm_clock_set(p_config->clock_freq);
204     nrf_pdm_mode_set(p_config->mode, p_config->edge);
205     nrf_pdm_gain_set(p_config->gain_l, p_config->gain_r);
206 
207     nrf_gpio_cfg_output(p_config->pin_clk);
208     nrf_gpio_pin_clear(p_config->pin_clk);
209     nrf_gpio_cfg_input(p_config->pin_din, NRF_GPIO_PIN_NOPULL);
210     nrf_pdm_psel_connect(p_config->pin_clk, p_config->pin_din);
211 
212     nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED);
213     nrf_pdm_event_clear(NRF_PDM_EVENT_END);
214     nrf_pdm_event_clear(NRF_PDM_EVENT_STOPPED);
215     nrf_pdm_int_enable(NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED);
216     NRFX_IRQ_PRIORITY_SET(PDM_IRQn, p_config->interrupt_priority);
217     NRFX_IRQ_ENABLE(PDM_IRQn);
218     m_cb.drv_state = NRFX_DRV_STATE_INITIALIZED;
219 
220     err_code = NRFX_SUCCESS;
221     NRFX_LOG_INFO("Function: %s, error code: %s.",
222                   __func__,
223                   NRFX_LOG_ERROR_STRING_GET(err_code));
224     return err_code;
225 }
226 
nrfx_pdm_uninit(void)227 void nrfx_pdm_uninit(void)
228 {
229     nrf_pdm_disable();
230     nrf_pdm_psel_disconnect();
231     m_cb.drv_state = NRFX_DRV_STATE_UNINITIALIZED;
232     NRFX_LOG_INFO("Uninitialized.");
233 }
234 
pdm_start()235 static void pdm_start()
236 {
237     m_cb.drv_state = NRFX_DRV_STATE_POWERED_ON;
238     nrf_pdm_enable();
239     nrf_pdm_event_clear(NRF_PDM_EVENT_STARTED);
240     nrf_pdm_task_trigger(NRF_PDM_TASK_START);
241 }
242 
pdm_buf_request()243 static void pdm_buf_request()
244 {
245     m_cb.irq_buff_request = 1;
246     NRFX_IRQ_PENDING_SET(PDM_IRQn);
247 }
248 
nrfx_pdm_start(void)249 nrfx_err_t nrfx_pdm_start(void)
250 {
251     NRFX_ASSERT(m_cb.drv_state != NRFX_DRV_STATE_UNINITIALIZED);
252     nrfx_err_t err_code;
253 
254     if (m_cb.op_state != NRFX_PDM_STATE_IDLE)
255     {
256         if (m_cb.op_state == NRFX_PDM_STATE_RUNNING)
257         {
258             err_code = NRFX_SUCCESS;
259             NRFX_LOG_INFO("Function: %s, error code: %s.",
260                           __func__,
261                           NRFX_LOG_ERROR_STRING_GET(err_code));
262             return err_code;
263         }
264         err_code = NRFX_ERROR_BUSY;
265         NRFX_LOG_WARNING("Function: %s, error code: %s.",
266                          __func__,
267                          NRFX_LOG_ERROR_STRING_GET(err_code));
268         return err_code;
269     }
270 
271     m_cb.op_state = NRFX_PDM_STATE_STARTING;
272     pdm_buf_request();
273 
274     err_code = NRFX_SUCCESS;
275     NRFX_LOG_INFO("Function: %s, error code: %s.",
276                   __func__,
277                   NRFX_LOG_ERROR_STRING_GET(err_code));
278     return err_code;
279 }
280 
nrfx_pdm_buffer_set(int16_t * buffer,uint16_t buffer_length)281 nrfx_err_t nrfx_pdm_buffer_set(int16_t * buffer, uint16_t buffer_length)
282 {
283     if (m_cb.drv_state == NRFX_DRV_STATE_UNINITIALIZED)
284     {
285         return NRFX_ERROR_INVALID_STATE;
286     }
287     if (m_cb.op_state == NRFX_PDM_STATE_STOPPING)
288     {
289         return NRFX_ERROR_BUSY;
290     }
291     if ((buffer == NULL) || (buffer_length > NRFX_PDM_MAX_BUFFER_SIZE))
292     {
293         return NRFX_ERROR_INVALID_PARAM;
294     }
295 
296     nrfx_err_t err_code = NRFX_SUCCESS;
297 
298     // Enter the PDM critical section.
299     NRFX_IRQ_DISABLE(PDM_IRQn);
300 
301     uint8_t next_buffer = (~m_cb.active_buffer) & 0x01;
302     if (m_cb.op_state == NRFX_PDM_STATE_STARTING)
303     {
304         next_buffer = 0;
305     }
306 
307     if (m_cb.buff_address[next_buffer])
308     {
309         // Buffer already set.
310         err_code = NRFX_ERROR_BUSY;
311     }
312     else
313     {
314         m_cb.buff_address[next_buffer] = buffer;
315         m_cb.buff_length[next_buffer] = buffer_length;
316         nrf_pdm_buffer_set((uint32_t *)buffer, buffer_length);
317 
318         if (m_cb.drv_state != NRFX_DRV_STATE_POWERED_ON)
319         {
320             pdm_start();
321         }
322     }
323 
324     NRFX_IRQ_ENABLE(PDM_IRQn);
325     return err_code;
326 }
327 
nrfx_pdm_stop(void)328 nrfx_err_t nrfx_pdm_stop(void)
329 {
330     NRFX_ASSERT(m_cb.drv_state != NRFX_DRV_STATE_UNINITIALIZED);
331     nrfx_err_t err_code;
332 
333     if (m_cb.op_state != NRFX_PDM_STATE_RUNNING)
334     {
335         if (m_cb.op_state == NRFX_PDM_STATE_IDLE ||
336             m_cb.op_state == NRFX_PDM_STATE_STARTING)
337         {
338             nrf_pdm_disable();
339             m_cb.op_state = NRFX_PDM_STATE_IDLE;
340             err_code = NRFX_SUCCESS;
341             NRFX_LOG_INFO("Function: %s, error code: %s.",
342                           __func__,
343                           NRFX_LOG_ERROR_STRING_GET(err_code));
344             return err_code;
345         }
346         err_code = NRFX_ERROR_BUSY;
347         NRFX_LOG_WARNING("Function: %s, error code: %s.",
348                          __func__,
349                          NRFX_LOG_ERROR_STRING_GET(err_code));
350         return err_code;
351     }
352     m_cb.drv_state = NRFX_DRV_STATE_INITIALIZED;
353     m_cb.op_state = NRFX_PDM_STATE_STOPPING;
354 
355     nrf_pdm_task_trigger(NRF_PDM_TASK_STOP);
356     err_code = NRFX_SUCCESS;
357     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
358     return err_code;
359 }
360 
361 #endif // NRFX_CHECK(NRFX_PDM_ENABLED)
362