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