Giter Club home page Giter Club logo

levelx's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

levelx's Issues

LevelX initialization time problem

I ported levelX to work with the STM32F412ZGT6 discovery board with MICRON N25Q128 SPI flash memory. The volume used is 4096 sectors (physical) of 4 kilobytes each.

Before starting to work with wear-leveled flash memory, I call the function:

_lx_nor_flash_open(&nor_mem_desc, "VOL0:", flash_driver_init);

Its execution takes about 1 second. In the image below, I provide the necessary information:

image

I looked through the code and found that during the initialization process levelX reads all blocks of flash memory.

Is it possible to reduce the startup time without reducing the memory size?
I plan to use 1 Gbit NOR memory, but in this case the initialization time will increase several times more.

For more information, I have uploaded the project code

Question on error

Hi, if this is not the appropriate place to post this question please let me know, but I couldn't locate a support forum for LevelX.

We are using Azure ThreadX & FileX along with LevelX on a Winbond 1Gbit SLC NAND. File X version is 6.1 and Level X is 6.1.9.

We have noticed that during start-up, in the function _lx_nand_flash_open() , LX_SYSTEM_INVALID_FORMAT error(s) are being detected and logged. See attached screenshots showing the state of LX_NAND_FLASH data structure on error and soon after init.

It appears this error is not considered fatal by Level X as the process continues and eventually, the function returns LX_SUCCESS.

  1. Is this error something to be concerned about?
  2. What may be causing the error?

Thank you.

Capture1

Capture2

LevelX Nand "defrag" problem

Hi,

I am using LevelX (6.4.1) with NAND flash. In my test, I created a 64MB disk and repeatedly cycled through writing, reading, and deleting ten 200KB files. After several cycles, I can no longer write files because the free block list tail is 0, causing the lx_nand_flash_block_allocate function to error out.

What I don't understand is why the tail goes to 0. When I check the block status table, I find that some blocks are full (0xC040), but many blocks have only partial writes (0xA002). In this case, is it not possible to perform a defrag to optimize the utilization of the blocks? I tried reading the forum and I understand that with the new lx_nand_flash_sector_release I don't need to defrag the disk, but something is wrong.
Can you help me?

Thanks a lot
error_func
nand_flash_var
status_table

Weak ECC check

The function _lx_nand_flash_256byte_ecc_check cannot properly detect single-bit errors in the ECC bytes themselves.
Such single-bit errors result in a LX_NAND_ERROR_NOT_CORRECTED return result from the function.

Repro:

UCHAR buff[256];
memset(buff, 0xFF, 256);
UCHAR ecc[3];
lx_nand_flash_256byte_ecc_compute(buff, ecc); // this results in an ECC of {0xFF, 0xFF, 0xFF}
ecc[0] ^= 0x1;
UINT res = lx_nand_flash_256byte_ecc_check((UCHAR*)buff, (UCHAR*)ecc); // this returns LX_NAND_ERROR_NOT_CORRECTED

The same code, injecting an error in the data rather than the ECC:

UCHAR buff[256];
memset(buff, 0xFF, 256);
UCHAR ecc[3];
lx_nand_flash_256byte_ecc_compute(buff, ecc); // this results in an ECC of {0xFF, 0xFF, 0xFF}
buff[0] ^= 0x1; // <<-- CHANGED HERE
UINT res = lx_nand_flash_256byte_ecc_check((UCHAR*)buff, (UCHAR*)ecc); // this works correctly, and returns LX_NAND_ERROR_CORRECTED

I don't know the details of the ECC algorithm used here (whether the ECC is actually strong enough to reliably correct all 1-bit errors in the data or ECC itself, and to reliably detect all 2-bit errors), but maybe a simple fix would be the following?
Here:

/* Determine if there are any errors. */
if (error_count == 0)
{
/* Everything is okay, return success. */
return(LX_SUCCESS);
}
/* Was a correctable error discovered? */
else if (error_count == 11)

add a check:

/* Was a correctable error discovered in the ECC itself?  */
else if (error_count == 1) {
	/* Error in the ECC: nothing to actually correct in the data */
	return(LX_NAND_ERROR_CORRECTED);
}

Possible array out of bound in lx_nor_flash_extended_cache array

The function _lx_nor_flash_driver_read has a section that iterates over the lx_nor_flash_extended_cache array

https://github.com/azure-rtos/levelx/blob/61f92c00c74ebe8c5798652b756115cc8995b894/common/src/lx_nor_flash_driver_read.c#L107-L155

this Array is of size LX_NOR_EXTENDED_CACHE_SIZE which is set to 8, but the for loop iterates till lx_nor_flash_extended_cache_entries

the lx_nor_flash_extended_cache_entries value is set in the _lx_nor_flash_extended_cache_enable function, and is basically the number of sector sized chunks from the given ram Cache

https://github.com/azure-rtos/levelx/blob/61f92c00c74ebe8c5798652b756115cc8995b894/common/src/lx_nor_flash_extended_cache_enable.c#L117-L139

