espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.32k stars 7.2k forks source link

ESP32-S2 Co-processor example of I2C (IDFGH-6788) #8415

Closed DylanGWork closed 2 years ago

DylanGWork commented 2 years ago

It would be great to see an example of I2C in the co-processor.

I have read through the Technical Reference Guide section on this, and with enough time I'm sure I could get something working.

An example would naturally be an excellent place to start and I'm sure many people have many uses for it.

My current situation is wanting to read an accelerometer output while in low power, have a rolling average of the accelerometer readings and wake-up the main processor if a threshold is met.

I also have successfully setup interrupts in ULP as per a different feature request I made (thank you for the fast work on that), it would be very beneficial to read the accelerometer output from the co-processor as it has a much faster wake-up time and may capture the data from the peak of an impact more accurately.

Cheers, Dylan

DylanGWork commented 2 years ago

Just bumping this Feature request, is someone able to comment if this feature is possible?

mholeys commented 2 years ago

I have also had a go at reading through the technical documentation on how to perform I2C operations on the ULP (RISC-V) co-processor, and it seems like there are similarities with the RTC listed registers and the registers listed in the I2C controller section. Both contain different instructions on what registers should be used and how to use the I2C controller, and I have yet to work out a way to use the I2C peripheral from the ULP processor successfully.
An example of this would be great, as I think this would be a very powerful ability of the ULP processor, not just the FSM one.

Is there any news on if an example would be possible? I have seen examples online of using the ULP-FSM to use I2C but nothing related to the RISC-V co-processor

sudeep-mohanty commented 2 years ago

Hello @DylanGWork, @mholeys Apologies for coming around to this feature request quite late. We now have RTC I2C support for ULP RISC-V coprocessor on the esp32s2 and esp32s3 added via commit 867745a05c5cb1fe5eb212200580626ad0fa839d. There is also a new example added to demonstrate the usage of I2C with the ULP RISC-V coprocessor. I would welcome you to try it out and let us know your feedback. Thank you!

mholeys commented 1 year ago

Hello @sudeep-mohanty Thank you very much for getting back to us/me on this, sorry for the delay I have been unable to get things working to test for you. I have tried your example, but I have not had much luck, as I only have a couple of I2C sensors that I can play with. I cannot currently test with BMP180, but I have tried modifying the example with a couple of sensors I have, AM2320 and SGP30. After finding this to be unsuccessful I have written some more attempts, but by using the ulp_riscv_i2c_format_cmd function and others based on your code, but I still have failed this time just for the SGP30. I have not managed to get usable results with the sensors I have (yet). Using my oscilloscope I noticed that when trying to send an address in read mode, the devices I have do not answer correctly. I think the RTC I2C controller is failing to send the high bit for the R/W part of the address (8th bit) Setting SENS_SAR_I2C_CTRL_REG bit 27 as used in your code SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 0, 27); for Write SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 1, 27); for Read I cannot verify if this is the correct register/bit combination as these are not listed in the technical manual.

I have managed to get the device to answer me in some way, but all the data it is sending is 255, which I suspect is due to the sensor being in write mode, not read and so the high signal I am getting is just the pull up. I have only been using this in the main CPU until I get anything working, if this is the problem please let me know, as debugging the ULP RISCV cpu is not as easy.

Any help with this would be appreciated

sudeep-mohanty commented 1 year ago

Thank you for the feedback @mholeys. Really appreciate the time and effort! Unfortunately, we do not have the AM2320 or the SGP30 sensors on hand at the moment so it might be difficult to recreate the issue that you are observing right away. However, I have a few follow up queries/comments to get a better understanding of the problem you are seeing -

  1. May I know some more details about how you used the ulp_riscv/i2c example for your sensors? I assume, you might have had to update all the device and register addresses. What output did you see when you used it (either on console or oscilloscope) and if possible, could you share a code snippet of it so that I can take a deeper look?

  2. Just for my clarity -

I have only been using this in the main CPU

