How to send a single RS422 Command with a Teensy 2.0?

Hello all, I'm a complete novice when it comes to programming an arduino, but I'm pretty sure what I'm looking to do is relatively simple, but not-so-simple being relatively inexperienced.

I have a video tape recorder that accepts RS422 commands (which is basically RS232 with two paired transmit (+ and -) and receive lines (+ and -) that have opposite levels to each other at all times. The main purpose of that is to have long distance communication of more than a kilometer which I clearly do not need for my application haha.

I'm only interested in sending a single command out of the entire protocol - the serial command for "Stop". Basically what I want the arduino to do is when two pins on the arduino are shorted with a switch, I want it to send the "Stop" command. I am fairly certain that the system will work without prior handshaking or needing to hear a response back saying that the command was received, so receive lines shouldn't matter at all here.

My hope is that it's possible to have two of the digital outputs just send what essentially is the equivalent of RS422 data (doesn't need to understand what it is sending, just needs to know timing of high/low pulses and have two of the digital outputs that have a high and low state that is opposite of each other at all times), that should work here I think. If it "can't" be done that way, I'm also ok with hooking up a simple RS232 to RS422 converter inline, but I'd like to avoid that if it isn't absolutely necessary to keep complexity/components to a minimum.

The arduino I have to work with is a genuine Teensy 2.0.

The protocol itself is called the Sony "9-Pin protocol" with this site explains the exact formatting of the commands:

Screenshot below from the link above gives a general idea of the formatting:

Basically says commands are RS422A, No synchronization, 1 start bit, 8 data bits, 1 stop bit, Data rate of 38400 bps, Odd parity, start bit is "Space", stop bit is "Mark". It also has a checksum, and the actual stop command itself is Send: "20 00 20"

There is another arduino project that has the full protocol built in here, that may be useful to reference: GitHub - hideakitai/Sony9PinRemote: RS422 Sony 9-Pin Protocol Remote Controller of VTRs for Arduino

-In that project's implementation, they wanted to be able to receive responses back and full support for all features which I do not need here.

Again, since I don't actually need to get a response back from the device, I think just sending the correctly formatted high/low pulse string almost like you would with an infrared remote and not exactly knowing if it was received will work fine here.

If anyone is willing write this code up for me to try with a Teensy 2.0 and tell me which two pins to short for the "switch" and what the output pins (TX+, TX-, and GND) are assigned to .... and it actually works, I'd absolutely be willing to send a donation for your time/effort and buy you "several" coffees :slight_smile: Any explanation of how the code actually works would be great, but I don't want to take up too much of your valuable time for the effort in helping me. Having working code to look at will be good enough for me to study for educational purposes and I think I can figure out how to add other commands later if need be.

You must have an RS-422 adapter card to convert your Arduino voltages to the required RS-422 voltages.

The teensy does not use RS232 so you can leave that out.

Personally I would just hook a TTL-to-RS422 converter to the RX and TX of the teensy (I'm quite sure that they are broken out) and write through the UART.

I'm ok with using an RS232 to RS422 adapter if that's absolutely required, but I still need to know how what code I'd need to use for that that full "stop" command with the Teensy 2.0 triggered each time a switch is triggered on two of its other pins.

It's not a question of protocol, but of standard. Rs422 is -6V...+6V and you need converter to use that.

But! Have you tried that project to see if it works for you just as it is? If so then that code can be modified to do only what you want to send.

It's not an RS232-to-RS422 adapter, it's a TTL-to-RS422 adapter that you need; something like https://www.mantech.co.za/ProductInfo.aspx?Item=15M0790. You connect that between the Rx/Tx pins of the Teensy and your video tape recorder.

Unfortunately the Teensy 2.0 core does not seem to support the 8O1 serial format. So some hacking hacking has to be done.

Issue is I believe the other project is meant to be controlled by a computer and I am not sure that it supports the teensy 2.0 specifically or if you can assign two of the pins to send a specific command with it?

I really thought it would be rather simple to send an 8 bit string based on a known protocol with the correct baud rate, parity, stop bit, and check digit that is initiated by a button press and would be only a few lines of code. I now realize that getting the TTL into RS422 will need to be done with an adapter, but that part seems to be relatively straightforward.

I think I really just need a way to get the command sent via the TTL lines output with a button press so that I can then convert them to RS422.

Anyone know how that would be done based on the protocols mentioned linked in the original post?

Any reason why you want to use the Teensy? A SparkFun Pro Micro and a RS422 converter will do the job. As mentioned earlier, the Teensy 2.0 does not seem to support the 8O1 serial format.

Definitely not opposed to using a Pro micro and RS422 converter, I'm just not sure how to compile the project for it specifically and how I can assign a physical button to that "stop" command. Teensy I've just found to be a bit easier to get back into the boot loader if you need to re-upload code.

How would you program a single button for the Pro-Micro to send only that stop command using that 9 pin remote project?

I don't use Teensy's so I have no idea. The Arduino IDE handles uploads smoothly on my system.

You will need to install the library that you linked in the opening post as well as the dependencies mentioned under dependent libraries

The code is fully based on the play_stop example. loop() was changed, other changes marked with sterretje. You need to wire the button between pin and GND; choose any pin you want except 0 and 1 (which are Serial1).

You will need to hook up a RS422 converter to pins 0 and 1 of a SparkFun Pro Micro or Arduino Leonardo or Arduino Micro.

You can clean out the setup() function if needed; I can not test what can be removed as I don't have the machine (feel free to donate one and some tapes :wink: ).

In loop(), a state change is implemented so the code will only send a command when the button becomes pressed, not when it is pressed. Buttons may bounce (resulting in a few rapid changes between pressed and released); for that reason a elementary debouce is implemented using delay(50). You can adjust the value if needed.

// sterretje: button between pin and GND
#define ISPRESSED LOW

// sterretje: button pin, adjust to needs
const uint8_t buttonPin = 2;

// #define SONY9PINREMOTE_DEBUGLOG_ENABLE
#include <Sony9PinRemote.h>

Sony9PinRemote::Controller deck;

void setup()
{
  // sterretje: configure button pin with internal pullup; button between pin and GND
  pinMode(buttonPin, INPUT_PULLUP);

  Serial.begin(115200);
  // sterretje: wait for communication channel with PC to open. Remove if you want to use it stand alone.
  while(!Serial);

  Serial1.begin(Sony9PinSerial::BAUDRATE, Sony9PinSerial::CONFIG);
  delay(2000);

  deck.attach(Serial1);

  // get device status
  deck.status_sense();
  if (deck.parse_until(1000))
  {  // wait until response comes (timeout = 1000ms)
    if (!deck.is_media_exist())
      Serial.println("ERROR: there is no media!");

    if (!deck.is_remote_enabled())
      Serial.println("ERROR: remote control is disabled!");

    if (!deck.is_disk_available())
      Serial.println("ERROR: removable media is not available!");

    if (!deck.is_stopping())
    {
      deck.stop();
      deck.parse_until(1000);
    }

    deck.device_type_request();
    if (deck.parse_until(1000))
    {
      Serial.print("device type = ");
      Serial.println(deck.device_type(), HEX);

      if (deck.device_type() == Sony9PinDevice::BLACKMAGIC_HYPERDECK_STUDIO_MINI_NTSC)
      {
        Serial.println("this device is BlackMagic HyperDeck Studio Mini NTSC");
      }
    }
    else
      Serial.println("ERROR: device type request failed!!");
  }
  else
  {
    Serial.println("ERROR: device status request failed!!");
  }
}

void loop()
{
  // remember status of button pin so we can detect a change
  static uint8_t prevButtonState = !ISPRESSED;

  // read the button
  uint8_t buttonState = digitalRead(buttonPin);

  // if the button changed from pressed to released or fromn released to pressed
  if(buttonState != prevButtonState)
  {
    // remember
    prevButtonState = buttonState;

    // if button is now pressed
    if(buttonState == ISPRESSED)
    {
      // stop
      deck.stop();
    }
  }

  // a primitive debounce; adjust to needs
  delay(50);
}

Code compiles for the three boards mentioned above; it will not compile for a Teensy 2.0.

Note:
I do not know if this will always be connected to a PC or not. Normal use of boards with native USB usually contain the line while(!Serial) in setup(); the intention is that you will not miss the first few serial prints. On boards with native USB (lkike the ones mentioned) this will however block if the board is not connected to a PC or a terminal program (e.g. serial monitor) is not opened. For stand-alone use, you can remove the line.

If your setup is externally powered and the communication channel was opened and you disconnect the USB, it can bring your code to snail pace because the board can not get rid of the data that the code prints.

I will give that a try! The idea is not to have it hooked up to a computer at all so that it can be a standalone device to just tell the recording device to stop when the button is pressed.

Just as a side question, is there any reason that just having the unit programmed for when a button is pressed to just output the equivalent "stop" RS232 string that then gets converted from TTL to RS422 by the external converter? Seems like a lot simpler than doing the above I would think, but I'll try it anyway. Thanks!

There is more to it than just the stop string (as far as I can see). Study the library and the manual :slight_smile:

A couple of changes to make it work on Teensy 2 (untested):

Sketch

#if defined(TEENSYDUINO) && defined(ARDUINO_ARCH_AVR)
    Serial1.begin(Sony9PinSerial::BAUDRATE);
    UCSR1C = (UCSR1C & ~(3<<UPM10)) | (3<<UPM10); // odd parity; change the second 3 to 2 for even parity
#else
    Serial1.begin(Sony9PinSerial::BAUDRATE, Sony9PinSerial::CONFIG);
#endif

Sony9PinRemote.h line 41

namespace serial {
    static constexpr size_t BAUDRATE {38400};
#if defined(TEENSYDUINO) && defined(ARDUINO_ARCH_AVR)
    // Serial1.begin() does not have a configuration parameter
    // SERIAL_8O1 is not defined
#else
    static constexpr size_t CONFIG {SERIAL_8O1};
#endif
}  // namespace serial
1 Like

Just in trying to understand, since these devices don't require handshaking or feedback and the communication to do something and the machine is only listening for certain commands formatted a certain way (similar to how an IR remote works) - why would it "need" the rest of the protocol to be there if those functions are not needed for my application? I really never need to be able to get responses back from the machine to know the command was received.

I agree there "is more to the protocol" - but I don't need any of those other functions for this application.

I believe the bulk of the 9 pin remote code is to interpret signals coming from the VTR like timecode and what the current state of the machine is - such as if currently playing, fast forwarding, etc, and feedback that a command was received which doesn't actually affect operation or mean that it actually did anything with the command sent.

Even if the arduino didn't know that the signal it was sending was - as long as it knew what voltages to output and for how long before each voltage change (going from high to low or low to high for how long), it should still contain the same information as long as those voltages are expanded to RS422 format by the TTL to RS422 converter, correct? I don't think the RS422 converter requires handshaking either, if it did, that'd be a different story I think.

Something like start with line output of 0V. When button is pressed, set output pin to 5v for X number of milliseconds, drop back to 0V for X number of milliseconds, then go back to high for X number of milliseconds etc? Then just connect that to the TTL to RS422 converter and the machine would then receive the serial pulses with the expected voltages present for RS422?

So basically what I'm kind of fishing for (and would like to try in addition to the above suggestions) is what would that RS422 command itself look like for "stop" given the known protocol laid out above, and what program sketch could I use to try just sending the command string data itself when I press a button on the Arduino? I really do not need the arduino to understand what it is sending or receive anything back, just want it to send high and low pulses for defined periods of time that the TTL to RS422 converter can then change the voltages to expected levels for the receiving device.

RS-422 is an electrical interface. looks like you need to send a command to video tape recorder that uses the VVCR 422 protocol over an rs-422 interface.

looks like the interface can be driven using the Arduino UART at 38400 bits/sec. If you know that the command is, the values of the msg bytes, you can use Serial.write() to queue those bytes to the UART and the UART will transmit those values with the appropriate start and stop bits at the specified bit-rate

    byte buf [] = { 20, 0, 20 };
    Serial.write (buf, 3);