[GO] Save data to flash with STM32 Nucleo Board

Introduction

The STM32F303K8 I have has a 64KB flash. In the past, flash was used to store code. I didn't know the detailed method because I wrote the code via gdb. Therefore, flash control is performed so that data can be freely saved on the software created by the user.

Development target

STM32F303K8

Investigation

The reference manual describes how to do this. It can be read, written, and erased. Due to the characteristics of the flash, the area is divided into pages. flash_org.png Reading is possible in Byte units, but writing is in Half Word (16bit) units and erasing is in Page (2KByte) units.

Read procedure

The reading procedure is described as follows.

flash_read.png

It can be accessed like normal memory.

sample_read


uint8_t read(uint8_t* address){
    return *address;
}

Write / erase procedure

The flash deteriorates after repeated writing and erasing, so it seems to be locked after reset. Therefore, unlock it before writing / erasing. Also, writing can only be done in the erased (unwritten) area. It is necessary to erase the corresponding area before writing.

unlock

The unlock method is described as follows. flash_unlock.png You can unlock the FLASH_KEYR register by setting KEY1 and KEY2 in sequence to access the FLASH_CR register.

sample_unlock


void unlock(void){
    FLASH->KEYR = FLASH_KEY1;
    FLASH->KEYR = FLASH_KEY2;
}

writing

The writing procedure is described as follows. flash_prog.png The code looks like this:

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;
    }
}

Erase

There are Page Erase and Whole Erase, but here we will explain Page Erase. The erasing procedure is described as follows. flash_ers.png The code looks like this:

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;
    }
}

Although the address is specified, the entire Page including the address is deleted. It's hard to understand at this rate, so you may need to devise an interface.

create

Test code

Test embedded software with Google test has made it possible to introduce TDD, so let's write the test code first. Since the whole test code is long, I will post the Write OK test. The whole is located here [https://github.com/mitazet/stm32/blob/master/v10/Main/driver/flash/test/test_flash.cpp). Since STM32 is 32bit, the address of the virtual flash area of the host PC must also be 32bit. Therefore, this test only works in a 32-bit environment. Please leave the countermeasures as a future issue.

class FlashTest : public ::testing::Test {
    protected:
        virtual void SetUp()
        {
            mock = new MockIo();
            //Virtual flash register
            virtualFlash = new FLASH_TypeDef();
            //Virtual flash area Just an array
	        virtualAddress = new uint8_t[100];
            //Set the start and end addresses of the array to determine the flash area
	        virtualStart = (uint32_t)&virtualAddress[0];
	        virtualEnd = (uint32_t)&virtualAddress[100]; //Get out-of-range address
            FlashCreate(virtualFlash, virtualStart, virtualEnd);
        }
        
        virtual void TearDown()
        {
            delete mock;
            delete virtualFlash;
            delete virtualAddress;
        }
};

TEST_F(FlashTest, WriteOK)
{
    mock->DelegateToVirtual();

    //Clear the planned writing area to 0
    virtualAddress[0] = 0;
    virtualAddress[1] = 0;
  //Virtual flash write address
    uint16_t* dummy = (uint16_t*)&virtualAddress[0];
  //Write data
    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);
}

The test prepared the following. ・ Read OK ・ Read NG (address over) ・ Writing OK ・ Write NG (write failure) ・ Write NG (address over) ・ Erase OK ・ Erase NG (erasure failure) ・ Erase NG (address over) Implement to finally bring the test to the path. gtest_flash.png

Product code

It's not a product, but it's a mainstream code. Details such as register operations are internal functions. The entire source code is here.

python


//Created for virtual settings in tests
void FlashCreate(FLASH_TypeDef* flash_address, uint32_t start_address, uint32_t end_address)
{
    flashAddress = flash_address;
    flashStart = start_address;
    flashEnd = end_address;
}

//Address setting and unlocking
void FlashInit(void)
{
#ifndef DEBUG_GTEST
    FlashCreate(FLASH, (uint32_t)&_flash_addr, (uint32_t)&_flash_addr + (uint32_t)&_flash_size);
#endif
    flash_unlock();
}

//reading
uint8_t FlashRead(uint8_t* address)
{
    if(!is_flash_area((uint32_t)address, sizeof(*address))){
        return 0;
    }

    return *address;
}

//writing
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();
}

//Erase
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();
}

move

I will actually write it on the 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;
}

I will do it. flash_rw.png

BEEF has been written !!

at the end

I would like to use this to create a bootloader that writes code to flash, reads it to memory and boots it.

Recommended Posts

Save data to flash with STM32 Nucleo Board
I tried to save the data with discord
Save tweet data with Django
Save & load data with joblib, pickle
How to deal with imbalanced data
How to deal with imbalanced data
How to Data Augmentation with PyTorch
Save the results of crawling with Scrapy to the Google Data Store
Send data to DRF API with Vue.js
Convert FX 1-minute data to 5-minute data with Python
Try converting to tidy data with pandas
How to read problem data with paiza
How to create sample CSV data with hypothesis
Convert data with shape (number of data, 1) to (number of data,) with numpy.
I want to knock 100 data sciences with Colaboratory
I tried to get CloudWatch data with Python
How to scrape horse racing data with BeautifulSoup
[Introduction to minimize] Data analysis with SEIR model ♬
Save the object to a file with pickle
Write CSV data to AWS-S3 with AWS-Lambda + Python
Save pandas data in Excel format to data assets with Cloud Pak for Data (Watson Studio)
How to use xgboost: Multi-class classification with iris data
I tried to read and save automatically with VOICEROID2 2
How to scrape image data from flickr with python
Reading Note: An Introduction to Data Analysis with Python
I tried to automatically read and save with VOICEROID2
How to get more than 1000 data with SQLAlchemy + MySQLdb
How to extract non-missing value nan data with pandas
I tried to analyze J League data with Python
Input Zaim data to Amazon Elasticsearch Service with Logstash
Carry over data to another page (tab) with streamlit
How to extract non-missing value nan data with pandas