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.
Hello, I'm currently trying to implement a timed PWM signal, that is that when ever I press a button a bi-phasic PWM (using 2 PWM outputs) signal will start for a determined time(figure A). For this, I'm using the available 2 timers in the MSP430F2132. One of the timers is used to produce the PWM, and the other one is used as a counter to set how long the signal will be ON. The PWM timer (TA0) is used in the up and down mode, in order to produce some dead times between the 2 outputs activations as the figure A shows.
In this case the button activation is obtain by an SPI command, when the command is received, the Timer A0 is started in the up and down mode (TA0CTL=TASSEL_2 + MC_3) as well as the Timer A1 in the up mode(TA1CTL=TASSEL_2 + MC_1). When the desire activation time finishes (Stimulation_Data[4] =Activation_Time ), the timers are turned off (TA1CTL = TASSEL_2 + MC_0 and TA0CTL = TASSEL_2 + MC_0) and also the TACLR is activate to reset the timers.
The part I can't understand, and haven't been able to fix is, Why the first 2 activation signals (figure B and C) are double the desire frequency, and then after adjusts. If I change any of the parameters the phenomena still appears.
I also tried deactivation the PWM timer by setting TA0CCR0=0, and reactivating it by setting a non-zero value to it. But have the same response.
Thank you for any help!
Here is the code of my program.
#include "msp430x21x2.h"
#include "Slave_Define.h"
int instruction, data_flag,firstpass_flag, Activated_Flag, Period_Count, Burst_Number;
int SPI_R, initpass, Freq_Perido_Half;
int Stimulation_Data[7];
int value_pointer, multiplo;
unsigned int Width_before;
short PWM_OFF, PWM_ON;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
BCSCTL1 = CALBC1_16MHZ; // calibration of the DCO to 16MHz
DCOCTL = CALDCO_16MHZ;
/**************** Timer A0, PWM activated ************************************/
P1DIR |= 0x0C; // P1.2 and P1.3 set to output
P1SEL &= 0x00; // Selects I/O option
P1OUT &= 0xF3; // Sets P1.2 and P1.3 to 0
TA0CCR0 =8000; // sets the PWM frequency to 1KHz
TA0CCTL1 = OUTMOD_6 ; // TACCR1 toggle/set
TA0CCR1 = 4000+160; // TACCR1 PWM duty cycle and IP to 20us
TA0CCTL2 = OUTMOD_2; // TACCR2 toggle/reset
TA0CCR2 = 4000-160; // TACCR2 PWM duty cycle and IP to 20us
TA0CTL = TASSEL_2 + MC_0; // SMCLK, stop mode
/**************** Timer B, interrupt activated ******************************/
TA1CCTL0 = CCIE; // TA1CCR0 interrupt disabled
TA1CCR0 = 60; // Sets the interruption time
TA1CTL = TASSEL_2 + MC_0; // SMCLK, stop mode
/**************** SPI, 4pin, 8bit, slave ************************************/
P3OUT |= 0x10;
P3SEL |= 0x0F; // P3.0, P3.1,2,3 USCI_B0 option select
UCB0CTL1 = UCSWRST; // **Put state machine in reset**
UCB0CTL0 |= UCCKPL + UCMSB + UCSYNC + 0x02; // 4-pin, 8-bit SPI master
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
IE2 |= UCB0RXIE; // Enable USCI0 RX interrupt
/****************************************************************************/
__bis_SR_register(GIE); // enable interrupts
/********************** Variable Init ***************************************/
Stimulation_Data[1] = 8000; /// init the frequency;
Stimulation_Data[3] = 524; /// init the duty
Stimulation_Data[4] = 2; /// init stimulation time
Stimulation_Data[5] = 1904; /// init the period
Burst_Number=0; /// Counter of the number of burst which is equal to
/// to the stimulation time
data_flag = 0; /// SPI received flag
firstpass_flag=1; /// To activate the PWM only once, when the button
/// is pressed.
instruction = 0x00; // starts output signal
Activated_Flag=0; /// indicates stimulation is on (1) or off (0).
while (1){
if (instruction == sti_start){ // starts the output signal, Slave_Define.h
if (firstpass_flag == 1){ // if the button is just pressed
P1DIR |= 0x0C; // P1.2 and P1.3 output
P1SEL |= 0x0C; // P1.2 and P1.3 TA1/2 otions
TA1R=0; // resets timer B to 0
TA1CTL = TASSEL_2 + MC_1; // timer B starts counting up
TA0R = 1; // resets timer A to 0
TA0CTL = TASSEL_2 + MC_3; // Starts counting, but TA0CCR0=0, so not counting.
Period_Count=0; // makes sure the Period counter is 0
P3OUT |= 0x10;
firstpass_flag =0; // to disable this if.
}
data_flag=0; // resets SPI received flag
instruction=0x00; // instruction idle
//P2OUT = 0xFF; // Turns on the Stimulation LED
Activated_Flag=1; // Activates Stimulation Flag
}
if ( Stimulation_Data[4] == Activation_Time){ // stops the output signal
TA1CTL = TASSEL_2 + MC_0; // timer B stop counting up
TA0CTL = TASSEL_2 + MC_0; // stops the PWM
TA0CTL |= TACLR;
// TA0CCR0 = 0; // assigns 0 to reset the counting direction.
Activated_Flag=0; // output off flag
if (firstpass_flag==0) {
data_flag=0; // resets SPI received flag
firstpass_flag=1; // resets the first pass flag.
Period_Count = 0;
}
P1SEL &= 0x00;
P1OUT &= 0xF3;
P3OUT &= 0xEF;
instruction=0x00; // instruction idle
Activation_Time=0; // Resets the activation time Number Count
}
}
}
// Echo character
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR (void)
{
char spi_ch;
double double_val;
spi_ch=UCB0RXBUF; receives the button activation code
...
instruction=spi_ch;
}
// Timer B0 interrupt service routine
#pragma vector=TIMER1_A0_VECTOR
__interrupt void Timer1_A0 (void)
{
if (Activated_Flag==1) { //This flag is active when output started
Period_Count++; // counts the period units
if (Period_Count == Stimulation_Data[5]) { // if counts reached the set period
Period_Count=0; // period counter reset
}
if (Period_Count == Stimulation_Data[3]) { // if count reached the set width
Burst_Number++; // count a burst
}
}
}
Hi Jose,
Can you verify the operation of the timer when using one of the code examples provided here. You should be able to use the msp430x21x2_ta0_16.c example.
You may also want to reference the User's Guide (pg. 394) in relation to modifying the Timer_A registers.
Jose Gonzalez said:TA1R=0; // resets timer B to 0
TA1CTL = TASSEL_2 + MC_1; // timer B starts counting up
TA0R = 1; // resets timer A to 0
TA0CTL = TASSEL_2 + MC_3; // Starts counting, but TA0CCR0=0, so not counting.
Here it may be better to use the statement TA1CTL = TASSEL_2 + MC_1 + TACLR; instead of directly modifying the TAR register.
One important thing when using the compare registers is that the compare event happens only if/when the timer counts to the given value.
This means, writing 0 to TAR does NOT initialize OUT1 and OUT2. Setting and resetting happens 1/2 period later, when TAR counts to 8000. But 1/4 period later, the signals toggle again (at 3840/4160). This is the 'double frequency' you see. Now TAR counts down to 0 (another 1/4 period) where nothing happens except that TAR counts up again. At 3840/4160, they are again toggled and at 8000, nothing happens since the signals have already been toggled twice since last time.
So you see the first wave with twice the frequency, but what you didn't notice (and what's not important, maybe) is that the signal is 1/4 period (90 degree) out of phase too.
There's no easy solution to the problem if you need the 'off time' when switching output level. if not, configure TAR to up mode only (TACCR=16000) and the outputs to 8000 using set/reset and reset/set mode.
if nyou need the 'off time', things are way more complicated. You'll need to initialize the OUT modes with 0 (using OUT bit and Out mode 0, Then you'll need an ISR for CCR1 (the second one coming) and when it is hit, switch OUT1 to high, then change outmodes to toggle toggle. Then disable ISR.
The outcome is: at start of TA, both start low. At 1/4 OUT1 goes high (manually by ISR). OUT2 stays low. At 1/2 (TACCR0), nothing happens. At 3/4 both are toggled. at 4/4 nothing happens, at 5/4 both are toggled again. You are still 90 degree off phase, but at least your duty cycle is correct from the first on. Disabling the PWM without glitches requires switching to outmode 0 again when both outputs are on the same level. This happens in the middle of TACCR1 and TACCR2. So select your timerB timeout so it triggers in the middle of TACCR1 and TACCR2 when both are cleared (both timers are synchroneously clocked, so this is no problem, you have a 3200 MCLK cycles window) and set both OUTs to 0 and the outmodes to 0.
Good luck.
Thank you very much both of you for the help, and the fast response.
I did what Jens-Michael Gross commented and it seems to be working, but I haven't have time to test it in different conditions, which I will do soon. I do need the 'off time', but I don't necessary care about the phase, but the shape itself. Therefore, this solution suits me very well! Thank you very much. Also, I took in consideration what Devin advised me.
Again thank you very much for the help!
**Attention** This is a public forum