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

Parents
  • 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);
    					}
    }
    
Reply
  • 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);
    					}
    }
    
Children
Related