xref: /nrf52832-nimble/nordic/nrfx/drivers/src/nrfx_adc.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_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