Le groupe DDS

De Wiki_du_Réseau_des_Electroniciens_du_CNRS
Révision datée du 20 juin 2019 à 16:58 par Wiotte fabrice (discussion | contributions) (DDS AD9852 sur port SPI 10MHz Projet 2019 avec interface graphique pour modulation FSK AOM@80MHz)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à : navigation, rechercher


Introduction

Le but de ce tutoriel est de donner les outils de bases pour démarrer un projet autour d'un DDS, de la programmation à l'implémentation sur circuits imprimés : réalisation de cartes "propriétaires".

Vous pouvez aussi participer à l'enrichissement de cette page avec vos sources ou partager vos projets.

Contacter l'animateur du Groupe DDS par mail Fabrice.wiotte@univ-paris13.fr

LPL Université Paris 13

http://jmfriedt.free.fr/network_analyzer.pdf : travaux pratiques de Master1 EEA Besançon pour réaliser un petit analyseur de réseau à base d'AD9834 (faible consommation, MCK=75 MHz) commandé par STM32F410.

Projets LPL

Développements électroniques autour des applications DDS "digital signal synthesis".

Générateur DDS pour asservissement Oscillateur YIG 8-18GHz Fichier:GeneYIG.pdf

General Note on the DDS card and on the BUS driver with labview for AOM control Fichier:NoteBusDDS25042014 2.pdf

Phase shifter with DDS AD9959 Fichier:CARTE AD9959 on USB port pour detection synchrone@30MHz.pdf

Quad SPI control for DDS board with ARM TM4C1294 120MHzFichier:DDS board Quad SPI@60MHz.pdf

Développements électroniques autour des expériences atomes froids.

Asservissement numérique de température sur cavité laser ultra-stable (projet 2018) Asservissement en température numérique d'une cavité ultra-stable au LPL pour le Strontium condition de stabilité +/- 10mK Résultas obtenus : 1mk sur la journée

Compte tenu des constantes de temps d'intégration nous avons opté pour un lock numérique avec un uC 16 bits. ADC et DAC 12 bits MSP430F169 16bits Texas instruments, and IAR Workbench for MSP430 or Code composer studio Cahier des charges: La précision du lock en température devrait être de l'ordre de 10 mK, pour assurer une stabilité en fréquence du laser de l'ordre de quelques kHz. L'élément chauffant a une résistance de 6 Ohm. Un courant de l'ordre de 0.6 A devrait fournir la puissance pour nous amener au point de fonctionnement vers 27°C. Élément de mesure : thermistor MC65F103B

Ci-joint le code C du projet: gestion affiche LCD + calcul température + fonction standby + contrôle de la consigne de température + lock + timer + déclaration des variables + déclaration prototypes + fichier init système (ADC-DAC TIMER-PORT IN OUT) Fichier:Vh6010-4 inst manual.pdf Fichier:Asservissement en température numérique pour cavité laser ultra-stable.pdf

Pcb asservissement.png

Manipulations d'atomes froids piège magnéto-optique: Coupure rapide de bobine 400A refroidissement eau

Commande igbt 400a.png

Projet complet: Fichier:Driverigbt.pdf

Boucle de régulation pour alimentation bas bruit de courant pour diode laser (0-1A) Sources de courant pour le Sodium et la puce à atomes alimentation pilotée sur liaison USB-série

Current low noise source.png

Comparatif alimentation bas bruit de courant maison et alimentation DELTA ELECTRONIKA

Comparatif low noise source.png

Généralités sur les DDS

Les "Direct Digital Synthesizers" (DDS) sont des synthétiseurs qui peuvent générer des formes d'ondes arbitraires à diverses fréquences à partir d'une fréquence de référence fixe.

Une bonne note expliquant le fonctionnement des DDS se trouve ici : Média:Tuto_dds.pdf

DDS.jpg

Pourquoi les DDS: Visualisation d'une sortie et programmation

Depuis quelques années pour les équipes de recherches du Laboratoire de Physique des Lasers (LPL), nous utilisons la technologie DDS pour développer des générateurs radiofréquences de quelques MHz à plusieurs centaines de MHz nécessaires au fonctionnement des expériences, ainsi qu'à l'étude et au développement des Condensats d'atomes froids (BEC). Cette technologie au travers de composants spécifiques, nous permet de réaliser des cartes électroniques adaptées aux expériences du laboratoire. Ces dernières sont entièrement pilotable numériquement, on peut ainsi programmer les paramètres principaux tel que la fréquence, la phase et l’amplitude. Les caractéristiques de ces composants font qu’ils disposent d'une grande pureté spectrale, d’une grande stabilité, d’un faible bruit de phase et d’une grande agilité en fréquence sans saut de phase. Les applications: Générateurs de fonctions, oscillateur local, PLL, driver AOM...


  1. Ci-dessous schéma fonctionnel de l'AD9852.


Schéma bloc AD9852.png
1.1 Description des principales fonctions d'entrées et de sorties.
 REFERENCE CLOCK IN si l'horloge externe = 20MHz PLL activée x 15 = 300MHz (fréquence du system clock) ou si PLL off horloge 
 externe max =300MHz.
 MASTER RESET  bit actif sur front logic 1 initialise le DDS et met la sortie RF à zéro.
 ANALOG OUT est la sortie RF principale 0dBm en général.
 I/O UPDATE CLOCK est le bit de chargement des données dans le DDS (par défaut généré en interne et synchronisé sur system clock.
 FSK/BPSK/HOLD bit actif sur front logic 1 lance les rampes de fréquences en autres.
 OSK bit actif sur front logic 1 lance les rampes d'amplitudes.
 8-BIT PARALLEL LOAD bus 8bits pour chargement des données actif si mode parallèle sélectionné.
 6-BIT ADDRESS OR SERIAL PROGRAMMING bus 6bits pour chargement des adresses en mode parallèle sinon utiliser seulement bit A0 pour
 le mode SPI. 
 SERIAL/PARALLEL SELECT bit de sélection des modes de programmation du DDS: = 1 si chargement parallèle, 0 si chargement série(pin
 70 du DDS).
 DIFF/SINGLE SELECT bit de sélection single ended or differential clock input. pin 64 du DDS.
 WRITE OR WR/SCLK si mode Parallèle => bit de chargement I/O port buffers, actif sur front descendant ou SCLK en mode SPI.

Visualisation d'une sortie d'un DDS (AD9852)

               Continuité de phase DDS.jpg 
Ci-dessus visualisation du changement de la fréquence de sortie d'un DDS sans saut de phase.
Mode de programmation parallèle: en bas de l'écran bus de données(B1) et bus d'adresses(B2). 
Attention dans cet exemple je ne programme que l'octet de poids fort pour la fréquence et l'amplitude.
En jaune signal d'actualisation des données et adresses, en rouge sortie RF sur 50ohms.
En vert signal WR/SCLK bit de chargement dans I/O port buffers actif sur front descendant et durée minimale programmable = 50ns.
En bleu I/O UPDATE données transmises au DDS actif sur front montant et durée minimale programmable  = 50ns.
Les courbes en vert et bleu sont volontairement décalées suivant la procédure de chargement des données fournie dans le
datasheet du DDS(page 18 du datasheet AD9852).le mot de fréquence pour ce DDS est codé sur 48 bits et donc 6 Octets avec 
pour parallel address: 0x04;0x05;0x06;0x07;0x08;0x09 (0x04 Octet de poids fort)ou serial address= 0x02 en mode SPI.
le mot d'amplitude pour ce DDS est codé sur 12 bits et donc 2 Octets avec pour parallel address:0x21;0x22;
(0x21 Octet de poids fort) ou serial address= 0x07 en mode SPI.

Comment programmer un DDS Une des pages importantes dans un datasheet de DDS est la page register layout table.

celle-ci définie tous les registres à utiliser pour programmer l'ensemble des fonctions de bases.

Register layout table AD9852.png

En rouge le mot de fréquence f1 programmable 48 bits soit sur 6 Octets.
En bleu le mot d'amplitude programmable sur 12 bits soit sur 2 Octets.
Ce sont les deux paramètres à programmer à minima pour générer un signal RF en sortie.

un DDS utilisé au LPL : l'AD9959

Ad9959.jpg

= Une Application concrète au service électronique du LPL = Un MICROCONTROLEUR 16bits MSP430F169 avec un DDS 4 voies l'AD9959

MSP430 et AD9959.jpeg
Comment programmer le DDS

La programmation sur ce DDS est uniquement en mode SPI:


    Single-bit serial 2-wire mode (default mode)
    Single-bit serial 3-wire mode
    2-bit serial mode
    4-bit serial mode (SYNC_I/O not available)

SPI MODE.jpg

Côté MSP430F169 : Les sorties SIMO1 P5.1, UCLK1 P5.3 et ACLK P5.6 sont utilisées pour programmer en mode SPI 2 fils (mode par défaut du DDS)

Côté DDS AD9959: SCLK, SDIO_0 et CS/ sont à connecter au microcontrôleur. ci-dessous le mode par défaut.SDIO_1,2 et 3 sont connectés au microcontrôleur pour réaliser si on le souhaite, des profiles de rampes de fréquences ou de phases.

   SCLK = serial clock pin 48 du DDS
   CS/  =  Chip select pin 47  du DDS
   SDIO_0 = Serial data I/O pin 50 du DDS

Quel microcontrôleur?

le DDS est programmé par l'intermédiaire d'un microcontrôleur 16 bits de chez TI,le MSP430F169 @8MHz d'horloge. l'environnement de programmation du MSP430 est IAR Embedded Workbench téléchargeable gratuite dans sa version de base. Je conseil d'acheter le kit de débogage MSP430USB MSP-FET430UIF qui permet un débogage pas à pas pratique. Bien entendu bien d'autres microcontrôleurs peuvent êtres utilisés à partir du moment que l'on dispose au moins d'un port SPI. Un développement récent avec l'AD9959 à été réalisé avec un microcontrôleur ATMEL ARDUINO DUE,microcontrôleur 32 bits ARM @84MHz. avec chargement SPI 4 fils. Les dernières cartes développées utilisent un microcontrôleur TEXAS TM4C123GH6PM ARM® Cortex®-M4F Based MCU TM4C123G.

Les différents registres du DDS l'AD9959 table 28 du datasheet de l'AD9959

   registre CSR (channel select register)
   One byte is assigned to this register:  le  nombre d'octets du registre ici 1 octet.
   CSR serial address = 0x00; 
   CSR defaut value = 0xF0;

Ce registre active les voies de sorties et les modes SPI: Par défaut toutes les voies sont activées et le mode SPI Single-bit serial 2-wire est sélectionné. Il est évidemment possible de redéfinir ce registre suivant son application.

   Le second registre est le registre FR1: table 28 du datasheet
   registre FR1 (fonction register 1) 
   three bytes is assigned to this register: nombre d'octets du registre 
   FR1 serial address = 0x01; 
   FR1 defaut value = 0x00;

Ce registre permet en autres de définir la PLL interne et le coefficient multiplicateur x4 à x20. Pour exemple la valeur à fournir pour activer la PLL x20 ⇒ FR1 = 0xD00000; Dans ce cas il suffit de fournir un quartz à 25MHz avec la PLL activée x20 on a 500MHz d'horloge PIN 22 et 23 du DDS.

   Le troisième registre est le registre CFR table 29 du datasheet
   registre CFR (Channel Function Register) 
   three bytes is assigned to this register: nombre d'octets du registre 
   CFR serial address = 0x03; 
   CFR defaut value =0x302; 

Ce registre défini les différents mode de fonctionnement du DDS.Ce registre est important si vous utiliser certains modes de fonctionnement: balayage de fréquence, de phase, ou d'amplitude. Important par défaut les sortie sont en mode DAC full-scale current.

   Le quatrième registre est le registre CFTW0: table 29 du datasheet
   registre CFTW0 (Channel Frequency Tuning Word 01) 
   four bytes is assigned to this register: nombre d'octets du registre 
   CFTW0 serial address = 0x04; 
   CFTW0 defaut value =0x00; 

Ce registre permet de rentrer la fréquence désirée suivant la relation ci-dessous:

   FTW0 = frequency output x 2^32 /frequency clock en Hexadecimal
   Le cinquième registre est le registre CPOW0 table 29 du datasheet
   registre CPOW0 (Channel Phase Offset Word 01) 
   two bytes is assigned to this register:  nombre d'octets du registre 
   CPOW0 serial address = 0x05; 
   CPOW0 defaut value =0x00; 

Ce registre définie la phase du signal de sortie codé sur 14 bits avec la relation ci-dessous:

   CPOW0 = Delta phi x 2^14 /360°
   Le sixième registre est le registre ACR: table 29 du datasheet
   registre ACR (Amplitude Control Register)
   two bytes is assigned to this register:  nombre d'octets du registre 
   ACR serial address = 0x06; 
   ACR defaut value =0x00; 

Ce registre permet de définir l'amplitude. Par défaut l'amplitude est en mode full scale mais programmable si on modifie le registre CFR.

Les autres registres sont utiles pour programmer le DDS pour des balayages de fréquences, de phases et d'amplitudes en autres.

   Registre FR2 (Function Register 2)
   Registre LSRR (Linear Sweep Ramp Rate1)
   Registre FDW (LSR Falling delta Word1) 
   Registre RDW (LSR Risingdelta Word1)
   Registre CW1 (Channel Word 1)
   ...

Programme en C écrit dans un microcontrôleur, le MSP430F169

initialisation et chargement des registres CSR et CFTW0:

    int  CSR_ADDRESS = 0x00;   AD9959 CSR adresss Byte
    int CSR_NUM_BYTE = 0x01;   CSR nombre d'octet du registre
    long CSR0 = 0x10;          AD9959 du channel 0 MSB first SPI par défaut
       
    int  FTW_ADDRESS = 0x04;   AD9959 FTW adresss Byte
    int FTW_NUM_BYTE = 0x04;   FTW nombre d'octet du registre
    long FTW0 = 0x28F5C28F;    frequence en hex = fout x2^32/fclock

dans le main

    P4OUT = 0x40;          AD9959 master reset bit de validation du MSP430
    P4OUT = 0x00;          AD9959 master set   bit de validation du MSP430
    
    write_serial_port(CSR_ADDRESS, CSR0, CSR_NUM_BYTE);
    P5OUT = 0x40;          I/O update du DDS bit de validation du MSP430 
    P5OUT = 0x00;          I/O update du DDS bit de validation du MSP430  
    
    write_serial_port(FTW_ADDRESS, FTW0, FTW_NUM_BYTE);
    P5OUT = 0x40;          I/O update du DDS bit de validation du MSP430 
    P5OUT = 0x00;          I/O update du DDS bit de validation du MSP430

Commentaires sur le programme:

on fait un RESET du DDS (pin 3), on charge les données de chaque registre au travers du port SPI write_serial_port… Puis on réalise un I/O UPDATE pin 46 du DDS pour la validation et le transfert des données. Ce bout de programme permet de charger le channel 0 avec une fréquence de 80MHz et une amplitude par défaut FULL DAC.

I/O_UPDATE is synchronous to the SYNC_CLK (Pin 54) = Master clock/4. Voir figure 40 du datasheet du DDS.

Ci-dessous le sous programme d'initialisation des ports du microcontrôleur et du SPI pour le MSP430F169 : TI fourni de nombreux exemples de codes de bases pour configurer les modes SPI, I2C et utiliser la mémoire Flash: slac015p.zip

#include  <msp430x16x.h>
    void DDS_quartz_oscillator_init(void)
    {
      BCSCTL1 |= XTS;               ACLK= LFXT1= HF XTAL 
      BCSCTL2 |= SELM_3;            MCLK = LFXT1 (safe) pin 8,9 du MSP430
      P1SEL = 0x00;                 P1 I/O select
      P2SEL = 0x00;                 P2 I/O select
      P3SEL = 0x00;                 P3 I/O select
      P4SEL = 0x00;                 P4 I/O select
      P5SEL = 0x0A;                 P5.1,3 SPI option select
      P6SEL = 0x00;                 P6 I/O select
      P1DIR = 0xFF;                 P1.output direction
      P2DIR = 0xFF;                 P2 output direction
      P3DIR = 0xFF;                 P3 output direction
      P4DIR = 0xFF;                 P4 output direction
      P5DIR = 0xFF;                 P5 output direction
      P6DIR = 0xFF;                 P6 output direction
      ME2 |= USPIE1;                Enable USART1 SPI
      UCTL1 |= CHAR + SYNC + MM;    8-bit SPI Master **SWRST**
      UTCTL1 = CKPH + SSEL1 + STC;  SMCLK delayed, 3-pin
      UBR01 = 0x2;                  ACLK/2 for baud rate
      UBR11 = 0x0;                  ACLK/2 for baud rate
      UMCTL1 = 0x0;                 Clear modulation
      UCTL1 &= ~SWRST;              Initialize USART state machine
    }

BCSCTL1 |= XTS; et BCSCTL2 |= SELM_3; permet d'être en mode HF XTAL le MSP430 fonctionnera à 8MHZ au lieu de 32KHz par défaut.

  MSP430F169
          -----------------
      /|\|              XIN|-
       | |                 | HF XTAL (455k - 8Mhz)
       --|RST          XOUT|-
         |                 |
         |             P5.4|-->MCLK = XTAL

D'après : M. Buccini Texas Instruments Inc. Feb 2005 Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.21A

le sous programme pour le chargement des données en mode SPI du MSP430F169

      void write_serial_port(int instruction, long data, int num_byte)
      {
       int i=0;
       TXBUF1 = instruction;
        do
       {
       TXBUF1 = data >>(num_byte-1-i)*8;
       i++;
       }
        while (i < num_byte);
      }

Un code complet pour charger le DDS avec le MSP430F169

  #include <msp430x16x.h>
  #include "DDS_quartz_oscillator.h"
  void init_sys(void);                MSP430 Initialisation routine 
  void tempo_loop(int loop_number);   wait loop
  void write_serial_port1(int instruction, long data, int num_byte); 
          /   main() variable declarations  /                                      
         / configuration Channel Select Register /                  
                Channel Select Register                               
   int  CSR_ADRESS = 0x00;           AD9959 CSR adresss Byte
   long CSR = 0x10;                  AD9959 CH0 only MSB first 
   int CSR_NUM_BYTE = 0x01;          AD9959 byte number by CSR 
   int  FTW0_ADRESS = 0x04;          AD9959 FTW0 adresss Byte 
   long FTW0 = 0x38C9138C;           AD9959 Frequency Tuning Word0 122MHz 
   int FTW_NUM_BYTE = 0x04;          AD9959 byte number by FTW 
   void main(void)
   {
            / initialisation du msp430  /
   init_sys();                       Initialise the MSP430
   tempo_loop(10000);                wait loop
   P5OUT = 0x00;   
   P4OUT = 0x40;                     Reset AD9959  
   tempo_loop(10000);                wait loop  
   P4OUT = 0x00;                     Set AD9959
   write_serial_port1(CSR_ADRESS, CSR, CSR_NUM_BYTE);
   tempo_loop(100);                  wait loop
   P5OUT = 0x40;                     AD9959 I/O update
   P5OUT = 0x00;                        
   write_serial_port1(FTW0_ADRESS, FTW0, FTW_NUM_BYTE);                                        
   tempo_loop(10);                   wait loop
   P5OUT = 0x40;                     AD9959 I/O update
   P5OUT = 0x00;                         
   }
   void init_sys(void)
   {
   WDTCTL = WDTPW + WDTHOLD;       // stop Watch Dog Timer
   DDS_quartz_oscillator_init();   // init usart1, spi mode, 2wire
   }
   void write_serial_port1(int instruction, long data, int num_byte)
   {
    int i=0;
    TXBUF1 = instruction;
   do
   {
    TXBUF1 = data >>(num_byte-1-i)*8;
    i++;
   }while (i < num_byte);
   }
   void tempo_loop(int loop_number)
   {
   int i;
   int j;
   for(i = 0; i < loop_number; ++i)           wait loop
   { 
    j=j+i; 
   } 
   }

ne pas oublier le fichier DDS_quartz_oscillator.h dans le projet pour compiler le programme.

Un kit de prototypage

MSP430-P169.jpg

MPS430F169 HEADER BOARD olimex Price 22.95 EUR


IAR for MSP430 en version gratuite : code size limited (8Ko)

Programme principal

IAR for MSP430.jpg

fichier Init MSP430F169

Init MSP430F169.jpg

DDS Card AD9858 on ARM uC TM4C123GH6PM with USB-serial interface@1MHz Baud Rate

CARTE DDS sur BUS USB-SERIE 1MHz

Pour remplacer des cartes d'évaluations Analog device avec un programme souvent non versatile on a développé une source RF entièrement pilotable numériquement grâce à une interface USB-Série et un programme pour microsoft PC C-sharp (dérivé du C++ et très proche du Java,utilisé notamment pour développer des applications web sur la plateforme ASP.NET.). La partie hardware se compose d'un DDS AD9858 @1GHz Clock et d'un uC TEXAS INSTRUMENT TM4C123 @80MHz d'horloge. Un firmware en C à été développé pour le uC qui pilote directement le DDS en mode SPI 3fils @10MHz. L'environnement de programmation est le même que pour le uC développé plus haut, c'est à dire sous IAR Embedded pour ARM. Le programme envoi donc le mot de fréquence (4 Octets) en mode continu ou en single mode, pour réaliser des balayages de fréquences dont la résolution est définie par le nombre de points et le pas entre deux fréquences envoyées par le programme sous C-sharp.

DONNEES SUR BUS USB-SERIE 1MHz MOT DE FREQUENCE SUR 4 OCTETS

code C firmware pour SPI sur uC TM4C123GH6PM

void ssi0PutData( int instruction,long data,int num_byte)
   {
   int i=0;
   SSI0_DR_R =  instruction; 
    while( num_byte )
     {
          while(!(SSI0_SR_R & SSI_SR_TNF)) {} // wait until there is space to write in the buffer
          SSI0_DR_R =  data >>(num_byte-1-i)*8;
          num_byte--;           
     }
    
    while( !( SSI0_SR_R & SSI_SR_TNF ) )
          {
            ;
          }
    }
void init_SPI0(void)
    {
    // Enable Peripheral SSI0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); //Enable GPIO port A pins which are used for SSI0.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    GPIOPinConfigure(GPIO_PA2_SSI0CLK); 
    //GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    //GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_3 | GPIO_PIN_2);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_2);
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 10000000, 8);
    SSIEnable(SSI0_BASE); // Enable the SSI 
    }
