static int32_t mflash_drv_sector_update()

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;
}