EmbeddedRelated.com
Forums

PWM using TimerB in Continuous mode

Started by ti2tt September 2, 2009
Hello All and a special hello to Michael,

Sorry to keep pestering you, Michael.

I am still unable to resolve the PWM issue and seriously thinking of changing career as Michael advised. Sincerely speaking, I tried very much to analyse the timer behaviour but to my tough luck I could not figure out the classic mistake. I tried to capture the timer counts, both theoretically and practically, at different stages of execution to analyse. I also tried different register settings for TimerB. Please help me out to resolve the issue. I am including the functions here again. Some constants in code - PWM_Period = 3334; ACLK=1MHz; DACOUT=any value less than 3334;

void Init_TimerB (void)
{
TBCTL = (TBCLR | MC_0); //Individual compare latch / Clear TimerB / Stop TimerB
TBCTL = (CNTL_0 | TBSSEL_1 | ID_1); //16bit / ACLK / Divide by 2 / Stop
TBCTL &= ~(TBIE | TBIFG); //Disable TBIV and flag

TBCTL = (CNTL_0 | TBSSEL_1 | ID_1 | MC_2); //16bit / ACLK / Divide by 2 / Continuous
}

void ConfigTimerB5_PWM (void)
{
P4SEL &= ~0xA0;
P4SEL |= 0x20; // P4.5 - Select as TB5 functionality
P4DIR |= 0x20; // P4.5 - Select compare as output

TBCCTL5 &= ~CCIE; //Disable interrupt
TBCCTL5 &= ~CAP; //Compare mode
//CM_0 = No Capture
//CCIS_1 = Capture/Compare input is TB4
//SCS = Synchronous capture
//CLLD_0 = Load compare latch (TBCLx) when TBCCRx is written
//OUTMOD_3 = Set/Reset
//CCIE = Enable interrupt
//OUT = Output high on pin
TBCCTL5 = (CM_0 | CCIS_1 | SCS | CLLD_0 | OUTMOD_3 | CCIE | OUT);
TBCCR5 = DACOUT; //PWM Duty cycle
}

Timer ISR -
void ISR_TimerB (void) INTERRUPT[TIMERB1_VECTOR]
{
switch (TBIV)
{
case TBIV_TBCCR1:
break;
case TBIV_TBCCR5: // CCR5 int
TBCCTL5 &= ~CCIFG; //Clear interrupt flag
TBCCR0 = (TBCCR5 + DACOUT);
TBCCR5 += PWM_Period; //PWM_Period334
break;
}
}

Please help me to figure out the implementation. Thanks in advance.

--- In m..., "Michael" wrote:
>
> > When TBR=TBCCR5, the EQUx event will set the pin and when
> > TBR=TBCCR0, EQUx event will reset the pin. So I need to handle both
> > the TBCCR0 and TBCCR5.
>
> Yes... almost. Only EQUx doesn't use TBCCRx but TBCLx, which is an internal (invisible) register. You can control when TBCLx is automatically loaded with the value in TBCCRx by means of the CLLDx bits in TBCCTLx register. Any mode but CLLD_0 will solve your problem and you won't have missed EQUx events, so no jumps to DC0% when changing to a lower DC.
>
> Michael K.
>
> --- In m..., "ti2tt" wrote:
> >
> > Hello Michael,
> >
> > Sorry to keep pestering you.
> >
> > Below is my understanding for continous mode of TimerB.
> >
> > In continuous mode for TimerB to generate the PWM,TBCCR0 and TBCCR5
> > will come into picture. TBCCR5 is my code requirement while the
> > TBCCR0 is default. I have selected the output mode 3 which is
> > set/reset. When TBR=TBCCR5, the EQUx event will set the pin and when
> > TBR=TBCCR0, EQUx event will reset the pin. So I need to handle both
> > the TBCCR0 and TBCCR5.
> >
> > Please clarify if I am wrongly interpreting the continuous mode.
> >
> > Thanks in advance.
>

Beginning Microcontrollers with the MSP430

You changed from timer A to timer B but are not using the feature of timer B that solves your problem. My guess is you haven't taken the time to read THE ENTIRE CHAPTER of timer B, from top to bottom without skipping anything, no matter if you already readed it or if you don't understand it at first.
Basically, you're using CLLD_0 which is the same as using timer A, disregarding the ability of choosing when TBCLx will be loaded with the value in TBCCRx. Use CLLD_1 and your problems will disappear.

