Setting Trickle Charge on DS1302

The DS1302 will trickle-charge a Supercap for backup power, but not in its supplied state - it needs a register value changing in order to do this - as noted in the datasheet

Has anyone managed this?

I can change other register values, but the Trickle byte (write address=0x90, read address=0x91) either won’t change or won’t report its value. Any suggestions on what I am doing wrong?

Demonstration sketch:

//written for Uno R3

#include <Time.h>
#include <DS1302RTC.h> //http://playground.arduino.cc/uploads/Main/DS1302RTC.zip
const byte tcOption[]={B11110000,B10100101,B10100110,B10100111,B10101001,B10101010,B10101011,B00111010};
const int kCePin   = 5;  // Chip Enable
const int kIoPin   = 6;  // Input/Output
const int kSclkPin = 7;  // Serial Clock

DS1302RTC my1032rtc(kCePin, kIoPin, kSclkPin);


void setup() {
  Serial.begin(9600);
  //initialise RTC to be writeable but clock stopped (doesn't make a difference)
  my1032rtc.writeEN(1);
  my1032rtc.haltRTC(1);
  
  //First, demonstrate that I can change a register value: modify the YEAR value in the RTC - this WORKS
  
  byte currentByte_RTCyear=my1032rtc.readRTC(0x8d);
  Serial.print("currentByte_RTCyear=");
  Serial.println(currentByte_RTCyear);
  //now set it to a different value
  if (currentByte_RTCyear==B11110000){
    my1032rtc.writeRTC(0x8c,B10100101);
  } else {
    my1032rtc.writeRTC(0x8c,B11110000);
  }
  byte updatedValue_RTCyear=my1032rtc.readRTC(0x8d);
  Serial.print("updatedValue_RTCyear=");
  Serial.println(updatedValue_RTCyear);
  
  //Now, try changing the register for Trickle Charge settings - DOES NOT WORK

  byte startValue=my1032rtc.readRTC(0x91);
    Serial.print("TC - start value=");
    Serial.println(startValue);
    
  for (byte opt=0; opt<8; opt++){
    Serial.print("opt=");
    Serial.print(opt);
    Serial.print(": attempting to set to ");
    Serial.println(tcOption[opt]);
    
    my1032rtc.writeRTC(0x91,tcOption[opt]);
    
    byte newValue=my1032rtc.readRTC(0x91);
    Serial.print("newValue=");
    Serial.println(newValue);
  }
}
void loop() {}

Output:

currentByte_RTCyear=165
updatedValue_RTCyear=240
TC - start value=0
opt=0: attempting to set to 240
newValue=0
opt=1: attempting to set to 165
newValue=0
opt=2: attempting to set to 166
newValue=0
opt=3: attempting to set to 167
newValue=0
opt=4: attempting to set to 169
newValue=0
opt=5: attempting to set to 170
newValue=0
opt=6: attempting to set to 171
newValue=0
opt=7: attempting to set to 58
newValue=0

John Geddes
UK

You are writing to 0x91, that is the read address. The write address is 0x90.

Thanks for spotting that (apologies: a transcription error as I simplified the code for the forum)- but in fact it doesn't change the problem - changing the line to what it should have been:

my1032rtc.writeRTC(0x90,tcOption[opt]);

produces exactly the same output. The mystery continues.

John Geddes

JohnGeddes: (apologies: a transcription error as I simplified the code for the forum)

Definitely unwise. Because you might easily simplify away the error, then nobody can see it. Can you please post the entire, latest non-working code?

//written for Uno R3

#include <Time.h>
#include <DS1302RTC.h> //http://playground.arduino.cc/uploads/Main/DS1302RTC.zip
const byte tcOption[]={B11110000,B10100101,B10100110,B10100111,B10101001,B10101010,B10101011,B00111010};
const int kCePin   = 5;  // Chip Enable
const int kIoPin   = 6;  // Input/Output
const int kSclkPin = 7;  // Serial Clock

DS1302RTC my1032rtc(kCePin, kIoPin, kSclkPin);


void setup() {
  Serial.begin(9600);
  //initialise RTC to be writeable but clock STOPPED
  my1032rtc.writeEN(1);
  my1032rtc.haltRTC(1);
  
  //First, demonstrate that I can change a register value: modify the YEAR value in the RTC
  
  byte currentByte_RTCyear=my1032rtc.readRTC(0x8d);
  Serial.print("currentByte_RTCyear=");
  Serial.println(currentByte_RTCyear);
  //now set it to a different value
  if (currentByte_RTCyear==B11110000){
    my1032rtc.writeRTC(0x8c,B10100101);
  } else {
    my1032rtc.writeRTC(0x8c,B11110000);
  }
  byte updatedValue_RTCyear=my1032rtc.readRTC(0x8d);
  Serial.print("updatedValue_RTCyear=");
  Serial.println(updatedValue_RTCyear);
  
  //Now, try changing the register for Trickle Charge settings
  byte startValue=my1032rtc.readRTC(0x91);
    Serial.print("TC - start value=");
    Serial.println(startValue);
    
  for (byte opt=0; opt<8; opt++){
    Serial.print("opt=");
    Serial.print(opt);
    Serial.print(": attempting to set to ");
    Serial.println(tcOption[opt]);
    
    my1032rtc.writeRTC(0x90,tcOption[opt]);
    
    byte newValue=my1032rtc.readRTC(0x91);
    Serial.print("newValue=");
    Serial.println(newValue);
  }
}
void loop() {}

