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 #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_PDM0, NRF_PDM_EVENT_STARTED))
77     {
78         nrf_pdm_event_clear(NRF_PDM0, 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_PDM0, NRF_PDM_EVENT_STOPPED))
129     {
130         nrf_pdm_event_clear(NRF_PDM0, NRF_PDM_EVENT_STOPPED);
131         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_PDM_EVENT_STOPPED));
132         nrf_pdm_disable(NRF_PDM0);
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 #if NRF_PDM_HAS_RATIO_CONFIG
204     nrf_pdm_ratio_set(NRF_PDM0, p_config->ratio);
205 #endif
206 
207 #if NRF_PDM_HAS_MCLKCONFIG
208     nrf_pdm_mclksrc_configure(NRF_PDM0, p_config->mclksrc);
209 #endif
210     nrf_pdm_clock_set(NRF_PDM0, p_config->clock_freq);
211     nrf_pdm_mode_set(NRF_PDM0, p_config->mode, p_config->edge);
212     nrf_pdm_gain_set(NRF_PDM0, p_config->gain_l, p_config->gain_r);
213 
214     nrf_gpio_cfg_output(p_config->pin_clk);
215     nrf_gpio_pin_clear(p_config->pin_clk);
216     nrf_gpio_cfg_input(p_config->pin_din, NRF_GPIO_PIN_NOPULL);
217     nrf_pdm_psel_connect(NRF_PDM0, p_config->pin_clk, p_config->pin_din);
218 
219     nrf_pdm_event_clear(NRF_PDM0, NRF_PDM_EVENT_STARTED);
220     nrf_pdm_event_clear(NRF_PDM0, NRF_PDM_EVENT_END);
221     nrf_pdm_event_clear(NRF_PDM0, NRF_PDM_EVENT_STOPPED);
222     nrf_pdm_int_enable(NRF_PDM0, NRF_PDM_INT_STARTED | NRF_PDM_INT_STOPPED);
223     NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(NRF_PDM0), p_config->interrupt_priority);
224     NRFX_IRQ_ENABLE(nrfx_get_irq_number(NRF_PDM0));
225     m_cb.drv_state = NRFX_DRV_STATE_INITIALIZED;
226 
227     err_code = NRFX_SUCCESS;
228     NRFX_LOG_INFO("Function: %s, error code: %s.",
229                   __func__,
230                   NRFX_LOG_ERROR_STRING_GET(err_code));
231     return err_code;
232 }
233 
nrfx_pdm_uninit(void)234 void nrfx_pdm_uninit(void)
235 {
236     nrf_pdm_disable(NRF_PDM0);
237 
238     nrf_gpio_cfg_default(nrf_pdm_clk_pin_get(NRF_PDM0));
239     nrf_gpio_cfg_default(nrf_pdm_din_pin_get(NRF_PDM0));
240 
241     m_cb.drv_state = NRFX_DRV_STATE_UNINITIALIZED;
242     NRFX_LOG_INFO("Uninitialized.");
243 }
244 
pdm_start()245 static void pdm_start()
246 {
247     m_cb.drv_state = NRFX_DRV_STATE_POWERED_ON;
248     nrf_pdm_enable(NRF_PDM0);
249     nrf_pdm_event_clear(NRF_PDM0, NRF_PDM_EVENT_STARTED);
250     nrf_pdm_task_trigger(NRF_PDM0, NRF_PDM_TASK_START);
251 }
252 
pdm_buf_request()253 static void pdm_buf_request()
254 {
255     m_cb.irq_buff_request = 1;
256     NRFX_IRQ_PENDING_SET(nrfx_get_irq_number(NRF_PDM0));
257 }
258 
nrfx_pdm_start(void)259 nrfx_err_t nrfx_pdm_start(void)
260 {
261     NRFX_ASSERT(m_cb.drv_state != NRFX_DRV_STATE_UNINITIALIZED);
262     nrfx_err_t err_code;
263 
264     if (m_cb.op_state != NRFX_PDM_STATE_IDLE)
265     {
266         if (m_cb.op_state == NRFX_PDM_STATE_RUNNING)
267         {
268             err_code = NRFX_SUCCESS;
269             NRFX_LOG_INFO("Function: %s, error code: %s.",
270                           __func__,
271                           NRFX_LOG_ERROR_STRING_GET(err_code));
272             return err_code;
273         }
274         err_code = NRFX_ERROR_BUSY;
275         NRFX_LOG_WARNING("Function: %s, error code: %s.",
276                          __func__,
277                          NRFX_LOG_ERROR_STRING_GET(err_code));
278         return err_code;
279     }
280 
281     m_cb.op_state = NRFX_PDM_STATE_STARTING;
282     pdm_buf_request();
283 
284     err_code = NRFX_SUCCESS;
285     NRFX_LOG_INFO("Function: %s, error code: %s.",
286                   __func__,
287                   NRFX_LOG_ERROR_STRING_GET(err_code));
288     return err_code;
289 }
290 
nrfx_pdm_buffer_set(int16_t * buffer,uint16_t buffer_length)291 nrfx_err_t nrfx_pdm_buffer_set(int16_t * buffer, uint16_t buffer_length)
292 {
293     if (m_cb.drv_state == NRFX_DRV_STATE_UNINITIALIZED)
294     {
295         return NRFX_ERROR_INVALID_STATE;
296     }
297     if (m_cb.op_state == NRFX_PDM_STATE_STOPPING)
298     {
299         return NRFX_ERROR_BUSY;
300     }
301     if ((buffer == NULL) || (buffer_length > NRFX_PDM_MAX_BUFFER_SIZE))
302     {
303         return NRFX_ERROR_INVALID_PARAM;
304     }
305 
306     nrfx_err_t err_code = NRFX_SUCCESS;
307 
308     // Enter the PDM critical section.
309     NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_PDM0));
310 
311     uint8_t next_buffer = (~m_cb.active_buffer) & 0x01;
312     if (m_cb.op_state == NRFX_PDM_STATE_STARTING)
313     {
314         next_buffer = 0;
315     }
316 
317     if (m_cb.buff_address[next_buffer])
318     {
319         // Buffer already set.
320         err_code = NRFX_ERROR_BUSY;
321     }
322     else
323     {
324         m_cb.buff_address[next_buffer] = buffer;
325         m_cb.buff_length[next_buffer] = buffer_length;
326         nrf_pdm_buffer_set(NRF_PDM0, (uint32_t *)buffer, buffer_length);
327 
328         if (m_cb.drv_state != NRFX_DRV_STATE_POWERED_ON)
329         {
330             pdm_start();
331         }
332     }
333 
334     NRFX_IRQ_ENABLE(nrfx_get_irq_number(NRF_PDM0));
335     return err_code;
336 }
337 
nrfx_pdm_stop(void)338 nrfx_err_t nrfx_pdm_stop(void)
339 {
340     NRFX_ASSERT(m_cb.drv_state != NRFX_DRV_STATE_UNINITIALIZED);
341     nrfx_err_t err_code;
342 
343     if (m_cb.op_state != NRFX_PDM_STATE_RUNNING)
344     {
345         if (m_cb.op_state == NRFX_PDM_STATE_IDLE ||
346             m_cb.op_state == NRFX_PDM_STATE_STARTING)
347         {
348             nrf_pdm_disable(NRF_PDM0);
349             m_cb.op_state = NRFX_PDM_STATE_IDLE;
350             err_code = NRFX_SUCCESS;
351             NRFX_LOG_INFO("Function: %s, error code: %s.",
352                           __func__,
353                           NRFX_LOG_ERROR_STRING_GET(err_code));
354             return err_code;
355         }
356         err_code = NRFX_ERROR_BUSY;
357         NRFX_LOG_WARNING("Function: %s, error code: %s.",
358                          __func__,
359                          NRFX_LOG_ERROR_STRING_GET(err_code));
360         return err_code;
361     }
362     m_cb.drv_state = NRFX_DRV_STATE_INITIALIZED;
363     m_cb.op_state = NRFX_PDM_STATE_STOPPING;
364 
365     nrf_pdm_task_trigger(NRF_PDM0, NRF_PDM_TASK_STOP);
366     err_code = NRFX_SUCCESS;
367     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
368     return err_code;
369 }
370 
371 #endif // NRFX_CHECK(NRFX_PDM_ENABLED)
372