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

关于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

查看全部评分

toofree 回答时间: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 结贴奖励

查看全部评分

toofree 回答时间: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个数据呢
dsjsjf 回答时间:2018-3-22 11:39:06
ADC总线时钟配置成38.4M,ADC时钟分频设置为256分频,得到150K的频率,采样时间设置为47.5Cycles,得出的最终采样频率是2.5K(150K/(47.5+12.5))

QQ截图20180322113324.jpg
QQ截图20180322113831.jpg

评分

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

查看全部评分

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管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版