Code Monkey home page Code Monkey logo

mcp7940's Introduction

License: GPL v3 Build Format Wiki Doxygen arduino-library-badge

MCP7940 library

Arduino library for accessing the Microchip MCP7940 real time clock. There are two versions of the RTC, MCP7940M and MCP7940N, which differ only in that the MCP7940N has a battery backup supply pin and keeps the clock running on power failure. The MCP7940N also has additional registers which store the timepoint of power failure and point in time when power was restored. In addition there are 3 more RTC chips, the MCP79400, MCP79401 and MCP79402 which are backwards compatible but include a special EEPROM storage for EUI address and these are also supported by this library

Overview

The MCP7940M, MCP7940N and MCP7940x datasheets describe the chip in detail. While there is no breakout board available for this RTC at the present time, it is not difficult to build into a project. The MCP7940 is available as a PDIP 8 pin which allows for easy use on a breadboard and the only additional parts necessary are a 32.768kHz crystal with 2 small capacitors (~6pF, depends upon circuit capacitance) and some pull-up resistors for the I2C data lines as well as for the multifunction pin, if that is to be used.

Features

Apart from performing as a real-time clock, the MCP4790 has 64 Bytes of SRAM storage available and features 2 separate alarms that can be set to be recurring or a single use. The alarm state can be checked using library functions or can pull down the the MFP (multi-function pin) for a hardware interrupt or other action. The MCP7940 allows for software trimming and the library has functions which support fine-tuning the RTC to increase accuracy.

Description

A detailed library description along with further details are available at the GitHub MCP7940 Wiki. This includes wiring information and sample sketches that illustrate the library and it's functionality.





Examples

Several example sketches exist and are documented on the Wiki pages

Example Program Description
SetAndCalibrate Set and Calibrate the RTC using various methods
SetAlarms Set Alarm 0 and Alarm 1
SquareWave Output a Square Wave
TestBatteryBackup Show how the battery backup can be used
AccessMemory Read and Write to the MCP7940 memory
RegressionTests Run regression test after changing library code

Documentation

The library and example programs have Doxygen documentation, whose output can be found at Doxygen Documentation

Supported Hardware

The following configurations have been compiled and/or tested. Travis-CI is used for automated continuous integration and testing.

Name Tested CPU Comments
Arduino UNO Yes ATMega328P
Arduino Mega Yes ATMega 2560
Arduino Micro Yes ATMega32U4
Arduino 1280 Yes ATMega1280
Arduino 328 Yes ATMega328
Arduino 168 Yes ATMega168

Zanshin Logo

mcp7940's People

Contributors

davidlehrian avatar per1234 avatar sv-zanshin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

mcp7940's Issues

RPI2040 using Wire1 instead of Wire

Hi,

I've tried your library on RPI2040. RPI2040 has 2pc of 2wire interfaces, and unfortunately the MCP7940 is connected to the i2c1 (Wire1) interface on my board, so it won't worked as Wire is hard wired in the library.
I've modified the code to be able to use Wire1 also. Now it can be set as an optional parameter to the MCP7940_Class constructor: MCP7940_Class MCP7940(&Wire1); // Create an instance of the MCP7940

Here are my modified files, include them in the next version if you find it useful:
MCP7940.cpp.txt
MCP7940.h.txt

One more problem:
It could be some configuration problem, but for some reason PlatformIO sees only and downloads version 1.2.0 of the library instead of the newest one.

MCP7940.adjust() freezing in main loop

Hello,

I'm finding that adjust() is working ok on initialisation in the setup() routine
however I have a menu-driven date and time input system to allow the user to
set their correct time. When I just use setTime() from the Arduino library it works
(at least sets the time locally) however if I use the the MCP7940.adjust(DateTime)
the system freezes. At the end of the menu input I have even hardcoded a value
to see if I can get it to work: MCP7940.adjust(DateTime(2020,9,9,18,19,20));
but that has the same problem.

It is strange that during setup I can adjust the date to any hardcoded value using on the
RTC but this doesn't help me allow the user to set their own date/time.

