February 21, 2017

The ESP8266 - working with GPIO

First, some things to watch out for.

What about this GPIO 16?

This is (or can be) the output of a timer that runs when the unit is in deep sleep, and can be used to bring the module out of deep sleep by tripping reset. But if you don't need this capability, you can just use it as a PIO pin, but it has an interface all its own and is not discussed here.

The basic IO pin

As with most devices these days, there is competition for pins that connect to the outside world, the ESP8266 is no exception. So there is a software controlled mux (multiplexor) that you have to configure to indicate whether GPIO or something else is talking to a pin.

The above table gives the second argument to the following function:


Once you get the mux set up, you may want to enable (or disable) a weak pullup. This is the sort of thing you would only do for an input pin.


Once the pin is configured, you either write to it or read from it. You can also do PWM with GPIO pins or configure them to generate interrupts, but I am not discussing that here. If it is an input pin, you read values with this:

This gives you the values for all 16 pins, so you mask off whatever you want. Before you can actually read from an input pin, you must disable the output driver with a call like this:
gpio_output_set(0, 0, 0, mask)
But we need to talk about this call a bit more and the "mask" I am using here. Both gpio_input_get() and gpio_output_set() deal with all 16 gpio at one time. If you want to deal with just one at a time (which is the usual case), let us say GPIO4, you use a mask value of 0x10 (which is 1 << 4).

The gpio_output_set routine tries to do everything possible all at once, so the arguments are:

gpio_output_set(set_mask, clear_mask, enable_mask, disable_mask)
So to set a bit you do this:
gpio_output_set ( mask, 0, mask, 0 );
Here you are setting and enabling the desired bit, and neither clearing nor disabling any bits.

Notice a couple of things if you really want to understand this. First is that this routine could both be setting and clearing (along with enabling or disabling) any number of bits. This is not usually (i.e. hardly ever) done, but it could be.

Also notice that you could just enable the bit once during setup, then change its state using only the set or clear mask later. But enabling the bit every time does no harm and is what is usually done, for better or worse.

More than you need or want to know

If you are really curious about this, take a look at the code that implements these calls in the ROM. They are quite simple and fiddle with GPIO registers as follow:

;  0x60000304 <-- set
;  0x60000308 <-- clear
;  0x60000310 <-- enable
;  0x60000314 <-- disable
; to set high:  gpio_output_set ( m, 0, m, 0 )
; to set low:  gpio_output_set ( 0, m, m, 0 )
; for input:  gpio_output_set ( 0, 0, 0, m )

40004cd0 :
40004cd0:       61bdf0          l32r    a6, 40000fc4    ; ( 60000200 )
40004cd3:       c02000          memw
40004cd6:       226641          s32i    a2, a6, 0x104
40004cd9:       c02000          memw
40004cdc:       326642          s32i    a3, a6, 0x108
40004cdf:       c02000          memw
40004ce2:       426644          s32i    a4, a6, 0x110
40004ce5:       c02000          memw
40004ce8:       526645          s32i    a5, a6, 0x114
40004ceb:       0df0            ret.n

40004ced:       000000          ill

; simply reads from 0x60000318

40004cf0 :
40004cf0:       21b5f0          l32r    a2, 40000fc4    ; ( 60000200 )
40004cf3:       c02000          memw
40004cf6:       222246          l32i    a2, a2, 0x118
40004cf9:       0df0            ret.n


Having the register and pin list provided as xls files is kinda wonky, but hey - I am glad to have the information in any readable form, so I'll refrain from complaining too much. I translated them to PDF using libreoffice "calc" via:
libreoffice --headless --convert-to pdf *.xlsx
libreoffice --headless --convert-to pdf *.xls
On linux you can use "oocalc" to view the xls files.