cancel
Showing results for 
Search instead for 
Did you mean: 

Backup SRAM write failure (STM32F446)

sebkeinert
Associate II
Posted on June 22, 2017 at 07:20

Hello.

I have an issue using the backup SRAM on a STM32F446.

The backup SRAM is used to store calibration data  which must be retained in case of a power fail reset. For that I connected the VBAT pin to a capacitor which is charged from VDD through a diode and can power VBAT for about 15 seconds when VDD is not present.

Because the calibration data must always be read accessable, peripheral clock is enabled setting the BKPSRAMEN bit in the RCC_AHB1ENR register just after startup.

The write of the calibration data into the SRAM is done after first startup. For that subroutines accessing the data call this routine

void bak_write_enable()

{

  RCC->APB1ENR |= RCC_APB1ENR_PWREN;

  PWR->CR |= PWR_CR_DBP;

}

to disable the SRAM write protection before writing the SRAM.

Furthermore the backup regulator will be enabled in normal operation (setting the BRE bit in PWR_CSR) to retain data in VBAT mode. Except when the debugger is running and I want to verify if the calibration routines are working correctly. And here rises my problem:

The reference manual says that the backup regulator must not be enabled to use the backup SRAM. But I trapped into a situation where the write access to backup SRAM fails when the regulator is off. Running this code

bak_write_enable();

...

backup_sram_var1 = xxx;

backup_sram_var2 = xxx;

backup_sram_var3 = xxx;

....

bak_write_disable();

I could figure out, that setting the value of backup sram data sometimes fails, when the regulator is off. Enabling it all works fine.

Any ideas? Thanks a lot.

Sebastian

9 REPLIES 9
sebkeinert
Associate II
Posted on June 22, 2017 at 17:42

I did further investigations on this issue and could find out, that the write failures do not arise from the switch off of the backup SRAM regulator. Rather the problem seems to be, that the sequence to gain access to the backup SRAM is not exactly the same as documented in the reference manual under 'Backup domain access'.

To get read access all the time I enable the backup SRAM clock on startup. After that write access is gained by enabling the power interface clock and setting the DBP bit, which does not function.

The question that arises now is, how to get write access with read access always enabled?

Posted on June 22, 2017 at 18:08

Can't this be similar to

https://community.st.com/0D50X00009XkaBaSAJ

?

Or is your problem that DBP does not get set at all? Even if you place some delay between enabling the PWR clock in RCC and setting DBP?

JW

sebkeinert
Associate II
Posted on June 22, 2017 at 20:08

Hello Jan,

DBP gets set correctly.

The problem looks more than you described it in your Enabling LSE post. With single stepping it works flawlessly, otherwise not. Even inserting a large delay loop after DBP is set and before the write to the backup SRAM is done, does not fix the issue.

Hence guarding the write accesses setting the PWR_CR_DBP bit on/off seems not to be a working solution. It will be best to set the DBP bit at startup und leave it untouched up to the last write to backup SRAM has finished.

Any better solution?

Posted on June 22, 2017 at 21:30

I've just noticed that in the opening post you wrote:

The reference manual says that the backup regulator must not be enabled to use the backup SRAM.

Where?

I just set it after reset and leave it so.

JW

Posted on June 22, 2017 at 22:21

waclawek.jan wrote:

I've just noticed that in the opening post you wrote:

The reference manual says that the backup regulator must not be enabled to use the backup SRAM.

Where?

Oh no, stupid german to english translation error 🙂

I meant the backup regulator needs not to be enabled... This is documented under the BRE bit of the PWR_CSR register. The reference manual says: 'If BRE is reset, the backup regulator is switched off. The backup

SRAM can still be used but its content will be lost in the Standby and VBAT modes'
Posted on June 23, 2017 at 02:22

german to english translation error

Same here... This may be a unique feature of the English language... 😉

OK I see but why don't you simply enable it upon every reset, it should make no harm even if not useful.

Other than that...

DBP gets set correctly.

Even in the case of full run, not only in the single-stepping case?

inserting a large delay loop after DBP is set

Wasn't the delay optimized out?

After writing DBP I read it back before accessing the backup SRAM, that's IMO a better method than a delay.

JW

Posted on June 23, 2017 at 08:53

OK I see but why don't you simply enable it upon every reset, it should make no harm even if not useful.

