cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 mass storage class with internal flash

Alexey Kondakov
Associate II
Posted on February 01, 2017 at 10:10

Hi! I am using stm32f4-discovery to start working with mass storage clas and internal flash.

I have tried different ways but every time I've had the same resault. I can see storage device

in My Computer but can't use it because I can't format it. I've seen another topics with the same

problem but I have not found any solution yet. Can somebody help me?

I'd like to use the last sector of internal flash (128 Kb) to store my device's settings. There is my code in attach...and thanks a lot!

P.S. I'm sorry for my poor English.

#stm32f407-msc-format #stm32f4-discovery #msc
8 REPLIES 8
MARTIN LAZZARI
Associate II
Posted on April 20, 2017 at 06:13

Hi, I'm also trying to do the same, with an STM32F433. It was easy to implement the drive in RAM, just defined a static array, and memcpy'd to and from it. However, I'm having problems when trying to implement it in internal flash. Have you had any luck with this? The 'F433 has a different Flash structure (size, locations, etc) and it seems to have a different set of functions in the HAL driver for the Flash (compared to the processor in the F4 discovery). By looking at your code, something that pops up is that in your write operation you are calling

HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);

but 

EraseInitStruct

has been filled only in STORAGE_Init_FS and it is pointing to your whole Sector 11, and therefore, every time you're writing to a Flash Drive sector, you're erasing your whole user memory. The rest seems to make sense for me (although I am not yet familiar with the Flash functions in this micro)

Alexey Kondakov
Associate II
Posted on April 20, 2017 at 14:35

Hi, Martin!

I' ve succeedded in programming STM with USB MSC & internal FLASH (great thanks to dang_son.hai for his help). But I've still have unsolved problem.

I can successfully create, format, write to and read from a mass storage. In my case it's a 32K mass storage located in the last 11'th FLASH sector.

 I told you I can format my mass storage. It's true. But I can do it with Windows 7 (only as quick format) and Linux (Windows XP can't format device). I don't know about Windows 7 & XP differeces so I can only conjecture.

The second problem is speed. All procedure (format, change & save data) is very slow. Format to FAT from Linux lasts about 2 minutes, from Windows lasts about 1 minutes.

Saving 1K *.txt file lasts about 30 sec. I gebugged my project and found out that saving one simbol change in *.txt file leads to calling 'STORAGE_Write_FS()' procedure in project about 10 times!

In another words it leads to reading data and erasing flash secter 10 times per one simbol! It's curiously. I don't understand why USB HAL cal my procedure many times... It waste time and demage flash memory.

Mr. Dang_son.hai supposed I was wrong with USB initial. May be. But I have workable project with mass storage & SD card. And it works better!

Martin, you wrote '...every time you're writting to a Flash Drive sector, you're erasing your whole user memory...'. Yeah. You can erase whole Flash memory or whole sector. I erase whole 11'th sector.

Alexey Kondakov
Associate II
Posted on April 20, 2017 at 14:38

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6ru&d=%2Fa%2F0X0000000bwx%2F9XOKP2OC1W.3oSumD4yHMiONBo.LlkOBEogboaoajcI&asPdf=false
Posted on April 20, 2017 at 15:15

The PC expects to be able to write 512 byte blocks randomly, you would need to implement a caching scheme and a lazy writer so that you only do the erase/write once, or highly infrequently. The erase speed of the 128KB sectors is very slow, the smaller sectors would be faster, so if you can carve some space early in flash that would help that aspect.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 21, 2017 at 03:08

Hi, Alexey

Thank you for sharing your code. I just checked and saw that the processor you're using does not support erasing less than 128K in the area you're using. Then erasing the whole 128k 'makes sense' since it is the only way to go. As Clive One mentioned, that's the main reason why you're getting such low speeds (erasing 128K for every sector write operation). Keep in mind that for overwriting a 1KB file, you will need at least 4 write operations (probably more). When you overwrite the file, you are actually re-writing the whole file. So at least you have to: 1) Write the first sector of the file (first 512 bytes) 2) write the 2nd sector of the file to complete the 1KB 3) update the sector that contains the directory entry with the new time stamp and a new pointer to the first FAT entry in the FAT 4) Update the FAT to point to the new sectors that the file is using. I'm probably missing some operations, but the number of writes that you see are probably due to the way FAT works, and not related to the implementation of the USB Mass Storage Device in the ST libraries. I'll make some more tries with my code to see if I can get it to work on the L433.

Posted on April 21, 2017 at 05:10

FAT is non-ideal, with enough RAM you can mask the issue, but here we are obviously resource constrained. A file system like UDF as used on write-once media like CD-R/DVD-R might work better, but does eat a lot in file system structures, and on flash would need some garbage collection to recover discarded blocks periodically.

I did build a MSC RAM-DRIVE using the SDRAM of an STM32F429I-DISCO

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 22, 2017 at 05:26

 ,

 ,