If the user gives a cache in the size of more than LX_NOR_EXTENDED_CACHE_SIZE sectors this may lead to exceeding the size of the lx_nor_flash_extended_cache array.

Maybe some sort of input validation should be added to make sure the given ram memory isn't too big?

_lx_nor_flash_logical_sector_find costs a lot of time, making LevelX writes quite slow

I'm using Filex with LevelX nor flash driver. I found that when writing a lot of data, _lx_nor_flash_logical_sector_find costs a lot of time(about 50ms each write), making LevelX write quite slow (about 5kb/s).

I checked the source code of LevelX, this while block costs the most of the time. Is there anyway to improve the write speed of LevelX?

while (total_blocks--) 
    {

        /* Setup the block word pointer to the first word of the search block.  */
        block_word_ptr =  (nor_flash -> lx_nor_flash_base_address + (i * nor_flash -> lx_nor_flash_words_per_block));

        /* Determine if the minimum and maximum logical sector values are present in the block header.  If these are 
           present, we can quickly skip blocks that don't have our sector.  */

        /* Read the minimum and maximum logical sector values in this block.  */
#ifdef LX_DIRECT_READ
        
        /* Read the word directly.  */
        min_logical_sector =  *(block_word_ptr + LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET);
#else
        status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr + LX_NOR_FLASH_MIN_LOGICAL_SECTOR_OFFSET, &min_logical_sector, 1);

        /* Check for an error from flash driver. Drivers should never return an error..  */
        if (status)
        {
        
            /* Call system error handler.  */
            _lx_nor_flash_system_error(nor_flash, status);

            /* Return the error.  */
            return(status);
        }
#endif
#ifdef LX_DIRECT_READ
        
        /* Read the word directly.  */
        max_logical_sector =  *(block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET);
#else
        status =  _lx_nor_flash_driver_read(nor_flash, block_word_ptr + LX_NOR_FLASH_MAX_LOGICAL_SECTOR_OFFSET, &max_logical_sector, 1);

        /* Check for an error from flash driver. Drivers should never return an error..  */
        if (status)
        {
        
            /* Call system error handler.  */
            _lx_nor_flash_system_error(nor_flash, status);

            /* Return the error.  */
            return(status);
        }
