STM32 F4 DAC DMA Waveform Generator

Goal: generating an arbitrary periodic waveform using a DAC with DMA and TIM6 as a trigger.

Agenda:

    1. Modeling a waveform in MATLAB and getting the waveform data
    2. Studying the DAC, DMA, and TIM6 to see how it can be used to generate a waveform
    3. Coding and testing a couple of functions
%% Generating an n-bit sine wave
% Modifiable parameters: step, bits, offset
close; clear; clc; points = ; % number of points between sin() to sin(*pi)
bits = ; % -bit sine wave for -bit DAC
offset = ; % limiting DAC output voltage t = :((*pi/(points-))):(*pi); % creating a vector from to *pi
y = sin(t); % getting the sine values
y = y + ; % getting rid of negative values (shifting up by )
y = y*((^bits-)-*offset)/+offset; % limiting the range (+offset) to (^bits-offset)
y = round(y); % rounding the values
plot(t, y); grid % plotting for visual confirmation fprintf('%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \n', y);

There's a trade-off between the sine wave resolution (number of points from sin(0) to sin(2*pi)), output frequency range, and precision of the output frequency (e.g. we want a 20kHz wave, but we can only get 19.8kHz or 20.2kHz because the step is 0.4kHz). The output frequency is a non-linear function with multiple variables. To complicate it further, some of these variables must be integers within 1 to 65535 range which makes it impossible to output certain frequencies precisely.
Although precise frequency control is terribly hard (if not impossible), one feature does stand out - ability to generate a periodic waveform of any shape. 
Below is the code for mediocre range/precision/resolution but excellent versatility in terms of shaping the output waveform.

@input - uint16_t function[waveform_resolution]
@output - PA4 in analog configuration
@parameters - OUT_FREQ, SIN_RES

To tailor other parameters, study the DAC channel block diagram, electrical characteristics, timing diagrams, etc. To switch DAC channels, see memory map, specifically DAC DHRx register for DMA writes.

#include <stm32f4xx.h>
#include "other_stuff.h" #define OUT_FREQ 5000 // Output waveform frequency
#define SINE_RES 128 // Waveform resolution
#define DAC_DHR12R1_ADDR 0x40007408 // DMA writes into this reg on every request
#define CNT_FREQ 42000000 // TIM6 counter clock (prescaled APB1)
#define TIM_PERIOD ((CNT_FREQ)/((SINE_RES)*(OUT_FREQ))) // Autoreload reg value const uint16_t function[SINE_RES] = { , , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , , , ,
, , , , , , , }; static void TIM6_Config(void);
static void DAC1_Config(void); int main()
{
GPIO_InitTypeDef gpio_A; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); gpio_A.GPIO_Pin = GPIO_Pin_4;
gpio_A.GPIO_Mode = GPIO_Mode_AN;
gpio_A.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio_A); TIM6_Config();
DAC1_Config(); while ()
{ } } static void TIM6_Config(void)
{
TIM_TimeBaseInitTypeDef TIM6_TimeBase; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseStructInit(&TIM6_TimeBase);
TIM6_TimeBase.TIM_Period = (uint16_t)TIM_PERIOD;
TIM6_TimeBase.TIM_Prescaler = ;
TIM6_TimeBase.TIM_ClockDivision = ;
TIM6_TimeBase.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6, &TIM6_TimeBase);
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); TIM_Cmd(TIM6, ENABLE);
} static void DAC1_Config(void)
{
DAC_InitTypeDef DAC_INIT;
DMA_InitTypeDef DMA_INIT; DAC_INIT.DAC_Trigger = DAC_Trigger_T6_TRGO;
DAC_INIT.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_INIT.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_1, &DAC_INIT); DMA_DeInit(DMA1_Stream5);
DMA_INIT.DMA_Channel = DMA_Channel_7;
DMA_INIT.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDR;
DMA_INIT.DMA_Memory0BaseAddr = (uint32_t)&function;
DMA_INIT.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_INIT.DMA_BufferSize = SINE_RES;
DMA_INIT.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_INIT.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_INIT.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_INIT.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_INIT.DMA_Mode = DMA_Mode_Circular;
DMA_INIT.DMA_Priority = DMA_Priority_High;
DMA_INIT.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_INIT.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_INIT.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_INIT.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream5, &DMA_INIT); DMA_Cmd(DMA1_Stream5, ENABLE);
DAC_Cmd(DAC_Channel_1, ENABLE);
DAC_DMACmd(DAC_Channel_1, ENABLE);
}

Using the code above we are supposed to get a 5kHz sine wave constructed with 128 points (for better quality, consider using more points).
Here's a picture of what we actually get (off by 25Hz, not too bad).

And here's the cool sinc(x) function. To generate other functions, model it in MATLAB, cast to 12-bit, STM32F4 does the rest.

STM32 F4 DAC DMA Waveform Generator的更多相关文章

  1. STM32 F4 ADC DMA Temperature Sensor

    STM32 F4 ADC DMA Temperature Sensor Goal: detecting temperature variations using a temperature senso ...

  2. STM32之DAC君

    如花说得好:呃呃呃.是俗话说得好:有了ADC,怎可少了DAC..我觉得奇怪.今天我开头就直奔主题了.我想了想,总结了一句话:孙悟空纵然有七十二变.无论是变成猫也好,变成狗也罢.始终还是会变回他本身.所 ...

  3. STM32之串口DMA接收不定长数据

    STM32之串口DMA接收不定长数据 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? 同学A:数据来了就会进入串口 ...

  4. STM32的USART DMA传输(转)

    源:STM32的USART DMA传输 问题描述: 我有一个需求,AD采得一定数目的数据之后,由串口DMA发出,由于AD使用双缓冲,所以每次开始DMA的时候都需要重新设置开始的内存地址以及传输的数目( ...

  5. STM32 F4 Clock Sources

    STM32 F4 Clock Sources Goal: routing clock sources to the microcontroller output pin (MCO1)    High- ...

  6. STM32 F4 General-purpose Timers for Periodic Interrupts

    STM32 F4 General-purpose Timers for Periodic Interrupts

  7. STM32 F4 SPI Accelerometer

    STM32 F4 SPI Accelerometer

  8. STM32 F4 GPIO Modes

    STM32 F4 GPIO Modes Goal: creating a visual summary of GPIO configuration modes. The summary at the ...

  9. 重学STM32---(六)DAC+DMA+TIM

    这两天复习了DAC,DMA再加上把基本定时器TIM6和TIM7看了一下,打算写一个综合点的程序,,,就在网上找了一些关于DAC,DMA和定时器相关的程序,最终打算写了输出正弦波的程序... 由于没有示 ...

随机推荐

  1. HTML5+CSS把footer固定在底部

    在刚开始给网页写footer的时候,我们会碰到一个让人烦躁的问题:当页面内容太少时,footer显示在了页面中间,这是我们不希望出现的,我们希望它能够永远呆在底部,不管网页的内容是多还是少.下面的代码 ...

  2. TrID文件类型识别linux版

    读取文件头根据特征码进行文件类型匹配. 官方:http://mark0.net/soft-trid-e.html windows版本小工具:FileAnalysis 以下是linux版本 wget h ...

  3. 【转】深入理解C++中public、protected及private用法

    首先明白以下两点: 1.类的一个特征就是封装,public和private作用就是实现这一目的. 即:用户代码(类外)可以访问public成员而不能访问private成员:private成员只能由类成 ...

  4. springcloud Zuul中路由配置细节

    上篇文章我们介绍了API网关的基本构建方式以及请求过滤,小伙伴们对Zuul的作用应该已经有了一个基本的认识,但是对于路由的配置我们只是做了一个简单的介绍,本文我们就来看看路由配置的其他一些细节. 首先 ...

  5. 在 Ubuntu13.10 服务器中安装 Munin(监视工具)【转】

    Munin 监测工具可检测所有的计算机,并记录好看到的计算机.通过图形Web界面的的方式显示所有信息.重点是即插即用的功能.完成安装后,大量的控插件会被打. 使用 Munin 您可以轻松地监视您的计算 ...

  6. 浅谈HIbernate

    Hiberbate是面向对象,需要把对象和数据库进行映射.与数据库无关,操作的是对象,会根据数据源和数据库的方言生成对应的sql语句进行查询,是一个优秀的java持久层解决方案,是当今主流的对象-关系 ...

  7. SqlServer中 CREATE PARTITION FUNCTION使用

    表分区的操作三步走: 1.创建分区函数 CREATE PARTITION FUNCTION xx1(int) 解释:在当前数据库中创建一个函数,该函数可根据指定列的值将表或索引的各行映射到分区. 语法 ...

  8. 主动学习(Active Learning)

    主动学习简介 在某些情况下,没有类标签的数据相当丰富而有类标签的数据相当稀少,并且人工对数据进行标记的成本又相当高昂.在这种情况下,我们可以让学习算法主动地提出要对哪些数据进行标注,之后我们要将这些数 ...

  9. ORACLE 表空间扩展方法

    ORACLE 表空间扩展方法 环境: linux系统 工具:PL/SQL DEVELOPER 第一步:查看表空间的名字及文件所在位置: select tablespace_name, file_id, ...

  10. ERROR 2003 (HY000): Can't connect to MySQL server on "192.168.xxx.xxx" (111)

    mac  homebrew 安装的mysql5.6 除本机外无法被其他ip的电脑访问. 网上查原因 有几个: 1.my.cnf配置中 查看是否有   bind-address = 127.0.0.1  ...