I would like to build a DMX backup box. I. e. I want to read DMX signals from one channel (RX) and write DMX signals to another channel (TX). For this project I would like to use an ESP32-C6 but ran into some difficulties.
I tried esp_dmx but wasn't able to get the program execute anything after dmx_driver_install(...) . It feels like the controller "hangs", but it might also be some FreeRTOS magic I don't understand.
Therefore I switched over to EasyDMX. With this library I could receive DMX values, but I had to add delay(500) at the end of the main loop. With different delay times the DMX values were assigned to the wrong channels.
Transmitting DMX with EasyDMX worked, but I wasn't able to set more than one channel. Any additions to the program (even as small as setting an LED output pin) led to a state where I couldn't set any DMX channel at all.
Another try with the DMX Transceiver library showed me that this library requires avr/io.h and avr/interrupt.h (at least in the example), so I wasn't able to compile it at all.
I am using ArduinoIDE under Linux. My embedded programming skills are rather "basic". Now I am stuck and would be glad if anyone might help me to make progress with reading/writing DMX with my ESP32-C6.
Thank you, Railroader, for your response and your guidance! Yes, I missed to mention: The code mentioned before was taken from the original examples found in the according Github repos. I modified it slightly to match my pinning (Rx=17, Tx=16) and set the DMX channels different from the example. For the sake of readability of this thread I removed some comments regarding copyright and circuit before posting:
/*
* Credits to EasyDMX https://github.com/tesa-klebeband/EasyDMX
* Copyright (c) 2024 tesa-klebeband
* - see full copyright note in the original projekt on Github
*/
#include <Arduino.h>
#include <easydmx.h>
// Create an instance of the EasyDMX class, so we can use its functions
EasyDMX dmx;
void setup() {
Serial.begin(115200);
dmx.begin(DMXMode::Transmit, DMXPin::NoRx, 16);
}
void loop() {
// Set channel 2 to 170
dmx.setChannel(2, 170);
delay(1000);
// Set channel 1 to 200
dmx.setChannel(1, 200);
}
Channel 2 is set to 170, channel 1 remains 0 (checked by means of an oscilloscope on the Tx pin).
This is the simplest example. I am trying not to mess up this thread with superfluous information. Therefore, please let me know when you are interested in the code of my tries with esp_dmx as well.
I am at the very beginning of this project. Therefore I tried to manage sending and receiving with minimal examples before integrating them into a more complex project. The code posted above is just the transmit example. Do you see a reason why not assigning the receive pin might cause the code to fail in this case?
void setup() {
Serial.begin(115200);
/**
* Start the DMX driver in transmit mode on Serial2 (pin 17)
* The MAX485's DI pin should be connected to the TX pin of the ESP32
* and RE and DE should be connected to 3.3V.
*/
dmx.begin(DMXMode::Transmit, DMXPin::NoRx, DMXPin::Serial2Tx);
...
I wrote Dmx_ESP32.
Transmission on an ESP32 is fairly straightforward, reception can be a different matter. Most libraries use the Serial event Queue to detect the break, Dmx_ESP32 uses the RMT idle callback.
On ESP32 core version 3.x.x the minimum requirement is 3.3.x
I don't own a C6 and so i haven't tested it on that particular board, but it compiles just fine.
For that you do need 2 separate UARTs. I think the ESPC6 does have them, but i am not sure if you can assigned exposed pins to both. As i said, i don't own one. EDIT: Of course all peripheral pins are free assignable on all ESP32 boards.
Most DMX libraries use the same trick to generate the frame reset break, switching the baud-rate from 250kbps to a much lower rate (less than 100kbps) and sending a '0'. With the baud-rate switching you can not do reception on that same UART.
I don't know for that specific board. I was just referring to the example code. It uses pin 17 for Tx where to OP used pin 16. I was pointing out the difference since OP said they started with the example code.
Thanks @Deva_Rishi!
In order to match my hardware, I simply adapted two lines in the transmit example of your Dmx_ESP32 project: #define TX_PIN 16 (instead of 32) #define DMX_PORT &Serial1 (instead of &Serial1)
and copied the files Dmx_ESP32.cpp and Dmx_ESP32.h to the folder of Dmx_transmit_example.ino.
Transmission works perfect, the loop is executed every 45 ms. [edit] I measured the cycle time on the wrong pin. The corect cycle time is 22.8 ms[/edit]
My next step will be to combine receive + transmit in one project.
For that as i said before (i think) you will need to use 2 different UARTs.
Now i am not fully familiar with the C6, but from the datasheet is says it has 2 UARTs and 2 LP(Low Power) UARTs, but to be honest i don't actually know how these are implemented in the Arduino core, since there is also the USB TX/Rx available.
That would be instead of '&Serial2' I actually suggest you keep it the way it was. Peripherals are freely assignable to pins on an ESP32, and with '&Serial2' it compiles, which probably suggests it works, but i am curious to hear from you about that. (&Serial3 doesn't, Serial3 is not defined, so i figure Serial2 is also a normal UART)
The reception example uses Serial1. In a way it really doesn't matter which is which, but they can not be the same.
That should be near 25ms. 513 bytes (of 11 bits, so 5643 bits at 250.000 bps comes down to 22,572 ms + the breaktime. I am not even sure what you mean by that. How did you measure this ?
I suspect the USB is defined as 'Serial' (UART0), but i haven't looked through the datasheet and the implementation in the core that closely, so i also don't know how to easily access the LP-UARTs. They would suffice for both transmission and reception, though their FIFO is quite a bit smaller.
As i said the datasheet implies 2 more Low Power UARTs, which theoretically could also be used.
The normal procedure is to download the zip file, extract it in you sketchbook->libraries folder and the main folder will then have the examples folder which will make examples show up from the IDE File->Examples. (once you close and re-open the IDE)
Currently I am limited to "LED debugging", as the serial monitor doesn't work for me with this project (no idea why). My next try would still be to test the receive example. Maybe this one will operate with Serial2(?). As you see, my understanding of ESP32 UART is very limited.
Ok, well what if you remove the debug messages and try each with '&Serial'
There are 2 UARTs on the C6 but if one is used for USB then there aren't 2 available for reception and transmission, which would be a problem, since 2 separate UARTs are required.
I replaced #define DMX_PORT &Serial2 with #define DMX_PORT &Serial and removed all Serial.print(ln) lines. The project does not compile because...
~/Arduino/DMX/dmx-esp32/Dmx_transmit_Serial/Dmx_transmit_Serial.ino:14:58: error: no matching function for call to 'dmxTx::dmxTx(HWCDC*, int, int, int, int)'
14 | dmxTx dmxSend(DMX_PORT, TX_PIN, TX_ENABLE, LED_GREEN, LOW);
| ^
In file included from ~/Arduino/DMX/dmx-esp32/Dmx_transmit_Serial/Dmx_transmit_Serial.ino:1:
~/Arduino/DMX/dmx-esp32/Dmx_transmit_Serial/Dmx_ESP32.h:106:5: note: candidate: 'dmxTx::dmxTx(HardwareSerial*, int8_t, int8_t, int8_t, int8_t)'
106 | dmxTx(HardwareSerial* port, int8_t pinTx, int8_t pinEnable = -1, int8_t pinToggle = -1, int8_t ledOn = HIGH);
| ^~~~~
~/Arduino/DMX/dmx-esp32/Dmx_transmit_Serial/Dmx_ESP32.h:106:27: note: no known conversion for argument 1 from 'HWCDC*' to 'HardwareSerial*'
106 | dmxTx(HardwareSerial* port, int8_t pinTx, int8_t pinEnable = -1, int8_t pinToggle = -1, int8_t ledOn = HIGH);
| ~~~~~~~~~~~~~~~~^~~~
~/Arduino/DMX/dmx-esp32/Dmx_transmit_Serial/Dmx_ESP32.h:102:7: note: candidate: 'constexpr dmxTx::dmxTx(const dmxTx&)'
102 | class dmxTx {
| ^~~~~
~/Arduino/DMX/dmx-esp32/Dmx_transmit_Serial/Dmx_ESP32.h:102:7: note: candidate expects 1 argument, 5 provided
~/Arduino/DMX/dmx-esp32/Dmx_transmit_Serial/Dmx_ESP32.h:102:7: note: candidate: 'constexpr dmxTx::dmxTx(dmxTx&&)'
~/Arduino/DMX/dmx-esp32/Dmx_transmit_Serial/Dmx_ESP32.h:102:7: note: candidate expects 1 argument, 5 provided
exit status 1
Compilation error: no matching function for call to 'dmxTx::dmxTx(HWCDC*, int, int, int, int)'
Additionally I have to make a correction:
Last time I mentioned the Rx eample was working with Serial1. I was just too happy to see the serial monitor output "DMX Configured". Now I have to admit that this is the latest console output. I should expect another line "DMX reception Started", but it doesn't turn up. Now I inserted digitalWrite(LED_WHITE, HIGH) right at the beginning of the main loop() and removed the analogWrite(LED_WHITE... statement, but the according pin did not go high. Which means to me that the main loop is never entered.
Yeah so Serial is not a definable UART. it is just USB-Serial (or just, i mean it has merit having one, but it is not usable for DMX reception or transmission)
It does compile when you use
#define DMX_PORT &Serial0
Also the defined GPIO RX-pin in the example doesn't exist on the C6, so i guess you should try a different pin.
Well it should be either one or the other. If it doesn't do anything then it must have crashed.
Can you add a
delay(100);
after that statement to given some time to transmit either of those statements.
also you can try the basic receive example with debug level 'verbose'
There will be some warning coming up about the sharing of the pin between the RMT and the UART and the freeing of the bus not being supported anymore.
You can also try using 2 separate pins for the UART and the RMT and tie them together with a 1K current limiting resistor in between just to be safe.
It does feel a little unpractical to do this without having a C6 myself, i did order an S2 the other day for a different reason, but no C6 on the way either.
Edit: Just in case, which core version are you using ?
#define DMX_PORT &Serial0 did the job . Thank you very much!
I am using a board (with RS485 interfaces), where the receive pin is 17. I chose this pin, because it is marked as Rx pin in the ESP-C6 data sheet. I didn't see a warning regarding the combination of UART and RMT pin - which doesn't mean there is none. Should I have a closer look (and where)?
Once I tried to assign pin 20 to RMT, but the program still crashed.
With additional delays and the output of the core version my setup() function is now
void setup() {
Serial.begin(500000);
Serial.println("\n");
Serial.println("DMX Reception using RMT for break detection.");
uint32_t cv = ESP_ARDUINO_VERSION; // added to find out core version
Serial.printf("ESP32 Core Version: %d.%d.%d\n", cv >> 16, (cv >> 8) & 0xFF, cv & 0xFF);
if (!dmxReceive.configure()) { // configures and starts the UART (with default parameters)
Serial.println("DMX Configure failed.");
}
else {
Serial.println("DMX Configured.");
}
delay(100); // delay increased from 10, just in case
if (dmxReceive.start()) {
Serial.println("DMX reception Started");
delay(100); // added to give more time for serial output
}
else {
Serial.println("DMX aborted");
delay(100); // added to give more time for serial output
}
pinMode(LED_WHITE, OUTPUT); // the indicator LED
}
The console prints
DMX Reception using RMT for break detection.
ESP32 Core Version: 3.3.6
DMX Configured.
So I have core version 3.3.6, but the program still crashes right after DMX Configured.
Below you find an extract of the verbose debugging output.
(...)
DMX Configured.
Guru Meditation Error: Core 0 panic'ed (Stack protection fault).
Detected in task "BreakDetector" at 0x40035b92
Stack pointer: 0x40815a80
Stack bounds: 0x40815abc - 0x408160b0
(...)