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

Flash erase/write problems

I've spent several days reading all the support tickets regarding this issue but I cannot find a resolution.

I am running the ble_central_uart example with SD 132, SES 4.30, SDK 15.3 on an nRF52 DK dev board.  

I have been unable to erase flash consistently or to write flash at all.  It appears that I am having problems with both erasing and writing flash.  I implemented the sd_flash_page_erase() function as follows:

uint32_t static pg_size;
uint32_t static pg_num;
uint32_t static flash_addr;
uint32_t static p_flash_addr;

static uint32_t nrf5_flash_end_addr_get()
{
    pg_size = NRF_FICR->CODEPAGESIZE;
    pg_num = NRF_FICR->CODESIZE-2; // Use last page in flash
    flash_addr = (uint32_t *)(pg_size * pg_num);
    p_flash_addr = &flash_addr;
}

void erase_flash_page(void)
{

  flash_operation_completed = false;
  sd_flash_page_erase(pg_num);

  while(!flash_operation_completed)
  {
  sd_app_evt_wait();
  flash_operation_completed = true;
  }
}

This code executes but it does not check for the flash erase function to complete.  In debugging the problem, I found that the write function sd_flash_write() was erroring out on err_code == NRF_ERROR_BUSY.  So I figured the erase function required more time to complete.  I added a delay nrf_delay_ms(100) and tried a timer as well.  Neither did any good.  So I added an error check on the sd_flash_page_erase() function, like this:

void erase_flash_page(void)
{
uint32_t evt = 0;
retry_flash:
    flash_operation_completed = false;
    sd_flash_page_erase(pg_num);
   
    while(!flash_operation_completed)
    {
      sd_evt_get (&evt);
      if (evt == NRF_EVT_FLASH_OPERATION_SUCCESS || evt == NRF_EVT_FLASH_OPERATION_ERROR)
      {
        flash_operation_completed = true;
        goto resume_flash_operations;
      }
      else 
      {
        start_flash_timer();
        goto retry_flash;
      }
    }

//  nrf_delay_ms(10);     // give flash time to finish

  while(!flash_operation_completed)
  {
  sd_app_evt_wait();
  flash_operation_completed = true;
  }

resume_flash_operations:
return (12345);
}

Line 11 never evaluates as true.  So the code gets stuck in this loop.

The other problem I have is that even when I put a delay in the erase code and let it pass through the erase function to the write function, I get an NRF_BUSY_ERROR in the write flash function.  See code below:

void write_flash_page(void)
{
  ret_code_t err_code;
uint8_t block_size = sizeof(write_flash_block);

//  sd_flash_write((uint32_t*)flash_addr, (uint32_t*)&write_flash_block, sizeof(write_flash_block));
//  sd_flash_write((uint32_t*)&flash_addr, p_write_flash_block, sizeof(write_flash_block));
//  sd_flash_write(p_flash_addr, p_write_flash_block, sizeof(write_flash_block));

  flash_operation_completed = false;
  err_code = sd_flash_write((uint32_t*)flash_addr, p_write_flash_block, block_size);

  if (err_code != NRF_SUCCESS)
  {
     NRF_LOG_INFO("Error writing to flash, err_code = \"%x\" .", err_code);
      if (err_code == NRF_ERROR_INVALID_LENGTH) while (1);
      if (err_code == NRF_ERROR_INVALID_ADDR) while (1);
      if (err_code == NRF_ERROR_BUSY) while (1);
      if (err_code == NRF_ERROR_FORBIDDEN) while (1);
  }

  while(!flash_operation_completed)
  {
  sd_app_evt_wait();
  flash_operation_completed = true;
  }
}

The code always hangs on line 18 - if (err_code == NRF_ERROR_BUSY) while (1);

I make sure that my writes are word aligned as shown:

    struct blockstruct // block to write into flash.
    {
      int desired_temp;                       // Last water temperature requested by user.
      int desired_flow;                       // same
      int user_max_temp;
      int absolute_max_temp;
      bool startup_done;
      bool install_mode;
      bool initialization_done;
      bool clockwise_heat;
      int shower_timer;
      bool temp_scale;
      int user_last_preset;
      int user_last_temp;
    }__ALIGN(4)write_flash_block, __ALIGN(4)read_flash_block;

and my flash writes always begin at the start of the flash page which happens to be 7e000.  

Finally, I tried to supply my own event handler with this code:

static void sys_evt_dispatch(uint32_t sys_evt)
{
    app_sys_event_handler(sys_evt);
}

