Reputation: 1
I'm using ESP32 Arduino IDE. I have one task at each core. In the core0 task I set up a timer interrupt that signals to the task (through the interruptCounter variable) to toggle a pin every 100 us. On core1 I have a task which sends some gibberish on bluetooth with the SerialBT.println("1") function.
I measured the pin with an oscilloscope. If I delete SerialBT.println("1") function, or use Serial.println("1"), or don't open the bluetooth serial monitor on Arduino IDE, it works fine and I get a nice 5 kHz square signal. However, if I open the serial monitor on the port associated with bluetooth, the pin toggles at very random intervals, so the frequency changes all the time.
I tried many things, but I still have no idea how one core affects the other in this code.
EDIT: After finding the run/stop button on the oscilloscope, I realised that it still mostly toggles at a regular 100us interval, but every after every few toggle it forgets to toggle for a few ms usually. The interval and the pulses between these glitches seem to be irrergular. So the problem remains, but I just added this info.
EDIT1: I also noticed the interruptCounter goes up like it's supposed to during these stops. So it's just the core 0 function somehow not responding to that.
#include "BluetoothSerial.h"
#include "esp_task_wdt.h"
volatile int interruptCounter = 0;
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
BluetoothSerial SerialBT;
//interrupt routine
void IRAM_ATTR onTimer() {
portENTER_CRITICAL_ISR(&timerMux);
interruptCounter++;
portEXIT_CRITICAL_ISR(&timerMux);
}
void setup() {
Serial.begin(2000000);
SerialBT.begin("ESP32"); //Bluetooth device name
Serial.println("The device started, now you can pair it with bluetooth!");
pinMode(26, OUTPUT);
disableCore0WDT();
disableCore1WDT();
xTaskCreatePinnedToCore(
adc_read, /* Function to implement the task */
"adc_read_task", /* Name of the task */
1024, /* Stack size in words */
NULL, /* Task input parameter */
1, /* Priority of the task */
NULL, /* Task handle. */
0); /* Core where the task should run */
xTaskCreatePinnedToCore(
bl_send, /* Function to implement the task */
"bl_send_task", /* Name of the task */
1024, /* Stack size in words */
NULL, /* Task input parameter */
2, /* Priority of the task */
NULL, /* Task handle. */
1); /* Core where the task should run */
}
void loop() {vTaskDelete(NULL); }
static void adc_read (void *pvParameters )
{
//launch the interrupt on core 0
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 100, true);
timerAlarmEnable(timer);
for(;;) {
if (interruptCounter > 0) {
portENTER_CRITICAL(&timerMux);
interruptCounter=0;
portEXIT_CRITICAL(&timerMux);
digitalWrite(26, !digitalRead(26));
}
}
}
static void bl_send (void *pvParameters )
{
for( ;; )
{
SerialBT.println("1");
}
}
Upvotes: 0
Views: 920
Reputation: 4762
Firstly, the ESP has other stuff to do, primarily running the WiFi and Bluetooth stacks (traditionally run on core 0, but I'm not sure if it's deterministic these days). Your task is sharing the CPU with a bunch of other real time critical code running there. This leaves you with rather few guarantees on when your application code will execute. If you set the priority of your task to be higher than every other task (including the WiFi and BT stacks) then you give it a chance. Note that in such case you cannot run busy-loops or blocking I/O operations, as those will starve the other tasks.
Secondly, even if you bump your task's priority, you need to tell FreeRTOS to notify your task immediately after the ISR terminates. Incrementing a counter (and polling for it in a loop) is not a task notification mechanism. Use a semaphore, that is precisely what it's intended for. Don't forget to call portYIELD_FROM_ISR
with relevant value when ending the ISR to trigger immediate task switching.
Third, ISR latency in ESP32 is a bit iffy, apparently you need to account for at least 2 us to begin with.
Upvotes: 1