May 18, 2024, 05:54:57 AM

News:

You can now use Vixen to program your Prop-1 and Prop-2 controllers!  Get started quickly and easily, without having to learn PBASIC.  Details in the Library forum.


Triggering stored DMX sequences from TTL input

Started by TomStrong, June 18, 2012, 09:17:35 AM

Previous topic - Next topic

TomStrong

Hello, I'm working on a show that needs to have 14 inputs (using input 0 as a bank switch, and the remaining 1-7 twice) that will trigger playback of a DMX sequence.  I have the uSD card reader for the HC-8+, and VSA to create the stored sequences, but I can't find anything in the documentation that would tell me how to connect the dots. 

Is there any example code that will read (pairs of) TTL inputs and output DMX from a file on a uSD card?

JonnyMac

June 18, 2012, 10:42:08 AM #1 Last Edit: June 24, 2012, 05:49:06 PM by JonnyMac
This is an obviously an advanced project that would fit under "Hacking the HC-8+" -- the title of a web series I will be producing later this summer.

It's always important to build these things step-by-step.  We will start with the button inputs.  The TTL input header has 8 inputs (IN7..IN0). If we dedicate one as a "shift" input we write a bit of code that allows us to return the button # (0 if none pressed) using the appropriate schematic (see attached).

How the circuit works.  The buttons for 1..7 connect between the R (+5v) pins and the IN1.W .. IN7.W pins on the TTL header.  The buttons for 8..14 connect to IN1.W .. IN7.W through 1N4148 steering diodes.  The 8..14 buttons also connect to IN0.W through steering diodes.  The diodes are critical and must be used as they allow the "banks" to work independently of each other. 

Note, though, that this kind of input is only good for one button at a time.  If, for example, we pressed buttons 1 and 14 at the same time the use of the shift input for 14 would make the input on 1 look like an input on 8.  For this reason the code disqualifies inputs of two or more buttons.

This is the code (added to the standard HC-8+ template) that is used to read and qualify the matrix input.

pub rd_matrix | btns

