Page 1 of 1

UART DMA Example

Posted: Sun Dec 29, 2019 7:33 am
by ConnorN
I was looking for some help with; understanding DMA, Serial, managing interrupts and blocking code.

I have an ESP32 DEVKITC v4 that I'm using to handle user Input both from hardware such as rotary encoders and from wifi. The ESP32 is also responsible for driving an 20x4 LCD to display a menu for the user to interact with.

I then have a Teensy 3.5 handling the pixel driving. It's handles generating the pixels frame, loading it to the buffer and outputting the signal. I'm running a modified version of the Adafruit Neopixel Library to control my TM1814 LED's

The trouble I'm having at the moment is the communication between the ESP32 and Teensy. The neopixel's code requires blocking in order to get right the timings for the LED driver IC's. while the ESP has interrupts used for the rotary encoder to keep an accurate count, both of these mess with the Serial communication. Here is my test code so far, it is a stripped back version of the final project's code to make it simple to identify problems and help build complexity slowly.

ESP_Transmitter

Code: Select all

#include <Rotary.h>

#define RTS_PIN 5

int previousArray;
int previousRGBW;

#define inPinA  35

//rotary acceleration variables
int rotaryTime;
volatile int counterA;
volatile int counterB;
byte enableAcceleration;
bool lockFlag = false;

Rotary rotaryA = Rotary(32, 33);

//teensy is expecting data <rgbwArrayToTeensy,rgbwToTeensy>
typedef struct ESPtransmit_t {
  char startMarker;
  int rgbwArrayToTeensy;
  char comma;
  int rgbwToTeensy;
  char endMarker;
};

typedef union Channel_Packet_t {
  ESPtransmit_t rgbwLED;
  byte ChannelPacket[sizeof(ESPtransmit_t)];
};

Channel_Packet_t blueOn;

void setup() {
  Serial.begin(9600);
  Serial2.begin(115200, SERIAL_8N1, 16, 17);

  while (!Serial);
  while (!Serial2);

  pinMode(RTS_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(RTS_PIN), Transmit_Data, RISING);
  attachInterrupt(digitalPinToInterrupt(32), rotateA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(33), rotateA, CHANGE);

}

void loop() {
  blueOn.rgbwLED = {'<', 2, ',', counterA, '>'};
}


void Transmit_Data() {
  noInterrupts();
  if (previousRGBW != blueOn.rgbwLED.rgbwToTeensy) {
    Serial2.write(blueOn.ChannelPacket, sizeof(ESPtransmit_t));
    Serial.println("send");
    previousRGBW = blueOn.rgbwLED.rgbwToTeensy;
  }
  interrupts();
}

void rotateA() {
  int speedMultiplier = 1;
  unsigned char result = rotaryA.process();
  if (lockFlag == false) {
    if (result == DIR_CW) {
      if (millis() - rotaryTime <= 10 && enableAcceleration == 0x01) {
        speedMultiplier = 7;

      }
      else if (digitalRead(inPinA) == HIGH) {
        speedMultiplier = 700;
      }
      counterA += speedMultiplier;
      rotaryTime = millis();
    }
    else if (result == DIR_CCW) {
      if (millis() - rotaryTime <= 10 && enableAcceleration == 0x01) {
        speedMultiplier = 7;

      }
      else if (digitalRead(inPinA) == HIGH) {
        speedMultiplier = 700;
      }
      counterA -= speedMultiplier;
      rotaryTime = millis();
    }
  }
}
Although this code mostly works I still get errors in transmission while turning the encoder quickly. This is where I'm hoping DMA might be a solution. If I understand DMA correctly I can use it and uart, Serial, to send data between the two MCU's and ignore the blocking delay code and interrupts. Then in the main loop poll DMA buffer and parse the received data but I'm unable to find a solid example of using DMA and Uart. Does anyone know if this will work and if so are there some examples you can link for me to check out?

I would prefer to find a software solution but As a hardware solution I was also looking at using this or an external SRAM that both MCU's have access to. To act as a buffer to store the user generated variables to be polled when appropriate.

I'm still fairly new to all this so any further questions are welcome and I want to know people's thoughts on this.