Because some of the I/O on the EMBDZ19121 is accessed using the integrated 16-bit GPIO Expander device (PCAL6416AH) it will be necessary to write/read to/from this device to set some of the GPIO header pins. This includes the Status LED on the EMBDZ19121 itself.

The GPIO Expander is accessed via the I2C bus which means setting and reading these pins must be done through I2C register commands as opposed to simple "digitalWrite() and digitalRead()" functions when accessing pins directly connected to the ESP32.

The hardware initialization code is shown below.



#include "Wire.h" static uint8_t gpio0; // port 0 mirror variable of the GPIO expander static uint8_t gpio1; // port 1 mirror variable of the GPIO expander // initialize the hardware GPIO Expander and Serial UART void setup() { Serial.begin(115200); // setup port mirror variables gpio0 = 0b00000000; gpio1 = 0b00000000; // setup the GPIO expander ports on EMBDZ19121 // port 0 // - bit 0 = input GPIO23 (header pin 16) // - bit 1 = input GPIO24 (header pin 18) // - bit 2 = input GPIO05 (header pin 29) // - bit 3 = input GPIO06 (header pin 31) // - bit 4 = input GPIO22 (header pin 15) // - bit 5 = input GPIO27 (header pin 13) // - bit 6 = input GPIO17 (header pin 11) // - bit 7 = input GPIO04 (header pin 7) // port 1 // - bit 0 = output (unused set low) // - bit 1 = output (unused set low) // - bit 2 = output (unused set low) // - bit 3 = output (unused set low) // - bit 4 = input GPIO26 (header pin 37) // - bit 5 = output GPIO25 (header pin 22) Status LED // - bit 6 = input GPIO16 (header pin 36) // - bit 7 = input GPIO21 (header pin 38) // setup the I2C bus Wire.begin(32, 33, 100000); // initialize GPIO expander port 0 direction register Wire.beginTransmission(0x20); Wire.write(0x06); // internal GPIO expander port 0 direction register address Wire.write(0xff); Wire.endTransmission(); // initialize GPIO expander port 1 direction register Wire.beginTransmission(0x20); Wire.write(0x07); // internal GPIO expander port 1 direction register address Wire.write(0xd0); Wire.endTransmission(); // initialize GPIO expander port 0 output values Wire.beginTransmission(0x20); Wire.write(0x02); // internal GPIO expander port 0 output register address Wire.write(gpio0); Wire.endTransmission(); // initialize GPIO expander port 1 output values Wire.beginTransmission(0x20); Wire.write(0x03); // internal GPIO expander port 1 output register address Wire.write(gpio1); Wire.endTransmission(); Serial.println("GPIO Expander setup complete..."); }

The initialization code starts off including the "Wire.h" file which allows the use of the I2C bus and I/O functions.

Then two variables (byte) are allocated in memory to hold the value that is a mirror of what is latched on the output pins of hte GPIO expander. Those will be used to modify specific pins without affecting other pins. Those are also initialized to 0 here.

Within the "setup()" routine we first setup the serial console. This will be for simple debugging purposes here. Notice the 115,200 bps rate.

After that we define what all the bits (pins) on the GPIO expander are used for. This is mapped according to the EMBDZ19121 user guide. These are simply comments so we have a convenient reference in the code.

The I2C bus driver is initialized with the "Wire.begin()" function using GPIO 32 & 33 of the ESP32 as defined by the EMBDZ19121 user guide.

Next we need to setup the internal registers within the GPIO Expander appropriately. There are many configuration registers that control many features of the device. We're going to simply setup the direction register to setup which pins are outputs which will be inputs. By default once the GPIO expander is powered up all pins are inputs. All we need to set are the outputs.

According to the PCAL6416AH data sheet the internal pin direction registers are at address 0x06 and 0x07 for port 0 and port 1 respectively.

The last two I2C write operations are to the GPIO Expander output registers for port 0 and 1. We write the contents of the "gpio0" and "gpio1" registers to the internal registers 0x02 and 0x03 to initialize ports 0 and 1 respectively.

In the next section we turn the status LED on and off in a continuous loop.



// loop forever toggling the Status LED on & off void loop() { // turn the Status LED on // setup the gpio1 mirror register to set bit 5 high without // changing the other bits in the gpio1 mirror register gpio1 = gpio1 | 0b00100000; // write the port value to the GPIO Expander Wire.beginTransmission(0x20); Wire.write(0x03); // internal GPIO expander port 1 output register address Wire.write(gpio1); Wire.endTransmission(); Serial.println("Set Status LED on..."); delay(500); // wait for 500 mSec // turn the Status LED off // setup the gpio1 mirror register to set bit 5 low without // changing the other bits in the gpio1 mirror register gpio1 = gpio1 & 0b11011111; // write the port value to the GPIO Expander Wire.beginTransmission(0x20); Wire.write(0x03); // internal GPIO expander port 1 output register address Wire.write(gpio1); Wire.endTransmission(); Serial.println("Set Status LED off..."); delay(500); // wait for 500 mSec }

We change bit 5 in the "gpio1" mirror register using the logic "OR" operator with the mask 0b00100000. This allows us to set bit 5 without changing the other bits within the variable.

After we've updated the gpio1 variable we write it into the GPIO Expander output register 0x03 (port1). This sets the pin to a logic high level and turns the status LED on.

After a brief delay we update the gpio1 variable again this time clearing bit 5 with the logic "AND" operator and bitmask 0b11011111. Again the gpio1 is written to the GPIO Expander port 0x03 to turn the LED off.

© à la mods. All rights reserved