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.
STM32F303K8
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. Reading is possible in Byte units, but writing is in Half Word (16bit) units and erasing is in Page (2KByte) units.
The reading procedure is described as follows.
It can be accessed like normal memory.
sample_read
uint8_t read(uint8_t* address){
return *address;
}
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.
The unlock method is described as follows. 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;
}
The writing procedure is described as follows. 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;
}
}
There are Page Erase and Whole Erase, but here we will explain Page Erase. The erasing procedure is described as follows. 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.
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.
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();
}
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.
BEEF has been written !!
I would like to use this to create a bootloader that writes code to flash, reads it to memory and boots it.
Recommended Posts