ESP32-S3 Running a 'background' task on the second core and feeding data to the first core

Hi. I'm still a relative novice with Arduino (6-9 months maybe - I used CircuitPython for a few months before I realised the limitations), and I may have to give a lot of background to the task I am trying to achieve, so apologies if this post is a bit too long...

I am creating a datalogging device for motorcycles, it has custom hardware that is essentially an ESP32-S3 Reverse TFT feather with on-board SPI microSD, SPI CANBus using the one-chip MCP25625 and serial GNSS using the CD-PA1616D module on a daughterboard.

I have several spare GPIOs that I plan to use for handlebar buttons and possibly other inputs, but I want this device to also be used as a road-legal speedometer while logging, so relying solely on the GPS for speed isn't an option (not road legal due to tunnels etc). The bikes it will be used on all have ABS, so using the pulses from the ABS sensors would be a legal way to go about it. I have the GPS speedometer working perfectly.

Currently, logging is done at 5Hz, which suits the GPS and CANBus (OBD2) perfectly - OBD2 only allows 20 requests per second to avoid overloading the vehicle systems, so four parameters five times a second is fine. However, sampling the input from an ABS sensor ring at 5Hz would be far too slow, and using a system that is triggered by the pulses from the ring rather than using a fixed sampling rate would be better. From the time between these pulses, I would be able to calculate the wheel speed which can be used to give road speed.

To achieve this, it seems I have to have a separate process that is constantly measuring the wheel speed and making this value available for the main process to access, so using the second core to run this second process seems ideal. I'm not using wifi / bluetooth etc. (the hardware isn't on my board, just using the bare microcontroller) , so the second core is largely sat doing nothing.

I've got the main logger & display functions working really well, but I have no idea how to go about creating a second process on the other core, and telling it what to do. I'm sure I'd be able to create the code for all the triggering and calculating I need, but I need to know how to wrap it up and send it to the second core, and how it would then make the values available to the first core.

Any help & suggestions, including a different approach if you think it's appropriate, would be welcome.

You can use xTaskCreatePinnedToCore function. Here is an example.

You have to take care how to access the same variables from different tasks. There are different options available (like semaphores, ... for example see inter process synchronization. Basically if one task only writes to the variable and the other only reads there shouldn't be a problem.

Thanks. I saw that, but I was put off by the discussion of creating classes and so on, which is beyond my current skill set. Do I just need to follow the pattern set in the first snippet ( ESP32CoreTaskTest.ino) and not worry about the class part ( ESP32CoreTaskTest_Class.ino) ?

You only have to create a function like void task( void* parameter ){ ... and pass its reference to xTaskCreat function like

xTaskCreatePinnedToCore(
task, // <--- <our function name
"taskname", // <--- just some string for identification
6000, // <--- this is important - reserve enough stack otherwise strane things will happen
NULL, // <---- you can use this if you want to pass parameter to task function, NULL otherwise
0, // <--- 1 = normal priority, 0 = low priority, 2 = high priority
NULL, // <--- you probabbly don't need this (from what you have described)
1); // <--- core: 0 or 1 (Arduino by default runs its code on core 1)

You don't need to use both cores for that. I'd recommend confining your multi-task programming to a single core until you actually know what you're doing. Using two cores adds an extra level of complexity. Also, Core 0's watch dog timer is quite intolerant of tasks that don't play properly with the FreeRTOS task scheduler. Core 1's watch dog won't fire unless you hang a task with interrupts disabled.

It sounds like what you need is an ISR that triggers from the ABS pulses. The code in the ISR would do some minimal processing (say averaging the time interval between several pulses) that would smooth the noise and perhaps reduce the rate of data flow to the main code. The resultant processed data would be feed into a FreeRTOS Queue to be picked up by FreeRTOS task that's pending on it.

Start by reading Mastering the FreeRTOS Real Time Kernel. You can skip the first two chapters.

The Espressif Documentation contains sections that describe the few differences between Vanilla FreeRTOS as described the above book and the version implemented on the ESP32.

Also, please specify which version of the ESP32 Arduino Core you're using. There are major differences in many of the APIs between version 2.x and 3.x.

Seems to me that an application like this is unlikely to be "road-legal" without the proper documentation, testing, and certification by the appropriate agencies. Requirements that aren't within the reach of your average hobbyist.

Hi gfvalvo,

The main legal requirements are that it operates under all conditions, is clearly readable, and doesn't under-read. For type-approved vehicles, yes there is a lot of red tape, testing etc. that needs to be done as you say, but for prototypes, customs and other single-vehicle approved bikes, as long as it can be demonstrated as being accurate and not under-reading, it's legal. It's then up to the rider to ensure they are keeping to the posted limits... :slight_smile:

Hi gfvalvo,

Thanks for your advice. For info, I am using ESP-32 boards v3.0.1, and specifically telling Arduino my board is an Adafruit ESP32-S3 reverse TFT, the closest I can find to my specification of board, and the board I based my design on. Versions 3.0.0 and 3.0.2 don't seem to work with my board. 3.0.0 didn't work with the standard Adafruit ESP32-S3 reverse TFT board either.