Maxim DS1077 EconOscillator/Divider Library

Maxim DS1077 EconOscillator/Divider

This class wraps the functions of the DS1077 oscillator into a usable class for mBed. The oscillator uses I2C to communicate with the host MCU. This oscillator output a square wave, so if you're looking for a sine wave - this isn't it.

Be sure to download the DATASHEET (You'll need it to work with this chip). You can also purchase a breakout board from SparkFun. Be sure to ground the CTRL1 and CTRL0 pins if you don't plan on using them.

This library was created using the mbed NXP LPC11U24. Pins p27 and p28 were used for the I2C functions. Be sure to install 1K pull-up resistors on both lines.

Here's the output from the OUT1 pin on my scope after running the sample code below:

/media/uploads/sophtware/ds1077-32khz.png

Below is some sample code that sets the oscillator OUT2 pin to 16.67MHz and the OUT1 pin to 32kHz. It then outputs the content of all the control registers. You'll need the serial debug setup for your mBed. If you still need the serial driver for your mbed, you can get it here.

Sample Code

#include "mbed.h"
#include "DS1077.h"

I2C i2c(p28, p27);       // sda, scl

// Comment out all of the references to 'pc' on this page if you don't have the 
// serial debug driver for your mbed board installed on your computer. If you do,
// I personally like to use Putty as the terminal window to capture debug messages.
Serial pc(USBTX, USBRX); // tx, rx

// Again, remove the '&pc' parameter if you're not debugging.
DS1077 osc(&i2c, &pc);

DigitalOut myled(LED1);

int main() 
{
    pc.printf("** DS1077 EconOscillator **\r\n");

    osc.setSelect();
    wait_ms(1);
    // Set OUT2 to ~16.67MHz
    osc.setPrescalerP0Divisor(DS1077::X8);
    wait_ms(1);
    // Set OUT1 to ~32kHz
    osc.setPrescalerP1Divisor(DS1077::X4);
    wait_ms(1);
    osc.setDivisor(0xFFF);
    wait_ms(1);

    pc.printf("DIV: 0x%X\r\n", osc.divRegister()&0x0000FFFF);
    wait_ms(1);
    pc.printf("MUX: 0x%X\r\n", osc.muxRegister()&0x0000FFFF);
    wait_ms(1);
    pc.printf("BUS: 0x%X\r\n", osc.busRegister());

//    osc.write();

    while(1) {
        myled = 1;
        wait(0.2);
        myled = 0;
        wait(0.2);
    }
}

DS1077.cpp

Committer:
sophtware
Date:
2014-04-06
Revision:
2:86284a0a46ca
Parent:
1:162fd9241279

File content as of revision 2:86284a0a46ca:

#include "DS1077.h"
#include "mbed.h"

#include "stdarg.h" // For debugOut use of the ... parameter and va_list

DS1077::DS1077(I2C *i2c, Serial *pc) : _i2c(i2c), _debug(pc)
{
}

void DS1077::write()
{
    char cmd[1];
    cmd[0] = CMD_E2;
    if (_i2c->write(DS1077_ADDRESS, cmd, 1) != 0)
        debugOut("DS1077::write: Failed issuing write command to register 0x%X\r\n", CMD_E2);    
}

void DS1077::setShutdownControl(DS1077::pdnType pdn)
{
    short temp = i2cTwoByteRead(CMD_DIV);   // Read the current register value

    switch (pdn)
    {
        case NONE:
            temp &= ~0x6000;
            break;        
        case CTRL1:
            temp &= ~0x4000;
            temp |= 0x2000;
            break;
        case CTRL0:
            temp &= ~0x2000;
            temp |= 0x4000;
            break;        
        case EITHER:
            temp |= 0x6000;
            break;        
    }

    i2cTwoByteWrite(CMD_DIV, (char)(temp>>8), (char)temp);         // Write register value back
}

char DS1077::address()
{
    return (char)(i2cTwoByteRead(CMD_BUS) & 0x7);
}

void DS1077::setAddress(char addr)
{
    short temp = i2cTwoByteRead(CMD_BUS) & 0xFFF8;
    temp |= (addr & 0x7);                     
    i2cTwoByteWrite(CMD_BUS, (char)(temp>>8), (char)temp);      
}

DS1077::prescalerType DS1077::prescalerP0Divisor()
{
    short temp = (i2cTwoByteRead(CMD_MUX) & 0x600) >> 9;
    
    switch (temp)
    {
        case 0:
            return X1;
        case 1:
            return X2;
        case 2:
            return X4;
        case 3:
            return X8;
    }
    
    return X1;
}

void DS1077::setPrescalerP0Divisor(DS1077::prescalerType prescaler)
{
    short temp = i2cTwoByteRead(CMD_MUX);   // Read the current register value

    switch (prescaler)
    {
        case X1:
            temp &= ~0x600;
            break;        
        case X2:
            temp = (~0x600 & temp | (0x1<<9));
            break;
        case X4:
            temp = (~0x600 & temp | (0x2<<9));
            break;        
        case X8:
            temp |= 0x600;
            break;        
    }

    i2cTwoByteWrite(CMD_MUX, (char)(temp>>8), (char)temp);         // Write register value back
}

DS1077::prescalerType DS1077::prescalerP1Divisor()
{
    short temp = (i2cTwoByteRead(CMD_MUX) & 0x180) >> 7;
    
    switch (temp)
    {
        case 0:
            return X1;
        case 1:
            return X2;
        case 2:
            return X4;
        case 3:
            return X8;
    }
    
    return X1;
}

void DS1077::setPrescalerP1Divisor(DS1077::prescalerType prescaler)
{
    short temp = i2cTwoByteRead(CMD_MUX);   // Read the current register value

    switch (prescaler)
    {
        case X1:
            temp &= ~0x180;
            break;        
        case X2:
            temp = (~0x180 & temp | (0x1<<7));
            break;
        case X4:
            temp = (~0x180 & temp | (0x2<<7));
            break;        
        case X8:
            temp |= 0x180;
            break;        
    }

    i2cTwoByteWrite(CMD_MUX, (char)(temp>>8), (char)temp);         // Write register value back
}

void DS1077::clearRegisterBit(const char regAddr, const char bitMask)
{
    char temp = i2cRead(regAddr);   // Read the current register value
    temp &= ~bitMask;               // Clear the bit from the value
    i2cWrite(regAddr, temp);        // Write register value back
}

void DS1077::setRegisterBit(const char regAddr, const char bitMask)
{
    char temp = i2cRead(regAddr);   // Read the current register value
    temp |= bitMask;                // Set the bit in the value
    i2cWrite(regAddr, temp);        // Write register value back
}

void DS1077::clearTwoByteRegisterBit(const char regAddr, const short bitMask)
{
    short temp = i2cTwoByteRead(regAddr);   // Read the current register value
    temp &= ~bitMask;                       // Clear the bit from the value
    wait_ms(1);
    i2cTwoByteWrite(regAddr, (char)(temp>>8), (char)temp);         // Write register value back
}

void DS1077::setTwoByteRegisterBit(const char regAddr, const short bitMask)
{
    short temp = i2cTwoByteRead(regAddr);   // Read the current register value
    temp |= bitMask;                        // Set the bit in the value
    wait_ms(1);
    i2cTwoByteWrite(regAddr, (char)(temp>>8), (char)temp);         // Write register value back
}

char DS1077::i2cRead(char regAddr)
{
    _i2c->start();                              // Start
    if (_i2c->write(DS1077_ADDRESS)!=1)         // A write to device
        debugOut("DS1077::i2cRead: Oscillator failed to respond to write request at address 0x%X\r\n", DS1077_ADDRESS);
    
    if (_i2c->write(regAddr)!=1)                // Register to read
        debugOut("DS1077::i2cRead: Oscillator at address 0x%X did not acknowledge register 0x%X\r\n", DS1077_ADDRESS, regAddr);
    
    _i2c->start();                  
    if (_i2c->write(DS1077_ADDRESS|0x01)!=1)    // Read from device
        debugOut("DS1077::i2cRead: Oscillator failed to respond to read request at address 0x%X\r\n", DS1077_ADDRESS);

    char result = _i2c->read(READ_NAK);         // Read the data
    _i2c->stop();
    
    return result;  
}

void DS1077::i2cWrite(char regAddr, char msb)
{
    char cmd[2];
    cmd[0] = regAddr;
    cmd[1] = msb;
    if (_i2c->write(DS1077_ADDRESS, cmd, 2) != 0)
        debugOut("DS1077::i2cWrite: Failed writing msb (%d, 0x%X) to register 0x%X\r\n", msb, regAddr);    
}

short DS1077::i2cTwoByteRead(char regAddr)
{
    _i2c->start();                              // Start
    if (_i2c->write(DS1077_ADDRESS)!=1)         // A write to device
        debugOut("DS1077::i2cRead: Oscillator failed to respond to write request at address 0x%X\r\n", DS1077_ADDRESS);
    
    if (_i2c->write(regAddr)!=1)                // Register to read
        debugOut("DS1077::i2cRead: Oscillator at address 0x%X did not acknowledge register 0x%X\r\n", DS1077_ADDRESS, regAddr);
    
    _i2c->start();                  
    if (_i2c->write(DS1077_ADDRESS|0x01)!=1)    // Read from device
        debugOut("DS1077::i2cRead: Oscillator failed to respond to read request at address 0x%X\r\n", DS1077_ADDRESS);

    char msb = _i2c->read(READ_ACK);            // Read the data
    char lsb = _i2c->read(READ_NAK);            // Read the data
    _i2c->stop();
    
    return ((short)msb<<8)|lsb;  
}

void DS1077::i2cTwoByteWrite(char regAddr, char msb, char lsb)
{
    char cmd[3];
    cmd[0] = regAddr;
    cmd[1] = msb;
    cmd[2] = lsb;
    if (_i2c->write(DS1077_ADDRESS, cmd, 3) != 0)
        debugOut("DS1077::i2cWrite: Failed writing msb (%d, 0x%X) and lsb (%d, 0x%X) to register 0x%X\r\n", msb, lsb, regAddr);    
}
    
void DS1077::debugOut(const char * format, ...)
{
    if (_debug == NULL)
        return;
        
    va_list arg;
    _debug->printf(format, arg);
}