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