Sunday 16 April 2017

Getting it straight - AD985x IC Arduino library "ADS9850 & 51"

I’ve seen a lot of libraries on the web for the AD9850 and AD9851 Analog Digital Synthesisers. And as far as I can see none of them meet the data sheet description of how to program the devices.

Most people use the AD985x devices mounted on modules made in China.

IMG 0993

These all seem to have the same circuit diagram. The device is wired for either parallel or serial data inputs, and two sine and two square wave outputs.

Screen Shot 2017 04 17 at 11 26 00

Large board

Screen Shot 2017 04 17 at 11 25 09

Small board

But ONLY one sine output has a filter to filter the DAC jitters, a 70MHz LPF, this is on the IOUT pin. So this is the output you should use.

ARDUINO

Lets start with the Arduino, and assume we are going to send data to the device in serial mode. We need 4 pins for this, for the signals W_CLK, FQ_UP, DATA and RESET. So we set up 4 Arduino pins in OUTPUT mode. On the Arduino this defaults the output to LOW level, which is what we want.

The first thing to do is to reset the device, this is a bit difficult as it starts in parallel mode and could cause a problem. With the device in parallel mode a reset (a LOW-HIGH-LOW pulse on RESET) will zero the phase accumulator & offset, set the output IOUT to zero mA, set the internal address pointer to the first of the five programming bytes, set power down PD off and, for the AD9851 set the internal x6 xtal frequency REFCLK  multiplier off. But it won’t clear the frequency registers or the control and phase set registers. So they could contain random bits…  this is chance you have to take. They will anyway be overwritten by the following code, but could briefly put the device  in an illegal factory control mode...

The large modules from China are hard wired with pins D0 & D1 to VCC and D2 via a jumper J1 to GND, but the small modules should be wired externally to be safe. This gives the input code required to the parallel input D0-D7 of xxxxx011 which will switch the device to serial mode by a pulse on W_CLK followed by FQ_UD.

Next thing to do for the AD985x is to place the device in power down mode, which will clear all the registers, and for the AD9851 set the PD and the REFCLK registers. We need the REFCLK set to ‘1’ for the AD9851 to enable the x6 xtal frequency multiplier, as all AD9851 modules from China seem to come with a lower cost 30MHz xtal, not an external 180MHz one. But we need an internal 180MHz for correct frequency outputs. (This seems to be a BIG mistake many users make as AD9850 modules come with a 125MHz xtal...).

So the first call is to the library function “begin":

// init calFreq, pins, reset & serial mode
void ADS9850::begin(int W_CLK, int FQ_UD, int DATA, int RESET) {
	_W_CLK = W_CLK;
	_FQ_UD = FQ_UD;
	_DATA = DATA;
	_RESET = RESET;

	_calFreq = ADS_XTAL;

	pinMode(_W_CLK, OUTPUT); // outputs default to LOW
	pinMode(_FQ_UD, OUTPUT);
	pinMode(_DATA, OUTPUT);
	pinMode(_RESET, OUTPUT);

	pulse(_RESET); // reset, parallel mode, ptr to W0
        
        pulse(_W_CLK); // switch to serial mode, xxxxx011 wired on d0-d2
        pulse(_FQ_UD);

        down(); // clear freq and phase registers, REFCLK=1 (x6 en), PD=1 (pwd dn)
}

To set an output frequency we need to calculate the 32 bit value to serially transfer into the first 4 bytes of the 40 bit control register. This we do like this for the AD9850:

// calculate 4 freq bytes, convert double to to uint32_t
void ADS9850::setFreq(double f, double cf, uint8_t p) {
        uint32_t delta;

	delta = (uint32_t)((f + cf/100.0) * 4294967296.0 / _calFreq);
	p = p << 3; // = ppppp000
	update(delta, p);
}
or for the AD9851
// calculate 4 freq bytes, convert double to to uint32_t
void ADS9851::setFreq(double f, double cf, uint8_t p) {
     uint32_t delta;

	delta = (uint32_t)((f + cf/100.0) * 4294967296.0 / _calFreq);
	p = p << 3; // PD off = ppppp000
    setBit(p, 0); // REFCLK on, = ppppp001
	update(delta, p);
}

We start with frequencies f (Hz) and cf (cHz) in double floating point, calculate the "delta" value then convert the result to a 32 bit uint32_t value. And we calculate the phase register contents, setting the REFCLK flag for the AD9851

Next we have to transfer the uint32_t frequency, and the byte p for the control and phase of the ouptut. This is done by the function update().

The update is made like this (same for the AD9851):

// load the 4 delta & the control/phase registers
void ADS9850::update(uint32_t d, uint8_t c) {
    for (int i=0; i <4 ; i++, d >>= 8) {
       shiftOut(_DATA, _W_CLK, LSBFIRST, d); // output freq byte
    }
    shiftOut(_DATA, _W_CLK, LSBFIRST, c); // output control & phase byte

    pulse(_FQ_UD);
}

First "shiftOut" the four delta frequency bytes then the control/phase byte with the previous settings for PD and REFCLK. The function "shiftOut" generates the W_CLK signal for the transfer.

So here are the complete libraries.

Study them both to understand the differences between the AD9850 and 51.

No comments: