1. New to Christmas lighting? Get started with the AusChristmasLighting 101 Manual:
    auschristmaslighting.com/wiki/AusChristmasLighting-101

ESP8266 adapter for AC-SSR boards - testers needed.

Discussion in 'DMX, E1.31 & Networking' started by Barnabybear, Mar 1, 2017.

  1. Barnabybear

    Barnabybear New Elf

    Joined:
    Mar 30, 2012
    Messages:
    21
    Likes Received:
    1
    Location:
    UK
    Hi, this simply an ESP with zero cross detection that will plug directly into Renard type AS-SSR boards and control them from e1.31 packets. Early tests look good with 4 and 8 channels but I’m still working on the mods for the 8. Let me know what you think.

    A schematic and code attached below and before that some notes / random thoughts:

    This schematic and code only supports four channels on GPIOs 12 (D6), 13 (D7), 14 (D5), & 16 (D0).

    The second four channels will be on GPIOs 0 (D3), 2 (D4), 4 (D2) & 5 (D1) and the zero cross will move to Rx (RXD), I’ve not implemented the Rx change yet as it will require a jumper to disconnect the zero cross to upload the software and that seems a bit silly at this stage of testing / development.

    You will need to set your own network and show values in this section. These should be lines 26 to 29.
    - const char ssid[] = "<YOUR_SSID>"; // AP SSID
    - const char passphrase[] = "<YOUR_AP_PASSWORD>"; // AP password
    - const int universe = 1; // universe number
    - const int channel = 1; // start channel (first of the 4 consecutive to be used)

    Until an E1.31 packet is received the outputs will send out the ‘= values’. Once a packet has been received its values will be sent out until a new one is received. These should be lines 14 to 17.
    - int channel_value_1 = 255; // update & dummy values for channel data
    - int channel_value_2 = 155; // update & dummy values for channel data
    - int channel_value_3 = 55; // update & dummy values for channel data
    - int channel_value_4 = 1; // update & dummy values for channel data

    When compile/flashing, in tools set the CPU frequency to 160MHz for best results.

    When booted the ESP will output through serial @ 115200 baud, its connection status and when connected the IP address.

    The ESP will crash (WDT) if a zero cross signal is not seen before the Wi-Fi connection is completed / main loop starts to run. This is not thought to be a problem as the ESP is likely to be powered from the same AC source as the zero cross. Given the 2 to 5 seconds Wi-Fi connection time the zero cross signal will be in place before the main loop runs.

    Reasons for this to not work:
    - The most common value of series resistor on AC SSRs seems to be 680 ohms. This value was picked to be used with a 5V signal it may be to large when used with the 3.3V signal from an ESP.
    - As I live in the UK where is mains 240V @ 50Hz, I’ve had to use an Arduino to emulate a zero cross signal at 60Hz. If you don’t get an output try reducing ‘unsigned int step_delay = 30; // delay for 60Hz’. It can be anything down to 1 but reduces the duty cycle.

    An important thought – normally on any ESP project I would protect the outputs with a 270 ohm resistor as the outputs are only good for 12mA, yes 12mA. The SSRs already have current limiting resistors we can’t add any more. So please be careful not to short the pins on the RJ45s.

    GPIO15 is toggled high and low buy the code as a debug. If things don't go well and you have a logic analyser or scope this will give some pointers as to the problem.

    “WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 8, 0x8000);” appears all over the place. It’s direct port addressing, the same as ‘digitalWrite (output_4, HIGH)’ but faster. If you’re interested, read the next text, if not skip it as it’s not important to know the details.

    - The ESP is a little different to an Arduino in that it has three registers associated with the output port:
    - GPIO_OUT this holds the value to be outputted, the same as ‘PORTD’.
    - GPIO_OUT_W1TS (Write 1 To Set) writing a 1 to a bit in this register will set the same bit in GPIO_OUT without changing any of the other values. The same as ‘PORTD = PORTD |0x0001’.
    - GPIO_OUT_W1TC (Write 1 To Clear) writing a 1 to a bit in this register will clear the same bit in GPIO_OUT without changing any of the other values. The same as ‘PORTD &= PORTD ~0x0001’.
    - GPIO_OUT is at ‘BASEADDR + 0’ (0x60000300).
    - GPIO_OUT_W1TS is at ‘BASEADDR + 4’ (0x60000304).
    - GPIO_OUT_W1TC is at ‘BASEADDR + 8’ (0x60000308).

    That’s all I can think of so thanks for trying this and have fun.

    Development schematic - only outputs four channels.
    [​IMG]


    Code:
    // ESP8266-12 development code V0.1 by Barnabybear (consider to be non-working).
    #include <ESP8266WiFi.h>
    #include <E131.h> // https://github.com/forkineye/E1.31
    
    // set the pin numbers of the in/outputs
    int output_1 = 12; // (D6) pin number of output 1 to triac
    int output_2 = 13; // (D7) pin number of output 2 to triac
    int output_3 = 14; // (D5) pin number of output 3 to triac
    int output_4 = 16; // (D0) pin number of output 4 to triac
    int output_D = 15; // (D8) debug waveform output
    int input_zc = 4; // (D2) pin number of zero cross input
    
    // variables for the DMX value & dummy untill E1.31 arrives
    int channel_value_1 = 255; // update & dummy values for channel data
    int channel_value_2 = 155; // update & dummy values for channel data
    int channel_value_3 = 55; // update & dummy values for channel data
    int channel_value_4 = 1; // update & dummy values for channel data
    
    // general variables
    long int num_channels; // number of DMX values in E1.31 packet
    int loop_number = 255; // number of times too/looped
    unsigned int step_ends; // single loop time value
    unsigned int step_delay = 30; // delay for 60Hz
    
    // E1.31 setup
    const char ssid[] = "<YOUR_SSID>"; // AP SSID
    const char passphrase[] = "<YOUR_AP_PASSWORD>"; // AP password
    const int universe = 1; // universe number
    const int channel = 1; // start channel
    E131 e131;
    
    void setup() {
      // start serial
      Serial.begin(115200); // outputs - IP etc
      
      // set the function & state of the in / output pins
      pinMode(input_zc, INPUT); // set pin 4 as input
      pinMode(output_1, OUTPUT); // set pin 12 (D6) as output
      pinMode(output_2, OUTPUT); // set pin 13 (D7) as output
      pinMode(output_3, OUTPUT); // set pin 14 (D5) as output
      pinMode(output_4, OUTPUT); // set pin 16 (D0) as output
      pinMode(output_D, OUTPUT); // set pin 15 (D8) as output
      digitalWrite(output_1, HIGH);  // set output low / off
      digitalWrite(output_2, HIGH);  // set output low / off
      digitalWrite(output_3, HIGH);  // set output low / off
      digitalWrite(output_4, HIGH);  // set output low / off
      digitalWrite(output_D, LOW);  // set output low / off
      
      // select unicast or multicast - one must be commented out
      //e131.begin(ssid, passphrase); // unicast
      e131.beginMulticast(ssid, passphrase, universe); // multicast
    }
    
    void loop() {
      WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 8, 0x8000); // DEBUG LOW not part of finished code
      WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 4, 0x8000); // DEBUG HIGH not part of finished code
      num_channels = e131.parsePacket(); //if a new packet has arrived parse it
      WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 8, 0x8000); // DEBUG LOW not part of finished code
      // do this if a new packet arrives
      if (num_channels) { // if a new packet has arrived - set new channel values
        channel_value_1 = (e131.data[channel + 1]);  // update with value from E1.31 packet
        channel_value_2 = (e131.data[channel + 2]);  // update with value from E1.31 packet
        channel_value_3 = (e131.data[channel + 3]);  // update with value from E1.31 packet
        channel_value_4 = (e131.data[channel + 4]);  // update with value from E1.31 packet
        step_ends += 870; // as we didn't look for the zero cross & set 'stop_ends' (don't have time to when a packet comes in)
        // use the value from the last loop and add some time to make the end time correct
      }
      else { // do this if NO new packet
        WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 4, 0x8000); //DEBUG HIGH not part of finished code
        while (!digitalRead(input_zc)); // loop untill zero cross pin goes high
        WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 8, 0x8000); //DEBUG LOW not part of finished code
        WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 4, 0x8000); //DEBUG HIGH not part of finished code
        while (digitalRead(input_zc)) { // loop untill zero cross pin goes low
          step_ends = micros(); // set time to now - saves a little time doing it in this loop
        }
        WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 8, 0x8000); //DEBUG LOW not part of finished code
      }
      do {
        // switch on output / triac if we have waited long enough
        if (loop_number == channel_value_1)
          WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 8, 0x1000); // set output low / on
        if (loop_number == channel_value_2)
          WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 8, 0x2000); // set output low / on
        if (loop_number == channel_value_3)
          WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 8, 0x4000); // set output low / on
        if (loop_number == channel_value_4)
     //     WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 9, 0x0001); // set output low / on
       digitalWrite(output_4, LOW); // set output low / on (haven't found the register for GPIO16)
    
        // wait untill it's time to loop & set the next outputs if required
        step_ends += step_delay; // add delay time to last end time to get new end time
        while (micros() < step_ends) { // check time now against end time & loop
          delay(0); // the magic delay - frees the processor to do some quick housekeeping, WiFi & stack stuff
        }
        loop_number--; // reduce loop counter by 1
      } while (loop_number > 0); // 'do' it all again unless ==0
      
      WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 4, 0xF000); // re-sets all outputs high as we are close to zero cross
      digitalWrite(output_4, HIGH); // apart from this one
      loop_number = 255; // re-set the value for loop counter ready for the next run
      WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + 4, 0x8000); //DEBUG HIGH not part of finished code
    }
    
     
  2. damo1271

    damo1271 Full Time Elf Generous Elf

    Joined:
    Oct 12, 2011
    Messages:
    195
    Likes Received:
    3
    Location:
    Adelaide
    Find Me On:
    Wow an awesome project. I am replacing almost all of my 240V stuff this year, otherwise would have been very useful.
    I do have some ESP modules around and If I get some time I will program one up to test.
     
  3. SmartAlecLights

    SmartAlecLights Im a SmartAlec what can i say! Community Project Designer

    Joined:
    May 4, 2010
    Messages:
    1,205
    Likes Received:
    12
    Location:
    S.A.
    Find Me On:
    great work Barnabybear,
    I built a similar controller over a month ago for my home automation system
    the only difference is it has 6 mosfets an it only does low voltage dc.

    How easy do you think it would be to change your code to do 6 outputs instead?
    thanks Alec
     

Share This Page