Skip to content

ESP32-S3 ULP GPIO input reads incorrectly (only 1s) (IDFGH-9689) #11030

Description

@readmodifywrite

Answers checklist.

  • I have read the documentation ESP-IDF Programming Guide and the issue is not addressed there.
  • I have updated my IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a similar issue.

IDF version.

release/v5.0 11c59a2

Operating System used.

Linux

How did you build your project?

Command line with idf.py

If you are using Windows, please specify command line type.

None

Development Kit.

Custom board

Power Supply used.

USB

What is the expected behavior?

GPIO inputs should correctly report bus level.

What is the actual behavior?

GPIO reads from the ULP are only reporting a 1.

Steps to reproduce.

I'm bit-banging I2C to talk to an SHT40 temperature sensor. ULP GPIO is set to open drain with both input and output enabled. I am able to correctly write to the SHT40 and the SHT40 responds correctly. All signals have been verified with a bus analyzer - everything there is working properly on both reads and writes.

However, the GPIO level reported by the ulp_riscv_gpio_get_level() is returning only 1s. Thus, while my I2C writes are correct and the read data returned by the SHT40 are correct, the input level reported by the ESP32 itself is incorrect.

According to the DS18B20 ULP example, this exact use case is possible: both input and output enabled in open drain mode.

Note that the ULP GPIO API is completely undocumented. I don't know if there are any special considerations needed to make this work, because none are documented. The register level documentation in the technical reference manual is similarly useless. The logic diagram does indicate this functionality should be possible - assuming the diagram is accurate.

I have also verified this behavior with a simple IO level check: Drive a 1 and ground the pin. I verified the pin itself is pulled to 0V via DMM, however, the ULP is reporting a 1.

Here's my IO init code:


ulp_riscv_gpio_init( I2C_GPIO_SDA );
ulp_riscv_gpio_init( I2C_GPIO_SCL );

ulp_riscv_gpio_output_enable( I2C_GPIO_SDA );
ulp_riscv_gpio_output_enable( I2C_GPIO_SCL );
ulp_riscv_gpio_input_enable( I2C_GPIO_SDA );
ulp_riscv_gpio_input_enable( I2C_GPIO_SCL );

ulp_riscv_gpio_set_output_mode( I2C_GPIO_SDA, RTCIO_MODE_OUTPUT_OD );
ulp_riscv_gpio_set_output_mode( I2C_GPIO_SCL, RTCIO_MODE_OUTPUT_OD );

ulp_riscv_gpio_output_level( I2C_GPIO_SDA, 1 );
ulp_riscv_gpio_output_level( I2C_GPIO_SCL, 1 );

And the check code:

    ulp_riscv_gpio_output_level( I2C_GPIO_SDA, 0 );    
    delay_us(1);
    gpio_low = ulp_riscv_gpio_get_level( I2C_GPIO_SDA );

    ulp_riscv_gpio_output_level( I2C_GPIO_SDA, 1 );    
    delay_us(1);
    gpio_high = ulp_riscv_gpio_get_level( I2C_GPIO_SDA );

gpio_high will read a 1 regardless of the actual voltage on the pin. It will correctly drive a 1, but if pulled down, will still read 1. It must be reporting the selected output level, as gpio_low will correctly report a 0 (and 0 is what the pin is actually driven to).

Debug Logs.

No response

More Information.

No response

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions