I wrote a simple DMX driver for Axe programs. It uses assembly opcodes to access the link port and the CPU timer, but it's designed to be included into normal Axe programs and accessed through a subroutine. I am not an expert at assembly though, so it may have errors. If I was better at assembly then I might make it into an axiom instead of an include file since it's pretty much all assembly anyway.

The problem is that I can't test the driver out on a real DMX system because a) I don't have any DMX or link cables to splice, and b) I'm not an electrical engineer, so I have no idea if such a cable is even possible. If it is, how simple would it be to make? Is it as easy as connecting the ring/tip to the pins, or does it require more work to make them compatible?


The rest of this post describes the workings of DMX. Most of the following information I found at http://www.dmx512-online.com/physl.html and http://elationlighting.com/pdffiles/dmx-101-handbook.pdf.

DMX cables use XLR connectors. They have 5 pins in a semicircle arrangement, but only the first 3 are used. Pin 1 is ground, Pin 2 is the negative data wire, and Pin 3 is the positive data wire. Pins 4 and 5 are spare. The pins are numbered counterclockwise from the top left on the male connector, and clockwise from the top right on the female connector. Here's a diagram:



One thing worth mentioning: Although my diagram is labeled as an XLR connector, and technically XLR cables should be interchangeable with DMX cables, they are not suitable for DMX wiring in the real world because they can't carry a 250 kHz signal well. Never replace a DMX cable with an XLR cable.

A 0 bit is sent when Pin 2 is a higher potential than Pin 3, and a 1 bit is sent when Pin 3 is higher than Pin 2. This is to nullify the effects of interference in the wires because both wires are affected equally, so the potential difference is not changed by interference. However, the cable still needs shielding, and the lines should be twisted to ensure that they both receive equal interference. Also, the ground shield (Pin 0) should never be attached to the connector because it can cause data errors in such a case.

Both wires can go up to +12V and down to -7V, but only a difference of 0.2V is required to trigger a state change and therefore signal a bit. Most implementations send a +5V on one line and a -5V on the other to make a difference of +/-10V, but this is usually overkill. The reason for it is that on a highly resistive wire, the ending difference is probably still greater than 0.2V, which still signals a bit.

The cable works at 250 kHz, which means that each bit is measured in 4 microsecond intervals. My driver uses a CPU timer at 250 kHz to time the bit sending. It manually pulls each line low and high rather than trying to send bytes through the link assist because apparently the OS sends bits at 9.6 kHz. Anyway, to send a 0 bit, I pull the tip low and the ring high, and vice versa for a 1 bit. I can post the driver code if anyone is interested in checking for errors. It's nothing too complicated - only 205 bytes compiled.

What I want to know is if this cabling is as easy as connecting the tip to Pin 3 and the ring to Pin 2, or if there's more to it. Kerm said that the calculator outputs +5V for high and 0V for low, which seems like it should work for DMX. I'm not sure about all the nitty-gritty electrical details, which is why I'd like some input on this idea.


P.S. For those who don't know, DMX is both a protocol and a type of cable. It's used commonly in theaters for lighting and special effects, as well as in other settings. My goal with this driver is, if possible, to run lights in a theater from a calculator. Because that would be amazing.

EDIT: DMX is technically not a type of cable. It requires a specially designed type of XLR cable that is suitable for carrying signals at DMX frequency.
ajcord wrote:
The problem is that I can't test the driver out on a real DMX system because a) I don't have any DMX or link cables to splice, and b) I'm not an electrical engineer, so I have no idea if such a cable is even possible. If it is, how simple would it be to make? Is it as easy as connecting the ring/tip to the pins, or does it require more work to make them compatible?
It bothers me that you say you have written a program that does something, but you haven't tested it or even know if it can do what you intend it to do. How is that possible; what am I missing? I am of course not trying to discourage you, but I also try to be realistic about what is possible and reasonable to expect.

