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 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 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 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 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 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 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 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 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 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 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 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