News:

Let's find out together what makes a PIC Tick!

Main Menu

DMX system design

Started by John Lawton, Jul 18, 2023, 05:18 PM

Previous topic - Next topic

John Lawton

I'm about to start a DMX512 project. It will consist of up to 16 off RS485 bus driven Lamp boards (that I've already designed) fed by a DMX controlled Host board that I will need to design.

DMX at top speed, receives 512 bytes of data every 25ms. At a DMX speed of 250kbaud, that's 4uS per bit, 11bits per byte or a UART interrupt of 44uS between bytes received. Every DMX512 'packet' that is received will need to be processed and sent out the RS485 bus at high speed in order to keep up with the incoming data rate.

To do this I'm considering using one small PIC with a DMX capable USART just to do the DMX reception then send that data (by high speed SPI) to a second PIC connected to the RS485 bus. This might avoid a complex interrupt based system using one PIC.

Alternatively I might be able to use a PIC with DMA between memory and UART to receive the DMX data without the use of an interrupt.

Another question - to use a PC as a DMX controller with my Host board, I need to use a USB <> DMX adaptor, but what PC software might I use to test my DMX system?

I'd be grateful for any comments pn the above, there's surprisingly little reference to DMX on the forum to date, so I don't know if anyone else has tackled these issues before.



RGV250


John Lawton

Hi Bob, thank you, yes I have seen that doc and some others. They don't appear to address my question of how best to deal with two fast serial streams at the same time, one the DMX incoming and the other the RS485 bus data outgoing. All on one PIC, possibly using DMA, or split between 2 PICs.

John

trastikata

Hello John,

have you thought switching to a dsPIC - with its standard 140MHz clock, two clocks per cycle and DMA you won't have to complicate things. Price-wise, standard dsPICs don't differ from 18F's and they are still available.

John Lawton

Hi Trastikata, thanks, no I hadn't. As long as they include a DMX capable UART then I could go that route.

Mapo

Hi John,
this is the routine I created to transfer from one baudrate to another simultaneously (the fastest way) and it works great
You can adapt this routine for your use

Mapo



Device = 18F26K22

Declare Reminders Off
@ CONFIG_REQ = 0 ; Override Compiler's configuration settings
Asm-
Config FOSC = HSHP    ;HS oscillator (high power > 16 MHz)
Config PLLCFG = On    ;Oscillator multiplied by 4
Config PRICLKEN = On    ;Primary clock enabled
Config FCMEN = OFF    ;Fail-Safe Clock Monitor disabled
Config IESO = OFF    ;Oscillator Switchover mode disabled
Config PWRTEN = OFF    ;Power up timer disabled
Config BOREN = SBORDIS    ;Brown-out Reset enabled in hardware only (SBOREN is disabled)
Config BORV = 190    ;VBOR set to 1.90 V nominal
Config WDTEN = OFF    ;Watch dog timer is always disabled. SWDTEN has no effect.
Config WDTPS = 32768    ;1:32768
Config CCP2MX = PORTB3    ;CCP2 input/output is multiplexed with RB3
Config PBADEN = OFF    ;PORTB<5:0> pins are configured as digital I/O on Reset
Config CCP3MX = PORTB5    ;P3A/CCP3 input/output is multiplexed with RB5
Config HFOFST = On    ;HFINTOSC output and ready status are not delayed by the oscillator stable status
Config T3CMX = PORTC0    ;T3CKI is on RC0
Config P2BMX = PORTB5    ;P2B is on RB5
Config MCLRE = INTMCLR    ;RE3 input pin enabled; MCLR disabled
Config STVREN = On    ;Stack full/underflow will cause Reset
Config LVP = On    ;Single-Supply ICSP enabled if MCLRE is also 1
Config XINST = OFF    ;Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
Config Debug = OFF    ;Disabled
Config Cp0 = OFF    ;Block 0 (000800-003FFFh) not code-protected
Config CP1 = OFF    ;Block 1 (004000-007FFFh) not code-protected
Config CP2 = OFF    ;Block 2 (008000-00BFFFh) not code-protected
Config CP3 = OFF    ;Block 3 (00C000-00FFFFh) not code-protected
Config CPB = OFF    ;Boot block (000000-0007FFh) not code-protected
Config CPD = OFF    ;Data EEPROM not code-protected
Config WRT0 = OFF    ;Block 0 (000800-003FFFh) not write-protected
Config WRT1 = OFF    ;Block 1 (004000-007FFFh) not write-protected
Config WRT2 = OFF    ;Block 2 (008000-00BFFFh) not write-protected
Config WRT3 = OFF    ;Block 3 (00C000-00FFFFh) not write-protected
Config WRTC = OFF    ;Configuration registers (300000-3000FFh) not write-protected
Config WRTB = OFF    ;Boot Block (000000-0007FFh) not write-protected
Config WRTD = OFF    ;Data EEPROM not write-protected
Config EBTR0 = OFF    ;Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
Config EBTR1 = OFF    ;Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
Config EBTR2 = OFF    ;Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
Config EBTR3 = OFF    ;Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
Config EBTRB = OFF    ;Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
Endasm-
Declare Reminders On

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------
                Declare Xtal 64

                Declare All_Digital = TRUE

                TRISA = %11111111
                TRISB = %11111111
                TRISC = %11111111

                Declare Hserial_Baud = 560000                      ' Set baud rate to 560000
                Declare Hserial_RCSTA = %10010000                  ' Enable serial port and continuous receive
                Declare Hserial_TXSTA = %01100100                  ' Enable transmit and asynchronous mode -
                Declare Hserial_Clear = On                          ' Enable Error clearing on received characters

                Declare Hserial2_Baud = 400000                      ' Set baud rate to 400000
                Declare Hserial2_RCSTA = %10010000                  ' Enable serial port and continuous receive
                Declare Hserial2_TXSTA = %01100100                  ' Enable transmit And asynchronous mode
                Declare Hserial2_Clear = On                          ' Enable Error clearing on received characters

                Dim Conta1 As Byte
                Dim Conta2 As Byte
                Dim Buffer1 As Byte
                Dim Buffer2 As Byte
                Dim Numero_byte1 As Byte
                Dim Numero_byte2 As Byte

                Dim Conta_In1 As Byte
                Dim Conta_Out1 As Byte
                Dim Conta_In2 As Byte
                Dim Conta_Out2 As Byte

                Dim In_Buffer1[128] As Byte
                Dim In_Buffer2[128] As Byte

'-------------------------------------------------------------------------------------------------------------

                Clear In_Buffer1
                Clear In_Buffer2
                Clear Conta1
                Clear Conta2

                Clear Conta_In1
                Clear Conta_Out1
                Clear Conta_In2
                Clear Conta_Out2


'-------------------------------------------------------------------------------------------------------------
' MAIN
'-------------------------------------------------------------------------------------------------------------
Main:
                If PIR1.5 = 1 Then                            'baud rate 560000
                    Buffer1 = HRSIn
                    In_Buffer1[Conta_In1] = Buffer1
                    Inc Conta_In1
                EndIf

                If TXSTA2.1 = 1 Then
                    If Conta_In1 > 0 Then                      ' se ho già ricevuto 1 byte
                        Buffer1 = In_Buffer1[Conta_Out1]          ' allora inizio ad inviare
                        HRSOut2 Buffer1
                        Dec Conta_In1
                        If Conta_In1 = Conta_Out1 Then          ' controllo se ho inviato tutti i dati
                            Clear Conta_In1
                            Clear Conta_Out1
                            GoTo Main
                        EndIf
                        Inc Conta_In1
                        Inc Conta_Out1

                    EndIf
                EndIf

                If PIR3.5 = 1 Then                              'baud rate 400000
                    Buffer2 = HRSIn2
                    In_Buffer2[Conta_In2] = Buffer2
                    Inc Conta_In2
                EndIf

                If TXSTA1.1 = 1 Then
                    If Conta_In2 > 0 Then                      ' se ho già ricevuto 1 byte
                        Buffer2 = In_Buffer2[Conta_Out2]          ' allora inizio ad inviare
                        HRSOut Buffer2
                        Dec Conta_In2
                        If Conta_In2 = Conta_Out2 Then          ' controllo se ho inviato tutti i dati
                            Clear Conta_In2
                            Clear Conta_Out2
                            GoTo Main
                        EndIf
                        Inc Conta_In2
                        Inc Conta_Out2

                    EndIf
                EndIf

                GoTo Main


