ADC家族分有ADC和ADC_ETC,在很多时候他们是结合一起使用的.ADC就真的只是ADC,除了转换相关的功能以外,其他功能几乎没有.
ADC功能:
- 15个ADC_IN输入引脚
- 采样相关(8/10/12B采样)
- 硬件平均数(4/8/16/32次平均)
- 连续转换/DMA/结果覆盖/中断申请
- 自动校正/硬件比较/偏移量自动
ADC_ETC功能:
- 为ADC服务的模块,因为不同Trigger和Chain可能公用一个ADC,需要特别注意.
- 从XBAR输入触发,支持4个TRIG,每个TRIG又支持8条Chain,Chain中可以发起DONEx中断/Chain完成中断.
- 提供多个结果寄存器,支持DMA发起.
- 支持软件触发开始某条Chain.
ADC框图(基本不用怎么去理解他,看得多不代表功能多):

ADC采样时间:
由于ADC模块是通过胶水的方式放在芯片内部的,所有时钟域不太一样,互相呼唤需要一些时间差,具体描述就像下图一样.计算公式有点复杂.根据上面的图来带代入参数.
- SFCAdder : 前后增加的时间
- (异步时钟)当ADACKEN = 0 并且 ADICLK = 11b 时,所需时间是1.5us + 4 ADCK + 2总线时钟,常规条件(即总线时钟很快,快到不是一个量级,比如125MHz IPG)下用2.1us代替.
- (正常情况)当其他情况的时候,所需时间是4 ADCK + 2总线时钟,常规条件(即总线时钟很快,快到不是一个量级,比如125MHz IPG)下用0.6us代替.
- LSTAdder : Long Time Sample Adder (单位ADCK)
- BCT : 基本转换时间(固定) 8B=>17 ADCK,10B => 21 ADCK,12B => 25ADCK
- 平均次数 : 1 / 4 /8 / 16 / 32
- LSTAdder + BCT才算是实际采样时间.
- 10MHz 时,每ADCK 0.1us.
- (LSTAdder = 3) + (BCT = 17) = 20 ADCK ≈ 2us
- 转换时间 = SFCAdder + 平均次数*(BCT+LSTAdder)
- 最短单次转换 2.0us + 0.6us = 2.6us
- 为了减少转换时间应该减少在不同工作域下切换.12B模式,最长采样条件下,32份平均,则采样时间和取出时间是160.6us (大约6.2Ksps)
ADC的配置基本没什么需要做的.
int16_t value = 0;
static void MainTask(void *pvParameters)
{
adc_config_t adcConfigStrcut;
adc_channel_config_t adcChannelConfigStruct;
adc_offest_config_t adcOffsetStrcut;
/* Set configuration */
CLOCK_EnableClock(kCLOCK_Adc1);
IOMUXC_SetPinConfig(
IOMUXC_GPIO_AD_14_GPIOMUX_IO28, /* GPIO_AD_14 PAD functional properties : */
0xA0U); /* Slew Rate Field: Slow Slew Rate
Drive Strength Field: R0/4
Speed Field: fast(150MHz)
Open Drain Enable Field: Open Drain Disabled
Pull / Keep Enable Field: Pull/Keeper Disabled
Pull / Keep Select Field: Keeper
Pull Up / Down Config. Field: 100K Ohm Pull Down
Hyst. Enable Field: Hysteresis Disabled */
/*
* config->enableAsynchronousClockOutput = true;
* config->enableOverWrite = false;
* config->enableContinuousConversion = false;
* config->enableHighSpeed = false;
* config->enableLowPower = false;
* config->enableLongSample = false;
* config->referenceVoltageSource = kADC_ReferenceVoltageSourceVref;
* config->samplePeriodMode = kADC_SamplePeriod2or12Clocks;
* config->clockSource = kADC_ClockSourceAD;
* config->clockDriver = kADC_ClockDriver1;
* config->resolution = kADC_Resolution12Bit;
*/
ADC_GetDefaultConfig(&adcConfigStrcut);
ADC_Init(ADC1, &adcConfigStrcut);
ADC_SetHardwareAverageConfig(ADC1, kADC_HardwareAverageCount32);
adcOffsetStrcut.enableSigned = true;
adcOffsetStrcut.offsetValue = 2048;
ADC_SetOffsetConfig(ADC1, &adcOffsetStrcut);
ADC_DoAutoCalibration(ADC1);
adcChannelConfigStruct.channelNumber = 14U;
adcChannelConfigStruct.enableInterruptOnConversionCompleted = false;
for (;;)
{
ADC_SetChannelConfig(ADC1, 0U, &adcChannelConfigStruct);
while (0U == ADC_GetChannelStatusFlags(ADC1, 0U))
{
}
value = ADC_GetChannelConversionValue(ADC1, 0U);
if (value == 0)
{
vTaskDelay(pdMS_TO_TICKS(1));
}
}
}
如果用ADC_ETC则可以配置触发,拿最简单的PIT来说事.
- 先定义一个30ms的PIT.
- 把PIT输出连到到ADC触发输入.
- 初始化ADC触发.
- 初始化ADC_ETC等待发生事件.
- (反复)中断出取出数据.
volatile uint32_t g_AdcConversionValue0;
volatile uint32_t g_AdcConversionValue1;
void ADC_ETC_IRQ0_IRQHandler(void)
{
ADC_ETC_ClearInterruptStatusFlags(ADC_ETC, kADC_ETC_Trg0TriggerSource, kADC_ETC_Done0StatusFlagMask);
g_AdcConversionValue0 = ADC_ETC_GetADCConversionValue(ADC_ETC, 0U, 0U); /* 通道CH7结果. */
g_AdcConversionValue1 = ADC_ETC_GetADCConversionValue(ADC_ETC, 0U, 1U); /* 通道CH14结果. */
__DSB();
}
static void PIT_Configuration()
{
CLOCK_EnableClock(kCLOCK_Pit);
PIT->MCR = 0x00;
PIT->CHANNEL[0].LDVAL = 1499999;
}
void XBARA_Configuration(void)
{
XBARA_Init(XBARA);
XBARA_SetSignalsConnection(XBARA, kXBARA1_InputPitTrigger0, kXBARA1_OutputAdcEtcTrig00);
}
void ADC_Configuration(void)
{
adc_config_t adcConfigStrcut;
adc_channel_config_t adcChannelConfigStruct;
CLOCK_EnableClock(kCLOCK_Adc1);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_07_GPIOMUX_IO21, 0xA0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_14_GPIOMUX_IO28, 0xA0U);
ADC_GetDefaultConfig(&adcConfigStrcut);
ADC_Init(ADC1, &adcConfigStrcut);
ADC_SetHardwareAverageConfig(ADC1, kADC_HardwareAverageCount32);
//使用ADC_ETC关键就是加入这一个,使能硬件触发.
ADC_EnableHardwareTrigger(ADC1, true);
//使用ADC_ETC时候,采样哪个通道就是ADC_ETC说了算了.
adcChannelConfigStruct.channelNumber = 16U;
adcChannelConfigStruct.enableInterruptOnConversionCompleted = false;
ADC_SetChannelConfig(ADC1, 0, &adcChannelConfigStruct);
ADC_SetChannelConfig(ADC1, 1, &adcChannelConfigStruct);
ADC_DoAutoCalibration(ADC1);
}
void ADC_ETC_Configuration(void)
{
adc_etc_config_t adcEtcConfig;
adc_etc_trigger_config_t adcEtcTriggerConfig;
adc_etc_trigger_chain_config_t adcEtcTriggerChainConfig;
/* 初始化ADC_ETC */
ADC_ETC_GetDefaultConfig(&adcEtcConfig);
adcEtcConfig.XBARtriggerMask = 1U; /* 使能 kXBARA1_OutputAdcEtcTrig00 */
ADC_ETC_Init(ADC_ETC, &adcEtcConfig);
/* 配置触发动作. */
adcEtcTriggerConfig.enableSyncMode = false;
adcEtcTriggerConfig.enableSWTriggerMode = false;
adcEtcTriggerConfig.triggerChainLength = 1; /* 整条链长度2,填1即表示长度2. */
adcEtcTriggerConfig.triggerPriority = 0U;
adcEtcTriggerConfig.sampleIntervalDelay = 0U;
adcEtcTriggerConfig.initialDelay = 0U;
ADC_ETC_SetTriggerConfig(ADC_ETC, 0U, &adcEtcTriggerConfig);
/* 背对背模式,如果是True,不等待延迟,佛祖额等待延迟. */
adcEtcTriggerChainConfig.enableB2BMode = true;
/* (Chain 0/Trigger 0)配置ADC_HC0,采样CH7. */
adcEtcTriggerChainConfig.ADCHCRegisterSelect = 1U << 0;
adcEtcTriggerChainConfig.ADCChannelSelect = 07;
ADC_ETC_SetTriggerChainConfig(ADC_ETC, 0U, 0U, &adcEtcTriggerChainConfig);
/* (Chain 1/Trigger 0)配置ADC_HC1,采样CH14,结束时发起中断,然后可以一次性取出结果. */
adcEtcTriggerChainConfig.ADCHCRegisterSelect = 1U << 1;
adcEtcTriggerChainConfig.ADCChannelSelect = 14;
adcEtcTriggerChainConfig.InterruptEnable = kADC_ETC_Done0InterruptEnable;
adcEtcTriggerChainConfig.enableIrq = true;
ADC_ETC_SetTriggerChainConfig(ADC_ETC, 0U, 1U, &adcEtcTriggerChainConfig);
EnableIRQ(ADC_ETC_IRQ0_IRQn);
/* Start PIT channel0. */
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN(1);
}
static void MainTask(void *pvParameters)
{
/* Set PERCLK_CLK source to OSC_CLK*/
CLOCK_SetMux(kCLOCK_PerclkMux, 1U);
/* Set PERCLK_CLK divider to 1 */
CLOCK_SetDiv(kCLOCK_PerclkDiv, 0U);
ADC_Configuration();
XBARA_Configuration();
PIT_Configuration();
ADC_ETC_Configuration();
for (;;)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
要说明一个概念:
- ADC_ETC包含4个Trigger,有各自优先级.
- 1个Trigger包含8条Chain,按顺序采集下去,可以采集同一个通道.
- 每条Chain可以选择不同的通道,中断发起.
发现一个大佬,mark