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

关于STM32L476RC ADC DMA时钟的配置问题

[复制链接]
ccmm520 提问时间:2018-3-21 12:00 /
总线时钟是64M,目前要实现ADC的采样频率为2.5kHz,代码中需要如何配置ADC和DMA的相关时钟?
目前配置代码如下:
  1. void SystemClock_Config(void)
  2. {

  3.   RCC_OscInitTypeDef RCC_OscInitStruct;
  4.   RCC_ClkInitTypeDef RCC_ClkInitStruct;
  5.   RCC_PeriphCLKInitTypeDef PeriphClkInit;

  6.     /**Initializes the CPU, AHB and APB busses clocks
  7.     */
  8.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
  9.   RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  10.   RCC_OscInitStruct.MSICalibrationValue = 0;
  11.   RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  12.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  13.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  14.   RCC_OscInitStruct.PLL.PLLM = 1;
  15.   RCC_OscInitStruct.PLL.PLLN = 40;
  16.   RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  17.   RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  18.   RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;

  19.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  20.   {
  21.     Error_Handler();
  22.   }

  23.     /**Initializes the CPU, AHB and APB busses clocks
  24.     */
  25.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  26.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  27.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  28.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  29.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  30.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  31.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  32.   {
  33.     Error_Handler();
  34.   }

  35.   PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART3|RCC_PERIPHCLK_ADC;
  36.   PeriphClkInit.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1;
  37.   PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
  38.   PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
  39.   PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
  40.   PeriphClkInit.PLLSAI1.PLLSAI1N = 16;
  41.   PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
  42.   PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
  43.   PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
  44.   PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
  45.   if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  46.   {
  47.     Error_Handler();
  48.   }
  49.        
  50.     /**Configure the main internal regulator output voltage
  51.     */
  52.   if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  53.   {
  54.     Error_Handler();
  55.   }

  56.     /**Configure the Systick interrupt time
  57.     */
  58.   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  59.     /**Configure the Systick
  60.     */
  61.   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  62.   /* SysTick_IRQn interrupt configuration */
  63.   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
  64. }
复制代码
  1. /* ADC1 init function */
  2. void MX_ADC1_Init(void)
  3. {
  4.   ADC_MultiModeTypeDef multimode;
  5.   ADC_ChannelConfTypeDef sConfig;
  6.     /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
  7.     */
  8.   hadc1.Instance = ADC1;
  9.   hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV8;
  10.   hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  11.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  12.   hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
  13.   hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  14.   hadc1.Init.LowPowerAutoWait = DISABLE;
  15.   hadc1.Init.ContinuousConvMode = ENABLE;
  16.   hadc1.Init.NbrOfConversion = 4;
  17.   hadc1.Init.DiscontinuousConvMode = DISABLE;
  18.   hadc1.Init.NbrOfDiscConversion = 1;
  19.   hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  20.   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  21.   hadc1.Init.DMAContinuousRequests = DISABLE;
  22.   hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  23.   hadc1.Init.OversamplingMode = DISABLE;
  24.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
  25.   {
  26.     Error_Handler();
  27.   }

  28.     /**Configure the ADC multi-mode
  29.     */
  30.   multimode.Mode = ADC_MODE_INDEPENDENT;
  31.   if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  32.   {
  33.     Error_Handler();
  34.   }

  35.   sConfig.Channel = ADC_CHANNEL_5;
  36.   sConfig.Rank = ADC_REGULAR_RANK_1;
  37.   sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5; //47.5 个ADC 时钟
  38.   sConfig.SingleDiff   = ADC_SINGLE_ENDED;            /* Single-ended input channel */
  39.   sConfig.OffsetNumber = ADC_OFFSET_NONE;             /* No offset subtraction */
  40.   sConfig.Offset = 0;                                 /* Parameter discarded because offset correction is disabled */
  41.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  42.   {
  43.     Error_Handler();
  44.   }

  45.     /**Configure Regular Channel
  46.     */
  47.   sConfig.Channel = ADC_CHANNEL_6;
  48.   sConfig.Rank = ADC_REGULAR_RANK_2;
  49.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  50.   {
  51.     Error_Handler();
  52.   }

  53.     /**Configure Regular Channel
  54.     */
  55.   sConfig.Channel = ADC_CHANNEL_3;
  56.   sConfig.Rank = ADC_REGULAR_RANK_3;
  57.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  58.   {
  59.     Error_Handler();
  60.   }

  61.     /**Configure Regular Channel
  62.     */
  63.   sConfig.Channel = ADC_CHANNEL_4;
  64.   sConfig.Rank = ADC_REGULAR_RANK_4;
  65.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  66.   {
  67.     Error_Handler();
  68.   }

  69. }

  70. void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
  71. {
  72.   GPIO_InitTypeDef GPIO_InitStruct;
  73. //  static DMA_HandleTypeDef hdma_adc1;
  74.   
  75.   if(hadc->Instance==ADC1)
  76.   {
  77.   /* USER CODE BEGIN ADC1_MspInit 0 */

  78.   /* USER CODE END ADC1_MspInit 0 */
  79.     /* ADC1 clock enable */
  80.     __HAL_RCC_ADC_CLK_ENABLE();
  81.   
  82.     /**ADC1 GPIO Configuration   
  83.     PC2     ------> ADC1_IN3
  84.     PC3     ------> ADC1_IN4
  85.     PA0     ------> ADC1_IN5
  86.     PA1     ------> ADC1_IN6
  87.     */
  88.     GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
  89.     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
  90.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  91.     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  92.        
  93.     GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
  94.     GPIO_InitStruct.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
  95.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  96.     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  97. //    GPIO_InitStruct.Pin = GPIO_PIN_1;
  98. //    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  99. //    GPIO_InitStruct.Pull = GPIO_NOPULL;
  100. //    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  101.     /* Peripheral DMA init*/
  102.   
  103.     hdma_adc1.Instance = DMA1_Channel1;
  104.     hdma_adc1.Init.Request = DMA_REQUEST_0;
  105.     hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
  106.     hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
  107.     hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
  108.     hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
  109.     hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
  110.     hdma_adc1.Init.Mode = DMA_CIRCULAR;
  111.     hdma_adc1.Init.Priority = DMA_PRIORITY_MEDIUM;
  112.     if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
  113.     {
  114.       Error_Handler();
  115.     }

  116.     __HAL_LINKDMA(hadc,DMA_Handle,hdma_adc1);

  117.   /* USER CODE BEGIN ADC1_MspInit 1 */

  118.   /* USER CODE END ADC1_MspInit 1 */
  119.   }
  120. }

  121. void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)
  122. {
  123.   if(hadc->Instance==ADC1)
  124.   {
  125.   /* USER CODE BEGIN ADC1_MspDeInit 0 */

  126.   /* USER CODE END ADC1_MspDeInit 0 */
  127.     /* Peripheral clock disable */
  128.     __HAL_RCC_ADC_CLK_DISABLE();
  129.   
  130.     /**ADC1 GPIO Configuration   
  131.     PC2     ------> ADC1_IN3
  132.     PC3     ------> ADC1_IN4
  133.     PA0     ------> ADC1_IN5
  134.     PA1     ------> ADC1_IN6
  135.     */
  136.     HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1);
  137.     HAL_GPIO_DeInit(GPIOC, GPIO_PIN_2|GPIO_PIN_3);
  138. //                HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1);
  139.     /* Peripheral DMA DeInit*/
  140.     HAL_DMA_DeInit(hadc->DMA_Handle);
  141.   }
  142.   /* USER CODE BEGIN ADC1_MspDeInit 1 */

  143.   /* USER CODE END ADC1_MspDeInit 1 */
  144. }
复制代码
  1. void MX_DMA_Init(void)
  2. {
  3.   /* DMA controller clock enable */
  4.   __HAL_RCC_DMA1_CLK_ENABLE();

  5.   /* DMA interrupt init */
  6.   /* DMA1_Channel1_IRQn interrupt configuration */
  7.   HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  8.   HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);

  9. }
复制代码
目前都好模糊,也找不到对应的数据手册,求大神帮忙解决~
收藏 评论9 发布时间:2018-3-21 12:00

举报

9个回答
feixiang20 回答时间:2018-3-21 12:21:19
要不先去参考下STM32 DMA使用详解这个资料

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

wenyangzeng 回答时间:2018-3-21 13:20:19
官方的参考资料有介绍:

无标题.png

STM32L4模数转换模块(ADC)介绍.rar (506.18 KB, 下载次数: 40)

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2

查看全部评分

七哥 回答时间:2018-3-21 15:00:24

按照你程序配出来的ADC时钟是32M,不是64M。系统时钟是80M。
我改了下PLLSAI1的N值,ADC时钟才成64M的。
傲游截图20180321144107.png

你要的ADC采样为2.5KHz,是4个通道循环为一周期算的频率呢,还是就指ADC本身的采样频率。

如果是本身ADC采样频率的话,取决于ADC主时钟和采样时间设置。
比如,你要设置2.5KHz采样的话,采样时间假如设置为最大的640.5 cycles,那么主时钟频率就是2.5K*640.5=1601250=1.60125MHz。ADC主时钟能不能设置这么小还两说。
傲游截图20180321145554.png

评分

参与人数 1蝴蝶豆 +3 收起 理由
zero99 + 3

查看全部评分

ccmm520 回答时间:2018-3-21 19:23:21
toofree 发表于 2018-3-21 15:00
按照你程序配出来的ADC时钟是32M,不是64M。系统时钟是80M。
我改了下PLLSAI1的N值,ADC时钟才成64M的。

时钟问题已解决,谢谢~
另外,问一下:
在做ADC-DMA转电压值时,输出值存储在uhADCxConvertedValue中,长度为256,但是打印出来的值每个通道的前128个有数值,但是后128个数据都为0,很奇怪,不知道为什么?

#define NB  256 //每个通道长度为256
#define CHN  2  //两个通道
#define ADCNB NB*CHN

u16 uhADCxConvertedValue[NB][CHN];

HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&uhADCxConvertedValue, ADCNB);