#endif

        /* Are the values valid?  */
        if ((min_logical_sector != LX_ALL_ONES) && (max_logical_sector != LX_ALL_ONES))
        {

            /* Now let's check to see if the search sector is within this range.  */
            if ((logical_sector < min_logical_sector) || (logical_sector > max_logical_sector))
            {

                /* Move to the next block.  */
                i++;
      
                /* Determine if we have wrapped.  */
                if (i >= nor_flash -> lx_nor_flash_total_blocks)
                {
        
                    /* Yes, we have wrapped, set to block 0.  */
                    i =  0;
                }

                /* Start at the first sector in the next block.  */
                j =  0;
              
                /* No point in looking further into this block, just continue the loop.  */
                continue;            
            }
        }
       
        /* Setup the total number of sectors.  */
        total_sectors =  nor_flash -> lx_nor_flash_physical_sectors_per_block;
        
        /* Remember the start of the search.  */
        search_start =  j;
        
        /* Now search through the sector list to find a match.  */
        while (total_sectors--)
        {

            /* Setup a pointer to the mapped list.  */
            list_word_ptr =  block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_mapping_offset + j;

            
            /* Read in the mapped list for this block.  */
#ifdef LX_DIRECT_READ
        
            /* Read the word directly.  */
            list_word =  *(list_word_ptr);
#else
            status =  _lx_nor_flash_driver_read(nor_flash, list_word_ptr, &list_word, 1);

            /* Check for an error from flash driver. Drivers should never return an error..  */
            if (status)
            {
        
                /* Call system error handler.  */
                _lx_nor_flash_system_error(nor_flash, status);

                /* Return the error.  */
                LOGE("sector find costs: %d", tx_time_get() - s);
                return(status);
            }
#endif
            
            /* Determine if the entry hasn't been used.  */
            if (list_word == LX_NOR_PHYSICAL_SECTOR_FREE)
            {
                
                /* Since the mapping is done sequentially in the block, we know nothing
                   else exists after this point.  */
              
                /* Determine if the search started at the beginning of the block.  */
                if (search_start == 0)
                {
                 
                    /* Yes, we started at the beginning of the block.  We are now done with this block. */
                    break;
                }
                else
                {
              
                    /* Setup the new total to the search start.  */
                    total_sectors =  search_start;
                    
                    /* Clear search start.  */
                    search_start =  0;
                    
                    /* Start search over.  */
                    j =  0;
                    continue;
                }
            }
            
            /* Is this entry valid?  */
            if ((list_word & (LX_NOR_PHYSICAL_SECTOR_VALID | LX_NOR_PHYSICAL_SECTOR_MAPPING_NOT_VALID)) == LX_NOR_PHYSICAL_SECTOR_VALID)
            {
                
                /* Decrement the number of mapped sectors.  */
                mapped_sectors--;    

                /* Do we have a valid sector match?  */
                if ((list_word & LX_NOR_LOGICAL_SECTOR_MASK) == logical_sector)
                {

                    /* Determine if we care about the superceded bit.  */
                    if (superceded_check == LX_FALSE)
                    {
                                    
                        /* Prepare the return information.  */
                        *physical_sector_map_entry =  list_word_ptr;
                        *physical_sector_address =    block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_offset + (j * LX_NOR_SECTOR_SIZE);

                        /* Determine if the sector mapping cache is enabled.  */
                        if (nor_flash -> lx_nor_flash_sector_mapping_cache_enabled)
                        {

                            /* Yes, update the cache with the sector mapping.  */
                            
                            /* Move all the cache entries down so the oldest is at the bottom.  */
                            *(sector_mapping_cache_entry_ptr + 3) =  *(sector_mapping_cache_entry_ptr + 2);
                            *(sector_mapping_cache_entry_ptr + 2) =  *(sector_mapping_cache_entry_ptr + 1);
                            *(sector_mapping_cache_entry_ptr + 1) =  *(sector_mapping_cache_entry_ptr);

                            /* Setup the new sector information in the cache.  */
                            sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_logical_sector =             (logical_sector | LX_NOR_SECTOR_MAPPING_CACHE_ENTRY_VALID);
                            sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_map_entry =  *physical_sector_map_entry;
                            sector_mapping_cache_entry_ptr -> lx_nor_sector_mapping_cache_physical_sector_address =    *physical_sector_address;
                        }

                        /* Remember the last found block for next search.  */
                        nor_flash -> lx_nor_flash_found_block_search =  i;
                        
                        /* Remember the last found sector.  */
                        nor_flash -> lx_nor_flash_found_sector_search =  j+1;
                        
                        /* Has this wrapped around?  */
                        if (nor_flash -> lx_nor_flash_found_sector_search >= nor_flash -> lx_nor_flash_physical_sectors_per_block)
                        {
                        
                            /* Reset to the beginning sector.  */
                            nor_flash -> lx_nor_flash_found_sector_search =  0;
                        }

                        /* Return success!  */
                        LOGI("sector find costs: %d", tx_time_get() - s);
                        return(LX_SUCCESS);                     
                    }

                    /* Check for the superceded bit being clear, which means the sector was superceded.  */
                    else if (list_word & LX_NOR_PHYSICAL_SECTOR_SUPERCEDED)
                    {
                        
                        /* Prepare the return information.  */
                        *physical_sector_map_entry =  list_word_ptr;
                        *physical_sector_address =    block_word_ptr + nor_flash -> lx_nor_flash_block_physical_sector_offset + (j * LX_NOR_SECTOR_SIZE);

                        /* No need to update the cache here, since this condition only happens during initialization.  */

                        /* Remember the last found block for next search.  */
                        nor_flash -> lx_nor_flash_found_block_search =  i;

                        /* Remember the last found sector.  */
                        nor_flash -> lx_nor_flash_found_sector_search =  j+1;
                        
                        /* Has this wrapped around?  */
                        if (nor_flash -> lx_nor_flash_found_sector_search >= nor_flash -> lx_nor_flash_physical_sectors_per_block)
                        {
                        
                            /* Reset to the beginning sector.  */
                            nor_flash -> lx_nor_flash_found_sector_search =  0;
                        }

                        /* Return success!  */
                        LOGI("sector find costs: %d", tx_time_get() - s);
                        return(LX_SUCCESS);                     
                    }
                }
            }

            /* Move to the next list entry.  */
            j++;
            
            /* Check for wrap around.  */
            if (j >= nor_flash -> lx_nor_flash_physical_sectors_per_block)
            {
            
                /* Yes, wrap around, go back to the beginning.  */
                j =  0;
            }
        }

        /* Determine if there are any more mapped sectors.  */
        if (mapped_sectors == 0)
            break;
            
        /* Move to the next block.  */
        i++;
       
        /* Determine if we have wrapped.  */
        if (i >= nor_flash -> lx_nor_flash_total_blocks)
        {
        
            /* Yes, we have wrapped, set to block 0.  */
            i =  0;
        }

        /* Start at the first sector in the next block.  */
        j =  0;
    }

Questions about the use of ECC

Hello, I found some questions about the use of ECC:
In the block, it should be ensured that each page is written only once, and then the ECC data of the page can be written into the OOB. However, since the erasing times of the block are stored in the 0th page, it will result in the 0th page Data will be written multiple times, resulting in unequal ECC data each time, which will cause ECC error correction errors.
On line 286 and line 296 in lx_nand_flash_open.c

Problems using LevelX with FileX + USBX

I've had lots of problems trying to get LevelX to play nicely with a FileX filesystem that a host device can access using USB MSD.

In my case, I have about 8 megabytes of flash storage that I need to wear level using LevelX, so I do. I use a FileX exfat filesystem on top of this.

However, I need this storage to be accessible to a PC so I use USBX to allow a host machine to mount the FileX filesystem via USB MSD.

