RTC control register being reset by Lora

I have a DS3234 RTC sharing SPI SCK/MOSI/MISO with a Lora board. Both are working fine but the RTC oscillator stops when Vcc is off and the RTC is on battery. That's because whenever Lora sends a packet, it resets the control register of the RTC to 255 (11111111).

The Lora board and antenna are about 4 inches from the RTC on a separate breadboard. If I don't send a Lora packet the RTC control register retains its value (195). This is enough to reset the RTC control register:

LoRa.beginPacket();
LoRa.print("");
LoRa.endPacket();

Would the register reset be caused by radio interference from the Lora board?

codebrane:
Would the register reset be caused by radio interference from the Lora board?

Its possible.

Could be a code or connection issue as well, but you have not provided either.

The code to read the RTC control register:

byte CBDS3234::getControlRegister() {
  digitalWrite(_chipSelectPin, LOW);
  SPI.transfer(READ_CONTROL_REGISTER);
  byte changedConfig = SPI.transfer(0x00);
  digitalWrite(_chipSelectPin, HIGH);
  return changedConfig;
}

works fine until

LoRa.beginPacket();

is called. Don't actually have to send anything. The RTC and Lora have different CS pins in code.

codebrane:
Don't actually have to send anything. The RTC and Lora have different CS pins in code.

So that we are clear, in your first post you said;

That's because whenever Lora sends a packet, it resets the control register of the RTC to 255 (11111111).
Would the register reset be caused by radio interference from the Lora board?

Are you now saying that you dont have to send or transmit a packet, and that just the use of;

LoRa.beginPacket();

Causes problems with the RTC ?

And you have still not provided a schematic ........................

Hi,
Can you post your complete code and a schematic please?
What model controller are you using?

Thanks.. Tom.. :slight_smile:

NodeMCU ESP8266-12E.

Apologies for the diagram and yes, it only takes comms with the Lora board to cause the control register of the RTC to go to 255 so perhaps it's wiring but the routing all looks fine.

I checked my code in case I hadn't set the RTC CS HIGH at some point but it's all fine.

The RTC sends 1Hz SQW:

void timeInterruptFunction() {
  timeTriggers++;
  if (timeTriggers < 5) { // every 10s flag to loop()
    return;
  }
  timeTriggers = 0;
  readSensors = true;
}

and the main loop acts on it:

void loop() {
// this gets the correct value of the RTC control register
cbDS3234->getControlRegister();

// comment this out and the RTC control register is fine
LoRa.beginPacket();

// this gets 255 from the RTC control register (should be 195)
cbDS3234->getControlRegister();
}

I disabled the interrupt from the RTC but it doesn't make any difference. Lora.beginPacket(); changes the RTC control register. There isn't anywhere in the Lora library that sets anything to 0xFF. It's as if the RTC CS is LOW and is receiving a register write but there isn't a register 0x8E (write to RTC control register) in the Lora chip so the Lora library would never write to the RTC register.

Are there no ground and power connections?

sorry about that. Both use 3V3 and GND pins next to the FLASH button via breadboard lines. So they both have the same GND connection.

In case I'm somehow reading from something else's register I put a check in setup() and the RTC control register is the 255 written there by LoRa.beginPacket(); Perhaps there's something wrong with the MCU.

Please post all your code, as requested in reply #4.

#include <SPI.h>
#include <LoRa.h>
#include "cbds3234.h"

void ICACHE_RAM_ATTR timeInterruptFunction();

#define LORA_SYNC_WORD 0xF3
#define LORA_CS_PIN D1 // GPIO5

CBDS3234* cbDS3234;

volatile uint32_t timeTriggers = 0;
int ds3234ChipSelectPin = D8; // GPIO15
int ds3234InterruptPin = D2; // SQW -> GPIO4

timeParameters timeValues = {
  00, // seconds
  30, // minutes
  9, // hour
  5,  // d Sun=1,Mon=2,Tue=3,Wed=4,Thu=5,Fri=6,Sat=7
  2, // date = 2nd
  4, // month = April
  21  // year = 2021
};

bool readSensors = false;