Quote:
A 0 bit is sent when Pin 2 is a higher potential than Pin 3, and a 1 bit is sent when Pin 3 is higher than Pin 2. This is to nullify the effects of interference in the wires because both wires are affected equally, so the potential difference is not changed by interference.
This scheme is called differential signalling, and is used in everything from RS232 to USB. Unfortunately, your calculator can't handle it without some bidirectional interface hardware. Technically you could use 5v/0v as one bit and 0v/5v as the other, but I suspect that's outside the DMX specification.

Quote:
My driver uses a CPU timer at 250 kHz to time the bit sending.
On a 6MHz calculator, that is 4*6=24 cycles in between ticks, which is about 3-6 instructions. It is impossible for a 6MHz calculator to keep up. Even a 15MHz calculator would be dealing with 60 cycles per bit, which though a stretch would be feasible for a very tightly-written send and receive. You're better off just doing cycle-counting than dealing with the overhead associated with timers.
KermMartian wrote:
ajcord wrote:
The problem is that I can't test the driver out on a real DMX system because a) I don't have any DMX or link cables to splice, and b) I'm not an electrical engineer, so I have no idea if such a cable is even possible. If it is, how simple would it be to make? Is it as easy as connecting the ring/tip to the pins, or does it require more work to make them compatible?
It bothers me that you say you have written a program that does something, but you haven't tested it or even know if it can do what you intend it to do. How is that possible; what am I missing? I am of course not trying to discourage you, but I also try to be realistic about what is possible and reasonable to expect.

I originally intended it to be a purely theoretical endeavor for me to learn a little about linking, whether or not it ended up being compatible with DMX. I used example code from WikiTI here and here to do the linking and the timing. Then I got to wondering if maybe it actually could work, so I posted this thread to find out.

KermMartian wrote:
Quote:
A 0 bit is sent when Pin 2 is a higher potential than Pin 3, and a 1 bit is sent when Pin 3 is higher than Pin 2. This is to nullify the effects of interference in the wires because both wires are affected equally, so the potential difference is not changed by interference.
This scheme is called differential signalling, and is used in everything from RS232 to USB. Unfortunately, your calculator can't handle it without some bidirectional interface hardware. Technically you could use 5v/0v as one bit and 0v/5v as the other, but I suspect that's outside the DMX specification.

As far as I can tell, there just needs to be a voltage difference. However, one line may need to be negative rather than 0v. I don't know; that's why I asked.

KermMartian wrote:
Quote:
My driver uses a CPU timer at 250 kHz to time the bit sending.
On a 6MHz calculator, that is 4*6=24 cycles in between ticks, which is about 3-6 instructions. It is impossible for a 6MHz calculator to keep up. Even a 15MHz calculator would be dealing with 60 cycles per bit, which though a stretch would be feasible for a very tightly-written send and receive. You're better off just doing cycle-counting than dealing with the overhead associated with timers.

That's what I was afraid of. Would I just decrement A and jump backward if nz to loop?
According to Wikipedia, DMX512 follows EIA-485 (RS-485) differential signalling, which just means that the difference between the data lines must be greater than 200mV (0.2 mV). So 0v/5v will work fine for sending, but it's not safe to subject your linkport to a potential -7v/+12v. You'll still need some hardware. According to this page about interfacing RS-485, shows an EIA-485 to TTL transceiver (TTL is what you need on the calculator side). It appears that TI's SN75176B chip, Maxim's MAX485, LT's LTC485, and National Semiconductor's DS3695 will all work as transceivers.
KermMartian wrote:
According to Wikipedia, DMX512 follows EIA-485 (RS-485) differential signalling, which just means that the difference between the data lines must be greater than 200mV (0.2 mV). So 0v/5v will work fine for sending, but it's not safe to subject your linkport to a potential -7v/+12v. You'll still need some hardware. According to this page about interfacing RS-485, shows an EIA-485 to TTL transceiver (TTL is what you need on the calculator side). It appears that TI's SN75176B chip, Maxim's MAX485, LT's LTC485, and National Semiconductor's DS3695 will all work as transceivers.


Like I said, I'm not very familiar with electronic parts. Would the transceiver act as a mediator between the link port and the DMX cable to regulate the voltage?
On the transmit side, it will take either 0v or 5v (indicating a 1 or a 0) and turn it into two differential voltages to send over the DMX line. On the receive side, it's basically an operational amplifier that compares the voltages of the data pair, and emits either a 0v or a 5v to indicate if it's a 1 or a 0. The datasheets on those chips plus the page I linked have additional information.
That makes sense. I looked at the data sheets, but they are mostly greek to me. So to make a cable using the SN75176B for example, would I just solder the link cable's tip line to pin 1 of the transceiver, the ring to pin 8, line A of the DMX cable to pin 6, and line B to pin 7? That's what I gather from the transceiver in this diagram:


Here's another one:


From what I can tell, the ring needs to be connected to pin 8 to provide the +5V to the transceiver. It would just need to be high the whole time and the tip would provide the data by itself by going high and low. Are these conclusions correct? Also, the calculator itself shouldn't receive any data from the DMX, but the transceiver is probably necessary to prevent the link port from getting accidentally fried.
No, you need to separately supply 5V to the chip. You need to use the tip and ring respectively as the input bit and output bit, and the base of the plug is common ground.
Got it. So the transceiver would need a separate power adapter, and the transceiver's pin 5 would need connected to the ground wire of the link cable.
KermMartian wrote:
You need to use the tip and ring respectively as the input bit and output bit

The input bit and output bit are just inverses of each other then, like the 0v/+5v and +5v/0v we discussed earlier?

Also, I rewrote my driver purely in assembly this time to use CPU cycles instead of the timer, as you suggested. This is the first assembly program I have written without copying the majority of it out of a guide, so please let me know if anything is wrong or can be optimized. The program certainly isn't pretty, but that's mostly due to getting the speed right. I used http://clrhome.org/table/ for the instruction timings, and from that, I counted out 60 cycles between every out (0),a, so it should be perfectly timed out. It is only compatible with 15 MHz calculators.

Code:
;These lines need to be as close to the beginning of the program as possible
;because the DMX cable cannot be plugged in until the link cable is initialized.
exx
;Initialize the cable. It must be high until a packet is ready to send.
ld a,2
out (0),a


;Give control back to the original program until it wants to send the DMX packet.
;This probably should be an axiom, not an include file. Then I can just register
;an InitDMX() token and a SendDMXPacket() token or something like that.


;Send the break header (at least 22 low bits).
ld a,1
out (0),a
;Wait for 1422 cycles (24 bits, to be on the safe side):
ld b,108      ;7 cycles.
djnz 0        ;13/8 cycles.
nop           ;4 cycles.
nop           ;4 cycles.
nop           ;4 cycles.
nop           ;4 cycles.
;Stop waiting. Next, send the mark-after-break (at least 2 high bits).
ld a,2        ;7 cycles.
out (0),a     ;11 cycles.
;Wait for 162 cycles (3 bits, to be on the safe side):
ld b,12       ;7 cycles.
djnz 0        ;13/8 cycles.
nop           ;4 cycles.
;Stop waiting. Next, send the start code (2 low bits, 0x00, and 2 high bits).
ld a,1        ;9 low bits. 7 cycles.
out (0),a     ;11 cycles.
;Wait for 522 cycles:
ld b,40       ;7 cycles.
djnz 0        ;13/8 cycles.
;Stop waiting. Send 2 high bits to signal the end of the start code.
ld a,2        ;7 cycles.
out (0),a     ;11 cycles.
;Wait for 78 cycles:
ld b,5        ;7 cycles.
ld b,5        ;This is just to get the timing right. 7 cycles.
djnz 0        ;13/8 cycles.
nop           ;4 cycles.
;Stop waiting. Begin sending the DMX data (this is where it gets tough).



ld hl,$86EC   ;Load the start of the data (saveSScreen). 10 cycles.
ld b,0        ;The number of bytes to send (256). This can go up to 512, but I
              ;picked 256 because it fits in a single register. 7 cycles.
ld c,0        ;This is only used to get the carry flag. 7 cycles.


