atmel-samd: Initial ADC support.
This commit is contained in:
parent
3cb4938c63
commit
259ae8a39d
@ -47,6 +47,7 @@ INC += $(addprefix -Iasf/sam0/,\
|
||||
drivers/extint/ \
|
||||
drivers/port \
|
||||
drivers/system \
|
||||
drivers/adc/adc_sam_d_r \
|
||||
drivers/system/clock \
|
||||
drivers/system/clock/clock_samd21_r21_da \
|
||||
drivers/system/interrupt \
|
||||
@ -97,6 +98,7 @@ SRC_ASF = $(addprefix asf/sam0/,\
|
||||
drivers/sercom/sercom_interrupt.c \
|
||||
drivers/sercom/usart/usart.c \
|
||||
drivers/sercom/usart/usart_interrupt.c \
|
||||
drivers/adc/adc_sam_d_r/adc.c \
|
||||
drivers/system/clock/clock_samd21_r21_da/clock.c \
|
||||
drivers/system/clock/clock_samd21_r21_da/gclk.c \
|
||||
drivers/system/interrupt/system_interrupt.c \
|
||||
@ -108,6 +110,7 @@ SRC_ASF = $(addprefix asf/sam0/,\
|
||||
)
|
||||
|
||||
SRC_C = \
|
||||
adc.c \
|
||||
main.c \
|
||||
modmachine.c \
|
||||
modutime.c \
|
||||
|
139
atmel-samd/adc.c
Normal file
139
atmel-samd/adc.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/binary.h"
|
||||
#include "py/mphal.h"
|
||||
#include "adc.h"
|
||||
#include "pin.h"
|
||||
|
||||
#include "asf/sam0/drivers/adc/adc.h"
|
||||
|
||||
/// \moduleref machine
|
||||
/// \class ADC - analog to digital conversion: read analog values on a pin
|
||||
///
|
||||
/// Usage:
|
||||
///
|
||||
/// adc = machine.ADC(pin) # create an analog object from a pin
|
||||
/// val = adc.read() # read an analog value
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
pin_obj_t * pin;
|
||||
struct adc_module adc_instance;
|
||||
} adc_obj_t;
|
||||
|
||||
/******************************************************************************/
|
||||
/* Micro Python bindings : adc object (single channel) */
|
||||
|
||||
STATIC void adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
adc_obj_t *self = self_in;
|
||||
mp_print_str(print, "<ADC on ");
|
||||
mp_obj_print_helper(print, self->pin, PRINT_STR);
|
||||
}
|
||||
|
||||
|
||||
STATIC void adc_init_single(adc_obj_t *adc_obj) {
|
||||
struct adc_config config_adc;
|
||||
adc_get_config_defaults(&config_adc);
|
||||
|
||||
config_adc.positive_input = adc_obj->pin->adc_input;
|
||||
config_adc.resolution = ADC_RESOLUTION_CUSTOM;
|
||||
config_adc.accumulate_samples = ADC_ACCUMULATE_SAMPLES_16;
|
||||
config_adc.divide_result = ADC_DIVIDE_RESULT_16;
|
||||
config_adc.clock_prescaler = ADC_CLOCK_PRESCALER_DIV128;
|
||||
|
||||
adc_init(&adc_obj->adc_instance, ADC, &config_adc);
|
||||
}
|
||||
|
||||
/// \classmethod \constructor(pin)
|
||||
/// Create an ADC object associated with the given pin.
|
||||
/// This allows you to then read analog values on that pin.
|
||||
STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
|
||||
// check number of arguments
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
|
||||
// 1st argument is the pin name
|
||||
mp_obj_t pin_obj = args[0];
|
||||
|
||||
const pin_obj_t *pin = pin_find(pin_obj);
|
||||
if (!pin->has_adc) {
|
||||
// No ADC function on that pin
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %q does not have ADC capabilities", pin->name));
|
||||
}
|
||||
|
||||
adc_obj_t *o = m_new_obj(adc_obj_t);
|
||||
memset(o, 0, sizeof(*o));
|
||||
o->base.type = &adc_type;
|
||||
o->pin = pin_obj;
|
||||
adc_init_single(o);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/// \method read()
|
||||
/// Read the value on the analog pin and return it. The returned value
|
||||
/// will be between 0 and 4095.
|
||||
// TODO(tannewt): Don't turn it all on just for one read. This simplifies
|
||||
// handling of reading multiple inputs and surviving sleep though so for now its
|
||||
// ok.
|
||||
STATIC mp_obj_t mp_adc_read(mp_obj_t self_in) {
|
||||
adc_obj_t *self = self_in;
|
||||
|
||||
adc_enable(&self->adc_instance);
|
||||
adc_start_conversion(&self->adc_instance);
|
||||
|
||||
uint16_t data;
|
||||
enum status_code status = adc_read(&self->adc_instance, &data);
|
||||
while (status == STATUS_BUSY) {
|
||||
status = adc_read(&self->adc_instance, &data);
|
||||
}
|
||||
if (status == STATUS_ERR_OVERFLOW) {
|
||||
// TODO(tannewt): Throw an error.
|
||||
}
|
||||
|
||||
adc_disable(&self->adc_instance);
|
||||
return mp_obj_new_int(data);
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_read_obj, mp_adc_read);
|
||||
|
||||
STATIC const mp_map_elem_t adc_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&adc_read_obj},
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(adc_locals_dict, adc_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t adc_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_ADC,
|
||||
.print = adc_print,
|
||||
.make_new = adc_make_new,
|
||||
.locals_dict = (mp_obj_t)&adc_locals_dict,
|
||||
};
|
27
atmel-samd/adc.h
Normal file
27
atmel-samd/adc.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013, 2014 Damien P. George
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
extern const mp_obj_type_t adc_type;
|
1155
atmel-samd/asf/sam0/drivers/adc/adc.h
Normal file
1155
atmel-samd/asf/sam0/drivers/adc/adc.h
Normal file
File diff suppressed because it is too large
Load Diff
182
atmel-samd/asf/sam0/drivers/adc/adc_callback.h
Normal file
182
atmel-samd/asf/sam0/drivers/adc/adc_callback.h
Normal file
@ -0,0 +1,182 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Peripheral Analog-to-Digital Converter Driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
|
||||
#ifndef ADC_CALLBACK_H_INCLUDED
|
||||
#define ADC_CALLBACK_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup asfdoc_sam0_adc_group
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <adc.h>
|
||||
|
||||
/**
|
||||
* Enum for the possible types of ADC asynchronous jobs that may be issued to
|
||||
* the driver.
|
||||
*/
|
||||
enum adc_job_type {
|
||||
/** Asynchronous ADC read into a user provided buffer */
|
||||
ADC_JOB_READ_BUFFER,
|
||||
};
|
||||
|
||||
/**
|
||||
* \name Callback Management
|
||||
* @{
|
||||
*/
|
||||
void adc_register_callback(
|
||||
struct adc_module *const module,
|
||||
adc_callback_t callback_func,
|
||||
enum adc_callback callback_type);
|
||||
|
||||
void adc_unregister_callback(
|
||||
struct adc_module *module,
|
||||
enum adc_callback callback_type);
|
||||
|
||||
/**
|
||||
* \brief Enables callback.
|
||||
*
|
||||
* Enables the callback function registered by \ref
|
||||
* adc_register_callback. The callback function will be called from the
|
||||
* interrupt handler when the conditions for the callback type are met.
|
||||
*
|
||||
* \param[in] module Pointer to ADC software instance struct
|
||||
* \param[in] callback_type Callback type given by an enum
|
||||
*
|
||||
* \return Status of the operation.
|
||||
* \retval STATUS_OK If operation was completed
|
||||
* \retval STATUS_ERR_INVALID If operation was not completed,
|
||||
* due to invalid callback_type
|
||||
*
|
||||
*/
|
||||
static inline void adc_enable_callback(
|
||||
struct adc_module *const module,
|
||||
enum adc_callback callback_type)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module);
|
||||
|
||||
/* Enable callback */
|
||||
module->enabled_callback_mask |= (1 << callback_type);
|
||||
|
||||
/* Enable window interrupt if this is a window callback */
|
||||
if (callback_type == ADC_CALLBACK_WINDOW) {
|
||||
adc_enable_interrupt(module, ADC_INTERRUPT_WINDOW);
|
||||
}
|
||||
/* Enable overrun interrupt if error callback is registered */
|
||||
if (callback_type == ADC_CALLBACK_ERROR) {
|
||||
adc_enable_interrupt(module, ADC_INTERRUPT_OVERRUN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disables callback.
|
||||
*
|
||||
* Disables the callback function registered by the \ref
|
||||
* adc_register_callback.
|
||||
*
|
||||
* \param[in] module Pointer to ADC software instance struct
|
||||
* \param[in] callback_type Callback type given by an enum
|
||||
*
|
||||
* \return Status of the operation.
|
||||
* \retval STATUS_OK If operation was completed
|
||||
* \retval STATUS_ERR_INVALID If operation was not completed,
|
||||
* due to invalid callback_type
|
||||
*
|
||||
*/
|
||||
static inline void adc_disable_callback(
|
||||
struct adc_module *const module,
|
||||
enum adc_callback callback_type)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module);
|
||||
|
||||
/* Disable callback */
|
||||
module->enabled_callback_mask &= ~(1 << callback_type);
|
||||
|
||||
/* Disable window interrupt if this is a window callback */
|
||||
if (callback_type == ADC_CALLBACK_WINDOW) {
|
||||
adc_disable_interrupt(module, ADC_INTERRUPT_WINDOW);
|
||||
}
|
||||
/* Disable overrun interrupt if this is the error callback */
|
||||
if (callback_type == ADC_CALLBACK_ERROR) {
|
||||
adc_disable_interrupt(module, ADC_INTERRUPT_OVERRUN);
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* \name Job Management
|
||||
* @{
|
||||
*/
|
||||
enum status_code adc_read_buffer_job(
|
||||
struct adc_module *const module_inst,
|
||||
uint16_t *buffer,
|
||||
uint16_t samples);
|
||||
|
||||
enum status_code adc_get_job_status(
|
||||
struct adc_module *module_inst,
|
||||
enum adc_job_type type);
|
||||
|
||||
void adc_abort_job(
|
||||
struct adc_module *module_inst,
|
||||
enum adc_job_type type);
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ADC_CALLBACK_H_INCLUDED */
|
426
atmel-samd/asf/sam0/drivers/adc/adc_sam_b.h
Normal file
426
atmel-samd/asf/sam0/drivers/adc/adc_sam_b.h
Normal file
@ -0,0 +1,426 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAMB Peripheral Analog-to-Digital Converter Driver
|
||||
*
|
||||
* Copyright (C) 2015 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
|
||||
#ifndef ADC_SAM_B_H_INCLUDED
|
||||
#define ADC_SAM_B_H_INCLUDED
|
||||
|
||||
/**
|
||||
* \defgroup asfdoc_samb_adc_group SAM Analog-to-Digital Converter (ADC) Driver
|
||||
*
|
||||
* This driver for Atmel® | SMART SAM devices provides an interface for the
|
||||
* configuration and management of the device's Analog-to-Digital Converter
|
||||
* functionality, for the conversion of analog voltages into a corresponding
|
||||
* digital form.
|
||||
*
|
||||
* The following peripheral is used by this module:
|
||||
* - ADC (Analog-to-Digital Converter)
|
||||
*
|
||||
* The following devices can use this module:
|
||||
* - Atmel | SMART SAM B11
|
||||
*
|
||||
* The outline of this documentation is as follows:
|
||||
* - \ref asfdoc_samb_adc_prerequisites
|
||||
* - \ref asfdoc_samb_adc_module_overview
|
||||
* - \ref asfdoc_samb_adc_special_considerations
|
||||
* - \ref asfdoc_samb_adc_extra_info
|
||||
* - \ref asfdoc_samb_adc_examples
|
||||
* - \ref asfdoc_samb_adc_api_overview
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_adc_prerequisites Prerequisites
|
||||
*
|
||||
* There are no prerequisites for this module.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_adc_module_overview Module Overview
|
||||
*
|
||||
* This driver provides an interface for the Analog-to-Digital conversion
|
||||
* functions on the device, to convert analog voltages to a corresponding
|
||||
* digital value. The ADC has up to 12-bit resolution.
|
||||
*
|
||||
* \subsection asfdoc_samb_adc_module_overview_prescaler Sample Clock Prescaler
|
||||
* \f[
|
||||
* F_{clk} = N + 2 \times {(throughput\_frequency)}
|
||||
* \f]
|
||||
* \f[
|
||||
* (N = ADC resolution)
|
||||
* \f]
|
||||
*
|
||||
* Example: For throughput of 100KS/s use sampling clock (Fclk=1.3MHz)
|
||||
*
|
||||
* \subsection asfdoc_samb_adc_module_overview_resolution ADC Resolution
|
||||
* There are two ADC resolution of operation:
|
||||
* - \b High Resolution (11-bit)
|
||||
*
|
||||
* Set the reference voltage to half the supply voltage or below. In this
|
||||
* mode the input signal dynamic range equals twice the reference voltage.
|
||||
*
|
||||
* Example: If supply voltage =3V and reference voltage= 1.4V, input signal
|
||||
* dynamic range can be from ground to 2*reference voltage (0~2.8V).
|
||||
* - \b Medium Resolution (10-bit)
|
||||
*
|
||||
* Set the reference voltage to any value below supply voltage (up to
|
||||
* supply voltage - 300mV) and in this condition the input dynamic range is
|
||||
* from zero to reference voltage.
|
||||
*
|
||||
* Example: If supply voltage =3V and reference voltage= 2.7V, input signal
|
||||
* dynamic range can be from ground to reference voltage (0~2.7V).
|
||||
*
|
||||
* \subsection asfdoc_samb_adc_module_overview_conversion Channel Modes
|
||||
* There are two modes for input channel selection:
|
||||
* - Either to assign a specific input channel
|
||||
* - Time domain multiplexing between 4 input channels
|
||||
* - Channel1 to channel4
|
||||
* - channel5 to channel8
|
||||
*
|
||||
* \section asfdoc_samb_adc_special_considerations Special Considerations
|
||||
* An integrated analog temperature sensor is available for use with the ADC.
|
||||
* The internal specific voltage can also be measured by the ADC. For internal
|
||||
* ADC inputs, the internal source(s) may need to be manually enabled by the
|
||||
* user application before they can be measured.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_adc_extra_info Extra Information
|
||||
*
|
||||
* For extra information, see \ref asfdoc_samb_adc_extra. This includes:
|
||||
* - \ref asfdoc_samb_adc_extra_acronyms
|
||||
* - \ref asfdoc_samb_adc_extra_dependencies
|
||||
* - \ref asfdoc_samb_adc_extra_errata
|
||||
* - \ref asfdoc_samb_adc_extra_history
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_adc_examples Examples
|
||||
*
|
||||
* For a list of examples related to this driver, see
|
||||
* \ref asfdoc_samb_adc_exqsg.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_adc_api_overview API Overview
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <compiler.h>
|
||||
#include <system_sam_b.h>
|
||||
|
||||
/**
|
||||
* \brief ADC internal reference voltage level enum
|
||||
*
|
||||
* Enum for the possible internal reference voltage level for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_internal_buf {
|
||||
/** Internal buffer voltage level: 0.5V */
|
||||
ADC_INTERNAL_BUF_0_5 = 0,
|
||||
/** Internal buffer voltage level: 0.6V */
|
||||
ADC_INTERNAL_BUF_0_6,
|
||||
/** Internal buffer voltage level: 0.7V */
|
||||
ADC_INTERNAL_BUF_0_7,
|
||||
/** Internal buffer voltage level: 0.8V */
|
||||
ADC_INTERNAL_BUF_0_8,
|
||||
/** Internal buffer voltage level: 0.9V */
|
||||
ADC_INTERNAL_BUF_0_9,
|
||||
/** Internal buffer voltage level: 1.0V */
|
||||
ADC_INTERNAL_BUF_1_0,
|
||||
/** Internal buffer voltage level: 1.1V */
|
||||
ADC_INTERNAL_BUF_1_1,
|
||||
/** Internal buffer voltage level: 1.2V */
|
||||
ADC_INTERNAL_BUF_1_2,
|
||||
/** Internal buffer voltage level: 1.3V */
|
||||
ADC_INTERNAL_BUF_1_3,
|
||||
/** Internal buffer voltage level: 1.4V */
|
||||
ADC_INTERNAL_BUF_1_4,
|
||||
/** Internal buffer voltage level: 1.5V */
|
||||
ADC_INTERNAL_BUF_1_5,
|
||||
/** Internal buffer voltage level: 1.6V */
|
||||
ADC_INTERNAL_BUF_1_6,
|
||||
/** Internal buffer voltage level: 1.7V */
|
||||
ADC_INTERNAL_BUF_1_7,
|
||||
/** Internal buffer voltage level: 1.8V */
|
||||
ADC_INTERNAL_BUF_1_8,
|
||||
/** Internal buffer voltage level: 1.9V */
|
||||
ADC_INTERNAL_BUF_1_9,
|
||||
/** Internal buffer voltage level: 2.0V */
|
||||
ADC_INTERNAL_BUF_2_0,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC reference voltage enum
|
||||
*
|
||||
* Enum for the possible reference voltages for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_reference {
|
||||
/** Internal form buffer reference */
|
||||
ADC_REFERENCE_INTERNAL_BUF = 0,
|
||||
/** Internal from IxR reference */
|
||||
ADC_REFERENCE_INTERNAL_IR,
|
||||
/** VBATT/2 reference */
|
||||
ADC_REFERENCE_VBATT_2,
|
||||
/** GPIO_MS1 reference */
|
||||
ADC_REFERENCE_GPIO_MS1,
|
||||
/** GPIO_MS2 reference */
|
||||
ADC_REFERENCE_GPIO_MS2,
|
||||
/** GPIO_MS3 reference */
|
||||
ADC_REFERENCE_GPIO_MS3,
|
||||
/** GPIO_MS4 reference */
|
||||
ADC_REFERENCE_GPIO_MS4,
|
||||
/** VBATTERY reference */
|
||||
ADC_REFERENCE_VBATT,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC input channel selection enum
|
||||
*
|
||||
* Enum for the possible input channel selections for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_input_channel {
|
||||
/** GPIO_MS1 input */
|
||||
ADC_INPUT_CH_GPIO_MS1 = 0,
|
||||
/** GPIO_MS2 input */
|
||||
ADC_INPUT_CH_GPIO_MS2,
|
||||
/** GPIO_MS3 input */
|
||||
ADC_INPUT_CH_GPIO_MS3,
|
||||
/** GPIO_MS4 input */
|
||||
ADC_INPUT_CH_GPIO_MS4,
|
||||
/** On chip temperature measurement input */
|
||||
ADC_INPUT_CH_TEMPERATURE,
|
||||
/** VBATT divided by 4 voltage level */
|
||||
ADC_INPUT_CH_VBATT_4,
|
||||
/** LP_LDO_OUT_1P2 low power domain voltage */
|
||||
ADC_INPUT_CH_LPD0_LDO,
|
||||
/** ADC reference voltage level */
|
||||
ADC_INPUT_CH_VREF,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC input channel time multiplexing selection mode enum
|
||||
*
|
||||
* Enum for the possible channel time multiplexing mode for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_channel_mode {
|
||||
/**
|
||||
* Input channels time multiplexing is between channel 0 to channel 3.
|
||||
* In this mode, ADC input channel selection is invalid.
|
||||
*/
|
||||
ADC_CH_MODE_CH0_TO_CH3,
|
||||
/**
|
||||
* Input channels time multiplexing is between channel 4 to channel 7.
|
||||
* In this mode, ADC input channel selection is invalid.
|
||||
*/
|
||||
ADC_CH_MODE_CH4_TO_CH7,
|
||||
/** Assign a specific input channel using \ref adc_input_channel */
|
||||
ADC_CH_MODE_ASSIGN,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC input dynamic range selection enum
|
||||
*
|
||||
* Enum for the possible input dynamic range for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_input_dynamic_range{
|
||||
/** Input dynamic range from 0V to VBATT voltage level */
|
||||
ADC_INPUT_DYNAMIC_RANGE_0 = 0,
|
||||
/** Input dynamic range from 0.08*VBATT to 0.92*VBATT voltage level */
|
||||
ADC_INPUT_DYNAMIC_RANGE_1,
|
||||
/** Input dynamic range from 0.17*VBATT to 0.83*VBATT voltage level */
|
||||
ADC_INPUT_DYNAMIC_RANGE_2,
|
||||
/** Input dynamic range from 0.25*VBATT to 0.75*VBATT voltage level */
|
||||
ADC_INPUT_DYNAMIC_RANGE_3,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC comparator biasing current enum
|
||||
*
|
||||
* Enum for the possible comparator biasing current for the ADC different
|
||||
* sampling rates.
|
||||
*
|
||||
*/
|
||||
enum adc_bias_current {
|
||||
/** Comparator bias current is 4uA for throughput 100KS/s */
|
||||
ADC_BIAS_CURRENT_0 = 0,
|
||||
/** Comparator bias current is 8uA */
|
||||
ADC_BIAS_CURRENT_1,
|
||||
/** Comparator bias current is 20uA */
|
||||
ADC_BIAS_CURRENT_2,
|
||||
/** Comparator bias current is 24uA for throughput 1MS/s */
|
||||
ADC_BIAS_CURRENT_3,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC configuration structure
|
||||
*
|
||||
* Configuration structure for an ADC instance. This structure should be
|
||||
* initialized by the \ref adc_get_config_defaults()
|
||||
* function before being modified by the user application.
|
||||
*/
|
||||
struct adc_config {
|
||||
/** Voltage reference */
|
||||
enum adc_reference reference;
|
||||
/** Internal reference voltage level */
|
||||
enum adc_internal_buf internal_vref;
|
||||
/** Input channel */
|
||||
enum adc_input_channel input_channel;
|
||||
/** Input channel selection */
|
||||
enum adc_channel_mode channel_mode;
|
||||
/** Input channel time multiplexing selection mode */
|
||||
enum adc_input_dynamic_range input_dynamic_range;
|
||||
/** Comparator biasing current selection */
|
||||
enum adc_bias_current bias_current;
|
||||
/** Invert ADC Clock */
|
||||
bool invert_clock;
|
||||
/** Fractional part for the clock divider */
|
||||
uint8_t frac_part;
|
||||
/** Integer part for the clock divider */
|
||||
uint16_t int_part;
|
||||
};
|
||||
|
||||
/** \name Configuration, initialization and get status
|
||||
* @{
|
||||
*/
|
||||
void adc_get_config_defaults(struct adc_config *const config);
|
||||
void adc_init(struct adc_config *config);
|
||||
uint32_t adc_get_status(void);
|
||||
/** @}*/
|
||||
|
||||
/** \name Enable/Disable and Reset
|
||||
* @{
|
||||
*/
|
||||
void adc_enable(void);
|
||||
void adc_disable(void);
|
||||
void adc_reset(void);
|
||||
/** @}*/
|
||||
|
||||
/** \name Read Result
|
||||
* @{
|
||||
*/
|
||||
enum status_code adc_read(enum adc_input_channel input_channel, uint16_t *result);
|
||||
/** @}*/
|
||||
|
||||
/** @}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* \page asfdoc_samb_adc_extra Extra Information for ADC Driver
|
||||
*
|
||||
* \section asfdoc_samb_adc_extra_acronyms Acronyms
|
||||
* Below is a table listing the acronyms used in this module, along with their
|
||||
* intended meanings.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Acronym</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>ADC</td>
|
||||
* <td>Analog-to-Digital Converter</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_adc_extra_dependencies Dependencies
|
||||
* There are no dependencies related to this driver.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_adc_extra_errata Errata
|
||||
* There are no errata related to this driver.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_adc_extra_history Module History
|
||||
* An overview of the module history is presented in the table below, with
|
||||
* details on the enhancements and fixes made to the module since its first
|
||||
* release. The current version of this corresponds to the newest version in
|
||||
* the table.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Changelog</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Initial Release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page asfdoc_samb_adc_exqsg Examples for ADC Driver
|
||||
*
|
||||
* This is a list of the available Quick Start guides (QSGs) and example
|
||||
* applications for \ref asfdoc_samb_adc_group. QSGs are simple examples with
|
||||
* step-by-step instructions to configure and use this driver in a selection of
|
||||
* use cases. Note that a QSG can be compiled as a standalone application or be
|
||||
* added to the user application.
|
||||
*
|
||||
* - \subpage asfdoc_samb_adc_basic_use_case
|
||||
*
|
||||
* \page asfdoc_samb_adc_document_revision_history Document Revision History
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Doc. Rev.</td>
|
||||
* <th>Date</td>
|
||||
* <th>Comments</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>A</td>
|
||||
* <td>09/2015</td>
|
||||
* <td>Initial document release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#endif /* ADC_SAM_B_H_INCLUDED */
|
715
atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc.c
Normal file
715
atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc.c
Normal file
@ -0,0 +1,715 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Peripheral Analog-to-Digital Converter Driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
|
||||
#include "asf/sam0/drivers/adc/adc.h"
|
||||
|
||||
#if SAMD20
|
||||
/* The Die revision D number */
|
||||
#define REVISON_D_NUM 3
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Initializes an ADC configuration structure to defaults
|
||||
*
|
||||
* Initializes a given ADC configuration struct to a set of known default
|
||||
* values. This function should be called on any new instance of the
|
||||
* configuration struct before being modified by the user application.
|
||||
*
|
||||
* The default configuration is as follows:
|
||||
* \li GCLK generator 0 (GCLK main) clock source
|
||||
* \li 1V from internal bandgap reference
|
||||
* \li Div 4 clock prescaler
|
||||
* \li 12-bit resolution
|
||||
* \li Window monitor disabled
|
||||
* \li No gain
|
||||
* \li Positive input on ADC PIN 0
|
||||
* \li Negative input on ADC PIN 1
|
||||
* \li Averaging disabled
|
||||
* \li Oversampling disabled
|
||||
* \li Right adjust data
|
||||
* \li Single-ended mode
|
||||
* \li Free running disabled
|
||||
* \li All events (input and generation) disabled
|
||||
* \li Sleep operation disabled
|
||||
* \li No reference compensation
|
||||
* \li No gain/offset correction
|
||||
* \li No added sampling time
|
||||
* \li Pin scan mode disabled
|
||||
*
|
||||
* \param[out] config Pointer to configuration struct to initialize to
|
||||
* default values
|
||||
*/
|
||||
void adc_get_config_defaults(struct adc_config *const config)
|
||||
{
|
||||
Assert(config);
|
||||
config->clock_source = GCLK_GENERATOR_0;
|
||||
config->reference = ADC_REFERENCE_INT1V;
|
||||
config->clock_prescaler = ADC_CLOCK_PRESCALER_DIV4;
|
||||
config->resolution = ADC_RESOLUTION_12BIT;
|
||||
config->window.window_mode = ADC_WINDOW_MODE_DISABLE;
|
||||
config->window.window_upper_value = 0;
|
||||
config->window.window_lower_value = 0;
|
||||
config->gain_factor = ADC_GAIN_FACTOR_1X;
|
||||
#if SAMR21
|
||||
config->positive_input = ADC_POSITIVE_INPUT_PIN6 ;
|
||||
#else
|
||||
config->positive_input = ADC_POSITIVE_INPUT_PIN0 ;
|
||||
#endif
|
||||
config->negative_input = ADC_NEGATIVE_INPUT_GND ;
|
||||
config->accumulate_samples = ADC_ACCUMULATE_DISABLE;
|
||||
config->divide_result = ADC_DIVIDE_RESULT_DISABLE;
|
||||
config->left_adjust = false;
|
||||
config->differential_mode = false;
|
||||
config->freerunning = false;
|
||||
config->event_action = ADC_EVENT_ACTION_DISABLED;
|
||||
config->run_in_standby = false;
|
||||
config->reference_compensation_enable = false;
|
||||
config->correction.correction_enable = false;
|
||||
config->correction.gain_correction = ADC_GAINCORR_RESETVALUE;
|
||||
config->correction.offset_correction = ADC_OFFSETCORR_RESETVALUE;
|
||||
config->sample_length = 0;
|
||||
config->pin_scan.offset_start_scan = 0;
|
||||
config->pin_scan.inputs_to_scan = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets the ADC window mode
|
||||
*
|
||||
* Sets the ADC window mode to a given mode and value range.
|
||||
*
|
||||
* \param[in] module_inst Pointer to the ADC software instance struct
|
||||
* \param[in] window_mode Window monitor mode to set
|
||||
* \param[in] window_lower_value Lower window monitor threshold value
|
||||
* \param[in] window_upper_value Upper window monitor threshold value
|
||||
*/
|
||||
void adc_set_window_mode(
|
||||
struct adc_module *const module_inst,
|
||||
const enum adc_window_mode window_mode,
|
||||
const int16_t window_lower_value,
|
||||
const int16_t window_upper_value)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module_inst);
|
||||
Assert(module_inst->hw);
|
||||
|
||||
Adc *const adc_module = module_inst->hw;
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Set window mode */
|
||||
adc_module->WINCTRL.reg = window_mode << ADC_WINCTRL_WINMODE_Pos;
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Set lower window monitor threshold value */
|
||||
adc_module->WINLT.reg = window_lower_value << ADC_WINLT_WINLT_Pos;
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Set upper window monitor threshold value */
|
||||
adc_module->WINUT.reg = window_upper_value << ADC_WINUT_WINUT_Pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal Configure MUX settings for the analog pins
|
||||
*
|
||||
* This function will set the given ADC input pins
|
||||
* to the analog function in the pinmux, giving
|
||||
* the ADC access to the analog signal
|
||||
*
|
||||
* \param [in] pin AINxx pin to configure
|
||||
*/
|
||||
static inline void _adc_configure_ain_pin(uint32_t pin)
|
||||
{
|
||||
#define PIN_INVALID_ADC_AIN 0xFFFFUL
|
||||
|
||||
/* Pinmapping table for AINxx -> GPIO pin number */
|
||||
const uint32_t pinmapping[] = {
|
||||
#if (SAMD20E) || (SAMD21E)|| (SAMDA1E)
|
||||
PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
|
||||
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
|
||||
PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
|
||||
#elif (SAMD20G) || (SAMD21G)|| (SAMDA1G)
|
||||
PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
|
||||
PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3,
|
||||
PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
|
||||
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
|
||||
PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
|
||||
#elif (SAMD20J) || (SAMD21J)|| (SAMDA1J)
|
||||
PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
|
||||
PIN_PB08B_ADC_AIN2, PIN_PB09B_ADC_AIN3,
|
||||
PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
|
||||
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
|
||||
PIN_PB00B_ADC_AIN8, PIN_PB01B_ADC_AIN9,
|
||||
PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
|
||||
PIN_PB04B_ADC_AIN12, PIN_PB05B_ADC_AIN13,
|
||||
PIN_PB06B_ADC_AIN14, PIN_PB07B_ADC_AIN15,
|
||||
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
|
||||
PIN_PA10B_ADC_AIN18, PIN_PA11B_ADC_AIN19,
|
||||
#elif SAMR21E
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
#elif SAMR21G
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA04B_ADC_AIN4, PIN_PA05B_ADC_AIN5,
|
||||
PIN_PA06B_ADC_AIN6, PIN_PA07B_ADC_AIN7,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PB02B_ADC_AIN10, PIN_PB03B_ADC_AIN11,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA08B_ADC_AIN16, PIN_PA09B_ADC_AIN17,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
#elif (SAMD09C) || (SAMD10C) || (SAMD11C)
|
||||
PIN_PA02B_ADC_AIN0, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
#elif (SAMD09D)
|
||||
PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
|
||||
PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3,
|
||||
PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5,
|
||||
PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
#elif (SAMD10DS) || (SAMD10DU) || (SAMD11DS) || (SAMD11DU)
|
||||
PIN_PA02B_ADC_AIN0, PIN_INVALID_ADC_AIN,
|
||||
PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3,
|
||||
PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5,
|
||||
PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
#elif (SAMD10DM) || (SAMD11DM)
|
||||
PIN_PA02B_ADC_AIN0, PIN_PA03B_ADC_AIN1,
|
||||
PIN_PA04B_ADC_AIN2, PIN_PA05B_ADC_AIN3,
|
||||
PIN_PA06B_ADC_AIN4, PIN_PA07B_ADC_AIN5,
|
||||
PIN_PA14B_ADC_AIN6, PIN_PA15B_ADC_AIN7,
|
||||
PIN_PA10B_ADC_AIN8, PIN_PA11B_ADC_AIN9,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
PIN_INVALID_ADC_AIN, PIN_INVALID_ADC_AIN,
|
||||
#else
|
||||
# error ADC pin mappings are not defined for this device.
|
||||
#endif
|
||||
};
|
||||
|
||||
uint32_t pin_map_result = PIN_INVALID_ADC_AIN;
|
||||
|
||||
if (pin <= ADC_EXTCHANNEL_MSB) {
|
||||
pin_map_result = pinmapping[pin >> ADC_INPUTCTRL_MUXPOS_Pos];
|
||||
|
||||
Assert(pin_map_result != PIN_INVALID_ADC_AIN);
|
||||
|
||||
struct system_pinmux_config config;
|
||||
system_pinmux_get_config_defaults(&config);
|
||||
|
||||
/* Analog functions are all on MUX setting B */
|
||||
config.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
|
||||
config.mux_position = 1;
|
||||
|
||||
system_pinmux_pin_set_config(pin_map_result, &config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \internal Writes an ADC configuration to the hardware module
|
||||
*
|
||||
* Writes out a given ADC module configuration to the hardware module.
|
||||
*
|
||||
* \param[out] module_inst Pointer to the ADC software instance struct
|
||||
* \param[in] config Pointer to configuration struct
|
||||
*
|
||||
* \return Status of the configuration procedure
|
||||
* \retval STATUS_OK The configuration was successful
|
||||
* \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided
|
||||
*/
|
||||
static enum status_code _adc_set_config(
|
||||
struct adc_module *const module_inst,
|
||||
struct adc_config *const config)
|
||||
{
|
||||
uint8_t adjres = 0;
|
||||
uint32_t resolution = ADC_RESOLUTION_16BIT;
|
||||
enum adc_accumulate_samples accumulate = ADC_ACCUMULATE_DISABLE;
|
||||
#if SAMD20
|
||||
uint8_t revision_num = ((REG_DSU_DID & DSU_DID_DIE_Msk) >> DSU_DID_DIE_Pos);
|
||||
#endif
|
||||
|
||||
/* Get the hardware module pointer */
|
||||
Adc *const adc_module = module_inst->hw;
|
||||
|
||||
/* Configure GCLK channel and enable clock */
|
||||
struct system_gclk_chan_config gclk_chan_conf;
|
||||
system_gclk_chan_get_config_defaults(&gclk_chan_conf);
|
||||
gclk_chan_conf.source_generator = config->clock_source;
|
||||
system_gclk_chan_set_config(ADC_GCLK_ID, &gclk_chan_conf);
|
||||
system_gclk_chan_enable(ADC_GCLK_ID);
|
||||
|
||||
/* Setup pinmuxing for analog inputs */
|
||||
if (config->pin_scan.inputs_to_scan != 0) {
|
||||
uint8_t offset = config->pin_scan.offset_start_scan;
|
||||
uint8_t start_pin =
|
||||
offset +(uint8_t)config->positive_input;
|
||||
uint8_t end_pin =
|
||||
start_pin + config->pin_scan.inputs_to_scan;
|
||||
|
||||
while (start_pin < end_pin) {
|
||||
_adc_configure_ain_pin((offset % 16)+(uint8_t)config->positive_input);
|
||||
start_pin++;
|
||||
offset++;
|
||||
}
|
||||
_adc_configure_ain_pin(config->negative_input);
|
||||
} else {
|
||||
_adc_configure_ain_pin(config->positive_input);
|
||||
_adc_configure_ain_pin(config->negative_input);
|
||||
}
|
||||
|
||||
/* Configure run in standby */
|
||||
adc_module->CTRLA.reg = (config->run_in_standby << ADC_CTRLA_RUNSTDBY_Pos);
|
||||
|
||||
/* Configure reference */
|
||||
adc_module->REFCTRL.reg =
|
||||
(config->reference_compensation_enable << ADC_REFCTRL_REFCOMP_Pos) |
|
||||
(config->reference);
|
||||
|
||||
/* Set adjusting result and number of samples */
|
||||
switch (config->resolution) {
|
||||
|
||||
case ADC_RESOLUTION_CUSTOM:
|
||||
adjres = config->divide_result;
|
||||
accumulate = config->accumulate_samples;
|
||||
/* 16-bit result register */
|
||||
resolution = ADC_RESOLUTION_16BIT;
|
||||
break;
|
||||
|
||||
case ADC_RESOLUTION_13BIT:
|
||||
/* Increase resolution by 1 bit */
|
||||
adjres = ADC_DIVIDE_RESULT_2;
|
||||
accumulate = ADC_ACCUMULATE_SAMPLES_4;
|
||||
/* 16-bit result register */
|
||||
resolution = ADC_RESOLUTION_16BIT;
|
||||
break;
|
||||
|
||||
case ADC_RESOLUTION_14BIT:
|
||||
/* Increase resolution by 2 bit */
|
||||
adjres = ADC_DIVIDE_RESULT_4;
|
||||
accumulate = ADC_ACCUMULATE_SAMPLES_16;
|
||||
/* 16-bit result register */
|
||||
resolution = ADC_RESOLUTION_16BIT;
|
||||
break;
|
||||
#if SAMD20
|
||||
/* See $35.1.8 for ADC errata of SAM D20.
|
||||
The revisions before D have this issue.*/
|
||||
case ADC_RESOLUTION_15BIT:
|
||||
/* Increase resolution by 3 bit */
|
||||
if(revision_num < REVISON_D_NUM) {
|
||||
adjres = ADC_DIVIDE_RESULT_8;
|
||||
} else {
|
||||
adjres = ADC_DIVIDE_RESULT_2;
|
||||
}
|
||||
accumulate = ADC_ACCUMULATE_SAMPLES_64;
|
||||
/* 16-bit result register */
|
||||
resolution = ADC_RESOLUTION_16BIT;
|
||||
break;
|
||||
|
||||
case ADC_RESOLUTION_16BIT:
|
||||
if(revision_num < REVISON_D_NUM) {
|
||||
/* Increase resolution by 4 bit */
|
||||
adjres = ADC_DIVIDE_RESULT_16;
|
||||
} else {
|
||||
adjres = ADC_DIVIDE_RESULT_DISABLE;
|
||||
}
|
||||
accumulate = ADC_ACCUMULATE_SAMPLES_256;
|
||||
/* 16-bit result register */
|
||||
resolution = ADC_RESOLUTION_16BIT;
|
||||
break;
|
||||
#else
|
||||
case ADC_RESOLUTION_15BIT:
|
||||
/* Increase resolution by 3 bit */
|
||||
adjres = ADC_DIVIDE_RESULT_2;
|
||||
accumulate = ADC_ACCUMULATE_SAMPLES_64;
|
||||
/* 16-bit result register */
|
||||
resolution = ADC_RESOLUTION_16BIT;
|
||||
break;
|
||||
|
||||
case ADC_RESOLUTION_16BIT:
|
||||
/* Increase resolution by 4 bit */
|
||||
adjres = ADC_DIVIDE_RESULT_DISABLE;
|
||||
accumulate = ADC_ACCUMULATE_SAMPLES_256;
|
||||
/* 16-bit result register */
|
||||
resolution = ADC_RESOLUTION_16BIT;
|
||||
break;
|
||||
#endif
|
||||
case ADC_RESOLUTION_8BIT:
|
||||
/* 8-bit result register */
|
||||
resolution = ADC_RESOLUTION_8BIT;
|
||||
break;
|
||||
case ADC_RESOLUTION_10BIT:
|
||||
/* 10-bit result register */
|
||||
resolution = ADC_RESOLUTION_10BIT;
|
||||
break;
|
||||
case ADC_RESOLUTION_12BIT:
|
||||
/* 12-bit result register */
|
||||
resolution = ADC_RESOLUTION_12BIT;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unknown. Abort. */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
adc_module->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(adjres) | accumulate;
|
||||
|
||||
/* Check validity of sample length value */
|
||||
if (config->sample_length > 63) {
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
} else {
|
||||
/* Configure sample length */
|
||||
adc_module->SAMPCTRL.reg =
|
||||
(config->sample_length << ADC_SAMPCTRL_SAMPLEN_Pos);
|
||||
}
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Configure CTRLB */
|
||||
adc_module->CTRLB.reg =
|
||||
config->clock_prescaler |
|
||||
resolution |
|
||||
(config->correction.correction_enable << ADC_CTRLB_CORREN_Pos) |
|
||||
(config->freerunning << ADC_CTRLB_FREERUN_Pos) |
|
||||
(config->left_adjust << ADC_CTRLB_LEFTADJ_Pos) |
|
||||
(config->differential_mode << ADC_CTRLB_DIFFMODE_Pos);
|
||||
|
||||
/* Check validity of window thresholds */
|
||||
if (config->window.window_mode != ADC_WINDOW_MODE_DISABLE) {
|
||||
switch (resolution) {
|
||||
case ADC_RESOLUTION_8BIT:
|
||||
if (config->differential_mode &&
|
||||
(config->window.window_lower_value > 127 ||
|
||||
config->window.window_lower_value < -128 ||
|
||||
config->window.window_upper_value > 127 ||
|
||||
config->window.window_upper_value < -128)) {
|
||||
/* Invalid value */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
} else if (config->window.window_lower_value > 255 ||
|
||||
config->window.window_upper_value > 255){
|
||||
/* Invalid value */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
break;
|
||||
case ADC_RESOLUTION_10BIT:
|
||||
if (config->differential_mode &&
|
||||
(config->window.window_lower_value > 511 ||
|
||||
config->window.window_lower_value < -512 ||
|
||||
config->window.window_upper_value > 511 ||
|
||||
config->window.window_upper_value < -512)) {
|
||||
/* Invalid value */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
} else if (config->window.window_lower_value > 1023 ||
|
||||
config->window.window_upper_value > 1023){
|
||||
/* Invalid value */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
break;
|
||||
case ADC_RESOLUTION_12BIT:
|
||||
if (config->differential_mode &&
|
||||
(config->window.window_lower_value > 2047 ||
|
||||
config->window.window_lower_value < -2048 ||
|
||||
config->window.window_upper_value > 2047 ||
|
||||
config->window.window_upper_value < -2048)) {
|
||||
/* Invalid value */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
} else if (config->window.window_lower_value > 4095 ||
|
||||
config->window.window_upper_value > 4095){
|
||||
/* Invalid value */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
break;
|
||||
case ADC_RESOLUTION_16BIT:
|
||||
if (config->differential_mode &&
|
||||
(config->window.window_lower_value > 32767 ||
|
||||
config->window.window_lower_value < -32768 ||
|
||||
config->window.window_upper_value > 32767 ||
|
||||
config->window.window_upper_value < -32768)) {
|
||||
/* Invalid value */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
} else if (config->window.window_lower_value > 65535 ||
|
||||
config->window.window_upper_value > 65535){
|
||||
/* Invalid value */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Configure window mode */
|
||||
adc_module->WINCTRL.reg = config->window.window_mode;
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Configure lower threshold */
|
||||
adc_module->WINLT.reg =
|
||||
config->window.window_lower_value << ADC_WINLT_WINLT_Pos;
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Configure lower threshold */
|
||||
adc_module->WINUT.reg = config->window.window_upper_value <<
|
||||
ADC_WINUT_WINUT_Pos;
|
||||
|
||||
uint8_t inputs_to_scan = config->pin_scan.inputs_to_scan;
|
||||
if (inputs_to_scan > 0) {
|
||||
/*
|
||||
* Number of input sources included is the value written to INPUTSCAN
|
||||
* plus 1.
|
||||
*/
|
||||
inputs_to_scan--;
|
||||
}
|
||||
|
||||
if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) ||
|
||||
config->pin_scan.offset_start_scan > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) {
|
||||
/* Invalid number of input pins or input offset */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Configure pin scan mode and positive and negative input pins */
|
||||
adc_module->INPUTCTRL.reg =
|
||||
config->gain_factor |
|
||||
(config->pin_scan.offset_start_scan <<
|
||||
ADC_INPUTCTRL_INPUTOFFSET_Pos) |
|
||||
(inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos) |
|
||||
config->negative_input |
|
||||
config->positive_input;
|
||||
|
||||
/* Configure events */
|
||||
adc_module->EVCTRL.reg = config->event_action;
|
||||
|
||||
/* Disable all interrupts */
|
||||
adc_module->INTENCLR.reg =
|
||||
(1 << ADC_INTENCLR_SYNCRDY_Pos) | (1 << ADC_INTENCLR_WINMON_Pos) |
|
||||
(1 << ADC_INTENCLR_OVERRUN_Pos) | (1 << ADC_INTENCLR_RESRDY_Pos);
|
||||
|
||||
if (config->correction.correction_enable){
|
||||
/* Make sure gain_correction value is valid */
|
||||
if (config->correction.gain_correction > ADC_GAINCORR_GAINCORR_Msk) {
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
} else {
|
||||
/* Set gain correction value */
|
||||
adc_module->GAINCORR.reg = config->correction.gain_correction <<
|
||||
ADC_GAINCORR_GAINCORR_Pos;
|
||||
}
|
||||
|
||||
/* Make sure offset correction value is valid */
|
||||
if (config->correction.offset_correction > 2047 ||
|
||||
config->correction.offset_correction < -2048) {
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
} else {
|
||||
/* Set offset correction value */
|
||||
adc_module->OFFSETCORR.reg = config->correction.offset_correction <<
|
||||
ADC_OFFSETCORR_OFFSETCORR_Pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load in the fixed device ADC calibration constants */
|
||||
adc_module->CALIB.reg =
|
||||
ADC_CALIB_BIAS_CAL(
|
||||
(*(uint32_t *)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos)
|
||||
) |
|
||||
ADC_CALIB_LINEARITY_CAL(
|
||||
(*(uint64_t *)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos)
|
||||
);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initializes the ADC channel sequence
|
||||
*
|
||||
* Like SAMD and SAMR21 the INPUTOFFSET register will be incremented one
|
||||
* automatically after a conversion done, causing the next conversion
|
||||
* to be done with the positive input equal to MUXPOS + INPUTOFFSET,
|
||||
* it is scanning continuously one by one even ADC channels are not continuous.
|
||||
*
|
||||
* Initializes the ADC channel sequence by the sequence of pin_array.
|
||||
*
|
||||
* \param[in] pin_array The array of the Mux selection for the positive ADC input
|
||||
* \param[in] size The size of pin_array
|
||||
*/
|
||||
void adc_regular_ain_channel(uint32_t *pin_array, uint8_t size)
|
||||
{
|
||||
for (int i = 0; i < size; i++) {
|
||||
_adc_configure_ain_pin(pin_array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initializes the ADC
|
||||
*
|
||||
* Initializes the ADC device struct and the hardware module based on the
|
||||
* given configuration struct values.
|
||||
*
|
||||
* \param[out] module_inst Pointer to the ADC software instance struct
|
||||
* \param[in] hw Pointer to the ADC module instance
|
||||
* \param[in] config Pointer to the configuration struct
|
||||
*
|
||||
* \return Status of the initialization procedure.
|
||||
* \retval STATUS_OK The initialization was successful
|
||||
* \retval STATUS_ERR_INVALID_ARG Invalid argument(s) were provided
|
||||
* \retval STATUS_BUSY The module is busy with a reset operation
|
||||
* \retval STATUS_ERR_DENIED The module is enabled
|
||||
*/
|
||||
enum status_code adc_init(
|
||||
struct adc_module *const module_inst,
|
||||
Adc *hw,
|
||||
struct adc_config *config)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module_inst);
|
||||
Assert(hw);
|
||||
Assert(config);
|
||||
|
||||
/* Associate the software module instance with the hardware module */
|
||||
module_inst->hw = hw;
|
||||
|
||||
/* Turn on the digital interface clock */
|
||||
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_ADC);
|
||||
|
||||
if (hw->CTRLA.reg & ADC_CTRLA_SWRST) {
|
||||
/* We are in the middle of a reset. Abort. */
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
if (hw->CTRLA.reg & ADC_CTRLA_ENABLE) {
|
||||
/* Module must be disabled before initialization. Abort. */
|
||||
return STATUS_ERR_DENIED;
|
||||
}
|
||||
|
||||
/* Store the selected reference for later use */
|
||||
module_inst->reference = config->reference;
|
||||
|
||||
/* Make sure bandgap is enabled if requested by the config */
|
||||
if (module_inst->reference == ADC_REFERENCE_INT1V) {
|
||||
system_voltage_reference_enable(SYSTEM_VOLTAGE_REFERENCE_BANDGAP);
|
||||
}
|
||||
|
||||
#if ADC_CALLBACK_MODE == true
|
||||
for (uint8_t i = 0; i < ADC_CALLBACK_N; i++) {
|
||||
module_inst->callback[i] = NULL;
|
||||
};
|
||||
|
||||
module_inst->registered_callback_mask = 0;
|
||||
module_inst->enabled_callback_mask = 0;
|
||||
module_inst->remaining_conversions = 0;
|
||||
module_inst->job_status = STATUS_OK;
|
||||
|
||||
_adc_instances[0] = module_inst;
|
||||
|
||||
if (config->event_action == ADC_EVENT_ACTION_DISABLED &&
|
||||
!config->freerunning) {
|
||||
module_inst->software_trigger = true;
|
||||
} else {
|
||||
module_inst->software_trigger = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Write configuration to module */
|
||||
return _adc_set_config(module_inst, config);
|
||||
}
|
255
atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_callback.c
Normal file
255
atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_callback.c
Normal file
@ -0,0 +1,255 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Peripheral Analog-to-Digital Converter Driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#include "adc_callback.h"
|
||||
|
||||
struct adc_module *_adc_instances[ADC_INST_NUM];
|
||||
|
||||
static void _adc_interrupt_handler(const uint8_t instance)
|
||||
{
|
||||
struct adc_module *module = _adc_instances[instance];
|
||||
|
||||
/* get interrupt flags and mask out enabled callbacks */
|
||||
uint32_t flags = module->hw->INTFLAG.reg;
|
||||
|
||||
if (flags & ADC_INTFLAG_RESRDY) {
|
||||
if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_READ_BUFFER)) &&
|
||||
(module->registered_callback_mask & (1 << ADC_CALLBACK_READ_BUFFER))) {
|
||||
/* clear interrupt flag */
|
||||
module->hw->INTFLAG.reg = ADC_INTFLAG_RESRDY;
|
||||
|
||||
while (adc_is_syncing(module)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* store ADC result in job buffer */
|
||||
*(module->job_buffer++) = module->hw->RESULT.reg;
|
||||
|
||||
if (--module->remaining_conversions > 0) {
|
||||
if (module->software_trigger == true) {
|
||||
adc_start_conversion(module);
|
||||
}
|
||||
} else {
|
||||
if (module->job_status == STATUS_BUSY) {
|
||||
/* job is complete. update status,disable interrupt
|
||||
*and call callback */
|
||||
module->job_status = STATUS_OK;
|
||||
adc_disable_interrupt(module, ADC_INTERRUPT_RESULT_READY);
|
||||
|
||||
(module->callback[ADC_CALLBACK_READ_BUFFER])(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & ADC_INTFLAG_WINMON) {
|
||||
module->hw->INTFLAG.reg = ADC_INTFLAG_WINMON;
|
||||
if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_WINDOW)) &&
|
||||
(module->registered_callback_mask & (1 << ADC_CALLBACK_WINDOW))) {
|
||||
(module->callback[ADC_CALLBACK_WINDOW])(module);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (flags & ADC_INTFLAG_OVERRUN) {
|
||||
module->hw->INTFLAG.reg = ADC_INTFLAG_OVERRUN;
|
||||
if ((module->enabled_callback_mask & (1 << ADC_CALLBACK_ERROR)) &&
|
||||
(module->registered_callback_mask & (1 << ADC_CALLBACK_ERROR))) {
|
||||
(module->callback[ADC_CALLBACK_ERROR])(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Interrupt handler for the ADC module. */
|
||||
void ADC_Handler(void)
|
||||
{
|
||||
_adc_interrupt_handler(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Registers a callback
|
||||
*
|
||||
* Registers a callback function which is implemented by the user.
|
||||
*
|
||||
* \note The callback must be enabled by for the interrupt handler to call it
|
||||
* when the condition for the callback is met.
|
||||
*
|
||||
* \param[in] module Pointer to ADC software instance struct
|
||||
* \param[in] callback_func Pointer to callback function
|
||||
* \param[in] callback_type Callback type given by an enum
|
||||
*
|
||||
*/
|
||||
void adc_register_callback(
|
||||
struct adc_module *const module,
|
||||
adc_callback_t callback_func,
|
||||
enum adc_callback callback_type)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module);
|
||||
Assert(callback_func);
|
||||
|
||||
/* Register callback function */
|
||||
module->callback[callback_type] = callback_func;
|
||||
|
||||
/* Set the bit corresponding to the callback_type */
|
||||
module->registered_callback_mask |= (1 << callback_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Unregisters a callback
|
||||
*
|
||||
* Unregisters a callback function which is implemented by the user.
|
||||
*
|
||||
* \param[in] module Pointer to ADC software instance struct
|
||||
* \param[in] callback_type Callback type given by an enum
|
||||
*
|
||||
*/
|
||||
void adc_unregister_callback(
|
||||
struct adc_module *const module,
|
||||
enum adc_callback callback_type)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module);
|
||||
|
||||
/* Unregister callback function */
|
||||
module->callback[callback_type] = NULL;
|
||||
|
||||
/* Clear the bit corresponding to the callback_type */
|
||||
module->registered_callback_mask &= ~(1 << callback_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Read multiple samples from ADC
|
||||
*
|
||||
* Read \c samples samples from the ADC into the buffer \c buffer.
|
||||
* If there is no hardware trigger defined (event action) the
|
||||
* driver will retrigger the ADC conversion whenever a conversion
|
||||
* is complete until \c samples samples has been acquired. To avoid
|
||||
* jitter in the sampling frequency using an event trigger is advised.
|
||||
*
|
||||
* \param[in] module_inst Pointer to the ADC software instance struct
|
||||
* \param[in] samples Number of samples to acquire
|
||||
* \param[out] buffer Buffer to store the ADC samples
|
||||
*
|
||||
* \return Status of the job start.
|
||||
* \retval STATUS_OK The conversion job was started successfully and is
|
||||
* in progress
|
||||
* \retval STATUS_BUSY The ADC is already busy with another job
|
||||
*/
|
||||
enum status_code adc_read_buffer_job(
|
||||
struct adc_module *const module_inst,
|
||||
uint16_t *buffer,
|
||||
uint16_t samples)
|
||||
{
|
||||
Assert(module_inst);
|
||||
Assert(samples);
|
||||
Assert(buffer);
|
||||
|
||||
if(module_inst->remaining_conversions != 0 ||
|
||||
module_inst->job_status == STATUS_BUSY){
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
module_inst->job_status = STATUS_BUSY;
|
||||
module_inst->remaining_conversions = samples;
|
||||
module_inst->job_buffer = buffer;
|
||||
|
||||
adc_enable_interrupt(module_inst, ADC_INTERRUPT_RESULT_READY);
|
||||
|
||||
if(module_inst->software_trigger == true) {
|
||||
adc_start_conversion(module_inst);
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Gets the status of a job
|
||||
*
|
||||
* Gets the status of an ongoing or the last job.
|
||||
*
|
||||
* \param [in] module_inst Pointer to the ADC software instance struct
|
||||
* \param [in] type Type of job to get status
|
||||
*
|
||||
* \return Status of the job.
|
||||
*/
|
||||
enum status_code adc_get_job_status(
|
||||
struct adc_module *module_inst,
|
||||
enum adc_job_type type)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module_inst);
|
||||
|
||||
if (type == ADC_JOB_READ_BUFFER ) {
|
||||
return module_inst->job_status;
|
||||
} else {
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Aborts an ongoing job
|
||||
*
|
||||
* Aborts an ongoing job.
|
||||
*
|
||||
* \param [in] module_inst Pointer to the ADC software instance struct
|
||||
* \param [in] type Type of job to abort
|
||||
*/
|
||||
void adc_abort_job(
|
||||
struct adc_module *module_inst,
|
||||
enum adc_job_type type)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module_inst);
|
||||
|
||||
if (type == ADC_JOB_READ_BUFFER) {
|
||||
/* Disable interrupt */
|
||||
adc_disable_interrupt(module_inst, ADC_INTERRUPT_RESULT_READY);
|
||||
/* Mark job as aborted */
|
||||
module_inst->job_status = STATUS_ABORTED;
|
||||
module_inst->remaining_conversions = 0;
|
||||
}
|
||||
}
|
||||
|
728
atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h
Normal file
728
atmel-samd/asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h
Normal file
@ -0,0 +1,728 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM ADC functionality
|
||||
*
|
||||
* Copyright (C) 2014-2015 Atmel Corporation. All rights reserved.
|
||||
*
|
||||
* \asf_license_start
|
||||
*
|
||||
* \page License
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of Atmel may not be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* 4. This software may only be redistributed and used in connection with an
|
||||
* Atmel microcontroller product.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* \asf_license_stop
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef ADC_FEATURE_H_INCLUDED
|
||||
#define ADC_FEATURE_H_INCLUDED
|
||||
|
||||
/**
|
||||
* \addtogroup asfdoc_sam0_adc_group
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if ADC_CALLBACK_MODE == true
|
||||
# include <system_interrupt.h>
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
extern struct adc_module *_adc_instances[ADC_INST_NUM];
|
||||
#endif
|
||||
|
||||
/** Forward definition of the device instance. */
|
||||
struct adc_module;
|
||||
|
||||
/** Type of the callback functions. */
|
||||
typedef void (*adc_callback_t)(struct adc_module *const module);
|
||||
|
||||
/**
|
||||
* \brief ADC Callback enum
|
||||
*
|
||||
* Callback types for ADC callback driver.
|
||||
*
|
||||
*/
|
||||
enum adc_callback {
|
||||
/** Callback for buffer received */
|
||||
ADC_CALLBACK_READ_BUFFER,
|
||||
/** Callback when window is hit */
|
||||
ADC_CALLBACK_WINDOW,
|
||||
/** Callback for error */
|
||||
ADC_CALLBACK_ERROR,
|
||||
# if !defined(__DOXYGEN__)
|
||||
/** Number of available callbacks */
|
||||
ADC_CALLBACK_N,
|
||||
# endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief ADC reference voltage enum
|
||||
*
|
||||
* Enum for the possible reference voltages for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_reference {
|
||||
/** 1.0V voltage reference */
|
||||
ADC_REFERENCE_INT1V = ADC_REFCTRL_REFSEL_INT1V,
|
||||
/** 1/1.48V<SUB>CC</SUB> reference */
|
||||
ADC_REFERENCE_INTVCC0 = ADC_REFCTRL_REFSEL_INTVCC0,
|
||||
/** 1/2V<SUB>CC</SUB> (only for internal V<SUB>CC</SUB> > 2.1V) */
|
||||
ADC_REFERENCE_INTVCC1 = ADC_REFCTRL_REFSEL_INTVCC1,
|
||||
/** External reference A */
|
||||
ADC_REFERENCE_AREFA = ADC_REFCTRL_REFSEL_AREFA,
|
||||
/** External reference B */
|
||||
ADC_REFERENCE_AREFB = ADC_REFCTRL_REFSEL_AREFB,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC clock prescaler enum
|
||||
*
|
||||
* Enum for the possible clock prescaler values for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_clock_prescaler {
|
||||
/** ADC clock division factor 4 */
|
||||
ADC_CLOCK_PRESCALER_DIV4 = ADC_CTRLB_PRESCALER_DIV4,
|
||||
/** ADC clock division factor 8 */
|
||||
ADC_CLOCK_PRESCALER_DIV8 = ADC_CTRLB_PRESCALER_DIV8,
|
||||
/** ADC clock division factor 16 */
|
||||
ADC_CLOCK_PRESCALER_DIV16 = ADC_CTRLB_PRESCALER_DIV16,
|
||||
/** ADC clock division factor 32 */
|
||||
ADC_CLOCK_PRESCALER_DIV32 = ADC_CTRLB_PRESCALER_DIV32,
|
||||
/** ADC clock division factor 64 */
|
||||
ADC_CLOCK_PRESCALER_DIV64 = ADC_CTRLB_PRESCALER_DIV64,
|
||||
/** ADC clock division factor 128 */
|
||||
ADC_CLOCK_PRESCALER_DIV128 = ADC_CTRLB_PRESCALER_DIV128,
|
||||
/** ADC clock division factor 256 */
|
||||
ADC_CLOCK_PRESCALER_DIV256 = ADC_CTRLB_PRESCALER_DIV256,
|
||||
/** ADC clock division factor 512 */
|
||||
ADC_CLOCK_PRESCALER_DIV512 = ADC_CTRLB_PRESCALER_DIV512,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC resolution enum
|
||||
*
|
||||
* Enum for the possible resolution values for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_resolution {
|
||||
/** ADC 12-bit resolution */
|
||||
ADC_RESOLUTION_12BIT = ADC_CTRLB_RESSEL_12BIT,
|
||||
/** ADC 16-bit resolution using oversampling and decimation */
|
||||
ADC_RESOLUTION_16BIT = ADC_CTRLB_RESSEL_16BIT,
|
||||
/** ADC 10-bit resolution */
|
||||
ADC_RESOLUTION_10BIT = ADC_CTRLB_RESSEL_10BIT,
|
||||
/** ADC 8-bit resolution */
|
||||
ADC_RESOLUTION_8BIT = ADC_CTRLB_RESSEL_8BIT,
|
||||
/** ADC 13-bit resolution using oversampling and decimation */
|
||||
ADC_RESOLUTION_13BIT,
|
||||
/** ADC 14-bit resolution using oversampling and decimation */
|
||||
ADC_RESOLUTION_14BIT,
|
||||
/** ADC 15-bit resolution using oversampling and decimation */
|
||||
ADC_RESOLUTION_15BIT,
|
||||
/** ADC 16-bit result register for use with averaging. When using this mode
|
||||
* the ADC result register will be set to 16-bit wide, and the number of
|
||||
* samples to accumulate and the division factor is configured by the
|
||||
* \ref adc_config.accumulate_samples and \ref adc_config.divide_result
|
||||
* members in the configuration struct.
|
||||
*/
|
||||
ADC_RESOLUTION_CUSTOM,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC window monitor mode enum
|
||||
*
|
||||
* Enum for the possible window monitor modes for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_window_mode {
|
||||
/** No window mode */
|
||||
ADC_WINDOW_MODE_DISABLE = ADC_WINCTRL_WINMODE_DISABLE,
|
||||
/** RESULT > WINLT */
|
||||
ADC_WINDOW_MODE_ABOVE_LOWER = ADC_WINCTRL_WINMODE_MODE1,
|
||||
/** RESULT < WINUT */
|
||||
ADC_WINDOW_MODE_BELOW_UPPER = ADC_WINCTRL_WINMODE_MODE2,
|
||||
/** WINLT < RESULT < WINUT */
|
||||
ADC_WINDOW_MODE_BETWEEN = ADC_WINCTRL_WINMODE_MODE3,
|
||||
/** !(WINLT < RESULT < WINUT) */
|
||||
ADC_WINDOW_MODE_BETWEEN_INVERTED = ADC_WINCTRL_WINMODE_MODE4,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC gain factor selection enum
|
||||
*
|
||||
* Enum for the possible gain factor values for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_gain_factor {
|
||||
/** 1x gain */
|
||||
ADC_GAIN_FACTOR_1X = ADC_INPUTCTRL_GAIN_1X,
|
||||
/** 2x gain */
|
||||
ADC_GAIN_FACTOR_2X = ADC_INPUTCTRL_GAIN_2X,
|
||||
/** 4x gain */
|
||||
ADC_GAIN_FACTOR_4X = ADC_INPUTCTRL_GAIN_4X,
|
||||
/** 8x gain */
|
||||
ADC_GAIN_FACTOR_8X = ADC_INPUTCTRL_GAIN_8X,
|
||||
/** 16x gain */
|
||||
ADC_GAIN_FACTOR_16X = ADC_INPUTCTRL_GAIN_16X,
|
||||
/** 1/2x gain */
|
||||
ADC_GAIN_FACTOR_DIV2 = ADC_INPUTCTRL_GAIN_DIV2,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC event action enum
|
||||
*
|
||||
* Enum for the possible actions to take on an incoming event.
|
||||
*
|
||||
*/
|
||||
enum adc_event_action {
|
||||
/** Event action disabled */
|
||||
ADC_EVENT_ACTION_DISABLED = 0,
|
||||
/** Flush ADC and start conversion */
|
||||
ADC_EVENT_ACTION_FLUSH_START_CONV = ADC_EVCTRL_SYNCEI,
|
||||
/** Start conversion */
|
||||
ADC_EVENT_ACTION_START_CONV = ADC_EVCTRL_STARTEI,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC positive MUX input selection enum
|
||||
*
|
||||
* Enum for the possible positive MUX input selections for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_positive_input {
|
||||
/** ADC0 pin */
|
||||
ADC_POSITIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXPOS_PIN0,
|
||||
/** ADC1 pin */
|
||||
ADC_POSITIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXPOS_PIN1,
|
||||
/** ADC2 pin */
|
||||
ADC_POSITIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXPOS_PIN2,
|
||||
/** ADC3 pin */
|
||||
ADC_POSITIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXPOS_PIN3,
|
||||
/** ADC4 pin */
|
||||
ADC_POSITIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXPOS_PIN4,
|
||||
/** ADC5 pin */
|
||||
ADC_POSITIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXPOS_PIN5,
|
||||
/** ADC6 pin */
|
||||
ADC_POSITIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXPOS_PIN6,
|
||||
/** ADC7 pin */
|
||||
ADC_POSITIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXPOS_PIN7,
|
||||
/** ADC8 pin */
|
||||
ADC_POSITIVE_INPUT_PIN8 = ADC_INPUTCTRL_MUXPOS_PIN8,
|
||||
/** ADC9 pin */
|
||||
ADC_POSITIVE_INPUT_PIN9 = ADC_INPUTCTRL_MUXPOS_PIN9,
|
||||
/** ADC10 pin */
|
||||
ADC_POSITIVE_INPUT_PIN10 = ADC_INPUTCTRL_MUXPOS_PIN10,
|
||||
/** ADC11 pin */
|
||||
ADC_POSITIVE_INPUT_PIN11 = ADC_INPUTCTRL_MUXPOS_PIN11,
|
||||
/** ADC12 pin */
|
||||
ADC_POSITIVE_INPUT_PIN12 = ADC_INPUTCTRL_MUXPOS_PIN12,
|
||||
/** ADC13 pin */
|
||||
ADC_POSITIVE_INPUT_PIN13 = ADC_INPUTCTRL_MUXPOS_PIN13,
|
||||
/** ADC14 pin */
|
||||
ADC_POSITIVE_INPUT_PIN14 = ADC_INPUTCTRL_MUXPOS_PIN14,
|
||||
/** ADC15 pin */
|
||||
ADC_POSITIVE_INPUT_PIN15 = ADC_INPUTCTRL_MUXPOS_PIN15,
|
||||
/** ADC16 pin */
|
||||
ADC_POSITIVE_INPUT_PIN16 = ADC_INPUTCTRL_MUXPOS_PIN16,
|
||||
/** ADC17 pin */
|
||||
ADC_POSITIVE_INPUT_PIN17 = ADC_INPUTCTRL_MUXPOS_PIN17,
|
||||
/** ADC18 pin */
|
||||
ADC_POSITIVE_INPUT_PIN18 = ADC_INPUTCTRL_MUXPOS_PIN18,
|
||||
/** ADC19 pin */
|
||||
ADC_POSITIVE_INPUT_PIN19 = ADC_INPUTCTRL_MUXPOS_PIN19,
|
||||
/** Temperature reference */
|
||||
ADC_POSITIVE_INPUT_TEMP = ADC_INPUTCTRL_MUXPOS_TEMP,
|
||||
/** Bandgap voltage */
|
||||
ADC_POSITIVE_INPUT_BANDGAP = ADC_INPUTCTRL_MUXPOS_BANDGAP,
|
||||
/** 1/4 scaled core supply */
|
||||
ADC_POSITIVE_INPUT_SCALEDCOREVCC = ADC_INPUTCTRL_MUXPOS_SCALEDCOREVCC,
|
||||
/** 1/4 scaled I/O supply */
|
||||
ADC_POSITIVE_INPUT_SCALEDIOVCC = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC,
|
||||
/** DAC input */
|
||||
ADC_POSITIVE_INPUT_DAC = ADC_INPUTCTRL_MUXPOS_DAC,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC negative Multiplexer(MUX) input selection enum
|
||||
*
|
||||
* Enum for the possible negative Multiplexer(MUX) input selections for the ADC.
|
||||
*
|
||||
*/
|
||||
enum adc_negative_input {
|
||||
/** ADC0 pin */
|
||||
ADC_NEGATIVE_INPUT_PIN0 = ADC_INPUTCTRL_MUXNEG_PIN0,
|
||||
/** ADC1 pin */
|
||||
ADC_NEGATIVE_INPUT_PIN1 = ADC_INPUTCTRL_MUXNEG_PIN1,
|
||||
/** ADC2 pin */
|
||||
ADC_NEGATIVE_INPUT_PIN2 = ADC_INPUTCTRL_MUXNEG_PIN2,
|
||||
/** ADC3 pin */
|
||||
ADC_NEGATIVE_INPUT_PIN3 = ADC_INPUTCTRL_MUXNEG_PIN3,
|
||||
/** ADC4 pin */
|
||||
ADC_NEGATIVE_INPUT_PIN4 = ADC_INPUTCTRL_MUXNEG_PIN4,
|
||||
/** ADC5 pin */
|
||||
ADC_NEGATIVE_INPUT_PIN5 = ADC_INPUTCTRL_MUXNEG_PIN5,
|
||||
/** ADC6 pin */
|
||||
ADC_NEGATIVE_INPUT_PIN6 = ADC_INPUTCTRL_MUXNEG_PIN6,
|
||||
/** ADC7 pin */
|
||||
ADC_NEGATIVE_INPUT_PIN7 = ADC_INPUTCTRL_MUXNEG_PIN7,
|
||||
/** Internal ground */
|
||||
ADC_NEGATIVE_INPUT_GND = ADC_INPUTCTRL_MUXNEG_GND,
|
||||
/** I/O ground */
|
||||
ADC_NEGATIVE_INPUT_IOGND = ADC_INPUTCTRL_MUXNEG_IOGND,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC number of accumulated samples enum
|
||||
*
|
||||
* Enum for the possible numbers of ADC samples to accumulate.
|
||||
* This setting is only used when the \ref ADC_RESOLUTION_CUSTOM
|
||||
* resolution setting is used.
|
||||
*
|
||||
*/
|
||||
enum adc_accumulate_samples {
|
||||
/** No averaging */
|
||||
ADC_ACCUMULATE_DISABLE = ADC_AVGCTRL_SAMPLENUM_1,
|
||||
/** Average 2 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_2 = ADC_AVGCTRL_SAMPLENUM_2,
|
||||
/** Average 4 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_4 = ADC_AVGCTRL_SAMPLENUM_4,
|
||||
/** Average 8 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_8 = ADC_AVGCTRL_SAMPLENUM_8,
|
||||
/** Average 16 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_16 = ADC_AVGCTRL_SAMPLENUM_16,
|
||||
/** Average 32 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_32 = ADC_AVGCTRL_SAMPLENUM_32,
|
||||
/** Average 64 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_64 = ADC_AVGCTRL_SAMPLENUM_64,
|
||||
/** Average 128 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_128 = ADC_AVGCTRL_SAMPLENUM_128,
|
||||
/** Average 256 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_256 = ADC_AVGCTRL_SAMPLENUM_256,
|
||||
/** Average 512 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_512 = ADC_AVGCTRL_SAMPLENUM_512,
|
||||
/** Average 1024 samples */
|
||||
ADC_ACCUMULATE_SAMPLES_1024 = ADC_AVGCTRL_SAMPLENUM_1024,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC possible dividers for the result register
|
||||
*
|
||||
* Enum for the possible division factors to use when accumulating
|
||||
* multiple samples. To keep the same resolution for the averaged
|
||||
* result and the actual input value, the division factor must
|
||||
* be equal to the number of samples accumulated. This setting is only
|
||||
* used when the \ref ADC_RESOLUTION_CUSTOM resolution setting is used.
|
||||
*/
|
||||
enum adc_divide_result {
|
||||
/** Don't divide result register after accumulation */
|
||||
ADC_DIVIDE_RESULT_DISABLE = 0,
|
||||
/** Divide result register by 2 after accumulation */
|
||||
ADC_DIVIDE_RESULT_2 = 1,
|
||||
/** Divide result register by 4 after accumulation */
|
||||
ADC_DIVIDE_RESULT_4 = 2,
|
||||
/** Divide result register by 8 after accumulation */
|
||||
ADC_DIVIDE_RESULT_8 = 3,
|
||||
/** Divide result register by 16 after accumulation */
|
||||
ADC_DIVIDE_RESULT_16 = 4,
|
||||
/** Divide result register by 32 after accumulation */
|
||||
ADC_DIVIDE_RESULT_32 = 5,
|
||||
/** Divide result register by 64 after accumulation */
|
||||
ADC_DIVIDE_RESULT_64 = 6,
|
||||
/** Divide result register by 128 after accumulation */
|
||||
ADC_DIVIDE_RESULT_128 = 7,
|
||||
};
|
||||
|
||||
#if ADC_CALLBACK_MODE == true
|
||||
/**
|
||||
* Enum for the possible ADC interrupt flags.
|
||||
*/
|
||||
enum adc_interrupt_flag {
|
||||
/** ADC result ready */
|
||||
ADC_INTERRUPT_RESULT_READY = ADC_INTFLAG_RESRDY,
|
||||
/** Window monitor match */
|
||||
ADC_INTERRUPT_WINDOW = ADC_INTFLAG_WINMON,
|
||||
/** ADC result overwritten before read */
|
||||
ADC_INTERRUPT_OVERRUN = ADC_INTFLAG_OVERRUN,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief ADC oversampling and decimation enum
|
||||
*
|
||||
* Enum for the possible numbers of bits resolution can be increased by when
|
||||
* using oversampling and decimation.
|
||||
*
|
||||
*/
|
||||
enum adc_oversampling_and_decimation {
|
||||
/** Don't use oversampling and decimation mode */
|
||||
ADC_OVERSAMPLING_AND_DECIMATION_DISABLE = 0,
|
||||
/** 1-bit resolution increase */
|
||||
ADC_OVERSAMPLING_AND_DECIMATION_1BIT,
|
||||
/** 2-bit resolution increase */
|
||||
ADC_OVERSAMPLING_AND_DECIMATION_2BIT,
|
||||
/** 3-bit resolution increase */
|
||||
ADC_OVERSAMPLING_AND_DECIMATION_3BIT,
|
||||
/** 4-bit resolution increase */
|
||||
ADC_OVERSAMPLING_AND_DECIMATION_4BIT
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Window monitor configuration structure
|
||||
*
|
||||
* Window monitor configuration structure.
|
||||
*/
|
||||
struct adc_window_config {
|
||||
/** Selected window mode */
|
||||
enum adc_window_mode window_mode;
|
||||
/** Lower window value */
|
||||
int32_t window_lower_value;
|
||||
/** Upper window value */
|
||||
int32_t window_upper_value;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC event enable/disable structure.
|
||||
*
|
||||
* Event flags for the ADC module. This is used to enable and
|
||||
* disable events via \ref adc_enable_events() and \ref adc_disable_events().
|
||||
*/
|
||||
struct adc_events {
|
||||
/** Enable event generation on conversion done */
|
||||
bool generate_event_on_conversion_done;
|
||||
/** Enable event generation on window monitor */
|
||||
bool generate_event_on_window_monitor;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Gain and offset correction configuration structure
|
||||
*
|
||||
* Gain and offset correction configuration structure.
|
||||
* Part of the \ref adc_config struct and will be initialized by
|
||||
* \ref adc_get_config_defaults.
|
||||
*/
|
||||
struct adc_correction_config {
|
||||
/**
|
||||
* Enables correction for gain and offset based on values of gain_correction and
|
||||
* offset_correction if set to true
|
||||
*/
|
||||
bool correction_enable;
|
||||
/**
|
||||
* This value defines how the ADC conversion result is compensated for gain
|
||||
* error before written to the result register. This is a fractional value,
|
||||
* 1-bit integer plus an 11-bit fraction, therefore
|
||||
* 1/2 <= gain_correction < 2. Valid \c gain_correction values ranges from
|
||||
* \c 0b010000000000 to \c 0b111111111111.
|
||||
*/
|
||||
uint16_t gain_correction;
|
||||
/**
|
||||
* This value defines how the ADC conversion result is compensated for
|
||||
* offset error before written to the result register. This is a 12-bit
|
||||
* value in two's complement format.
|
||||
*/
|
||||
int16_t offset_correction;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Pin scan configuration structure
|
||||
*
|
||||
* Pin scan configuration structure. Part of the \ref adc_config struct and will
|
||||
* be initialized by \ref adc_get_config_defaults.
|
||||
*/
|
||||
struct adc_pin_scan_config {
|
||||
/**
|
||||
* Offset (relative to selected positive input) of the first input pin to be
|
||||
* used in pin scan mode
|
||||
*/
|
||||
uint8_t offset_start_scan;
|
||||
/**
|
||||
* Number of input pins to scan in pin scan mode. A value below two will
|
||||
* disable pin scan mode.
|
||||
*/
|
||||
uint8_t inputs_to_scan;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC configuration structure
|
||||
*
|
||||
* Configuration structure for an ADC instance. This structure should be
|
||||
* initialized by the \ref adc_get_config_defaults()
|
||||
* function before being modified by the user application.
|
||||
*/
|
||||
struct adc_config {
|
||||
/** GCLK generator used to clock the peripheral */
|
||||
enum gclk_generator clock_source;
|
||||
/** Voltage reference */
|
||||
enum adc_reference reference;
|
||||
/** Clock prescaler */
|
||||
enum adc_clock_prescaler clock_prescaler;
|
||||
/** Result resolution */
|
||||
enum adc_resolution resolution;
|
||||
/** Gain factor */
|
||||
enum adc_gain_factor gain_factor;
|
||||
/** Positive Multiplexer (MUX) input */
|
||||
enum adc_positive_input positive_input;
|
||||
/** Negative MUX input. For singled-ended conversion mode, the negative
|
||||
* input must be connected to ground. This ground could be the internal
|
||||
* GND, IOGND or an external ground connected to a pin. */
|
||||
enum adc_negative_input negative_input;
|
||||
/** Number of ADC samples to accumulate when using the
|
||||
* \c ADC_RESOLUTION_CUSTOM mode. Note: if the result width increases,
|
||||
* result resolution will be changed accordingly.
|
||||
*/
|
||||
enum adc_accumulate_samples accumulate_samples;
|
||||
/** Division ration when using the ADC_RESOLUTION_CUSTOM mode */
|
||||
enum adc_divide_result divide_result;
|
||||
/** Left adjusted result */
|
||||
bool left_adjust;
|
||||
/** Enables differential mode if true.
|
||||
* if false, ADC will run in singled-ended mode. */
|
||||
bool differential_mode;
|
||||
/** Enables free running mode if true */
|
||||
bool freerunning;
|
||||
/** Enables ADC in standby sleep mode if true */
|
||||
bool run_in_standby;
|
||||
/**
|
||||
* Enables reference buffer offset compensation if true.
|
||||
* This will increase the accuracy of the gain stage, but decreases the input
|
||||
* impedance; therefore the startup time of the reference must be increased.
|
||||
*/
|
||||
bool reference_compensation_enable;
|
||||
/**
|
||||
* This value (0-63) control the ADC sampling time in number of half ADC
|
||||
* prescaled clock cycles (depends of \c ADC_PRESCALER value), thus
|
||||
* controlling the ADC input impedance. Sampling time is set according to
|
||||
* the formula:
|
||||
* Sample time = (sample_length+1) * (ADCclk / 2).
|
||||
*/
|
||||
uint8_t sample_length;
|
||||
/** Window monitor configuration structure */
|
||||
struct adc_window_config window;
|
||||
/** Gain and offset correction configuration structure */
|
||||
struct adc_correction_config correction;
|
||||
/** Event action to take on incoming event */
|
||||
enum adc_event_action event_action;
|
||||
/** Pin scan configuration structure */
|
||||
struct adc_pin_scan_config pin_scan;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ADC software device instance structure.
|
||||
*
|
||||
* ADC software instance structure, used to retain software state information
|
||||
* of an associated hardware module instance.
|
||||
*
|
||||
* \note The fields of this structure should not be altered by the user
|
||||
* application; they are reserved for module-internal use only.
|
||||
*/
|
||||
struct adc_module {
|
||||
#if !defined(__DOXYGEN__)
|
||||
/** Pointer to ADC hardware module */
|
||||
Adc *hw;
|
||||
/** Keep reference configuration so we know when enable is called */
|
||||
enum adc_reference reference;
|
||||
# if ADC_CALLBACK_MODE == true
|
||||
/** Array to store callback functions */
|
||||
adc_callback_t callback[ADC_CALLBACK_N];
|
||||
/** Pointer to buffer used for ADC results */
|
||||
volatile uint16_t *job_buffer;
|
||||
/** Remaining number of conversions in current job */
|
||||
volatile uint16_t remaining_conversions;
|
||||
/** Bit mask for callbacks registered */
|
||||
uint8_t registered_callback_mask;
|
||||
/** Bit mask for callbacks enabled */
|
||||
uint8_t enabled_callback_mask;
|
||||
/** Holds the status of the ongoing or last conversion job */
|
||||
volatile enum status_code job_status;
|
||||
/** If software triggering is needed */
|
||||
bool software_trigger;
|
||||
# endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
/**
|
||||
* \brief Determines if the hardware module(s) are currently synchronizing to the bus.
|
||||
*
|
||||
* Checks to see if the underlying hardware peripheral module(s) are currently
|
||||
* synchronizing across multiple clock domains to the hardware bus. This
|
||||
* function can be used to delay further operations on a module until such time
|
||||
* that it is ready, to prevent blocking delays for synchronization in the
|
||||
* user application.
|
||||
*
|
||||
* \param[in] module_inst Pointer to the ADC software instance struct
|
||||
*
|
||||
* \return Synchronization status of the underlying hardware module(s).
|
||||
*
|
||||
* \retval true if the module synchronization is ongoing
|
||||
* \retval false if the module has completed synchronization
|
||||
*/
|
||||
static inline bool adc_is_syncing(
|
||||
struct adc_module *const module_inst)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module_inst);
|
||||
|
||||
Adc *const adc_module = module_inst->hw;
|
||||
|
||||
if (adc_module->STATUS.reg & ADC_STATUS_SYNCBUSY) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \name ADC Gain and Pin Scan Mode
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets ADC gain factor
|
||||
*
|
||||
* Sets the ADC gain factor to a specified gain setting.
|
||||
*
|
||||
* \param[in] module_inst Pointer to the ADC software instance struct
|
||||
* \param[in] gain_factor Gain factor value to set
|
||||
*/
|
||||
static inline void adc_set_gain(
|
||||
struct adc_module *const module_inst,
|
||||
const enum adc_gain_factor gain_factor)
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module_inst);
|
||||
Assert(module_inst->hw);
|
||||
|
||||
Adc *const adc_module = module_inst->hw;
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Set new gain factor */
|
||||
adc_module->INPUTCTRL.reg =
|
||||
(adc_module->INPUTCTRL.reg & ~ADC_INPUTCTRL_GAIN_Msk) |
|
||||
(gain_factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets the ADC pin scan mode
|
||||
*
|
||||
* Configures the pin scan mode of the ADC module. In pin scan mode, the first
|
||||
* conversion will start at the configured positive input + start_offset. When
|
||||
* a conversion is done, a conversion will start on the next input, until
|
||||
* \c inputs_to_scan number of conversions are made.
|
||||
*
|
||||
* \param[in] module_inst Pointer to the ADC software instance struct
|
||||
* \param[in] inputs_to_scan Number of input pins to perform a conversion on
|
||||
* (must be two or more)
|
||||
* \param[in] start_offset Offset of first pin to scan (relative to
|
||||
* configured positive input)
|
||||
*
|
||||
* \return Status of the pin scan configuration set request.
|
||||
*
|
||||
* \retval STATUS_OK Pin scan mode has been set successfully
|
||||
* \retval STATUS_ERR_INVALID_ARG Number of input pins to scan or offset has
|
||||
* an invalid value
|
||||
*/
|
||||
static inline enum status_code adc_set_pin_scan_mode(
|
||||
struct adc_module *const module_inst,
|
||||
uint8_t inputs_to_scan,
|
||||
const uint8_t start_offset)
|
||||
|
||||
{
|
||||
/* Sanity check arguments */
|
||||
Assert(module_inst);
|
||||
Assert(module_inst->hw);
|
||||
|
||||
Adc *const adc_module = module_inst->hw;
|
||||
|
||||
if (inputs_to_scan > 0) {
|
||||
/*
|
||||
* Number of input sources included is the value written to INPUTSCAN
|
||||
* plus 1.
|
||||
*/
|
||||
inputs_to_scan--;
|
||||
}
|
||||
|
||||
if (inputs_to_scan > (ADC_INPUTCTRL_INPUTSCAN_Msk >> ADC_INPUTCTRL_INPUTSCAN_Pos) ||
|
||||
start_offset > (ADC_INPUTCTRL_INPUTOFFSET_Msk >> ADC_INPUTCTRL_INPUTOFFSET_Pos)) {
|
||||
/* Invalid number of input pins */
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
while (adc_is_syncing(module_inst)) {
|
||||
/* Wait for synchronization */
|
||||
}
|
||||
|
||||
/* Set pin scan mode */
|
||||
adc_module->INPUTCTRL.reg =
|
||||
(adc_module->INPUTCTRL.reg &
|
||||
~(ADC_INPUTCTRL_INPUTSCAN_Msk | ADC_INPUTCTRL_INPUTOFFSET_Msk)) |
|
||||
(start_offset << ADC_INPUTCTRL_INPUTOFFSET_Pos) |
|
||||
(inputs_to_scan << ADC_INPUTCTRL_INPUTSCAN_Pos);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disables pin scan mode
|
||||
*
|
||||
* Disables pin scan mode. The next conversion will be made on only one pin
|
||||
* (the configured positive input pin).
|
||||
*
|
||||
* \param[in] module_inst Pointer to the ADC software instance struct
|
||||
*/
|
||||
static inline void adc_disable_pin_scan_mode(
|
||||
struct adc_module *const module_inst)
|
||||
{
|
||||
/* Disable pin scan mode */
|
||||
adc_set_pin_scan_mode(module_inst, 0, 0);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* ADC_FEATURE_H_INCLUDED */
|
||||
|
@ -1,32 +1,25 @@
|
||||
#include "pins.h"
|
||||
#include "asf/sam0/drivers/system/system.h"
|
||||
|
||||
#define PIN(p_name) \
|
||||
const pin_obj_t pin_## p_name = { \
|
||||
{ &pin_type }, \
|
||||
.name = MP_QSTR_ ## p_name, \
|
||||
.pin = (PIN_## p_name), \
|
||||
}
|
||||
|
||||
PIN(PA02);
|
||||
PIN(PB08);
|
||||
PIN(PB09);
|
||||
PIN(PA04);
|
||||
PIN(PA05);
|
||||
PIN(PB02);
|
||||
PIN(PA11);
|
||||
PIN(PA10);
|
||||
PIN(PA14);
|
||||
PIN(PA09);
|
||||
PIN(PA08);
|
||||
PIN(PA15);
|
||||
PIN(PA20);
|
||||
PIN(PA06);
|
||||
PIN(PA07);
|
||||
PIN(PA18);
|
||||
PIN(PA16);
|
||||
PIN(PA19);
|
||||
PIN(PA17);
|
||||
PIN(PA02, true, ADC_POSITIVE_INPUT_PIN0);
|
||||
PIN(PB08, true, ADC_POSITIVE_INPUT_PIN8);
|
||||
PIN(PB09, true, ADC_POSITIVE_INPUT_PIN9);
|
||||
PIN(PA04, true, ADC_POSITIVE_INPUT_PIN4);
|
||||
PIN(PA05, true, ADC_POSITIVE_INPUT_PIN5);
|
||||
PIN(PB02, true, ADC_POSITIVE_INPUT_PIN10);
|
||||
PIN(PA11, true, ADC_POSITIVE_INPUT_PIN19);
|
||||
PIN(PA10, true, ADC_POSITIVE_INPUT_PIN18);
|
||||
PIN(PA14, false, NO_ADC_INPUT);
|
||||
PIN(PA09, true, ADC_POSITIVE_INPUT_PIN17);
|
||||
PIN(PA08, true, ADC_POSITIVE_INPUT_PIN16);
|
||||
PIN(PA15, false, NO_ADC_INPUT);
|
||||
PIN(PA20, false, NO_ADC_INPUT);
|
||||
PIN(PA06, true, ADC_POSITIVE_INPUT_PIN6);
|
||||
PIN(PA07, true, ADC_POSITIVE_INPUT_PIN7);
|
||||
PIN(PA18, false, NO_ADC_INPUT);
|
||||
PIN(PA16, false, NO_ADC_INPUT);
|
||||
PIN(PA19, false, NO_ADC_INPUT);
|
||||
PIN(PA17, false, NO_ADC_INPUT);
|
||||
|
||||
STATIC const mp_map_elem_t pin_cpu_pins_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PA02), (mp_obj_t)&pin_PA02 },
|
||||
|
@ -1,33 +1,26 @@
|
||||
#include "pins.h"
|
||||
#include "asf/sam0/drivers/system/system.h"
|
||||
|
||||
#define PIN(p_name) \
|
||||
const pin_obj_t pin_## p_name = { \
|
||||
{ &pin_type }, \
|
||||
.name = MP_QSTR_ ## p_name, \
|
||||
.pin = (PIN_## p_name), \
|
||||
}
|
||||
|
||||
PIN(PA02);
|
||||
PIN(PB08);
|
||||
PIN(PB09);
|
||||
PIN(PA04);
|
||||
PIN(PA05);
|
||||
PIN(PB02);
|
||||
PIN(PB11);
|
||||
PIN(PB10);
|
||||
PIN(PA12);
|
||||
PIN(PA11);
|
||||
PIN(PA10);
|
||||
PIN(PA22);
|
||||
PIN(PA23);
|
||||
PIN(PA15);
|
||||
PIN(PA20);
|
||||
PIN(PA07);
|
||||
PIN(PA18);
|
||||
PIN(PA16);
|
||||
PIN(PA19);
|
||||
PIN(PA17);
|
||||
PIN(PA02, true, ADC_POSITIVE_INPUT_PIN0);
|
||||
PIN(PB08, true, ADC_POSITIVE_INPUT_PIN8);
|
||||
PIN(PB09, true, ADC_POSITIVE_INPUT_PIN9);
|
||||
PIN(PA04, true, ADC_POSITIVE_INPUT_PIN4);
|
||||
PIN(PA05, true, ADC_POSITIVE_INPUT_PIN5);
|
||||
PIN(PB02, true, ADC_POSITIVE_INPUT_PIN10);
|
||||
PIN(PB11, false, NO_ADC_INPUT);
|
||||
PIN(PB10, false, NO_ADC_INPUT);
|
||||
PIN(PA12, false, NO_ADC_INPUT);
|
||||
PIN(PA11, true, ADC_POSITIVE_INPUT_PIN19);
|
||||
PIN(PA10, true, ADC_POSITIVE_INPUT_PIN18);
|
||||
PIN(PA22, false, NO_ADC_INPUT);
|
||||
PIN(PA23, false, NO_ADC_INPUT);
|
||||
PIN(PA15, false, NO_ADC_INPUT);
|
||||
PIN(PA20, false, NO_ADC_INPUT);
|
||||
PIN(PA07, true, ADC_POSITIVE_INPUT_PIN7);
|
||||
PIN(PA18, false, NO_ADC_INPUT);
|
||||
PIN(PA16, false, NO_ADC_INPUT);
|
||||
PIN(PA19, false, NO_ADC_INPUT);
|
||||
PIN(PA17, false, NO_ADC_INPUT);
|
||||
|
||||
STATIC const mp_map_elem_t pin_cpu_pins_locals_dict_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_PA02), (mp_obj_t)&pin_PA02 },
|
||||
|
@ -31,12 +31,14 @@
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "adc.h"
|
||||
#include "pin.h"
|
||||
|
||||
#if MICROPY_PY_MACHINE
|
||||
|
||||
STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&adc_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Pin), MP_ROM_PTR(&pin_type) },
|
||||
};
|
||||
|
||||
|
@ -27,8 +27,24 @@
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_PIN_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_PIN_H__
|
||||
|
||||
// This file requires pin_defs_xxx.h (which has port specific enums and
|
||||
// defines, so we include it here. It should never be included directly
|
||||
// Don't reorder these includes because they are dependencies of adc_feature.h.
|
||||
// They should really be included by adc_feature.h.
|
||||
#include "compiler.h"
|
||||
#include "asf/sam0/drivers/system/clock/gclk.h"
|
||||
#include "asf/sam0/utils/cmsis/samd21/include/component/adc.h"
|
||||
#include "asf/sam0/drivers/adc/adc_sam_d_r/adc_feature.h"
|
||||
|
||||
// This macro is used to simplify pin definition in boards/<board>/pins.c
|
||||
#define PIN(p_name, p_has_adc, p_adc_input) \
|
||||
const pin_obj_t pin_## p_name = { \
|
||||
{ &pin_type }, \
|
||||
.name = MP_QSTR_ ## p_name, \
|
||||
.pin = (PIN_## p_name), \
|
||||
.has_adc = p_has_adc, \
|
||||
.adc_input = p_adc_input, \
|
||||
}
|
||||
|
||||
#define NO_ADC_INPUT (0)
|
||||
|
||||
#include "mpconfigport.h"
|
||||
|
||||
@ -38,6 +54,8 @@ typedef struct {
|
||||
mp_obj_base_t base;
|
||||
qstr name;
|
||||
uint32_t pin;
|
||||
bool has_adc;
|
||||
enum adc_positive_input adc_input;
|
||||
} pin_obj_t;
|
||||
|
||||
extern const mp_obj_type_t pin_type;
|
||||
|
Loading…
x
Reference in New Issue
Block a user