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.
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.
Not in calendar mode. Only in timer mode.Mark Richards said:So it appears I cannot use RTC_C to trigger an interrupt using RTCPS1 every 1/2 second, is this correct?
You can source ACLK or SMCLK from the crystal. And feed tehm into any tiemr which can provide you the required interrupt.Mark Richards said:can the 32KHz clock at least drive another counter, which can then be divided to provide me this 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
Yes, I had already started replying when you wrote it and didn't notice it after sending.Mark Richards said:Perhaps you missed my last message..
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
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.Mark Richards said:I'll lose may of the RTC_C registers
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