Generating DMX512 - simple demo

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
clack
Posts: 20
Joined: Sat May 03, 2014 11:09 am

Generating DMX512 - simple demo

Post by clack » Fri Jul 22, 2016 2:54 pm

Hello,

I am just sharing somthing I am experimenting with as I saw there was no mention of sending DMX on the forum. I am no expert but I have got some initial tests working, eventually I will make a simple library.

I am using a standard MAX485 to drive it.

This post was a great help
http://www.ubasics.com/DMX-512

I am not sure if I am matching the standard enough that it will guaruntee work with all lights but here is the test script that works for me.

Code: Select all

from pyb import UART

#Serial Tx on pin X9
dmx = UART(1)
dmx.init(250000, bits=8, parity=None, stop=2)

#make an editable frame
dmx_bytes = [chr(0)]*513

#This is just a simple test to make the first 3 channels a certain brightness
def write_frame(brightness):
    # Change first 3 channels
    dmx_bytes[1] = chr(brightness)
    dmx_bytes[2] = chr(brightness)
    dmx_bytes[3] = chr(brightness)
    # It expects a minimum 88uS break to begin a frame, this produces a low for 52uS but works on my device
    dmx.sendbreak()
    #send bytes
    dmx.write(''.join(dmx_bytes))

#Dim up forever
while True:
    for i in range(255):
        write_frame(i)
After a while of loops though I get an error? is this because nothing is on Rx?

Code: Select all

Traceback (most recent call last):
  File "main.py", line 24, in <module>
  File "main.py", line 19, in write_frame
OSError: 116
Im using

Code: Select all

MicroPython v1.5.2-62-gaeadda4 on 2016-01-15; PYBv1.0 with STM32F405RG

User avatar
dhylands
Posts: 3821
Joined: Mon Jan 06, 2014 6:08 pm
Location: Peachland, BC, Canada
Contact:

Re: Generating DMX512 - simple demo

Post by dhylands » Fri Jul 22, 2016 4:13 pm

I tried your demo (albeit on 1.8.1 firmware) and it's been running for 30 minutes with no error.

OSError 116 is a timeout error.

It looks like the default timeout_char is zero so I think that what might be happening is that if the write occurs soon enough after the call to the sendbreak, and the sendbreak isn't quite finished, then I think that could cause the timeout.

Possible workarounds:
1 - Pass in a timeout_char when initializing the UART. I suspect a small value (perhaps 2 or 3) is all that would be needed.
2 - Add a small delay after the sendbreak

clack
Posts: 20
Joined: Sat May 03, 2014 11:09 am

Re: Generating DMX512 - simple demo

Post by clack » Wed Aug 10, 2016 10:26 am

I created a simple class to make it easier

Code: Select all

from pyb import UART, Pin, udelay
from array import array

tx_pins = [None, 'X9', 'X3', 'Y9', 'X1', None, 'Y1']

class universe():
    def __init__(self, port):
        self.port = port

        # To check if port is valid
        dmx_uart = UART(port)
        del(dmx_uart)

        # First byte is always 0, 512 after that is the 512 channels
        self.dmx_message = array('B', [0] * 513)

    def set_channels(self, message):
        """
        takes a dict and writes them to the array
        format {channel:value}
        """

        for ch in message:
            self.dmx_message[ch] = message[ch]

        # for i, ch in enumerate(channels):
        #     self.dmx_message[ch] = values[i]

    def write_frame(self):
        """
        Send a DMX frame
        """
        # DMX needs a 88us low to begin a frame,
        # 77uS us used because of time it takes to init pin
        dmx_uart = Pin(tx_pins[self.port], Pin.OUT_PP)
        dmx_uart.value(0)
        udelay(74)
        dmx_uart.value(1)

        # Now turn into a UART port and send DMX data
        dmx_uart = UART(self.port)
        dmx_uart.init(250000, bits=8, parity=None, stop=2)
        #send bytes
        dmx_uart.write(self.dmx_message)
        #Delete as its going to change anyway
        del(dmx_uart)

I delete the objects as I use them as the mode has to switch for the serial port so I can get a 88us low, is it nessesary to delete them or would it automatically be garbage collected if it is unassigned?

You can use it like this, although it would be better to put the write_frame() in a timer interrupt as DMX512 expects regular messages, some lights might go back to a default value.

Code: Select all

import dmx

# create a dmx device on UART port 1
dmx1 = dmx.universe(1)

# Set the channel(s) to the value you want, this sets channel 1 to 100
dmx1.set_channels({1:100})

# Send the message
dmx1.write_frame()
on github for updates
https://github.com/clacktronics/pyb_dmx/tree/master

ptrdvds
Posts: 1
Joined: Mon Aug 22, 2016 12:58 pm

Re: Generating DMX512 - simple demo

Post by ptrdvds » Mon Aug 22, 2016 1:01 pm

Has anyone used this on other boards than the pyboard?
I want to use a ESP8266 with DMX512.

The micropython ecosystem is new to me and what i have seen can "pyb" only be imported on a pyboard, hence the question.

Thanks

briancstaton
Posts: 1
Joined: Tue Aug 29, 2017 6:28 pm

Re: Generating DMX512 - simple demo

Post by briancstaton » Tue Aug 29, 2017 6:35 pm

Hey guys,

Im a little new to python so forgive me for this rookie move. I cannot for the life of me download the library for this. Is there any step by step you could give me to help me out?

Thanks

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Generating DMX512 - simple demo

