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.
程序中使用了DMA通道进行数据搬运,但是我的问题是程序中有没有数据锁存,如果没有,程序是如何确保fft分析的数据是实时数据而不是上一个窗口的数据。
void ad_acquire_data(int16_t* pAdcDataArr)
{
uint16_t idx;
for (idx = 0; idx < ADSAMPLE_SIZE; idx++)
{
test_input[2 * idx] = (int32_t) pAdcDataArr[idx];
test_input[2 * idx + 1] = 0;
}
}
这个函数是如何读取dma搬运数据结果的,搬运的结果是否为adc实时采样结果,并且这组数据到fft输入口时,数据是否还在发生改变?
您好
1、DMA数据搬运:
DMA用于在不需要CPU干预的情况下,快速地在内存之间或内存与外设之间传输数据。在你的情况下,DMA被用来从ADC(模数转换器)搬运数据到内存中的某个缓冲区。
2、数据锁存:
数据锁存通常指的是在数据被读取或处理之前,确保它不会被改变。在你的场景中,如果没有显式的锁存机制(如使用信号量、互斥锁等),那么需要依靠其他方式来确保数据的完整性。
3、数据的实时性:
对于FFT分析来说,确保输入的数据是实时的(即当前采样的数据,而不是上一个窗口的数据)是至关重要的。
4、函数ad_acquire_data的分析:
你的函数ad_acquire_data从一个指针pAdcDataArr读取数据,并将其复制到另一个数组test_input中。这里有几个关键点需要注意:
pAdcDataArr指向的数据源是什么?如果它是DMA搬运的目标缓冲区,那么它应该包含最新的ADC采样数据。
数据的复制是同步进行的吗?也就是说,在复制数据时,是否有可能DMA还在向pAdcDataArr写入新的数据?如果是这样,那么可能会存在数据竞争,导致读取的数据不是完全一致的。
4、确保数据的实时性和完整性:
双缓冲或环形缓冲:一种常见的方法是使用双缓冲或环形缓冲。这样,当一个缓冲区被DMA填充时,另一个缓冲区可以被用来进行FFT分析。通过适当的同步机制(如标志位、信号量等),可以确保在FFT分析时使用的数据是完整的且不会被DMA写入覆盖。
中断或DMA完成回调:可以利用DMA完成传输后的中断或回调来通知CPU数据已经准备好,从而开始FFT分析。这样可以确保FFT分析的数据是最新的。
数据拷贝的同步:如果ad_acquire_data函数在DMA传输完成之前被调用,那么需要确保在复制数据时DMA不会同时修改pAdcDataArr中的数据。这可以通过禁用DMA、使用锁、或确保DMA传输和数据处理在不同的时间片中进行来实现。
数据是否还在发生改变:
如果ad_acquire_data函数在DMA传输完成后被调用,并且在此期间没有其他进程或线程修改pAdcDataArr中的数据,那么可以认为数据在复制到test_input时是不会发生改变的。
然而,如果DMA在ad_acquire_data执行期间仍在运行,并且没有适当的同步机制来防止数据竞争,那么数据可能会在被复制时发生改变。
综上所述,要确保FFT分析的数据是实时的且没有被上一个窗口的数据污染,你需要:
确保DMA传输和数据处理之间有适当的同步。
使用双缓冲或环形缓冲来分离数据采集和数据处理。
在数据处理之前确认数据已经完整且不会被修改。
如果你的当前实现没有这些机制,那么可能需要修改代码来添加适当的同步和缓冲管理。
这是官方公布的相关SDK,您可以参考这个资料。
感谢您的回复,这段例程是TI官方给的电弧检测的程序,我在阅读程序的时候,发现了DMA有三条通道,第一个通道搬运了采样结果的前512个数据,而第二通道搬运了后512个数据,第三条通道将1024个数据进行了整合,我看到程序的注释中写到了乒乓缓存的方法。
void ARC_HAL_setupDMA(void)
{
//
// Perform a hard reset on DMA
//
DMA_initController();
//
// Allow DMA to run free on emulation suspend
//
DMA_setEmulationMode(DMA_EMULATION_FREE_RUN);
//
// DMA channel 1 set up for ADCA first 512 Samples
//
DMA_configAddresses(ARC_DMA1_BASE, &ARC_ADCResults1,
(uint16_t *)ARC_ADC_RESULTS_BASE);
//
//Transfer 1 Word (16-Bit) per burst
//
DMA_configBurst(ARC_DMA1_BASE, 1, 0, 1);
//
//Do SAMPLES amount of burst per transfer
//
DMA_configTransfer(ARC_DMA1_BASE, ARC_SAMPLES / 2, 0, 1);
DMA_configMode(ARC_DMA1_BASE, DMA_TRIGGER_ADCA1,
(DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE |
DMA_CFG_SIZE_16BIT));
DMA_enableTrigger(ARC_DMA1_BASE);
DMA_disableOverrunInterrupt(ARC_DMA1_BASE);
DMA_setInterruptMode(ARC_DMA1_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(ARC_DMA1_BASE);
//
// DMA channel 2 set up for ADCA second 512 Samples
//
DMA_configAddresses(ARC_DMA2_BASE, &ARC_ADCResults2,
(uint16_t *)ARC_ADC_RESULTS_BASE);
//
//Transfer 1 Word (16-Bit) per burst
//
DMA_configBurst(ARC_DMA2_BASE, 1, 0, 1);
//
//Do SAMPLES amount of burst per transfer
//
DMA_configTransfer(ARC_DMA2_BASE, ARC_SAMPLES / 2, 0, 1);
DMA_configMode(ARC_DMA2_BASE, DMA_TRIGGER_ADCA2,
(DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE |
DMA_CFG_SIZE_16BIT));
DMA_enableTrigger(ARC_DMA2_BASE);
DMA_disableOverrunInterrupt(ARC_DMA2_BASE);
DMA_setInterruptMode(ARC_DMA2_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(ARC_DMA2_BASE);
//
// DMA channel 3 set up for copying from ADCResult1 or ADCResults to CH1Data
//
DMA_configAddresses(ARC_DMA3_BASE, &ARC_CH1Data,
&ARC_ADCResults1);
//
//Transfer 1 Word (16-Bit) per burst
//
DMA_configBurst(ARC_DMA3_BASE, 1, 1, 1);
//
//Do SAMPLES amount of burst per transfer
//
DMA_configTransfer(ARC_DMA3_BASE, ARC_SAMPLES / 2, 1, 1);
DMA_configMode(ARC_DMA3_BASE, DMA_TRIGGER_SOFTWARE,
(DMA_CFG_ONESHOT_ENABLE | DMA_CFG_CONTINUOUS_DISABLE |
DMA_CFG_SIZE_16BIT));
DMA_enableTrigger(ARC_DMA3_BASE);
DMA_disableOverrunInterrupt(ARC_DMA3_BASE);
DMA_setInterruptMode(ARC_DMA3_BASE, DMA_INT_AT_END);
DMA_enableInterrupt(ARC_DMA3_BASE);
DMA_clearTriggerFlag(ARC_DMA1_BASE); // DMA channel 1
DMA_clearTriggerFlag(ARC_DMA2_BASE); // DMA channel 2
DMA_clearTriggerFlag(ARC_DMA3_BASE); // DMA channel 3
//
// Start DMA 1
//
DMA_startChannel(ARC_DMA1_BASE);
}
void ARC_reinitArcDetect(void)
{
//
//Stop sampling while Arc Detection is re-initialized
//
ARC_HAL_disableADCTrigger();
ARC_HAL_DMA_stop(ARC_DMA1_BASE);
ARC_HAL_DMA_stop(ARC_DMA2_BASE);
ARC_HAL_DMA_stop(ARC_DMA3_BASE);
//
//Re-initialize Arc Detection
//
ARC_InitArcDetect(1);
//
//Reset all flags
//
ARC_ReinitArcDetect = 0;
ARC_startArcDetect = 0;
is_ArcTimingError = 0;
//
//Start sampling again
//
ARC_HAL_DMA_start(ARC_DMA1_BASE);
ARC_HAL_enableADCTrigger();
}
//
//DMA CH1 ISR:
//
/*
* Stops DMA CH1 after first 512 Samples have bin copied to ADCResults1.
* Starts DMA CH2, which copies second 512 Samples to ADCResults2 Buffer
* Sets DMA CH3 source address to ADCResults1 and destination address to CH1Data
* Starts DMA 3, which now copies all values from ADCResults1 into the
* 1st halve of CH1Data
*/
void runArcDMA1ISR(void)
{
ARC_HAL_DMA_stop(ARC_DMA1_BASE);
ARC_HAL_DMA_start(ARC_DMA2_BASE);
is_ArcDataBufferFull = false;
//
// DMA channel 3 set up for copying from ADCResult1 or ADCResults to CH1Data
//
ARC_HAL_DMA_configAddresses(ARC_DMA3_BASE, &ARC_CH1Data,
&ARC_ADCResults1);
ARC_HAL_DMA_startAndTrigger(ARC_DMA3_BASE);
//
// Acknowledge interrupt
//
ARC_HAL_DMA_clearInterruptFlag();
}
//
//DMA CH2 ISR:
//
/*
* Stops DMA CH2 after first 512 Samples have bin copied to ADCResults1.
* Starts DMA CH1, which copies second 512 Samples to ADCResults2 Buffer
* Sets DMA CH3 source address to ADCResults2 and destination address to
* CH1Data[512]
* Starts DMA 3, which now copies all values from ADCResults2
* into the 2nd halve of CH1Data
*/
void runArcDMA2ISR(void)
{
ARC_HAL_DMA_stop(ARC_DMA2_BASE);
ARC_HAL_DMA_start(ARC_DMA1_BASE);
is_ArcDataBufferFull = true;
//
// DMA channel 3 set up for copying from ADCResult1 or ADCResults to CH1Data
//
ARC_HAL_DMA_configAddresses(ARC_DMA3_BASE, &ARC_CH1Data[ARC_SAMPLES/2],
&ARC_ADCResults2);
ARC_HAL_DMA_startAndTrigger(ARC_DMA3_BASE);
//
// Acknowledge interrupt
//
ARC_HAL_DMA_clearInterruptFlag();
}
//
//DMA CH1 ISR:
//
/*
* Stops DMA CH3 after ADCResult_N has been copied to CH1Data
* Sets startArcDetect Flag to 1 if ADCResults 2 has been copied to CH1Data
*/
void runArcDMA3ISR(void)
{
ARC_HAL_DMA_stop(ARC_DMA3_BASE);
if(is_ArcDataBufferFull)
{
if(!is_ArcBusy)
{
ARC_startArcDetect = 1;
}
else
{
is_ArcTimingError = true;
}
}
//
// Acknowledge interrupt
//
ARC_HAL_DMA_clearInterruptFlag();
}
目前,使用该DMA通道,读取出的采样是存在问题的。
该输入为60kHz,峰峰值2.5V,偏移1.25V的正弦信号,程序的采样频率为500kHz,我当时认为是garph拟合波形不理想,所以我将数据导数使用matlab进行拟合,拟合结果如下。
发现问题确实是由于数据引起的。但是当我将程序暂停,发现波形变好。
所以我认为是ad采样时,数据刷新的速度比读取速度要快,导致了数据出现跳变这种情况,当程序暂停时,采样的刷新速度和数据读取速度对齐,所以波形变好,我不知道这样理解是否有问题,还需要向您请教,再次感谢您的回复!
我在读取程序的部分加入了100ms的延迟,最后得到的波形确实好了很多,感谢您的回复!
如果可以的话,我想问一下检测程序中,这三行的修正系数是如何计算的?
scaled = 4.342944819f * logf(BandSum);
scaled += 2.129f; // Correct for Hanning window amplitude shift & broadband noise bin width; same as *2.0/1.225
scaled -= POSTPROCESS_SCALING; // Subtract the post-processing bias
您好
如果这是TI给的相关例程,在库文件和代码后有注释,或者在项目包里面有指导文件,如果您没有找到,您可以分享一下您看到的程序的链接,我帮您找一下。
感谢您的回复,https://www.ti.com.cn/tool/cn/TIDA-010231?keyMatch=TIDA-010231&tisearch=universal_search&usecase=refdesign 这里是TI官方给出的前端设计参考,程序在CCS中resource explorer中查找TIDA-010231即可,但是我在设计文档中并没有找到程序说明。