Watchdog on PSoC 1

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

cross mob
PeCa_4386336
Level 2
Level 2
5 replies posted First reply posted First question asked

Using the CY8C29466, watchdog enabled, sleep timer = 1Hz. Watchdog reset approximately every 5mS with RES_WDT = 0x38;  to ensure 3 second timeout. Very occasionally the watchdog resets the system. You could be forgiven for thinking, well it's doing it's job then, your code is crashing somewhere. However code is really quite simple, and if I take the watchdog out, nothing bad happens. Has anybody seen this before?

0 Likes
1 Solution

PeCa,

Thank you for the project download.   It'll take me a while to perform a code analysis.  It's be a long while since I worked on a PSoC1 project.

A few questions:   I don't have your specific hardware.  However if I can download it to a PSoC1 I have on hand, will the watchdog "bark" if sitting at idle?  Does it "bark" on your HW in idle?  If no, my experiment will not work to reproduce your results.

You have a tool to program your PsoC1.  Does your tool also allow debugging?

A few observations:

1. You are using a delay() function three times in your code.  One time uses a 100ms delay, Another a 200ms delay and the last in pid.c has a 10 second delay.   You are aware this function as you implemented in speed.c is a blocking function.

2.  You are only "petting" the watchdog (RES_WDT = 0x38) in two places.  Both are in main().

The first is in the initialization.  No problem.

The second place is in the main's while loop.   This could be a problem.

You state:

 

Watchdog reset approximately every 5mS with RES_WDT = 0x38;  

 

I don't see it.   Are you performing a reset to the WDT in an interrupt?   Again, I must be missing it.

With the delay()s you are performing which are blocking functions and other blocking functions such as UART_1_CPutString()s, there is no guarantee of resetting the WDT in time.

You have 23 places in spi.c and uart.c where you use the while() statement.  This could result in significant blocking events if not carefully coded.

It is always tricky to use the watchdog in code that uses while() and do() statements.   Bad coding using these statements can result in infinite loops.   The exception is there is a while (1) which is guaranteed to be an infinite loop.  However, this line in main() was intended to be infinite and you have a RES_WDT somewhere in it.

Badly coded while()s or do()s are one of the reasons for the watchdog.  There it is doing one of its jobs.  However, this could result in unintended system operation.   Therefore it is best to code properly.  You could throw in RES_WDTs into these while()s and do()s but that potentially defeats the purpose of the watchdog and could result in "hung" code under the right conditions.

Recommendations:

The best technique is to analyze your code and fully get rid of all blocking code (this includes the delay functions).   The common coding technique is to create virtual task threads for HW and SW subsystems.  For example, the following would be a separate threads:

  • UART
  • SPI
  • Speed control
  • PID
  • I2C
  • Hall Effect

Each virtual task thread would be called in main() and inside the thread you can ONLY check the status of the devices (such as the UART, SPI, I2C) and if not ready it will return to the task in the next main() loop iteration.   If the status indicates that it ready to read or write the next data, for example, you can process to do so.

To do this you may need to keep state variables as to the progress of each task.   This method can prevent blocking functions.  Make sure that in any task thread you spend no more than 1 to 10ms executing.

If you don't want to significantly restructure your code, then you are trying to create a tightly-coupled single task state machine.   To do this successfully, you need to have decent means to debug when and WHERE the watchdog is being triggered.  Understanding these will provide knowledge of what led to this event.  Then it can be "fixed".

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
5 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

PeCa,

If you are "petting" the watchdog every 5ms, then the WDT should not "bark" (trigger).

Are you willing to share your project with the forum for code analysis?

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
lock attach
Attachments are accessible only for community members.
PeCa_4386336
Level 2
Level 2
5 replies posted First reply posted First question asked

Thanks for your interest, here's an archive of the project.

0 Likes

PeCa,

Thank you for the project download.   It'll take me a while to perform a code analysis.  It's be a long while since I worked on a PSoC1 project.

A few questions:   I don't have your specific hardware.  However if I can download it to a PSoC1 I have on hand, will the watchdog "bark" if sitting at idle?  Does it "bark" on your HW in idle?  If no, my experiment will not work to reproduce your results.

You have a tool to program your PsoC1.  Does your tool also allow debugging?

A few observations:

1. You are using a delay() function three times in your code.  One time uses a 100ms delay, Another a 200ms delay and the last in pid.c has a 10 second delay.   You are aware this function as you implemented in speed.c is a blocking function.

2.  You are only "petting" the watchdog (RES_WDT = 0x38) in two places.  Both are in main().

The first is in the initialization.  No problem.

The second place is in the main's while loop.   This could be a problem.

You state:

 

Watchdog reset approximately every 5mS with RES_WDT = 0x38;  

 

I don't see it.   Are you performing a reset to the WDT in an interrupt?   Again, I must be missing it.

With the delay()s you are performing which are blocking functions and other blocking functions such as UART_1_CPutString()s, there is no guarantee of resetting the WDT in time.

You have 23 places in spi.c and uart.c where you use the while() statement.  This could result in significant blocking events if not carefully coded.

It is always tricky to use the watchdog in code that uses while() and do() statements.   Bad coding using these statements can result in infinite loops.   The exception is there is a while (1) which is guaranteed to be an infinite loop.  However, this line in main() was intended to be infinite and you have a RES_WDT somewhere in it.

Badly coded while()s or do()s are one of the reasons for the watchdog.  There it is doing one of its jobs.  However, this could result in unintended system operation.   Therefore it is best to code properly.  You could throw in RES_WDTs into these while()s and do()s but that potentially defeats the purpose of the watchdog and could result in "hung" code under the right conditions.

Recommendations:

The best technique is to analyze your code and fully get rid of all blocking code (this includes the delay functions).   The common coding technique is to create virtual task threads for HW and SW subsystems.  For example, the following would be a separate threads:

  • UART
  • SPI
  • Speed control
  • PID
  • I2C
  • Hall Effect

Each virtual task thread would be called in main() and inside the thread you can ONLY check the status of the devices (such as the UART, SPI, I2C) and if not ready it will return to the task in the next main() loop iteration.   If the status indicates that it ready to read or write the next data, for example, you can process to do so.

To do this you may need to keep state variables as to the progress of each task.   This method can prevent blocking functions.  Make sure that in any task thread you spend no more than 1 to 10ms executing.

If you don't want to significantly restructure your code, then you are trying to create a tightly-coupled single task state machine.   To do this successfully, you need to have decent means to debug when and WHERE the watchdog is being triggered.  Understanding these will provide knowledge of what led to this event.  Then it can be "fixed".

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
PeCa_4386336
Level 2
Level 2
5 replies posted First reply posted First question asked

Thanks for your reply. I am currently going throught the code ensuring all the loops have timeouts. One question, why do you say UART_1_CPutString is a blocking function? Is that because it's interrupt driven and could wait for the interrupt for ever? 

0 Likes

PeCa,

Here is a snip from the UART datasheet on the _CPutString() function:

UART_PutString

Description:
Sends a null terminated (RAM) string to the UART TX.
C Prototype:
void UART_PutString(char * szRamString)
Assembler:
mov  A,>szRamString     ; Load MSB part of pointer to RAM based null
                        ; terminated string.
mov  X,<szRamString     ; Load LSB part of pointer to RAM based null
                        ; terminated string.
lcall UART_PutString     ; Call function to send string out UART TX port
Parameters:
char * aRamString: Pointer to the string to be sent to the UART TX. MSB is passed in the Accumulator and LSB is passed in X register.
Return Value:
None
Side Effects:
Program flow stays in this function until the last character is loaded into the UART transmit buffer. The A and X registers may be modified by this or future implementations of this function. The same is true for all RAM page pointer registers in the Large Memory Model (CY8C29xxx and CY8CLED16). When necessary, it is the calling function's responsibility to preserve the values across calls to fastcall16 functions. Currently, only the IDX_PP page pointer register is modified.

This function is theoretically not infinite but is blocking because it uses the equivalent of a do() loop in the function UART_1_PutChar  ( jz .BufEmptyWaitLoop).  Therefore until ALL the bytes of the string are sent out, the time in the function is potentially long.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes