STM32G474 DAC+DMA输出正弦波
STM32G474CET6 DAC+DMA输出正弦波
通过DAC输出正弦波可以直接在while循环中设置DAC的输出值,函数是HAL_DAC_SetValue(&hdac1,DAC1_CHANNEL_1,DAC_ALIGN_12B_R,2000)。但这种方式会导致CPU的负载率太高,刷新频率也不够快。所以,我需要用DMA来帮助CPU把数据快速的写入DAC的值寄存器中。CubeMX中的具体配置步骤如下
第一步,配置总线时钟,按下图配置即可,我们用的一般都是陶瓷晶振。注意是HSE作为时钟输入源,系统时钟选择PLLCLK。
第二步,配置JTAG口,下载和调试程序使用
第三步,配置TIM6,这个是作为DAC输出更新的触发源,DAC就是按这个TIM6的时间间隔更新输出。其他定时器也可以作为触发源的,具体哪些看对应芯片手册。分频系数为0就是不分配,总线时钟168M,计数值1680-1就是10us更新一次。触发事件要选择update,这个一定要选,不然DAC没有触发源,不会工作的。
第四步,配置DAC,DAC的配置要选择连接到外部的pin,这样信号就是在pin脚输出了。Trigger触发源要选择TIM6 trigger,如果配置的是其他TIM就对应更改,DAC配置这两个就可以了,其他默认即可。
第五步,配置DMA,DMA是英文Direct memory access的缩写,就是内存的直接访问,这样的话就不需要CPU来写入了,并且它的速率远高于通过CPU操作的方式。模式选择circular,这样只需启动一次DMA传输即可。数据宽度需要特别注意,外设是选择Word而不是halfword,被这个坑了很久。
问题解决后看到官方手册的如下描述,访问AHB总线的外设不支持byte/half-word传输,这个一定要注意,被坑了很久。
配置好之后用CubeMX工具生产代码,主要要选择对应的编译器,我用的是KEIL v5。只需要在主函数中加两条指令和一个sin波形数组就可以了。如下是sin波形生产数据,这里只是举例,大家可以有自己的数组。
在初始化这里添加如下函数,第一个函数是启动TIM,这样TIM就会按设定好的时间去触发DAC。当DAC被触发后就会发送DMA请求,DMA收到请求后就会把一个数据传入DAC寄存器,然后等待下一次的请求。流程就是TIM—>DAC—>DMA,DMA把数据传入DAC后,DAC就会释放DMA请求,等带下一次TIM的触发信号。当整个数组传输完成后,又会开始下一轮的传输,因为DMA的模式是circular。
第二个函数就是启动DAC和DMA,最后一个参数是12bit的右对齐。这个就是这么简单,改变定时器的定时时间也就是改变正弦波的周期,可以根据需要自己调节。正弦波的周期就是 定时时间间隔*数组长度。我试了下TIM6的频率为12Mhz的时候信号输出正常,频率再高的时候DAC输出不变化了,这个12Mhz的更新频率比直接在while循环中赋值的方式至少快了一个数量级。
接示波器效果如下,唯一遇到是就是DMA配置的坑,其他一次成功。