Il existe deux manières d'émuler une mémoire EEPROM sur le STM32F4:
La deuxième option est décrite ici: AN3969.
Mais, malheureusement, Google n'a pas été en mesure de fournir des informations sur la manière d'utiliser la première option, à savoir utiliser les 4 Ko de mémoire SRAM de sauvegarde en tant que mémoire EEPROM? ..
Quelqu'un peut-il aider sur le sujet?
doit faire ces:
Activer l'horloge PWR
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
Activer l'accès au domaine de sauvegarde
PWR_BackupAccessCmd(ENABLE);
Activer la sauvegarde SRAM Clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
Activer le régulateur à faible consommation d'énergie SRAM pour conserver son contenu en mode VBAT
PWR_BackupRegulatorCmd(ENABLE);
et vous pouvez écrire/lire des données dans sram (ces codes à partir des codes BKP_Domain dans STM32F4xx_DSP_StdPeriph_Lib) (dans mon mcu stm32f417 BKPSRAM_BASE = 0x40024000)
// Write to Backup SRAM with 32-Bit Data
for (i = 0x0; i < 0x100; i += 4) {
*(__IO uint32_t *) (BKPSRAM_BASE + i) = i;
}
// Check the written Data
for (i = 0x0; i < 0x100; i += 4) {
if ((*(__IO uint32_t *) (BKPSRAM_BASE + i)) != i){
errorindex++;
}
}
alors si vous voulez:
// Wait until the Backup SRAM low power Regulator is ready
while(PWR_GetFlagStatus(PWR_FLAG_BRR) == RESET)
{}
vous pouvez trouver ces fonctions dans STM32F4xx_DSP_StdPeriph_Lib.
après avoir lu le manuel de référence pour stm32f4 et la fiche technique stm32f405xx/stm32f407xx, je conviens qu'il n'est pas clair comment utiliser réellement la sauvegarde sram (ou son emplacement). Voici ce que j'ai trouvé. Les registres RTC et la SRAM de secours contiennent une quantité de stockage qui est maintenue tant que vous disposez de la batterie. Le RTC contient 20 registres (80 octets) et le sram de sauvegarde (qui est son propre périphérique sur AHB1 et situé dans la région d'adresse du registre) contient 0x1000 (4096 octets). Ni sont activés par défaut.
dans DM00037051 (Fiche technique 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).
page 71 de la fiche technique et p65 du manuel de référence
AHB1 | 0x4002 4000 - 0x4002 4FFF | BKPSRAM
et page 73 de la fiche technique et p67 du manuel de référence
APB1 | 0x4000 2800 - 0x4000 2BFF | RTC & BKP Registers
Le Manuel de référence contient des informations sur l’activation des registres SRAM et RTC de sauvegarde.
REMARQUE: si vous utilisez déjà le RTC dans le domaine de sauvegarde et que vous ne devez stocker que <= 80 octets, il est préférable d'utiliser les registres de sauvegarde RTC, car l'activation de la SRAM de sauvegarde va essentiellement doubler la consommation de courant (voir tableau 25 dans la fiche technique stm32f405/7).
voici mes fonctions d'écriture et de lecture pour les registres de sauvegarde SRAM et de sauvegarde 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;
}
Je devais passer du programme principal au chargeur de démarrage à la demande de l'utilisateur. J'ai donc mis un «nombre magique» dans BKPSRAM dans le programme principal, effectuez la réinitialisation à chaud du processeur. Le chargeur de démarrage démarre toujours en premier. .] Il vérifie le nombre magique s'il est présent, il s'exécute, sinon le programme principal démarre
pour utiliser HAL, voici comment accéder au chargeur de démarrage:
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
__BKPSRAM_CLK_ENABLE();
*(__IO uint8_t *)0x40024000 = 42;//magic number
HAL_NVIC_SystemReset();
dans le chargeur de démarrage pour lire le nombre magique, il suffit d'activer la sauvegarde de l'horloge sram uniquement (le chargeur de démarrage utilise StdPeriphDriver).
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
extRequest = *(__IO uint8_t *)0x40024000;
if(extRequest == 42)
//run bootloader
cpu est stm32f407
J'utilise actuellement un microcontrôleur STM32F2xx. Selon la fiche technique:
La SRAM de sauvegarde de 4 Ko est une zone de type EEPROM.
Pour conserver le contenu des registres de sauvegarde RTC… lorsque VDD est désactivé, la broche VBAT peut être connectée à une tension de veille optionnelle fournie par une batterie ou par une autre source.
Une supercap, par exemple, serait nécessaire pour conserver le contenu des registres de sauvegarde pendant que le microcontrôleur est mis hors tension.
Aussi, selon le document:
Après la réinitialisation, le domaine de sauvegarde (… SRAM de sauvegarde) est protégé contre les éventuels accès en écriture indésirables. Pour activer l'accès au domaine de sauvegarde, procédez comme suit…
Il vous explique comment accéder au domaine de sauvegarde en écrivant directement dans le registre de certains périphériques. Si vous avez accès à la bibliothèque STM32F4xx, vous pouvez appeler quelque chose comme ceci (note: j'utilise la bibliothèque STM32F2xx):
PWR_BackupAccessCmd(ENABLE);
Remarque: Il ne suffit pas d'appeler la fonction ci-dessus, par exemple d'activer l'horloge de sauvegarde de l'interface SRAM. Consultez la documentation de la série STM32F4.
Il existe une grande quantité de documentation incorporée dans la source de la bibliothèque qui doit être lue si elle est disponible.
Sur le microcontrôleur de la série STM32F2, la mémoire SRAM est située dans la plage d'adresses mémoire suivante:
0x40024000 - 0x40024FFF
Et peut être écrit quelque part à l'emplacement, par exemple, comme suit:
#define VAR_LOC ((volatile uint8_t *)(0x40024000))
volatile uint8_t *pVar = VAR_LOC;
*pVar = 5;
Configuration HAL pour STM32H7 pour accéder à la SRAM de sauvegarde:
#define BKP_RAM (*(__IO uint32_t *) (D3_BKPSRAM_BASE)) //Start address: 0x38800000
Main() {
__HAL_RCC_BKPRAM_CLK_ENABLE();
HAL_PWREx_EnableBkUpReg();
BKP_RAM = 0xA5AA5A55;
}
En outre, vous devez ajouter une ligne ci-dessous dans systemInit () pour permettre l'accès en écriture à Backup SRAM.
SCB->CACR |= 1<<2;
Exemple utilisable Dans l'en-tête:
//------------------------------------
typedef struct
{
uint32_t isDefault; //must by 0x12345678
uint32_t LastTestNumber;
uint32_t LastUserNumber;
uint32_t LastModeTest;
uint32_t calibv;
uint32_t calibc;
uint32_t WorkTime;
int32_t RTCCalib;
uint32_t LCDContrast;
} sBKPSRAM;
extern sBKPSRAM *BKPSRAM;// = (sSDRAM *)SDRAM_BANK_ADDR;
//------------------------------------
Dans la tête de code , Définissez comme données:
sBKPSRAM *BKPSRAM = (sBKPSRAM *)BKPSRAM_BASE;
Dans Init:
void main(void)
{
(....)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_BKPSRAM, ENABLE);
PWR_BackupAccessCmd(ENABLE);
PWR_BackupRegulatorCmd(ENABLE);
ifDefault();
(....)
}
En procédure:
//-------------------------------------------------
void ifDefault(void)
{
if (BKPSRAM->LastModeTest!=0x12345678)
{
printf("BKPSRAM to default\r\n");
memset(BKPSRAM,0,sizeof(sBKPSRAM));
BKPSRAM->calibv =66920;
BKPSRAM->calibc =79230;
BKPSRAM->RTCCalib =1;
BKPSRAM->LCDContrast =2;
BKPSRAM->LastModeTest =0x12345678;
}
}
//-------------------------------------------------
Voici l'exemple de la bibliothèque HAL pour utiliser une SRAM de sauvegarde.
#define WRITE_READ_ADDR 0x01 //offset value.you can change according to your application
uint32_t write_arr = 0xA5A5A5A6;
uint32_t read_arr;
int main()
{
enable_backup_sram();
writeBkpSram(write_arr);
while(1)
{
read_arr = readBkpSram();
}
}
void enable_backup_sram(void)
{
/*DBP : Enable access to Backup domain */
HAL_PWR_EnableBkUpAccess();
/*PWREN : Enable backup domain access */
__HAL_RCC_PWR_CLK_ENABLE();
/*BRE : Enable backup regulator
BRR : Wait for backup regulator to stabilize */
HAL_PWREx_EnableBkUpReg();
/*DBP : Disable access to Backup domain */
HAL_PWR_DisableBkUpAccess();
}
void writeBkpSram(uint32_t l_data)
{
/* Enable clock to BKPSRAM */
__HAL_RCC_BKPSRAM_CLK_ENABLE();
/* Pointer write on specific location of backup SRAM */
(uint32_t *) (BKPSRAM_BASE + WRITE_READ_ADDR) = l_data;
/* Disable clock to BKPSRAM */
__HAL_RCC_BKPSRAM_CLK_DISABLE();
}
uint32_t readBkpSram(void)
{
uint32_t i_retval;
/* Enable clock to BKPSRAM */
__HAL_RCC_BKPSRAM_CLK_ENABLE();
/* Pointer write from specific location of backup SRAM */
i_retval = *(uint32_t*) (BKPSRAM_BASE + WRITE_READ_ADDR);
/* Disable clock to BKPSRAM */
__HAL_RCC_BKPSRAM_CLK_DISABLE();
return i_retval;
}