硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1658|回复: 13
收起左侧

[有问必答] DAC+DMA+TIM6输出波形问题

[复制链接]

1

主题

22

回帖

25

积分

新手上路

积分
25
发表于 2021-11-21 16:18:50 | 显示全部楼层 |阅读模式
本帖最后由 billy 于 2021-11-21 16:25 编辑

各位好,我在做DAC输出波形的时候,通过DMA+TIM6触发,始终没有输出,具体描述如下,哪位能指导一二,看问题到底在哪?

一,首先确定DAC正常工作。
    1.1,生成正弦波表格。
        uint8_t dat[256] = {
        128,131,134,137,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,189,191,194,197,199,202,205,207,209,212,
        ……………………
        51,54,57,59,62,65,67,70,73,76,79,82,85,88,91,94,97,100,103,106,109,112,115,119,122,125,128,
        };
    1.2,通过cubemx配置时钟,配置DAC输出:
    1.png    


1.3,生成keil工程,在main函数中通过for循环给DAC送正弦波数据表
int main(void)
{
  /* USER CODE BEGIN 1 */
        uint32_t i;
  /* USER CODE END 1 */
  这里省略了MX自动生成的代码
   ………………

  /* USER CODE BEGIN 2 */
                HAL_DAC_Start(&hdac,DAC_CHANNEL_2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
                for(i = 0;i<256;i++)
                        HAL_DAC_SetValue(&hdac,DAC_CHANNEL_2,DAC_ALIGN_8B_R,dat);
  }
  /* USER CODE END 3 */
}

  1.4,观察波形
2.png
从上面的结果来看,可以确定正弦波数据表没有错误,DAC也能正常工作。

二,接下来尝试用DMA方式:
2.1,修改DAC配置TIM6触发方式,配置DMA 循环模式,8byte宽度
3.png


4.png



2.2配置定TIM6
5.png


2.3,修改main函数
int main(void)
{
  /* USER CODE BEGIN 1 */
        uint32_t i;
  /* USER CODE END 1 */
这里省略了MX自动生成的代码
   ………………

  /* USER CODE BEGIN 2 */
   //开启TIM6,启动DAC
    HAL_TIM_Base_Start(&htim6);
     HAL_DAC_Start_DMA(&hdac,DAC_CHANNEL_2,(uint32_t *)dat,256,DAC_ALIGN_8B_R);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}


以上是尝试用tim6触发,DMA方式去生成波形,但是并没有得到任何输出。
在线仿真,程序跑起来后:
6.png
DHR8R2中的值一直是0,并没有变化,这个DMAUDR2被值位了,没有任何波形输出,手动更改DHR8R2值,输出有变化。

结论AC工作正常(因为手动更改DHR8R2有变化),DMA和TIM6并没有和DAC协调,将正弦波表格的数据一个一个送过去。

问题:网上看了不少博主写的,基本也是这样配置,目前不知道问题出在哪里。望各位指教,不胜感激!



回复

使用道具 举报

1

主题

22

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2021-11-21 16:19:48 | 显示全部楼层
?图片都哪里去了?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107100
QQ
发表于 2021-11-21 16:48:45 | 显示全部楼层
这是我的配置,供参考
  1. /*
  2. *********************************************************************************************************
  3. *
  4. *        模块名称 : DAC驱动
  5. *        文件名称 : bsp_dac.c
  6. *        版    本 : V1.0
  7. *        说    明 : DAC定时器触发+DMA方式双通道同步输出
  8. *        修改记录 :
  9. *                版本号   日期        作者     说明
  10. *                V1.0    2019-06-01  armfly   正式发布
  11. *
  12. *        Copyright (C), 2018-2030, 安富莱电子 www.armfly.com
  13. *
  14. *********************************************************************************************************
  15. */
  16. #include "bsp.h"



  17. /* 方便Cache类的API操作,做32字节对齐 */
  18. #if defined ( __ICCARM__ )
  19. #pragma location = ".RAM_D3"  
  20. ALIGN_32BYTES(uint16_t g_usWaveBuff[64]);

  21. #elif defined ( __CC_ARM )
  22. ALIGN_32BYTES(__attribute__((section (".RAM_D3"))) uint16_t g_usWaveBuff[64]);
  23. #endif


  24. /*
  25. *********************************************************************************************************
  26. *                                                                                变量
  27. *********************************************************************************************************
  28. */
  29. static TIM_HandleTypeDef      htim;
  30. static DMA_HandleTypeDef      hdma_dac1;
  31. static DMA_HandleTypeDef      hdma_dac2;
  32. static DAC_ChannelConfTypeDef sConfig;
  33. static DAC_HandleTypeDef      DacHandle;

  34. void TIM6_Config(void);
  35. void DAC_WaveConfig(void);          

  36. /*
  37. *********************************************************************************************************
  38. *        函 数 名: bsp_InitDAC
  39. *        功能说明: DAC初始化
  40. *        形    参: 无
  41. *        返 回 值: 无
  42. *********************************************************************************************************
  43. */
  44. void bsp_InitDAC(void)
  45. {   
  46.     uint8_t i;

  47.         /* 一个周期的方波 */
  48.         for(i =0; i < 32; i++)
  49.         {
  50.                 g_usWaveBuff[i] = 0;
  51.         }
  52.        
  53.         for(i =0; i < 32; i++)
  54.         {
  55.                 g_usWaveBuff[i+32] = 4095;
  56.         }
  57.        
  58.         DAC_WaveConfig();
  59.         TIM6_Config();
  60. }

  61. /*
  62. *********************************************************************************************************
  63. *        函 数 名: TIM6_Config
  64. *        功能说明: 配置定时器6,用于触发DAC。
  65. *        形    参: 无
  66. *        返 回 值: 无
  67. *********************************************************************************************************
  68. */
  69. void TIM6_Config(void)
  70. {
  71.         /*-----------------------------------------------------------------------
  72.                 bsp.c 文件中 void SystemClock_Config(void) 函数对时钟的配置如下:

  73.         System Clock source       = PLL (HSE)
  74.         SYSCLK(Hz)                = 400000000 (CPU Clock)
  75.         HCLK(Hz)                  = 200000000 (AXI and AHBs Clock)
  76.         AHB Prescaler             = 2
  77.         D1 APB3 Prescaler         = 2 (APB3 Clock  100MHz)
  78.         D2 APB1 Prescaler         = 2 (APB1 Clock  100MHz)
  79.         D2 APB2 Prescaler         = 2 (APB2 Clock  100MHz)
  80.         D3 APB4 Prescaler         = 2 (APB4 Clock  100MHz)

  81.         因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = APB1 x 2 = 200MHz;
  82.         因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = APB2 x 2 = 200MHz;
  83.         APB4上面的TIMxCLK没有分频,所以就是100MHz;

  84.         APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14,LPTIM1
  85.         APB2 定时器有 TIM1, TIM8 , TIM15, TIM16,TIM17

  86.         APB4 定时器有 LPTIM2,LPTIM3,LPTIM4,LPTIM5
  87.        
  88.         TIM6 更新周期是 = TIM6CLK / (Period + 1)/(Prescaler + 1)
  89.         根据如下的配置,更新周期是:
  90.         TIM6CLK /(Period + 1)/(Prescaler + 1)
  91.         = 200MHz /(30+1)/(0+1)
  92.         ≈ 6.45MHz
  93.         ----------------------------------------------------------------------- */
  94.         TIM_MasterConfigTypeDef sMasterConfig;
  95.        
  96.                 /* TIM6 时钟使能 */
  97.         __HAL_RCC_TIM6_CLK_ENABLE();

  98.         /* 配置定时器外设 */
  99.         htim.Instance = TIM6;

  100.         htim.Init.Period            = 30;
  101.         htim.Init.Prescaler         = 0;
  102.         htim.Init.ClockDivision     = 0;
  103.         htim.Init.CounterMode       = TIM_COUNTERMODE_UP;
  104.         htim.Init.RepetitionCounter = 0;
  105.         HAL_TIM_Base_Init(&htim);

  106.         /* TIM6 TRGO 选择 */
  107.         sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  108.         sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

  109.         HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig);

  110.         /* 使能定时器 */
  111.         HAL_TIM_Base_Start(&htim);
  112. }

  113. /*
  114. *********************************************************************************************************
  115. *        函 数 名: DAC_WaveConfig
  116. *        功能说明: DAC通道1和通道2方波输出
  117. *             上面函数TIM6_Config已将将TIM6的输出配置成6.45MHz,下面DMA的缓存大小是64,那么方波的输出频率就是
  118. *             方波周期 = TIM6更新周期/64 = 6.45MHz / 64 ≈ 100KHz
  119. *        形    参: 无
  120. *        返 回 值: 无
  121. *********************************************************************************************************
  122. */
  123. void DAC_WaveConfig(void)
  124. {
  125.         GPIO_InitTypeDef          GPIO_InitStruct;
  126.        

  127.         /*##-1- 使能时钟 #################################*/
  128.     __HAL_RCC_GPIOA_CLK_ENABLE();
  129.         __HAL_RCC_DAC12_CLK_ENABLE();
  130.         __HAL_RCC_DMA1_CLK_ENABLE();

  131.         /*##-2- 配置GPIO ##########################################*/
  132.         GPIO_InitStruct.Pin = GPIO_PIN_4;
  133.         GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  134.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  135.         HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  136.    
  137.     GPIO_InitStruct.Pin = GPIO_PIN_5;
  138.         GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  139.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  140.         HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  141.   
  142.         /*##-3- 初始化DAC外设 ######################################*/
  143.     DacHandle.Instance = DAC1;
  144.   
  145.         HAL_DAC_DeInit(&DacHandle);       
  146.    
  147.         if (HAL_DAC_Init(&DacHandle) != HAL_OK)
  148.         {
  149.                 Error_Handler(__FILE__, __LINE__);
  150.         }

  151.         /*##-4- 配置DAC通道1和通道2 ######################################*/
  152.         sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;        /* 关闭采样保持模式,这个模式主要用于低功耗 */
  153.         sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;                    /* 采用定时器6触发 */
  154.         sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;           /* 使能输出缓冲 */
  155.         sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_DISABLE;/* 不将DAC连接到片上外设 */
  156.         sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;              /* 使用出厂校准 */

  157.         if (HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_1) != HAL_OK)
  158.         {
  159.                 Error_Handler(__FILE__, __LINE__);
  160.         }
  161.    
  162.     if (HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DAC_CHANNEL_2) != HAL_OK)
  163.         {
  164.                 Error_Handler(__FILE__, __LINE__);
  165.         }
  166.    
  167.         /*##-5- 配置通道1的DMA ##########################################*/
  168.         hdma_dac1.Instance = DMA1_Stream0;              /* 使用的DAM1 Stream0 */
  169.         hdma_dac1.Init.Request  = DMA_REQUEST_DAC1;     /* DAC触发DMA传输 */
  170.         hdma_dac1.Init.Direction = DMA_MEMORY_TO_PERIPH;/* 存储器到外设 */
  171.         hdma_dac1.Init.PeriphInc = DMA_PINC_DISABLE;    /* 外设地址禁止自增 */
  172.         hdma_dac1.Init.MemInc = DMA_MINC_ENABLE;        /* 存储器地址自增 */
  173.         hdma_dac1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; /* 外输操作数据宽度,半字 */
  174.         hdma_dac1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;    /* 存储器操作数据宽度,半字 */
  175.         hdma_dac1.Init.Mode = DMA_CIRCULAR;                           /* 循环模式 */
  176.         hdma_dac1.Init.Priority = DMA_PRIORITY_HIGH;                  /* 优先级高 */

  177.         HAL_DMA_Init(&hdma_dac1);

  178.         /* 关联DMA句柄到DAC句柄下 */
  179.         __HAL_LINKDMA(&DacHandle, DMA_Handle1, hdma_dac1);

  180.         /* 启动DAC DMA */
  181.         if (HAL_DAC_Start_DMA(&DacHandle, DAC_CHANNEL_1, (uint32_t *)g_usWaveBuff, 64, DAC_ALIGN_12B_R) != HAL_OK)
  182.         {
  183.                 Error_Handler(__FILE__, __LINE__);
  184.         }

  185.         /*##-6- 配置通道2的DMA ##########################################*/       
  186.     hdma_dac2.Instance = DMA1_Stream1;                        /* 使用的DAM1 Stream1 */
  187.         hdma_dac2.Init.Request  = DMA_REQUEST_DAC2;               /* DAC触发DMA传输 */
  188.         hdma_dac2.Init.Direction = DMA_MEMORY_TO_PERIPH;          /* 存储器到外设 */
  189.         hdma_dac2.Init.PeriphInc = DMA_PINC_DISABLE;              /* 外设地址禁止自增 */
  190.         hdma_dac2.Init.MemInc = DMA_MINC_ENABLE;                  /* 存储器地址自增 */
  191.         hdma_dac2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;/* 外输操作数据宽度,半字 */
  192.         hdma_dac2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;/* 存储器操作数据宽度,半字 */
  193.         hdma_dac2.Init.Mode = DMA_CIRCULAR;                       /* 循环模式 */
  194.         hdma_dac2.Init.Priority = DMA_PRIORITY_HIGH;              /* 优先级高 */

  195.         HAL_DMA_Init(&hdma_dac2);

  196.         /* 关联DMA句柄到DAC句柄下 */
  197.         __HAL_LINKDMA(&DacHandle, DMA_Handle2, hdma_dac2);

  198.         /* 启动DAC DMA */   
  199.         if (HAL_DAC_Start_DMA(&DacHandle, DAC_CHANNEL_2, (uint32_t *)g_usWaveBuff, 64, DAC_ALIGN_12B_R) != HAL_OK)
  200.         {
  201.                 Error_Handler(__FILE__, __LINE__);
  202.         }
  203. }

  204. /***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
复制代码


回复

使用道具 举报

1

主题

22

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2021-11-21 17:21:31 | 显示全部楼层
eric2013 发表于 2021-11-21 16:48
这是我的配置,供参考

感觉配置没什么差别,不过我的是F407的,配置结构体的内容没有你这个这么多。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107100
QQ
发表于 2021-11-22 01:14:55 | 显示全部楼层
billy 发表于 2021-11-21 17:21
感觉配置没什么差别,不过我的是F407的,配置结构体的内容没有你这个这么多。

分享你的程序到百度云看下。
回复

使用道具 举报

1

主题

22

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2021-11-22 17:06:06 | 显示全部楼层
eric2013 发表于 2021-11-22 01:14
分享你的程序到百度云看下。

链接:https://pan.baidu.com/s/1eMmhstZESo8h_M2O1mDjFg
提取码:xl0m

已经上传,有劳硬汉给瞅瞅。
回复

使用道具 举报

5

主题

30

回帖

45

积分

新手上路

积分
45
发表于 2021-11-22 17:17:04 | 显示全部楼层
老哥用的是虚拟示波器吗?用的是哪款的?界面不错。
回复

使用道具 举报

1

主题

22

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2021-11-22 18:03:42 | 显示全部楼层
xdh873939316 发表于 2021-11-22 17:17
老哥用的是虚拟示波器吗?用的是哪款的?界面不错。

梦源实验室的dscope :DSCope U3P100
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107100
QQ
发表于 2021-11-23 08:31:33 | 显示全部楼层
billy 发表于 2021-11-22 17:06
链接:https://pan.baidu.com/s/1eMmhstZESo8h_M2O1mDjFg
提取码:xl0m

看了没发现什么问题,只能你再调试排查下了。
回复

使用道具 举报

1

主题

22

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2021-11-23 09:11:15 | 显示全部楼层
eric2013 发表于 2021-11-23 08:31
看了没发现什么问题,只能你再调试排查下了。

确实觉得很奇怪,如果去掉tim6触发,自己一个一个喂给dac是正常的。
回复

使用道具 举报

5

主题

133

回帖

148

积分

初级会员

积分
148
发表于 2021-11-23 09:25:50 | 显示全部楼层
看看初始化顺序是不是有问题,DMA初始化要在TIM前面,之前也遇到过TIM+DMA有问题的情况,TIM初始化的时候会配置DMA寄存器,如果DMA时钟没开就会写不进去DMA寄存器

评分

参与人数 1金币 +20 收起 理由
billy + 20

查看全部评分

回复

使用道具 举报

1

主题

22

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2021-11-23 15:21:53 | 显示全部楼层
无关风月 发表于 2021-11-23 09:25
看看初始化顺序是不是有问题,DMA初始化要在TIM前面,之前也遇到过TIM+DMA有问题的情况,TIM初始化的时候会 ...

若然和顺序有关,非常感谢!
cubemx生成的初始化顺序是:
MX_GPIO_Init();
  MX_DAC_Init();
  MX_DMA_Init();
  MX_TIM2_Init();
始终没有波形出现

我手动改成:
MX_GPIO_Init();
  MX_DMA_Init();
  MX_DAC_Init();
  MX_TIM2_Init();

即最先初始化DMA,然后其他的什么都没改,波形就出来了。

再次感谢!!!!
回复

使用道具 举报

1

主题

22

回帖

25

积分

新手上路

积分
25
 楼主| 发表于 2021-11-23 15:27:00 | 显示全部楼层
问题已经解决:原因,cubemx生成的初始化顺序不对,如下:
  MX_GPIO_Init();
  MX_DAC_Init();
  MX_DMA_Init();
  MX_TIM2_Init();

将DMA放到DAC之前初始化问题得到解决:
   MX_GPIO_Init();
MX_DMA_Init();
  MX_DAC_Init();
  MX_TIM2_Init();

太过相信cubemx这东西了,一直去排查自己添加的内容,而自己添加的似乎只有个数据表,以及启动TIM和DAC,导致这个问题卡了两天。

非常感谢11楼的经验分享。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107100
QQ
发表于 2021-11-23 15:39:07 | 显示全部楼层
billy 发表于 2021-11-23 15:27
问题已经解决:原因,cubemx生成的初始化顺序不对,如下:
  MX_GPIO_Init();
  MX_DAC_Init();

我看你的工程的时候我还特地关注了下时钟初始化。

你这个  __HAL_RCC_DMA1_CLK_ENABLE() 还没有初始化就去操作DMA了。CubeMX生成的代码也太水了。

好多年前就有这个问题,竟然两年过去了,还没有没有修改。。。

STM32H7配置DMA前,务必先初始化时钟,否则容易导致配置失败
http://www.armbbs.cn/forum.php?m ... 1585&fromuid=58
(出处: 硬汉嵌入式论坛)


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-17 11:37 , Processed in 0.303034 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表