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