for(int a=0;a<NB;a++){
  printf("uhADCxConvertedValue[%d][0]= %d\r\n",a,uhADCxConvertedValue[a][0]);  //通道1的数据
  printf("uhADCxConvertedValue[%d][1]= %d\r\n",a,uhADCxConvertedValue[a][1]); //通道2的数据
}

评分

参与人数 1蝴蝶豆 +2 收起 理由
zero99 + 2 结贴奖励

查看全部评分

七哥 回答时间:2018-3-21 22:05:39
本帖最后由 toofree 于 2018-3-21 22:21 编辑

没看出来,你什么时候读数据的?
从程序看,DMA会进两次中断,第一次是一半传输完,第二次是全部传输完
ccmm520 回答时间:2018-3-22 09:52:05
toofree 发表于 2018-3-21 22:05
没看出来,你什么时候读数据的?
从程序看,DMA会进两次中断,第一次是一半传输完,第二次是全部传输完
...
  1. int main(void)
  2. {
  3.   /* USER CODE BEGIN 1 */

  4.   /* USER CODE END 1 */
  5.   /* MCU Configuration----------------------------------------------------------*/
  6.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  7.   HAL_Init();
  8.   /* Configure the system clock */
  9.   SystemClock_Config();
  10.   /* Initialize all configured peripherals */
  11.   MX_GPIO_Init();
  12. #if DEBUG_ENABLE
  13.    debugInit(115200);
  14. #endif
  15.   MX_DMA_Init();
  16.   MX_ADC1_Init();

  17.   HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); //不校准会出现检测结果有偏差
  18.   HAL_ADC_Start_DMA(&hadc1, (uint32_t*)uhADCxConvertedValue, ADCNB);
  19.   
  20.   while (1)
  21.   {
  22.                 if(dmaflage==1)
  23.                 {
  24.                         dmaflage=0;

  25.                         for(int a=0;a<NB;a++){
  26.                           printf("uhADCxConvertedValue[%d][0]= %d\r\n",a,uhADCxConvertedValue[a][0]);  //通道1的数据
  27.                           printf("uhADCxConvertedValue[%d][1]= %d\r\n",a,uhADCxConvertedValue[a][1]); //通道2的数据
  28.                         }

  29.                         HAL_ADC_Start_DMA(&hadc1, (uint32_t*)uhADCxConvertedValue, ADCNB);
  30.                 }
  31.   }
  32. }
复制代码

dmaflage在DMA中断的时候进行赋值1的。

我这还有个疑问,你说的这句话“从程序看,DMA会进两次中断,第一次是一半传输完,第二次是全部传输完”怎么理解,我现在遇到一个问题就是中断给dmaflage赋值1后,我就在while进行读值,每次只读到uhADCxConvertedValue的前128个数据有值,后128个数据都是0;是不是和你说的这句话有关,麻烦帮忙解释下“DMA会进两次中断,第一次是一半传输完,第二次是全部传输完”?我需要怎么操作才能读完整这256个数据呢
埃斯提爱慕 回答时间:2018-3-22 11:39:06
提示: 作者被禁止或删除 内容自动屏蔽
yecho 回答时间:2020-4-20 17:51:05
我的问题是,用DMA配置一个300HZ的ADC,我想尝试用两种方法来实现:
1,如楼上朋友的方法,通过中断标志来读取
2,通过外部中断TIM3触发采样,TIM3设置为300HZ定时器
但是遇到的问题是,方式一,CLOCK如何配置?
问题二,调试时
__IO uint16_t uhADCxConvertedValue[1000];

  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)uhADCxConvertedValue,10);
启动DMA后,进不了中断。
但是,修改为HAL_ADC_Start_DMA(&hadc1, (uint32_t*)uhADCxConvertedValue,4); // 测试1,2,3,4都能进中断。请各位老师帮忙指点一下是什么原因大于4就不能进中断呢?
我的配置和源代码如下:
微信图片_20200420173747.png 微信图片_20200420173445.png
int main(void)
{
  /* USER CODE BEGIN 1 */
  /* USER CODE END 1 */
  /* MCU Configuration----------------------------------------------------------*/
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  /* 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();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)uhADCxConvertedValue,4);
  printf("start\r");
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
    HAL_Delay(1000);
    printf("1scc\r");
  /* USER CODE BEGIN 3 */
    //check_ecg_dma_data();
  }
  /* USER CODE END 3 */
}
打的DEBUG LOG位置:
void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
    printf("dma ir\r");
  /* USER CODE END DMA1_Channel1_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_adc1);
  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
  /* USER CODE END DMA1_Channel1_IRQn 1 */
}

__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hadc);
    printf("cplt \r");
  /* NOTE : This function should not be modified. When the callback is needed,
            function HAL_ADC_ConvCpltCallback must be implemented in the user file.
   */
}


启动后的打印log:
dma ir
dma ir
cplt
start
1scc
1scc
1scc
1scc
1scc

把参数修改为10后:
start
1scc

1scc

1scc

1scc

1scc

1scc

1scc






yecho 回答时间:2020-4-20 17:59:19
为何我发的贴子看不到呢?

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版