Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32S3 Error reading multiple bytes with ulp-riscv i2c driver (IDFGH-9822) #11154

Closed
3 tasks done
bitfixer opened this issue Apr 7, 2023 · 4 comments
Closed
3 tasks done
Assignees
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Bug bugs in IDF

Comments

@bitfixer
Copy link

bitfixer commented Apr 7, 2023

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.

42261df

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.

esp32s3 custom board with MMC5603 magnetometer

Power Supply used.

USB

What is the expected behavior?

Hello, I would like to report an issue with the ulp-riscv i2c driver, specifically ulp_riscv_i2c_master_read_from_device.
I have a board with an esp32s3 connected to an MMC5603 magnetometer via i2c.
On this board, SDA is GPIO 1 and SCL is GPIO 0. I am doing readings from the magnetometer, which involves first writing a control byte, waiting for a status bit, and then reading 9 bytes back from addresses 0x00-0x08 using the ulp i2c driver. I was attempting to use ulp_riscv_i2c_master_read_from_device to read multiple bytes at a time, i.e.
ulp_riscv_i2c_master_read_from_device(buffer, 9);

However, this results in i2c errors like:
Initializing RTC I2C ...
doing magnetometer reading.
attempt 0
E (12163) ulp_riscv_i2c: Read Failed!
E (12163) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (12163) ulp_riscv_i2c: RTC I2C Status Reg 0x65f00000
x 240 z 126
doing magnetometer reading.
attempt 0
E (18203) ulp_riscv_i2c: Read Failed!
E (18203) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (18203) ulp_riscv_i2c: RTC I2C Status Reg 0x65d00000
x 208 z 126
doing magnetometer reading.
attempt 0
E (24243) ulp_riscv_i2c: Read Failed!
E (24243) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (24243) ulp_riscv_i2c: RTC I2C Status Reg 0x65f00000
x 240 z 126

If these bytes are read individually, i.e.
for (int i = 0; i < size; i++) {
ulp_riscv_i2c_master_read_from_device(buffer, 1);
buffer++;
}
the read works properly.
The multiple byte read had worked properly until commit 88e4c06, but only when read from the riscv processor.

Expected behavior would be for the multiple byte read to work without error.

What is the actual behavior?

using ulp_riscv_i2c_master_read_from_device to read multiple bytes at once yields errors like:
Initializing RTC I2C ...
doing magnetometer reading.
attempt 0
E (12163) ulp_riscv_i2c: Read Failed!
E (12163) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (12163) ulp_riscv_i2c: RTC I2C Status Reg 0x65f00000
x 240 z 126
doing magnetometer reading.
attempt 0
E (18203) ulp_riscv_i2c: Read Failed!
E (18203) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (18203) ulp_riscv_i2c: RTC I2C Status Reg 0x65d00000
x 208 z 126
doing magnetometer reading.
attempt 0
E (24243) ulp_riscv_i2c: Read Failed!
E (24243) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (24243) ulp_riscv_i2c: RTC I2C Status Reg 0x65f00000
x 240 z 126

Steps to reproduce.

  1. Initialize the ulp riscv i2c driver
  2. Set slave address to the device
  3. Set slave register address
  4. Attempt to read multiple bytes at once with ulp_riscv_i2c_master_read_from_device

Sample code:
`#include <stdio.h>
#include <inttypes.h>
#include <ulp_riscv.h>
#include <ulp_riscv_i2c.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "ulp_main.h"

#define MAG_ADDRESS 0x30
#define MAG_CONTROL_0_REG 0x1B
#define MAG_DEVICE_ID_REG 0x39
#define MAG_DEVICE_STATUS_REG_1 0x18
#define MAG_STATUS_MEAS_DONE_BIT 0x40
#define MAG_X_OUT_0 0
#define MAG_Z_OUT_0 4

// select method of i2c reading
#define I2C_READ_MULTIPLE 1

static void init_i2c(void);

void delayms(int ms) {
vTaskDelay(ms / portTICK_PERIOD_MS);
}

void readBytesMultiple(uint8_t* buffer, int size) {
ulp_riscv_i2c_master_read_from_device(buffer, size);
}

void readBytesSingle(uint8_t* buffer, int size) {
for (int i = 0; i < size; i++) {
ulp_riscv_i2c_master_read_from_device(buffer, 1);
buffer++;
}
}

// read values from MMC5603 magnetometer
void magReading() {
ulp_riscv_i2c_master_set_slave_addr(MAG_ADDRESS);

uint8_t dataRd = 0x21;
uint8_t magReadingBytes[9];

// initiate a reading
ulp_riscv_i2c_master_set_slave_reg_addr(MAG_CONTROL_0_REG);
ulp_riscv_i2c_master_write_to_device(&dataRd, 1);

delayms(10);
ulp_riscv_i2c_master_set_slave_reg_addr(MAG_DEVICE_STATUS_REG_1);

// Keep reading status until max tries exceeded
int attempt = 0;
int maxAttempts = 50;
while (1) {
    printf("attempt %d\n", attempt);
    ulp_riscv_i2c_master_read_from_device(&dataRd, 1);
    if ((dataRd & MAG_STATUS_MEAS_DONE_BIT) != 0) {
        break;
    }
    delayms(1);
    attempt++;

    if (attempt > maxAttempts) {
        printf("max attempts exceeded\n");
        return;
    }
}

// read magnetometer data
ulp_riscv_i2c_master_set_slave_reg_addr(0x00);

#if I2C_READ_MULTIPLE
readBytesMultiple(magReadingBytes, 9);
#else
readBytesSingle(magReadingBytes, 9);
#endif

uint8_t xReading = magReadingBytes[MAG_X_OUT_0];
uint8_t zReading = magReadingBytes[MAG_Z_OUT_0];
printf("x %d z %d\n", xReading, zReading);

}

static void init_i2c(void)
{
/* Configure RTC I2C */
printf("Initializing RTC I2C ...\n");
ulp_riscv_i2c_cfg_t i2c_cfg = ULP_RISCV_I2C_DEFAULT_CONFIG();
i2c_cfg.i2c_pin_cfg.sda_io_num = GPIO_NUM_1;
i2c_cfg.i2c_pin_cfg.scl_io_num = GPIO_NUM_0;
esp_err_t ret = ulp_riscv_i2c_master_init(&i2c_cfg);
if (ret!= ESP_OK) {
printf("ERROR: Failed to initialize RTC I2C. Aborting...\n");
abort();
}
}

void app_main(void)
{
printf("Hello world!\n");
delayms(1000);
init_i2c();
while (1) {
printf("doing magnetometer reading.\n");
magReading();
delayms(1000);
}
}`

Debug Logs.

Initializing RTC I2C ...
doing magnetometer reading.
attempt 0
E (12163) ulp_riscv_i2c: Read Failed!
E (12163) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (12163) ulp_riscv_i2c: RTC I2C Status Reg 0x65f00000
x 240 z 126
doing magnetometer reading.
attempt 0
E (18203) ulp_riscv_i2c: Read Failed!
E (18203) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (18203) ulp_riscv_i2c: RTC I2C Status Reg 0x65d00000
x 208 z 126
doing magnetometer reading.
attempt 0
E (24243) ulp_riscv_i2c: Read Failed!
E (24243) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x10c
E (24243) ulp_riscv_i2c: RTC I2C Status Reg 0x65f00000
x 240 z 126

More Information.

Before commit 88e4c06, the multiple byte read worked properly when used from the ulp riscv processor but not from the CPU - on CPU it would hang.

@bitfixer bitfixer added the Type: Bug bugs in IDF label Apr 7, 2023
@github-actions github-actions bot changed the title ESP32S3 Error reading multiple bytes with ulp-riscv i2c driver ESP32S3 Error reading multiple bytes with ulp-riscv i2c driver (IDFGH-9822) Apr 7, 2023
@espressif-bot espressif-bot added the Status: Opened Issue is new label Apr 7, 2023
@sudeep-mohanty
Copy link
Collaborator

Hello @bitfixer, Apologies for getting to this issue very late.

The commit 88e4c06 added a default ULP RISC-V I2C transaction timeout of 500 msec which should have been enough for a 9-byte transaction. However, I'm not sure what is the case with the particular sensor you are using. Could you confirm if the complete 9-byte transaction is not taking more than 500 msec? Maybe you could hook up a protocol analyzer to check?

Nevertheless, I shall update the driver to make timeout behaviour configurable and in a way add capability to restore the behavior of the driver before the commit so that you use case is not affected.

@espressif-bot espressif-bot added Status: In Progress Work is in progress and removed Status: Opened Issue is new labels Apr 25, 2023
@aircable
Copy link

I can confirm the bug with the ESP32S3_R8V even when reading a single byte.
I used the IDF example esp-idf/examples/system/ulp_riscv/i2c
Checked configuration for the GPIO pins and verified with an oscilloscope.
SCL clock is there but data looks a bit weird. Maybe it isn't set to input?

Code to reproduce:

        printf("Initializing RTC I2C ...\n");
        ulp_riscv_i2c_cfg_t i2c_cfg = ULP_RISCV_I2C_DEFAULT_CONFIG(); // GPIO 2 and 3
        esp_err_t ret = ulp_riscv_i2c_master_init(&i2c_cfg);
        ulp_riscv_i2c_master_set_slave_addr( 0x0E );
        ulp_riscv_i2c_master_set_slave_reg_addr( 0x0F );
        ulp_riscv_i2c_master_read_from_device( &data_rd, 1 ); // return 0x35
        printf( "KXTJ3 0x%x\n", data_rd );

Still the error shows:

Not a ULP-RISC V wakeup (cause = 0)
Initializing RTC I2C ...
E (99) ulp_riscv_i2c: Read Failed!
E (109) ulp_riscv_i2c: RTC I2C Interrupt Raw Reg 0x13c
E (109) ulp_riscv_i2c: RTC I2C Status Reg 0x62000010
KXTJ3 0x0

ERROR: Cannot communicate with I2C sensor

@aircable
Copy link

I can confirm that the the RISCV is able to communicate with I2C.
It's just the LX7 which cannot use the RTC controller.
On a side note, when I mix
ulp_riscv_i2c_master_init()
and

i2c_bus_create()
i2c_bus_device_create()

the LX7 will no longer able to communicate, either way RTC or BUS.

@sudeep-mohanty
Copy link
Collaborator

@aircable
I'm sorry but I am not clear on the issue you face. In case you still are seeing some problems, I would request you to open a new issue for us. Do list your development environment and the steps to reproduce the problem. That would help us to look into it more carefully. Thanks!

@espressif-bot espressif-bot added Status: Done Issue is done internally Resolution: NA Issue resolution is unavailable and removed Status: In Progress Work is in progress labels May 9, 2023
espressif-bot pushed a commit that referenced this issue May 19, 2023
The commit 88e4c06 introduced a loop timeout for all ULP RISC-V I2C
transactions to avoid getting stuck in a forever loop. The loop timeout
was set to 500 msec by default. This commit improves on the concept by
making the loop timeout configurable via a Kconfig option in terms of
CPU ticks. If the timeout is set to -1 value then the transaction loops
will never timeout, therefore restoring the driver behavior before the
timeout was introduced.

The commit also updates the I2C Fast mode timings for esp32s2 which need
to be adjusted due to bus timing constraints.

Closes #11154
ilutchenko pushed a commit to ilutchenko/esp-idf that referenced this issue Jun 26, 2023
The commit 88e4c06 introduced a loop timeout for all ULP RISC-V I2C
transactions to avoid getting stuck in a forever loop. The loop timeout
was set to 500 msec by default. This commit improves on the concept by
making the loop timeout configurable via a Kconfig option in terms of
CPU ticks. If the timeout is set to -1 value then the transaction loops
will never timeout, therefore restoring the driver behavior before the
timeout was introduced.

The commit also updates the I2C Fast mode timings for esp32s2 which need
to be adjusted due to bus timing constraints.

Closes espressif#11154
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: NA Issue resolution is unavailable Status: Done Issue is done internally Type: Bug bugs in IDF
Projects
None yet
Development

No branches or pull requests

4 participants