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_ADC_ENABLED)
35
36 #include <nrfx_adc.h>
37
38 #define NRFX_LOG_MODULE ADC
39 #include <nrfx_log.h>
40
41 #define EVT_TO_STR(event) (event == NRF_ADC_EVENT_END ? "NRF_ADC_EVENT_END" : "UNKNOWN EVENT")
42
43 typedef struct
44 {
45 nrfx_adc_event_handler_t event_handler;
46 nrfx_adc_channel_t * p_head;
47 nrfx_adc_channel_t * p_current_conv;
48 nrf_adc_value_t * p_buffer;
49 uint16_t size;
50 uint16_t idx;
51 nrfx_drv_state_t state;
52 } adc_cb_t;
53
54 static adc_cb_t m_cb;
55
nrfx_adc_init(nrfx_adc_config_t const * p_config,nrfx_adc_event_handler_t event_handler)56 nrfx_err_t nrfx_adc_init(nrfx_adc_config_t const * p_config,
57 nrfx_adc_event_handler_t event_handler)
58 {
59 NRFX_ASSERT(p_config);
60 nrfx_err_t err_code;
61
62 if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
63 {
64 err_code = NRFX_ERROR_INVALID_STATE;
65 NRFX_LOG_WARNING("Function: %s, error code: %s.",
66 __func__,
67 NRFX_LOG_ERROR_STRING_GET(err_code));
68 return err_code;
69 }
70
71 nrf_adc_event_clear(NRF_ADC_EVENT_END);
72 if (event_handler)
73 {
74 NRFX_IRQ_PRIORITY_SET(ADC_IRQn, p_config->interrupt_priority);
75 NRFX_IRQ_ENABLE(ADC_IRQn);
76 }
77 m_cb.event_handler = event_handler;
78 m_cb.state = NRFX_DRV_STATE_INITIALIZED;
79
80 err_code = NRFX_SUCCESS;
81 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
82 return err_code;
83 }
84
nrfx_adc_uninit(void)85 void nrfx_adc_uninit(void)
86 {
87 NRFX_IRQ_DISABLE(ADC_IRQn);
88 nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
89 nrf_adc_task_trigger(NRF_ADC_TASK_STOP);
90
91 // Disable all channels. This must be done after the interrupt is disabled
92 // because adc_sample_process() dereferences this pointer when it needs to
93 // switch back to the first channel in the list (when the number of samples
94 // to read is bigger than the number of enabled channels).
95 m_cb.p_head = NULL;
96
97 m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
98 }
99
nrfx_adc_channel_enable(nrfx_adc_channel_t * const p_channel)100 void nrfx_adc_channel_enable(nrfx_adc_channel_t * const p_channel)
101 {
102 NRFX_ASSERT(!nrfx_adc_is_busy());
103
104 p_channel->p_next = NULL;
105 if (m_cb.p_head == NULL)
106 {
107 m_cb.p_head = p_channel;
108 }
109 else
110 {
111 nrfx_adc_channel_t * p_curr_channel = m_cb.p_head;
112 while (p_curr_channel->p_next != NULL)
113 {
114 NRFX_ASSERT(p_channel != p_curr_channel);
115 p_curr_channel = p_curr_channel->p_next;
116 }
117 p_curr_channel->p_next = p_channel;
118 }
119
120 NRFX_LOG_INFO("Enabled.");
121 }
122
nrfx_adc_channel_disable(nrfx_adc_channel_t * const p_channel)123 void nrfx_adc_channel_disable(nrfx_adc_channel_t * const p_channel)
124 {
125 NRFX_ASSERT(m_cb.p_head);
126 NRFX_ASSERT(!nrfx_adc_is_busy());
127
128 nrfx_adc_channel_t * p_curr_channel = m_cb.p_head;
129 nrfx_adc_channel_t * p_prev_channel = NULL;
130 while (p_curr_channel != p_channel)
131 {
132 p_prev_channel = p_curr_channel;
133 p_curr_channel = p_curr_channel->p_next;
134 NRFX_ASSERT(p_curr_channel != NULL);
135 }
136 if (p_prev_channel)
137 {
138 p_prev_channel->p_next = p_curr_channel->p_next;
139 }
140 else
141 {
142 m_cb.p_head = p_curr_channel->p_next;
143 }
144
145 NRFX_LOG_INFO("Disabled.");
146 }
147
nrfx_adc_all_channels_disable(void)148 void nrfx_adc_all_channels_disable(void)
149 {
150 NRFX_ASSERT(!nrfx_adc_is_busy());
151
152 m_cb.p_head = NULL;
153 }
154
nrfx_adc_sample(void)155 void nrfx_adc_sample(void)
156 {
157 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
158 NRFX_ASSERT(!nrf_adc_busy_check());
159 nrf_adc_task_trigger(NRF_ADC_TASK_START);
160 }
161
nrfx_adc_sample_convert(nrfx_adc_channel_t const * const p_channel,nrf_adc_value_t * p_value)162 nrfx_err_t nrfx_adc_sample_convert(nrfx_adc_channel_t const * const p_channel,
163 nrf_adc_value_t * p_value)
164 {
165 nrfx_err_t err_code;
166
167 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
168 if (m_cb.state == NRFX_DRV_STATE_POWERED_ON)
169 {
170 err_code = NRFX_ERROR_BUSY;
171 NRFX_LOG_WARNING("Function: %s, error code: %s.",
172 __func__,
173 NRFX_LOG_ERROR_STRING_GET(err_code));
174 return err_code;
175 }
176 else
177 {
178 m_cb.state = NRFX_DRV_STATE_POWERED_ON;
179
180 nrf_adc_init(&p_channel->config);
181 nrf_adc_enable();
182 nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
183 nrf_adc_task_trigger(NRF_ADC_TASK_START);
184 if (p_value)
185 {
186 while (!nrf_adc_event_check(NRF_ADC_EVENT_END)) {}
187 nrf_adc_event_clear(NRF_ADC_EVENT_END);
188 *p_value = (nrf_adc_value_t)nrf_adc_result_get();
189 nrf_adc_disable();
190
191 m_cb.state = NRFX_DRV_STATE_INITIALIZED;
192 }
193 else
194 {
195 NRFX_ASSERT(m_cb.event_handler);
196 m_cb.p_buffer = NULL;
197 nrf_adc_int_enable(NRF_ADC_INT_END_MASK);
198 }
199 err_code = NRFX_SUCCESS;
200 NRFX_LOG_INFO("Function: %s, error code: %s.",
201 __func__,
202 NRFX_LOG_ERROR_STRING_GET(err_code));
203 return err_code;
204 }
205 }
206
adc_sample_process()207 static bool adc_sample_process()
208 {
209 nrf_adc_event_clear(NRF_ADC_EVENT_END);
210 nrf_adc_disable();
211 m_cb.p_buffer[m_cb.idx] = (nrf_adc_value_t)nrf_adc_result_get();
212 m_cb.idx++;
213 if (m_cb.idx < m_cb.size)
214 {
215 bool task_trigger = false;
216 if (m_cb.p_current_conv->p_next == NULL)
217 {
218 // Make sure the list of channels has not been somehow removed
219 // (it is when all channels are disabled).
220 NRFX_ASSERT(m_cb.p_head);
221
222 m_cb.p_current_conv = m_cb.p_head;
223 }
224 else
225 {
226 m_cb.p_current_conv = m_cb.p_current_conv->p_next;
227 task_trigger = true;
228 }
229 nrf_adc_init(&m_cb.p_current_conv->config);
230 nrf_adc_enable();
231 if (task_trigger)
232 {
233 nrf_adc_task_trigger(NRF_ADC_TASK_START);
234 }
235 return false;
236 }
237 else
238 {
239 return true;
240 }
241 }
242
nrfx_adc_buffer_convert(nrf_adc_value_t * buffer,uint16_t size)243 nrfx_err_t nrfx_adc_buffer_convert(nrf_adc_value_t * buffer, uint16_t size)
244 {
245 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
246
247 nrfx_err_t err_code;
248
249 NRFX_LOG_INFO("Number of samples requested to convert: %d.", size);
250
251 if (m_cb.state == NRFX_DRV_STATE_POWERED_ON)
252 {
253 err_code = NRFX_ERROR_BUSY;
254 NRFX_LOG_WARNING("Function: %s, error code: %s.",
255 __func__,
256 NRFX_LOG_ERROR_STRING_GET(err_code));
257 return err_code;
258 }
259 else
260 {
261 m_cb.state = NRFX_DRV_STATE_POWERED_ON;
262 m_cb.p_current_conv = m_cb.p_head;
263 m_cb.size = size;
264 m_cb.idx = 0;
265 m_cb.p_buffer = buffer;
266 nrf_adc_init(&m_cb.p_current_conv->config);
267 nrf_adc_event_clear(NRF_ADC_EVENT_END);
268 nrf_adc_enable();
269 if (m_cb.event_handler)
270 {
271 nrf_adc_int_enable(NRF_ADC_INT_END_MASK);
272 }
273 else
274 {
275 while (1)
276 {
277 while (!nrf_adc_event_check(NRF_ADC_EVENT_END)){}
278
279 if (adc_sample_process())
280 {
281 m_cb.state = NRFX_DRV_STATE_INITIALIZED;
282 break;
283 }
284 }
285 }
286 err_code = NRFX_SUCCESS;
287 NRFX_LOG_INFO("Function: %s, error code: %s.",
288 __func__,
289 NRFX_LOG_ERROR_STRING_GET(err_code));
290 return err_code;
291 }
292 }
293
nrfx_adc_is_busy(void)294 bool nrfx_adc_is_busy(void)
295 {
296 NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
297 return (m_cb.state == NRFX_DRV_STATE_POWERED_ON) ? true : false;
298 }
299
nrfx_adc_irq_handler(void)300 void nrfx_adc_irq_handler(void)
301 {
302 if (m_cb.p_buffer == NULL)
303 {
304 nrf_adc_event_clear(NRF_ADC_EVENT_END);
305 NRFX_LOG_DEBUG("Event: %s.",NRFX_LOG_ERROR_STRING_GET(NRF_ADC_EVENT_END));
306 nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
307 nrf_adc_disable();
308 nrfx_adc_evt_t evt;
309 evt.type = NRFX_ADC_EVT_SAMPLE;
310 evt.data.sample.sample = (nrf_adc_value_t)nrf_adc_result_get();
311 NRFX_LOG_DEBUG("ADC data:");
312 NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)(&evt.data.sample.sample), sizeof(nrf_adc_value_t));
313 m_cb.state = NRFX_DRV_STATE_INITIALIZED;
314 m_cb.event_handler(&evt);
315 }
316 else if (adc_sample_process())
317 {
318 NRFX_LOG_DEBUG("Event: %s.", NRFX_LOG_ERROR_STRING_GET(NRF_ADC_EVENT_END));
319 nrf_adc_int_disable(NRF_ADC_INT_END_MASK);
320 nrfx_adc_evt_t evt;
321 evt.type = NRFX_ADC_EVT_DONE;
322 evt.data.done.p_buffer = m_cb.p_buffer;
323 evt.data.done.size = m_cb.size;
324 m_cb.state = NRFX_DRV_STATE_INITIALIZED;
325 NRFX_LOG_DEBUG("ADC data:");
326 NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)m_cb.p_buffer, m_cb.size * sizeof(nrf_adc_value_t));
327 m_cb.event_handler(&evt);
328 }
329 }
330
331 #endif // NRFX_CHECK(NRFX_ADC_ENABLED)
332