Я искал помощи; понимание DMA, последовательного порта, управления прерываниями и кода блокировки.
У меня есть ESP32 DEVKITC v4, который я использую для обработки пользовательского ввода как с оборудования, такого как поворотные энкодеры, так и с Wi-Fi. ESP32 также отвечает за управление ЖК-дисплеем 20x4 для отображения меню, с которым пользователь может взаимодействовать.
Затем у меня есть Teensy 3.5, обрабатывающий пиксельное вождение. Он обрабатывает создание кадра пикселей, загрузку его в буфер и вывод сигнала. Я использую модифицированную версию Adafruit Neopixel Library для управления своими светодиодами TM1814.
Проблема, с которой я столкнулся на данный момент, - это связь между ESP32 и Teensy. Код neopixel требует блокировки, чтобы получить правильные тайминги для ИС драйвера светодиода. в то время как ESP имеет прерывания, используемые поворотным энкодером для точного подсчета, оба из них мешают последовательной связи. Вот мой тестовый код, это урезанная версия окончательного кода проекта, чтобы упростить выявление проблем и помочь медленно наращивать сложность.
ESP_Transmitter
#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();
}
}
}
ПОДРОСТКА3.5_RECEIVER
// include the library code:
#include <Adafruit_NeoPixel.h>
//number of LEDs in Strip
int NUM_LEDS = 52;
//data and clock pin RGB
#define DATA_PINA 11
#define RTR_PIN 28
uint32_t amp = ((uint32_t)63 << 24) | ((uint32_t)63 << 16) | ((uint32_t)63 << 8) | 63;
Adafruit_NeoPixel pixelsA(NUM_LEDS, DATA_PINA, NEO_WRGB + NEO_KHZ800);
struct Received_Data_t {
char startMarker;
int rgbwArrayFromESP;
char comma;
int rgbwFromESP;
char endMarker;
};
union Channel_Packet_t {
Received_Data_t rgbwLED;
byte ChannelPacket[sizeof(Received_Data_t)];
};
Channel_Packet_t LEDon;
//apeture controls
int apeture = NUM_LEDS;
int apeturePosition = NUM_LEDS / 2;
//RGB Sub Menu Variables
int rgbArraySelector;
uint8_t subRed;
uint8_t subGreen;
uint8_t subBlue;
uint8_t subWhite;
uint8_t rgbwArray [] = {subRed, subGreen, subBlue, subWhite};
const byte numChars = sizeof(Received_Data_t);
char receivedChars[numChars];
int rgbwFromESP = 0;
boolean newData = false;
void setup() {
Serial1.setTX(26);
Serial1.setRX(27);
Serial1.begin(115200);
Serial.begin(9600);
while (!Serial);
while (!Serial1);
pixelsA.begin(); // INITIALIZE NeoPixel strip object
//clear the LEDS
pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
pixelsA.show();
pinMode(RTR_PIN, OUTPUT);
digitalWrite(RTR_PIN, LOW);
}
void loop() {
Read_to_Receive(); //activate transmission
recvWithStartEndMarkers(); //read buffer
if (newData == true) {
parseData();
showParsedData();
newData = false;
}
}
void LED_clear() {
pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
pixelsA.show();
}
void LED_RGBW() {
pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition, apeture / 2);
pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition - (apeture / 2), apeture / 2);
pixelsA.show();
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial1.available() > 0 && newData == false) {
rc = Serial1.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = rc; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
receivedChars[ndx] = rc;
ndx++;
recvInProgress = true;
}
}
}
//============
void Read_to_Receive() {
pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition, apeture / 2);
pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition - (apeture / 2), apeture / 2);
digitalWrite(RTR_PIN, LOW);
pixelsA.show();
digitalWrite(RTR_PIN, HIGH);
//wait for ESP to transmit
delay(1);
}
//============
void parseData() { // split the data into its parts
for (uint8_t k = 0; k < sizeof(Received_Data_t); k++) {
LEDon.ChannelPacket[k] = receivedChars[k];
}
rgbArraySelector = LEDon.rgbwLED.rgbwArrayFromESP;
rgbwFromESP = LEDon.rgbwLED.rgbwFromESP;
rgbwArray[rgbArraySelector] = rgbwFromESP;
}
//============
void showParsedData() {
Serial.print("Array ");
Serial.println(rgbArraySelector);
Serial.print("Intensity ");
Serial.println(rgbwFromESP);
}
Хотя этот код в основном работает, я все равно получаю ошибки при передаче при быстром повороте кодировщика. Вот где я надеюсь, что DMA может быть решением. Если я правильно понимаю DMA, я могу использовать его и uart, Serial, для передачи данных между двумя MCU и игнорировать код блокировки и прерывания. Затем в основном цикле опрашиваем буфер DMA и анализируем полученные данные, но я не могу найти убедительного примера использования DMA и Uart. Кто-нибудь знает, будет ли это работать, и если да, то есть ли примеры, на которые вы можете ссылаться, чтобы я мог их проверить?
Я бы предпочел найти программное решение, но в качестве аппаратного решения я также искал использование этого или внешняя SRAM, к которой имеют доступ оба MCU. Действовать как буфер для хранения сгенерированных пользователем переменных для опроса при необходимости.
Я все еще новичок во всем этом, поэтому любые дополнительные вопросы приветствуются, и я хочу знать, что думают люди по этому поводу.