But-- From what I can tell after extensive research and debugging, LevelX starts to perform terribly if it is not notified about released sectors as the amount of (incorrectly) mapped sectors will continuously grow over time if files are deleted via USB and not via the filesystem (which would notify levelx of sectors to release).

From what I understand, there isn't any clean way for LevelX to be notified when USB "deletes" files, as USB MSD just writes and reads to logical sectors and the device itself isn't notified of higher level filesystem interaction.

Right now, I'm able to somewhat mitigate this issue through manual parsing of the EXFAT allocation bitmap on device startup. For every sector/cluster that is marked as unallocated, I tell LevelX about this in an attempt to turn any incorrectly mapped sectors into obsolete sectors that can be freed. Once this operation is complete, I defragment a bit to turn obsolete sectors into free sectors for use (just to increase performance during writes later).

Is there any guidance or anything better I can do here? Or any parameters that can be tuned to make LevelX perform better when the mapped sector count nears the total sector count (not because of many files, but due to USB deleting files and LevelX doesn't get notified about these sectors being released).

I'll note that USB has exclusive filesystem access when it has it. So there isn't an issue of USB and my device trying to access the filesystem at the same time. When USB needs to access the device's filesystem, we close the filesystem and reopen it after its done.

ECC calibration problem

Hello! In the process of using it, I found that page 0 will be written many times in “lx_nand_flash_open.c ". On lines 286 and 296, I can only block the ECC verification on page 0 before I can use it normally.

Assert is happen in lx_nand_flash_open() API

Dear LevelX,

I have tested demo with SPINAND as your nand flash demo. 
Some  Assert problem is happened very time.

![image](https://user-images.githubusercontent.com/11240975/90312179-eadf0800-df34-11ea-83cc-5d111b3a1965.png)

  1. lx_nand_flash_open is called by fx_media_format firstly.
  2. lx_nand_flash_open is called by fx_media_open again.

As you seen, The follow is in problem.
` LX_PARAMETER_NOT_USED(name);

/* Clear the NAND flash control block.  */

TX_MEMSET(nand_flash, 0, sizeof(LX_NAND_FLASH));



/* Call the flash driver's initialization function.  */

(nand_driver_initialize)(nand_flash);`

` if (_lx_nand_flash_opened_count)

{



    /* List is not empty - other NAND flashes are open.  */



    /* Pickup tail pointer.  */

    tail_ptr =  _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous;



    /* Place the new NAND flash control block in the list.  */

    _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous =  nand_flash;

    tail_ptr -> lx_nand_flash_open_next =                       nand_flash;



    /* Setup this NAND flash's opened links.  */

    nand_flash -> lx_nand_flash_open_previous =  tail_ptr;

    nand_flash -> lx_nand_flash_open_next =      _lx_nand_flash_opened_ptr;   

}`

Because of memst of nand flash, some assert is happened.

Best Regards
Joshu Wang

Error in _lx_nor_flash_driver_read and potentially elsewhere with zero starting flash address and extended cache.

When the extended cache is enabled AND the base address of the flash device given to levelx is zero, _lx_nor_flash_driver_read will never return.

The nor flash's base address is set, at least in my case, in my driver as follows. This is very convenient as for writing as I need to provide a flash address which is not offset by any amount. For reading from the device, I offset as necessary.

nor_flash->lx_nor_flash_base_address = 0;

When _lx_nor_flash_driver_read checks if there is a cache entry for an address, there is a check to see if cache_entry_start is non zero. This causes the caching of the first sector to fail and when _lx_nor_flash_driver_read tries to read the first sector, it will never return as it can never see the cache entry which exists.

Specifically at the very least, this line:

if ((cache_entry_start) && (flash_address >= cache_entry_start) && (flash_address < cache_entry_end))

Should not simply check if cache_entry_start is non-zero. However, I don't think the solution is just to remove that check, but I'm not sure.

Given this error, I'm concerned there are other errors in the code regarding a flash address base of zero. I'm assuming this is just a mistake, as if it was not, the init function should check for the zeroed flash address.

LX_SYSTEM_INVALID_BLOCK

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?

[NAND] Handling of bad blocks and ECC errors

I can't figure out if and how LevelX handles these two error conditions:
A) blocks that go bad (not factory-marked as bad)
B) correctable ECC errors

For bad blocks: when a block must be erased, the driver function LX_NAND_FLASH.lx_nand_flash_driver_block_erase is called.
This function will trigger an erase in the NAND chip, which can fail if the block has gone bad. In this scenario, the block wasn't bad at first, so it is not yet marked as bad, and LevelX still thinks it is good.
The function can return an error; it seems that all the LevelX functions that call it, check its result. These functions are:
lx_nand_flash_block_data_move
lx_nand_flash_driver_block_erase
lx_nand_flash_driver_block_erased_verify
lx_nand_flash_format
lx_nand_flash_metadata_allocate
lx_nand_flash_sector_release
lx_nand_flash_sector_write
Upon error, they all call _lx_nand_flash_system_error, which in turn calls the driver function LX_NAND_FLASH.lx_nand_flash_driver_system_error
However, after this, as the error is reported up the call stack, it seems that one of two things happen:

  1. the whole operation fails because of the error
  2. the error is ignored (eg. when _lx_nand_flash_metadata_write calls _lx_nand_flash_metadata_allocate, here)
    When the error is ignored, it also seems that this causes corruption of the LevelX internal data: the operation itself is reported as successful, but then LevelX starts misbehaving (eg. in future operations, it asks the driver to access non-existing block 0xFFFF).

I tried calling _lx_nand_flash_block_status_set from within the driver function lx_nand_flash_driver_system_error, to let LevelX know that the block is bad, but it didn't work; the call seemed to succeed, but LevelX misbehaved anyway.
Also, I don't think I can just mark the block as bad in hardware, as in this case LevelX wouldn't know it.

How can I handle these blocks that go bad? Should I call some LevelX utility, inside the system error function or elsewhere?
Should I just ignore it (just report the error), and LevelX will automatically take care of it during the next operation?

For correctable ECC errors: when a page is read, and there is an ECC error, and this error is corrected, the data can be used normally. This works. However, to prevent the data from accumulating errors, thus making them uncorrectable (or even undetectable) in the future, the corrupted page should be moved to another page, so that the data and ECC code is rewritten, thus restoring it to a 0-errors condition.
LevelX doesn't seem to do that.
The page will eventually be moved elsewhere, thus removing the error, as a consequence of other operations. However, this can be arbitrarily far in the future, especially if the data is mostly read, and rarely written, so there is no guarantee about when the error will disappear, and in the meantime the error might get worse. So, we cannot just let the error be, and wait.
In case of a corrected ECC error, I return the error LX_NAND_ERROR_CORRECTED from these driver functions:
LX_NAND_FLASH.lx_nand_flash_driver_pages_read
LX_NAND_FLASH.lx_nand_flash_driver_pages_copy
The error is then handled by these LevelX functions:
lx_nand_flash_metadata_allocate
lx_nand_flash_open
lx_nand_flash_sector_read
lx_nand_flash_sector_release
lx_nand_flash_sector_write
It is handled by calling lx_nand_flash_driver_system_error, and then continuing with the operation, without a failure.
This is ok, but it seems that LevelX never tries to move the page elsewhere to remove the error.

How can I handle this "repair" of the errored page? Should I call some LevelX utility, inside the system error function or elsewhere?
Should I just ignore it (just report the error)?

levelX doesnot work-well

Dear levelx,

I have done much work with levelx In my platform.

cpu : Cortex R5
Flahs: Winbond SPINAND.

But it is donot work-well.
As Power On, The spare area with nand is all 0xFFFFFFFF, So all important fucntion is not called , And the result is failed.

` /* Determine if the page is free. */

                if (extra_info.lx_nand_page_extra_info_logical_sector == LX_NAND_PAGE_FREE)

                {

                

                    /* The page is free and we know that the pages are allocated sequentially

                       so there is no need to go further.  */

                

                    /* Increment the free pages counter.  */

                    free_pages =  free_pages + (nand_flash -> lx_nand_flash_pages_per_block - page);

                    

                    /* Verify that the same position in the mapped list from page 0 is also free.  */

                    if (page_word_ptr[page] != LX_NAND_PAGE_FREE)

                    {

                        

                        /* Increment the invalid mapping counter.  */

                        nand_flash -> lx_nand_flash_diagnostic_mapping_invalid++;

                        

                        /* Call system error handler.  */

                        _lx_nand_flash_system_error(nand_flash, LX_SYSTEM_INVALID_FORMAT, block, page);

                    }

                    

                    /* Determine if the associated page is really free... it could be the case that the 

                       page data area was in the process of being written or just completed when a power

                       interruption occurs before the extra bytes are setup with the logical sector.  */



                    /* Read verify the page is erased.  */

                    status =  _lx_nand_flash_driver_page_erased_verify(nand_flash, block, page);



                    /* Check for an error from flash driver.   */

                    if (status == LX_ERROR)

                    {



                        /* Increment the page data not free diagnostic counter.  */

                        nand_flash -> lx_nand_flash_diagnostic_page_data_not_free++;

                        

                        /* Decrement the free page counter and increment the obsolete page counter.  */

                        free_pages--;

                        obsolete_pages++;

                        

                        /* Now setup the extra info to show this page is obsolete.  */

                        extra_info.lx_nand_page_extra_info_logical_sector =  0;

                        status =  _lx_nand_flash_driver_extra_bytes_set(nand_flash, block, page, (UCHAR *) &extra_info, sizeof(extra_info));



                        /* Check for an error from flash driver.   */

                        if (status)

                        {

    

                            /* Call system error handler.  */

                            _lx_nand_flash_system_error(nand_flash, status, block, page);



                            /* Return an error.  */

                            return(LX_ERROR);

                        }

                    }

                       

                    /* At this point we can break out of the page traversal loop, since nothing else can exist after this page.  */

                    break;

                }`

Some question is listed here.

  1. How to initlized the spare zone of per page of nand.
    If it is all 0XFFFFFFFF, it is in probem.

