Ok, so I have created a simplified test sketch which I am running on a Devkit 1. Here, the 8 pins assigned to a "bus" are initially set to input_pullup. The bus is next set to output high using two different methods - the standard Arduino pinMode() function and then using ESP functions, but the result is different. When using pinMode() both the input and output register are set to '1', but when using the equivalent ESP function, only the output register is set, which confuses digitalRead(). I have verified with a multi-meter that the pin is actually going high. Since one can't write to the input register - it is read-only, what is pinMode() doing that gpio_config_t isn't?
On an AVR, digitalRead() will return '1' in both the case when the pin is set to output and output is set high, or, when it is set to input and the input is high or pulled up. The ESP is behaving differently here if I use the ESP functions.
Code:
/*
* ESP32 GPIO pin test
*/
// Pin assignments
#define DIO1 32
#define DIO2 33
#define DIO3 25
#define DIO4 26
#define DIO5 27
#define DIO6 14
#define DIO7 4
#define DIO8 13
// Struct used to hold GPIO register values
struct gpioregister_t {
uint32_t reg0 = 0;
uint32_t reg1 = 0;
};
// Array holding pin map
const uint8_t databus[8] = { DIO1, DIO2, DIO3, DIO4, DIO5, DIO6, DIO7, DIO8 };
// 64-bit control and data bus mask
uint64_t gpioDbMask = 0;
// ESP GPIO configuratiom object
gpio_config_t gpioCfg;
const gpio_config_t * gpioCfgPtr = &gpioCfg;
/***** Covert 64-bit mask to 2 x 32-bit regster values *****/
void mask64ToReg(gpioregister_t& gpioreg, uint64_t mask) {
gpioreg.reg0 = (mask & 0xFFFFFFFF);
gpioreg.reg1 = (mask >> 32);
}
/***** Convert 2 x 32-bit register values to 64-bit mask *****/
uint64_t regToMask64(gpioregister_t& gpioreg) {
uint64_t gpiomask = 0;
gpiomask = gpioreg.reg0;
gpiomask |= ((uint64_t)gpioreg.reg1 << 32);
return gpiomask;
}
/***** Generate GPIO mask from assigned pin map *****/
uint64_t genGpioMask(const uint8_t buspins[], uint8_t bitmask) {
uint64_t gpioreg = 0;
for (uint8_t i=0; i<8; i++) {
if (bitmask & (1 << i)) {
gpioreg |= ( 1ULL << buspins[i] );
}
}
return gpioreg;
}
/***** Set the direction of GPIO pins using pinMode() and mask *****/
void setGpioDirMasked1(const uint8_t bus[], uint8_t mask, uint8_t state = INPUT_PULLUP) {
// OUTPUT mode
if (state == OUTPUT) {
for (uint8_t i=0; i<8; i++) {
if ( mask & (1U << i) ) pinMode(bus[i], OUTPUT);
}
return;
}
// INPUT_PULLUP mode
for (uint8_t i=0; i<8; i++) {
if ( mask & (1U << i) ) pinMode(bus[i], INPUT_PULLUP);
}
}
/***** Set the direction of GPIO pins using ESP functions and mask *****/
void setGpioDirMasked2(const uint8_t bus[], uint8_t mask, uint8_t state = INPUT_PULLUP) {
uint64_t gpiomask = 0;
for (uint8_t i=0; i<8; i++){
if ( mask & (1U << i) ) gpiomask |= (1ULL<<bus[i]);
}
if (state == OUTPUT) {
// OUTPUT mode
gpioCfg.pin_bit_mask = gpiomask;
gpioCfg.mode = GPIO_MODE_OUTPUT;
gpioCfg.pull_up_en = GPIO_PULLUP_DISABLE;
}else{
// INPUT_PULLUP mode
gpioCfg.pin_bit_mask = gpiomask;
gpioCfg.mode = GPIO_MODE_INPUT;
gpioCfg.pull_up_en = GPIO_PULLUP_ENABLE;
}
gpio_config(gpioCfgPtr);
}
/***** Set the bus using registers *****/
void setDbusHigh() {
gpioregister_t gpiodb;
mask64ToReg(gpiodb, gpioDbMask);
// Set all high
REG_WRITE(GPIO_OUT_W1TS_REG, gpiodb.reg0);
REG_WRITE(GPIO_OUT1_W1TS_REG, gpiodb.reg1);
}
/***** Show the bus using standard Arduino function *****/
void showBus(){
for (uint8_t i=0; i<8; i++){
Serial.print("DIO");
Serial.print(i);
Serial.print(": ");
Serial.println(digitalRead(databus[i]));
}
}
/***** Show the bus using registers *****/
void showBusReg(){
uint64_t gpioall = 0;
gpioregister_t gpioreg;
// Read the input register
gpioreg.reg0 = REG_READ(GPIO_IN_REG);
gpioreg.reg1 = REG_READ(GPIO_IN1_REG);
gpioall = regToMask64(gpioreg);
Serial.print("IN: ");
Serial.println(gpioall, BIN);
// Read the output register
gpioreg.reg0 = REG_READ(GPIO_OUT_REG);
gpioreg.reg1 = REG_READ(GPIO_OUT1_REG);
gpioall = regToMask64(gpioreg);
Serial.print("OUT:");
Serial.println(gpioall, BIN);
}
void setup(){
uint8_t i=0;
Serial.begin(115200);
delay(2000);
// Generate masks
gpioDbMask = genGpioMask(databus, 0xFF);
// Configure all GPIOs to input pullup (default?)
gpioCfg.pin_bit_mask = gpioDbMask;
gpioCfg.mode = GPIO_MODE_INPUT;
gpioCfg.pull_up_en = GPIO_PULLUP_ENABLE;
gpioCfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpioCfg.intr_type = GPIO_INTR_DISABLE;
gpio_config(gpioCfgPtr);
// Default INPUT_PULLUP
Serial.println("Default INPUT_PULLUP:");
showBus();
// Test3: OUTPUT pinmode()
Serial.println("\nTest1: OUTPUT using pinMode():");
setGpioDirMasked1(databus, 0xFF, OUTPUT);
for (i=0; i<8; i++){
digitalWrite(databus[i], HIGH);
}
showBus();
showBusReg();
// Test4: OUTPUT using registers
Serial.println("\nTest1: OUTPUT using registers:");
setGpioDirMasked2(databus, 0xFF, OUTPUT);
setDbusHigh();
showBus();
showBusReg();
Serial.flush();
}
void loop(){
}
Result:
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:4980
load:0x40078000,len:16612
load:0x40080400,len:3480
entry 0x400805b4
Default INPUT_PULLUP:
DIO1: 1
DIO2: 1
DIO3: 1
DIO4: 1
DIO5: 1
DIO6: 1
DIO7: 1
DIO8: 1
Test1: OUTPUT using pinMode():
DIO1: 1
DIO2: 1
DIO3: 1
DIO4: 1
DIO5: 1
DIO6: 1
DIO7: 1
DIO8: 1
IN: 1100001110000000001110101010111001
OUT:1100001110000000000110000000010000
Test2: OUTPUT using registers:
DIO1: 0
DIO2: 0
DIO3: 0
DIO4: 0
DIO5: 0
DIO6: 0
DIO7: 0
DIO8: 0
IN: 1000101010101001
OUT:1100001110000000000110000000010000
So what have I missed? What is pinMode() doing that the equivalent ESP functions are not?