Commit e44ea54cde229bd447cc03a99697a16bc2b32450

Authored by qqqlab
Committed by GitHub
1 parent 14e13c2c

.

Documentation/DALI Commands.xlsx 0 → 100644
No preview for this file type
Documentation/Renesas DALI Applicaton Note.pdf 0 → 100644
No preview for this file type
Examples/Commissioning/Commissioning.ino
... ... @@ -50,26 +50,28 @@ void loop() {
50 50 while (Serial.available() > 0) {
51 51 int incomingByte = Serial.read();
52 52 switch(incomingByte) {
53   - case '1': menu_flash(); menu(); break;
  53 + case '1': menu_blink(); menu(); break;
54 54 case '2': menu_scan_short_addr(); menu(); break;
55 55 case '3': menu_commission(); menu(); break;
56   - case '4': menu_delete_short_addr(); menu(); break;
  56 + case '4': menu_commission_debug(); menu(); break;
  57 + case '5': menu_delete_short_addr(); menu(); break;
57 58 }
58 59 }
59 60 }
60 61  
61 62 void menu() {
62 63 Serial.println("----------------------------");
63   - Serial.println("1 Flash all lights");
  64 + Serial.println("1 Blink all lamps");
64 65 Serial.println("2 Scan short addresses");
65 66 Serial.println("3 Commission short addresses");
66   - Serial.println("4 Delete short addresses");
  67 + Serial.println("4 Commission short addresses (VERBOSE)");
  68 + Serial.println("5 Delete short addresses");
67 69 Serial.println("----------------------------");
68 70 }
69 71  
70 72  
71   -void menu_flash() {
72   - Serial.println("Running: Flash all");
  73 +void menu_blink() {
  74 + Serial.println("Running: Blinking all lamps");
73 75 for(uint8_t i=0;i<5;i++) {
74 76 dali.set_level(254);
75 77 Serial.print(".");
... ... @@ -117,8 +119,18 @@ void menu_scan_short_addr() {
117 119  
118 120 //might need a couple of calls to find everything...
119 121 void menu_commission(){
120   - Serial.println("Running: Commission - be patient, this takes a while ....");
121   -// uint8_t cnt = dali.commission(0xff); //init_arg=0b11111111 : all without short address
  122 + Serial.println("Running: Commission");
  123 + Serial.println("Might need a couple of runs to find all lamps ...");
  124 + Serial.println("Be patient, this takes a while ...");
  125 + uint8_t cnt = dali.commission(0xff); //init_arg=0b11111111 : all without short address
  126 + Serial.print("DONE, assigned ");Serial.print(cnt);Serial.println(" new short addresses");
  127 +}
  128 +
  129 +//might need a couple of calls to find everything...
  130 +void menu_commission_debug(){
  131 + Serial.println("Running: Commission (VERBOSE)");
  132 + Serial.println("Might need a couple of runs to find all lamps ...");
  133 + Serial.println("Be patient, this takes a while ...");
122 134 uint8_t cnt = debug_commission(0xff); //init_arg=0b11111111 : all without short address
123 135 Serial.print("DONE, assigned ");Serial.print(cnt);Serial.println(" new short addresses");
124 136 }
... ... @@ -140,26 +152,25 @@ uint8_t debug_commission(uint8_t init_arg) {
140 152 uint8_t arr[64];
141 153 uint8_t sa;
142 154 for(sa=0; sa<64; sa++) arr[sa]=0;
143   -
144   - //find existing short addresses when not assigning all
145   - if(init_arg!=0b00000000) {
146   - Serial.println("Find existing short adr");
147   - for(sa = 0; sa<64; sa++) {
148   - int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
149   - if(rv!=DALI_RESULT_NO_REPLY) {
150   - arr[sa]=1;
151   - Serial.print("sortadr=");
152   - Serial.print(sa);
153   - Serial.print(" status=0x");
154   - Serial.print(rv,HEX);
155   - Serial.print(" minLevel=");
156   - Serial.println(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
157   - }
158   - }
159   - }
160 155  
  156 + dali.cmd(DALI_RESET,0x00);
161 157 dali.cmd(DALI_INITIALISE,init_arg);
162 158 dali.cmd(DALI_RANDOMISE,0x00);
  159 +
  160 + //find used short addresses (run always, seems to work better than without...)
  161 + Serial.println("Find existing short adr");
  162 + for(sa = 0; sa<64; sa++) {
  163 + int16_t rv = dali.cmd(DALI_QUERY_STATUS,sa);
  164 + if(rv!=DALI_RESULT_NO_REPLY) {
  165 + if(init_arg!=0b00000000) arr[sa]=1; //remove address from list if not in "all" mode
  166 + Serial.print("sortadr=");
  167 + Serial.print(sa);
  168 + Serial.print(" status=0x");
  169 + Serial.print(rv,HEX);
  170 + Serial.print(" minLevel=");
  171 + Serial.println(dali.cmd(DALI_QUERY_MIN_LEVEL,sa));
  172 + }
  173 + }
163 174  
164 175 Serial.println("Find random adr");
165 176 while(1) {
... ...
Examples/Monitor/Monitor.ino 0 → 100644
  1 +/*###########################################################################
  2 +DALI Interface Demo
  3 +
  4 +Monitors all messages on the DALI bus
  5 +
  6 +----------------------------------------------------------------------------
  7 +Changelog:
  8 +2020-11-10 Created & tested on ATMega328 @ 8Mhz
  9 +----------------------------------------------------------------------------
  10 + Monitor.ino - copyright qqqlab.com / github.com/qqqlab
  11 +
  12 + This program is free software: you can redistribute it and/or modify
  13 + it under the terms of the GNU General Public License as published by
  14 + the Free Software Foundation, either version 3 of the License, or
  15 + (at your option) any later version.
  16 +
  17 + This program is distributed in the hope that it will be useful,
  18 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20 + GNU General Public License for more details.
  21 +
  22 + You should have received a copy of the GNU General Public License
  23 + along with this program. If not, see <http://www.gnu.org/licenses/>.
  24 +###########################################################################*/
  25 +
  26 +#define DALI_OUTPUT_PIN 3
  27 +#define DALI_INPUT_PIN 4
  28 +
  29 +#include "qqqDali_ATMega328.h"
  30 +
  31 +Dali_ATMega328 dali;
  32 +
  33 +uint8_t rx_out=0;
  34 +volatile uint8_t rx_in=0;
  35 +uint8_t rx_data[256];
  36 +
  37 +//callback to handle received data on dali2 interface - executes in interrupt context, store data in buffer and display in loop()
  38 +void dali_receiver(Dali *d, uint8_t *data, uint8_t len) {
  39 + //push data in buffer
  40 + int16_t freebuf = (int16_t)256 + rx_in - rx_out - len - 2;
  41 + if(freebuf<=1) return; //buffer full
  42 + uint8_t j = rx_in;
  43 + rx_data[j++] = len; //push length
  44 + for(uint8_t i=0;i<len;i++) rx_data[j++]=data[i]; //push data
  45 + rx_in = j; //increment in pointer upon completion
  46 +}
  47 +
  48 +
  49 +void setup() {
  50 + Serial.begin(115200);
  51 + Serial.println("DALI Monitor Demo");
  52 +
  53 + //start the DALI interfaces
  54 + //arguments: tx_pin, rx_pin (negative values disable transmitter / receiver)
  55 + //Note: the receiver pins should be on different PCINT groups, e.g one
  56 + //receiver on pin0-7 (PCINT2) one on pin8-13 (PCINT0) and one on pin14-19 (PCINT1)
  57 + dali.begin(DALI_OUTPUT_PIN, DALI_INPUT_PIN);
  58 +
  59 + //attach a received data handler
  60 + dali.EventHandlerReceivedData = dali_receiver;
  61 +}
  62 +
  63 +#define MIN_LEVEL 100 //most LED Drivers do not get much lower than this
  64 +int16_t level = 254; //254 is max level, 1 is min level (if driver supports it), 0 is off
  65 +int8_t level_step = 4;
  66 +
  67 +void loop() {
  68 + if(rx_out!=rx_in) {
  69 + //Serial.print("RX:");
  70 + uint8_t len = rx_data[rx_out++];
  71 + for(uint8_t i=0;i<len;i++) {
  72 + Serial.print(rx_data[rx_out++],HEX);
  73 + Serial.print(' ');
  74 + }
  75 + Serial.println();
  76 + }
  77 +}
... ...
qqqDali.cpp
... ... @@ -24,7 +24,7 @@ Changelog:
24 24 //###########################################################################
25 25 // Helpers
26 26 //###########################################################################
27   -#define DALI_TOL 15 //allow for 15% tolerance on timing (DALI spec calls for 10%, add 5% for uc clock tolerance)
  27 +#define DALI_TOL 25 //percentage tolerance on timing. DALI specs call for 10%, but use higher value to allow for implementation micros() jitter. NOTE: Max value is 50% to differentiate between TE and 2TE.
28 28 #define DALI_TE ((1000000+(DALI_BAUD))/(2*(DALI_BAUD))) //417us
29 29 #define DALI_TE_MIN ((100-DALI_TOL)*DALI_TE)/100
30 30 #define DALI_TE_MAX ((100+DALI_TOL)*DALI_TE)/100
... ... @@ -157,7 +157,7 @@ void Dali::ISR_pinchange() {
157 157 this->rx_state = RX_IDLE;
158 158 //TODO rx error
159 159 return;
160   - }
  160 + }
161 161 break;
162 162 }
163 163 }
... ... @@ -177,34 +177,42 @@ void Dali::push_halfbit(uint8_t bit) {
177 177 //###########################################################################
178 178 // Dali Class
179 179 //###########################################################################
  180 +
  181 +//non blocking send - check tx_state for completion, check tx_collision for collision errors
180 182 uint8_t Dali::send(uint8_t* tx_msg, uint8_t tx_len_bytes) {
181   - if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG);
  183 + if(tx_len_bytes>3) return -(DALI_RESULT_DATA_TOO_LONG);
182 184 if(this->tx_state != TX_IDLE) return -(DALI_RESULT_TIMEOUT);
183 185 for(uint8_t i=0;i<tx_len_bytes;i++) this->tx_msg[i]=tx_msg[i];
184 186 this->tx_len = tx_len_bytes<<3;
185 187 this->tx_collision=0;
186   - this->tx_state = TX_START;
  188 + this->tx_state = TX_START; //start transmission
187 189 return 0;
188 190 }
189 191  
  192 +//blocking send - wait until successful send or timeout
190 193 uint8_t Dali::sendwait(uint8_t* tx_msg, uint8_t tx_len_bytes, uint32_t timeout_us) {
191   - if(tx_len_bytes>3) return -(DALI_RESULT_INVALID_TOO_LONG);
  194 + if(tx_len_bytes>3) return -(DALI_RESULT_DATA_TOO_LONG);
192 195 uint32_t ts = HAL_micros();
193   - //wait for idle
194   - while(this->tx_state != TX_IDLE) {
195   - if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TIMEOUT);
196   - }
197   - //start transmit
198   - uint8_t rv = this->send(tx_msg,tx_len_bytes);
199   - if(rv) return rv;
200   - //wait for completion
201   - while(this->tx_state != TX_IDLE) {
202   - if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TX_TIMEOUT);
  196 +
  197 + while(1) {
  198 + //wait for idle
  199 + while(this->tx_state != TX_IDLE) {
  200 + if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TIMEOUT);
  201 + }
  202 + //start transmit
  203 + uint8_t rv = this->send(tx_msg,tx_len_bytes);
  204 + if(rv) return rv;
  205 + //wait for completion
  206 + while(this->tx_state != TX_IDLE) {
  207 + if(HAL_micros() - ts > timeout_us) return -(DALI_RESULT_TX_TIMEOUT);
  208 + }
  209 + //check for collisions
  210 + if(this->tx_collision==0) return 0;
203 211 }
204   - return 0;
  212 + return -(DALI_RESULT_TIMEOUT);
205 213 }
206 214  
207   -//transmit 2 byte command, receive 1 byte reply
  215 +//blocking transmit 2 byte command, receive 1 byte reply (if reply was sent)
208 216 int16_t Dali::tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_us) {
209 217 uint8_t tx[2];
210 218 tx[0] = cmd0;
... ... @@ -227,8 +235,6 @@ int16_t Dali::tx(uint8_t cmd0, uint8_t cmd1, uint32_t timeout_us) {
227 235 return this->rx_msg[0];
228 236 }
229 237  
230   -
231   -
232 238 //=================================================================
233 239 // High level
234 240 //=================================================================
... ... @@ -324,7 +330,7 @@ void Dali::set_searchaddr(uint32_t adr) {
324 330 this->cmd(DALI_SEARCHADDRL,adr);
325 331 }
326 332  
327   -//set search address, but set only changed bytes
  333 +//set search address, but set only changed bytes (takes less time)
328 334 void Dali::set_searchaddr_diff(uint32_t adr_new,uint32_t adr_current) {
329 335 if( (uint8_t)(adr_new>>16) != (uint8_t)(adr_current>>16) ) this->cmd(DALI_SEARCHADDRH,adr_new>>16);
330 336 if( (uint8_t)(adr_new>>8) != (uint8_t)(adr_current>>8) ) this->cmd(DALI_SEARCHADDRM,adr_new>>8);
... ... @@ -336,8 +342,6 @@ uint8_t Dali::compare() {
336 342 return (0xff == this->cmd(DALI_COMPARE,0x00));
337 343 }
338 344  
339   -
340   -
341 345 //The slave shall store the received 6-bit address (AAAAAA) as a short address if it is selected.
342 346 void Dali::program_short_address(uint8_t shortadr) {
343 347 this->cmd(DALI_PROGRAM_SHORT_ADDRESS, (shortadr << 1) | 0x01);
... ... @@ -384,57 +388,45 @@ uint8_t Dali::commission(uint8_t init_arg) {
384 388 uint8_t arr[64];
385 389 uint8_t sa;
386 390 for(sa=0; sa<64; sa++) arr[sa]=0;
387   -
388   - //find existing short addresses when not assigning all
389   - if(init_arg!=0b00000000) {
390   - //Serial.println("Short adr");
391   - for(sa = 0; sa<64; sa++) {
392   - int16_t rv = this->cmd(DALI_QUERY_STATUS,sa);
393   - if(rv!=DALI_RESULT_NO_REPLY) {
394   - arr[sa]=1;
395   - //Serial.print(sa);
396   - //Serial.print(" status=0x");
397   - //Serial.print(rv,HEX);
398   - //Serial.print(" minLevel=");
399   - //Serial.println(this->cmd(DALI_QUERY_MIN_LEVEL,sa));
400   - }
401   - }
402   - }
403 391  
  392 + //start commissioning
  393 + this->cmd(DALI_RESET,0x00);
404 394 this->cmd(DALI_INITIALISE,init_arg);
405 395 this->cmd(DALI_RANDOMISE,0x00);
  396 +
  397 + //find used short addresses (run always, seems to work better than without...)
  398 + for(sa = 0; sa<64; sa++) {
  399 + int16_t rv = this->cmd(DALI_QUERY_STATUS,sa);
  400 + if(rv!=DALI_RESULT_NO_REPLY) {
  401 + if(init_arg!=0b00000000) arr[sa]=1; //remove address from list if not in "all" mode
  402 + }
  403 + }
406 404  
  405 + //find random addresses and assign unused short addresses
407 406 while(1) {
408   - //Serial.print("addr=");
409   - //Serial.println(this->get_random_address(0xff),HEX);
410   -
411 407 uint32_t adr = this->find_addr();
412 408 if(adr>0xffffff) break; //no more random addresses found -> exit
413   - //Serial.print("found adr=");
414   - //Serial.println(adr,HEX);
415 409  
416   - //Serial.print("short adr=");
417   - //Serial.println(dali_query_short_address());
418   -
419   - //find available address
  410 + //find first unused short address
420 411 for(sa=0; sa<64; sa++) {
421 412 if(arr[sa]==0) break;
422 413 }
423 414 if(sa>=64) break; //all 64 short addresses assigned -> exit
  415 +
  416 + //mark short address as used
424 417 arr[sa] = 1;
425 418 cnt++;
426 419  
427   - //Serial.print("program short adr=");
428   - //Serial.println(sa);
  420 + //assign short address
429 421 this->program_short_address(sa);
430   - //dali_program_short_address(0xff);
431   -
432   - //Serial.print("read short adr=");
  422 +
433 423 //Serial.println(this->query_short_address()); //TODO check read adr, handle if not the same...
434 424  
  425 + //remove the device from the search
435 426 this->cmd(DALI_WITHDRAW,0x00);
436 427 }
437   -
  428 +
  429 + //terminate the DALI_INITIALISE command
438 430 this->cmd(DALI_TERMINATE,0x00);
439 431 return cnt;
440 432 }
... ...
qqqDali.h
... ... @@ -60,7 +60,7 @@ public:
60 60  
61 61 //initialize variables
62 62 Dali() : tx_state(TX_IDLE), rx_state(RX_IDLE), tx_bus_low(0), tx_len(0), EventHandlerReceivedData(0) {};
63   -
  63 +
64 64 protected:
65 65 //low level functions
66 66 enum tx_stateEnum { TX_IDLE=0,TX_START,TX_START_X,TX_BIT,TX_BIT_X,TX_STOP1,TX_STOP1_X,TX_STOP2,TX_STOP2_X,TX_STOP3};
... ... @@ -79,6 +79,8 @@ protected:
79 79 volatile uint8_t rx_len; //number of bytes received
80 80 volatile int8_t rx_halfbitlen; //number of half bits received
81 81 volatile uint8_t rx_last_halfbit; //last halfbit received
  82 +
  83 +
82 84  
83 85 volatile uint8_t bus_idle_te_cnt; //number of Te since start of idle bus
84 86  
... ... @@ -94,13 +96,12 @@ protected:
94 96  
95 97 #define DALI_BAUD 1200
96 98  
97   -#define DALI_RESULT_TIMEOUT -1 //Timeout waiting for DALI bus
98   -#define DALI_RESULT_INVALID_TOO_LONG -2 //Trying to send too many bytes (max 3)
99   -#define DALI_RESULT_TX_TIMEOUT -3 //Timeout during transmission
100   -#define DALI_RESULT_NO_REPLY -4 //cmd() did not receive a reply (i.e. received a 'NO' Backward Frame)
101   -#define DALI_RESULT_INVALID_CMD -5 //The cmd argument in the call to cmd() was invalid
102   -#define DALI_RESULT_INVALID_REPLY -6 //cmd() received an invalid reply (too long)
103   -
  99 +#define DALI_RESULT_TIMEOUT -1 //Timeout waiting for DALI bus
  100 +#define DALI_RESULT_DATA_TOO_LONG -2 //Trying to send too many bytes (max 3)
  101 +#define DALI_RESULT_TX_TIMEOUT -3 //Timeout during transmission
  102 +#define DALI_RESULT_NO_REPLY -4 //cmd() did not receive a reply (i.e. received a 'NO' Backward Frame)
  103 +#define DALI_RESULT_INVALID_CMD -5 //The cmd argument in the call to cmd() was invalid
  104 +#define DALI_RESULT_INVALID_REPLY -6 //cmd() received an invalid reply (too long)
104 105  
105 106 //bit8=extended commands, bit9=repeat
106 107 #define DALI_OFF 0 //0 - Turns off lighting.
... ...