'-------------------------------------------------------------------------------------------------------------


John Lawton

Thanks Mapo.

Sorry, I should have explained my requirements a bit further, but I didn't want to over-complicate my original posting.

The incoming DMX lamp data once received needs to be split up into 32 byte chunks in order to feed up to 16 off Lamp boards, each of which drives 32 lamps, thereby providing for a full DMX universe.

But because the Lamp boards are on a RS485 bus, they also need to be addressed so at the very minimum the DMX lamp data has to be split into 32 bytes chunks then a board address (etc) must be added to the data, so it isn't the basic job of translating one serial stream into another.

I think I am going to pursue using DMA with a DMX capable UART as discussed in Microchip's notes TB3204 (and DMA itself in TB3164) as DMA reduces the CPU involvement which is good.

tumbleweed

I've done a few DMX projects using an 18F, and running at 64MHz you should have plenty of horsepower for something like that. An 18FxxQ43 would be a good choice... it has 1 DMX UART + 4 regular UARTS (5 total), and the 18Fx7Q43 even has 8K of RAM to work with.

Setup the incoming DMX packets to use two buffers and "ping-pong" reception between the two. That way you can be receiving an incoming packet into one while you work on the last packet in the other. That way you don't have to move the data and it gives you a full packet time to send data out to the RS485 modules (of which you could split into 4 chains if you like... you've got the UARTs).

You'll be a lot better off just using a single PIC to do this. Splitting it into two PICS just adds all the communications complications and latency between the two, especially since a master/slave PIC setup using SPI  isn't as easy as it seems at first glance.
 
 

John Lawton

Thanks Tumbleweed, that all makes sense.

John

tumbleweed

How fast are you going to run the RS485 link to the 16 slave modules?
If you want to keep up with the incoming DMX stream and not miss packets on the master it needs to be faster than the DMX @ 250K baud.

I've run 18F uart interrupts at 460K baud, but that only gives you about 22us/byte on the receiving end so you have to be careful.

Using the Q43, if you split the single RS485 into four uart chains of 4 devices each you can send four bytes out almost simultaneously, and by the time you send the "UART4" data "UART1" would almost be ready to accept a new byte to transmit.

That would cut the time down by a factor of 4 and let you use a slower baud rate.



tumbleweed

... and if you don't want all that extra hardware, even two RS485 chains of 8 devices each would cut the time in half, so you could get away with 230K baud (assuming you want to use standard baud rates on the 485 side).

John Lawton

Hi Tumbleweed,
yes you are right, I will have to run the Lamp board bus at a very fast rate as the data has some overhead, it isn't just DMX brightness bytes.

Yes, 460kBaud is a standard speed, but it has also occurred to me to use a non-standard speed as a better fit for my needs if I can do that.

Splitting the RS485 bus is a great idea, I'll have to run it past the customer to see how practical it is for him, but even running two buses in system rather than one is a big help on the data rate required.

tumbleweed

Regarding software to test this stuff with, it's been a few years, but there are a number of open-source packages available.

Two that I've used were xLights (http://www.xlights.org) and Vixen (https://www.vixenlights.com).
I think they're both still available.

Just make sure they support your USB-DMX adapter. And watch out... some adapters are MUCH better than others.

John Lawton

Many thanks for the info.

Yes, I've hard that about adaptors, I've been recommended the ENTTEC DMX USB PRO but apparently they do a cheaper version.

tumbleweed

you can't go wrong with ENTTEC.

The cheaper OpenDMX adapter is very basic... think of it as a USB-UART converter. The more expensive DMX PRO lets you control timing of the BREAK, which is nice if you want to test your hardware, and has a buffer so its timing isn't dependent on the PC.

Oskar-svr

Hello Juan, I hope this program is useful to you, regards

John Lawton

Thank you, that is interesting.

John