2021-09-21 01:23 PM
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?
2021-09-22 02:21 AM
Post a minimal (with no dependency on any library), but complete compilable example exhibiting the problem.
JW
2021-09-22 10:40 AM
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!
}
2021-09-22 01:12 PM
> 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
2021-09-22 02:58 PM
// 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!
}
2021-09-22 03:28 PM
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
2021-09-23 04:49 PM
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?
2021-09-23 05:54 PM
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
2021-09-24 06:54 AM
> 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
2021-09-24 09:25 AM
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?