Board and library for 'simultaneous' sending and receiving DMX?


Hello all,

I want to receive DMX, remap/reprocess some values, then send DMX - in realtime. Assuming the processing is very lightweight, what most reliable approach?

I have seen TeensyDMX which I would hope together with the 600Mhz Teensy 4 would do this.

Any insights appreciated

Haven't used the TeensyDMX library used myself but it seems mature, well documented and the author is active on this forum. Perhaps just give it a try?
Found this thread on the forum where the author states it can be done using 2 serial ports.
More threads can be found on this forum when searching for "TeensyDMX".

Thanks, @PaulS. I just released TeensyDMX v4.1.0 and it works fine on the Teensy 4. I tested send, receive, and RDM. It should also be able to retransmit as you wish, per your question above.

There's actually two ways to do it. The first is to continuously read values and send each received packet out the transmitter side. The second is event-based, where a handler is registered for packets having specific start codes; it would inform the main loop to then take the data and retransmit. The first is far simpler.

Here's an over-built example that I haven't tested:
// DMXRelay example program.
// This relays DMX data from a receiver to a transmitter,
// with some optional filtering and modification.

#include <TeensyDMX.h>

namespace teensydmx = ::qindesign::teensydmx;

// Timeout after which it's considered that DMX is no longer
// sending, in milliseconds.
constexpr uint32_t kDMXTimeout = 1000;  // 1 second

// Create the DMX receiver on Serial1.
teensydmx::Receiver dmxRx{Serial1};

// Create the DMX sender on Serial1.
teensydmx::Sender dmxTx{Serial2};

// DMX input buffer.
uint8_t packetBuf[513]{0};

// Time since the last frame was received.
elapsedMillis lastFrameTimer = 0;

// Indicates whether we've seen a packet within the timeout.
bool connected = false;

void setup() {
  // Serial initialization, for printing things
  while (!Serial && millis() < 4000) {
    // Wait for initialization to complete or a time limit
  Serial.println("Starting DMXRelay.");

  // Use the LED to indicate activity
  // You could also use the LED to indicate different modes,
  // for example flashing or on or off to indicate active
  // reception, etc.
  digitalWriteFast(LED_BUILTIN, LOW);  // Start with the LED off

  // Start the receiver

  // Don't start the transmitter here because we may not yet
  // be receiving any data
  // Note: Everything happens asynchronously. This means
  //       that if data is set on the transmitter, it will
  //       keep transmitting the same thing until told
  //       otherwise.

void loop() {
  // Try reading a packet
  int read = dmxRx.readPacket(packetBuf, 0, 513);
  if (read > 0) {
    // A new packet was received
    lastFrameTimer = 0;  // Reset the timer to zero

    // We want to transmit the same packet size that we
    // received. Other options would be to set the remaining
    // bytes to zero, track statistics, filter by start
    // code, etc. There are many things you could do here.
    if (read != dmxTx.packetSize()) {
      // Atomically set the packet size
      // We want to ensure the transmitted packet size
      // matches the data, so ensure nothing happens
      // between the two calls
      dmxTx.set(0, packetBuf, read);
      // Instead of this approach, you could also leave the
      // packet at 513 bytes and just set anything past the
      // end of the current received packet to zero
    } else {
      dmxTx.set(0, packetBuf, read);

  // Connect or disconnect
  if (lastFrameTimer <= kDMXTimeout) {
    if (!connected) {
      // Start up the transmitter
      digitalWriteFast(LED_BUILTIN, HIGH);
      connected = true;
  } else {
    if (connected) {
      // Stop transmitting
      // Another approach would be to just fill the output
      // with all zeros instead of disabling the transmitter
      digitalWriteFast(LED_BUILTIN, LOW);
      connected = false;