1
\$\begingroup\$

I am trying to set up an Arduino as DALI-Master for multiple light sources. As a starting point I made use of this excellent project. There is also a gitpage with a good overview of the available commands. I rewrote the code to to send commands directly after initializing.

#include <Arduino.h>
#include <Dali.h>

//#include<Logger.h>
bool DEBUGLOG = 1;

uint8_t MODE = 0;
uint8_t OK = 0;

#define BROADCAST_DP 0b11111110
#define BROADCAST_C 0b11111111
#define ON_DP 0b11111110
#define OFF_DP 0b00000000
#define ON_DP1 0b00111111
#define ON_DP2 0b11010100
#define ON_DP3 0b11100001
#define ON_C 0b00000101
#define OFF_C 0b00000000
# define QUERY_STATUS 0b10010000
# define RESET 0b00100000

void setup() {
  Serial.begin(9600);

  dali.setupTransmit(3);
  dali.setupAnalogReceive(A7);
  dali.busTest();
  dali.msgMode = true;

  //Logger::log("--- Dali EXP ---");
  Serial.println("--- Dali EXP ---");
}

bool scanByte(byte &result) {
  bool byteArr[8];
  bool ERR = 0;
  bool scandone = 0;

  while(Serial.available()) {
    // byte _temp = Serial.read();
    // Serial.print("-");Serial.print(_temp);Serial.print("-");

    uint8_t _temp = Serial.read();
    // Logger::log("-",_temp);

    if(_temp==124) { // begin scan

      for(int n=7;n>=0;n--) {
        uint8_t temp = Serial.read();
        
        if(temp==49) {
          byteArr[n] = 1;
        } else if(temp==48) {
          byteArr[n] = 0;
        } else {
          ERR = 1;
        }

      }

      scandone=1;
    } 
    // else if(_temp==88) {
    //   MODE=0;
    //   Serial.println("X");
    //   return false;
    // }

    if(scandone) {
      if(Serial.read()==124) { // end scan
        result = 0;
        for(int i=0;i<8;i++) {
          if(byteArr[i]) {
            result = result | (1<<i);
          }
        }

        if(ERR) {
          return false;
        } {
          return true;
        }
      }
    }
  }
  
  return false;
}

bool dimmer = false;
uint8_t dimlevel = 0b00000101;

void loop() {

  String comMsg;

  if(MODE==0) {

    while(Serial.available()) {
      comMsg = comMsg + (char)(Serial.read());
    }

    if(comMsg == "C") {
      MODE = 1;
      Serial.print("C");
      comMsg = "";
    }
    if(comMsg == "X") {
      MODE = 0;
      Serial.print("X");
    }

    if(comMsg == "ini") {    
      Serial.println(comMsg);
      dali.initialisation();
    }
    if(comMsg == "scan") {
      dali.scanShortAdd();
    }
    if(comMsg == "response") {
      bool res = dali.getResponse;
      //Logger::log("Response: ");
      Serial.print("Response: ");
      Serial.println(res);
    }
    if(comMsg == "help") {
      //Logger::log("help"); 
    }
    if(comMsg== "on") {
      dali.transmit(BROADCAST_C, ON_C);
    }
    if (comMsg == "off") {
      dali.transmit(BROADCAST_C, OFF_C);
    }
    if (comMsg == "dimoff") {
      dimlevel = 0;
      dimmer = false;
      Serial.print("OFF: dim = "); Serial.println(dimlevel);
      dali.transmit(BROADCAST_DP,OFF_DP);
    } else if(comMsg == "dim1") {
      dali.transmit(BROADCAST_DP,ON_DP1);
    } else if(comMsg == "dim2") {
      dali.transmit(BROADCAST_DP,ON_DP2);
    }  else if(comMsg == "dim3") {
      dali.transmit(BROADCAST_DP,ON_DP3);
    }  else if(comMsg == "dim4") {
      dali.transmit(BROADCAST_DP,ON_DP);
    } else if(comMsg == "dimon") {
      dimlevel = 10;
      dimmer = true;
      Serial.print("ON: dim = "); Serial.println(dimlevel);
      dali.transmit(BROADCAST_DP,dimlevel);
    } else if(comMsg == "up" && dimmer) {
      dimlevel += 5;
      Serial.print("dim = "); Serial.println(dimlevel);
      dali.transmit(BROADCAST_DP,dimlevel);
    } else if(comMsg == "down" && dimmer) {
      dimlevel -= 5;
      dali.transmit(BROADCAST_DP,dimlevel);
      Serial.print("dim = "); Serial.println(dimlevel);
    }

  }
  
  if(MODE==1) {

    if(Serial.available()) {
      
      byte result,result1;
      OK = scanByte(result);
      OK &= scanByte(result1);

      if(OK) {
        Serial.print(result,BIN); Serial.print(" "); Serial.println(result1,BIN);
        // Logger::log("result  = ",result,BIN);
        // Logger::log("result1 = ",result1,BIN);

        dali.transmit(result,result1);
        uint8_t resp = dali.receive();
        Serial.print("Respons: "); Serial.print(resp); Serial.print(" "); Serial.println(resp,BIN);
      }

      Serial.flush();

    }


  }

  
  delay(250);
}

