DS3231 - am I doing something wrong or is the part defective?

I have one of the cheap DS3231 modules from aliexpress. I can’t get it to work, and I’m wondering if it’s something I’m doing or I have a bad part.

I’m using an Arduino Diecimila, the DS3231 module has a good CR2032 installed, I have Vcc and GND connected to the 5v and GND pins on the arduino. SCL is connected to A5 and SDA is connected to A4. The power light on the DS3231 module comes on.

I have a very simplified code to try and see if the module is working:

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // set the initial time here:
  Serial.print("Starting to set time -- ");
  Wire.beginTransmission(DS3231_I2C_ADDRESS);  // set a time
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(1); // set seconds
  Wire.write(2); // set minutes
  Wire.write(3); // set hours -- time should now be set to (3:02:01 am)
  Wire.write(1); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(4); // set date (1 to 31)
  Wire.write(5); // set month
  Wire.write(6); // set year (0 to 99) --- date should now be set to May 4th, 2006 -- remember DS3231 expects BCD
  Wire.endTransmission();
  Serial.println(" -- completed");

}

void loop()
{
  Serial.print("Begin read - ");
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  for (int i = 0; i < 7; i++) {
     Serial.print (Wire.read());   // read and display each byte, starting from seconds.  Not compensating for DS3231 BCD for this test.
     Serial.print (" - ");
  }
  
  Serial.println(" EOL");  
  
  delay(1000); // wait a second before repeating the read
}

the output on my serial monitor is:

Starting to set time --  -- completed
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
Begin read - -1 - -1 - -1 - -1 - -1 - -1 - -1 -  EOL
......continues forever

Am I doing anything wrong here? I also find it strange that I’m getting 15 dashes on each output line when I expected 8.

Thanks for any help.
Jason

Are there 4.7K pullups to 5V on the SCL & SDA lines?

Check the data sheet - I think you also need to set the MSB of the seconds register to have it keep track of time. Maybe clear the but, I haven’t looked at that in a while.

Oracle:
The power light on the DS3231 module comes on.

I have a very simplified code

The power light only means there is power connected, and the wiring may still be wrong, so check SDA, SCL.

The code doesn't look very simple to me. You might get some saner help from here.

CrossRoads:
Are there 4.7K pullups to 5V on the SCL & SDA lines?

Check the data sheet - I think you also need to set the MSB of the seconds register to have it keep track of time. Maybe clear the but, I haven't looked at that in a while.

Thanks for your reply.

This is the module I'm using

.

It has pullups on board for SCL and SDA.

I don't see anything in the data sheet about setting the MSB of the seconds register. The data sheet does say the oscillator is always enabled when the chip is powered from Vcc. But even if it wasn't keeping track of time, shouldn't I be able to read back the same time data I set?

Nick_Pyner:
The power light only means there is power connected, and the wiring may still be wrong, so check SDA, SCL.

The code doesn't look very simple to me. You might get some saner help from here.

http://bildr.org/2011/03/ds1307-arduino/

I do know what the power LED means, and it has nothing to do with how the rest of the board is wired. I'm not sure I follow the logic that could confuse someone about the meaning of the power LED. The pins are wired exactly as i said in my original post. I've also tried the module with multiple Arduinos. I have a DS1307 IC, crystal and caps I bought from a reliable score and assembled on a prototyping shield, and it works fine, it's just not accurate enough for my purposes.

In what way could my code be simpler? Your link is quite a bit more complicated as it tries to be a functional program and not simply see if the chip is working or not. Can you suggest a simpler way to test this chip than writing and reading a few bytes?

Run Nick Gammon's I2C Scanner which is at the bottom of this web page:

If it doesn't find the DS3231 address, you've got a wiring problem.

Pete

Try this code.
It was written for DS1307, the registers are the same.

/*
Test of RTC DS1307 via I2C.
 Counts 
 Seconds, 
 Minutes, 
 Hours, 
 Date of the Month, 
 Month, 
 Day of the week, and 
 Year with Leap-Year
 
 56 bytes battery backed RAM
 Square Wave Output
 
 11/17/2012- Updated for Wire.write & Wire.read commands
 1/18/13 - fixed unclear reference to 0x00
 */

/*
Modified to Run thru IDE Serial port
*/
#include <Wire.h>

//variables
byte zeroByte = 0;
byte seconds_address = 0x00;
byte seconds; // bit 7 = Clock Halt, Enabled = 0, Halt = 1
// bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9