Do you mean you have been able to use the sensors with the RTC_I2C peripheral itself with the newly added APIs available under ulp_riscv_i2c.h or with the I2C0/I2C1 peripheral driver which is available under i2c.h?

  1. Which SoC are you using - esp32s2 or esp32s3?

  2. It is the correct that bit#27 of the register SENS_SAR_I2C_CTRL_REG controls the read/write mode of the controller, however, it is the opposite configuration to what you have mentioned above: SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 0, 27); for Read SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 1, 27); for Write

As you correctly pointed out, this register is not described in a granular manner in our TRM docs but we already have an internal ticket tracking this and hopefully the docs would be updated soon to reflect it.

mholeys commented 1 year ago

Hello @sudeep-mohanty,

  1. I am using the esp32s2, specifically a board by Unexpected Maker called FeatherS2 Neo if that's any help too. I have also been using pins 1 (SDA) and 0 (SCL) in case this changes anything. I also have an INA219 if that is any help.

  2. I must have made a mistake copying that to github/labelling them here, as I am using the correct 1/0 for SENS_SAR_I2C_CTRL_REG.

  3. To answer your second question first, I mean that I have not been using the ULP RISC-V core at all, and all the code I have tried was using the functions in the ulp_riscv_i2c.c/.h files under the esp32s2's normal core. I have been able to use the RTC_I2C peripheral using the new APIs. I was going to have another go at using the riscv co-processor but I could not get anything to compile, which I suspect is unrelated. I will have another go today, starting fresh based on the example. I will be talking about the SGP30 unless I say otherwise to reduce any confusion.

  4. By using the example I meant that I opened up the example in eclipse, and modified the code to use the ulp_riscv_i2c_master_* functions to use the addresses of the sensors I have. I removed the BMP180 references under ulp_riscv_rtc_i2c_example.c, e.g. changing lines line ulp_riscv_i2c_master_set_slave_addr(BMP180_SENSOR_I2C_ADDR); to use the address of SGP30_ADDRESS (0x58) , and changing the registers/data to be written to match the requirements of the SGP30 sensor, { 0x36, 0x82 } to get the serial number. I however hit an issue, which is that the sensor I have expects you to write to one address and send 2 register bytes, but then to read back, what you have asked for, it expects just the device address, no other bytes. At this point I changed to use the ulp_riscv_i2c_format_cmd instead and started a new project, so that I could send the address byte as needed, but not the register byte. I did have to modify the ulp_riscv_i2c.c file to remove the static keyword so that I could use it. The closest I have got to working is the code here, sorry for a bit of mess, but I wanted it to be as is:

#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <math.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_sleep.h"

#include "esp_log.h"
#include "tinyusb.h"
#include "tusb_cdc_acm.h"
#include "tusb_console.h"
#include "sdkconfig.h"

//#include "ulp_main.h"

#include "soc/sens_reg.h"
#include "soc/rtc_i2c_reg.h"
#include "soc/i2c_reg.h"

#include "hal/i2c_ll.h"

#include "ulp_riscv.h"
#include "ulp_riscv_i2c.h"

// Provided in ulp_riscv_i2c.c
extern void ulp_riscv_i2c_format_cmd(uint32_t cmd_idx, uint8_t op_code, uint8_t ack_val,
        uint8_t ack_expected, uint8_t ack_check_en, uint8_t byte_num);

void init_usb_comms(); // for Tiny USB CDC based logging
void deinit_usb_comms();

void init_rtc_i2c();
void sgp30_get_serial_number();

void app_main(void)
{
    init_usb_comms();
    vTaskDelay(1000 / portTICK_PERIOD_MS);

    esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
    if (cause != ESP_SLEEP_WAKEUP_ULP) {
        init_rtc_i2c();
        sgp30_get_serial_number();
    }
}

/*** #####################################
 *   RTC I2C SETUP
 *   #####################################
 */
// Copied from ulp_riscv_i2c.c
#define I2C_CTRL_SLAVE_ADDR_MASK        (0xFF << 0)
#define I2C_CTRL_SLAVE_REG_ADDR_MASK    (0xFF << 11)
#define I2C_CTRL_MASTER_TX_DATA_MASK    (0xFF << 19)

#if CONFIG_IDF_TARGET_ESP32S3
#define ULP_I2C_CMD_RESTART 0                   /*!<I2C restart command */
#define ULP_I2C_CMD_WRITE   1                   /*!<I2C write command */
#define ULP_I2C_CMD_READ    2                   /*!<I2C read command */
#define ULP_I2C_CMD_STOP    3                   /*!<I2C stop command */
#define ULP_I2C_CMD_END     4                   /*!<I2C end command */
#else
#define ULP_I2C_CMD_RESTART I2C_LL_CMD_RESTART  /*!<I2C restart command */
#define ULP_I2C_CMD_WRITE   I2C_LL_CMD_WRITE    /*!<I2C write command */
#define ULP_I2C_CMD_READ    I2C_LL_CMD_READ     /*!<I2C read command */
#define ULP_I2C_CMD_STOP    I2C_LL_CMD_STOP     /*!<I2C stop command */
#define ULP_I2C_CMD_END     I2C_LL_CMD_END      /*!<I2C end command */
#endif // CONFIG_IDF_TARGET_ESP32S3

void init_rtc_i2c() {
    /* 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;
    i2c_cfg.i2c_pin_cfg.sda_pullup_en = false;
    i2c_cfg.i2c_pin_cfg.scl_pullup_en = false;
    ulp_riscv_i2c_master_init(&i2c_cfg);
}

#define SGP30_ADDRESS 0x58
#define SGP30_FEATURESET 0x0020    ///< The required set for this library
#define SGP30_CRC8_POLYNOMIAL 0x31 ///< Seed for SGP30's CRC polynomial
#define SGP30_CRC8_INIT 0xFF       ///< Init value for CRC
#define SGP30_WORD_LEN 2           ///< 2 bytes per word

void sgp30_get_serial_number() {
    ulp_riscv_i2c_master_set_slave_addr(SGP30_ADDRESS);
    ulp_riscv_i2c_master_set_slave_reg_addr(0x36);

    uint8_t data_wr[1] = { 0x82 };

    uint32_t i = 0;
    uint32_t cmd_idx = 0;
    uint8_t recSize = 9; // S/N is 2 + 1 crc
    uint8_t data_rd[9] = {0};

    ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_WRITE, 0, 0, 1, 3); // Send address, and 2 command bytes
//  ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_RESTART, 0, 0, 0, 0); // Restart comms so we can read
    ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_STOP, 0, 0, 0, 0); // Restart comms so we can read

    /* Configure the RTC I2C controller in write mode */
    SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 1, 27);
    /* Configure the RTC I2C controller in read mode */
//  SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 0, 27);

    /* Enable Tx data interrupt */
    SET_PERI_REG_MASK(RTC_I2C_INT_ENA_REG, RTC_I2C_TX_DATA_INT_ENA);
    /* Enable Rx data interrupt */
    SET_PERI_REG_MASK(RTC_I2C_INT_ENA_REG, RTC_I2C_RX_DATA_INT_ENA);

    // Start
    SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE);
    SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);

    // Put second command byte in
    CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, I2C_CTRL_MASTER_TX_DATA_MASK);
    SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0xFF, data_wr[0], 19);

    printf("I2C waiting for byte to be sent 1\n");
    /* Poll for RTC I2C Tx Data interrupt bit to be set */
    while (!REG_GET_FIELD(RTC_I2C_INT_ST_REG, RTC_I2C_TX_DATA_INT_ST)) {
        /* Minimal delay to avoid hogging the CPU */
        vTaskDelay(1);
    }

    /* Clear the Tx data interrupt bit */
    SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_TX_DATA_INT_CLR);

    /* Clear the RTC I2C transmission bits */
    CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE);
    CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);

    vTaskDelay(1 / portTICK_PERIOD_MS);

    ulp_riscv_i2c_master_set_slave_addr(SGP30_ADDRESS);

    /* Configure the RTC I2C controller in read mode */
    printf("I2C r/w bit %d\n", GET_PERI_REG_BITS(RTC_I2C_STATUS_REG, RTC_I2C_SLAVE_RW, RTC_I2C_SLAVE_RW));
    SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0x1, 0, 27);

    cmd_idx = 2;
//  ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_RESTART, 0, 0, 1, 0);
    ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_WRITE, 0, 0, 1, 1); // Write the address again
    if (recSize > 1) {
        /* Read n - 1 bytes */
        ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_READ, 0, 0, 1, recSize - 1);
    }
    /* Read last byte + NACK */
    ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_READ, 1, 1, 1, 1);

    /* STOP */
    ulp_riscv_i2c_format_cmd(cmd_idx++, ULP_I2C_CMD_STOP, 0, 0, 0, 0);

//  // Put address in again
//  CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, I2C_CTRL_MASTER_TX_DATA_MASK);
//  SET_PERI_REG_BITS(SENS_SAR_I2C_CTRL_REG, 0xFF, (SGP30_ADDRESS << 1) | I2C_MASTER_READ, 19);

    // Start second transaction
    SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE);
    SET_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);

//  printf("I2C waiting for byte to be sent 2\n");
//  /* Poll for RTC I2C Tx Data interrupt bit to be set */
//  while (!REG_GET_FIELD(RTC_I2C_INT_ST_REG, RTC_I2C_TX_DATA_INT_ST)) {
//      /* Minimal delay to avoid hogging the CPU */
//      vTaskDelay(1);
//  }
//  /* Clear the Tx data interrupt bit */
//  SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_TX_DATA_INT_CLR);

    printf("I2C Starting read loop\n");
    for (i = 0; i < recSize; i++) {
        printf("Waiting for read\n");
        /* Poll for RTC I2C Rx Data interrupt bit to be set */
        while (!REG_GET_FIELD(RTC_I2C_INT_ST_REG, RTC_I2C_RX_DATA_INT_ST)) {
            /* Minimal delay to avoid hogging the CPU */
            vTaskDelay(1);
        }
        printf("Read byte [%d]\n", i);

        /* Read the data
         *
         * Unfortunately, the RTC I2C has no fifo buffer to help us with reading and storing
         * multiple bytes of data. Therefore, we need to read one byte at a time and clear the
         * Rx interrupt to get ready for the next byte.
         */
#if CONFIG_IDF_TARGET_ESP32S2
        data_rd[i] = REG_GET_FIELD(RTC_I2C_DATA_REG, RTC_I2C_RDATA);
#elif CONFIG_IDF_TARGET_ESP32S3
        data_rd[i] = REG_GET_FIELD(RTC_I2C_DATA_REG, RTC_I2C_I2C_RDATA);
#endif // CONFIG_IDF_TARGET_ESP32S2
        printf("Read byte [%d]: %d\n", i, data_rd[i]);
        /* Clear the Rx data interrupt bit */
        SET_PERI_REG_MASK(RTC_I2C_INT_CLR_REG, RTC_I2C_RX_DATA_INT_CLR);
        printf("Finished byte [%d]\n", i);
    }

    /* Clear the RTC I2C transmission bits */
    CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START_FORCE);
    CLEAR_PERI_REG_MASK(SENS_SAR_I2C_CTRL_REG, SENS_SAR_I2C_START);
}

/*** #####################################
 *   USB SETUP
 *   #####################################
 */

void init_usb_comms() {
    tinyusb_config_t tusb_cfg = {}; // the configuration using default values
    ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));

    tinyusb_config_cdcacm_t amc_cfg = {
        .usb_dev = TINYUSB_USBDEV_0,
        .cdc_port = TINYUSB_CDC_ACM_0,
        .rx_unread_buf_sz = 64,
        .callback_rx = NULL, //&tinyusb_cdc_rx_callback, // the first way to register a callback
        .callback_rx_wanted_char = NULL,
        .callback_line_state_changed = NULL,
        .callback_line_coding_changed = NULL
    };

    ESP_ERROR_CHECK(tusb_cdc_acm_init(&amc_cfg));
    esp_tusb_init_console(TINYUSB_CDC_ACM_0); // log to usb
}

void deinit_usb_comms() {
    esp_tusb_deinit_console(TINYUSB_CDC_ACM_0); // log to uart
}

The output from the ESP32s2 via usb cdc:

Initializing RTC I2C ...
I2C waiting for byte to be sent 1
I2C r/w bit 0
I2C Starting read loop
Waiting for read
Read byte [0]
Read byte [0]: 255
Finished byte [0]
Waiting for read

Oscilloscope output, the first is the data being sent in the first set of commands, to request the serial number of the SGP30 chip, and the second is the commands to read the data back. Write to request Reading the data back

My code is based on information from https://www.mouser.com/pdfdocs/Sensirion_Gas_Sensors_SGP30_Datasheet_EN-1148053.pdf

sudeep-mohanty commented 1 year ago

Hello @mholeys, Thank you for sharing the detailed code and captures!

Using GPIO 1 and 0 is perfectly fine and should not lead to any problems. I notice that you have disabled internal pullup on the GPIO pins -

    i2c_cfg.i2c_pin_cfg.sda_pullup_en = false;
    i2c_cfg.i2c_pin_cfg.scl_pullup_en = false;

I would assume that you have some kind of external pullup enabled for the I2C pins to make sure that the signals are correctly received by the sensor.

After reading through the datasheet and understanding your scenario, I believe it should be possible to read data from the sensor with the public functions and may not need to use internal functions such as ulp_riscv_i2c_format_cmd. I have the below code suggestion for reading the serial ID. It would be great if you could try out and let me know the results -

void sgp30_get_serial_number() {
    ulp_riscv_i2c_master_set_slave_addr(SGP30_ADDRESS);
    ulp_riscv_i2c_master_set_slave_reg_addr(0x36);

    uint8_t data_wr = 0x82;
        uint8_t data_rd[9] = {0};

        // Write hexcode 0x3682
        ulp_riscv_i2c_master_write_to_device(&data_wr, 1);

        // Wait at least 0.5 msec
        vTaskDelay(1);

        // Set slave register sub address to 0
    ulp_riscv_i2c_master_set_slave_reg_addr(0x00);

        // Receive 9 bytes. 6 bytes ID + 3 bytes CRC
        ulp_riscv_i2c_master_write_to_device(data_rd, 9);

        // Parse data_rd to extract the ID and the CRC separately
}
mholeys commented 1 year ago

Thank you for getting back @sudeep-mohanty I have tested this code, (found that "write to" instead of "read from"?) and it does indeed answer with a serial number now, but the ESP does not pickup the bytes as far as I can tell. The program hangs, after the call to ulp_riscv_i2c_master_read_from_device(data_rd, 9);

Yes I do have external pull ups

I have looked on scope during the read operation the address is sent, a zero byte is sent, but there is then a odd byte before the 9 S/N bytes. I think this may be the problem

mholeys commented 1 year ago

Here is the read operation on my scope, in case it helps. I understand this to be 0x58, 0x00, 0xD8 (with NACK) 5 unknown low bits, followed by 9 bytes of data image This is the reason I decided to use the command functions directly

sudeep-mohanty commented 1 year ago

Thanks for trying out @mholeys. Yes you correctly noticed the error in the code I shared.

While I don't have an explanation yet for the stray unknown 5 bits that are seen on the scope, I do suspect that the RTC_I2C driver misses the 9 bytes of data because the I2C Rx interrupt is probably being missed. In your tests, could you help to read the register bit RTC_I2C_RX_DATA_INT_RAW from the register RTC_I2C_INT_RAW_REG?

mholeys commented 1 year ago

Hello @sudeep-mohanty I was unsure when at what point you wanted me to check the register, so I checked within the ulp_riscv_i2c_master_read_from_device function. I used GET_PERI_REG_BITS(RTC_I2C_INT_RAW_REG, RTC_I2C_RX_DATA_INT_RAW, RTC_I2C_RX_DATA_INT_RAW) please correct me if I am using the wrong register macro. I added a print statement to after the while loop to see when bytes were being read as well, here are the results: For the first byte: Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 0 Got byte value of 0 For second byte: Raw Reg Rx before while loop: 0 Raw Reg Rx in read while wait: 0

sudeep-mohanty commented 1 year ago

Thanks for trying out @mholeys. It looks like that the Rx interrupt bit is always zero which is why we missed receiving the data. Not quite sure why the controller doesn't generate the interrupt. I'm afraid I do not see this with the BMP180 sensor that I have but I plan to test out the driver with more sensors and if possible with the SGP80 as well. I will keep you updated on it.

mholeys commented 1 year ago

@sudeep-mohanty I have ordered and recived an BMP180 and can confirm that it seems to communicate correctly. EDITIED I kept the print statements in in regards to the RX raw interrupt, I have changed the code for printing the interrupt bit.

Here is my output: Not a ULP-RISC V wakeup (cause = 0) Initializing RTC I2C ... Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 85 Reading calibration data from BMP180 ... Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 25 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 160 ac1 = 6560 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 252 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 104 ac2 = -920 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 199 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 80 ac3 = -14512 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 122 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 223 ac4 = 31455 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 99 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 143 ac5 = 25487 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 56 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 153 ac6 = 14489 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 25 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 115 b1 = 6515 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 0 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 25 b2 = 25 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 128 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 0 mb = -32768 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 209 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 246 mc = -11786 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 9 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 219 md = 2523

Reading initial uncompensated temperature and pressure data ... Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 87 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 236 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 150 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 1 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 0 Uncompensated Temperature = 22508 Uncompensated Pressure = 38401

Real Temperature = 21.799999 deg celcius Real Pressure = 1003.120000 hPa

Here is the code I used for testing the raw bit:

        printf("Raw Reg Rx before while loop: %d\n", REG_GET_FIELD(RTC_I2C_INT_RAW_REG, RTC_I2C_RX_DATA_INT_RAW));
        while (!REG_GET_FIELD(RTC_I2C_INT_ST_REG, RTC_I2C_RX_DATA_INT_ST)) {
            /* Minimal delay to avoid hogging the CPU */
            vTaskDelay(1);
        }
        printf("Raw Reg Rx after while loop: %d\n", REG_GET_FIELD(RTC_I2C_INT_RAW_REG, RTC_I2C_RX_DATA_INT_RAW));

Hopefully this helps.

Here is the new output for the SGP30 after using the correct macro, I have also removed my pull up resistors, and enabled the built in ones as to rule anything else out:

Initializing RTC I2C ... Getting S/N Raw Reg Rx: 0 Raw Reg Rx before while loop: 0 Raw Reg Rx after while loop: 1 Got byte[0]: 101 Raw Reg Rx before while loop: 0 Raw Reg Rx in read while wait: 0

I am not sure if this is a coincidence but the value 101 is within the expected bytes, but it is the 5th byte.

mholeys commented 1 year ago

@sudeep-mohanty I found that I was using the wrong function/macro to get the Raw interrupt bit, so I have edited the information above after it now works.

remyhx commented 1 year ago

I'm investigating the ULP for reading an SCD41 from Sensirion. It appears the basic I2C instructions only work with 8 bit registers. Sensirion uses 16-bit for almost every sensor they make... Writing is no problem, like mentioned above: MSB as slave reg address and one write to the LSB. But reading the sensor needs the same (so 1 write) and a couple of reads... If I use slave addr reg 0x00 the communication hangs. (doesn't expect a write)

remyhx commented 1 year ago

It is solved with the help of @sudeep-mohanty (as a reply to my question during DevCon22)! He asked me to remove the delay of the receive loop in ulp_risc_i2c.c and now it works. (The vtaskdelay)

sudeep-mohanty commented 1 year ago

@remyhx Thanks for reporting the issue and for trying out the solution! I will take it forward and create an internal ticket to update the driver appropriately so that it works with all kinds of sensors. Thanks!

Veldmonster commented 1 year ago

Why is the current ulp_risc_i2c restricted to GPIO0-3? It is not apparent from the datasheet that such a restriction should apply. For my hardware (ESP32S3) it would be ideal if GPIO17 (SCL) and GPIO18 (SDA) was supported. Please indicate if this will be supported in future.

remyhx commented 1 year ago

It’s mentioned in the technical reference manual Reference link

It would be awesome if other GPIO’s were also possible. Agree with you that the regular datasheet should be more clear about this.

Veldmonster commented 1 year ago

@remyhx Thanks for pointing out that it is noted in the technical reference manual. Unfortunately, that probably means it is not likely to change.