Any ideas would be appreciated,
thanks,
Stuart

Alarm problem

Hi
setting an alarm for the next day, this is not generated when alarmTypes is set to matchAll. I checked the code and it seems that the problem is in the setAlarm function because the MCP7940_RTCWKDAY is not set for the next day but remains set at the previous day.

thanks

calibrate can cause value overflow

calibrate() checks if the local variable int8_t trim goes out of bound of 130 and -130.
However a 8bit value cannot exceed [128,-127], so checking for an out of bound condition at this point is too late, since it already happened.

Affected lines of code:
https://github.com/SV-Zanshin/MCP7940/blob/0678a66569f9ea81a9d959c8c6cce5247a6916eb/src/MCP7940.cpp#L497 [...]
https://github.com/SV-Zanshin/MCP7940/blob/0678a66569f9ea81a9d959c8c6cce5247a6916eb/src/MCP7940.cpp#L511-L516

Fix:
I think the trim value should be changed to a uint16_t. calibrate(uint8_t) needs to be fixed accordingly too.

calibration sign

I believe this line:

int32_t SecDeviation = dt.unixtime()-now().unixtime();

needs to be this:

int32_t SecDeviation = now().unixtime()-dt.unixtime();

So that the sign of the trim is correct.

thanks

Working with ESP chips

Adding new begin() method for selectable pins of Wire library
To communicate ESP chips to MCP7940, we need to set up pins, which means we need to pass the number of GPIO to the MCP7940 class

Adding a new begin(SDA_PIN, SCL_PIN) method to the library
To connect the chips, in which i2C pins can be selected, a new method should be added to the library in both .h and .cpp files

Adding begin(SDA_PIN, SCL_PIN) header file
bool begin(int sda, int scl, const uint32_t i2cSpeed = I2C_STANDARD_MODE) const;

I have changed and tested your library with ESP chips and have attached them here.
MCP7940.zip

ATmega328PB & MiniCore incompatible??

I've before worked with this RTC with the ATmega328P and it worked great. Now I've build a board around the new ATmega328PB, using the MiniCore, and I'm running into some weird problems.

First I found out the battery backup doesn't work. My multimeter shows voltage at the VBAT pin (about 2.5V - a fresh 3V battery minus a diode drop) , but it doesn't keep the time over power cycles as it should.

Also I had to replace the simple MCP7940.adjust() calls with this:

char d[13];
strcpy_P(d, PSTR(__DATE__));
char t[13];
strcpy_P(t, PSTR(__TIME__));
DateTime dt = DateTime(d, t);
MCP7940.adjust(dt);                                                         // Set to library compile Date/Time //

This code works properly setting the time to the compile time Jan 22 2020 at 22:30:04; the adjust() function sets the time to "2075-01-30 32:50:50" (yes, hour 32! No idea how that is even possible). This accounts for both the TestBatteryBackup sketch and the SetAndCalibrate sketch.

As long as the power is up, the time runs just fine. So the chip appears to be in proper working order, and communicates as it should. The ATmega328PB itself runs at 18.432 MHz, Vcc = 5V.

signed integer handling in calibration methods

I tested your methods to calibrate by time deviation. As long as trim value is positive, everything is fine.

When I setup a deviation of -1 second and an ExpectedSec of 1 day (86400 secs), the first trim value is -10 what should be correct. I started a new calibration with the same deviation and ExpectedSec then, expecting a new trim value of -20 (Using positive values that is exacty what happened 10, 20, 30, ...).

Unfortunately the method calculated a new trim of 108, which is completely wrong obviously, followed by 98, 88, 78,...

While searching the reason I noticed that you simply write negative trim values to RTC what is invalid regarding to MCP7940 datasheet p. 29. As it is described there, the absolute value of trim must be saved in register bits [0-6]. Setting SIGN bit [7] to 1 will then result in adding this amount of clock cycles. (subtracting for 0 vice versa).

Therefore I suggest changing

int8_t MCP7940_Class::calibrate(const int8_t newTrim) {                     
int8_t trim = newTrim;                                    // Make a local copy                        //
if (trim < 0) {                                                   // if the trim is less than 0, then      //
    trim = 0x80 | (trim * -1);                             // set non-excess 128 negative val  //
}

to

int8_t MCP7940_Class::calibrate(const int8_t newTrim) {                 
    uint8_t trim = abs(newTrim);                       // Get abs                                        //
    if (newTrim < 0)                                           // if the trim is less than 0, then     //
    {                                                             
        trim = 0x80 | trim;                                   // SET SIGN Bit to add clock cycles //
    }

And

int8_t MCP7940_Class::calibrate(const DateTime& dt) {
  ...
  if (trim >> 7) {                                                 // use negative value if necessary  //
      trim = trim * -1;                                               
  }
  ...

to

int8_t MCP7940_Class::calibrate(const DateTime& dt) {
  ...
  if (trim >> 7)                                                    // if SIGN Bit is set               //
  {              
      trim = (~0x80 & trim) * -1;                          // Clear SIGN Bit and make negative //
  }
  ...

These changings seem to lead in the expeced behaviour.

Test changes with MCP7940

Ensure Regression tests and that the new functionality in #16 works as specified. Need to dig out an unused MCP7940 and put together a test bench for this.

Cancel a setAlarm

Hi
for particular project i need to cancel a setAlarm setting. For example i set a alarm, but in a specific condition is possible to cancel the alarm settings so that this is not generated?

Thanks

setAlarm overwrites AlarmPolarity bit

If setAlarmPolarity(1) is called before setting an alarm through setAlarm() the polarity will be forced to zero again.
I don't think this is intended, since changing the polarity after setting up the alarm can cause the MFP to have the wrong polarity for the first few us.

Affected line of code:
https://github.com/SV-Zanshin/MCP7940/blob/0678a66569f9ea81a9d959c8c6cce5247a6916eb/src/MCP7940.cpp#L592

Fix: also keep the polarity bit. I also force the dow to be only 3 bit long to prevent an accidental overwrite.

    uint8_t wkdayRegister = readByte(MCP7940_ALM0WKDAY + offset);             //                                  //
    wkdayRegister &= ((1 << MCP7940_ALM0IF) | (1 << MCP7940_ALMPOL));         // Keep pol and alm flag bit        //
    wkdayRegister |= alarmType << 4;                                          // Set 3 bits from alarmType        //
    wkdayRegister |= (dt.dayOfTheWeek() & 0x07);                              // Set 3 bits for dow from date     //

Maybe it would also be beneficial to be able to set the polarity right in the setAlarm() function with an additional optional paramter?

bool setAlarm(const uint8_t alarmNumber, const uint8_t alarmType, const DateTime dt, const bool state = true, const uint8_t polarity = 0);

MCP7940 how to set alarm to Day-of-the-week(1-7)

Hello,

Can anybody help me te set an alarm at a day of the week(1-7). I want to create an interrupt(MFP) on a day-of-the-week, other than just a day in the month. is that possible?

the line i am using is:

/*

  • AlarmType Description
    0 Alarms off
    1 Minutes match
    2 Hours match
    3 Day-of-Week matches
    4 Date matches
    7 Seconds, Minutes, Hours, Day-of-Week, Date and Month match
    */

MCP7940.setAlarm(0,3,DateTime(0,0,3,0,0,0));

kind regards,

Wim

SAMD21 board support

Hi Zanshin,

Nice job with the library. But It looks like the library doesn't compile for SAMD21 based boards such as Arduino M0, or adafruit Feather M0. I am not an expert, but I happen to be using these boards, not sure what is wrong...

BR.
Newerbee

I2C clock config uses uint16_t values

The constants and the function arguments for setting the I2C clock speed are uint_16t, but the actual values are out of range (100000, 400000), hence they are truncated (compiler throws a warning).

Fix:
in MCP7940.h line 72 & 73

#ifndef I2C_MODES                                                           // I2C related constants            //
  #define I2C_MODES                                                         // Guard code to prevent multiple   //
  const uint16_t I2C_STANDARD_MODE      =     100000;                       // Default normal I2C 100KHz speed  //
  const uint16_t I2C_FAST_MODE          =     400000;                       // Fast mode                        //
#endif  

line 185:

      bool     begin(const uint16_t i2cSpeed = I2C_STANDARD_MODE); 

in MCP7940.cpp line 231

bool MCP7940_Class::begin(const uint16_t i2cSpeed) {
...

change the uint16_t to uint32_t
Arduino Wire library expects an uint32_t passed to the setClock method.

ppm out of range

Another thought I was having about calibrate is with regard to the PPM being adjusted to be within the range -130 to 130. I know this is done to keep the trim from overflowing -127/127, but if the PPM is out of range then the time has gotten WAY off. For example ~34 min in 6 months or ~1.5 min a week will give a value of 130 ppm. If the clock is performing that poorly it is at the edge of being able to be corrected and if the value is significantly outside of that there is probably a problem with the chip/crystal/design. What might make more sense in that case would be to assume that the clock was simply wrong when the calibrate method was called. So I'm proposing a method that is calibrateOrAdjust (which I have already implemented) that would either calibrate the chip if the PPM is within range, or adjust the clock to be the correct value (I haven't contemplated if the trim should be zeroed out or not when the clock is adjusted, I'm thinking not, but maybe that is an optional flag passed in to the method).

This came up in my application as I was thinking about daylight savings time. I get the time passed in periodically and I use the passed in value to initially set the time if the oscillator isn't running or to calibrate the chip if the oscillator is running. But twice a year, because I haven't coded to adjust the clock for daylight savings time, the time passed in will be an hour off. This will create a PPM error of approx. 230 or -230 which will cause maximum trim values to be ADDED to or SUBTRACTED from the existing trim value which, as I continue looking at the code, will possibly cause the following line in calibrate to overflow if the previous trim value was not 0. There should probably be a check on the line

trim += ppm * 32768 * 60 / 2000000; // compute the new trim value

to prevent this.

And as I noted in my other post, the time will still be wrong since the time doesn't appear to be adjusted when the timer is calibrated.

'BUFFER_LENGTH' was not declared in this scope

In file included from C:\Users\Donald\Documents\Arduino\libraries\MCP7940\examples\SquareWave\SquareWave.ino:37:0:

C:\Users\Donald\Documents\Arduino\libraries\MCP7940\src/MCP7940.h: In member function 'uint8_t& MCP7940_Class::readRAM(uint8_t, T&)':

C:\Users\Donald\Documents\Arduino\libraries\MCP7940\src/MCP7940.h:238:17: error: 'BUFFER_LENGTH' was not declared in this scope

       if (i%BUFFER_LENGTH==0) {                                           // Read I2C again on buffer boundary//

Bit Mask hour register

hi
in your code the mask bit for the hour register is 7F

from DateTime MCP7940_Class::now()

_hh = bcd2int(Wire.read() & 0x7F);

the correct mask should be 0x3F because the bit6 set the 12/24 format and should be exclude it

the mask bit is present in the follow functions
DateTime MCP7940_Class::now()
DateTime MCP7940_Class::getPowerDown()
DateTime MCP7940_Class::getPowerUp()

regards
Marco

ESP8266 (Generic Module)

MCP7940-master/MCP7940.h:176:19: error: extra qualification 'MCP7940_Class::' on member 'readRAM' [-fpermissive]

     uint8_t&  MCP7940_Class::readRAM(const uint8_t addr,T &value) {       //                                  //

               ^

MCP7940-master/MCP7940.h:190:12: error: extra qualification 'MCP7940_Class::' on member 'writeRAM' [-fpermissive]

   bool MCP7940_Class::writeRAM(const uint8_t addr, const T &value) {      // the MCP7940 SRAM                 //

        ^

exit status 1
Error compiling for board Generic ESP8266 Module.

Observation about calibrate...

I'm looking at the two calibrate methods

int8_t MCP7940_Class::calibrate(const DateTime& dt)
and
int8_t MCP7940_Class::calibrate(const int8_t newTrim)

and am concerned that while the trim value gets set, the actual time is never adjusted. _SetUnixTime is updated to be the current unit time and the comment says "Store time of last change" but all that changed was the trim value. So if the clock was off, it will still be off and the next time calibrate is called the same trim value (assuming the clock was 100% accurate after the current trim) will be calculated and added to the trim throwing the trim off. I'm thinking that the time should be adjusted and _SetUnixTime set as soon as the trim value is calculated. What do you think?

hello guys,

hello guys,
In my case, i get the code stuck in "waiting for power" once i remove the VCC pin from 3.3V and get it back. I'm also attaching a CR2032 coin cell to VBAT pin.

Originally posted by @manaioussema in #45 (comment)

Add a regression test example program

Describe what the feature request is and if it solves an issue or adds functionality
At present there is no sketch for regression testing of new code and such a sketch should be added and documented

Describe the solution you'd like
Write a "RegressionTests.ino" sketch that calls up all functions in the library and determines, where possible, if the functions are working as expected.

Describe alternatives you've considered
n/a

Additional context
n/a

MCP7940.adjust() function reset the PWRFAIL and VBATEN

The adjust() function resets the RTCWDAY, PWRFAIL bit and VBATEN bit somehow; this function should only affect the WDAY2-WDAY0 bits?

So if you use a backup battery and multiple adjust() functions in the main loop, the battery will be disabled whenever you call the adjust() function moving forward.

DateTime(0) doesn't resolve correctly to the epoch

Expected Behavior

A DateTime object initialised to zero should resolve to the unix epoch, i.e. 1/1/1970 00:00:00

I'm trying to initialise the time component to 00:00:00. This seems the easiest way.

Actual Behavior

The actual output is 6/2/2106 6:28:16

Steps to Reproduce the Problem

Minimum reproducible code:

#include <MCP7940.h>

void setup() {
  Serial.begin(115200);

  DateTime dt1 = DateTime(0);
  // DateTime dt1(0); //  produces same result
  Serial.println(dt1.unixtime());
  Serial.print(dt1.day());
  Serial.print("/");
  Serial.print(dt1.month());
  Serial.print("/");
  Serial.print(dt1.year());
  Serial.print(" ");
  Serial.print(dt1.hour());
  Serial.print(":");
  Serial.print(dt1.minute());
  Serial.print(":");
  Serial.print(dt1.second());
  Serial.println();
}

void loop() {
}

Output is:

0
6/2/2106 6:28:16

If I construct the object as

DateTime dt1(1970, 1, 1, 0, 0, 0);

the output is:

2269013504
1/1/2178 0:0:0

Specifications

  • Library Version: 1.2.0
  • IDE Version: 1.8.13
  • Platform: Arduino Uno R3

alarm do not set when DOW is 0

hi
i have found a problem when i use the alarm function.
i use the mach_all_alarm and the mfp output do not generated when the date and the time corresponded at the dow = 0.
In the datasheet the day of the week is beetween 1 and 7 but the function dayOfTheWeek() in your library produce numbert beetween 0 and 6.

this code simulate the problem:

#include <MCP7940.h>
#include "LowPower.h"

MCP7940_Class MCP7940;
DateTime timing;
DateTime allarme;
DateTime prox;
DateTime prova;

byte alarmtype = 0;

enum alarmTypes { matchSeconds, matchMinutes, matchHours, matchDayOfWeek, matchDayOfMonth, Unused1, Unused2, matchAll, Unknown};


void wakeUp()
{
  //incrementa la variabile
  Serial.println("-------wakeUp-------");
  delay(100);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  MCP7940.begin();
  delay(500);
  MCP7940.setBattery(true);

  //set date time 
  MCP7940.adjust(DateTime(2018, 6, 17, 0, 53, 0));

  //retrivie date e time
  timing = MCP7940.now();
  Serial.print("NOW ");
  Serial.print(timing.day());
  Serial.print("/");
  Serial.print(timing.month());
  Serial.print("/");
  Serial.print(timing.year());
  Serial.print(" ");
  Serial.print(timing.hour());
  Serial.print(":");
  Serial.print(timing.minute());
  Serial.print(":");
  Serial.println(timing.second());

  //set alarm at 10 second from current time
  timing = timing + TimeSpan(0, 0, 0, 10);
  MCP7940.setAlarm(0, 7, DateTime(timing.year(), timing.month(), timing.day(), timing.hour(), timing.minute(), timing.second()));

  //verify if the allarm is set correctly
  allarme = MCP7940.getAlarm(0, alarmtype);

  Serial.print("ALLARME ");
  Serial.print(allarme.day());
  Serial.print("/");
  Serial.print(allarme.month());
  Serial.print("/");
  Serial.print(allarme.year());
  Serial.print(" ");
  Serial.print(allarme.hour());
  Serial.print(":");
  Serial.print(allarme.minute());
  Serial.print(":");
  Serial.println(allarme.second());
}

void loop() {

  delay(1000);

  attachInterrupt(digitalPinToInterrupt(2), wakeUp, LOW);

  //Serial.println("----POWER DOWN----");
  //Serial.println("");
  //Serial.flush();

  // Enter power down state with ADC and BOD module disabled.
  // Wake up when wake up pin is low.
  //LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);

  // Disable external pin interrupt on wake up pin.
  detachInterrupt(digitalPinToInterrupt(2));

  if (MCP7940.isAlarm(0)) {
    Serial.println("-------ALLARME-------");
    MCP7940.clearAlarm(0);

    prox = MCP7940.now();
    prox = prox + TimeSpan(1, 0, 0, 0);
    MCP7940.adjust(prox);

    prox = MCP7940.now();
    Serial.print("PROX ");
    Serial.print(prox.day());
    Serial.print("/");
    Serial.print(prox.month());
    Serial.print("/");
    Serial.print(prox.year());
    Serial.print(" ");
    Serial.print(prox.hour());
    Serial.print(":");
    Serial.print(prox.minute());
    Serial.print(":");
    Serial.print(prox.second());
    Serial.print(" WOD ");
    Serial.println(prox.dayOfTheWeek());

    timing = MCP7940.now();
    timing = timing + TimeSpan(0, 0, 0, 5);

    Serial.print("ALARM ");
    Serial.print(timing.day());
    Serial.print("/");
    Serial.print(timing.month());
    Serial.print("/");
    Serial.print(timing.year());
    Serial.print(" ");
    Serial.print(timing.hour());
    Serial.print(":");
    Serial.print(timing.minute());
    Serial.print(":");
    Serial.print(timing.second());
    Serial.print(" WOD ");
    Serial.println(timing.dayOfTheWeek());

    MCP7940.setAlarm(0, 7, DateTime(timing.year(), timing.month(), timing.day(), timing.hour(), timing.minute(), timing.second()));

  }
}

i have modified the dayOfTheWeek() function adding 1 at the result and my code run correctly

uint8_t DateTime::dayOfTheWeek() const {  
  uint16_t day = date2days(yOff, m, d); 
  return ((day + 6) % 7)+1; //add 1 at the result
} // of method dayOfTheWeek()

you could verify that
regards
Marco Lai

No need to wait after Wire.requestFrom()

In the file "MCP7940.cpp" there are while-loops with a timeout after the Wire.requestFrom. Those while-loops and those timeouts are not needed and can be removed.

When the Wire.requestFrom() returns, the I2C transaction has completely finished and the received data is waiting in a buffer in the Wire library.

To check if the I2C transaction was successful, you may compare the number of requested bytes to the number of bytes that have been received and are waiting in a buffer.

Wire.requestFrom( Wire.requestFrom(MCP7940_ADDRESS, (uint8_t)7);
if( Wire.available() == 7) {
  // good
} else {
  // fail
}

Wire.begin() is not called if ESP8266 is not defined

Code snippet below is from Line 250 of MCP7940.cpp. Both #if and #elif conditions are the same. Wire.begin() never gets called. if ESP8266 is not defined.

#if defined(ESP8266)
  Wire.begin(sda, scl);  // Start I2C as master device using the specified SDA and SCL
#elif defined(ESP8266)
  Wire.begin();  // Start I2C as master device
#endif

Changing `#elif defined(ESP8266)` to `#else` solves the issue.

  - Library Version: 1.2.0
  - Testing on Arduino Due

Question about int8_t MCP7940_Class::calibrate(const int8_t newTrim)...

I was looking though the code and saw something that looked odd to me. Lines 469 - 473 seem to be doing nothing. Here are the lines.

  int8_t trim = abs(newTrim);  // Make a local copy of absolute value
  if (newTrim < 0)             // if the trim is less than 0
  {
    trim = 0x80 | trim;                                // set non-excess 128 negative val
  }                                                    // of if-then value of trim is less than 0

A new variable trim is set equal to the absolute value of the passed in newTrim which makes bit 8 of trim 0. Then, if newTrim is negative trim is or'ed with 0x80 which flips bit 8 back to 1. I fail to see the point of this code. It seems to be setting bit 8 to 0 and then if it was originally 1 it sets it back to 1. Why not just use the passed in trim value directly?

Alarm problem #2

Hi
i have tested the new version but i have another issue. if i run the code:

#include <MCP7940.h>

MCP7940_Class MCP7940;
DateTime now;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  MCP7940.adjust(DateTime(2018, 04, 29, 23, 59, 45));
  MCP7940.setAlarm(1, 7, DateTime(2018, 04, 30, 0, 0, 10));

}

void loop() {
  // put your main code here, to run repeatedly:
  delay(1000);
  now = MCP7940.now();
  Serial.print(now.day());
  Serial.print("/");
  Serial.print(now.month());
  Serial.print("/");
  Serial.print(now.year());
  Serial.print(" ");
  Serial.print(now.hour());
  Serial.print(":");
  Serial.print(now.minute());
  Serial.print(":");
  Serial.println(now.second());

  if (MCP7940.isAlarm(0)) {
    Serial.print("Alarm0*");
    MCP7940.clearAlarm(0);
  }

the alarm is generated at 2018/04//30 0:0:0 but i expected the alarm at 2018/04//30 0:0:10

regards
Marco Lai

Bug in begin()

I think this line:

writeByte(MCP7940_RTCSEC,readByte(MCP7940_RTCHOUR)&B10111111);

Should be

writeByte(MCP7940_RTCHOUR,readByte(MCP7940_RTCHOUR)&B10111111);

Thanks for the project.

Autocalibration

Hi, I saw that you created the Square Wave Output function. The mcp7940 has two methods to be calibrated. One is what you have already implemented. the second is to measure the quartz frequency and correct the difference between the measurement and the nominal value.
Could you create a function that allows you to measure the frequency and calibrate the mcp7940?

rif datasheet equation 5-2 (calculating trim value from measured frequency)

How to obtain power failure date/hour

Hello !
First of all, thank you for this librairy !
In the documentation, it is said that the RTC memorize power outage time/ date and when the power comes back on, how do we obtain these times/dates ?

Optimize c++ code

Describe what the feature request is and if it solves an issue or adds functionality
Create a more robust and optimized library

Describe the solution you'd like
Apply some new c++ knowledge, particularly around making the library more rounded and robust and attempt to minimize the memory footprint

Describe alternatives you've considered
n/a

Additional context
n/a

Battery backup not working if power to micro-controller is cut

Or no clear example on how to do this properly.

BTW, thanks for making this library... it seems super thorough :-)

I have the TestBatteryBackup example working, and I can disconnect 3V to the MCP7940N and then reconnect and it keeps time fine... but if I pull power to the microcontroller, and re-connect, time is reset.

I though it was due to the
MCP7940.adjust();
Being called in start, but if I change that to look for the powerfail flag and and adjust based on the power restore time and clear the flag, it doesn't work.

Am I missing something here? The entire purpose of a battery backed RTC is to keep time when power to the main device is down, but I can't find any code setup that does this.

Thanks!
Seon
unexpectedmaker.com

Weekday changes after deviceStart causing alarm to not work

Expected Behavior

Actual Behavior

When the date and time is set using the Adjust() function, the weekday in the registry is sometimes not correct afterwards. For me this is mainly a problem because it causes the alarm to not work when using alarmType=0x7.

Steps to Reproduce the Problem

The problem only occurs in some chips. It seems some batches are more affected then others. This makes reproduction somewhat tricky. For issue 4 what I had to do to reproduce was:

  • Stop the oscillator
  • Set the day of the week to 4 or 5
  • Start the oscillator
  • Read the day of the week
  • The day of the week has changed

Specifications

  • Library Version: Current master
  • IDE Version:
  • Platform: esp-idf
  • Subsystem:
  • any other details needed to reproduce the problem

Add a new example program for MCP7940N power fail

Describe what the feature request is and if it solves an issue or adds functionality
the current "SimpleBatteryBackup.ino" program assumes that the Arduino remains powered up while power is removed from the MCP7940N. This is typically not the case in a real implementation, so another example program is needed to demonstrate power-up checking in the sketch.

Describe the solution you'd like
Create new example program

Describe alternatives you've considered
None

Battery backup

Hello
I have a problem. after setting the time and date in the mcp7940, if I remove main power to the RTC and after a few minutes, i give power to the RTC, the time and date are reset to 1/1/2001 0:0:0.
(the battery backup is connected and it is charged)
the time data is not retained in memory and is not increased!!

you can verify this

regards

readRAM has wrong return type

Expected Behavior

According to function header notes, the return type is a "Pointer to return data structure". This does not make sense as there is no data structure returned. The method behaviour is to populate the variable that is passed in by reference. E.g.:

uint32_t someValue;
rtc.readRam(0, someValue);

Upon execution, someValue contains the value read from RTC RAM.

Actual Behavior

Instead of returning a "pointer to return data structure", the function actually returns the number of bytes read by I2C_READ. However, I believe this is also incorrect: The return type of readRAM is defined as uint8_t&. This is a problem because it is returning a reference to the local variable i, which immediately goes out of scope, resulting in potentially undefined behaviour (generating appropriate compiler warnnings).

Steps to Reproduce the Problem

MCP7940 rtc;
rtc.begin();
uint32_t contents, temp;
temp = rtc.ramRead(0, contents);

Example Compiler Warning

src/rtc.cpp:38:51:   required from here
.pio/libdeps/esp-wrover-kit/MCP7940/src/MCP7940.h:284:13: warning: reference to local variable 'i' returned [-Wreturn-local-addr]
     uint8_t i = I2C_read((addr % 64) + MCP7940_RAM_ADDRESS, value);

Specifications

  • Library Version: 1.2.0 (latest available from PlatformIO)
  • IDE Version:
  • Platform: ESP32
  • Subsystem:

Comment

I believe the correct implementation would be:

  template <typename T>
  uint8_t readRAM(const uint8_t& addr, T& value) const {
    /*!
     @brief     Template for readRAM()
     @details   As a template it can support compile-time data type definitions
     @param[in] addr Memory address
     @param[in] value    Data Type "T" to read
     @return    Pointer to return data structure
    */
    return I2C_read((addr % 64) + MCP7940_RAM_ADDRESS, value);
  }  // of method readRAM()

This simply returns the number of bytes read, rather than a reference to the number of bytes read.

SetMFP never fails

SetMFP() should return false if pin is being used for square wave or alarm output. The statement to test the control register (line 538) is incorrect and never gives a true result (to cause function to return false) because of operator precedence ('&' is below equals/not equals test). It should be if ((registerValue & 0x70) != 0)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.