stm32f4 のリファレンス マニュアルと stm32f405xx/stm32f407xx データシートを読んだ後、バックアップ sram を実際に使用する方法 (またはその場所) が明確ではないことに同意します。これが私が見つけたものです。RTC レジスタとバックアップ SRAM の両方に、バッテリ電源がある限り維持されるある程度のストレージが含まれています。RTC には 20 個のレジスタ (80 バイト) が含まれており、バックアップ SRAM (AHB1 上の独自のペリフェラルであり、レジスタ アドレス領域内にある) には 0x1000 (4096 バイト) が含まれています。どちらもデフォルトでは有効になっていません。
DM00037051 (stm32f405xx/stm32f407xx データシート、p29):
The 4-Kbyte backup SRAM is an EEPROM-like memory area. It can be used to store
data which need to be retained in VBAT and standby mode. This memory area is
disabled by default to minimize power consumption (see Section 2.2.19:
Low-power modes). It can be enabled by software.
The backup registers are 32-bit registers used to store 80 bytes of user
application data when VDD power is not present. Backup registers are not reset
by a system, a power reset, or when the device wakes up from the Standby mode
(see Section 2.2.19: Low-power modes).
データシートの71ページとリファレンスマニュアルの65ページ
AHB1 | 0x4002 4000 - 0x4002 4FFF | BKPSRAM
データシートの73ページとリファレンスマニュアルの67ページ
APB1 | 0x4000 2800 - 0x4000 2BFF | RTC & BKP Registers
リファレンス マニュアルの 118 ~ 119 ページには、バックアップ SRAM および RTC レジスタの有効化に関する情報が含まれています。
注: バックアップ ドメインで RTC を既に使用していて、80 バイト以下しか保存する必要がない場合は、RTC バックアップ レジスタを使用することをお勧めします。これは、バックアップ SRAM を有効にすると、基本的に消費電流が 2 倍になるためです ( stm32f405/7 データシート)。
ここに、バックアップ SRAM とバックアップ RTC レジスタの両方に対する書き込みおよび読み取り関数を示します。
int8_t write_to_backup_sram( uint8_t *data, uint16_t bytes, uint16_t offset ) {
const uint16_t backup_size = 0x1000;
uint8_t* base_addr = (uint8_t *) BKPSRAM_BASE;
uint16_t i;
if( bytes + offset >= backup_size ) {
/* ERROR : the last byte is outside the backup SRAM region */
return -1;
}
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
/* disable backup domain write protection */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // set RCC->APB1ENR.pwren
PWR_BackupAccessCmd(ENABLE); // set PWR->CR.dbp = 1;
/** enable the backup regulator (used to maintain the backup SRAM content in
* standby and Vbat modes). NOTE : this bit is not reset when the device
* wakes up from standby, system reset or power reset. You can check that
* the backup regulator is ready on PWR->CSR.brr, see rm p144 */
PWR_BackupRegulatorCmd(ENABLE); // set PWR->CSR.bre = 1;
for( i = 0; i < bytes; i++ ) {
*(base_addr + offset + i) = *(data + i);
}
PWR_BackupAccessCmd(DISABLE); // reset PWR->CR.dbp = 0;
return 0;
}
int8_t read_from_backup_sram( uint8_t *data, uint16_t bytes, uint16_t offset ) {
const uint16_t backup_size = 0x1000;
uint8_t* base_addr = (uint8_t *) BKPSRAM_BASE;
uint16_t i;
if( bytes + offset >= backup_size ) {
/* ERROR : the last byte is outside the backup SRAM region */
return -1;
}
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
for( i = 0; i < bytes; i++ ) {
*(data + i) = *(base_addr + offset + i);
}
return 0;
}
int8_t write_to_backup_rtc( uint32_t *data, uint16_t bytes, uint16_t offset ) {
const uint16_t backup_size = 80;
volatile uint32_t* base_addr = &(RTC->BKP0R);
uint16_t i;
if( bytes + offset >= backup_size ) {
/* ERROR : the last byte is outside the backup SRAM region */
return -1;
} else if( offset % 4 || bytes % 4 ) {
/* ERROR: data start or num bytes are not word aligned */
return -2;
} else {
bytes >>= 2; /* divide by 4 because writing words */
}
/* disable backup domain write protection */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // set RCC->APB1ENR.pwren
PWR_BackupAccessCmd(ENABLE); // set PWR->CR.dbp = 1;
for( i = 0; i < bytes; i++ ) {
*(base_addr + offset + i) = *(data + i);
}
PWR_BackupAccessCmd(DISABLE); // reset PWR->CR.dbp = 0;
// consider also disabling the power peripherial?
return 0;
}
int8_t read_from_backup_rtc( uint32_t *data, uint16_t bytes, uint16_t offset ) {
const uint16_t backup_size = 80;
volatile uint32_t* base_addr = &(RTC->BKP0R);
uint16_t i;
if( bytes + offset >= backup_size ) {
/* ERROR : the last byte is outside the backup SRAM region */
return -1;
} else if( offset % 4 || bytes % 4 ) {
/* ERROR: data start or num bytes are not word aligned */
return -2;
} else {
bytes >>= 2; /* divide by 4 because writing words */
}
/* read should be 32 bit aligned */
for( i = 0; i < bytes; i++ ) {
*(data + i) = *(base_addr + offset + i);
}
return 0;
}