Dynamically change the PW of Timer B based on user input

Hello;

Is it possible to change the PW based on the user input. Keeping the period constant and varying the duty cycle. I am using Timer B. The code is as shown below and I see the same output. I tried clearing the registers through TBCLR and later set the clock, TBBCR0 and count direction with no success. During the user input, I can see the LED resetting to the new values for a short duration but it returns back to the original cycle.

I have set the clock for 1MHZ and Timer as follows:

BCSCTL1 = CALBC1_8MHZ; // Set DCO = 8MHz for MCLK
DCOCTL = CALDCO_8MHZ;
BCSCTL2 |= DIVS_3;
TBCCTL0 = CCIE;
 
TBCCTL0 |= OUTMOD_7;//
TBCTL |= CNTL_0; //16 bit counter
TBCCR0 = 65000;
TBCTL |= TBSSEL_2 + MC_2 + ID_3;

In the Interrupt, based on the user input, I set the TBCCR1 and then toggle the output LED and the output
if( value == '0') { //shut the light
 TBCCR1 = 50000;
} else if( value == '1') { //PW duration is longer  
 TBCCR1 = 500;
}
P4OUT ^= BIT5;
P1OUT ^= 0x01;
Dave
  •  Hi Dave, from your code I understand you want to set an output with an hardware pwm function, no pin alternate function select appear so possible error I can see are:

    Dave Charles
    TBCCTL0 |= OUTMOD_7;//

    it can be cctl1 if you wish to have pin set by pwm on taccr1:

    Dave Charles
    if( value == '0') { //shut the light
     TBCCR1 = 50000;
    } else if( value == '1') { //PW duration is longer  
     TBCCR1 = 500;
    }

     How is used this code?

    Dave Charles
    P4OUT ^= BIT5;
    P1OUT ^= 0x01;
    
    

    if you wish to use these pin as alternate pwm out function (if available so please check on datasheet) do

    P1SEL|= BIT1;

    this case P1.1 is assigned to alternate function but timerB use other pin.

     If you wish to use an interrupt based pwm then you must properly set and reset output on some timing based algorithm otherwise your led flash at interrupt rate and you get forever a ffast flashing or 50% duty.

  • In reply to Roberto Romano:

    Hi Roberto,

    Thanks for your response. Yes, I want to output a PWM using hardware if possible. I want to use port 4 pin 5 as the output generating multiple pulse width based on a user input, meaning a single pin as the output generating different widths. I don't want to use different pins to output the different pulse width. Looking at the examples, I am not sure and I don't know if this is possible. The code shown above toggles the output of P4 and P1 (LED) when interrupts are generated. I have set P4.5 as the output in the code prior to setting the timer B

    Roberto Romano
    otherwise your led flash at interrupt rate and you get forever a ffast flashing or 50% duty.

    My understanding from the statement above is that you can only generate one set of PWM and it is set prior to generating the interrupt. Once set the duty cycle value cannot be changed. Am I correct in understanding what you described above?

    I have not understood the statement

    Roberto Romano
     If you wish to use an interrupt based pwm then you must properly set and reset output on some timing based algorithm
    Could you please elaborate and if possible any code examples that I can look for inspiration.

    In my code, during interrupts, I am changing TBCCR1 to different values with the hope that the new values will be picked by the appropriate registers ( based on user input) but this has no effect on the output. It is the same duty cycle when initially set.

    Is it possible to generate different pulse width once set by TBCCR0 and dynamically changing the pulse width by changing values for TBCCR1?

    Thanks

    David

  • In reply to Dave Charles:

    Dave Charles
    Is it possible to generate different pulse width once set by TBCCR0

    I meant pulse period  set by TBCCR0 and not pulse width

  • In reply to Dave Charles:

     Hi Dave, TBCCR0 can only generate reset pulse or upper count to TAR register so determinate the timing divisor of clock and consequently PWM rate and resolution too.

     All the other TxCCRy can be directed to a pin but you need read on datasheet which one is fed by the compare register. Timer B has some multiple pin action so read datasheet and if you are again in trouble ask again and I try locate a solution.

     If you generate hardware pwm no interrupt are needed, if you wish to generate software pwm then your timer is used to generate an interval then on service a software counter is compared with pwm value and output can be switched on or off if pwm value is respectively less or greater than counter, when counter reach max value is reset to zero.

     The statement about fast flashing signify that every interrupt on a regular timer interval set then reset led bit, so one time led os on and one is off, this equal timing result in a square wave and led are lit at50% duty cycle or fast flashing depending on timer constant.

  • In reply to Dave Charles:

    Dave Charles

    I have not understood the statement

    Roberto Romano
     If you wish to use an interrupt based pwm then you must properly set and reset output on some timing based algorithm
    Could you please elaborate and if possible any code examples that I can look for inspiration.

    ----------------------------------------

    #define MAXPWM www

    glabal var declaration

    volatile int pwm=0;

    ----------------------------------------

    your code

     pwm=xx; // xx <= MAXPWM

    ----------------------------------------

    interrupt service:

    {

    static int pwmcounter=0;

    if(pwm>=pwmcounter)

      PxOUT &=~BITy;

    else

     PxOUT |=BITy;

    if(++pwmcounter>MAXPWM)

      pwmcounter=0;

    }

  • In reply to Roberto Romano:

    Hi Roberto.

    Thanks for the response. My code functionality was such that I set different values for TBCCR1 and was thinking that this would generate different pulse widths at the same port and pin P4.5. This was done by initially setting the TBCCR0 max value of 65535 and temporarily setting a value in TBCCR1. This would generate the interrupt at the end of that interval and the cycle would continue. When the user inputs a new setting on the console, a new value would be set in TBCCR1 register and during the next clock cycle the new values of TBCCR1 would be picked up generating the required width as per user input.

    Anyhow, I will try the example that you have shown and see if I could generate different PW through code.

    Thanks once again, I will respond once I am able to do as you had mentioned.

    Dave

  • In reply to Dave Charles:

    Dave Charles
    I set different values for TBCCR1 and was thinking that this would generate different pulse widths at the same port and pin P4.5.

     Hi Dave, I checked on datasheet, TBCCR1 can set P4.1 and/or P4.4 if you wish to use P4.5 and/or P4.2 change TBCCR1, TBCTCL1 with TACCR2, TBCTCL2 otherwise no action appear to selected pin. Also check 16 bit mode is selected otherwise some value like 5000 65536 may be out of range.

     On software example I set PWM control in an interrupt service regular timer but it work well if it is called in a loop.

  • In reply to Roberto Romano:

    Hi Roberto,

    Thanks for the response. I was busy so couldn't answer earlier. I made the settings as you had mentioned for the outputs on Port4, pin5. I changed the values as follows:

    In the halInit I added (BIT5) P4DIR = BIT0+BIT1 + BIT4 + BIT5; P4SEL = 0; P4OUT &= ~BIT4; In desperation I modified even these to - P4SEL|=BIT5 and P4OUT |=BIT5;

    TBCCR2 = 500; TBCCTL2 |= CCIE; TBCCTL2 |= OUTMOD_3; and TBCTL |= TBSSEL_1 + MC_1 ; but no luck. I changed the interrupt service from 0 to 1, as shown below, with no luck. The interrupts are not being called because when I put a printf statement its not shown on the putty screen.

    #pragma vector=TIMERB0_VECTOR //1

    __interrupt void Timer_B (void){//interrupt code}

    Since that was not successful, I went back to TBCCR0 and reverted back to the old values. I am getting the values on P4.6 (I think this is high impedance output for all timers TB0 to TB3). I am using this output because I need to connect a wire from the Minikit board to the LED panel. The outputs from the CC2530 ZNP Minikit board is mentioned in this link : http://processors.wiki.ti.com/index.php/HW_Users_Guide

    Now, I am able to vary the duty cycle as I want. I am still stuck with one problem. The output frequency is low and the LED on the kit is blinking and when connected to the LED panel it also flickers along with the dimming and brightening of the LED as PW is varied. I am setting the clock as follows:

    BCSCTL1 = CALBC1_8MHZ; // Set DCO = 8MHz for MCLK
    DCOCTL = CALDCO_8MHZ;
    BCSCTL2 |= DIVS_1; //SMCLK = DCO/2 (4MHz)
    BCSCTL3 |= LFXT1S_2;

    I changed the DIVS from 1 to 0 with no effect, since SMCLK is used (BCSCTL2).

    Is there any way of increasing the frequency of the PWM. I feel with a higher frequency the flickering would go away or less visible to human eye.

    Thanks,

    Dave