https://esp8266.ru/esp8266-gpio-register/
And the second table below lists the registers for setting in/out pullups etc.
https://esp8266.ru/esp8266-pin-register-strapping/
Basicaly for outputs there are two 16 bit registers:
GPIO_OUT_W1TS // Write 1 To Set.
GPIO_OUT_W1TC // Write 1 To Clear.
So if the GPIO is set as an output and you write a 1 to a bit position the corresponding GPIO will be set or cleared depending on which register you wrote to. If I remember correctly the bit positions correspond with the GPIO numbers apart for GPIO16 which is in the clock register.
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TS_ADDRESS, 0xF000); // set gpio 12 -> 15 output high / off
I've attached a sketch below with some working examples. It’s a 4 channel zero cross dimmer and won’t run without a 100Hz / 120Hz clock on pin 4 but will give you some ideas. GPIO 15 / D8 is just so I could debug with the logic analyser. I find it hard to track posts on here so PM me if you need any help.
#include <ESP8266WiFi.h>
#include <E131.h>
// 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
unsigned int step_delay = 35; // delay for 50Hz
// E1.31 setup
const char ssid[] = "<SSID>"; // AP SSID
const char passphrase[] = "<password>"; // AP password
const int universe = 101; // universe number
const int channel_1 = 1; // output 1 channel number
const int channel_2 = 2; // output 2 channel number
const int channel_3 = 3; // output 3 channel number
const int channel_4 = 4; // output 4 channel number
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
// WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U, READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U) & ~0x130);
// WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U, READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U) | 0x30);
// WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ENABLE_ADDRESS, READ_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_ENABLE_ADDRESS) | 0xF000); // set gpio 12 -> 15 as outputs
// WRITE_PERI_REG(RTC_GPIO_ENABLE, READ_PERI_REG(RTC_GPIO_ENABLE) | 1); // set gpio 16 as output
pinMode(output_D, OUTPUT); // set pin 15 (D8) as output
digitalWrite(output_1, HIGH); // set output high / off
digitalWrite(output_2, HIGH); // set output high / off
digitalWrite(output_3, HIGH); // set output high / off
digitalWrite(output_4, HIGH); // set output high / off
// WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TS_ADDRESS, 0xF000); // set gpio 12 -> 15 output high / off
// WRITE_PERI_REG(RTC_GPIO_OUT, READ_PERI_REG(RTC_GPIO_OUT) | 1); // set gpio 16 output high
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 + GPIO_OUT_W1TC_ADDRESS, 0x8000); // DEBUG LOW not part of finished code
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TS_ADDRESS, 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 + GPIO_OUT_W1TC_ADDRESS, 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 + GPIO_OUT_W1TS_ADDRESS, 0x8000); //DEBUG HIGH not part of finished code
// while (!(READ_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS)& 0x10)); // loop untill zero cross pin goes high
// while (READ_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_IN_ADDRESS)& 0x10) { // loop untill zero cross pin goes low
while (!digitalRead(input_zc));
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TC_ADDRESS, 0x8000); // DEBUG LOW not part of finished code
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TS_ADDRESS, 0x8000); // DEBUG HIGH not part of finished code
while (digitalRead(input_zc)) {
step_ends = micros(); // set time to now - saves a little time doing it in this loop
}
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TC_ADDRESS, 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 + GPIO_OUT_W1TC_ADDRESS, 0x1000); // set output low / on
if (loop_number == channel_value_2)
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TC_ADDRESS, 0x2000); // set output low / on
if (loop_number == channel_value_3)
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TC_ADDRESS, 0x4000); // set output low / on
if (loop_number == channel_value_4)
WRITE_PERI_REG(RTC_GPIO_OUT, READ_PERI_REG(RTC_GPIO_OUT) & ~1); // set output low / on
// 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 + GPIO_OUT_W1TS_ADDRESS, 0xF000); // re-sets all outputs high as we are close to zero cross
WRITE_PERI_REG(RTC_GPIO_OUT, READ_PERI_REG(RTC_GPIO_OUT) | 1); // set output high / on
loop_number = 255; // re-set the value for loop counter ready for the next run
}
Should be quite easy to generate the WS2812b signal.
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TS_ADDRESS, <all GPIOs>); // set all high
delay();
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TC_ADDRESS, <some GPIOs>); // set 0s low leave 1s high
delay();
WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TC_ADDRESS, <all GPIOs>); // set all low
delay();
Using the above a high - low for a '1' can be done in 83nS and a high - low for a '0' can be done in 166nS, so plenty fast enough. The slow part is returning to the start of the loop, from a '0' going low to the start of the next 'start' going high takes 3uS. You have 6uS to do this in, so not a problem but it doesn't leave you much processing time for data.