kopia lustrzana https://github.com/open-ham/OpenGD77
484 wiersze
16 KiB
C
484 wiersze
16 KiB
C
/*
|
|
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
|
* Copyright 2016-2017 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "fsl_adc16.h"
|
|
|
|
/* Component ID definition, used by tools. */
|
|
#ifndef FSL_COMPONENT_ID
|
|
#define FSL_COMPONENT_ID "platform.drivers.adc16"
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
/*!
|
|
* @brief Get instance number for ADC16 module.
|
|
*
|
|
* @param base ADC16 peripheral base address
|
|
*/
|
|
static uint32_t ADC16_GetInstance(ADC_Type *base);
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
/*! @brief Pointers to ADC16 bases for each instance. */
|
|
static ADC_Type *const s_adc16Bases[] = ADC_BASE_PTRS;
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/*! @brief Pointers to ADC16 clocks for each instance. */
|
|
static const clock_ip_name_t s_adc16Clocks[] = ADC16_CLOCKS;
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
static uint32_t ADC16_GetInstance(ADC_Type *base)
|
|
{
|
|
uint32_t instance;
|
|
|
|
/* Find the instance index from base address mappings. */
|
|
for (instance = 0; instance < ARRAY_SIZE(s_adc16Bases); instance++)
|
|
{
|
|
if (s_adc16Bases[instance] == base)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(instance < ARRAY_SIZE(s_adc16Bases));
|
|
|
|
return instance;
|
|
}
|
|
|
|
/*!
|
|
* brief Initializes the ADC16 module.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
* param config Pointer to configuration structure. See "adc16_config_t".
|
|
*/
|
|
void ADC16_Init(ADC_Type *base, const adc16_config_t *config)
|
|
{
|
|
assert(NULL != config);
|
|
|
|
uint32_t tmp32;
|
|
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/* Enable the clock. */
|
|
CLOCK_EnableClock(s_adc16Clocks[ADC16_GetInstance(base)]);
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
|
|
/* ADCx_CFG1. */
|
|
tmp32 = ADC_CFG1_ADICLK(config->clockSource) | ADC_CFG1_MODE(config->resolution);
|
|
if (kADC16_LongSampleDisabled != config->longSampleMode)
|
|
{
|
|
tmp32 |= ADC_CFG1_ADLSMP_MASK;
|
|
}
|
|
tmp32 |= ADC_CFG1_ADIV(config->clockDivider);
|
|
if (config->enableLowPower)
|
|
{
|
|
tmp32 |= ADC_CFG1_ADLPC_MASK;
|
|
}
|
|
base->CFG1 = tmp32;
|
|
|
|
/* ADCx_CFG2. */
|
|
tmp32 = base->CFG2 & ~(ADC_CFG2_ADACKEN_MASK | ADC_CFG2_ADHSC_MASK | ADC_CFG2_ADLSTS_MASK);
|
|
if (kADC16_LongSampleDisabled != config->longSampleMode)
|
|
{
|
|
tmp32 |= ADC_CFG2_ADLSTS(config->longSampleMode);
|
|
}
|
|
if (config->enableHighSpeed)
|
|
{
|
|
tmp32 |= ADC_CFG2_ADHSC_MASK;
|
|
}
|
|
if (config->enableAsynchronousClock)
|
|
{
|
|
tmp32 |= ADC_CFG2_ADACKEN_MASK;
|
|
}
|
|
base->CFG2 = tmp32;
|
|
|
|
/* ADCx_SC2. */
|
|
tmp32 = base->SC2 & ~(ADC_SC2_REFSEL_MASK);
|
|
tmp32 |= ADC_SC2_REFSEL(config->referenceVoltageSource);
|
|
base->SC2 = tmp32;
|
|
|
|
/* ADCx_SC3. */
|
|
if (config->enableContinuousConversion)
|
|
{
|
|
base->SC3 |= ADC_SC3_ADCO_MASK;
|
|
}
|
|
else
|
|
{
|
|
base->SC3 &= ~ADC_SC3_ADCO_MASK;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* brief De-initializes the ADC16 module.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
*/
|
|
void ADC16_Deinit(ADC_Type *base)
|
|
{
|
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
|
/* Disable the clock. */
|
|
CLOCK_DisableClock(s_adc16Clocks[ADC16_GetInstance(base)]);
|
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
|
}
|
|
|
|
/*!
|
|
* brief Gets an available pre-defined settings for the converter's configuration.
|
|
*
|
|
* This function initializes the converter configuration structure with available settings. The default values are as
|
|
* follows.
|
|
* code
|
|
* config->referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
|
|
* config->clockSource = kADC16_ClockSourceAsynchronousClock;
|
|
* config->enableAsynchronousClock = true;
|
|
* config->clockDivider = kADC16_ClockDivider8;
|
|
* config->resolution = kADC16_ResolutionSE12Bit;
|
|
* config->longSampleMode = kADC16_LongSampleDisabled;
|
|
* config->enableHighSpeed = false;
|
|
* config->enableLowPower = false;
|
|
* config->enableContinuousConversion = false;
|
|
* endcode
|
|
* param config Pointer to the configuration structure.
|
|
*/
|
|
void ADC16_GetDefaultConfig(adc16_config_t *config)
|
|
{
|
|
assert(NULL != config);
|
|
|
|
/* Initializes the configure structure to zero. */
|
|
memset(config, 0, sizeof(*config));
|
|
|
|
config->referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
|
|
config->clockSource = kADC16_ClockSourceAsynchronousClock;
|
|
config->enableAsynchronousClock = true;
|
|
config->clockDivider = kADC16_ClockDivider8;
|
|
config->resolution = kADC16_ResolutionSE12Bit;
|
|
config->longSampleMode = kADC16_LongSampleDisabled;
|
|
config->enableHighSpeed = false;
|
|
config->enableLowPower = false;
|
|
config->enableContinuousConversion = false;
|
|
}
|
|
|
|
#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
|
|
/*!
|
|
* brief Automates the hardware calibration.
|
|
*
|
|
* This auto calibration helps to adjust the plus/minus side gain automatically.
|
|
* Execute the calibration before using the converter. Note that the hardware trigger should be used
|
|
* during the calibration.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
*
|
|
* return Execution status.
|
|
* retval kStatus_Success Calibration is done successfully.
|
|
* retval kStatus_Fail Calibration has failed.
|
|
*/
|
|
status_t ADC16_DoAutoCalibration(ADC_Type *base)
|
|
{
|
|
bool bHWTrigger = false;
|
|
volatile uint32_t tmp32; /* 'volatile' here is for the dummy read of ADCx_R[0] register. */
|
|
status_t status = kStatus_Success;
|
|
|
|
/* The calibration would be failed when in hardwar mode.
|
|
* Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/
|
|
if (0U != (ADC_SC2_ADTRG_MASK & base->SC2))
|
|
{
|
|
bHWTrigger = true;
|
|
base->SC2 &= ~ADC_SC2_ADTRG_MASK;
|
|
}
|
|
|
|
/* Clear the CALF and launch the calibration. */
|
|
base->SC3 |= ADC_SC3_CAL_MASK | ADC_SC3_CALF_MASK;
|
|
while (0U == (kADC16_ChannelConversionDoneFlag & ADC16_GetChannelStatusFlags(base, 0U)))
|
|
{
|
|
/* Check the CALF when the calibration is active. */
|
|
if (0U != (kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base)))
|
|
{
|
|
status = kStatus_Fail;
|
|
break;
|
|
}
|
|
}
|
|
tmp32 = base->R[0]; /* Dummy read to clear COCO caused by calibration. */
|
|
|
|
/* Restore the hardware trigger setting if it was enabled before. */
|
|
if (bHWTrigger)
|
|
{
|
|
base->SC2 |= ADC_SC2_ADTRG_MASK;
|
|
}
|
|
/* Check the CALF at the end of calibration. */
|
|
if (0U != (kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base)))
|
|
{
|
|
status = kStatus_Fail;
|
|
}
|
|
if (kStatus_Success != status) /* Check if the calibration process is succeed. */
|
|
{
|
|
return status;
|
|
}
|
|
|
|
/* Calculate the calibration values. */
|
|
tmp32 = base->CLP0 + base->CLP1 + base->CLP2 + base->CLP3 + base->CLP4 + base->CLPS;
|
|
tmp32 = 0x8000U | (tmp32 >> 1U);
|
|
base->PG = tmp32;
|
|
|
|
#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
|
|
tmp32 = base->CLM0 + base->CLM1 + base->CLM2 + base->CLM3 + base->CLM4 + base->CLMS;
|
|
tmp32 = 0x8000U | (tmp32 >> 1U);
|
|
base->MG = tmp32;
|
|
#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
|
|
|
|
return kStatus_Success;
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
|
|
|
|
#if defined(FSL_FEATURE_ADC16_HAS_MUX_SELECT) && FSL_FEATURE_ADC16_HAS_MUX_SELECT
|
|
/*!
|
|
* brief Sets the channel mux mode.
|
|
*
|
|
* Some sample pins share the same channel index. The channel mux mode decides which pin is used for an
|
|
* indicated channel.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
* param mode Setting channel mux mode. See "adc16_channel_mux_mode_t".
|
|
*/
|
|
void ADC16_SetChannelMuxMode(ADC_Type *base, adc16_channel_mux_mode_t mode)
|
|
{
|
|
if (kADC16_ChannelMuxA == mode)
|
|
{
|
|
base->CFG2 &= ~ADC_CFG2_MUXSEL_MASK;
|
|
}
|
|
else /* kADC16_ChannelMuxB. */
|
|
{
|
|
base->CFG2 |= ADC_CFG2_MUXSEL_MASK;
|
|
}
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_MUX_SELECT */
|
|
|
|
/*!
|
|
* brief Configures the hardware compare mode.
|
|
*
|
|
* The hardware compare mode provides a way to process the conversion result automatically by using hardware. Only the
|
|
* result
|
|
* in the compare range is available. To compare the range, see "adc16_hardware_compare_mode_t" or the appopriate
|
|
* reference
|
|
* manual for more information.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
* param config Pointer to the "adc16_hardware_compare_config_t" structure. Passing "NULL" disables the feature.
|
|
*/
|
|
void ADC16_SetHardwareCompareConfig(ADC_Type *base, const adc16_hardware_compare_config_t *config)
|
|
{
|
|
uint32_t tmp32 = base->SC2 & ~(ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK);
|
|
|
|
if (!config) /* Pass "NULL" to disable the feature. */
|
|
{
|
|
base->SC2 = tmp32;
|
|
return;
|
|
}
|
|
/* Enable the feature. */
|
|
tmp32 |= ADC_SC2_ACFE_MASK;
|
|
|
|
/* Select the hardware compare working mode. */
|
|
switch (config->hardwareCompareMode)
|
|
{
|
|
case kADC16_HardwareCompareMode0:
|
|
break;
|
|
case kADC16_HardwareCompareMode1:
|
|
tmp32 |= ADC_SC2_ACFGT_MASK;
|
|
break;
|
|
case kADC16_HardwareCompareMode2:
|
|
tmp32 |= ADC_SC2_ACREN_MASK;
|
|
break;
|
|
case kADC16_HardwareCompareMode3:
|
|
tmp32 |= ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
base->SC2 = tmp32;
|
|
|
|
/* Load the compare values. */
|
|
base->CV1 = ADC_CV1_CV(config->value1);
|
|
base->CV2 = ADC_CV2_CV(config->value2);
|
|
}
|
|
|
|
#if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE
|
|
/*!
|
|
* brief Sets the hardware average mode.
|
|
*
|
|
* The hardware average mode provides a way to process the conversion result automatically by using hardware. The
|
|
* multiple
|
|
* conversion results are accumulated and averaged internally making them easier to read.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
* param mode Setting the hardware average mode. See "adc16_hardware_average_mode_t".
|
|
*/
|
|
void ADC16_SetHardwareAverage(ADC_Type *base, adc16_hardware_average_mode_t mode)
|
|
{
|
|
uint32_t tmp32 = base->SC3 & ~(ADC_SC3_AVGE_MASK | ADC_SC3_AVGS_MASK);
|
|
|
|
if (kADC16_HardwareAverageDisabled != mode)
|
|
{
|
|
tmp32 |= ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(mode);
|
|
}
|
|
base->SC3 = tmp32;
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */
|
|
|
|
#if defined(FSL_FEATURE_ADC16_HAS_PGA) && FSL_FEATURE_ADC16_HAS_PGA
|
|
/*!
|
|
* brief Configures the PGA for the converter's front end.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
* param config Pointer to the "adc16_pga_config_t" structure. Passing "NULL" disables the feature.
|
|
*/
|
|
void ADC16_SetPGAConfig(ADC_Type *base, const adc16_pga_config_t *config)
|
|
{
|
|
uint32_t tmp32;
|
|
|
|
if (!config) /* Passing "NULL" is to disable the feature. */
|
|
{
|
|
base->PGA = 0U;
|
|
return;
|
|
}
|
|
|
|
/* Enable the PGA and set the gain value. */
|
|
tmp32 = ADC_PGA_PGAEN_MASK | ADC_PGA_PGAG(config->pgaGain);
|
|
|
|
/* Configure the misc features for PGA. */
|
|
if (config->enableRunInNormalMode)
|
|
{
|
|
tmp32 |= ADC_PGA_PGALPb_MASK;
|
|
}
|
|
#if defined(FSL_FEATURE_ADC16_HAS_PGA_CHOPPING) && FSL_FEATURE_ADC16_HAS_PGA_CHOPPING
|
|
if (config->disablePgaChopping)
|
|
{
|
|
tmp32 |= ADC_PGA_PGACHPb_MASK;
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_PGA_CHOPPING */
|
|
#if defined(FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT) && FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT
|
|
if (config->enableRunInOffsetMeasurement)
|
|
{
|
|
tmp32 |= ADC_PGA_PGAOFSM_MASK;
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT */
|
|
base->PGA = tmp32;
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_PGA */
|
|
|
|
/*!
|
|
* brief Gets the status flags of the converter.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
*
|
|
* return Flags' mask if indicated flags are asserted. See "_adc16_status_flags".
|
|
*/
|
|
uint32_t ADC16_GetStatusFlags(ADC_Type *base)
|
|
{
|
|
uint32_t ret = 0;
|
|
|
|
if (0U != (base->SC2 & ADC_SC2_ADACT_MASK))
|
|
{
|
|
ret |= kADC16_ActiveFlag;
|
|
}
|
|
#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
|
|
if (0U != (base->SC3 & ADC_SC3_CALF_MASK))
|
|
{
|
|
ret |= kADC16_CalibrationFailedFlag;
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
|
|
return ret;
|
|
}
|
|
|
|
/*!
|
|
* brief Clears the status flags of the converter.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
* param mask Mask value for the cleared flags. See "_adc16_status_flags".
|
|
*/
|
|
void ADC16_ClearStatusFlags(ADC_Type *base, uint32_t mask)
|
|
{
|
|
#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
|
|
if (0U != (mask & kADC16_CalibrationFailedFlag))
|
|
{
|
|
base->SC3 |= ADC_SC3_CALF_MASK;
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
|
|
}
|
|
|
|
/*!
|
|
* brief Configures the conversion channel.
|
|
*
|
|
* This operation triggers the conversion when in software trigger mode. When in hardware trigger mode, this API
|
|
* configures the channel while the external trigger source helps to trigger the conversion.
|
|
*
|
|
* Note that the "Channel Group" has a detailed description.
|
|
* To allow sequential conversions of the ADC to be triggered by internal peripherals, the ADC has more than one
|
|
* group of status and control registers, one for each conversion. The channel group parameter indicates which group of
|
|
* registers are used, for example, channel group 0 is for Group A registers and channel group 1 is for Group B
|
|
* registers. The
|
|
* channel groups are used in a "ping-pong" approach to control the ADC operation. At any point, only one of
|
|
* the channel groups is actively controlling ADC conversions. The channel group 0 is used for both software and
|
|
* hardware
|
|
* trigger modes. Channel group 1 and greater indicates multiple channel group registers for
|
|
* use only in hardware trigger mode. See the chip configuration information in the appropriate MCU reference manual for
|
|
* the
|
|
* number of SC1n registers (channel groups) specific to this device. Channel group 1 or greater are not used
|
|
* for software trigger operation. Therefore, writing to these channel groups does not initiate a new conversion.
|
|
* Updating the channel group 0 while a different channel group is actively controlling a conversion is allowed and
|
|
* vice versa. Writing any of the channel group registers while that specific channel group is actively controlling a
|
|
* conversion aborts the current conversion.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
* param channelGroup Channel group index.
|
|
* param config Pointer to the "adc16_channel_config_t" structure for the conversion channel.
|
|
*/
|
|
void ADC16_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc16_channel_config_t *config)
|
|
{
|
|
assert(channelGroup < ADC_SC1_COUNT);
|
|
assert(NULL != config);
|
|
|
|
uint32_t sc1 = ADC_SC1_ADCH(config->channelNumber); /* Set the channel number. */
|
|
|
|
#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
|
|
/* Enable the differential conversion. */
|
|
if (config->enableDifferentialConversion)
|
|
{
|
|
sc1 |= ADC_SC1_DIFF_MASK;
|
|
}
|
|
#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
|
|
/* Enable the interrupt when the conversion is done. */
|
|
if (config->enableInterruptOnConversionCompleted)
|
|
{
|
|
sc1 |= ADC_SC1_AIEN_MASK;
|
|
}
|
|
base->SC1[channelGroup] = sc1;
|
|
}
|
|
|
|
/*!
|
|
* brief Gets the status flags of channel.
|
|
*
|
|
* param base ADC16 peripheral base address.
|
|
* param channelGroup Channel group index.
|
|
*
|
|
* return Flags' mask if indicated flags are asserted. See "_adc16_channel_status_flags".
|
|
*/
|
|
uint32_t ADC16_GetChannelStatusFlags(ADC_Type *base, uint32_t channelGroup)
|
|
{
|
|
assert(channelGroup < ADC_SC1_COUNT);
|
|
|
|
uint32_t ret = 0U;
|
|
|
|
if (0U != (base->SC1[channelGroup] & ADC_SC1_COCO_MASK))
|
|
{
|
|
ret |= kADC16_ChannelConversionDoneFlag;
|
|
}
|
|
return ret;
|
|
}
|