byte minutes_address = 0x01;
byte minutes;  // bits 6-5-4 = tens of minutes, bits 3-2-1-0 = units of minutes

byte hours_address = 0x02; 
byte hours;  // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
// bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
// bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

byte day_week_address = 0x03; 
byte day_week = 0; // range 01-07

byte date_month_address = 0x04;
byte date_month = 0; // range 01-31

byte month_address = 0x05;
byte month = 0; // range 01-12

byte year_address = 0x06;
int year = 0; // upper byte 0-9, lower byte 0-9

byte square_address = 0x07;
byte sqwe = 0;  // square wave enable
// Out-0-0-Sqwe-0-0-RS1-RS0
// Out, Sqwe = 0/0 - Square wave output = 0
// Out, Sqwe = 1/0 - Square wave output = 1
// Out, Sqwe = 0/1 or 1/1 - Square wave output per RS1/RS0
// RS1/RS0 = 00 = 1 Hz
// RS1/RSo = 01 = 4 KHz
// RS1/RS0 = 10 = 8 KHz
// RS1/RS0 = 11 = 32 KHz

byte RTC_ram_address = 0x08; //range = 08-63, 0x08-0x3F

int RTC_address = 0x68; // 1101 000 

byte incomingCommand = 0;
byte RTC_write_command = 0;
byte RTC_read_command = 0;
byte RTC_ram_command = 0;

// use F0xx, F1xx,F2xx, F3xx, F4xx, F5xx, F6xx, F7xx
// to send one register write commands
// use E0xx to read registers back - not coded yet
// use C0xx to read RAM back - not coded yet

byte incomingRegister = 0;
byte RTC_register = 0;
byte incomingData1 = 0;
byte incomingData2 = 0;
byte new_data = 0;
byte outgoingData = 0;
int delay_time = 100;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long duration = 5000;

void setup() {
  Wire.begin(); // no address, we are master
  Serial.begin (57600);  
  Serial.flush();
  currentMillis = millis();  
}

