diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 30cf37b..4544650 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -2,6 +2,7 @@ idf_component_register(SRCS "main.c" "app_task_led.c" "app_task_epd.c" + "app_task_battery.c" "app_lib_i2c_system.c" "app_lib_bat_impl.c" "app_lib_epd_impl.c" diff --git a/main/app_lib_bat_impl.c b/main/app_lib_bat_impl.c index ac6b40f..b9bdbe1 100644 --- a/main/app_lib_bat_impl.c +++ b/main/app_lib_bat_impl.c @@ -1,15 +1,52 @@ #include "esp_log.h" -#include "driver/i2c.h" + +#include "user_board.h" #include "app_lib_bat_impl.h" #define LTC2941_ADDR 0x64 // Unshifted -static const char *TAG = "BAT_IMPL" +static const char *TAG = "BAT_IMPL"; ltc2941_ret_t app_lib_bat_read_register(app_lib_bat_impl_t *impl, uint8_t reg, uint8_t *value) { + ESP_LOGD(TAG, "Read register: %d", reg); + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, LTC2941_ADDR << 1 | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, reg, true); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, LTC2941_ADDR << 1 | I2C_MASTER_READ, true); + i2c_master_read_byte(cmd, value, I2C_MASTER_LAST_NACK); + i2c_master_stop(cmd); + + esp_err_t err = i2c_master_cmd_begin(impl->i2c_num, cmd, pdMS_TO_TICKS(1000)); + i2c_cmd_link_delete(cmd); + + if(err != ESP_OK) { + ESP_LOGE(TAG, "Read register reported error, %s", esp_err_to_name(err)); + return LTC2941_ERROR; + } + + return LTC2941_OK; } ltc2941_ret_t app_lib_bat_write_register(app_lib_bat_impl_t *impl, uint8_t reg, uint8_t value) { + ESP_LOGD(TAG, "Write register: %d", reg); + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, LTC2941_ADDR << 1 | I2C_MASTER_WRITE, true); + i2c_master_write_byte(cmd, reg, true); + i2c_master_write_byte(cmd, value, true); + i2c_master_stop(cmd); + + esp_err_t err = i2c_master_cmd_begin(impl->i2c_num, cmd, pdMS_TO_TICKS(1000)); + i2c_cmd_link_delete(cmd); + + if(err != ESP_OK) { + ESP_LOGE(TAG, "Write register reported error, %s", esp_err_to_name(err)); + return LTC2941_ERROR; + } + + return LTC2941_OK; } \ No newline at end of file diff --git a/main/app_lib_bat_impl.h b/main/app_lib_bat_impl.h index 56969ac..81bd510 100644 --- a/main/app_lib_bat_impl.h +++ b/main/app_lib_bat_impl.h @@ -1,10 +1,12 @@ #ifndef __APP_LIB_BAT_IMPL_H #define __APP_LIB_BAT_IMPL_H +#include "driver/i2c.h" + #include "ltc2941_battery.h" typedef struct { - + int i2c_num; } app_lib_bat_impl_t; ltc2941_ret_t app_lib_bat_read_register(app_lib_bat_impl_t *impl, uint8_t reg, uint8_t *value); diff --git a/main/app_lib_epd_impl.c b/main/app_lib_epd_impl.c index e69de29..e902a6f 100644 --- a/main/app_lib_epd_impl.c +++ b/main/app_lib_epd_impl.c @@ -0,0 +1,114 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "user_board.h" + +#include "app_lib_epd_impl.h" + +#define MAXIMUM_XFER_SIZE 400 * 300 / 8 // FULL fb. +#define MAX_BUSY_POLL_COUNT 10 + +static void _spi_pre_transfere_callback(spi_transaction_t *txn) { + gpio_set_level(BOARD_EPD_DC_PIN, (int)txn->user); +} + +void app_lib_epd_impl_init(app_lib_epd_impl_t *impl) { + gpio_config_t io_config = { + .intr_type = GPIO_INTR_DISABLE, + .mode = GPIO_MODE_OUTPUT_OD, + .pin_bit_mask = (1 << BOARD_EPD_RES_PIN), + .pull_up_en = GPIO_PULLUP_ENABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE + }; + gpio_config(&io_config); + + io_config.pin_bit_mask = (1 << BOARD_EPD_DC_PIN); + io_config.pull_up_en = GPIO_PULLUP_DISABLE; + io_config.mode = GPIO_MODE_OUTPUT; + gpio_config(&io_config); + + io_config.pin_bit_mask = (1 << BOARD_EPD_BUSY_PIN); + io_config.mode = GPIO_MODE_INPUT; + gpio_config(&io_config); + + spi_bus_config_t bus_cfg = { + .mosi_io_num = BOARD_EPD_SPI_MOSI_PIN, + .sclk_io_num = BOARD_EPD_SPI_SCK_PIN, + .miso_io_num = -1, + .quadhd_io_num = -1, + .quadwp_io_num = -1, + .max_transfer_sz = MAXIMUM_XFER_SIZE + }; + + spi_device_interface_config_t interface_config = { + .clock_speed_hz = 8 * 1000 * 1000, + .mode = 0, + .spics_io_num = BOARD_EPD_SPI_CS_PIN, + .queue_size = 7, + .pre_cb = _spi_pre_transfere_callback, + }; + + ESP_ERROR_CHECK(spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO)); + ESP_ERROR_CHECK(spi_bus_add_device(SPI2_HOST, &interface_config, &impl->spi_handle)); +} + +gd_epd_042_ret_t app_lib_epd_impl_reset(app_lib_epd_impl_t *impl) { + gpio_set_level(BOARD_EPD_RES_PIN, 1); + vTaskDelay(10); + gpio_set_level(BOARD_EPD_RES_PIN, 0); + vTaskDelay(10); + gpio_set_level(BOARD_EPD_RES_PIN, 1); + vTaskDelay(10); + + return EPD_OK; +} + +gd_epd_042_ret_t app_lib_epd_impl_write_cmd(app_lib_epd_impl_t *impl, uint8_t *cmd, uint8_t len) { + esp_err_t ret; + spi_transaction_t txn = { + .length = 8, + .tx_buffer = cmd, + .user = (void *)0 + }; + + ret = spi_device_polling_transmit(impl->spi_handle, &txn); + if(ret != ESP_OK) return EPD_ERR; + + if(len > 1) { + txn.length = 8 * len - 1; + txn.tx_buffer = &cmd[1]; + + ret = spi_device_polling_transmit(impl->spi_handle, &txn); + if(ret != ESP_OK) return EPD_ERR; + } + + return EPD_OK; +} + +gd_epd_042_ret_t app_lib_epd_impl_write_data(app_lib_epd_impl_t *impl, uint8_t *data, uint32_t len) { + esp_err_t ret; + spi_transaction_t txn = { + .length = 8 * len, + .tx_buffer = data, + .user = (void *)1 + }; + + ret = spi_device_polling_transmit(impl->spi_handle, &txn); + + if(ret != ESP_OK) return EPD_ERR; + return EPD_OK; +} + +gd_epd_042_ret_t app_lib_epd_impl_poll_busy(app_lib_epd_impl_t *impl) { + uint8_t count = MAX_BUSY_POLL_COUNT; + while(gpio_get_level(BOARD_EPD_BUSY_PIN) == 0) { + vTaskDelay(10); + if(count == 0) { + return EPD_ERR; + } + count--; + } + + return EPD_OK; + +} \ No newline at end of file diff --git a/main/app_lib_epd_impl.h b/main/app_lib_epd_impl.h index f7e4076..03fce9c 100644 --- a/main/app_lib_epd_impl.h +++ b/main/app_lib_epd_impl.h @@ -1,6 +1,19 @@ #ifndef __APP_LIB_EPD_IMPL_H #define __APP_LIB_EPD_IMPL_H +#include "driver/spi_master.h" +#include "driver/gpio.h" +#include "gdew042t2_epd.h" + +typedef struct { + spi_device_handle_t spi_handle; +} app_lib_epd_impl_t; + +void app_lib_epd_impl_init(app_lib_epd_impl_t *impl); +gd_epd_042_ret_t app_lib_epd_impl_reset(app_lib_epd_impl_t *impl); +gd_epd_042_ret_t app_lib_epd_impl_write_cmd(app_lib_epd_impl_t *impl, uint8_t *cmd, uint8_t len); +gd_epd_042_ret_t app_lib_epd_impl_write_data(app_lib_epd_impl_t *impl, uint8_t *data, uint32_t len); +gd_epd_042_ret_t app_lib_epd_impl_poll_busy(app_lib_epd_impl_t *impl); #endif \ No newline at end of file diff --git a/main/app_lib_i2c_system.c b/main/app_lib_i2c_system.c index 8ad08ee..a377e4a 100644 --- a/main/app_lib_i2c_system.c +++ b/main/app_lib_i2c_system.c @@ -8,9 +8,9 @@ void app_lib_i2c_system_init(void) { .mode = I2C_MODE_MASTER, .sda_io_num = BOARD_SYSTEM_I2C_SDA_PIN, .scl_io_num = BOARD_SYSTEM_I2C_SCL_PIN, - .sda_pullup_en = GPIO_PULLUP_DISABLE, - .scl_pullup_en = GPIO_PULLUP_DISABLE, - .master.clk_speed = 400000 + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = 100000 }; esp_err_t err = i2c_param_config(BOARD_SYSTEM_I2C_NUM, &conf); diff --git a/main/app_task_battery.c b/main/app_task_battery.c new file mode 100644 index 0000000..96317b6 --- /dev/null +++ b/main/app_task_battery.c @@ -0,0 +1,48 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" + +#include "esp_log.h" + +#include "user_board.h" + +#include "app_lib_bat_impl.h" + +#define BATTERY_CAP 3000.0 +#define MAH_LSB 0.053125 // Shunt 20mR +#define PRESCALER_M LTC2941_PRE_32 + +const static char *TAG = "TASK_BAT"; + +TaskHandle_t xTaskBatteryExampleHandle = NULL; +void vTasBatteryExample(void *pvParameters) { + app_lib_bat_impl_t impl = { + .i2c_num = BOARD_SYSTEM_I2C_NUM + }; + + ltc2941_t battery_fg = { + .user_data = &impl, + .cb = { + .read_register_cb = (ltc2941_ret_t (*)(void *, uint8_t, uint8_t *))app_lib_bat_read_register, + .write_register_cb = (ltc2941_ret_t (*)(void *, uint8_t, uint8_t))app_lib_bat_write_register + }, + .config = { + .alert_level = LTC2941_ALERT_3_0V, + .alert_mode = LTC2941_ALERT_DISABLED, + .prescaler = PRESCALER_M + } + }; + + ltc2941_init(&battery_fg); + + for(;;) { + uint16_t fg_data = 0x00; + ltc2941_read_charge(&battery_fg, &fg_data); + + float percentage = fg_data * MAH_LSB * 100.0 / BATTERY_CAP; + + ESP_LOGI(TAG, "Charge: %.2f", percentage); + + vTaskDelay(pdMS_TO_TICKS(30000)); + } +} \ No newline at end of file diff --git a/main/app_task_epd.c b/main/app_task_epd.c index 8e56ea0..0b39a22 100644 --- a/main/app_task_epd.c +++ b/main/app_task_epd.c @@ -1,11 +1,39 @@ +#include + #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" -#include "gdew042t2_epd.h" +#include "app_lib_epd_impl.h" +static uint8_t frame_data[15000][2]; +static uint8_t current_frame = 0; + +TaskHandle_t xTaskEPDExampleHandle = NULL; void vTaskEPDExample(void *pvParameters) { - for(;;) { + app_lib_epd_impl_t epd_impl = {0}; + gd_epd_042_t epd = { + .cb = { + .write_data_cb = (gd_epd_042_ret_t (*)(void *, uint8_t *, uint32_t))app_lib_epd_impl_write_data, + .write_cmd_cb = (gd_epd_042_ret_t (*)(void *, uint8_t *, uint8_t))app_lib_epd_impl_write_cmd, + .poll_busy_cb = (gd_epd_042_ret_t (*)(void *))app_lib_epd_impl_poll_busy, + .reset_cb = (gd_epd_042_ret_t (*)(void *))app_lib_epd_impl_reset + }, + .user_data = &epd_impl + }; + + app_lib_epd_impl_init(&epd_impl); + gd_epd_042_init(&epd); + + memset(frame_data[current_frame], 0xFF, 15000); + memset(frame_data[(~current_frame) & 0x01], 0xFF, 15000); + + gd_epd_042_load(&epd, frame_data[current_frame], frame_data[(~current_frame) & 0x01]); + gd_epd_042_update(&epd); + gd_epd_042_deepsleep(&epd); + + for(;;) { + vTaskDelay(10000); } } \ No newline at end of file diff --git a/main/app_task_led.c b/main/app_task_led.c index 3bd7539..7371364 100644 --- a/main/app_task_led.c +++ b/main/app_task_led.c @@ -8,6 +8,8 @@ #include "user_board.h" #define BREATHE_LED_NUM 3 +#define BREATHE_LED_MAXIMUM_BRIGHTNESS 512 +#define BREATHE_LED_CYCLE 2500 TaskHandle_t xTaskLEDsHandle = NULL; void vTaskLEDs(void *pvParameters) { @@ -85,16 +87,17 @@ void vTaskLEDs(void *pvParameters) { ledc_fade_func_install(0); for(;;) { + vTaskDelay(pdMS_TO_TICKS(BREATHE_LED_CYCLE)); ledc_set_fade_with_time(ledc_channels[BREATHE_LED_NUM].speed_mode, - ledc_channels[BREATHE_LED_NUM].channel, 1023, 2500); + ledc_channels[BREATHE_LED_NUM].channel, BREATHE_LED_MAXIMUM_BRIGHTNESS, BREATHE_LED_CYCLE); ledc_fade_start(ledc_channels[BREATHE_LED_NUM].speed_mode, ledc_channels[BREATHE_LED_NUM].channel, LEDC_FADE_NO_WAIT); - vTaskDelay(pdMS_TO_TICKS(2500)); + vTaskDelay(pdMS_TO_TICKS(BREATHE_LED_CYCLE)); ledc_set_fade_with_time(ledc_channels[BREATHE_LED_NUM].speed_mode, - ledc_channels[BREATHE_LED_NUM].channel, 0, 2500); + ledc_channels[BREATHE_LED_NUM].channel, 0, BREATHE_LED_CYCLE); ledc_fade_start(ledc_channels[BREATHE_LED_NUM].speed_mode, ledc_channels[BREATHE_LED_NUM].channel, LEDC_FADE_NO_WAIT); - vTaskDelay(pdMS_TO_TICKS(2500)); + vTaskDelay(pdMS_TO_TICKS(BREATHE_LED_CYCLE)); } } \ No newline at end of file diff --git a/main/lib/gdew042t2_epd.c b/main/lib/gdew042t2_epd.c index 783762d..394cf0f 100644 --- a/main/lib/gdew042t2_epd.c +++ b/main/lib/gdew042t2_epd.c @@ -51,4 +51,4 @@ gd_epd_042_ret_t gd_epd_042_update(gd_epd_042_t *epd) { epd->cb.poll_busy_cb(epd->user_data); return EPD_OK; -} \ No newline at end of file +} diff --git a/main/lib/gdew042t2_epd.h b/main/lib/gdew042t2_epd.h index 5818def..064d749 100644 --- a/main/lib/gdew042t2_epd.h +++ b/main/lib/gdew042t2_epd.h @@ -21,5 +21,8 @@ typedef struct { } gd_epd_042_t; gd_epd_042_ret_t gd_epd_042_init(gd_epd_042_t *epd); +gd_epd_042_ret_t gd_epd_042_load(gd_epd_042_t *epd, uint8_t *old_data, uint8_t *new_data); +gd_epd_042_ret_t gd_epd_042_update(gd_epd_042_t *epd); +gd_epd_042_ret_t gd_epd_042_deepsleep(gd_epd_042_t *epd); #endif \ No newline at end of file diff --git a/main/lib/htu21d_dht.c b/main/lib/htu21d_dht.c new file mode 100644 index 0000000..f9ceb1c --- /dev/null +++ b/main/lib/htu21d_dht.c @@ -0,0 +1,6 @@ +#include "htu21d_dht.h" + +htu21d_ret_t htu21d_init(htu21d_t *htu) { + htu->cb.write_command_cb(htu->user_data, 0xFE, 0x00); + return HTU21D_OK; +} \ No newline at end of file diff --git a/main/lib/htu21d_dht.h b/main/lib/htu21d_dht.h new file mode 100644 index 0000000..246ff80 --- /dev/null +++ b/main/lib/htu21d_dht.h @@ -0,0 +1,21 @@ +#ifndef __HTU21D_DHT_H +#define __HTU21D_DHT_H + +#include + +typedef enum { + HTU21D_OK, + HTU21D_ERROR +} htu21d_ret_t; + +typedef struct { + htu21d_ret_t (*write_command_cb)(void * handle, uint8_t reg, uint8_t value); + htu21d_ret_t (*read_data_cb)(void *handle, uint8_t reg, uint8_t *value); +} htu21d_cb_t; + +typedef struct { + htu21d_cb_t cb; + void *user_data; +} htu21d_t; + +#endif \ No newline at end of file diff --git a/main/lib/ltc2941_battery.h b/main/lib/ltc2941_battery.h index 0d3d659..dcca6fb 100644 --- a/main/lib/ltc2941_battery.h +++ b/main/lib/ltc2941_battery.h @@ -56,4 +56,8 @@ typedef struct { #define LTC2941_STATUS_ALRT_VBAT (1 << 1U) #define LTC2941_STATUS_ALRT_UVLO 1U +ltc2941_ret_t ltc2941_init(ltc2941_t *bat); +ltc2941_ret_t ltc2941_read_status(ltc2941_t *bat, uint8_t *status); +ltc2941_ret_t ltc2941_read_charge(ltc2941_t *bat, uint16_t *charge); + #endif \ No newline at end of file diff --git a/main/main.c b/main/main.c index 9ee8142..986d75b 100644 --- a/main/main.c +++ b/main/main.c @@ -4,16 +4,34 @@ #include "freertos/task.h" #include "freertos/queue.h" +#include "esp_log.h" + #include "driver/gpio.h" +#include "driver/i2c.h" + +#include "user_board.h" void vTaskLEDs(void *pvParameters); extern TaskHandle_t xTaskLEDsHandle; +void vTasBatteryExample(void *pvParameters); +extern TaskHandle_t xTaskBatteryExampleHandle; + +extern TaskHandle_t xTaskEPDExampleHandle; +void vTaskEPDExample(void *pvParameters); + void app_lib_i2c_system_init(void); +static const char *TAG = "APP_MAIN"; + void app_main(void) { + // Init system peripherals. app_lib_i2c_system_init(); + + // Init tasks xTaskCreate(vTaskLEDs, "TASK_LEDs", 1024, NULL, 4, &xTaskLEDsHandle); + xTaskCreate(vTasBatteryExample, "TASK_BAT", 2048, NULL, 4, &xTaskBatteryExampleHandle); + xTaskCreate(vTaskEPDExample, "TASK_EPD", 2048, NULL, 4, &xTaskEPDExampleHandle); for(;;) { vTaskSuspend(NULL); diff --git a/main/user_board.h b/main/user_board.h index 3e2e40a..3c7b03e 100644 --- a/main/user_board.h +++ b/main/user_board.h @@ -16,4 +16,11 @@ #define BOARD_SYSTEM_I2C_SDA_PIN GPIO_NUM_39 #define BOARD_SYSTEM_I2C_SCL_PIN GPIO_NUM_40 +#define BOARD_EPD_SPI_CS_PIN GPIO_NUM_13 +#define BOARD_EPD_SPI_MOSI_PIN GPIO_NUM_15 +#define BOARD_EPD_SPI_SCK_PIN GPIO_NUM_14 +#define BOARD_EPD_RES_PIN GPIO_NUM_10 +#define BOARD_EPD_DC_PIN GPIO_NUM_12 +#define BOARD_EPD_BUSY_PIN GPIO_NUM_11 + #endif \ No newline at end of file