My current setup is shown in the picture below. The circuit is the same as in the tutorial. The transistor is replaced with standard 2N2222A . Sending and receiving commands works even with the 12V. The library used is found here

enter image description here

One of the LED drivers is a Skydance 4Channel constant voltage driver (link). Every channel should have its own DALI address.

After startup I can use the commands "ini" send the startup commands, "scan" to look for the available addresses on the bus, "on\off" to send the on/ off command to all bus members. With the input command "C" I can switch to command mode and enter commands in binary form

|YAAAAAAS||xXxXxXxX|

After initiation and scanning I only get one addresses

--- Dali EXP ---
Short addresses:
BIN: 0 DEC: 0 HEX: 0 Get response
BIN: 1 DEC: 1 HEX: 1 No response
BIN: 10 DEC: 2 HEX: 2 No response
BIN: 11 DEC: 3 HEX: 3 No response
BIN: 100 DEC: 4 HEX: 4 No response
BIN: 101 DEC: 5 HEX: 5 No response
BIN: 110 DEC: 6 HEX: 6 No response
BIN: 111 DEC: 7 HEX: 7 No response
BIN: 1000 DEC: 8 HEX: 8 No response
BIN: 1001 DEC: 9 HEX: 9 No response
BIN: 1010 DEC: 10 HEX: A No response
BIN: 1011 DEC: 11 HEX: B No response
BIN: 1100 DEC: 12 HEX: C No response
BIN: 1101 DEC: 13 HEX: D No response
BIN: 1110 DEC: 14 HEX: E No response
BIN: 1111 DEC: 15 HEX: F No response
BIN: 10000 DEC: 16 HEX: 10 No response
BIN: 10001 DEC: 17 HEX: 11 No response
BIN: 10010 DEC: 18 HEX: 12 No response
BIN: 10011 DEC: 19 HEX: 13 No response
BIN: 10100 DEC: 20 HEX: 14 No response
BIN: 10101 DEC: 21 HEX: 15 No response
BIN: 10110 DEC: 22 HEX: 16 No response
BIN: 10111 DEC: 23 HEX: 17 No response
BIN: 11000 DEC: 24 HEX: 18 No response
BIN: 11001 DEC: 25 HEX: 19 No response
BIN: 11010 DEC: 26 HEX: 1A No response
BIN: 11011 DEC: 27 HEX: 1B No response
BIN: 11100 DEC: 28 HEX: 1C No response
BIN: 11101 DEC: 29 HEX: 1D No response
BIN: 11110 DEC: 30 HEX: 1E No response
BIN: 11111 DEC: 31 HEX: 1F No response
BIN: 100000 DEC: 32 HEX: 20 No response
BIN: 100001 DEC: 33 HEX: 21 No response
BIN: 100010 DEC: 34 HEX: 22 No response
BIN: 100011 DEC: 35 HEX: 23 No response
BIN: 100100 DEC: 36 HEX: 24 No response
BIN: 100101 DEC: 37 HEX: 25 No response
BIN: 100110 DEC: 38 HEX: 26 No response
BIN: 100111 DEC: 39 HEX: 27 No response
BIN: 101000 DEC: 40 HEX: 28 No response
BIN: 101001 DEC: 41 HEX: 29 No response
BIN: 101010 DEC: 42 HEX: 2A No response
BIN: 101011 DEC: 43 HEX: 2B No response
BIN: 101100 DEC: 44 HEX: 2C No response
BIN: 101101 DEC: 45 HEX: 2D No response
BIN: 101110 DEC: 46 HEX: 2E No response
BIN: 101111 DEC: 47 HEX: 2F No response
BIN: 110000 DEC: 48 HEX: 30 No response
BIN: 110001 DEC: 49 HEX: 31 No response
BIN: 110010 DEC: 50 HEX: 32 No response
BIN: 110011 DEC: 51 HEX: 33 No response
BIN: 110100 DEC: 52 HEX: 34 No response
BIN: 110101 DEC: 53 HEX: 35 No response
BIN: 110110 DEC: 54 HEX: 36 No response
BIN: 110111 DEC: 55 HEX: 37 No response
BIN: 111000 DEC: 56 HEX: 38 No response
BIN: 111001 DEC: 57 HEX: 39 No response
BIN: 111010 DEC: 58 HEX: 3A No response
BIN: 111011 DEC: 59 HEX: 3B No response
BIN: 111100 DEC: 60 HEX: 3C No response
BIN: 111101 DEC: 61 HEX: 3D No response
BIN: 111110 DEC: 62 HEX: 3E No response
BIN: 111111 DEC: 63 HEX: 3F No response

Sending commands to the address '0' changes the behavior of all ballasts on the driver simultaneously. For example:

|00000001||00000001|

sends the command for 'UP'. Here, all ballasts increase their brightness. It looks like the driver is assigned one address instead of four. When scanning for the short addresses each lamps lights up individually (like a sweep), which suggests that every channel can be controlled individually.

