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.

MSP430F5529: resetting a delayed monostable pulse

Part Number: MSP430F5529

Hello Everyone,

I would like to have a pair of delayed monostable pulses that can be terminated by an input or an interrupt.   (One of the monostables will set a status flag for the other one.)
(I am only working with one pulse thus far, eventually I will need two.)
Specifically I want to:

1) drive an LED
2) close a switch (producing an output pulse.)
3) reset the timer
4) turn off the LED
5) start the timer with a delay period
6) open the switch
7) after delay, turn on the LED 

Repeat steps 2-6 indefinitely. . I am using the 32,768 crystal as the ACLK clock.  ( I would prefer to have step 2 have a fast ~ a few microseconds delayed output pulse.)

So far I have been able to close the switch and reset the timer which are steps 2 and 3.   I can start the timer in step 4, and I can turn on the LED in step 5. 

What I can not do is turn OFF the LED, in step 4. (i.e. one of Port P2.4, P2.5)  I am using the PWM, pulse width modulation approach, with the switch closure as an interrupt in step 2.  The timer output is the LED drive. 

Any switch closure resets the TAR timer, to zero, which is desired. Whatever state the P2.4 or P2.5  LEDs are in, (on or off) remains frozen in place while the timer begins a new delay cycle.  

I have tried several approaches to modifying the registers to effect P2.4,  I will detail below.  None have worked.  

I could try using software to use a manually controllable auxiliary port as the LED driver, say P2.3,  or  even a hard reset on the NMI input.  That would require two separate chips I think.

I have tried setting TA2CTL = MC_0  and TACLR,, and setting TACCR0 and TACCR2 to various values.  Also setting TA2CCTL2 = OUTMOD_7  Nothing turns off P2.4, or P2.5.  

Should I try to drive port P2.3  using logic like   if(P2OUT && BIT4 == 0x10)  P2OUT &= ~BIT3;  Or should I hard reset the uP with NMI?  Any ideas?

Here is my code for the MSP430F5529:  

#include <msp430.h> //for MSP430F5529
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= BIT0; // Set P1.0 to output direction
P2REN |= BIT1; // Enable P2.1 internal resistance
P2OUT |= BIT1; // Set P2.1 as pull-Up resistance
P2IES |= BIT1; // P2.1 Hi/Lo edge
P2IFG &= ~BIT1; // P2.1 IFG cleared
P2IE |= BIT1; // P2.1 interrupt enabled

P2DIR |= BIT3+BIT4+BIT5; // P2.3, P2.4and P2.5 output
P2SEL |= BIT4+BIT5; // P2.4 and P2.5 options select

TA2CCR0 = 65535; // PWM full Period (16 seconds)
TA2CCTL1 = OUTMOD_3; // 7=CCR1 reset/set, 3=set/reset
TA2CCR1 = 29000; // CCR1 PWM duty cycle (7 seconds)
TA2CCTL2 = OUTMOD_3; // 7=CCR2 reset/set, 3=set/reset
TA2CCR2 = 21000; // CCR2 PWM duty cycle (5 seconds)

P2OUT != BIT3;
P1OUT |= BIT0;
                         // 1=ACLK,up mode, div8=16 sec, clear TAR
TA2CTL = TASSEL_1 + MC_1 + ID_3 + TACLR; // Starts the timer
__bis_SR_register(LPM4_bits + GIE); // Enter LPM4 w/interrupt
__no_operation(); // For debugger
}
// Port 2 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(PORT2_VECTOR))) Port_2 (void)
#else
#error Compiler not supported!
#endif
{
P1OUT ^= BIT0;

TA2CTL = TASSEL_1 + MC_1 + ID_3 + TACLR; // 1=ACLK,up mode, div8=16 sec, clear TAR

P2IFG &= ~BIT1; // P1.4 IFG cleared
}


Thank you!  -Sandy

  • I'm not completely sure what you're doing, but I'll just mention that setting OUTMOD=0 and wiggling the OUT bit gives you GPIO-ish control over the output.

  • Specifically: Since you're (implicitly) setting OUT=0, in the ISR, after you reset the timer, just set each of the TA2CCTL's to OUTMOD_0, then back to OUTMOD_3. The first setting will force the pin to 0 (=OUT) and the second will put you back into PWM. If either of the CCRs were small numbers, there could be a race, but in this case you have plenty of time.

    In the PWM modes (OUTMOD>0) the pin signal only changes on a compare event, and TACLR doesn't cause an event. You can also use this trick to create an initial condition in PWM cases where it's very important that the first cycle is correct (often the first cycle doesn't matter much).

  • Bruce,

    Thank you for your reply and the suggestion.   I have made considerable progress using "OUTMOD_0".   My code follows.  

    I was able to use "TA2CCTL1 = OUTMOD_0; "  but  I could not use "OUT0" or "OUT_0"  or “OUT_1” etc. with it.
     Meaning trying, "TA2CCTL1 = OUTMOD_0 + OUT_0" gives me an error.  What is the correct syntax, please?

    None the less it does seem to default to 0. So my code will run.  

    Goal: I am trying to drive a clock pendulum with a magnetic drive to maintain a constant amplitude. There is an LED photogate at bottom dead center (BDC) and one at some convenient amplitude (AMPL) of oscillation.  The idea is to maintain the amplitude so it is essentially constant.  As the pendulum decays after a few swings, it gets a brief (~5ms) magnetic pull to the side, -but only at the BDC position.  This location for impulse minimizes period variation/error.  

    My comments reflect this approach.  The BDC and AMPL LEDs would be the photogate LEDs, and are pulsed as needed to conserve battery power. Pressing the switches simulates blocking the photogates.  (I know I need a bit more logic to make actual photogates work in this way.)  

    Imagining I want an ~8 second period on my pendulum, and I measure the amplitude at ~6 seconds. 
    So I now have things arranged so that the timers run and drive the AMP LED starting at ~5 seconds and the BDC LED starting at ~7 seconds. If I press the S1 switch at P2.1, (simulating blocking the AMPL photogate) then I enter the Port 1 ISR.  That latches the P2.3 port HIGH as the AMPL flag and shuts off the Ampl LED at P2.5 .

    If I press switch S2 at P1.1 simulating the position is at the bottom, I turn off the BDC LED and reset the Timer TAR to restart the timer for the next cycle 

    Then I would like to check the AMPL flag on P2.3. If it is sufficient, (HIGH) just reset the flag to LOW. If it is LOW, trigger the magnet with a brief (~1-5 ms) pulse. 

    Most of this works now, except….

    1) I don’t know if the “if ()… else…” has the correct logical or syntactical form to verify the state of the P2.3 bit and then produce the output I want.

    2) I don’t see the desired magnet trigger pulse (p2.6) by eye, (I am not using an oscilloscope) and I would like to know it is there, or add a delay to lengthen it. (That for loop is using the 32KHz ACLK?)

    3) Final approach would use a ~100Khz 10% duty factor for the BDC and AMPL LEDs illumination to save more battery power.  Can I use the 1 MHz clock to generate this and AND it with the LED drive, possibly with 4000 series logic?

    4) As mentioned, I don’t know the syntax for the combined "TA2CCTL1 = OUTMOD_0 + OUT_x" (x=1,0) command. 

    Question: I notice that the NMI reset for the board S3 does not “reset” after loading the code, but if I cycle power, then it works as expected. I don’t recall seeing why this would be the case in reading the Family Uesr Guide? 

    And thank again for the OUTMOD_ 0 suggestion. It is literally 2 lines in a thousand page manual. Hard to find such a thing, and it is very much the way to go. You comment about getting the first cycle correct, makes sense too. I knew there had to be a way to make a monostable pulser out of this board. 

    Thanks. Sandy

    #include <msp430.h> //for MSP430F5529
    int main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
    //setup the outputs
    P1DIR |= BIT0; // Set P1.0 to output direction // BDC annun. toggle
    P4DIR |= BIT7; // Set P4.7 to output //AMPL annun. toggle
    P2DIR |= BIT4; // P2.4 drive for BDC LED, photogate
    P2DIR |= BIT5; // P2.5 drive for AMPL LED photogate
    P2SEL |= BIT4 + BIT5; // P2.4 and P2.5 options, select Timer outputs
    P2DIR |= BIT3; // Store AMPL flag bit here (1=suff ampl, 0=insuff ampl)
    P2DIR |= BIT6; // magnetic DRIVE SCR trigger, i.e. the output

    //setup the input P2.1 // AMPL LED photogate // measures pendulum ampl.
    P2REN |= BIT1; // Enable P2.1 internal resistance
    P2OUT |= BIT1; // Set P2.1 as pull-Up resistance
    P2IES |= BIT1; // P2.1 Hi/Lo edge
    P2IFG &= ~BIT1; // P2.1 IFG cleared
    P2IE |= BIT1; // P2.1 interrupt enabled

    //setup the input P1.1 // BDC LED photogate // controls LED timing + drive
    P1REN |= BIT1; // Enable P1.1 internal resistance
    P1OUT |= BIT1; // Set P1.1 as pull-Up resistance
    P1IES |= BIT1; // P1.1 Hi/Lo edge
    P1IFG &= ~BIT1; // P1.1 IFG cleared
    P1IE |= BIT1; // P1.1 interrupt enabled

    //timing: want 3/4 of a second, and 1 second, eventually. (ID_x = divisor)
    TA2CCR0 = 65535; // PWM full Period (16 seconds)
    TA2CCTL1 = OUTMOD_3; // 1=set, 7=CCR1 reset/set, 3=set/reset
    TA2CCR1 = 29000; // CCR1 PWM duty cycle (44%, ~7 seconds)
    TA2CCTL2 = OUTMOD_3; // 1=set, 7=CCR2 reset/set, 3=set/reset
    TA2CCR2 = 21000; // CCR2 PWM duty cycle (32%, ~5 seconds)
    //initialization
    P2OUT &= ~BIT3; //Set AMPL flag to 0, (Magnet drive ON)
    P2OUT &= ~BIT6; //Set Magnet drive bit to OFF.
    P1OUT |= BIT0; // Set AMPL Annunciator ON
    P4OUT |= BIT7; // Set BDC annunciator ON

    // 1=ACLK,up mode, div8=16 sec, clear TAR
    TA2CTL = TASSEL_1 + MC_1 + ID_3 + TACLR; // Starts the timer
    __bis_SR_register(LPM4_bits + GIE); // Enter LPM4 w/interrupt
    __no_operation(); // For debugger
    }
    // Port 1 interrupt service routine
    //ISR ==> determines position is BDC // Mag drive applied at BDC, if needed
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
    #else
    #error Compiler not supported!
    #endif
    {
    volatile unsigned int i; // needed for FOR loop, but delay doesn't work???
    TA2CCTL1 = OUTMOD_0; //Shut off P2.4 (BDC LED)
    TA2CCTL1 = OUTMOD_3; // Restore normal mode
    P4OUT ^= BIT7; // toggle P1.0 as annunciator
    // 1=ACLK,up mode, div8=16 sec, clear TAR
    TA2CTL = TASSEL_1 + MC_1 + ID_3 + TACLR; //reset timer
    // if(P2OUT && BIT4 == 0x10) P2OUT &= ~BIT3;

    //Is this "if ()... else... " properly setup??
    if(P2OUT && BIT3 == 0x08) // if flag P2.3 is high, Turn off AMPL LED
    {
    TA2CCTL2 = OUTMOD_0; //Shut off P2.5 (AMPL LED)
    TA2CCTL2 = OUTMOD_3; // Restore normal mode
    P2OUT &= ~BIT3; // reset the AMPL flag.
    }
    else //Ampl = LOW so magnetic drive is needed. Trigger it.
    {
    P2OUT |= BIT6; // Magnet drive ON (trigger pulse OUT)
    for(i=20000;i>0;i--);//***ADD delay here??? i.e pulse stretcher.
    //***maybe ~1 ms or 100 microsec?
    P2OUT &= ~BIT6; // turn off trigger.
    //AMP LED is already low.
    }
    P1IFG &= ~BIT1; // P1.1 IFG cleared, BDC photogate
    }

    // Port 2 interrupt service routine
    //ISR ==> determines if pendulum amplitude is high enough, store in P2.3
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC)
    #pragma vector=PORT2_VECTOR
    __interrupt void Port_2(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(PORT2_VECTOR))) Port_2 (void)
    #else
    #error Compiler not supported!
    #endif
    {
    TA2CCTL2 = OUTMOD_0; //Shut off P2.5 (AMPL measuring LED)
    TA2CCTL2 = OUTMOD_3; // Restore normal mode
    P2OUT |= BIT3; // set P2.3 as AMPL flag.
    P1OUT ^= BIT0; // toggle P4.7 as annunciator
    P2IFG &= ~BIT1; // P2.1 IFG cleared, AMPL photogate
    }

  • > if(P2OUT && BIT3 == 0x08) // if flag P2.3 is high, Turn off AMPL LED

    This doesn't do what you want. Also, P2OUT might reflect the pin state, but P2IN really should. Try:

    > if((P2IN & BIT3) == BIT3) // if flag P2.3 is high, Turn off AMPL LED

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

    I don't recommend using a for() loop for a delay. I suggest __delay_cycles() instead; among other things it's immune to optimization. I think your clock is 1MHz, so a 50ms delay (visible as a "blip") would be "__delay_cycles(50*1000);"

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

    You can generate a 100kHz PWM with a 1MHz clock (CCR=10-1) with a resolution of 10% duty (i.e. 10 possible settings).

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

    Some of the newer devices (.h files) define OUT_0 and OUT_1, but my copy of f5529.h doesn't. Not mentioning OUT implicitly sets it to 0. When I want to remind myself that I'm intentionally setting it to 0 I write it as "(0*OUT)", but that's just for show..

  • Bruce,
    It will take me a while to work though your comments.  Basically, I make conjectures and test them.  So a set of them takes a while.

    Thank you for you patience, with my errors in naming, syntax and so on.  I don't fully know, what I don't know yet.  Once I gain enough experience  the learning curve will go faster.  Basically, these are amazing chips and they can do many many things, that is my basic assumption.  Finding they way to implement a given function, is the key.  

    This page looks useful with respect to the OUTMODx, OUTMOD_x and OUTMOD__x naming and function. 

  • Posting my code with Bruce's suggestions incorporated. 

    I now have to combine as a logical AND,  the ~58.0 Khz oscillator with the P2.4 and P2.5 bits.  Should that be external 4000 series CMOS or in software?  
    -Sandy 

    #include <msp430.h> //for MSP430F5529
    int main(void)
    {
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
    // Set up the high freq, low duty oscillator
    P1DIR |= BIT2+BIT3; // P1.2 and P1.3 output
    P1SEL |= BIT2+BIT3; // P1.2 and P1.3 options select
    TA0CCR0 = 9; // PWM Period/2
    TA0CCTL1 = OUTMOD_7; // CCR1 toggle/set=6, 7=reset/set
    TA0CCR1 = 7; // CCR1 PWM duty cycle
    TA0CCTL2 = OUTMOD_7; // CCR2 toggle/set
    TA0CCR2 = 1; // CCR2 PWM duty cycle
    TA0CTL = TASSEL_2 + MC_3 + TACLR; //ON // SMCLK, up-down mode, clear TAR
    //58.67 Khz ^^^
    // do the same ^^^ for TA1.1 Pin19(board) port P2.0 for a second channel.
    // The above oscillator could be ANDed to the P2.4 bit with an AND gate
    // in CMOS logic to make the final LED drive with a low duty cycle.

    //setup the outputs
    P1DIR |= BIT0; // Set P1.0 to output direction // BDC annun. toggle
    P4DIR |= BIT7; // Set P4.7 to output //AMPL annun. toggle
    P2DIR |= BIT4; // P2.4 drive for BDC LED, photogate
    P2DIR |= BIT5; // P2.5 drive for AMPL LED photogate
    P8DIR |= BIT1; // magnetic DRIVE SCR trigger, i.e. the output
    P2SEL |= BIT4 + BIT5; // P2.4 and P2.5 options, select Timer outputs
    P2DIR |= BIT3; // Store AMPL flag bit here (1=suff ampl, 0=insuff ampl)

    //setup the input P2.1 // AMPL LED photogate // measures pendulum ampl.
    P2REN |= BIT1; // Enable P2.1 internal resistance
    P2OUT |= BIT1; // Set P2.1 as pull-Up resistance
    P2IES |= BIT1; // P2.1 Hi/Lo edge
    P2IFG &= ~BIT1; // P2.1 IFG cleared
    P2IE |= BIT1; // P2.1 interrupt enabled

    //setup the input P1.1 // BDC LED photogate // controls LED timing + drive
    P1REN |= BIT1; // Enable P1.1 internal resistance
    P1OUT |= BIT1; // Set P1.1 as pull-Up resistance
    P1IES |= BIT1; // P1.1 Hi/Lo edge
    P1IFG &= ~BIT1; // P1.1 IFG cleared
    P1IE |= BIT1; // P1.1 interrupt enabled
    cv
    //timing: want 3/4 of a second, and 1 second, eventually. (ID_x = divisor)
    TA2CCR0 = 65535; // PWM full Period (16 seconds)
    TA2CCTL1 = OUTMOD_3; // 1=set, 7=CCR1 reset/set, 3=set/reset
    TA2CCR1 = 29000; // CCR1 PWM duty cycle (44%, ~7 seconds)
    TA2CCTL2 = OUTMOD_3; // 1=set, 7=CCR2 reset/set, 3=set/reset
    TA2CCR2 = 21000; // CCR2 PWM duty cycle (32%, ~5 seconds)
    //initialization
    P2OUT &= ~BIT3; //Set AMPL flag to 0, (Magnet drive ON)
    P8OUT &= ~BIT1; //Set Magnet drive bit to OFF.
    P1OUT |= BIT0; // Set AMPL Annunciator ON
    P4OUT |= BIT7; // Set BDC annunciator ON

    // 1=ACLK,up mode, div8=16 sec, clear TAR
    TA2CTL = TASSEL_1 + MC_1 + ID_3 + TACLR; // Starts the timer
    __bis_SR_register(LPM4_bits + GIE); // Enter LPM4 w/interrupt
    __no_operation(); // For debugger
    }
    // Port 1 interrupt service routine
    //ISR ==> determines position is BDC // Mag drive applied at BDC, if needed
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=PORT1_VECTOR
    __interrupt void Port_1(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
    #else
    #error Compiler not supported!
    #endif
    {
    TA2CCTL1 = OUTMOD_0; //Shut off P2.4 (BDC LED)
    TA2CCTL1 = OUTMOD_3; // Restore normal mode
    P4OUT ^= BIT7; // toggle P1.0 as annunciator
    // 1=ACLK,up mode, div8=16 sec, clear TAR
    TA2CTL = TASSEL_1 + MC_1 + ID_3 + TACLR; //reset timer

    if((P2IN & BIT3) == BIT3) // if flag P2.3 is high, Turn off AMPL LED
    {
    TA2CCTL2 = OUTMOD_0; //Shut off P2.5 (AMPL LED)
    TA2CCTL2 = OUTMOD_3; // Restore normal mode
    P2OUT &= ~BIT3; // reset the AMPL flag.
    }
    else //Ampl = LOW so magnetic drive is needed. Trigger it.
    {
    TA2CCTL2 = OUTMOD_0; //Shut off P2.5 (AMPL LED)
    TA2CCTL2 = OUTMOD_3; // Restore normal mode
    P8OUT |= BIT1; // Magnet drive ON (trigger pulse OUT)
    __delay_cycles(900); // (900) is ~ 900 usec, ~90um ,
    P8OUT &= ~BIT1; // turn off trigger.
    }
    P1IFG &= ~BIT1; // P1.1 IFG cleared, BDC photogate
    }

    // Port 2 interrupt service routine
    //ISR ==> determines if pendulum amplitude is high enough, store in P2.3
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC)
    #pragma vector=PORT2_VECTOR
    __interrupt void Port_2(void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(PORT2_VECTOR))) Port_2 (void)
    #else
    #error Compiler not supported!
    #endif
    {
    TA2CCTL2 = OUTMOD_0; //Shut off P2.5 (AMPL measuring LED)
    TA2CCTL2 = OUTMOD_3; // Restore normal mode
    P2OUT |= BIT3; // set P2.3 as AMPL flag.
    P1OUT ^= BIT0; // toggle P4.7 as annunciator
    P2IFG &= ~BIT1; // P2.1 IFG cleared, AMPL photogate
    }

**Attention** This is a public forum