STMicroelectronics / x-cube-azrtos-h7

X-CUBE-AZRTOS-H7 (Azure RTOS Software Expansion for STM32Cube) provides a full integration of Microsoft Azure RTOS in the STM32Cube environment for the STM32H7 series of microcontrollers.

Home Page:https://www.st.com/en/embedded-software/x-cube-azrtos-h7.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FX_IO_ERROR - LX_SYSTEM_INVALID_BLOCK

erFalcon opened this issue · comments

Hello,

I am trying to install FileX + LevelX in an stm32h7 microcontroller using a nor custom driver. I do have in my hardware an AT45DB641 NOR memory.

I am working it as an stand alone and also with fault tolerant enable.

My flash chip does have 4096 blocks of 2048 bytes each. i can write and read on pages of 256 bytes each.

Right now i am being able to format and open the media after doing a full reset of my chip, as i understand, putting everything to 1 (0xFF).

I can run the example that stm32 provide about creating a file etc...

My issue happens the second time i do run the code, but this time without erasing the chip.

I am getting following error from levelx: LX_SYSTEM_INVALID_BLOCK

and from filex: FX_IO_ERROR.

My code is as follows:

nor_custom_driver

#ifndef LX_DIRECT_READ

#ifndef NOR_SECTOR_BUFFER_SIZE
#define NOR_SECTOR_BUFFER_SIZE 512
#endif

static ULONG nor_sector_memory[NOR_SECTOR_BUFFER_SIZE];
#endif

UINT lx_stm32_nor_custom_driver_initialize(LX_NOR_FLASH *nor_flash)
{
UINT ret = LX_SUCCESS;

ULONG total_blocks = 0;
ULONG words_per_block = 0;

/* USER CODE BEGIN Init_Section_0 */
total_blocks = _45DBXX_ACTUALBLOCKS;
words_per_block = _45DBXX_BLOCKBYTES / sizeof(ULONG);

nor_flash->lx_nor_flash_base_address = _45DBXX_STARTADD;

/* USER CODE END Init_Section_0 */

nor_flash->lx_nor_flash_total_blocks = total_blocks;
nor_flash->lx_nor_flash_words_per_block = words_per_block;

/* USER CODE BEGIN Init_Section_1 */

/* USER CODE END Init_Section_1 */

nor_flash->lx_nor_flash_driver_read = lx_nor_driver_read;
nor_flash->lx_nor_flash_driver_write = lx_nor_driver_write;

nor_flash->lx_nor_flash_driver_block_erase = lx_nor_driver_block_erase;
nor_flash->lx_nor_flash_driver_block_erased_verify = lx_nor_driver_block_erased_verify;

#ifndef LX_DIRECT_READ
nor_flash->lx_nor_flash_sector_buffer = nor_sector_memory;
#endif

/* USER CODE BEGIN Init_Section_2 */

/* USER CODE END Init_Section_2 */

return ret;

}

static UINT lx_nor_driver_write(ULONG *flash_address, ULONG *source, ULONG words)
{
UINT ret = LX_SUCCESS;

/* USER CODE BEGIN NOR_DRIVER_WRITE */

uint16_t size = words * sizeof(ULONG);			//	TRANSFORMAMOS LAS WORDS A BYTES
uint8_t writeBuffer[_45DBXX_BLOCKBYTES];
for (int i = 0; i < size; ++i)
{
	writeBuffer[i] = ((uint8_t *)source)[i];
}
uint16_t arrayElement = 0 ;
ULONG *localFlashAddress = flash_address;

while (size > 0)
{
    uint32_t chunk_size = (size > _45DBXX_PAGEBYTES) ? _45DBXX_PAGEBYTES : size; // Determine the size of the next chunk
    AT45dbxx_WritePage2(&writeBuffer[arrayElement], (uint16_t)chunk_size, (uint32_t)localFlashAddress);

    // Update the buffer and address for the next chunk
    arrayElement += (chunk_size);
    localFlashAddress += chunk_size ;
    size -= chunk_size;
}

/* USER CODE END  NOR_DRIVER_WRITE */

return ret;

}

static UINT lx_nor_driver_block_erase(ULONG block, ULONG erase_count)
{

UINT ret = LX_SUCCESS;

/* USER CODE BEGIN NOR_DRIVER_BLOCK  */

uint32_t at45Block = (block * _45DBXX_BLOCKBYTES) + _45DBXX_STARTADD ;
AT45dbxx_EraseBlock(at45Block);


/* USER CODE END  NOR_DRIVER_BLOCK  */

return ret;

}