CARTE DDS sur BUS USB-SERIE 1MHz

code C pour initialiser le port série

 void init_UART0(void)
 {
  // Enable Peripheral UART0
  SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
  GPIOPinConfigure(GPIO_PA0_U0RX);
  GPIOPinConfigure(GPIO_PA1_U0TX);
  GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
  UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 1000000,                      
  (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
 }

Routine pour les données reçus et transmises

 void UART0_send(void)
   {
  temp[t++] = UART_InChar(); //Read from buffer
  if(t >3)
     {  write_immediate();
        for(t=0;t<4;t++)
        {
        UART_OutChar(temp[i++]);
        }
        t = 0; //Reset read length
        i = 0;
     } 
    }

DDS Card AD9852 and AD9858 sur NI Card DIO 32

Description du projet

Pour une nouvelle expérience du laboratoire, nous avons développé de nouvelles cartes électroniques qui utilisent des composants DDS contrôlés par un ordinateur sur un bus de données numériques. La carte numérique qui contrôle le bus est la carte DIO 32 HS de National Instrument. Ces sources RF programmables à base de technologie DDS seront mises en œuvre sur la nouvelle expérience des atomes froids de l’équipe Gaz Quantique Dipolaire pour conduire les AOM de l'expérience. Pour contrôler les cartes, un programme simple sous LABVIEW a été développé. La principale motivation de ce projet était de construire un système de contrôle pour l'expérience qui permet d'intégrer de nombreuses fonctions avec une interface utilisateur. Les cartes DDS permettront de contrôler avec une bonne synchronisation les différents AOM.

Le bus de données :

Le bus est un bus parallèle de 25 lignes qui est transféré avec un câble plat de 50 lignes, de sorte que les lignes de masses et les lignes de signaux sont alternées. La vitesse du bus dépend des caractéristiques des cartes NI fournies soit de l’ordre de 1/10MHz soit 100ns. Les 16 premières lignes du bus sont les lignes des données et les huit dernières lignes correspondent aux adresses d’appareils (255 en théorie mais 6 bits en pratique et donc 64 appareils adressables). Enfin, la dernière ligne (ligne 25) est l'horloge (STROBE) qui contrôle le débit de données qui est transmis sur le bus. Ce signal met à jour les données et les adresses sur le bus. Ce signal d'horloge doit être présent sur le bus.

Programmation des DDS :

Les huit premières lignes de données transmises au DDS sont les DATA : D0-D7 Les huit secondes lignes transmises au DDS sont les ADRESSES : A0-A5 et A6-A7 pour les modes FSK et OSK de l’AD9852 et PS0 PS1 pour l’AD9858. Les huit dernières lignes permettent le décodage d’adresses : decodeA2-decodeA7 Décode au maximum 64 cartes. Les lignes decodeA0 et decodeA1, sont utilisées pour initialisées le DDS de tel sorte que :

  A1 A0 = 00 :  Master reset DDS
  A1 A0 = 01 :  Load data  DDS
  A1 A0 = 10 :  I/O update DDS  non utilisé  si  I/O  Update interne.
  A1 A0 = 11 :  non utilisé
CARTES DDS sur BUS NI and DIO32 Card


Pour initialiser les cartes DDS et transférer les données aux DDS via le bus nous utilisons des composants programmables du type CPLD (circuit logique programmable) associés à des translateurs de niveaux pour passer du niveau TTL (5v) au niveau LVCMOS (3.3v). Le composant utilisé est un CPLD de la famille XILINX XC2C64A 64 cellules. Ce composant initialise la carte DDS, assure le décodage d’adresses d’appareils, et surtout la synchronisation des pins du DDS (MASTER RESET, LOAD DATA et I/O UPDATE). Les cartes DDS disposes de deux CPLD le premier en bas (CPLD1) de la carte pour la synchronisation et l’initialisation du DDS, le deuxième (CPLD2) recopie les données en entrée du bus après autorisation du CPLD1. La programmation des CPLD se fait grâce à l’environnement ISE design suite 14 ou ultérieur téléchargeable gratuitement sur le site de XILINX (ISE WEB PACK) ; Ci-joint dans ce document les codes sources pour charger les deux CPLD. Un câble JTAG-USB est indispensable pour la programmation.

CARTES DDS AD9852 sur BUS NI and DIO32 Card
CARTES DDS AD9858 sur BUS NI and DIO32 Card

BUS en fond de panier 25 lignes dont la fréquence de rafraîchissement est d'environ 10MHz et limité par la carte DIO 32 ancienne génération. Chaque carte a une adresse propre (64 max). Le SWITCH DIP 8 sur la carte défini celle-ci.Le code VHDL pour les deux CPLD est simple et modifiable si nécessaire.






























  '''VHDL pour  CPLD1 carte DDS AD9852 et bus NI'''
  library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  use IEEE.STD_LOGIC_ARITH.all;
  use IEEE.STD_LOGIC_UNSIGNED.all;
  entity '''addressbus_and_decode''' is
  GENERIC (n: INTEGER := 20);
  Port (
  ADDR_BUS_in : in  STD_LOGIC_VECTOR (5 downto 0);
  A0_A1_address: in  STD_LOGIC_VECTOR (1 downto 0);
  STROBE : in  STD_LOGIC;
  MASTER_CLOCK : in  STD_LOGIC;
  STROBE_OUT : out  STD_LOGIC;
  --IO_UPDATE : out  STD_LOGIC;  -- par défaut mode dds
  RD : out  STD_LOGIC;
  LOAD_DATA : out  STD_LOGIC;
  MASTER_RESET : out  STD_LOGIC;
  SP_MODE : out  STD_LOGIC;
  CONTROL_DIP8 : in  STD_LOGIC_VECTOR (5 downto 0)
  );
  end addressbus_and_decode;
  '''architecture Behavioral of addressbus_and_decode is'''
  SIGNAL internal: STD_LOGIC_VECTOR (n-1 DOWNTO 0);
  SIGNAL STROBE_OUT_bis : STD_LOGIC;
  SIGNAL SEL0 : STD_LOGIC;
  SIGNAL SEL1 : STD_LOGIC;
  SIGNAL SEL2 : STD_LOGIC;
  SIGNAL SEL3 : STD_LOGIC;
  SIGNAL reset : STD_LOGIC;
  SIGNAL load : STD_LOGIC;
  begin
  SP_MODE <='1';
  RD <='1';
  --registre a décalage Tempo STROBE  générérateur de temporisation pour décalage
  '''PROCESS(MASTER_CLOCK,STROBE)'''
  BEGIN
  IF (STROBE ='0') THEN
    internal <= (OTHERS => '0');
  ELSIF (MASTER_CLOCK'EVENT AND MASTER_CLOCK='1') THEN
    internal <= STROBE & internal(internal'LEFT DOWNTO 1);
  END IF;
  END PROCESS;
  -- 2 bits address A0 et A1 decoder 2 to 4 and control ADDR = CONTROL_dip8
  '''process(A0_A1_address,ADDR_BUS_in,CONTROL_DIP8)'''
  begin
  if  internal(15) ='1' and ADDR_BUS_in = CONTROL_DIP8  then
  case A0_A1_address is
  when "00"=> SEL0 <='1'; SEL1<='0'; SEL2<='0'; SEL3<='0';
  when "01"=> SEL0 <='0'; SEL1<='1'; SEL2<='0'; SEL3<='0';
  when "10"=> SEL0 <='0'; SEL1<='0'; SEL2<='1'; SEL3<='0';
  when "11"=> SEL0 <='0'; SEL1<='0'; SEL2<='0'; SEL3<='1';
  when others => SEL0 <='Z'; SEL1<='Z'; SEL2 <='Z'; SEL3 <='Z';
  end case;
  else
  SEL0 <='Z'; SEL1<='Z'; SEL2 <='Z'; SEL3 <='Z';
  end if;
  end process;
  STROBE_OUT <= STROBE_OUT_bis;
  --STROBE out  pour autorisation sur CPLD2 latchs   décalage de 50ns /strobe
  '''process(internal(15),ADDR_BUS_in,CONTROL_DIP8)'''
  begin
  if internal(15) ='1' and ADDR_BUS_in = CONTROL_DIP8 and SEL0 ='0' then
   STROBE_OUT_bis <='1';
  else
   STROBE_OUT_bis <='0';
  end if;
  end process;
  -- control bit MASTER_RESET  décalage de 50ns /strobe
  '''process(internal(15),SEL0,ADDR_BUS_in,CONTROL_DIP8)'''
  begin
  if  internal(15) = '1' and SEL0 ='1' and ADDR_BUS_in = CONTROL_DIP8 then
  MASTER_RESET <= '1';
  else
  MASTER_RESET <= '0';
  end if;
  end process;
  -- control bit Load data into IO buffer(WR)  décalage de 100ns /strobe
  '''process(internal(10),SEL1,ADDR_BUS_in,CONTROL_DIP8)'''
  begin
  if internal(10)= '1' and SEL1 ='1' and ADDR_BUS_in = CONTROL_DIP8 then
  LOAD_DATA <= '0';
  else
  LOAD_DATA <= '1';
  end if;
  end process;
  end Behavioral;

  '''VHDL pour CPLD2 AD9852 et AD9858'''
  --Programme CPLD2 pour AD9852 et AD9858—
  library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  entity test_cpld_haut is
  Port (
  DATA_in : in  STD_LOGIC_VECTOR (7 downto 0);
  ADDRESS_in : in  STD_LOGIC_VECTOR (7 downto 0);
  DATA_out : out  STD_LOGIC_VECTOR (7 downto 0);
  ADDRESS_out : out  STD_LOGIC_VECTOR (7 downto 0);
  STROBE_in : in  STD_LOGIC
  );
  end test_cpld_haut;
  architecture '''Behavioral of test_cpld_haut''' is
  begin
  -- octal 2 d-type latches 3 états, 8bits
  '''process(STROBE_in,DATA_in,ADDRESS_in)'''
  begin
  if STROBE_in ='1' then
  DATA_out <= DATA_in;
  ADDRESS_out <= ADDRESS_in;
  end if;
  end process;
  end Behavioral;

Nous avons récemment développer une carte FPGA indépendante pour tester les cartes DDS sans le bus numérique : kit utilisé spartan 6 CMODS6. avril 2019

Carte spartan 6 test bus.png
  library IEEE;
  use IEEE.STD_LOGIC_1164.ALL;
  use IEEE.STD_LOGIC_ARITH.ALL;
  use IEEE.STD_LOGIC_UNSIGNED.ALL;

  -- programme pour tester le bus parallèle et les cartes DDS AD9852--
  entity XILINX_DDS_AD9852 is

  Port (
  MASTER_CLOCK : in STD_LOGIC;
  reset : in STD_LOGIC;
  dout : out std_logic_vector(7 downto 0);
  d_address : out std_logic_vector(7 downto 0);
  BP0 : in STD_LOGIC;
  DECODE_A0_A1_IN : in STD_LOGIC_VECTOR (1 downto 0);
  ADDRESS_BUS_CARD_in : in STD_LOGIC_VECTOR (5 downto 0);
  ADDRESS_BUS_CARD : out STD_LOGIC_VECTOR (5 downto 0);
  DECODE_A0_A1_OUT : out STD_LOGIC_VECTOR (1 downto 0);
  OUTPUT_GND : out STD_LOGIC_VECTOR (15 downto 0)
  );

  end XILINX_DDS_AD9852;

  architecture Behavioral of XILINX_DDS_AD9852 is
  TYPE mem_data IS ARRAY (0 TO 7) OF std_logic_vector(7 DOWNTO 0);
  --déclaration de zone mémoire pour les datas--
  TYPE mem_address IS ARRAY (0 TO 7) OF std_logic_vector(7 DOWNTO 0);
  --déclaration de zone mémoire pour les adresses--
  SIGNAL count_1MHz : integer := 255; --déclaration d'un compteur 8 bits--
  SIGNAL clock_1MHz_int : STD_LOGIC :='0'; -- signal issus du  diviseur d'horloge--
  SIGNAL compte : STD_LOGIC_VECTOR (3 DOWNTO 0):="0000";

  constant data : mem_data := (
  ("01001111"), --data PLL x 15 clk = 20MHz x15= 300MHz
  ("00001111"), --data amplitude;
  ("00001000"), --Fout = 10MHz AD9852
  ("10001000"), --Fout = 10MHz AD9852
  ("10001000"), --Fout = 10MHz AD9852
  ("10001000"), --Fout = 10MHz AD9852
  ("10001000"), --Fout = 10MHz AD9852
  ("10001000")); --Fout = 10MHz AD9852

  constant address : mem_address := (
  ("00011110"), -- adresse HEX=0x1E; AD9852 parallel address
  ("00100001"), -- adresse HEX=0x21; AD9852 parallel address
  ("00001001"), -- adresse HEX=0x09; AD9852 parallel address
  ("00001000"), -- adresse HEX=0x08; AD9852 parallel address
  ("00001101"), -- adresse HEX=0x07; AD9852 parallel address
  ("00000110"), -- adresse HEX=0x06; AD9852 parallel address
  ("00000101"), -- adresse HEX=0x05; AD9852 parallel address
  ("00000100")); -- adresse HEX=0x04; AD9852 parallel address

  begin
  -- GND ----------
  OUTPUT_GND <= (others => '0');

  ADDRESS_BUS_CARD <= ADDRESS_BUS_CARD_in; --adresse de décodage des DDS--
  DECODE_A0_A1_OUT <= DECODE_A0_A1_IN; -- initialisation des  données à transmettre A0 A1--
  --STROBE_out <= clock_1MHz_int;

  --Diviseur par 50 50MHz/50 = 1MHz
  PROCESS
  BEGIN
  wait until MASTER_CLOCK'EVENT and MASTER_CLOCK = '1';
  IF count_1MHz < 50 THEN
  count_1MHz <= count_1MHz + 1;
  ELSE
  count_1MHz <= 0;
  END IF;
  IF count_1MHz < 25 THEN
  clock_1MHz_int <='0';
  ELSE
  clock_1MHz_int <='1' ;
  end if;
  end process;


  --compteur et envoi des datas sure le bus parallèle--
  process(clock_1MHz_int,reset)
  begin
  if reset ='1' then
  compte <= "0000";
  dout <="00000000";
  d_address <="00000000";

  elsif clock_1MHz_int'event and clock_1MHz_int='1' then

  IF compte < 8 and BP0 ='1' THEN
  dout <= data(CONV_INTEGER(compte));
  d_address <= address(CONV_INTEGER(compte));
  end if;
  IF compte > 7 THEN
  compte <= "0000";
  ELSE
  compte <=compte + 1;
  END IF;
  end if;
  end process;

  end Behavioral;

Projet STRONTIUM antenne RF 375-400MHz

Projet Antenne RF: RF CARD 375 to 400MHz Frequency Sweep control for RF antenna. Le but est de générer des sweeps de fréquence arbitraire pour une antenne RF dans la gamme de fréquence 375 à 400 MHz avec des pas de qqs KHz. J'utilise deux DDS , l'AD9911 pour asservir un VCO ultra low noise à 1GHZ (ROS-1000-519+) minicircuits et le second l'AD9858 pour générer les fréquences arbitraires. Ce dernier est “clocké” grâce au 1GHz provenant du VCO sur la carte. J'utilise également le MSP430F169 pour piloter les deux DDS en mode SPI 2wire single bit (bus SPI commun, un master et deux slaves en utilisant le chip select (CS) de chaques DDS).

Générateur de rampe.png

Caractéristiques
Programmation en mode SPI  maître-esclave 2-wire mode single-bit.
L’AD9911 et l’AD9858 en mode esclaves via les Chip Select (CS).
Horloge commune le ROS-1000C-519@1GHz.
Pente de la rampe de fréquence programmée via l’interface CVI.
TTL externe commande rampe  up et rampe  down.
Nécessite un signal d’horloge externe 10MHz  5dBm.
Une sortie RF (AD9858) programmable 0-400MHz  0dBm.

Projet diffusion Raman expérience CHROME

Conception et réalisation d'un ensemble de deux pilotes acous-optiques d'une puissance unitaire de 2W. L'objectif est de régler le décalage en fréquence de deux faisceaux "Raman" corrélés en phase. Réalisation de deux sources RF@80MHz en corrélation de phase avec une fréquence centrale de 80MHz. Pilotage sur liaison USB-Série@10MHz (en cours de tests). Les signaux RF sont synchronisés sur une même horloge@500MHz à l'aide d'un DDS AD9959 qui dispose de plusieurs sorties RF basse puissance (5dBm).Les circuits sont implémentés sur des cartes au format Europe et insérées dans un châssis 19 pouces entièrement réalisé à l'atelier d'électronique.

Carte DDS ad9959.png

DDS pour détection synchrone et asservissement PDH

Système de lock laser sur cavité ultra stable voir synoptique ci-dessous: PDH AD9959.png

DDS card for PDH AD9959 on uC TM4C123 and LCD 2x16 and codeur Gray AD9959 PDH 43.png AD9959 PDH 45.png

Même si l'encodeur est utilisé dans un programme en c je fourni pour les amateurs de VHDL le programme pour l'encodeur numérique.VHD

Encodeur 24 pas.png

State machine encodeur.png

 --déclarations des librairies--
  library IEEE;
  use IEEE.STD_LOGIC_1164.all;
  use IEEE.STD_LOGIC_ARITH.all;
  use IEEE.STD_LOGIC_UNSIGNED.all;

  -- entité machine d'état pour l'encodeur numérique--

  entity codeur_incremental is
  Port ( clk : in STD_LOGIC; -- horloge de synchronisation 1KHz--
  reset: in STD_LOGIC; --RESET ASYNCHRONE--
  rotary_A : in STD_LOGIC; --sortie A codeur--
  rotary_B : in STD_LOGIC; --sortie B codeur--
  Up : out STD_LOGIC; --sortie pour incrementer le compteur--
  Down : out STD_LOGIC; --sortie pour decrementer le compteur--
  compte_out_codeur : out STD_LOGIC_VECTOR(15 downto 0)); -- sortie compteur pour données à envoyer vers la liaison SPI--

  end codeur_incremental;

  architecture Behavioral of codeur_incremental is
  type etat_codeur is(S1,S2,S3,S4,S5,S6,S7); -- declaration de la machine d'état et du nombre d'état--
  signal etat : etat_codeur;
  signal compteur: INTEGER range 0 to 65535; -- déclaration d'un compteur 16 bits qui servira à charger le DAC via la liaison SPI--
  signal INC :STD_LOGIC; -- signal incrementation déclaré pour la machine d'état--
  signal DEC :STD_LOGIC; -- signal décrementation déclaré pour la machine d'état--

  -- process machine d'état--
  begin
  process(clk,reset,rotary_A,rotary_B) -- liste de sensibilité toujours des entrées ou des signaux déclarés--
  begin
  if reset ='1' then

  INC <='0'; -- signal INC initialisé à zéro--
  DEC <='0'; -- signal DEC initialisé à zéro--
  compte_out_codeur <="0000000000000000"; -- on s'assure que le compteur de sortie soit à zéro à l'initialisation --
  compteur <= 0; -- compteur interne à zéro à l'initialisation--
  etat <= S1; -- on va à l'état S1 --

  elsif CLK'event and CLK ='1' then

  case etat is -- machine d'état on décrit tous les cas possibles--

  when S1=> if rotary_A ='1' and rotary_B = '1' then -- si pas d'action on reste en S1--
  INC <='0';
  DEC <='0';
  etat <= S1;

  elsif rotary_A ='0' and rotary_B = '1' then -- si rotation CW --
  INC <='0';
  DEC <='0';
  etat <= S2;

  elsif rotary_A ='1' and rotary_B = '0' then -- si rotation CCW --

  INC <='0';
  DEC <='0';
  etat <= S5;
  end if;

  when S2=> if rotary_A ='0' and rotary_B = '0' then
  INC <='0';
  DEC <='0';
  etat <= S3;
  end if;


  when S3=> if rotary_A ='1' and rotary_B = '0' then
  INC <='0';
  DEC <='0';
  etat <= S4;
  end if;

  when S4=> if rotary_A ='1' and rotary_B = '1' then
  compteur <= compteur + 1;
  INC <='1';
  DEC <='0';
  etat <= S1;
  end if;

  when S5=> if rotary_A ='0' and rotary_B = '0' then
  INC <='0';
  DEC <='0';
  etat <= S6;
  end if;

  when S6=> if rotary_A ='0' and rotary_B = '1' then
  INC <='0';
  DEC<='0';
  etat <= S7;
  end if;

  when S7=> if rotary_A ='1' and rotary_B = '1' then
  compteur <= compteur - 1;
  INC <='0';
  DEC<='1';
  etat <= S1;
  end if;

  end case;
  compte_out_codeur <= CONV_STD_LOGIC_VECTOR(compteur,16); -- on convertit des entiers en std_logic_vectors, bus logic.
  end if;
  end process;
  Up <= INC; -- on affecte le signal incrementation dans la sortie UP--
  Down <= DEC; -- on affecte le signal decrementation dans la sortie DOWN--

  end Behavioral;

Programme ARM for PDH

Fichier:Programme uC TM4C123GH6PM for PDH module.pdf

Carte partie Lock

Carte lock PDH.png

Carte partie DDS

PDH card.png

Double DDS AD9959 sur port SPI quad @60MHz Projet 2019 avec interface graphique Python

Développement 2018 : Piège RF Pour des considérations de vitesse d’exécution et de chargement des données nous avons fait évoluer les cartes DDS pour l'expérience BEC du LPL. La programmation des DDS est réalisé en Quad SPI à une vitesse de 60MHz. les données sont transmises au uC (ARM 120MHz) grâce à l'interface USB-UART non représentée sur le PCB ci-dessous à une vitesse de 10Mbps.

8 sorties RF programmables révision 1 2018:

Double DDS 2018.JPG

  Code C pour les routines principales: 
  //*****************************************************************************
  //                   Laboratoire de Physique des Lasers
  //                            Wiotte Fabrice 
  //                        Ingénieur d'étude CNRS
  //                    Service Electronique D002 Rdc
  //                CNRS – URM7538 – Université Paris 13
  //                       99 Avenue J.-B. Clément
  //                         93430 Villetaneuse
  //                    http://www-lpl.univ-paris13.fr/
  // 
  // This is part of revision 2.1.0.12573 of the EK-TM4C1294XL Firmware Package.
  //

  void init_SPI1_mode_quad_bit(void)
  {
           // Enable Peripheral SSI1
                  //if Quad SPI
             //***********************//
      //GPIO_PE4_SSI1XDAT0 <= BIT 4 BIT 0   only need 2 CLK cycle to send 8bits.
      //GPIO_PE5_SSI1XDAT1 <= BIT 5 BIT 1   only need 2 CLK cycle to send 8bits.
      //GPIO_PD4_SSI1XDAT2 <= BIT 6 BIT 2   only need 2 CLK cycle to send 8bits.
      //GPIO_PD5_SSI1XDAT3 <= BIT 7 BIT 3   only need 2 CLK cycle to send 8bits.

        //*************************************//
        //Polarity Phase       Mode
        //   0       0   SSI_FRF_MOTO_MODE_0
        //   0       1   SSI_FRF_MOTO_MODE_1
        //   1       0   SSI_FRF_MOTO_MODE_2
        //   1       1   SSI_FRF_MOTO_MODE_3
        //*************************************//

    //************************//
    // SSI1 is used with the following GPIO Pin Mapping
    // SSI1CLK   : PB5
    // SSI1FSS   : PB4
    // SSI1XDAT0 : PE4
    // SSI1XDAT1 : PE5
    // SSI1XDAT2 : PD4
    // SSI1XDAT3 : PD5
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
    // Configure the pin muxing for SSI1 functions on port B4, B5, E4, E5,D4, D5
    
    GPIOPinConfigure(GPIO_PB5_SSI1CLK);
    GPIOPinConfigure(GPIO_PB4_SSI1FSS);
    GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
    GPIOPinConfigure(GPIO_PE5_SSI1XDAT1);
    GPIOPinConfigure(GPIO_PD4_SSI1XDAT2);
    GPIOPinConfigure(GPIO_PD5_SSI1XDAT3);
    
    /* Configure pad settings */
    GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_5|GPIO_PIN_4, GPIO_STRENGTH_12MA, GPIO_PIN_TYPE_STD);
    GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_PIN_5|GPIO_PIN_4, GPIO_STRENGTH_12MA, GPIO_PIN_TYPE_STD);
    GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_PIN_5|GPIO_PIN_4, GPIO_STRENGTH_12MA, GPIO_PIN_TYPE_STD);
    // Configure the GPIO settings for the SSI pins.  This function also gives
    // control of these pins to the SSI hardware. 
    GPIOPinTypeSSI(GPIO_PORTB_BASE,GPIO_PIN_5|GPIO_PIN_4);
    GPIOPinTypeSSI(GPIO_PORTE_BASE,GPIO_PIN_5|GPIO_PIN_4);
    GPIOPinTypeSSI(GPIO_PORTD_BASE,GPIO_PIN_5|GPIO_PIN_4);
    SSIConfigSetExpClk(SSI1_BASE, 120000000, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 60000000, 8);
    //
    // Enable the SSI1 module.
    //
    SSI1_CR1_R = 0x00000080;
    SSIEnable(SSI1_BASE);
  }
  void init_SPI0_mode_quad_bit(void)
  {
           // Enable Peripheral SSI0
                  //if Quad SPI
             //***********************//
       //***********************//
       //GPIO_PA4_SSI0XDAT0 <= BIT 4 BIT 0   only need 2 CLK cycle to send 8bits.
       //GPIO_PA5_SSI0XDAT1 <= BIT 5 BIT 1   only need 2 CLK cycle to send 8bits.
       //GPIO_PA6_SSI0XDAT2 <= BIT 6 BIT 2   only need 2 CLK cycle to send 8bits.
       //GPIO_PA7_SSI0XDAT3 <= BIT 7 BIT 3   only need 2 CLK cycle to send 8bits.
       //************************//

        //*************************************//
        //Polarity Phase       Mode
        //   0       0   SSI_FRF_MOTO_MODE_0
        //   0       1   SSI_FRF_MOTO_MODE_1
        //   1       0   SSI_FRF_MOTO_MODE_2
        //   1       1   SSI_FRF_MOTO_MODE_3
        //*************************************//

    //************************//
    // SSI1 is used with the following GPIO Pin Mapping
    // SSI0CLK   : PA2
    // SSI0FSS   : PA3
    // SSI0XDAT0 : PA4
    // SSI0XDAT1 : PA5
    // SSI0XDAT2 : PA6
    // SSI0XDAT3 : PA7
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    // Configure the pin muxing for SSI0 functions on port A2, A3, A4, A5, A6, A7
    
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
    GPIOPinConfigure(GPIO_PA5_SSI0XDAT1);
    GPIOPinConfigure(GPIO_PA6_SSI0XDAT2);
    GPIOPinConfigure(GPIO_PA7_SSI0XDAT3);
    
    /* Configure pad settings */
    GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_2|GPIO_PIN_3, GPIO_STRENGTH_12MA, GPIO_PIN_TYPE_STD);
    GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_4|GPIO_PIN_5, GPIO_STRENGTH_12MA, GPIO_PIN_TYPE_STD);
    GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_6|GPIO_PIN_7, GPIO_STRENGTH_12MA, GPIO_PIN_TYPE_STD);
    // Configure the GPIO settings for the SSI pins.  This function also gives
    // control of these pins to the SSI hardware. 
    GPIOPinTypeSSI(GPIO_PORTA_BASE,GPIO_PIN_2|GPIO_PIN_3);
    GPIOPinTypeSSI(GPIO_PORTA_BASE,GPIO_PIN_4|GPIO_PIN_5);
    GPIOPinTypeSSI(GPIO_PORTA_BASE,GPIO_PIN_6|GPIO_PIN_7);
    SSIConfigSetExpClk(SSI0_BASE, 120000000, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 60000000, 8);
    SSIAdvModeSet(SSI0_BASE, SSI_ADV_MODE_WRITE); 
    SSIAdvModeSet(SSI0_BASE,SSI_ADV_MODE_BI_WRITE);
    //
    // Enable the SSI0 module.
    //
    SSI0_CR1_R = 0x00000080;
    SSIEnable(SSI0_BASE);
  }
  void init_SPI0_mode_single_bit(void)
  {
    // Enable Peripheral SSI0
    //if Single bit serial mode SPI
     //***********************//
    // SSI0 is used with the following GPIO Pin Mapping
    // SSI1CLK   : PA2
    // SSI1FSS   : PA3
    // SSI1XDAT0 : PA4
    //************************//
       
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
         
    GPIOPinConfigure(GPIO_PA2_SSI0CLK);
    GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA4_SSI0XDAT0);
    
     // Configure the GPIO settings for the SSI pins.  This function also gives
    // control of these pins to the SSI hardware. 
    GPIOPinTypeSSI(GPIO_PORTA_BASE,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4);
    SSIConfigSetExpClk(SSI0_BASE, 120000000, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 60000000, 8);
    //
    // Enable the SSI0 module.
    //
    SSI0_CR1_R = 0x00000000;
    SSIEnable(SSI0_BASE); // Enable the SSI 
  }
  void init_SPI1_mode_single_bit(void)
  {
    // Enable Peripheral SSI1
    //if Single bit serial mode SPI
     //***********************//   
    // SSI1 is used with the following GPIO Pin Mapping
    // SSI1CLK   : PB5
    // SSI1FSS   : PB4
    // SSI1XDAT0 : PE4
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI1);
    // Configure the pin muxing for SSI1 functions on port B4, B5, E4, 
    
    GPIOPinConfigure(GPIO_PB5_SSI1CLK);
    GPIOPinConfigure(GPIO_PB4_SSI1FSS);
    GPIOPinConfigure(GPIO_PE4_SSI1XDAT0);
    
    // Configure the GPIO settings for the SSI pins.  This function also gives
    // control of these pins to the SSI hardware. 
    GPIOPinTypeSSI(GPIO_PORTB_BASE,GPIO_PIN_5|GPIO_PIN_4);
    GPIOPinTypeSSI(GPIO_PORTE_BASE,GPIO_PIN_4);
    SSIConfigSetExpClk(SSI1_BASE, 120000000, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 60000000, 8);
    //
    // Enable the SSI1 module.
    //
    SSI1_CR1_R = 0x00000000;
    SSIEnable(SSI1_BASE);
  }
  // init data transfert SPI data to send SSI0
  void ssi0PutData( int instruction,long data,int num_byte)
  {
   int i=0;
     
   SSI0_DR_R =  instruction; 
   
    while( num_byte )
     {
          SSI0_DR_R =  data >>(num_byte-1-i)*8;
          num_byte--;           
     }
    
     while( !( SSI0_SR_R & SSI_SR_TNF ) )
          {
            ;
          }
  }
  // init data transfert SPI data to send SSI1
  void ssi1PutData( int instruction,long data,int num_byte)
  {
   int i=0;
     
   SSI1_DR_R =  instruction; 
   
    while( num_byte )
     {
          SSI1_DR_R =  data >>(num_byte-1-i)*8;
          num_byte--;           
     }
    
     while( !( SSI1_SR_R & SSI_SR_TNF ) )
          {
            ;
          }
  }
  void PortH_Init(void)  //// Initialize GPIO Port H
 {
                                  // activate clock for Port H
  SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R7;
                                   // allow time for clock to stabilize
  while((SYSCTL_PRGPIO_R&SYSCTL_PRGPIO_R7) == 0){};
  GPIO_PORTH_DIR_R = 0x0F;            // make PH3-0 out 
  GPIO_PORTH_AFSEL_R &= ~0x0F;     // disable alt funct on PH3-0
  //GPIO_PORTH_PUR_R = 0x03;        // enable pull-up on 
  GPIO_PORTH_DEN_R = 0x0F;         // enable digital I/O on PH3-0
  GPIO_PORTH_PCTL_R &= ~0x0000FFFF; // 4) configure PH3-0 as GPIO
  //GPIO_PORTH_AMSEL_R = 0;          // disable analog functionality on PH3-0
  }
  void PortD_Init(void)  //// Initialize GPIO Port D
  {
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
  // activate clock for Port H
  SYSCTL_RCGCGPIO_R = SYSCTL_RCGCGPIO_R3; // activate clock for Port D
                                   // allow time for clock to stabilize
  while((SYSCTL_PRGPIO_R&SYSCTL_PRGPIO_R3) == 0){};
  HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
  HWREG(GPIO_PORTD_BASE + GPIO_O_CR) = 0x80;
  GPIO_PORTD_DIR_R |= 0xFF;            // make PD7-0 out 
  //GPIO_PORTD_AFSEL_R &= ~0x0F;     // disable alt funct on PD7-0
  //GPIO_PORTD_PUR_R = 0x03;        // enable pull-up on 
  GPIO_PORTD_DEN_R |= 0xFF;         // enable digital I/O on PD7-0
  GPIO_PORTD_PCTL_R &= ~0xFFFFFFFF; // 4) configure PD7-0 as GPIO
  //GPIO_PORTH_AMSEL_R = 0;          // disable analog functionality on PD7-0
  }
  void PortN_Init(void)
  {
                                   // activate clock for Port N
  SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R12;
                                   // allow time for clock to stabilize
  while((SYSCTL_PRGPIO_R&SYSCTL_PRGPIO_R12) == 0){};
  GPIO_PORTN_DIR_R |= 0x3F;        // make PN5-0 out
  GPIO_PORTN_AFSEL_R &= ~0x3F;     // disable alt funct on PN5-0
  GPIO_PORTN_DEN_R |= 0x3F;        // enable digital I/O on PN5-0
                                   // configure PN3-0 as GPIO
  GPIO_PORTN_PCTL_R &= ~0xFFFFFFFF; // 4) configure PN7-0 as GPIO
  GPIO_PORTN_AMSEL_R &= ~0x3F;     // disable analog functionality on PN5-0
  }
  void PortA_Init(void)
  {
                                   // activate clock for Port A
  SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R0;
                                   // allow time for clock to stabilize
  while((SYSCTL_PRGPIO_R&SYSCTL_PRGPIO_R0) == 0){};
  GPIO_PORTA_DIR_R |= 0xC0;             // make PA6,7 out
  //GPIO_PORTA_AFSEL_R &= ~0xFF;     // disable alt funct on PA7-0 
  GPIO_PORTA_DEN_R |= 0xFF;        // enable digital I/O on PA7-0 
                                   // configure PA7-0  as GPIO
  //GPIO_PORTA_PCTL_R &= ~0xFFFFFFFF; // 4) configure PA7-0  as GPIO
  GPIO_PORTA_AMSEL_R &= ~0xFF;     // disable analog functionality on PA7-0 
  }
  void PeripheralEnableInit(void)
  {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    //SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
    //SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  }
  int main(void)
  {
    // clock to 120MHz
    ui32SysClkFreq = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);
    volatile uint32_t ui32Loop; 
    PeripheralEnableInit();
    PortA_Init();
    PortD_Init();
    PortH_Init();
    PortN_Init();
    
    //Enable Peripheral SSI0 single bit SPI
    
    init_SPI0_mode_single_bit();
    // make  master reset DDS2  
    PN1 = 0x02; // reset DDS2
    SysCtlDelay(200);
    PN1 = 0x00;
    
    // data send to SPI0 PORT @60Mbs to two DDS card
    ssi0PutData(FR1_ADRESS,FR1,FR1_NUM_BYTE);
    ssi0PutData(CSR_ADRESS,0xF0,CSR_NUM_BYTE);  //select CH0 and CH1 and CH2  and CH3
    ssi0PutData(FTW_ADRESS,0x10624DD,FTW_NUM_BYTE);
    ssi0PutData(CSR_ADRESS,0xF6,CSR_NUM_BYTE);  //AD9959 CH0 CH1 MSB first  4-bit serial mode 
    
    SysCtlDelay(100);
    PN0 = 0x01; // AD9959 I/O update
    SysCtlDelay(20);
    PN0 = 0x00;
    
    //Enable Peripheral SSI0 quad SPI
    init_SPI0_mode_quad_bit();
    ssi0PutData(FTW_ADRESS,0x51EB851,FTW_NUM_BYTE);
    
    SysCtlDelay(100);
    PN0 = 0x01; // AD9959 I/O update
    SysCtlDelay(20);
    PN0 = 0x00;
    
    //Enable Peripheral SSI1 single bit SPI
    init_SPI1_mode_single_bit();
    // make  master reset DDS1  
    PN4 = 0x10; // reset DDS1
    SysCtlDelay(200);
    PN4 = 0x00;
    // data send to SPI1 PORT @60Mbs to two DDS card
    ssi1PutData(FR1_ADRESS,FR1,FR1_NUM_BYTE);
    ssi1PutData(CSR_ADRESS,0xF0,CSR_NUM_BYTE);  //select CH0 and CH1 and CH2  and CH3
    ssi1PutData(FTW_ADRESS,0x10624DD,FTW_NUM_BYTE);
    ssi1PutData(CSR_ADRESS,0xF6,CSR_NUM_BYTE);  //AD9959 CH0 CH1 MSB first  4-bit serial mode 
       
    SysCtlDelay(100);
    PN3 = 0x08; // AD9959 I/O update
    SysCtlDelay(20);
    PN3 = 0x00;
    
     //Enable Peripheral SSI1 quad SPI
    init_SPI1_mode_quad_bit();
    ssi1PutData(FTW_ADRESS,0x51EB851,FTW_NUM_BYTE);
    
    SysCtlDelay(100);
    PN3 = 0x08; // AD9959 I/O update
    SysCtlDelay(20);
    PN3 = 0x00;
    
  }

