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

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

  • It is not easy to understand why you system broke when you used app_scheduler, there seemed to be some deadlock most likely due to the API usage of app_scheduler which might not be completely thread safe here.

Reply Children
No Data
Related