After connecting a second (cheap) DALI-driver and one ballast to it my test setup is now:

  • DALI_1: 3 Ballasts
  • DALI_2: 1 Ballast
  • 16.5V Busvoltage
  • 1.5mm2 cable for the bus cables

The signal for the "ON" command looks like enter image description hereenter image description here

Now no channels (or drivers) are detected, but the ON\ OFF goes through.

How can I initialize each channel? Are the edges of the signal flanks to rough in order to detect it by the drivers? Why are 'broadcast to all' commands work, but initializing only sets one address for all channels?

\$\endgroup\$
4
  • \$\begingroup\$ I'd agree that it looks like the Cosino library code is assigning Short Address 0 to all 4 channels but it's difficult to see exactly why without access to your setup. Do you have a DALI sniffer/analyser/logger that can show the bus messages during addressing? A common one is Tridonic DALI USB. The problem is I don't have confidence in either Skydance driver since it is not listed in dali-alliance.org as certified or in the library code since it refers to an obselete standard (since 2009) and cannot handle more than 1 device type out of 9. \$\endgroup\$
    – Martin
    Apr 20, 2021 at 14:10
  • \$\begingroup\$ Also the interface circuit that NabiyevTR provides isn't really good enough. The power supply is just specified as 12V 40W, which can drive 666mA when DALI PSUs require 250mA max and a fast current limit circuit. You can't use a standard PSU with its large caps and rely on the power rating, risks damaging all transmit transistors (master and slave) and several have done that according to their comments. In the latest version of the standard, the bus PSU min value is 12.0V, so a typical 12V +/-5% or 10% supply isn't strictly correct. The rise and fall times are not controlled to spec either. \$\endgroup\$
    – Martin
    Apr 20, 2021 at 14:57
  • \$\begingroup\$ My next step would be to improve the circuit. I bought a cheap driver to get myself acquainted with DALI. The PSU I am using is for laboratories and can be adjusted be adjusted accordingly. Since some commands are getting through I think that the circuit is just good enough. Before I analyze the BUS messages in more detail (a good oscilloscope is available) is it wiser to invest in a certified LED-Driver? \$\endgroup\$
    – v3xX
    Apr 20, 2021 at 16:58
  • \$\begingroup\$ At least have more than one LED driver for testing, and please test with at least two connected while running the addressing and check for responses on the scope. Responses are easy to spot because they are half the length of the commands. When multiple drivers are present, including your "multiple address" single driver, you should see collisions in the responses - lows longer than 1ms. An easy, fast current limiter is the Precision Current limiter shown electronics.stackexchange.com/questions/27502/… using LM317 and appropriate resistor. \$\endgroup\$
    – Martin
    Apr 21, 2021 at 10:01

1 Answer 1

1
\$\begingroup\$

The waveforms show that the DALI signal is well out of spec, which will be due to the use of the wrong power supply circuit. The high level voltage at 16.5V is acceptable, but the low voltage at 7.6V is wrong. DALI transmitters must pull the bus down to below 4.5V for the signal to be valid. There is an allowance of 2V for the line drop which means that receivers have to accept up to 6.5V as a low, which means they must set their voltage threshold between 6.5V and 9.5V. Therefore a low of 7.6V is indeterminate and will result in unpredictable results - some receivers might accept this signal under some conditions eg temperature and some might not.

The other obvious problem in these waveforms is the fall time, which seems to be around 100us. Although Edition 1 allowed up to 100us rise and fall times, the current Edition 2 has tightened that up to 25us maximum since larger rates were resulting in incorrect bit times and too much variance in received bit times due to the range of allowed threshold voltages. However, note that the fall time of these waveforms can't really be measured according to the standard which measures the time between 11.5V and 4.5V since the waveform does not reach 4.5V.

DALI transmitters are basically open collectors which pull down the bus voltage, which means the system relies on accurate and fast current limiting to produce the correct waveforms and to protect the drive transistors. Standard power supply current limit circuits do not have the right characterstics for this application and are behind large capacitors which can supply large peak currents.

The minimum circuit that might work is an LM317 with a resistor between Vout and Vadj LM317 current limiter

with a suitable resistor of 5 to 156 ohms depending on what current limit you want, 250mA to 8mA respectively. The output of this circuit is connected to Vadj, not Vout. Also note that unlike a normal power supply you cannot add arbitrarily large capacitors after the current limiter; I would caution against adding any.

When designing your own bus power supply you have to take into account more than just voltage and current limit; there is a whole of section 6 in IEC62386-101 which specifies all the requirement, including dynamic behaviour, short circuit behaviour and power up requirements as well as isolation. If this is for professional rather than hobbyist use, consider buying one of the products listed on the DALI Alliance certified products page.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks. I already improved my circuit based on a comment of my question and a similar problem appeared (with current limiting of an external powersupply). I would have answered my question with a reference to the improved one. If you can add that the circuit of the question is not a good setup and should be improved, I can fully accept the answer. \$\endgroup\$
    – v3xX
    Apr 29, 2021 at 12:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.