Close

Running a task at max priority

A project log for Bare metal second core on ESP32

Evaluate ways to run code on one of the ESP32s cores without the scheduler interfering

danielDaniel 09/08/2020 at 11:340 Comments

Method

The idea is simple, just build the SDK in normal Dual Core configuration, but pin all tasks to the first core. We then can run a task on the second core which should (in theory) run uninterrupted by everything.

But: We can't be sure nothing is running on the second core!

The ESP32 ecosystem and firmware is complex. There are so many libraries, so we can't be sure that there is really nothing else running on that core.

Testing

Easiest way to test this would be to toggle an IO in an infinite loop and then look at the output with a scope or a logic analyzer. If it is in fact running uninterrupted, the signal should be a clean square wave. If something is interrupting it, it should get 'stuck' from time to time. Since I have none of both at hand, I decided to measure the jitter in the execution time of a simple wait loop. With this method, I can't be sure it runs without interruptions, but I can at least detect some interruptions.

void app_task(void *param)
{
	(void)param;
	uint64_t min = UINT64_MAX;
	uint64_t max = 0;
	uint64_t sum = 0;
	uint64_t last = 0;

#define NUM_ROUNDS 1000
	uint64_t times[NUM_ROUNDS];

	printf("app_task started on core %i\n", xPortGetCoreID());

	last = esp_timer_get_time();

	for(volatile uint32_t i = 0; i < NUM_ROUNDS; i++)
	{
		for(volatile uint32_t delay = 0; delay < 1000; delay++);

		uint64_t now = esp_timer_get_time();
		uint64_t diff = now - last;
		last = now;

		if (diff < min)
		{
			min = diff;
		}

		if (diff > max)
		{
			max = diff;
		}

		sum += diff;
		times[i] = diff;
	}

	printf("app_task finished\nmin=%llu\nmax=%llu\navg=%llu\n", min, max, sum / 1000);
	for(volatile uint32_t i = 0; i < NUM_ROUNDS; i++)
	{
		printf("%i=%llu\n", i, times[i]);
	}
}

Results

If the code would run (more or less) uninterrupted, the times values should be almost the same (+/- 1). Except the first may be a bit off, due to the beginning of the loop. But looking at the output we get something like:

87=120                                                                          
88=120                                                                          
89=120                                                                          
90=121                                                                          
91=120                                                                          
92=130                                                                          
93=120                                                                          
94=120                                                                          
95=120                                                                          
96=120                                                                          
97=121

 So it seems like it takes ~120ns to execute one run. However, the 92th run took 130ns. So unless the esp_timer_get_time() itself takes longer from time to time.,we got an interruption here! Sadly I have no way to verify this. But, since just a few runs take longer (always about 10ns) I guess its some interrupt handling.

Conclusion

FAIL

The simplest, straight-forward approach with just running a task at max prio does not seem to work. I don't know what causes the problems, but it seems something (maybe interrupt handling) is ruining my timing here. Also, we can't be sure the core is actually free, so I can't recommend this method.

Discussions