void setup() {
  Serial.begin(115200);
  while(!Serial) {;}
  delay(1000);

  LoRa.setPins(LORA_CS_PIN, -1, 0);
  if (!LoRa.begin(433E6)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
  LoRa.setSyncWord(LORA_SYNC_WORD);
  Serial.println("LoRa started!");

  cbDS3234 = new CBDS3234(ds3234ChipSelectPin, ds3234InterruptPin, &timeInterruptFunction);
  byte originalConfig = cbDS3234->init(CBDS3234::INTERRUPT_FREQUENCY_1HZ);
}

void loop() {
  // this is fine and return 195, 1110011
  byte controlRegister = cbDS3234->getControlRegister();
  Serial.print("controlRegisterLoop = ");
  Serial.print(controlRegister);
  Serial.print(",");
  Serial.println(controlRegister, BIN);

 if (readSensors) {
    cbDS3234->readDateAndTime(&timeValues);
    displayTime();
    readSensors = false;

   // this is fine again, 195
    controlRegister = cbDS3234->getControlRegister();
  Serial.print("controlRegisterLoop2 = ");
  Serial.print(controlRegister);
  Serial.print(",");
  Serial.println(controlRegister, BIN);
    

Serial.println("beginPacket");
LoRa.beginPacket();

  // this is broken now, returns 255
  controlRegister = cbDS3234->getControlRegister();
  Serial.print("controlRegisterLoop = ");
  Serial.print(controlRegister);
  Serial.print(",");
  Serial.println(controlRegister, BIN);


  }
}

void timeInterruptFunction() {
  // accurate to frequency of SQW that we chose
  timeTriggers++;
  if (timeTriggers < 5) { // every 10s flag to loop()
    return;
  }
  timeTriggers = 0;
  readSensors = true;
}

void displayTime() {
  Serial.print(cbDS3234->dayOfWeek(timeValues.dy));
  Serial.print(" ");
  Serial.println(cbDS3234->formattedDateAndTime(&timeValues));
}
#include "cbds3234.h"

const char* CBDS3234Days[] = {
  "Monday",
  "Tuesday",
  "Wednesday",
  "Thursday",
  "Friday",
  "Saturday",
  "Sunday"
};

static uint8_t convertValueIN(uint8_t value);
static uint8_t convertValueOUT(uint8_t value);

const int CBDS3234::INTERRUPT_FREQUENCY_1HZ = 1;
const int CBDS3234::INTERRUPT_FREQUENCY_1024KHZ = 2;
const int CBDS3234::INTERRUPT_FREQUENCY_4096KHZ = 3;
const int CBDS3234::INTERRUPT_FREQUENCY_8192KHZ = 4;
const int CBDS3234::INTERRUPT_FREQUENCY_OFF = 5;

// p14 control register
#define WRITE_CONTROL_REGISTER 0x8E
#define READ_CONTROL_REGISTER 0x0E

// p12 address map timekeeping registers
#define WRITE_TIME_REGISTER 0x80
#define READ_TIME_REGISTER 0x00

CBDS3234::CBDS3234(int chipSelectPin, int interruptPin, void (*sqwFunction)()) {
  _chipSelectPin = chipSelectPin;
  _interruptPin = interruptPin;
  _sqwFunction = sqwFunction;
}

byte CBDS3234::getControlRegister() {
  digitalWrite(_chipSelectPin, LOW);
  SPI.transfer(READ_CONTROL_REGISTER);
  byte changedConfig = SPI.transfer(0x00);
  digitalWrite(_chipSelectPin, HIGH);
  return changedConfig;
}

byte CBDS3234::init(int interruptFrequency) {
  SPI.begin();

  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1);
 
  pinMode(_chipSelectPin, OUTPUT);
  
  digitalWrite(_chipSelectPin, LOW);

  SPI.transfer(READ_CONTROL_REGISTER);
  byte originalConfig = SPI.transfer(0x00); // receive from READ_CONTROL_REGISTER
  digitalWrite(_chipSelectPin, HIGH);
  
  delay(10); // in case controller is too fast for chip

  byte configModifier;
  byte newConfig;

  if (interruptFrequency == CBDS3234::INTERRUPT_FREQUENCY_OFF) {
    // bit 6 BBSQW = 0
    configModifier = 0b10111111; // turn off bit 6 BBSQW
    newConfig = configModifier & originalConfig; // bitwise AND
  }
  else {
    uint8_t frequencyOption = interruptFrequency - 1; // now 0-3 instead of 1-4
    configModifier = (frequencyOption << 3) | 0b01000000;
    newConfig = configModifier | (originalConfig & 0b11100011);
  }

  digitalWrite(_chipSelectPin, LOW);
  SPI.transfer(WRITE_CONTROL_REGISTER);
  SPI.transfer(newConfig);
  digitalWrite(_chipSelectPin, HIGH);
  
  delay(10);

  attachInterrupt(digitalPinToInterrupt(_interruptPin), _sqwFunction, RISING);

  delay(10);

  digitalWrite(_chipSelectPin, LOW);
  SPI.transfer(READ_CONTROL_REGISTER);
  byte changedConfig = SPI.transfer(0x00);
  digitalWrite(_chipSelectPin, HIGH);

  return originalConfig;
}

void CBDS3234::setDateAndTime(timeParameters* timeValues) {
  pinMode(_chipSelectPin, OUTPUT);
  digitalWrite(_chipSelectPin, LOW);
  SPI.transfer(WRITE_TIME_REGISTER);
  SPI.transfer(convertValueOUT(timeValues->ss)); // write to 0x80
  SPI.transfer(convertValueOUT(timeValues->mm)); // write to 0x81
  SPI.transfer(convertValueOUT(timeValues->hh)); // write to 0x82
  SPI.transfer(convertValueOUT(timeValues->dy)); // write to 0x83
  SPI.transfer(convertValueOUT(timeValues->d));  // write to 0x84
  SPI.transfer(convertValueOUT(timeValues->m));  // write to 0x85
  SPI.transfer(convertValueOUT(timeValues->y));  // write to 0x86
  digitalWrite(_chipSelectPin, HIGH);
  delay(10);
}

