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.
Hi guys
We are changing micro in our embedded systems MSP430F149 to MSP430F249. I have a function to read internal frequency of DCO oscillator and with this new micro dosen't work. No event capture happen if I have SMCLK with DCO. All it's ok if I use SMCLK with XT2CLK. Does anyone have any idea ?
This is my function.
//-----------------------------------------------------------------------------------------------
// GetDCOFreq
// Utilizza il TimerB e ACLK(32KHz) per misurare la frequenza del DCO (torna valore in Hz)
//-----------------------------------------------------------------------------------------------
LONG MSP430_GetDCOFreq()
{
BYTE SmclkFromXt2;
WORD n1,n2;
// Setta un flag se SMCLK è ricavato da XT2
if (BCSCTL2 & SELS) SmclkFromXt2=1; else SmclkFromXt2=0;
// Ricava il clock per SMCLK da DCO
BCSCTL2 &= ~SELS;
//BCSCTL2 |= SELS;
// Accende TimerB: conteggio continuo a 16 bit, clock = SMCLK
TBCTL = TBSSEL1 | MC1 | TBCLR;
// Capture da CC16B=ACLK, rising edge
TBCCTL6 = CM1 | CCIS0 | SCS | CAP;
// Attende il primo evento di capture
while ( (TBCCTL6 & CCIFG)==0 ) {};
// Memorizza valore attuale
n1 = TBCCR6;
// Azzera flag di capture e overflow
TBCCTL6 &= ~(COV|CCIFG);
// Attende il prossimo evento di capture
while ( (TBCCTL6 & CCIFG)==0 ) {};
// Memorizza valore attuale
n2 = TBCCR6;
// Se si e' verificato un overflow azzera il valore, se no calcola la differenza
if ( (TBCCTL6 & COV) != 0 ) n2=0; else n2=n2-n1;
// Ferma il TimerB
TBCTL = 0; TBCCTL6 = 0;
// Ripristina il clock a SMCLK da XT2 se necessario
if (SmclkFromXt2 != 0) BCSCTL2 |= SELS;
// Ritorna il valore calcolato in KHertz
return( (n2*32768L)/1000L );
}
Hi,
looking into your code, it seems that you are using CCI6B as input capture. Unfortunatelly this is not available in MSP430F249
This is the pin description of MSP430F249:
P4.6/TB6 42 I/O General-purpose digital I/O / Timer_B, capture: CCI6A input, compare: Out6 output
While for MSP430F149:
P4.6/TB6 42 I/O General-purpose digital I/O pin/Timer_B, capture: CCI6A or CCI6B input, compare: Out6 output
So try to change the TBCCTL6 setting to TBCCTL6 = CM1 | SCS | CAP.
I hope this helps you, otherwise please let me know.
-Leo-
Really thanks for the reply.
It's possible to use Timer6 with input capture syncronized with internal ACLK ( not only for external pin... ), and I must use it to read my DCO frequency. ( SLAS547H page 23 for detail )
Hi Kirkegaard,
ah, sorry for have mistaken your problem. So where is the problem actually? Could you please describe what you meant with "this code doesn't work"? Does it return wrong value?
-Leo-
Don't worry Leo thanks so much for the support, I read your e-mail to Riccardo.
"dosen't work" means that MSP430F249 micro is locked waiting first event capture.
...
while ( (TBCCTL6 & CCIFG)==0 ) {}; <--- dead lock
...
and there is nothing to do...
Hi Kirkegaard,
i tried to run your code using the following source:
#include <msp430f249.h> typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long LONG; LONG MSP430_GetDCOFreq(); void main(void) { volatile LONG result; WORD i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; // Wait for xtal to stabilize do { IFG1 &= ~OFIFG; // Clear OSCFault flag for (i = 0x47FF; i > 0; i--); // Time for flag to set } while ((IFG1 & OFIFG)); // OSCFault flag still set? // output ACLK, MCLK, SMCLK P5SEL |= BIT4 + BIT5 + BIT6; P5DIR |= BIT4 + BIT5 + BIT6; while(1) { result = MSP430_GetDCOFreq(); __no_operation(); } } //----------------------------------------------------------------------------------------------- // GetDCOFreq // Utilizza il TimerB e ACLK(32KHz) per misurare la frequenza del DCO (torna valore in Hz) //----------------------------------------------------------------------------------------------- LONG MSP430_GetDCOFreq() { BYTE SmclkFromXt2; WORD n1,n2; // Setta un flag se SMCLK � ricavato da XT2 if (BCSCTL2 & SELS) SmclkFromXt2=1; else SmclkFromXt2=0; // Ricava il clock per SMCLK da DCO BCSCTL2 &= ~SELS; //BCSCTL2 |= SELS; // Accende TimerB: conteggio continuo a 16 bit, clock = SMCLK TBCTL = TBSSEL1 | MC1 | TBCLR; // Capture da CC16B=ACLK, rising edge TBCCTL6 = CM1 | CCIS0 | SCS | CAP; // Attende il primo evento di capture while ( (TBCCTL6 & CCIFG)==0 ) {}; // Memorizza valore attuale n1 = TBCCR6; // Azzera flag di capture e overflow TBCCTL6 &= ~(COV|CCIFG); // Attende il prossimo evento di capture while ( (TBCCTL6 & CCIFG)==0 ) {}; // Memorizza valore attuale n2 = TBCCR6; // Se si e' verificato un overflow azzera il valore, se no calcola la differenza if ( (TBCCTL6 & COV) != 0 ) n2=0; else n2=n2-n1; // Ferma il TimerB TBCTL = 0; TBCCTL6 = 0; // Ripristina il clock a SMCLK da XT2 se necessario if (SmclkFromXt2 != 0) BCSCTL2 |= SELS; // Ritorna il valore calcolato in KHertz return( (n2*32768L)/1000L ); }
and it works fine. Here is the screencapture of the result:
In your case, i suggest that the ACLK is failing. Could you please check whether ACLK runs properly? In the code above, i set the ACLK, MCLK, and SMCLK to be output from P5.4,5,6.
I hope this helps, otherwise please let me know.
-Leo-
Ok Leo I suppose I found it. In your code you are using DCO as MCLK ? Only for debug can you set BCSCTL2 = SELM2 and use XT2 as MCLK..
Thanks in Advance.....
Hi Kirkegaard,
yes, i use DCOa s MCLK. Unfortunately i have problem using XT2 on my hardware board so i can only use DCO.
So does this solve the problem? Was my suggestion with the failing ACLK true?
-Leo-
Hi Leo
My embedded system is locked using XT2 as MCLK. Before to call my function I must switch MCLK to DCO. ( like you ... this is not good things... anyway ). This is what seems to happen . Can you find a board with XT2 ?
ACLK it's ok anyway thanks for your helpful support...
Hi Kirkegaard,
i will try to get a board with working XT2 and modify the code to work with XT2. Could you also try to run my code above on your hardware and tell me the result whether it works or not?
-Leo-
This was my first thought too, but it doesn't explain why ther eis no ISR trigger when SMCLK is switched to DCO.lhend said:In your case, i suggest that the ACLK is failing.
I would understand that if XT2 is failing too and the timer is clocked by SMCLK with failing XT2 and the capture is set to be synchronized that ther eis no capture event since ther eis no synchronization with SCMLK as SMCLK doesn't tick. But with DCO, it should always work. There is no chance that DCO isn't running at least on any freuency (or else the MSP wouldn't come up at all, independently of the code)
Leo in attach I send you your module with my "personal" configruation of system clock. This code in my embedded system doesn't work...
#include <msp430f249.h> typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long LONG; LONG MSP430_GetDCOFreq(); volatile LONG result; void MSP430_SetClock(); void MSP430_Clock_from_XT2(); // ----- Impostazione del DCO con resistenza interna - circa 4.7MHz ----- #define DCO_DCOx 3 #define DCO_RSELx 12 void main(void) { WORD i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; MSP430_SetClock(); // Wait for xtal to stabilize do { IFG1 &= ~OFIFG; // Clear OSCFault flag for (i = 0x47FF; i > 0; i--); // Time for flag to set } while ((IFG1 & OFIFG)); // OSCFault flag still set? // output ACLK, MCLK, SMCLK P5SEL |= BIT4 + BIT5 + BIT6; P5DIR |= BIT4 + BIT5 + BIT6; while(1) { result = MSP430_GetDCOFreq(); __no_operation(); } } //----------------------------------------------------------------------------------------------- // GetDCOFreq // Utilizza il TimerB e ACLK(32KHz) per misurare la frequenza del DCO (torna valore in Hz) //----------------------------------------------------------------------------------------------- LONG MSP430_GetDCOFreq() { BYTE SmclkFromXt2; WORD n1,n2; // Setta un flag se SMCLK � ricavato da XT2 if (BCSCTL2 & SELS) SmclkFromXt2=1; else SmclkFromXt2=0; // Ricava il clock per SMCLK da DCO BCSCTL2 &= ~SELS; //BCSCTL2 |= SELS; // Accende TimerB: conteggio continuo a 16 bit, clock = SMCLK TBCTL = TBSSEL1 | MC1 | TBCLR; // Capture da CC16B=ACLK, rising edge TBCCTL6 = CM1 | CCIS0 | SCS | CAP; // Attende il primo evento di capture while ( (TBCCTL6 & CCIFG)==0 ) {}; // Memorizza valore attuale n1 = TBCCR6; // Azzera flag di capture e overflow TBCCTL6 &= ~(COV|CCIFG); // Attende il prossimo evento di capture while ( (TBCCTL6 & CCIFG)==0 ) {}; // Memorizza valore attuale n2 = TBCCR6; // Se si e' verificato un overflow azzera il valore, se no calcola la differenza if ( (TBCCTL6 & COV) != 0 ) n2=0; else n2=n2-n1; // Ferma il TimerB TBCTL = 0; TBCCTL6 = 0; // Ripristina il clock a SMCLK da XT2 se necessario if (SmclkFromXt2 != 0) BCSCTL2 |= SELS; // Ritorna il valore calcolato in KHertz return( (n2*32768L)/1000L ); } //--------------------------------------------------------------------------- // SetClock // Inizializzazione sotto-sistema clock //--------------------------------------------------------------------------- void MSP430_SetClock() { unsigned long int d=200000; int i; // ========== Accende XT2 e lascia il resto come da default dopo POR ========== // XT2OFF=0[ON] XTS=0[LF] DIVAx=00[/1] XT5V=0 RSELx=100 BCSCTL1 = RSEL2; // SELM=00[DCO] DIVM=00[/1] SELS=0[DCO] DIVS=00[/1] DCOR=0 BCSCTL2 = 0; // ========== Attende accesione XT2 ========== do { IFG1 &= ~OFIFG; for(i=0;i<250;i++) d--; } while ( (IFG1&OFIFG)!=0 && d); // ========== Impostazione operativa del sottosistema clock ========== MSP430_Clock_from_XT2(); } //----------------------------------------------------------------------------------------------- // Clock from XT2 // // Usa XT2 per MCLK/SMCLK - XT2 deve gia essere in funzione !!! //----------------------------------------------------------------------------------------------- void MSP430_Clock_from_XT2() { // SELM=10[XT2] DIVM=00[/1] SELS=1[XT2] DIVS=00[/1] DCOR=1 //BCSCTL2 = SELM1 | SELS | DCOR; // Paolo 5.02.0A modifica per utilizzare la resistenza interna di pullup ca. 300K BCSCTL2 = SELM1 | SELS; // XT2OFF=0[ON] XTS=0[LF] DIVAx=00[/1] XT5V=0 RSELx=[SETUP] BCSCTL1 = DCO_RSELx; // DCOx come da impostazione , niente modulatore DCOCTL = (DCO_DCOx<<5); // Accende SMCLK __bic_SR_register(SCG1); }
Hi Jens .... Yes you are right.. make me crazy....
Kirkegaard,
i just want to let you know that i have managed to reproduce the problem. I am still working to find out what causes this problem and will get back to you as soon as i get the answer.
-Leo-
Kirkegaard,
i have narrowed down the problem, it seems that the root of the problem is actually the DCO is failing somehow. Therefore if you switch the SMCLK clock source from XT2 to DCO and use the DCO as the clock source of Timer_B, the whole timer will basically not work at all.
Here is the source code that i am using:
#include <msp430f249.h> typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long LONG; //#define USE_XT2_FOR_SMCLK_DEFAULT LONG MSP430_GetDCOFreq(); volatile LONG result = 0; void main(void) { WORD i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; // turn on XT2 BCSCTL1 &= ~XT2OFF; // set XT2 frequency range and XCAP bits BCSCTL3 |= XT2S_2 + XCAP_3; // Wait for xtal to stabilize do { IFG1 &= ~OFIFG; // Clear OSCFault flag for (i = 0x47FF; i > 0; i--); // Time for flag to set } while ((IFG1 & OFIFG)); // OSCFault flag still set? #ifdef USE_XT2_FOR_SMCLK_DEFAULT // use XT2 as MCLK and SMCLK BCSCTL2 |= SELM_2 + SELS; #else // use XT2 as MCLK and DCO as SMCLK BCSCTL2 |= SELM_2; #endif // output ACLK, MCLK, SMCLK P5SEL |= BIT4 + BIT5 + BIT6; P5DIR |= BIT4 + BIT5 + BIT6; IE1 |= OFIE; // Enable osc fault interrupt while(1) { result = MSP430_GetDCOFreq(); __no_operation(); } } //----------------------------------------------------------------------------------------------- // GetDCOFreq // Utilizza il TimerB e ACLK(32KHz) per misurare la frequenza del DCO (torna valore in Hz) //----------------------------------------------------------------------------------------------- LONG MSP430_GetDCOFreq() { WORD n1,n2; #ifdef USE_XT2_FOR_SMCLK_DEFAULT BYTE SmclkFromXt2; // Setta un flag se SMCLK � ricavato da XT2 if (BCSCTL2 & SELS) SmclkFromXt2=1; else SmclkFromXt2=0; // Ricava il clock per SMCLK da DCO BCSCTL2 &= ~SELS; #endif // Accende TimerB: conteggio continuo a 16 bit, clock = SMCLK TBCTL = TBSSEL1 | MC1 | TBCLR; // Capture da CC16B=ACLK, rising edge TBCCTL6 = CM1 | CCIS0 | SCS | CAP; // Attende il primo evento di capture while ( (TBCCTL6 & CCIFG)==0 ) {}; // Memorizza valore attuale n1 = TBCCR6; // Azzera flag di capture e overflow TBCCTL6 &= ~(COV|CCIFG); // Attende il prossimo evento di capture while ( (TBCCTL6 & CCIFG)==0 ) {}; // Memorizza valore attuale n2 = TBCCR6; // Se si e' verificato un overflow azzera il valore, se no calcola la differenza if ( (TBCCTL6 & COV) != 0 ) n2=0; else n2=n2-n1; // Ferma il TimerB TBCTL = 0; TBCCTL6 = 0; #ifdef USE_XT2_FOR_SMCLK_DEFAULT // Ripristina il clock a SMCLK da XT2 se necessario if (SmclkFromXt2 != 0) BCSCTL2 |= SELS; #endif // Ritorna il valore calcolato in KHertz return( (n2*32768L)/1000L ); } #pragma vector=NMI_VECTOR __interrupt void NMI_ISR(void) { volatile unsigned int i; P1OUT |= 0x01; // P1.0 = set BCSCTL2 &= ~SELM_3; // Ensure MCLK runs from DCO do { IFG1 &= ~OFIFG; // Clear OSCFault flag for (i = 0xFF; i > 0; i--); // Time for flag to set } while (IFG1 & OFIFG); // OSCFault flag still set? BCSCTL2 |= SELM_2; // MCLK = XT2 HF XTAL (safe) for (i=0; i>20000; i--); // Delay for LED on inside ISR P1OUT &= ~0x01; // P1.0 = reset }
And here is the MCLK, SMCLK, ACLK signals look like on the oscilloscope:
As you can see the SMCLK clock is missing.
Then i made another simple example code as follows:
#include <msp430f249.h> void main(void) { unsigned int i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; // turn on XT2 BCSCTL1 &= ~XT2OFF; // set XT2 frequency range and XCAP bits BCSCTL3 |= XT2S_2 + XCAP_3; // Wait for xtal to stabilize do { IFG1 &= ~OFIFG; // Clear OSCFault flag for (i = 0x47FF; i > 0; i--); // Time for flag to set } while ((IFG1 & OFIFG)); // OSCFault flag still set? // use XT2 as MCLK and SMCLK BCSCTL2 |= SELM_2 + SELS; // use XT2 as MCLK and DCO as SMCLK //BCSCTL2 |= SELM_2; // output ACLK, MCLK, SMCLK P5SEL |= BIT4 + BIT5 + BIT6; P5DIR |= BIT4 + BIT5 + BIT6; // set P3.5 as output P3DIR |= BIT5; P3OUT &= ~BIT5; IE1 |= OFIE; // Enable osc fault interrupt while(1) { P3OUT |= BIT5; BCSCTL2 &= ~SELS; __delay_cycles(10000); BCSCTL2 |= SELS; P3OUT &= ~BIT5; __delay_cycles(10000); } }
And here is the result on oscilloscope:
As you can see during P3.5 is set as "1", the the SMCLK is not working because it is sourced from DCO (SELS bit of BCSCTL2 is cleared). On the other hand during P3.5 is "0", the SELS bit is set back to "1" (source from XT2) and it works again.
FYI, I am using 32.768 kHz at LFXT1 and 6 MHz at XT2.
I will escalate the problem to the application team for further investigation.
-Leo-
Right Leo ! It's the same things that I see. SMCLK locked with DCO and XT2 ( 6Mhz ) as MCLK.
Looks like the DCO is switched off for some reason. Normally, it shouldn't as long as someone (MCLK or SMCLK) is using it. But who knows. In my own projects, I never had the DCO sourcing SMCLK when it was not at the same time sourcing MCLK. And it sounds weird to have MCLK running on a stable crystal frequency and then use the instable DCO to source SMCLK. Usually, you need the stable frequency for module usage while the MCLK is less important, so you either have SMCLK or both on the crystal.
Maybe you detected a silicon bug. :)
Hi Jens
I don't know what happen. Sure you and Leo are more expert than me but my suspect, contrary to you, is that DCO is ever running but the timer ( timer6 ) for some obscured reason can't read it. So, for me, there aren't problem to use XT2 or DCO as MCLK o SMCLK. I found also round tip, but I need to understand precisely where is the trouble, my production it's locked and ... you know... also if there is a silicon bug, but I can't beleive, I hope Texas give me more than a simply support ;-)
Kirkeegard,
i just got reply from the application team. They also suggested this is a silicon bug, and this case has been sent to the bug tracker. At the moment, we can only suggest the following workaround:
- MCLK = DCO clock (always) and SMCLK switches between DCO and XT2
- MCLK = SMCLK = DCO clock and both MCLK and SMCLK are switched to XT2 and back to DCO simulatneously.
Can you work with this workaround?
I am also trying to get the information when we will get the confirmation whether it is a real bug.
-Leo-
Leo
In this moment the second one it's right for me... I'm starting test of new firmware today. Please tell me very fast everything about a bug because I have a important industrial production to do.
Thank you for the support.
Dear All,
sorry for coming in late.
A simple question:
I understood that SCG0 is set somewhere in the program. Is that right?
If so, then why do you expect the DCO to be active? SCG0 turns the DCO off. There are only two functions in the system that would be able to keep the DCO active: WDT or CPU. A timer has no clock request capabilities in the 2xx family.
I have no explanation why the F1xx family shall be different here.
Let me know if the above assumption is not correct.
Thanks & Regards
Joerg
Joerg,
no, the SCG0 is not set in the test.c as you can see here:
#include <msp430f249.h> void main(void) { unsigned int i; WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // Set DCO DCOCTL = CALDCO_1MHZ; // turn on XT2 BCSCTL1 &= ~XT2OFF; // set XT2 frequency range and XCAP bits BCSCTL3 |= XT2S_2 + XCAP_3; // Wait for xtal to stabilize do { IFG1 &= ~OFIFG; // Clear OSCFault flag for (i = 0x47FF; i > 0; i--); // Time for flag to set } while ((IFG1 & OFIFG)); // OSCFault flag still set? // use XT2 as MCLK and SMCLK BCSCTL2 |= SELM_2 + SELS; // use XT2 as MCLK and DCO as SMCLK //BCSCTL2 |= SELM_2; // output ACLK, MCLK, SMCLK P5SEL |= BIT4 + BIT5 + BIT6; P5DIR |= BIT4 + BIT5 + BIT6; // set P3.5 as output P3DIR |= BIT5; P3OUT &= ~BIT5; IE1 |= OFIE; // Enable osc fault interrupt while(1) { P3OUT |= BIT5; BCSCTL2 &= ~SELS; __delay_cycles(10000); BCSCTL2 |= SELS; P3OUT &= ~BIT5; __delay_cycles(10000); } }
-Leo-
Kirkegaard,
i just got a short update, that this problem has been officially filed as a bug. More updates will come.
-Leo-
**Attention** This is a public forum