ByteLoop:     ;Prepares to send a byte.
    ld a,1        ;The first bit must be low to signal the start of a byte. 7 cycles.
    out (0),a     ;This buys me another 60 cycles to calculate the next bit. 11 cycles.
    ld e,b        ;djnz needs b to hold both the number of bytes left and the
                  ;number of bits left, hence the backup to e. 4 cycles.
    ld b,9        ;Number of bits to send plus 1. 7 cycles.
    dec b         ;Just for timing. 6 cycles.
    ld d,(hl)     ;Load the byte to send. 7 cycles.
    inc hl        ;Move to the next byte. 6 cycles.


BitLoop:      ;Sends a bit.
    rrc d         ;Shift bit 0 of d into the carry flag and shift the rest of d
                  ;to the right. 8 cycles.
    ld a,1        ;Prepare the value to send to the link port. 7 cycles.
    adc a,c       ;Add c and the carry flag to a (remember that c is 0, so it adds
                  ;only the carry flag to a). 4 cycles.
    out (0),a     ;Output high (2) if the carry flag was 1, low (1) if it was 0. 11 cycles.
    ;Wait for 17 cycles:
    ld a,1        ;7 cycles.
    dec a         ;6 cycles.
    nop           ;4 cycles.
    ;Stop waiting.
    djnz BitLoop  ;Keep sending bits until the whole byte is sent. 13/8 cycles.
    ;Wait for 18 cycles:
    ld a,0        ;7 cycles.
    ld a,0        ;7 cycles.
    nop           ;4 cycles.
    ;Stop waiting.
    ld a,2        ;The next two bits are high to signal the end of the byte. 7 cycles.
    out (0),a     ;11 cycles.
    ;Wait for 85 cycles:
    ld b,7        ;7 cycles.
    dec b         ;Again, only for timing. 6 cycles.
    dec b         ;6 cycles.
    dec b         ;6 cycles.
    djnz 0        ;13/8 cycles.
    ;Stop waiting.
    ld b,e        ;Get the backup of b to see how many bytes have been sent. 4 cycles.
    djnz ByteLoop ;Keep going until 256 bytes have been sent. 13/8 cycles.


;Wait for 23 cycles to make sure the last bit gets through:
ld a,2        ;7 cycles.
dec a         ;6 cycles.
dec a         ;6 cycles.
nop           ;4 cycles.
;Stop waiting.
exx

This assumes that the line is not pulled low/high by out (0),a until the end of the instruction (11 cycles). If this is not correct, I need to update my timings.

Edit: I suppose instead of doing ld e,b and ld b,e I could just do a push bc and a pop bc, but those are almost 3 times slower than the respective ld commands.
ajcord wrote:
Got it. So the transceiver would need a separate power adapter, and the transceiver's pin 5 would need connected to the ground wire of the link cable.
KermMartian wrote:
You need to use the tip and ring respectively as the input bit and output bit

The input bit and output bit are just inverses of each other then, like the 0v/+5v and +5v/0v we discussed earlier?
No, the transceiver abstracts that away for you. The input bit will be read-only, and will show you what the other end is transmitting. The output bit will be write-only, and it's where you send a bit to the opposite end. However, I'm not sure how you avoid reading what you are writing. Is there a third transmit-enable pin somewhere? If so, that could be a problem.
KermMartian wrote:
The input bit will be read-only, and will show you what the other end is transmitting.

I don't need to receive any transmissions because DMX is entirely one-way.
Quote:
The output bit will be write-only, and it's where you send a bit to the opposite end.

So I would send a bit by pulling the ring either high or low depending if I want to send a high signal or a low signal. The tip would be for the input bit, which I don't need because I don't receive any data. Is that correct?
Quote:
However, I'm not sure how you avoid reading what you are writing.

Do you mean that what I output would be fed back to the input bit? Possibly relevant is that the last DMX receiver on the line has a terminator to prevent the signal from being reflected and causing havoc. From what I understand, it's basically just a resistor that weakens the signal to the point that it's less than 0.2v and doesn't trigger a bit change. Would that prevent me from reading what I'm writing?
Quote:
Is there a third transmit-enable pin somewhere? If so, that could be a problem.

