in lib/nxp/mflash/lpc54xxx/mflash_drv.c [230:345]
static int32_t mflash_drv_sector_update(uint32_t sector_addr, uint32_t sect_off, const uint8_t *data, uint32_t data_len)
{
#if FLASHDRV_SMART_UPDATE
int sector_erase_req = 0;
uint32_t page_program_map = 0; /* Current implementation is limited to 32 pages per sector */
#endif
/* Address not aligned to sector boundary */
if (false == mflash_drv_is_sector_aligned((uint32_t)sector_addr))
return -1;
/* Offset + length exceeed sector size */
if (sect_off + data_len > MFLASH_SECTOR_SIZE)
return -1;
/* Switch back to read mode */
mflash_drv_read_mode();
/* Copy old sector data by 4B in each loop to buffer */
for (uint32_t i = 0; i < sizeof(g_flashm_sector) / sizeof(g_flashm_sector[0]); i++)
{
g_flashm_sector[i] = *((uint32_t *)(sector_addr) + i);
}
#if FLASHDRV_SMART_UPDATE /* Perform only the erase/program operations that are necessary */
/* Copy custom data (1B in each loop) to buffer at specific position */
for (uint32_t i = 0; i < data_len; i++)
{
/* Unless it was already decided to erase the whole sector, evaluate differences between current and new data */
if (0 == sector_erase_req)
{
uint8_t cur_value = ((uint8_t *)(g_flashm_sector))[sect_off + i];
uint8_t new_value = data[i];
/* Check the the bit transitions */
if ((cur_value | new_value) != cur_value)
{
sector_erase_req = 1; /* A bit needs to be flipped from 0 to 1, the sector has to be erased */
}
else if ((cur_value & new_value) != cur_value)
{
page_program_map |=
1 << ((sect_off + i) /
MFLASH_PAGE_SIZE); /* A bit needs to be flipped from 1 to 0, the page has to be programmed */
}
}
/* Copy data over to the buffer */
((uint8_t *)g_flashm_sector)[sect_off + i] = data[i];
}
/* Erase the sector if required */
if (0 != sector_erase_req)
{
if (0 != mflash_drv_sector_erase(sector_addr))
{
return -2;
}
/* Update page program map according to non-blank areas in the buffer */
for (int page_idx = 0; page_idx < MFLASH_SECTOR_SIZE / MFLASH_PAGE_SIZE; page_idx++)
{
int page_word_start = page_idx * (MFLASH_PAGE_SIZE / sizeof(g_flashm_sector[0]));
int page_word_end = page_word_start + (MFLASH_PAGE_SIZE / sizeof(g_flashm_sector[0]));
for (int i = page_word_start; i < page_word_end; i++)
{
if (g_flashm_sector[i] != 0xFFFFFFFF)
{
/* Mark the page for programming and go for next one */
page_program_map |= (1 << page_idx);
break;
}
}
}
}
/* Program the pages */
for (int page_idx = 0; page_idx < MFLASH_SECTOR_SIZE / MFLASH_PAGE_SIZE; page_idx++)
{
/* Skip programming of blank pages */
if (0 == (page_program_map & (1 << page_idx)))
{
continue; /* The page needs not be programmed, skip it */
}
mflash_drv_page_program(sector_addr + page_idx * MFLASH_PAGE_SIZE,
g_flashm_sector + page_idx * (MFLASH_PAGE_SIZE / sizeof(g_flashm_sector[0])));
}
#else /* Erase the sector and all the pages unconditionally */
/* Copy custom data (1B in each loop) to buffer at specific position */
for (uint32_t i = 0; i < data_len; i++)
{
((uint8_t *)g_flashm_sector)[sect_off + i] = data[i];
}
/* Erase the sector */
if (0 != mflash_drv_sector_erase(sector_addr))
{
return -2;
}
/* Program whole sector */
if (0 != mflash_drv_sector_program(sector_addr, g_flashm_sector))
{
return -2;
}
#endif /* FLASHDRV_SMART_UPDATE */
/* Switch back to read mode */
mflash_drv_read_mode();
return 0;
}