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?

  • you should add it in the ble_stack_init at the same level where you plugin your ble_evt_handler for your application as BLE events observer.

  • EricDelangis said:
    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

     It means that you need to set "flash_operation_completed = true;" in both NRF_EVT_FLASH_OPERATION_SUCCESS and also in the case NRF_EVT_FLASH_OPERATION_ERROR. This is because  your application is depending on the flash operation to complete to exit from the wait loop and if flash operation returns NRF_EVT_FLASH_OPERATION_ERROR, then your application will loop for ever even though there is no ongoing flash operations.

     

    EricDelangis said:
    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?

    If you are using peer_manager library for storing BLE keys, it does use FDS. I used them in my reply since it seemed that you are using them already based on your original question.

  • I am using ble_central without modifications. However, I do include ble_uart_central, pwm, saadc and flash functions.  A search of the code has NO references to FDS so I don't know how it saves the keys.  And as I said, disabling FDS in sdk_config.h did not generate any errors. The big question is how do I write to flash reliably since it doesn't return either success for failure messages?  With hard delays, i.e. nrf_delay_ms(100), for a flash page erase, and nrf_delay_ms(2) for a flash page write, it sometimes works.

  • Hi Susheel,

    I still can't get the flash writes working reliably.  I found this thread https://devzone.nordicsemi.com/f/nordic-q-a/44306/issue-with-nrf_sdh_soc_observer that solved the same problem as I am having but I haven't been able to get my code to work.  Here's what I've got:

    /****************** Erase Flash ***************************/
    void erase_flash_page(void)
    {
        NRF_LOG_INFO("Erasing Flash...");
        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;
          }
        }
    */
        while(!flash_operation_completed)
        {
    //    nrf_delay_ms(100);     // 85ms minimum flash time to finish erase cycle
    //    sd_app_evt_wait();
        flash_operation_completed = true;
        }
    
    resume_flash_operations:
        return (12345);
    }
    
    /****************** Write Flash ***************************/
    void write_flash_page(void)
    {
        NRF_LOG_INFO("Writing Flash...");
        uint8_t block_size = sizeof(write_flash_block);
        ret_code_t err_code;
        flash_operation_completed = false;
        err_code = sd_flash_write((uint32_t*)flash_addr, (uint32_t*)&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();
        nrf_delay_ms(2);     // <1 ms minimum flash time to finish write cycle
        flash_operation_completed = true;
        }
    }
    
    

    Here's my nrf_sdh_soc_observer and handler stuff: (Note: I found a thread that talked about enabling NRF_SDH_SOC_ENABLE, it is enabled in the sdk_config.h file, but I can't find any function in the Nordic directories and I get an error when I try to instantiate it in lines 42-45.)

      // flash storage handler
    static void soc_evt_handler(uint32_t evt_id, void * p_context)
    {
        switch (evt_id)
        {
            case NRF_EVT_FLASH_OPERATION_SUCCESS:
            // fall through 
            case NRF_EVT_FLASH_OPERATION_ERROR:
    
                if (flash_operation_completed)
                {
                    flash_operation_completed = false;
                }
                break;
    
            default:
                // No implementation needed.
                  flash_operation_completed = true;
                break;
        }
    }
    /* ******************************** End *********************************/
    
    static void ble_stack_init(void) {
      ret_code_t err_code;
      uint32_t   ram_start = 0;
    
      err_code = nrf_sdh_enable_request();
      APP_ERROR_CHECK(err_code);
    
      // Configure the BLE stack using the default settings.
      // Fetch the start address of the application RAM.
    //  uint32_t ram_start = 0;
      err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
      APP_ERROR_CHECK(err_code);
    
      // Enable BLE stack.
      err_code = nrf_sdh_ble_enable(&ram_start);
      APP_ERROR_CHECK(err_code);
    
     /*************************** Added by Eric ***********************/
     // Enable SOC.
    //  err_code = nrf_sdh_soc_enable();
    //  err_code = NRF_SDH_SOC_ENABLE();
    //  APP_ERROR_CHECK(err_code);
    /* ******************************** End *********************************/
    
      // Register a handler for BLE events.
      NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    
    /*************************** Added by Eric ***********************/
      NRF_SDH_SOC_OBSERVER(m_soc_observer, APP_SOC_OBSERVER_PRIO, soc_evt_handler, NULL);
    /*
      // Register with the SoftDevice handler module for BLE events.
      err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
      APP_ERROR_CHECK(err_code);
    
        /* Request Softdevice to turn on Crystal oscillator to test if SoC events are
           forwarded to the application. _SOC_ observers should get notified of the
           NRF_EVT_HFCLKSTARTED event after this call. */
        err_code = sd_clock_hfclk_request();
        APP_ERROR_CHECK(err_code);
    /* ******************************** End *********************************/
    }
    
    

  • 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.

Related