The reason is that the integrity of the backup SRAM is checked with a CRC-32 checksum after startup. An invalid checksum lets the subroutines know to rewrite the calibration data. So it is very simple to watch the behaviour of the subroutines, because with regulator off when debugging the checksum is invalid after every power-up and the calibration data is always rewritten.

waclawek.jan wrote:

DBP gets set correctly.

Even in the case of full run, not only in the single-stepping case?

inserting a large delay loop after DBP is set

Wasn't the delay optimized out?

After writing DBP I read it back before accessing the backup SRAM, that's IMO a better method than a delay.

Now things get interesting. I checked the DBP bit just after it was set atfull run this way:

PWR->CR |= PWR_CR_DBP;
if (0 == (PWR->CR & PWR_CR_DBP)) {
 led_on();
 for (;;);
}�?�?�?�?�?�?�?�?�?�?
//write some data into backup SRAM
....
//verify data just written into SRAM before
...�?�?�?�?�?�?�?�?�?�?�?
PWR->CR &= ~PWR_CR_DBP;�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

But the program never traps into the infinity for(;;) loop and the following data is written correctly into the backup SRAM. I checked this by executing this program section in a loop multiple hundred times. The very interesting thing with that code is, ifone omits the 'if' statement andexecutes this code

PWR->CR |= PWR_CR_DBP;
//write some data into backup SRAM
....
//verify data just written into SRAM before
...�?�?�?�?�?�?�?�?�?�?�?
PWR->CR &= ~PWR_CR_DBP;�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

datawrite fails and backup SRAM holds incorrect values.

Next I checked this:

PWR->CR |= PWR_CR_DBP;
PWR->CR |= PWR_CR_DBP;
//write some data into backup SRAM
....
//verify data just written into SRAM before
...�?�?�?�?�?�?�?�?�?�?�?
PWR->CR &= ~PWR_CR_DBP;�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Again executing this code section multiple hundred times in a loop at full run reveals no abnormalities. Data is written correctly.

All three code sections were executed with the power and backup SRAM interface clocks enabled at startup.

Posted on June 23, 2017 at 13:09

The reason is that the integrity of the backup SRAM is checked with a CRC-32 checksum after startup. An invalid checksum lets the subroutines know to rewrite the calibration data. So it is very simple to watch the behaviour of the subroutines, because with regulator off when debugging the checksum is invalid after every power-up and the calibration data is always rewritten.

Ah, I see. I use a 'real' battery (CR2032) in a battery holder, so something like this did not occur to me - for the  cursory backup-failure-testing I simply removed the battery.

----

The symptoms you described are the same as in the old thread I gave link to, i.e. when the write to PWR_CR_DBP is immediately followed by write to backup ram, the latter may fail unnoticed with written data falling over to void. The reason is that the write to PWR - which is behind an AHB/APB bridge - is delayed on that bridge, but as the bridge has a (single-issue) write buffer, it won't hold up the processor which proceeds with the write to the backup memory, and that - being directly on AHB1 - happens before the physical write to PWR. This hazard is dependent on the particular AHB-to-APB clock divider ratio, the particular state of the physical AHB-to-APB clock divider at the moment when the write happens, delays on the APB bus and inside the PWR module if any, delays on resynchronizators between PWR and the write gate on the backup RAM if any, and the exact ordering of instructions (and the state of instruction pipelines and prefetches and ART caches etc.) between the two writes.

Delay loops written in C without built-in 'volatility' tend to get optimized out, the compiler/optimizer's task is to avoid wasting time. That's why reading back the PWR register (or a repeated write to it) is better, as that has to wait until the write buffer on the AHB/APB bridge gets emptied, i.e. the first write gets accomplished. A well-crafted delay might be superior when it gets to ultimate speed down to the very last clock cycle, but we'd need to know more minute details about the exact timing of things than the manuals provide.

JW

Posted on June 23, 2017 at 13:45

Hello Jan,

many thanks for your detailed technical answear. The relation between the PWR and Backup SRAM, both sitting behind the AHB/APB bridge, and the latency DBP is set, explains everything.

Even though this sounds logically, it is very hard to read out this technical background from the reference manual.

You are right that the compiler has optimized out the simple delay loop, just incrementing a counting variable. The reason why it doesn't work with the loop.

To solve my problem I have the choice between double writing to PWR or reading it back.

Thanks for your help!

Sebastian