你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32G030K6Tx使用ADC+DMA进行6通道ADC采集,DMA传输错位问题。

[复制链接]
jinli 提问时间:2025-8-2 11:09 / 未解决

通过DMA将采集的ADC->DR的数据向adc_dma_buf[6]这个变量传输(指定的内存地址为adc_dma_buff[0]),CHSELR寄存器的值依次为5,6,7,8,9,10,F,0,实际测试的时候,AIN5的ADC转换结果被传输到了adc_dma_buff[1],AIN6的ADC转换结果被传输到了adc_dma_buff[2],以此类推,AIN10的转换结果被传输到了adc_dma_buff[0],而且数值也都是正确的。网上又说把`ADC_CFGR1.DMACFG置0的,但是这个置0后就不会自动连续传输了,而且成功的转这次转换,也是如上述一样错位。

从现象来看,好像ADC首先开启的是AIN10的转换。有人知道这是啥原因么?

初始化代码如下:

void MX_ADC1_Init(void) {/ USER CODE BEGIN ADC1_Init 0 /

LL_DMA_InitTypeDef DMA_Init_Struct; LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); / USER CODE END ADC1_Init 0 /

LL_ADC_InitTypeDef ADC_InitStruct = {0}; LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};

LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

/ Peripheral clock enable / LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC); LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA); LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);

GPIO_InitStruct.Pin = LL_GPIO_PIN_5; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_6; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_7; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_0; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_1; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO_InitStruct.Pin = LL_GPIO_PIN_2; GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/ ADC1 DMA Init / / USER CODE BEGIN ADC1_DMA_Init 1 /

DMA_Init_Struct.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY; DMA_Init_Struct.MemoryOrM2MDstAddress = (uint32_t)(adc_dma_data); DMA_Init_Struct.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD; DMA_Init_Struct.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; DMA_Init_Struct.Mode = LL_DMA_MODE_CIRCULAR; DMA_Init_Struct.NbData = 6; DMA_Init_Struct.PeriphOrM2MSrcAddress = (uint32_t)(&ADC1->DR); DMA_Init_Struct.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD; DMA_Init_Struct.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
DMA_Init_Struct.PeriphRequest = LL_DMAMUX_REQ_ADC1; DMA_Init_Struct.Priority = LL_DMA_PRIORITY_LOW;

LL_DMA_Init(DMA1,LL_DMA_CHANNEL_1,&DMA_Init_Struct);

/ USER CODE END ADC1_DMA_Init 1 /

ADC_InitStruct.Clock = LL_ADC_CLOCK_SYNC_PCLK_DIV2; ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B; ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE; LL_ADC_Init(ADC1, &ADC_InitStruct); LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_CONFIGURABLE);

/ Poll for ADC channel configuration ready / while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0) { } LL_ADC_ClearFlag_CCRDY(ADC1); ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE; ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_6RANKS; ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE; ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS; ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED; ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);

LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE); LL_ADC_SetTriggerFrequencyMode(ADC1, LL_ADC_CLOCK_FREQ_MODE_HIGH); LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_12CYCLES_5); LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_2, LL_ADC_SAMPLINGTIME_12CYCLES_5); LL_ADC_DisableIT_EOC(ADC1); LL_ADC_DisableIT_EOS(ADC1);

/ Enable ADC internal voltage regulator / LL_ADC_EnableInternalRegulator(ADC1);
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--; }

LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_5); while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0); LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_5, LL_ADC_SAMPLINGTIME_COMMON_1);

LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_6); while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0); LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_6, LL_ADC_SAMPLINGTIME_COMMON_1);

LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_3, LL_ADC_CHANNEL_7); while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0); LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_7, LL_ADC_SAMPLINGTIME_COMMON_1);

LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_4, LL_ADC_CHANNEL_8); while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0); LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_8, LL_ADC_SAMPLINGTIME_COMMON_1);

LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_5, LL_ADC_CHANNEL_9); while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0); LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_9, LL_ADC_SAMPLINGTIME_COMMON_1);

LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_6, LL_ADC_CHANNEL_10); while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0); LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_10, LL_ADC_SAMPLINGTIME_COMMON_1);

LL_ADC_StartCalibration(ADC1); while(LL_ADC_IsCalibrationOnGoing(ADC1)) { }

LL_ADC_Enable(ADC1); while(LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0); LL_ADC_REG_StartConversion(ADC1); LL_DMA_EnableChannel(DMA1,LL_DMA_CHANNEL_1);

}

收藏 评论4 发布时间:2025-8-2 11:09

举报

4个回答
jinli 回答时间:昨天 10:41

还没等来大神回复啊,自顶一下。

老牛洋车 回答时间:昨天 13:41

没看明白楼主的描述,是不是同时开通了多个ADC通道,然后通过DMA连续获得转换结果,然而DMA数组中数据的顺序与通道设置的顺序不一致。

我之前做过双通道示波器的实验,开通了两个转换通道,也是通过DMA来获得转换结果,然后通过DMA数组下标的奇偶来区分通道1或通道2。实验结果大部分时间转换结果是正常的,但是偶尔会两个通道的数据交换,原来偶数下标的数据成为了通道2的,也就是说转换时通道的先后次序改变了。我分析了很久都没有找到原因,多方求助也没有结果,最后实验没能得到预期的结果。

xmshao 回答时间:昨天 14:39

image.png

对于STM32G0系列来说,这里有两种配置模式,如果所用硬件通道号大于14以后,

就只能配置为not fully configurable模式,这时 转换顺序按默认硬件变化,转换方向

要么从前往后 要么从后往前。

另外一种模式就是fully configruable模式,这时转换顺序可以根据RANK配置。

如果所用硬件通道编号不超过14,两种模式都可以。

我刚才使用cubeMx和HAL库组织代码测试了下,传输符合设计预期。

会不会你代码方面有问题?

现在所用通道都到15了,你这句配置是有问题的:

LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_CONFIGURABLE);

应该是

LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_FIXED);

butterflyspring 回答时间:昨天 15:11
楼主试试将校准那部分注释掉,看看顺序是否正常了。

当然,转换结果会有些许偏差,但不影响顺序。


我这边测试,发现这样写校准函数不合适,可以照搬库里面的例程准函数的写法。

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版