Le STM32F303K8 que j'ai a un flash de 64 Ko. Dans le passé, le flash était utilisé pour stocker le code. Je ne connaissais pas la méthode détaillée car j'ai écrit le code via gdb. Par conséquent, le contrôle du flash est effectué afin que les données puissent être librement enregistrées sur votre propre logiciel.
STM32F303K8
Le manuel de référence décrit comment procéder. Il peut être lu, écrit et effacé. En raison des caractéristiques du flash, la zone est divisée en pages. La lecture est possible en unités d'octets, mais l'écriture est en unités d'un demi-mot (16 bits) et l'effacement est en unités de page (2 Ko).
La procédure de lecture est décrite comme suit.
Il est accessible comme la mémoire normale.
sample_read
uint8_t read(uint8_t* address){
return *address;
}
Le flash se détériore après une écriture et un effacement répétés, il semble donc être verrouillé après la réinitialisation. Par conséquent, écrivez / effacez après le déverrouillage. De plus, l'écriture ne peut être effectuée que dans la zone effacée (non écrite). Il est nécessaire d'effacer la zone correspondante avant d'écrire.
La méthode de déverrouillage est décrite comme suit. La définition séquentielle de KEY1 et KEY2 dans le registre FLASH_KEYR déverrouille et autorise l'accès au registre FLASH_CR.
sample_unlock
void unlock(void){
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
La procédure d'écriture est décrite comme suit. Le code ressemble à ceci:
sample_write
okng_t write(uint16_t* address, uint16_t data){
while(FLASH->FLASH_SR & FLASH_SR_BSY);
FLASH->CR |= FLASH_CR_PG;
*address = data;
while(FLASH->FLASH_SR & FLASH_SR_BSY);
if(FLASH->FLASH_SR & FLASH_SR_EOP){
FLASH->FLASH_SR &= ~FLASH_SR_EOP;
return OK;
}else{
return NG;
}
}
Il y a l'effacement de page et l'effacement complet, mais ici nous expliquerons l'effacement de page. La procédure d'effacement est décrite comme suit. Le code ressemble à ceci:
sample_erase
okng_t erase(uint8_t* address){
while(FLASH->FLASH_SR & FLASH_SR_BSY);
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = (uint32_t)address;
FLASH->CR |= FLASH_CR_STRT;
while(FLASH->FLASH_SR & FLASH_SR_BSY);
if(FLASH->FLASH_SR & FLASH_SR_EOP){
FLASH->FLASH_SR &= ~FLASH_SR_EOP;
return OK;
}else{
return NG;
}
}
J'ai spécifié une adresse, mais la page entière, y compris l'adresse, est effacée. C'est difficile à comprendre à ce rythme, vous devrez peut-être concevoir quelque chose dans l'interface.
Tester le logiciel embarqué avec Google test a permis d'installer TDD, alors écrivons d'abord le code de test. Puisque le code de test entier est long, je publierai le test Write OK. Le tout est à ici. Puisque STM32 est 32 bits, l'adresse de la zone flash virtuelle du PC hôte doit également être 32 bits. Par conséquent, ce test ne fonctionne que dans un environnement 32 bits. Veuillez laisser les contre-mesures comme un problème futur.
class FlashTest : public ::testing::Test {
protected:
virtual void SetUp()
{
mock = new MockIo();
//Registre flash virtuel
virtualFlash = new FLASH_TypeDef();
//Zone flash virtuelle Juste un tableau
virtualAddress = new uint8_t[100];
//Définissez les adresses de début et de fin de la baie pour déterminer la zone flash
virtualStart = (uint32_t)&virtualAddress[0];
virtualEnd = (uint32_t)&virtualAddress[100]; //Obtenir une adresse hors de portée
FlashCreate(virtualFlash, virtualStart, virtualEnd);
}
virtual void TearDown()
{
delete mock;
delete virtualFlash;
delete virtualAddress;
}
};
TEST_F(FlashTest, WriteOK)
{
mock->DelegateToVirtual();
//Effacez la zone d'écriture prévue à 0
virtualAddress[0] = 0;
virtualAddress[1] = 0;
//Adresse d'écriture flash virtuelle
uint16_t* dummy = (uint16_t*)&virtualAddress[0];
//Écrire des données
uint16_t data = 0xBEEF;
EXPECT_CALL(*mock, ReadBit(&virtualFlash->CR, FLASH_CR_LOCK)).WillOnce(Return(0));
EXPECT_CALL(*mock, ReadBit(&virtualFlash->SR, FLASH_SR_BSY)).WillRepeatedly(Return(FLASH_SR_BSY));
EXPECT_CALL(*mock, ReadBit(&virtualFlash->SR, FLASH_SR_BSY)).WillRepeatedly(Return(0));
EXPECT_CALL(*mock, SetBit(&virtualFlash->CR, FLASH_CR_PG));
EXPECT_CALL(*mock, ReadBit(&virtualFlash->SR, FLASH_SR_BSY)).WillRepeatedly(Return(FLASH_SR_BSY));
EXPECT_CALL(*mock, ReadBit(&virtualFlash->SR, FLASH_SR_BSY)).WillRepeatedly(Return(0));
EXPECT_CALL(*mock, ReadBit(&virtualFlash->SR, FLASH_SR_EOP)).WillOnce(Return(FLASH_SR_EOP));
EXPECT_CALL(*mock, ClearBit(&virtualFlash->SR, FLASH_SR_EOP));
EXPECT_EQ(FLASH_RESULT_OK, FlashWrite(dummy, data));
EXPECT_EQ(*dummy, data);
}
Le test a préparé ce qui suit. ・ Lire OK ・ Lire NG (adresse terminée) ・ Écriture OK ・ Write NG (échec d'écriture) ・ Ecrire NG (adresse over) ・ Effacer OK ・ Erase NG (échec de l'effacement) ・ Effacer NG (adresse terminée) Enfin, implémentez pour amener le test sur le chemin.
Ce n'est pas un produit, mais c'est un code grand public. Les détails tels que les opérations de registre sont des fonctions internes. Le code source complet est ici.
python
//Créé pour les paramètres virtuels dans les tests
void FlashCreate(FLASH_TypeDef* flash_address, uint32_t start_address, uint32_t end_address)
{
flashAddress = flash_address;
flashStart = start_address;
flashEnd = end_address;
}
//Réglage de l'adresse et déverrouillage
void FlashInit(void)
{
#ifndef DEBUG_GTEST
FlashCreate(FLASH, (uint32_t)&_flash_addr, (uint32_t)&_flash_addr + (uint32_t)&_flash_size);
#endif
flash_unlock();
}
//en train de lire
uint8_t FlashRead(uint8_t* address)
{
if(!is_flash_area((uint32_t)address, sizeof(*address))){
return 0;
}
return *address;
}
//l'écriture
flash_result_t FlashWrite(uint16_t* address, uint16_t data)
{
if(!is_flash_area((uint32_t)address, sizeof(*address))){
return FLASH_RESULT_NG;
}
if(is_flash_locked()){
return FLASH_RESULT_NG;
}
while(is_flash_busy());
flash_write(address, data);
while(is_flash_busy());
return check_flash_eop();
}
//Effacer
flash_result_t FlashPageErase(uint8_t* address)
{
if(!is_flash_area((uint32_t)address, sizeof(*address))){
return FLASH_RESULT_NG;
}
if(is_flash_locked()){
return FLASH_RESULT_NG;
}
while(is_flash_busy());
flash_page_erase(address);
while(is_flash_busy());
return check_flash_eop();
}
Je vais en fait l'écrire sur le flash.
python
static int flash(int argc, char *argv[])
{
flash_result_t ret;
FlashInit();
ret = FlashPageErase((uint8_t*)0x0800F800);
if(ret != FLASH_RESULT_OK){
printf("ERASE ERROR!!\n");
return 0;
}
printf("0x%X%X\n", FlashRead((uint8_t*)0x0800F801), FlashRead((uint8_t*)0x0800F800));
ret = FlashWrite((uint16_t*)0x0800F800, 0xBEEF);
if(ret != FLASH_RESULT_OK){
printf("WRITE ERROR!!\n");
return 0;
}
printf("0x%X%X\n", FlashRead((uint8_t*)0x0800F801), FlashRead((uint8_t*)0x0800F800));
return 0;
}
Je le ferai.
BEEF a été écrit !!
Je voudrais l'utiliser pour créer un chargeur de démarrage qui écrit le code sur le flash, le lit en mémoire et démarre.
Recommended Posts