static UINT lx_nor_driver_block_erased_verify(ULONG block)
{
UINT ret = LX_SUCCESS;

/* USER CODE BEGIN NOR_DRIVER_VERIFY  */

// Buffer to store the read data
uint8_t readBuffer[_45DBXX_PAGEBYTES];

// Calculate the starting address in bytes
ULONG start_address = block * _45DBXX_BLOCKBYTES + _45DBXX_STARTADD;

// Read and verify the block in chunks
for (ULONG offset = 0; offset < _45DBXX_BLOCKBYTES; offset += _45DBXX_PAGEBYTES)
{
    // Calculate the current address within the block
    ULONG current_address = start_address + offset;

    // Read a chunk of data
    AT45dbxx_ReadPage2(readBuffer, _45DBXX_PAGEBYTES, current_address);

    // Verify that all bytes in the chunk are 0xFF
    for (ULONG i = 0; i < _45DBXX_PAGEBYTES; ++i)
    {
        if (readBuffer[i] != 0xFF)
        {
            ret = LX_ERROR; // Block is not fully erased
            break;
        }
    }

    // Break out of the loop if an error is detected
    if (ret != LX_SUCCESS)
    {
        break;
    }
}

/* USER CODE END  NOR_DRIVER_VERIFY  */

return ret;

}


UCHAR media_memory[512];
UCHAR media_buffer[512];
ULONG detected_errors;
UCHAR sratch_memory[4096];

/* Define FileX global data structures. */
FX_MEDIA nor_flash_disk;
FX_FILE fx_file;

ULONG fault_tolerant_memory[3072 / sizeof(ULONG)];

and my filex code is:

UINT MX_FileX_Init(VOID)
{
UINT ret = FX_SUCCESS;
/* USER CODE BEGIN MX_FileX_Init */

/* USER CODE END MX_FileX_Init */

/* Initialize FileX. */
fx_system_initialize();

/* USER CODE BEGIN MX_FileX_Init 1*/

/* USER CODE END MX_FileX_Init 1*/

return ret;
}

void MX_FileX_Process()
{
/* USER CODE BEGIN fx_app_thread_entry 0 */

UINT status;
ULONG available_space_pre;
ULONG available_space_post;
ULONG bytes_read;
CHAR read_buffer[32];
CHAR data[] = "This is FileX working on STM32";

uint8_t err = 0 ;

err = 0x80;

 do{
	err = AT45dbxxx_Dataflash_ReadStatus(&_45DBXX_SPI);
 }while(err == 0x80);	

  AT45dbxx_EraseChip();

status =  fx_media_format(&nor_flash_disk,
						fx_stm32_levelx_nor_driver,   // Driver entry
						(VOID*)CUSTOM_DRIVER_ID, // Device info pointer
						(UCHAR*)media_memory,                 // Media buffer pointer
						sizeof(media_memory),         // Media buffer size
						"NOR_FLASH_DISK",             // Volume Name
						1,                            // Number of FATs
						32,                           // Directory Entries
						0,                            // Hidden sectors
						_45DBXX_ACTUALBLOCKS,      		  // Total sectors
						512,           // Sector size
						1,                            // Sectors per cluster
						1,                            // Heads
						1);                           // Sectors per track

 status =  fx_media_open(&nor_flash_disk, "FX_LX_NOR_DISK", fx_stm32_levelx_nor_driver,(VOID*)CUSTOM_DRIVER_ID , media_buffer, sizeof(media_buffer));

 status = fx_media_check(&nor_flash_disk, sratch_memory, 4096,
		FX_FAT_CHAIN_ERROR |
		FX_DIRECTORY_ERROR |
		FX_LOST_CLUSTER_ERROR, &detected_errors);

  status = fx_fault_tolerant_enable(&nor_flash_disk, fault_tolerant_memory, sizeof(fault_tolerant_memory));

  if (status != FX_SUCCESS)
  {
    Error_Handler();
  }

  status =  fx_media_space_available(&nor_flash_disk, &available_space_pre);

  /* Check the get available state request status.  */
  if (status != FX_SUCCESS)
  {
    Error_Handler();
  }

  status =  fx_file_create(&nor_flash_disk, "STM32.TXT");

  /* Check the create status.  */
  if (status != FX_SUCCESS)
  {
    /* Check for an already created status. This is expected on the
    second pass of this loop!  */
    if (status != FX_ALREADY_CREATED)
    {
      /* Create error, call error handler.  */
      Error_Handler();
    }
  }
  status =  fx_file_open(&nor_flash_disk, &fx_file, "STM32.TXT", FX_OPEN_FOR_WRITE);

  status =  fx_file_seek(&fx_file, 0);

  status =  fx_file_write(&fx_file, data, sizeof(data));

  status =  fx_file_close(&fx_file);

  status = fx_media_flush(&nor_flash_disk);

  status =  fx_file_open(&nor_flash_disk, &fx_file, "STM32.TXT", FX_OPEN_FOR_READ);

  status =  fx_file_seek(&fx_file, 0);

  status =  fx_file_read(&fx_file, read_buffer, sizeof(data), &bytes_read);

  status =  fx_file_close(&fx_file);

  status =  fx_media_space_available(&nor_flash_disk, &available_space_post);

  status =  fx_media_close(&nor_flash_disk);

  if (status != FX_SUCCESS)
  {
    /* Error closing the media, call error handler.  */
    Error_Handler();
  }

  while(1)
  {

// BSP_LED_Toggle(LED_GREEN);
// tx_thread_sleep(40);
}

}

I really dont understand what is happening, i am even doing a direct read with my memory functions and i am seeing that the text and file name is present in the memory... is this something someone can help me with?

Hi @erFalcon,
the LX_SYSTEM_INVALID_BLOCK is thrown due to formatting issue.

Looking at the code above, there are 2 visible issues.

  • the NOR_SECTOR_BUFFER_SIZE should be as large as a physical block i.e 2048 in your case.
  • the Total sectors in the format command should be the logical sectors seen by FileX not the LevelX physical blocks _45DBXX_ACTUALBLOCKS. typically it should be:
    (TOTAL_FLASH_SIZE - PHYSICAL_BLOCK_SIZE)/512

you'll need to keep an empty physical sector for better wearleveling performance.

regards
Haithem.

hello @rahmanih thanks a lot for your time and commends,

i have tryed your recomendations but unfortunatelly i am still getting the same two errors, one from LX driver and one from FX driver.

Do you know, or do anyone know if there is a example or if someone has tryed to run this in a SPI interface and not in an QSPI interface?

I have a "similar" "filesystem" running in this hardware, based on the SPIFFS project (i say this in order to "clean" any doubt in my hardware), but this is a system that is "death" and i really need something like FileX and LevelX which is in constant development.

Hope to hear from you soon.

Hello @rahmanih, thanks for your commends.

The issue is happening in the:

https://github.com/azure-rtos/levelx/blob/268e4edf9721beb8560a2d740e650bccb14e3270/common/src/lx_nor_flash_open.c#L410

This means that the some blocks are not fully 0xFFFFFFFF, does your nor flash contain any previous data?
if is the case you'll need to erase it before the format operation.

Hello @rahmanih, thanks for your commends.
The issue is happening in the:
https://github.com/azure-rtos/levelx/blob/268e4edf9721beb8560a2d740e650bccb14e3270/common/src/lx_nor_flash_open.c#L410

This means that the some blocks are not fully 0xFFFFFFFF, does your nor flash contain any previous data? if is the case you'll need to erase it before the format operation.

hello @rahmanih,

i do call the AT45dbxx_EraseChip(); function before mounting for the first time, at this moment, the system does run all ok, but when i turn it off, turn it on again and this time i do not call the mentioned function, i get the mentioned error. I understand all have to be 0xFF at the first mount, but it is happening to me at the second mount.

Could you please confirm that the application scenario is as following:

  1. Erase NOR Flash
  2. Format the Nor Flash
  3. Open the NOR flash Fx media
  4. Write Data on the media
  5. Close FX media
  6. turn off
  7. Turn On
  8. go to step 2

Yes, i can confirm that is what i am doing, and thats how it is failling.

Could you please confirm that the application scenario is as following:

  1. Erase NOR Flash
  2. Format the Nor Flash
  3. Open the NOR flash Fx media
  4. Write Data on the media
  5. Close FX media
  6. turn off
  7. Turn On
  8. go to step 2

Yes, i can confirm that is what i am doing, and thats how it is failling.

then that's clear, you are formatting the NOR flash in step2 without erasing it thus the error.
I suggest that you try to call the fx_media_open() first, it will fail than you erase the NOR flash and format it.
then after turn off/on the fx_media_open() will succeed since there is valid filesystem already.

i dont understand.

I do this:

Erase NOR Flash
Format the Nor Flash
Open the NOR flash Fx media
Write Data on the media
Close FX media
turn off
Turn On

then i do:

Format the Nor Flash
Open the NOR flash Fx media
Write Data on the media
Close FX media

but in this case it fails at format and i cannot use it anymore.

should i only format the media only once? after erasing it? Then everytime i do turn on the mcu, i only do open the media?

