{"id":28155918,"url":"https://github.com/trianglesis/i2c-tests","last_synced_at":"2026-06-28T22:31:41.508Z","repository":{"id":288918793,"uuid":"969537219","full_name":"trianglesis/I2C-tests","owner":"trianglesis","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-25T18:12:09.000Z","size":1584,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-06T06:28:10.417Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trianglesis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-04-20T11:30:03.000Z","updated_at":"2025-04-25T18:12:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"b2a1787d-98a7-46a1-80d2-6c4bfd50e06e","html_url":"https://github.com/trianglesis/I2C-tests","commit_stats":null,"previous_names":["trianglesis/i2c-tests"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/trianglesis/I2C-tests","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trianglesis%2FI2C-tests","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trianglesis%2FI2C-tests/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trianglesis%2FI2C-tests/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trianglesis%2FI2C-tests/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trianglesis","download_url":"https://codeload.github.com/trianglesis/I2C-tests/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trianglesis%2FI2C-tests/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34906700,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-15T07:14:50.316Z","updated_at":"2026-06-28T22:31:41.502Z","avatar_url":"https://github.com/trianglesis.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Test I2C\n\nThis project is just a separate logical branch from another project. \n\nThis is clean setup to test new `I2C` driver from `IDF 5.4.1` with few sensors I have.\n\nI will reuse old examples to send\\reveive commands, but with a new I2C driver.\n\nNEW I2C driver from 5.4+ [version](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html)\n\n## Info\n\nThis is a separate \"branch\" from my project [Air_Quality_station](https://github.com/trianglesis/Air_Quality_station/blob/4802c416501cf49720c3299119afd54bb335f894/README.md)\n\nWhere I stuck with `NACK` messages for any interaction with `I2C` device.\n\nCompose driver using official documentation.\n\nTest installed `I2C` device discovery with utility: [i2c_tools](https://github.com/espressif/esp-idf/blob/4c2820d377d1375e787bcef612f0c32c1427d183/examples/peripherals/i2c/i2c_tools/README.md)\n\nThen, create a `I2C` bus and communicate with devices:\n\n- `SCD40` - CO2 Sensor `0x62`\n- `BME680` - temperature, humidity, pressure sensor `0x77`\n\n## SDC4x\n\nSee datasheet.\nAddress: `0x62`\n\nThere are two representations for this sensor, both rely on old `I2C` driver and have partial implementation, something work, something is not:\n\n- [ESP IDF Lib (old)](https://github.com/Sensirion/embedded-i2c-scd4x/blob/455a41c6b7a7a86a55d6647f5fc22d8574572b7b)\n- [Sensirion (newer)](https://github.com/Sensirion/embedded-i2c-scd4x/blob/455a41c6b7a7a86a55d6647f5fc22d8574572b7b)\n- [issue](https://github.com/UncleRus/esp-idf-lib/issues/582)\n- [issue](https://github.com/UncleRus/esp-idf-lib/issues/624)\n- [old driver](https://github.com/UncleRus/esp-idf-lib/issues/667)\n\nMy current issue with `ESO IDF Lib`\n\n```log\nI (10157) CO2 SCD41 INIT: run scd4x_get_serial_number\nD (10167) i2cdev: Reconfiguring I2C driver on port 0\nD (10167) intr_alloc: Connected src 50 to int 15 (cpu 0)\nD (10177) i2cdev: I2C driver successfully reconfigured on port 0\nD (10187) i2cdev: Timeout: ticks = 0 (0 usec) on port 0\nD (10177) wifi:mms: 0-\u003e0\nE (10187) i2cdev: Could not write to device [0x62 at 0]: -1 (ESP_FAIL)\nESP_ERROR_CHECK failed: esp_err_t 0xffffffff (ESP_FAIL) at 0x42011308\n--- 0x42011308: sensor_init at D:/Projects/ESP/projects/ESP32-C6-OLED/Air_Quality_station/main/sensor_co2/co2_sensor.c:164 (discriminator 1)\n\nfile: \"./main/sensor_co2/co2_sensor.c\" line 164\nfunc: sensor_init\nexpression: scd4x_get_serial_number(\u0026dev, serial, serial + 1, serial + 2)\n\nabort() was called at PC 0x4080b6d1 on core 0\n--- 0x4080b6d1: _esp_error_check_failed at D:/Projects/ESP/Espressif/v5.4.1/esp-idf/components/esp_system/esp_err.c:49\n```\n\n## BME680\n\nSee datasheet.\nAddress: `0x77`\n\nThere is also a driver for `BME680` from the same repo, but again, it relies on an old `I2C` driver and there are issues with this driver:\n\n- [ESP IDF Lib (old)](https://github.com/UncleRus/esp-idf-lib/blob/a02cd6bb5190cab379125140780adcb8d88f9650/components/bme680)\n- [issue](https://github.com/UncleRus/esp-idf-lib/issues/609)\n- [old driver](https://github.com/UncleRus/esp-idf-lib/issues/667)\n- [Datasheet](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme680-ds001.pdf)\n\n## Test and discover\n\nUse `i2c_tools` from IDF official repo.\n\nBoth sensors are using same pins: `i2cconfig  --port=0 --freq=100000 --sda=22 --scl=23`\n\n![pins](doc/pics/sensor_pins_i2c.png)\n\nBoth of them discovered correctly, this means pins and solder OK\n\n```log\ni2c-tools\u003e i2cconfig  --port=0 --freq=100000 --sda=22 --scl=23\ni2c-tools\u003e i2cdetect\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00: 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n60: -- -- 62 -- -- -- -- -- -- -- -- -- -- -- -- --\n70: -- -- -- -- -- -- -- 77 -- -- -- -- -- -- -- --\n```\n\n\n## Setup and run\n\nSaving some doc here for faster accesss\n\n### Init\n\n```cpp\n    i2c_master_bus_config_t i2c_mst_config = {\n        .clk_source = I2C_CLK_SRC_DEFAULT,\n        .i2c_port = I2C_PORT,\n        .scl_io_num = COMMON_SCL_PIN,\n        .sda_io_num = COMMON_SDA_PIN,\n        .glitch_ignore_cnt = 7,\n        .flags.enable_internal_pullup = true,\n    };\n```\n\n- [i2c_master_bus_config_t](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html#_CPPv423i2c_master_bus_config_t)\n\nHints for LP:\n\n- [LP core](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html#install-i2c-master-bus-with-lp-i2c-peripheral)\n\n```cpp\ni2c_master_bus_config_t i2c_mst_config = {\n    .clk_source = LP_I2C_SCLK_DEFAULT,    // clock source for LP I2C, might different from HP I2C\n    .i2c_port = LP_I2C_NUM_0,             // Assign to LP I2C port\n    .scl_io_num = 7,                      // SCL IO number. Please refer to technical reference manual\n    .sda_io_num = 6,                      // SDA IO number. Please refer to technical reference manual\n    .glitch_ignore_cnt = 7,\n    .flags.enable_internal_pullup = true,\n};\n```\n\nProbably need to check PINs with names:\n- `LP_GPIO6` - `LP_I2C_SDA`\n- `LP_GPIO7` - `LP_I2C_SCL`\n\n\n### Conf\n\n# For SCD4x aka CO2 sensor\n\nConfig device or two\n\n```cpp\n    // Add CO2 sensor first\n    i2c_device_config_t dev_cfg = {\n        .dev_addr_length = I2C_ADDR_BIT_LEN_7,\n        .device_address = SCD4X_I2C_ADDR,\n        .scl_speed_hz = 100000,\n    };\n```\n\n- [i2c_device_config_t](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html#_CPPv419i2c_device_config_t)\n  - `disable_ack_check` - Disable ACK check. If this is set false, that means ack check is enabled, the transaction will be stopped and API returns error when nack is detected.\n  - `scl_wait_us` - Timeout value. (unit: us). Please note this value should not be so small that it can handle stretch/disturbance properly. If 0 is set, that means use the default reg value\n\n\n### Add\n\nAdd devices\n\n```cpp\n    // Add CO2 first\n    i2c_master_dev_handle_t scd41_handle;\n    ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, \u0026scd41_cfg, \u0026scd41_handle));\n    // Add BME680 device second\n    i2c_master_dev_handle_t bme680_handle;\n    ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, \u0026bme680_cfg, \u0026bme680_handle));\n```\n\n- `bus_handle` -- [in] I2C bus handle.\n  -  This is common bus for all devices!\n- `dev_config` -- [in] device config.\n  -  This is UNIQUE var for a SINGLE device\n- `ret_handle` -- [out] device handle.\n  -  This is UNIQUE handle of a SINGLE device\n\nReturns:\n- `ESP_OK`: Create I2C master device successfully.\n- `ESP_ERR_INVALID_ARG`: I2C bus initialization failed because of invalid argument.\n- `ESP_ERR_NO_MEM`: Create I2C bus failed because of out of memory.\n\nHint: use `i2c_master_get_bus_handle` to obtain al already created bus for another device to add, [doc](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html#get-i2c-master-handle-via-port)\n\n```cpp\ni2c_master_bus_handle_t bus_handle;\nESP_ERROR_CHECK(i2c_master_get_bus_handle(0, \u0026bus_handle));\n```\n\n- `port_num` -- I2C port number for which the handle is to be retrieved.\n- `ret_handle` -- Pointer to a variable where the retrieved handle will be stored.\n\nBuild and see if there are no errors in console.\n\n### Test and use\n\nConfig the build now.\n`LOG_DEFAULT_LEVEL` to debug\n`I2C_ENABLE_DEBUG_LOG` to debug\n`ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS` to `120` seconds, to have a time to read the log.\n\n\nUse [example](https://github.com/UncleRus/esp-idf-lib/blob/a02cd6bb5190cab379125140780adcb8d88f9650/examples/scd4x/default/main/main.c) (old) as refference.\n\nWe are skipping parts with `i2cdev` implemenatation and diretcly sending CMD to our sensor.\n\nWill trink about consurrency later, when sensor starts to work.\n\n### Wake UP\n\nStart CO2 sensor with `wake_up` command using [I2C Master Write](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html#i2c-master-write)\n\n\n| Command | Hex. Code  | I2C type     | time | During meas.  |\n| :---    | :---       | :---         | :--- | :---          |\n| `wake_up` | `0x36f6` | send command |  30  | no            |\n| `get_serial_number` | `0x3682` | read | 1    | no            |\n\n\nUsing example from `Sensiniron`: [scd4x_wake_up](https://github.com/Sensirion/embedded-i2c-scd4x/blob/455a41c6b7a7a86a55d6647f5fc22d8574572b7b/scd4x_i2c.c#L585)\n\nThere is no other implemenatation of `HAL` or `i2c` driver, so we will use it now in RAW mode, directly communicating with device.\n\nAssign vars and reuse buffer helpers from [Sensiniron](https://github.com/Sensirion/embedded-i2c-scd4x/blob/455a41c6b7a7a86a55d6647f5fc22d8574572b7b/sensirion_i2c.c#L180)\n\n```cpp\n    // Communicate with CO2\n    uint8_t* buff_wr = communication_buffer;\n    uint16_t local_offset = 0;\n    local_offset = sensirion_i2c_add_command16_to_buffer(buff_wr, local_offset, 0x36f6);\n\n    // Send wake_up cmd and wait 30 ms\n    ESP_ERROR_CHECK(i2c_master_transmit(scd41_handle, buff_wr, local_offset, 30));\n    ESP_LOGI(TAG, \"CMD Wake Up sent!\");\n```\n\nAfter sending the CMD - nothing bad happens, seems like it's working:\n\n```log\nI (1566) i2c_master: CMD Wake Up sent!\n```\n\n### Get Serial\n\nNow send cmd and receive serial! Using:\n- Sensiniron: [scd4x_get_serial_number](https://github.com/Sensirion/embedded-i2c-scd4x/blob/455a41c6b7a7a86a55d6647f5fc22d8574572b7b/scd4x_i2c.c#L448)\n  - In Rasp example: [serial_number](https://github.com/Sensirion/embedded-i2c-scd4x/blob/455a41c6b7a7a86a55d6647f5fc22d8574572b7b/sample-implementations/RaspberryPi_Pico/main.c#L40)\n- UncleRus: [scd4x_get_serial_number](https://github.com/UncleRus/esp-idf-lib/blob/a02cd6bb5190cab379125140780adcb8d88f9650/components/scd4x/scd4x.c#L317)\n\nNew `i2c` driver gives us fancy method to send and receive at once: [i2c_master_transmit_receive](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html#_CPPv427i2c_master_transmit_receive23i2c_master_dev_handle_tPK7uint8_t6size_tP7uint8_t6size_ti)\n\nUse new method, [doc](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html#i2c-master-write-and-read)\n\nModify default method according to real method from `UncleRus` repo, with buffer len 3:\n\nOR\n\nUse Sensiniron approach and copy their method: [sensirion_common_copy_bytes](https://github.com/Sensirion/embedded-i2c-scd4x/blob/455a41c6b7a7a86a55d6647f5fc22d8574572b7b/scd4x_i2c.c#L463)\n\n```cpp\n    // Read serial number\n    uint16_t serial_n_buff[3] = {0};\n    local_offset = 0; // Reset offset\n    local_offset = sensirion_i2c_add_command16_to_buffer(buff_wr, local_offset, 0x3682);\n    // Send and receive after a short wait\n    uint8_t buff_r[3] = {0};  // Output: serial number\n    sleep_ms = 1 * 1000;\n    ESP_ERROR_CHECK(i2c_master_transmit_receive(scd41_handle, buff_wr, sizeof(buff_wr), buff_r, sizeof(buff_r), sleep_ms));\n    // Transform received:\n    sensirion_common_copy_bytes(\u0026buff_r[0], (uint8_t*)serial_n_buff, (sizeof(serial_n_buff) * 2));\n    ESP_LOGI(TAG, \"Sensor serial number is: 0x%x 0x%x 0x%x\\n\", (int)serial_n_buff[0], (int)serial_n_buff[1], (int)serial_n_buff[2]);\n```\n\nWhere vars are:\n- `serial_n_buff` - where to save parsed number, as per Sensiniron example\n- `local_offset` - reset cmd buffer to 0 again\n- `buffer` - where to receive the CMD `get serial num` output\n- `sleep_ms` - from `UncleRus` example, wait for answer\n\nThe function args:\n- `i2c_dev` -- [in] I2C master device handle that created by i2c_master_bus_add_device.\n- `write_buffer` -- [in] Data bytes to send on the I2C bus.\n- `write_size` -- [in] Size, in bytes, of the write buffer.\n- `read_buffer` -- [out] Data bytes received from i2c bus.\n- `read_size` -- [in] Size, in bytes, of the read buffer.\n- `xfer_timeout_ms` -- [in] Wait timeout, in ms. Note: -1 means wait forever.\n\nAnd it's working fine:\n\n```log\nI (1567) i2c_master: Sensor serial number is: 0x499f 0xe0 0x499f\n```\n\nBy datasheet is should be like: `Example: serial number is 273’325’796’834’238`\n\n\n| | | | |                                                                                       |\n| :--- | :--- | :--- | :--- | :---                                                              |\n| Write | 0x3682                                                                                |\n| (hexadecimal) | Command                                                                       |\n| Wait | 1 ms | command execution time                                                          |\n| Response | 0xf896 | 0x31 | 0x9f07 | 0xc2 | 0x3bbe | 0x89                                      |\n| (hexadecimal) | word[0] | CRC of 0xf896 |  word[1] | CRC of 0x9f07 | word[2] | CRC of 0x3bbe  |\n\nSeems like I have a right response, but it should be converted, probably.\n\nTesting different aaproaches and it now shows stable output:\n\n```log\nI (1567) i2c_master: Sensor serial number is: 0x499f 0xe0 0x1c24\n```\n\nLet's move forward and get more meaningfull data.\n\n### Suddenly\n\nIt stopped working:\n\n```log\nI (591) i2c_master: Temperature sensor device added!\nI (10601) i2c_master: All devices added! Start communication\nE (10601) i2c.master: I2C transaction unexpected nack detected\nE (10601) i2c.master: s_i2c_synchronous_transaction(924): I2C transaction failed\nE (10601) i2c.master: i2c_master_multi_buffer_transmit(1186): I2C transaction failed\nESP_ERROR_CHECK failed: esp_err_t 0x103 (ESP_ERR_INVALID_STATE) at 0x4200c292\n--- 0x4200c292: app_main at D:/Projects/ESP/projects/ESP32-C6/I2C-tests/main/main.c:99 (discriminator 1)\n\nfile: \"./main/main.c\" line 99\nfunc: app_main\nexpression: i2c_master_transmit(scd41_handle, buff_wr, local_offset, 30)\n\n```\n\nTest I2C:\n\n```log\ni2c-tools\u003e i2cdetect\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00: 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n60: -- -- 62 -- -- -- -- -- -- -- -- -- -- -- -- --\n70: -- -- -- -- -- -- -- 77 -- -- -- -- -- -- -- -- \n```\n\nIt's ok...\nLog is the same!\n\nNow disable the wake up cmd and check again:\n\n```log\nI (10566) i2c_master: All devices added! Start communication\nE (10566) i2c.master: I2C transaction unexpected nack detected\nE (10566) i2c.master: s_i2c_synchronous_transaction(924): I2C transaction failed\nE (10566) i2c.master: i2c_master_transmit_receive(1220): I2C transaction failed\nESP_ERROR_CHECK failed: esp_err_t 0x103 (ESP_ERR_INVALID_STATE) at 0x4200c2a0\n--- 0x4200c2a0: app_main at D:/Projects/ESP/projects/ESP32-C6/I2C-tests/main/main.c:110 (discriminator 1)\n\nfile: \"./main/main.c\" line 110\nfunc: app_main\nexpression: i2c_master_transmit_receive(scd41_handle, buff_wr, sizeof(buff_wr), buff_r, sizeof(buff_r), sleep_ms)\n\nabort() was called at PC 0x40805835 on core 0\n```\n\nAdding while loop and retry counter:\n\n```log\nE (90767) i2c_master: Cannot get serial number of SO2 sensor! Retry: 2\nE (95777) i2c.master: I2C transaction unexpected nack detected\nE (95777) i2c.master: s_i2c_synchronous_transaction(924): I2C transaction failed\nE (95777) i2c.master: i2c_master_transmit_receive(1220): I2C transaction failed\nE (95777) i2c_master: Cannot get serial number of SO2 sensor! Retry: 1\nI (100787) i2c_master: Sensor serial number is: 0xe0e0 0xe0 0x1bfc\nE (100787) i2c.master: I2C transaction unexpected nack detected\nE (100787) i2c.master: s_i2c_synchronous_transaction(924): I2C transaction failed\nE (100787) i2c.master: i2c_master_multi_buffer_transmit(1186): I2C transaction failed\nE (100797) i2c_master: Cannot start CO2 sensor measurements! Retry: 10\n```\n\nWill now change sensors, check wires and try while loop 100\n\nAs soon as sensor was plugged out and plugged in again:\n\n```log\nI (35656) i2c_master: CMD Wake Up sent!\nI (35656) i2c_master: CMD Serial sent!\nI (35656) i2c_master: Sensor serial number is: 0x4944 0x3e 0x1bfc\nI (35656) i2c_master: CMD Start measurements sent! Get measumenets in 5 sec intervals\n```\n\nAnother approach - trying to stop sensor at the startup:\n\n```log\nI (556) i2c_master: Master bus added!\nI (556) i2c_master: CO2 sensor device added!\nI (556) i2c_master: Temperature sensor device added!\nI (566) i2c_master: All devices added! Start communication\nI (566) i2c_master: CMD Stop Measurements sent at start! Wait 5 sec!\nI (5576) i2c_master: CMD Wake Up sent!\nI (5576) i2c_master: CMD Serial sent!\nI (5576) i2c_master: Sensor serial number is: 0x4944 0x403e 0x0\nI (5576) i2c_master: CMD Start measurements sent! Get measumenets in 5 sec intervals\nI (5586) i2c_master: Data ready 58552 status: 1\nI (5586) main_task: Returned from app_main()\n```\n\nAnd it works! Moving on...\n\n### Start measurements\n\n\n- [scd4x_start_periodic_measurement](https://github.com/Sensirion/embedded-i2c-scd4x/blob/455a41c6b7a7a86a55d6647f5fc22d8574572b7b/sample-implementations/RaspberryPi_Pico/main.c#L50)\n\n```cpp\n    // Start measurement\n    sleep_ms = 1 * 5000; // Wait 5 seconds before trying to get measurements\n    local_offset = 0; // Reset offset\n    local_offset = sensirion_i2c_add_command16_to_buffer(buff_wr, local_offset, 0x21b1);\n    ESP_ERROR_CHECK(i2c_master_transmit(scd41_handle, buff_wr, local_offset, sleep_ms));\n    ESP_LOGI(TAG, \"CMD Start measurements sent! Get measumenets in 5 sec intervals\");\n```\n\n\n### Get Data Ready status\n\nMoving forward and now we should get sensor readiness.\n\nWith all examples we have from above, we can repeat most of the code just to clarify the process.\n\nThe process is the same, use modern i2c driver call to obtain sensor readiness during CMD call.\n\n```cpp\n    // Consume measurements with 5 sec interval!\n    TriesCount = 10;\n    local_offset = 0; // Reset offset\n    uint8_t buff_r[3] = {0};  // Output: serial number\n    sleep_ms = (1 * 1000);  // Send cmd and wait 30 ms\n    bool dataReady;\n    uint16_t data_ready_status = 0;\n    local_offset = sensirion_i2c_add_command16_to_buffer(buff_wr, local_offset, 0xe4b8);\n    ret = i2c_master_transmit_receive(scd41_handle, buff_wr, sizeof(buff_wr), buff_r, sizeof(buff_r), sleep_ms);\n    while (1) {\n        if (ret != ESP_OK) {\n            ESP_LOGE(TAG, \"Cannot get Data ready status! Retry: %d\", TriesCount);\n            vTaskDelay(pdMS_TO_TICKS(5000));\n            TriesCount--;\n            if (TriesCount == 0)\n                break;\n        } else {\n            data_ready_status = sensirion_common_bytes_to_uint16_t(\u0026buff_wr[0]);\n            dataReady = (data_ready_status \u0026 2047) != 0;\n            ESP_LOGI(TAG, \"Data ready %d status: %d\", data_ready_status, dataReady);\n            break;\n        }\n    }\n```\n\n\n### Get Measurements\n\nUse `i2c_master_transmit_receive`\n\n\n```text\nDescription: reads the sensor output. The measurement data can only be read out once per signal update interval as the buffer \nis emptied upon read-out. If no data is available in the buffer, the sensor returns a NACK. To avoid a NACK response, the \nget_data_ready_status can be issued to check data status (see Section 3.9.2 for further details). The I2C master can abort the \nread transfer with a NACK followed by a STOP condition after any data byte if the user is not interested in subsequent data. \n```\n\n| | | | |                                                                                                       |\n| :--- | :--- | :--- | :--- | :---                                                                              |\n| Write | 0xec05                                                                                                |\n| (hexadecimal) | Command                                                                                       |\n| Wait | 1 ms | command execution time                                                                          |\n| Response | 0x01f4 | 0x33 | 0x6667 | 0xa2 | 0x5eb9 | 0x3c                                                      |\n| (hexadecimal) | CO2 = 500 ppm | CRC of 0x01f4 |  Temp. = 25 °C | CRC of 0x6667 |  RH = 37% | CRC of 0x5eb9    |\n\n\nProbably works:\n\n```log\nI (557) i2c_master: Master bus added!\nI (557) i2c_master: CO2 sensor device added!\nI (557) i2c_master: Temperature sensor device added!\nI (567) i2c_master: All devices added! Start communication\nI (567) i2c_master: CMD Stop Measurements sent at start! Wait 5 sec!\nI (5577) i2c_master: CMD Wake Up sent!\nI (5577) i2c_master: CMD Serial sent!\nI (5577) i2c_master: Sensor serial number is: 0x4944 0x403e 0x0\nI (5577) i2c_master: CMD Start measurements sent! Get measumenets in 5 sec intervals\nI (10577) i2c_master: Data ready 58552 status: 1\nI (11577) i2c_master: RAW Measurements ready co2: 779, t: 18028 C Humidity: 0 (raw value)\nI (11577) main_task: Returned from app_main()\n```\n\nAdded a dumb loop just for test and it works:\n\n```log\nI (557) i2c_master: Master bus added!\nI (557) i2c_master: CO2 sensor device added!\nI (557) i2c_master: Temperature sensor device added!\nI (567) i2c_master: All devices added! Start communication\nI (567) i2c_master: CMD Stop Measurements sent at start! Wait 5 sec!\nI (5577) i2c_master: CMD Wake Up sent!\nI (5577) i2c_master: CMD Serial sent!\nI (5577) i2c_master: Sensor serial number is: 0x4944 0x3e 0x0\nI (5577) i2c_master: CMD Start measurements sent! Get measumenets in 5 sec intervals\nI (10577) i2c_master: Data ready 58552 status: 1\nI (16577) i2c_master: RAW Measurements ready co2: 735, t: 29292 C Humidity: 0 (raw value)\nI (21577) i2c_master: RAW Measurements ready co2: 726, t: 64107 C Humidity: 0 (raw value)\nI (26577) i2c_master: RAW Measurements ready co2: 733, t: 4203 C Humidity: 0 (raw value)\nI (31577) i2c_master: RAW Measurements ready co2: 806, t: 35947 C Humidity: 0 (raw value)\nI (36577) i2c_master: RAW Measurements ready co2: 1024, t: 618 C Humidity: 0 (raw value)\nI (41577) i2c_master: RAW Measurements ready co2: 1223, t: 53866 C Humidity: 0 (raw value)\nI (46577) i2c_master: RAW Measurements ready co2: 1358, t: 54378 C Humidity: 0 (raw value)\nI (51577) i2c_master: RAW Measurements ready co2: 1442, t: 26729 C Humidity: 0 (raw value)\nI (56577) i2c_master: RAW Measurements ready co2: 1461, t: 48233 C Humidity: 0 (raw value)\nI (56577) i2c_master: Stop measurements.\nI (56577) main_task: Returned from app_main()\n```\n\n\n# For bme680 aka temp, humidity, pressure, AIQ sensor\n\nUsign the same logic to add sensor to master bus:\n\n\n```cpp\n    // Configure BMD680\n    i2c_device_config_t bme680_cfg = {\n        .dev_addr_length = I2C_ADDR_BIT_LEN_7,\n        .device_address = BME680_I2C_ADDR_1,\n        .scl_speed_hz = I2C_FREQ_HZ,\n    };\n```\n\nNow start digging the controls:\n\n## Init and reset\n\nThere are two parts for sensor to init with: `register` and `command`:\n\n```cpp\n    uint8_t BME680_REG_RESET = 0xe0;\n    uint8_t BME680_RESET_CMD = 0xb6;    // BME680_REG_RESET\u003c7:0\u003e\n```\n\nIt seems pretty similar to what we can test with `i2c_tools`, I'll probe the registers to see how it works.\n\n- `i2cget -c 0x77`\n- `i2cset -c 0x77`\n- `i2cdump -c 0x77`\n\n```shell\ni2c-tools\u003e i2cconfig  --port=0 --freq=100000 --sda=22 --scl=23\ni2c-tools\u003e i2cdetect\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00: 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n60: -- -- 62 -- -- -- -- -- -- -- -- -- -- -- -- --\n70: -- -- -- -- -- -- -- 77 -- -- -- -- -- -- -- --\ni2c-tools\u003e i2cget -c 0x77\n0x80\ni2c-tools\u003e i2cset -c 0x77\nI (169704) cmd_i2ctools: Write OK\ni2c-tools\u003e i2cdump -c 0x77\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef\n00: 29 aa 16 4b e3 00 32 10 00 00 01 00 0e 00 02 04    )??K?.2?..?.?.??\n10: 10 00 40 00 80 00 1e 00 1f 7f 1f 10 00 00 00 80    ?.@.?.?.????...?\n20: 00 00 80 00 00 80 00 80 00 00 00 04 00 04 00 00    ..?..?.?...?.?..\n30: 80 00 00 80 00 00 80 00 80 00 00 00 04 00 04 00    ?..?..?.?...?.?.\n40: 00 80 00 00 80 00 00 80 00 80 00 00 00 04 00 04    .?..?..?.?...?.?\n50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................\n60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................\n70: 00 00 00 00 00 00 00 00 0f 04 fe 16 9b 08 00 ff    ........??????..\n```\n\n### Manually pull\\push registers\n\nNow test registers as per datasheet.\nAs I understand, I can `set` to register ADDR some cmd. Will see if I can set it manually.\nUsing `i2cset` must be pretty similar to `i2c_master_transmit` I just need to understand how should I pass `REG` address and `CMD_DATA` in this call.\n\n\n#### Get | read\n\nGet: `i2cget --chip=0x77 --register=REG_ADDR --length=1`\n\nChip ID: `BME680_REG_ID 0xd0` must be `0x61` = OK\n\n```shell\ni2cget --chip=0x77 --register=0xd0 --length=1\ni2cget --chip=0x77 --register=0xe0 --length=1\n```\n\nAnd results:\n\n```log\ni2c-tools\u003e i2cget --chip=0x77 --register=0xd0 --length=1\n0x61\ni2c-tools\u003e i2cget --chip=0x77 --register=0xe0 --length=1\n0x00\n```\n\n#### Set | write\n\nSet: `i2cset --chip=0x77 --register=REG_ADDR DATA_CMD`\n\n```shell\ni2cset --chip=0x77 --register=0xe0 0xb6\n```\n\nAnd results:\n\n```log\ni2c-tools\u003e i2cset --chip=0x77 --register=0xe0 0xb6\nI (575724) cmd_i2ctools: Write OK\n```\n\nAccording to example to a new I2C driver reg address and CMD data comes to one buffer:\n\n```cpp\n// Buffer allocation. Len of data args + 1 for reg addres at the start\nuint8_t *data = malloc(len + 1);\n// Adding REG address to the start\ndata[0] = data_addr;\n// Add each element of the DATA_CMD into a buffer\nfor (int i = 0; i \u003c len; i++) {\n    data[i + 1] = i2cset_args.data-\u003eival[i];\n}\n// When all data added - just send it\nesp_err_t ret = i2c_master_transmit(dev_handle, data, len + 1, I2C_TOOL_TIMEOUT_VALUE_MS);\n\n```\n\n#### In code\n\nTrying to read serial first: it works.\n- Similar to: `i2cget --chip=0x77 --register=0xd0 --length=1`\n- But still it shows `unexpected nack detected`\n\nTrying to send to REG `BME680_REG_RESET` and CMD `BME680_RESET_CMD`: \n- `E (596) i2c.master: I2C transaction unexpected nack detected`\n\nProblems:\n\nI see unexpected `nack` for a valid register read, such as getting chip id:\n\n- Seems like this \n  - https://esp32.com/viewtopic.php?t=45303\n  - https://github.com/espressif/esp-idf/issues/14715\n\nSolution:\n- Use custom: `i2c_master_execute_defined_operations`\n  - https://github.com/espressif/esp-idf/issues/14715#issuecomment-2586353494\n  - [doc](https://docs.espressif.com/projects/esp-idf/en/v5.4.1/esp32c6/api-reference/peripherals/i2c.html#_CPPv437i2c_master_execute_defined_operations23i2c_master_dev_handle_tP19i2c_operation_job_t6size_ti)\n\n### HOW IS THIS EVEN possible???\n\nI2C Test\n\n```log\nI (1235) main_task: Returned from app_main()\ni2c-tools\u003e i2cdetect\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00: 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n60: -- -- 62 -- -- -- -- -- -- -- -- -- -- -- -- -- \n70: -- -- -- -- -- -- -- 77 -- -- -- -- -- -- -- --\n```\n\nCurrent project:\n\n```log\nI (466) main_task: Started on CPU0\nI (466) main_task: Calling app_main()\nD (466) i2c.common: new bus(0) at 0x40811950\nD (476) i2c.common: bus clock source frequency: 40000000hz\nI (476) i2c-test-device: I2C Bus is ready - now add devices!\nI (986) i2c-test-device: CO2 sensor device added!\nE (986) i2c-test-device: ESP_ERR_NOT_FOUND: I2C probe failed, doesn't find the device with specific address you gave.\nI (986) i2c-test-device: Adding BME680...\nI (986) i2c-test-device: Added BME680 sensor! Now wait!\nE (1496) i2c-test-device: ESP_ERR_NOT_FOUND: I2C probe failed, doesn't find the device with specific address you gave.\nI (1496) main_task: Returned from app_main()\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrianglesis%2Fi2c-tests","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrianglesis%2Fi2c-tests","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrianglesis%2Fi2c-tests/lists"}