I got it to work on the STM32L433. For some reason Windows 7 (haven't tried any other OS) didn't like sector sizes different than 512 bytes. I had to write some logic to write several 512 bytes sectors in a Flash page (2K). This is my code (the rest not shown was untouched from whatever STM32CubeMX generated).

♯ define STORAGE_LUN_NBR 1

 ,

♯ define STORAGE_BLK_NBR 256 //256 blocks * 512 = 128k

 ,

♯ define STORAGE_BLK_SIZ 512 //doesn't seem to work well with values other than 512

 ,

 ,

/* USER CODE BEGIN PRIVATE_DEFINES */

 ,

//In order to reserve enough flash for my drive

 ,

//I modified the linker file <,projectName>,.ld

 ,

//Original file: FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K

 ,

//Modified file: FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K

 ,

//this should limit available memory for program to 128K, leaving

 ,

//another 128K for my flash drive

 ,

♯ define FLASH_STORAGE_START 0x08020000

 ,

♯ define FLASH_STORAGE_START_PAGE ((FLASH_STORAGE_START - FLASH_BASE)/FLASH_PAGE_SIZE)

 ,

♯ define STORAGE_BLK_PER_PAGE (FLASH_PAGE_SIZE/STORAGE_BLK_SIZ) //for the F433 would be 4

 ,

/* USER CODE END PRIVATE_DEFINES */

 ,

 ,

/*******************************************************************************

 ,

* Function Name : STORAGE_Read_FS

 ,

* Description :

 ,

* Input : None.

 ,

* Output : None.

 ,

* Return : None.

 ,

*******************************************************************************/

 ,

int8_t STORAGE_Read_FS (uint8_t lun,

 ,

uint8_t *buf,

 ,

uint32_t blk_addr,

 ,

uint16_t blk_len)

 ,

{

 ,

/* USER CODE BEGIN 6 */

 ,

memcpy(buf, (const void *)(FLASH_STORAGE_START + blk_addr * STORAGE_BLK_SIZ), blk_len * STORAGE_BLK_SIZ),

 ,

 ,

return (USBD_OK),

 ,

/* USER CODE END 6 */

 ,

}

 ,

 ,

 ,

/*******************************************************************************

 ,

* Function Name : STORAGE_Write_FS

 ,

* Description :

 ,

* Input : None.

 ,

* Output : None.

 ,

* Return : None.

 ,

*******************************************************************************/

 ,

int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {

 ,

/* USER CODE BEGIN 7 */

 ,

FLASH_EraseInitTypeDef eraseStruct,

 ,

eraseStruct.TypeErase=FLASH_TYPEERASE_PAGES,

 ,

eraseStruct.Page = FLASH_STORAGE_START_PAGE + blk_addr,

 ,

eraseStruct.NbPages = 1,

 ,

eraseStruct.Banks = 0,

 ,

 ,

 ,

uint32_t PageError,

 ,

uint64_t *pBuf64,

 ,

pBuf64 = (uint64_t *) buf,

 ,

//buffer to hold one full page

 ,

static uint8_t pageShadow[FLASH_PAGE_SIZE],

 ,

uint32_t targetFlashPage, lastTargetPage,

 ,

uint32_t targetPageOffset,

 ,

 ,

 ,

lastTargetPage = 0xFFFFFFFF, //some invalid page

 ,

HAL_FLASH_Unlock(),

 ,

 ,

for (uint32_t blk_index = blk_addr, blk_index <, (blk_addr + blk_len), blk_index++) {

 ,

//copy the contents of the whole page before erasing

 ,

targetFlashPage = FLASH_STORAGE_START_PAGE + (blk_index / STORAGE_BLK_PER_PAGE),

 ,

targetPageOffset = (blk_index % STORAGE_BLK_PER_PAGE) * STORAGE_BLK_SIZ,

 ,

//are we still writing to the page we wrote last?

 ,

if (lastTargetPage != targetFlashPage) {

 ,

//No, this is a different page

 ,

//copy the contents of the page to a buffer

 ,

memcpy(pageShadow, (const void *) (FLASH_BASE + targetFlashPage * FLASH_PAGE_SIZE), FLASH_PAGE_SIZE),

 ,

//erase the page

 ,

eraseStruct.Page = targetFlashPage,

 ,

eraseStruct.NbPages = 1,

 ,

HAL_FLASHEx_Erase(&,eraseStruct, &,PageError),

 ,

//no need to call FLASH_WaitForLastOperation() here

 ,

//remember the page we're on

 ,

lastTargetPage = targetFlashPage,

 ,

}

 ,

//copy one block to the buffer

 ,

memcpy(&,pageShadow[targetPageOffset], &,buf[(blk_index - blk_addr) * STORAGE_BLK_SIZ], STORAGE_BLK_SIZ),

 ,

//if we're about to change pages or this is the end, commit to Flash

 ,

//Use DWORD (64-bit) access when programming (I expect it to be faster)

 ,

if (((blk_index % STORAGE_BLK_PER_PAGE) == (STORAGE_BLK_PER_PAGE - 1))

 ,

|| blk_index == (blk_addr + blk_len - 1)) {

 ,

pBuf64 = (uint64_t*) pageShadow,

 ,

for (uint32_t dword_index = 0, dword_index <, FLASH_PAGE_SIZE, dword_index += 8) {

 ,

HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, targetFlashPage * FLASH_PAGE_SIZE + dword_index,

 ,

*pBuf64),

 ,

FLASH_WaitForLastOperation(1000), //not sure if this is required

 ,

pBuf64++, //next 64 bits

 ,

}

 ,

}

 ,

}

 ,

//lock the flash to prevent accidental changes

 ,

HAL_FLASH_Lock(),

 ,

 ,

return (USBD_OK),

 ,

/* USER CODE END 7 */

 ,

}

 ,

 ,

 ,

 ,

Hi Alexey,

could you please share your working usbd_storage_if.c file with the community? I suffer to get that working on different STM32. Thanks