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.

PWM sine wave : A question



I have generated a 10 kHz sine wave. It works fine and I had no problems with it.
Now the real problem I had was when:
I have a requirement that every 1 sec of the sine wave output , I need to stop the sine wave for 250 microseconds.
I used Timer B with ACLK, counted for 31994 cycles to interrupt. In the ISR I used the same to count 250 microseconds.
The code for this modification is in "sine_with_interrupt.txt"
Now I don't see any waveform at all. I am suspecting that there is only a slight mistake or overlook I must have made.
Could anyone please help.
  • HI Elec. ss,

                   A quick look in to the code, gave me an impression that, your TimerB [initially(1sec ) and later changes to (200us)] period is too short and you will loop in Main code and TimerB isr. try this, if u can c the wave form on the scope.

    __interrupt void TB0_ISR(void)
    {
      //TBCCR0 = 7-1;                           // 32 Khz clock, 999.8 ms delay, Clock period of TBCCR0

    TBCCTL1 &= ~CCIFG;

    //STOP timera AND timer b HERE

    _DELAY_CYCLES(/*200 MICRO SECONDS DELAY HERE*/);

    //  start timer a and b here
      TBCTL = TBSSEL_1 + MC_1;
      //TBCTL = 0;                                // Clear Timer_A control registers
      __bic_SR_register_on_exit(LPM0_bits);     // Exit LPMx, interrupts enabled
    }

    Regards,

    Sri.

  • There are several oddities...

    First, you don't configure TBCCR0 before enabling teh TimerB interrupt. TBCCR0 may or may not contain 0 at this point, giving you a 30µs delay or a 2s delay.

    Then, setting TBCCR0 to 6 gives you a 213µs delay, not a 1s delay, as the comment indicates. And not 250µs. Use 7 (8-1) for 244µs and 32759 for 999.756µs delay.

    Also, I don't see any code that will stop the sine wave.

    Finally, you use the DMA triggered by the DAC12 interrupt. However, DMA can only take place when the CPU isn't running. So while the CPU executes code, the DMA will create a cumulating jitter. Using a timer to trigger the DMA will still create jitter (and therefore sine wave distortion) when the CPU is currently executing instructions, but at least the jitter won't be cumulating.

    "01" and "027" are octal values, not decimal values., so the resulting TimerA period is 24 SMCLK cycles. Intentional?

    TBCCTL0 &= CCIE seems to be wrong. It doesn't disable the interrupt, it clears all bits in TBCCTL0 except the interrupt enable bit. So the instruciton is redundant and keep the interrupt enabled: the next comes with the next timer tick. You probably meant "~CCIE". Nw the next tick is 240 MCLK cycles away, so it shouldn't lock the CPU inan eternal ISR loop.

    The comments in the ISRs talk about cont mode, but MC_1 is up mode  (which is apparently the correct mode).

    However, I don't see a reason why the DMA doesn't start. It should. Except if the DCO calibration values have been erased and are illegal and the CPU crashes right when setting up the clocks.

  • Thank You sri,

    now the waveform is there, but there is no stopping it. I may have made some mistakes in the timers. I will post my issues and codes shortly

  • Hi Jens,

    Thank you for the response.

    I tried to fix the problem step by step as you have pointed out. I have made the following changes and everything worked fine. I am still testing it thoroughly though. I will let you know if there is more problems. Thank you for your suggestions

    1. I configured Timer B interrupt using: 

    TBCCTL0 = OUTMOD_3;                              // TBCCR1 set/reset
    TBCCR0 = 32760-1;                                      // Clock period of TBCCR0 for 1 sec @ 32 kHz clock
    TBCCTL0 |= CCIE;                                        // Enable timer B interrupt
    TBCTL = TASSEL_1 + MC_1;                    // ACLK, up mode
    __enable_interrupt();

    2. I want to stop the sine wave once the 1 sec is reached. In the ISR for timer B, I made following changes

    #pragma vector = TIMERB0_VECTOR
    __interrupt void TB0_ISR(void)
    {

    TACTL = 0; //Clear Timer A
    TBCTL = 0; //Clear Timer B


    TACCTL1 &= ~CCIFG;                          //STOP timer A AND timer B 
    TBCCTL0 &= ~CCIFG;

    __delay_cycles(2000);
    __delay_cycles(2000);

    TBCTL = TBSSEL_1 + MC_1;      // start timer A and B here
    TACTL = TBSSEL_2 + MC_1;
    //TACCTL1 |= CCIE;

    __bic_SR_register_on_exit(LPM0_bits); // Exit LPMx, interrupts enabled
    }

  • Elec. ss said:
    __delay_cycles(2000);

    Using busy-waiting delays inside an ISR is a horrible thing. It contradicts the use of low-power-modes. So see this as a quick hack. A 'correct' way would be switchign between two TimerB configurations with a static flag. If the flag is clear, TiemrA is halted and TimerB is set up for a second delay and the flag is set. On next ISR entry, the flag is set and the timerB is configured for the long delay, TimerA is restarted and the flag is cleared.

    I still don't see how the code could stop the DMA. Or was the trigger you use for the DMA a TimerA trigger? The comment was talking about DAC12IFG as trigger. (I didn't check the value). If so, keep in mind that you're halting (stretching) the sine wave somewhere in the middle, not at their zero-crossing point, giving the output a DC offset.

  • Jens,

    Thank you for the comments,

    I looked up my waveform and indeed, there is a DC when I stop the sine wave for the 200 us.

    To fix this, 

    I made the changes:

    DMACTL0 = DMA0TSEL_7 + DMA1TSEL_7;        // Timer A triggers

    Other thing I consider was: I made

    TBCCR0 = 32768-1;    // an Integer multiple of 32, on a hunch

    However I still see that, when the waveform is paused every 1 sec. it starts at a random point and not at the zero crossing. causing a DC voltage During the interval.

    Also, for __delay_cycles() inside ISR, I plan to change it later. I have attached my code for your reference

    Please suggest me on the these problems.

  • When you stop the PWM, you reset the DAC outpu tto 0 from whereever it currently is. This eliminates the DC during the pause. However, when the timer is enabled agian, teh DMA continues stuffing the DAC from where it was, making a jump back to the point where it was when you stopped the timer and manually set the DAC output to 0.

    The correct way would be that instead of stopping the timer, you switch the DMA from repeated to signle cycle mode, so it finishes the current wave and then ends. When the signal is to be re-enabled, you have to restart the DMA in repeated block mode so the output begins anew from zero crossing point. This won't stop the wave output mid-wave when the 'off' time begins but lets it continue to the end (avoiding high-frequency transients). And starts the wave smoothly again when the 'off' time is over.

**Attention** This is a public forum