The 4th and 5th DMX pins are for future use according to the spec, but they are only used in specialty applications. I don't need to deal with them at all. The only ones I'm concerned with are pins 2 and 3 for data transmission (and pin 1 for ground).
ajcord wrote:
KermMartian wrote:
The input bit will be read-only, and will show you what the other end is transmitting.

I don't need to receive any transmissions because DMX is entirely one-way.
Quote:
The output bit will be write-only, and it's where you send a bit to the opposite end.

So I would send a bit by pulling the ring either high or low depending if I want to send a high signal or a low signal. The tip would be for the input bit, which I don't need because I don't receive any data. Is that correct?
That is correct. Don't forget that 0v is pulling the link port bits to 1, and 5v is dropping them back to 0.

Quote:
Quote:
However, I'm not sure how you avoid reading what you are writing.

Do you mean that what I output would be fed back to the input bit? Possibly relevant is that the last DMX receiver on the line has a terminator to prevent the signal from being reflected and causing havoc. From what I understand, it's basically just a resistor that weakens the signal to the point that it's less than 0.2v and doesn't trigger a bit change. Would that prevent me from reading what I'm writing?
Reflection is a problem, but the serial lines are bi-directional, so you have a more immediate problem of immediately reading what you just wrote. That circuit you posted uses a very clever 555 system to avoid that problem.
KermMartian wrote:
ajcord wrote:
KermMartian wrote:
The input bit will be read-only, and will show you what the other end is transmitting.

I don't need to receive any transmissions because DMX is entirely one-way.
Quote:
The output bit will be write-only, and it's where you send a bit to the opposite end.

So I would send a bit by pulling the ring either high or low depending if I want to send a high signal or a low signal. The tip would be for the input bit, which I don't need because I don't receive any data. Is that correct?
That is correct. Don't forget that 0v is pulling the link port bits to 1, and 5v is dropping them back to 0.

Got it. Thanks.
Quote:
Quote:
Quote:
However, I'm not sure how you avoid reading what you are writing.

Do you mean that what I output would be fed back to the input bit? Possibly relevant is that the last DMX receiver on the line has a terminator to prevent the signal from being reflected and causing havoc. From what I understand, it's basically just a resistor that weakens the signal to the point that it's less than 0.2v and doesn't trigger a bit change. Would that prevent me from reading what I'm writing?
Reflection is a problem, but the serial lines are bi-directional, so you have a more immediate problem of immediately reading what you just wrote. That circuit you posted uses a very clever 555 system to avoid that problem.

So since I don't intend to receive any data, do I need to use the 555 system that circuit used in order to avoid the problem, or is it safe to leave it out and ignore the fact?
I suppose that you could hold the RE-bar line on the U1 transceiver always high (to disable receiving) and hold the DE line high as well (to enable transmitting) by just hooking pins 2 and 3 up to +5v. Then you'd need only a single bit from the calculator, either tip or ring, and you could omit the 555 timer.
So could I use USB to provide the 5v to the three pins (2, 3, and 8 )? If so, could I use the calculator's USB port, or would I need to use a wall adapter?
ajcord wrote:
So could I use USB to provide the 5v to the three pins (2, 3, and 8 )? If so, could I use the calculator's USB port, or would I need to use a wall adapter?
You can even use the calculator's own batteries, with a 5.1v Zener diode to drive the 6v the AAAs supply down to 5v. That's what I did for my Ultimate Calculator projects, in order to power their built-in PS/2 ports.
It's probably easiest just to use the calculator's USB port so there's no need for a wall adapter or a diode. I would need to connect pin 1 (+5v, red wire) of the USB OTG cable to pins 2, 3, and 8 of the transceiver, right? And then to start sending power, I output 0 to port 54h? Sorry if this is rather basic, but I don't know much about the USB port and I don't want to mess anything up.
Yup, that's about right. Don't forget to pull out the ground line as well; that's vital.
As in pull out the blue and black wires from this diagram, or leave them both in and just not connect the black wire from the cable to the transceiver?
As in use the black wire from the USB port as a ground. It should be the same as the ground from the I/O port, but it's safer to use both just in case, to be purely technical.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 4
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement