1 /**
2 * \file
3 *
4 * \brief SAM Sigma-Delta Analog-to-Digital Converter Driver
5 *
6 * Copyright (C) 2015 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46
47 #include "sdadc_callback.h"
48
49 struct sdadc_module *_sdadc_instances[SDADC_INST_NUM];
50
_sdadc_interrupt_handler(const uint8_t instance)51 static void _sdadc_interrupt_handler(const uint8_t instance)
52 {
53 struct sdadc_module *module = _sdadc_instances[instance];
54
55 /* get interrupt flags and mask out enabled callbacks */
56 uint32_t flags = module->hw->INTFLAG.reg;
57
58 if (flags & SDADC_INTFLAG_RESRDY) {
59 if ((module->enabled_callback_mask & (1 << SDADC_CALLBACK_READ_BUFFER)) &&
60 (module->registered_callback_mask & (1 << SDADC_CALLBACK_READ_BUFFER))) {
61 /* clear interrupt flag */
62 module->hw->INTFLAG.reg = SDADC_INTFLAG_RESRDY;
63
64 /* store SDADC result in job buffer */
65 *(module->job_buffer++) = ((int32_t)(module->hw->RESULT.reg << 8)) >> 8;
66
67 if (--module->remaining_conversions > 0) {
68 if (module->software_trigger == true) {
69 sdadc_start_conversion(module);
70 }
71 } else {
72 if (module->job_status == STATUS_BUSY) {
73 /* job is complete. update status,disable interrupt
74 *and call callback */
75 module->job_status = STATUS_OK;
76 sdadc_disable_interrupt(module, SDADC_INTERRUPT_RESULT_READY);
77
78 (module->callback[SDADC_CALLBACK_READ_BUFFER])(module);
79 }
80 }
81 }
82 }
83
84 if (flags & SDADC_INTFLAG_WINMON) {
85 module->hw->INTFLAG.reg = SDADC_INTFLAG_WINMON;
86 if ((module->enabled_callback_mask & (1 << SDADC_CALLBACK_WINDOW)) &&
87 (module->registered_callback_mask & (1 << SDADC_CALLBACK_WINDOW))) {
88 (module->callback[SDADC_CALLBACK_WINDOW])(module);
89 }
90
91 }
92
93 if (flags & SDADC_INTFLAG_OVERRUN) {
94 module->hw->INTFLAG.reg = SDADC_INTFLAG_OVERRUN;
95 if ((module->enabled_callback_mask & (1 << SDADC_CALLBACK_ERROR)) &&
96 (module->registered_callback_mask & (1 << SDADC_CALLBACK_ERROR))) {
97 (module->callback[SDADC_CALLBACK_ERROR])(module);
98 }
99 }
100 }
101
102 /** Interrupt handler for the SDADC module. */
SDADC_Handler(void)103 void SDADC_Handler(void)
104 {
105 _sdadc_interrupt_handler(0);
106 }
107
108 /**
109 * \brief Registers a callback.
110 *
111 * Registers a callback function which is implemented by the user.
112 *
113 * \note The callback must be enabled by for the interrupt handler to call it
114 * when the condition for the callback is met.
115 *
116 * \param[in] module Pointer to SDADC software instance struct
117 * \param[in] callback_func Pointer to callback function
118 * \param[in] callback_type Callback type given by an enum
119 *
120 */
sdadc_register_callback(struct sdadc_module * const module,sdadc_callback_t callback_func,enum sdadc_callback callback_type)121 void sdadc_register_callback(
122 struct sdadc_module *const module,
123 sdadc_callback_t callback_func,
124 enum sdadc_callback callback_type)
125 {
126 /* Sanity check arguments */
127 Assert(module);
128 Assert(callback_func);
129
130 /* Register callback function */
131 module->callback[callback_type] = callback_func;
132
133 /* Set the bit corresponding to the callback_type */
134 module->registered_callback_mask |= (1 << callback_type);
135 }
136
137 /**
138 * \brief Unregisters a callback.
139 *
140 * Unregisters a callback function which is implemented by the user.
141 *
142 * \param[in] module Pointer to SDADC software instance struct
143 * \param[in] callback_type Callback type given by an enum
144 *
145 */
sdadc_unregister_callback(struct sdadc_module * const module,enum sdadc_callback callback_type)146 void sdadc_unregister_callback(
147 struct sdadc_module *const module,
148 enum sdadc_callback callback_type)
149 {
150 /* Sanity check arguments */
151 Assert(module);
152
153 /* Unregister callback function */
154 module->callback[callback_type] = NULL;
155
156 /* Clear the bit corresponding to the callback_type */
157 module->registered_callback_mask &= ~(1 << callback_type);
158 }
159
160 /**
161 * \brief Read multiple samples from SDADC.
162 *
163 * Read \c samples from the SDADC into the \c buffer.
164 * If there is no hardware trigger defined (event action) the
165 * driver will retrigger the SDADC conversion whenever a conversion
166 * is complete until \c samples has been acquired. To avoid
167 * jitter in the sampling frequency using an event trigger is advised.
168 *
169 * \param[in] module_inst Pointer to the SDADC software instance struct
170 * \param[in] samples Number of samples to acquire
171 * \param[out] buffer Buffer to store the SDADC samples
172 *
173 * \return Status of the job start.
174 * \retval STATUS_OK The conversion job was started successfully and is
175 * in progress
176 * \retval STATUS_BUSY The SDADC is already busy with another job
177 */
sdadc_read_buffer_job(struct sdadc_module * const module_inst,int32_t * buffer,uint16_t samples)178 enum status_code sdadc_read_buffer_job(
179 struct sdadc_module *const module_inst,
180 int32_t *buffer,
181 uint16_t samples)
182 {
183 Assert(module_inst);
184 Assert(samples);
185 Assert(buffer);
186
187 if(module_inst->remaining_conversions != 0 ||
188 module_inst->job_status == STATUS_BUSY){
189 return STATUS_BUSY;
190 }
191
192 module_inst->job_status = STATUS_BUSY;
193 module_inst->remaining_conversions = samples;
194 module_inst->job_buffer = buffer;
195
196 sdadc_enable_interrupt(module_inst, SDADC_INTERRUPT_RESULT_READY);
197
198 if(module_inst->software_trigger == true) {
199 sdadc_start_conversion(module_inst);
200 }
201
202 return STATUS_OK;
203 }
204
205 /**
206 * \brief Gets the status of a job.
207 *
208 * Gets the status of an ongoing or the last job.
209 *
210 * \param [in] module_inst Pointer to the SDADC software instance struct
211 * \param [in] type Type of job to abort
212 *
213 * \return Status of the job.
214 */
sdadc_get_job_status(struct sdadc_module * module_inst,enum sdadc_job_type type)215 enum status_code sdadc_get_job_status(
216 struct sdadc_module *module_inst,
217 enum sdadc_job_type type)
218 {
219 /* Sanity check arguments */
220 Assert(module_inst);
221
222 if (type == SDADC_JOB_READ_BUFFER ) {
223 return module_inst->job_status;
224 } else {
225 return STATUS_ERR_INVALID_ARG;
226 }
227 }
228
229 /**
230 * \brief Aborts an ongoing job.
231 *
232 * Aborts an ongoing job with given type.
233 *
234 * \param [in] module_inst Pointer to the SDADC software instance struct
235 * \param [in] type Type of job to abort
236 */
sdadc_abort_job(struct sdadc_module * module_inst,enum sdadc_job_type type)237 void sdadc_abort_job(
238 struct sdadc_module *module_inst,
239 enum sdadc_job_type type)
240 {
241 /* Sanity check arguments */
242 Assert(module_inst);
243
244 if (type == SDADC_JOB_READ_BUFFER) {
245 /* Disable interrupt */
246 sdadc_disable_interrupt(module_inst, SDADC_INTERRUPT_RESULT_READY);
247 /* Mark job as aborted */
248 module_inst->job_status = STATUS_ABORTED;
249 module_inst->remaining_conversions = 0;
250 }
251 }
252
253