should i only format the media only once? after erasing it? Then everytime i do turn on the mcu, i only do open the media?

exactly.

i would give it a shoot and let you know the result. Thanks a lot for your help! Hopefully this was the mistake!

It still not working,

but what i have saw is, after formating it, using it, and after turning off/on but before trying to open the media (without erasing and formating) i am trying to read from the start address of my flash and i do this:

AT45dbxx_ReadPage2(read_data, 256, 0x40000);
AT45dbxx_ReadPage2(read_data, 256, 0x40800);
AT45dbxx_ReadPage2(read_data, 256, 0x41000);
AT45dbxx_ReadPage2(read_data, 256, 0x41800);
AT45dbxx_ReadPage2(read_data, 256, 0x42000);
AT45dbxx_ReadPage2(read_data, 256, 0x42800);
AT45dbxx_ReadPage2(read_data, 256, 0x43000);
AT45dbxx_ReadPage2(read_data, 256, 0x43800);
AT45dbxx_ReadPage2(read_data, 256, 0x44000);
AT45dbxx_ReadPage2(read_data, 256, 0x44800);
AT45dbxx_ReadPage2(read_data, 256, 0x45000);
AT45dbxx_ReadPage2(read_data, 256, 0x45800);
AT45dbxx_ReadPage2(read_data, 256, 0x46000);
AT45dbxx_ReadPage2(read_data, 256, 0x46800);

what i am seeing here is that, i am reading the first 256 bytes (page 1) of each block, and what i see here is, block 1 has data, block 2 has 0, and so on...

May i configuring something wrong for this behaivour? take in count that 0x40000 is my StartAddress (nor_flash->lx_nor_flash_base_address = _45DBXX_STARTADD;)

well you can't know exactely how and where do FileX/LevelX store the data, so having empty blocks is expected.
did check that the erase command is correctly working? i.e all blocks are 0xFFFFFFFF?

i just did that "find" because i have check in which blocks it normally "fail" and is in one of the first 10 blocks, always.

When i call the function: AT45dbxx_EraseChip(); it puts every single byte as 0xFF, same when i call the eraseblock, it put 2048 bytes as 0xFF each starting from the calculed address based on the block given from LevelX.

What i am starting to guess is that if when formating, if it is working in good way. since seems like it is writting "0", because i am very sure that the flash chip have all bytes as 0xFF and then there are bytes that are not.

commented

I have the same problem. I am using the board: STM32F412ZG Discovery with n25q128 nor flash. I found out that this is due to accessing the wrong address exceeding the size of the NOR memory. Moreover, this only works if lx_nor_flash_total_blocks is used equal to the maximum number of subsectors, in my case it is 4096 blocks with a size of 1024 words per block.

I would try to give this a shoot with your recomendation @SimonTechv . I have had to work my filesystem within other way, but with your recomendation maybe i can make it work now.

Thanks for your thoughs and i would let you know if this works for me, hopefully.

commented

@erFalcon Yesterday I came to the conclusion that the number of blocks for levelx should be 1 less than their countable number. Suppose there are 1024 blocks of 4096 bytes in memory, then the number of blocks for levelx will be listed as 1023. The documentation doesn't go into too much detail about the configuration options. So far, the throughput for sequential data recording does not exceed 2.5 KB/s for my configuration.

In my case i am going to launch a configuration with 4095 blocks of 2048 bytes each and then i would share the result.

Something that may also make a conflict with any filesystem is, to provide a different "start" address than the actual start 0x00, i have noted that in the SPIFFS, where i was starting not at address 0x00.

I am not worried about "speed" but about stability.

Thanks a lot for your commends, i would let you know my result

@erFalcon, @SimonTechv
the number of blocks exposed to FileX, when formatting, should be 1 less than those actually counted by levelx.
https://learn.microsoft.com/en-us/azure/rtos/levelx/chapter5#nor-filex-integration

commented

@rahmanih This note only applies to FileX integration. If I'm wrong, please explain in more detail.

@erFalcon, @SimonTechv the number of blocks exposed to FileX, when formatting, should be 1 less than those actually counted by levelx. https://learn.microsoft.com/en-us/azure/rtos/levelx/chapter5#nor-filex-integration

Thanks a lot for your clarification in that particular!

@rahmanih This note only applies to FileX integration. If I'm wrong, please explain in more detail.

As i understand, if the SPI Flash chip does have 4096 blocks, and you provide all of them to the LevelX driver, then when providing the LevelX driver to the FileX Formating/Mounting, you have to use 4095, 1 less than the count used in LevelX.

