DS3231 Function Library

Since my ChronoDot has arrived, I have been able to test the DS3231's extra functions. Until I can get all of them working, I'll be offering them "loose" for those that also want to help test or just want the working ones. They can be dropped into the DS1307 library as public members.

EDIT: All functions are working! A patch for the DS1307 library will come soon; alternatively, I can offer these as part of their own library. The functions below are merely for reference.

NOTE: During testing, with the 32K and SQW pins connected to digital pins 2 and 3 respectively, I've found that the SQW pin will interfere with the 32K one, causing pin 3 to read the SQW signals. After testing as many software combinations as I could think of, and even after attaching a stronger pull-up resistor to the 32K line, my thinking is that it has to do with EMI between the two pins. If you want a clear signal from either pin, your best bet is to disable one and enable the other in software.

Temperature readout, working. Returns a float representing the temperature measured since the last temperature conversion, in degrees celsius (temperatures below zero will be reported incorrectly because of a known bug):

float getTemperature(void)
{
	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x11);
	Wire.endTransmission();

	// Just the two this time (temperature int, frac)
	Wire.requestFrom(DS1307_CTRL_ID, 2);

	int8_t  fint  = Wire.receive();
	uint8_t ffrac = ((Wire.receive() >> 6));

	return (float)fint + ((float)ffrac * 0.25);
}

Force temperature conversion, also working. Argument determines whether or not the function should block until the conversion is complete. I tested it briefly; on my chip, it blocks for approximately 150ms.

void tempConv(uint8_t block)
{
	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0E);
	Wire.endTransmission();

	// control register
	Wire.requestFrom(DS1307_CTRL_ID, 1);

	uint8_t creg = Wire.receive();

	creg |= 0b00100000; // Write CONV bit

	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0E);
	Wire.send(creg);
	Wire.endTransmission();

	do
	{
		// Block until CONV is 0
		Wire.beginTransmission(DS1307_CTRL_ID);
		Wire.send(0x0E);
		Wire.endTransmission();
		Wire.requestFrom(DS1307_CTRL_ID, 1);
	} while ((block && (Wire.receive() & 0b00100000) != 0));
}

Battery-backed square-wave enableworking. When enabled, this disables the alarm function.

void SQWEnable(uint8_t enable)
{
	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0E);
	Wire.endTransmission();

	// control register
	Wire.requestFrom(DS1307_CTRL_ID, 1);

	uint8_t creg = Wire.receive();

	creg &= ~0b01000000; // Set to 0
	if (enable == true) {
		creg |=  0b01000000; // Enable if required.
		creg &= ~0b00000100; // Clear INTCN bit
	}

	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0E);
	Wire.send(creg);
	Wire.endTransmission();
}

Battery-backed square-wave frequency setting, working. Make sure the pin it's connected to is pulled up (this can be accomplished on an input pin by writing HIGH to it). Argument MUST be one of the four #defined below.

#define DS3231_SQW_FREQ_1    0b00000000 // 1Hz
#define DS3231_SQW_FREQ_1024 0b00001000 // 1024Hz
#define DS3231_SQW_FREQ_4096 0b00010000 // 4096Hz
#define DS3231_SQW_FREQ_8192 0b00011000 // 8192Hz

void SQWFrequency(uint8_t freq)
{
	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0E);
	Wire.endTransmission();

	// control register
	Wire.requestFrom(DS1307_CTRL_ID, 1);

	uint8_t creg = Wire.receive();

	creg &= ~0b00011000; // Set to 0
	creg |= freq; // Set freq bits

	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0E);
	Wire.send(creg);
	Wire.endTransmission();
}

Enable 32KHz pin, partially working. Needs to be pulled up if connected like the SQW pin.

void enable32Khz(uint8_t enable)
{
	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0F);
	Wire.endTransmission();

	// status register
	Wire.requestFrom(DS1307_CTRL_ID, 1);

	uint8_t sreg = Wire.receive();

	sreg &= ~0b00001000; // Set to 0
	if (enable == true)
		sreg |=  0b00001000; // Enable if required.

	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0F);
	Wire.send(sreg);
	Wire.endTransmission();
}

Enable internal oscillator, UNKNOWN if working. NOTE that this function differs from the actual bit value given in the datasheet, as the name it uses for this bit is misleading. Calling this with "true" will ENABLE the oscillator as the name implies.

void enableOSC(uint8_t enable)
{
	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0E);
	Wire.endTransmission();

	// status register
	Wire.requestFrom(DS1307_CTRL_ID, 1);

	uint8_t sreg = Wire.receive();

	sreg |= 0b10000000; // Set to 1 (disabled)
	if (enable == true)
		sreg &= ~0b10000000; // Enable if required.

	Wire.beginTransmission(DS1307_CTRL_ID);
	Wire.send(0x0E);
	Wire.send(sreg);
	Wire.endTransmission();
}

