Giter VIP home page Giter VIP logo

Comments (5)

boarchuz avatar boarchuz commented on May 23, 2024

Hi @Algonsi
I2C is very limited when using ULP commands. You can only do the most typical I2C write (address+register+write_8b) and read (address+register->restart->+read_8b) operations, which don't seem to be quite right for the BH1750.

There are bitbanging subroutines in HULP that will do the job. The SHT3X example (https://github.com/boarchuz/HULP/blob/master/examples/I2C/Bitbang/Cmd/SHT3X/main/main.cpp) seems very similar to the pattern described in the BH1750 data sheet so that should be a good starting point.

Unfortunately these subroutines can take up a fair bit of memory despite being optimised, so you might struggle to fit in much other logic due to Arduino's 512 byte default configuration.

Try to make sense of it, and don't hesitate to ask if you're having any issues.

from hulp.

Algonsi avatar Algonsi commented on May 23, 2024

Thank you so much, @boarchuz.
I'm going to try to make the module work with bitbanging as you suggested.

from hulp.

Algonsi avatar Algonsi commented on May 23, 2024

Well, I'm thinking about it and I'm going crazy.
According to the datasheet and as I can understand, to read the 16-bit measurement result from the sensor, the ESP32 has to do the following I2C measurement sequence as master, every time it wants to get it:

Start
Slave address | 0 (7 bits + 'Write' bit)
--- Receive slave's Ack
Measurement mode instruction (8 bits setting Continuous/One Time measurement and High/Low resolution)
--- Receive slave's Ack
Stop

Wait for the slave measurement to complete. Depending on the sensor's resolution mode, it can be up to 180 ms (H-resolution mode) or up to 24 ms (L-resolution mode). Then,

Start
Slave address | 1 (7 bits + 'Read' bit)
--- Receive slave's Ack
--- High Byte is received
Master's Ack
--- Low Byte is received
Master's NAck
Stop

It seems simple but I can't get it. How could I do it with HULP, please?

from hulp.

boarchuz avatar boarchuz commented on May 23, 2024

Hi @Algonsi,
Give this a try. It's not tested but should be pretty close. If it doesn't work please include your updated code and a I2C capture using an oscilloscope, if possible.

#define ULP_REPEAT_INTERVAL_MS 1000
#define SCL_PIN GPIO_NUM_4            // D1
#define SDA_PIN GPIO_NUM_15           // D2
#define LIGHT_SENSOR_I2C_ADDR 35      // 0x23

#define LIGHT_SENSOR_COMMAND_ONETIME_LOW_RESOLUTION 0b00100011
#define LIGHT_SENSOR_LOW_RESOLUTION_WAIT_MS 24

// Write slave address + command
static RTC_SLOW_ATTR ulp_var_t ulp_write_cmd[] = {
    HULP_I2C_CMD_HDR(LIGHT_SENSOR_I2C_ADDR, LIGHT_SENSOR_COMMAND_ONETIME_LOW_RESOLUTION, 0),
};

// Read result (16 bits)
static RTC_SLOW_ATTR ulp_var_t ulp_read_cmd[HULP_I2C_CMD_BUF_SIZE(2] = {
    HULP_I2C_CMD_HDR_NO_PTR(LIGHT_SENSOR_I2C_ADDR, 2),
};

static RTC_DATA_ATTR ulp_var_t ulp_error_code;
static RTC_DATA_ATTR ulp_var_t ulp_measurement_count;

void init_ulp() {
    enum {
        LABEL_I2C_READ,
        LABEL_I2C_WRITE,
        LABEL_I2C_ERROR,
    };

    const ulp_insn_t program[] = {
            I_MOVI(R2, 0),

            // Prepare write command
            I_MOVO(R1, ulp_write_cmd),
            // Go to subroutine
            M_RETURN(HULP_LBLA(), R3, LABEL_I2C_WRITE),
            // Check error code upon return
            M_BGE(LABEL_I2C_ERROR, 1),

            // Wait 24ms for result to be ready
            M_DELAY_MS_20_1000(LIGHT_SENSOR_LOW_RESOLUTION_WAIT_MS),

            // Prepare read command
            I_MOVO(R1, ulp_read_cmd),
            // Go to subroutine
            M_RETURN(HULP_LBLA(), R3, LABEL_I2C_READ),
            // Check error code upon return
            M_BGE(LABEL_I2C_ERROR, 1),

            // Success
            I_GET(R1, R2, ulp_measurement_count),
            I_ADDI(R1, R1, 1),
            I_PUT(R1, R2, ulp_measurement_count),
            // fall through to clear error code (R0==0) then halt

        M_LABEL(LABEL_I2C_ERROR),
            I_PUT(R0, R2, ulp_error_code),
            I_HALT(),

            M_INCLUDE_I2CBB_CMD(LABEL_I2C_READ, LABEL_I2C_WRITE, SCL_PIN, SDA_PIN)
    };

    ESP_ERROR_CHECK(hulp_configure_pin(SCL_PIN, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLUP_ONLY, 0));
    ESP_ERROR_CHECK(hulp_configure_pin(SDA_PIN, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLUP_ONLY, 0));

    ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), ULP_REPEAT_INTERVAL_MS * 1000, 0));
    ESP_ERROR_CHECK(hulp_ulp_run(0));
}

SoC:

for(;;)
{
    const uint16_t error_code = ulp_error_code.val;
    if(error_code != 0)
    {
        printf("ULP error: %u\n", error_code);
    }
    else
    {
        const uint16_t count = ulp_measurement_count.val;
        const uint16_t sensor_value = ulp_read_cmd[HULP_I2C_CMD_DATA_OFFSET].val;
        printf("ULP count: %u, sensor_value: %u\n", count, sensor_value);
    }
    vTaskDelay(250 / portTICK_PERIOD_MS);
}

from hulp.

Algonsi avatar Algonsi commented on May 23, 2024

Hi @boarchuz,
Really thanks for your help. Now it works.
I've made a few tiny modifications to your code for the Arduino IDE:

#include <hulp_arduino.h>

#define ULP_REPEAT_INTERVAL_MS 1000
#define SCL_PIN GPIO_NUM_4            // D1
#define SDA_PIN GPIO_NUM_15           // D2
#define LIGHT_SENSOR_I2C_ADDR 0x23

#define LIGHT_SENSOR_COMMAND_ONETIME_LOW_RESOLUTION 0b00100011
#define LIGHT_SENSOR_LOW_RESOLUTION_WAIT_MS 24

// Write slave address + command
static RTC_SLOW_ATTR ulp_var_t ulp_write_cmd[] = {
  HULP_I2C_CMD_HDR(LIGHT_SENSOR_I2C_ADDR, LIGHT_SENSOR_COMMAND_ONETIME_LOW_RESOLUTION, 0),
};

// Read result (16 bits)
static RTC_SLOW_ATTR ulp_var_t ulp_read_cmd[HULP_I2C_CMD_BUF_SIZE(2)] = {
  HULP_I2C_CMD_HDR_NO_PTR(LIGHT_SENSOR_I2C_ADDR, 2),
};

static RTC_DATA_ATTR ulp_var_t ulp_error_code;
static RTC_DATA_ATTR ulp_var_t ulp_measurement_count;
volatile RTC_DATA_ATTR ulp_var_t renew; // > 0 if a new read is ready

void init_ulp() {
  enum {
    LABEL_I2C_READ,
    LABEL_I2C_WRITE,
    LABEL_I2C_ERROR,
  };

  const ulp_insn_t program[] = {
    I_MOVI(R2, 0),

    // Prepare write command
    I_MOVO(R1, ulp_write_cmd),
    // Go to subroutine
    M_RETURN(HULP_LBLA(), R3, LABEL_I2C_WRITE),
    // Check error code upon return
    M_BGE(LABEL_I2C_ERROR, 1),

    // Wait 24ms for result to be ready
    M_DELAY_MS_20_1000(LIGHT_SENSOR_LOW_RESOLUTION_WAIT_MS),

    // Prepare read command
    I_MOVO(R1, ulp_read_cmd),
    // Go to subroutine
    M_RETURN(HULP_LBLA(), R3, LABEL_I2C_READ),
    // Check error code upon return
    M_BGE(LABEL_I2C_ERROR, 1),

    // Success
    I_MOVI(R2, 0),
    I_GET(R1, R2, ulp_measurement_count),
    I_ADDI(R1, R1, 1),
    I_PUT(R1, R2, ulp_measurement_count),

    // fall through to clear error code (R0==0) then halt
    M_LABEL(LABEL_I2C_ERROR),
    I_MOVI(R2, 0),
    I_PUT(R0, R2, ulp_error_code),

    // A new read is ready
    I_MOVI(R1, 1),
    I_PUT(R1, R2, renew),

    I_HALT(),

    M_INCLUDE_I2CBB_CMD(LABEL_I2C_READ, LABEL_I2C_WRITE, SCL_PIN, SDA_PIN)
  };

  ESP_ERROR_CHECK(hulp_configure_pin(SCL_PIN, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLUP_ONLY, 0));
  ESP_ERROR_CHECK(hulp_configure_pin(SDA_PIN, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLUP_ONLY, 0));

  ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), ULP_REPEAT_INTERVAL_MS * 1000, 0));
  ESP_ERROR_CHECK(hulp_ulp_run(0));
}