Thanks.
Best Regards

Joshua Wang

When should lv_nand_flash_format be called?

Hi,
I'm not sure whether it's a duplicate question. I find sample code demo_filex_nand_flash.c cannot work as ram disk is not formated before.

The sample code erases the ram disk in the beginning. But it's not formated by function lv_nand_flash_format. So lx_nand_flash_open would fail as no valid signature is found.

_lx_nand_flash_simulator_erase_all();

Is it needed to call lv_nand_flash_format in the sample code?

A block (128K Byte) of 1.5M data written to the levelx of the main line and the nand partition of 4M will be erased.

A block (128K Byte) of 1.5M data written to the levelx of the main line and the nand partition of 4M will be erased.
Trace the UINT _lx_nand_flash_metadata_allocate (LX_NAND_FLASH * nand_flash) call
_lx_nand_flash_driver_block_erase (nand_flash, block, nand_flash ->lx_nand_flash_base_erase_count+nand_flash ->lx_nand_flash_erase_count_table [block]) has been erased
, I locally implemented erase_count to erase multiple blocks, but the simulator only erased one block,
UINT _lx_nand_flash_simulator_block_erase (ULONG block, ULONG erase_count)
LX_PARAMETER_NOT_USED (erase_count);
According to the context, only one block is added to the list below, and it should be correct to erase only one block. I want to know the correct usage of erase_count.

lx_nor_flash_free_physical_sectors == 0, reclaim not possible although there is space on the device

Dear List,
i got an issue with LevelX 6.1.7 ( ) used in conjunction with FileX + ThreadX on an STM32H563 connected to a serial Flash via a custom driver.

Describe the bug

I somehow managed it to come into a situation where lx_nor_flash_free_physical_sectors == 0, which means that a write may end in an (nearly endless) loop, because the block may not be reclaimed ( which is tried until lx_nor_flash_total_block only but will continue again on next write-try ). The Flash-Structure still shows 276 obsolete sectors ( see nor_flash struct on the bottom of this page )

I'm just wondering if this can happen because of some erroneous condition from outside of levelX which is not catched gracefully or if i caught a bug in levelX code here.

I found out that the while loop checking if a reclaim is to be made is only existing in "lx_nor_flash_sector_write.c" @ line 114, which in my opinion would mean that it's possible to reach a lx_nor_flash_free_physical_sectors of 0 by reading sectors that are not mapped ( read routine also allocates sectors in lx_nor_flash_sector_read.c @ line 140 ) .

If this happened sometime before the reclaim routine may walk through all the blocks trying to reclaim but will fail each time because there are no physical blocks to copy the content to. This may also be checked in advance to not block the system all the time.

I also had a short look at the current development code if some of the issues may be fixed now, but i did not find fixes here up to now ( maybe I've overlooked something )

To Reproduce
Hard to reproduce.
This may only being reproduced on a rather small serial flash where writes and reads are done randomly over a longer time reaching the end of the flash, having no physical sectors free any more. I'll continue try reproducing in the next days and update the issue when there are more clear steps to do so.

Expected behavior
I excpect that the levelX does not run into the situation when there are no free sectors any more before a reclaim takes place. ( except filesystem is really full and fx routines will therefore fail directly ) May this be fixed by introducing another reclaim-while-loop to the read routine, or are there sill other pitfalls?

I also expect that the reclaim will fail when there are not enough free sectors outside of the block to reclaim (checked in lx_nor-flash_block_reclaim.c @ line 238) which then should break the reclaim loop in the write routine to not block the whole system.

** Impact **
Showstopper -> Filesystem unuseable

** Logs and Console Output **

On a sector write we try to reclame same erase_block all the time:

_lx_nor_flash_sector_write: free phys: 0 sect/block: 7
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
_lx_nor_flash_block_reclaim: erase_block: 483, erase_count: 8, mapped_sectors: 1, obsolete_sectors: 6
... // this runns nearly endless

** Additional Context **
The Filesystem still shows 968 kB of free space on a 4M serial-flash.

Contents of LEVELX nor-flash struct:

lx_nor_flash_state ULONG 1313821263
lx_nor_flash_total_blocks ULONG 1024
lx_nor_flash_words_per_block ULONG 1024
lx_nor_flash_total_physical_sectors ULONG 7168
lx_nor_flash_physical_sectors_per_block ULONG 7
lx_nor_flash_base_address ULONG * 0x0
lx_nor_flash_block_free_bit_map_offset ULONG 3
lx_nor_flash_block_bit_map_words ULONG 1
lx_nor_flash_block_bit_map_mask ULONG 127
lx_nor_flash_block_physical_sector_mapping_offset ULONG 4
lx_nor_flash_block_physical_sector_offset ULONG 128
lx_nor_flash_free_physical_sectors ULONG 0
lx_nor_flash_mapped_physical_sectors ULONG 6892
lx_nor_flash_obsolete_physical_sectors ULONG 276
lx_nor_flash_minimum_erase_count ULONG 3
lx_nor_flash_maximum_erase_count ULONG 9
lx_nor_flash_free_block_search ULONG 0
lx_nor_flash_found_block_search ULONG 997
lx_nor_flash_found_sector_search ULONG 0
lx_nor_flash_write_requests ULONG 0
lx_nor_flash_read_requests ULONG 42
lx_nor_flash_sector_mapping_cache_hits ULONG 22
lx_nor_flash_sector_mapping_cache_misses ULONG 20
lx_nor_flash_physical_block_allocates ULONG 0
lx_nor_flash_physical_block_allocate_errors ULONG 0
lx_nor_flash_diagnostic_system_errors ULONG 0
lx_nor_flash_diagnostic_system_error ULONG 0
lx_nor_flash_diagnostic_initial_format ULONG 0
lx_nor_flash_diagnostic_erased_block ULONG 0
lx_nor_flash_diagnostic_re_erase_block ULONG 0
lx_nor_flash_diagnostic_sector_being_obsoleted ULONG 0
lx_nor_flash_diagnostic_sector_obsoleted ULONG 0
lx_nor_flash_diagnostic_mapping_invalidated ULONG 0
lx_nor_flash_diagnostic_mapping_write_interrupted ULONG 0
lx_nor_flash_diagnostic_sector_not_free ULONG 0
lx_nor_flash_diagnostic_sector_data_not_free ULONG 0
lx_nor_flash_driver_read UINT (*)(ULONG , ULONG , ULONG) 0x803208d <FxSerialFlash_Read>
lx_nor_flash_driver_write UINT (
)(ULONG , ULONG , ULONG) 0x80320f9 <FxSerialFlash_Write>
lx_nor_flash_driver_block_erase UINT (
)(ULONG, ULONG) 0x80321dd <FxSerialFlash_BlockErase>
lx_nor_flash_driver_block_erased_verify UINT (
)(ULONG) 0x8032165 <FxSerialFlash_BlockEraseVerify>
lx_nor_flash_driver_system_error UINT (
)(UINT) 0x0
lx_nor_flash_sector_buffer ULONG * 0x20042c14 <g_fx_serial_flash+9412>
lx_nor_flash_sector_mapping_cache_enabled UINT 1
lx_nor_flash_sector_mapping_cache LX_NOR_SECTOR_MAPPING_CACHE_ENTRY [16] 0x200000e0 <fx_lx_nor_drivers+172>
lx_nor_flash_extended_cache_entries UINT 0
lx_nor_flash_extended_cache LX_NOR_FLASH_EXTENDED_CACHE_ENTRY [8] 0x200001a4 <fx_lx_nor_drivers+368>
lx_nor_flash_extended_cache_hits ULONG 0
lx_nor_flash_extended_cache_misses ULONG 0
lx_nor_flash_mutex TX_MUTEX {...}
lx_nor_flash_open_next struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>
lx_nor_flash_open_previous struct LX_NOR_FLASH_STRUCT * 0x20000034 <fx_lx_nor_drivers>

LevelX, ThreadX, FileX coming from STM32Cube_FW_H5_V1.2.0

LX_NOR_SECTOR_SIZE (512/sizeof(ULONG))

FX is initialzed as follows:
#define SF_SECTOR_SIZE (LX_NOR_SECTOR_SIZE * sizeof(ULONG))
#define SF_NUM_FATS (1)
#define SF_DIR_ENTRIES (32)
#define SF_HIDDEN_SECTORS (0)
#define SF_SECTORS_PER_CLUSTER (8)
#define SF_HEADS (1)
#define SF_SECTORS_PER_TRACK (1)

status = fx_media_format(&fsf->media, // nor_simulator_flash_disk pointer
fx_stm32_levelx_nor_driver, // Driver entry
(void*)NOR_CUSTOM_DRIVER_ID, // Device info pointer
(UCHAR *) fsf->media_mem, // Media buffer pointer
SF_SECTOR_SIZE, // Media buffer size
SF_VOLUME_NAME, // Volume Name
SF_NUM_FATS, // Number of FATs
SF_DIR_ENTRIES, // Directory Entries
SF_HIDDEN_SECTORS, // Hidden sectors
(flash_size / SF_SECTOR_SIZE), // Total sectors
SF_SECTOR_SIZE, // Sector size
SF_SECTORS_PER_CLUSTER, // Sectors per cluster
SF_HEADS, // Heads
SF_SECTORS_PER_TRACK);

NULL pointer dereference in _lx_nand_flash_open

If you call _lx_nand_flash_open twice in a row (without calling _lx_nand_flash_close in between), there is a NULL pointer dereference on line 508:

    /* Place the NAND flash control block on the list of opened NAND flashes.  First,
       check for an empty list.  */
    if (_lx_nand_flash_opened_count)
    {

        /* List is not empty - other NAND flashes are open.  */

        /* Pickup tail pointer.  */
        tail_ptr =  _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous;

        /* Place the new NAND flash control block in the list.  */
        _lx_nand_flash_opened_ptr -> lx_nand_flash_open_previous =  nand_flash;
        tail_ptr -> lx_nand_flash_open_next =                       nand_flash; <---- NULL pointer dereference here

        /* Setup this NAND flash's opened links.  */
        nand_flash -> lx_nand_flash_open_previous =  tail_ptr;
        nand_flash -> lx_nand_flash_open_next =      _lx_nand_flash_opened_ptr;   
    }

This is because the LX_NAND_FLASH control block is zeroed out at the top of the function.

levelx rewrite a nand physical page twice!!!

when i tested the sample nand simulator,i got an error:
_lx_nand_flash_simulator_system_error block:0 page:0 error_code:5

when format media,_lx_nand_flash_open is called,it writes the initial erase count 1 into block n,page 0.
when the block is full, it rewrites the page 0, the error occurs. Also, i found that levelx rewrites the nand spare several times.
As i know, one nand page is writted, we should erase the block before write the same page again.

Return status not checked in function _lx_nor_flash_block_reclaim

In function UINT _lx_nor_flash_block_reclaim(LX_NOR_FLASH *nor_flash)

A call is made to _lx_nor_flash_next_block_to_erase_find where the return status is not checked,
this result in that erase_block, erase_count, mapped_sectors, obsolete_sectors variables are unassigned,
and later used.

I would suggest a status handling like the one done in the same function when _lx_nor_flash_driver_write is called.

in lx_nand_flash_data_page_copy.c judge NOT SEQUENTIAL

levelx 6.2.1
in file lx_nand_flash_data_page_copy.c

/* Check if the pages in destination block is still sequential. /
if ((destination_page) != (logical_sector + i % nand_flash -> lx_nand_flash_pages_per_block))
{
/
Mark the block status as non sequential. */
dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
}

