本帖最后由 shanyuxiang 于 2025-9-20 13:19 编辑
玩转APM32的DMA-用DAC和DMA生成正弦波
一、前言
DAC可以产生0到3.3V的模拟电压,如果动态改变DAC输出的电压,那么就可以生成各种各样的模拟波形。
这里我们就用DAC+DMA+TMR配合来生成正弦波。
首先看看APM32E103上的相关外设资源:
2个12位的DAC;
2个16位基本定时器TMR6/7;
两个DMA,DMA1有7个通道,DMA2有5个通道。
DAC有两个,一个是DAC_OUT1(PA4) ,还有一个是DAC_OUT2(PA5),两个可以同时输出,这里以DAC_OUT1为例。
DAC支持定时器触发,也就是说定时器溢出时更新一次DAC的数据寄存器,这里用基础定时器就够了。
每触发一次DAC转换需要更新DAC数据寄存器的值,用DMA把数组中的数传输到DAC数据寄存器中
二、DAC、TMR、DMA的初始化配置
2.1、DAC的配置
这里以DAC1为例,DAC的配置和单独使用DAC类似,先初始化GPIO为模拟复用。
触发配成TMR6触发,不用内部的波形发生功能,使能输出缓存。
最后一定记得开启DAC的DMA功能。
- #define DAC_PIN GPIO_PIN_4
- #define DAC_GPIO GPIOA
- #define DAC_CHANNEL DAC_CHANNEL_1
- #define DAC_TIM TMR6
- #define DAC_TRIG DAC_TRIGGER_TMR6_TRGO
- //gpio config
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);
- GPIO_Config_T GPIO_ConfigStruct;
- GPIO_ConfigStruct.pin = DAC_PIN;
- GPIO_ConfigStruct.mode = GPIO_MODE_ANALOG;
- GPIO_Config(DAC_GPIO, &GPIO_ConfigStruct);
- //dac config
- RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_DAC);
- DAC_Config_T DAC_ConfigStruct;
- DAC_ConfigStruct.trigger = DAC_TRIG;
- DAC_ConfigStruct.waveGeneration = DAC_WAVE_GENERATION_NONE;
- DAC_ConfigStruct.maskAmplitudeSelect = DAC_TRIANGLE_AMPLITUDE_1;
- DAC_ConfigStruct.outputBuffer = DAC_OUTPUT_BUFFER_ENBALE;
- DAC_Config((uint32_t)DAC_CHANNEL, &DAC_ConfigStruct);
- DAC_DMA_Enable(DAC_CHANNEL);
- DAC_Enable(DAC_CHANNEL);
2.2、TMR的配置
通过用户手册可知,DAC支持多种触发源,这里我们用基础定时器TMR6去触发DAC转换。
定时器配置成最简单的向上计数即可,不需要开中断,更新事件用于触发输出。
定时器的溢出频率也就决定了DAC输出电压的变化快慢,也就是division 和 period,
这两个值越小,生成的正弦波频率越高;或者减小正弦波的采用点数,正弦波频率也能提高。
- //timer config
- RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR6);
-
- TMR_BaseConfig_T TMR_BaseConfigStruct;
- TMR_BaseConfigStruct.clockDivision = TMR_CLOCK_DIV_1;
- TMR_BaseConfigStruct.countMode = TMR_COUNTER_MODE_UP;
- TMR_BaseConfigStruct.division = 60-1;
- TMR_BaseConfigStruct.period = 4;
- TMR_ConfigTimeBase(DAC_TIM, &TMR_BaseConfigStruct);
- TMR_EnableAutoReload(DAC_TIM);
- TMR_SelectOutputTrigger(DAC_TIM, TMR_TRGO_SOURCE_UPDATE);
- TMR_Enable(DAC_TIM);
2.3、DMA的配置
DMA配成从内存到DAC,内存地址要自增,而DAC数据寄存器地址不变。
因为这里用的DAC是12位,所以内存和外设的数据宽度都设为半字,也就是16位。
如果想开启一次后一直产生波形,则使用循环模式;如果想每个波形周期都要手动启动,则使用正常模式。
通过手册上的请求映射表可看出对应的DMA通道是DMA2-channel3。
特别要注意DAC的数据寄存器地址,这里需要仔细看手册。
- //DMA config
- RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA2);
-
- DMA_Config_T dmaConfig;
- DMA_Reset(DAC_DMA_CHANNEL);
- dmaConfig.peripheralBaseAddr = (uint32_t)DAC_DATA_ADDRESS;
- dmaConfig.dir = DMA_DIR_PERIPHERAL_DST;
- dmaConfig.memoryBaseAddr = (uint32_t)NULL;
- dmaConfig.bufferSize = 0;
- dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
- dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
- dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_HALFWORD;
- dmaConfig.memoryDataSize = DMA_MEMORY_DATA_SIZE_HALFWORD;
- dmaConfig.loopMode = DMA_MODE_CIRCULAR;
- dmaConfig.priority = DMA_PRIORITY_HIGH;
- dmaConfig.M2M = DMA_M2MEN_DISABLE;
- DMA_Config(DAC_DMA_CHANNEL, &dmaConfig);
2.4 启动DMA的传输
上面的初始化完成后,需要启动使能相关外设才会产生波形。
先设置定时器的自动加载值,这个值决定了波形的频率,
然后波形采样点数组的地址和长度赋值给DMA的地址、长度寄存器,
最后使能DAM传输。
- //启动传输
- void dac_dma_transmit(unsigned short *addr, unsigned int len, unsigned short period)
- {
- if (len > 65535) len = 65535;
- DMA_Disable(DAC_DMA_CHANNEL);
- TMR_ConfigAutoreload(DAC_TIM,period-1);
- DAC_DMA_CHANNEL->CHNDATA = len;
- DAC_DMA_CHANNEL->CHMADDR = (uint32_t)addr;
- DMA_Enable(DAC_DMA_CHANNEL);
- }
三、使用与测试
为了展示最终效果,还需要制作一个正弦波的采样点数组。
方法很多,这里就通过正弦函数sin来计算一个360点的波形数据。
正弦函数计算结果有正有负,为了好看,统统平移到0V以上。
- #define WaveLength 360
- unsigned short WaveBuffer[WaveLength + 1];
- #include <math.h>
- #define PI 3.14159
- int generate_sine_wave(unsigned short buf[])
- {
- double temp;
- unsigned short i;
- for (i = 0; i < WaveLength; i++)
- {
- temp = sin(i * PI / 180.0) * 2048.0;
- temp = temp + 2047.0;
- buf[i] = (unsigned short)temp;
- }
- }
最后一步,调用刚才写好的的函数即可。
- int main(void)
- {
- usart_printf_init();
- printf("This a dac and dma demo(sine wave)\r\n");
- generate_sine_wave(WaveBuffer);
-
- dac_dma_init();
- dac_dma_transmit(WaveBuffer, WaveLength, 4);
- while (1)
- {
- }
- }
用示波器观察PA4脚上的波形。
顺便又做了个锯齿波。
以上方法除了用来产生各种自定义的波形,也可以用来播放wav音频。
APM32E10x_SDK_V1.3.1_dac_dma.rar
(777.77 KB, 下载次数: 1)
|