|
stm32g070rbt6 ADC1 多通道循环自动采样DMA传输到ram,采样值不准,而且开启校准的话值会更不准 /* USER CODE BEGIN Header */ /** --- * @file : main.c * @brief : Main program body --- * @attention * * Copyright (c) 2026 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * --- */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ uint16_t adc_buffer[3]={0}; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_ADC1_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ // /************************* ADC?? ???? *************************/ // // // if (LL_ADC_IsEnabled(ADC1) == 1) { // LL_ADC_Disable(ADC1); // } // // // LL_ADC_StartCalibration(ADC1); // // // Timeout = ADC_CALIBRATION_TIMEOUT_MS; // while (LL_ADC_IsCalibrationOnGoing(ADC1) == 1) { // if (LL_SYSTICK_IsActiveCounterFlag()) { // if (Timeout-- == 0) { // Error_Handler(); // } // } // } // /********************************************************************/ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR); /* SysTick_IRQn interrupt configuration */ NVIC_SetPriority(SysTick_IRQn, 3); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_ADC1_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { LL_FLASH_SetLatency(LL_FLASH_LATENCY_2); while(LL_FLASH_GetLatency() != LL_FLASH_LATENCY_2) { } /* HSI configuration and activation */ LL_RCC_HSI_Enable(); while(LL_RCC_HSI_IsReady() != 1) { } /* Main PLL configuration and activation */ LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_1, 8, LL_RCC_PLLR_DIV_2); LL_RCC_PLL_Enable(); LL_RCC_PLL_EnableDomain_SYS(); while(LL_RCC_PLL_IsReady() != 1) { } /* Set AHB prescaler*/ LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); /* Sysclk activation on the main PLL */ LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) { } /* Set APB1 prescaler*/ LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); LL_Init1msTick(64000000); /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */ LL_SetSystemCoreClock(64000000); } /** * @brief ADC1 Initialization Function * @param None * @retval None */ static void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ #define USE_TIMEOUT 1 #define ADC_CALIBRATION_TIMEOUT_MS 100U /* 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); /**ADC1 GPIO Configuration PA2 ------> ADC1_IN2 PA3 ------> ADC1_IN3 PA6 ------> ADC1_IN6 */ GPIO_InitStruct.Pin = LL_GPIO_PIN_2; 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_3; 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); /* ADC1 DMA Init */ /* ADC1 Init */ LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_ADC1); 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); LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR); 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); /* USER CODE BEGIN ADC1_Init 1 */ LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)&ADC1->DR); LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t) adc_buffer); LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, (uint32_t) 3); /* USER CODE END ADC1_Init 1 */ /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ #define ADC_CHANNEL_CONF_RDY_TIMEOUT_MS ( 1U) #if (USE_TIMEOUT == 1) uint32_t Timeout ; /* Variable used for Timeout management */ #endif /* USE_TIMEOUT */ 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 */ #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 (LL_SYSTICK_IsActiveCounterFlag()) { if(Timeout-- == 0) { Error_Handler(); } } #endif /* USE_TIMEOUT */ } /* Clear flag ADC channel configuration ready */ LL_ADC_ClearFlag_CCRDY(ADC1); ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE; ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_3RANKS; ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS; ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE; 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_39CYCLES_5); LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_2, LL_ADC_SAMPLINGTIME_39CYCLES_5); LL_ADC_DisableIT_EOC(ADC1); LL_ADC_DisableIT_EOS(ADC1); /* Enable ADC internal voltage regulator */ LL_ADC_EnableInternalRegulator(ADC1); /* Delay for ADC internal voltage regulator stabilization. */ /* Compute number of CPU cycles to wait for, from delay in us. */ /* Note: Variable divided by 2 to compensate partially */ /* CPU processing cycles (depends on compilation optimization). */ /* Note: If system core clock frequency is below 200kHz, wait time */ /* is only a few CPU processing cycles. */ __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--; } /************************* ADC?? ???? *************************/ // // if (LL_ADC_IsEnabled(ADC1) == 1) { // LL_ADC_Disable(ADC1); // } // // // LL_ADC_StartCalibration(ADC1); // // // Timeout = ADC_CALIBRATION_TIMEOUT_MS; // while (LL_ADC_IsCalibrationOnGoing(ADC1) == 1) { // if (LL_SYSTICK_IsActiveCounterFlag()) { // if (Timeout-- == 0) { // Error_Handler(); // } // } // } /********************************************************************/ /** Configure Regular Channel */ LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_2); /* 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 (LL_SYSTICK_IsActiveCounterFlag()) { if(Timeout-- == 0) { Error_Handler(); } } #endif /* USE_TIMEOUT */ } /* Clear flag ADC channel configuration ready */ LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_COMMON_1); /** Configure Regular Channel */ LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_3); /* 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 (LL_SYSTICK_IsActiveCounterFlag()) { if(Timeout-- == 0) { Error_Handler(); } } #endif /* USE_TIMEOUT */ } /* Clear flag ADC channel configuration ready */ LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_COMMON_1); /** Configure Regular Channel */ LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_3, LL_ADC_CHANNEL_6); /* 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 (LL_SYSTICK_IsActiveCounterFlag()) { if(Timeout-- == 0) { Error_Handler(); } } #endif /* USE_TIMEOUT */ } /* Clear flag ADC channel configuration ready */ LL_ADC_ClearFlag_CCRDY(ADC1); LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_6, LL_ADC_SAMPLINGTIME_COMMON_1); /* USER CODE BEGIN ADC1_Init 2 */ LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); // LL_ADC_Enable(ADC1); // while(LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0); LL_ADC_ClearFlag_ADRDY(ADC1); LL_ADC_REG_StartConversion(ADC1); /* USER CODE END ADC1_Init 2 */ } /** * Enable DMA controller clock */ static void MX_DMA_Init(void) { /* Init with LL driver */ /* DMA controller clock enable */ LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); /* DMA interrupt init */ /* DMA1_Channel1_IRQn interrupt configuration */ //NVIC_SetPriority(DMA1_Channel1_IRQn, 0); //NVIC_EnableIRQ(DMA1_Channel1_IRQn); /* DMA1_Ch4_7_DMAMUX1_OVR_IRQn interrupt configuration */ //NVIC_SetPriority(DMA1_Ch4_7_DMAMUX1_OVR_IRQn, 0); //NVIC_EnableIRQ(DMA1_Ch4_7_DMAMUX1_OVR_IRQn); } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ |
ST-LINK Utility不能识别STM32G0的芯片,不能下载程序
STM32G030J6M6如何禁用NRST将其复用为ADC
年终77折活动,有哪些想兑换的?
stm32G030C8T6 官方例程库
简单聊聊STM32的SPI外设
How to write the stm32g0's dts file for RB3 Gen2 ?
MDK5使用AC6优化等级问题
CMSIS里提供的GCC ld链接文件疑问
大家晚上好啊
stm32G071RBT6跑TOUCHGFX的时候使用仪表控件,更新数值的时候会卡死,怎么解决
微信公众号
手机版
不过它对电池电压检测,没有必要连续检测。定时间隔检测一下就好了。
这样它的采样时间长点也没问题。
[md]采样电路的输入阻抗太大了,R27 R28同时缩小10倍吧。
这个电路的确是对ADC采样有要求,需要更长的采样时间。
两个电阻比较大,那么它上面的电流就非常小,对ADC的采样电容充电时间必然会长一些。
对于ADC来说,就是一个高内阻。它的电压采样是有难度的。不考虑成本的话,加个跟随器是最好的。
你可以将这个分压电阻等比例减小,估计采样速度就可以提高些。
看你的补充描述,咋看起来有点逆天的味道。
问题很可能根本不是ADC本身的问题,先把芯片本身坏损原因除外,我怀疑你硬件系统有问题。建议你重点检查下你的硬件这块,尤其供电、接地这些。
时钟配置这块尽量使用CubeMx配置,至于基于HAL库还是LL库创建工程倒无所谓。如果单纯手动
操作寄存器,万一配置了不合适的时钟频率恐难以一时发现。
ADC本身配合DMA是完全可以正常工作的,这点放心。我随便选择了3个通道做了测试,2个通道接固定电压信号,另一通道悬空。ADC工作时钟16MHz, 设置12.5CLK采样时间。结果是正常的。
可以增加一个通道采集内部参考电压 VREFINT。
这个电压是固定电压,试试采样时间是否也需要在多通道扫描下增加才能采集的准。
通过这个方式判断ADC的采样时间需拉长是硬件问题,还是采样时刻问题。
然后根据需要再改回LL库。 好处是有了参照。 避免以往一些细节。
有些代码需要前后关联,或者顺序。有了成功的HAL库生成的代码,按照它的顺序,不容易出错。
还有一种方式混合编程,也可以节省一定代码空间,又能完成高效正确的初始化配置。
ADC单次和自动连续转换的时钟差异
和hal版本对比过了,hal版本的采样时钟也要设置得很慢才能采样到一定精度的值,而且采样时间长了精度会和时间短了一样不高.
之前的程序可以,之前的程序使用的是当次转换非DMA模式,有两路ADC采样,用于RFID检卡和检测电池电压,因为需求变更,需要再增加一路ADC用于检测直流有刷电机的电枢电流,由于电机ADC要在中断里面采样(10ms的采样周期)用于电机堵转控制,所以三路ADC的实现方式用自动连续转换DMA传输的方式,之前在同一个的硬件上使用下面的配置如下,ADC转换时间很短,原帖上面是需求变更后的程序,
当前的程序要达到一定的精度的话要把时钟配置成下面这样,时钟配置和之前的差异很大,不清楚这是什么原因
:
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_SYSCLK);
LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_ASYNC_DIV16);
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_160CYCLES_5);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_2, LL_ADC_SAMPLINGTIME_160CYCLES_5);
之前的单次转换程序:
/* Timeout values for ADC operations. */
/* (calibration, enable settling time, disable settling time, ...) */
/* Values defined to be higher than worst cases: low clock frequency, */
/* maximum prescalers. */
/* Unit: ms */
#define ADC_CHANNEL_CONF_RDY_TIMEOUT_MS ( 1U)
#define ADC_CALIBRATION_TIMEOUT_MS ( 1U)
#define ADC_ENABLE_TIMEOUT_MS ( 1U)
#define ADC_DISABLE_TIMEOUT_MS ( 1U)
#define ADC_STOP_CONVERSION_TIMEOUT_MS ( 1U)
#define ADC_CONVERSION_TIMEOUT_MS (4000U)
/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
static int MX_ADC1_Init(void)
{
unsigned int Timeout ; /* Variable used for Timeout management */
/* USER CODE BEGIN ADC1_Init 0 */
/* 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);
/**ADC1 GPIO Configuration
PA2 ------> ADC1_IN2
PA3 ------> ADC1_IN3
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
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_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
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 */
Timeout = ADC_CHANNEL_CONF_RDY_TIMEOUT_MS;
while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0){
/* Check Systick counter flag to decrement the time-out value */
if (LL_SYSTICK_IsActiveCounterFlag()){
if(Timeout-- == 0)
{
print_err("LL ADC REG SetSequencerConfigurable error...\n");
return MID_ERROR_ERROR;
}
}
}
/* Clear flag ADC channel configuration ready */
/// 经过测试,要想用非dma和中断模式只有这样配置可以正确进行多通道转换:扫描模式+单次转换模式+间断转换模式(每个间断组一个通道)
LL_ADC_ClearFlag_CCRDY(ADC1);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_2RANKS;
//ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
//ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_1RANK;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_ASYNC_DIV1);
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_1CYCLE_5);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_2, LL_ADC_SAMPLINGTIME_1CYCLE_5);
LL_ADC_DisableIT_EOC(ADC1);
LL_ADC_DisableIT_EOS(ADC1);
/* Enable ADC internal voltage regulator */
LL_ADC_EnableInternalRegulator(ADC1);
//LL_ADC_REG_SetSequencerChAdd(ADC1, LL_ADC_CHANNEL_3 | LL_ADC_CHANNEL_8);
/* Delay for ADC internal voltage regulator stabilization. */
/* Compute number of CPU cycles to wait for, from delay in us. */
/* Note: Variable divided by 2 to compensate partially */
/* CPU processing cycles (depends on compilation optimization). */
/* Note: If system core clock frequency is below 200kHz, wait time */
/* is only a few CPU processing cycles. */
unsigned int 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--;
}
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_2);
/* Poll for ADC channel configuration ready */
Timeout = ADC_CHANNEL_CONF_RDY_TIMEOUT_MS;
while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0){
/* Check Systick counter flag to decrement the time-out value */
if (LL_SYSTICK_IsActiveCounterFlag()){
if(Timeout-- == 0)
{
print_err("LL ADC REG SetSequencerRanks error...\n");
return MID_ERROR_ERROR;
}
}
}
/* Clear flag ADC channel configuration ready */
LL_ADC_ClearFlag_CCRDY(ADC1);
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_COMMON_1);
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_3);
/* Poll for ADC channel configuration ready */
Timeout = ADC_CHANNEL_CONF_RDY_TIMEOUT_MS;
while (LL_ADC_IsActiveFlag_CCRDY(ADC1) == 0){
/* Check Systick counter flag to decrement the time-out value */
if (LL_SYSTICK_IsActiveCounterFlag()){
if(Timeout-- == 0)
{
print_err("LL ADC REG SetSequencerRanks error...\n");
return MID_ERROR_ERROR;
}
}
}
/* Clear flag ADC channel configuration ready */
LL_ADC_ClearFlag_CCRDY(ADC1);
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_COMMON_1);
/* USER CODE BEGIN ADC1_Init 2 */
Timeout = ADC_CHANNEL_CONF_RDY_TIMEOUT_MS;
LL_ADC_Enable(ADC1);//开启ADC
while (LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0)
{
if (LL_SYSTICK_IsActiveCounterFlag()){
if(Timeout-- == 0)
{
print_err("LL ADC Enable error...\n");
return MID_ERROR_ERROR;
}
}
}//等待ADC准备好
return MID_ERROR_OK;
}
/***************************************************************************************
** 函数名称: ConversionStartPoll_ADC_GrpRegular
** 功能描述: 开始ADC规则转换
** 参 数: ADCx ADC instance
** 返 回 值: None
****************************************************************************************/
static int ConversionStartPoll_ADC_GrpRegular(ADC_TypeDef *ADCx)
{
unsigned int Timeout = ADC_CONVERSION_TIMEOUT_MS;
if ((LL_ADC_IsEnabled(ADCx) == 1) && \
(LL_ADC_IsDisableOngoing(ADCx) == 0) && \
(LL_ADC_REG_IsConversionOngoing(ADCx) == 0))
{
LL_ADC_REG_StartConversion(ADCx);//开始ADC转换
}
else
{
//*错误:无法执行ADC转换启动*/
print_err("adc enable failed...\n");
return MID_ERROR_ERROR;
}
while (LL_ADC_IsActiveFlag_EOC(ADCx) == 0)
{
if (LL_SYSTICK_IsActiveCounterFlag()){
if(Timeout-- == 0)
{
print_err("adc Conversion timeout...\n");
LL_ADC_ClearFlag_EOC(ADCx);//清除转换完成标志
return MID_ERROR_ERROR;
}
}
}//等待转换完成
LL_ADC_ClearFlag_EOC(ADCx);//清除转换完成标志
return MID_ERROR_OK;
}
/***************************************************************************************************************/
void adc_init_service(void)
{
MX_ADC1_Init();
}
void adc_reinit_service()
{
#if 1
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);
/**ADC1 GPIO Configuration
PA3 ------> ADC1_IN3
PB0 ------> ADC1_IN8
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
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_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
#endif
}
void adc_deinit_service(void)
{
LL_ADC_REG_StopConversion(ADC1);
LL_ADC_ClearFlag_EOC(ADC1);//清除转换完成标志
LL_ADC_ClearFlag_ADRDY(ADC1);//清除ADRDY标志
LL_ADC_DisableInternalRegulator(ADC1);
LL_ADC_Disable(ADC1);//关闭ADC
LL_ADC_DeInit(ADC1);
}
//--------------------------------------------------------------------------------------------------------------//
static int get_adc_value(unsigned short *value)
{
int idx = 0;
unsigned int Timeout = ADC_CONVERSION_TIMEOUT_MS;
if(!LL_ADC_IsEnabled(ADC1))
{
LL_ADC_Enable(ADC1);
while (LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0){
if (LL_SYSTICK_IsActiveCounterFlag()){
if(Timeout-- == 0)
{
return MID_ERROR_ERROR;
}
}
}//等待ADC准备好
}
for(idx=0; idx<2; idx++)
{
/* Check if the continous conversion is finished */
if(ConversionStartPoll_ADC_GrpRegular(ADC1) == MID_ERROR_OK)
{
/* Get the converted value */
value[idx] = LL_ADC_REG_ReadConversionData12(ADC1);
}
}
//LL_ADC_Disable(ADC1);
return MID_ERROR_OK;
}
unsigned short get_battery_value_service(void)
{
unsigned short AD_Value[2] = {0}; //AD_Value[0] --> PA2 channel 3(battery adc value)
//AD_Value[1] --> PA3 channel 8(mifare adc value)
get_adc_value(AD_Value);
return AD_Value[1];
}
unsigned short get_mifare_value_service(void)
{
unsigned short AD_Value[2] = {0}; //AD_Value[0] --> PA2 channel 3(battery adc value)
//AD_Value[1] --> PA3 channel 8(mifare adc value)
get_adc_value(AD_Value);
return AD_Value[0];
}
呵呵
至少要先把问题现象、疑惑点清晰的描述出来,之后跟上必要代码就行了。
ADC1 多通道循环自动采样DMA传输到ram,标题倒是很清晰了。具体问题是什么呢?
实现不了?结果异常?
结果异常,采样时间要设置得很长采样值才能和实际值差距小,可能和时钟有关,单次采样的时候采样时间很短也可以采样到相对准的值,但是ADC多通道循环采样DMA传送的时候就要采样时间很长而且分频值要很大才行,但是目前不清楚原因,
ADC使用内部时钟,配置如下
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_HSI);
LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_ASYNC_DIV1);
下面是两种sampletime的采样值,
//1.5cycle下,VREFINT采样值:0x0653,通道3采样的ADC:0x088A
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_1CYCLE_5);
//160.5cycle下,VREFINT采样值:0x063E,通道3采样的ADC:0x0C1F
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_160CYCLES_5);
可以看出两种不同sampletime的情况下,VERFINT的采样值差不多,但是通道3的采样值差异很大,通道3是通过分压电阻采样电池电压用的,VCC三分之一采样
VCC->1M->488K->GND,VCC是7.7V,
|
V
通道3
[md]硬件检查过了,比较稳定的产品,之前是单次多通道转换,现在需求变更只能改成连续多通道DMA的方式,
之前的ADC使用内部时钟,配置如下,
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_HSI);
LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_ASYNC_DIV1);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_1CYCLE_5);
现在配成这样不行,但是采样VERFINT的话,不管sampletime是在1.5cycle还是160.5cycle情况下,采样值比较准差距不大,其他通道在不同的sampletime下采样值差距很大
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_HSI);
LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_ASYNC_DIV1);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_1CYCLE_5);
这么做是为了尽量降低功耗
电池的话只是举个例子,还有另外两个通道包括检卡ADC和电机电枢电流采样,电机电枢电流采样间隔很短,而且要在10ms定时中断里面处理,但是在中断里面开启ADC转换并等待转换结束是不妥当的,电池和检卡ADC又要在main函数里面处理,g070只有一个ADC,这些需求冲突了,所以才想到连续转换DMA传输的方法,,这样adc资源使用不会冲突(不会产生多线程问题),但是要adc转换比较快,能自动转换
两种转换的ADC的时钟源都是HSI,然后同样的采样效果,采样时间却大不相同,而且不一定准,令人费解
,其中单次多通道转换改变时钟的话得出的结果差异不大,但是多通道连续转换改变时钟配置的话差异比较大
单次多通道间断转换:
/* Clear flag ADC channel configuration ready */
LL_ADC_ClearFlag_CCRDY(ADC1);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_2RANKS;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_1RANK;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CLOCK_ASYNC_DIV1);
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_1CYCLE_5);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_2, LL_ADC_SAMPLINGTIME_1CYCLE_5);
LL_ADC_DisableIT_EOC(ADC1);
LL_ADC_DisableIT_EOS(ADC1);
多通道连续转换(开不开启DMA不影响转换):
/* Clear flag ADC channel configuration ready */
LL_ADC_ClearFlag_CCRDY(ADC1);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_3RANKS;
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_160CYCLES_5);
LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_2, LL_ADC_SAMPLINGTIME_160CYCLES_5);
LL_ADC_DisableIT_EOC(ADC1);
LL_ADC_DisableIT_EOS(ADC1);