By the way, there are a lot of things that don't make much sense in
your code (comments stripped):

Number 1)
> void Init_TimerB (void)
> {
> TBCTL = (TBCLR | MC_0);
> TBCTL = (CNTL_0 | TBSSEL_1 | ID_1);
> TBCTL &= ~(TBIE | TBIFG);
> TBCTL = (CNTL_0 | TBSSEL_1 | ID_1 | MC_2)
> }
You're changing the TBCTL register 4 times in a row!! What's that about?

Number 2)
> TBCCTL5 &= ~CCIE;
> TBCCTL5 &= ~CAP;
> TBCCTL5 = (CM_0 | CCIS_1 | SCS | CLLD_0 | OUTMOD_3 | CCIE | OUT);
With the third instruction you're disregarding what you did with the first two. The first two are useless unless you use |= instad of = on the third instruction. Do you understand the difference between the operand |=, &= and = ?

Number 3)
> switch (TBIV)
> {
> case TBIV_TBCCR1:
> break;
> case TBIV_TBCCR5:
> TBCCTL5 &= ~CCIFG;
> TBCCR0 = (TBCCR5 + DACOUT);
> TBCCR5 += PWM_Period;
> break;
> }

TBCCTL5 &= ~CCIFG is superfluous, since by reading TBIV (by the switch instruction) and entering TBIV_TBCCR5 this flag is automatically cleared.

Really, STOP programming and RTFM. Then read it again and take notes. Then read it again along with your notes.

Michael K.

--- In m..., "ti2tt" wrote:
>
> Hello All and a special hello to Michael,
>
> Sorry to keep pestering you, Michael.
>
> I am still unable to resolve the PWM issue and seriously thinking of changing career as Michael advised. Sincerely speaking, I tried very much to analyse the timer behaviour but to my tough luck I could not figure out the classic mistake. I tried to capture the timer counts, both theoretically and practically, at different stages of execution to analyse. I also tried different register settings for TimerB. Please help me out to resolve the issue. I am including the functions here again. Some constants in code - PWM_Period = 3334; ACLK=1MHz; DACOUT=any value less than 3334;
>
> void Init_TimerB (void)
> {
> TBCTL = (TBCLR | MC_0); //Individual compare latch / Clear TimerB / Stop TimerB
> TBCTL = (CNTL_0 | TBSSEL_1 | ID_1); //16bit / ACLK / Divide by 2 / Stop
> TBCTL &= ~(TBIE | TBIFG); //Disable TBIV and flag
>
> TBCTL = (CNTL_0 | TBSSEL_1 | ID_1 | MC_2); //16bit / ACLK / Divide by 2 / Continuous
> }
>
> void ConfigTimerB5_PWM (void)
> {
> P4SEL &= ~0xA0;
> P4SEL |= 0x20; // P4.5 - Select as TB5 functionality
> P4DIR |= 0x20; // P4.5 - Select compare as output
>
> TBCCTL5 &= ~CCIE; //Disable interrupt
> TBCCTL5 &= ~CAP; //Compare mode
> //CM_0 = No Capture
> //CCIS_1 = Capture/Compare input is TB4
> //SCS = Synchronous capture
> //CLLD_0 = Load compare latch (TBCLx) when TBCCRx is written
> //OUTMOD_3 = Set/Reset
> //CCIE = Enable interrupt
> //OUT = Output high on pin
> TBCCTL5 = (CM_0 | CCIS_1 | SCS | CLLD_0 | OUTMOD_3 | CCIE | OUT);
> TBCCR5 = DACOUT; //PWM Duty cycle
> }
>
> Timer ISR -
> void ISR_TimerB (void) INTERRUPT[TIMERB1_VECTOR]
> {
> switch (TBIV)
> {
> case TBIV_TBCCR1:
> break;
> case TBIV_TBCCR5: // CCR5 int
> TBCCTL5 &= ~CCIFG; //Clear interrupt flag
> TBCCR0 = (TBCCR5 + DACOUT);
> TBCCR5 += PWM_Period; //PWM_Period334
> break;
> }
> }
>
> Please help me to figure out the implementation. Thanks in advance.
>
> --- In m..., "Michael" wrote:
> >
> > > When TBR=TBCCR5, the EQUx event will set the pin and when
> > > TBR=TBCCR0, EQUx event will reset the pin. So I need to handle both
> > > the TBCCR0 and TBCCR5.
> >
> > Yes... almost. Only EQUx doesn't use TBCCRx but TBCLx, which is an internal (invisible) register. You can control when TBCLx is automatically loaded with the value in TBCCRx by means of the CLLDx bits in TBCCTLx register. Any mode but CLLD_0 will solve your problem and you won't have missed EQUx events, so no jumps to DC0% when changing to a lower DC.
> >
> > Michael K.
> >
> > --- In m..., "ti2tt" wrote:
> > >
> > > Hello Michael,
> > >
> > > Sorry to keep pestering you.
> > >
> > > Below is my understanding for continous mode of TimerB.
> > >
> > > In continuous mode for TimerB to generate the PWM,TBCCR0 and TBCCR5
> > > will come into picture. TBCCR5 is my code requirement while the
> > > TBCCR0 is default. I have selected the output mode 3 which is
> > > set/reset. When TBR=TBCCR5, the EQUx event will set the pin and when
> > > TBR=TBCCR0, EQUx event will reset the pin. So I need to handle both
> > > the TBCCR0 and TBCCR5.
> > >
> > > Please clarify if I am wrongly interpreting the continuous mode.
> > >
> > > Thanks in advance.
>