void CBDS3234::readDateAndTime(timeParameters* timeValues) {
  pinMode(_chipSelectPin, OUTPUT);
  digitalWrite(_chipSelectPin, LOW);
  SPI.transfer(READ_TIME_REGISTER);
  // the chip will automatically increment the register to be read from to after each read
  timeValues->ss = convertValueIN(SPI.transfer(0x00)); // read from 0x80
  timeValues->mm = convertValueIN(SPI.transfer(0x00)); // read from 0x81
  timeValues->hh = convertValueIN(SPI.transfer(0x00)); // read from 0x82
  timeValues->dy = convertValueIN(SPI.transfer(0x00)); // read from 0x83
  timeValues->d = convertValueIN(SPI.transfer(0x00));  // read from 0x84
  timeValues->m = convertValueIN(SPI.transfer(0x00));  // read from 0x85
  timeValues->y = convertValueIN(SPI.transfer(0x00));  // read from 0x86
  digitalWrite(_chipSelectPin, HIGH);
  delay(10);
}

char* CBDS3234::formattedDateAndTime(timeParameters* timeValues) {
  static char dateAndTime[18] = {'\0'};
  snprintf(dateAndTime, sizeof(dateAndTime), "%02u/%02u/%02u %02u:%02u:%02u",
    timeValues->d,
    timeValues->m,
    timeValues->y,
    timeValues->hh,
    timeValues->mm,
    timeValues->ss
  );

  return dateAndTime;
}

String CBDS3234::dayOfWeek(uint8_t dayOfWeekFromDS3234) {
  return CBDS3234Days[dayOfWeekFromDS3234 - 1];
}

static uint8_t convertValueIN(uint8_t value) {
  uint8_t convertedValue = value - 6 * (value >> 4);
  return convertedValue;
}

static uint8_t convertValueOUT(uint8_t value) {
  uint8_t convertedValue = value + 6  * (value / 10);
  return convertedValue;
}
#ifndef  _CBDS3234_H
#define _CBDS3234_H

#include <Arduino.h>
#include <SPI.h>

typedef struct timeParameters {
  uint8_t ss; // seconds
  uint8_t mm; // minutes
  uint8_t hh; // hour
  uint8_t dy; // day
  uint8_t d;  // date
  uint8_t m;  // month
  uint8_t y;  // year
};

extern const char* CBDS3234Days[];

class CBDS3234 {
  int _chipSelectPin;
  int _interruptPin;
  void (*_sqwFunction)();
  
  public:
    CBDS3234(int chipSelectPin, int interruptPin, void (*sqwFunction)());

    byte getControlRegister();
    byte init(int interruptFrequency);
    void setDateAndTime(timeParameters* timeValues);
    void readDateAndTime(timeParameters* timeValues);
    String dayOfWeek(uint8_t dayOfWeekFromDS3234);
    char* formattedDateAndTime(timeParameters* timeValues);

    static const int INTERRUPT_FREQUENCY_1HZ;      // 1Hz
    static const int INTERRUPT_FREQUENCY_1024KHZ;  // 1.024KHz
    static const int INTERRUPT_FREQUENCY_4096KHZ;  // 4.096KHz
    static const int INTERRUPT_FREQUENCY_8192KHZ;  // 8.192KHz
    static const int INTERRUPT_FREQUENCY_OFF;      // OFF
};

#endif

I took the lora board off so there is only the RTC and saw the same odd behaviour now and then (255 in the RTC control register) so I suspect it's something to do with the wiring although LoRa.beginPacket(); with the lora board attached was reliable in putting it there. Perhaps it triggered a condition.

Then post images of your wiring, and a complete and accurate updated schematic. We can't guess what you might have done.

You might want to review the DS3234 'library', it does not appear to use SPI.beginTransaction(), which it should do if your mixing devices with different SPI modes.

thank you very much for that note about transactions. The DS3234 uses SPI_MODE1 whereas the LoRa uses SPI_MODE0. I'll read up on transactions and find a better way of creating schematics. I'm pretty new to this so thanks for the helpful advice.

I took it all back to basics and worked on the RTC on its own but it was still all weird, requiring the battery installed and registers that mostly returned zero. So it was back to the datasheet and something I'd missed the first time:

Active-Low Interrupt or Square-Wave Output

but I was enabling the interrupt on the rising edge. I presume that meant it was in constant interrupt mode. The following fixed the problem of not being able to manipulate the RTC registers:

pinMode(_interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(_interruptPin), _sqwFunction, FALLING);

and I added transactions to the SPI to deal with the LoRa board using a different SPI MODE from the DS3234.

Hi,
Good to see you have a solution.
Can you please post your working code or attach it so it will complete this thread?

Tom... :slight_smile:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.