Can´t erase data from flash memory (STM32) - c

I´m trying to save some data to flash memory on my STM32F407 board. Before I can save them I need to erase memory sector. I choosed 16 Kbytes Sector1 starting with address 0x08004000 and choosed Voltage range 2.1-2.7 V. I'm using HAL library.
Program stops responding after FLASH->CR |= FLASH_CR_STRT; line inside HAL_FLASHEx_Erase() -> FLASH_Erase_Sector() function.
I'm pretty sure it's my fault but I can't find out what is wrong.
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.Sector = FLASH_SECTOR_1;
EraseInitStruct.TypeErase = TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_2;
EraseInitStruct.NbSectors = 1;
uint32_t SectorError = 0;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
HAL_FLASH_Lock();
return;
}
uint16_t data = 300;
//----------------------------write data
if (HAL_FLASH_Program(TYPEPROGRAM_WORD, start_address, data) != HAL_OK) {
HAL_FLASH_Lock();
return;
}
HAL_FLASH_Lock();
Did I choosed wrong voltage range or number of sectors?
Thanks for your answers.

If your program is bigger than 16k, then you've just managed to erase a part of it from flash. You should pick a sector from the end of the flash (but then the erase times will be longer), or rearrange the sections a bit in your linker configuration.

I found the solution. I used HAL_FLASH_Lock() function instead of HAL_FLASHEx_Erase() function and it works fine. I also changed SECTOR because I was accidently erasing my program.
unit32_t address = 0x0800C000;
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
FLASH_Erase_Sector(FLASH_SECTOR_3, VOLTAGE_RANGE_3);
//----------------------------write data
uint8_t data = 'A';
if (HAL_FLASH_Program(TYPEPROGRAM_BYTE, address, data) != HAL_OK) {
HAL_FLASH_Lock();
return;
}
HAL_FLASH_Lock();
Thanks for your help.

Related

STM32 - writing and reading flash

Can someone tell me what stupid thing I am doing wrong or understanding? As a test, I am trying to write a simple number into flash and retrieve it. Once successful, I will expand this to 6 signed values.
My device is an STM32L476RG
uint64_t data = 88;
Erase_Flash();
HAL_FLASH_Unlock();
Address = ADDR_FLASH_PAGE_256;
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, Address, data) != HAL_OK)
serprintf("Error writing flash.");
HAL_FLASH_Lock();
uint8_t *flash_biases = (uint8_t*) (ADDR_FLASH_PAGE_256);
Based on what I've read, I should be able to access the flash memory like I have. But it's not retrieving the value I expect.
The Erase_Flash() function looks like this:
void Erase_Flash() {
HAL_FLASH_Unlock();
/* Clear OPTVERR bit set on virgin samples */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_MASSERASE;
EraseInitStruct.Banks = FLASH_BANK_2;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) {
serprintf("Error erasing flash.");
}
HAL_FLASH_Lock();
}
FLASH_TYPEPROGRAM_FAST mode is used for writing 32 double words at once and when this mode is used, the third argument (data) becomes the raw starting address of that 32 double word data source, not the data itself.
Currently, your code fetches data from the address starting from 0x88 and writes it (a total of 256 bytes) to the flash. It appears that there is 245 on address 0x88.
You need to use FLASH_TYPEPROGRAM_DOUBLEWORD for writing uint64_t data.

Problem with USB CDC settings and libraries for STM32F4

