3
\$\begingroup\$

This question is about understanding the functionality of RTCC alarm registers within one PIC family. While I am using 16LF19176, I believe this question relates to all RTCC modules in this family. I also should mention that I am maintaining someone else's code, I did not originally write it.

I am using the RTCC clock and it works properly. I have set up an alarm, giving me an interrupt, properly as expected, every 10 minutes.

The issue comes, when I want to change it to alarm every hour. I am sure it is my problem not understanding the documentation (which is quite short for this by the way).

I am first showing the working code for alarm every 10 minutes:

ALRMMTH = 0x1; // month 
ALRMWD = 0x2; // weekday // @todo: why is it 0x02?
ALRMDAY = 0x1; // day
ALRMHR = 0x0; // hours 
ALRMMIN = 0x09; // minutes
ALRMSEC = 0x5A; // seconds (it did not work with errata recommended 0x0A)

ALRMCON = 0x40 | (0x04<<2) // repeat indefinitely, alarm every 10 minutes

ALRMCONbits.ALRMEN = 1;

I wanted to change that for an alarm every hour. I assumed that just changing two lines of code would do it, but it doesn't:

ALRMHR = 0x01; // hours 
ALRMMIN = 0x00; // minutes

QUESTION 1: what to write into ALRMxx register(s) for an alarm every hour?

QUESTION 2: why is the weekday set to 0x02, or what does that do?

QUESTION 3: can someone clarify, why is it not a conflict of interest setting an alarm numbers versus telling how often the alarm happens in ALRMCON?

Thank you very much for your time!

UPDATE: I changed the code to @Paul's idea, but still did not wake after 1 hour (I am hoping to wake every whole hour, that is at xx:00:00). I did this code change:

ALRMCONbits.ALRMEN = 0;
ALRMRPT = 0xFF; // In order for alarm be 'sounding' repetitively, not just 255 times, remember to set the CHIME bit to '1' (in ALRMCON below).

ALRMMTH = 0x01; // month (probably this line does in my case nothing)
ALRMWD = 0x02; // weekday (probably this line does in my case nothing)
ALRMDAY = 0x01; // day (probably this line does in my case nothing)
ALRMHR = 0x00; // hours (probably this line does in my case nothing)
       
ALRMMIN = 0x00; // minutes // was 0x09 originally and woke every x10:00 minutes (10, 20, 30, ...)
ALRMSEC = 0x00; // seconds // I have a feeling I should return here my original 0x5A, which worked for every-10-min alarm

ALRMCON = 0x40 | (0x05<<2);
ALRMCONbits.ALRMEN = 1

UPDATE 2: See my answer, it looks like the Microchip Errata is wrong as well. The seconds alarm register must be set to a weird value of 0x5A in order to get an alarm at :00 seconds

\$\endgroup\$
0

2 Answers 2

4
\$\begingroup\$

While I am answering my own question, I must give big credit to @PaulGhobril, who led me to understand the code.

I want to help others to avoid sleepless nights when debugging this - I had to wait repeated hours to debug the hourly alarm.

There is an apparent bug in the PIC RTCC module, which sneaks up in a case you need any alarm at rounded time of xx:xx:00 seconds. It seems that both PIC documentation and Errata are wrong.

Normally you would think to set the ALRMSEC register to 0x00. Errata says to fix the bug, set it to 0x0A. Unfortunately, neither works.

The solution is to set the SECONDS alarm register to value of 0x5A (which is in 'RTC-language' same as saying 5-10, in other words one more than 59).

Below I give few examples clarifying this. Remember these basic steps before setting an alarm:

  • enable writing to RTC via RTCWREN register
  • disable alarms via ALRMEN register
  • set how many alarms you need via ALRMRPT register (if infinite, set it to 0xFF and later you must also set the CHIME bit in ALRMCON register)
  • set the desired alarm time in such a way, that minutes are 1_second_before_the_alarm, and the seconds are '1_second_after_the_alarm' (see below examples)
  • set the alarm desired frequency in ALRMCON register (upper bit must be set to enable the alarms)
  • avoid writing to RTC via RTCWREN register
  • clear interrupt flag before enabling interrupts

The 'secret' of the solution is in setting the value of the ALRMMIN and ALRMSEC registers:

/*
 * Error in both MCU and ERRATA documents:
 * If the alarm shall occur at :00 seconds -> ERRATA asks for 0x0A, but it has to be 0x5A!
 * 
 * EXAMPLES:
 *     For an alarm every minute on the minute, write       xx:xx:5A (HRS/MIN/SEC) // wakes at xx:00:00, xx:01:00, xx:02:00, xx:03:00, ...
 *     For an alarm every 10-minutes, write                 xx:09:5A (HRS/MIN/SEC) // wakes at xx:00:00, xx:10:00, xx:20:00, xx:30:00, ...
 *     For an alarm every hour on the hour, write           xx:59:5A (HRS/MIN/SEC) // wakes at x0:00:00, x1:00:00, x2:00:00, x3:00:00, ...
 *     For an alarm every hour at 01-minute, write          xx:00:5A (HRS/MIN/SEC) // wakes at x0:01:00, x1:01:00, x2:01:00, x3:01:00, ...
 * 
 * 0x5A is in BCD as five-ten (5-10), replacing the expected 5-9 (decimal "59" on the clock)
 * Likely the rollover mechanism in the PIC has this simple bug, that to get the rollover impulse the last digit needs ten instead of nine.
 */
