使用stm32G030C8T6芯片,配置ADC的DMA传输,ADC的DR寄存器数据正确,DMA数据错误
下面是配置代码
#if ADC_CONFIG_ENABLE
#define ADC_CHANNEL_COUN 1
#define ADC_ADD_COUN 1
#define ADC_DATA_COUNTER 1
#define CHANNEL 4
#define ADC_DELAY_CALIB_ENABLE_CPU_CYCLES (LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES * 32)
struct
{
vu32 DataTemp[ADC_CHANNEL_COUN];
vu16 DataCouter[ADC_CHANNEL_COUN];
vu16 Buffer[ADC_CHANNEL_COUN * ADC_ADD_COUN];
vu16 OutputData[ADC_CHANNEL_COUN];
vu32 Max[ADC_CHANNEL_COUN];//最大值
vu16 OUtputMax[ADC_CHANNEL_COUN];//最大值输出
vs16 TemperatureBuffer[CHANNEL];
vu16 VolumeBuffer[CHANNEL];
vu16 Flag;
vu32 SwitchCounter;
vu16 OutputTemperature[CHANNEL];
vu16 OutputVolume[CHANNEL];
vu16 OutputAcVoltage;
} AdcData;
void ADC_Config(void)
{
uint32_t wait_loop_index;
LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {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);
/* DMA controller clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
/**ADC1 GPIO Configuration
PA0 ------> ADC1_IN0
PA1 ------> ADC1_IN1
PA2 ------> ADC1_IN2
PA3 ------> ADC1_IN3
PA4 ------> ADC1_IN4
PA5 ------> ADC1_IN5
PA6 ------> ADC1_IN6
PA7 ------> ADC1_IN7
PB0 ------> ADC1_IN8
PB1 ------> ADC1_IN9
PB2 ------> ADC1_IN10
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_0 | LL_GPIO_PIN_1 |LL_GPIO_PIN_2 |
LL_GPIO_PIN_3 | LL_GPIO_PIN_4 | LL_GPIO_PIN_5|
LL_GPIO_PIN_6 | 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 | LL_GPIO_PIN_1 |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 */
/* ADC1 Init */
//LL_DMA_DeInit(DMA1,LL_DMA_CHANNEL_1);
// DMA传输方向 外设->内存
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
// 通道优先级 低
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);
// DMA模式 循环
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
// 外设地址递增模式 失能
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
// 内存地址递增模式 使能
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
// 外设半字
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);
// 内存半字
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
//外设地址
LL_DMA_SetPeriphAddress(DMA1,LL_DMA_CHANNEL_1,(uint32_t)&ADC1->DR);
// 内存地址
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)&AdcData.Buffer[0]);
// DMA传输数据长度
LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_1,ADC_ADD_COUN*ADC_CHANNEL_COUN);
LL_ADC_EnableInternalRegulator(ADC1);
LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_0
#if 0
|LL_ADC_CHANNEL_1
|LL_ADC_CHANNEL_2|LL_ADC_CHANNEL_3
|LL_ADC_CHANNEL_4|LL_ADC_CHANNEL_5
|LL_ADC_CHANNEL_6|LL_ADC_CHANNEL_7
|LL_ADC_CHANNEL_8|LL_ADC_CHANNEL_9
|LL_ADC_CHANNEL_10
#endif
);
NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);//使能DMA通道一完成中断
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
ADC_InitStruct.Clock = LL_ADC_CLOCK_SYNC_PCLK_DIV4; //ADC时钟分频
ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B; // 采样分辨率
ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT; // 对齐方式
ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE; // 低功耗模式,使用DMA的话无法使用,这里关闭
LL_ADC_Init(ADC1, &ADC_InitStruct);
#define ADC_CHANNEL_CONF_RDY_TIMEOUT_MS ( 1U)
#define USE_TIMEOUT 1
#if (USE_TIMEOUT == 1)
uint32_t Timeout ; /* Variable used for Timeout management */
#endif /* USE_TIMEOUT */
ADC_REG_InitStruct.triggerSource = LL_ADC_REG_TRIG_SOFTWARE; // 软件触发方式
//ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS; // 规则通道连续转换
// 使能DMA,并使用无限传输,如果DMA保存方式为循环覆盖的话才可以使用无限传输
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_LIMITED;
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED; // 采集的数据循环覆盖模式
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); // 采样时钟使用高频模式
//adc通道和硬件adc in是否强制对应,因为adc的io使用时是连续的,所以这里使用非完全配置
LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_FIXED);
// 设置通道共用取样时间,根据需要自行选择
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_160CYCLES_5);
LL_ADC_DisableIT_EOC(ADC1); // 禁用通道采样结束中断
LL_ADC_DisableIT_EOS(ADC1); // 禁用序列采样结束中断
LL_ADC_REG_SetSequencerScanDirection(ADC1, LL_ADC_REG_SEQ_SCAN_DIR_FORWARD); //扫描方向为通道数字从小到大
/* Poll for ADC channel configuration ready */
#if (USE_TIMEOUT == 1)
Timeout = ADC_CHANNEL_CONF_RDY_TIMEOUT_MS;
#endif /* USE_TIMEOUT */
while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0)
{
#if (USE_TIMEOUT == 1)
/* Check Systick counter flag to decrement the time-out value */
if(Timeout-- == 0)
{
//Error_Handler();
break;
}
#endif /* USE_TIMEOUT */
}
/* Clear flag ADC channel configuration ready */
LL_ADC_ClearFlag_CCRDY(ADC1);
wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
while(wait_loop_index != 0)
{
wait_loop_index--;
}
//DMA通道请求
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_ADC1);
LL_ADC_StartCalibration(ADC1);
while(LL_ADC_IsCalibrationOnGoing(ADC1));
wait_loop_index = (ADC_DELAY_CALIB_ENABLE_CPU_CYCLES >> 1);
while(wait_loop_index != 0)
{
wait_loop_index--;
}//等待校准
//启动ADC
LL_ADC_Enable(ADC1);
LL_ADC_REG_StartConversion(ADC1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); //使能
}
void ADC_GetValue(void)
{
u32 temp = 0; u16 tempMax = 0;
u8 i = 0;
u8 ChannelTemp=0;
for(ChannelTemp=0;ChannelTemp<ADC_CHANNEL_COUN;ChannelTemp++)
{
temp = 0;
tempMax = 0;
for(i = 0; i <ADC_ADD_COUN; i++)
{
temp += AdcData.Buffer[i*ADC_CHANNEL_COUN+ChannelTemp];
if(tempMax < AdcData.Buffer[i*ADC_CHANNEL_COUN+ChannelTemp])
{tempMax = AdcData.Buffer[i*ADC_CHANNEL_COUN+ChannelTemp];}
}
temp = temp/ADC_ADD_COUN;
if(temp>60000){temp=60000;}
AdcData.DataTemp[ChannelTemp]+=temp;
AdcData.Max[ChannelTemp] += tempMax;
AdcData.DataCouter[ChannelTemp]++;
if(AdcData.DataCouter[ChannelTemp]>=ADC_DATA_COUNTER)
{
AdcData.OutputData[ChannelTemp]=(u16)(AdcData.DataTemp[ChannelTemp]/ADC_DATA_COUNTER);
AdcData.OUtputMax[ChannelTemp] = (u16)(AdcData.Max[ChannelTemp] / ADC_DATA_COUNTER);
AdcData.Max[ChannelTemp] = 0;
AdcData.DataTemp[ChannelTemp]=0;
AdcData.DataCouter[ChannelTemp]=0;
}
}
}
void DMA1_Channel1_IRQHandler(void)
{
if(LL_DMA_IsActiveFlag_TC1(DMA1))
{
LL_DMA_ClearFlag_TC1(DMA1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
LL_ADC_Disable(ADC1);
ADC_GetValue();
// DMA传输数据长度
LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_1,ADC_ADD_COUN*ADC_CHANNEL_COUN);
//启动ADC
LL_ADC_Enable(ADC1);
LL_ADC_REG_StartConversion(ADC1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);//
}
}
#endif
主程序输出串口查看数据
USART1_SendData((u8*)&ADC1->DR,2);
USART1_SendData((u8*)AdcData.Buffer[0],2);
数据情况
两个1k电阻分压3.3v输入,ad结果截图,DMA 一直不正确
[10:21:57.059]收←◆0B 08 68 EB
[10:21:58.058]收←◆0B 08 68 EB
[10:21:59.058]收←◆0A 08 A9 68
[10:22:00.058]收←◆0B 08 68 EB
[10:22:01.058]收←◆0B 08 68 EB
前两个为寄存器DR输出 的值,0x080b转为电压大概1.66v是正确数值,DMA一直不正确