Pico-DMX icon indicating copy to clipboard operation
Pico-DMX copied to clipboard

Support for differential outputs (no RS-485 module necessary)

Open GlenHertz opened this issue 2 years ago • 7 comments

Fantastic project! Is it possible to add support for sending differential outputs in order to not have to purchase an RS-485 module? As far as I can tell using 2 pins to generate the differential signals (one the negation of the other) should work for DMX signals and the PIOs should be able to send them simultaneously. The RP2040 is using 3.3V logic and for the RS-485 receivers I've looked at they take ±200 mV for an ON/OFF bit so it should work. I'd like to use something like the RP2040 XIAO for a tiny DMX controller (send only).

GlenHertz avatar Apr 19 '22 20:04 GlenHertz

I absolutely love the idea. I'm also very eager to actually try this out but due to being in the hot phase of building a house, I didn't find the time yet. So, I'm just sharing my thoughts: If this works (and I assume it might), it would be amazing. Sacrificing an extra pin to get rid of one RS-485-driver: Why not? Of course the current should be limited and it might not be standard-compliant but as long as it can drive "most" fixtures out there: great! On the software side: The current code of this project generates the DMX signal by having a PIO state machine that drives the GPIO pin (singular) controlled by the logic in the PIO program. One PIO state machine can drive one Pin per step plus one "side set" pin. However, that "side set" functionality is used as part of the logic (and not sent to any GPIO). Therefore, the "side set" pin cannot be used to drive the pin's inverse signal to another pin. One could of course double the state machine's clock and set two pins in two steps but that would mean they are not perfectly in sync.Setting up an interrupt to drive another GPIO pin when one changes will most probably also be too late. To conclude, I would say that with the current implementation of DMX sending, it might not be easily possible.

But here comes the big BUT: For the DMX project of mine (in which is use Pico-DMX's code for DMX input), the DMX signal generation works like this: Put a complete DMX frame as bits into memory, 16 universes in parallel (= The actual bit pattern is generated by C-code on the CPU). The PIO is "simply" used to push the bits out the GPIO pins in a precisely timed manner. The PIO does nothing more than reading the data from the memory (with the help of the DMA, of course) and copying it to the GPIO output register, independent of the CPU's load or timing. Since the bit pattern is generated by the CPU beforehand, one can easily also generate the inverse of the pattern before sending it out. This way, I would assume what you plan to do is achievable. And that with 8 DMX universes at the same time if required and in case enough GPIO pins are available on your board.

As I said, I would love to check myself if this approach works. In the meantime, here is the code to the approach I described above: https://github.com/OpenLightingProject/rp2040-dmxsun/blob/main/src/localdmx.cpp#L37 https://github.com/OpenLightingProject/rp2040-dmxsun/blob/main/src/localdmx.cpp#L174 https://github.com/OpenLightingProject/rp2040-dmxsun/blob/main/src/tx16.pio

kripton avatar Jun 14 '22 20:06 kripton

Oh, what would probably also work: Have TWO PIO state machines per DMX universe, one generates the "positive signal", the other one the inverse. If both operate on the same data, have the same clock and are started simultaneously (not by the CPU as instructions but maybe via an interrupt?) that might work as well

kripton avatar Jun 14 '22 20:06 kripton

An RS485 transmitter is meant to drive a minimum 1.5V differential signal into a 54ohm load. Whilst the Pico will put out a 3.3V differential signal, the drive current may be limited (max 12mA according to the datasheet, and max 50mA for all GPIOs).

Yes an RS485 receiver is required to be sensitive enough for a 200mV differential signal, but launching a low signal onto a long line is possibly not the best plan. It would offer a cheap solution though.

6by9 avatar Jun 14 '22 21:06 6by9

If a per-GPIO-limit is a problem, one could try to use two GPIOs for "positive signal" and another two for "inverse signal". Of course, 50mA will stay the limit for the total current but it might make the transmission more reliable. And we should abandon the multi-universe approach then ;)

kripton avatar Jun 16 '22 12:06 kripton

One of my hardware colleagues here at Pi Towers is also involved in lighting for various theatres in the area, so I've had a quick chat with him.

The spec 12mA is fairly conservative, and that is for the output voltage to reach the specified VOH and VOL voltages on the pins.

