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?

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

  • So, how do I get around this so the flash erase and writes are reliable?  Do you have example code that uses hard delays (nrf_delay_xx)?  I can live with the delays as long as the SD 132 can.

  • Can you please upload your whole project, so that I can look at the contexts properly to be able to give any suggestions to you.

    EricDelangis said:
    Do you have example code that uses hard delays (nrf_delay_xx)?

     We normally use a timer asynchronous delay instead of of busy delays when we are using softdevice, since most of the processing is done in the interrupt handlers with BLe activity. It does not mean that you can not use a busy delay nrf_delay_ms when executing in Thread context.

  • Hi Susheel,

    I do not like hard delays either but I've been unable to get anything else working properly.  Though, I've got my doubts about hard delays working properly without excessively long delays that will affect the SD.

    I've attached my code./cfs-file/__key/communityserver-discussions-components-files/4/2043._2100_PerfShwrValve.zip

    You can unzip in examples directory.

  • There are tons of things that are wrong in your program. And I strongly suggest you to get your code peer reviewed. I have not done any detailed code review but spending 5 minutes with main.c file I see that you call ble_nus_c_evt_handler-> ble_handle_message->convert_temperature_values->update_flash_info->erase_flash->While(never_ending_loop)

    Basically doing a flash activity inside the BLE event handler and waiting for an event while in interrupt context is not a good idea at all. You need to probably use app_scheduler to push all this activity you are doing for converting temperature values into thread context instead of doing so much oeprations inside an interrupt context.

Reply
  • There are tons of things that are wrong in your program. And I strongly suggest you to get your code peer reviewed. I have not done any detailed code review but spending 5 minutes with main.c file I see that you call ble_nus_c_evt_handler-> ble_handle_message->convert_temperature_values->update_flash_info->erase_flash->While(never_ending_loop)

    Basically doing a flash activity inside the BLE event handler and waiting for an event while in interrupt context is not a good idea at all. You need to probably use app_scheduler to push all this activity you are doing for converting temperature values into thread context instead of doing so much oeprations inside an interrupt context.

Children
Related