Maxim advised that my DS1302’s were fake. For the benefit of others, they appeared to set and maintain clock OK, but would not set the Trickle Charge byte (and presumably lacked the Trickle Charge circuitry).

I’ve knocked up a sketch that will try to set the Trickle Charge byte, reporting back on success or failure

//written for Uno R3
//Tests whether a DS1302 will process a change of the byte controlling Trickle Charge settings (if not, may be a fake)
//John Geddes, March 2015

#include <Time.h>
#include <DS1302RTC.h> //http://playground.arduino.cc/uploads/Main/DS1302RTC.zip
const byte tcOption[]={B11110000,B10100101,B10100110,B10100111,B10101001,B10101010,B10101011,B00111010};
const int kCePin   = 5;  // Chip Enable
const int kIoPin   = 6;  // Input/Output
const int kSclkPin = 7;  // Serial Clock

DS1302RTC my1032rtc(kCePin, kIoPin, kSclkPin);

void printPaddedBin(unsigned long thisValue, byte outputLength=8, boolean endLine=false){
  String thisString;
  String netString=String(thisValue,BIN);//no leading zeroes
  byte padCharsRequired=outputLength-netString.length();
  for (byte padCount=0; padCount<(padCharsRequired);padCount++){
    thisString.concat("0");
  }
  Serial.print(thisString);
  Serial.print(netString);
  if (endLine){
    Serial.println();
  }
}

boolean setTrickleCharging(DS1302RTC thisRTC, boolean setChargingOn, byte ohms=0, byte noDiodes=0){
  //returns True if the setting is done successfully (or value is already correct)
  byte tcByte=0;//default=OFF (anything other than 1010 in bytes 7 to 4 disables trickle charging)
  if (setChargingOn){
    tcByte=160; //B10100000 - sets to Enabled but leaves resistor and diode bits at zero: we will add to these as appropriate;
    switch (noDiodes){
      case 1:
        tcByte+=4; //bit 2
        break;
      case 2:
        tcByte+=8; //bit 3
        break;
      default:
        Serial.println("Error: if setting ON, need either 1 or 2 diodes selected");
        return false;
    }
    switch (ohms){
      case 2:
        tcByte+=1; //bit 0
        break;
      case 4:
        tcByte+=2; //bit 1
        break;
      case 8:
        tcByte+=3; //bits 1 AND 2
        break;
      default:
        Serial.println("Error: if setting ON, need either 2, 4 or 8 ohms selected");
        return false;
    }
  } else {
    //leave value as default which sets as Disabled
  }
  thisRTC.writeEN(1); //in case the write-protect bit was set

  byte startValue=thisRTC.readRTC(0x91);

  if (startValue==tcByte){
    Serial.print("Trickle-charge byte was already set to ");
    Serial.print(tcByte);
    Serial.print(", ie ");
    printPaddedBin(tcByte, 8, true);
    return true;
  }
  //if here, then we are changing the byte
  thisRTC.writeRTC(0x90,tcByte);
  byte newValue=thisRTC.readRTC(0x91);
  if (newValue==startValue){
    //see if we can change the YEAR byte (which works on both genuine and dud/fake chips)
    byte currentByte_RTCyear=thisRTC.readRTC(0x8d);
    //now set it to a different value
    byte revisedYearByte;
    if (currentByte_RTCyear==B11110000){
      revisedYearByte=B10100101;
    } else {
      revisedYearByte=B11110000;   
    }
    thisRTC.writeRTC(0x8c,revisedYearByte);
    byte updatedValue_RTCyear=thisRTC.readRTC(0x8d);
    if (updatedValue_RTCyear==currentByte_RTCyear){
      Serial.print("Error 2: appears to write OK but does not change existing byte values for either Trickle-charge Byte (0x90) or Year byte (0x8c)");
      return false;
    } else {
      if (updatedValue_RTCyear==updatedValue_RTCyear){
        thisRTC.writeRTC(0x8c,currentByte_RTCyear);//set the year byte back again
        Serial.print("Error 3: will update Year byte (0x8c) but not Trickle-charge Byte (0x90) - looks like you might have a fake or defective DS1302");
      } else {
        thisRTC.writeRTC(0x8c,currentByte_RTCyear);//set the year byte back again
        Serial.print("Error 4: will update Year byte (0x8c) but to the wrong value - looks like you might have a fake or defective DS1302");
      }
    }
  } else {
    if (newValue==tcByte){
      //Bingo!
      Serial.print("SUCCESS - trickle-charging byte changed to ");
      Serial.print(tcByte);
      Serial.print(", ie ");
      printPaddedBin(tcByte);
      return true;
    } else {
      Serial.print("Error 5 changes existing value, which was  ");
      Serial.print(startValue);
      Serial.print(" (");
      printPaddedBin(startValue);
      Serial.print(") to new value of  ");
      Serial.print(newValue);
      Serial.print(" (");
      printPaddedBin(newValue);
      Serial.print(") instead of desired value of  ");
      Serial.print(tcByte);
      Serial.print(" (");
      printPaddedBin(tcByte);
      Serial.print(")");
      return false;
    }
  }
}


void setup() {
  delay (5000);//time to open Serial Monitor
  Serial.begin(9600);
  //initialise RTC to be writeable but clock STOPPED
  my1032rtc.writeEN(1);
  my1032rtc.haltRTC(1);//in case this helps
  setTrickleCharging(my1032rtc,true,2,1);
}

void loop() {}

Would it be cool to share with us where the forgery came from?

eBay - item 291291526518 - in retrospect, a suspiciously low price (10 for £1.99).

Supplier: 100fys

John