I'm working in an embedded aplication for STM32F401RBT6 and I'm trying to establish a connection with the PC (Windows 10) but the device is not recognized by the system. The code that I generated by STMCubeMX and debugged by Atollic not works. I saw and try reproduce several examples, but anything works. In the code, I have all libraries that i think necessary.
I'm have this archives generated by STMCubeMX for the CDC comunication, but I'm newbie and I don't know what I have to modify on the code for the USB be recognized by the system. Someone can help me?
Beside the point from Soup ( the failing malloc caused by a heap that is only 0x200 by default) some Windows version have a problem with the line coding in the example.
In the usbd_cdc_if.c you should add:
/* USER CODE BEGIN PRIVATE_VARIABLES */
USBD_CDC_LineCodingTypeDef LineCoding =
{
115200, /* baud rate*/
0x00, /* stop bits-1*/
0x00, /* parity - none*/
0x08 /* nb. of bits 8*/
};
And a little bit below
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
.
.
.
case CDC_SET_LINE_CODING:
LineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\
(pbuf[2] << 16) | (pbuf[3] << 24));
LineCoding.format = pbuf[4];
LineCoding.paritytype = pbuf[5];
LineCoding.datatype = pbuf[6];
break;
case CDC_GET_LINE_CODING:
pbuf[0] = (uint8_t)(LineCoding.bitrate);
pbuf[1] = (uint8_t)(LineCoding.bitrate >> 8);
pbuf[2] = (uint8_t)(LineCoding.bitrate >> 16);
pbuf[3] = (uint8_t)(LineCoding.bitrate >> 24);
pbuf[4] = LineCoding.format;
pbuf[5] = LineCoding.paritytype;
pbuf[6] = LineCoding.datatype;
break;
So the host won't get undefined data if he tries to set the line coding.
Inside USBD_CDC_Init(..) function there is a malloc function which allocates about 540 Bytes memory on the Heap.
This was not taken into account from CubeMX when code generated .
So , at least you must define the Heap size taking into account theese extra Bytes, to have the USB CDC port working.

HAL drivers erase/read/write flash on STM32F4 nucleo

