2019-02-18 02:13 PM
We ran a batch of boards with an STM32F401CE on them (this was not the first run of these boards or using this processor).
After loading application code, about 10% of the boards became unresponsive. Looking into it we found in the option bytes on the bad boards that the SPRMOD bit, which enables PCROP on all sectors, was set. We don't set this bit anywhere in the application.
We do set the brown out level on power up with this code:
if(( FLASH_OB_GetBOR() & 0x0F ) != OB_BOR_LEVEL3 )
{
FLASH_OB_Unlock();
FLASH_ClearFlag( FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR );
FLASH_OB_BORConfig( OB_BOR_LEVEL3 );
FLASH_OB_Launch();
}
...but that is the only time we update the option bytes and that code shouldn't touch the SPRMOD bit.
Any ideas what might be happening here?
I am able to remove the read/write protection with ST link, but I don't want to have to solder wires onto all these boards to unlock them.
2019-02-19 02:05 PM
How do you perform the initial programming? (I mean, couldn't have the problem happened there?)
Also, on the boards with SPRMOD bit errorneously set, were the BOR bits properly set as expected? Is there any check that the option bits programming was correctly finished?
JW
2019-02-19 03:46 PM
First we load our bootloader into the first 2 flash sectors using the built in firmware bootloader. Then we power cycle and load the application through our bootloader. We wrote a program to talk to the firmware bootloader, but it doesn't have provisions for writing to the option bytes. Our bootloader doesn't touch them either.
The (soon to be) bad boards powered up okay into our bootloader. It was only after loading the application that the problems happened. That's why I'm suspecting the BOR code, but not sure what I'm doing wrong.
The option bytes on the bad boards had all their default values except SPRMOD, which was set. We don't check if the BOR bits are set correctly (we're adding that step to the procedure).
Could it be caused by the board being powered off while the processor is still writing the option bytes? That seems like such a small window for this to happen as often as it did.
2019-02-19 04:03 PM
> Could it be caused by the board being powered off while the processor is still writing the option bytes?
That would most probably result in most bits being erased, isn't it? Is it consistent with your finding that
> The option bytes on the bad boards had all their default values except SPRMOD, which was set.
? In any case it means that BOR was not set to level 3.
> Could it be caused by the board being powered off while the processor is still writing the option bytes?
I don't know. Maybe you want to review those functions (is that SPL?) and the overall procedure. Imagine, for example, a bug resulting in this routine being called in an infinite loop...
It still may be something completely different, of course...
JW
2019-02-20 10:30 AM
If the bits were only erased and never re-set I'd expect them to all read as 1's, not their default values (plus one bit that's not the default value).
Yes, it is SPL code. We have resisted switching to HAL/LL since most of our code was written with SPL. Those functions expand to this:
/* (( FLASH_OB_GetBOR() & 0x0F ) != OB_BOR_LEVEL3 ) */
if(((uint8_t)(*(__IO uint8_t *)(OPTCR_BYTE0_ADDRESS) & 0x0C)
& 0x0F ) != OB_BOR_LEVEL3 )
{
/* FLASH_OB_Unlock(); */
if((FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) != RESET)
{
FLASH->OPTKEYR = FLASH_OPT_KEY1;
FLASH->OPTKEYR = FLASH_OPT_KEY2;
}
/* FLASH_ClearFlag( FLASH_FLAG_EOP | FLASH_FLAG_WRPERR
* | FLASH_FLAG_PGAERR ); */
FLASH->SR = FLASH_FLAG_EOP | FLASH_FLAG_WRPERR
| FLASH_FLAG_PGAERR;
/* FLASH_OB_BORConfig( OB_BOR_LEVEL3 ); */
*(__IO uint8_t *)OPTCR_BYTE0_ADDRESS &=
(~FLASH_OPTCR_BOR_LEV);
*(__IO uint8_t *)OPTCR_BYTE0_ADDRESS |= OB_BOR_LEVEL3;
/* FLASH_OB_Launch(); */
*(__IO uint8_t *)OPTCR_BYTE0_ADDRESS |= FLASH_OPTCR_OPTSTRT;
FLASH_Status status = FLASH_GetStatus();
while(status == FLASH_BUSY)
{
/* FLASH_GetStatus() is just a series of checks of the
* FLASH->SR bits */
status = FLASH_GetStatus();
}
}
I'll compare this to what's in the HAL/LL libraries to see if there are any significant differences.
I'm not too worried about a bug causing an infinite loop. The code checks these bits on power; if they're set correctly it doesn't do anything with them. The only time it could maybe get caught in a loop is either here in production or if the bits somehow get changed in the field, but then we'd have bigger problems to deal with.
I'm just wondering if anyone has seen this before so we can fix whatever is causing it.
2019-02-20 12:26 PM
> If the bits were only erased and never re-set I'd expect them to all read as 1's, not their default values (plus one bit that's not the default value).
Fair enough.
Code looks perfectly OK.
Does this code run immediately after powerup? Can't the power be not stable enough at that moment?
Does this code run at the default clocks settings?
I know this is pure speculation, you don't need to spend time to investigate my random ideas.No, I haven't seen anything like this our STM32-related production.
JW
2019-02-22 07:28 AM
This code runs on power up after the pins and clocks have been configured. We have a circuit on the board that holds the processor in reset until the power is good. It's running off the PLL by the time this code executes.
I'm at the point of speculation as well so thanks for the "random ideas".