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.

Cant get the LED toggle example working on an MSP-TS430PZ100 board

Other Parts Discussed in Thread: MSP430FG4618, MSP-TS430PZ100, MSP430FG4619, MAX232, MSP430F2274

I have been struggling with getting anyone from TI to answer phone calls or emails for the last 4 days. I have a MSP430-FET430UIF emulator which passes hardware self test described in the wiki. I successfully compiled and downloaded an LED toggle program (http://www.referencedesigner.com/tutorials/msp430/msp430_06.php)  on the target board which has an MSP430FG4618 microcontroller on it. The LED (D1) on the development board is connected to Pin 12 of the microcontroller. The MSP430FG4618 datasheet shows that Pin 12 is designated as P5.1. Anyhow, the LED does not blink at all. TI's radio silence for the last 4 days is very frustrating. Can some one please throw some pointers at me?

Actual code:

#include <msp430x14x.h>

unsigned int delay ( unsigned int x)
{
    unsigned int i,j;
    for (i = 0; i<= x; i++)
    {
      for(j=0;j<=1000; j++);
    }
    return 0;
}

int main( void )
{
    // Stop watchdog timer to prevent time out reset
    WDTCTL = WDTPW + WDTHOLD;
    P5DIR |= BIT1;
    while(true)
    {
      P5OUT|= BIT1 ; // P5.1 High
      delay(100);
      P5OUT&=~BIT1; // P5.1 Low
      delay(100);
    }

    return 0;
}

  • Every optimizing compiler will eliminate your delay functions content as dead code. J in the inner loop is not used for anything. So loop can be reduced to setting J to its end value (1000). And since it is never used later too, it can be completely eliminated. Same for I which is too never used. So all that remains from your delay loop is a call and a return, taking only a few MCLK cycles. I bet your eyes are way too slow to see the LED blinking at this speed, it's just 'glowing' a bit.

    It might help to make i and j global variables and declare them volatile. This will prevent them from being eliminated totally. It will not, however, keep the compiler from detecting the loops as empty.

    If you e.g. call a different (empty) function from within this loop, the compiler is forced to execute at least the call for the given number of loops. It's still ugly, but, well, if you don't have any timers running...

     

  • Thank you very much for your reply.

    If I changed the code to as shown below and then put a breakpoint at the point where P5.1 is high, then step through the code, I should have been able to see the LED light up. However, that doesn't happen either. Would you have any thoughts on what may be going on now? I have a MSP430FG4618 plugged in in the dev board. Did I include the right header for the MSP-TS430PZ100 board?

     

    #include <msp430fg4618.h>

    int main( void )

    {
        // Stop watchdog timer to prevent time out reset
        WDTCTL = WDTPW + WDTHOLD;

    P5DIR |= BIT1;
         P5OUT|= BIT1 ; // P5.1 High        
         P5OUT&=~BIT1; // P5.1 Low     <<<<< BREAKPOINT

         return 0;

    }

     

  • The headers do not belong to a board. They are made for a certain processor, no matter on which kind on PCB it is placed. So yes, you included the correct header.

    Since you can upload code and debug, I assume that the board is the right one for the 4618 :) (there's another board, the TS430PZ100A, I don't know the difference, and also the TS430PZ5x100 which I use for the 5438 processor).

    The LED is at Pin 12, which is port 5.1. Fine. Is the jumper on the other side of teh JTAG connector closed (J6)? It will disable the LED if removed. The text reads 'open J6 if LCD connected'. Note that it reads 'LCD' not 'LED'. If you connect an LCD, the LED needs to be disconnected. If you want the LED, close the jumper.

    Also, try to never place a breakpoint onto an instruction if you want to be sure that this instruction is NOT already executed when the debugger enters. Place a NOP(); in between. It takes one CPU cycle and is a harmless operation. Due to the pipelining in the CPU core, the next operation is already fetched when the previous is executed. Depending on the kind of operation, this might have side-effects. Always place a NOP() and write a comment that it is for breakpoint.

    Also, after disabling interrupts or entering LPM, add a NOP and do not use it as breakpoint. Add two nops if you want a breakpoint.

  • Thanks for clarifying my doubt about the header file. I am using the header file in a minimalistic manner (BIT1, P5DIR, P5OUT) so this shouldn't be an issue anyway. Based on your suggestion, I added two  __no_operation statements after disabling the WDT and also between the P5.1 toggle operation. However, I still cant get the LED to toggle. 

    I have the J6 connector in closed position since I don't have an LCD on this development board. I've used a multimeter to verify J6 terminates on Pin 12 of the uC also. The other end of the J6 does go to R3 and then to LED D1.

    I do have 3.07 VDC present on the board. The JTAG board also did the RED-RED-RED-GREEN POST cycle - so I believe it is working fine. Is there some way I can verify if the flash in MSP430FG4618 did actually get programmed? I noticed that even if I don't have the emulator plugged into my PC, IAR "downloaded"  the code anyway.

    Even though this should have had no effect I went ahead and soldered the included 32Khz crystal at the LFXTL location. The kit also has room for an XTCLK (which I don't have) but I would guess that this should not be an issue for the LED toggle program since there is no dependency on CLK.

  • SG said:
    Thanks for clarifying my doubt about the header file.

    The proper header file ensures that all (and only) the components (ports/USCI modules etc.) of a given processor are 'known' to the compiler. Also, you specify the exact processor type in your project. This should exclude any definitions in the header file which are available for a processor family (the header files are usually for a whole family) but not in this specific processor. So if a register is physically there, then it should be defined, if it is missing in this processor, it isn't defined.
    On the mspgcc compiler, it is sufficient to just include 'io.h', as this header file will automatically select the proper header files based on the project settings.

    Power, jumper and all seem to be okay.

    SG said:
    I noticed that even if I don't have the emulator plugged into my PC, IAR "downloaded"  the code anyway.

    that is weird. Really weird. And if this is true (I almost cannto believe it, since the usual problem is that IAR complains about the target NOT being found even if properly plugged), it is very well possible that your program never made it into your hardware. (and therefore you won't see an LED lighting up)
    It sounds like you're running your code in a software emulator instead on the real one. With a virtual (and invisible) LED flashing.

    If you do not connect the FET with the target board, IAR should complain. If you don't connect your FET with the PC, IAR should complain. If the code hasn't been programmed properly, IAR should complain. If it doesn't, I have no idea, what's going on. (and that's a rare case :) )

    It is possible (I'd have to look at the datasheet) that the 32kHz LFXT1 is automatically used as soon as it is running, for ACLK and WDT. At least I think I remember something like that from the 2xx series. The XT2 is only used if explicitely activated and selected. You can add a simple quartz crystal and two capacitors. This way you'll get a jitter-free and stable operating frequency for MCLK and SMCLK. (using DCO isn't very stable and using an FLL stabilisation - if available - introduces a clock jitter). But unless you want to use the UARTs at higher speeds, or require a jitter-free MCLK/SMCLK output signal, it isn't really necessary.

  • Thanks for staying with me on this. I think I goofed up on setting the project h correctly as you suspected.

    I found out a demo project set up (http://e2e.ti.com/support/microcontrollers/msp43016-bit_ultra-low_power_mcus/f/166/p/19537/76134.aspx#76134) and tried my LED Flashing code with the help of this cheat sheet.

    When I was ready to download the code onto the development board, IAR let me know that some firmware (not sure if it was referring to the emulator or the actual target) was outdated and asked if I wanted to install the latest. Given that the new firmware was downloaded over the course of a few minutes, I assume it refers to the emulator and not the target board. Either ways, this was a really good sign since IAR and the FET finally seem to be "communicating".

    After letting my PC download the latest firmware, I received an IAR warning: "Chosen derivative (MSP430FG4618) and actual hardware () do not match. Continue to download? Yes/ No". Since I don't want the emulator to become a brick, I thought I should check if this is a real warning or a CYA warning. I have double checked on the target board, the actual uC is indeed a MSP430FG4618 Rev G.

    Could it be that is this message relates to the uC inside the emulator? As I mentioned, I have a MSP-FET430UIF JTAG to USB emulator. 

    Thanks again for helping.

     

  • I Googled around and found that this "Warning" related to the MCU so I ended up clicking Yes since I can see that the MCU on the target board is indeed MSP430FG4618. Anyhow, the operation failed due to a memory read error - seems like IAR tdoes not handle this exception and it packed up.

     

    Since I had another MSP430FG4618 and two more MSP430FG4619s also, I tried them all. For MSP430FG4619, I had to make changes in the project before I tried. In each of these 4 cases, I got a memory access error which in turn caused IAR to pack up also.

    Unlikely that 4 MCUs' will be bad. Any more thoughts that might be helpful?

     

    Thanks

  • It is indeed unlikely that all MSPs are bad (except if you somehow applied AC power to the board, instantly frying the chips).

    It is possible that your FET does not know the chips. But then, the error message should be a different one. The FET needs to know the target processor, since it has to do all the JTAG communication. This is why you usually get a firmware update warning and IAR will upload the newest firmware to the FET, before using the FET for firmware uploads to the target. But only if the firmware is available.

    Since the header files for your processor are available, one should think that IAR knows how to program it. But maybe your version of IAR has updated headers but not (yet) the updated FET firmware. Perhaps you'll find newer FET firmware at the TI website. Anyway, the 4618 isn't really a new product, so I wonder why it couln't be supported by any recently bought programming tool.

    The 'chosen derivate' error seems to indicate that the FET cannot identify the target processor (hence no name in the brackets of the 'actual hardware'), so it seems that the FET is still unable to correctly identify (and access) the target processor. For whatever reason.

    The whole JTAG/FET compatibility stuff is one of the weakest points in the whole MSP development process. But others (Atmel, Microchip) aren't better.

    Of course there is the chance that you accidentally inserted the processor upside down. My MSP5438 has three dots on it on different corners, and the one identifying pin 1 is the smallest and deepest. Also it's easy to assume that pin1 is at the upper left corner (which it usually is on every programmer I've ever seen), but it isn't on my target board.Only a shy '1' between other text tells the true story. But well it's made form engineers for engineers, so I expect it being rather functional than handy. :)

  • Thanks for responding to my numerous emails.

    I am so thankful that you described exactly where Pin 1 needed to be. There is a JPEG in an online tutorial that shows the Pin 1 to be at the bottom left corner when the Board is held with the TI Logo at the top. Like a sucker, I blindly followed that JPEG without trusting logic.  

    Thanks to your persistence, my LED Flashing program now works. This forum is in good hands with people like you around.

  • SG said:
    Thanks for responding to my numerous emails

    You're welcome.

    SG said:
    There is a JPEG in an online tutorial that shows the Pin 1 to be at the bottom left corner when the Board is held with the TI Logo at the top.

    That's true for the TS430PZ5x100 and maybe the TS430PZ100, but (at least when trusting the PCB drawings in the FET manual) not for teh TS430PZ100A, where the TI logo is rotated 90° to the component names and 180° to the PCB name and revision number. So the '1' pin is at the lower right corner when holding the TI logo readable.
    Change happenz. (And confusion grows).

    Where's this online tutorial? It should be checked whether it still fits. TI (and not only TI) makes a LOT of copy/paste mistakes when migrating from one product to the next or even to the next revision of the same. The docs are full of copied errors, chapters have default notes copied over iven if they don't apply or are simply wrong, and, and, and. But the MSP documentation is still quite good compared to what I've seen from other manufacturers (where the datasheets are sometimes just scanned from a hand-writen designer note). Being a developer myself, I know that documentation is developers stepchild.

    Luckily, the MSP is quite a robust device. I've done my share of wrong connections and only lost one of all those I soldered myself during development. (not ocunting quite a few I had to cut down from the PCB due to uncorrectable bad  soldering - it's not easy to properly fix a TSSOP 64 pin package when your soldering iron's tip is twice the size of an IC pin).

    Sind the LED is flashing now, you can start doing 'real work'. When I started with the 5438, all I had was an LED for the initial development. With this and a frequency meter, I did all the testing and debugging until I finally got the UARTs working and had a text output for debugging messages. With pulse length and duty cycle, you can even transmit 16 bit values through a single LED :)

    SG said:
    This forum is in good hands with people like you around

    I wish I'd be paid for this :) But it's a good distraction when I'm weary hunting down my own bugs.

    Good luck with your project(s)!

  • The development board I have is the MSPTS-430PZ100 and the online picture I was referring to is at: http://focus.ti.com/graphics/tool/msp-ts430pz100.jpg. As you can see in the picture, the MCU has been placed incorrectly. The Pin 1 legend is on the top left corner of the board.

    My "real" work involves reading data off the UART interface; doing some sanity testing on the data and finally transmitting it as a Master to a device connected on the SPI interface. For this I was going to leverage a lot of the sample code TI has posted. The SPI interface will be implemented using USCI_B0 and the UART through USCI_A0. Like you, I will work on the UART first to "print" debug messages. Interesting thought about the LED though.

  • SG,

    Thanks for your feedback.

    It is indeed confusing to have the graphic show the target board  with the processor incorrectly placed.

    I will put in a request to get this fixed.

    Regards,

    Priya

  • Looks like there's a 'for illustration only' tag missing :)

    My guess is that the photographer has adjusted the processor so that Logo, part number and processor reading line up nicely.

    Unfortunately, there seems to be no '1' mark right beside the processor socket, so the only hint is the numbering on the brakout pins. On the PZ5X100 board, there is one.

    About the LED stuff, there is no chance to get the UART working properly, unless you made the clock module working first. With this LED, I got the clock module and the SVM working before I could rewrite my F1611 UART code to fit he USCI.

    If you need help for the SPI, there are some threads in this forum, complete with macros and inline functions from me. Using interrupts with SPI master doesn't make much sense (unless you have a really slow slave). For really fast transfers, I use DMA (like sending/receiving 512byte block to/from an SD card with 16MHz SPI-clock).

    Be careful with the sample code. It is usually designed to demonstrate how one thing works, but it often lacks the parts which make it work together with something else (like UART/SPI or more than one DMA channel or such). There are lots of pitfalls if you try to melt two sample code parts together.

  • Thankfully, a TI employee - Priya Thanighai, acknowledged the error and hopefully she will make sure that the picture doesn't cause grief to too many other people who rely on TI documentation.

    I do have need to write the SPI bus at 8/ 16 Mhz so I will greatly appreciate your pointing me to the macros and inline functions you have written for the DMA. Were you referring to your 3/2/2010 post: http://e2e.ti.com/support/microcontrollers/msp43016-bit_ultra-low_power_mcus/f/166/p/36582/127701.aspx#127701? I am not very familiar with MSP430 so your pointing me to anything more verbose will be very helpful.

    Thanks again.

     

  • No, this thread was about my own problems with the DMA when trying to drive the SPI through DMA. (I think this was actually my very first post here and the topic that originally brought me here).

    The macros are in a different thread: http://e2e.ti.com/support/microcontrollers/msp43016-bit_ultra-low_power_mcus/f/166/p/37139/132944.aspx There I posted the macros and also a lot of additional informations about SPI. You should read the whole first page, so you don't miss anything.

  • Thanks again. I have another sanity testing question for you.

    My PC of course doesn't have a Serial Port so I bought a Serial to USB adapter (has hardware in it so it can maintain timing). The said USB-RS232 shows up as COM4 in the Windows Device Manager. I also noticed that the MSP430PZ100 showed up as COM3 in the Device Manager.

    I thensoldered Pin 46 (UCA0_RXD) to Pin 3 of a RS232 connector and Pin 47 (UCA0_TXD) to Pin 2 of the same RS232 9-Pin DSUB. Then I hooked the USB-RS232 connector to the development board. So now I have COM4 on my PC set to listen to UCA0 RXD and TXD.

    I also downloaded HyperTerm for communicating on RS232.

    When I downloaded the sample TI 9600-N-8-1-None sample code on the MSP-TS430PZ100 board, I am unable to get the promised RXD to loopback on the TXD on COM4 (I also tried with COM3 just out of curiousity). Is there something glaringly wrong in my setup and/ or understanding of the MSP430?

  • SG said:
    Is there something glaringly wrong in my setup and/ or understanding of the MSP430?


    Ummmm... yes ;)

    The RS232 standard uses a symmetrical signal for the data transfer. A LOW signal is represented by a voltage level of 3..12V and a HIGH signal is represented as a voltage level of -12..-3V. The range from -3 to 3V is undefined. (the standard is also called V.24 because of the +-12V signal amplitude for increased signal integrity).

    Your USB connector most likely generates a +-5V output signal and also expects at least +-3V as input.

    The MSP, however, has TTL logic outputs. This means a LOW signal is represented as a voltage of 0..0.2V and HIGH is represented as (VCC-0.8V to VCC). You see, the voltage levels don't match and the signals are inverted too. This is standard for almost all UARTs in microcontrollers, not just for MSPs.

    The usual way to solve this is to add an RS232 converter such as MAX232 or its derivates between the MSP (or other microcontrollers) and the DSUB connector. The MAX322x family, for example, requires only 3V supply and generates the required positive and negative voltage levels with an intergrated charge pump. Depending on the exact type, it has more than one receiver and transmitter line, allowing the signal for hardware handshake to be converted to. It also adds some ESD and overvoltage protection.

    Luckily, the MSP is tough and the drivers inside the typical USB converter aren't that strong. So chances are you didn't blew up the port pins by applying -5V to them.

  • Thank you very much as always for your excellent diagnosis. 

    Fortunately, I found another development system, the ES2274 which has an on board RS 232 connector (and a bridge I hope) on it. 

  • I haven't been able to wrap my head around how the TimerA0 interrupt works and would thus be thankful for some advice. I was testing a "LED Flashing" program as below. As expected, after 10 toggles, the LED stops. After the said 10 toggles, I attempt to disable the interrupts - there seems to be no effect as the LED plays dead hereafter even though the while loop in main() should have caused the LED to start flashing again.

    Once again, I will be very thankful for your advice.

    #include "msp430F2274.h"

    void StartLEDP1_0(void)
    {
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
      P1DIR |= 0x01;                            // P1.0 output
      TACCTL0 = CCIE;                           // TACCR0 interrupt enabled
      TACCR0 = 10000;
      TACTL = TASSEL_1 + MC_2;                  // ACLK, contmode

      __bis_SR_register(LPM0_bits + GIE);       // Enter LPM0 w/ interrupt
    }

    // Timer A0 interrupt service routine
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      static volatile unsigned int i = 0;
     
      i++;
      if (i <=20)
      {
          if (TACCTL0 != CCIE)
              TACCTL0 = CCIE;
          P1OUT ^= 0x01;                            // Toggle P1.0
          TACCR0 += 10000;                          // Add Offset to TACCR0
      }
      if (i > 20) // Twenty toggles
      {
          TACCTL0 = ~CCIE;
          P1OUT = 0;
          //__bic_SR_register(LPM0_EXIT);
      }
     
    }

    void main(void)
    {
        while (1)
        {
            StartLEDP1_0();
        }
     
    }

     

  • I don't think your issue has anything to do with the Timer itself, but with the interrupt service routine.

    Your variable "i" doesn't every reset to 0 again in your program.  The interrupt service routine initially starts i=0 and increments by 1 every time the ISR is executed.

  • Thanks for your reply - greatly appreciate it.

    As you suggested, I assigned i = 0 in the if (i >20) condition. The code still behaves the same way - LED wont come on again.

    Is there another way to disable the interrupts that __bic_SR_register(LPM0_EXIT) ?

    Thanks for your help again.

  • I think the variable "i" gets reset to 0 every time the interrupt fires.

    Try declaring it outside the interrupt.

  • In your main, you constantly call teh timer init code over and over again, each time setting the timer registers and enabling the timer interrupt. You should only call it once (before the while loop), and then enable the interrupt when you need it.
    Also, it makes no sense to disable the timer interrupt in the ISR when you enable it with maximum speed in your main().
    For testing purposes, better leave it enabled, wait for the timer coutner variable to reach a certain value (e.g.50), then reset the variable to 0 to make the LED flashing again. Leave the timer interrupt on all the time, so it will continue counting up i.
    As an alternative (with no control from main at all), you can 1) remove clearing CCIE from the ISR, and make the i>20 to i==40 (so after i==20, port toggling stops until i==40) and reset i to 0 at this point (so port toggling starts again).

    Also, declaring a local variable (static or not) as volatile makes no sense. Since there exists no reference to it outisede the declaring function, it cannot be changed from outside and therefore isn't volatile. A good compiler wil noticew and dump the volatile modifier. If you pass a reference to I to a different function (or assign its reference to e.g. the DMA controller as destination address), then declaring it volatile might make sense, and the compiler will notice.

    For my first suggestion above, it would be necessary to define I as a global variable and not a local one. And since it is modified in the ISR, it then must be declared volatile.

  • Greatly appreciate your insight on the volatile keyword. I shall keep your advice in mind going forward. 

    In reality, I was looking for a mechanism for disabling all the interrupts after the LED had toggled X number of times. As you had suggested earlier, I was looking to use the LED as a pseudo "printf" statement by toggling it some X times before shutting it off. Therefore, after X toggles, I wanted to disable all interrupts and since there is still a thread executing an infinite while loop in main(), I was hoping that execution would resume again in that thread since I took the MCU out of an interrupt driven mode and into a "polled" mode. For that purpose I had thrown in a  __bic_SR_register(LPM0_EXIT) to see if I could disable all interrupts. As you can see I ended up commenting that since it didn't do as expected.

    As always, I will greatly appreciate your thoughts on how else I could return back to main() once the LED has done its job of toggling X times.

  • Why not setting a global variable to a certain value (an even one, as you need two toggles to make the LED blink once) and then just count it down to zero in your ISR:

    volatile int pulses = 0;

    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      TACCR0 += 10000;                          // Add Offset to TACCR0
      if(pulses){
        pulses--;
        P1OUT ^= 0x01;                            // Toggle P1.0
      }
    }

    main(){
      ...
      pulses=4;
      while(1);
    }

    You'll need, however, some sort of delay timer, so you can wait some time before starting the next pulse. This can be done by just adding a second global counter:

    volatile int pulses = 0;
    volatile int delay = 0;

    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      TACCR0 += 10000;                          // Add Offset to TACCR0
      delay++;
      if(pulses){
        pulses--;
        P1OUT ^= 0x01;                            // Toggle P1.0
      }
    }

    main(){
      ...
      pulses=4;
      while(pulses); // waits until all (4/2) pulses are given
      delay = 0;
      while (delay<100); // wait another 100 timer ticks
      pulses=8;
      while(1); // and another 8/2 pulses.
    }

  • Thanks again.

    That would definitely work but it would keep the TimerA running and firing every 10000 ticks but since pulse == 0, the LED wouldn't toggle any more. However, I was interested in knowing if there is some way I can disable TimerA0 altogether by doing something like __bic_SR_register() etc?

  • Well, if you have a timer, why not using it for delays too rather than just pulsing the LED.
    You can, of course, just disable the timer IE bit once the pulses have reached 0 (in an else statement) and exit LPM (teh macro for doing so is compiler dependent, so check the docs).

    In main, you'll need to set pulses, enable the timer and enter LPM. Once the LED stops blinking, main() will continue. To start blinking again, you need to set pulses to the new value (so it hasn't to be the same each time!), initialize TimerA again and enter LPM.  Note that it is necessary, to reset the TAR to 0 too (timer A counter register), or else you'll have a delay of up to 65536 pulses before blinking starts, depending on the current TAR value in the moment you configure CCR0.

    Anyway, you won't have a delay then that will help you to make a gap before the two blink sequences. For reasons I explaind several tiem sin this foum, just making a for loop won't give a suitable delay. You can, however, extend the ISR to count down the pulses variabel and a delay variable and it will wake-up the main once both have reached zero, so you can use the same ISR for blinking the LED and just doing a delay. Only your imagination limits the possibilities :)

  • Thanks for your explanation. Per your suggestion, I disabled the LPM0 when the pulse count went down to 0 and that successfully caused main() to move forward to the next statement.

    However, I am intrigued by a statement you made: "why not use the timer for delays too rather than pulsing the LED". Since the current Timer A0 ISR handler causes the LED to pulse X times, how would I go about mapping the ISR to a "delay" timer instead of the LED pulsing functionality at run time? I don't want to get rid of the LED Pulsing handler since I intend to use it for debug purposes.

  • Simply use two variables. One for the pulse and one for the delay.

    count them down both.

    As long as the pulse coutner is above 0, toggle the output for the LED.

    Then you have two options:
    Either you exit LPM mode only if the delay counter is zero (meaning the any delay has ended, or there is none) Then the LED will flash while main is continuing and main will only sleep when a delay is requested,
    Or you exit LPM when both, delay and pulse, have reached zero. Then main will sleep until LED has finished blinking and any delay has passed, whichever takes longer. (you can also decrement delay only if pulse is zero, so adding any delay, if any, starts after the LED has done flashing).

    In any case, you can set an LED pulse count and a delay at the same time and then enter LPM. You don't need to split this into two steps. But you can, if you want to use them separately.

    For my own projects, I have the timer running in 1ms intervals and it will, besides other things, handle up to 8 LEDs, switch them on for a given number of milliseconds, switch them off for some ms and then on again, or let them blink on and off with a given ratio for on and off duration (duty cycle). Well, that has grown over time to fulfil various jobs. And it started as simple as the function you currently use. Or even simpler: just set the port to 1 as long as pulses is != 0 and set it to 0 once pulses is 0.

**Attention** This is a public forum