sobota, 19 marca 2016

[10] STM32F4 - Discovery - DAC

W tym poście chciałbym opisać w jaki sposób zainicjować oraz odpalić konwerter cyfrowo analogowy.

Charakterystyka DAC


STM32F407 został wyposażony w dwa wyjścia sygnału DAC. Zlokalizowane są one w następujących wyprowadzeniach:

  • DAC1 - PA4
  • DAC2 - PA5

Każdy z kanałów został wyposażony w osobny konwerter. Jeśli wykorzystywany jest tryb dwukanałowy, wtedy dane mogą być wprowadzane osobno bądź jednocześnie. 

Przez ten układ akceptowane są trzy rodzaje danych całkowitych: 8 bitowe, 12 bitowe wyrównane do lewej oraz 12 bitowe wyrównane do prawej. Zakres danych 12 bitowych rozpoczyna się od 0x0000, natomiast maksymalnie można wprowadzić 0xFFFF.

Programowanie


Poniżej znajduje się podstawowy program, którego zadaniem jest generacja sygnału analogowego na określonym poziomie. 

Jeśli chodzi o strukturę włączająca DAC, do wyboru są cztery pola:

DAC_Trigger - pozwala na wybranie zewnętrznego sygnału generowanego dla wybranego kanału.

  1. #define DAC_Trigger_None                   ((uint32_t)0x00000000) //Konwersja automatyczna
  2. #define DAC_Trigger_T2_TRGO                ((uint32_t)0x00000024) //Generowane z TIM2
  3. #define DAC_Trigger_T4_TRGO                ((uint32_t)0x0000002C) //Generowane z TIM4
  4. #define DAC_Trigger_T5_TRGO                ((uint32_t)0x0000001C) //Generowane z TIM5
  5. #define DAC_Trigger_T6_TRGO                ((uint32_t)0x00000004) //Generowane z TIM6
  6. #define DAC_Trigger_T7_TRGO                ((uint32_t)0x00000014) //Generowane z TIM7
  7. #define DAC_Trigger_T8_TRGO                ((uint32_t)0x0000000C) //Generowane z TIM8
  8. #define DAC_Trigger_Ext_IT9                ((uint32_t)0x00000034) //Generacja z EXTI kanał 9
  9. #define DAC_Trigger_Software               ((uint32_t)0x0000003C) //Rozpoczęcie konwersji poprzez start w systemie

DAC_WaveGeneration - określa jaki sygnał będzie generowany czy sygnał szumu, trójkątny bądź bez generacji.

  1. #define DAC_WaveGeneration_None            ((uint32_t)0x00000000) //Bez generacji
  2. #define DAC_WaveGeneration_Noise           ((uint32_t)0x00000040) //Szum
  3. #define DAC_WaveGeneration_Triangle        ((uint32_t)0x00000080) //Sygnał trójkątny

DAC_LFSRUnmask_TriangleAmplitude - pozwala na określenie maski LFSR dla szumu oraz maksymalnej amplitudy sygnału trójkątnego

  1. #define DAC_LFSRUnmask_Bit0                ((uint32_t)0x00000000) //Odsloniete LFSR, bit0 dla generacji szumu
  2. #define DAC_LFSRUnmask_Bits1_0             ((uint32_t)0x00000100) //Odsloniete LFSR, bit[1:0]
  3. #define DAC_LFSRUnmask_Bits2_0             ((uint32_t)0x00000200) //Odsloniete LFSR, bit[2:0]
  4. #define DAC_LFSRUnmask_Bits3_0             ((uint32_t)0x00000300) //Odsloniete LFSR, bit[3:0]
  5. #define DAC_LFSRUnmask_Bits4_0             ((uint32_t)0x00000400) //Odsloniete LFSR, bit[4:0]
  6. #define DAC_LFSRUnmask_Bits5_0             ((uint32_t)0x00000500) //Odsloniete LFSR, bit[5:0]
  7. #define DAC_LFSRUnmask_Bits6_0             ((uint32_t)0x00000600) //Odsloniete LFSR, bit[6:0]
  8. #define DAC_LFSRUnmask_Bits7_0             ((uint32_t)0x00000700) //Odsloniete LFSR, bit[7:0]
  9. #define DAC_LFSRUnmask_Bits8_0             ((uint32_t)0x00000800) //Odsloniete LFSR, bit[8:0]
  10. #define DAC_LFSRUnmask_Bits9_0             ((uint32_t)0x00000900) //Odsloniete LFSR, bit[9:0]
  11. #define DAC_LFSRUnmask_Bits10_0            ((uint32_t)0x00000A00) //Odsloniete LFSR, bit[10:0]
  12. #define DAC_LFSRUnmask_Bits11_0            ((uint32_t)0x00000B00) //Odsloniete LFSR, bit[11:0]
  13. #define DAC_TriangleAmplitude_1            ((uint32_t)0x00000000) //Maksymalna amplituda sygnalu trojkatnego 1
  14. #define DAC_TriangleAmplitude_3            ((uint32_t)0x00000100) //Maksymalna amplituda sygnalu trojkatnego 3
  15. #define DAC_TriangleAmplitude_7            ((uint32_t)0x00000200) //Maksymalna amplituda sygnalu trojkatnego 7
  16. #define DAC_TriangleAmplitude_15           ((uint32_t)0x00000300) //Maksymalna amplituda sygnalu trojkatnego 15
  17. #define DAC_TriangleAmplitude_31           ((uint32_t)0x00000400) //Maksymalna amplituda sygnalu trojkatnego 31
  18. #define DAC_TriangleAmplitude_63           ((uint32_t)0x00000500) //Maksymalna amplituda sygnalu trojkatnego 63
  19. #define DAC_TriangleAmplitude_127          ((uint32_t)0x00000600) //Maksymalna amplituda sygnalu trojkatnego 127
  20. #define DAC_TriangleAmplitude_255          ((uint32_t)0x00000700) //Maksymalna amplituda sygnalu trojkatnego 255
  21. #define DAC_TriangleAmplitude_511          ((uint32_t)0x00000800) //Maksymalna amplituda sygnalu trojkatnego 511
  22. #define DAC_TriangleAmplitude_1023         ((uint32_t)0x00000900) //Maksymalna amplituda sygnalu trojkatnego 1023
  23. #define DAC_TriangleAmplitude_2047         ((uint32_t)0x00000A00) //Maksymalna amplituda sygnalu trojkatnego 2047
  24. #define DAC_TriangleAmplitude_4095         ((uint32_t)0x00000B00) //Maksymalna amplituda sygnalu trojkatnego 4095

DAC_OutputBuffer - ten parametr pozwala na włączenie bądź wyłączenie bufora wyjściowego

  1. #define DAC_OutputBuffer_Enable            ((uint32_t)0x00000000) //Wlaczony
  2. #define DAC_OutputBuffer_Disable           ((uint32_t)0x00000002) //Wylaczony


Teraz czas przejść do programu głównego. Składa się on z trzech funkcji. Pierwsza inicjuje pracę pinów GPIO oraz DAC, druga ustawia wartość na pinach, 

Włączenie pinów oraz DAC wygląda następująco:

  1. //Deklaracja nazw dla poszczególnych wejsc DAC
  2. typedef enum {
  3.     DAC1,
  4.     DAC2
  5. } DACxx;
  6. void DACInit(DACxx DACx)
  7. {
  8.     DAC_InitTypeDef DACInit;
  9.     GPIO_InitTypeDef GPIOInit;
  10.    
  11.     /* Select proper GPIO pin */
  12.     if (DACx == DAC1)
  13.     {
  14.         GPIOInit.GPIO_Pin = GPIO_Pin_4;
  15.     }
  16.     else if(DACx == DAC2)
  17.     {
  18.         GPIOInit.GPIO_Pin = GPIO_Pin_5;
  19.     }
  20.    
  21.     //Wlaczenie zegara dla portu GPIOA
  22.     //RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  23.     RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
  24.    
  25.     //Pozostale ustawienia wyprowadzen GPIO
  26.     GPIOInit.GPIO_Mode = GPIO_Mode_AN;
  27.     GPIOInit.GPIO_OType = GPIO_OType_PP;
  28.     GPIOInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
  29.     GPIOInit.GPIO_Speed = GPIO_Speed_50MHz;
  30.     GPIO_Init(GPIOA, &GPIOInit);
  31.     //Wlaczenie zegara dla DAC
  32.     //RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
  33.     RCC->APB1ENR |= RCC_APB1ENR_DACEN;
  34.    
  35.     //Ustawienie opcji dla DAC
  36.     DACInit.DAC_Trigger = DAC_Trigger_None;
  37.     DACInit.DAC_WaveGeneration = DAC_WaveGeneration_None;
  38.     DACInit.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
  39.    
  40.     //Inicjacja i wlaczenie wybranego pinu DAC
  41.     if (DACx == DAC1)
  42.     {
  43.         DAC_Init(DAC_Channel_1, &DACInit);
  44.         //Wlaczenie kanalu pierwszego
  45.         //DAC_Cmd(DAC_Channel_1, ENABLE);
  46.         DAC->CR |= DAC_CR_EN1;
  47.     }
  48.     else
  49.     {
  50.         DAC_Init(DAC_Channel_2, &DACInit);
  51.         //Wlaczenie kanalu drugiego
  52.         //DAC_Cmd(DAC_Channel_2, ENABLE);
  53.         DAC->CR |= DAC_CR_EN2;
  54.     }
  55. }

Teraz funkcja wprowadzająca wartości do rejestru. Dane w formacie 12 bitowym wyrównane do prawej strony.

  1. //Ustawienie wartosci cyfrowej, która bedzie zamieniona na analogowa
  2. void DAC_Set(DACxx DACx, uint32_t digit_val)
  3. {
  4.     //Wpisanie danych 12 bitowych wyrównanych do prawej
  5.     //do odpowiedniego rejestru
  6.     if (DACx == DAC1)
  7.     {
  8.         DAC->DHR12R1 = digit_val;
  9.     }
  10.     else if(DACx == DAC2)
  11.     {
  12.         DAC->DHR12R2 = digit_val;
  13.     }
  14. }

Poniżej główna funkcja programu, wywołująca te przedstawione wcześniej z odpowiednimi parametrami.

Dane wyprowadzone oblicza się w następujący sposób:

Wartość wyjściowa [V] = (Wartość wprowadzana) / (Wartość maksymalna dla 12bit) * 3.3V

Wartość wprowadzana do przetwornika, maksymalnie 4096
Wartość maksymalna dla 12 bit = 2^12 = 4096

  1. int main(void)
  2. {
  3.     //DAC1 PA4
  4.     DACInit(DAC1);
  5.     //DAC2 PA5
  6.     DACInit(DAC2);
  7.    
  8.     //Wprowadzenie wartosci do DAC1
  9.     DAC_Set(DAC1, 2000);
  10.     //Wprowadzenie wartosci do DAC2
  11.     DAC_Set(DAC2, 3000);
  12.    
  13.     while (1)
  14.     {
  15.     }
  16. }