ALRMMIN = 0x59; // minutes
ALRMSEC = 0x5A; // seconds

/*
 * Alarm control register
 */
ALRMCON = ALRMCTRL__REPEAT_INDEFINITELY | ALRMCTRL__EVERY_HOUR;

/*
 * Enable the alarm 
 */
ALRMCONbits.ALRMEN = 1;
\$\endgroup\$
3
  • \$\begingroup\$ Interesting! I wonder how did you find it? did you try any other value like 1A? I checked the ERRATA and it is important to note here what it indicates: 6.1 Real Time Clock and Calendar (RTCC) Alarm When using the RTCC alarm function in any mode other than AMASK<3:0> = 0b0000 or AMASK<3:0> = 0b0001, an alarm will not occur if the lower nibble of the ALRMSEC register, ALRMLSEC <3:0>, is configured to 0x0. Work around If an alarm is desired when the lower nibble of the SECONDS register = 0x0, configure ALRMLSEC<3:0> = 0xA. \$\endgroup\$ Commented Sep 9, 2020 at 5:34
  • \$\begingroup\$ @Paul: yes it says 0x0A. I had to put 0x5A, but than it comes next minute. So you remove one minute from the desired alarm, see my 4 tested example lines above \$\endgroup\$ Commented Sep 9, 2020 at 5:38
  • \$\begingroup\$ Thank you, I was about to lose my sanity over why I couldn't get the alarm to fire every minute... \$\endgroup\$
    – Ozbekov
    Commented Dec 4, 2020 at 19:03
2
\$\begingroup\$

First, I wonder how the 10 minutes alarm is working with ALRMCON = 0x40 | (0x04<<2) while it should be ALRMCON = 0xC0 | (0x04<<2) since in the first case the alarm is disabled (bit 7 of ALRMCON enables the alarm).

Then to get it to work for every hour what you should change first is AMASK in ALRMCON from 04 to 05 and so ALRMCON = 0xC0 | (0x05<<2)

To know how to configure ALARMXX depending on the alarm recurrence just follow the following figure in the datasheet:

enter image description here

for every ten minutes what only counts is m and ss

for every hour what only counts is mm and ss

ALARMDAY is for the case where you choose an alarm for every week and it represents the day of the week (like Tuesday).

To set the number of alarms for a limited value you must set CHIME to 0 (for instance ALRMCON = 0x80 | (0x04<<2)) and set ALRMRPT to the number of times you want the alarm to be repeated.

Finally, 0A and 5A are not BCD while monthes, days, hours, minutes and seconds are BCD coded.

\$\endgroup\$
7
  • \$\begingroup\$ Thank you Paul: 1) I edited my question, the top bit is set just after my snippet, at the end of initialization function. Yes, your observation is correct, but that was not my problem. 2) I admit I did not read the Figure 24-5 correctly until you explained it, you helped me with that, thank you \$\endgroup\$ Commented Sep 8, 2020 at 15:19
  • \$\begingroup\$ QUESTION 1 and 3: Paul explained, that that crucial part is the ALRMCON register to be set in my case to every hour, and ONLY THEN to use Figure 24-5 to identify, which of the BCD coded digits are considered by the RTCC. I though always all the bits are considered, but in my 'every hour' case only mm:ss has to be set by my code: Paul, am I correct, if I want alarm every hour at xx:00:00 that I have to set them both to 0x00? ALRMMIN = 0x00; // minutes ALRMSEC = 0x00; // seconds Maybe write it to your answer text, as that was my Question 1 :) \$\endgroup\$ Commented Sep 8, 2020 at 15:26
  • \$\begingroup\$ Yes that's it. Please try it and if you still have problems maybe I can help. \$\endgroup\$ Commented Sep 8, 2020 at 15:33
  • \$\begingroup\$ still no go... Please see my question update above, where I posted my changed code. There is no wakeup after 1 hour. My colleague says that there is a bug in PIC and that for 'seconds' I must set this weird 0x5A in order to wake at xx:00 seconds? I am going to try that now \$\endgroup\$ Commented Sep 8, 2020 at 16:55
  • 1
    \$\begingroup\$ did you consider the following from the datasheet: 24.1.2 WRITE LOCK To perform a write to any of the RTCC timer registers, the RTCWREN bit must be set. To avoid accidental writes to the timer, it is recommended that the RTCWREN bit is kept clear at any other time. \$\endgroup\$ Commented Sep 8, 2020 at 17:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.