Issues Calling Functions from Freertos Task (ESP32)

Currently I am having issues with a program running a freertos program. The purpose of the program is to control a stepper motor as well as an led. Implementing the motor control without microstepping does not have any issues as the two tasks take no parameters and call no functions.

However, when I introduce microstepping which requires two nested functions to be called by the move_routine task, the program will not do anything (no led flashing, no motor turning) when it did before. Does anyone have any solutions for this or any reasons on why this shouldn’t work? From what I can see it should be fine to call a function from a freertos task.


#include <Arduino.h>
#include <Stepper.h>

/*================PIN DEFINITIONS================*/
#define LEDC_CHANNEL_0  0
#define LEDC_CHANNEL_1  1
#define LEDC_CHANNEL_2  2
#define LEDC_CHANNEL_3  3

const int A1A =  14;
const int A1B = 27;
const int B1A = 26;
const int B2A = 25;
const int ledPin = 33;

/*================VARIABLE DEFINITIONS================*/
int stepnumber = 0;
int Pa; int Pb;

const int stepsPerRev = 200;

Stepper myStepper(stepsPerRev, 14,27,26,25);


/*================Function Definitions================*/
  
//Analogwrite using LEDC capabilities
  void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {

    //calculation of duty cycle
    uint32_t duty = (4095/valueMax)*min(value, valueMax); 
    ledcWrite(channel,duty);
  }

  
  
void move(int stepnumber, int MAXpower, int wait) {

    Pa = (sin(stepnumber*0.098174)*MAXpower);
    Pb = (cos(stepnumber*0.098174)*MAXpower);

    if (Pa>0)
    { 
      ledcAnalogWrite(LEDC_CHANNEL_0,Pa);
      ledcAnalogWrite(LEDC_CHANNEL_1,0);
    }
    else
    {
      ledcAnalogWrite(LEDC_CHANNEL_0,0);
      ledcAnalogWrite(LEDC_CHANNEL_1,abs(Pa));
    }
    
    if (Pb>0)
    {
      ledcAnalogWrite(LEDC_CHANNEL_2,Pb);
      ledcAnalogWrite(LEDC_CHANNEL_3,0);
    }

    else
    {
      ledcAnalogWrite(LEDC_CHANNEL_2,0);
      ledcAnalogWrite(LEDC_CHANNEL_3,abs(Pb));
    }
}
 


void move_routine(void *parameters) {
  while(1) {
    for (int i=0; i<3199; i++)
    {
      stepnumber++;
      move(stepnumber,255,250);
      }

      vTaskDelay(3000/portTICK_PERIOD_MS);
      for (int i=0; i<1599; i++)
      { 
        stepnumber--;
        move(stepnumber,255,1000);
        }

      vTaskDelay(3000/portTICK_PERIOD_MS);
  }
}

void led_task(void * parameters){
  while(1){
    digitalWrite(ledPin, HIGH); 
    vTaskDelay(500/portTICK_PERIOD_MS); 
    digitalWrite(ledPin, LOW); 
    vTaskDelay(500/portTICK_PERIOD_MS);
  }
}

void setup(){
  myStepper.setSpeed(60);
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);


  xTaskCreatePinnedToCore(
    move_routine, 
    "Move Routine",
    8192,
    NULL,
    1,
    NULL, 
    1
  );


  xTaskCreatePinnedToCore(
    led_task, 
    "LED Task", 
    1024, 
    NULL, 
    1, 
    NULL, 
    1
  );

}

void loop(){

}

When it is “not doing anything” - what is it doing? If that makes sense. That is, if you pause the application in the debugger - what is executing? Maybe an assert()? Maybe a stack overflow?

Hi @finsmy,

Looking at your code, my first thought is that the stack size given to the move_routine task isn’t large enough, causing the task to run out of stack space when calling the move function - I’m not terribly familiar with the ESP32 port to arduino, but I imagine that it uses some underlying version of ESP-IDF, which should output an error and restart if a stack overflow is detected. Try doubling its stack size and see if the issue still persists or try reading the serial output from the device to see if its outputting any error messages from ESP-IDF - there may be additional steps to actually have the device output the underlying ESP-IDF output (I’m using this as reference Arduino as an ESP-IDF component — Arduino-ESP32 2.0.2 documentation.

Additionally, if these steps are time critical, I would recommend using vTaskDelayUntil (FreeRTOS - A FREE Open Source Simple RTOS Scheduler API documentation) instead of vTaskDelay. Or use a FreeRTOS software timer (FreeRTOS - RTOS software timer functionality and features description). Even better would be to use a hardware timer interrupt.

Hi there, when I say does nothing I mean no normal functioning of either the motor or the LED. I should check the serial monitor though

I will have a try at increasing the allocated stack size and see if that helps. Along with reading the serial output hopefully something turns up.

Sounds good - feel free to continue to reach out if you are still running into problems. We will be able to help you out more with output logs.