Introduction: Faster ESP32
There are two ways to make the ESP32 GPIO stay at 0 or 1. You can call the #digitalwrite function, or you can go straight to the recorder. I’m showing the second option today: how to go straight to the register and write in the memory. This way, the command will instantly change state. Thus, we’ll first learn how to modify multiple GPIOs at once by using bitmasks. In our example today, we used five leds.
Step 1: Demonstration
Step 2: Registers /sdk/include/soc/soc/rtc_io_struct.h
union {
struct { uint32_t reserved0:14; uint32_t w1ts:18; /*GPIO0~17 output value write 1 to set*/ }; uint32_t val; } out_w1ts; union { struct { uint32_t reserved0:14; uint32_t w1tc:18; /*GPIO0~17 output value write 1 to clear*/ }; uint32_t val; } out_w1tc;
Step 3: DigitalWrite ESP32 Code Arduino /cores/esp32/esp32-hal-gpio.c
extern void IRAM_ATTR __digitalWrite(uint8_t pin, uint8_t val){ if(val) { if(pin < 32) { GPIO.out_w1ts = ((uint32_t)1 << pin); } else if(pin < 34) { GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32)); } } else { if(pin < 32) { GPIO.out_w1tc = ((uint32_t)1 << pin); } else if(pin < 34) { GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32)); } } }
Step 4: Multiple Pins at Once Ex.1
Setup
void setup()
{ //Configuração dos gpios gpio_config_t io_conf //Colocamos como OUTPUT io_conf.mode = GPIO_MODE_OUTPUT; //Definição dos gpios que fazem parte desta configuração //Da direita para a esquerda, os que tem 1 fazem parte da configuração //Neste exemplo, contando da direita para esquerda (começando do 0) temos o gpio 2 e o gpio 4 //Para facilitar quando temos pinos de valor alto podemos utilizar //deslocamento de bits, por exemplo: (1 << 2) | (1 << 4) io_conf.pin_bit_mask = 0b10100; //Ou poderia ser //io_conf.pin_bit_mask = (1 << 2) | (1 << 4); //Aplica a configuração gpio_config(&io_conf); }
Loop
void loop()
{ //Máscara de bits com os pinos que serão "setados" como ativos GPIO.out_w1ts = 0b10100; //Ou poderia ser //GPIO.out_w1ts = (1 << 2) | (1 << 4); //Delay de 1 segundo delay(1000); //Máscara de bits com os pinos serão desativados (clear) GPIO.out_w1tc = 0b10100; //Ou poderia ser //GPIO.out_w1tc = (1 << 2) | (1 << 4); //Delay de 1 segundo delay(1000); }
Step 5: Multiple Pins at Once Ex.2
Setup
//Máscara com os GPIOs 0, 2 e 4
//Se invertermos esta máscara com "~" teremos 0b01010 //e passamos a ter selecionados os GPIOs 1 e 3 int mask = 0b10101; void setup() { //Configuração dos gpios gpio_config_t io_conf; //Colocamos como OUTPUT io_conf.mode = GPIO_MODE_OUTPUT; //Definição dos gpios que fazem parte desta configuração //Da direita para a esquerda, os que tem 1 fazem parte da conifguração //No caso os GPIOs 0, 1, 2, 3 e 4 io_conf.pin_bit_mask = 0b11111; //Aplica a configuração gpio_config(&io_conf); }
Loop
void loop()
{ //Invertamos os bits da máscara //Os que estavam selecionados são desselecionados e vice-versa mask = ~mask; //Máscara de bits com os pinos que serão "setados" como ativos GPIO.out_w1ts = mask; //Máscara de bits com os pinos que serão desativados (clear) GPIO.out_w1tc = ~mask; //Delay de 1 segundo delay(1000); }
Step 6: Digital Speed TestWrite
void setup()
{ pinMode(4, OUTPUT); } void loop() { digitalWrite(4, HIGH); digitalWrite(4, LOW); }
Step 7: Speed Test Bit Mask
void setup(){ //Configuração dos gpios gpio_config_t io_conf; //Colocamos como OUTPUT io_conf.mode = GPIO_MODE_OUTPUT; //Definição dos gpios que fazem parte desta configuração io_conf.pin_bit_mask = 0b10000; //Aplica a configuração gpio_config(&io_conf); } void loop() { //Máscara de bits com os pinos que serão "setados" como ativos GPIO.out_w1ts = 0b10000; //Máscara de bits com os pinos serão desativados (clear) GPIO.out_w1tc = 0b10000; }
3 Comments
3 months ago
"Old way": Period ~2.2us (freq. approx. = 455Khz), and there is a 300ns phase-lag between RED and GRN pulses; 600ns lag RED-BLU, due to sequential writes (see images)
"New way": Period ~200ns (freq. approx. = 5Mhz), and there is no lag - pulses are simultaneous.
These images are screenshots from my 10-yr-old 2-chan USB O'scope. RED is the red line in all images, but there are two images for each "way" - one shows GRN in blue, the other shows BLU in blue. The 5Mhz signal is really too fast for it, but it has captured the fundamental frequency and relative phase of the output signals.
------------------------------[ code ]----------------------------------------
#include
// define gpios-- use consecutive GPIOs (consecutive io register bits)
// so "new way" can write all of them with one instruction
#define RED 17
#define GRN 18
#define BLU 19
// config gpios
gpio_config_t io_conf;
void setup()
{
// output mode - old way
pinMode(RED, OUTPUT);
pinMode(GRN, OUTPUT);
pinMode(BLU, OUTPUT);
// output mode - new way
io_conf.intr_type = (gpio_int_type_t)GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
// io_conf.pin_bit_mask = (1 << RED) | (1 << GRN) | (1 << BLU); // or
io_conf.pin_bit_mask = (0b111 << RED); // or
// io_conf.pin_bit_mask = (0b11100000000000);
gpio_config(&io_conf);
}
void old_way()
{
digitalWrite(RED, HIGH);
digitalWrite(GRN, HIGH);
digitalWrite(BLU, HIGH);
digitalWrite(RED, LOW);
digitalWrite(GRN, LOW);
digitalWrite(BLU, LOW);
}
void new_way() {
// GPIO.w1ts = (1 << RED) | (1 << GRN) | (1 << BLU); // or
GPIO.out_w1ts = (0b111 << RED);
// GPIO.out_w1tc = (1 << RED) | (1 << GRN) | (1 << BLU); //or
GPIO.out_w1tc = (0b111 << RED);
}
void loop() { new_way(); }
2 years ago
I found that ";" is missing at the end of "gpio_config_t io_conf"
Thank you for this software.
JY
Question 2 years ago on Step 10
Hello Mr. Fernando Koyanagi
I like the way you quickly change the state of ESP32's GPIOs. However, while uploading your examples to the Arduino IDE, I get the following message: "expected initializer before 'io_conf'".
Where is my mistake?
Thank you for your reply.
jyfiloche@sfr.fr