Skip to content

GPIO_OUTPUT_SET() vs GPIO_OUT_W1TS/GPIO_OUT_W1TC comparison

Notifications You must be signed in to change notification settings

wdim0/esp8266_direct_gpio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 

Repository files navigation

Faster GPIOs on ESP8266

Do you use standard GPIO_OUTPUT_SET() macros for your bit-banging and do you want to make it faster? Well, then you're on the right place. Continue reading and you'll see how to get 6x faster GPIOs compared to standard GPIO_OUTPUT_SET() macros.

The way I see it, GPIO_OUTPUT_SET() was/is intended to be just for first initialization. For controlling the output GPIOs in the code it's much better to skip all the unnecessary calling underlying the GPIO_OUTPUT_SET() and set output GPIO pins directly using GPIO_OUT_W1TS_ADDRESS / GPIO_OUT_W1TC_ADDRESS registers. The resulting code will be smaller and faster.

Test A - using GPIO_OUTPUT_SET()

PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15);
GPIO_OUTPUT_SET(15, 1);
//
while(1){
    uint8_t i;
    for(i=0;i<20;i++) GPIO_OUTPUT_SET(15, 1);
    GPIO_OUTPUT_SET(15, 0);
    //
    vTaskDelay(1);
}

Test A

Test B - using GPIO_OUT_W1TS/C directly

PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15);
GPIO_OUTPUT_SET(15, 1);
//
while(1){
    uint8_t i;
    for(i=0;i<20;i++) GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1<<15);
    GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1<<15);
    //
    vTaskDelay(1);
}

Test B

The timebase of the scope is set to 2 us per div in both test cases.
Test A - impulse length is around 12 us.
Test B - impulse length is around 1.9 us
=> code B is around 6x faster than A

Tests configuration: ESP8266 running at default 80 MHz, RTOS (SDK 1.4.0)

GPIO_OUT_W1TS/C details

Each register is for all GPIOs - every bit corresponds to one GPIO (GPIO 0 is bit0, GPIO 1 is bit1, ...). You don't need to mask anything. If you just want to set one GPIO H/L, set the proper bit to 1, leave other bits to 0. Easy, fancy, fast.

GPIO_OUT_W1TS_ADDRESS - write 1 to set GPIO (high)

GPIO_OUT_W1TC_ADDRESS - write 1 to clear GPIO (low)

Reading these registers, will give you 0 - they are just for writing.

Conclusion

It's definitely better to use direct GPIO control of output pins by writing to GPIO_OUT_W1TS_ADDRESS / GPIO_OUT_W1TC_ADDRESS registers. I've briefly looked into Espressif's GPIO driver (gpio.c, gpio.h) but there are no macros dedicated to this exactly. But anyway, it's so easy that we can do our own macros.

Also, if you're using standard GPIO_INPUT_GET(...) for reading of GPIO inputs, you can optimize for speed. Just simply read GPIO_IN_ADDRESS register directly like this:
((GPIO_REG_READ(GPIO_IN_ADDRESS)&(BIT(12)))!=0)

To sum it up and give you some hints:

... macros:

#define GPIO4           ((GPIO_REG_READ(GPIO_IN_ADDRESS)&(BIT(4)))!=0) //each bit is for corresponding GPIO

#define GPIO2_H         (GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1<<2))
#define GPIO2_L         (GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1<<2))
#define GPIO2(x)        ((x)?GPIO2_H:GPIO2_L)

... init:

PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
GPIO_OUTPUT_SET(2, 0); //GPIO2 as output low

GPIO_DIS_OUTPUT(4); //GPIO4 as input
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);

... work with GPIOs:

GPIO2_H; //set GPIO2 high (as fast as possible)
GPIO2_L; //set GPIO2 low (as fast as possible)
GPIO2(1); //set GPIO2 high (slightly slower, because of decision in macro)
GPIO2(GPIO4); //set on GPIO2 the same level as is on GPIO4 input

About

GPIO_OUTPUT_SET() vs GPIO_OUT_W1TS/GPIO_OUT_W1TC comparison

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published