DMX break detect
macdroid53 opened this issue · 21 comments
Sorry, more questions.
I'm studying the dmx.cpp and the example .ino.
I don't see anything specific about detecting the dmx break. Is this done by the uart driver?
I thought there was some issue that the default drivers couldn't actually detect the 88uS break?
(I've looked at so much info and code that I'm easily confused...and, of course, I have this code working...) :(
Yes, the break detection is coming from the UART driver in ESP-IDF.
I didn't know that there were issues regarding the driver. Probably someone implemented it wrong and so it didn't work out?
Or the IDF Team maybe made an update to the driver in the past and didn't communicate it.
I don't know, but i can say that with recent versions of IDF / Arduino this code works without problems on different DMX Consoles.
Where did you read this about the break detection?
The sparkfun dmx library was an attempt to do a simplified version of the claudeheintz did. In it he had a modified uart hal. See the readme here: https://github.com/claudeheintz/LXESP32DMX/tree/master/extras
It could be that was implemented when there was some issue and now it's fixed...
I don't think the 88uS would be a standard break time, so I wonder why default setting is making it work. (since, I don't think your code is doing anything to tell the driver to look for 88uS...) But, I haven't looked at the RS232 or DMX specs since I bit banged DMX receive in assembly on an arduino uno...um, 10 years ago?) :)
I'm getting multiple break events in the queue, so yes there is a problem with the break time. But I worked around this with my state machine.
I think the break detection in the UART driver just looks for a longer zero than a normal byte would be. That explains why I get multiple break events and is more robust, because the timing of the sender can also be out of spec and it will always lock on the first byte.
I know both libraries, the spark fun dmx library was not working robust for me and the one from claudeheintz with the modified Hal has to many pitfalls for my opinion...
Yes, I didn't like the idea of having to use modified hal code.
I'm looking at freertos more deeply at the moment because I am using ESP32 and have no need for the arduino environment. (in fact it may be the cause of the issue I'm having at power on in the system I'm building...but, that's a stretch, I really have no idea what's happening. )
I need to adjust the pwm output on 4 pins that are sync'ed with the 60Hz line voltage. And that works by itself but when I add the DMX input, sometimes it hangs on power up. And it hangs on the init of the DMX input.
I'm going to try a full freertos implementation with no Arduino loop() by creating a task that gets the DMX value and bumps the PWM duty cycle. Hopefully with that thread safe the hang will go away...maybe.
Getting the DMX values via the Read function uses a semaphore in the background so it should be thread safe out of the box
In fact the Arduino loop is just a function called by a thread:
you have the main function in Arduino, which inits the Arduino Environment and starts a loop task
extern "C" void app_main()
{
loopTaskWDTEnabled = false;
initArduino();
xTaskCreateUniversal(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, CONFIG_ARDUINO_RUNNING_CORE);
}
and the loop task then runs the setup()
function and in a loop resets the watchdog and calls the loop()
function.
extern "C" void app_main()
{
loopTaskWDTEnabled = false;
initArduino();
xTaskCreateUniversal(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, CONFIG_ARDUINO_RUNNING_CORE);
}
Yeah, I just whipped up the PWM stuff with tasks and got that working. Then I added this DMX code after looking at the dmx.cpp, thinking Read() would be thread safe.
But, I stumbled on two things. When I create the task that reads the dmx value and then updates the duty cycle. I'm not sure about the semaphores. Should the this function, in an endless loop, take a semaphore, call DMX::Read(int), give up the semaphore, etc.? (I'm really a noob with freertos...) :(
And, when I add #include dmx.h to my .c file it gaked because Arduino is not around and because it was defining a class, and a bunch of the typedefs (I'm assuming are in the arduino.h) aren't there.
Yeah, I tend to get over my head... ;)
Take a closer look at the read function:
xSemaphoreTake(sync_dmx, portMAX_DELAY);
uint8_t tmp_dmx = dmx_data[channel];
xSemaphoreGive(sync_dmx);
return tmp_dmx;
There is all you need implemented for thread safe access. No need to decorate the function in your own code. Except your are assigning the return value from read()
to a variable, which can be read by another task.
This code should run on plan ESP-IDF without problems, because there a no functions used from the Arduino library.
It gaked when I added dmx.h to my .c, and dmx.h has #include Arduino.h...I probably misunderstood what VSC was tell me. :(
Maybe I added i because of the bool data type in the DMX::IsHealty()
function. Just change the bool to uint8_t and you can remove the reference to the Arduino library.
It also doesn't like millis().
Oh yeah damn. Forgot about these...
When you add something to a library that you are not using in your own code, then this will happen.
So if you don't need the IsHealty()
function, you can simply remove it
Probably doesn't help I'm using it with a .c file...it seems upset about there being a class definition in dmx.h
AS for IsHealthy(), I'm not sure...do i need it? :)
The function is true if there were valid DMX frames detected within the last 500ms.
So if you are building a device where you need to do certain actions when the DMX signal is lost, this function is your go to goal.
For example when building a fog machine: if you lose the dmx signal the machine will spill out fog the whole time, because Read()
always return the last values. So you check if IsHealthy() == false
and you can manually set the pump to zero to prevent flooding the venue with fog.
Ok, sure. And in this case, I'm making new brains for an old Electrol dimmer. So, I might want to know if DMX is lost...
So, if I open dmx.h in VSC it shows 'class' as an unknown type. I'm missing something obvious me thinks. :(
You are using a cpp class in a c environment. Try to rename your main.c to
main.cpp
this should tell gcc to use the compiler for cpp which should sort out these problems
I had tried that. And I just put back a bunch of stuff I'd trialed and renamed it to .cpp.
Still no joy.
I've got to pick this up later (I'm leaving town for a couple days tomorrow and won't get to look at it until Sunday or Monday.
Thank you very much for you help and patience!!!
Because it's a static class, you can extract the functions out of it and use it in a normal c header environment. (ist just a class, because the ArduinoIDE wants it, but there are not technical reasons for this library to be a class)
Hi, back at it.
I have attempted to modify things for C only, ESP-IDF (i.e. no arduino) the current result is here: https://github.com/macdroid53/NoArduino.git
The only thing that doesn't compile is the call to millis(). I'm looking at the preferred way to do that in esp land. It appears to be esp_timer_get_time(), but I haven't been able to clear up the exact sequence of calls needed for that or if the timer it's creating will effect the uarts or PWM module.
I had to modify some things like the static defines in dmx.h and I added a bunch of .h files to the dmx.c and dmx.h...blunderbuss approach to get it to compile. :( (i.e. me shooting in the dark.)
At one point I was complaining about not finding bzero(), tried memset(). After I got memset() to compile, I switched back to bzero() and it compiled. (Could be me...could be VSC) It appears both memtest() and bzero() are supposed to be included without the need of a specific include file...couldn't verify... :O
I poked around some more on the esp_timer_get_time() and have successfully replaced millis()...I think.
I have added PWM for one channel and it appears to be working in cursory test. I pushed the latest to github.