The battery-backed square wave feature is present in the DS1307, but it uses a different address to enable/configure it. If anyone could make the necessary changes and see if they can debug it on the DS1307, I would be grateful, as having an accurate external timer would be handy!

This will probably help. I can confirm that the sqw function in this library does work.
http://code.google.com/p/gfb/source/browse/arduino/DS3231/DS3231.pde?r=77&safe=vss

Mowcius

I was not aware of the existence of this DS3231 but now I want to test it :slight_smile: Looks the cool version of the DS1307...

mowcius:
This will probably help. I can confirm that the sqw function in this library does work.
http://code.google.com/p/gfb/source/browse/arduino/DS3231/DS3231.pde?r=77&safe=vss

Mowcius

I couldn't find anything wave-related in the code behind that link, but the 32K line is magically working now (perhaps I wired it wrong the first time). Configurable square-wave still isn't functioning, however.

EDIT: I fixed the square wave code, so now everything is working(to my knowledge).

ccfreak2k:

mowcius:
This will probably help. I can confirm that the sqw function in this library does work.
Google Code Archive - Long-term storage for Google Code Project Hosting.

Mowcius

I couldn't find anything wave-related in the code behind that link, but the 32K line is magically working now (perhaps I wired it wrong the first time). Configurable square-wave still isn't functioning, however.

EDIT: I fixed the square wave code, so now everything is working(to my knowledge).

Oh sorry - wrong page. I meant this:

Wire.beginTransmission(104);
Wire.send(0x0e); //select control register
//set sqw at specified Hz of 0=1Hz
Wire.send(0);
Wire.endTransmission();

Glad you got it working though.

The library is fairly complete, and I've fixed all the bugs I've found so far. I can upload the library wherever it should go. The archive can also include Doxygen-generated documentation (the header is marked up for this). What's left to add would be alarms, which I'll be able to add in the coming days.

Setting the Square wave on the DS1307 is pretty simple.

(First post -- so no links...)

I just finished testing the DS1307...

byte Osc_Base = 0x90; // just a number they like...
byte Osc_Rate = 0; // 0= 1HZ, 1 = 4096Hz, 2 = 8192Hz, 3 = 32768Hz

then in the program loop...
RTC.set(DS1307_OSC,Osc_Base + 1 );

// NOTE --- no mneed to start or stop the clock -- I tested and used oscilloscope to verify changing frequency
// As mentioned -- Pull up resistor to 5Volts -- I used a 3.9k for testing and checked it on an oscilloscope.

The Location DS1307_OSC is just byte 7 of the DS1307's registers...

I modified Matts Library so that I could access the 8th register (numbered 07 in the 00 -- 07 scheme)

I modified his START procedure -- to preserve the seconds and make it easier to set...

void DS1307::start(void)
{
// unset the ClockHalt bit to start the rtc
// TODO : preserve existing seconds -- DONE!!!
rtc_bcd[DS1307_SEC]= rtc_bcd[DS1307_SEC] & 0x7F; // the AND preserves the old value -- just sets the start/stop bit
save_rtc();
}

I hope that helps people...

If I had an email I would send matt all the updates.

I modified his .h file as so...

#define DS1307_SEC 0
#define DS1307_MIN 1
#define DS1307_HR 2
#define DS1307_DOW 3
#define DS1307_DATE 4
#define DS1307_MTH 5
#define DS1307_YR 6
#define DS1307_OSC 7

//NOTE last entry above adding OSC byte as the 7th byte... (the eighth one)
// Note the array is expanded to 8 bytes...

private:
byte rtc_bcd[8]; // *** used prior to read/set ds1307 registers;
void read_rtc(void);
void save_rtc(void);
};

In his CPP you can modify the Case for GET as so... by adding this case at the end...

case DS1307_OSC:
v = rtc_bcd[DS1307_OSC];
break;

You can modify the SET function by adding this case...

case DS1307_OSC:
rtc_bcd[DS1307_OSC]= lowByte(v);
break;

These functions get changed to add the eighth byte...

void DS1307::read_rtc(void)
{
// use the Wire lib to connect to the rtc
// reset the register pointer to zero
Wire.beginTransmission(DS1307_CTRL_ID);
Wire.send(0x00);
Wire.endTransmission();

// request the 8 bytes of data (secs, min, hr, dow, date. mth, yr,osc)
Wire.requestFrom(DS1307_CTRL_ID, 8); //change param to 8 from 7
for(int i=0; i<8; i++)
{
// store data in raw bcd format
rtc_bcd*=Wire.receive();*

  • }*
    }
    // update the data on the IC from the bcd formatted data in the buffer
    void DS1307::save_rtc(void)
    {
  • Wire.beginTransmission(DS1307_CTRL_ID); //this is the chip address*
  • Wire.send(0x00); // reset register pointer*
  • for(int i=0; i<8; i++)*
  • {*
    Wire.send(rtc_bcd*);
    _
    }_
    _
    Wire.endTransmission();_
    _
    }_
    _
    ...Again Hope that helps people...*_