AD9833 - Generator funkcyjny DDS

To nie jest miejsce tylko dla początkujących, wszyscy jesteśmy w czymś początkujący i wymieniamy się doświadczeniami.
Awatar użytkownika
gaweł
Geek
Geek
Posty: 1262
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

AD9833 - Generator funkcyjny DDS

Postautor: gaweł » środa 26 kwie 2017, 14:13

Zainspirowany ciekawymi rozważaniami "Model generatora sygnałowego na wzmacniaczach operacyjnych LM741" koleżanki Taszy przedstawiam swoje eksperymenty w podobnym temacie.
Elektronika schodzi pod strzechy, czyli coś, co w niezbyt odległych czasach było szczytem możliwości, dzisiaj zaczyna robić się dostępne dla każdego. Przykładem tego procesu może być układ AD9833 oferowany przez firmę Analog Devices. Wymieniony układ jest generatorem funkcyjnym (generującym sygnał sinusoidalny, trójkątny lub prostokątny) jako układ DDS. Określenie DDS (ang. Direct Digital Synthesis) oznacza bezpośrednią syntezę cyfrową – metodę generowania sygnałów o określonych kształtach bez udziału elementów analogowych w obwodach generatora. Układ jest w pełni sterowany cyfrowo z zewnątrz (przykładowo przez mikrokontroler).
AD9833 jest taktowany sygnałem cyfrowym o maksymalnej częstotliwości 25MHz. W oparciu o ten sygnał zegarowy wytwarzany jest wyjściowy przebieg o zadanym kształcie i zadanej częstotliwości. Stabilność generowanego przebiegu jest uzależniona od stabilności sygnału taktującego układem DDS. Przeciętna stabilność generatorów taktujących wynosi kilkadziesiąt pps, co w wielu amatorskich zastosowaniach jest w pełni wystarczająca.
Przykładowa aplikacja składa się z mikrokontrolera ATMEGA644, który jest użyty do sterowania generatorem (schemat jednostki centralnej pokazuje rysunek 1). Jest to standardowe środowisko obejmujące mikrokontroler oraz niezbędne do jego pracy elementy zewnętrzne jak obwód generatora sygnału taktującego (C102, C103, X101), obwód do generowania sygnału zerującego (D101, R101, P102, C101), przyłącza do zaprogramowania pamięci FLASH mikrokontrolera (P101).
sch1-cpng.PNG

Do mikrokontrolera przyłączony jest standardowy moduł LCD (schemat pokazuje rysunek 2) oraz sam generator DDS (schemat pokazuje rysunek 3).
sch4-cpng.PNG
sch3a-cpng.PNG

Aplikacja generatora AD9833 oprócz kilku kondensatorów (C301, C302, C303) wymaga sygnału taktującego (jako sygnał MCLK dla układu U302). Jest on uzyskany ze standardowego generatora sygnału taktującego (U301). Na wyjściu tego generatora wytwarzany jest przebieg fali prostokątnej o częstotliwości 25 MHz. Częstotliwość tego sygnału jest maksymalną dopuszczalną częstotliwością dla układu DDS. Przy takim sygnale taktującym układem DDS możliwe jest generowanie na jego wyjściu sygnałów o częstotliwości od 0 do 12,5 MHZ. Jednak z uwagi na jakość produkowanego sygnału, rzeczywiste możliwości układu są ograniczone do praktycznie 1 MHz (przy większych częstotliwościach dają o sobie znać wyższe harmoniczne a przebieg sinusoidalny staje się zbyt schodkowy). Przy taktowaniu układu DDS sygnałem o częstotliwości 25 MHz możliwe jest uzyskanie rozdzielczości 0.1 Hz, czyli można wytworzyć przykładowo dowolny przebieg sinusoidalny w zakresie od 0 Hz do 1 MHz z dokładnością 0.1 Hz. Zmiana częstotliwości sygnału taktującego na 2.5 MHz pozwala uzyskać rozdzielczość 0.01 Hz. Oczywiście jest to okupione dziesięciokrotnym zmniejszeniem zakresu częstotliwości generowanego sygnału (od 0 Hz do 100 kHz) [w przykładach zastosowany jest generator taktujący o częstotliwości 2,5 MHz].
Do zaprogramowania układu AD9833 używany jest szeregowy interfejs synchroniczny, na który składa się sygnał zegarowy (SCLK), sygnał synchronizacji ramki przesyłanych do układu danych (FSYNC) oraz sygnał danych szeregowych (SDATA). Przebieg sygnałów sterujących pokazuje rysunek 4. Zapis kolejnych bitów danych do układu DDS następuje przy opadającym zboczu sygnału SCLK zaczynając od pozycji najbardziej znaczącej (za każdym razem zapisywanych jest 16 bitów sterujących).
dds1.PNG

Układ AD9833 ma dwa zestawy rejestrów do zapisu danych określających generowaną częstotliwość (FREQ0 oraz FREQ1) oraz dwa rejestry do zapisu danych określających fazę generowanego sygnału (PHASE0 oraz PHASE1). Znaczenie każdego zapisywanego do układu DDS słowa sterującego jest rozpoznawane po zawartości dwóch najbardziej znaczących bitów w następujący sposób:
Bit 15,Bit 14,Bit 13 - Znaczenie
0 0 x - Słowo sterujące.
0 1 x - Zapis danych określających generowaną częstotliwość do rejestru FREQ0
1 0 x - Zapis danych określających generowaną częstotliwość do rejestru FREQ1
1 1 0 - Zapis danych określających fazę generowanego sygnału do rejestru PHASE0
1 1 1 - Zapis danych określających fazę generowanego sygnału do rejestru PHASE1
Słowo sterujące ma następującą strukturę:
Bit - Nazwa - Znaczenie
Bit 13 - B28 - Aby załadować pełne słowo do jednego z rejestrów częstotliwości, wymagane są dwie operacje zapisu. B28 = 1 umożliwia pełne załadowanie całego słowa do rejestru częstotliwości w dwóch kolejnych zapisach. Pierwszy zapis zawiera 14 LSB słowa częstotliwości, a następny zapis zawiera 14 MSB. Pierwsze dwa bity każdego słowa 16-bitowego definiują rejestr częstotliwości, do którego słowo jest załadowane, a zatem powinny być takie same dla obu kolejnych zapisów. Gdy B28 = 0, 28-bitowy rejestr częstotliwości działa jak dwa rejestry 14-bitowe, jeden zawierający 14 MSB, a drugi zawierający 14 LSB. Oznacza to, że 14 MSB słowa częstotliwości może być zmieniane niezależnie od 14 LSB i vice versa. Aby zmienić 14 MSB lub 14 LSB, zostanie wysłany pojedynczy zapis do odpowiedniego adresu częstotliwości. Bit kontrolny D12 (HLB) informuje AD9833, czy bity mają być zmienione to 14 MSB lub 14 LSB.
Bit 12 - HLB - W przypadku gdy B28 = 0, 28-bitowy rejestr funkcjonalnie jak 14-bitowy, jeden zawierający 14 MSB, drugi zawierający 14 LSB. Bit kontrolny D12 (HLB) informuje AD9833, czy bity mogą być zmienione na 14 MSB lub 14 LSB.
Bit 11 - FSELECT - Bit FSELECT definiuje, czy układ DDS wykorzystuje rejestr FREQ0 lub rejestr FREQ1 do generowania sygnału wyjściowego.
Bit 10 - PSELECT - Bit PSELECT definiuje, czy układ DDS wykorzystuje rejestr PHASE0 lub PHASE1.
Bit 9 - Ten bit powinien być ustawiony na 0.
Bit 8 - RESET - Reset = 1 resetuje wewnętrzne rejestry do 0, co odpowiada wyjściu analogowemu średniej wielkości. Reset = 0 wyłącza reset.
Bit 7 - SLEEP1 - Gdy SLEEP1 = 1, wewnętrzny zegar MCLK jest wyłączony, a wyjście DAC pozostaje w wartości bieżącej.
Bit 6 - SLEEP12 - SLEEP12 = 1 wyłącza procesor DAC. SLEEP12 = 0 oznacza, że DAC jest aktywny.
Bit 5 - OPBITEN - Funkcja tego bitu, w połączeniu z D1 (MODE), polega na sterowaniu tym, co jest przesyłane na wyjściu VOUT. Gdy OPBITEN = 1, wyjście DAC nie jest już dostępne na wyjściu VOUT. Gdy OPBITEN = 0, DAC jest podłączony do VOUT. Bity trybu określają, czy jest dostępny sygnał sinusoidalny lub wyjściowy trójkątny.
Bit 4 - Ten bit powinien być ustawiony na 0.
Bit 3 - DIV2 - DIV2 jest używany w połączeniu z D5 (OPBITEN). Gdy DIV2 = 1, MSB danych DAC jest przekazywany bezpośrednio do wyjścia VOUT. Gdy DIV2 = 0, MSB / 2 danych DAC jest wyprowadzane na wyjściu VOUT.
Bit 2 - Ten bit powinien być ustawiony na 0.
Bit 1 - MODE - Ten bit jest używany w połączeniu z OPBITEN (D5). Funkcja tego bitu polega na sterowaniu tym, co jest przesyłane na wyjście VOUT, gdy wewnętrzny DAC jest podłączony do VOUT. Ten bit powinien być ustawiony na 0, jeśli bit kontrolny OPBITEN = 1. Gdy MODE = 1, ROM SIN jest pomijany, co skutkuje trójkątnym wyjściem z DAC. Gdy MODE = 0, ROM SIN jest używany do przekształcania informacji fazy w informacje o amplitudzie, co powoduje sinusoidalny sygnał na wyjściu.
Bit 0 - Ten bit powinien być ustawiony na 0.
Do określenia wymaganej częstotliwości wygenerowanego sygnału należy do układu DDS wpisać 28-bitową liczbę określającą ta częstotliwość. Te dane sterujące są podzielone na dwa zestawy 14-bitowe określające część bardziej znaczącą oraz mniej znaczącą. Dane te są wpisywane jako dwie operacje zapisu (w sytuacji zapisu obu części 14-bitowych [bit B28=1], w pierwszej kolejności część mniej znacząca oraz w drugiej kolejności część bardziej znacząca). Dane określające fazę generowanego sygnału są 12-bitowe, więc wpis do układu DDS jest realizowany jako pojedyncza operacja zapisu. Nastawy determinujące częstotliwość generowanego sygnału są obliczane w następujący sposób:
form1.PNG

Gdzie:
fOUT – częstotliwość na wyjściu układu DDS,
fMCLK – częstotliwość sygnału taktującego
FREQREG – nastawa zapisana w rejestrze.
Łatwo zauważyć, że
form2.PNG
gdzie:
form3.PNG

Zakładając, że wymagana częstotliwość wyjściowa sygnału z rozdzielczością do 0.01 Hz jest określana jako liczba całkowita (wyrażana w setnych częściach Hz, czyli fOUT=1 oznacza 0.01Hz; fOUT=101 oznacza 1.01Hz), w przykładzie oprogramowania stała ta ma wartość:
form4.PNG

Do prezentacji został napisany program (projekt w AVRSTUDIO)
dds_avr.zip

Kod: Zaznacz cały

#ifndef _HardwModule_
#define _HardwModule_

#include <inttypes.h>

#define SquareWaveFormat                 0              // generowana jest fala mprostokątna
#define SineWaveFormat                   1              // generowana jest fala sin
#define TriangularWaveFormat             2              // generowana jest fala trójkątna

extern void StartDDSWaveGeneration ( uint8_t  /* WaveFormat */ ,
                                     uint32_t /* Frequency  */ ) ;


extern void StopDDSWaveGeneration ( void ) ;

extern void InitDDSEnvir ( void ) ;

#endif

Kod: Zaznacz cały

#include "ddsmodule.h"
#include <avr/io.h>


#define nop() __asm__ __volatile__ ("nop")


#define DDSPort                         PORTC
#define DDSDirPort                      DDRC
#define SDATPin                         3               // PC.3
#define SCLKPin                         4               // PC.4
#define FSYNCPin                        5               // PC.5
#define SetSDATLow                      DDSPort &= ~ ( 1 << SDATPin )
#define SetSDATHigh                     DDSPort |= ( 1 << SDATPin )
#define SetSCLKLow                      DDSPort &= ~ ( 1 << SCLKPin )
#define SetSCLKHigh                     DDSPort |= ( 1 << SCLKPin )
#define SetFSYNCLow                     DDSPort &= ~ ( 1 << FSYNCPin )
#define SetFSYNCHigh                    DDSPort |= ( 1 << FSYNCPin )


#define B28_BitPos                      13
#define HLB_BitPos                      12
#define FSELECT_BitPos                  11
#define PSELECT_BitPos                  10
#define Reset_BitPos                    8
#define SLEEP1_BitPos                   7
#define SLEEP12_BitPos                  6
#define OPBITEN_BitPos                  5
#define DIV2_BitPos                     3
#define Mode_BitPos                     1
#define FreqDataRegister                0x4000
#define PhaseDataRegister               0xC000
#define FreqPrescaler                   1.073741824