If driving the two sides of the line from GPIOs, then you're looking at 3.3V being driven down the line, through the 100ohm terminator, and coming back again. 3.3 / 100 = 33mA.

Put a 47ohm resistor in series with each leg before putting it on the wire, you halve the voltage down the line, but also halve the current to 16..8mA. It also gives some protection the output against shorts, and acts as a terminator for any reflections coming back up the line. If driving a 54ohm load then you'd be looking at a 108ohm load total, which would want 30.5mA. You may not achieve the full 1.5V of the spec, but it should be pretty reasonable.

The current per universe is constant as whenever one GPIO is sourcing, the other is sinking. If running at 16.8mA, then 4 universes be plausible at 67mA total. Running 8 universes without buffering may be pushing it.

Looking at your rp2040-dmxsun project, an output board that takes 4 GPIOs and produces 2 universes without buffers would be simple for a reduced cost board. You obviously have very little ESD or other protection on those ports compared to an RS485 transceiver, but it would work in many situations.

6by9 avatar Jun 16 '22 13:06 6by9

I can confirm that this is working. I implemented it the way I proposed in the dmxsun project (= generating the bit patterns "in software" = by the CPU) and having it simply clocked out via one PIO. = Not how Pico-DMX does it): https://github.com/kripton/rp2040-dongle/tree/DirectDifferentialOutput

I have only one Cameo ThunderWash 100 RGB connected at the moment and it actually already works when only GND and XLR pin 3 (positive) is connected. The fixture flickers from time to time but it's really rare. Connecting the XLR pin 2 (negative) makes it rock solid. no RS-485 driver used on my board.

Ideally, there would be a video here as proof but it's too messy around here right now, so a picture needs to be enough (you need to believe me that the fixture is connected to the XLR cable one can see in the picture): IMG_20220622_210438_crop

So, yes, regarding the rp2040-dmxsun project, this would be a very cheap output-board. ESD and protections might not be toooo bad (Rs in series to the data lines, Z-diodes to clamp the voltage, ...). It might not meet the DMX512-standard but as the OP said, it might help in some situations and is really cheap.

Hopefully I can provide some oscilloscope-screenshots comparing what's on the line with the direct GPIO outs vs. one RS-485 driver.

I'm still thinking about this feature (differential output) could be implemented in Pico-DMX's current implementation but in my head, it's not easy. Yes, as I already mentioned, using two State-Machines per universe might work. I'd like to try it out at least ;)

kripton avatar Jun 22 '22 19:06 kripton

Just discovered this library (havent used it yet) but it looks super exciting!

As for the whole trying to avoid using an RS485 driver, I don't see why one would really need to do so. Max485 chips are incredibly cheap on Aliexpress and even on amazon aren't too bad. Using the right chip will help you avoid implementation issues down the line when lights are flickering because your Pi can't put out enough power.

That said, the fact that you figured it out without said chip is quite impressive none the less and definitely an option for the absolute easiest option.

drewTheNerd avatar Jun 25 '22 05:06 drewTheNerd

DMX is specified for up to +6V on either data pin, so unless you know that you're the only one ever driving the bus, expect 6V (at least 5V would be common) to get to your 2040's pins that to my knowledge is not 5V tolerant. DMX standard also require the port to withstand 4kV contact discharge and 8kV air discharge.

Not wanna be harsh or so, but as a person making products for the professional part of the industry - I have seen non-standard compliant solutions from projects online ending up on the market. I love these projects as a way to make it easier for people to do things right. So, let's keep things right.

If you want to push short cable runs and not care about the standard, just bias Data- to 1.5ish V and drive the 3v3 level from the output to D+.

e120guru avatar Oct 28 '22 07:10 e120guru

@kripton amazing work! I'll have to try it out. In my application I'm just driving a DMX input on a DMX Controller and want to put it in a small surface mount RG45 box. This will be ideal. Thanks again!

GlenHertz avatar Oct 28 '22 14:10 GlenHertz

@GlenHertz : Thanks! You're welcome, keep us posted on the progress and if it worked! And I have to agree with @e120guru : DMX was not meant to be driven directly by IO pins. You have 0 protection and it might not work. Don't use it for DMX input, only for output. I would say that the "0 protection" can be ignored since the Pico is reeealllyyy cheap :D If it breaks, just replace it. Just bad if it happens during a show ...

kripton avatar Oct 28 '22 21:10 kripton