AutoMecUA / AutoMec-AD

Autonomous RC car with the help of ROS Noetic and ML.
GNU General Public License v3.0
15 stars 2 forks source link

Explore EPS32 2 core programs #169

Closed manuelgitgomes closed 1 year ago

manuelgitgomes commented 2 years ago

Explore how ESP32 runs with its 2 cores.

andrefdre commented 2 years ago

This is a example code that uses the 2 cores of the esp32 which I didn't manage to try it out, which can be used as a guide. but basically it was a encoder tester that reads the 6 signlas from the encoder and counts it's rotations with the interrupts in one core and the data serial in the other

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define ChannelA 4
#define ChannelA_negatted 5
#define ChannelB 13
#define ChannelB_negatted 16
#define ChannelZ 17
#define ChannelZ_negatted 18

#define SCL 22
#define SDA 21

void attachInterruptTask(void *pvParameters);
void isr();

volatile long encoderPos = 0;
volatile long encoderPosInversed = 0;
volatile long FullRotations = 0;

TaskHandle_t Task1;
TaskHandle_t Attach_Interrupt_Task;

void setup() {
  Serial.begin(115200);

  //Create the two different takst to each Core
  //Core 0
  xTaskCreatePinnedToCore(
    Task1code, /* Function to implement the task */
    "Task1", /* Name of the task */
    10000,  /* Stack size in words */
    NULL,  /* Task input parameter */
    0,  /* Priority of the task */
    &Task1,  /* Task handle. */
    0); /* Core where the task should run */

  //Core 1
  xTaskCreatePinnedToCore(
    attachInterruptTask,
    "Attach_Interrupt_Task",
    2000,
    NULL,
    6,
    NULL,
    0);

  //Declare the Pin functionality
  pinMode(ChannelA, INPUT);
  pinMode(ChannelA_negatted, INPUT);
  pinMode(ChannelB, INPUT);
  pinMode(ChannelB_negatted, INPUT);
  pinMode(ChannelZ, INPUT);
  pinMode(ChannelZ_negatted, INPUT);
  attachInterrupt(digitalPinToInterrupt(ChannelA), doEncoderA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ChannelB), doEncoderB, CHANGE);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  delay(2000);
  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 10);
  // Display static text
  display.println("Hello, world!");
  display.display();
  delay(2000);
}

void attachInterruptTask(void *pvParameters) {
  //Attach Interrupt in core 0
  attachInterrupt(digitalPinToInterrupt(ChannelZ), isr, RISING);
  Serial.println("Task 1 Running");
  vTaskDelete(NULL);
}

void Task1code( void * parameter) {
  for (;;) {
    //Display in the LCD Screen
    display.clearDisplay();
    display.setCursor(0, 10);
    display.print("Pos:");
    display.print(encoderPos);
    display.setCursor(2, 10);
    display.print("PosInverted:");
    display.print(encoderPosInversed);
    display.setCursor(3, 10);
    display.print("Full Rotations:");
    display.print(FullRotations);

    //Send information to the Serial Port
    //  Serial.print("POS:");
    //  Serial.print(encoderPos);
    //  Serial.print("  ");
    //  Serial.print("POSINVERTED:");
    //  Serial.print(encoderPosInversed);
    //  Serial.print("  ");
    Serial.print("FullRotations:");
    Serial.print(FullRotations);
    Serial.print("  ");
    Serial.print("EncoderA:");
    Serial.print( digitalRead(ChannelA));
    Serial.print("  ");
    Serial.print("EncoderB:");
    Serial.print( digitalRead(ChannelB));
    Serial.print("  ");
    Serial.print("EncoderAInversed:");
    Serial.print( digitalRead(ChannelA_negatted));
    Serial.print("  ");
    Serial.print("EncoderBInversed:");
    Serial.print( digitalRead(ChannelB_negatted));
    Serial.print("  ");
    Serial.print("EncoderZ0:");
    Serial.print( digitalRead(ChannelZ));
    Serial.print("  ");
    Serial.print("EncoderZ0Inversed:");
    Serial.println( digitalRead(ChannelZ_negatted));
  }
  vTaskDelete(Task1);
}

void loop() {
}

void doEncoderA()
{
  if (digitalRead(ChannelA) != digitalRead(ChannelB)) {
    encoderPos++;
  } else {
    encoderPos--;
  }
  if (digitalRead(ChannelA_negatted) != digitalRead(ChannelB_negatted)) {
    encoderPosInversed++;
  } else {
    encoderPosInversed--;
  }
  if (digitalRead(ChannelZ) == 1) {
    FullRotations++;
  }
}

void doEncoderB()
{
  if (digitalRead(ChannelA) == digitalRead(ChannelB)) {
    encoderPos++;
  } else {
    encoderPos--;
  }
  if (digitalRead(ChannelA_negatted) == digitalRead(ChannelB_negatted)) {
    encoderPosInversed++;
  } else {
    encoderPosInversed--;
  }
  if (digitalRead(ChannelZ) == 1) {
    FullRotations++;
  }
}

void IRAM_ATTR isr()
{
  FullRotations++;
}

Maybe it can give some lights about this issue.

inaciose commented 2 years ago

As far as know the encoder doesnt have six signals it have only two. Edited, because after another checking i notice that the encoderA and encoderB are misleading, because both drive the same variable.

andrefdre commented 2 years ago

This code is for another project but it uses both cores and was just an example. This was suppose to test the functionallity of a general encoder.

inaciose commented 2 years ago

You need to make serveral changes to the code to use it with the current encoder with full resolution. If you try it as it is i belive that will give strange results!

andrefdre commented 2 years ago

The code was more to show using the 2 cores of the esp32 more than the encoder cause that is for TTL encoders and not magnetic. Now that I read my post again maybe it's misleading. That code was not for automec, was something I had Wich was using 2 cores and was an example for @PedroMaia21 to search about using the 2 cores in automec.

PedroMaia21 commented 2 years ago

The research made by me brought the following conclusions:

Non-internal interrupt slots in both CPU cores are wired to an interrupt multiplexer, which can be used to route any external interrupt source to any of these interrupt slots.

Allocating an external interrupt will always allocate it on the core that does the allocation.

Freeing an external interrupt must always happen on the same core it was allocated on.

Disabling and enabling external interrupts from another core is allowed.

Multiple external interrupt sources can share an interrupt slot by passing ESP_INTR_FLAG_SHARED as a flag to [esp_intr_alloc()]

Care should be taken when calling [esp_intr_alloc()] from a task which is not pinned to a core. During task switching, these tasks can migrate between cores. Therefore it is impossible to tell which CPU the interrupt is allocated on, which makes it difficult to free the interrupt handle and may also cause debugging difficulties. It is advised to use [xTaskCreatePinnedToCore()] with a specific CoreID argument to create tasks that will allocate interrupts. In the case of internal interrupt sources, this is required.

Source