Comments (5)
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.
Thank you so much, @boarchuz.
I'm going to try to make the module work with bitbanging as you suggested.
from hulp.
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.
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.
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)
- undefined reference error in example code for simple debugging HOT 4
- support for mpu6050 HOT 2
- problems reading sht3x i2c sensor HOT 10
- How can I make this work with Arduino? HOT 3
- touch, ULP FSM instructions, without macros
- is i2c bitbang limited to RTC GPIOs ?? HOT 2
- Arduino ide8.16 compilation error on Mac HOT 6
- Variable gets a value as if the shift command had not been executed HOT 4
- Possible confrontation with some libraries HOT 7
- HULP ADC read problem while wake up HOT 2
- I2C bitbang CRC third byte does not match HOT 23
- Measuring pulse length in milliseconds HOT 5
- ESP32 Not Waking On I_WAKE() HOT 3
- feature request: UART with parity bit HOT 2
- ADC example, comparing if value is wihin a range, rather than just under a threshold HOT 3
- issue with I_GPIO_HOLD_DIS HOT 7
- ESP32-S2 HOT 2
- Add librairies in Arduino ide HOT 11
- Pulse counter HOT 17
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from hulp.