Post by pythoncoder » Wed Aug 30, 2017 8:56 am

@clack Local variables and objects will be garbage collected once they are out of scope. There is no need for explicit deletion. If you want the code to be portable to platforms other than the Pyboard you might want to consider using the machine module rather than pyb.

As for putting write_frame in a timer interrupt handler, it won't work because it instantiates a UART (see http://docs.micropython.org/en/latest/e ... rules.html). However you should be able to achieve it by having the interrupt handler issue micropython.schedule to schedule a call to write_frame (http://docs.micropython.org/en/latest/p ... ython.html).

I'm surprised that DMX hasn't cropped up before, but it seems you're a trailblazer ;)

@briancstaton This is the preferred method: ensure you have git installed on your PC. Change to a suitable directory then issue

Code: Select all

git clone https://github.com/clacktronics/pyb_dmx.git
The repository will be copied to your chosen directory. You'll then need to copy the code to your Pyboard.

And this is the hacky way, for a module like this comprising just one source file. Go into the source file listing on GitHub, click Raw, then issue ctrl-A ctrl-C to copy the code. Then paste it into your favourite text editor with ctrl-V and save it to a file.
Peter Hinch
Index to my micropython libraries.

klankschap
Posts: 16
Joined: Tue Feb 02, 2016 11:20 am

Re: Generating DMX512 - simple demo

Post by klankschap » Mon Jul 20, 2020 11:41 am

The implementation of the dmx protocol in
uses the Pin.OUT_PP
but the ESP32 does not have this option.
What would be an alternative?

.F

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Generating DMX512 - simple demo

Post by jimmo » Tue Jul 21, 2020 4:59 am

klankschap wrote:
Mon Jul 20, 2020 11:41 am
uses the Pin.OUT_PP
but the ESP32 does not have this option.
What would be an alternative?
I'm not sure why ESP32 doesn't have OUT_PP, but OUT is the same thing.

On STM32, OUT_PP is an alias for OUT anyway.

(It's just to distinguish between push/pull and open-drain).

kevinkk525
Posts: 969
Joined: Sat Feb 03, 2018 7:02 pm

Re: Generating DMX512 - simple demo

Post by kevinkk525 » Tue Jul 21, 2020 7:12 am

I worked with DMX512 once but not with micropython. We bought a Raspberry Pi DMX shield that had an esp8266 on the board to drive the DMX bus. The Pi was programmed with Python and worked great. Since this was a work project and I don't work for that company anymore, I don't have any sources files..
Not sure this is of any help to you now :D But I wish you luck with DMX and python.
Kevin Köck
Micropython Smarthome Firmware (with Home-Assistant integration): https://github.com/kevinkk525/pysmartnode

klankschap
Posts: 16
Joined: Tue Feb 02, 2016 11:20 am

Re: Generating DMX512 - simple demo

Post by klankschap » Tue Jul 21, 2020 8:22 am

jimmo wrote:
Tue Jul 21, 2020 4:59 am
I'm not sure why ESP32 doesn't have OUT_PP, but OUT is the same thing.
On STM32, OUT_PP is an alias for OUT anyway.
(It's just to distinguish between push/pull and open-drain).
The OUT_PP is not defined:
What would be the best alternative ?


>>> import machine
>>> dir(machine)
['__class__', '__name__', 'ADC', 'DAC', 'DEEPSLEEP', 'DEEPSLEEP_RESET', 'EXT0_WAKE', 'EXT1_WAKE', 'HARD_RESET', 'I2C', 'PIN_WAKE', 'PWM', 'PWRON_RESET', 'Pin', 'RTC', 'SDCard', 'SLEEP', 'SOFT_RESET', 'SPI', 'Signal', 'TIMER_WAKE', 'TOUCHPAD_WAKE', 'Timer', 'TouchPad', 'UART', 'ULP_WAKE', 'WDT', 'WDT_RESET', 'deepsleep', 'disable_irq', 'enable_irq', 'freq', 'idle', 'lightsleep', 'mem16', 'mem32', 'mem8', 'reset', 'reset_cause', 'sleep', 'soft_reset', 'time_pulse_us', 'unique_id', 'wake_reason']
>>> dir(machine.Pin)
['__class__', '__name__', 'value', '__bases__', '__dict__', 'IN', 'IRQ_FALLING', 'IRQ_RISING', 'OPEN_DRAIN', 'OUT', 'PULL_DOWN', 'PULL_HOLD', 'PULL_UP', 'WAKE_HIGH', 'WAKE_LOW', 'init', 'irq', 'off', 'on']
>>> import esp32
>>> dir(esp32)
['__class__', '__name__', 'HEAP_DATA', 'HEAP_EXEC', 'Partition', 'RMT', 'ULP', 'WAKEUP_ALL_LOW', 'WAKEUP_ANY_HIGH', 'hall_sensor', 'idf_heap_info', 'raw_temperature', 'wake_on_ext0', 'wake_on_ext1', 'wake_on_touch']
>>> dir(esp)
['__class__', '__name__', 'LOG_DEBUG', 'LOG_ERROR', 'LOG_INFO', 'LOG_NONE', 'LOG_VERBOSE', 'LOG_WARNING', 'dht_readinto', 'flash_erase', 'flash_read', 'flash_size', 'flash_user_start', 'flash_write', 'gpio_matrix_in', 'gpio_matrix_out', 'neopixel_write', 'osdebug']
>>>

Post Reply