In the previous guide, we took a look at the internal DAC of STM32L053 (here) and we where are able to generate sawtooth using DAC and software trigger. In this guide, we shall use timer and DMA to generate sinewave using DAC.
In this guide, we shall cover the following:
- DAC trigger sources.
- DAC with timer trigger calculations.
- Configure DMA for DAC.
- Configure timer for DAC.
- Configure DAC with DMA.
- Code.
- Results.
1. Trigger Sources of DAC:
The DAC of the STM32 has three major trigger sources:
- Timer triggered.
- External Triggered.
- Software triggered.
In the previous guide, we covered the software trigger part.
For timer trigger, there are several options:
In this guide, we shall use timer6 to trigger the DAC.
2. DAC with timer trigger calculation:
Let’s say we’ve generated a sinewave lookup table with 128 sample points (Ns), and configured Timer2 so it triggers the DMA transfer to the DAC output. What would be the output sine wave frequency?
Here are the formulas to be used
Where FCLK is the frequency of the clock used by your timer module, PSC is the Prescaler, and ARR is the value of the auto-reload register.
Where Ns is the sample points number in the lookup table.
For example, let’s assume the following settings:
The FCLK is 80MHz, the PSC is 0, ARR is 1000, and the sine lookup table has 128 sample points. What would be the output sine wave frequency?
TriggerFrequency = 80MHz / 1001 = 79920.08
Output Sinewave Frequency = TriggerFrequency / 128 = 624.37 Hz
3. Configuring DMA for the DAC:
Before we configure the DMA, we need to get which DMA is responsible for DAC.
From STM32L053 Reference manual DMA section:
We can find that Channel2 C9S is responsible for DAC Channel1
Then we start of by enabling clock access to DMA1:
RCC->AHBENR|=RCC_AHBENR_DMAEN;
Configure the DMA to do the following:
- Memory and peripheral size to 16-bit (half-word).
- Memory increment mode
- Circular.
- Read from memory.
DMA1_Channel2->CCR=DMA_CCR_MSIZE_0|DMA_CCR_PSIZE_0|DMA_CCR_MINC|DMA_CCR_CIRC|DMA_CCR_DIR;
Then set the length:
DMA1_Channel2->CNDTR=SINE_RES;
Memory address that holds the data:
DMA1_Channel2->CMAR=(uint32_t)function;
Peripheral address:
DMA1_Channel2->CPAR=(uint32_t)(&DAC1->DHR12R1);
Set the C2S to be 9:
DMA_CSELR|=(0x09<<4);
4. Configure Timer6 for DAC:
In order to configure timer6, we need just those four lines:
RCC->APB1ENR|=RCC_APB1ENR_TIM6EN; TIM6->PSC=0; TIM6->ARR=1; TIM6->CR2|=TIM_CR2_MMS_1;
5. Configure DAC for DMA:
First enable clock access to DAC1:
RCC->APB1ENR|=RCC_APB1ENR_DACEN;
Since Timer6 is responsible for triggering the DMA, we shall set trigger selection for timer6 which is 000
DAC1->CR&=~(DAC_CR_TSEL1_0|DAC_CR_TSEL1_1|DAC_CR_TSEL1_2);
Set amplitude to be 4095:
DAC1->CR|=DAC_CR_MAMP1_3|DAC_CR_MAMP1_1|DAC_CR_MAMP1_0;
Enable trigger:
DAC1->CR|=DAC_CR_TEN1;
Enable output buffer:
DAC1->CR|=DAC_CR_BOFF1;
Enable DMA request:
DAC1->CR|=DAC_CR_DMAEN1;
Finally, enable DMA1_Channel2,DAC and Timer6:
DMA1_Channel2->CCR|=DMA_CCR_EN; DAC1->CR|=DAC_CR_EN1; TIM6->CR1|=TIM_CR1_CEN;
The lookup table for sinewave:
#define SINE_RES 128 uint16_t function[SINE_RES] = { 2048, 2145, 2242, 2339, 2435, 2530, 2624, 2717, 2808, 2897, 2984, 3069, 3151, 3230, 3307, 3381, 3451, 3518, 3581, 3640, 3696, 3748, 3795, 3838, 3877, 3911, 3941, 3966, 3986, 4002, 4013, 4019, 4020, 4016, 4008, 3995, 3977, 3954, 3926, 3894, 3858, 3817, 3772, 3722, 3669, 3611, 3550, 3485, 3416, 3344, 3269, 3191, 3110, 3027, 2941, 2853, 2763, 2671, 2578, 2483, 2387, 2291, 2194, 2096, 1999, 1901, 1804, 1708, 1612, 1517, 1424, 1332, 1242, 1154, 1068, 985, 904, 826, 751, 679, 610, 545, 484, 426, 373, 323, 278, 237, 201, 169, 141, 118, 100, 87, 79, 75, 76, 82, 93, 109, 129, 154, 184, 218, 257, 300, 347, 399, 455, 514, 577, 644, 714, 788, 865, 944, 1026, 1111, 1198, 1287, 1378, 1471, 1565, 1660, 1756, 1853, 1950, 2047 };
5. Code:
Hence, the entire code:
#include "stm32l0xx.h" #include "core.h" #define SINE_RES 128 uint16_t function[SINE_RES] = { 2048, 2145, 2242, 2339, 2435, 2530, 2624, 2717, 2808, 2897, 2984, 3069, 3151, 3230, 3307, 3381, 3451, 3518, 3581, 3640, 3696, 3748, 3795, 3838, 3877, 3911, 3941, 3966, 3986, 4002, 4013, 4019, 4020, 4016, 4008, 3995, 3977, 3954, 3926, 3894, 3858, 3817, 3772, 3722, 3669, 3611, 3550, 3485, 3416, 3344, 3269, 3191, 3110, 3027, 2941, 2853, 2763, 2671, 2578, 2483, 2387, 2291, 2194, 2096, 1999, 1901, 1804, 1708, 1612, 1517, 1424, 1332, 1242, 1154, 1068, 985, 904, 826, 751, 679, 610, 545, 484, 426, 373, 323, 278, 237, 201, 169, 141, 118, 100, 87, 79, 75, 76, 82, 93, 109, 129, 154, 184, 218, 257, 300, 347, 399, 455, 514, 577, 644, 714, 788, 865, 944, 1026, 1111, 1198, 1287, 1378, 1471, 1565, 1660, 1756, 1853, 1950, 2047 }; #define DMA_CSELR (*(volatile unsigned int *)(0x400200a8)) int main(void) { /*Set the core frequency to 32MHz*/ config_core_32mhz(); /*Set PA4 to Analog mode*/ RCC->IOPENR|=RCC_IOPENR_GPIOAEN; GPIOA->MODER|=GPIO_MODER_MODE4; /*Configure the DAC*/ RCC->APB1ENR|=RCC_APB1ENR_DACEN; DAC1->CR|=DAC_CR_MAMP1_3|DAC_CR_MAMP1_1|DAC_CR_MAMP1_0; DAC1->CR|=DAC_CR_TEN1; DAC1->CR|=DAC_CR_BOFF1; DAC1->CR|=DAC_CR_DMAEN1; /*TIMER6 configuration*/ RCC->APB1ENR|=RCC_APB1ENR_TIM6EN; TIM6->PSC=0; TIM6->ARR=1; TIM6->CR2|=TIM_CR2_MMS_1; RCC->AHBENR|=RCC_AHBENR_DMAEN; DMA1_Channel2->CCR=DMA_CCR_MSIZE_0|DMA_CCR_PSIZE_0|DMA_CCR_MINC|DMA_CCR_CIRC|DMA_CCR_DIR; DMA1_Channel2->CNDTR=SINE_RES; DMA1_Channel2->CMAR=(uint32_t)function; DMA1_Channel2->CPAR=(uint32_t)(&DAC1->DHR12R1); DMA_CSELR|=(0x09<<4); DMA1_Channel2->CCR|=DMA_CCR_EN; DAC1->CR|=DAC_CR_EN1; TIM6->CR1|=TIM_CR1_CEN; while(1) { } }
How to set STM32L053 to 32MHz, please refer to this topic: here
6. Result:
When you probe pin PA4 using oscilloscope, you should see this:
Happy coding 🙂
Add Comment