AD9850 / Arduino – Librairie Python

AD9850 / Arduino – Librairie Python

Voici en gros un projet pour piloter un AD9850, générateur DDS (Direct Digital Synthesizer) via une interface en ligne de commande Python utilisant une Arduino en guise de convertisseur USB/SERIAL. Ici on règle les timings du convertisseur à la main sans passer par un contrôleur SPI et ça marche très bien même à grande vitesse. Ne pas faire ça à grande vitesse par contre.

L’Arduino est utilisée en tant que driver interface, le python pilote cette dernière par un port série rapide à 2Mb/s, c’est important pour les sweep où beaucoup de données sont échangées. Le brochage du port série émulé par l’Arduino pour contrôler l’AD9850 est situé dans l’en tête du driver. L’intérêt d’utiliser du python réside dans la facilité de manipulation des périphériques, c’est beaucoup plus souple et puissant qu’un simple µc.

Pilotage Python (2.7) :


# coding: utf-8
'''
Created on 2 mai 2017
Controle des frequences dynamiques AD9850 - LIBRAIRIE
@author: DOUAY
'''

import serial #pip install pyserial
import time
from math import floor

ser = serial.Serial()
    
def AD9850(cmd):
    
    if (ser.is_open == False):
        print("Connecting to " + cmd[0] + " ... ") 
        ser.baudrate = cmd[1]
        ser.port = cmd[0]
        ser.open()
        time.sleep(0.5) # delay after port opening
        
        if(ser.is_open):
            #ser.write(b'0')
            print ("Serial " + cmd[0] + " online.")
        
    if(ser.is_open):       
        if (cmd[2] == "sweep"): # sweep mode
            print ("Entering sweep from " + cmd[3] + " to " + cmd[4] + " for " + cmd[5] + " loop(s) " + " ... ")
        
            for x in range(0, int(cmd[5])):
                freq = int(cmd[3]) 
                while freq < int(cmd[4]):
                        ser.write(str(freq).encode())
                        freq = floor(freq + freq/1000)+1
                        time.sleep(0.0075)
                        print(freq)
            print("Over.") 
        ser.write(b'0')
        time.sleep(0.03)
    
        if (cmd[2] == "frq"): # dicrete frequency mode
            print ("Generating " + str(cmd[3]) + " Hz ... ")
            ser.write(str(cmd[3]).encode()) #cast int 32b to string then encode to ASCII and write
            
            if cmd[4] >= 0.03: #0.03 sec -> Minimum time 
                time.sleep(cmd[4])
            else:
                time.sleep(0.03)
        

if __name__ == "__main__": #Tests
    
    port = "COM7" #dmesg | grep tty (Linux)
    speed = 2000000 #2Mb/s
    duration = 0.1 #Frequency duration for FRQ mode
    
    AD9850([port,speed,"sweep","85000","150000","1"])
    AD9850([port,speed,"frq","1000000",3])
    AD9850([port,speed,"frq","30000000",2])
    AD9850([port,speed,"frq","500000",2])
    
    for f in range(85000,200000,3000):
        AD9850([port,speed,"frq",f,duration])
    

Driver ARDUINO UNO :



// Douay Corentin - 28/04/2017

#define W_CLK 3       // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 4       // Pin 9 - connect to freq update pin (FQ)
#define DATA 5       // Pin 10 - connect to serial data load pin (DATA)
#define RESET 6      // Pin 11 - connect to reset pin (RST).
#define Led 12

#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }

long freq = 0;
String cmd = "";
unsigned long currentMillis = millis();
unsigned long previousMillis = 0;
int ledState = LOW;

// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data)
{
  for (int i = 0; i < 8; i++, data >>= 1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
  }
}

// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency)
{
  int32_t freq = frequency * 4294967295 / (125 000 000 + 15); // note 125 MHz clock on 9850
  for (int b = 0; b < 4; b++, freq >>= 8) {
    tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip
  pulseHigh(FQ_UD);  // Done!  Should see output
}

void clear_buffer()
{
  while(Serial.available () > 0){
     Serial.read(); 
    }
}

void blink_led(int interval)
{
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    digitalWrite(Led, ledState);
  }
}

void setup() {
  pinMode(FQ_UD, OUTPUT);
  pinMode(W_CLK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RESET, OUTPUT);
  pinMode(Led, OUTPUT);

  Serial.begin(2000000); // 2Mb/s
  Serial.setTimeout(2);
  Serial.println("-- DDS Ready --");
  
  pulseHigh(RESET);
  pulseHigh(W_CLK);
  pulseHigh(FQ_UD);  // this pulse enables serial mode - Datasheet page 12 figure 10
}

void loop() {

  while (Serial.available() > 0)
  {
    long in = Serial.parseInt();
    sendFrequency(in);
    Serial.println(in);
    delay(5);
    clear_buffer();
    delay(5);
  }

}

Laisser un commentaire