UART RX interrupt in high priority causing WDT resets

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

cross mob
michaelym
Level 1
Level 1
10 sign-ins 5 replies posted 5 sign-ins

In my application, there is a control interrupt (isr_1) with a period of 200us. The total time spent in the interrupt is approximately 180us. The UART is running at 115200 and the fifo is set to >4 so it uses the UART RX interrupt and the sw ring buffer for storing the data. As soon as I make the UART RX interrupt priority higher (priority 0) than isr_1 (priority 1) the PSoC resets every few seconds with the reset reason being WDT. Do you know what might cause this? 

When the UART interrupt is at a lower priority (priority 7) everything works fine and I read the received data in the main loop. I measured the time spent in the UART interrupt and it about 1us.

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

michael,

Where is the WDT being "petted"?  The main() task, isr_UART_RX or isr_1?

What is your WDT period?

The immediate issue I see is that you're potentially spending too much time in the isr_UART_RX.

You're spending 90% of the CPU time in the isr_UART_RX.   You're only leaving 20us available for the main() task and isr_1.   

Have are two suggestions:

Suggestion #1:  Optimize your UART_RX data processing

Here are ways of optimizing:

  • Only use a RX_data_ready flag in isr_UART_RX to signal the main() task to further process the data.  You are using RAM buffer for the data which is a very good temporary buffer.   This will reduce the CPU utilization of this interrupt to <4% instead of 90%.
  • You can potentially eliminate the isr_UART_RX by polling for the Data Ready signal in the UART component API.
  • General rule for interrupts:  Avoid ANY blocking functions.  The worst is CyDelay().  Some UART API calls are blocking.  Don't use them.

Suggestion #2:  Use the UART FIFOs

The UART component provides 4 bytes of RX data.  In addition, you are augmenting these FIFOs with RAM buffer storage.   Keep the interrupt priority to 7 and use the FIFOs for what they are designed for.

You can theoretically unit test UART RX performance throughput.  I use this method often to find out the "design margin" and/or the point where "the wheels fall off the bus".

There are two practical ways.

  1. With the UART set at 115.2Kbps, set a timer to continuously issue an ISR at a fairly high rate.   This emulates isr_1 CPU utilization.  By increasing the timer ISR rate, you can determine the actual point of CPU utilization before UART RX data corruption or WDT occurs.
  2. Increase the UART data rate above 115.2K bps.  Increase the rate in steps.  Like way '1.', this determines the CPU utilization before data corruption or WDT occurs.
Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Thanks for your detailed response. 

The init of the WDT is CyWdtStart(3,3) and I'm feeding it in the main loop, I verified with a toggle pin that it is indeed being fed at least once every ms. I tried feeding it in both interrupts and it didn't help my situation.

Yes, I am spending 180us of every 200us in isr_1 and when the uart is receiving continuously there is another maximum of 2 interrupts of 1us. Should be plenty of time left for processing the main loop. 

I'm actually seeing very odd behavior. I toggle pin next to "CyWdtClear" in the main loop to verify that I am feeding the WDT.  The code looks like this:

CyWdtClear();
debFlag = 1-debFlag;
Test_port_Write(debFlag);
debFlag = 1-debFlag;
Test_port_Write(debFlag);

And there are no WDT resets.

When I change it to this:
CyWdtClear();
debFlag = 1-debFlag;
Test_port_Write(debFlag);
debFlag = 1-debFlag;
Test_port_Write(debFlag);
Test_port_Write(debFlag);

It resets every few seconds

When I change it to this:
CyWdtClear();
debFlag = 1-debFlag;
Test_port_Write(debFlag);
debFlag = 1-debFlag;
Test_port_Write(debFlag);
Test_port_Write(debFlag);
Test_port_Write(debFlag);

There are no resets!!

Also instead of the "Test_port_Write" i put "CyDelayUs" like this:
CyWdtClear();
debFlag = 1-debFlag;
Test_port_Write(debFlag);
debFlag = 1-debFlag;
Test_port_Write(debFlag);
CyDelayUs(100);

And it works fine!!

I tried disabling the interrupts like the suggestion in the header of the function "Test_port_Write" with no luck

The "Test_port" is on P12[6] and not connected internaly or externaly to anything else.

In desperation, I tried increasing the stack and heap to 32K but it did not help.

My hunch is that it may not be a WDT issue but some other exception that is causing a fault.

Do you have any ideas?

0 Likes

michael,

Having your project would be useful.

However with a little research, I found the following:

You are using CyWdtStart(3,3) to start the WDT.

This translates to CyWdtStart(CYWDT_1024_TICKS,  CYWDT_LPMODE_DISABLED) 

where:

CYWDT_1024_TICKS =>  2.048 - 3.072 s

CYWDT_LPMODE_DISABLED => Disable WDT during low power mode

If you read the Comments to the CyWdtStart() you find:

/*******************************************************************************
* Function Name: CyWdtStart
****************************************************************************//**
*
* Enables the watchdog timer.
*
* The timer is configured for the specified count interval, the central
* timewheel is cleared, the setting for the low power mode is configured and
* the watchdog timer is enabled.
*
* Once enabled the watchdog cannot be disabled. The watchdog counts each time
* the Central Time Wheel (CTW) reaches the period specified. The watchdog must
* be cleared using the CyWdtClear() function before three ticks of the watchdog
* timer occur. The CTW is free running, so this will occur after between 2 and
* 3 timer periods elapse.
*
* PSoC5: The watchdog timer should not be used during sleep modes. Since the
* WDT cannot be disabled after it is enabled, the WDT timeout period can be
* set to be greater than the sleep wakeup period, then feed the dog on each
* wakeup from Sleep.
*
* \param ticks: One of the four available timer periods. Once WDT enabled, the
interval cannot be changed.
* CYWDT_2_TICKS - 4 - 6 ms
* CYWDT_16_TICKS - 32 - 48 ms
* CYWDT_128_TICKS - 256 - 384 ms
* CYWDT_1024_TICKS - 2.048 - 3.072 s
*
* \param lpMode: Low power mode configuration. This parameter is ignored for PSoC 5.
* The WDT always acts as if CYWDT_LPMODE_NOCHANGE is passed.
*
* CYWDT_LPMODE_NOCHANGE - No Change
* CYWDT_LPMODE_MAXINTER - Switch to longest timer mode during low power
* mode
* CYWDT_LPMODE_DISABLED - Disable WDT during low power mode
*
* \sideeffect
* PSoC5: The ILO 1 KHz must be enabled for proper WDT operation. Stopping the
* ILO 1 kHz could break the active WDT functionality.
*
*******************************************************************************/

Is it possible that one of the side effects (shown in BLUE) using the PSoC5 applies in your project?

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

michael,

Wow.   You are correct.  Your description indicates some strange behavior.

Are you willing (and able) to share your project with the forum?

It appears the issue is not straightforward and not an easy solve.   Hopefully accessing your project will allow me to replicate your issue.

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