This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

pstorage raw, clearing small portions of flash

Hello,

In my quest of working with pstorage_raw.c I found an annoying situation when I tried to clear small portions (as I thought by using raw I would have full control). The pstorage_clear method directly calls sd_flash_page_erase(page); and by doing that, corrupts other data I had saved on the same page. My approach to that was to write my own pstorage_clear which would deal with single word up to page deletions, even if the cleared block spans to new pages. Here is my implementation of the cmd_process function:

static uint32_t cmd_process(void){

    uint32_t              retval;
    uint32_t              storage_addr;
    cmd_queue_element_t * p_cmd;

    retval = NRF_ERROR_FORBIDDEN;

    p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];

    storage_addr = p_cmd->storage_addr.block_id;
		
uint32_t  size = p_cmd->size;
uint32_t  offset = p_cmd->offset;
    switch (p_cmd->op_code) {


case PSTORAGE_STORE_OP_CODE: {
        uint8_t * p_data_addr = p_cmd->p_data_addr;
        offset        = (m_round_val * SOC_MAX_WRITE_SIZE);
        size          = p_cmd->size - offset;
        p_data_addr  += offset;
        storage_addr += (p_cmd->offset + offset);

        if (size < SOC_MAX_WRITE_SIZE){
            retval = sd_flash_write(((uint32_t *)storage_addr),
                                    (uint32_t *)p_data_addr,
                                    size / sizeof(uint32_t));
        }
        else {
            retval = sd_flash_write(((uint32_t *)storage_addr),
                                    (uint32_t *)p_data_addr,
                                    SOC_MAX_WRITE_SIZE / sizeof(uint32_t));
        }
    }
    break;

case PSTORAGE_CLEAR_OP_CODE: {

        uint32_t page_start, page_end, page;
        page_start =  (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
					page_end =  ((storage_addr + size) / PSTORAGE_FLASH_PAGE_SIZE);
								
for(page = page_start; page <= page_end; page++){
	// get page
	memcpy(page_swap, (uint32_t *)(page * PSTORAGE_FLASH_PAGE_SIZE), PSTORAGE_FLASH_PAGE_SIZE);

	// first page
	if(page == page_start){					
	    offset = (storage_addr - (page * PSTORAGE_FLASH_PAGE_SIZE)); // distance from page start
                if((size + offset) > PSTORAGE_FLASH_PAGE_SIZE){ // if it goes to another page, delete from this page to the end							
	        memset(page_swap + offset, 0xFF, PSTORAGE_FLASH_PAGE_SIZE - offset);
	    else // if not, delete from offset to size
	        memset(page_swap + offset, 0xFF, size);
	} else if(page == page_end){ // second page
		memset(page_swap, 0xFF, size - (PSTORAGE_FLASH_PAGE_SIZE - offset)); // delete the remaining size
	}
							
	retval = sd_flash_page_erase(page);	
	if (retval != NRF_SUCCESS)
		break;
						
	retval = sd_flash_write((uint32_t *) (page * PSTORAGE_FLASH_PAGE_SIZE), (uint32_t *) page_swap, PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
	if (retval != NRF_SUCCESS)
		break;
    }
    }
    break;

    default:
        // Should never reach here.
        break;
}

if (retval == NRF_SUCCESS)
{
   m_cmd_queue.flash_access = true;
}

return retval;

}

In this implementation, I use a 1KB RAM buffer serving as swap page, which is fine for my application.

The problem here is that I am getting NRF_ERROR_BUSY on the sd_flash_write call from the PSTORAGE_CLEAR_OP_CODE branch. The page is cleared, but the data from swap RAM buffer fails to be re-written on that page. And also, the queue is never empty anymore, so the command is not processed again.

By using the pstorage queue, wouldn't I supposed to have CPU time to do this operation as well? What am I missing here?

Sorry, but complex questions require long explanations.

Thanks in advance and best regards,

Victor

  • Nevermind.

    I transferred the clear logic to pstorage itself. Now I am en-queuing the pstorage_clear() on the page I want and then en-queuing pstorage_store() to restore that page untouched content without dealing directly with sd_* functions.

    The question is going to stay here for information purposes.

    Final pstorage_clear_block():

    uint32_t pstorage_clear_block(pstorage_handle_t storage_handle, uint16_t size){
    	static uint8_t page_swap[PAGE_SIZE];
    	uint32_t retval, page_start, page_end, page, offset, storage_addr = storage_handle.block_id;
            page_start =  (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
    					page_end =  ((storage_addr + size) / PSTORAGE_FLASH_PAGE_SIZE);
    					for(page = page_start; page <= page_end; page++){
    							storage_handle.block_id = page * PAGE_SIZE;
    							// get page
    							memcpy(page_swap, (uint32_t *)(page * PSTORAGE_FLASH_PAGE_SIZE), PSTORAGE_FLASH_PAGE_SIZE);
    							// first page
    							if(page == page_start){
    								offset = (storage_addr - (page * PSTORAGE_FLASH_PAGE_SIZE)); // distance from page start
    								if((size + offset) > PSTORAGE_FLASH_PAGE_SIZE){ // if it goes to another page, delete from this page to the end
    									memset(page_swap + offset, 0xFF, PSTORAGE_FLASH_PAGE_SIZE - offset);
    								}
    								else // if not, delete from offset to size
    									memset(page_swap + offset, 0xFF, size);
    							} else if(page == page_end){ // second page
    								memset(page_swap, 0xFF, size - (PSTORAGE_FLASH_PAGE_SIZE - offset)); // delete the remaining size
    							}
    							
    						pstorage_clear(&storage_handle, PAGE_SIZE);
    						pstorage_store(&storage_handle,
    								(uint8_t *) page_swap,
    									PAGE_SIZE,
    									0);
    					}
    }
    
  • @Victor: Thanks for sharing the solution. In RAW mode we don't use swap page for updating part of a page. Only store and clear op code are supported. The pstorage_raw library mainly created for the DFU, not for generic use. You can use the pstorage.c library instead, but will have to orgnize your data in modules and blocks, not directly access them via flash address.

Related