static void SendDDSData ( uint16_t DDSData )
{
  uint8_t Loop ;
  /*-------------------------------------------------------------------------*/
  SetSCLKHigh ;
  nop ( ) ;
  nop ( ) ;
  nop ( ) ;
  SetFSYNCLow ;
  nop ( ) ;
  nop ( ) ;
  for ( Loop = 0 ; Loop < 16 ; Loop ++ )
  {
    if ( DDSData & 0x8000 )
    {
      SetSDATHigh ;
    } /* if ... */
    else
    {
      SetSDATLow ;
    } /* if ... else */ ;
    SetSCLKLow ;
    nop ( ) ;
    nop ( ) ;
    nop ( ) ;
    SetSCLKHigh ;
    DDSData = DDSData << 1 ;
  } /* for */ ;
  SetFSYNCHigh ;
  nop ( ) ;
  nop ( ) ;
  nop ( ) ;
  SetSCLKLow ;
} /* SendDDSData */


static void SetControlRegister ( uint8_t B28 ,
                                 uint8_t HLB ,
                                 uint8_t FSELECT ,
                                 uint8_t PSELECT ,
                                 uint8_t Reset ,
                                 uint8_t SLEEP1 ,
                                 uint8_t SLEEP12 ,
                                 uint8_t OPBITEN ,
                                 uint8_t DIV2 ,
                                 uint8_t Mode )
{
  uint16_t ControlData ;
  /*-------------------------------------------------------------------------*/
  ControlData = 0 ;
  if ( B28 )
    ControlData |= ( 1 << B28_BitPos ) ;
  if ( HLB )
    ControlData |= ( 1 << HLB_BitPos ) ;
  if ( FSELECT )
    ControlData |= ( 1 << FSELECT_BitPos ) ;
  if ( PSELECT )
    ControlData |= ( 1 << PSELECT_BitPos ) ;
  if ( Reset )
    ControlData |= ( 1 << Reset_BitPos ) ;
  if ( SLEEP1 )
    ControlData |= ( 1 << SLEEP1_BitPos ) ;
  if ( SLEEP12 )
    ControlData |= ( 1 << SLEEP12_BitPos ) ;
  if ( OPBITEN )
    ControlData |= ( 1 << OPBITEN_BitPos ) ;
  if ( DIV2 )
    ControlData |= ( 1 << DIV2_BitPos ) ;
  if ( Mode )
    ControlData |= ( 1 << Mode_BitPos ) ;
  SendDDSData ( ControlData ) ;
} /* SetControlRegister */


void StartDDSWaveGeneration ( uint8_t  WaveFormat ,
                              uint32_t Frequency )
{
  float FrequencyDataFloat ;
  uint32_t FrequencyData ;
  uint16_t ControlData ;
  /*-------------------------------------------------------------------------*/
  FrequencyDataFloat = ( float ) Frequency * FreqPrescaler ;
  FrequencyData = ( uint32_t ) FrequencyDataFloat ;
  SetControlRegister ( 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ) ;
  ControlData = FreqDataRegister | ( ( ( uint16_t ) FrequencyData ) & 0x3FFF ) ;
  SendDDSData ( ControlData ) ;
  ControlData = FreqDataRegister | ( ( ( uint16_t ) ( FrequencyData >> 14 ) ) & 0x3FFF ) ;
  SendDDSData ( ControlData ) ;
  ControlData = PhaseDataRegister ;
  SendDDSData ( ControlData ) ;
  switch ( WaveFormat )
  {
    case SquareWaveFormat :
      SetControlRegister ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 0 ) ;
      break ;
    case SineWaveFormat :
      SetControlRegister ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
      break ;
    case TriangularWaveFormat :
      SetControlRegister ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) ;
      break ;
    default :
      SetControlRegister ( 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
  } /* case */ ;
} /* StartDDSWaveGeneration */


void StopDDSWaveGeneration ( void )
{
  /*-------------------------------------------------------------------------*/
  SetControlRegister ( 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ) ;
} /* StopDDSWaveGeneration */


void InitDDSEnvir ( void )
{
  /*-------------------------------------------------------------------------*/
  DDSDirPort |= ( 1 << SDATPin ) | ( 1 << SCLKPin ) | ( 1 << FSYNCPin ) ;
  SetSDATHigh ;
  SetSCLKLow ;
  SetFSYNCHigh ;
  SetControlRegister ( 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 ) ;
} /* InitDDSEnvir */




Kod: Zaznacz cały

/*

   Taktowanie procesora : 20MHx
   Taktowanie układu DDS: 2.5 MHz (rozdzielczosc 0.01Hz)


*/



#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "ddsmodule.h"
#include "lcdmodule.h"


#define SysTimeReq                      6

#define TRUE                            1
#define FALSE                           0


static volatile uint8_t SysTimerTick ;
static volatile uint16_t Timer0IRQCounter ;

