In this post finally I’m going to design an oscillator using the DDS AD9837, digitally controlled by Arduino.

What I have done until now?

Before continue I feel that is interesting to look back and sumarize the previous posts.

  1. In the first part of the tests, I take the Bus Pirate and it was plugged together with the evaluation Board of DDS AD9837. I didn’t use arduino, because I wanted to focus on the DDS, the SPI protocol and how to configure Bus Pirate to hold SPI comunication with DDS.
  2. Then, in the second post of the serie, I implemented a slave device with the Arduino. I connected to Bus Pirate and I was able to sniffing data from it. In that way I build a tool to check the reliability of a future Master Device implemented with Arduino. Also improve my acknowledge about SPI.
  3. In the third part, I build the Master device to hold SPI communication. I discovered a problem regarding the pins definition in the arduino platform and I solved in a convenient way. Using the slave device designed before, I check the communication between both devices.

The complete system

So in this post I’m going to program a Master device to control and program DDS, while the slave sniffer will check the correctness of the data. A potentiometer will set the outputfrequency that canbe measured using a frequencymeter.
The following draft shows how everything must be connected.

The potentiometer is connected to the Analog Input 0 to read a voltage value. This value will be suitably converted into data sended for the SPI interface lines and this data will be processed for DDS and Sniffed by the Slave Arduino at once.

Both Arduinos provide information to user with the USB connected to terminal serial monitor. I usually do this job with Moserial.

The Code

The code is organiized in three different levels:

  1. The SPI Interface.
  2. The DDS control interface.
  3. The main control program.
/*
 *******************************************************
 *  Name:            DDS Oscillator Controller V2    
 *
 *  Author:        Joan Martínez
 *
 *  Start Date:         2 ago 2012        
 *
 *  Version Date:       3 ago 2012
 *
 *  Description:    Use of SPI Mode in ATmega as master
 *                      SCK: PB5(D13), MISO: PB4(D12),
 *                      MOSI: PB3(D11), SS: PB2(D10).
 *  Platform:           Arduino UNO, 2009,...
 *
 *******************************************************/

#define POT A0
#define F_MIN 1800
#define F_MAX 2200

/* SPI Pin Config.
 ---------------
 These are the pin configuration for Arduino with ATMEGA328, 
 ATMEGA168. To be sure about what the pins to use check the 
 documentation of your MCU */
#define DD_SS (1<<DDB2)
#define DD_SCK (1<<DDB5)
#define DD_MOSI (1<<DDB3)
#define DD_MISO (1<<DDB4)

uint32_t frequency, old_freq;
boolean out_on=false;

void setup(){
  Serial.begin(9600);
  DDS_Init();
  delay(1000);
  DDS_Reset(); 
  Serial.println("DDS Master Ready!!"); 
}

void loop(){
  frequency=Read_Pot();
  if(old_freq!=frequency){
    Serial.print(frequency);
    Serial.print("Hz : ");
    Set_frequency(frequency);
    old_freq=frequency;
    delay(200);
  }
}

uint16_t Read_Pot()
{
  /* Reads a vale form POT, changes the 
   value an return the value */
  int value;
  value=analogRead(POT);
  return map(value, 0, 1023, F_MIN, F_MAX);
}

void Set_frequency(uint32_t freq){
  PORTB &= ~DD_SS;
  Serial.print("[");  
  //DDS_Reset();
  //DDS_SetFrequency(freq);
  DDS_SetDirectFrequency(freq);
  //DDS_SetPhase(0);
  if(!out_on) {
    DDS_Start();
    out_on=true;
  }
  PORTB |= DD_SS;
  Serial.println("]");
}

/***********************
 *
 *          DDS 
 *
 ************************/

#define FREQ_MUL 16.777216f
#define PHSE_MUL 651.8986469f

#define RESET_WD 0x0100
#define START_WD 0x2000
#define SET_F_WD 0x2100
#define PHSE_MSK 0xC000
#define FREQ_MSK 0x4000

void DDS_Reset(){
  /* Resets output (not registers)
   output is held in middle value */
  SPI_Master16bTransmit(RESET_WD);
}

void DDS_Init(){
  /* Prepares Master Device 
   and stops DDS */
  SPI_MasterInit();
  DDS_Reset();
}

void DDS_Start(){
  /* Enables DDS Output */
  SPI_Master16bTransmit(START_WD);
}

void DDS_SetFrequency(uint32_t frequency){
  /* Sets a new frequency reseting 
   previously the output */
  uint32_t divisor=frequency*FREQ_MUL;
  SPI_Master16bTransmit(SET_F_WD);
  SPI_Master16bTransmit((divisor & 0x3fff) | FREQ_MSK);
  SPI_Master16bTransmit((divisor >> 14) | FREQ_MSK);
}

void DDS_SetDirectFrequency(uint32_t frequency){
  /* Sets a new frequency without 
   reseting the output */
  uint32_t divisor=frequency*FREQ_MUL;
  SPI_Master16bTransmit((divisor & 0x3fff) | FREQ_MSK);
  SPI_Master16bTransmit((divisor >> 14) | FREQ_MSK);
}

void DDS_SetPhase(uint16_t phase){
  /* Sets a new phase */
  /* NOT CHECKED: just zero phase */
  SPI_Master16bTransmit((uint16_t)(phase*PHSE_MUL) | PHSE_MSK);
}

/***********************
 *
 *          SPI 
 *
 ************************/

/* Master */

void SPI_MasterInit(void){
  /* Set SCK, MOSI & SS as outputs, left unchanged others
   (MISO must!!! be set as input as default of SPI master mode) */
  DDRB = DD_MOSI | DD_SCK | DD_SS;
  PORTB |= ((1<<DD_SS)|(1<<DD_MOSI) | (1<<DD_SCK));

  /* Set mode 2, Enable SPI, set clock, master mode and order */
  SPSR &= ~(1<<SPI2X);
  SPCR &= ~((1<<SPIE) | (1<<CPHA) | (1<<DORD)) ;  
  SPCR |=  (1<<SPE) | (1<<MSTR) | (1<<CPOL) | (1<<SPR1) | (1<<SPR0);
}

uint8_t SPI_MasterTransmit(uint8_t cData){
  SPDR=cData;
  Serial.print(" 0x");
  Serial.print(cData,HEX);  
  while(!(SPSR & (1<<SPIF)))
    ;
  return SPDR;
}

void SPI_Master16bTransmit(uint16_t wData){
  SPI_MasterTransmit(wData>>8);
  SPI_MasterTransmit(wData & 0xff);
}

The SPI part only has the functions that holds the SPI communication protocol. This functions are used by next level.

The functions od DDS are in charge of convert freqüency information in data to send by SPI.

With this structure the previous two parts can be used in diferent and more complex projects, because this is only a tinny part of whant can be done using the same devices .

In the top of the code is the main part that reads the potentiometerr value and gives a freqúency value to the other levels.

Changing values of F_MAX and F_MIN is possible to change the freqúency range that can be adjusted by the potentiometer connected to A0.

Conclussion

This series of posts has shown the method to use Arduino with SPI, learning in every step from the previuos step. Collecting the aknowledge from the begining I learn about Bus Pirate, a great tool despite some limitations, but a Must to get in the home lab. Also I discovered the DDS technology, something I already heard to talk about but never before face by my self.

Using the tools descrived it’s easy to get new ideas, new project. Now, it looks to me easy to design and build a function generator, controlled by PC, or a FSK/PSK Modem.

I hope these posts may help you to get inspiration in new projects.

Anuncios