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