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

Add FreeRTOS to do a lot of caculation and BLE data data transmission in MutilRole device

Hi,

I got the example github.com/.../nrf52-ble-multi-link-multi-role and I have added FreeRTOS to the example refer to ble_app_hrs_freertos in SDK v15.2.0 with S140 v6.1.0.

We want to do a game project. One 52840 works in mutilrole(central_and_peripheral) and another one just work in peripheral. APP,peripheral and mutilrole device would exchane data each other and also the devie would have a lot of data to cacaulate using FPU.

static void BLEAppTask(void * pvParameter)
{	
		if (pdPASS != xTimerStart(m_battery_timer, OSTIMER_WAIT_FOR_QUEUE))
		{
				APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
		}		
			
		while(1)
		{
			  process_ble_commands();
			  send_device_status();
			  flash_operate(fs_event_num);
			  taskYIELD();		
		}
}

static void ble_task(void *arg)
{		
		advertising_start(); 	
		scan_start();                          // Start scanning for peripherals and initiate connection to devices which  advertise.	
}	
static void app_task_demo(void *arg)
{		
		if (pdPASS != xTimerStart(m_master_receive_timer, OSTIMER_WAIT_FOR_QUEUE))
		{
				APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
		}
		uart_printf("app_task_demo start.\n");
		vTaskSuspend(NULL);	
}	
static void run_task(void)
{
	nrf_sdh_freertos_init(ble_task, NULL);	                                 // Create a FreeRTOS task for the BLE stack.

    if (pdPASS != xTaskCreate(BLEAppTask, "BLEAppTask", 256, NULL, 2, &m_app_thread))
    {
        uart_printf("Failed to create BLEAppTask.\n");
    }
    else
    {
        uart_printf("BLEAppTask FreeRTOS created.\n");
    }
		
		
    if (pdPASS != xTaskCreate(app_task_demo, "TaskDemo", 256, NULL, 1, &m_demo_thread))
    {
        uart_printf("Failed to create TaskDemo task.\n");
    }
    else
    {
        uart_printf("TaskDemo FreeRTOS created.\n");
    }				
}	
int main(void)
{
    .....
    .....
	run_task();
    vTaskStartScheduler();		
	uart_printf("MutilRole application start %s\n",FIRM_WARE_REVERSION);
    for (;;)
    {	
		APP_ERROR_HANDLER(NRF_ERROR_FORBIDDEN);
    }
		
}

void send_device_status(void)
{
	uint8_t dev_info[10];
	if(DeviceStaChanged)
	{
			DeviceStaChanged = false;
			uart_printf("send_device_status\n");	
			dev_info[0] = APP_PACKET_TAG;
			dev_info[1] = 1;
			dev_info[2] = MODULE_EVENT_TYPE;
			dev_info[3] = 0;
			dev_info[4] = 4;
			dev_info[5] = 7;
			dev_info[6] = 0;
			dev_info[7] = 1;
			if(m_service_discovery_conn_handle!= BLE_CONN_HANDLE_INVALID)
				dev_info[8] = 1;        // connected status
			else
				dev_info[8] = 0;        // disconnected status
			dev_info[9] = Crc8(dev_info,9);		
			BLE_peripheral_send(dev_info,10);
			
	}
}	

 

In the BLEAppTask, process_ble_commands() is used to send data to APP or peripheral and it's OK now.

send_device_status() is used to send the link status to APP between center and peripheral . But I found that it would send data to APP even though it has run into send_device_status function and have printf send_device_status log. I'm also sure BLE_peripheral_send function is good.

It seems that CPU has been rob by other task so that it couldn't send data to APP. I set the priority of BLEAppTask to 2 and it is the same as nrf_sdh_freertos_init(ble_task, NULL);

If I set the priority to 1 for the BLEAppTask ,the  BLEAppTask couldn't run well. For example, mutilrole could connect to peripheral but it wouldn't advertise after center connect to peripheral .

So could you give me some advice about it? Thanks.

Another question, I also want to do some data caculation in the app_task_demo, but I have not done caculation now. The task creation is OK.

I hope the task wouldn't affect BLE data transmission. 

I have start a timer in the app_task_demo task and it  would invert a LED on the development kit. But the task has not run becasuse the LED could not blink.

Best regards,

Bruse

