This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

msp430F6721 RTC_C: using RTCPS1 for precise interval interrupt

Other Parts Discussed in Thread: MSP430F6736

msp430F6736

It appears that the RTC_C implementation in the msp430F6736 (and probably the 6721, which is another possible target for my development) is not as advertised in the MSP430 x5/x6 user guide.  Note that determining the features in the 6736 versus other devices in the x5/x6 line requires a debugging view of the RTC_C registers, as the device specific data sheet doesn't offer much clarity.

Specifically the RTC_C is operating in clock/calendar mode.  However, while RTC is running (and in LPM 3.5, too) I'd like it to generate an interrupt every 500 milliseconds.  It seems, from reading the user guide, that RTCPS1 can be used for this purpose.  The controlling register is called RTCPS1CTL in the documentation and, in the user guide this presents a 16 bit register.  However, in debug view, this register is truncated.  It presents the following:

RTCPS1CTL    0x0000    Real Timer Prescale Timer 1 Control [Memory Mapped]    
    RT1IP    000 - RT1IP_0    RTC Prescale Timer 1 Interrupt Interval Bit: 2    
    RT1PSIE    0    RTC Prescale Timer 1 Interrupt Enable Flag    
    RT1PSIFG    0    RTC Prescale Timer 1 Interrupt Flag    

Missing are the prescaler timer select, divide, and hold registers, RT1SSELx, RT1PSDIVx, and RT1PSHOLD.

So it appears I cannot use RTC_C to trigger an interrupt using RTCPS1 every 1/2 second, is this correct?

If this isn't possible, can the 32KHz clock at least drive another counter, which can then be divided to provide me this interrupt?

  • Mark Richards said:
    RTC_C is operating in clock/calendar mode.  [...]Missing are the prescaler timer select, divide, and hold registers, RT1SSELx, RT1PSDIVx, and RT1PSHOLD.

    From user guide:

    RT1SSELx RW 0h Prescale timer 1 clock source select. Selects clock input source to the RT1PS
    counter. In real-time clock calendar mode, these bits are do not care. RT1PS
    clock input is automatically set to the output of RT0PS.
    RT1PSDIVx RW 0h Prescale timer 1 clock divide. These bits control the divide ratio of the RT0PS
    counter. In real-time clock calendar mode, these bits are don't care for RT0PS
    and RT1PS. RT0PS clock output is automatically set to /256. RT1PS clock
    output is automatically set to /128.
    RT1PSHOLD RW 1h Prescale timer 1 hold. In real-time clock calendar mode, this bit is don't care.

    Mark Richards said:
    So it appears I cannot use RTC_C to trigger an interrupt using RTCPS1 every 1/2 second, is this correct?

    Not in calendar mode. Only in timer mode.
    And this is strictly conforming to the users guide.

    Mark Richards said:
    can the 32KHz clock at least drive another counter, which can then be divided to provide me this interrupt?

    You can source ACLK or SMCLK from the crystal. And feed tehm into any tiemr which can provide you the required interrupt.

    E.g. XT->ACLK->TimerA0; TimerA0 running in up mode, CCR0 set to 16343 and CCR0 interrupt enabled for interrupt on TIMER0_A0_VECTOR every 500ms.

  • Only in timer mode. And this is strictly conforming to the users guide.

    Jens-Michael, thanks for pointing this out.  I read that section several times and totally missed it.  Perhaps a better statement in the documentation:

    RT1SSELx (Timer mode only)

    And I appreciate the suggestion for TIMER_A.

    In debugging this I set a hardware breakpoint to my RTC ISR at the RTCIV_RTCRDYIFG.  After setting up RTC, _EINT() is called.  However the breakpoint is not triggering.  And when I examine the RTC time registers, they are all 0x0000, even after I have set these.

    ISR and RTC setup code follows.  Any ideas?

    RTC ISR:

     // RTC Interrupt Service Routine
     #pragma vector=RTC_VECTOR
     __interrupt void rtc_isr(void)
     {
         switch (__even_in_range(RTCIV, 16))
         {
         case RTCIV_NONE: // No interrupts
             break;
         case RTCIV_RTCOFIFG: // RTCOFIFG
             break;
         case RTCIV_RTCRDYIFG: // RTCRDYIFG
             _DINT();
             P1OUT ^= 0x01; // Toggles P1.0 every second
             // write time to LCD
             WriteLCDDigit(RTCSEC & 0xF0, 2);
             WriteLCDDigit(RTCSEC & 0x0F, 1);
             _EINT();
             break;
         case RTCIV_RTCTEVIFG: // RTCEVIFG
             _DINT();
             __no_operation(); // Interrupts every minute
             _EINT();
             break;
         case RTCIV_RTCAIFG: // RTCAIFG
             __no_operation(); // Interrupts every alarm event
             break;
         case 14:
             break; // Reserved
         case 16:
             break; // Reserved
         default:
             break;
         }
     }

    RTC setup:

        // Unlock RTC_C module
        RTCCTL0_H = RTCKEY_H;

        // enable RTC interrupts fpr
        // 32KHZ fault, RTC event, RTC Alarm, RTC Ready (for safe read)
        RTCCTL0_L |= RTCOFIE | RTCTEVIE | RTCAIE | RTCRDYIE; // Enable RTC time event, alarm event, read ready interrupt

        // set RTC to BCD Mode; place in HOLD; place in Calendar mode
        // default source 32KHZ and RTC event is default to 1 minute
        RTCCTL1 |= RTCBCD | RTCHOLD | RTCMODE ;

        RTCSEC = 0x59; // Seconds = 0x55
        RTCYEAR = 0x2012; // Year = 0x2012 = 2012
        RTCMON = 0x12; // Month = 0x12 = December
        RTCDAY = 0x05; // Day = 0x05 = 5th
        RTCDOW = 0x03; // Day of week = 0x03 = Wednesday
        RTCHOUR = 0x23; // Hour = 0x23
        RTCMIN = 0x59; // Minute = 0x59

        // release hold; start RTC calendar
        RTCCTL1 &= ~(RTCHOLD);

        // write bogus to lock the registers
        RTCCTL0_H = 0;

    Writes to the RTCCTL0 and RTCCTL1 registers are seen using the debugger (viewing RTC_C registers).  However writes to set the RTC time (RTCSEC, RTCYEAR, ect) do not appear (the registers all stay at 0).  When I release the hold, run my program for a few seconds, and then look at the registers, they are still at 0. 

    It seems the RTC is not running, even as I have set it.

  • It looks like you do not properly unlock the RTC registers. (se chapter 24.2.4 of the users guide).

    What value does RTCKEY_H have? double-check the header-file. It should be 0xa5 but maybe it is 0xA500. Which is good for OR'ing it to the other config bits in a write to RTCCTL0 (16 bit write) but not suitable for writing it to RTCCTL0_H (8 bit write).

  • It looks like you do not properly unlock the RTC registers. (se chapter 24.2.4 of the users guide).

    The register RTCCTL0_H is defined as 

    SFR_8BIT(RTCCTL0_H)

    RTCCTL0_H appears to be the high byte of RTCCTL0.

    My unlock key RTCCTL0_H, right from the provided msp430f6736.h header file shows

    #define RTCKEY_H               (0xA5)         /* RTC Key for RTC write access (high word) */

    This seems to be correct, because, for example, when in debug I see that these statements:

        // enable RTC interrupts fpr
        // 32KHZ fault, RTC event, RTC Alarm, RTC Ready (for safe read)
        RTCCTL0_L |= RTCOFIE | RTCTEVIE | RTCAIE | RTCRDYIE; // Enable RTC time event, alarm event, read ready interrupt

        // set RTC to BCD Mode; place in HOLD; place in Calendar mode
        // default source 32KHZ and RTC event is default to 1 minute
        RTCCTL1 |= RTCBCD | RTCHOLD | RTCMODE ;

    change the registers as they are intended to.  Only these:

    RTCSEC = 0x55; // Seconds = 0x36
    RTCYEAR = 0x2011; // Year = 0x2011 = 2011
    RTCMON = 0x12; // Month = 0x12 = December
    RTCDAY = 0x05; // Day = 0x05 = 5th
    RTCDOW = 0x03; // Day of week = 0x03 = Wednesday
    RTCHOUR = 0x24; // Hour = 0x12
    RTCMIN = 0x59; // Minute = 0x57

    have no effect whatsoever on these registers.

    Might it have something to do with UCS?

    void SetupUCS(void)
    {
        // These all work out to UCSCTL6 == 0x81CC
        // turn ON XT1
        UCSCTL6 &=~XT1OFF;
        // turn ON SMCLK
        UCSCTL6 &=~SMCLKOFF;
        // xcap 3
        UCSCTL6 |= XCAP0 | XCAP1;
        // source internally
        UCSCTL6 &=~XT1BYPASS;
        // Low frequency mode
        UCSCTL6 &=~XTS;
        // Drive max
        UCSCTL6 |= XT1DRIVE0 | XT1DRIVE1;
        // xt2 off (does not matter for this CPU)
        UCSCTL6 |=XT2OFF;
        // xt2 source internal (does not matter for this CPU)
        UCSCTL6 &=~XT2BYPASS;
        // xt2 drive level lowest (does not matter for this CPU)
        UCSCTL6 &=~XT2DRIVE0;

        // set the bits for DCO mult (0x1378)
        UCSCTL0 =  MOD0 | MOD1 | MOD2 | MOD3 | DCO0 | DCO1 | DCO4 ;
        // select dco range 2 (poorly named register!)
        UCSCTL1 = DCORSEL1;

        // set FLL Loop Multiplier bits (0x001F)
        UCSCTL2 = 0x0000;
        UCSCTL2 = FLLN0 | FLLN1 | FLLN2 | FLLN3 | FLLN4;

        // set FLL Reference to XT1CLK and Ref Divider to /1
        UCSCTL3 = 0x0000;
        // set ACLK to XT1CLK (32kHz)
        UCSCTL4 = 0x0000;
        // set SELS to DCO Clock source
        UCSCTL4 |= SELS__DCOCLK;
        // set SELM to DCO Clock source
        UCSCTL4 |= SELM__DCOCLK;

        // set ACLK and SMCLK dividers to x/1
        UCSCTL5 = 0x0000;

        // enable conditional module requests for SMCLK, MCLK and ACLK
        UCSCTL8 |= SMCLKREQEN | MCLKREQEN | ACLKREQEN;

        do
        {
            // Clear XT2,XT1,DCO fault flags
            UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
            SFRIFG1 &= ~OFIFG; // Clear fault flags
            DelayUs(100);
        } while (SFRIFG1 & OFIFG); // Test oscillator fault flag

        UCSCTL6 &= ~(XT1DRIVE_1); // Xtal is now stable, reduce drive (0x818C)

        // Disable Supply Voltage Supervisor
        PMMCTL0_H = PMMPW_H; // PMM Password
        SVSMHCTL &= ~(SVMHE + SVSHE); // Disable High side SVS
        SVSMLCTL &= ~(SVMLE + SVSLE); // Disable Low side SVS

    }


  • I found this rather hidden in the RTC_C Registers introduction.

    The high-side SVS must not be disabled by software if the real-time clock feature is needed. When the
    high-side SVS is disabled, the RTC_C registers with LPM3.5 retention are not accessible by the CPU.

    Pfaff!!

    This critical item should be part of the overall description for both the SVS and the RTC (and anything else that is considered a dependency).

    Boy, the TI documentation seems to need some work to be more useful.

    /m

  • That's strange. Writes to the registers should take effect imemdiately. it's possible that you can see the write result only after RTCHOLD was cleared and the next clock cycle happened. In this case the debugger is simply not showing you the truth. YOu shoudl write soem code that reads the RTC registers and look at the result in the debugger.

    The RT0PS is directly sourced by the LFXT1 crystal and has no auto-fallback to REFO as ACLK has. (but has its own fault interrupt).

    If you have LFXT1 running (and you code seems to ensure that), the RTC should run.

    Well, I haven't use the RTC_C module myself. Only the RTC_A, whose clock system is a bit different.

  • Jens-Michael,

    Thanks very much.

    Perhaps you missed my last message.. the issue was that I had disabled the SVS.

    RTC registers setting OK now and they seem to be updating every 1 second, but I'm not getting my 1 second interrupt consistently, so tracking this down now.

    /m

  • Mark Richards said:
    Perhaps you missed my last message..

    Yes, I had already started replying when you wrote it and didn't notice it after sending.

    I guess, this SVS thing is because the RTC_C has the backup and LPM3.5 features and requires the high-side SVS signal for proper operation. If the SVS is off, the RTC 'thinks' it is in LPM and disables the CPU interface for these registers.

    The 1s interrupt should come consistently. What exactly do you observe?

    (I only use the RTC_A and in counter mode as a timebase for preemptive multitasking. For RTC, I always use an external I2C chip with buffer cap. The standard code for this works for all my MSPs)

  • Jens-Michael,


    Yes, that's exactly what I observe so far.. consistent 1 second interrupts.  However I have not switched to LPM3.5 yet.

    When LPM3.5 is enabled, and according to what I read, I'll lose may of the RTC_C registers.  Some testing is about to occur so I can see how this may gum up the works.

    /m

  • Mark Richards said:
    I'll lose may of the RTC_C registers

    AFAIk, you'll lose all of the control registers. But the old settings are still in effect until you 'unlock' the LPM5 control bit. So you have to completely re-configure the RTC (and everything else) after waking from LPM3.5 and then unlock the LPM5 control bit. The counter registers, however, are a bit different as they are completely kept in working (counting) state and sewered from the CPU access instead. While all others are discarded on LPM3.5 but sewered from the circuits they control.

  • i have some problem in RTC_C. in my program after  writing the values in  RTC_C register my program enter into LPM3. but it disable the CPU and Global interrupt.

    this my code for writing values in RTC_C.

    void RTC_write()
    {
        RTCCTL0_H = RTCKEY_H;                   // Unlock RTC_C module    
        RTCCTL0_L |= RTCRDYIE;                  // read ready interrupt
        RTCCTL1 |=RTCBCD | RTCHOLD;             // RTC hold
        RTCHOUR = HEX_TO_BCD(Hrs);              // Hour
        RTCMIN = HEX_TO_BCD(Minute);            // Minute
        RTCCTL1 &= ~(RTCHOLD);                  // Start RTC calendar mode
        RTCCTL0_H =0;  
        return;
    }

    after this

     while(1)
        {
           __low_power_mode_3();          // Enter Low power mode 3
         LCD_Display(TANK_LEVEL);
         control_logic();
        }
    }

  • I don't understand what your problem is.

    The code you posted doesn't show where or when or whether RTC_write is called.
    And yes, in the while loop, the CPU enters LPM3. Whether anything was configured to ever wakeup from LPM again is unknown.

    With the information posted, I can't tell anyting.

  • hey i m facing the problem in writing in the registers of RTC_C. in single step debug it will not modify anything it will give 0000 for any value.

    and my program is not going in ISR also... So is there can anyone help me in this...

    I cant find my fault either it is in initialization or it is in hardware..

    my code is:

    #include <msp430.h>

    int main(void)
    {
        WDTCTL = WDTPW | WDTHOLD;               // Stop WTD

        // Initialize LFXT1
        UCSCTL6 &= ~(XT1OFF);                   // Enable XT1
        UCSCTL6 |= XCAP_3;                      // Internal load cap

        // Loop until XT1, XT2 & DCO fault flag is cleared
        do
        {
            UCSCTL7 &= ~(XT2OFFG | XT1LFOFFG | DCOFFG);
            // Clear XT2,XT1,DCO fault flags
            SFRIFG1 &= ~OFIFG;                  // Clear fault flags
        } while (SFRIFG1 & OFIFG);              // Test oscillator fault flag

        P1OUT &= ~BIT0;                         // Clear P1.0 output
        P1DIR |= BIT0;                          // Set P1.0 as output

        // Configure RTC_C
        RTCCTL0_H = RTCKEY_H;                   // Unlock RTC_C module
        RTCCTL0_L |= RTCTEVIE | RTCAIE | RTCRDYIE; // Enable RTC time event, alarm event,
                                                // read ready interrupt
        RTCCTL1 |= RTCBCD | RTCHOLD;            // RTC enable BCD mode, RTC hold

        RTCYEAR = 0x2011;                       // Year = 0x2011 = 2011
        RTCMON = 0x12;                          // Month = 0x12 = December
        RTCDAY = 0x05;                          // Day = 0x05 = 5th
        RTCDOW = 0x03;                          // Day of week = 0x03 = Wednesday
        RTCHOUR = 0x24;                         // Hour = 0x12
        RTCMIN = 0x59;                          // Minute = 0x57
        RTCSEC = 0x55;                          // Seconds = 0x36

        RTCADOWDAY = 0x3;                       // RTC Day of week alarm = 0x2
        RTCADAY = 0x22;                         // RTC Day Alarm = 0x22
        RTCAHOUR = 0x23;                        // RTC Hour Alarm
        RTCAMIN = 0x45;                         // RTC Minute Alarm

        RTCCTL1 &= ~(RTCHOLD);                  // Start RTC calendar mode
        RTCCTL0_H = 0;                          // Lock RTC_C module

        __bis_SR_register(LPM3_bits | GIE);     // Enter LPM3 w/ interrupts
                                                // enabled
        __no_operation();
    }

    // RTC Interrupt Service Routine
    #pragma vector=RTC_VECTOR
    __interrupt void rtc_isr(void)
    {
        switch (__even_in_range(RTCIV, 16))
        {
            case RTCIV_NONE:                    // No interrupts
                break;
            case RTCIV_RTCOFIFG:                // RTCOFIFG
                break;
            case RTCIV_RTCRDYIFG:               // RTCRDYIFG
                P1OUT ^= 0x01;                  // Toggles P1.0 every second
                break;
            case RTCIV_RTCTEVIFG:               // RTCEVIFG
                __no_operation();               // Interrupts every minute
                break;
            case RTCIV_RTCAIFG:                 // RTCAIFG
                __no_operation();               // Interrupts every alarm event
                break;
            case RTCIV_RT0PSIFG:                // RT0PSIFG
                break;
            case RTCIV_RT1PSIFG:                // RT1PSIFG
                break;
            case 14: break;                     // Reserved
            case 16: break;                     // Reserved
            default: break;
        }
    }

**Attention** This is a public forum