'' Reads 7x2 button matrix on IN7..IN0
'' -- returns 0 (no button) to 14 (button #)
'' -- requires 7x2 matrix with steering diodes
''    * IN0 is shift input

  btns := ttl_inputs(true)                                      ' read ttl inputs

  if (btns & %0000_0001)                                        ' shift bit active?
    btns := (btns & %1111_1110) << 7                            ' remove shift, adjust

  if (bit_count(btns) == 1)                                     ' only one button pressed?
    return bit_pos(btns, 0)                                     '  yes, return button #
  else
    return 0                                                    '  none or bad input

   
pub bit_count(value) | bc

'' Returns # of bits set (1) in value

  bc := 0                                                       ' clear count
  repeat 32                                                     ' test all bits
    bc += (value & %1)                                          ' add bit value to count
    value >>= 1                                                 ' next bit

  return bc


pub bit_pos(value, mode)

'' Returns position of 1st bit set
'' -- mode 0 to scan from lsb, mode 1 to scan from msb
'' -- -1 = no bits set

  if (value == 0)                                               ' if no bits                                   
    return -1                                                   '  return -1

  else
    if (mode == 0)                                              ' check from LSB
      value ><= 32                                              '  flip for >|
      return (32 - >|value)
    else
      return (>|value - 1)


As you see it does a new scan of the TTL header and then checks for BIT0 of that value -- this is the shift input.  If this bit is 1 then it is stripped from the value and everything is shifted left so that the IN1 pin lands in the BIT8 position.  The bit_count() method is called to ensure that only one button was pressed and when that's the case the bit_pos() method converts the 15-bit value to a digit, 0 (no button) or 1 to 14 (button #).

Unzip the test program and give it a go with your hardware.  I don't have time to build a matrix so while I know the code compiles and I have confidence it will work, I could be wrong.

Running the program:
-- unzip project files to a folder where you can find it
-- open hc-8_matrix.spin in the Propeller Tool
-- connect the Prop-Plug to the 4-pin header just below the Propeller chip on the HC-8+; label faces the chip
-- connect matrix circuit to TTL input port
-- connect power to the HC-8+; move power switch to position 1
-- press F11 in Propeller Tool to download program to the HC-8+ EEPROM
-- press F12 to bring up PST (Parallax Serial Terminal)
-- click on the Enable button (if flashing)
-- press any key on your keyboard; the terminal will display a banner and the button #


On the DMX file -- there is no such thing as a standard DMX file; all vendors use their own format as far as we know. 

We certainly know how to read files from an SD card as we do this in the AP-16+ to play WAV files; we have to tools and essential knowledge.  What you have to do is tell us the specification on the DMX file you want to use.  It may take a little time but we can probably figure out how to read it once we have the specification.  Once we have the spec and can read values from the file it's easy to move into a DMX transmitter object that we've used many times.

Final code moved to another post -- see end of thread.
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

Note: I added a second, more verbose, version of the schematic for those that may be new to building circuits from scratch.
Jon McPhalen
EFX-TEK Hollywood Office

TomStrong

June 18, 2012, 03:37:58 PM #3 Last Edit: June 18, 2012, 03:40:00 PM by TomStrong
Quote from: JonnyMac on June 18, 2012, 10:42:08 AM
On the DMX file -- there is no such thing as a standard DMX file; all vendors use their own format as far as we know. 

We certainly know how to read files from an SD card as we do this in the AP-16+ to play WAV files; we have to tools and essential knowledge.  What you have to do is tell us the specification on the DMX file you want to use.  It may take a little time but we can probably figure out how to read it once we have the specification.  Once we have the spec and can read values from the file it's easy to move into a DMX transmitter object that we've used many times.

I'm flexible on the format, I can go with any file format that VSA can generate/export.  If it makes it easier I can also restrict the DMX universe to any convenient set of 32 adjacent channels. 

Given the above, what kind of format would work best?  How would we make that kind of file play back?


Also, on the hardware side, I'm having trouble finding a diagram to indicate which pins of the TTL input do what.  From looking at the circuit traces it appears that the middle row is the power source, but should the inputs go toward the center of the board or toward the edge to work with that schematic?

JonnyMac

June 18, 2012, 04:17:51 PM #4 Last Edit: June 18, 2012, 04:21:29 PM by JonnyMac
Hit a snag....

I remember you mentioning VSA and 32 channels so I created a quick test file (CSV format) that is what VSA can export.  I have written code that will open the file and parse the data but the timing is not what I had hoped.  For 32 channels it takes a little over 60ms -- the normal frame rate from VSA is 30FS which works out to 33.3ms.  VSA has a 15FPS setting but that would mean fades wouldn't be as smooth.

The nice thing about the CSV format is that it's just text and humans can read and modify it with a text editor.  I just went and looked and found VSA also has a binary format; I will have to do some research on how that is output so that I can develop some code to read it.

QuoteAlso, on the hardware side, I'm having trouble finding a diagram to indicate which pins of the TTL input do what.  From looking at the circuit traces it appears that the middle row is the power source, but should the inputs go toward the center of the board or toward the edge to work with that schematic?

If you look right above the TTL header you'll see B R W; B is ground (black wire of servo cable), R is +5v, and W is the active-high input which is pulled down to ground through a 10K resistor. Note that the verbose schematic I posted earlier calls out these pins more specifically.
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

June 18, 2012, 04:42:48 PM #5 Last Edit: June 18, 2012, 06:34:23 PM by JonnyMac
Good news: Reading a 32-channel frame in binary mode only takes 6 milliseconds, well under the 33ms frame time we're shooting for; this is good as we have to move the data to the DMX output and then trigger it. 

Bad news: I'm not getting the values I expected; will have to crack open the file with a hex editor to see how the bytes are stored -- this could affect read speed if they are not Little-Endian.

After reviewing the SD object docs and verifying binary files are stored as desired, got the code to work.  This is really good news as we can read the values directly off of the card, no parsing the CSV file or converting text to values is required.  I added a little safety code it takes about 6.5ms to read 32 channel values.  This is great as it gives the program a lot of breathing room.

As a teaser, this is what I think the working core will look like.  I've  made this somewhat generic so that I can use it with your DMX project and my servo project with just a tiny bit of updating.

pub play_show(fpntr, nchans, fps, dest, size) | check, t, idx, level

'' Open show file and play to end
'' -- fpntr pointer to file name (z-string)
'' -- nchans is number of channels per frame
'' -- fps is frames per second, usually 30
'' -- destination is pointer to output array
'' -- size is destination element size in bytes: 1, 2, or 4

  check := \sd.popen(fpntr, "r")                                ' open in read mode
  if (check < 0)                                                ' if error
    return check                                                ' abort

  t := cnt                                                      ' sync timer
 
  repeat                                                        ' loop to end of file
    repeat idx from 0 to nchans-1                               ' loop through channesl
      check := \sd.pread(@level, 4)                             ' values are 32 bits (4 bytes)
      if (check == 4)                                           ' valid read?
        case size                                               ' output to destination
          1 : byte[dest][idx] := level
          2 : word[dest][idx] := level
          4 : long[dest][idx] := level   
      else                                                       
        quit                                                     
                                                                 
    if (check == 4)                                             ' if not at end of file
      ' move to dmx or servo driver
      waitcnt(t += clkfreq / fps)                               ' let frame timing expire
                                                                 
    else                                                         
      quit                                                      ' break out of loop
     
  \sd.pclose
  return 0                                                      ' show played


I've got to "pay some bills" as it were and put more time into other projects.  I'll do a little more work on this tomorrow.
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

Have you connected and tried the matrix inputs?  I want to make sure that's working moving to the next step.
Jon McPhalen
EFX-TEK Hollywood Office

TomStrong

Quote from: JonnyMac on June 19, 2012, 12:05:35 PM
Have you connected and tried the matrix inputs?  I want to make sure that's working moving to the next step.


Just finished debugging things (I managed to short a pair of traces on my board and I also had a bad diode, but the design was fine), and yep, it's working great now.  I did make one minor change, instead of doing a bit-shift by 7 I did it by 10 so that the buttons are 1-7 and 11-17, but it makes no functional difference.  Also, I went by the earlier schematic where all of the +5 V connections were common instead of running a separate line for each one of them.  I've attached a couple of pictures of the rig as it exists so far, I'll retake them once I get the last two buttons and have something better than a phone camera to take them with.

Moving forward, would you also be able to put the VSA files that you're using up on here?  I'm thinking the easiest way to make sure things work is to just use the ones you're using and then make adjustments as needed.

TomStrong

Quote from: JonnyMac on June 18, 2012, 04:42:48 PM
pub play_show(fpntr, nchans, fps, dest, size) | check, t, idx, level
  check := \sd.popen(fpntr, "r")                                ' open in read mode


I was just trying out the DMX playback, and I'm getting a problem on the line above at compile time.  It's unable to find \sd.popen.  Is there anything I should be setting, or am I missing a file?

JonnyMac

June 20, 2012, 01:01:39 PM #9 Last Edit: June 24, 2012, 05:49:34 PM by JonnyMac
Quoteam I missing a file?

Yes, a few, in fact -- that was just to show you what I was thinking.


It turns out that my clever coding was, well, not as clever as I had hoped and I had to re-write the play routine.  The attached (work in progress) does everything it's supposed to; I just haven't had time to hook it up to a DMX device.  That said, my DMX output code is well-worn and I'm pretty confident it wlll work.  Use the T+ and T- outputs on the HC-8+ to the DMX+ and DMX- inputs on your dimmer board.  If you open a terminal (F12) and set the baud rate to 115200 the program will tell you what it's doing.

Now... I've spent a good chunk of time on this and know you're a programmer.  I'm expecting you to study this and learn from it.  If you can program in C/C++, you can certainly code in Spin.  ;)

Note that my program is setup for 8 channels -- you can change the CHANNELS constant.  Note, too, that your VSA binary export must match what the program is set to (channel count).  I've attached my test VSA file and a binary output from it; you'll need to enable channels 8 - 31 and set the parameters for DMX as I have (this is one aspect of VSA that is a big pain in the backside).  That will allow you to test live; once you're happy with show you can export in binary format.  Again, export channels 0 to 31 if you have set the CHANNELS constant to 32.

The export filename should be SHOWxx.BIN where xx is the show number for your buttons, 01 to 14.

I'm doing some more work and testing -- this may take us another week or so (given my schedule) to get things 100%.

Favor, please: Do not upload raw image files to the forums.  Please take them into an editor and reduce them to 800 or few pixels wide.  This is a good size for most screens and doesn't use too much forum storage space.  Thanks.


Final code moved to another post -- see end of thread.
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

Any progress? 

FWIW, I took a big 8-channel file and ran it through some test code that read it as a 32-channel frame and measured the duration from frame read to move to DMX driver of all channels -- never more than 6ms so we're really good to go.  This likely means that those wanting to do larger VSA shows probably could.  The binary output compatibility with the Propeller standard data type (32-bit long) was a life and time saver.
Jon McPhalen
EFX-TEK Hollywood Office

TomStrong

Quote from: JonnyMac on June 21, 2012, 01:14:06 PM
Any progress? 

I have everything assembled, now I'm starting to put the pieces together and bring in one part at a time.

I should have the HC-8+ tied in within a couple of hours if all goes well.

TomStrong

Ok, everything works except the HC-8+ and I'm getting confused.

I've tested it with VSA driving through a USB to DMX box, and that works as expected.  I loaded the code you provided with the channels changed to 32, the code seems happy enough to load, and the receiving device is indicating that it's getting valid DMX (as opposed to complaining about what I sent it when I had the number of channels wrong) but nothing makes it to the output, instead I'm just getting some constant small value on the channel (enough to make the motor buzz bot not enough to make it move) any time that the program makes it to the initialization step.  (it never gets down to zero when driven by the HC-8+)  The serial terminal is printing out successful messages and telling me it sent 160 frames as I'd expect. 

Here's the VSA files I'm using, maybe you can spot something weird.  Bringing the binary file up in a hex editor looks pretty similar to your example one, the main thing I'm doing is fiddling with channels 23 and 24 (I have a test motor on 24) and like you I'm starting with channel 0. 

JonnyMac

I'm made some cosmetic updates to my DMX driver -- let me look at that and get back to you.
Jon McPhalen
EFX-TEK Hollywood Office

TomStrong

Quote from: JonnyMac on June 22, 2012, 07:38:21 AM
I'm made some cosmetic updates to my DMX driver -- let me look at that and get back to you.

Did you spot anything going through it?  I looked through things here as well but I'm not really sure whatI'm looking for.