我使用双ADC交替采集10kHz正弦电压信号。ADC1和ADC2综合采样频率均配置为4.5MHz(H7顶配)。当使用连续模式(不使用TIM)时,采样点数完全正确(一个周期内能采集900个点,且波形正确),而当配置为4MHz的TIM进行单次触发时,在相同条件下单周期仅能采集到400个样本点(理论上不应该是800个吗?),请问这是为什么?有没有有经验的大佬解答一下?
[C] 纯文本查看 复制代码
#ifdef USE_ADC
/* 头文件 */
#include "adc.h"
/* 全局变量 */
uint32_t WaveShape[BUFF_SIZE] = {0};
/*
*********************************************************************************************************
* 函 数 名: ADC_GPIO_Config
* 功能说明: 配置ADC的GPIO端口并使能
* 形 参: NONE
* 返 回 值: NONE
*********************************************************************************************************
*/
static void ADC12_GPIO_Config(void)
{
/* GPIO配置 */
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = LL_GPIO_PIN_4;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* GPIO时钟使能 */
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOC);
}
/*
*********************************************************************************************************
* 函 数 名: ADC_CLK_Config
* 功能说明: 配置ADC的时钟源PLL2并使能
* 形 参: NONE
* 返 回 值: NONE
*********************************************************************************************************
*/
static void ADC12_CLK_Config(void)
{
/* 将PLL2配置为ADC1的时钟源(综合采样频率满配4.5MHz) */
LL_RCC_PLL2FRACN_Disable();
LL_RCC_PLL2_SetM(25);
LL_RCC_PLL2_SetN(504);
LL_RCC_PLL2_SetP(7);
LL_RCC_PLL2_SetQ(2);
LL_RCC_PLL2_SetR(2);
LL_RCC_PLL2_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4);
LL_RCC_PLL2_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL2_Enable();
while(LL_RCC_PLL2_IsReady() != 1){}
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLL2P);
/* 使能ADC1\ADC2时钟 */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12);
}
/*
*********************************************************************************************************
* 函 数 名: ADC1_Normal_Config
* 功能说明: 配置ADC1常规寄存器并使能
* 形 参: NONE
* 返 回 值: NONE
*********************************************************************************************************
*/
void ADC12_Normal_Config(void)
{
/* 定义ADC配置结构体实例 */
LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
/* ADC常规配置 */
LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE);
LL_ADC_SetBoostMode(ADC1, LL_ADC_BOOST_MODE_20MHZ);
LL_ADC_SetOverSamplingScope(ADC2, LL_ADC_OVS_DISABLE);
LL_ADC_SetBoostMode(ADC2, LL_ADC_BOOST_MODE_20MHZ);
/* 结构体1 */
/*分辨率*/
ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
/*禁用左对齐*/
ADC_InitStruct.LeftBitShift = LL_ADC_LEFT_BIT_SHIFT_NONE;
/*禁用掉电模式*/
ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
/* 配置 */
LL_ADC_Init(ADC1, &ADC_InitStruct);
LL_ADC_Init(ADC2, &ADC_InitStruct);
/* 结构体2 */
/*TIM3 的TRGO触发*/
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_EXT_TIM3_TRGO;
/*禁用扫描模式*/
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
/*禁用队列*/
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
/*ADC单次触发模式*/
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;
/*转换后的数据->DR*/
ADC_REG_InitStruct.DataTransferMode = LL_ADC_REG_DR_TRANSFER ;
/*数据溢出覆写*/
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
/*上升沿触发*/
LL_ADC_REG_SetTriggerEdge(ADC1, LL_ADC_REG_TRIG_EXT_RISING);
/* 配置 */
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_REG_Init(ADC2, &ADC_REG_InitStruct);
/* 结构体3 */
/*时钟1分频*/
ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV1;
/*单通道-双ADC交替采样*/
ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_DUAL_REG_INTERL;
/*配置DMA32位-10位分辨率(直接影响CDR寄存器是否有值,哪怕不启用DMA内存搬运,也要写这行)*/
ADC_CommonInitStruct.MultiDMATransfer = LL_ADC_MULTI_REG_DMA_RES_32_10B;
/*采集时间延迟2.5个周期*/
ADC_CommonInitStruct.MultiTwoSamplingDelay = LL_ADC_MULTI_TWOSMP_DELAY_2CYCLES_5;
/* 配置 */
LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
/* ADC1电源配置 */
LL_ADC_DisableDeepPowerDown(ADC1);
LL_ADC_EnableInternalRegulator(ADC1);
__IO uint32_t wait_loop_index;
wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
while(wait_loop_index != 0){wait_loop_index--;}
/* ADC2电源配置 */
LL_ADC_DisableDeepPowerDown(ADC2);
LL_ADC_EnableInternalRegulator(ADC2);
__IO uint32_t wait_loop_index2;
wait_loop_index2 = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
while(wait_loop_index2 != 0){wait_loop_index2--;}
/* ADC1通道配置 */
/*rank1, 通道4*/
LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_4);
/*采样时间1.5个周期*/
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_1CYCLE_5);
/*单端模式(禁用差分模式)*/
LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_4, LL_ADC_SINGLE_ENDED);
/*预选通道4,非常关键*/
ADC1->PCSEL |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_CHANNEL_4) & 0x1FUL));
/* ADC2通道配置 */
/*rank1, 通道4*/
LL_ADC_REG_SetSequencerRanks(ADC2, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_4);
/*采样时间1.5个周期*/
LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_1CYCLE_5);
/*单端模式(禁用差分模式)*/
LL_ADC_SetChannelSingleDiff(ADC2, LL_ADC_CHANNEL_4, LL_ADC_SINGLE_ENDED);
/*预选通道4,非常关键*/
ADC2->PCSEL |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_CHANNEL_4) & 0x1FUL));
/* 校准 */
LL_ADC_StartCalibration(ADC1, LL_ADC_SINGLE_ENDED, LL_ADC_SINGLE_ENDED);
while(LL_ADC_IsCalibrationOnGoing(ADC1)){};
/* 校准 */
LL_ADC_StartCalibration(ADC2, LL_ADC_SINGLE_ENDED, LL_ADC_SINGLE_ENDED);
while(LL_ADC_IsCalibrationOnGoing(ADC2)){};
/* 使能 */
LL_ADC_Enable(ADC1);
while(LL_ADC_IsActiveFlag_ADRDY(ADC1) != SET){};
/* 使能 */
LL_ADC_Enable(ADC2);
while(LL_ADC_IsActiveFlag_ADRDY(ADC2) != SET){};
}
/*
*********************************************************************************************************
* 函 数 名: Threshold_Beyond_Process
* 功能说明: 高频ADC中断时的阈值处理
* 形 参: NONE
* 返 回 值: NONE
*********************************************************************************************************
*/
void ADC12_NVIC_Config(void)
{
NVIC_SetPriority(ADC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
NVIC_EnableIRQ(ADC_IRQn);
/* 仅使能ADC2的中断 */
LL_ADC_EnableIT_EOC(ADC2);
}
/*
*********************************************************************************************************
* 函 数 名: ADC_IRQHandler
* 功能说明: ADC1的中断服务函数;判断输入阈值并做出相应处理
* 形 参: NONE
* 返 回 值: NONE
*********************************************************************************************************
*/
void ADC_IRQHandler(void)
{
/* 清除标志位 */
if (LL_ADC_IsActiveFlag_EOC(ADC2))
{
LL_ADC_ClearFlag_EOC(ADC2);
}
/* 阈值超出时的执行逻辑 */
if ((float)ADC2->DR*3.3/4096 >= 1.0 )
{
/* 停止ADC的中断,但EOC仍在发送 */
LL_ADC_DisableIT_EOC(ADC2);
/* 局部变量计数指针 */
uint16_t counter = 0;
/* 将当前ADC寄存器中的值搬运到缓冲区.这建立在CPU中断处理速度大于ADC转换的速度之上 */
while (counter<BUFF_SIZE)
{
/* 轮询检查标志位等待下一次ADC12转换完成 */
while (LL_ADC_IsActiveFlag_EOC(ADC1) != 1){ }
/* 轮询通过则将当前寄存器的值搬运至缓冲区 */
WaveShape[counter] = ADC12_COMMON->CDR;
/* 清除标志位 */
LL_ADC_ClearFlag_EOC(ADC1);
/*自增1*/
counter++;
}
/* 重新使能EOC中断,恢复连续模式 */
// 调试模式下先不重新使能ADC的中断,避免中断造成CPU的printf的阻塞
LL_ADC_EnableIT_EOC(ADC2);
}
}
/*
*********************************************************************************************************
* 函 数 名: User_ADC_Init
* 功能说明: 调用各种配置函数
* 形 参: NONE
* 返 回 值: NONE
*********************************************************************************************************
*/
void User_ADC12_Init(void)
{
ADC12_GPIO_Config();
ADC12_CLK_Config();
ADC12_NVIC_Config();
ADC12_Normal_Config();
}
/*
*********************************************************************************************************
* 函 数 名: ADC1_Start
* 功能说明: 启动ADC1开始转换
* 形 参: NONE
* 返 回 值: NONE
*********************************************************************************************************
*/
void ADC1_Start(void)
{
LL_ADC_REG_StartConversion(ADC1);
}
#endif
|