Barnabybear
New elf
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:
- GPI
UT this holds the value to be outputted, the same as ‘PORTD’.
- GPI
UT_W1TS (Write 1 To Set) writing a 1 to a bit in this register will set the same bit in GPI
UT without changing any of the other values. The same as ‘PORTD = PORTD |0x0001’.
- GPI
UT_W1TC (Write 1 To Clear) writing a 1 to a bit in this register will clear the same bit in GPI
UT without changing any of the other values. The same as ‘PORTD &= PORTD ~0x0001’.
- GPI
UT is at ‘BASEADDR + 0’ (0x60000300).
- GPI
UT_W1TS is at ‘BASEADDR + 4’ (0x60000304).
- GPI
UT_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.
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:
- GPI
- GPI
- GPI
- GPI
- GPI
- GPI
That’s all I can think of so thanks for trying this and have fun.
Development schematic - only outputs four channels.
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
}
Last edited: