STM32 sine wave output

Publisher:asd123yuiLatest update time:2016-10-11 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
STM32 can output sine waves! How? To output sine waves, several peripherals are needed: Timer, DAC, DMA. Timer is used to set the frequency of the sine wave; DAC, as the name implies, converts digital quantities into analog quantities, which is converted into voltage signals here; DMA directly controls the DAC output without bothering the chip core.
Let's talk about how they work together. First, configure the frequency of the timer and set the timer as an output trigger. Then configure the trigger source of the DAC to be the timer trigger and turn on the MDA function of the DAC. Next, it is the turn of the DMA to work, and set the DMA operation object to DAC. After the above configuration, the three peripherals can work normally: each time the timer count value increases, it triggers the DAC to work, and then the DMA controls the DAC to output the corresponding voltage value. Within a timing cycle, the DAC output voltage value output changes according to the sine wave, so a sine wave is generated!
Next, I will talk about the sine wave output code of STM32, still modifying it in my own standard project.
1. Project changes
1) The timer is needed in the code, so add stm32f10x_tim.c to the STM32F10x_StdPeriod_Driver working group.
2) In addition to the timer, DAC is also needed, so add stm32f10x_dac.c to the STM32F10x_StdPeriod_Driver working group.
3) Finally, you need to add stm32f10x_dma.c to the STM32F10x_StdPeriod_Driver working group
4) Open the stm32f10x_conf.h file and include stm32f10x_tim.h, stm32f10x_dac.h, and stm32f10x_dma.h. That is, unblock the statements that originally included these files.
5) Create two new files, SineWave.c and sineWave.h, and save them in the src and inc folders of the BSP folder respectively, and add SineWave.c to the BSP of the project.
 
2. Programming of SineWave.c and SineWave.h
In the code, I set two sine wave outputs, one with an output frequency of 800Hz and the other with an output frequency of 1600Hz. They correspond to the PA4 pin of DAC channel 1 and the PA5 pin of DAC channel 2 respectively. So the code first initializes these two pins:

/****************************************************************
Function: SineWave_GPIO_Config
Description: Pin configuration
Input: none
return: none
**********************************************************/
static void SineWave_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //Initialize pin clock

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; //DAC channel1 and channel2 corresponding pins
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //Push-pull output
GPIO_InitStructure.GPIO_Speed ​​= GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

Next, we need to configure the timer. The function of the timer is to set the frequency of the sine wave. Since we need to output two timers with different frequencies, we need to configure two timers here. One timer is set to 800Hz and the other timer is set to 1600Hz. The code is as follows:

#define _800Hz (u16)(72000000/sizeof(Sine12bit)*2/800) //800Hz
#define _1600Hz (u16)(72000000/sizeof(Sine12bit)*2/1600) //1600Hz

3100 , 3143
, 3185, 3227, 3267, 3307, 3347, 3385, 3423, 3460, 3496, 3531, 3565, 3594, 3631,
3642, 3690, 3737, 3785, 3831, 3877, 3923, 3968, 3013, 3057, 3100, 3143, 3185,
3227, 3267, 3307, 3347, 3385, 3423,
3460, 3496, 3531, 3565, 3598, 3631, 3662, 3692, 3722,
3750, 3778, 3804, 3829, 3854, 3877, 3899, 3920, 3940, 3958, 3976,
3992, 4007, 4021, 4034, 4046, 4056, 40 65, 4073, 4080, 4086
, 4090, 4093, 4095, 4095, 4095, 4093, 4090, 4086, 4080, 4073
, 4065, 4056, 4046, 4034, 4021, 4007, 3992, 3976, 3958,
3940, 3920, 3899, 3877, 3854, 3829, 3804, 3778, 3750, 3722, 3692, 3662
, 3631, 3598, 3565, 3531, 3496, 3460, 34 23, 3385, 3347, 3307
, 3267, 3227, 3185, 3143, 3100, 3057, 3013, 2968, 2923,
2877, 2831, 2785, 2737, 2690, 2642, 2594, 2545, 2496,
2447, 2398, 2348, 2298, 2248, 2198, 2148, 2098, 2047, 1997, 1947, 1897,
1847, 1797, 1747, 1697, 1648, 1599, 1550, 15 01, 1453
, 1405, 1358, 1310, 1264, 1218, 1172, 1127, 1082, 1038,
995, 952, 910, 868, 828, 788, 748, 710, 672, 635,
599, 564, 530, 497, 464, 433, 403, 373, 345, 317,
291, 266, 241, 218, 196, 175, 155, 137, 119, 103,
88, 74, 61, 49, 39, 30, 22, 15, 9, 5,
2, 0, 0, 0, 2, 5, 9, 15, 22, 30,
39, 49, 61, 74, 88, 103, 119, 137, 155, 175,
196, 218, 241, 266, 291, 317, 345, 373, 1797,
1847, 1897, 1947, 1997 }; // const u16 Sine12bit[32] = { // sine 12bit, 16bit, 2047, 2048, 2049, 2050, 2060, 2072, 2080, 2092,
2127, 2172, 2218, 2264,
1310, 1358, 1405, 1453, 1501, 1550, 1599, 1648, 1697, 1747
, 1797, 1847, 1897, 1947, 1997 };

// const u16 Sine12bit[32] = { // sine 12bit, 16bit, 2047, 2080
, 2092, 2080, 2092 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056,
// 3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909,
// 599, 34 4, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647};

 

/****************************************************************
Function: SineWave_TIM_Config
Description: Timer configuration
Input: none
return: none
**************************************************************/
static void SineWave_TIM_Config(void)
{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM6, ENABLE);//Initialize the clocks of timer 2 and

6TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = _800Hz; //Set the frequency of sine wave
1TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //No pre-
scalingTIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //No clock
divisionTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//Increase
countTIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Period = _1600Hz; //Set sine wave 2 frequency
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); //Update TIM2 output trigger
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); //Update TIM6 output trigger
}

In the above code, the sizeof(Sine12bit) in the macro definition is the size of the array that outputs the sine wave. Its type is u16, so when you want to find out the number of elements in the array, sizeof(Sine12bit) must be divided by 2. The reason why sizeof(Sine12bit)/2 is used instead of the constant 256 is that in the above code, I defined two Sine12bit arrays, one of which was masked. If you want to use the masked Sine12bit array, after unmasking it and masking the other Sine12bit array, the values ​​of _800Hz and _1600Hz will change automatically to meet the correct frequency output of the timer. In the above two Sine12bit[] arrays, one array is Sine12bit[256] with a total of 256 elements, and the other masked array is Sine12bit[32] with a total of 32 elements. If the elements of these two arrays are plotted on the coordinates, they will form a periodic sine wave, but the curve drawn by the array with 256 elements is much more accurate than the curve drawn by the array with only 32 elements. I have given both arrays so that you can choose according to the occasion in the future. In this project, I chose Sine12bit[256] to draw an accurate sine wave.
Next, configure the DAC. The DAC has two channels in total. Since a sine wave is to be output, both channels need to be configured. The code is as follows:

/****************************************************************
Function: SineWave_DAC_Config
Description: DAC configuration
Input: none
return: none
*************************************************************/
static void SineWave_DAC_Config(void)
{
DAC_InitTypeDef DAC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//Initialize DAC clock

DAC_StructInit(&DAC_InitStructure);
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;//Specify trigger timer TIM2 for DAC1
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;//No waveform generation
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //Not enable DAC output buffer
DAC_Init(DAC_Channel_1, &DAC_InitStructure); //Initialize DAC channel1

DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; //Specify trigger timer TIM6 for DAC2
DAC_Init(DAC_Channel_2, &DAC_InitStructure); //Initialize DAC channel2

DAC_Cmd(DAC_Channel_1, ENABLE); //Enable DAC channel1
DAC_Cmd(DAC_Channel_2, ENABLE); //Enable DAC channel2

DAC_DMACmd(DAC_Channel_1, ENABLE); //Enable DMA for DAC Channel1
DAC_DMACmd(DAC_Channel_2, ENABLE); //Enable DMA for DAC Channel2
}

In the above code, DAC_Trigger of channel 1 and channel 2 of DAC are set to timer 2 trigger DAC_Trigger_T2_TRGO and timer 6 trigger DAC_Trigger_T6_TRGO respectively. Regarding the external trigger source of DAC, it can only be the following ones: TIM2, TIM4, TIM5, TIM6, TIM7, TIM8, EXIT_Line9, SWTRIG (software trigger), as shown in the following figure:
STM32 Sine Wave Output - ziye334 - ziye334's Blog
 After configuring DAC channel 1 and channel 2, you also need to turn on the DAC's DMA function: DAC_DMACmd(DAC_Channel_1, ENABLE); DAC_DMACmd(DAC_Channel_2, ENABLE); so that DMA can control the DAC output.
After DAC is configured, it is time to configure DAM. The DMA configuration code is as follows:

#define DAC_DHR12R1 0x40007408 //Base address of peripheral DAC channel 1
#define DAC_DHR12R2 0x40007414 //Base address of peripheral DAC channel 2

/****************************************************************
Function: SineWave_DMA_Config
Description: DMA configuration
Input: none
return: none
**********************************************************/
static void SineWave_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);//Initialize DMA2 clock

DMA_DeInit(DMA2_Channel3); //Configure DMA to default values
​​DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R1;//Specify the target address of DMA2 channel 3 as DAC1_DHR12R1
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit;//Specify the source address of DMA as array Sine12bit
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //Peripheral as the destination of data transferDMA_InitStructure.DMA_BufferSize
= sizeof(Sine12bit)/2; //DMA buffer sizeDMA_InitStructure.DMA_PeripheralInc
= DMA_PeripheralInc_Disable; //Peripheral machine address register unchangedDMA_InitStructure.DMA_MemoryInc
= DMA_MemoryInc_Enable; //Memory address register incrementDMA_InitStructure.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_HalfWord; //Peripheral data width is half
wordDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //Memory data width is half
wordDMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //Work in circular cache mode. When the number of data transfers is 0, the initial configuration value is automatically restored
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //Very high priority
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //The channel is not set to memory-to-memory mode, which is opposite to the circular mode
DMA_Init(DMA2_Channel3, &DMA_InitStructure); //Initialize DMA

DMA_DeInit(DMA2_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R2; //Specify the target address of DMA2 channel 3 as DAC2_DHR12R2
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
DMA_Init(DMA2_Channel4, &DMA_InitStructure);

DMA_Cmd(DMA2_Channel3, ENABLE); //Enable DMA channel3
DMA_Cmd(DMA2_Channel4, ENABLE); //Enable DMA channel4
}

First of all, we need to explain why the configuration is DMA2, and it is DMA2's channel 3 and channel 4. This is because different peripherals correspond to different DMAs and DMA channels, and their corresponding relationship is shown in the following figure:
STM32 Sine Wave Output - ziye334 - ziye334's Blog
STM32 Sine Wave Output - ziye334 - ziye334's Blog
From the two pictures above, we can see that DAC channel 1 corresponds to channel 3 of DMA2, and DAC channel 2 corresponds to channel 4 of DMA.
DMA_PeripheralBaseAddr = DAC_DHR12R1; This sentence specifies the base address of the DAC peripheral, and its address has been given in the macro definition. The value of this peripheral base address can be queried by referring to the "STM32 Reference Manual". I take DAC channel 1 as an example: by checking Section 2.3 of the "STM32 Reference Manual", it can be found that the register group address range of DAC is: 0x40007400~0x00077FF, as shown in the figure below:
STM32 Sine Wave Output - ziye334 - ziye334's Blog
Then you can refer to "Section 11.5.14 of STM32" to find the DAC register image table, select the DAC_DHR12R1 register, and check that its offset is 0x08, as shown in the following figure:
STM32 Sine Wave Output - ziye334 - ziye334's Blog
 So the DAC_DHR12R1 defined above = base address + offset address = 0x40007400 + 0x08 = 0x40007408. The following is an explanation of the registers, which may help to understand the code:
DAC_CR: DAC Control Register (Offset: 0x00)
DAC_SWTRIGR: DAC Software Trigger Register (offset: 0x04)
  DAC_DHR12R1: 12-bit right-aligned data holding register for DAC channel 1 (offset: 0x08)
DAC_DHR12L1: 12-bit left-aligned data holding register for DAC channel 1 (offset: 0x0C)
DAC_DHR8R1: 8-bit right-aligned data holding register for DAC channel 1 (offset: 0x10)
  DAC_DHR12R2: 12-bit right-aligned data holding register for DAC channel 2 (offset: 0x14)
DAC_DHR12L2: 12-bit left-aligned data holding register for DAC channel 2 (offset: 0x18)
DAC_DHR8R2: 8-bit right-aligned data holding register for DAC channel 2 (offset: 0x1C)
DAC_DHR12LD: 12-bit left-aligned data holding register for dual DAC (offset: 0x20)
DAC_DHR12RD: Dual DAC 12-bit right-aligned data holding register (offset: 0x24)
DAC_DHR8RD: 8-bit right-aligned data holding register for dual DAC (offset: 0x28)
DAC_DOR1: DAC channel 1 data output register (offset: 0x2C)
DAC_DOR2: DAC channel 2 data output register (offset: 0x30)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit; This sentence specifies the source address of the data, that is, the data during DMA operation is taken from this address.
DMA_InitStructure.DMA_BufferSize = sizeof(Sine12bit)/2; defines the size of the DMA buffer. The size of the buffer should be the same as the size of the Sine12bit[] array.
There are some other codes later, I won’t go into details, just read the comments yourself.
Finally, you need to define a general function: SineWave_Init(), which calls the above functions to initialize the code related to the sine wave:

/****************************************************************
Function: SineWave_Init();
Description: Sine wave initialization
Input: none
return: none
*************************************************************/
void SineWave_Init(void)
{
SineWave_GPIO_Config(); //Configure pins
SineWave_TIM_Config(); //Configure timer
SineWave_DAC_Config(); //Configure DAC
SineWave_DMA_Config(); //Configure DMA

TIM_Cmd(TIM2, ENABLE); //Turn on TIM2
TIM_Cmd(TIM6, ENABLE); //Turn on TIM6
}

Download and talk about the SineWave.h file. It only declares the SineWave_Init() function to facilitate calling by other files.
3. Writing main.c function
The main function needs to call the SineWave_Init() function defined above to initialize the relevant code:

/****************************************************** ************
Function: main
Description: mainInput
: none
return: none
************************* ************************************/
int main(void)
{
BSP_Init();
SineWave_Init() ;
PRINTF("\nmain() is running!\r\n");
while(1)
{
LED1_Toggle();
Delay_ms(1000);
}
}

4. Testing
Using an oscilloscope to check the output waveform, we can detect sine waves with frequencies of 800Hz and 1600Hz. In fact, this is not the focus of the test. The focus is to observe the difference between the output waveforms using Sine12bit[32] and Sine12bit[256]. I collected waveforms with an output frequency of 1600Hz, using Sine12bit[32] and Sine12bit[256] respectively, which correspond to the first and second pictures below respectively:
STM32 Sine Wave Output - ziye334 - ziye334's Blog
 
STM32 Sine Wave Output - ziye334 - ziye334's Blog
Comparing the two figures, we can see that the waveform outputted using Sine12bit[32] is somewhat discontinuous, while the sine wave outputted using Sine12bit[256] is very continuous and smooth.

Keywords:STM32 Reference address:STM32 sine wave output

Previous article:STM32 ADC conversion
Next article:STM32 external interrupt analysis

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号