Ofcourse if you are not using FileX, you can avoid this part, but i understand the goal is to integrate all, your chip with LevelX and also with FileX.

commented

@erFalcon, If I do not use a file system and my memory contains 4096 blocks if we count from 1, then according to my assumption (I analyzed the code a little) I should specify the number 4095 for the number of blocks. When integrating with FileX, this number should decrease to 4094. (This is just my guess, since I could not understand the cause of the error with going beyond the flash address space by 1 block)

What i still not understand is, if i check the STM32 example for an STM32U5G which uses "lx_stm32_nor_custom_driver", in the LevelX implementation, it does define the sector buffer size as 512, and then it creates the nor_sector_memory array with that buffer as number of elements.

Then it does initialize and provides to levelX the blocksize and total blocks, which is 64K for block size and 2048 for total blocks. then block size is converted to words, which is necesary for levelx.

My concern comes in the app_filex (FileX implementation) where FileX does use as sector size 512. And here is where i mix things. Whats the difference in FileX/LevelX between sectors (512 bytes per sector) and blocks(64Kilobytes per block). because this is something until today i still do not understand. As far as i can see, 512 bytes sector size is something like "logical" an the 64Kb per block is something like "phisical" ?. Because at the end, in this example, the total sectors numbers is 262144 but the block count is 2048.

can you @rahmanih provide some guidance on this? Thanks!

Unfortunate i have found same issue as before, i can format and mount the filesystem for the first time, but the second time, i get the IO error when trying to open the media.

commented

@erFalcon
I also encountered a similar problem, however, when testing for fault tolerance. After a sudden reset while recording, I intermittently get the error LX_INVALID_BLOCK. To make sure the driver was working correctly, I tested it and found no recording errors. Perhaps LevelX has some restrictions that are not indicated in the documentation.

Hello everyone,

I have previously posted in the wrong (old?) thread so here is a summary of my problem, which sounds similar to what is discussed here. Though I am not using FileX + LevelX in standalone, but with ThreadX.

I can use the media (NOR Flash over SPI) without any problems if I have written files or have it formatted in the same session. But when I restart the microcontroller (STMH5), it can read the file names of previously created files, but fails in reading their properties. The file handle then either has 0 or max value for each variable. This means that I can "open" files, but cannot read them if they have been created before a shutdown.
Similarly, at the beginning the same kind of problem appeared with opening the media, though that kind of disappeared after formatting it 10 or so times.

As this is discussed here a lot, my size settings are:
Flash Blocks: 4096 Bytes (1024 Words)
Flash Size: 256 Blocks = 2MB
FileX Sector Size: 512
FileX Total Sectors: Size/512 = 4096
LevelX Total Blocks: Size/Block Size = 512

Not sure if this is the same problem, but have you checked what your file or media handles look like when/after your opening them?

For clarity: My steps are:
For Media (This works now but failed at the first few starts):

  1. Erasing Chip
  2. Formatting
  3. Opening
  4. Reading/Writing Files
  5. Turn Off
  6. Turn On
  7. Go To 3

And for Files (Still not working properly):

  1. Opening Media
  2. Creating File
  3. Writing File
  4. Close File for Write
  5. Open For Read
  6. Reading File
  7. Turn Off
  8. Turn On
  9. Go to 5

And by the way, have any of you tried to erase and format the media for like 10-20 times and see if it works properly then? Still not sure if my code is the issue (and it's not a proper solution) but this solved my media issue with 3 different devices already.

Hi @m1ndbr34ker,

after step 4. do you call the fx_media_flush() ?

regards
haithem.

@rahmanih No I do not. Though I also not have fault tolerance enabled. Are these two not correlated?

commented

I performed fault tolerance testing on a real device for NOR memory. LevelX does not meet the requirements. The developers do not respond to requests for information about the problem.

@rahmanih No I do not. Though I also not have fault tolerance enabled. Are these two not correlated?

you need to do it, to make filex update the filesystem on the nor flash.

Thanks for the quick response. I'll update the code right away.

Is that also necessary when a new media is formatted or is that a separate issue?

I performed fault tolerance testing on a real device for NOR memory. LevelX does not meet the requirements. The developers do not respond to requests for information about the problem.

hi @SimonTechv
LevelX doesn't manage fault tolerance it is FileX who does.

commented

I performed fault tolerance testing on a real device for NOR memory. LevelX does not meet the requirements. The developers do not respond to requests for information about the problem.

hi @SimonTechv
LevelX doesn't manage fault tolerance it is FileX who does.

How should I deal with flash memory translation level errors?