uint32_t PAGEError = 0;
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS ;
EraseInitStruct.Sector = FLASH_SECTOR_0;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, 0x08000000, counter)
HAL_FLASH_Lock();
counter2 = *(__IO uint32_t *)0x08000000;
counter3 = *(__IO uint32_t *)0x08000001;
counter4 = *(__IO uint32_t *)0x08000002;
sprintf(buf, "%d", counter2); //gets send to the OLED with I2C
sprintf(buf2, "%d", counter3);
sprintf(buf3, "%d", counter4);
I want to write the variable counter to the flash and then read it as counter2.
The first flash sector starts at 0x08000000.
counter2, 3 and 4 are display trough an OLED screen.
Displaying counter2 works and shows me the value of counter-1, but it works only once. If I write again to the flash nothing seems to happen.
counter3 and counter4 don't work at all.
Output on the OLED when counter=0x00000008 after I have erased the flash but not written anything:
counter2: 536873624
counter3: -652214262
counter4: 31006720
And after writting and ressetting:
counter2: 8
counter3: -654311424
counter4: 30998528
What is going on here? Can someone tell me why all variables change?
Do I have to configure the linker?
I will treat you now as begineer, but will say sorry if you are not.
STM32 devices have flash on 0x08000000 and by erasing this sector, you did failure on startup because you erased actual part from where CPU loads instructions.
When you tried to erase sectors, you did not specify how many sectors to erase.
Reading of counters is wrong. Since you have uint32_t variable, you have to do 4-bytes between readings, something like:
counter2 = *(__IO uint32_t *)0x08000000;
counter3 = *(__IO uint32_t *)0x08000004;
counter4 = *(__IO uint32_t *)0x08000008;
Correct erasing is shown below.
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = FLASH_SECTOR_0; //Specify sector number
EraseInitStruct.NbSectors = 1; //This is also important!
if(HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
//Erase error!
}
So, find out how long is your program and do your operations in sector after your program.
You can find example for EraseProgram in STM32CubeF4 package.
STM32Cube_FW_F4_V1.16.0\Projects\STM324x9I_EVAL\Examples\FLASH\FLASH_EraseProgram\Src\main.c
Concept will work also on your nucleo, just make sure you set correct address for flash erasing.
Thanks to #phoenix!
In Stm32CubF3 reference erasing flash works as follows:
There is to mention how a memory page address is looking:
/* Base address of the Flash sectors */
#define ADDR_FLASH_PAGE_0 ((uint32_t)0x08000000) /* Base # of Page 0, 2 Kbytes */
#define ADDR_FLASH_PAGE_1 ((uint32_t)0x08000800) /* Base # of Page 1, 2 Kbytes */
#define ADDR_FLASH_PAGE_2 ((uint32_t)0x08001000) /* Base # of Page 2, 2 Kbytes */
#define ADDR_FLASH_PAGE_3 ((uint32_t)0x08001800) /* Base # of Page 3, 2 Kbytes */
#define ADDR_FLASH_PAGE_4 ((uint32_t)0x08002000) /* Base # of Page 4, 2 Kbytes */
#define ADDR_FLASH_PAGE_5 ((uint32_t)0x08002800) /* Base # of Page 5, 2 Kbytes */
#define ADDR_FLASH_PAGE_6 ((uint32_t)0x08003000) /* Base # of Page 6, 2 Kbytes */
So your minimal code looks as follows:
I want to delete my application # 0x08003000 --> FLASH_PAGE_6. The erasing is done 2kB wise:
/* EEPROM start address in Flash */
#define EEPROM_START_ADDRESS ((uint32_t)ADDR_FLASH_PAGE_32) /* EEPROM emulation start address */
/* Pages 0 and 1 base and end addresses */
#define PAGE0_BASE_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + 0x0000))
#define PAGE0_END_ADDRESS ((uint32_t)(EEPROM_START_ADDRESS + (PAGE_SIZE - 1)))
//#define PAGE0_ID ADDR_FLASH_PAGE_32
/* Clear flash flags */
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGERR);
uint32_t *flash_ptr = 0x8003000;
uint32_t page_error = 0;
HAL_StatusTypeDef flashstatus;
FLASH_EraseInitTypeDef s_eraseinit;
/* Fill EraseInit structure*/
s_eraseinit.TypeErase = FLASH_TYPEERASE_PAGES;
s_eraseinit.NbPages = 1; // seems to be 1 !!!!
/* I want to delete 54kB in my flash --> 52kB / 2kB (per erase) = 26 iterations
After erasing one page, increment page by 0x800 = 2048 byte = 2kB = pagesize */
for(int pageCount = 0; pageCount < 26; pageCount++){
s_eraseinit.PageAddress = ADDR_FLASH_PAGE_6 + pageCount * 0x800;
flashstatus = HAL_FLASHEx_Erase(&s_eraseinit, &page_error);
}
The best way is to create the new segment of flash in the linkescriptr and place the data there. It is the safest.
If do not know linker scripts create a table of the one segment size, and place it at the end of the flash using your compiler directives.
If you do not know both I suggest a ready made STM eeprom emulation example from the Cube

Erasing my Flash on STM32L1

