diff --git a/hardware/sam/system/libsam/cmsis/sam3u/include/component/adc.h b/hardware/sam/system/libsam/cmsis/sam3u/include/component/adc.h index 3e344c325..c8ce564b3 100644 --- a/hardware/sam/system/libsam/cmsis/sam3u/include/component/adc.h +++ b/hardware/sam/system/libsam/cmsis/sam3u/include/component/adc.h @@ -42,11 +42,23 @@ typedef struct { #define ADC_CR_START (0x1u << 1) /**< \brief (ADC_CR) Start Conversion */ /* -------- ADC_MR : (ADC Offset: 0x04) Mode Register -------- */ #define ADC_MR_TRGEN (0x1u << 0) /**< \brief (ADC_MR) Trigger Enable */ +#define ADC_MR_TRGEN_DIS (0x0u << 0) /**< \brief (ADC_MR) Hardware triggers are disabled. Starting a conversion is only possible by software. */ +#define ADC_MR_TRGEN_EN (0x1u << 0) /**< \brief (ADC_MR) Hardware trigger selected by TRGSEL field is enabled. */ #define ADC_MR_TRGSEL_Pos 1 #define ADC_MR_TRGSEL_Msk (0x7u << ADC_MR_TRGSEL_Pos) /**< \brief (ADC_MR) Trigger Selection */ #define ADC_MR_TRGSEL(value) ((ADC_MR_TRGSEL_Msk & ((value) << ADC_MR_TRGSEL_Pos))) +#define ADC_MR_TRGSEL_ADC_TRIG0 (0x0u << 1) /**< \brief (ADC_MR) External trigger */ +#define ADC_MR_TRGSEL_ADC_TRIG1 (0x1u << 1) /**< \brief (ADC_MR) TIO Output of the Timer Counter Channel 0 */ +#define ADC_MR_TRGSEL_ADC_TRIG2 (0x2u << 1) /**< \brief (ADC_MR) TIO Output of the Timer Counter Channel 1 */ +#define ADC_MR_TRGSEL_ADC_TRIG3 (0x3u << 1) /**< \brief (ADC_MR) TIO Output of the Timer Counter Channel 2 */ +#define ADC_MR_TRGSEL_ADC_TRIG4 (0x4u << 1) /**< \brief (ADC_MR) PWM Event Line 0 */ +#define ADC_MR_TRGSEL_ADC_TRIG5 (0x5u << 1) /**< \brief (ADC_MR) PWM Event Line 1 */ #define ADC_MR_LOWRES (0x1u << 4) /**< \brief (ADC_MR) Resolution */ +#define ADC_MR_LOWRES_BITS_10 (0x0u << 4) /**< \brief (ADC_MR) 12-bit resolution */ +#define ADC_MR_LOWRES_BITS_8 (0x1u << 4) /**< \brief (ADC_MR) 10-bit resolution */ #define ADC_MR_SLEEP (0x1u << 5) /**< \brief (ADC_MR) Sleep Mode */ +#define ADC_MR_SLEEP_NORMAL (0x0u << 5) /**< \brief (ADC_MR) Normal Mode: The ADC Core and reference voltage circuitry are kept ON between conversions */ +#define ADC_MR_SLEEP_SLEEP (0x1u << 5) /**< \brief (ADC_MR) Sleep Mode: The ADC Core and reference voltage circuitry are OFF between conversions */ #define ADC_MR_PRESCAL_Pos 8 #define ADC_MR_PRESCAL_Msk (0xffu << ADC_MR_PRESCAL_Pos) /**< \brief (ADC_MR) Prescaler Rate Selection */ #define ADC_MR_PRESCAL(value) ((ADC_MR_PRESCAL_Msk & ((value) << ADC_MR_PRESCAL_Pos))) @@ -173,6 +185,10 @@ typedef struct { /* -------- ADC_CDR[8] : (ADC Offset: 0x30) Channel Data Register -------- */ #define ADC_CDR_DATA_Pos 0 #define ADC_CDR_DATA_Msk (0x3ffu << ADC_CDR_DATA_Pos) /**< \brief (ADC_CDR[8]) Converted Data */ +/* -------- ADC_ACR : (ADC Offset: 0x94) Analog Control Register -------- */ +#define ADC_ACR_IBCTL_Pos 8 +#define ADC_ACR_IBCTL_Msk (0x3u << ADC_ACR_IBCTL_Pos) /**< \brief (ADC_ACR) ADC Bias Current Control */ +#define ADC_ACR_IBCTL(value) ((ADC_ACR_IBCTL_Msk & ((value) << ADC_ACR_IBCTL_Pos))) /* -------- ADC_RPR : (ADC Offset: 0x100) Receive Pointer Register -------- */ #define ADC_RPR_RXPTR_Pos 0 #define ADC_RPR_RXPTR_Msk (0xffffffffu << ADC_RPR_RXPTR_Pos) /**< \brief (ADC_RPR) Receive Pointer Register */ diff --git a/hardware/sam/system/libsam/cmsis/sam3u/include/component/adc12b.h b/hardware/sam/system/libsam/cmsis/sam3u/include/component/adc12b.h index b1b7c7f61..11ca0601b 100644 --- a/hardware/sam/system/libsam/cmsis/sam3u/include/component/adc12b.h +++ b/hardware/sam/system/libsam/cmsis/sam3u/include/component/adc12b.h @@ -49,6 +49,8 @@ typedef struct { #define ADC12B_MR_TRGSEL_Msk (0x7u << ADC12B_MR_TRGSEL_Pos) /**< \brief (ADC12B_MR) Trigger Selection */ #define ADC12B_MR_TRGSEL(value) ((ADC12B_MR_TRGSEL_Msk & ((value) << ADC12B_MR_TRGSEL_Pos))) #define ADC12B_MR_LOWRES (0x1u << 4) /**< \brief (ADC12B_MR) Resolution */ +#define ADC12B_MR_LOWRES_BITS_12 (0x0u << 4) /**< \brief (ADC_MR) 12-bit resolution */ +#define ADC12B_MR_LOWRES_BITS_10 (0x1u << 4) /**< \brief (ADC_MR) 10-bit resolution */ #define ADC12B_MR_SLEEP (0x1u << 5) /**< \brief (ADC12B_MR) Sleep Mode */ #define ADC12B_MR_PRESCAL_Pos 8 #define ADC12B_MR_PRESCAL_Msk (0xffu << ADC12B_MR_PRESCAL_Pos) /**< \brief (ADC12B_MR) Prescaler Rate Selection */ diff --git a/hardware/sam/system/libsam/include/adc.h b/hardware/sam/system/libsam/include/adc.h index c20104c48..f1cd4f136 100644 --- a/hardware/sam/system/libsam/include/adc.h +++ b/hardware/sam/system/libsam/include/adc.h @@ -1,4 +1,8 @@ -/* ---------------------------------------------------------------------------- +/*! \file ********************************************************************* + * + * \brief API for SAM3 Analog-to-Digital Converter (ADC/ADC12B) controller. + * + * ---------------------------------------------------------------------------- * SAM Software Package License * ---------------------------------------------------------------------------- * Copyright (c) 2011, Atmel Corporation @@ -24,134 +28,1004 @@ * 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. - * ---------------------------------------------------------------------------- - */ + * + * - Compiler: IAR EWARM and CodeSourcery GCC for ARM + * - Supported devices: All SAM devices with a Analog-to-Digital Converter can be used. + * - AppNote: + * + * \author Atmel Corporation: http://www.atmel.com \n + * Support and FAQ: http://support.atmel.com/ + * + *******************************************************************************/ + -/** - * \file - * - * \section Purpose - * - * Interface for configuration the Analog-to-Digital Converter (ADC) peripheral. - * - * \section Usage - * - * -# Configurate the pins for ADC - * -# Initialize the ADC with ADC_Initialize(). - * -# Select the active channel using ADC_EnableChannel() - * -# Start the conversion with ADC_StartConversion() - * -# Wait the end of the conversion by polling status with ADC_GetStatus() - * -# Finally, get the converted data using ADC_GetConvertedData() - * -*/ -#ifndef _ADC_ -#define _ADC_ -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ +#ifndef ADC_H_INCLUDED +#define ADC_H_INCLUDED + #include "../chip.h" -#include -#include +#if SAM3U +#define ADC_12B +#endif -/*------------------------------------------------------------------------------ - * Definitions - *------------------------------------------------------------------------------*/ -/* SAM3S */ #define ADC_FREQ_MAX 20000000 #define ADC_FREQ_MIN 1000000 #define ADC_STARTUP_NORM 40 #define ADC_STARTUP_FAST 12 -#define ADC_CHANNEL_0 0 -#define ADC_CHANNEL_1 1 -#define ADC_CHANNEL_2 2 -#define ADC_CHANNEL_3 3 -#define ADC_CHANNEL_4 4 -#define ADC_CHANNEL_5 5 -#define ADC_CHANNEL_6 6 -#define ADC_CHANNEL_7 7 -#define ADC_CHANNEL_8 8 -#define ADC_CHANNEL_9 9 -#define ADC_CHANNEL_10 10 -#define ADC_CHANNEL_11 11 -#define ADC_CHANNEL_12 12 -#define ADC_CHANNEL_13 13 -#define ADC_CHANNEL_14 14 -#define ADC_CHANNEL_15 15 - -#ifdef __cplusplus - extern "C" { +/* Definitions for ADC resolution */ +#if SAM3S || SAM3XA +typedef enum _adc_resolution_t { + ADC_10_BITS = ADC_MR_LOWRES_BITS_10, /* ADC 10-bit resolution */ + ADC_12_BITS = ADC_MR_LOWRES_BITS_12 /* ADC 12-bit resolution */ +} adc_resolution_t; +#elif SAM3N +typedef enum _adc_resolution_t { + ADC_8_BITS = ADC_MR_LOWRES_BITS_8, /* ADC 8-bit resolution */ + ADC_10_BITS = ADC_MR_LOWRES_BITS_10 /* ADC 10-bit resolution */ +} adc_resolution_t; +#elif SAM3U +#ifdef ADC_12B +typedef enum _adc_resolution_t { + ADC_10_BITS = ADC12B_MR_LOWRES_BITS_10, /* ADC 10-bit resolution */ + ADC_12_BITS = ADC12B_MR_LOWRES_BITS_12 /* ADC 12-bit resolution */ +} adc_resolution_t; +#else +typedef enum _adc_resolution_t { + ADC_8_BITS = ADC_MR_LOWRES_BITS_8, /* ADC 8-bit resolution */ + ADC_10_BITS = ADC_MR_LOWRES_BITS_10 /* ADC 10-bit resolution */ +} adc_resolution_t; #endif -/*------------------------------------------------------------------------------ - * Macros function of register access - *------------------------------------------------------------------------------*/ +#endif +/* Definitions for ADC trigger */ +typedef enum _adc_trigger_t { + ADC_TRIG_SW = ADC_MR_TRGEN_DIS, /* Starting a conversion is only possible by software. */ + ADC_TRIG_EXT = ((ADC_MR_TRGSEL_ADC_TRIG0 <ADC_MR) +#if SAM3S || SAM3N || SAM3XA +/* Definitions for ADC channel number */ +typedef enum _adc_channel_num_t { + ADC_CHANNEL_0 = 0, + ADC_CHANNEL_1 = 1, + ADC_CHANNEL_2 = 2, + ADC_CHANNEL_3 = 3, + ADC_CHANNEL_4 = 4, + ADC_CHANNEL_5 = 5, + ADC_CHANNEL_6 = 6, + ADC_CHANNEL_7 = 7, + ADC_CHANNEL_8 = 8, + ADC_CHANNEL_9 = 9, + ADC_CHANNEL_10 = 10, + ADC_CHANNEL_11 = 11, + ADC_CHANNEL_12 = 12, + ADC_CHANNEL_13 = 13, + ADC_CHANNEL_14 = 14, + ADC_TEMPERATURE_SENSOR = 15, + ADC_ALL_CHANNEL +} adc_channel_num_t; +#elif SAM3U +/* Definitions for ADC channel number */ +typedef enum _adc_channel_num_t { + ADC_CHANNEL_0 = 0, + ADC_CHANNEL_1 = 1, + ADC_CHANNEL_2 = 2, + ADC_CHANNEL_3 = 3, + ADC_CHANNEL_4 = 4, + ADC_CHANNEL_5 = 5, + ADC_CHANNEL_6 = 6, + ADC_CHANNEL_7 = 7, + ADC_ALL_CHANNEL +} adc_channel_num_t; +#endif -#define ADC_StartConversion( pAdc ) ((pAdc)->ADC_CR = ADC_CR_START) +typedef enum{ + ADC_GAINVALUE_0 = 0, + ADC_GAINVALUE_1 = 1, + ADC_GAINVALUE_2 = 2, + ADC_GAINVALUE_3 = 3 +}adc_gainvalue_t; + +#if SAM3S || SAM3XA +typedef enum{ + ADC_SETTLING_TIME_0 = ADC_MR_SETTLING_AST3, + ADC_SETTLING_TIME_1 = ADC_MR_SETTLING_AST5, + ADC_SETTLING_TIME_2 = ADC_MR_SETTLING_AST9, + ADC_SETTLING_TIME_3 = ADC_MR_SETTLING_AST17 +}adc_settling_time_t; +#endif +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Initializes the given ADC with the specified ADC clock and startup time. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_mck Main clock of the device (value in Hz). + * \param dw_adc_clock Analog-to-Digital conversion clock (value in Hz). + * \param uc_startup ADC start up time. Please refer to the product datasheet for details. + * + * \retval 0 The initialization operation succeeds. + * \retval others The initialization operation fails. + */ +extern uint32_t adc_init(Adc *p_adc, uint32_t ul_mck, uint32_t ul_adc_clock, uint8_t uc_startup); + +#endif + + #if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures conversion resolution. + * + * \param p_adc Pointer to an ADC instance. + * \param resolution ADC resolution. + * + */ +extern void adc_set_resolution(Adc *p_adc, adc_resolution_t resolution); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures conversion trigger and free run mode. + * + * \param p_adc Pointer to an ADC instance. + * \param trigger Conversion trigger. + * \param uc_freerun ADC_MR_FREERUN_ON enables freerun mode + * ADC_MR_FREERUN_OFF disables freerun mode + * + */ +extern void adc_configure_trigger(Adc *p_adc, adc_trigger_t trigger, uint8_t uc_freerun); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures ADC power saving mode. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_sleep ADC_MR_SLEEP_NORMAL keeps the ADC Core and reference voltage circuitry ON between conversions + * ADC_MR_SLEEP_SLEEP keeps the ADC Core and reference voltage circuitry OFF between conversions + * \param uc_fwup ADC_MR_FWUP_OFF configures sleep mode as uc_sleep setting + * ADC_MR_FWUP_ON keeps voltage reference ON and ADC Core OFF between conversions + * + */ +extern void adc_configure_power_save(Adc *p_adc, uint8_t uc_sleep, uint8_t uc_fwup); +/** + * \brief Configures conversion sequence. + * + * \param p_adc Pointer to an ADC instance. + * \param ch_list Channel sequence list. + * \param number Number of channels in the list. + * + */ +extern void adc_configure_sequence(Adc *p_adc, adc_channel_num_t ch_list[], uint8_t uc_num); +#endif + +#if SAM3S || SAM3XA +/** + * \brief Configures ADC timing. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_tracking ADC tracking time = uc_tracking / ADC clock. + * \param uc_settling Analog settling time = (uc_settling + 1) / ADC clock. + * \param uc_transfer Data transfer time = (uc_transfer * 2 + 3) / ADC clock. + * + */ +extern void adc_configure_timing(Adc *p_adc, uint8_t uc_tracking, adc_settling_time_t settling, uint8_t uc_transfer); +#elif SAM3N +/** + * \brief Configures ADC timing. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_tracking ADC tracking time = uc_tracking / ADC clock. + * + */ +extern void adc_configure_timing(Adc *p_adc, uint8_t uc_tracking); + +#endif + +#if SAM3S || SAM3XA +/** + * \brief enable analog change. + * + * note it allows different analog settings for each channel, + * + * \param pAdc Pointer to an Adc instance. + */ +extern void adc_enable_anch( Adc *pAdc ); +#endif + +#if SAM3S || SAM3XA +/** + * \brief disable analog change. + * + * note DIFF0, GAIN0 and OFF0 are used for all channels. + * + * \param pAdc Pointer to an Adc instance. + */ +extern void adc_disable_anch( Adc *pAdc ); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Starts analog-to-digital conversion. + * + * \note If one of the hardware event is selected as ADC trigger, this function can NOT start analog to digital conversion. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_start(Adc *p_adc); +/** + * \brief Stop analog-to-digital conversion. + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_stop(Adc *p_adc); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + */ +extern void adc_enable_channel(Adc *p_adc, adc_channel_num_t adc_ch); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Disables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + */ +extern void adc_disable_channel(Adc *p_adc, adc_channel_num_t adc_ch); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads the ADC channel status. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval 1 means the specified channel is enabled. + * 0 means the specified channel is disabled. + */ +extern uint32_t adc_get_status(Adc *p_adc, adc_channel_num_t adc_ch); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads the ADC result data of the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval ADC data of the specified channel. + */ +extern uint32_t adc_get_value(Adc *p_adc, adc_channel_num_t adc_ch); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads the last ADC result data. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC data. + */ +extern uint32_t adc_get_latest_value(Adc *p_adc); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables TAG option so that the number of the last converted channel can be indicated. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_enable_tag(Adc *p_adc); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Disables TAG option. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_disable_tag(Adc *p_adc); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Indicates the last converted channel. + * + * \note If TAG option is NOT enabled before, an incorrect channel number is returned. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval The last converted channel number. + */ +extern adc_channel_num_t adc_get_tag(Adc *p_adc); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables conversion sequencer. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_start_sequencer(Adc *p_adc); + +/** + * \brief Disables conversion sequencer. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_stop_sequencer(Adc *p_adc); + +/** + * \brief Configures comparsion mode. + * + * \param p_adc Pointer to an ADC instance. + * \param mode ADC comparsion mode. + * + */ +extern void adc_set_comparison_mode(Adc *p_adc, uint8_t uc_mode); + +/** + * \brief get comparsion mode. + * + * \param p_adc Pointer to an ADC instance. + * \param mode ADC comparsion mode. + * + * \retval compare mode value. + */ +extern uint32_t adc_get_comparison_mode(Adc *p_adc); + +/** + * \brief Configures ADC compare window. + * + * \param p_adc Pointer to an ADC instance. + * \param w_low_threshold Low threshold of compare window. + * \param w_high_threshold High threshold of compare window. + * + */ +extern void adc_set_comparsion_window(Adc *p_adc, uint16_t us_low_threshold, uint16_t us_high_threshold); + +/** + * \brief Configures comparison selected channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Comparison selected channel. + * + */ +extern void adc_set_comparison_channel(Adc *p_adc, adc_channel_num_t channel); +#endif + +#if SAM3S || SAM3XA +/** + * \brief Enables differential input for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * + */ +extern void adc_enable_differential_input(Adc *p_adc, adc_channel_num_t channel); + +/** + * \brief Disables differential input for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * + */ +extern void adc_disable_differential_input(Adc *p_adc, adc_channel_num_t channel); + +/** + * \brief Enables analog signal offset for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * + */ +extern void adc_enable_input_offset(Adc *p_adc, adc_channel_num_t channel); + +/** + * \brief Disables analog signal offset for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * + */ +extern void adc_disable_input_offset(Adc *p_adc, adc_channel_num_t channel); + +/** + * \brief Configures input gain for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * \param gain Gain value for the input. + * + */ +extern void adc_set_input_gain(Adc *p_adc, adc_channel_num_t channel, adc_gainvalue_t uc_gain); +#endif + +#if SAM3S8 || SAM3SD8 +/** + * \brief set adc auto calibration mode. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_set_calibmode(Adc *p_adc); +#endif + + #if SAM3S || SAM3N || SAM3XA +/** + * \brief Returns the actual ADC clock. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_mck Main clock of the device (value in Hz). + * + * \retval 0 The actual ADC clock (value in Hz). + */ +extern uint32_t adc_get_actual_adc_clock(Adc *p_adc, uint32_t ul_mck); +#endif + + #if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be enabled. + * + */ +extern void adc_enable_interrupt(Adc *p_adc, uint32_t ul_source); + +/** + * \brief Disables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be disabled. + * + */ +extern void adc_disable_interrupt(Adc *p_adc, uint32_t ul_source); + +/** + * \brief Reads ADC interrupt status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC interrupt status. + */ +extern uint32_t adc_get_interrupt_status(Adc *p_adc); + +/** \brief Read ADC interrupt mask. + * + * \param p_uart pointer to a UART instance. + * + * \return The interrupt mask value. + */ +extern uint32_t adc_get_interrupt_mask(Adc *p_adc); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads overrun status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC overrun status. + */ +extern uint32_t adc_check_ovr(Adc *p_adc,adc_channel_num_t adc_ch); +#endif + +#if SAM3S || SAM3XA +/** + * \brief Adapts performance versus power consumption. + * + * \note Please refer to ADC Characteristics in the product datasheet for the details. + * + * \param p_adc Pointer to an ADC instance. + * \param ibctl ADC Bias current control. + * + */ +extern void adc_set_bias_current(Adc *p_adc, uint8_t uc_ibctl); +#endif + +#if SAM3S || SAM3XA +/** + * \brief turn on temperature sensor. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_enable_ts(Adc *p_adc); + +/** + * \brief turn off temperature sensor. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_disable_ts(Adc *p_adc); +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables or disables write protection of ADC registers. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_eanble 1 to eanble, 0 to disable. + */ +extern void adc_set_writeprotect(Adc *p_adc, uint32_t ul_enable); + +/** + * \brief Indicates write protect status. + * + * \param p_adc Pointer to an ADC instance. + * + * \return 0 if the peripheral is not protected, or 16-bit Write Protect Violation Status. + */ +extern uint32_t adc_get_writeprotect_status(Adc *p_adc); -#define ADC_EnableChannel( pAdc, channel ) {\ - assert( (channel) < 16 ) ;\ - (pAdc)->ADC_CHER = (1 << (channel));\ - } +/** + * \brief Checks ADC configurations. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_mck Main clock of the device (value in Hz). + */ +extern void adc_check(Adc* p_adc, uint32_t ul_mck); +#endif -#define ADC_DisableChannel(pAdc, channel) {\ - assert( (channel) < 16 ) ;\ - (pAdc)->ADC_CHDR = (1 << (channel));\ - } +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Gets PDC registers base address. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval PDC registers base for PDC driver to access. + */ +extern Pdc *adc_get_pdc_base(Adc *p_adc); +#endif -#define ADC_EnableIt(pAdc, dwMode) {\ - (pAdc)->ADC_IER = (dwMode);\ - } +#if SAM3U -#define ADC_DisableIt(pAdc, dwMode) {\ - (pAdc)->ADC_IDR = (dwMode);\ - } +#ifdef ADC_12B +/** + * \brief Initializes the given ADC with the specified ADC clock and startup time. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_mck Main clock of the device (value in Hz). + * \param dw_adc_clock Analog-to-Digital conversion clock (value in Hz). + * \param uc_startup ADC start up time value(value in us). Please refer to the product datasheet for details. + * \param ul_offmode_startuptime ADC off mode startup Time value(value in us). Please refer to the product datasheet for details. + * + * \retval 0 The initialization operation succeeds. + * \retval others The initialization operation fails. + */ +extern uint32_t adc_init(Adc12b *p_adc, uint32_t ul_mck, uint32_t ul_adc_clock, uint32_t ul_startuptime, uint32_t ul_offmode_startuptime); +/** + * \brief Configures conversion resolution. + * + * \param p_adc Pointer to an ADC instance. + * \param resolution ADC resolution. + */ +extern void adc_set_resolution(Adc12b *p_adc, adc_resolution_t resolution); +/** + * \brief Configures conversion trigger and free run mode. + * + * \param p_adc Pointer to an ADC instance. + * \param trigger Conversion trigger. + */ +extern void adc_configure_trigger(Adc12b *p_adc, adc_trigger_t trigger); +/** + * \brief Configures ADC power saving mode. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_sleep ADC_MR_SLEEP_NORMAL keeps the ADC Core and reference voltage circuitry ON between conversions + * ADC_MR_SLEEP_SLEEP keeps the ADC Core and reference voltage circuitry OFF between conversions + * \param uc_offmode 0 Standby Mode (if Sleep Bit = 1) + * 1 Off Mode + */ +extern void adc_configure_power_save(Adc12b *p_adc, uint8_t uc_sleep, uint8_t uc_offmode); +/** + * \brief Configures ADC timing. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_sh ADC sample and hold time = uc_sh / ADC clock. + */ +extern void adc_configure_timing(Adc12b *p_adc, uint32_t ul_sh); +/** + * \brief Starts analog-to-digital conversion. + * + * \note If one of the hardware event is selected as ADC trigger, this function can NOT start analog to digital conversion. + * + * \param p_adc Pointer to an ADC instance. + */ +extern void adc_start(Adc12b *p_adc); +/** + * \brief Stop analog-to-digital conversion. + * \param p_adc Pointer to an ADC instance. + */ +extern void adc_stop(Adc12b *p_adc); +/** + * \brief Enables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + */ +extern void adc_enable_channel(Adc12b *p_adc, adc_channel_num_t adc_ch); -#define ADC_EnableTS(pAdc,dwMode) {\ - (pAdc)->ADC_ACR |= (dwMode);\ - } +/** + * \brief Disables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + */ +extern void adc_disable_channel(Adc12b *p_adc, adc_channel_num_t adc_ch); -#define ADC_EnableDataReadyIt(pAdc) ((pAdc)->ADC_IER = AT91C_ADC_DRDY) +/** + * \brief Reads the ADC channel status. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval 1 means the specified channel is enabled. + * 0 means the specified channel is disabled. + */ +extern uint32_t adc_get_status(Adc12b *p_adc, adc_channel_num_t adc_ch); -#define ADC_GetStatus(pAdc) ((pAdc)->ADC_ISR) +/** + * \brief Reads the ADC result data of the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval ADC data of the specified channel. + */ +extern uint32_t adc_get_value(Adc12b *p_adc, adc_channel_num_t adc_ch); +/** + * \brief Reads the last ADC result data. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC data. + */ +extern uint32_t adc_get_latest_value(Adc12b *p_adc); -#define ADC_GetCompareMode(pAdc) (((pAdc)->ADC_EMR)& (ADC_EMR_CMPMODE_Msk)) +/** + * \brief Enables differential input for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + */ +extern void adc_enable_differential_input(Adc12b *p_adc); -#define ADC_GetChannelStatus(pAdc) ((pAdc)->ADC_CHSR) +/** + * \brief Disables differential input for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_disable_differential_input(Adc12b *p_adc); -#define ADC_GetInterruptMaskStatus(pAdc) ((pAdc)->ADC_IMR) +/** + * \brief Enables analog signal offset for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_enable_input_offset(Adc12b *p_adc); -#define ADC_GetLastConvertedData(pAdc) ((pAdc)->ADC_LCDR) +/** + * \brief Disables analog signal offset for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_disable_input_offset(Adc12b *p_adc); -/*------------------------------------------------------------------------------ - * Exported functions - *------------------------------------------------------------------------------*/ -extern void ADC_Initialize( Adc* pAdc, uint32_t idAdc ); -extern void ADC_CfgTiming( Adc* pAdc, uint32_t tracking, uint32_t settling, uint32_t transfer ); -extern void ADC_cfgFrequency( Adc* pAdc, uint32_t startup, uint32_t prescal ); -extern void ADC_CfgTrigering( Adc* pAdc, uint32_t trgEn, uint32_t trgSel, uint32_t freeRun ); -extern void ADC_CfgLowRes( Adc* pAdc, uint32_t resolution ); -extern void ADC_CfgPowerSave( Adc* pAdc, uint32_t sleep, uint32_t fwup ); -extern void ADC_CfgChannelMode( Adc* pAdc, uint32_t useq, uint32_t anach ); -extern void ADC_check( Adc* pAdc, uint32_t mck_freq ); +/** + * \brief Configures input gain for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param gain Gain value for the input. + * + */ +extern void adc_set_input_gain(Adc12b *p_adc, adc_gainvalue_t uc_gain); +/** + * \brief Returns the actual ADC clock. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_mck Main clock of the device (value in Hz). + * + * \retval 0 The actual ADC clock (value in Hz). + */ +extern uint32_t adc_get_actual_adc_clock(Adc12b *p_adc, uint32_t ul_mck); -extern uint32_t ADC_GetConvertedData( Adc* pAdc, uint32_t dwChannel ) ; -extern void ADC_SetCompareChannel( Adc* pAdc, uint32_t dwChannel ) ; -extern void ADC_SetCompareMode( Adc* pAdc, uint32_t dwMode ) ; -extern void ADC_SetComparisonWindow( Adc* pAdc, uint32_t dwHi_Lo ) ; -extern uint32_t ADC_IsInterruptMasked( Adc* pAdc, uint32_t dwFlag ) ; -extern uint32_t ADC_IsStatusSet( Adc* pAdc, uint32_t dwFlag ) ; -extern uint32_t ADC_IsChannelInterruptStatusSet( uint32_t adc_sr, uint32_t dwChannel ) ; -extern uint32_t ADC_ReadBuffer( Adc* pADC, int16_t *pwBuffer, uint32_t dwSize ) ; +/** + * \brief Enables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be enabled. + * + */ +extern void adc_enable_interrupt(Adc12b *p_adc, uint32_t ul_source); +/** + * \brief Disables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be disabled. + */ +extern void adc_disable_interrupt(Adc12b *p_adc, uint32_t ul_source); + +/** \brief Read ADC interrupt mask. + * + * \param p_uart pointer to a UART instance. + * + * \return The interrupt mask value. + */ +extern uint32_t adc_get_interrupt_mask(Adc12b *p_adc); +/** + * \brief Reads ADC interrupt status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC interrupt status. + */ +extern uint32_t adc_get_interrupt_status(Adc12b *p_adc); +/** + * \brief Reads overrun status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC overrun status. + */ +extern uint32_t adc_check_ovr(Adc12b *p_adc,adc_channel_num_t adc_ch); +/** + * \brief Adapts performance versus power consumption. + * + * \note Please refer to ADC Characteristics in the product datasheet for the details. + * + * \param p_adc Pointer to an ADC instance. + * \param ibctl ADC Bias current control. + * + */ +extern void adc_set_bias_current(Adc12b *p_adc, uint8_t uc_ibctl); +/** + * \brief Gets PDC registers base address. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval PDC registers base for PDC driver to access. + */ +extern Pdc *adc_get_pdc_base(Adc12b *p_adc); +#else +/** + * \brief Initializes the given ADC with the specified ADC clock and startup time. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_mck Main clock of the device (value in Hz). + * \param dw_adc_clock Analog-to-Digital conversion clock (value in Hz). + * \param uc_startup ADC start up time value(value in us). Please refer to the product datasheet for details. + * \param ul_offmode_startuptime ADC off mode startup Time value(value in us). Please refer to the product datasheet for details. + * + * \retval 0 The initialization operation succeeds. + * \retval others The initialization operation fails. + */ +extern uint32_t adc_init(Adc *p_adc, uint32_t ul_mck, uint32_t ul_adc_clock, uint32_t ul_startuptime, uint32_t ul_offmode_startuptime); + +/** + * \brief Configures conversion resolution. + * + * \param p_adc Pointer to an ADC instance. + * \param resolution ADC resolution. + * + */ +extern void adc_set_resolution(Adc *p_adc, adc_resolution_t resolution); +/** + * \brief Configures conversion trigger and free run mode. + * + * \param p_adc Pointer to an ADC instance. + * \param trigger Conversion trigger. + * + */ +extern void adc_configure_trigger(Adc *p_adc, adc_trigger_t trigger); +/** + * \brief Configures ADC power saving mode. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_sleep ADC_MR_SLEEP_NORMAL keeps the ADC Core and reference voltage circuitry ON between conversions + * ADC_MR_SLEEP_SLEEP keeps the ADC Core and reference voltage circuitry OFF between conversions + * \param uc_offmode 0 Standby Mode (if Sleep Bit = 1) + * 1 Off Mode + * + */ +extern void adc_configure_power_save(Adc *p_adc, uint8_t uc_sleep, uint8_t uc_offmode); +/** + * \brief Configures ADC timing. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_sh ADC sample and hold time = uc_sh / ADC clock. + * + */ +extern void adc_configure_timing(Adc *p_adc, uint32_t ul_sh); +/** + * \brief enable analog change. + * + * note it allows different analog settings for each channel, + * + * \param pAdc Pointer to an Adc instance. + */ +extern void adc_enable_anch( Adc *pAdc ); + +/** + * \brief disable analog change. + * + * note DIFF0, GAIN0 and OFF0 are used for all channels. + * + * \param pAdc Pointer to an Adc instance. + */ +extern void adc_disable_anch( Adc *pAdc ); + +/** + * \brief Starts analog-to-digital conversion. + * + * \note If one of the hardware event is selected as ADC trigger, this function can NOT start analog to digital conversion. + * + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_start(Adc *p_adc); +/** + * \brief Stop analog-to-digital conversion. + * \param p_adc Pointer to an ADC instance. + * + */ +extern void adc_stop(Adc *p_adc); +/** + * \brief Enables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + */ +extern void adc_enable_channel(Adc *p_adc, adc_channel_num_t adc_ch); + +/** + * \brief Disables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + */ +extern void adc_disable_channel(Adc *p_adc, adc_channel_num_t adc_ch); + +/** + * \brief Reads the ADC channel status. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval 1 means the specified channel is enabled. + * 0 means the specified channel is disabled. + */ +extern uint32_t adc_get_status(Adc *p_adc, adc_channel_num_t adc_ch); + +/** + * \brief Reads the ADC result data of the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval ADC data of the specified channel. + */ +extern uint32_t adc_get_value(Adc *p_adc, adc_channel_num_t adc_ch); + +/** + * \brief Reads the last ADC result data. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC data. + */ +extern uint32_t adc_get_latest_value(Adc *p_adc); + +/** + * \brief Returns the actual ADC clock. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_mck Main clock of the device (value in Hz). + * + * \retval 0 The actual ADC clock (value in Hz). + */ +extern uint32_t adc_get_actual_adc_clock(Adc *p_adc, uint32_t ul_mck); + +/** + * \brief Enables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be enabled. + * + */ +extern void adc_enable_interrupt(Adc *p_adc, uint32_t ul_source); + +/** + * \brief Disables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be disabled. + * + */ +extern void adc_disable_interrupt(Adc *p_adc, uint32_t ul_source); +/** \brief Read ADC interrupt mask. + * + * \param p_uart pointer to a UART instance. + * + * \return The interrupt mask value. + */ +extern uint32_t adc_get_interrupt_mask(Adc *p_adc); +/** + * \brief Reads ADC interrupt status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC interrupt status. + */ +extern uint32_t adc_get_interrupt_status(Adc *p_adc); + +/** + * \brief Reads overrun status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC overrun status. + */ +extern uint32_t adc_check_ovr(Adc *p_adc,adc_channel_num_t adc_ch); + +/** + * \brief Gets PDC registers base address. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval PDC registers base for PDC driver to access. + */ +extern Pdc *adc_get_pdc_base(Adc *p_adc); +#endif + +#endif + +/// @cond 0 +/**INDENT-OFF**/ #ifdef __cplusplus } #endif +/**INDENT-ON**/ +/// @endcond -#endif /* #ifndef _ADC_ */ +#endif /* #ifndef ADC_H_INCLUDED */ diff --git a/hardware/sam/system/libsam/include/sam.h b/hardware/sam/system/libsam/include/sam.h new file mode 100644 index 000000000..429bb71b7 --- /dev/null +++ b/hardware/sam/system/libsam/include/sam.h @@ -0,0 +1,137 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: 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 + * 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. + * ---------------------------------------------------------------------------- + */ + +#ifndef _SAM_DEFS_ +#define _SAM_DEFS_ + +#define part_is_defined(part) (defined(__ ## part ## __)) + +/* SAM3 family */ + +/* SAM3S series */ +#define SAM3S1 ( \ + part_is_defined( SAM3S1A ) || \ + part_is_defined( SAM3S1B ) || \ + part_is_defined( SAM3S1C ) ) + +#define SAM3S2 ( \ + part_is_defined( SAM3S2A ) || \ + part_is_defined( SAM3S2B ) || \ + part_is_defined( SAM3S2C ) ) + +#define SAM3S4 ( \ + part_is_defined( SAM3S4A ) || \ + part_is_defined( SAM3S4B ) || \ + part_is_defined( SAM3S4C ) ) + +#define SAM3S8 ( \ + part_is_defined( SAM3S8B ) || \ + part_is_defined( SAM3S8C ) ) + +#define SAM3SD8 ( \ + part_is_defined( SAM3SD8B ) || \ + part_is_defined( SAM3SD8C ) ) + +#define SAM3U1 ( \ + part_is_defined( SAM3U1C ) || \ + part_is_defined( SAM3U1E ) ) + +#define SAM3U2 ( \ + part_is_defined( SAM3U2C ) || \ + part_is_defined( SAM3U2E ) ) + +#define SAM3U4 ( \ + part_is_defined( SAM3U4C ) || \ + part_is_defined( SAM3U4E ) ) + +#define SAM3N1 ( \ + part_is_defined( SAM3N1A ) || \ + part_is_defined( SAM3N1B ) || \ + part_is_defined( SAM3N1C ) ) + +#define SAM3N2 ( \ + part_is_defined( SAM3N2A ) || \ + part_is_defined( SAM3N2B ) || \ + part_is_defined( SAM3N2C ) ) + +#define SAM3N4 ( \ + part_is_defined( SAM3N4A ) || \ + part_is_defined( SAM3N4B ) || \ + part_is_defined( SAM3N4C ) ) + +#define SAM3X2 ( \ + part_is_defined( SAM3X2C ) || \ + part_is_defined( SAM3X2E ) || \ + part_is_defined( SAM3X2G ) || \ + part_is_defined( SAM3X2H ) ) + +#define SAM3X4 ( \ + part_is_defined( SAM3X4C ) || \ + part_is_defined( SAM3X4E ) || \ + part_is_defined( SAM3X4G ) || \ + part_is_defined( SAM3X4H ) ) + +#define SAM3X8 ( \ + part_is_defined( SAM3X8C ) || \ + part_is_defined( SAM3X8E ) || \ + part_is_defined( SAM3X8G ) || \ + part_is_defined( SAM3X8H ) ) + +#define SAM3A2 ( \ + part_is_defined( SAM3A2C ) ) + +#define SAM3A4 ( \ + part_is_defined( SAM3A4C ) ) + +#define SAM3A8 ( \ + part_is_defined( SAM3A8C ) ) + +/* Entire SAM3S Family */ +#define SAM3S (SAM3S1 || SAM3S2 || SAM3S4 || SAM3S8 || SAM3SD8) + +/* Entire SAM3U Family */ +#define SAM3U (SAM3U1 || SAM3U2 || SAM3U4) + +/* Entire SAM3N Family */ +#define SAM3N (SAM3N1 || SAM3N2 || SAM3N4) + +/* Entire SAM3XA Family */ +#define SAM3XA (SAM3X2 || SAM3X4 || SAM3X8 || SAM3A2 || SAM3A4 || SAM3A8) + +/* SAM9 family */ + +/* SAM7 family */ + + +/* Global SAM product line */ +#define SAM ( SAM3S || SAM3U || SAM3N || SAM3XA ) + +#include "include/sam3.h" + +#endif /* _SAM_DEFS_ */ diff --git a/hardware/sam/system/libsam/source/adc.c b/hardware/sam/system/libsam/source/adc.c new file mode 100644 index 000000000..f21f1d7b0 --- /dev/null +++ b/hardware/sam/system/libsam/source/adc.c @@ -0,0 +1,849 @@ +/*! \file ********************************************************************* + * + * \brief API for SAM3 Analog-to-Digital Converter (ADC/ADC12B) controller. + * + * ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: 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 + * 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. + * + * - Compiler: IAR EWARM and CodeSourcery GCC for ARM + * - Supported devices: All SAM devices with a Analog-to-Digital Converter can be used. + * - AppNote: + * + * \author Atmel Corporation: http://www.atmel.com \n + * Support and FAQ: http://support.atmel.com/ + * + *******************************************************************************/ + +#include "adc.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Initializes the given ADC with the specified ADC clock and startup time. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_mck Main clock of the device (value in Hz). + * \param dw_adc_clock Analog-to-Digital conversion clock (value in Hz). + * \param uc_startup ADC start up time. Please refer to the product datasheet for details. + * + * \retval 0 The initialization operation succeeds. + * \retval others The initialization operation fails. + */ +uint32_t adc_init(Adc *p_adc, uint32_t ul_mck, uint32_t ul_adc_clock, uint8_t uc_startup) +{ + uint32_t ul_prescal; + + /* Reset the controller */ + p_adc->ADC_CR = ADC_CR_SWRST; + + /* Reset Mode Register */ + p_adc->ADC_MR = 0; + + /* Reset PDC transfer */ + p_adc->ADC_PTCR = (ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS); + p_adc->ADC_RCR = 0; + p_adc->ADC_RNCR = 0; + p_adc->ADC_TCR = 0; + p_adc->ADC_TNCR = 0; + + ul_prescal = ul_mck/(2 * ul_adc_clock) - 1; + p_adc->ADC_MR |= ADC_MR_PRESCAL( ul_prescal ) | ( (uc_startup<ADC_MR |= (resolution<<4) & ADC_MR_LOWRES; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures conversion trigger and free run mode. + * + * \param p_adc Pointer to an ADC instance. + * \param trigger Conversion trigger. + * \param uc_freerun ADC_MR_FREERUN_ON enables freerun mode + * ADC_MR_FREERUN_OFF disables freerun mode + * + */ +void adc_configure_trigger(Adc *p_adc, adc_trigger_t trigger, uint8_t uc_freerun) +{ + p_adc->ADC_MR |= trigger | ((uc_freerun<<7) & ADC_MR_FREERUN); +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures ADC power saving mode. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_sleep ADC_MR_SLEEP_NORMAL keeps the ADC Core and reference voltage circuitry ON between conversions + * ADC_MR_SLEEP_SLEEP keeps the ADC Core and reference voltage circuitry OFF between conversions + * \param uc_fwup ADC_MR_FWUP_OFF configures sleep mode as uc_sleep setting + * ADC_MR_FWUP_ON keeps voltage reference ON and ADC Core OFF between conversions + * + */ +void adc_configure_power_save(Adc *p_adc, uint8_t uc_sleep, uint8_t uc_fwup) +{ + p_adc->ADC_MR |= ( ((uc_sleep<<5) & ADC_MR_SLEEP) | ((uc_fwup<<6) & ADC_MR_FWUP) ); +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures conversion sequence. + * + * \param p_adc Pointer to an ADC instance. + * \param ch_list Channel sequence list. + * \param number Number of channels in the list. + * + */ +void adc_configure_sequence(Adc *p_adc, adc_channel_num_t ch_list[], uint8_t uc_num) +{ + uint8_t uc_counter; + if(uc_num < 8) + { + for(uc_counter=0;uc_counter < uc_num;uc_counter++) + { + p_adc->ADC_SEQR1 |= ch_list[uc_counter] << (4*uc_counter); + } + } + else + { + for(uc_counter=0;uc_counter < 8;uc_counter++) + { + p_adc->ADC_SEQR1 |= ch_list[uc_counter] << (4*uc_counter); + } + for(uc_counter=0;uc_counter < uc_num-8;uc_counter++) + { + p_adc->ADC_SEQR2 |= ch_list[uc_counter] << (4*uc_counter); + } + } +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief Configures ADC timing. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_tracking ADC tracking time = uc_tracking / ADC clock. + * \param uc_settling Analog settling time = (uc_settling + 1) / ADC clock. + * \param uc_transfer Data transfer time = (uc_transfer * 2 + 3) / ADC clock. + * + */ +void adc_configure_timing(Adc *p_adc, uint8_t uc_tracking, adc_settling_time_t settling, uint8_t uc_transfer) +{ + p_adc->ADC_MR |= ADC_MR_TRANSFER( uc_transfer ) + | settling + | ADC_MR_TRACKTIM( uc_tracking ) ; +} +#elif SAM3N +/** + * \brief Configures ADC timing. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_tracking ADC tracking time = uc_tracking / ADC clock. + * + */ +void adc_configure_timing(Adc *p_adc, uint8_t uc_tracking) +{ + p_adc->ADC_MR |= ADC_MR_TRACKTIM( uc_tracking ) ; +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief enable analog change. + * + * note it allows different analog settings for each channel, + * + * \param pAdc Pointer to an Adc instance. + */ +void adc_enable_anch( Adc *pAdc ) +{ + pAdc->ADC_MR |= ADC_MR_ANACH; +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief disable analog change. + * + * note DIFF0, GAIN0 and OFF0 are used for all channels. + * + * \param pAdc Pointer to an Adc instance. + */ +void adc_disable_anch( Adc *pAdc ) +{ + pAdc->ADC_MR &= ~ADC_MR_ANACH; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Starts analog-to-digital conversion. + * + * \note If one of the hardware event is selected as ADC trigger, this function can NOT start analog to digital conversion. + * + * \param p_adc Pointer to an ADC instance. + * + */ + +void adc_start(Adc *p_adc) +{ + p_adc->ADC_CR = ADC_CR_START; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Stop analog-to-digital conversion. + * \param p_adc Pointer to an ADC instance. + * + */ +void adc_stop(Adc *p_adc) +{ + p_adc->ADC_CR = ADC_CR_SWRST; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + */ +void adc_enable_channel(Adc *p_adc, adc_channel_num_t adc_ch) +{ + p_adc->ADC_CHER = 1 << adc_ch; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Disables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + */ +void adc_disable_channel(Adc *p_adc, adc_channel_num_t adc_ch) +{ + p_adc->ADC_CHDR = 1 << adc_ch; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads the ADC channel status. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval 1 means the specified channel is enabled. + * 0 means the specified channel is disabled. + */ +uint32_t adc_get_status(Adc *p_adc, adc_channel_num_t adc_ch) +{ + return p_adc->ADC_CHSR & (1 << adc_ch); +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads the ADC result data of the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval ADC data of the specified channel. + */ +uint32_t adc_get_value(Adc *p_adc, adc_channel_num_t adc_ch) +{ + uint32_t dwData = 0; + + if ( 15 >= adc_ch ) + { + dwData=*(p_adc->ADC_CDR+adc_ch) ; + } + + return dwData ; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads the last ADC result data. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC data. + */ +uint32_t adc_get_latest_value(Adc *p_adc) +{ + return p_adc->ADC_LCDR; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables TAG option so that the number of the last converted channel can be indicated. + * + * \param p_adc Pointer to an ADC instance. + * + */ +void adc_enable_tag(Adc *p_adc) +{ + p_adc->ADC_EMR |= ADC_EMR_TAG; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Disables TAG option. + * + * \param p_adc Pointer to an ADC instance. + * + */ +void adc_disable_tag(Adc *p_adc) +{ + p_adc->ADC_EMR &= ~ADC_EMR_TAG; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Indicates the last converted channel. + * + * \note If TAG option is NOT enabled before, an incorrect channel number is returned. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval The last converted channel number. + */ +adc_channel_num_t adc_get_tag(Adc *p_adc) +{ + return (p_adc->ADC_LCDR & ADC_LCDR_CHNB_Msk) >> ADC_LCDR_CHNB_Pos; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables conversion sequencer. + * + * \param p_adc Pointer to an ADC instance. + * + */ +void adc_start_sequencer(Adc *p_adc) +{ + p_adc->ADC_MR |= ADC_MR_USEQ; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Disables conversion sequencer. + * + * \param p_adc Pointer to an ADC instance. + * + */ +void adc_stop_sequencer(Adc *p_adc) +{ + p_adc->ADC_MR &= ~ADC_MR_USEQ; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures comparsion mode. + * + * \param p_adc Pointer to an ADC instance. + * \param mode ADC comparsion mode. + * + */ +void adc_set_comparison_mode(Adc *p_adc, uint8_t uc_mode) +{ + p_adc->ADC_EMR &= (uint32_t)~(ADC_EMR_CMPMODE_Msk); + p_adc->ADC_EMR |= (uc_mode & ADC_EMR_CMPMODE_Msk); +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief get comparsion mode. + * + * \param p_adc Pointer to an ADC instance. + * \param mode ADC comparsion mode. + * + * \retval compare mode value. + */ +uint32_t adc_get_comparison_mode(Adc *p_adc) +{ + return p_adc->ADC_EMR & ADC_EMR_CMPMODE_Msk; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures ADC compare window. + * + * \param p_adc Pointer to an ADC instance. + * \param w_low_threshold Low threshold of compare window. + * \param w_high_threshold High threshold of compare window. + * + */ +void adc_set_comparsion_window(Adc *p_adc, uint16_t us_low_threshold, uint16_t us_high_threshold) +{ + p_adc->ADC_CWR = ADC_CWR_LOWTHRES(us_low_threshold) | ADC_CWR_HIGHTHRES(us_high_threshold); +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Configures comparison selected channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Comparison selected channel. + * + */ +void adc_set_comparison_channel(Adc *p_adc, adc_channel_num_t channel) +{ + if ( channel < 16 ) + { + p_adc->ADC_EMR &= (uint32_t)~(ADC_EMR_CMPALL); + p_adc->ADC_EMR &= (uint32_t)~(ADC_EMR_CMPSEL_Msk); + p_adc->ADC_EMR |= (channel << ADC_EMR_CMPSEL_Pos); + } + else + { + p_adc->ADC_EMR |= ADC_EMR_CMPALL; + } +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief Enables differential input for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * + */ + void adc_enable_differential_input(Adc *p_adc, adc_channel_num_t channel) +{ + p_adc->ADC_COR |= 0x01u << (16+ channel); +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief Disables differential input for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * + */ +void adc_disable_differential_input(Adc *p_adc, adc_channel_num_t channel) +{ + uint32_t ul_temp; + ul_temp = p_adc->ADC_COR; + p_adc->ADC_COR &= 0xfffeffffu << channel; + p_adc->ADC_COR |= ul_temp; +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief Enables analog signal offset for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * + */ +void adc_enable_input_offset(Adc *p_adc, adc_channel_num_t channel) +{ + p_adc->ADC_COR |= 0x01u << channel; +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief Disables analog signal offset for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * + */ +void adc_disable_input_offset(Adc *p_adc, adc_channel_num_t channel) +{ + uint32_t ul_temp; + ul_temp = p_adc->ADC_COR; + p_adc->ADC_COR &= (0xfffffffeu << channel); + p_adc->ADC_COR |= ul_temp; +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief Configures input gain for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param channel Channel number. + * \param gain Gain value for the input. + * + */ +void adc_set_input_gain(Adc *p_adc, adc_channel_num_t channel, adc_gainvalue_t gain) +{ + p_adc->ADC_CGR |= (0x03u << (2*channel)) & (gain << (2*channel)); +} +#endif + +#if SAM3S8 || SAM3SD8 +/** + * \brief set adc auto calibration mode. + * + * \param p_adc Pointer to an ADC instance. + * + */ +void adc_set_calibmode(Adc *p_adc) +{ + p_adc->ADC_CR |= ADC_CR_AUTOCAL; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Returns the actual ADC clock. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_mck Main clock of the device (value in Hz). + * + * \retval 0 The actual ADC clock (value in Hz). + */ +uint32_t adc_get_actual_adc_clock(Adc *p_adc, uint32_t ul_mck) +{ + uint32_t ul_adcfreq; + uint32_t ul_prescal; + + /* ADCClock = MCK / ( (PRESCAL+1) * 2 ) */ + ul_prescal = (( p_adc->ADC_MR & ADC_MR_PRESCAL_Msk) >> ADC_MR_PRESCAL_Pos); + ul_adcfreq = ul_mck / ((ul_prescal+1)*2); + return ul_adcfreq; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be enabled. + * + */ +void adc_enable_interrupt(Adc *p_adc, uint32_t ul_source) +{ + p_adc->ADC_IER = ul_source; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Disables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be disabled. + * + */ +void adc_disable_interrupt(Adc *p_adc, uint32_t ul_source) +{ + p_adc->ADC_IDR = ul_source; +} + +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads ADC interrupt status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC interrupt status. + */ +uint32_t adc_get_interrupt_status(Adc *p_adc) +{ + return p_adc->ADC_ISR ; +} + +#endif + +#if SAM3S || SAM3N || SAM3XA +/** \brief Read ADC interrupt mask. + * + * \param p_uart pointer to a UART instance. + * + * \return The interrupt mask value. + */ +uint32_t adc_get_interrupt_mask(Adc *p_adc) +{ + return p_adc->ADC_IMR; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Reads overrun status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC overrun status. + */ +uint32_t adc_check_ovr(Adc *p_adc,adc_channel_num_t adc_ch) +{ + return p_adc->ADC_OVER & (0x01u << adc_ch); +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief Adapts performance versus power consumption. + * + * \note Please refer to ADC Characteristics in the product datasheet for the details. + * + * \param p_adc Pointer to an ADC instance. + * \param ibctl ADC Bias current control. + * + */ +void adc_set_bias_current(Adc *p_adc, uint8_t uc_ibctl) +{ + p_adc->ADC_ACR |= ADC_ACR_IBCTL(uc_ibctl); +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief turn on temperature sensor. + * + * \param p_adc Pointer to an ADC instance. + * + */ +void adc_enable_ts(Adc *p_adc) +{ + p_adc->ADC_ACR |= ADC_ACR_TSON; +} +#endif + +#if SAM3S || SAM3XA +/** + * \brief turn off temperature sensor. + * + * \param p_adc Pointer to an ADC instance. + * + */ +void adc_disable_ts(Adc *p_adc) +{ + p_adc->ADC_ACR &= ~ADC_ACR_TSON; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Enables or disables write protection of ADC registers. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_eanble 1 to eanble, 0 to disable. + */ +void adc_set_writeprotect(Adc *p_adc, uint32_t ul_enable) +{ + p_adc->ADC_WPMR |= ADC_WPMR_WPKEY(ul_enable); +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief Indicates write protect status. + * + * \param p_adc Pointer to an ADC instance. + * + * \return 0 if the peripheral is not protected, or 16-bit Write Protect Violation Status. + */ +uint32_t adc_get_writeprotect_status(Adc *p_adc) +{ + return p_adc->ADC_WPSR & ADC_WPSR_WPVS; +} +#endif + +#if SAM3S || SAM3N || SAM3XA +/** + * \brief calcul_startup + */ +static uint32_t calcul_startup( uint32_t ul_startup ) +{ + uint32_t ul_startup_value=0; + + if( ul_startup == 0 ) + ul_startup_value = 0; + else if( ul_startup == 1 ) + ul_startup_value = 8; + else if( ul_startup == 2 ) + ul_startup_value = 16; + else if( ul_startup == 3 ) + ul_startup_value = 24; + else if( ul_startup == 4 ) + ul_startup_value = 64; + else if( ul_startup == 5 ) + ul_startup_value = 80; + else if( ul_startup == 6 ) + ul_startup_value = 96; + else if( ul_startup == 7 ) + ul_startup_value = 112; + else if( ul_startup == 8 ) + ul_startup_value = 512; + else if( ul_startup == 9 ) + ul_startup_value = 576; + else if( ul_startup == 10 ) + ul_startup_value = 640; + else if( ul_startup == 11 ) + ul_startup_value = 704; + else if( ul_startup == 12 ) + ul_startup_value = 768; + else if( ul_startup == 13 ) + ul_startup_value = 832; + else if( ul_startup == 14 ) + ul_startup_value = 896; + else if( ul_startup == 15 ) + ul_startup_value = 960; + + return ul_startup_value; +} + +/** + * \brief Checks ADC configurations. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_mck Main clock of the device (value in Hz). + */ +void adc_check(Adc* p_adc, uint32_t ul_mck) +{ + uint32_t ul_adcfreq; + uint32_t ul_prescal; + uint32_t ul_startup; + + /* ADCClock = MCK / ( (PRESCAL+1) * 2 ) */ + ul_prescal = (( p_adc->ADC_MR & ADC_MR_PRESCAL_Msk) >> ADC_MR_PRESCAL_Pos); + ul_adcfreq = ul_mck / ((ul_prescal+1)*2); + printf("ADC clock frequency = %d Hz\r\n", (int)ul_adcfreq ); + + if( ul_adcfreq < ADC_FREQ_MIN ) + { + printf("adc frequency too low (out of specification: %d Hz)\r\n", (int)ADC_FREQ_MIN); + } + if( ul_adcfreq > ADC_FREQ_MAX ) + { + printf("adc frequency too high (out of specification: %d Hz)\r\n", (int)ADC_FREQ_MAX); + } + + ul_startup = (( p_adc->ADC_MR & ADC_MR_STARTUP_Msk) >> ADC_MR_STARTUP_Pos); + if( !(p_adc->ADC_MR & ADC_MR_SLEEP_SLEEP) ) + { + /* 40µs */ + if( ADC_STARTUP_NORM * ul_adcfreq / 1000000 > calcul_startup(ul_startup) ) + { + printf("Startup time too small: %d, programmed: %d\r\n", (int)(ADC_STARTUP_NORM * ul_adcfreq / 1000000), (int)calcul_startup(ul_startup)); + } + } + else + { + if(p_adc->ADC_MR & ADC_MR_FREERUN_ON) + { + printf("FreeRun forbidden in sleep mode\n\r"); + } + if( !(p_adc->ADC_MR & ADC_MR_FWUP_ON) ) + { + /* Sleep 40µs */ + if( ADC_STARTUP_NORM * ul_adcfreq / 1000000 > calcul_startup(ul_startup) ) + { + printf("Startup time too small: %d, programmed: %d\r\n", (int)(ADC_STARTUP_NORM * ul_adcfreq / 1000000), (int)(calcul_startup(ul_startup))); + } + } + else + { + if( p_adc->ADC_MR & ADC_MR_FWUP_ON ) + { + /* Fast Wake Up Sleep Mode: 12µs */ + if( ADC_STARTUP_FAST * ul_adcfreq / 1000000 > calcul_startup(ul_startup) ) + { + printf("Startup time too small: %d, programmed: %d\r\n", (int)(ADC_STARTUP_NORM * ul_adcfreq / 1000000), (int)(calcul_startup(ul_startup))); + } + } + } + } +} +#endif + +/** + * \brief Gets PDC registers base address. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval PDC registers base for PDC driver to access. + */ +#if SAM3S || SAM3N || SAM3XA +Pdc *adc_get_pdc_base(Adc *p_adc) +{ + return PDC_ADC; +} +#endif +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond + +//#endif /* #ifndef _SAM_ADC_ */ + diff --git a/hardware/sam/system/libsam/source/adc.c.disabled b/hardware/sam/system/libsam/source/adc.c.disabled deleted file mode 100644 index 7e48f0b27..000000000 --- a/hardware/sam/system/libsam/source/adc.c.disabled +++ /dev/null @@ -1,295 +0,0 @@ -/* - %atmel_license% -*/ - -/** \addtogroup adc_module Working with ADC - * The ADC driver provides the interface to configure and use the ADC peripheral. - * \n - * - * It converts the analog input to digital format. The converted result could be - * 12bit or 10bit. The ADC supports up to 16 analog lines. - * - * To Enable a ADC conversion,the user has to follow these few steps: - *
    - *
  • Select an appropriate reference voltage on ADVREF
  • - *
  • Configure the ADC according to its requirements and special needs,which - * could be broken down into several parts: - * -# Select the resolution by setting or clearing ADC_MR_LOWRES bit in - * ADC_MR (Mode Register) - * -# Set ADC clock by setting ADC_MR_PRESCAL bits in ADC_MR, the clock is - * calculated with ADCClock = MCK / ( (PRESCAL+1) * 2 ) - * -# Set Startup Time,Tracking Clock cycles and Transfer Clock respectively - * in ADC_MR. -
  • - *
  • Start conversion by setting ADC_CR_START in ADC_CR.
  • - *
- * - * For more accurate information, please look at the ADC section of the - * Datasheet. - * - * Related files :\n - * \ref adc.c\n - * \ref adc.h\n - */ -/*@{*/ -/*@}*/ -/** - * \file - * - * Implementation of Analog-to-Digital Converter (ADC). - * - */ -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "chip.h" - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Initialize the ADC controller - * - * \param pAdc Pointer to an Adc instance. - * \param idAdc ADC Index - * \param trgEn trigger mode, software or Hardware - * \param trgSel hardware trigger selection - * \param sleepMode sleep mode selection - * \param resolution resolution selection 10 bits or 12 bits - * \param mckClock value of MCK in Hz - * \param adcClock value of the ADC clock in Hz - * \param startup value of the start up time (in ADCClock) (see datasheet) - * \param tracking Tracking Time (in ADCClock cycle) - */ -extern void ADC_Initialize( Adc* pAdc, uint32_t idAdc ) -{ - /* Enable peripheral clock*/ - PMC_EnablePeripheral( idAdc ) ; - - /* Reset the controller */ - pAdc->ADC_CR = ADC_CR_SWRST; - - /* Reset Mode Register set to default */ - /* TrackTime set to 0 */ - /* Transfer set to 1 */ - /* settling set to 3 */ - pAdc->ADC_MR = ADC_MR_TRANSFER(1) | ADC_MR_TRACKTIM(0) | ADC_MR_SETTLING_AST17 ; -} - -/** - * \brief Initialize the ADC Timing - */ -extern void ADC_CfgTiming( Adc* pAdc, uint32_t tracking, uint32_t settling, uint32_t transfer ) -{ - pAdc->ADC_MR = ADC_MR_TRANSFER( transfer ) - | settling - | ADC_MR_TRACKTIM( tracking ) ; -} - -/** - * \brief Initialize the ADC Timing - */ -extern void ADC_cfgFrequency( Adc* pAdc, uint32_t startup, uint32_t prescal ) -{ - pAdc->ADC_MR |= ADC_MR_PRESCAL( prescal ) - | ( (startup<ADC_MR |= ((trgEn<<0) & ADC_MR_TRGEN) - | ((trgSel<ADC_MR |= (resolution<<4) & ADC_MR_LOWRES; -} - -/** - * \brief Initialize the ADC PowerSave - */ -extern void ADC_CfgPowerSave( Adc* pAdc, uint32_t sleep, uint32_t fwup ) -{ - pAdc->ADC_MR |= ( ((sleep<<5) & ADC_MR_SLEEP) - | ((fwup<<6) & ADC_MR_FWUP) ); -} - -/** - * \brief Initialize the ADC Channel Mode - */ -extern void ADC_CfgChannelMode( Adc* pAdc, uint32_t useq, uint32_t anach ) -{ - pAdc->ADC_MR |= ( ((anach<<23) & ADC_MR_ANACH) - | ((useq <<31) & (uint32_t)ADC_MR_USEQ) ); -} - - -/** - * \brief calcul_startup - */ -static uint32_t calcul_startup( uint32_t dwStartup ) -{ - static uint32_t adwValue[16]={ 0, 8, 16, 24, 64, 80, 96, 112, 512, 576, 640, 704, 768, 832, 896, 960 } ; - - assert( dwStartup < sizeof( adwValue )/sizeof( adwValue[0] ) ) ; - - return adwValue[dwStartup] ; -} - -/** - * Return the Channel Converted Data - * - * \param pAdc Pointer to an Adc instance. - * \param channel channel to get converted value - */ -extern uint32_t ADC_GetConvertedData( Adc* pAdc, uint32_t dwChannel ) -{ - uint32_t dwData = 0; - - assert( dwChannel < 16 ) ; - - if ( 15 >= dwChannel ) - { - dwData=*(pAdc->ADC_CDR+dwChannel) ; - } - - return dwData ; -} -/** - * Set compare channel - * - * \param pAdc Pointer to an Adc instance. - * \param channel channel number to be set,16 for all channels - */ -extern void ADC_SetCompareChannel( Adc* pAdc, uint32_t dwChannel ) -{ - assert( dwChannel <= 16 ) ; - - if ( dwChannel < 16 ) - { - pAdc->ADC_EMR &= (uint32_t)~(ADC_EMR_CMPALL); - pAdc->ADC_EMR &= (uint32_t)~(ADC_EMR_CMPSEL_Msk); - pAdc->ADC_EMR |= (dwChannel << ADC_EMR_CMPSEL_Pos); - } - else - { - pAdc->ADC_EMR |= ADC_EMR_CMPALL; - } -} -/** - * Set compare mode - * - * \param pAdc Pointer to an Adc instance. - * \param mode compare mode - */ -extern void ADC_SetCompareMode( Adc* pAdc, uint32_t dwMode ) -{ - pAdc->ADC_EMR &= (uint32_t)~(ADC_EMR_CMPMODE_Msk); - pAdc->ADC_EMR |= (dwMode & ADC_EMR_CMPMODE_Msk) ; -} -/** - * Set comparison window, one threshold each time - * - * \param pAdc Pointer to an Adc instance. - * \param hi_lo Comparison Window - */ -extern void ADC_SetComparisonWindow( Adc* pAdc, uint32_t dwHi_Lo ) -{ - pAdc->ADC_CWR = dwHi_Lo ; -} - -/**---------------------------------------------------------------------------- - * Test if ADC Interrupt is Masked - * - * \param pAdc Pointer to an Adc instance. - * \param flag flag to be tested - * - * \return 1 if interrupt is masked, otherwise 0 - */ -uint32_t ADC_IsInterruptMasked( Adc* pAdc, uint32_t dwFlag ) -{ - return (ADC_GetInterruptMaskStatus( pAdc ) & dwFlag) ; -} - -/**---------------------------------------------------------------------------- - * Test if ADC Status is Set - * - * \param pAdc Pointer to an Adc instance. - * \param flag flag to be tested - * - * \return 1 if the staus is set; 0 otherwise - */ -extern uint32_t ADC_IsStatusSet( Adc* pAdc, uint32_t dwFlag ) -{ - return (ADC_GetStatus( pAdc ) & dwFlag) ; -} - -/**---------------------------------------------------------------------------- - * Test if ADC channel interrupt Status is Set - * - * \param adc_sr Value of SR register - * \param channel Channel to be tested - * - * \return 1 if interrupt status is set, otherwise 0 - */ -extern uint32_t ADC_IsChannelInterruptStatusSet( uint32_t dwAdc_sr, uint32_t dwChannel ) -{ - uint32_t dwStatus ; - - if ( (dwAdc_sr & ((uint32_t)1 << dwChannel)) == ((uint32_t)1 << dwChannel) ) - { - dwStatus = 1 ; - } - else - { - dwStatus = 0 ; - } - - return dwStatus ; -} - -/** - * \brief Read converted data through PDC channel - * - * \param pADC the pointer of adc peripheral - * \param pBuffer the destination buffer - * \param dwSize the size of the buffer - */ -extern uint32_t ADC_ReadBuffer( Adc* pADC, int16_t *pwBuffer, uint32_t dwSize ) -{ - /* Check if the first PDC bank is free*/ - if ( (pADC->ADC_RCR == 0) && (pADC->ADC_RNCR == 0) ) - { - pADC->ADC_RPR = (uint32_t)pwBuffer ; - pADC->ADC_RCR = dwSize ; - pADC->ADC_PTCR = ADC_PTCR_RXTEN; - - return 1; - } - /* Check if the second PDC bank is free*/ - else - { - if ( pADC->ADC_RNCR == 0 ) - { - pADC->ADC_RNPR = (uint32_t)pwBuffer ; - pADC->ADC_RNCR = dwSize ; - - return 1 ; - } - else - { - return 0 ; - } - } -} - diff --git a/hardware/sam/system/libsam/source/adc_sam3u.c b/hardware/sam/system/libsam/source/adc_sam3u.c new file mode 100644 index 000000000..f928c291e --- /dev/null +++ b/hardware/sam/system/libsam/source/adc_sam3u.c @@ -0,0 +1,608 @@ +/*! \file ********************************************************************* + * + * \brief API for SAM3 Analog-to-Digital Converter (ADC/ADC12B) controller. + * + * ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2011, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: 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 + * 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. + * + * - Compiler: IAR EWARM and CodeSourcery GCC for ARM + * - Supported devices: All SAM devices with a Analog-to-Digital Converter can be used. + * - AppNote: + * + * \author Atmel Corporation: http://www.atmel.com \n + * Support and FAQ: http://support.atmel.com/ + * + *******************************************************************************/ + +#include "adc.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond +#if SAM3U + +#ifdef ADC_12B +/** + * \brief Initializes the given ADC with the specified ADC clock and startup time. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_mck Main clock of the device (value in Hz). + * \param dw_adc_clock Analog-to-Digital conversion clock (value in Hz). + * \param ul_startuptime ADC start up time value(value in us). Please refer to the product datasheet for details. + * \param ul_offmode_startuptime ADC off mode startup Time value(value in us). Please refer to the product datasheet for details. + * + * \retval 0 The initialization operation succeeds. + * \retval others The initialization operation fails. + */ +uint32_t adc_init(Adc12b *p_adc, uint32_t ul_mck, uint32_t ul_adc_clock, uint32_t ul_startuptime, uint32_t ul_offmode_startuptime) +{ + uint32_t ul_prescal,ul_startup,ul_offmode; + p_adc->ADC12B_CR = ADC12B_CR_SWRST; + + /* Reset Mode Register */ + p_adc->ADC12B_MR = 0; + + /* Reset PDC transfer */ + p_adc->ADC12B_PTCR = (ADC12B_PTCR_RXTDIS | ADC12B_PTCR_TXTDIS); + p_adc->ADC12B_RCR = 0; + p_adc->ADC12B_RNCR = 0; + p_adc->ADC12B_TCR = 0; + p_adc->ADC12B_TNCR = 0; + ul_prescal = ul_mck/(2 * ul_adc_clock) - 1; + ul_startup = ((ul_adc_clock/1000000) * ul_startuptime / 8) - 1; + ul_offmode = ((ul_adc_clock/1000000) * ul_offmode_startuptime / 8) - 1; + p_adc->ADC12B_MR |= ADC12B_MR_PRESCAL( ul_prescal ) | ( (ul_startup<ADC12B_EMR |= (ul_offmode<<16) & (0xffu << 16); + return 0; +} +/** + * \brief Configures conversion resolution. + * + * \param p_adc Pointer to an ADC instance. + * \param resolution ADC resolution. + */ +void adc_set_resolution(Adc12b *p_adc, adc_resolution_t resolution) +{ + p_adc->ADC12B_MR |= (resolution<<4) & ADC12B_MR_LOWRES; +} +/** + * \brief Configures conversion trigger and free run mode. + * + * \param p_adc Pointer to an ADC instance. + * \param trigger Conversion trigger. + */ +void adc_configure_trigger(Adc12b *p_adc, adc_trigger_t trigger) +{ + p_adc->ADC12B_MR |= trigger; +} +/** + * \brief Configures ADC power saving mode. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_sleep ADC_MR_SLEEP_NORMAL keeps the ADC Core and reference voltage circuitry ON between conversions + * ADC_MR_SLEEP_SLEEP keeps the ADC Core and reference voltage circuitry OFF between conversions + * \param uc_offmode 0 Standby Mode (if Sleep Bit = 1) + * 1 Off Mode + */ +void adc_configure_power_save(Adc12b *p_adc, uint8_t uc_sleep, uint8_t uc_offmode) +{ + p_adc->ADC12B_MR |= ((uc_sleep<<5) & ADC12B_MR_SLEEP) ; + p_adc->ADC12B_EMR |= uc_offmode; +} +/** + * \brief Configures ADC timing. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_sh ADC sample and hold time = uc_sh / ADC clock. + * + */ +void adc_configure_timing(Adc12b *p_adc, uint32_t ul_sh) +{ + p_adc->ADC12B_MR |= ADC_MR_SHTIM( ul_sh ) ; +} +/** + * \brief Starts analog-to-digital conversion. + * + * \note If one of the hardware event is selected as ADC trigger, this function can NOT start analog to digital conversion. + * + * \param p_adc Pointer to an ADC instance. + */ + +void adc_start(Adc12b *p_adc) +{ + p_adc->ADC12B_CR = ADC12B_CR_START; +} +/** + * \brief Stop analog-to-digital conversion. + * \param p_adc Pointer to an ADC instance. + */ +void adc_stop(Adc12b *p_adc) +{ + p_adc->ADC12B_CR = ADC12B_CR_SWRST; +} +/** + * \brief Enables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + */ +void adc_enable_channel(Adc12b *p_adc, adc_channel_num_t adc_ch) +{ + p_adc->ADC12B_CHER = 1 << adc_ch; +} + +/** + * \brief Disables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + */ +void adc_disable_channel(Adc12b *p_adc, adc_channel_num_t adc_ch) +{ + p_adc->ADC12B_CHDR = 1 << adc_ch; +} + +/** + * \brief Reads the ADC channel status. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval 1 means the specified channel is enabled. + * 0 means the specified channel is disabled. + */ +uint32_t adc_get_status(Adc12b *p_adc, adc_channel_num_t adc_ch) +{ + return p_adc->ADC12B_CHSR & (1 << adc_ch); +} + +/** + * \brief Reads the ADC result data of the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval ADC data of the specified channel. + */ +uint32_t adc_get_value(Adc12b *p_adc, adc_channel_num_t adc_ch) +{ + uint32_t dwData = 0; + + if ( 15 >= adc_ch ) + { + dwData=*(p_adc->ADC12B_CDR+adc_ch) ; + } + + return dwData ; +} + +/** + * \brief Reads the last ADC result data. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC data. + */ +uint32_t adc_get_latest_value(Adc12b *p_adc) +{ + return p_adc->ADC12B_LCDR; +} +/** + * \brief Enables differential input for all channels. + * + * \param p_adc Pointer to an ADC instance. + */ + void adc_enable_differential_input(Adc12b *p_adc) +{ + p_adc->ADC12B_ACR |= (0x01u << 16); +} + +/** + * \brief Disables differential input for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + */ +void adc_disable_differential_input(Adc12b*p_adc) +{ + p_adc->ADC12B_ACR &= (0x01u << 16); +} + +/** + * \brief Enables analog signal offset for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + */ +void adc_enable_input_offset(Adc12b *p_adc) +{ + p_adc->ADC12B_ACR |= (0x01u << 17); +} + +/** + * \brief Disables analog signal offset for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + */ +void adc_disable_input_offset(Adc12b *p_adc) +{ + p_adc->ADC12B_ACR &= (0x01u << 17); +} +/** + * \brief Configures input gain for the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param gain Gain value for the input. + */ +void adc_set_input_gain(Adc12b *p_adc, adc_gainvalue_t gain) +{ + p_adc->ADC12B_ACR |= (0x03u & gain); +} +uint32_t adc_get_actual_adc_clock(Adc12b *p_adc, uint32_t ul_mck) +{ + uint32_t ul_adcfreq; + uint32_t ul_prescal; + + /* ADCClock = MCK / ( (PRESCAL+1) * 2 ) */ + ul_prescal = (( p_adc->ADC12B_MR & ADC12B_MR_PRESCAL_Msk) >> ADC12B_MR_PRESCAL_Pos); + ul_adcfreq = ul_mck / ((ul_prescal+1)*2); + return ul_adcfreq; +} +/** + * \brief Enables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be enabled. + */ +void adc_enable_interrupt(Adc12b *p_adc, uint32_t ul_source) +{ + p_adc->ADC12B_IER = ul_source; +} + +/** + * \brief Disables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be disabled. + */ +void adc_disable_interrupt(Adc12b *p_adc, uint32_t ul_source) +{ + p_adc->ADC12B_IDR = ul_source; +} +/** \brief Read ADC interrupt mask. + * + * \param p_uart pointer to a UART instance. + * + * \return The interrupt mask value. + */ +uint32_t adc_get_interrupt_mask(Adc12b *p_adc) +{ + return p_adc->ADC12B_IMR; +} +/** + * \brief Reads ADC interrupt status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC interrupt status. + */ +uint32_t adc_get_interrupt_status(Adc12b *p_adc) +{ + return p_adc->ADC12B_SR ; +} +/** + * \brief Reads overrun status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC overrun status. + */ +uint32_t adc_check_ovr(Adc12b *p_adc,adc_channel_num_t adc_ch) +{ + return p_adc->ADC12B_SR & (0x01u << (adc_ch+8)); +} +/** + * \brief Adapts performance versus power consumption. + * + * \note Please refer to ADC Characteristics in the product datasheet for the details. + * + * \param p_adc Pointer to an ADC instance. + * \param ibctl ADC Bias current control. + */ +void adc_set_bias_current(Adc12b *p_adc, uint8_t uc_ibctl) +{ + p_adc->ADC12B_ACR |= ADC12B_ACR_IBCTL(uc_ibctl); +} +/** + * \brief Gets PDC registers base address. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval PDC registers base for PDC driver to access. + */ +Pdc *adc_get_pdc_base(Adc12b *p_adc) +{ + return PDC_ADC12B; +} +#else +/** + * \brief Initializes the given ADC with the specified ADC clock and startup time. + * + * \param p_adc Pointer to an ADC instance. + * \param dw_mck Main clock of the device (value in Hz). + * \param dw_adc_clock Analog-to-Digital conversion clock (value in Hz). + * \param ul_startuptime ADC start up time value(value in us). Please refer to the product datasheet for details. + * \param ul_offmode_startuptime ADC off mode startup Time value(value in us). Please refer to the product datasheet for details. + * + * \retval 0 The initialization operation succeeds. + * \retval others The initialization operation fails. + */ +uint32_t adc_init(Adc *p_adc, uint32_t ul_mck, uint32_t ul_adc_clock, uint32_t ul_startuptime, uint32_t ul_offmode_startuptime) +{ + uint32_t ul_prescal,ul_startup,ul_offmode; + p_adc->ADC_CR = ADC_CR_SWRST; + + /* Reset Mode Register */ + p_adc->ADC_MR = 0; + + /* Reset PDC transfer */ + p_adc->ADC_PTCR = (ADC_PTCR_RXTDIS | ADC_PTCR_TXTDIS); + p_adc->ADC_RCR = 0; + p_adc->ADC_RNCR = 0; + p_adc->ADC_TCR = 0; + p_adc->ADC_TNCR = 0; + ul_prescal = ul_mck/(2 * ul_adc_clock) - 1; + ul_startup = ((ul_adc_clock/1000000) * ul_startuptime / 8) - 1; + ul_offmode = ((ul_adc_clock/1000000) * ul_offmode_startuptime / 8) - 1; + p_adc->ADC_MR |= ADC_MR_PRESCAL( ul_prescal ) | ( (ul_startup<ADC_MR |= (resolution<<4) & ADC_MR_LOWRES; +} +/** + * \brief Configures conversion trigger and free run mode. + * + * \param p_adc Pointer to an ADC instance. + * \param trigger Conversion trigger. + */ +void adc_configure_trigger(Adc *p_adc, adc_trigger_t trigger) +{ + p_adc->ADC_MR |= trigger; +} +/** + * \brief Configures ADC power saving mode. + * + * \param p_adc Pointer to an ADC instance. + * \param uc_sleep ADC_MR_SLEEP_NORMAL keeps the ADC Core and reference voltage circuitry ON between conversions + * ADC_MR_SLEEP_SLEEP keeps the ADC Core and reference voltage circuitry OFF between conversions + * \param uc_offmode 0 Standby Mode (if Sleep Bit = 1) + * 1 Off Mode + */ +void adc_configure_power_save(Adc *p_adc, uint8_t uc_sleep, uint8_t uc_offmode) +{ + p_adc->ADC_MR |= ((uc_sleep<<5) & ADC_MR_SLEEP) ; +} +/** + * \brief Configures ADC timing. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_sh ADC sample and hold time = uc_sh / ADC clock. + */ +void adc_configure_timing(Adc *p_adc, uint32_t ul_sh) +{ + p_adc->ADC_MR |= ADC_MR_SHTIM( ul_sh ) ; +} +/** + * \brief Starts analog-to-digital conversion. + * + * \note If one of the hardware event is selected as ADC trigger, this function can NOT start analog to digital conversion. + * + * \param p_adc Pointer to an ADC instance. + */ +void adc_start(Adc *p_adc) +{ + p_adc->ADC_CR = ADC_CR_START; +} +/** + * \brief Stop analog-to-digital conversion. + * \param p_adc Pointer to an ADC instance. + */ +void adc_stop(Adc *p_adc) +{ + p_adc->ADC_CR = ADC_CR_SWRST; +} +/** + * \brief Enables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + */ +void adc_enable_channel(Adc *p_adc, adc_channel_num_t adc_ch) +{ + p_adc->ADC_CHER = 1 << adc_ch; +} + +/** + * \brief Disables the specified ADC channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + */ +void adc_disable_channel(Adc *p_adc, adc_channel_num_t adc_ch) +{ + p_adc->ADC_CHDR = 1 << adc_ch; +} + +/** + * \brief Reads the ADC channel status. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval 1 means the specified channel is enabled. + * 0 means the specified channel is disabled. + */ +uint32_t adc_get_status(Adc *p_adc, adc_channel_num_t adc_ch) +{ + return p_adc->ADC_CHSR & (1 << adc_ch); +} + +/** + * \brief Reads the ADC result data of the specified channel. + * + * \param p_adc Pointer to an ADC instance. + * \param adc_ch ADC channel number. + * + * \retval ADC data of the specified channel. + */ +uint32_t adc_get_value(Adc *p_adc, adc_channel_num_t adc_ch) +{ + uint32_t dwData = 0; + + if ( 15 >= adc_ch ) + { + dwData=*(p_adc->ADC_CDR+adc_ch) ; + } + + return dwData ; +} + +/** + * \brief Reads the last ADC result data. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC data. + */ +uint32_t adc_get_latest_value(Adc *p_adc) +{ + return p_adc->ADC_LCDR; +} +/** + * \brief Returns the actual ADC clock. + * + * \param p_adc Pointer to an ADC instance. + * \param ul_mck Main clock of the device (value in Hz). + * + * \retval 0 The actual ADC clock (value in Hz). + */ +uint32_t adc_get_actual_adc_clock(Adc *p_adc, uint32_t ul_mck) +{ + uint32_t ul_adcfreq; + uint32_t ul_prescal; + + /* ADCClock = MCK / ( (PRESCAL+1) * 2 ) */ + ul_prescal = (( p_adc->ADC_MR & ADC_MR_PRESCAL_Msk) >> ADC_MR_PRESCAL_Pos); + ul_adcfreq = ul_mck / ((ul_prescal+1)*2); + return ul_adcfreq; +} +/** + * \brief Enables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be enabled. + */ +void adc_enable_interrupt(Adc *p_adc, uint32_t ul_source) +{ + p_adc->ADC_IER = ul_source; +} + +/** + * \brief Disables ADC interrupt(s). + * + * \param p_adc Pointer to an ADC instance. + * \param dw_source Interrupt(s) to be disabled. + */ +void adc_disable_interrupt(Adc *p_adc, uint32_t ul_source) +{ + p_adc->ADC_IDR = ul_source; +} +/** + * \brief Reads ADC interrupt mask. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC interrupt status. + */ + uint32_t adc_get_interrupt_status(Adc *p_adc) +{ + return p_adc->ADC_SR ; +} +/** \brief Read ADC interrupt mask. + * + * \param p_uart pointer to a UART instance. + * + * \return The interrupt mask value. + */ +uint32_t adc_get_interrupt_mask(Adc *p_adc) +{ + return p_adc->ADC_IMR; +} +/** + * \brief Reads overrun status. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval ADC overrun status. + */ +uint32_t adc_check_ovr(Adc *p_adc,adc_channel_num_t adc_ch) +{ + return p_adc->ADC_SR & (0x01u << (adc_ch+8)); +} +/** + * \brief Gets PDC registers base address. + * + * \param p_adc Pointer to an ADC instance. + * + * \retval PDC registers base for PDC driver to access. + */ +Pdc *adc_get_pdc_base(Adc *p_adc) +{ + return PDC_ADC; +} +#endif + + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond + +#endif