Start running code based upon event without tying up the main code?

Total noob question here, just starting with FreeRTOS

I have set up a Nordic 52832 project based upon the freertos hrs project. And now I’m trying to build my application. One of the things I want to do is when a write comes in, schedule generating a notification. And the key is “schedule” a notification. I don’t want to call the notification code directly from when the write happened, because my fear is that I will be doing “a lot” of work, and therefore I’m tying things up, and thus would violate bluetooth specs.

In a non-FreeRTOS world, I would build a buffer of the data I would want to send in the notification, set some internal flag, and the main loop, as it goes through, would see that flag set and do the work needed. And if it failed (say bluetooth was busy so the notification couldn’t be sent right now), set the flag again for processing through the main loop again.

So, I’m trying to figure out how to do something like this in a FreeRTOS context. My thoughts were “software interrupt” or “task”, or… something. But either because I don’t know the terminology to use, or I’m just overthinking it, I can’t seem to “schedule” what I want to do.

I tried creating a task through xTaskCreate, but that task never seems to execute. Here was that code


xTaskHandle TaskHandle_1;

void MyTask1(void *pvParameters) {
	NRF_LOG_INFO ("MyTask1");	
	bsp_board_led_color(LED_COLOR_RED);
	vTaskDelete(TaskHandle_1);
}

void generateResponse() {
	NRF_LOG_INFO ("generateResponse");
	
	xTaskCreate( MyTask1, (signed char *) "Task1", configMINIMAL_STACK_SIZE, NULL, 3, &TaskHandle_1);
	
	NRF_LOG_INFO ("ok then");
}

Note that this is all done “after” the code is running, and vTaskScheduler has already been called.

I’m sorry for being so… well, noob-ish on this. I just can’t figure out what to do here.

Sounds like that would be a task. Generate the task at startup and have it wait for a notification, then it does its stuff, then wait for the next notification to do it again.

Sounds like a lower priority task to not interfere with other operations.

yes, that sounds exactly like what I want to do :grinning:

Ok, I see how to make that work with xTaskNotifyGive() and xTaskNotifyWait(). I have run into a secondary issue which is once I created this task, vTaskStartScheduler() was falling through, meaning not enough memory.

I adjusted the RAM start and RAM size quite a bit, but it still was dying. I was only able to get it to go once I turned off logging (NRF_LOG). which is not great for debug. must do more thinking I guess… If adding one task caused me to fall over and die, that doesn’t bode well. I could see adding several tasks in the future of this application!

Ok so they problem was fixed by increasing the heap size…

I know you’ve already solved the problem, but as a general practice with FreeRTOS (and a few others small real-time executives) I endeavor to use static allocation of the OS objects (TCBs, task stacks, semaphores, queues, etc.). With freeRTOS, you must configure the kernel to allow static allocation by defining “configSUPPORT_STATIC_ALLOCATION” with a value of 1 (it defaults to 0). This is not mutually exclusive with “configSUPPORT_DYNAMIC_ALLOCATION”, which defaults to 1. At least with some versions, enabling static allocation in the kernel requires adding a few functions and static structure instances. Here’s what I have in my “freeRTOS_support.c” that I include in several of my projects:

#if (configSUPPORT_STATIC_ALLOCATION == 1)

static StaticTask_t zTimerTaskBuffer;
static StackType_t zTimerTaskStack[configTIMER_TASK_STACK_DEPTH];

void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer,
                                    StackType_t **ppxTimerTaskStackBuffer,
                                    uint32_t *pulTimerTaskStackSize)
{
   *ppxTimerTaskTCBBuffer = &zTimerTaskBuffer;
   *ppxTimerTaskStackBuffer = zTimerTaskStack;
   *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
} /* end of vApplicationGetTimerTaskMemory() */

static StaticTask_t zIdleTaskBuffer;
static StackType_t zIdleTaskStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
                                   StackType_t **ppxIdleTaskStackBuffer,
                                   uint32_t *pulIdleTaskStackSize)
{
   *ppxIdleTaskTCBBuffer = &zIdleTaskBuffer;
   *ppxIdleTaskStackBuffer = zIdleTaskStack;
   *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
} /* end of vApplicationGetIdleTaskMemory() */
#endif /* (configSUPPORT_STATIC_ALLOCATION == 1) */