Parents
  • Hi,

    Have you done any bench marking of the various tasks you have? Sounds as you are running out of CPU time and would need to optimize some function or adapt you app to handle that in some way.

    As for raising app priorities to a higher level, this could disturb the SD behavior and is not recommended. If you use the app high level for some of  your tasks you need to make sure the sd has some time to run tasks in SD low priority as well, or it will not able to funciton properly.

  • Hi

    How to do bench marking of the various tasks?

    Now I just have two task. One task(BLEAppTask) mainly is used for  BLE data transmission. Another task(app_task_demo) is just used to start a timer to toggle a LED.

    Should I merge BLEAppTask into the task which's created by nrf_sdh_freertos_init(). I have tried to do it as follow, but it  couldn't funciton properly. 

    static void ble_task(void *arg)
    {		
    		advertising_start(); 	
    		scan_start();                          // Start scanning for peripherals and initiate connection to devices which  advertise.	
    	
    		while(1)
    		{
    			  process_ble_commands();				
    			flash_operate(fs_event_num);
    			taskYIELD();
    		}
    }
    
    nrf_sdh_freertos_init(ble_task, NULL);

    I see some issues about nRF52 SDK on https://devzone.nordicsemi.com/f/nordic-q-a/34155/what-are-sdk-15-x-0-known-issues. Would these issues cause my issue?

    Best regards,

    Bruse

  • Hi,
    Please try to add the workaround for the issue to your code to see if that helps. Since there is a known issue, it's probably better to test that first, before starting to benchmark other functions.

    One way to do the benchmarking is to add gpio toggling to parts of your code that you want to check run time for, then observe that using a logic analyzer.

  • Hi,

    I just add a delay vTaskDelay(xDelay) to the while(1) in the BLEAppTask task, then the two task could run, also I have add a while(1) to the app_task_demo task.

    But I meet other issue. I need to write some data to flash which is receive from UART. When it runs nrf_fstorage_erase() function, the code is dead and it couldn't run any more. 

    static void BLEAppTask(void * pvParameter)
    {	
    	uint8_t task_run_count = 0;
    	const portTickType xDelay = pdMS_TO_TICKS(50); 
    
    		if (pdPASS != xTimerStart(m_battery_timer, OSTIMER_WAIT_FOR_QUEUE))
    		{
    				APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
    		}		
    		while(1)
    		{	
    			  process_ble_commands();				
    				flash_operate(fs_event_num);
    				taskYIELD();
    				vTaskDelay(xDelay);	
    		}
    }
    
    static void ble_task(void *arg)
    {		
    		advertising_start(); 	
    		scan_start();                          // Start scanning for peripherals and initiate connection to devices which  advertise.	
    }	
    static void app_task_demo(void *arg)
    {		
    		
    		if (pdPASS != xTimerStart(m_test_timer, OSTIMER_WAIT_FOR_QUEUE))
    		{
    				APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
    		}	
    		uart_printf("app_task_demo start.\n");
    		
    		while(1)
    		{
    
    		}
    }	
    static void run_task(void)
    {
    	nrf_sdh_freertos_init(ble_task, NULL);	                                 // Create a FreeRTOS task for the BLE stack.
    
        if (pdPASS != xTaskCreate(BLEAppTask, "BLEAppTask", 256, NULL, 2, &m_app_thread))
        {
            uart_printf("Failed to create BLEAppTask.\n");
        }
    
        if (pdPASS != xTaskCreate(app_task_demo, "TaskDemo", 256, NULL, 1, &m_demo_thread))
        {
            uart_printf("Failed to create TaskDemo task.\n");
        }
    }
    int main(void)
    {
        ....
        ....
    	run_task();
    		
    	uart_printf("MutilRole application start %s\n",FIRM_WARE_REVERSION);	
        vTaskStartScheduler();		
    
        for (;;)
        {	
    		APP_ERROR_HANDLER(NRF_ERROR_FORBIDDEN);
        }
    		
    }

    I refer to flash_fstorage example to do flash writing and the main code as follow:

    nrf_fstorage_api_t * p_fs_api;
    
    //uint32_t data_arry[5]={0x110A0B0C,0x220A0B0C,0x330A0B0C,0x440A0B0C,0x550A0B0C};
    
    void fstorage_evt_handler(nrf_fstorage_evt_t * p_evt)
    {
        if (p_evt->result != NRF_SUCCESS)
        {
            uart_printf("--> Event received: ERROR while executing an fstorage operation.\n");
            return;
        }
    
        switch (p_evt->id)
        {
            case NRF_FSTORAGE_EVT_WRITE_RESULT:
            {
                uart_printf("--> Event received: wrote %d bytes at address 0x%x.\n",
                             p_evt->len, p_evt->addr);
    							
            } break;
    
            case NRF_FSTORAGE_EVT_ERASE_RESULT:
            {
                uart_printf("--> Event received: erased %d page from address 0x%x.\n",
                             p_evt->len, p_evt->addr);
            } break;
    				
            default:
                break;
        }
    }
    NRF_FSTORAGE_DEF(nrf_fstorage_t fstorage) =
    {
        /* Set a handler for fstorage events. */
        .evt_handler = fstorage_evt_handler,
    
        /* These below are the boundaries of the flash space assigned to this instance of fstorage.
         * You must set these manually, even at runtime, before nrf_fstorage_init() is called.
         * The function nrf5_flash_end_addr_get() can be used to retrieve the last address on the
         * last page of flash available to write data. */
        .start_addr = 0x3e000,
        .end_addr   = 0x3ffff,
    };
    static void print_flash_info(nrf_fstorage_t * p_fstorage)
    {
        uart_printf("========| flash info |========\n");
        uart_printf("erase unit: \t%d bytes\n",      p_fstorage->p_flash_info->erase_unit);
        uart_printf("program unit: \t%d bytes\n",    p_fstorage->p_flash_info->program_unit);
    		uart_printf("start_addr: \t0x%x\n",    p_fstorage->start_addr);
    		uart_printf("end_addr: \t0x%x\n",    p_fstorage->end_addr);
        uart_printf("==============================\n");
    }
    void wait_for_flash_ready(nrf_fstorage_t const * p_fstorage)
    {
        /* While fstorage is busy, sleep and wait for an event. */
        while (nrf_fstorage_is_busy(p_fstorage))
        {
           ;
        }
    }
    
    void flash_clear(void)
    {
        ret_code_t rc = nrf_fstorage_erase(&fstorage, fstorage.start_addr, 1, NULL);
        if (rc != NRF_SUCCESS)
        {
            uart_printf("nrf_fstorage_erase() returned: 0x%x\r\n", rc);
        } 	
    }
    void flash_store(uint32_t *dat,uint16_t len)
    {
    		ret_code_t rc;
    	  rc = nrf_fstorage_write(&fstorage, fstorage.start_addr, dat, len, NULL); //Write data to memory address 0x100000. Check it with command: nrfjprog --memrd 0x100000 --n 16
        APP_ERROR_CHECK(rc);
        wait_for_flash_ready(&fstorage);
        uart_printf("Done.\n");
    }
    
    void flash_load(uint32_t *dat,uint16_t len)
    {
    		ret_code_t rc;
    	  rc = nrf_fstorage_read(&fstorage, fstorage.start_addr, dat, len); //Write data to memory address 0x100000. Check it with command: nrfjprog --memrd 0xFF000 --n 16
        APP_ERROR_CHECK(rc);	
    }	
    
    
    /**@brief   Helper function to obtain the last address on the last page of the on-chip flash that
     *          can be used to write user data.
     */
    static uint32_t nrf5_flash_end_addr_get()
    {
        uint32_t const bootloader_addr = NRF_UICR->NRFFW[0];
        uint32_t const page_sz         = NRF_FICR->CODEPAGESIZE;
        uint32_t const code_sz         = NRF_FICR->CODESIZE;
    
    		uart_printf("bootloader_addr=%x page_sz=%x code_sz=%x\n",    bootloader_addr,page_sz,code_sz);
        return (bootloader_addr != 0xFFFFFFFF ?
                bootloader_addr : (code_sz * page_sz));
    }		
    void fstorage_init(void)
    {		
        ret_code_t rc;	
    		p_fs_api = &nrf_fstorage_sd;
    		fstorage.start_addr = nrf5_flash_end_addr_get()- 0x1000;	
    		fstorage.end_addr = fstorage.start_addr + 0x1000;
        rc = nrf_fstorage_init(&fstorage, p_fs_api, NULL);
        APP_ERROR_CHECK(rc);
    		print_flash_info(&fstorage);
    
    }
    void flash_operate(fs_evt event)
    {
    		switch(event)
    		{
    			case FS_STORE_EVT:
    				uart_printf("Store......\r\n");	
    				break;
    			
    			case FS_ERASE_EVT:
    					uart_printf("Erase......\r\n");
    			//		flash_load((uint32_t *)&at_com_data,sizeof(at_com_data_t));	
        			flash_clear();
    					flash_store((uint32_t *)&at_com_data,sizeof(at_com_data_t));			
    					fs_event_num = FS_IDLE;
    				break;			
    		}
    }
    

    However, if I commen out if (pdPASS != xTaskCreate(app_task_demo, "TaskDemo", 256, NULL, 1, &m_demo_thread)), that is to say, the task app_task_demo has not been created, the flash erasing and writing is all OK.

    Best regards,

    Bruse

  • I also try to lock when flash is erasing like this:

    			taskENTER_CRITICAL();
        		flash_clear();				
    			taskEXIT_CRITICAL();

    However,the code still would die and it couldn't run any more when it runs to flash_clear unless I reset or power up again.

    Is there any solutions for this issue? Thanks.

Reply
  • I also try to lock when flash is erasing like this:

    			taskENTER_CRITICAL();
        		flash_clear();				
    			taskEXIT_CRITICAL();

    However,the code still would die and it couldn't run any more when it runs to flash_clear unless I reset or power up again.

    Is there any solutions for this issue? Thanks.

Children
No Data
Related