cancel
Showing results for 
Search instead for 
Did you mean: 

WDGA bit not immediately set after WWDG_Enable().

MBoren
Associate II

STM32F405 using STLIBF4 v1.4.0

Near the beginning of my code, I enable the windowed watchdog with

WWDG_Enable()

Shortly thereafter, I have a conditional block that executes only if the windowed watchdog is enabled, i.e.

if ((WWDG->CR & WWDG_CR_WDGA) != 0)
{
     // do stuff
}

If this condition is checked immediately after the WWDG_Enable() call, the block fails to execute. However, if I move this conditional block later in the code (ensuring that some time has passed after enabling the watchdog), the block will execute as expected.

Through in-circuit debugging, I have confirmed that the WDGA bit in the WWDG_CR register does not read as set immediately after the execution of WWDG_Enable().

Please help me understand this behavior. Is the value of the WWDG_CR register only updated on the edge of PCLK1?

11 REPLIES 11

Post a minimal (with no dependency on any library), but complete compilable example exhibiting the problem.

JW

MBoren
Associate II

Example #1:

// set up and enable windowed watchdog
uint32_t tmpreg = 0;
tmpreg = WWDG->CFR & 0xFFFFFF80;
tmpreg |= 0x00000043 & 0x0000007F;
WWDG->CFR = tmpreg;     // set window value
WWDG->CR = 0x0000007F & 0x0000007F;     // set max counter value
WWDG-CR = 0x00000080 | 0x0000005F;     // set counter value and WDGA bit
 
// execute code if watchdog is enabled
if ((WWDG->CR & 0x00000080) != 0) 
{
     // this block is never reached!
}

Example #2:

// set up and enable windowed watchdog
uint32_t tmpreg = 0;
tmpreg = WWDG->CFR & 0xFFFFFF80;
tmpreg |= 0x00000043 & 0x0000007F;
WWDG->CFR = tmpreg;     // set window value
WWDG->CR = 0x0000007F & 0x0000007F;     // set max counter value
WWDG-CR = 0x00000080 | 0x0000005F;     // set counter value and WDGA bit
 
// force wait until watchdog is enabled
while ((WWDG->CR & 0x00000080) == 0)
{
     delay(1);     // generic delay for 1ms
}
 
// execute code if watchdog is enabled
if ((WWDG->CR & 0x00000080) != 0) 
{
     // this time it works!
}

> WWDG-CR = 0x00000080 | 0x0000005F; // set counter value and WDGA bit

Please prepare a minimal but complete compilable example exhibiting the problem, and post it verbatim.

JW

MBoren
Associate II
// set up and enable windowed watchdog
uint32_t tmpreg = 0;
tmpreg = WWDG->CFR & 0xFFFFFF80;
tmpreg |= 0x00000043 & 0x0000007F;
WWDG->CFR = tmpreg;     // set window value
WWDG->CR = 0x0000007F & 0x0000007F;     // set max counter value
WWDG->CR = 0x00000080 | 0x0000005F;     // set counter value and WDGA bit
 
// execute code if watchdog is enabled
if ((WWDG->CR & 0x00000080) != 0) 
{
     // this block is never reached!
}

Hi @MBoren​ ,

I of course added the missing > and tried to reproduce to no avail, the code landed inside the block (where I placed a __BKPT(), otherwise there would be nothing to stop on there).

My point is, that the key to the problem may lie in code outside the snippet you've posted. That's why a complete compilable program is needed, best with the resulting .elf, to try to reproduce it independently.

JW

MBoren
Associate II

I understand. Unfortunately, the code base is large and complex and I am limited in what I can provide outside my organization.

Any information you can provide of a general nature would still be of assistance. Are there any known circumstances under which the WDGA bit in the WWDG_CR register cannot be set? For example, could the operation fail if the APB1 peripheral clock was not enabled?

MBoren
Associate II

I have come up with a code example that could illustrate the above theory:

int main(void)
{
       int idx = 0;
 
        WWDG->CR = 0xDF;     // this should set the WDGA bit and set the counter to 0x5F
 
	if ((WWDG->CR & 0x80) != 0)
	{
		idx += 1;     // this code is never reached
	}
 
       // enable the peripheral clock for WWDG
	temp = RCC->APB1ENR;
	temp |= 0x00000800;
	RCC->APB1ENR = temp;
 
       // stop WWDG during debug (necessary for ICDB)
	temp = DBGMCU->APB1FZ;
	temp |= 0x800;
	DBGMCU->APB1FZ = temp;
 
  	WWDG->CR = 0xDF;     // try again
 
  	if ((WWDG->CR & 0x80) != 0)
  	{
  		idx += 2;     // this time it works!
  	}
}
// final value of idx is 2

> Unfortunately, the code base is large and complex

This is often the case, but that also means that various interactions are likely. This is why creating a minimal experiment proving the point is important; or, inversely, simplifying (possibly by bisection) the large project down to the point where the symptoms disappear, thus finding the cause.

> For example, could the operation fail if the APB1 peripheral clock was not enabled?

Yes. Generally, if a peripheral's clock is not enabled in RCC, that peripheral's registers cannot be accessed (writes are ignored and reads return 0). Here, quite surprisingly, reads appear to work and return the reset values even if RCC is not enabled; but that's just a curiosity detail which does not impact the overall working of WWDG.

> I have come up with a code example that could illustrate the above theory:

Yes and this indeed works as expected, but then in your previous example, if WWDG clock in RCC is not enabled, even when delay() is inserted, it would stick there in that loop with delay() infinitely, wouldn't it?

JW

MBoren
Associate II

Thank you for your clarification. It makes sense that the peripheral registers would not be available before the peripheral is enabled, but this was not something that I came across when searching the documentation. Where is this stated?