Stop after 5 times for(;;) loop

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
AnCo_2736831
Level 4
Level 4
25 likes received 10 likes received 10 likes given

Hi All,

I am using a Long Deep Sleep program for PSoC 4 BLE using this link's program: PSoC 4200M WDT Long Deep Sleep .

I am wondering how to make the program stop after 5 blinks from the LED. For the for(;;) loop, I tried using:  for (count=1; count<=N1; count++), but this did not work.

Does anyone know how to accomplish this?

Thanks,

Andrew Collins

0 Likes
1 Solution
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Use a static or global variable which is tested in the interrupt handler for being >= 10.

If not, toggle the led and increment the variable.

void wdtCallback()
{

static uint8 Counter = 0;

     if(Counter >= 10) return;

     Counter++;
     RED_Write(~RED_Read());
}

Happy coding

Bob

View solution in original post

30 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Use a static or global variable which is tested in the interrupt handler for being >= 10.

If not, toggle the led and increment the variable.

void wdtCallback()
{

static uint8 Counter = 0;

     if(Counter >= 10) return;

     Counter++;
     RED_Write(~RED_Read());
}

Happy coding

Bob

Hi Bob,

That works. Now I want separate on time (0.5s) and off-time (1s) for the LED. I tried to do as below but the deep sleep does not work.

void wdtCallback()

{

    static uint8 Counter = 0;

    LED_Write(1);

    CyDelay(500);

    LED_Write(0);

    if(Counter >= 10) return;

    Counter++;

}

As a general rule of thumb: NEVER use a delay in an interrupt handler. This can make the system non-responsive.

Instead I would suggest you to set the WDT to 100ms and use that as a timebase. This will allow you to have a time resolution of 100ms.

Bob

Bob

We want to use two WDTs for long delay. We have totally 3 WDTs in PSOC4 BLE. What if we want to use more WDTs for other delay requirements?

Anonymous
Not applicable

You will either want to change the watchdog timer count for each time period you measure dynamically, or have the two cascaded timers used for a larger period and use the third WDT for a smaller period with counts keeping track of timing for each timed operation individually.

Something akin to "systick" timer, but using the WDT period as the base "systick". This also allows timing while in deep sleep mode as well.

In my own project, to get more functionality, I ended up dedicating one timer to a large timed period (18h~) and the other two to individual 1ms and second/quarter-second timing individually. (Not fun to get setup and figure out, but works well considering the low-power, multiple timed operations, and no remote interaction requirements of the project.)

That's exactly what I want to do. Presently I'm cascading two WDTs. How do I use a single timer for 18hrs period? Could you point me to an example?

Thanks,

Andrew Collins

Anonymous
Not applicable

The WDT2 has a longer period (maximum of 18h~) with resolution of doubles starting from ms up to hours.

The basic WDT examples should work: http://www.cypress.com/file/193966/download

Since the WDT2 uses a 32-bit timer, it behaves as a single WDT with double the count, but only allows resolution of a single bit for detecting periods/interrupts. The cascade will give better resolution, but the WDT2 is nice for using as a "long resolution" or approximate timer.

Let me know if you can't get it working

I ran the Project #2 from your link to wake the system from deep sleep. It works well for CY_SYS_WDT_COUNTER1 and CY_SYS_WDT_COUNTER0; but does not wake up for CY_SYS_WDT_COUNTER2. In all these cases SLEEP_INTERVAL_250MS is 250. Please let me know if I need to take care of something for COUNTER2 (32bit).

Anonymous
Not applicable

This is the initialization code I use to start the WDT2 interrupt:

        CySysWdtDisable(CY_SYS_WDT_COUNTER2_MASK);//enable wdt2 resetting system on 3rd failed interrupt

        CySysWdtWriteMode(CY_SYS_WDT_COUNTER2, CY_SYS_WDT_MODE_INT);//set wdtcounter2 to interrupt mode

        CySysWdtSetToggleBit(WDT2_COUNT);//set period/interval to 18H 12M 16S

        //(WDT2_COUNT is 31, which triggers an interrupt on bit 31 being set)

        //CySysWdtWriteClearOnMatch(CY_SYS_WDT_COUNTER2, 1u);//clear counter on match event

        CySysWdtClearInterrupt(CY_SYS_WDT_COUNTER2_MASK);

        CySysWdtEnable(CY_SYS_WDT_COUNTER2_MASK);//enable wdt2 resetting system on 3rd failed interrupt

        CySysWdtEnableCounterIsr(CY_SYS_WDT_COUNTER2);//enable wdt2 ISR

And this is the code I put in the ISR when the interrupt for WDT fires:

    if(WDT_IF & CY_SYS_WDT_COUNTER2_INT) {

        CySysWdtClearInterrupt(CY_SYS_WDT_COUNTER2_INT);

    }

Thank you for the code. It works very well. Now I want to stop the loop after 10 times execution

Can I use the code previously mentioned by Bob? Where should I insert?

static uint8 Counter = 0;

     if(Counter >= 10) return;

     Counter++;

Anonymous
Not applicable

You should be able to reuse it, yes. Just call the wdtCallback() function from the ISR when the WDT fires:

if(WDT_IF & CY_SYS_WDT_COUNTER2_INT) {

        CySysWdtClearInterrupt(CY_SYS_WDT_COUNTER2_INT);

        wdtCallback(); //You can add other functions to call inside the ISR here for the WDT2 interrupt as well, but try to minimze code in ISRs to prevent timing issues.

    }

Thanks for your  suggestion. I will add the wdtCallback() function in the CY_ISR(isr_WDT) function.

The for (;;) loop has the LED_on, deepsleep and LED_off.

For 10 times execution should the WdtCallback function look like the following?

void wdtCallback()

{

    static uint8 Counter = 0;

     if(Counter >= 10) return;

     Counter++;

}

Anonymous
Not applicable

The code bob.marlowe​ posted will work fine. I didn't mention it as I figured you would go ahead and use it as he posted it.

I did that; but the loop is not breaking after 10 times.

My code is below. Please let me know if I have placed the codes correctly. (I also need to fix deep sleep mode next).

Thanks

#include <project.h>

/******************************************************************************

* Macro definition

* ----------------------------------------------------------------------------

* These Macro are only used in this module for button pressing event

* detection. These Macro should not be populated to other modules.

******************************************************************************/

#define LED_ON                      (uint8)0x00

#define LED_OFF                     (uint8)0x01

#define SLEEP_INTERVAL_250MS        15                    /* millisecond */

#define ILO_FREQ                    32000                       /* Hz */

#define LOG_ROW_INDEX               (CY_FLASH_NUMBER_ROWS - 1)  /* last row */

#define DoSomething(void)           CyDelay(500)                /* just delay 500ms */

/******************************************************************************

* Global variables definition

* ----------------------------------------------------------------------------

* These varialbes should be populated to other modules. Header file contain

* the extern statement for these variables.

******************************************************************************/        

void InitWatchdog(uint16 sleep_interval);

CY_ISR(isr_WDT);

void wdtCallback()

{

    static uint8 Counter = 0;

     if(Counter >= 10) return;

     Counter++;

}

int main()

{

    /*===========================================================================================

     * this code piece turns on Green LED for normally system working

     *==========================================================================================*/

    /* turn on Green LED to indicate system is powered up */

    LED_Green_Write(LED_ON);

    LED_Red_Write(LED_OFF);

    LED_Blue_Write(LED_OFF);   

    /* delay for a while to give enough time for Green LED display */

    CyDelay(100);

   

    /*===========================================================================================

     * this code piece initializes the watchdog function

     *==========================================================================================*/

    /* initialize watchdog */

    InitWatchdog(SLEEP_INTERVAL_250MS);

    /* connect ISR routine to Watchdog interrupt */

    ISR_WDT_StartEx(isr_WDT);

    /* set the highest priority to make ISR is executed in all condition */

    ISR_WDT_SetPriority(0);

        CySysClkEcoStart(24);

    /* enable global interrupt */

    CyGlobalIntEnable;

        /*==========================================================================================*/

    for(;;)

    {

        /* turn on Green LED to indicate system is in active mode */

        LED_Green_Write(LED_ON);

        LED_Red_Write(LED_OFF);

        LED_Blue_Write(LED_OFF);  

       

        /* clear watchdog counter before deep sleep */

        CySysWdtResetCounters(CY_SYS_WDT_COUNTER2_RESET);

        /* reset watchdog counter requires several LFCLK cycles to take effect */

    //    CyDelayUs(150);

        /* go to deep sleep mode */

                    CySysClkEcoStop();

        CySysPmDeepSleep();

       

        /* turn on Red LED after wakeup by Watchdog interrupt */

        LED_Green_Write(LED_OFF);

        LED_Blue_Write(LED_OFF);

        LED_Red_Write(LED_ON);       

       

        /* do something here after wakeup from deep sleep*/

        DoSomething(); 

    }

}

void InitWatchdog(uint16 sleep_interval)

{

        CySysWdtDisable(CY_SYS_WDT_COUNTER2_MASK);//enable wdt2 resetting system on 3rd failed interrupt

        CySysWdtWriteMode(CY_SYS_WDT_COUNTER2, CY_SYS_WDT_MODE_INT);//set wdtcounter2 to interrupt mode

        CySysWdtSetToggleBit(sleep_interval);//set 31 sleep_interval for 18H 12M 16S

        CySysWdtClearInterrupt(CY_SYS_WDT_COUNTER2_MASK);

        CySysWdtEnable(CY_SYS_WDT_COUNTER2_MASK);//enable wdt2 resetting system on 3rd failed interrupt

        CySysWdtEnableCounterIsr(CY_SYS_WDT_COUNTER2);//enable wdt2 ISR

}

CY_ISR(isr_WDT)

{

    if(CY_SYS_WDT_COUNTER2_INT) {

        CySysWdtClearInterrupt(CY_SYS_WDT_COUNTER2_INT);

        wdtCallback();

    }

}

Anonymous
Not applicable

The counter code looks like it works, but the code it would stop doing after 10 loops would need to be right after the "Counter++;" line inside the wdtCallback(); function.

Or, you need to change the code to use a global variable that you can check for the 10 loops being done.

Based on what you are trying to do, I've modified the code you posted and attached it as a text file.

Somehow it does not work and did not quite get this.

We have the code for 10 times execution including LED blink, WDT2 and deep_sleep in the for (;;) loop. Should I transfer the codes from for(;;) loop to the wdtCallback() function right after the "Counter++?

I want (1) LED blink (2) Deep_Sleep using WDT2 (3) Repeat 10 times.

lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

When the unit enters the deep sleep, it will not run the following line of code until the unit wakes up from an interrupt/WDT.

But, when that occurs it will run the interrupt handler, and then proceed to run the code after the deepsleep call. This means that the for(;;) loop will have the unit entering/leaving deep sleep mode forever and looping through the LEDs turning ON/OFF forever.

The Counter++ code will prevent the code following the if(Counter>=10) return; statement from running after the 10th iteration, this means that any code you only want to run the first ten times when deep-sleeping should be put to run after that if statement.

I'm not sure you are understanding the C code and the deepsleep/interrupt functionality. Try reading some documentation on interrupts and sleep modes: Interrupt - Wikipedia and https://www.embedded.com/design/power-optimization/4237635/Understanding-MCU-sleep-modes-and-energy-...

If you only want the deep sleep and the LED to run ten times total, then you can change the for(;;) loop to be for(uint8 i =0; i<10; i++)

Thanks for the code and information. The code works good. DeepSleep function and long WDT works good with the for (;;) loop and wdtcallback().

I may need some more fine tuning on the power saving. Using the pioneer kit, the deepsleep consumes 1mA with LED OFF. What are the devices we can turn off for power saving?

Anonymous
Not applicable

Some of the current will be due to the pioneer kit hardware itself (leakage, etc.) But any peripherals internal to the PSoC will be able to turn off or put into a power-saving mode I believe.

The BLE, any TopDesign.cysch components, and GPIO with active current draw will be the main culprits for power draw.

One way to test minimum current draw is to create a blank project, set the Debug Select in "System" to GPIO, then immediately set the CPU to "Deep Sleep" mode in main(). This will give you the lowest current you can get with the kit/hardware you are using, with adding peripherals just adding more current draw to the base amount.

In our testing with a custom PCB board, we got the PSoC current draw down to 1-2 uA when the CPU is in deep sleep with external GPIO edge-triggered interrupts, and two external GPIO set to output HIGH logic voltage.

I have observed 12 microAmp when running the example AN86233_PowerModes in Deepsleep mode.

But, in this example, we are using WDT2 and the current is 1mA. Does the WDT2 require any consideration for power saving?

Anonymous
Not applicable

I'm sure the WDT will increase current cost, but I think the amount is on such a small scale that it is nA or less. I didn't notice any practical measured difference. Since it would be some similar in hardware to a SR-latch using MOSfets, it probably has very little current draw except when triggered, and even then I would suspect the current to be more from the CPU re-activating than from the WDT itself. (The WDT interrupt circuitry is more of a mesh with a few transistors than active current components).

(With all three WDTs running in our application we still get below 2 uA)

I tried to remove the LEDs and turn off the devices in sleep mode but could not reduce the current below 1mA. Could you send me the program using WDT2 where you see current in microamp?

Anonymous
Not applicable

I don't have time to post the project today (Lots of stuff going on), but I can try to post it tomorrow or over the weekend for you. It should be pretty simple to get working (most of the work is in the implementation/handling). I'll try to setup a good example for others to use as a template while I'm at it.

lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

I've written up a mock program that advertises each second, then goes back into deep sleep. Due to a bug/misunderstanding of the BLE, I have the device resetting after each wakeup, but that should have minimal effect.

It is setup to use WDT1 (WDT2 should be only a slight difference in implementation due to the timer triggering on a certain bit rather than a register match).

I've attached the project to this reply

Pratt,

Sorry for the delay of sending this reply! I have used your DemoProject program and it gives me around 2 uA, which is what I wanted. However, setting up WDT3 is proving to be trickier than I thought. When I try to convert to the bit instead of the register match, it does not seem to be working. I have attached LEDs to see if the timer is going longer when I change the bit from 13 to 15 or higher, but it still remains the same as it was in WDT1. Can you send me the code of how to implement WDT3 in place of WDT1?

Thanks,

Andrew Collins

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hello Andrew,

No problem. Sounds like it was working well for the example

I've rewritten the code to use the WDT2 to demonstrate the difference in the bit behavior (using a bit interrupt instead of a match interrupt).

I've attached it here, but I haven't tested it, so let me know if it works for you

0 Likes

Pratt,

Yes, the program works! I have tested it with an LED that blinks for 1 second at the start, then the program goes into deep sleep, and finally, the LED turns back on. I tested the program from 13-bit to 19-bit and it goes for the correct amount of seconds as you have commented on the program.

However, I have noticed that the deep sleep runs in exponents of 2. Is it possible to give a specific time that falls in between the bits? For example,

    26 (bit) = 34 M, 8 s

    25 (bit) = 17 M, 4 s

But is it possible to have a 'fractional' in between those two numbers so that the time is equal to 20 minutes?

Thanks,

Andrew Collins

0 Likes
Anonymous
Not applicable

Hello Andrew,

Sadly, No. The WDT2 has the built-in 32-bit timer for longer times (up to 18 hours), but it does NOT have the fractional/fine steps as you are asking.

Essentially, the counter is hardcoded with only access to one bit at a time for rollover as implemented in hardware, leading to the exponential time settings.

In my own project, I ended up using the WDT2, but counting the number of interrupts/counts with some RAM to get the precise count that I wanted. I'm assuming you are already using the WDT0 and WDT1 for other things, and thus want to limit use to just the WDT2 for this instance/function.

My advice would be to try using a RAM counter variable that increments on WDT2 interrupts, and just change the LED when that count reaches the desired timed interval;

For example, set WDT2 to 2 minutes, 4 seconds, and then count up to 10 for a 20 minutes 40 seconds operation. The resolution still won't be perfect, but with lower resolution and a larger RAM variable you can tweak that count to be more accurate at the expense of more time waking up the chip.

By cascading the WDTs you could implement a combined WDT with a much more precise count, but that would require more than one for the timing.

Best of luck,

Elijah Pratt

Hi Pratt,

Thank you for your suggestion to use RAM/WDT to fine-tune the delay!

In my program, WDT1 is available and I would like to cascade WDT1 and WDT2 for a long time (30 minutes).  As I look at the LongDeepSleepTimer example, I thought I can do this on your code for WDT2 LongDelay (DemoProjects).

    CySysWdtSetCascade(CY_SYS_WDT_CASCADE_12);

    CySysWdtSetMatch(1,512);

    CySysWdtSetMatch(2,32768);

Could you let me know where I should put this code on your program?

Thanks,

Andrew Collins

0 Likes
Anonymous
Not applicable

Hello Andrew,

I would think you can put it into the void StartTimeout() function and replace the settings as needed in there.

The StartTimeout() is only called once at startup, but if you end up wanting to change the timer behavior dynamically, then keeping the settings within the StartTimeout() function makes coding practices and operation easier.

You will want to remove/replace the following lines for the operation to work correctly I think:

        CySysWdtDisable(CY_SYS_WDT_COUNTER2_MASK);//enable wdt2 resetting system on 3rd failed interrupt

        CySysWdtWriteMode(CY_SYS_WDT_COUNTER2, CY_SYS_WDT_MODE_INT);//set wdtcounter2 to interrupt mode

        CySysWdtSetToggleBit(WDT2_COUNT);

There may be some trial and error, but that is the function I would setup the cascading and WDT1 and WDT2 setup in.

0 Likes