should be
/* Check if the pages in destination block is still sequential. /
if ( destination_page != ((logical_sector + i )% nand_flash -> lx_nand_flash_pages_per_block))
{
/
Mark the block status as non sequential. */
dest_block_status |= LX_NAND_BLOCK_STATUS_NON_SEQUENTIAL;
}

The problem of levelX's block recovery of nand flash

UINT _lx_nand_flash_block_reclaim(LX_NAND_FLASH *nand_flash)
{
...
if (obsolete_pages == nand_flash->lx_nand_flash_pages_per_block)
...
}

obsolete_pages cannot exceed (nand_flash->lx_nand_flash_pages_per_block-1), Because the first page is used as the mapping list.

Address alignment issue while writing to internal falsh of stm32u5

HI

I am using the STM32U575 for my project with the internal nor flash provided.
Noticing that the address are word(32bits) aligned while writing to the flash, but for STM32U5 internal flash the address needs to be quadword(128bits) aligned. Is there a configuration in levelx (like a line size) with which levelx will provide me quadword aligned addresses, or I need to take care of this specifically in the flash write driver routine(I think will affect the performance of write operation)?

Thanks

Substraction underflow in lx_nor_flash_open.c

Hi,
I am using Filex + LevelX (standalone). But every try I received LX_ERROR. When I investigated the occuring error, I came to that point in lx_nor_flash_open where
used_sectors = sectors_per_block - free_sectors;
is assigned. In my case free_sectors was of a greater value than sectors_per_block (128 > 126) and thereby the substraction lead to an underflow and the following code execution failed.
I am assuming that decrementing 1 when assingning the value to sectors_per_block causes the issue:
sectors_per_block = (nor_flash -> lx_nor_flash_words_per_block / LX_NOR_SECTOR_SIZE) - 1;

LevelX doesnot work-well

Dear Scott & Tiejun,

I am running LevelX & FileX with your demo API, demo_flilx_nand_flash.c.

Platform -> ARMR5 Comminication Processor
NAND -> SPI NAND winbond 1G.
Driver -> SPI NAND Driver is ported by myself.

The result looks like abnormal with LevelX.

image009

Here is detailed information with your demo.

  1. fx_media_format() is called firstly.
    

Because of no bad blocks, The routine is very simple.
Routine 1:
The Code Sample:
image010

The log info:
image011

Routine 2
The Code Sample:
image012

The log info:
image014

Routine3
The Code Sample:
image016

The Log info:
image018

  1. SECTOR_WRITE -> lx_nand_flash_sector_wite()
    

image026

Routine1:
image027

The Log Info:
image028

Routine2:
image029

The log info:
image030

As you seen, The Write Operation is failed. BUT I donot know the reason.

Pls give me some handle.
Thanks very much.

Best Regards
Joshua Wang

NOR simulator assumes sizeof(ULONG) == 4

Provided example assumes sizeof(ULONG) is 4B

    /* Setup pointer.  */
    pointer =  (ULONG *) &nor_memory_area[0];

    /* Loop to erase block.  */
    words =  sizeof(nor_memory_area)/(sizeof(ULONG));
    while (words--)
    {
        
        /* Erase word of block.  */
        *pointer++ =  (ULONG) 0xFFFFFFFF;
    }

when changed to

memset((uint8_t *) &nor_memory_area[0], 0xFF, sizeof(FLASH_BLOCK) * TOTAL_BLOCKS);

subsequent write/read test failes

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.