void setup()
{
  renew.val = 0;
  init_ulp();
}

void loop()
{
  if (renew.val)
  {
    renew.val = 0;
    const uint16_t error_code = ulp_error_code.val;
    if (error_code != 0)
    {
      printf("ULP error: %u\n", error_code);
    }
    else
    {
      const uint16_t count = ulp_measurement_count.val;
      const uint16_t sensor_value = ulp_read_cmd[HULP_I2C_CMD_DATA_OFFSET].val;
      printf("ULP count: %u, sensor_value: %u\n", count, sensor_value);
    }
  }
  delay(1);
}

Btw, there are several warnings during compilation due to the 'M_RETURN' subroutine call:

In file included from C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp_compat.h:17,
from C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp.h:8,
from C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp_arduino.h:1,
from C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:1:
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino: In function 'void init_ulp()':
C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp_macros.h:35:53: warning: narrowing conversion of '({...})' from 'int' to 'uint32_t' {aka 'unsigned int'} inside { } [-Wnarrowing]
(CONFIG_HULP_LABEL_AUTO_BASE + LINE);
^
C:\Users\algonsi\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3/tools/sdk/esp32/include/ulp/include/esp32/ulp.h:815:14: note: in definition of macro 'M_LABELPC'
.label = label_num,
^~~~~~~~~
C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp_macros.h:142:5: note: in expansion of macro 'M_MOVL'
M_MOVL(reg, label_return_point),
^~~~~~
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:38:5: note: in expansion of macro 'M_RETURN'
M_RETURN(HULP_LBLA(), R3, LABEL_I2C_WRITE),
^~~~~~~~
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:38:14: note: in expansion of macro 'HULP_LBLA'
M_RETURN(HULP_LBLA(), R3, LABEL_I2C_WRITE),
^~~~~~~~~
C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp_macros.h:35:53: warning: narrowing conversion of '({...})' from 'int' to 'uint32_t' {aka 'unsigned int'} inside { } [-Wnarrowing]
(CONFIG_HULP_LABEL_AUTO_BASE + LINE);
^
C:\Users\algonsi\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3/tools/sdk/esp32/include/ulp/include/esp32/ulp.h:795:14: note: in definition of macro 'M_LABEL'
.label = label_num,
^~~~~~~~~
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:38:5: note: in expansion of macro 'M_RETURN'
M_RETURN(HULP_LBLA(), R3, LABEL_I2C_WRITE),
^~~~~~~~
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:38:14: note: in expansion of macro 'HULP_LBLA'
M_RETURN(HULP_LBLA(), R3, LABEL_I2C_WRITE),
^~~~~~~~~
C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp_macros.h:35:53: warning: narrowing conversion of '({...})' from 'int' to 'uint32_t' {aka 'unsigned int'} inside { } [-Wnarrowing]
(CONFIG_HULP_LABEL_AUTO_BASE + LINE);
^
C:\Users\algonsi\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3/tools/sdk/esp32/include/ulp/include/esp32/ulp.h:815:14: note: in definition of macro 'M_LABELPC'
.label = label_num,
^~~~~~~~~
C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp_macros.h:142:5: note: in expansion of macro 'M_MOVL'
M_MOVL(reg, label_return_point),
^~~~~~
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:48:5: note: in expansion of macro 'M_RETURN'
M_RETURN(HULP_LBLA(), R3, LABEL_I2C_READ),
^~~~~~~~
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:48:14: note: in expansion of macro 'HULP_LBLA'
M_RETURN(HULP_LBLA(), R3, LABEL_I2C_READ),
^~~~~~~~~
C:\Users\algonsi\ArduinoProjects\libraries\HULP-master\src/hulp_macros.h:35:53: warning: narrowing conversion of '({...})' from 'int' to 'uint32_t' {aka 'unsigned int'} inside { } [-Wnarrowing]
(CONFIG_HULP_LABEL_AUTO_BASE + LINE);
^
C:\Users\algonsi\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.3/tools/sdk/esp32/include/ulp/include/esp32/ulp.h:795:14: note: in definition of macro 'M_LABEL'
.label = label_num,
^~~~~~~~~
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:48:5: note: in expansion of macro 'M_RETURN'
M_RETURN(HULP_LBLA(), R3, LABEL_I2C_READ),
^~~~~~~~
C:\Users\algonsi\ArduinoProjects\prueba_ulp_i2c_sensor_luz\prueba_ulp_i2c_sensor_luz.ino:48:14: note: in expansion of macro 'HULP_LBLA'
M_RETURN(HULP_LBLA(), R3, LABEL_I2C_READ),
^~~~~~~~~

Thanks again and have a nice weekend!

from hulp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.