static uint8_t HelloText [ ] PROGMEM                   = "DDS generator" ;





SIGNAL ( TIMER0_OVF_vect )
{
  /*-------------------------------------------------------------------------*/
  Timer0IRQCounter ++ ;
  if ( Timer0IRQCounter >= SysTimeReq )
  {
    SysTimerTick = TRUE ;
    Timer0IRQCounter = 0 ;
  } /* if */ ;
} /* TIMER0_OVF_vect */


static void HardwareInit ( void )
{
  /*-------------------------------------------------------------------------*/
  TIMSK0 = ( 1 << TOIE0 ) ;
  TCCR0A = 0 ;
  TCCR0B = ( 1 << CS00 ) | ( 1 << CS01 ) ;
} /* HardwareInit */


static void EnvirInit ( void )
{
  /*-------------------------------------------------------------------------*/
  InitDDSEnvir ( ) ;
  InitLCDEnvir ( ) ;
} /* EnvirInit */


static void SoftwareInit ( void )
{
  /*-------------------------------------------------------------------------*/
  Timer0IRQCounter = 0 ;
  SysTimerTick = FALSE ;
} /* SoftwareInit */


static void LongDelay ( void )
{
  uint16_t LoopCounter ;
  /*-------------------------------------------------------------------------*/
  LoopCounter = 0 ;
  SysTimerTick = FALSE ;
  for ( ; ; )
  {
    if ( SysTimerTick )
    {
      SysTimerTick = FALSE ;
      LoopCounter ++ ;
      if ( LoopCounter > 5000 )
      {
        break ;
      } /* if */ ;
    } /* if */ ;
  } /* for */ ;
} /* LongDelay */


int main ( void )
{
  /*-------------------------------------------------------------------------*/
  SoftwareInit ( ) ;
  HardwareInit ( ) ;
  EnvirInit ( ) ;
  sei ( ) ;
  StopDDSWaveGeneration ( ) ;
  LongDelay ( ) ;
  InitialiseLCD ( ) ;
  ClrScrLCD ( ) ;
  WriteTextLCDFlash ( HelloText ) ;
  for ( ; ; )
  {
    StopDDSWaveGeneration ( ) ;
    StartDDSWaveGeneration ( SquareWaveFormat , ( uint32_t ) 100000 ) ;
    LongDelay ( ) ;
    StopDDSWaveGeneration ( ) ;
    StartDDSWaveGeneration ( SineWaveFormat , ( uint32_t ) 100000 ) ;
    LongDelay ( ) ;
    StopDDSWaveGeneration ( ) ;
    StartDDSWaveGeneration ( TriangularWaveFormat , ( uint32_t ) 100000 ) ;
    LongDelay ( ) ;
  } /* for */ ;
  return ( 0 ) ;
} /* main */



Po zaprogramowaniu mikrokontrolera układ DDS generował:
osc001.PNG
osc002.PNG
osc003.PNG
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
j23
Expert
Expert
Posty: 506
Rejestracja: czwartek 08 paź 2015, 18:40

Re: AD9833 - Generator funkcyjny DDS

Postautor: j23 » czwartek 27 kwie 2017, 07:33

Dobry tutorial, dobra robota. Dziękuję, bo pewnie mi się to gdzieś przyda. :)
Pozdrawiam! j23 Jarek
Internet łączy ludzi, którzy dzielą się swoimi zainteresowaniami, pomysłami i potrzebami, bez względu na geograficzne (przeciwności).
BOB TAYLOR, PARC

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1262
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: AD9833 - Generator funkcyjny DDS

Postautor: gaweł » czwartek 27 kwie 2017, 15:16

Jak się komuś przyda, to znaczy, że warto było. :D
W szufladzie wala mi się jeszcze AD9951, może trzeba będzie się nad nim kiedyś pochylić :D

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

SuperGość
Uber Geek
Uber Geek
Posty: 2346
Rejestracja: piątek 04 wrz 2015, 09:03

Re: AD9833 - Generator funkcyjny DDS

Postautor: SuperGość » czwartek 27 kwie 2017, 17:50

A u mnie leżą dwa AD9854 może jednak trzeba by je odkurzyć przydałby się generator większych częstotliwości.

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1262
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: AD9833 - Generator funkcyjny DDS

Postautor: gaweł » piątek 28 kwie 2017, 00:14

wojtek pisze:A u mnie leżą dwa AD9854 może jednak trzeba by je odkurzyć przydałby się generator większych częstotliwości.

Wg datasheeta też fajny :)

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse


Wróć do „Podstawy elektroniki - teoria i praktyka”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 2 gości