This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to make FDS blocking

Hi,

I am using an nRF52840 with SDK 17.0.2 and S140 7.2.0. I am running a scheduler based on app_scheduler.

I am trying to make my FDS implementation blocking as it is too complex to run a synchronously as there are quite a few calls to it that are causing havoc with the queues. I have set up a flag that I set to true before executing an FDS operation and then I want to wait for that flag to become false before continuing. I have tried the following:

Simple, empty while loop. This just locks the processor up and the command is never received

while( _fdsBusy ) ;

NRF Delay. This has a similar effect to above

while( _fdsBusy )
{
    nrf_delay_ms(1);
}

Using my scheduler to wait. While the event is received in the Event Handler, the code never carries on executing.

while( _fdsBusy )
{
   app_sched_execute( );
   nrf_pwr_mgmt_run( );
}

Is there any way to achieve what I want?

Thanks,

Parents
  • Hi,

    I still do not have a complete picture of the problem based on the info but have 2 small observations.

    1. _fdsBusy seems like a global (.bss) level flag which is not an atomic operation so this flag wherever used might need to fenced into a critical section (enter and exit).
    2. nrf_delay_ms is very power inefficient, and I would suggest sleeping instead of busy waiting (__WFE or sd_app_evt_wait depending on whether you are using BLE stack, softdevice or not)
  • Hi Susheel,

    Here is a snippet of my code including initialisation and an example write. The function "Storage_Wait" is the function I am referring to about making the code blocking. I hope this helps shed some light on the situation?

    I tried "sd_app_evt_wait()" but that also did not work. The event handler is never invoked after the write or garbage collection.

    #define MAX_EVENT_SIZE 128
    #define QUEUE_SIZE	   180
    
    static uint32_t _eventBuffer[CEIL_DIV( APP_SCHED_BUF_SIZE( MAX_EVENT_SIZE, QUEUE_SIZE ), sizeof( uint32_t ) )] __ALIGN( 4 );
    
    #define TEST_FILE ( 0xBFFE )
    #define TEST_KEY  ( 0x0001 )
    
    static bool volatile _fdsBusy = false;
    static bool volatile m_fds_initialised = false;
    
    static char const* fds_evt_str[] = {
    	"FDS_EVT_INIT", "FDS_EVT_WRITE", "FDS_EVT_UPDATE", "FDS_EVT_DEL_RECORD", "FDS_EVT_DEL_FILE", "FDS_EVT_GC",
    };
    
    static void fds_evt_handler( fds_evt_t const* p_evt );
    static void Storage_Wait( void );
    const char* fds_err_str( ret_code_t ret );
    
    const char* fds_err_str( ret_code_t ret )
    {
    	// Array to map FDS return values to strings.
    	static char const* err_str[] = {
    		"FDS_ERR_OPERATION_TIMEOUT", "FDS_ERR_NOT_INITIALIZED",
    		"FDS_ERR_UNALIGNED_ADDR",	 "FDS_ERR_INVALID_ARG",
    		"FDS_ERR_NULL_ARG",			 "FDS_ERR_NO_OPEN_RECORDS",
    		"FDS_ERR_NO_SPACE_IN_FLASH", "FDS_ERR_NO_SPACE_IN_QUEUES",
    		"FDS_ERR_RECORD_TOO_LARGE",	 "FDS_ERR_NOT_FOUND",
    		"FDS_ERR_NO_PAGES",			 "FDS_ERR_USER_LIMIT_REACHED",
    		"FDS_ERR_CRC_CHECK_FAILED",	 "FDS_ERR_BUSY",
    		"FDS_ERR_INTERNAL",
    	};
    
    	return err_str[ret - NRF_ERROR_FDS_ERR_BASE];
    }
    
    static void fds_evt_handler( fds_evt_t const* p_evt )
    {
    	if( p_evt->result == NRF_SUCCESS )
    	{
    		Log_Info( "Event: %s received (NRF_SUCCESS)", fds_evt_str[p_evt->id] );
    	}
    	else
    	{
    		Log_Info( "Event: %s received (%s)", fds_evt_str[p_evt->id], fds_err_str( p_evt->result ) );
    	}
    
    	switch( p_evt->id )
    	{
    		case FDS_EVT_INIT:
    			if( p_evt->result == NRF_SUCCESS )
    			{
    				m_fds_initialised = true;
    			}
    			break;
    		default:
    			break;
    	}
    
    	_fdsBusy = false;
    
    	while( nrf_log_frontend_dequeue( ) )
    		;
    }
    
    static void Storage_Wait( void )
    {
    	while( _fdsBusy )
    	{
    		sd_app_evt_wait( );
    	}
    }
    
    int main( void )
    {
    	// Initialise clocks and power
    	ret_code_t rc = nrf_drv_clock_init( );
    	APP_ERROR_CHECK( rc );
    
    	if( !nrf_drv_power_init_check( ) )
    	{
    		nrf_drv_power_init( NULL );
    	}
    
    	// Initialise Scheduler
    	rc = nrf_pwr_mgmt_init( );
    	APP_ERROR_CHECK( rc );
    
    	rc = app_sched_init( MAX_EVENT_SIZE, QUEUE_SIZE, ( void* )_eventBuffer );
    	APP_ERROR_CHECK( rc );
    
    	uint32_t   ram_start;
    
    	// Enable the SoftDevice
    	rc = nrf_sdh_enable_request( );
    	APP_ERROR_CHECK( rc );
    
    	rc = nrf_sdh_ble_default_cfg_set( 1, &ram_start );
    	APP_ERROR_CHECK( rc );
    
    	rc = nrf_sdh_ble_enable( &ram_start );
    	APP_ERROR_CHECK( rc );
    
    	// Initialise Logging
    	rc = NRF_LOG_INIT( NULL );
    	APP_ERROR_CHECK( rc );
    
    	// Initialise the default backends as enabled in the configuration
    	NRF_LOG_DEFAULT_BACKENDS_INIT( );
    
    	NRF_LOG_INFO( "Application Started" );
    
    	// Initialise Storage
    
    	rc = fds_register( fds_evt_handler );
    	APP_ERROR_CHECK( rc );
    
    	rc = fds_init( );
    	APP_ERROR_CHECK( rc );
    
    	while( !m_fds_initialised )
    	{
    		sd_app_evt_wait();
    	}
    
    	Log_Info( "FDS Initialised" );
    
    	fds_stat_t stat = { 0 };
    
    	rc = fds_stat( &stat );
    	APP_ERROR_CHECK( rc );
    
    	NRF_LOG_INFO( "Found %d valid records.", stat.valid_records );
    	NRF_LOG_INFO( "Found %d dirty records (ready to be garbage collected).", stat.dirty_records );
    
    	if( stat.dirty_records > 0 )
    	{
    		_fdsBusy = true;
    
    		rc = fds_gc( );
    		APP_ERROR_CHECK( rc );
    
    		Storage_Wait( );
    	}
    
    	fds_record_desc_t desc = { 0 };
    	fds_find_token_t  tok  = { 0 };
    
    
    	// Test Write
    
    	static uint32_t const m_deadbeef = 0xDEADBEEF;
    
    	fds_record_t	  record;
    	fds_record_desc_t record_desc;
    
    	record.file_id			 = TEST_FILE;
    	record.key				 = TEST_KEY;
    	record.data.p_data		 = &m_deadbeef;
    	record.data.length_words = 1;
    
    	_fdsBusy = true;
    	rc = fds_record_write( &record_desc, &record );
    	APP_ERROR_CHECK( rc );
    	
    	Storage_Wait( );
    
    	while(1)
    	{
    		app_sched_execute( );
    
    		if( nrf_log_frontend_dequeue( ) == false )
    		{
    			nrf_pwr_mgmt_run( );
    		}
    	}
    }

    Thanks

  • Hi Susheel,

    I commented out everything in "main.c" and pasted the snippet in so there is only this code running. I did a chip erase and programmed the SD and then this code and I am still seeing the same errors. Sometimes the event handler is never invoked (not even for Init) and it never invokes after the GC call.

    I have attached my sdk_config.h snippet for the FDS part:

    // <e> FDS_ENABLED - fds - Flash data storage module
    //==========================================================
    #ifndef FDS_ENABLED
    #define FDS_ENABLED 1
    #endif
    // <h> Pages - Virtual page settings
    
    // <i> Configure the number of virtual pages to use and their size.
    //==========================================================
    // <o> FDS_VIRTUAL_PAGES - Number of virtual flash pages to use. 
    // <i> One of the virtual pages is reserved by the system for garbage collection.
    // <i> Therefore, the minimum is two virtual pages: one page to store data and one page to be used by the system for garbage collection.
    // <i> The total amount of flash memory that is used by FDS amounts to @ref FDS_VIRTUAL_PAGES * @ref FDS_VIRTUAL_PAGE_SIZE * 4 bytes.
    
    #ifndef FDS_VIRTUAL_PAGES
    #define FDS_VIRTUAL_PAGES 5
    #endif
    
    // <o> FDS_VIRTUAL_PAGE_SIZE  - The size of a virtual flash page.
     
    
    // <i> Expressed in number of 4-byte words.
    // <i> By default, a virtual page is the same size as a physical page.
    // <i> The size of a virtual page must be a multiple of the size of a physical page.
    // <1024=> 1024 
    // <2048=> 2048 
    
    #ifndef FDS_VIRTUAL_PAGE_SIZE
    #define FDS_VIRTUAL_PAGE_SIZE 1024
    #endif
    
    // <o> FDS_VIRTUAL_PAGES_RESERVED - The number of virtual flash pages that are used by other modules. 
    // <i> FDS module stores its data in the last pages of the flash memory.
    // <i> By setting this value, you can move flash end address used by the FDS.
    // <i> As a result the reserved space can be used by other modules.
    
    #ifndef FDS_VIRTUAL_PAGES_RESERVED
    #define FDS_VIRTUAL_PAGES_RESERVED 4
    #endif
    
    // </h> 
    //==========================================================
    
    // <h> Backend - Backend configuration
    
    // <i> Configure which nrf_fstorage backend is used by FDS to write to flash.
    //==========================================================
    // <o> FDS_BACKEND  - FDS flash backend.
     
    
    // <i> NRF_FSTORAGE_SD uses the nrf_fstorage_sd backend implementation using the SoftDevice API. Use this if you have a SoftDevice present.
    // <i> NRF_FSTORAGE_NVMC uses the nrf_fstorage_nvmc implementation. Use this setting if you don't use the SoftDevice.
    // <1=> NRF_FSTORAGE_NVMC 
    // <2=> NRF_FSTORAGE_SD 
    
    #ifndef FDS_BACKEND
    #define FDS_BACKEND 2
    #endif
    
    // </h> 
    //==========================================================
    
    // <h> Queue - Queue settings
    
    //==========================================================
    // <o> FDS_OP_QUEUE_SIZE - Size of the internal queue. 
    // <i> Increase this value if you frequently get synchronous FDS_ERR_NO_SPACE_IN_QUEUES errors.
    
    #ifndef FDS_OP_QUEUE_SIZE
    #define FDS_OP_QUEUE_SIZE 500
    #endif
    
    // </h> 
    //==========================================================
    
    // <h> CRC - CRC functionality
    
    //==========================================================
    // <e> FDS_CRC_CHECK_ON_READ - Enable CRC checks.
    
    // <i> Save a record's CRC when it is written to flash and check it when the record is opened.
    // <i> Records with an incorrect CRC can still be 'seen' by the user using FDS functions, but they cannot be opened.
    // <i> Additionally, they will not be garbage collected until they are deleted.
    //==========================================================
    #ifndef FDS_CRC_CHECK_ON_READ
    #define FDS_CRC_CHECK_ON_READ 1
    #endif
    // <o> FDS_CRC_CHECK_ON_WRITE  - Perform a CRC check on newly written records.
     
    
    // <i> Perform a CRC check on newly written records.
    // <i> This setting can be used to make sure that the record data was not altered while being written to flash.
    // <1=> Enabled 
    // <0=> Disabled 
    
    #ifndef FDS_CRC_CHECK_ON_WRITE
    #define FDS_CRC_CHECK_ON_WRITE 0
    #endif
    
    // </e>
    
    // </h> 
    //==========================================================
    
    // <h> Users - Number of users
    
    //==========================================================
    // <o> FDS_MAX_USERS - Maximum number of callbacks that can be registered. 
    #ifndef FDS_MAX_USERS
    #define FDS_MAX_USERS 1
    #endif
    
    // </h> 
    //==========================================================
    
    // </e>

    and fstorage:

    // <e> NRF_FSTORAGE_ENABLED - nrf_fstorage - Flash abstraction library
    //==========================================================
    #ifndef NRF_FSTORAGE_ENABLED
    #define NRF_FSTORAGE_ENABLED 1
    #endif
    // <h> nrf_fstorage - Common settings
    
    // <i> Common settings to all fstorage implementations
    //==========================================================
    // <q> NRF_FSTORAGE_PARAM_CHECK_DISABLED  - Disable user input validation
     
    
    // <i> If selected, use ASSERT to validate user input.
    // <i> This effectively removes user input validation in production code.
    // <i> Recommended setting: OFF, only enable this setting if size is a major concern.
    
    #ifndef NRF_FSTORAGE_PARAM_CHECK_DISABLED
    #define NRF_FSTORAGE_PARAM_CHECK_DISABLED 0
    #endif
    
    // </h> 
    //==========================================================
    
    // <h> nrf_fstorage_sd - Implementation using the SoftDevice
    
    // <i> Configuration options for the fstorage implementation using the SoftDevice
    //==========================================================
    // <o> NRF_FSTORAGE_SD_QUEUE_SIZE - Size of the internal queue of operations 
    // <i> Increase this value if API calls frequently return the error @ref NRF_ERROR_NO_MEM.
    
    #ifndef NRF_FSTORAGE_SD_QUEUE_SIZE
    #define NRF_FSTORAGE_SD_QUEUE_SIZE 8
    #endif
    
    // <o> NRF_FSTORAGE_SD_MAX_RETRIES - Maximum number of attempts at executing an operation when the SoftDevice is busy 
    // <i> Increase this value if events frequently return the @ref NRF_ERROR_TIMEOUT error.
    // <i> The SoftDevice might fail to schedule flash access due to high BLE activity.
    
    #ifndef NRF_FSTORAGE_SD_MAX_RETRIES
    #define NRF_FSTORAGE_SD_MAX_RETRIES 8
    #endif
    
    // <o> NRF_FSTORAGE_SD_MAX_WRITE_SIZE - Maximum number of bytes to be written to flash in a single operation 
    // <i> This value must be a multiple of four.
    // <i> Lowering this value can increase the chances of the SoftDevice being able to execute flash operations in between radio activity.
    // <i> This value is bound by the maximum number of bytes that can be written to flash in a single call to @ref sd_flash_write.
    // <i> That is 1024 bytes for nRF51 ICs and 4096 bytes for nRF52 ICs.
    
    #ifndef NRF_FSTORAGE_SD_MAX_WRITE_SIZE
    #define NRF_FSTORAGE_SD_MAX_WRITE_SIZE 1024
    #endif
    
    // </h> 
    //==========================================================
    
    // </e>

  • I have used your SDK_config.h file and still able to build and run your code without any issues. Seems like the program is stuck in your case not because of the code snippet you produced. I am attaching my whole project for you to run and test if you want to see.

    7673.ble_app_gls.zip

  • Hi Susheel,

    Your project works well for me, but I cannot understand why mine isn't working, even though the code appears identical. Is there a way I can privately upload my project for you to take a look?

  • Unfortunately,  we here at Techsupport do not have the capacity to debug issues that we know are not inside our solution. I would suggest you to take my project as template and keep on adding extra layers of logic in your application until you hit this case. For me it seems like a deadlock in some other context of you application.

  • Hi Susheel,

    No problem, thanks for your advice.

    I actually found the issue last night and it was within my sdk_config.h file. When I used my sdk_config.h file with your project it did not work.

    My SDK Config had the define NRF_SDH_DISPATCH_MODEL set to NRF_SDH_DISPATCH_MODEL_APPSH whereas your SDK Config had it set to NRF_SDH_DISPATCH_MODEL_INTERRUPT.

    Please could you explain why this would cause the system to break as I am using the Scheduler and I would have thought all events should be dispatched to that?

Reply
  • Hi Susheel,

    No problem, thanks for your advice.

    I actually found the issue last night and it was within my sdk_config.h file. When I used my sdk_config.h file with your project it did not work.

    My SDK Config had the define NRF_SDH_DISPATCH_MODEL set to NRF_SDH_DISPATCH_MODEL_APPSH whereas your SDK Config had it set to NRF_SDH_DISPATCH_MODEL_INTERRUPT.

    Please could you explain why this would cause the system to break as I am using the Scheduler and I would have thought all events should be dispatched to that?

Children
Related