From 83d62c0ef7177c88d51859cb5300069ee2439c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 25 Dec 2021 22:34:59 +0100 Subject: [PATCH] wip modbus --- main/Kconfig.projbuild | 12 +++ main/co2_sensor.c | 181 +++++++++++------------------------------ main/co2_sensor_i2c.c | 164 +++++++++++++++++++++++++++++++++++++ main/periph_init.c | 57 +++++++++++++ sdkconfig | 11 +++ 5 files changed, 290 insertions(+), 135 deletions(-) create mode 100644 main/co2_sensor_i2c.c diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 5c7779d..a961d52 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -16,6 +16,18 @@ menu "App Configuration" config PIN_I2C_SCL1 int "I2C0 SCL" default 18 + + config PIN_CO2_NRDY + int "CO2 NRDY" + default 23 + + config PIN_CO2_COMSEL + int "CO2 COMSEL" + default 13 + + config PIN_CO2_EN + int "CO2 EN" + default 15 endmenu menu "Console" diff --git a/main/co2_sensor.c b/main/co2_sensor.c index 3165cde..99a9d08 100644 --- a/main/co2_sensor.c +++ b/main/co2_sensor.c @@ -13,152 +13,63 @@ #include "i2c_utils.h" #include "periph_init.h" #include "data_report.h" +#include static const char *TAG = "co2"; #define CO2_ADDR 104 -#define CO2_I2C_NUM I2C_NUM_1 +#define CO2_UART_NUM 1 #define TIMEOUT_MS 500 -// this works, but the bus is fucked up -bool wake_up() { - esp_err_t suc; -#define TRY(x) suc=x; if(suc!=ESP_OK) return suc; - for (int i = 0; i < 5; i++) { - ESP_LOGD(TAG, "Wake up try %d", i); - uint8_t dummy; - - i2c_cmd_handle_t chain; - - chain = i2c_cmd_link_create(); - TRY(i2c_master_start(chain)); - TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_WRITE, false)); - TRY(i2c_master_write_byte(chain, 0x30, false)); - TRY(i2c_master_start(chain)); - TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_READ, false)); // TODO expect ack? - TRY(i2c_master_read(chain, &dummy, 1, I2C_MASTER_LAST_NACK)); - TRY(i2c_master_stop(chain)); - i2c_master_cmd_begin(CO2_I2C_NUM, chain, pdMS_TO_TICKS(70)); - i2c_cmd_link_delete(chain); - - chain = i2c_cmd_link_create(); - TRY(i2c_master_start(chain)); - TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_WRITE, false)); - TRY(i2c_master_write_byte(chain, 0x30, false)); - TRY(i2c_master_start(chain)); - TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_READ, true)); // TODO expect ack? - TRY(i2c_master_read(chain, &dummy, 1, I2C_MASTER_LAST_NACK)); - TRY(i2c_master_stop(chain)); - suc = i2c_master_cmd_begin(CO2_I2C_NUM, chain, pdMS_TO_TICKS(80)); - i2c_cmd_link_delete(chain); - - if (suc == ESP_OK) { - ESP_LOGD(TAG, "Woken up at try %d", i); - return true; - } - } - ESP_LOGE(TAG, "Fail to wake up"); - return false; -#undef TRY -} - - -static esp_err_t do_reg_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_reg_read(cmd, CO2_ADDR, reg_addr, reg_data, length); - esp_err_t ret = i2c_master_cmd_begin(CO2_I2C_NUM, cmd, pdMS_TO_TICKS(TIMEOUT_MS)); - i2c_cmd_link_delete(cmd); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "I2C read error: %s, devaddr %x, reg %d, len %d", esp_err_to_name(ret), CO2_ADDR, reg_addr, length); - } - ESP_LOG_BUFFER_HEXDUMP(TAG, reg_data, length, ESP_LOG_DEBUG); - return ret; -} - -static esp_err_t reg_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { -// BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(SEMA_TIMEOUT_MS)); -// if (suc != pdPASS) { -// ESP_LOGE(TAG, "Sema fail"); -// return ESP_ERR_TIMEOUT; -// } - if (!wake_up()) { -// xSemaphoreGive(g_mux_i2c); - return ESP_ERR_TIMEOUT; - } - esp_err_t rv = do_reg_read(reg_addr, reg_data, length, timeout_ms); -// xSemaphoreGive(g_mux_i2c); -// ets_delay_us(12000); - return rv; -} - -static esp_err_t do_reg_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_reg_write(cmd, CO2_ADDR, reg_addr, reg_data, length); - esp_err_t ret = i2c_master_cmd_begin(CO2_I2C_NUM, cmd, pdMS_TO_TICKS(timeout_ms)); - i2c_cmd_link_delete(cmd); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "I2C write error: %s, devaddr %x, reg %d, len %d", esp_err_to_name(ret), CO2_ADDR, reg_addr, length); - } - return ret; -} - -static esp_err_t reg_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { -// BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(SEMA_TIMEOUT_MS)); -// if (suc != pdPASS) { -// ESP_LOGE(TAG, "Sema fail"); -// return ESP_ERR_TIMEOUT; -// } - if (!wake_up()) { -// xSemaphoreGive(g_mux_i2c); - return ESP_ERR_TIMEOUT; - } - esp_err_t rv = do_reg_write(reg_addr, reg_data, length, timeout_ms); -// xSemaphoreGive(g_mux_i2c); -// ets_delay_us(12000); - return rv; -} - void co2_read_task(void *param) { - // i2c is protected by a semaphore inside the driver, no need to worry about it here - - // continuous is the default - + esp_err_t rv; + vTaskDelay(pdMS_TO_TICKS(500)); - - uint8_t pld[] = {0x00, 0x05, 0x00, 0x05}; - if (ESP_OK == reg_write(0x96, pld, 4, TIMEOUT_MS)) { - ESP_LOGI(TAG, "CO2 init OK"); - } - - bool init_suc = false; - vTaskDelay(pdMS_TO_TICKS(250)); + + // TODO + + uint8_t buffer[128]; + while (1) { - + vTaskDelay(pdMS_TO_TICKS(2000)); - - uint8_t data[4] = {}; - - for (int retry = 0; retry < 3; retry++) { - if (ESP_OK == reg_read(0x06, data, 4, TIMEOUT_MS)) { - uint16_t filtered = (data[0] << 8) | data[1]; - uint16_t unfiltered = (data[2] << 8) | data[3]; - - ESP_LOGI(TAG, "CO2 ppm %d, raw %d", filtered, unfiltered); - - if (pdPASS == xSemaphoreTake(g_mux_data_report, pdMS_TO_TICKS(750))) { - if (filtered > 400 && filtered < 5000) { - g_data_report.co2_ppm = (float) filtered; - g_data_report.co2_ready = true; - g_data_report.co2_timestamp = xTaskGetTickCount(); - } else { - g_data_report.co2_ready = false; - } - } - xSemaphoreGive(g_mux_data_report); - break; + + + uint16_t ppm = 0; + + int i = 0; + buffer[i++] = 0x68; + buffer[i++] = 0x04; + buffer[i++] = 0x00; + buffer[i++] = 0x00; + buffer[i++] = 0x00; + buffer[i++] = 0x04; + buffer[i++] = 0xf8; + buffer[i++] = 0xf0; + + uart_write_bytes(CO2_UART_NUM, buffer, i); + i = uart_read_bytes(CO2_UART_NUM, buffer, 13, pdMS_TO_TICKS(1000)); + + if (i != 13) { + ESP_LOGE(TAG, "Rx failed"); + continue; + } + + ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, i, ESP_LOG_DEBUG); + continue; + + + ESP_LOGI(TAG, "CO2 ppm %d", ppm); + + if (pdPASS == xSemaphoreTake(g_mux_data_report, pdMS_TO_TICKS(750))) { + if (ppm > 400 && ppm < 5000) { + g_data_report.co2_ppm = (float) ppm; + g_data_report.co2_ready = true; + g_data_report.co2_timestamp = xTaskGetTickCount(); + } else { + g_data_report.co2_ready = false; } - - vTaskDelay(pdMS_TO_TICKS(50)); } + xSemaphoreGive(g_mux_data_report); } } diff --git a/main/co2_sensor_i2c.c b/main/co2_sensor_i2c.c new file mode 100644 index 0000000..3165cde --- /dev/null +++ b/main/co2_sensor_i2c.c @@ -0,0 +1,164 @@ +#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG + +#include "co2_sensor.h" + +#include +#include +#include +#include +#include +#include +#include +#include "voc_sensor.h" +#include "i2c_utils.h" +#include "periph_init.h" +#include "data_report.h" + +static const char *TAG = "co2"; + +#define CO2_ADDR 104 +#define CO2_I2C_NUM I2C_NUM_1 +#define TIMEOUT_MS 500 + +// this works, but the bus is fucked up +bool wake_up() { + esp_err_t suc; +#define TRY(x) suc=x; if(suc!=ESP_OK) return suc; + for (int i = 0; i < 5; i++) { + ESP_LOGD(TAG, "Wake up try %d", i); + uint8_t dummy; + + i2c_cmd_handle_t chain; + + chain = i2c_cmd_link_create(); + TRY(i2c_master_start(chain)); + TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_WRITE, false)); + TRY(i2c_master_write_byte(chain, 0x30, false)); + TRY(i2c_master_start(chain)); + TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_READ, false)); // TODO expect ack? + TRY(i2c_master_read(chain, &dummy, 1, I2C_MASTER_LAST_NACK)); + TRY(i2c_master_stop(chain)); + i2c_master_cmd_begin(CO2_I2C_NUM, chain, pdMS_TO_TICKS(70)); + i2c_cmd_link_delete(chain); + + chain = i2c_cmd_link_create(); + TRY(i2c_master_start(chain)); + TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_WRITE, false)); + TRY(i2c_master_write_byte(chain, 0x30, false)); + TRY(i2c_master_start(chain)); + TRY(i2c_master_write_byte(chain, (CO2_ADDR << 1) | I2C_MASTER_READ, true)); // TODO expect ack? + TRY(i2c_master_read(chain, &dummy, 1, I2C_MASTER_LAST_NACK)); + TRY(i2c_master_stop(chain)); + suc = i2c_master_cmd_begin(CO2_I2C_NUM, chain, pdMS_TO_TICKS(80)); + i2c_cmd_link_delete(chain); + + if (suc == ESP_OK) { + ESP_LOGD(TAG, "Woken up at try %d", i); + return true; + } + } + ESP_LOGE(TAG, "Fail to wake up"); + return false; +#undef TRY +} + + +static esp_err_t do_reg_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_reg_read(cmd, CO2_ADDR, reg_addr, reg_data, length); + esp_err_t ret = i2c_master_cmd_begin(CO2_I2C_NUM, cmd, pdMS_TO_TICKS(TIMEOUT_MS)); + i2c_cmd_link_delete(cmd); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "I2C read error: %s, devaddr %x, reg %d, len %d", esp_err_to_name(ret), CO2_ADDR, reg_addr, length); + } + ESP_LOG_BUFFER_HEXDUMP(TAG, reg_data, length, ESP_LOG_DEBUG); + return ret; +} + +static esp_err_t reg_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { +// BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(SEMA_TIMEOUT_MS)); +// if (suc != pdPASS) { +// ESP_LOGE(TAG, "Sema fail"); +// return ESP_ERR_TIMEOUT; +// } + if (!wake_up()) { +// xSemaphoreGive(g_mux_i2c); + return ESP_ERR_TIMEOUT; + } + esp_err_t rv = do_reg_read(reg_addr, reg_data, length, timeout_ms); +// xSemaphoreGive(g_mux_i2c); +// ets_delay_us(12000); + return rv; +} + +static esp_err_t do_reg_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_reg_write(cmd, CO2_ADDR, reg_addr, reg_data, length); + esp_err_t ret = i2c_master_cmd_begin(CO2_I2C_NUM, cmd, pdMS_TO_TICKS(timeout_ms)); + i2c_cmd_link_delete(cmd); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "I2C write error: %s, devaddr %x, reg %d, len %d", esp_err_to_name(ret), CO2_ADDR, reg_addr, length); + } + return ret; +} + +static esp_err_t reg_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t length, uint32_t timeout_ms) { +// BaseType_t suc = xSemaphoreTake(g_mux_i2c, pdMS_TO_TICKS(SEMA_TIMEOUT_MS)); +// if (suc != pdPASS) { +// ESP_LOGE(TAG, "Sema fail"); +// return ESP_ERR_TIMEOUT; +// } + if (!wake_up()) { +// xSemaphoreGive(g_mux_i2c); + return ESP_ERR_TIMEOUT; + } + esp_err_t rv = do_reg_write(reg_addr, reg_data, length, timeout_ms); +// xSemaphoreGive(g_mux_i2c); +// ets_delay_us(12000); + return rv; +} + +void co2_read_task(void *param) { + // i2c is protected by a semaphore inside the driver, no need to worry about it here + + // continuous is the default + + vTaskDelay(pdMS_TO_TICKS(500)); + + uint8_t pld[] = {0x00, 0x05, 0x00, 0x05}; + if (ESP_OK == reg_write(0x96, pld, 4, TIMEOUT_MS)) { + ESP_LOGI(TAG, "CO2 init OK"); + } + + bool init_suc = false; + vTaskDelay(pdMS_TO_TICKS(250)); + while (1) { + + vTaskDelay(pdMS_TO_TICKS(2000)); + + uint8_t data[4] = {}; + + for (int retry = 0; retry < 3; retry++) { + if (ESP_OK == reg_read(0x06, data, 4, TIMEOUT_MS)) { + uint16_t filtered = (data[0] << 8) | data[1]; + uint16_t unfiltered = (data[2] << 8) | data[3]; + + ESP_LOGI(TAG, "CO2 ppm %d, raw %d", filtered, unfiltered); + + if (pdPASS == xSemaphoreTake(g_mux_data_report, pdMS_TO_TICKS(750))) { + if (filtered > 400 && filtered < 5000) { + g_data_report.co2_ppm = (float) filtered; + g_data_report.co2_ready = true; + g_data_report.co2_timestamp = xTaskGetTickCount(); + } else { + g_data_report.co2_ready = false; + } + } + xSemaphoreGive(g_mux_data_report); + break; + } + + vTaskDelay(pdMS_TO_TICKS(50)); + } + } +} diff --git a/main/periph_init.c b/main/periph_init.c index 5443065..809d473 100644 --- a/main/periph_init.c +++ b/main/periph_init.c @@ -3,6 +3,8 @@ #include "driver/i2c.h" #include "data_report.h" +#include + static const char *TAG = "periph_init"; esp_err_t periph_init() { @@ -38,6 +40,7 @@ esp_err_t periph_init() { // senseair i2c { +#if 0 int i2c_master_port = I2C_NUM_1; i2c_config_t conf2 = { .mode = I2C_MODE_MASTER, @@ -57,6 +60,60 @@ esp_err_t periph_init() { ESP_LOGE(TAG, "Err in i2c_driver_install"); return rv; } +#else + const uart_config_t uart_config = { + .baud_rate = 9600, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .use_ref_tick = true + }; + ESP_ERROR_CHECK( uart_param_config(UART_NUM_1, &uart_config) ); + + // Set UART pins(TX: IO17 (UART2 default), RX: IO16 (UART2 default), RTS: IO18, CTS: IO19) + ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, + CONFIG_PIN_I2C_SCL1, + CONFIG_PIN_I2C_SDA1, + UART_PIN_NO_CHANGE, + UART_PIN_NO_CHANGE)); + + ESP_ERROR_CHECK(uart_driver_install(UART_NUM_1, + /* rxbuf */ 256, /* txbuf */ 0, /* que */ 0, /* uart que */ NULL, /* alloc flags */ 0)); +#endif + } + + // outputs + { + gpio_config_t gpioconf = { + .pin_bit_mask = (1 << CONFIG_PIN_CO2_COMSEL) | (1 << CONFIG_PIN_CO2_EN), + .mode = GPIO_MODE_OUTPUT, + }; + + rv = gpio_config(&gpioconf); + if (rv != ESP_OK) { + ESP_LOGE(TAG, "Err in gpio_config"); + return rv; + } + + gpio_set_level(CONFIG_PIN_CO2_COMSEL, 0); // low=I2C + gpio_set_level(CONFIG_PIN_CO2_EN, 1); // active high + } + + // input + { + gpio_config_t gpioconf = { + .pin_bit_mask = (1 << CONFIG_PIN_CO2_NRDY), + .mode = GPIO_MODE_INPUT, + .pull_up_en = 1, + .pull_down_en = 0, + .intr_type = GPIO_INTR_DISABLE, + }; + + rv = gpio_config(&gpioconf); + if (rv != ESP_OK) { + ESP_LOGE(TAG, "Err in gpio_config"); + return rv; + } } return ESP_OK; diff --git a/sdkconfig b/sdkconfig index 693e8b1..c1e5bdc 100644 --- a/sdkconfig +++ b/sdkconfig @@ -63,6 +63,7 @@ CONFIG_BOOTLOADER_WDT_TIME_MS=9000 # CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0 # CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set +CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT=y # end of Bootloader config # @@ -136,6 +137,9 @@ CONFIG_PIN_I2C_SDA0=16 CONFIG_PIN_I2C_SCL0=17 CONFIG_PIN_I2C_SDA1=5 CONFIG_PIN_I2C_SCL1=18 +CONFIG_PIN_CO2_NRDY=23 +CONFIG_PIN_CO2_COMSEL=13 +CONFIG_PIN_CO2_EN=15 # end of Pin mapping # @@ -480,6 +484,7 @@ CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y # CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set # CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set CONFIG_ESP_SYSTEM_PD_FLASH=y +# CONFIG_ESP_SYSTEM_FLASH_LEAKAGE_WORKAROUND is not set # # Memory protection @@ -599,6 +604,10 @@ CONFIG_FMB_SERIAL_BUF_SIZE=256 CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8 CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000 CONFIG_FMB_PORT_TASK_PRIO=10 +# CONFIG_FMB_PORT_TASK_AFFINITY_NO_AFFINITY is not set +CONFIG_FMB_PORT_TASK_AFFINITY_CPU0=y +# CONFIG_FMB_PORT_TASK_AFFINITY_CPU1 is not set +CONFIG_FMB_PORT_TASK_AFFINITY=0x0 CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233 CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20 @@ -608,6 +617,8 @@ CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 CONFIG_FMB_TIMER_PORT_ENABLED=y CONFIG_FMB_TIMER_GROUP=0 CONFIG_FMB_TIMER_INDEX=0 +CONFIG_FMB_MASTER_TIMER_GROUP=0 +CONFIG_FMB_MASTER_TIMER_INDEX=0 # CONFIG_FMB_TIMER_ISR_IN_IRAM is not set # end of Modbus configuration