HULP: I2C bitbang CRC third byte does not match
Great job implementing the I2C bitbang mode in ULP! Your repo deserves more stars.
I’m porting the C code of reading the Sensirion SDP8xx digital sensor to HULP I2C bitbang. I’m reading the sensor periodically in continuous mode. C code is proven to work right, and it’s here https://github.com/dizcza/sdpsensor-esp-arduino/blob/master/sdpsensor.cpp
The issue happens with the third byte which is CRC according to the documentation. The read value does not match with the expected (only in ULP mode, works fine in plain C).
#include <esp_log.h>
#include <esp_sleep.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <hulp.h>
#include <hulp_i2cbb.h>
#include "sdpsensor.h"
static const char *TAG = "MAIN";
static const uint8_t SLAVE_ADDR = 0x25;
static const gpio_num_t SDA_PIN = GPIO_NUM_33;
static const gpio_num_t SCL_PIN = GPIO_NUM_32;
static RTC_SLOW_ATTR ulp_var_t ulp_read_cmd[HULP_I2C_CMD_BUF_SIZE(3)] = {
HULP_I2C_CMD_HDR_NO_PTR(SLAVE_ADDR, 3),
};
void init_ulp() {
enum {
LABEL_I2C_READ,
LABEL_I2C_READ_CONTINUOUS,
LABEL_I2C_READ_RETURN,
LABEL_I2C_WRITE,
LABEL_I2C_ERROR,
};
const ulp_insn_t program[] = {
M_LABEL(LABEL_I2C_READ_CONTINUOUS),
M_DELAY_US_100_5000(1000),
I_MOVO(R1, ulp_read_cmd),
M_MOVL(R3, LABEL_I2C_READ_RETURN),
M_BX(LABEL_I2C_READ),
M_LABEL(LABEL_I2C_READ_RETURN),
M_BGE(LABEL_I2C_ERROR, 1),
M_BX(LABEL_I2C_READ_CONTINUOUS),
M_LABEL(LABEL_I2C_ERROR),
I_WAKE(),
I_END(), // end ulp program so it won't run again
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_FLOATING, 0));
ESP_ERROR_CHECK(hulp_configure_pin(SDA_PIN, RTC_GPIO_MODE_INPUT_ONLY, GPIO_FLOATING, 0));
hulp_peripherals_on();
vTaskDelay(1000 / portTICK_PERIOD_MS);
ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 10ULL * 1000, 0));
ESP_ERROR_CHECK(hulp_ulp_run(0));
}
void print_result() {
const int16_t dp = (int16_t) ulp_read_cmd[HULP_I2C_CMD_DATA_OFFSET].val;
const uint8_t crc = ulp_read_cmd[HULP_I2C_CMD_DATA_OFFSET + 1].val_bytes[0];
ESP_LOGI(TAG, "Diff pressure %3d CRC %3d expected %3d", dp, crc, compute_crc((uint8_t*) &dp));
}
void app_main(void) {
SDPSensor_I2C_GPIO i2c_gpio = {
.addr = SLAVE_ADDR,
.port = 0,
.sda = SDA_PIN,
.scl = SCL_PIN
};
// Init the sensor & start continuous mode
SDPSensor_Init(&i2c_gpio, NULL);
init_ulp();
while (1) {
vTaskDelay(pdMS_TO_TICKS(100));
print_result();
}
}
Logs
I (2943) MAIN: Diff pressure -8 CRC 0 expected 2
I (3043) MAIN: Diff pressure 7 CRC 0 expected 47
I (3143) MAIN: Diff pressure 3 CRC 0 expected 172
I (3243) MAIN: Diff pressure 9 CRC 0 expected 66
I (3343) MAIN: Diff pressure 3 CRC 0 expected 172
I (3443) MAIN: Diff pressure 2 CRC 0 expected 88
I (3543) MAIN: Diff pressure 10751 CRC 0 expected 14 // 10751 looks fishy, need to investigate; probably due to unsynchonous read-write operations of the same memory block
I (3643) MAIN: Diff pressure 4 CRC 0 expected 2
I (3743) MAIN: Diff pressure -5 CRC 0 expected 47
I (3843) MAIN: Diff pressure 0 CRC 0 expected 129
I (3943) MAIN: Diff pressure -4 CRC 0 expected 129
I (4043) MAIN: Diff pressure 12 CRC 0 expected 53
I (4143) MAIN: Diff pressure 1 CRC 0 expected 117
I (4243) MAIN: Diff pressure -3 CRC 0 expected 117
I (4343) MAIN: Diff pressure 1 CRC 0 expected 117
I (4443) MAIN: Diff pressure 4 CRC 0 expected 2
Would much appreciate if you provide any hint why this might happen.
I have several other questions but let’s deal with this one first.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 23 (8 by maintainers)
The ULP can only access RTC Slow Memory. For that reason, I think it’s best to be explicit and use
RTC_SLOW_ATTRfor anything and everything the ULP will be using.RTC Fast Memory is very useful if you’re running low on Slow, but can only be accessed by CPU0 so you need to take care using it.
RTC_DATA_ATTRshould be avoided here, in my opinion. It will almost always default to Slow but is sometimes Fast, depending on configuration. Only use it if you’re sure you don’t need to care which segment is used, or need to support targets which may not have one or the other segment. Just to be extra clear: There are only two RTC memory segments - Fast and Slow; anything with theRTC_DATA_ATTRattribute will be placed in one of these, depending on config.So to answer your questions directly:
RTC_DATA_ATTR==RTC_SLOW_ATTRfor your config. I would suggest usingRTC_SLOW_ATTRto be “more correct”.2 & 3. No, the ULP can only access RTC Slow Mem.
Yes you should make that change, that’s a typo sorry!
There would be no need for the delay usually, so you can safely remove it. It was probably something I stuck there to be conservative with the ULP/bus initialisation one day, and it got copied to all of the others too.