Michael,

You have to give credit to ti2tt. He did write his own code and did not rely on video or "sample code".

-- OCY

--- In m..., "Michael" wrote:
>
> You changed from timer A to timer B but are not using the feature of timer B that solves your problem. My guess is you haven't taken the time to read THE ENTIRE CHAPTER of timer B, from top to bottom without skipping anything, no matter if you already readed it or if you don't understand it at first.
> Basically, you're using CLLD_0 which is the same as using timer A, disregarding the ability of choosing when TBCLx will be loaded with the value in TBCCRx. Use CLLD_1 and your problems will disappear.
>
> By the way, there are a lot of things that don't make much sense in
> your code (comments stripped):
>
> Number 1)
> > void Init_TimerB (void)
> > {
> > TBCTL = (TBCLR | MC_0);
> > TBCTL = (CNTL_0 | TBSSEL_1 | ID_1);
> > TBCTL &= ~(TBIE | TBIFG);
> > TBCTL = (CNTL_0 | TBSSEL_1 | ID_1 | MC_2)
> > }
> You're changing the TBCTL register 4 times in a row!! What's that about?
>
> Number 2)
> > TBCCTL5 &= ~CCIE;
> > TBCCTL5 &= ~CAP;
> > TBCCTL5 = (CM_0 | CCIS_1 | SCS | CLLD_0 | OUTMOD_3 | CCIE | OUT);
> With the third instruction you're disregarding what you did with the first two. The first two are useless unless you use |= instad of = on the third instruction. Do you understand the difference between the operand |=, &= and = ?
>
> Number 3)
> > switch (TBIV)
> > {
> > case TBIV_TBCCR1:
> > break;
> > case TBIV_TBCCR5:
> > TBCCTL5 &= ~CCIFG;
> > TBCCR0 = (TBCCR5 + DACOUT);
> > TBCCR5 += PWM_Period;
> > break;
> > }
>
> TBCCTL5 &= ~CCIFG is superfluous, since by reading TBIV (by the switch instruction) and entering TBIV_TBCCR5 this flag is automatically cleared.
>
> Really, STOP programming and RTFM. Then read it again and take notes. Then read it again along with your notes.
>
> Michael K.
>
> --- In m..., "ti2tt" wrote:
> >
> > Hello All and a special hello to Michael,
> >
> > Sorry to keep pestering you, Michael.
> >
> > I am still unable to resolve the PWM issue and seriously thinking of changing career as Michael advised. Sincerely speaking, I tried very much to analyse the timer behaviour but to my tough luck I could not figure out the classic mistake. I tried to capture the timer counts, both theoretically and practically, at different stages of execution to analyse. I also tried different register settings for TimerB. Please help me out to resolve the issue. I am including the functions here again. Some constants in code - PWM_Period = 3334; ACLK=1MHz; DACOUT=any value less than 3334;
> >
> > void Init_TimerB (void)
> > {
> > TBCTL = (TBCLR | MC_0); //Individual compare latch / Clear TimerB / Stop TimerB
> > TBCTL = (CNTL_0 | TBSSEL_1 | ID_1); //16bit / ACLK / Divide by 2 / Stop
> > TBCTL &= ~(TBIE | TBIFG); //Disable TBIV and flag
> >
> > TBCTL = (CNTL_0 | TBSSEL_1 | ID_1 | MC_2); //16bit / ACLK / Divide by 2 / Continuous
> > }
> >
> > void ConfigTimerB5_PWM (void)
> > {
> > P4SEL &= ~0xA0;
> > P4SEL |= 0x20; // P4.5 - Select as TB5 functionality
> > P4DIR |= 0x20; // P4.5 - Select compare as output
> >
> > TBCCTL5 &= ~CCIE; //Disable interrupt
> > TBCCTL5 &= ~CAP; //Compare mode
> > //CM_0 = No Capture
> > //CCIS_1 = Capture/Compare input is TB4
> > //SCS = Synchronous capture
> > //CLLD_0 = Load compare latch (TBCLx) when TBCCRx is written
> > //OUTMOD_3 = Set/Reset
> > //CCIE = Enable interrupt
> > //OUT = Output high on pin
> > TBCCTL5 = (CM_0 | CCIS_1 | SCS | CLLD_0 | OUTMOD_3 | CCIE | OUT);
> > TBCCR5 = DACOUT; //PWM Duty cycle
> > }
> >
> > Timer ISR -
> > void ISR_TimerB (void) INTERRUPT[TIMERB1_VECTOR]
> > {
> > switch (TBIV)
> > {
> > case TBIV_TBCCR1:
> > break;
> > case TBIV_TBCCR5: // CCR5 int
> > TBCCTL5 &= ~CCIFG; //Clear interrupt flag
> > TBCCR0 = (TBCCR5 + DACOUT);
> > TBCCR5 += PWM_Period; //PWM_Period334
> > break;
> > }
> > }
> >
> > Please help me to figure out the implementation. Thanks in advance.
> >
> > --- In m..., "Michael" wrote:
> > >
> > > > When TBR=TBCCR5, the EQUx event will set the pin and when
> > > > TBR=TBCCR0, EQUx event will reset the pin. So I need to handle both
> > > > the TBCCR0 and TBCCR5.
> > >
> > > Yes... almost. Only EQUx doesn't use TBCCRx but TBCLx, which is an internal (invisible) register. You can control when TBCLx is automatically loaded with the value in TBCCRx by means of the CLLDx bits in TBCCTLx register. Any mode but CLLD_0 will solve your problem and you won't have missed EQUx events, so no jumps to DC0% when changing to a lower DC.
> > >
> > > Michael K.
> > >
> > > --- In m..., "ti2tt" wrote:
> > > >
> > > > Hello Michael,
> > > >
> > > > Sorry to keep pestering you.
> > > >
> > > > Below is my understanding for continous mode of TimerB.
> > > >
> > > > In continuous mode for TimerB to generate the PWM,TBCCR0 and TBCCR5
> > > > will come into picture. TBCCR5 is my code requirement while the
> > > > TBCCR0 is default. I have selected the output mode 3 which is
> > > > set/reset. When TBR=TBCCR5, the EQUx event will set the pin and when
> > > > TBR=TBCCR0, EQUx event will reset the pin. So I need to handle both
> > > > the TBCCR0 and TBCCR5.
> > > >
> > > > Please clarify if I am wrongly interpreting the continuous mode.
> > > >
> > > > Thanks in advance.
> > >
>

OCY,
> You have to give credit to ti2tt. He did write his own code and did
> not rely on video

funny...

> or "sample code".
Is that supposed to be a good thing? Maybe not "rely on" but at least take a look at.
But anyway, it seems to me he is not relying on the User's Guide either, nor on the previous posts and explanations for that matter.

I challenge you (I don't mean it harshly) to read the entire thread (all twenty-something posts) and say that again.

Maybe I'm being too harsh, but if you read the entire thread you will understand why. He needs to stop writing code almost blindly (you can see that on his last code snippet) hoping to get it working and start THINKING. For godness sake, STOP WRITING CODE AND START THINKING! (you can hardly call it programming as there seems to be no 'programm' - no structure - behind his code and posts)

Regards,
Michael K.

--- In m..., "old_cow_yellow" wrote:
>
> Michael,
>
> You have to give credit to ti2tt. He did write his own code and did not rely on video or "sample code".
>
> -- OCY
>
> --- In m..., "Michael" wrote:
> >
> > You changed from timer A to timer B but are not using the feature of timer B that solves your problem. My guess is you haven't taken the time to read THE ENTIRE CHAPTER of timer B, from top to bottom without skipping anything, no matter if you already readed it or if you don't understand it at first.
> > Basically, you're using CLLD_0 which is the same as using timer A, disregarding the ability of choosing when TBCLx will be loaded with the value in TBCCRx. Use CLLD_1 and your problems will disappear.
> >
> > By the way, there are a lot of things that don't make much sense in
> > your code (comments stripped):
> >
> > Number 1)
> > > void Init_TimerB (void)
> > > {
> > > TBCTL = (TBCLR | MC_0);
> > > TBCTL = (CNTL_0 | TBSSEL_1 | ID_1);
> > > TBCTL &= ~(TBIE | TBIFG);
> > > TBCTL = (CNTL_0 | TBSSEL_1 | ID_1 | MC_2)
> > > }
> > You're changing the TBCTL register 4 times in a row!! What's that about?
> >
> > Number 2)
> > > TBCCTL5 &= ~CCIE;
> > > TBCCTL5 &= ~CAP;
> > > TBCCTL5 = (CM_0 | CCIS_1 | SCS | CLLD_0 | OUTMOD_3 | CCIE | OUT);
> > With the third instruction you're disregarding what you did with the first two. The first two are useless unless you use |= instad of = on the third instruction. Do you understand the difference between the operand |=, &= and = ?
> >
> > Number 3)
> > > switch (TBIV)
> > > {
> > > case TBIV_TBCCR1:
> > > break;
> > > case TBIV_TBCCR5:
> > > TBCCTL5 &= ~CCIFG;
> > > TBCCR0 = (TBCCR5 + DACOUT);
> > > TBCCR5 += PWM_Period;
> > > break;
> > > }
> >
> > TBCCTL5 &= ~CCIFG is superfluous, since by reading TBIV (by the switch instruction) and entering TBIV_TBCCR5 this flag is automatically cleared.
> >
> > Really, STOP programming and RTFM. Then read it again and take notes. Then read it again along with your notes.
> >
> > Michael K.
> >
> > --- In m..., "ti2tt" wrote:
> > >
> > > Hello All and a special hello to Michael,
> > >
> > > Sorry to keep pestering you, Michael.
> > >
> > > I am still unable to resolve the PWM issue and seriously thinking of changing career as Michael advised. Sincerely speaking, I tried very much to analyse the timer behaviour but to my tough luck I could not figure out the classic mistake. I tried to capture the timer counts, both theoretically and practically, at different stages of execution to analyse. I also tried different register settings for TimerB. Please help me out to resolve the issue. I am including the functions here again. Some constants in code - PWM_Period = 3334; ACLK=1MHz; DACOUT=any value less than 3334;
> > >
> > > void Init_TimerB (void)
> > > {
> > > TBCTL = (TBCLR | MC_0); //Individual compare latch / Clear TimerB / Stop TimerB
> > > TBCTL = (CNTL_0 | TBSSEL_1 | ID_1); //16bit / ACLK / Divide by 2 / Stop
> > > TBCTL &= ~(TBIE | TBIFG); //Disable TBIV and flag
> > >
> > > TBCTL = (CNTL_0 | TBSSEL_1 | ID_1 | MC_2); //16bit / ACLK / Divide by 2 / Continuous
> > > }
> > >
> > > void ConfigTimerB5_PWM (void)
> > > {
> > > P4SEL &= ~0xA0;
> > > P4SEL |= 0x20; // P4.5 - Select as TB5 functionality
> > > P4DIR |= 0x20; // P4.5 - Select compare as output
> > >
> > > TBCCTL5 &= ~CCIE; //Disable interrupt
> > > TBCCTL5 &= ~CAP; //Compare mode
> > > //CM_0 = No Capture
> > > //CCIS_1 = Capture/Compare input is TB4
> > > //SCS = Synchronous capture
> > > //CLLD_0 = Load compare latch (TBCLx) when TBCCRx is written
> > > //OUTMOD_3 = Set/Reset
> > > //CCIE = Enable interrupt
> > > //OUT = Output high on pin
> > > TBCCTL5 = (CM_0 | CCIS_1 | SCS | CLLD_0 | OUTMOD_3 | CCIE | OUT);
> > > TBCCR5 = DACOUT; //PWM Duty cycle
> > > }
> > >
> > > Timer ISR -
> > > void ISR_TimerB (void) INTERRUPT[TIMERB1_VECTOR]
> > > {
> > > switch (TBIV)
> > > {
> > > case TBIV_TBCCR1:
> > > break;
> > > case TBIV_TBCCR5: // CCR5 int
> > > TBCCTL5 &= ~CCIFG; //Clear interrupt flag
> > > TBCCR0 = (TBCCR5 + DACOUT);
> > > TBCCR5 += PWM_Period; //PWM_Period334
> > > break;
> > > }
> > > }
> > >
> > > Please help me to figure out the implementation. Thanks in advance.
> > >
> > > --- In m..., "Michael" wrote:
> > > >
> > > > > When TBR=TBCCR5, the EQUx event will set the pin and when
> > > > > TBR=TBCCR0, EQUx event will reset the pin. So I need to handle both
> > > > > the TBCCR0 and TBCCR5.
> > > >
> > > > Yes... almost. Only EQUx doesn't use TBCCRx but TBCLx, which is an internal (invisible) register. You can control when TBCLx is automatically loaded with the value in TBCCRx by means of the CLLDx bits in TBCCTLx register. Any mode but CLLD_0 will solve your problem and you won't have missed EQUx events, so no jumps to DC0% when changing to a lower DC.
> > > >
> > > > Michael K.
> > > >
> > > > --- In m..., "ti2tt" wrote:
> > > > >
> > > > > Hello Michael,
> > > > >
> > > > > Sorry to keep pestering you.
> > > > >
> > > > > Below is my understanding for continous mode of TimerB.
> > > > >
> > > > > In continuous mode for TimerB to generate the PWM,TBCCR0 and TBCCR5
> > > > > will come into picture. TBCCR5 is my code requirement while the
> > > > > TBCCR0 is default. I have selected the output mode 3 which is
> > > > > set/reset. When TBR=TBCCR5, the EQUx event will set the pin and when
> > > > > TBR=TBCCR0, EQUx event will reset the pin. So I need to handle both
> > > > > the TBCCR0 and TBCCR5.
> > > > >
> > > > > Please clarify if I am wrongly interpreting the continuous mode.
> > > > >
> > > > > Thanks in advance.
> > > >
> > >
>

Michael,

I see your point.

I am aware of IMPS. Is there also an IPPS? (Where the first P stands for Parrot.) M or P, which is better?

-- OCY

--- In m..., "Michael" wrote:
>
> OCY,
> > You have to give credit to ti2tt. He did write his own code and did
> > not rely on video
>
> funny...
>
> > or "sample code".
> Is that supposed to be a good thing? Maybe not "rely on" but at least take a look at.
> But anyway, it seems to me he is not relying on the User's Guide either, nor on the previous posts and explanations for that matter.
>
> I challenge you (I don't mean it harshly) to read the entire thread (all twenty-something posts) and say that again.
>
> Maybe I'm being too harsh, but if you read the entire thread you will understand why. He needs to stop writing code almost blindly (you can see that on his last code snippet) hoping to get it working and start THINKING. For godness sake, STOP WRITING CODE AND START THINKING! (you can hardly call it programming as there seems to be no 'programm' - no structure - behind his code and posts)
>
> Regards,
> Michael K.
>
> --- In m..., "old_cow_yellow" wrote:
> >
> > Michael,
> >
> > You have to give credit to ti2tt. He did write his own code and did not rely on video or "sample code".
> >
> > -- OCY
> >