void loop() {

  if (Serial.available() >3){
    incomingCommand = Serial.read();
    incomingRegister = Serial.read();
    incomingData1 = Serial.read();
    incomingData1 = incomingData1 - 0x30; // convert ASCII to HEX
    incomingData2 = Serial.read();
    incomingData2 = incomingData2 - 0x30;  // convert ASCII to HEX
    new_data = (incomingData1 << 4) + incomingData2;  // put the Upper/Lower nibbles together
    Serial.print ("command ");
    Serial.println (incomingCommand);
    Serial.print ("register ");
    Serial.println(incomingRegister);
    Serial.print ("data1 ");
    Serial.println (incomingData1, HEX);
    Serial.print ("data2 ");
    Serial.println (incomingData2, HEX);
    Serial.print ("combined data ");    
    Serial.println (new_data, HEX);
    
  }
  // *******************************************
//  RTC_write_command = incomingCommand & 0xF0;  // mask off high byte
//  if (RTC_write_command == 0xF0){  // check for Write command
if ((incomingCommand == 'F') | (incomingCommand == 'f')){
  incomingCommand = 0;  // reset for next pass
//    RTC_register = incomingCommand & 0x0F;  // mask off low btye
//    incomingCommand = 0;
//    new_data = incomingData;
    Serial.println (" Sending a command ");
//    switch (RTC_register){
switch (incomingRegister){
  case '0': // write seconds
        Serial.println ("Seconds ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(seconds_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
      delay (delay_time);
      break;
    case '1': // write minutes
    Serial.println ("Minutes ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(minutes_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
      delay (delay_time);
      break;
    case '2': // write hours
        Serial.println ("Hours ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(hours_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '3': // write day
        Serial.println ("Day ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(day_week_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '4': // write date of month
        Serial.println ("Day of Month ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(date_month_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '5': // write month
        Serial.println ("Month ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(month_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '6': // write year
        Serial.println ("Year ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(year_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '7': // write square wave
        Serial.println ("Square Wave ");
    Serial.println (RTC_register, HEX);
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(square_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '8': // write RAM
        Serial.print ("RAM ");
    Serial.println (RTC_register, HEX);
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(RTC_ram_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
      // all others,do nothing
      Serial.println ("Invalid command ");
    }  // end Switch
  } // end if command == 'F'
  // ************************************

  currentMillis = millis();
  if ( (currentMillis - previousMillis) >= duration){
    previousMillis = currentMillis;  
    // Reset the register pointer  
    Wire.beginTransmission(RTC_address);  
    Wire.write(zeroByte);  
    Wire.endTransmission();   

    Wire.requestFrom(RTC_address,8 );  
    seconds = Wire.read();  
    minutes = Wire.read();  
    hours = Wire.read();  
    day_week = Wire.read();  
    date_month = Wire.read();  
    month = Wire.read();  
    year = Wire.read();  
    sqwe = Wire.read();

    // Seconds 
    // bit 7 = Clock Halt, Enabled = 0, Halt = 1
    // bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9 

    // Hours
    // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
    // bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
    // bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

    Serial.print ("Hrs " );
    Serial.print (hours, HEX);
    Serial.print (" Mins ");
    Serial.print (minutes, HEX);
    Serial.print (" Secs ");
    Serial.print (seconds, HEX);
    Serial.print (" Day ");
    Serial.print (day_week, HEX);
    Serial.print (" Date ");
    Serial.print (date_month, HEX);
    Serial.print (" Month ");
    Serial.print (month, HEX);
    Serial.print (" Year 20");
    Serial.print (year, HEX);
    Serial.print (" Square Wave ");
    Serial.println (sqwe, HEX);

  }
}

Try this code.
It was written for DS1307, the registers are the same.
Outputs to serial port at 57600

/*
Test of RTC DS1307 via I2C.
 Counts 
 Seconds, 
 Minutes, 
 Hours, 
 Date of the Month, 
 Month, 
 Day of the week, and 
 Year with Leap-Year
 
 56 bytes battery backed RAM
 Square Wave Output
 
 11/17/2012- Updated for Wire.write & Wire.read commands
 1/18/13 - fixed unclear reference to 0x00
 */

/*
Modified to Run thru IDE Serial port
*/
#include <Wire.h>

//variables
byte zeroByte = 0;
byte seconds_address = 0x00;
byte seconds; // bit 7 = Clock Halt, Enabled = 0, Halt = 1
// bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9

byte minutes_address = 0x01;
byte minutes;  // bits 6-5-4 = tens of minutes, bits 3-2-1-0 = units of minutes

byte hours_address = 0x02; 
byte hours;  // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
// bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
// bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

byte day_week_address = 0x03; 
byte day_week = 0; // range 01-07

byte date_month_address = 0x04;
byte date_month = 0; // range 01-31

byte month_address = 0x05;
byte month = 0; // range 01-12

byte year_address = 0x06;
int year = 0; // upper byte 0-9, lower byte 0-9

byte square_address = 0x07;
byte sqwe = 0;  // square wave enable
// Out-0-0-Sqwe-0-0-RS1-RS0
// Out, Sqwe = 0/0 - Square wave output = 0
// Out, Sqwe = 1/0 - Square wave output = 1
// Out, Sqwe = 0/1 or 1/1 - Square wave output per RS1/RS0
// RS1/RS0 = 00 = 1 Hz
// RS1/RSo = 01 = 4 KHz
// RS1/RS0 = 10 = 8 KHz
// RS1/RS0 = 11 = 32 KHz

byte RTC_ram_address = 0x08; //range = 08-63, 0x08-0x3F

int RTC_address = 0x68; // 1101 000 

byte incomingCommand = 0;
byte RTC_write_command = 0;
byte RTC_read_command = 0;
byte RTC_ram_command = 0;

// use F0xx, F1xx,F2xx, F3xx, F4xx, F5xx, F6xx, F7xx
// to send one register write commands
// use E0xx to read registers back - not coded yet
// use C0xx to read RAM back - not coded yet

byte incomingRegister = 0;
byte RTC_register = 0;
byte incomingData1 = 0;
byte incomingData2 = 0;
byte new_data = 0;
byte outgoingData = 0;
int delay_time = 100;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long duration = 5000;

void setup() {
  Wire.begin(); // no address, we are master
  Serial.begin (57600);  
  Serial.flush();
  currentMillis = millis();  
}

void loop() {

  if (Serial.available() >3){
    incomingCommand = Serial.read();
    incomingRegister = Serial.read();
    incomingData1 = Serial.read();
    incomingData1 = incomingData1 - 0x30; // convert ASCII to HEX
    incomingData2 = Serial.read();
    incomingData2 = incomingData2 - 0x30;  // convert ASCII to HEX
    new_data = (incomingData1 << 4) + incomingData2;  // put the Upper/Lower nibbles together
    Serial.print ("command ");
    Serial.println (incomingCommand);
    Serial.print ("register ");
    Serial.println(incomingRegister);
    Serial.print ("data1 ");
    Serial.println (incomingData1, HEX);
    Serial.print ("data2 ");
    Serial.println (incomingData2, HEX);
    Serial.print ("combined data ");    
    Serial.println (new_data, HEX);
    
  }
  // *******************************************
//  RTC_write_command = incomingCommand & 0xF0;  // mask off high byte
//  if (RTC_write_command == 0xF0){  // check for Write command
if ((incomingCommand == 'F') | (incomingCommand == 'f')){
  incomingCommand = 0;  // reset for next pass
//    RTC_register = incomingCommand & 0x0F;  // mask off low btye
//    incomingCommand = 0;
//    new_data = incomingData;
    Serial.println (" Sending a command ");
//    switch (RTC_register){
switch (incomingRegister){
  case '0': // write seconds
        Serial.println ("Seconds ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(seconds_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
      delay (delay_time);
      break;
    case '1': // write minutes
    Serial.println ("Minutes ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(minutes_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
      delay (delay_time);
      break;
    case '2': // write hours
        Serial.println ("Hours ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(hours_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '3': // write day
        Serial.println ("Day ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(day_week_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '4': // write date of month
        Serial.println ("Day of Month ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(date_month_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '5': // write month
        Serial.println ("Month ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(month_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '6': // write year
        Serial.println ("Year ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(year_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '7': // write square wave
        Serial.println ("Square Wave ");
    Serial.println (RTC_register, HEX);
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(square_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '8': // write RAM
        Serial.print ("RAM ");
    Serial.println (RTC_register, HEX);
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(RTC_ram_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
      // all others,do nothing
      Serial.println ("Invalid command ");
    }  // end Switch
  } // end if command == 'F'
  // ************************************

  currentMillis = millis();
  if ( (currentMillis - previousMillis) >= duration){
    previousMillis = currentMillis;  
    // Reset the register pointer  
    Wire.beginTransmission(RTC_address);  
    Wire.write(zeroByte);  
    Wire.endTransmission();   

    Wire.requestFrom(RTC_address,8 );  
    seconds = Wire.read();  
    minutes = Wire.read();  
    hours = Wire.read();  
    day_week = Wire.read();  
    date_month = Wire.read();  
    month = Wire.read();  
    year = Wire.read();  
    sqwe = Wire.read();

    // Seconds 
    // bit 7 = Clock Halt, Enabled = 0, Halt = 1
    // bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9 

    // Hours
    // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
    // bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
    // bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

    Serial.print ("Hrs " );
    Serial.print (hours, HEX);
    Serial.print (" Mins ");
    Serial.print (minutes, HEX);
    Serial.print (" Secs ");
    Serial.print (seconds, HEX);
    Serial.print (" Day ");
    Serial.print (day_week, HEX);
    Serial.print (" Date ");
    Serial.print (date_month, HEX);
    Serial.print (" Month ");
    Serial.print (month, HEX);
    Serial.print (" Year 20");
    Serial.print (year, HEX);
    Serial.print (" Square Wave ");
    Serial.println (sqwe, HEX);

  }
}
Control Register (0Eh)
Bit 7: Enable Oscillator (EOSC). When set to logic 0,
the oscillator is started. When set to logic 1, the oscillator
is stopped when the DS3231 switches to VBAT. This
bit is clear (logic 0) when power is first applied. When
the DS3231 is powered by VCC, the oscillator is always
on regardless of the status of the EOSC bit. When
EOSC is disabled, all register data is static.

Got to write to the control register it seems, so things are different than the DS1307 somewhat.

el_supremo:
Run Nick Gammon's I2C Scanner which is at the bottom of this web page:
Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino

If it doesn't find the DS3231 address, you've got a wiring problem.

Pete

CrossRoads:
Got to write to the control register it seems, so things are different than the DS1307 somewhat.

I ran Nick Gammon's scanner. Much to my surprise, it found the the DS3231 at 0x68, and the EEPROM at 0x57. I thought the EEPROM was supposed to be at 0x50 since none of the address lines on the module are bridged, so that will save me some head scratching later.

After I ran the scanner, I re-ran the sketch I posted at the start of this thread. It's working perfectly. I haven't changed any wiring, all I did was run the port scanner and now the device is working.

I didn't do anything to write the control register, so I'm not sure why it started working after that.

Thank you very much for all the help.