This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LAUNCHXL-F28379D: 官方例程adc_ex5_soc_continuous.c的一些问题,包括采样率,采样思路。我会通过截图详细列出想问的问题,恳请Ti工程师给出大致的方向、可参考的资料,谢谢。

Part Number: LAUNCHXL-F28379D
Other Parts Discussed in Thread: C2000WARE

首先对Ti工程师,Ti公司致以诚挚敬意!

        回到问题本身,我在研究Ti提供的C2000WARE F2837Xd 库函数驱动例程adc_ex5_soc_continuous.c中,有一些体会和疑虑。

  • (问题1):首先,我成功测出来了相当不错的波形,这是一个5次顺序谐波,失真度是40%,基频10kHz。

          注:在测量中我对转换缓存容量进行了扩大(从256到1024)

            #define RESULTS_BUFFER_SIZE     1024 //buffer for storing conversion results

图示中的三个波形,第一个和最后一个都相当好看,因此我认为实验成功。但是为什么中间这个会出现半段的波动呢?我反复测定了多次,一直如此。大约每3个波形会有一个出现问题。(我用的是杜邦线连接探头)

我的连线图如下

我对ADC采样的转化方法有一些理解问题。我说一下我的理解,如果不对请工程师指正。

首先经过一系列初始化( Device_init();Device_initGPIO;Interrupt_initModule;Interrupt_initVectorTable)之后,我们开始adc配置:configureADC(ADCA_BASE);配置了ADC时钟并给ADCA供电(ADC时钟不影响采样频率);

其次,我们进行ADCA 通道0 的连续采样配置:setupADCContinuous(ADCA_BASE, ADC_CH_ADCIN0);

在这个函数内部我们首先配置了12位采样窗口长度;然后把ADC_SOC_NUMBER0到ADC_SOC_NUMBER15这16个SOC/EOC标签,以软件触发(ADC_TRIGGER_SW_ONLY)的形式链接到ADC_CH_ADCIN0上,并规范了采样窗口。  这个过程通过ADC_setupSOC函数实现。

随后我们进行SOC的中断配置,在这里,我插一段我对SOC的理解:

SOC理解:

用于触发、排序和中断生成的ADC实现都建立在SOC对象上,而不是ADC输入通道上。
ADCRESULTn编号被映射到SOCn编号(,其实暂时还没看到ADCRESULTn,实际上是一个ADCARESULT_BASE 对应ADCA的结果,加上偏移量,偏移量就是SOC的number编号,实现唯一性)。
每个SOC对象可以被配置为转换其ADC上的任何一个可用采样通道(这是可变的)。
我们回归到配置过程,将ADC_SOC_NUMBER0到ADC_SOC_NUMBER7通过ADC_INT_SOC_TRIGGER_ADCINT2,使得ADCINT2触发这8个SOC,这个过程是通过ADC_setInterruptSOCTrigger函数实现的;
同样,我们用ADC_setInterruptSOCTrigger函数将ADC_SOC_NUMBER8到ADC_SOC_NUMBER15用ADCINT1触发。
此时,我们配置了两个中断,ADCINT1,ADCINT2。我们禁用了ADCINT1,2,3,4,然后把这4个ADCINT配置成连续模式,(问题2):其实我这里已经有疑惑了,ADCINT3,4需要进行前面的,基于ADC_setInterruptSOCTrigger的配置吗?
就感觉ADCINT3,4是凭空出现的一样。
在之后的代码中,更让我困惑的事儿发生了,我把代码贴出来:
//
// Configure interrupt triggers
//
ADC_setInterruptSource(adcBase, ADC_INT_NUMBER1, ADC_SOC_NUMBER6);
ADC_setInterruptSource(adcBase, ADC_INT_NUMBER2, ADC_SOC_NUMBER14);
ADC_setInterruptSource(adcBase, ADC_INT_NUMBER3, ADC_SOC_NUMBER7);
ADC_setInterruptSource(adcBase, ADC_INT_NUMBER4, ADC_SOC_NUMBER15);

(问题3):为什么是ADC_SOC_NUMBER6,14,7,15呢?为什么不是其他的SOCnumber?然后ADC_INT_NUMBER3,4的作用又是什么?

我带着问题继续研究代码,现在回到主函数里面,在对结果存储数组初始化(置零)并用EINT,ERTM开启中断之后,我看到以下代码:

使能中断,这个很好理解,但是到这里我还是不知道ADCINT3,4的作用,让我们继续。

//
// Enable ADC interrupts
//
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER2);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER3);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER4);

(问题4):清除标志位,下面这段代码(HWREGH(ADCA_BASE + ADC_O_INTFLGCLR) = 0x000F)应该就是库函数ADC_clearInterruptStatus的作用,然后一次性清理完成4个ADCINT,提高效率

//
// Clear all interrupts flags(INT1-4)
//
HWREGH(ADCA_BASE + ADC_O_INTFLGCLR) = 0x000F;

初始化存储数组指示符index,便于存储

//
// Initialize results index
//
resultsIndex = 0;

(问题5):

软件强制触发SOC0到SOC7,我想请问,这里已经开始采集了吗,这段代码改怎么理解?

值得注意的是,下面的代码(HWREGH(ADCA_BASE + ADC_O_SOCFRC1) = 0x00FF;)应该是库函数ADC_forceMultipleSOC,把SOC0到7一口气配置完成,也是提高效率,我应该没理解错吧?

//
// Software force start SOC0 to SOC7
//
HWREGH(ADCA_BASE + ADC_O_SOCFRC1) = 0x00FF;

然后我们继续看代码:我的理解是,当这个存储数组没装满,我们继续存,

当第一系列的8个转换完成,ADC_INT_NUMBER3的标志位会置1,也就是true,此时,ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER3)读到的值是true,跳出while,执行之后的语句。

我的疑问是,为啥当第一系列的8个转换完成时,ADC_INT_NUMBER3的标志位会置1呢?

到这里,我大约明白了ADCINT3,4的作用。但也说不清楚。

while(resultsIndex < RESULTS_BUFFER_SIZE)
{
//
// Wait for first set of 8 conversions to complete

while(false == ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER3));

//
// Clear the interrupt flag
// 清除中断标志
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER3);

(问题6):

下面一段代码我觉得理解没问题,但我仍然不知道第二个系列的8个转换是谁,怎么,或者说基于什么条件触发,才开始转换的呢?

其实第一个系列的8个转换触发条件我也不是很确定,是HWREGH(ADCA_BASE + ADC_O_SOCFRC1) = 0x00FF实现的吗?

且下面这段代码也写了是SOC/EOC6,链接到ADCINT1触发,但是具体如何触发呢?触发会不会改变ADCINT1的中断标志位(供给ADC_getInterruptStatus)读取呢?

//
// Save results for first 8 conversions
// 保存前8次转换的结果
// Note that during this time, the second 8 conversions have
// already been triggered by EOC6->ADCIN1 and will be actively
// converting while first 8 results are being saved
// 注意,在保存(把前八次转换的结果写入寄存器)的过程中,第二系列的8个转换
// 已经开始触发了,且开始转换(通过SOC/EOC 6,对应的是ADCIN1)。
// 这里的存储方式是:实际上是一个ADCARESULT_BASE 对应ADCA的结果,加上偏移
// 量,偏移量就是SOC的number编号,实现唯一性
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER0);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER1);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER2);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER3);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER4);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER5);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER6);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER7);

接下来的代码跟上面类似,我的疑惑也是类似的,为什么是ADCINT4的中断标志位置1?

//
// Wait for the second set of 8 conversions to complete
// 等待第二组8个转换完成
// 第二组的8个通道值转换完成后,ADC_INT_NUMBER4的值会置1,此时跳出循环
// 所以ADC_INT_NUMBER4标志着第二组的8个通道是否转换完成。
while(false == ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER4));

//
// Clear the interrupt flag
//
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER4);

//
// Save results for second 8 conversions
//
// Note that during this time, the first 8 conversions have
// already been triggered by EOC14->ADCIN2 and will be actively
// converting while second 8 results are being saved
//
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER8);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER9);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER10);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER11);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER12);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER13);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER14);
adcAResults[resultsIndex++] = ADC_readResult(ADCARESULT_BASE,
ADC_SOC_NUMBER15);
}

统观全局

(问题7):

ADCINT3,ADCINT4中断标志位置1是通过前面的

//
// Configure interrupt triggers
//
ADC_setInterruptSource(adcBase, ADC_INT_NUMBER1, ADC_SOC_NUMBER6);
ADC_setInterruptSource(adcBase, ADC_INT_NUMBER2, ADC_SOC_NUMBER14);
ADC_setInterruptSource(adcBase, ADC_INT_NUMBER3, ADC_SOC_NUMBER7);
ADC_setInterruptSource(adcBase, ADC_INT_NUMBER4, ADC_SOC_NUMBER15);

实现的吗?

(问题8):

最后,关闭相关的中断,采样结束。我计算了一下,100kHz的输入波形,每个周期可以采集20个点左右,似乎最高采样频率在2MHz左右?如果使用DMA技术,能提高这个采样频率吗?或者说,到底什么地方,是ADC转换,还是写入寄存器,会较大程度占用CPU资源呢?

之后准备研究ex6,ADC与DMA技术的结合,特别希望Ti的工程师帮我解决ADC连续采样的这些问题。作为本科生,我觉得我的理解能力有所不足,还望工程师先生,不吝赐教。

祝好!