Mesures double DDS 2019 Ci-joint une copie d'écran du taux de transfert en mode 4 fils SPI qui montre la vitesse max des datas sur le port SPI. CLK SPI 60MHz. Test avec des liaisons filaires courtes sur une carte DDS AD9959 voie 0 et 1 activées. En rouge : I/O Update En jaune : CLK data SPI 2 coups d'horloge / Octet transmis. En bleu et vert : chanel 0 et chanel 1.


Scope 6.jpg

Sous Altium 2019 4 couches et plan de masse interne 35um Alimentation +5v, consommation 0.6A

New dds board 2019.png


double DDS 2019 sous Altium 2019 4 couches et plan de masse interne 35um


Double dds board 2019.png


Programme Python pour la liaison USB-Série : Pour charger les fréquences et les amplitudes des sorties RF j'ai utilisé Pyserial et Python 3.7 Ci-dessous le code Python éditer avec l'IDE Thonny ( pour les débutants comme moi c'est pas mal ;) !)

il suffit d'installer Python 3.7 puis d'importer la bibliothèque PySerial. L'interface graphique est en cours d'élaboration.

IMPORTANT : le code c pour transmettre et recevoir les données via l'UART ci-dessous un exemple:

  void write_immediate()  //AD9959
  {   
  //frequency DDS0//
  frequency_value_f1_DDS0 = temp[3]<<24|temp[2]<<16|temp[1]<<8|temp[0];
  FTW0_DDS0 = frequency_value_f1_DDS0 * 4294967296 / 500000000; //Convert to command for DDS  //ad9959 
  
  frequency_value_f2_DDS0 = temp[7]<<24|temp[6]<<16|temp[5]<<8|temp[4];
  FTW1_DDS0 = frequency_value_f2_DDS0 * 4294967296 / 500000000; //Convert to command for DDS  //ad9959 
  
  frequency_value_f3_DDS0 = temp[11]<<24|temp[10]<<16|temp[9]<<8|temp[8];
  FTW2_DDS0 = frequency_value_f3_DDS0 * 4294967296 / 500000000; //Convert to command for DDS  //ad9959 
  
  frequency_value_f4_DDS0 = temp[15]<<24|temp[14]<<16|temp[13]<<8|temp[12];
  FTW3_DDS0 = frequency_value_f4_DDS0 * 4294967296 / 500000000; //Convert to command for DDS  //ad9959 

  ....
  }
  //*****************************************************************************
  //
  //          The UART interrupt handler.
  //
  //*****************************************************************************
  void UARTIntHandler(void)
 {
    uint32_t ui32Status;
    ui32Status = UARTIntStatus(UART0_BASE, true);
    UARTIntClear(UART0_BASE, ui32Status);
  
   while(UARTCharsAvail(UART0_BASE)) //loop while there are chars
     {
       //send data to uC via USB/Uart for change one output frequency ( 4 octets) 
       temp[t++] = UART0_DR_R; //Read from buffer
           if(t >...)
             {
              write_immediate();
              t = 0; //Reset read length
             }
     }
  }
 Code Python:
  #!/usr/bin/python
  # -*- coding: utf-8 -*-
  import serial
  import time
  import struct

  TM4C1294 =serial.Serial(
  port ='COM8', 
  baudrate = 9600, 
  parity = serial.PARITY_NONE, 
  stopbits = serial.STOPBITS_ONE, 
  bytesize = serial.EIGHTBITS,
  timeout = 5 )

  def packIntegerAsULong(value):
  """Packs a python 4 byte unsigned integer to an arduino unsigned long"""
  return struct.pack('I', value)    #should check bounds

  print(TM4C1294.name)
  print("données prêtes à envoyer!")
  time.sleep(0.5)
  # send and receive via pyserial  DDS0 
  frequency_value_f1 = 12000000  # en Hz #
  TM4C1294.write(packIntegerAsULong(frequency_value_f1))  # DDS0 CHO
 
  frequency_value_f2 = 10000001  # en Hz #
  TM4C1294.write(packIntegerAsULong(frequency_value_f2))  # DDS0 CH1

  frequency_value_f3 = 11000000  # en Hz #
  TM4C1294.write(packIntegerAsULong(frequency_value_f3))  # DDS0 CH2

  frequency_value_f4 = 12000001  # en Hz #
  TM4C1294.write(packIntegerAsULong(frequency_value_f4))  # DDS0 CH3

  amplitude_value_f1 = 600   # 0 to 1024 #
  TM4C1294.write(packIntegerAsULong(amplitude_value_f1))  # AMPLITUDE DDS0 CHO

  amplitude_value_f2 = 400   # 0 to 1024 #
  TM4C1294.write(packIntegerAsULong(amplitude_value_f2))  # AMPLITUDE DDS0 CH1

  amplitude_value_f3 = 620   # 0 to 1024 #
  TM4C1294.write(packIntegerAsULong(amplitude_value_f3))  # AMPLITUDE DDS0 CH2

  amplitude_value_f4 = 200  # 0 to 1024 #
  TM4C1294.write(packIntegerAsULong(amplitude_value_f4))  # AMPLITUDE DDS0 CH3

  print("DDS0 chargé!")
  time.sleep(1)
  # send and receive via pyserial  DDS1 
  frequency_value_f1 = 14000001  # en Hz #
  TM4C1294.write(packIntegerAsULong(frequency_value_f1))  # DDS1 CHO

  frequency_value_f2 = 12000001  # en Hz #
  TM4C1294.write(packIntegerAsULong(frequency_value_f2))  # DDS1 CH1

  frequency_value_f3 = 9700000  # en Hz #
  TM4C1294.write(packIntegerAsULong(frequency_value_f3))  # DDS1 CH2

  frequency_value_f4 = 11000000  # en Hz #
  TM4C1294.write(packIntegerAsULong(frequency_value_f4))  # DDS1 CH3

  amplitude_value_f1 = 620   # 0 to 1024 #
  TM4C1294.write(packIntegerAsULong(amplitude_value_f1))  # AMPLITUDE DDS1 CHO

  amplitude_value_f2 = 820   # 0 to 1024 #
  TM4C1294.write(packIntegerAsULong(amplitude_value_f2))  # AMPLITUDE DDS1 CH1

  amplitude_value_f3 = 320   # 0 to 1024 #
  TM4C1294.write(packIntegerAsULong(amplitude_value_f3))  # AMPLITUDE DDS1 CH2

  amplitude_value_f4 = 600  # 0 to 1024 #
  TM4C1294.write(packIntegerAsULong(amplitude_value_f4))  # AMPLITUDE DDS1 CH3

  print("DDS1 chargé!")
  time.sleep(1)
  TM4C1294.close()
  print("sortie du programme serial fabrice!")
  exit()
Interface tkinter.png




 Code Python avec l'interface graphique
  # -*- coding: utf-8 -*-
  # On importe Tkinter
  from tkinter import Tk, StringVar, Label, Entry, Button
  from tkinter import*
  from functools import partial
  import serial
  import struct


  def packIntegerAsULong(valeur):
    """Packs a python 4 byte unsigned integer to an arduino unsigned long"""
    return struct.pack('I', valeur)    #should check bounds

  def update_label(label, stringvar):
    
    t0 = values.get()
    #print(t0)
    ser =serial.Serial(
    port = t0,
    baudrate = 9600, 
    parity = serial.PARITY_NONE, 
    stopbits = serial.STOPBITS_ONE, 
    bytesize = serial.EIGHTBITS,
    timeout = 10)
    text = stringvar.get()
    label.config(text=text)
    stringvar.set('data load!')
    t = value.get()
    ser.write(packIntegerAsULong(t))
    t2 = value2.get()
    ser.write(packIntegerAsULong(t2))
    t3 = value3.get()
    ser.write(packIntegerAsULong(t3))
    t4 = value4.get()
    ser.write(packIntegerAsULong(t4))
    t5 = value5.get()
    ser.write(packIntegerAsULong(t5))
    t6 = value6.get()
    ser.write(packIntegerAsULong(t6))
    t7 = value7.get()
    ser.write(packIntegerAsULong(t7))
    t8 = value8.get()
    ser.write(packIntegerAsULong(t8))
    t9 = value9.get()
    ser.write(packIntegerAsULong(t9))
    t10 = value10.get()
    ser.write(packIntegerAsULong(t10))
    t11 = value11.get()
    ser.write(packIntegerAsULong(t11))
    t12 = value12.get()
    ser.write(packIntegerAsULong(t12))
    t13 = value13.get()
    ser.write(packIntegerAsULong(t13))
    t14 = value14.get()
    ser.write(packIntegerAsULong(t14))
    t15 = value15.get()
    ser.write(packIntegerAsULong(t15))
    t16 = value16.get()
    ser.write(packIntegerAsULong(t16)) 
    print("virtual serial port")
    print(ser.name)
    print("baudrate")
    print(ser.baudrate)
    print("parity")
    print(ser.parity)
    print("stopbits")
    print(ser.stopbits)
    print("bytesize")
    print(ser.bytesize)
    print("timeout")
    print(ser.timeout)
    
  root = Tk() # Création de la fenêtre racine
  root.title("SERIAL FOR DDS board F.Wiotte 2019")
  root.geometry("600x600")
  #root.configure(background="none")
  frame = Frame(root)
  frame.pack()

  bottomframe = Frame(root)
  bottomframe.pack( side = BOTTOM )

  bouton=Button(root, text="quitter", fg="red",font=3,command=root.destroy) # Bouton qui détruit la fenêtre
  bouton.pack(side = BOTTOM)       # insère le bouton dans la fenêtre

  values = StringVar(root) 
  #values.set('COM8')
  spin = Spinbox(root,values=('COM1','COM2','COM3','COM4','COM5',
  'COM6','COM7','COM8'),textvariable=values)
  spin.pack(side = BOTTOM)


  text = StringVar(root)
  label = Label(frame, text='')
  entry_name = Entry(frame, textvariable=text)
  button = Button(frame, text='charger les fréquences', 
                command=partial(update_label, label, text))

  label.grid(column=20, row=80)
  entry_name.grid(column=20, row=80)
  button.grid(column=10, row=80)


  #value = IntVar(root) DDS0
  value =IntVar()
  value.set(10000000)
  scale1 = Scale(frame, from_=0, to=100000000,resolution=1000,fg="blue", showvalue=True, label='Freq DDS0 CH0',
  variable=value, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value)
  scale1.grid(row=0, column=0)
  entry.grid(row=0, column=1)

  #value2 = IntVar(root) DDS0
  value2 =IntVar()
  value2.set(10000000)
  scale2 = Scale(frame, from_=0, to=100000000,resolution=1000,fg="blue", showvalue=True, label='Freq DDS0 CH1',
  variable=value2, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value2)
  scale2.grid(row=1, column=0)
  entry.grid(row=1, column=1)

  #value2 = IntVar(root) DDS0
  value3 =IntVar()
  value3.set(10000000)
  scale3 = Scale(frame, from_=0, to=100000000,resolution=1000,fg="blue", showvalue=True, label='Freq DDS0 CH2',
  variable=value3, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value3)
  scale3.grid(row=2, column=0)
  entry.grid(row=2, column=1)

  #value2 = IntVar(root) DDS0
  value4 =IntVar()
  value4.set(10000000)
  scale4 = Scale(frame, from_=0, to=100000000,resolution=1000,fg="blue", showvalue=True, label='Freq DDS0 CH3',
  variable=value4, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value4)
  scale4.grid(row=3, column=0)
  entry.grid(row=3, column=1)

  value5 =IntVar() #DDS0
  value5.set(1023)
  scale5 = Scale(frame, from_=0, to=1023,resolution=10,fg="blue", showvalue=True, label='Amp DDS0 CH0',
  variable=value5, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value5)
  scale5.grid(row=10, column=0)
  entry.grid(row=10, column=1)

  value6 =IntVar() #DDS0
  value6.set(1023)
  scale6 = Scale(frame, from_=0, to=1023,resolution=10,fg="blue", showvalue=True, label='Amp DDS0 CH1',
  variable=value6, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value6)
  scale6.grid(row=20, column=0)
  entry.grid(row=20, column=1)

  value7 =IntVar() #DDS0
  value7.set(1023)
  scale7 = Scale(frame, from_=0, to=1023,resolution=10,fg="blue", showvalue=True, label='Amp DDS0 CH2',
  variable=value7, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value7)
  scale7.grid(row=30, column=0)
  entry.grid(row=30, column=1)

  value8 =IntVar() #DDS0
  value8.set(1023)
  scale8 = Scale(frame, from_=0, to=1023,resolution=10,fg="blue", showvalue=True, label='Amp DDS0 CH3',
  variable=value8, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value8)
  scale8.grid(row=40, column=0)
  entry.grid(row=40, column=1)

  #value = IntVar(root) DDS1
  value9=IntVar()
  value9.set(10000000)
  scale9 = Scale(frame, from_=0, to=100000000,resolution=1000,fg="green", showvalue=True, label='Freq DDS1 CH0',
  variable=value9, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value9)
  scale9.grid(row=0, column=10)
  entry.grid(row=0, column=20)

  #value = IntVar(root) DDS1
  value10=IntVar()
  value10.set(10000000)
  scale10 = Scale(frame, from_=0, to=100000000,resolution=1000,fg="green", showvalue=True, label='Freq DDS1 CH1',
  variable=value10, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value10)
  scale10.grid(row=1, column=10)
  entry.grid(row=1, column=20)


  #value = IntVar(root) DDS1
  value11=IntVar()
  value11.set(10000000)
  scale11= Scale(frame, from_=0, to=100000000,resolution=1000,fg="green", showvalue=True, label='Freq DDS1 CH2',
  variable=value11, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value11)
  scale11.grid(row=2, column=10)
  entry.grid(row=2, column=20)

  #value = IntVar(root) DDS1
  value12=IntVar()
  value12.set(10000000)
  scale12= Scale(frame, from_=0, to=100000000,resolution=1000,fg="green", showvalue=True, label='Freq DDS1 CH3',
  variable=value12, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value12)
  scale12.grid(row=3, column=10)
  entry.grid(row=3, column=20)

  value13 =IntVar() #DDS1
  value13.set(1023)
  scale13 = Scale(frame, from_=0, to=1023,resolution=10,fg="green", showvalue=True, label='Amp DDS1 CH0',
  variable=value13, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value13)
  scale13.grid(row=10, column=10)
  entry.grid(row=10, column=20)

  value14 =IntVar() #DDS1
  value14.set(1023)
  scale14 = Scale(frame, from_=0, to=1023,resolution=10,fg="green", showvalue=True, label='Amp DDS1 CH1',
  variable=value14, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value14)
  scale14.grid(row=20, column=10)
  entry.grid(row=20, column=20)

  value15 =IntVar() #DDS1
  value15.set(1023)
  scale15 = Scale(frame, from_=0, to=1023,resolution=10, showvalue=True, label='Amp DDS1 CH2',
  variable=value15, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value15)
  scale15.grid(row=30, column=10)
  entry.grid(row=30, column=20)

  value16 =IntVar() #DDS1
  value16.set(1023)
  scale16 = Scale(frame, from_=0, to=1023,resolution=10, showvalue=True, label='Amp DDS1 CH3',
  variable=value16, tickinterval=4, orient='h')
  entry = Entry(frame, textvariable=value16)
  scale16.grid(row=40, column=10)
  entry.grid(row=40, column=20)

  root.mainloop() # Lancement de la boucle principale

DDS AD9852 sur port SPI 10MHz Projet 2019 avec interface graphique pour modulation FSK AOM@80MHz

Objectif: remplacer un pilote acousto-optique analogique et un générateur de fonction arbitraire par une DDS programmable
et modulé en fréquence (FSK) l'AOM autour d'une raie centrale@80MHz.
fréquence centrale autour de 80 MHz, réglable ;
modulation de fréquence FSK :
 - modulation continue interne
 - une fréquence de modulation autour de 100 kHz, réglable ; actuellement on utilise 110 kHz, une amplitude de modulation allant jusqu'à 500 kHz, réglable.
Ci-joint code c pour le µC arm TM4C123:
//#include "inc/tm4c123gh6pm.h"

//*****************************************************************************
//             Table 1: Character LCD pins with 1 Controller
//           **********************************************//
//                    1	VSS	Power supply (GND)
//                    2	VCC	Power supply (+5V)
//                    3	VEE	Contrast adjust
//                    4	RS	0 = Instruction input
//                    1 = Data input
//                    5	R/W	0 = Write to LCD module
//                    1 = Read from LCD module
//                    6	EN	Enable signal
//                    7	D0	Data bus line 0 (LSB)
//                    8	D1	Data bus line 1
//                    9	D2	Data bus line 2
//                    10  D3	Data bus line 3
//                    11  D4	Data bus line 4
//                    12  D5	Data bus line 5
//                    13  D6	Data bus line 6
//                    14  D7	Data bus line 7 (MSB)
//**************************************************************************//
//**********************************************************************************
//
// SSI registers (SSI0) code C TM4C123GH6PM for control multi DDS AD9852 on SPI port
//                     program of Wiotte Fabrice 30/08/2018
//**********************************************************************************
#define SSI0_CR0_R              (*((volatile uint32_t *)0x40008000))
#define SSI0_CR1_R              (*((volatile uint32_t *)0x40008004))
#define SSI0_DR_R               (*((volatile uint32_t *)0x40008008))
#define SSI0_SR_R               (*((volatile uint32_t *)0x4000800C))
#define SSI0_CPSR_R             (*((volatile uint32_t *)0x40008010))
#define SSI0_IM_R               (*((volatile uint32_t *)0x40008014))
#define SSI0_RIS_R              (*((volatile uint32_t *)0x40008018))
#define SSI0_MIS_R              (*((volatile uint32_t *)0x4000801C))
#define SSI0_ICR_R              (*((volatile uint32_t *)0x40008020))
#define SSI0_DMACTL_R           (*((volatile uint32_t *)0x40008024))
#define SSI0_CC_R               (*((volatile uint32_t *)0x40008FC8))
#define SSI_SR_TNF    0x00000002  // SSI Transmit FIFO Not Full

//*****************************************************************************
//
// SSI registers (SSI3)
//
//*****************************************************************************
#define SSI3_CR0_R              (*((volatile unsigned long *)0x4000B000))
#define SSI3_CR1_R              (*((volatile unsigned long *)0x4000B004))
#define SSI3_DR_R               (*((volatile unsigned long *)0x4000B008))
#define SSI3_SR_R               (*((volatile unsigned long *)0x4000B00C))
#define SSI3_CPSR_R             (*((volatile unsigned long *)0x4000B010))
#define SSI3_IM_R               (*((volatile unsigned long *)0x4000B014))
#define SSI3_RIS_R              (*((volatile unsigned long *)0x4000B018))
#define SSI3_MIS_R              (*((volatile unsigned long *)0x4000B01C))
#define SSI3_ICR_R              (*((volatile unsigned long *)0x4000B020))
#define SSI3_DMACTL_R           (*((volatile unsigned long *)0x4000B024))
#define SSI3_CC_R               (*((volatile unsigned long *)0x4000BFC8))

// UART0
#define UART0_DR_R              (*((volatile unsigned long *)0x4000C000))
#define UART0_FR_R              (*((volatile unsigned long *)0x4000C018))
#define UART0_IBRD_R            (*((volatile unsigned long *)0x4000C024))
#define UART0_FBRD_R            (*((volatile unsigned long *)0x4000C028))
#define UART0_LCRH_R            (*((volatile unsigned long *)0x4000C02C))
#define UART0_CTL_R             (*((volatile unsigned long *)0x4000C030))

#define UART_FR_RXFF            0x00000040  // UART Receive FIFO Full
#define UART_FR_TXFF            0x00000020  // UART Transmit FIFO Full
#define UART_FR_RXFE            0x00000010  // UART Receive FIFO Empty
#define UART_LCRH_WLEN_8        0x00000060  // 8 bit word length
#define UART_LCRH_FEN           0x00000010  // UART Enable FIFOs
#define UART_CTL_UARTEN         0x00000001  // UART Enable

// GPIO for port F
#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_PUR_R        (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_AMSEL_R      (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_LOCK_R       (*((volatile unsigned long *)0x40025520))
#define GPIO_PORTF_CR_R         (*((volatile unsigned long *)0x40025524))
#define GPIO_PORTF_PCTL_R       (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))
#define GPIO_PORTF_AFSEL_R      (*((volatile unsigned long *)0x40025420))

// GPIO for port A
#define GPIO_PORTA_DATA_R       (*((volatile unsigned long *)0x400043FC))
#define GPIO_PORTA_DIR_R        (*((volatile unsigned long *)0x40004400))
#define GPIO_PORTA_DEN_R        (*((volatile unsigned long *)0x4000451C))
#define GPIO_PORTA_PUR_R        (*((volatile unsigned long *)0x40004510))
#define GPIO_PORTA_AMSEL_R      (*((volatile unsigned long *)0x40004528))
#define GPIO_PORTA_CR_R         (*((volatile unsigned long *)0x40004524))
#define GPIO_PORTA_AFSEL_R      (*((volatile unsigned long *)0x40004420))
#define GPIO_PORTA_PCTL_R       (*((volatile unsigned long *)0x4000452C))

//*****************************************************************************
//
// GPIO registers (PORTB)
//
//*****************************************************************************
#define GPIO_PORTB_DATA_BITS_R  ((volatile uint32_t *)0x40005000)
#define GPIO_PORTB_DATA_R       (*((volatile uint32_t *)0x400053FC))
#define GPIO_PORTB_DIR_R        (*((volatile uint32_t *)0x40005400))
#define GPIO_PORTB_IS_R         (*((volatile uint32_t *)0x40005404))
#define GPIO_PORTB_IBE_R        (*((volatile uint32_t *)0x40005408))
#define GPIO_PORTB_IEV_R        (*((volatile uint32_t *)0x4000540C))
#define GPIO_PORTB_IM_R         (*((volatile uint32_t *)0x40005410))
#define GPIO_PORTB_RIS_R        (*((volatile uint32_t *)0x40005414))
#define GPIO_PORTB_MIS_R        (*((volatile uint32_t *)0x40005418))
#define GPIO_PORTB_ICR_R        (*((volatile uint32_t *)0x4000541C))
#define GPIO_PORTB_AFSEL_R      (*((volatile uint32_t *)0x40005420))
#define GPIO_PORTB_DR2R_R       (*((volatile uint32_t *)0x40005500))
#define GPIO_PORTB_DR4R_R       (*((volatile uint32_t *)0x40005504))
#define GPIO_PORTB_DR8R_R       (*((volatile uint32_t *)0x40005508))
#define GPIO_PORTB_ODR_R        (*((volatile uint32_t *)0x4000550C))
#define GPIO_PORTB_PUR_R        (*((volatile uint32_t *)0x40005510))
#define GPIO_PORTB_PDR_R        (*((volatile uint32_t *)0x40005514))
#define GPIO_PORTB_SLR_R        (*((volatile uint32_t *)0x40005518))
#define GPIO_PORTB_DEN_R        (*((volatile uint32_t *)0x4000551C))
#define GPIO_PORTB_LOCK_R       (*((volatile uint32_t *)0x40005520))
#define GPIO_PORTB_CR_R         (*((volatile uint32_t *)0x40005524))
#define GPIO_PORTB_AMSEL_R      (*((volatile uint32_t *)0x40005528))
#define GPIO_PORTB_PCTL_R       (*((volatile uint32_t *)0x4000552C))
#define GPIO_PORTB_ADCCTL_R     (*((volatile uint32_t *)0x40005530))
#define GPIO_PORTB_DMACTL_R     (*((volatile uint32_t *)0x40005534))

// GPIO for port D
#define GPIO_PORTD_DATA_BITS_R  ((volatile unsigned long *)0x40007000)
#define GPIO_PORTD_DATA_R       (*((volatile unsigned long *)0x400073FC))
#define GPIO_PORTD_DIR_R        (*((volatile unsigned long *)0x40007400))
#define GPIO_PORTD_IS_R         (*((volatile unsigned long *)0x40007404))
#define GPIO_PORTD_IBE_R        (*((volatile unsigned long *)0x40007408))
#define GPIO_PORTD_IEV_R        (*((volatile unsigned long *)0x4000740C))
#define GPIO_PORTD_IM_R         (*((volatile unsigned long *)0x40007410))
#define GPIO_PORTD_RIS_R        (*((volatile unsigned long *)0x40007414))
#define GPIO_PORTD_MIS_R        (*((volatile unsigned long *)0x40007418))
#define GPIO_PORTD_ICR_R        (*((volatile unsigned long *)0x4000741C))
#define GPIO_PORTD_AFSEL_R      (*((volatile unsigned long *)0x40007420))
#define GPIO_PORTD_DR2R_R       (*((volatile unsigned long *)0x40007500))
#define GPIO_PORTD_DR4R_R       (*((volatile unsigned long *)0x40007504))
#define GPIO_PORTD_DR8R_R       (*((volatile unsigned long *)0x40007508))
#define GPIO_PORTD_ODR_R        (*((volatile unsigned long *)0x4000750C))
#define GPIO_PORTD_PUR_R        (*((volatile unsigned long *)0x40007510))
#define GPIO_PORTD_PDR_R        (*((volatile unsigned long *)0x40007514))
#define GPIO_PORTD_SLR_R        (*((volatile unsigned long *)0x40007518))
#define GPIO_PORTD_DEN_R        (*((volatile unsigned long *)0x4000751C))
#define GPIO_PORTD_LOCK_R       (*((volatile unsigned long *)0x40007520))
#define GPIO_PORTD_CR_R         (*((volatile unsigned long *)0x40007524))
#define GPIO_PORTD_AMSEL_R      (*((volatile unsigned long *)0x40007528))
#define GPIO_PORTD_PCTL_R       (*((volatile unsigned long *)0x4000752C))
#define GPIO_PORTD_ADCCTL_R     (*((volatile unsigned long *)0x40007530))
#define GPIO_PORTD_DMACTL_R     (*((volatile unsigned long *)0x40007534))

// GPIO for port E
#define GPIO_PORTE_DATA_R       (*((volatile unsigned long *)0x400243FC))
#define GPIO_PORTE_DIR_R        (*((volatile unsigned long *)0x40024400))
#define GPIO_PORTE_DEN_R        (*((volatile unsigned long *)0x4002451C))
#define GPIO_PORTE_PUR_R        (*((volatile unsigned long *)0x40024510))
#define GPIO_PORTE_AMSEL_R      (*((volatile unsigned long *)0x40024528))
#define GPIO_PORTE_CR_R         (*((volatile unsigned long *)0x40024524))
#define GPIO_PORTE_AFSEL_R      (*((volatile unsigned long *)0x40024420))
#define GPIO_PORTE_PCTL_R       (*((volatile unsigned long *)0x4002452C))

#define PF0 (*((volatile unsigned long *)0x40025004))
#define PF1 (*((volatile unsigned long *)0x40025008))    
#define PF2 (*((volatile unsigned long *)0x40025010))     
#define PF3 (*((volatile unsigned long *)0x40025020))
#define PF4 (*((volatile unsigned long *)0x40025040))

#define PD0 (*((volatile unsigned long *)0x40007004))    // CS3
#define PD1 (*((volatile unsigned long *)0x40007008))    // CS2
#define PD2 (*((volatile unsigned long *)0x40007010))    // CS1
#define PD3 (*((volatile unsigned long *)0x40007020))    // Master Reset

#define PE2 (*((volatile unsigned long *)0x40024010))    // CS5
#define PE3 (*((volatile unsigned long *)0x40024020))    // CS4

#define RS (*((volatile unsigned long *)0x40004200))     // RS LCD
#define E  (*((volatile unsigned long *)0x40004100))     // ENABLE LCD

// Flash ROM addresses must be 1k byte aligned, e.g., 0x8000, 0x8400, 0x8800...
// frequency in memory
#define FLASH0                  0x8000  // location in flash to write; make sure no program code is in this block
#define FLASH1                  0x8400
#define FLASH2                  0x8800
#define FLASH3                  0x9000
#define FLASH4                  0x9400
// amplitude in memory
#define FLASH5                  0x10000  
#define FLASH6                  0x10400  
#define FLASH7                  0x10800  
#define FLASH8                  0x20000  
#define FLASH9                  0x20400

//AD9852//

long long FTW0;   
long long FTW1; 
//float  FTW1 = 0x2AAAAAAAAAA80;   // 80 MHz
//float  FTW1 = 0x3C9C9C9C9C9C;   // 80.5 MHz

int  FTW0_ADRESS = 0x02;   //F1
int  FTW0_NUM_BYTE = 0x06;

int  FTW1_ADRESS = 0x03;   //F2
int  FTW1_NUM_BYTE = 0x06;

unsigned short int OSK_ADRESS = 0x08; 
int OSK = 2048;
int OSK_NUM_BYTE = 0x02;

unsigned short int DFW_ADRESS = 0x04;  // delta frequency word
long long DFW;
int DFW_NUM_BYTE = 0x06;

unsigned short int RRC_ADRESS = 0x06;  // delta frequency word
long RRC;
int RRC_NUM_BYTE = 0x03;

unsigned short int PLL_ADRESS = 0x07; 
//long PLL = 0x10542560;      //PLL x20 bypass inv sync FSK mode Ramp + Triangle bit auto
//long PLL = 0x10540160;    //PLL x20 bypass inv sync FSK mode Ramp
//long PLL = 0x104A0100;    //PLL X10
//long PLL = 0x104F0100;    //PLL x15
//long PLL = 0x104F0160;    //PLL x15 bypass inv sync OSK enable
//long PLL = 0x10510160;   // PLL x17 bypass inv sync OSK enable
long PLL;
int PLL_NUM_BYTE = 0x04;
//long PLL = 0x10200160;    // PLL OFF  bypass inv sync OSK enable

int i = 0;
int j = 0;
int t = 0;
char s[20];

float f_affichage1;
int  f_affichage2;

int Amp1;
int Amp2;
int Amp3;
int Amp4;
int Amp5;
float Indice_modulation;
float f_modul;

uint32_t FTW0_memory[2];
long long read_byte;
long long read_flash;

uint32_t FTW1_memory[2];
long long read_byte2;
long long read_flash2;

uint32_t ACR1_memory[1];
int read_byte5;
int read_flash5;

uint32_t F_modul_memory[1];
int read_byte3;
int read_flash3;

unsigned long input_data_amplitude_dds1 = 0;

unsigned char temp[14];
int input_data_cs = 0;

unsigned long mot_32bits;
unsigned long  command_form_freq = 0;
void write_immediate(void);
void ssi0PutData( int instruction,long long data,int num_byte);
int Lcd_Cmd(int portB);
int lcd_display(char *disp);
int Lcd_Clear();
void Lcd_Init(void);

//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif
//*****************************************************************************
//
// The UART interrupt handler.
//
//*****************************************************************************
void UARTIntHandler(void)
{
    
    uint32_t ui32Status;
    ui32Status = UARTIntStatus(UART0_BASE, true);
    UARTIntClear(UART0_BASE, ui32Status);

  
   while(UARTCharsAvail(UART0_BASE)) //loop while there are chars
     {
       //send data to uC via USB/Uart for change one output frequency ( 4 octets) 
       temp[t++] = UART0_DR_R; //Read from buffer
           if(t >13)
             {
              write_immediate();
              t = 0; //Reset read length
             }
     }
}
//------------UART_InChar------------
// Wait for new input, then return ASCII code
unsigned char UART_InChar(void)
{
  while((UART0_FR_R&0x0010) != 0);      // wait until RXFE is 0
  return((unsigned char)(UART0_DR_R&0xFF));
}
//------------UART_OutChar------------
// Wait for new output, then return ASCII code
void UART_OutChar(unsigned char data)
{
  while((UART0_FR_R&0x0020) != 0);      // wait until TXFF is 0
  UART0_DR_R = data;
}
void PortA_Init(void)
{
  volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x00000001;     // 1) activate clock for Port A
  delay = SYSCTL_RCGC2_R;           // allow time for clock to start
  GPIO_PORTA_AMSEL_R &= ~0x80;      // 3) disable analog on PA7
  GPIO_PORTA_PCTL_R &= ~0xF0000000; // 4) PCTL GPIO on PA7
  GPIO_PORTA_DIR_R |= 0xC0;       // 5) PA7-PA6 out
  GPIO_PORTA_AFSEL_R &= ~0x80;      // 6) disable alt funct on PA7
  GPIO_PORTA_DEN_R |= 0xC0;         // 7) enable digital I/O on PA7-PA6 
  
}
 void PortB_Init(void)
  {
  volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x00000002;     // 1) activate clock for Port B
  delay = SYSCTL_RCGC2_R;           // allow time for clock to start
  GPIO_PORTB_AMSEL_R = 0x00;        // 3) disable analog on PB
  GPIO_PORTB_PCTL_R = 0x00000000;   // 4) PCTL GPIO on PB0
  GPIO_PORTB_DIR_R |= 0xFF;         // 5) PB0-PB7 is out
  //GPIO_PORTB_AFSEL_R &= ~0x01;      // 6) disable alt funct on PB0
  GPIO_PORTB_AFSEL_R &= ~0xFF;      // 6) disable alt funct on PB0-PB7
  GPIO_PORTB_DEN_R |= 0xFF;         // 7) enable digital I/O on PB0-PB7
  }
   void PortD_Init(void)
  {
  volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x00000008;     // 1) activate clock for Port D
  delay = SYSCTL_RCGC2_R;           // allow time for clock to start
                                    // 2) no need to unlock PD3-0
  GPIO_PORTD_AMSEL_R &= ~0x0F;      // 3) disable analog functionality on PD3-0
  GPIO_PORTD_AFSEL_R &= ~0x0F;      // 6) regular port function 
  GPIO_PORTD_PCTL_R &= ~0x0000FFFF; // 4) GPIO
  //GPIO_PORTD_DIR_R |= 0x00;         // 5) make PD3-0 in
  GPIO_PORTD_DIR_R |= 0x0F;           //PD0 PD1 PD2 PD3 output 
  //GPIO_PORTD_DEN_R |= 0x0F;         // 7) enable digital I/O on PD3-0
  GPIO_PORTD_DEN_R |= 0x0F;
  }
  void PortE_Init(void)
  {
  volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x10;           // activate clock for Port E
  delay = SYSCTL_RCGC2_R;           // wait 3-5 bus cycles
  GPIO_PORTE_DIR_R |= 0x0F;         // Output
  GPIO_PORTE_AFSEL_R &= ~0x30;     // 6a) disable alt funct on PE4 PE5
  GPIO_PORTE_AMSEL_R  = 0x00;        // 3a) disable analog 
  GPIO_PORTE_PCTL_R &= ~0x0000FFFF; // bits for PE3,PE2,PE1,PE0
  GPIO_PORTE_DEN_R |= 0x0F;         // enable PE
  }
  void PortF_Init(void)
  {
  volatile unsigned long delay;
  SYSCTL_RCGC2_R |= 0x00000020;     // F clock
  delay = SYSCTL_RCGC2_R;           // delay
  GPIO_PORTF_LOCK_R = 0x4C4F434B;   //  unlock GPIO Port F
  GPIO_PORTF_CR_R = 0x1F;           //  allow changes to PF4-0
  GPIO_PORTF_AMSEL_R = 0x00;        //  disable analog on PF only PF0 needs to be unlocked, other bits can't be locked
  GPIO_PORTF_PCTL_R = 0x00000000;   //  PCTL GPIO on PF4-0
  GPIO_PORTF_AFSEL_R = 0x00;        //  no alternate function
  GPIO_PORTF_DIR_R = 0x0E;          //  PF4 PF0 input, PF3,PF2,PF1 output
  GPIO_PORTF_PUR_R = 0x11;          //  enable pull-up resistor on PF0 and PF4
  GPIO_PORTF_DEN_R = 0x1F;          //  enable digital I/O on PF4-0
  }
  void PeripheralEnableInit(void)
  {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
  }
  void init_UART0(void)
  {
  // Enable Peripheral UART0
  SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
  GPIOPinConfigure(GPIO_PA0_U0RX);
  GPIOPinConfigure(GPIO_PA1_U0TX);
  GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
  UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 9600,                      
  (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
  }
  //*****************************************************************************
  //
  //  SSI0 SERIAL PORT
  //
  //*****************************************************************************
  void ssi0PutData( int instruction,long long data,int num_byte)
  {
   int i=0;
   SSI0_DR_R =  instruction; 
    while( num_byte )
     {
          while(!(SSI0_SR_R & SSI_SR_TNF)) {} // wait until there is space to write in the buffer
          SSI0_DR_R =  data >>(num_byte-1-i)*8;
          num_byte--;           
     }
    
    while( !( SSI0_SR_R & SSI_SR_TNF ) )
          {
            ;
          }
  }
  void init_SPI0(void)
  {
    // Enable Peripheral SSI0
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); //Enable GPIO port A pins which are used for SSI0.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);
    GPIOPinConfigure(GPIO_PA2_SSI0CLK); 
    //GPIOPinConfigure(GPIO_PA3_SSI0FSS);
    GPIOPinConfigure(GPIO_PA5_SSI0TX);
    //GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_3 | GPIO_PIN_2);
    GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_2);
    SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 10000000, 8);
    //SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 100000, 8);
    SSIEnable(SSI0_BASE); // Enable the SSI 
  }
  /************************************************************/
  /* Prototype - write_immediate                              */
 /*                                                          */
  /*  Description                                             */
  /*  Reads incoming frequency and send to DDS immediately    */
  /************************************************************/
  void write_immediate()  //AD9852
  {
     
    unsigned long  mot_32bits = ((unsigned long)(temp[3]) << 24) | ((unsigned long)(temp[2]) << 16) | ((unsigned long)(temp[1]) << 8) | ((unsigned long)(temp[0]));
    unsigned long  mot_32bits_2 = ((unsigned long)(temp[7]) << 24) | ((unsigned long)(temp[6]) << 16) | ((unsigned long)(temp[5]) << 8) | ((unsigned long)(temp[4]));
     
    float FTW0 = (mot_32bits * 281474976710656.0 / 340000000); //Convert to command for DDS  //ad9852
    
    float FTW1 = (mot_32bits_2 * 281474976710656.0 / 340000000); //Convert to command for DDS  //ad9852
    
    input_data_amplitude_dds1 = ((unsigned long)(temp[9]) << 8) | ((unsigned long)(temp[8]));
    
    unsigned long f_modulation = ((unsigned long)(temp[13]) << 24) | ((unsigned long)(temp[12]) << 16) | ((unsigned long)(temp[11]) << 8) | ((unsigned long)(temp[10]));
    
    Indice_modulation = (mot_32bits_2 - mot_32bits)/f_modulation;
    
    float n1 = abs(mot_32bits_2 - mot_32bits)/1e6;
    
    float n =1;
    
    //f_modul = f_modul / Indice_modulation;
    f_modul = f_modulation *(n1/n) / 83,3333333;
  
    //long pas_frequence = ((unsigned long)(temp[13]) << 24) | ((unsigned long)(temp[12]) << 16) | ((unsigned long)(temp[11]) << 8) | ((unsigned long)(temp[10]));
    
    float DFW = (f_modul * 281474976710656.0 / 340000000); //Convert to DFW  //ad9852
    
       
    FTW0_memory[0] = (long long)FTW0;
    FTW0_memory[1] = (long long)FTW0>>32;
    
    FTW1_memory[0] = (long long)FTW1;
    FTW1_memory[1] = (long long)FTW1>>32;
    
    ACR1_memory[0] = (int)input_data_amplitude_dds1;
    
    F_modul_memory[0] = (long long)f_modulation;
   
    FlashErase(FLASH0), FlashErase(FLASH1),  FlashErase(FLASH2), FlashErase(FLASH5);
    FlashProgram(FTW0_memory, FLASH0, sizeof(FTW0_memory));
    FlashProgram(FTW1_memory, FLASH1, sizeof(FTW1_memory));
    FlashProgram(ACR1_memory, FLASH5, sizeof(ACR1_memory));
    FlashProgram(F_modul_memory, FLASH2, sizeof(F_modul_memory));
    
    PD2 =0x00,PD1 =0x00,PD0 =0x00,PE3 =0x00,PE2 =0x00;    //CS = 0
    
    ssi0PutData(PLL_ADRESS,0x10512560,PLL_NUM_BYTE);  //mode 1 FSK ramped triangle bit
    ssi0PutData(OSK_ADRESS,input_data_amplitude_dds1,OSK_NUM_BYTE);
    ssi0PutData(FTW0_ADRESS,(long long)FTW0,FTW0_NUM_BYTE);
    ssi0PutData(FTW1_ADRESS,(long long)FTW1,FTW1_NUM_BYTE);
    ssi0PutData(DFW_ADRESS,(long long)DFW,DFW_NUM_BYTE);
    ssi0PutData(RRC_ADRESS,(long)0x01,RRC_NUM_BYTE); 
       

  }
   int Lcd_Port(int portB)
  {
     GPIO_PORTB_DATA_R = portB;
     return 0;
  }  
  //  Function for sending command to LCD
  int Lcd_Cmd(int portB)
  {
     RS = 0x00;             // => RS = 0
     Lcd_Port(portB);
     E  = 0x40;             // Enable = 1
     SysCtlDelay(15000);
     E  = 0x00;             // Enable = 0
     return 0;
  }
  //  Function for sending data to LCD
  int Lcd_data(int portB)
  {
    Lcd_Port(portB);
    RS   = 0x80;  // RS = 1
    E   = 0x40;    //Enable = 1
    SysCtlDelay(15000);
    E   = 0x00;    // Enable = 0
    return 0;
  }
  int Lcd_Clear()
  {
	Lcd_Cmd(0);
        Lcd_Cmd(1);
        return 0;
  }
  void Lcd_display_off()
  {
	Lcd_Cmd(0);
	Lcd_Cmd(0x0C);
  }
  void Lcd_Shift_Right()
  {
	Lcd_Cmd(0x01);
	Lcd_Cmd(0x18);
  }

  void Lcd_Shift_Left()
  {
	Lcd_Cmd(0x01);
	Lcd_Cmd(0x1C);
  }
  //  Function for initializing LCD
  void Lcd_Init()
 { 
  SysCtlDelay(10000); 
  Lcd_Cmd(0x38);     //Function set: 2 Line, 8-bit, 5x7 dots
  SysCtlDelay(10000); 
  //Lcd_Cmd(0x0f);     // Display on Cursor blinking
  //SysCtlDelay(10000);
  Lcd_Cmd(0x0c);
  SysCtlDelay(10000);
  Lcd_Cmd(0x01);     //Clear LCD
  SysCtlDelay(10000);
  Lcd_Cmd(0x06);     //Entry mode, auto increment with no shift
  SysCtlDelay(10000);
  Lcd_Cmd(0x83);  // DDRAM addresses 0x80..0x8F + 0xC0..0xCF are used.
  SysCtlDelay(10000); 
  }
  //  Function for sending string to LCD
  int lcd_display(char *disp)
  {
    int x=0;
    while(disp[x]!=0)
    {
        Lcd_data(disp[x]);
        x++;
    }
    return 0;
  }
  //*****************************************************************************
  //
  // The interrupt handler for the second timer interrupt.
  //
  //*****************************************************************************
  void Timer1IntHandler(void)
  {
       TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);        // clear the timer interrupt
       float k = 340000000/281474976710656.0;
       
       SysCtlDelay(15000000);
       Lcd_Clear();
       read_byte =  *(long long *)FLASH0;
       read_flash = read_byte;
       f_affichage1 = (read_flash*k)/1000000;
       read_byte5 =  *(int *)FLASH5;
       read_flash5 = read_byte5;
       Amp1 = read_flash5;
       Lcd_Cmd(0x80);
       sprintf(s,"  DDS AMP=%d",Amp1);
       lcd_display(s);
       Lcd_Cmd(0xc0);
       sprintf(s," F1(MHz)=%.3f",f_affichage1);
       lcd_display(s);
       
       SysCtlDelay(15000000);
       Lcd_Clear();
       read_byte2 =  *(long long *)FLASH1;
       read_flash2 = read_byte2;
       f_affichage1 = (read_flash2*k)/1000000;
       Lcd_Cmd(0x80);
       sprintf(s,"  DDS AMP=%d",Amp1);
       lcd_display(s);
       Lcd_Cmd(0xc0);
       sprintf(s," F2(MHz)=%.3f",f_affichage1);
       lcd_display(s);
       
       SysCtlDelay(15000000);
       Lcd_Clear();
       Lcd_Cmd(0x80);
       lcd_display("     AD9852");
       Lcd_Cmd(0xc2);
       lcd_display("Fclock=340MHz");
       
       
       SysCtlDelay(15000000);
       Lcd_Clear();
       read_byte3 =  *(long long *)FLASH2;
       read_flash3 = read_byte3;
       f_affichage2 =  read_byte3;
       Lcd_Cmd(0x80);
       lcd_display(" F modululation");
       Lcd_Cmd(0xc0);
       sprintf(s," F(Hz)= %d",f_affichage2);
       lcd_display(s);
       
  }
   int main(void)
    {  
    uint32_t Period;
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);  // Set the clocking to run at 50MHz from the PLL.
    PeripheralEnableInit();
    init_UART0();
    PortA_Init();
    PortB_Init();
    PortD_Init();
    PortE_Init();
    PortF_Init();
    init_SPI0();
    IntEnable(INT_UART0);  //enable the UART interrupt
    UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT); //only enable RX and TX interrupts
    Lcd_Init(); 
    SysCtlDelay(20000);
    Lcd_Clear();
    Lcd_Cmd(0x80);
    lcd_display("Welcome to");
    Lcd_Cmd(0xc0);
    lcd_display("CNRS-LPL-IG-UP13");
    SysCtlDelay(10000000);  //37.5ns * 50000000 = 1,875 s
    Lcd_Clear();
    SysCtlDelay(400000);
    Lcd_Cmd(0x84);
    lcd_display("Atelier");
    Lcd_Cmd(0xc2);
    lcd_display("Electronique");
    SysCtlDelay(5000000);  //37.5ns * 50000000 = 1,875 s
    Lcd_Cmd(0x84);
    lcd_display(" PLLx17");
    Lcd_Cmd(0xc2);
    lcd_display("Fclock=340MHz");
    //SysCtlDelay(5000000);  //37.5ns * 50000000 = 1,875 s
    
    PD3 =0x08; // reset DDS
    SysCtlDelay(1000);
    PD3 =0x00;
    
    //CS DDS
    PD2=0x04,PD1=0x02,PD0=0x01,PE3=0x08,PE2=0x04;   //CS1  DDS1 OFF CS2  DDS2 OFF CS3  DDS3 OFF CS4  DDS4 OFF CS5  DDS5 OFF
    PD2 =0x00,PD1 =0x00,PD0 =0x00,PE3 =0x00,PE2 =0x00;    //CS = 0
    
    read_byte =  *(long long *)FLASH0;
    read_flash = read_byte;
    
    read_byte2 =  *(long long *)FLASH1;
    read_flash2 = read_byte2;
    
    read_byte5 =  *(int *)FLASH5;
    read_flash5 = read_byte5; 
    
    ssi0PutData(PLL_ADRESS,0x10510160,PLL_NUM_BYTE);   // PLL x17 bypass inv sync OSK enable
    SysCtlDelay(1000);
    ssi0PutData(OSK_ADRESS,read_flash5,OSK_NUM_BYTE);
    SysCtlDelay(1000);
    ssi0PutData(FTW0_ADRESS,(long long)read_flash,FTW0_NUM_BYTE);
    SysCtlDelay(1000);
    ssi0PutData(FTW1_ADRESS,(long long)read_flash2,FTW1_NUM_BYTE);
    SysCtlDelay(1000);     
       
     
    //Period2 = (SysCtlClockGet()*5); //To toggle a GPIO at 1000Hz and a 50% duty cycle
    // The Timer0 peripheral must be enabled for use. Configure Timer0B as a 16-bit periodic timer.
    //SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);  // enable timer peripheral
    //TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC);  // 16 bits Timer 
    //TimerLoadSet(TIMER0_BASE, TIMER_B, Period2 -1);
    //IntEnable(INT_TIMER0B); // Enable Timer0B Interrupt
    // Configure the Timer0B interrupt for timer timeout.
    //TimerIntEnable(TIMER0_BASE, TIMER_TIMB_TIMEOUT);
    
    // Enable processor interrupts.
    IntMasterEnable();
       
    //TimerEnable(TIMER0_BASE, TIMER_B);     // enable the timer0B
    //TimerEnable(TIMER1_BASE, TIMER_A);     // enable the timer1A
    
    //modulation FSK//
    //long PLL = 0x10512560; //mode 1 FSK ramped triangle bit
    //long PLL = 0x10510560; 
    //long PLL = 0x10510260;  // mode 0 FSK 
    //long PLL = 0x10512560; //mode 1 FSK ramped triangle bit
    //ssi0PutData(PLL_ADRESS,PLL,PLL_NUM_BYTE); 
    //DFW = 0x3B36B546;   // 1.2KHz and Ramp rate @1 = 10us soit 100KHz de modulation
    read_byte2 =  *(long long *)FLASH2;
    read_flash2 = read_byte2;
    ssi0PutData(DFW_ADRESS,(long long)0x00,DFW_NUM_BYTE); 
    ssi0PutData(RRC_ADRESS,(long)0x00,RRC_NUM_BYTE); 
    
    
    Period = (SysCtlClockGet()*1); //To toggle a GPIO at 1000Hz and a 50% duty cycle
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);            // enable timer peripheral
    //TimerConfigure(TIMER1_BASE,TIMER_CFG_PERIODIC);  // timer1A configured 32 bit periodic timer.
    TimerConfigure(TIMER1_BASE,TIMER_CFG_PERIODIC_UP); 
    TimerLoadSet(TIMER1_BASE, TIMER_A, Period -1);
    IntEnable(INT_TIMER1A); // interrupt enabled for the timer0A
    // interrupt setup for the timer0A timeouts
    TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);  
        
    TimerEnable(TIMER1_BASE, TIMER_A);     // enable the timer1A
    
    while(1)
    {} // Loop forever while the timers run.
    
   }