void app_sys_event_handler(uint32_t sys_evt)
{
//    flash_operation_completed = false;

	switch (sys_evt)
	{
		case NRF_EVT_FLASH_OPERATION_SUCCESS:
			flash_operation_completed = true;
                        NRF_LOG_INFO("--> Flash page operation sucessfull.");
			break;

		case NRF_EVT_FLASH_OPERATION_ERROR:
			// Handle error
                        NRF_LOG_INFO("--> Flash page operation FAILED!!!!!!!!!!!!!!.");
			break;
	}
}

    // Register with the SoftDevice handler module for BLE events.
ret_code_t err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
softdevice_sys_evt_handler_set(sys_evt_dispatch);
APP_ERROR_CHECK(err_code);

But it seems that this code isn't supported by SDK 15.3.  I get compile errors.

Where am I going wrong?

Parents
  • This code executes but it does not check for the flash erase function to complete.  In debugging the problem, I found that the write function sd_flash_write() was erroring out on err_code == NRF_ERROR_BUSY.  So I figured the erase function required more time to complete

    Are you calling your write_flash_page from main Thread context or an intterrupt context? Calling this interrupt context si not a good idea as you seem to be busy waiting on the flash complete flag

    sd_evt_get (&evt);

    So you are using sd_evt_get (&evt); in your code to know if the flash event is complete or not. Then it means that which ever is not the flash event will be ignored completely by your whole application since sd_evt_get pull the event from the buffer and hence the rest of the application will not get any other event while you are calling sd_evt_get (&evt); and ignoring the non flash events.

    using NRF_EVT_FLASH_OPERATION_SUCCESS/NRF_EVT_FLASH_OPERATION_ERROR both tells that the flash operation has completed and NRF_EVT_FLASH_OPERATION_SUCCESS only tells that the flash operation has been successful. You need to differentiate your logic between the completed flag and successful flag.

    in the file examples\ble_central\ble_app_gatts\main.c you can see that you can plug in a soc_evt_handler as an observer to soc events, you need to do that instead of creating your own callback function

    NRF_SDH_SOC_OBSERVER(m_soc_observer, APP_SOC_OBSERVER_PRIO, soc_evt_handler, NULL);

  • Hi Susheel,

    I am calling my flash routines from my main(void) functions. NOT INTERRUPTS. You said "Then it means that which ever is not the flash event will be ignored completely by your whole application since sd_evt_get pull the event from the buffer and hence the rest of the application will not get any other event while you are calling sd_evt_get (&evt); and ignoring the non flash events."  I had that same thought when working with the sd_evt_get (&evt) function.  Thanks for confirming that.

    I'm not sure when you say "You need to differentiate your logic between the completed flag and successful flag." The problem is that neither flag is getting set!  So differentiating at this point will make no difference.  I'll try the soc_evt_handler to see how that works.  

    Finally, are you saying that the sd_flash_write/erase functions will work with the ble_central apps and that I don't need to use FDS?  I turned OFF (disabled) FDS in the sdk_config.h file and didn't get any compile errors so I don't think that FDS is used for saving ble keys as previously stated by Turbo J.  Is that correct?

  • Why do you have the below?

        while(!flash_operation_completed)
        {
    //    nrf_delay_ms(100);     // 85ms minimum flash time to finish erase cycle
    //    sd_app_evt_wait();
        flash_operation_completed = true;
        }

    If the flash oepration is complete, you will get the event from the SD, why do you force it to be completed within 100ms anyways. Then there would be no point in having the events.

  • I put this code in because the SD events functions were not working.  I left them in because they don't affect the writing anyway.  Even so, the SD events aren't working so this code should allow enough time for a write to work.  However, it doesn't work reliably anyway.  I will remove this code once the SD events are confirmed to be working.

    Why aren't my SD events working? 

  • They should work, your application should have received SD events unless your application has while() statement in an interrupt context that blocks the SD_EVT_IRQHandler

  • Hi Susheel,

    Are you sure that I don't have any coding errors that are causing the problems?  I am not using interrupts, only timers and I don't have any while() statements in my timer handling routines.  Am I correctly processing the SD event?

  • EricDelangis said:
    Are you sure that I don't have any coding errors that are causing the problems? 

     Hi Eric,

    I cannot answer that since I do no know the contexts of all the calls happening. But if you are calling erase_flash_page and write_flash_page from Thread context, then I do not see anything in your code that blocks the SD events indefinitely.

Reply Children
Related