I'm facing a problem with my erasing function.
I try to erase 15 sectors of my Flash in order to put a new binary file.
I don't understand why but my function freeze and i cannot erase all memory i need.
Here is my code if you want to give a try
/*
* bootloader.c
*
* Created on: 9 juin 2015
* Author: tgloaguen
*/
#include "usart.h"
#include "stm32l1xx_flash.h"
#define WRITE_START_ADDR 0x08000000
#define WRITE_END_ADDR 0x0800FFFF
#define FLASH_PAGE_SIZE ((uint16_t)0x100) //If a page is 256 bits
#define MY_BL_FUNCTIONS __attribute__((section(".bootsection")))
void BootLoader(void) MY_BL_FUNCTIONS;
FLASH_Status Flash_Write ( uint32_t StartAddress, uint8_t *p, uint32_t Size ) MY_BL_FUNCTIONS;
uint8_t Flash_Erase() MY_BL_FUNCTIONS;
void Receive_Data(char * buffer,int size)MY_BL_FUNCTIONS;
void Receive_Size(char * buffer, int *sizeData)MY_BL_FUNCTIONS;
void BootLoader(void) {
//clear all ITs
USART_ITConfig( USART1, USART_IT_RXNE, DISABLE );
//SendString("HELLO",USART2);
uint8_t status,i;
char buffer[33];
//en dur
uint16_t *adr = WRITE_START_ADDR;
uint16_t sizeBin = 51400,k = 0,k_hexa = 0x20;
SendString("BOOTLOADER",USART2);
Flash_Erase();
SendString("ERASEOK",USART2);
//if sizeBin ok
}
and the erase function
uint8_t Flash_Erase() {
uint32_t EraseCounter = 0x00, Address = 0x00;//Erase count, write address
uint32_t NbrOfPage = 0x00;//Recording to erase the pages
volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;/*FLASH complete erasure marks*/
/*Unlock FLASH*/
FLASH_Unlock();
/*Calculate the number of FLASH pages need to erase */
NbrOfPage = (WRITE_END_ADDR - WRITE_START_ADDR) / FLASH_PAGE_SIZE;
/* Remove all hang flags */
FLASH_ClearFlag ( FLASH_FLAG_EOP |
FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR |
FLASH_FLAG_SIZERR |
FLASH_FLAG_OPTVERR );
/* Erase the FLASH page*/
for(EraseCounter = 0; (EraseCounter <NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
{
SendString("ok |",USART2);
FLASHStatus = FLASH_ErasePage(WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
}
FLASH_Lock ( );
return (uint8_t)FLASHStatus;
}
In your code you are tring to erase the whole flash, but you are executing your bootloader from flash from final sectors.
As reported by th REF man
During a write/erase operation to the NVM (except Half Page programming or Double-word
erase/write), any attempt to read the same bank of NVM stalls the bus.
Then you have to preserve the space of bootloader changing WRITE_END_ADDR define according to your memory map.
Example: if your bootloader is 4K long and belongs to the last sector (0x0801 F000 - 0x0801 FFFF) then WRITE_END_ADDR must be 0x0801 EFFF.
EDIT
As #Olaf wrote take care about your ISP (Initial Stack Pointer) and IPC (Initial Program Counter) that belong to first 8 bytes in your flash at address 0.

C program for NIOS II running in wrong sequence

I'm writing a code in C language for my NIOS II processor.
I'm using Ecplipse that making me crazy!
It stuck a lot!!
This part of code should read register using SPI, change the data, write it back and then read it again for a validation.
So the sequence should be SPIread->SPIwrite->SPIread.
When I run it i get SPIread->SPIread->SPIwrite.
The code example:
alt_u32 SpiRead(alt_u8 spiNbytes, alt_u8 spiReg)
{
IOWR_32DIRECT(NRF24_SPI_BASE, 0, 0x1f & spiReg); //set register
IOWR_8DIRECT(NRF24_SPI_BASE, 8, 0x07 & spiNbytes); //Start SPI read
return IORD_32DIRECT(NRF24_SPI_BASE, 12); //return the data
}
void SpiWrite(alt_u32 data,alt_u8 spiNbytes,alt_u8 spiReg)
{
spiReg = 0x1F & spiReg;
spiReg = 0x20 | spiReg;
data = data<<8;
IOWR_32DIRECT(NRF24_SPI_BASE, 0, data | spiReg); //set register
IOWR_8DIRECT(NRF24_SPI_BASE, 8, 0x07 & spiNbytes); //begin write SPI
}
int main(void)
{
alt_u32 dat = 0;
dat = SpiRead(1, 0x06); //read spi
dat = ((dat>>8) & 0x000000f8) | 0x00000005; //change data
SpiWrite(dat, 1, 0x06); //write data back
dat = SpiRead(1, 0x06); //read data to validate
while (1) { } //stay here forever
return 0;
}
If I remove the while loop I get 4 times SPIread and after that 2 times SPIwrite. Each little change may change everything...
My program is 6Kbytes now and I have 18Kbytes dedicated memory (OnChipMemory).
What is wrong, please help!
Dmitry.

Resources