From e4a5ccb043e7cb890867e679d2eed76ff0a5883b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Ryb=C3=A1rsky?= Date: Fri, 8 May 2026 14:56:29 +0200 Subject: [PATCH] Init --- .clangd | 2 + .devcontainer/Dockerfile | 13 + .devcontainer/devcontainer.json | 19 ++ .gitignore | 78 ++++++ .vscode/c_cpp_properties.json | 20 ++ .vscode/launch.json | 10 + .vscode/settings.json | 20 ++ CMakeLists.txt | 6 + dependencies.lock | 57 ++++ hw.txt | 8 + main/CMakeLists.txt | 28 ++ main/drivers/battery.c | 153 +++++++++++ main/drivers/battery.h | 7 + main/drivers/bmi270.c | 40 +++ main/drivers/bmi270.h | 54 ++++ main/drivers/es8311.c | 89 +++++++ main/drivers/es8311.h | 76 ++++++ main/drivers/fonts.c | 383 ++++++++++++++++++++++++++ main/drivers/fonts.h | 4 + main/drivers/i2c.c | 87 ++++++ main/drivers/i2c.h | 16 ++ main/drivers/i2s.c | 34 +++ main/drivers/i2s.h | 7 + main/drivers/irled.c | 39 +++ main/drivers/irled.h | 7 + main/drivers/pins.c | 33 +++ main/drivers/pins.h | 57 ++++ main/drivers/sdcard.c | 57 ++++ main/drivers/sdcard.h | 3 + main/drivers/spi.c | 0 main/drivers/spi.h | 1 + main/drivers/st7789.c | 291 ++++++++++++++++++++ main/drivers/st7789.h | 45 ++++ main/drivers/tca8418.c | 105 ++++++++ main/drivers/tca8418.h | 459 ++++++++++++++++++++++++++++++++ main/drivers/ws2812.c | 50 ++++ main/drivers/ws2812.h | 6 + main/idf_component.yml | 18 ++ main/main.c | 99 +++++++ 39 files changed, 2481 insertions(+) create mode 100644 .clangd create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .gitignore create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 CMakeLists.txt create mode 100644 dependencies.lock create mode 100644 hw.txt create mode 100644 main/CMakeLists.txt create mode 100644 main/drivers/battery.c create mode 100644 main/drivers/battery.h create mode 100644 main/drivers/bmi270.c create mode 100644 main/drivers/bmi270.h create mode 100644 main/drivers/es8311.c create mode 100644 main/drivers/es8311.h create mode 100644 main/drivers/fonts.c create mode 100644 main/drivers/fonts.h create mode 100644 main/drivers/i2c.c create mode 100644 main/drivers/i2c.h create mode 100644 main/drivers/i2s.c create mode 100644 main/drivers/i2s.h create mode 100644 main/drivers/irled.c create mode 100644 main/drivers/irled.h create mode 100644 main/drivers/pins.c create mode 100644 main/drivers/pins.h create mode 100644 main/drivers/sdcard.c create mode 100644 main/drivers/sdcard.h create mode 100644 main/drivers/spi.c create mode 100644 main/drivers/spi.h create mode 100644 main/drivers/st7789.c create mode 100644 main/drivers/st7789.h create mode 100644 main/drivers/tca8418.c create mode 100644 main/drivers/tca8418.h create mode 100644 main/drivers/ws2812.c create mode 100644 main/drivers/ws2812.h create mode 100644 main/idf_component.yml create mode 100644 main/main.c diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..437f255 --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Remove: [-f*, -m*] diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..dafb8ad --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,13 @@ +ARG DOCKER_TAG=latest +FROM espressif/idf:${DOCKER_TAG} + +ENV LC_ALL=C.UTF-8 +ENV LANG=C.UTF-8 + +RUN apt-get update -y && apt-get install udev -y + +RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc + +ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] + +CMD ["/bin/bash", "-c"] \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..246b79f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,19 @@ +{ + "name": "ESP-IDF QEMU", + "build": { + "dockerfile": "Dockerfile" + }, + "customizations": { + "vscode": { + "settings": { + "terminal.integrated.defaultProfile.linux": "bash", + "idf.gitPath": "/usr/bin/git" + }, + "extensions": [ + "espressif.esp-idf-extension", + "espressif.esp-idf-web" + ] + } + }, + "runArgs": ["--privileged"] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7805557 --- /dev/null +++ b/.gitignore @@ -0,0 +1,78 @@ +# macOS +.DS_Store +.AppleDouble +.LSOverride + +# Directory metadata +.directory + +# Temporary files +*~ +*.swp +*.swo +*.bak +*.tmp + +# Log files +*.log + +# Build artifacts and directories +**/build/ +build/ +*.o +*.a +*.out +*.exe # For any host-side utilities compiled on Windows + +# ESP-IDF specific build outputs +*.bin +*.elf +*.map +flasher_args.json # Generated in build directory +sdkconfig.old +sdkconfig + +# ESP-IDF dependencies +# For older versions or manual component management +/components/.idf/ +**/components/.idf/ +# For modern ESP-IDF component manager +managed_components/ +# If ESP-IDF tools are installed/referenced locally to the project +.espressif/ + +# CMake generated files +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +install_manifest.txt +CTestTestfile.cmake + +# Python environment files +*.pyc +*.pyo +*.pyd +__pycache__/ +*.egg-info/ +dist/ + +# Virtual environment folders +venv/ +.venv/ +env/ + +# Language Servers +.clangd/ +.ccls-cache/ +compile_commands.json + +# Windows specific +Thumbs.db +ehthumbs.db +Desktop.ini + +# User-specific configuration files +*.user +*.workspace # General workspace files, can be from various tools +*.suo # Visual Studio Solution User Options +*.sln.docstates # Visual Studio diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..74eaadb --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,20 @@ +{ + "configurations": [ + { + "name": "ESP-IDF", + "compilerPath": "/home/bruno/.espressif/tools/xtensa-esp-elf/esp-15.2.0_20251204/xtensa-esp-elf/bin/xtensa-esp32s3-elf-gcc", + "compileCommands": "${config:idf.buildPath}/compile_commands.json", + "intelliSenseMode": "gcc-x86", + "includePath": [ + "${workspaceFolder}/**" + ], + "browse": { + "path": [ + "${workspaceFolder}" + ], + "limitSymbolsToIncludedHeaders": true + } + } + ], + "version": 4 +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3694ae4 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,10 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "gdbtarget", + "request": "attach", + "name": "Eclipse CDT GDB Adapter" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..fc08e50 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,20 @@ +{ + "C_Cpp.intelliSenseEngine": "default", + "idf.extensionActivationMode": "always", + "idf.openOcdConfigs": [ + "board/esp32s3-builtin.cfg" + ], + "idf.port": "/dev/ttyACM0", + "idf.currentSetup": "/home/bruno/.espressif/v6.0/esp-idf", + "idf.customExtraVars": { + "IDF_TARGET": "esp32s3", + "OPENOCD_USB_ADAPTER_LOCATION": "1-1" + }, + "clangd.path": "/home/bruno/.espressif/tools/esp-clang/esp-20.1.1_20250829/esp-clang/bin/clangd", + "clangd.arguments": [ + "--background-index", + "--query-driver=**", + "--compile-commands-dir=/home/bruno/Documents/Programming/projects/carputerosobny/build" + ], + "idf.flashType": "UART" +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..50bfd2b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(carputerosobny) diff --git a/dependencies.lock b/dependencies.lock new file mode 100644 index 0000000..da9cd27 --- /dev/null +++ b/dependencies.lock @@ -0,0 +1,57 @@ +dependencies: + espressif/esp_tinyusb: + component_hash: 8e57a14ac14d8e4d4588b5b9222977b96475323bcebae3c838919bb4e8587887 + dependencies: + - name: idf + require: private + version: '>=5.0' + - name: espressif/tinyusb + registry_url: https://components.espressif.com + require: public + version: '>=0.17.0~2' + source: + registry_url: https://components.espressif.com/ + type: service + targets: + - esp32s2 + - esp32s3 + - esp32p4 + - esp32h4 + - esp32s31 + version: 2.2.0 + espressif/led_strip: + component_hash: 28621486f77229aaf81c71f5e15d6fbf36c2949cf11094e07090593e659e7639 + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 3.0.3 + espressif/tinyusb: + component_hash: 5ea9d3b6d6b0734a0a0b3491967aa0e1bece2974132294dbda5dd2839b247bfa + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com + type: service + targets: + - esp32s2 + - esp32s3 + - esp32p4 + - esp32h4 + version: 0.19.0~2 + idf: + source: + type: idf + version: 6.0.0 +direct_dependencies: +- espressif/esp_tinyusb +- espressif/led_strip +- idf +manifest_hash: 4367414e2d87717eea085884b361169910107724286ca676c237567381b84306 +target: esp32s3 +version: 3.0.0 diff --git a/hw.txt b/hw.txt new file mode 100644 index 0000000..0dd4bd4 --- /dev/null +++ b/hw.txt @@ -0,0 +1,8 @@ +IMU - not working +AUDIO - not working +IR - direct drive from gpio, delayed +DISPLAY - can draw +KEYBOARD - SCANNING DONE +WS2812 - works +BATTERY ADC - works +MICROSD - mounted \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..70ac771 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,28 @@ +idf_component_register(SRCS "main.c" + "drivers/battery.c" + "drivers/battery.h" + "drivers/bmi270.c" + "drivers/bmi270.h" + "drivers/es8311.c" + "drivers/es8311.h" + "drivers/i2c.c" + "drivers/i2c.h" + "drivers/i2s.c" + "drivers/i2s.h" + "drivers/irled.c" + "drivers/irled.h" + "drivers/pins.h" + "drivers/pins.c" + "drivers/sdcard.h" + "drivers/sdcard.c" + "drivers/spi.c" + "drivers/spi.h" + "drivers/fonts.c" + "drivers/fonts.c" + "drivers/st7789.c" + "drivers/st7789.h" + "drivers/tca8418.c" + "drivers/tca8418.h" + "drivers/ws2812.c" + "drivers/ws2812.h" + INCLUDE_DIRS ".") diff --git a/main/drivers/battery.c b/main/drivers/battery.c new file mode 100644 index 0000000..043098a --- /dev/null +++ b/main/drivers/battery.c @@ -0,0 +1,153 @@ +#include "hal/adc_types.h" +#include +#include +#include + +#include "pins.h" +#include "FreeRTOS.h" + +static float g_battery_voltage = 0; +static int g_battery_percent = 0; + +adc_oneshot_unit_handle_t adc_handle; +adc_cali_handle_t adc_cali_handle; + +float getBatteryVoltage() { + return g_battery_voltage; +} + +int getBatteryPercentage() { + return g_battery_percent; +} + +void battery_adc_init() { + // ADC init + adc_oneshot_unit_init_cfg_t init_config = { + .unit_id = ADC_UNIT_1, + .clk_src = ADC_RTC_CLK_SRC_DEFAULT, + }; + + ESP_ERROR_CHECK(adc_oneshot_new_unit(&init_config, &adc_handle)); + + // Channel config + adc_oneshot_chan_cfg_t config = { + .bitwidth = ADC_BITWIDTH_DEFAULT, + .atten = ADC_ATTEN_DB_12, + }; + + ESP_ERROR_CHECK( + adc_oneshot_config_channel(adc_handle, ADC_CHANNEL_9, &config) + ); + + // Calibration + adc_cali_curve_fitting_config_t cali_config = { + .unit_id = ADC_UNIT_1, + .chan = ADC_CHANNEL_9, + .atten = ADC_ATTEN_DB_12, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + + ESP_ERROR_CHECK( + adc_cali_create_scheme_curve_fitting( + &cali_config, + &adc_cali_handle + ) + ); +} + +typedef struct { + float voltage; + int percentage; +} BatteryPoint; + +static const BatteryPoint battery_curve[] = { + {4.20, 100}, + {4.10, 90}, + {4.00, 80}, + {3.90, 70}, + {3.80, 60}, + {3.70, 45}, + {3.60, 30}, + {3.50, 15}, + {3.40, 8}, + {3.30, 5}, + {3.20, 0}, +}; + +int batteryPercentage(float voltage) { + int size = sizeof(battery_curve) / sizeof(BatteryPoint); + + // Above max + if (voltage >= battery_curve[0].voltage) + return 100; + + // Below min + if (voltage <= battery_curve[size - 1].voltage) + return 0; + + // Find range + for (int i = 0; i < size - 1; i++) { + if (voltage <= battery_curve[i].voltage && + voltage >= battery_curve[i + 1].voltage) { + + float v1 = battery_curve[i].voltage; + float v2 = battery_curve[i + 1].voltage; + + int p1 = battery_curve[i].percentage; + int p2 = battery_curve[i + 1].percentage; + + // Linear interpolation + float t = (voltage - v2) / (v1 - v2); + + return p2 + (int)((p1 - p2) * t); + } + } + + return 0; +} + +static float readBatteryVoltsSamples(int samples) { + uint32_t raw_sum = 0; + int raw; + int voltage_mv; + + for (int i = 0; i < samples; i++) { + ESP_ERROR_CHECK( + adc_oneshot_read(adc_handle, ADC_CHANNEL_9, &raw) + ); + raw_sum += raw; + + // only delay for "slow mode" + if (samples > 16) { + vTaskDelay(pdMS_TO_TICKS(10)); + } + } + + int raw_avg = raw_sum / samples; + + ESP_ERROR_CHECK( + adc_cali_raw_to_voltage(adc_cali_handle, raw_avg, &voltage_mv) + ); + + return (voltage_mv / 1000.0f) * 2.0f; +} + +static void battery_task(void *arg) { + battery_adc_init(); + g_battery_voltage = readBatteryVoltsSamples(1); + while (1) { + g_battery_voltage = readBatteryVoltsSamples(256); + g_battery_percent = batteryPercentage(g_battery_voltage); + } +} + +void battery_start_task() { + xTaskCreate( + battery_task, + "battery_task", + 4096, + NULL, + 5, + NULL + ); +} \ No newline at end of file diff --git a/main/drivers/battery.h b/main/drivers/battery.h new file mode 100644 index 0000000..17cefaa --- /dev/null +++ b/main/drivers/battery.h @@ -0,0 +1,7 @@ +#pragma once + +float getBatteryVoltage(); + +int getBatteryPercentage(); + +void battery_start_task(); \ No newline at end of file diff --git a/main/drivers/bmi270.c b/main/drivers/bmi270.c new file mode 100644 index 0000000..f272034 --- /dev/null +++ b/main/drivers/bmi270.c @@ -0,0 +1,40 @@ +#include "bmi270.h" +#include "FreeRTOS.h" +#include "i2c.h" +#include "pins.h" +#include + +void bmi270_init(void) { + uint8_t id; + i2c_read_reg(IMU_I2C_ADDRESS, BMI270_CHIP_ID, &id); + + if (id != 0x24) + return; + + // soft reset + i2c_write_reg(IMU_I2C_ADDRESS, 0x7E, 0xB6); + vTaskDelay(pdMS_TO_TICKS(10)); + + // power on accel + gyro + i2c_write_reg(IMU_I2C_ADDRESS, BMI270_PWR_CTRL, 0x0E); + + // accel config (100 Hz-ish) + i2c_write_reg(IMU_I2C_ADDRESS, BMI270_ACC_CONF, 0xA8); + + // gyro config + i2c_write_reg(IMU_I2C_ADDRESS, BMI270_GYR_CONF, 0xA9); +} + +void bmi270_read(bmi270_data_t *d) { + uint8_t buf[12]; + + i2c_read_reg_multi(IMU_I2C_ADDRESS, BMI270_ACC_X_L, buf, 12); + + d->ax = (int16_t)(buf[1] << 8 | buf[0]); + d->ay = (int16_t)(buf[3] << 8 | buf[2]); + d->az = (int16_t)(buf[5] << 8 | buf[4]); + + d->gx = (int16_t)(buf[7] << 8 | buf[6]); + d->gy = (int16_t)(buf[9] << 8 | buf[8]); + d->gz = (int16_t)(buf[11] << 8 | buf[10]); +} \ No newline at end of file diff --git a/main/drivers/bmi270.h b/main/drivers/bmi270.h new file mode 100644 index 0000000..530cdb7 --- /dev/null +++ b/main/drivers/bmi270.h @@ -0,0 +1,54 @@ +#pragma once +// --- Core IDs --- +#include +#define BMI270_CHIP_ID 0x00 +#define BMI270_REV_ID 0x01 + +// --- Power / system --- +#define BMI270_PWR_CONF 0x7C +#define BMI270_PWR_CTRL 0x7D +#define BMI270_CMD 0x7E + +// --- Accel config --- +#define BMI270_ACC_CONF 0x40 +#define BMI270_ACC_RANGE 0x41 + +// --- Gyro config --- +#define BMI270_GYR_CONF 0x42 +#define BMI270_GYR_RANGE 0x43 + +// --- Data registers --- +#define BMI270_ACC_X_L 0x0C +#define BMI270_ACC_X_H 0x0D +#define BMI270_ACC_Y_L 0x0E +#define BMI270_ACC_Y_H 0x0F +#define BMI270_ACC_Z_L 0x10 +#define BMI270_ACC_Z_H 0x11 + +#define BMI270_GYR_X_L 0x12 +#define BMI270_GYR_X_H 0x13 +#define BMI270_GYR_Y_L 0x14 +#define BMI270_GYR_Y_H 0x15 +#define BMI270_GYR_Z_L 0x16 +#define BMI270_GYR_Z_H 0x17 + +// --- Commands --- +#define BMI270_CMD_SOFTRESET 0xB6 +#define BMI270_CMD_FIFO_FLUSH 0xB0 + +// --- Power bits --- +#define BMI270_PWR_ACCEL_EN (1 << 3) +#define BMI270_PWR_GYRO_EN (1 << 2) + +// --- Config presets (minimal usable defaults) --- +#define BMI270_ACC_CONF_100HZ 0xA8 +#define BMI270_GYR_CONF_100HZ 0xA9 + +typedef struct { + int16_t ax, ay, az; + int16_t gx, gy, gz; +} bmi270_data_t; + +void bmi270_init(void); + +void bmi270_read(bmi270_data_t *d); diff --git a/main/drivers/es8311.c b/main/drivers/es8311.c new file mode 100644 index 0000000..4541bd0 --- /dev/null +++ b/main/drivers/es8311.c @@ -0,0 +1,89 @@ +#include "es8311.h" + +#include "drivers/i2s.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "driver/i2s_std.h" + +#include "i2c.h" +#include "pins.h" + +void es8311_write(uint8_t reg, uint8_t val) { + i2c_write_reg(ES8311_I2C_ADDR, reg, val); +} + +void es8311_set_dac_volume(uint8_t vol) { + es8311_write(ES8311_DAC_VOL_L, vol); + es8311_write(ES8311_DAC_VOL_R, vol); +} + +void es8311_set_adc_volume(uint8_t vol) { es8311_write(ES8311_ADC_VOL, vol); } + +void es8311_init(void) { + es8311_write(ES8311_RESET, ES8311_RESET_CMD); + + vTaskDelay(pdMS_TO_TICKS(20)); + + // enable ADC + DAC + es8311_write(ES8311_PWR_UP_DOWN, ES8311_PWR_DAC_EN | ES8311_PWR_ADC_EN); + + es8311_write(ES8311_PWR_ANALOG, ES8311_ALL_ON); + + // I2S 16-bit + es8311_write(ES8311_SER_FMT, ES8311_FMT_I2S | ES8311_WORD_LEN_16); + + // ADC config + es8311_write(ES8311_ADC_CTRL1, 0x44); + + es8311_write(ES8311_ADC_CTRL2, 0x0C); + + // DAC config + es8311_write(ES8311_DAC_CTRL1, 0x04); + + es8311_write(ES8311_DAC_CTRL2, 0x0C); + + es8311_set_dac_volume(0xBF); + es8311_set_adc_volume(0x88); + + es8311_write(ES8311_SPK_CTRL, 0xFF); + + audio_i2s_init(); +} + +int audio_write(const int16_t *samples, size_t count) { + size_t written; + + esp_err_t r = i2s_channel_write(i2s_tx, samples, count * sizeof(int16_t), + &written, portMAX_DELAY); + + if (r != ESP_OK) + return -1; + + return written / sizeof(int16_t); +} + +int audio_read(int16_t *samples, size_t count) { + size_t read; + + esp_err_t r = i2s_channel_read(i2s_rx, samples, count * sizeof(int16_t), + &read, portMAX_DELAY); + + if (r != ESP_OK) + return -1; + + return read / sizeof(int16_t); +} + +void audio_beep(void) { + static int16_t buf[4410]; + + for (int i = 0; i < 4410; i++) { + + int phase = (i / 20) & 1; + + buf[i] = phase ? 12000 : -12000; + } + + audio_write(buf, 4410); +} \ No newline at end of file diff --git a/main/drivers/es8311.h b/main/drivers/es8311.h new file mode 100644 index 0000000..c4a429d --- /dev/null +++ b/main/drivers/es8311.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +// ---------------------- +// I2C +// ---------------------- +#define ES8311_I2C_ADDR 0x18 + +// ---------------------- +// System +// ---------------------- +#define ES8311_RESET 0x00 +#define ES8311_CLK_MANAGE 0x01 +#define ES8311_CLK_DIV 0x02 + +// ---------------------- +// Power +// ---------------------- +#define ES8311_PWR_UP_DOWN 0x0C +#define ES8311_PWR_ANALOG 0x0D + +#define ES8311_PWR_DAC_EN (1 << 0) +#define ES8311_PWR_ADC_EN (1 << 1) + +// ---------------------- +// Audio format +// ---------------------- +#define ES8311_SER_FMT 0x10 + +#define ES8311_FMT_I2S 0x18 +#define ES8311_FMT_LEFT 0x10 + +#define ES8311_WORD_LEN_16 0x10 +#define ES8311_WORD_LEN_24 0x20 + +// ---------------------- +// ADC +// ---------------------- +#define ES8311_ADC_CTRL1 0x14 +#define ES8311_ADC_CTRL2 0x15 + +#define ES8311_ADC_VOL 0x16 + +// ---------------------- +// DAC +// ---------------------- +#define ES8311_DAC_CTRL1 0x17 +#define ES8311_DAC_CTRL2 0x18 + +#define ES8311_DAC_VOL_L 0x33 +#define ES8311_DAC_VOL_R 0x34 + +// ---------------------- +// Output +// ---------------------- +#define ES8311_HP_CTRL 0x31 +#define ES8311_SPK_CTRL 0x32 + +// ---------------------- +// Common +// ---------------------- +#define ES8311_RESET_CMD 0x1F +#define ES8311_ALL_ON 0xFF + +void es8311_init(void); + +void es8311_set_dac_volume(uint8_t vol); +void es8311_set_adc_volume(uint8_t vol); + +int audio_write(const int16_t *samples, size_t count); + +int audio_read(int16_t *samples, size_t count); + +void audio_beep(void); diff --git a/main/drivers/fonts.c b/main/drivers/fonts.c new file mode 100644 index 0000000..62d91c3 --- /dev/null +++ b/main/drivers/fonts.c @@ -0,0 +1,383 @@ +#include "fonts.h" + +const uint8_t font5x7[256][5] = { + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x3E, 0x5B, 0x4F, 0x5B, 0x3E}, + {0x3E, 0x6B, 0x4F, 0x6B, 0x3E}, {0x1C, 0x3E, 0x7C, 0x3E, 0x1C}, + {0x18, 0x3C, 0x7E, 0x3C, 0x18}, {0x1C, 0x57, 0x7D, 0x57, 0x1C}, + {0x1C, 0x5E, 0x7F, 0x5E, 0x1C}, {0x00, 0x18, 0x3C, 0x18, 0x00}, + {0xFF, 0xE7, 0xC3, 0xE7, 0xFF}, {0x00, 0x18, 0x24, 0x18, 0x00}, + {0xFF, 0xE7, 0xDB, 0xE7, 0xFF}, {0x30, 0x48, 0x3A, 0x06, 0x0E}, + {0x26, 0x29, 0x79, 0x29, 0x26}, {0x40, 0x7F, 0x05, 0x05, 0x07}, + {0x40, 0x7F, 0x05, 0x25, 0x3F}, {0x5A, 0x3C, 0xE7, 0x3C, 0x5A}, + {0x7F, 0x3E, 0x1C, 0x1C, 0x08}, {0x08, 0x1C, 0x1C, 0x3E, 0x7F}, + {0x14, 0x22, 0x7F, 0x22, 0x14}, {0x5F, 0x5F, 0x00, 0x5F, 0x5F}, + {0x06, 0x09, 0x7F, 0x01, 0x7F}, {0x00, 0x66, 0x89, 0x95, 0x6A}, + {0x60, 0x60, 0x60, 0x60, 0x60}, {0x94, 0xA2, 0xFF, 0xA2, 0x94}, + {0x08, 0x04, 0x7E, 0x04, 0x08}, {0x10, 0x20, 0x7E, 0x20, 0x10}, + {0x08, 0x08, 0x2A, 0x1C, 0x08}, {0x08, 0x1C, 0x2A, 0x08, 0x08}, + {0x1E, 0x10, 0x10, 0x10, 0x10}, {0x0C, 0x1E, 0x0C, 0x1E, 0x0C}, + {0x30, 0x38, 0x3E, 0x38, 0x30}, {0x06, 0x0E, 0x3E, 0x0E, 0x06}, + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x5F, 0x00, 0x00}, + {0x00, 0x07, 0x00, 0x07, 0x00}, {0x14, 0x7F, 0x14, 0x7F, 0x14}, + {0x24, 0x2A, 0x7F, 0x2A, 0x12}, {0x23, 0x13, 0x08, 0x64, 0x62}, + {0x36, 0x49, 0x56, 0x20, 0x50}, {0x00, 0x08, 0x07, 0x03, 0x00}, + {0x00, 0x1C, 0x22, 0x41, 0x00}, {0x00, 0x41, 0x22, 0x1C, 0x00}, + {0x2A, 0x1C, 0x7F, 0x1C, 0x2A}, {0x08, 0x08, 0x3E, 0x08, 0x08}, + {0x00, 0x80, 0x70, 0x30, 0x00}, {0x08, 0x08, 0x08, 0x08, 0x08}, + {0x00, 0x00, 0x60, 0x60, 0x00}, {0x20, 0x10, 0x08, 0x04, 0x02}, + {0x3E, 0x51, 0x49, 0x45, 0x3E}, {0x00, 0x42, 0x7F, 0x40, 0x00}, + {0x72, 0x49, 0x49, 0x49, 0x46}, {0x21, 0x41, 0x49, 0x4D, 0x33}, + {0x18, 0x14, 0x12, 0x7F, 0x10}, {0x27, 0x45, 0x45, 0x45, 0x39}, + {0x3C, 0x4A, 0x49, 0x49, 0x31}, {0x41, 0x21, 0x11, 0x09, 0x07}, + {0x36, 0x49, 0x49, 0x49, 0x36}, {0x46, 0x49, 0x49, 0x29, 0x1E}, + {0x00, 0x00, 0x14, 0x00, 0x00}, {0x00, 0x40, 0x34, 0x00, 0x00}, + {0x00, 0x08, 0x14, 0x22, 0x41}, {0x14, 0x14, 0x14, 0x14, 0x14}, + {0x00, 0x41, 0x22, 0x14, 0x08}, {0x02, 0x01, 0x59, 0x09, 0x06}, + {0x3E, 0x41, 0x5D, 0x59, 0x4E}, {0x7C, 0x12, 0x11, 0x12, 0x7C}, + {0x7F, 0x49, 0x49, 0x49, 0x36}, {0x3E, 0x41, 0x41, 0x41, 0x22}, + {0x7F, 0x41, 0x41, 0x41, 0x3E}, {0x7F, 0x49, 0x49, 0x49, 0x41}, + {0x7F, 0x09, 0x09, 0x09, 0x01}, {0x3E, 0x41, 0x41, 0x51, 0x73}, + {0x7F, 0x08, 0x08, 0x08, 0x7F}, {0x00, 0x41, 0x7F, 0x41, 0x00}, + {0x20, 0x40, 0x41, 0x3F, 0x01}, {0x7F, 0x08, 0x14, 0x22, 0x41}, + {0x7F, 0x40, 0x40, 0x40, 0x40}, {0x7F, 0x02, 0x1C, 0x02, 0x7F}, + {0x7F, 0x04, 0x08, 0x10, 0x7F}, {0x3E, 0x41, 0x41, 0x41, 0x3E}, + {0x7F, 0x09, 0x09, 0x09, 0x06}, {0x3E, 0x41, 0x51, 0x21, 0x5E}, + {0x7F, 0x09, 0x19, 0x29, 0x46}, {0x26, 0x49, 0x49, 0x49, 0x32}, + {0x03, 0x01, 0x7F, 0x01, 0x03}, {0x3F, 0x40, 0x40, 0x40, 0x3F}, + {0x1F, 0x20, 0x40, 0x20, 0x1F}, {0x3F, 0x40, 0x38, 0x40, 0x3F}, + {0x63, 0x14, 0x08, 0x14, 0x63}, {0x03, 0x04, 0x78, 0x04, 0x03}, + {0x61, 0x59, 0x49, 0x4D, 0x43}, {0x00, 0x7F, 0x41, 0x41, 0x41}, + {0x02, 0x04, 0x08, 0x10, 0x20}, {0x00, 0x41, 0x41, 0x41, 0x7F}, + {0x04, 0x02, 0x01, 0x02, 0x04}, {0x40, 0x40, 0x40, 0x40, 0x40}, + {0x00, 0x03, 0x07, 0x08, 0x00}, {0x20, 0x54, 0x54, 0x78, 0x40}, + {0x7F, 0x28, 0x44, 0x44, 0x38}, {0x38, 0x44, 0x44, 0x44, 0x28}, + {0x38, 0x44, 0x44, 0x28, 0x7F}, {0x38, 0x54, 0x54, 0x54, 0x18}, + {0x00, 0x08, 0x7E, 0x09, 0x02}, {0x18, 0xA4, 0xA4, 0x9C, 0x78}, + {0x7F, 0x08, 0x04, 0x04, 0x78}, {0x00, 0x44, 0x7D, 0x40, 0x00}, + {0x20, 0x40, 0x40, 0x3D, 0x00}, {0x7F, 0x10, 0x28, 0x44, 0x00}, + {0x00, 0x41, 0x7F, 0x40, 0x00}, {0x7C, 0x04, 0x78, 0x04, 0x78}, + {0x7C, 0x08, 0x04, 0x04, 0x78}, {0x38, 0x44, 0x44, 0x44, 0x38}, + {0xFC, 0x18, 0x24, 0x24, 0x18}, {0x18, 0x24, 0x24, 0x18, 0xFC}, + {0x7C, 0x08, 0x04, 0x04, 0x08}, {0x48, 0x54, 0x54, 0x54, 0x24}, + {0x04, 0x04, 0x3F, 0x44, 0x24}, {0x3C, 0x40, 0x40, 0x20, 0x7C}, + {0x1C, 0x20, 0x40, 0x20, 0x1C}, {0x3C, 0x40, 0x30, 0x40, 0x3C}, + {0x44, 0x28, 0x10, 0x28, 0x44}, {0x4C, 0x90, 0x90, 0x90, 0x7C}, + {0x44, 0x64, 0x54, 0x4C, 0x44}, {0x00, 0x08, 0x36, 0x41, 0x00}, + {0x00, 0x00, 0x77, 0x00, 0x00}, {0x00, 0x41, 0x36, 0x08, 0x00}, + {0x02, 0x01, 0x02, 0x04, 0x02}, {0x3C, 0x26, 0x23, 0x26, 0x3C}, + {0x1E, 0xA1, 0xA1, 0x61, 0x12}, {0x3A, 0x40, 0x40, 0x20, 0x7A}, + {0x38, 0x54, 0x54, 0x55, 0x59}, {0x21, 0x55, 0x55, 0x79, 0x41}, + {0x21, 0x54, 0x54, 0x78, 0x41}, {0x21, 0x55, 0x54, 0x78, 0x40}, + {0x20, 0x54, 0x55, 0x79, 0x40}, {0x0C, 0x1E, 0x52, 0x72, 0x12}, + {0x39, 0x55, 0x55, 0x55, 0x59}, {0x39, 0x54, 0x54, 0x54, 0x59}, + {0x39, 0x55, 0x54, 0x54, 0x58}, {0x00, 0x00, 0x45, 0x7C, 0x41}, + {0x00, 0x02, 0x45, 0x7D, 0x42}, {0x00, 0x01, 0x45, 0x7C, 0x40}, + {0xF0, 0x29, 0x24, 0x29, 0xF0}, {0xF0, 0x28, 0x25, 0x28, 0xF0}, + {0x7C, 0x54, 0x55, 0x45, 0x00}, {0x20, 0x54, 0x54, 0x7C, 0x54}, + {0x7C, 0x0A, 0x09, 0x7F, 0x49}, {0x32, 0x49, 0x49, 0x49, 0x32}, + {0x32, 0x48, 0x48, 0x48, 0x32}, {0x32, 0x4A, 0x48, 0x48, 0x30}, + {0x3A, 0x41, 0x41, 0x21, 0x7A}, {0x3A, 0x42, 0x40, 0x20, 0x78}, + {0x00, 0x9D, 0xA0, 0xA0, 0x7D}, {0x39, 0x44, 0x44, 0x44, 0x39}, + {0x3D, 0x40, 0x40, 0x40, 0x3D}, {0x3C, 0x24, 0xFF, 0x24, 0x24}, + {0x48, 0x7E, 0x49, 0x43, 0x66}, {0x2B, 0x2F, 0xFC, 0x2F, 0x2B}, + {0xFF, 0x09, 0x29, 0xF6, 0x20}, {0xC0, 0x88, 0x7E, 0x09, 0x03}, + {0x20, 0x54, 0x54, 0x79, 0x41}, {0x00, 0x00, 0x44, 0x7D, 0x41}, + {0x30, 0x48, 0x48, 0x4A, 0x32}, {0x38, 0x40, 0x40, 0x22, 0x7A}, + {0x00, 0x7A, 0x0A, 0x0A, 0x72}, {0x7D, 0x0D, 0x19, 0x31, 0x7D}, + {0x26, 0x29, 0x29, 0x2F, 0x28}, {0x26, 0x29, 0x29, 0x29, 0x26}, + {0x30, 0x48, 0x4D, 0x40, 0x20}, {0x38, 0x08, 0x08, 0x08, 0x08}, + {0x08, 0x08, 0x08, 0x08, 0x38}, {0x2F, 0x10, 0xC8, 0xAC, 0xBA}, + {0x2F, 0x10, 0x28, 0x34, 0xFA}, {0x00, 0x00, 0x7B, 0x00, 0x00}, + {0x08, 0x14, 0x2A, 0x14, 0x22}, {0x22, 0x14, 0x2A, 0x14, 0x08}, + {0xAA, 0x00, 0x55, 0x00, 0xAA}, {0xAA, 0x55, 0xAA, 0x55, 0xAA}, + {0x00, 0x00, 0x00, 0xFF, 0x00}, {0x10, 0x10, 0x10, 0xFF, 0x00}, + {0x14, 0x14, 0x14, 0xFF, 0x00}, {0x10, 0x10, 0xFF, 0x00, 0xFF}, + {0x10, 0x10, 0xF0, 0x10, 0xF0}, {0x14, 0x14, 0x14, 0xFC, 0x00}, + {0x14, 0x14, 0xF7, 0x00, 0xFF}, {0x00, 0x00, 0xFF, 0x00, 0xFF}, + {0x14, 0x14, 0xF4, 0x04, 0xFC}, {0x14, 0x14, 0x17, 0x10, 0x1F}, + {0x10, 0x10, 0x1F, 0x10, 0x1F}, {0x14, 0x14, 0x14, 0x1F, 0x00}, + {0x10, 0x10, 0x10, 0xF0, 0x00}, {0x00, 0x00, 0x00, 0x1F, 0x10}, + {0x10, 0x10, 0x10, 0x1F, 0x10}, {0x10, 0x10, 0x10, 0xF0, 0x10}, + {0x00, 0x00, 0x00, 0xFF, 0x10}, {0x10, 0x10, 0x10, 0x10, 0x10}, + {0x10, 0x10, 0x10, 0xFF, 0x10}, {0x00, 0x00, 0x00, 0xFF, 0x14}, + {0x00, 0x00, 0xFF, 0x00, 0xFF}, {0x00, 0x00, 0x1F, 0x10, 0x17}, + {0x00, 0x00, 0xFC, 0x04, 0xF4}, {0x14, 0x14, 0x17, 0x10, 0x17}, + {0x14, 0x14, 0xF4, 0x04, 0xF4}, {0x00, 0x00, 0xFF, 0x00, 0xF7}, + {0x14, 0x14, 0x14, 0x14, 0x14}, {0x14, 0x14, 0xF7, 0x00, 0xF7}, + {0x14, 0x14, 0x14, 0x17, 0x14}, {0x10, 0x10, 0x1F, 0x10, 0x1F}, + {0x14, 0x14, 0x14, 0xF4, 0x14}, {0x10, 0x10, 0xF0, 0x10, 0xF0}, + {0x00, 0x00, 0x1F, 0x10, 0x1F}, {0x00, 0x00, 0x00, 0x1F, 0x14}, + {0x00, 0x00, 0x00, 0xFC, 0x14}, {0x00, 0x00, 0xF0, 0x10, 0xF0}, + {0x10, 0x10, 0xFF, 0x10, 0xFF}, {0x14, 0x14, 0x14, 0xFF, 0x14}, + {0x10, 0x10, 0x10, 0x1F, 0x00}, {0x00, 0x00, 0x00, 0xF0, 0x10}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0xF0, 0xF0, 0xF0, 0xF0, 0xF0}, + {0xFF, 0xFF, 0xFF, 0x00, 0x00}, {0x00, 0x00, 0x00, 0xFF, 0xFF}, + {0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, {0x38, 0x44, 0x44, 0x38, 0x44}, + {0x7C, 0x2A, 0x2A, 0x3E, 0x14}, {0x7E, 0x02, 0x02, 0x06, 0x06}, + {0x02, 0x7E, 0x02, 0x7E, 0x02}, {0x63, 0x55, 0x49, 0x41, 0x63}, + {0x38, 0x44, 0x44, 0x3C, 0x04}, {0x40, 0x7E, 0x20, 0x1E, 0x20}, + {0x06, 0x02, 0x7E, 0x02, 0x02}, {0x99, 0xA5, 0xE7, 0xA5, 0x99}, + {0x1C, 0x2A, 0x49, 0x2A, 0x1C}, {0x4C, 0x72, 0x01, 0x72, 0x4C}, + {0x30, 0x4A, 0x4D, 0x4D, 0x30}, {0x30, 0x48, 0x78, 0x48, 0x30}, + {0xBC, 0x62, 0x5A, 0x46, 0x3D}, {0x3E, 0x49, 0x49, 0x49, 0x00}, + {0x7E, 0x01, 0x01, 0x01, 0x7E}, {0x2A, 0x2A, 0x2A, 0x2A, 0x2A}, + {0x44, 0x44, 0x5F, 0x44, 0x44}, {0x40, 0x51, 0x4A, 0x44, 0x40}, + {0x40, 0x44, 0x4A, 0x51, 0x40}, {0x00, 0x00, 0xFF, 0x01, 0x03}, + {0xE0, 0x80, 0xFF, 0x00, 0x00}, {0x08, 0x08, 0x6B, 0x6B, 0x08}, + {0x36, 0x12, 0x36, 0x24, 0x36}, {0x06, 0x0F, 0x09, 0x0F, 0x06}, + {0x00, 0x00, 0x18, 0x18, 0x00}, {0x00, 0x00, 0x10, 0x10, 0x00}, + {0x30, 0x40, 0xFF, 0x01, 0x01}, {0x00, 0x1F, 0x01, 0x01, 0x1E}, + {0x00, 0x19, 0x1D, 0x17, 0x12}, {0x00, 0x3C, 0x3C, 0x3C, 0x3C}, + {0x00, 0x00, 0x00, 0x00, 0x00}}; + +// Hitachi HD44780A02 +const uint8_t fontHitachi[256][5] = { + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00}, + {0x00, 0xFE, 0x7C, 0x38, 0x10}, // 10 16 + {0x10, 0x38, 0x7C, 0xFE, 0x00}, // 11 17 + {0x0C, 0x0A, 0x00, 0x0C, 0x0A}, // 12 18 + {0x0A, 0x06, 0x00, 0x0A, 0x06}, // 13 19 + {0x88, 0xCC, 0xEE, 0xCC, 0x88}, // 14 20 + {0x22, 0x66, 0xEE, 0x66, 0x22}, // 15 21 + {0x38, 0x7C, 0x7C, 0x7C, 0x38}, // 16 22 + {0x20, 0x70, 0xA8, 0x20, 0x3E}, // 17 23 + {0x08, 0x04, 0xFE, 0x04, 0x08}, // 18 24 + {0x20, 0x40, 0xFE, 0x40, 0x20}, // 19 25 + {0x10, 0x10, 0x54, 0x38, 0x10}, // 1A 26 + {0x10, 0x38, 0x54, 0x10, 0x10}, // 1B 27 + {0x80, 0x88, 0x94, 0xA2, 0x80}, // 1C 28 + {0x80, 0xA2, 0x94, 0x88, 0x80}, // 1D 29 + {0x40, 0x70, 0x7C, 0x70, 0x40}, // 1E 30 + {0x04, 0x1C, 0x7C, 0x1C, 0x04}, // 1F 31 + {0x00, 0x00, 0x00, 0x00, 0x00}, // 20 32 + {0x00, 0x00, 0x9E, 0x00, 0x00}, // 21 33 ! + {0x00, 0x0E, 0x00, 0x0E, 0x00}, // 22 34 " + {0x28, 0xFE, 0x28, 0xFE, 0x28}, // 23 35 # + {0x48, 0x54, 0xFE, 0x54, 0x24}, // 24 36 $ + {0x46, 0x26, 0x10, 0xC8, 0xC4}, // 25 37 % + {0x6C, 0x92, 0xAA, 0x44, 0xA0}, // 26 38 & + {0x00, 0x0A, 0x06, 0x00, 0x00}, // 27 39 ' + {0x00, 0x38, 0x44, 0x82, 0x00}, // 28 40 ( + {0x00, 0x82, 0x44, 0x38, 0x00}, // 29 41 ) + {0x28, 0x10, 0x7C, 0x10, 0x28}, // 2A 42 * + {0x10, 0x10, 0x7C, 0x10, 0x10}, // 2B 43 + + {0x00, 0xA0, 0x60, 0x00, 0x00}, // 2C 44 , + {0x10, 0x10, 0x10, 0x10, 0x10}, // 2D 45 - + {0x00, 0xC0, 0xC0, 0x00, 0x00}, // 2E 46 . + {0x40, 0x20, 0x10, 0x08, 0x04}, // 2F 47 / + {0x7C, 0xA2, 0x92, 0x8A, 0x7C}, // 30 48 0 + {0x00, 0x84, 0xFE, 0x80, 0x00}, // 31 49 1 + {0x84, 0xC2, 0xA2, 0x92, 0x8C}, // 32 50 2 + {0x42, 0x82, 0x8A, 0x96, 0x62}, // 33 51 3 + {0x30, 0x28, 0x24, 0xFE, 0x20}, // 34 52 4 + {0x4E, 0x8A, 0x8A, 0x8A, 0x72}, // 35 53 5 + {0x78, 0x94, 0x92, 0x92, 0x60}, // 36 54 6 + {0x06, 0x02, 0xE2, 0x12, 0x0E}, // 37 55 7 + {0x6C, 0x92, 0x92, 0x92, 0x6C}, // 38 56 8 + {0x0C, 0x92, 0x92, 0x52, 0x3C}, // 39 57 9 + {0x00, 0x6C, 0x6C, 0x00, 0x00}, // 3A 58 : + {0x00, 0xAC, 0x6C, 0x00, 0x00}, // 3B 59 ; + {0x10, 0x28, 0x44, 0x82, 0x00}, // 3C 60 < + {0x28, 0x28, 0x28, 0x28, 0x28}, // 3D 61 = + {0x00, 0x82, 0x44, 0x28, 0x10}, // 3E 62 > + {0x04, 0x02, 0xA2, 0x12, 0x0C}, // 3F 63 ? + {0x64, 0x92, 0xF2, 0x82, 0x7C}, // 40 64 @ + {0xF8, 0x24, 0x22, 0x24, 0xF8}, // 41 65 A + {0xFE, 0x92, 0x92, 0x92, 0x6C}, // 42 66 B + {0x7C, 0x82, 0x82, 0x82, 0x44}, // 43 67 C + {0xFE, 0x82, 0x82, 0x44, 0x38}, // 44 68 D + {0xFE, 0x92, 0x92, 0x92, 0x82}, // 45 69 E + {0xFE, 0x12, 0x12, 0x12, 0x02}, // 46 70 F + {0x7C, 0x82, 0x92, 0x92, 0xF4}, // 47 71 G + {0xFE, 0x10, 0x10, 0x10, 0xFE}, // 48 72 H + {0x00, 0x82, 0xFE, 0x82, 0x00}, // 49 73 I + {0x40, 0x80, 0x82, 0x7E, 0x02}, // 4A 74 J + {0xFE, 0x10, 0x28, 0x44, 0x82}, // 4B 75 K + {0xFE, 0x80, 0x80, 0x80, 0x80}, // 4C 76 L + {0xFE, 0x04, 0x18, 0x04, 0xFE}, // 4D 77 M + {0xFE, 0x08, 0x10, 0x20, 0xFE}, // 4E 78 N + {0x7C, 0x82, 0x82, 0x82, 0x7C}, // 4F 79 O + {0xFE, 0x12, 0x12, 0x12, 0x0C}, // 50 80 P + {0x7C, 0x82, 0xA2, 0x42, 0xBC}, // 51 81 Q + {0xFE, 0x12, 0x32, 0x52, 0x8C}, // 52 82 R + {0x4C, 0x92, 0x92, 0x92, 0x64}, // 53 83 S + {0x02, 0x02, 0xFE, 0x02, 0x02}, // 54 84 T + {0x7E, 0x80, 0x80, 0x80, 0x7E}, // 55 85 U + {0x3E, 0x40, 0x80, 0x40, 0x3E}, // 56 86 V + {0x7E, 0x80, 0x70, 0x80, 0x7E}, // 57 87 W + {0xC6, 0x28, 0x10, 0x28, 0xC6}, // 58 88 X + {0x0E, 0x10, 0xE0, 0x10, 0x0E}, // 59 89 Y + {0xC2, 0xA2, 0x92, 0x8A, 0x86}, // 5A 90 Z + {0x00, 0xFE, 0x82, 0x82, 0x00}, // 5B 91 [ + {0x04, 0x08, 0x10, 0x20, 0x40}, // 5C 92 '\' + {0x00, 0x82, 0x82, 0xFE, 0x00}, // 5D 93 ] + {0x08, 0x04, 0x02, 0x04, 0x08}, // 5E 94 ^ + {0x80, 0x80, 0x80, 0x80, 0x80}, // 5F 95 _ + {0x00, 0x02, 0x04, 0x08, 0x00}, // 60 96 ` + {0x40, 0xA8, 0xA8, 0xA8, 0xF0}, // 61 97 a + {0xFE, 0x90, 0x88, 0x88, 0x70}, // 62 98 b + {0x70, 0x88, 0x88, 0x88, 0x40}, // 63 99 c + {0x70, 0x88, 0x88, 0x90, 0xFE}, // 64 100 d + {0x70, 0xA8, 0xA8, 0xA8, 0x30}, // 65 101 e + {0x10, 0xFC, 0x12, 0x02, 0x04}, // 66 102 f + {0x10, 0xA8, 0xA8, 0xA8, 0x78}, // 67 103 g + {0xFE, 0x10, 0x08, 0x08, 0xF0}, // 68 104 h + {0x00, 0x90, 0xFA, 0x80, 0x00}, // 69 105 i + {0x40, 0x80, 0x88, 0x7A, 0x00}, // 6A 106 j + {0xFE, 0x20, 0x50, 0x88, 0x00}, // 6B 107 k + {0x00, 0x82, 0xFE, 0x80, 0x00}, // 6C 108 l + {0xF8, 0x08, 0xF0, 0x08, 0xF0}, // 6D 109 m + {0xF8, 0x10, 0x08, 0x08, 0xF0}, // 6E 110 n + {0x70, 0x88, 0x88, 0x88, 0x70}, // 6F 111 o + {0xF8, 0x28, 0x28, 0x28, 0x10}, // 70 112 p + {0x10, 0x28, 0x28, 0x30, 0xF8}, // 71 113 q + {0xF8, 0x10, 0x08, 0x08, 0x10}, // 72 114 r + {0x90, 0xA8, 0xA8, 0xA8, 0x40}, // 73 115 s + {0x08, 0x7E, 0x88, 0x80, 0x40}, // 74 116 t + {0x78, 0x80, 0x80, 0x40, 0xF8}, // 75 117 u + {0x38, 0x40, 0x80, 0x40, 0x38}, // 76 118 v + {0x78, 0x80, 0x60, 0x80, 0x78}, // 77 119 w + {0x88, 0x50, 0x20, 0x50, 0x88}, // 78 120 x + {0x18, 0xA0, 0xA0, 0xA0, 0x78}, // 79 121 y + {0x88, 0xC8, 0xA8, 0x98, 0x88}, // 7A 122 z + {0x00, 0x10, 0x6C, 0x82, 0x00}, // 7B 123 { + {0x00, 0x00, 0xFE, 0x00, 0x00}, // 7C 124 | + {0x00, 0x82, 0x6C, 0x10, 0x00}, // 7D 125 } + {0x20, 0x10, 0x10, 0x20, 0x10}, // 7E 126 ~ + {0x78, 0x44, 0x42, 0x44, 0x78}, // 7F 127 + {0xFE, 0x92, 0x92, 0x92, 0x66}, // 80 128 + {0xF0, 0x29, 0x27, 0x21, 0xFF}, // 81 129 + {0xEE, 0x10, 0xFE, 0x10, 0xEE}, // 82 130 + {0x82, 0x82, 0x92, 0x92, 0x6C}, // 83 131 + {0xFE, 0x20, 0x10, 0x08, 0xFE}, // 84 132 + {0xFC, 0x41, 0x22, 0x11, 0xFC}, // 85 133 + {0x40, 0x82, 0x7E, 0x02, 0xFE}, // 86 134 + {0xFE, 0x02, 0x02, 0x02, 0xFE}, // 87 135 + {0x8E, 0x50, 0x20, 0x10, 0x0E}, // 88 136 + {0x7E, 0x40, 0x40, 0x40, 0xFE}, // 89 137 + {0x0E, 0x10, 0x10, 0x10, 0xFE}, // 8A 138 + {0xFC, 0x80, 0xFC, 0x80, 0xFC}, // 8B 139 + {0x7E, 0x40, 0x7E, 0x40, 0xFE}, // 8C 140 + {0x02, 0xFE, 0x90, 0x90, 0x60}, // 8D 141 + {0xFE, 0x90, 0x60, 0x00, 0xFE}, // 8E 142 + {0x44, 0x92, 0x8A, 0x92, 0x7C}, // 8F 143 + {0x70, 0x88, 0x90, 0x60, 0x98}, // 90 144 + {0xC0, 0xC0, 0xFE, 0x04, 0x18}, // 91 145 + {0xFE, 0x02, 0x02, 0x02, 0x06}, // 92 146 + {0x88, 0x78, 0x08, 0xF8, 0x88}, // 93 147 + {0xC6, 0xAA, 0x92, 0x82, 0x82}, // 94 148 + {0x70, 0x88, 0x88, 0x78, 0x08}, // 95 149 + {0x60, 0x60, 0x3F, 0xC5, 0xFE}, // 96 150 + {0x10, 0x08, 0x78, 0x88, 0x04}, // 97 151 + {0x20, 0x3C, 0x7E, 0x3C, 0x20}, // 98 152 + {0x7C, 0x92, 0x92, 0x92, 0x7C}, // 99 153 + {0xB8, 0xC4, 0x04, 0xC4, 0xB8}, // 9A 154 + {0x60, 0x94, 0x8A, 0x92, 0x64}, // 9B 155 + {0x30, 0x28, 0x10, 0x28, 0x18}, // 9C 156 + {0x38, 0x7C, 0xF8, 0x7C, 0x38}, // 9D 157 + {0x50, 0xA8, 0xA8, 0x88, 0x40}, // 9E 158 + {0xFC, 0x02, 0x02, 0x02, 0xFC}, // 9F 159 + {0xFE, 0xFE, 0x00, 0xFE, 0xFE}, // A0 160 + {0x00, 0x00, 0xF2, 0x00, 0x00}, // A1 161 + {0x38, 0x44, 0xFE, 0x44, 0x20}, // A2 162 + {0x90, 0x7C, 0x92, 0x82, 0x40}, // A3 163 + {0x44, 0x38, 0x28, 0x38, 0x44}, // A4 164 + {0x2A, 0x2C, 0xF8, 0x2C, 0x2A}, // A5 165 + {0x00, 0x00, 0xEE, 0x00, 0x00}, // A6 166 + {0x40, 0x94, 0xAA, 0x52, 0x04}, // A7 167 + {0x50, 0x90, 0x7C, 0x12, 0x14}, // A8 168 + {0xFE, 0x82, 0xBA, 0x92, 0xFE}, // A9 169 + {0x90, 0xAA, 0xAA, 0xAA, 0xBC}, // AA 170 + {0x10, 0x28, 0x54, 0x28, 0x44}, // AB 171 + {0xFE, 0x10, 0x7C, 0x82, 0x7C}, // AC 172 + {0x8C, 0x52, 0x32, 0x12, 0xFE}, // AD 173 + {0xFE, 0x82, 0xCA, 0xA2, 0xFE}, // AE 174 + {0x00, 0x0C, 0x0A, 0x00, 0x00}, // AF 175 + {0x0E, 0x11, 0x11, 0x0E, 0x00}, // B0 176 + {0x88, 0x88, 0xBE, 0x88, 0x88}, // B1 177 + {0x12, 0x19, 0x15, 0x12, 0x00}, // B2 178 + {0x11, 0x15, 0x15, 0x0A, 0x00}, // B3 179 + {0x7F, 0x05, 0x25, 0xF2, 0xA0}, // B4 180 + {0xFE, 0x20, 0x20, 0x10, 0x3E}, // B5 181 + {0x0C, 0x12, 0x12, 0xFE, 0xFE}, // B6 182 + {0x00, 0x30, 0x30, 0x00, 0x00}, // B7 183 + {0x70, 0x88, 0x60, 0x88, 0x70}, // B8 184 + {0x12, 0x1F, 0x10, 0x00, 0x00}, // B9 185 + {0x9C, 0xA2, 0xA2, 0xA2, 0x9C}, // BA 186 + {0x44, 0x28, 0x54, 0x28, 0x10}, // BB 187 + {0x17, 0x68, 0x54, 0xFA, 0x41}, // BC 188 + {0x17, 0x08, 0x94, 0xCA, 0xB1}, // BD 189 + {0x15, 0x1F, 0x60, 0x50, 0xF8}, // BE 190 + {0x60, 0x90, 0x8A, 0x80, 0x40}, // BF 191 + {0xF0, 0x29, 0x26, 0x28, 0xF0}, // C0 192 + {0xF0, 0x28, 0x26, 0x29, 0xF0}, // C1 193 + {0xF0, 0x2A, 0x29, 0x2A, 0xF0}, // C2 194 + {0xF2, 0x29, 0x29, 0x2A, 0xF1}, // C3 195 + {0xF0, 0x29, 0x24, 0x29, 0xF0}, // C4 196 + {0xF0, 0x2A, 0x2D, 0x2A, 0xF0}, // C5 197 + {0xF8, 0x24, 0xFE, 0x92, 0x92}, // C6 198 + {0x1E, 0x21, 0xA1, 0xE1, 0x12}, // C7 199 + {0xF8, 0xA9, 0xAA, 0xA8, 0x88}, // C8 200 + {0xF8, 0xA8, 0xAA, 0xA9, 0x88}, // C9 201 + {0xF8, 0xAA, 0xA9, 0xAA, 0x88}, // CA 202 + {0xF8, 0xAA, 0xA8, 0xAA, 0x88}, // CB 203 + {0x00, 0x89, 0xFA, 0x88, 0x00}, // CC 204 + {0x00, 0x88, 0xFA, 0x89, 0x00}, // CD 205 + {0x00, 0x8A, 0xF9, 0x8A, 0x00}, // CE 206 + {0x00, 0x8A, 0xF8, 0x8A, 0x00}, // CF 207 + {0x10, 0xFE, 0x92, 0x82, 0x7C}, // D0 208 + {0xFA, 0x11, 0x21, 0x42, 0xF9}, // D1 209 + {0x78, 0x85, 0x86, 0x84, 0x78}, // D2 210 + {0x78, 0x84, 0x86, 0x85, 0x78}, // D3 211 + {0x70, 0x8A, 0x89, 0x8A, 0x70}, // D4 212 + {0x72, 0x89, 0x89, 0x8A, 0x71}, // D5 213 + {0x78, 0x85, 0x84, 0x85, 0x78}, // D6 214 + {0x44, 0x28, 0x10, 0x28, 0x44}, // D7 215 + {0x10, 0xAA, 0xFE, 0xAA, 0x10}, // D8 216 + {0x7C, 0x81, 0x82, 0x80, 0x7C}, // D9 217 + {0x7C, 0x80, 0x82, 0x81, 0x7C}, // DA 218 + {0x78, 0x82, 0x81, 0x82, 0x78}, // DB 219 + {0x7C, 0x81, 0x80, 0x81, 0x7C}, // DC 220 + {0x04, 0x08, 0xF2, 0x09, 0x04}, // DD 221 + {0x81, 0xFF, 0xA4, 0x24, 0x18}, // DE 222 + {0x80, 0x7C, 0x92, 0x92, 0x6C}, // DF 223 + {0x40, 0xA9, 0xAA, 0xA8, 0xF0}, // E0 224 + {0x40, 0xA8, 0xAA, 0xA9, 0xF0}, // E1 225 + {0x40, 0xAA, 0xA9, 0xAA, 0xF0}, // E2 226 + {0x42, 0xA9, 0xA9, 0xAA, 0xF1}, // E3 227 + {0x40, 0xAA, 0xA8, 0xAA, 0xF0}, // E4 228 + {0x40, 0xAA, 0xAD, 0xAA, 0xF0}, // E5 229 + {0x64, 0x94, 0x78, 0x94, 0x58}, // E6 230 + {0x18, 0xA4, 0xE4, 0x24, 0x10}, // E7 231 + {0x70, 0xA9, 0xAA, 0xA8, 0x30}, // E8 232 + {0x70, 0xA8, 0xAA, 0xA9, 0x30}, // E9 233 + {0x70, 0xAA, 0xA9, 0xAA, 0x30}, // EA 234 + {0x70, 0xAA, 0xA8, 0xAA, 0x30}, // EB 235 + {0x00, 0x91, 0xFA, 0x80, 0x00}, // EC 236 + {0x00, 0x90, 0xFA, 0x81, 0x00}, // ED 237 + {0x00, 0x92, 0xF9, 0x82, 0x00}, // EE 238 + {0x00, 0x92, 0xF8, 0x82, 0x00}, // EF 239 + {0x4A, 0xA4, 0xAA, 0xB0, 0x60}, // F0 240 + {0xFA, 0x11, 0x09, 0x0A, 0xF1}, // F1 241 + {0x70, 0x89, 0x8A, 0x88, 0x70}, // F2 242 + {0x70, 0x88, 0x8A, 0x89, 0x70}, // F3 243 + {0x60, 0x94, 0x92, 0x94, 0x60}, // F4 244 + {0x64, 0x92, 0x92, 0x94, 0x62}, // F5 245 + {0x70, 0x8A, 0x88, 0x8A, 0x70}, // F6 246 + {0x10, 0x10, 0x54, 0x10, 0x10}, // F7 247 + {0x10, 0xA8, 0x7C, 0x2A, 0x10}, // F8 248 + {0x78, 0x81, 0x82, 0x40, 0xF8}, // F9 249 + {0x78, 0x80, 0x82, 0x41, 0xF8}, // FA 250 + {0x78, 0x82, 0x81, 0x42, 0xF8}, // FB 251 + {0x78, 0x82, 0x80, 0x42, 0xF8}, // FC 252 + {0x18, 0xA0, 0xA4, 0xA2, 0x78}, // FD 253 + {0x00, 0x82, 0xFE, 0xA8, 0x10}, // FE 254 + {0x18, 0xA2, 0xA0, 0xA2, 0x78}, // FF 255 +}; \ No newline at end of file diff --git a/main/drivers/fonts.h b/main/drivers/fonts.h new file mode 100644 index 0000000..73cd830 --- /dev/null +++ b/main/drivers/fonts.h @@ -0,0 +1,4 @@ +#pragma once +#include +extern const uint8_t font5x7[256][5]; +extern const uint8_t fontHitachi[256][5]; diff --git a/main/drivers/i2c.c b/main/drivers/i2c.c new file mode 100644 index 0000000..7f5b96f --- /dev/null +++ b/main/drivers/i2c.c @@ -0,0 +1,87 @@ +#include "i2c.h" +#include "esp_err.h" +#include + +i2c_master_bus_handle_t bus; + +void i2c_init(int sda, int scl) { + i2c_master_bus_config_t cfg = { + .i2c_port = I2C_PORT, + .sda_io_num = sda, + .scl_io_num = scl, + .clk_source = I2C_CLK_SRC_DEFAULT, + .glitch_ignore_cnt = 7, + .flags.enable_internal_pullup = true, + }; + + i2c_new_master_bus(&cfg, &bus); +} + +esp_err_t i2c_write_reg(uint8_t addr, uint8_t reg, uint8_t val) { + uint8_t data[2] = {reg, val}; + + i2c_master_dev_handle_t dev; + i2c_device_config_t dev_cfg = { + .device_address = addr, + .scl_speed_hz = 400000, + }; + + i2c_master_bus_add_device(bus, &dev_cfg, &dev); + + esp_err_t r = i2c_master_transmit(dev, data, 2, -1); + + i2c_master_bus_rm_device(dev); + return r; +} + +esp_err_t i2c_read_reg(uint8_t addr, uint8_t reg, uint8_t *val) { + i2c_master_dev_handle_t dev; + i2c_device_config_t dev_cfg = { + .device_address = addr, + .scl_speed_hz = 400000, + }; + + i2c_master_bus_add_device(bus, &dev_cfg, &dev); + + i2c_master_transmit_receive(dev, ®, 1, val, 1, -1); + + i2c_master_bus_rm_device(dev); + return ESP_OK; +} + +esp_err_t i2c_read_multi(uint8_t addr, uint8_t reg, uint8_t *buf, int len) { + i2c_master_dev_handle_t dev; + i2c_device_config_t dev_cfg = { + .device_address = addr, + .scl_speed_hz = 400000, + }; + + i2c_master_bus_add_device(bus, &dev_cfg, &dev); + + i2c_master_transmit_receive(dev, ®, 1, buf, len, -1); + + i2c_master_bus_rm_device(dev); + return ESP_OK; +} + +esp_err_t i2c_read_reg_multi(uint8_t addr, uint8_t reg, uint8_t *buf, + size_t len) { + i2c_master_dev_handle_t dev; + + i2c_device_config_t cfg = { + .device_address = addr, + .scl_speed_hz = 400000, + }; + + esp_err_t err; + + err = i2c_master_bus_add_device(bus, &cfg, &dev); + if (err != ESP_OK) + return err; + + err = i2c_master_transmit_receive(dev, ®, 1, buf, len, -1); + + i2c_master_bus_rm_device(dev); + + return err; +} \ No newline at end of file diff --git a/main/drivers/i2c.h b/main/drivers/i2c.h new file mode 100644 index 0000000..74a7b37 --- /dev/null +++ b/main/drivers/i2c.h @@ -0,0 +1,16 @@ +#pragma once + +#include "driver/i2c_master.h" + +#define I2C_PORT I2C_NUM_0 + +extern i2c_master_bus_handle_t bus; + +void i2c_init(int sda, int scl); + +esp_err_t i2c_write_reg(uint8_t addr, uint8_t reg, uint8_t val); +esp_err_t i2c_read_reg(uint8_t addr, uint8_t reg, uint8_t *val); +esp_err_t i2c_read_multi(uint8_t addr, uint8_t reg, uint8_t *buf, int len); + +esp_err_t i2c_read_reg_multi(uint8_t addr, uint8_t reg, uint8_t *buf, + size_t len); diff --git a/main/drivers/i2s.c b/main/drivers/i2s.c new file mode 100644 index 0000000..c674c1b --- /dev/null +++ b/main/drivers/i2s.c @@ -0,0 +1,34 @@ +#include "i2s.h" +#include "pins.h" + +i2s_chan_handle_t i2s_tx; +i2s_chan_handle_t i2s_rx; +void audio_i2s_init(void) { + i2s_chan_config_t cfg = + I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); + + i2s_new_channel(&cfg, &i2s_tx, &i2s_rx); + + i2s_std_config_t stdcfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(44100), + + .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, + I2S_SLOT_MODE_STEREO), + + .gpio_cfg = + { + .mclk = I2S_GPIO_UNUSED, + .bclk = AUDIO_SCLK, + .ws = AUDIO_LRCK, + .dout = AUDIO_DSDIN, + .din = AUDIO_ASDOUT, + }, + }; + + i2s_channel_init_std_mode(i2s_tx, &stdcfg); + + i2s_channel_init_std_mode(i2s_rx, &stdcfg); + + i2s_channel_enable(i2s_tx); + i2s_channel_enable(i2s_rx); +} diff --git a/main/drivers/i2s.h b/main/drivers/i2s.h new file mode 100644 index 0000000..1017371 --- /dev/null +++ b/main/drivers/i2s.h @@ -0,0 +1,7 @@ +#pragma once +#include "driver/i2s_std.h" +#include "driver/i2s_types.h" + +extern i2s_chan_handle_t i2s_tx; +extern i2s_chan_handle_t i2s_rx; +void audio_i2s_init(void); diff --git a/main/drivers/irled.c b/main/drivers/irled.c new file mode 100644 index 0000000..d4d10bf --- /dev/null +++ b/main/drivers/irled.c @@ -0,0 +1,39 @@ +#include "driver/ledc.h" +#include "pins.h" + +#define LEDC_TIMER LEDC_TIMER_0 +#define LEDC_MODE LEDC_LOW_SPEED_MODE +#define LEDC_CHANNEL LEDC_CHANNEL_0 +#define LEDC_DUTY_RES LEDC_TIMER_8_BIT + +void ir_pwm_init() { + ledc_timer_config_t timer = { + .speed_mode = LEDC_MODE, + .timer_num = LEDC_TIMER, + .duty_resolution = LEDC_DUTY_RES, + .freq_hz = 38000, + .clk_cfg = LEDC_AUTO_CLK + }; + ledc_timer_config(&timer); + + ledc_channel_config_t channel = { + .speed_mode = LEDC_MODE, + .channel = LEDC_CHANNEL, + .timer_sel = LEDC_TIMER, + .gpio_num = IR_LED, + .duty = 0, + .hpoint = 0 + }; + ledc_channel_config(&channel); +} + +void ir_carrier_on() { + // ~50% duty cycle (strong IR signal) + ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 128); + ledc_update_duty(LEDC_MODE, LEDC_CHANNEL); +} + +void ir_carrier_off() { + ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0); + ledc_update_duty(LEDC_MODE, LEDC_CHANNEL); +} \ No newline at end of file diff --git a/main/drivers/irled.h b/main/drivers/irled.h new file mode 100644 index 0000000..2831737 --- /dev/null +++ b/main/drivers/irled.h @@ -0,0 +1,7 @@ +#pragma once + +void ir_pwm_init(); + +void ir_carrier_on(); + +void ir_carrier_off(); \ No newline at end of file diff --git a/main/drivers/pins.c b/main/drivers/pins.c new file mode 100644 index 0000000..6243cff --- /dev/null +++ b/main/drivers/pins.c @@ -0,0 +1,33 @@ +#include "pins.h" +#include "driver/gpio.h" +void set_pin_dirs() { + gpio_set_direction(WS2812_PIN, GPIO_MODE_OUTPUT); + gpio_set_direction(BUTTON_BACK, GPIO_MODE_INPUT); + gpio_set_direction(LCD_BACKLIGHT_AND_RGB_POWER, GPIO_MODE_OUTPUT); + gpio_set_direction(LCD_RESET, GPIO_MODE_OUTPUT); + gpio_set_direction(LCD_RS, GPIO_MODE_OUTPUT); + gpio_set_direction(LCD_DAT, GPIO_MODE_OUTPUT); + gpio_set_direction(LCD_SCK, GPIO_MODE_OUTPUT); + gpio_set_direction(LCD_CS, GPIO_MODE_OUTPUT); + // gpio_set_direction(BUS_I2C_SDA , GPIO_MODE_); + // gpio_set_direction(BUS_I2C_SCL , GPIO_MODE_); + // gpio_set_direction(SIDE_PORT_A , GPIO_MODE_); + // gpio_set_direction(SIDE_PORT_B , GPIO_MODE_); + gpio_set_direction(AUDIO_SCLK, GPIO_MODE_OUTPUT); + gpio_set_direction(AUDIO_ASDOUT, GPIO_MODE_INPUT); + gpio_set_direction(AUDIO_LRCK, GPIO_MODE_OUTPUT); + gpio_set_direction(AUDIO_DSDIN, GPIO_MODE_OUTPUT); + gpio_set_direction(KEYBOARD_INT, GPIO_MODE_INPUT); + gpio_set_direction(IR_LED, GPIO_MODE_OUTPUT); + gpio_set_direction(BATTERY_ADC, GPIO_MODE_INPUT); + gpio_set_direction(MICROSD_CS, GPIO_MODE_OUTPUT); + gpio_set_direction(MICROSD_MOSI, GPIO_MODE_OUTPUT); + gpio_set_direction(MICROSD_CLK, GPIO_MODE_OUTPUT); + gpio_set_direction(MICROSD_MISO, GPIO_MODE_INPUT); + gpio_set_direction(HEADER_RESET, GPIO_MODE_OUTPUT); + gpio_set_direction(HEADER_INT, GPIO_MODE_INPUT); + gpio_set_direction(HEADER_BUSY, GPIO_MODE_INPUT); + gpio_set_direction(HEADER_CS, GPIO_MODE_OUTPUT); + gpio_set_direction(HEADER_UART_RX, GPIO_MODE_INPUT); + gpio_set_direction(HEADER_UART_TX, GPIO_MODE_OUTPUT); +} \ No newline at end of file diff --git a/main/drivers/pins.h b/main/drivers/pins.h new file mode 100644 index 0000000..a88c466 --- /dev/null +++ b/main/drivers/pins.h @@ -0,0 +1,57 @@ +#pragma once +#include "soc/gpio_num.h" + +#define WS2812_PIN GPIO_NUM_21 +#define BUTTON_BACK GPIO_NUM_0 + +#define LCD_BACKLIGHT_AND_RGB_POWER GPIO_NUM_38 +#define LCD_RESET GPIO_NUM_33 +#define LCD_RS GPIO_NUM_34 +#define LCD_DAT GPIO_NUM_35 +#define LCD_SCK GPIO_NUM_36 +#define LCD_CS GPIO_NUM_37 + +#define BUS_I2C_SDA GPIO_NUM_8 +#define BUS_I2C_SCL GPIO_NUM_9 + +// audio ic is an es8311 +// class d pa(not controlled) is ns415db +#define AUDIO_SCLK GPIO_NUM_41 +#define AUDIO_ASDOUT GPIO_NUM_46 +#define AUDIO_LRCK GPIO_NUM_43 +#define AUDIO_DSDIN GPIO_NUM_42 + +// imu is bmi270 +#define IMU_I2C_ADDRESS 0x69 +// the keyboard is tca8418 +#define KEYBOARD_I2C_ADDRESS 0x34 +#define ES8311_I2C_ADDR 0x18 +#define KEYBOARD_INT GPIO_NUM_11 +// uses the i2c bus + +#define IR_LED GPIO_NUM_44 + +#define BATTERY_ADC GPIO_NUM_10 + +#define MICROSD_CS GPIO_NUM_12 +#define MICROSD_MOSI GPIO_NUM_14 +#define MICROSD_CLK GPIO_NUM_40 +#define MICROSD_MISO GPIO_NUM_39 + +#define SIDE_PORT_A GPIO_NUM_1 +#define SIDE_PORT_B GPIO_NUM_2 + +#define HEADER_RESET GPIO_NUM_3 +#define HEADER_INT GPIO_NUM_4 +#define HEADER_BUSY GPIO_NUM_6 +/* +#define HEADER_SCK GPIO_NUM_40 +#define HEADER_MOSI GPIO_NUM_14 +#define HEADER_MISO GPIO_NUM_39 +*/ +#define HEADER_CS GPIO_NUM_5 +// also has i2c bus +#define HEADER_UART_RX GPIO_NUM_13 +#define HEADER_UART_TX GPIO_NUM_15 + +void set_pin_dirs(); diff --git a/main/drivers/sdcard.c b/main/drivers/sdcard.c new file mode 100644 index 0000000..e208edb --- /dev/null +++ b/main/drivers/sdcard.c @@ -0,0 +1,57 @@ +#include "driver/sdspi_host.h" +#include "driver/spi_common.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_vfs_fat.h" +#include "sdmmc_cmd.h" +#include "pins.h" + +static const char *TAG = "sdspi"; + +static sdmmc_card_t *card = NULL; + +void initSD(void) { + esp_err_t ret; + + // FAT mount config + esp_vfs_fat_sdmmc_mount_config_t mount_config = { + .format_if_mount_failed = false, + .max_files = 5, + .allocation_unit_size = 16 * 1024}; + + // SPI host (this is correct for SDSPI) + sdmmc_host_t host = SDSPI_HOST_DEFAULT(); + + // SPI bus config + spi_bus_config_t bus_cfg = {.mosi_io_num = MICROSD_MOSI, + .miso_io_num = MICROSD_MISO, + .sclk_io_num = MICROSD_CLK, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = 4000}; + + ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "SPI bus init failed: %s", esp_err_to_name(ret)); + return; + } + + // SD card device config (CS pin lives here) + sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); + slot_config.gpio_cs = MICROSD_CS; + slot_config.host_id = host.slot; + + // Mount filesystem + ret = + esp_vfs_fat_sdspi_mount("/sd", &host, &slot_config, &mount_config, &card); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "SD mount failed: %s", esp_err_to_name(ret)); + spi_bus_free(host.slot); + return; + } + + ESP_LOGI(TAG, "SD card mounted successfully"); + + // Optional: print card info + sdmmc_card_print_info(stdout, card); +} \ No newline at end of file diff --git a/main/drivers/sdcard.h b/main/drivers/sdcard.h new file mode 100644 index 0000000..c3fd3e1 --- /dev/null +++ b/main/drivers/sdcard.h @@ -0,0 +1,3 @@ +#pragma once + +void initSD(void); \ No newline at end of file diff --git a/main/drivers/spi.c b/main/drivers/spi.c new file mode 100644 index 0000000..e69de29 diff --git a/main/drivers/spi.h b/main/drivers/spi.h new file mode 100644 index 0000000..7b9637e --- /dev/null +++ b/main/drivers/spi.h @@ -0,0 +1 @@ +#pragma once \ No newline at end of file diff --git a/main/drivers/st7789.c b/main/drivers/st7789.c new file mode 100644 index 0000000..18fd961 --- /dev/null +++ b/main/drivers/st7789.c @@ -0,0 +1,291 @@ +#include "st7789.h" + +#include "driver/gpio.h" +#include "driver/spi_master.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "string.h" + +#include "fonts.h" +#include "pins.h" +#include + +static spi_device_handle_t lcd_spi; + +/* ---------------- LOW LEVEL SPI ---------------- */ + +static void spi_tx(const void *data, size_t len) { + spi_transaction_t t = { + .length = len * 8, + .tx_buffer = data, + .flags = 0, + }; + spi_device_transmit(lcd_spi, &t); +} + +void st7789_write_cmd(uint8_t cmd) { + gpio_set_level(LCD_RS, 0); + spi_tx(&cmd, 1); +} + +void st7789_write_data(const void *data, size_t len) { + gpio_set_level(LCD_RS, 1); + spi_tx(data, len); +} + +/* commands */ + +/* ---------------- WINDOW ---------------- */ + +void st7789_set_window(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye) { + uint8_t data[4]; + + st7789_write_cmd(0x2A); + data[0] = (xs + X_OFFSET) >> 8; + data[1] = (xs + X_OFFSET) & 0xFF; + data[2] = (xe + X_OFFSET) >> 8; + data[3] = (xe + X_OFFSET) & 0xFF; + st7789_write_data(data, 4); + + st7789_write_cmd(0x2B); + data[0] = (ys + Y_OFFSET) >> 8; + data[1] = (ys + Y_OFFSET) & 0xFF; + data[2] = (ye + Y_OFFSET) >> 8; + data[3] = (ye + Y_OFFSET) & 0xFF; + st7789_write_data(data, 4); + + st7789_write_cmd(0x2C); +} + +/* ---------------- PIXELS ---------------- */ + +void st7789_push_pixels(const uint16_t *pixels, size_t count) { + gpio_set_level(LCD_RS, 1); + + const uint8_t *data = (const uint8_t *)pixels; + size_t bytes = count * 2; + + while (bytes > 0) { + size_t chunk = (bytes > SPI_MAX_CHUNK) ? SPI_MAX_CHUNK : bytes; + + spi_transaction_t t = { + .length = chunk * 8, + .tx_buffer = data, + .flags = 0, + }; + + spi_device_transmit(lcd_spi, &t); + + data += chunk; + bytes -= chunk; + } +} + +/* ---------------- INIT ---------------- */ + +static void st7789_reset(void) { + gpio_set_level(LCD_RESET, 0); + vTaskDelay(pdMS_TO_TICKS(20)); + gpio_set_level(LCD_RESET, 1); + vTaskDelay(pdMS_TO_TICKS(120)); +} + +void st7789_init(void) { + gpio_config_t io = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = (1ULL << LCD_RS) | (1ULL << LCD_RESET) | (1ULL << LCD_CS), + }; + gpio_config(&io); + + spi_bus_config_t buscfg = { + .mosi_io_num = LCD_DAT, + .miso_io_num = -1, + .sclk_io_num = LCD_SCK, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + }; + + spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO); + + spi_device_interface_config_t devcfg = { + .clock_speed_hz = 40000000, + .mode = 0, + .spics_io_num = LCD_CS, + .queue_size = 1, + }; + + spi_bus_add_device(SPI3_HOST, &devcfg, &lcd_spi); + + st7789_reset(); + + st7789_write_cmd(0x01); // SWRESET + vTaskDelay(pdMS_TO_TICKS(150)); + + st7789_write_cmd(0x11); // SLPOUT + vTaskDelay(pdMS_TO_TICKS(120)); + + uint8_t colmod = 0x55; // RGB565 stable + st7789_write_cmd(0x3A); + st7789_write_data(&colmod, 1); + + uint8_t madctl = 0x70; // typical working orientation (adjust if needed) + st7789_write_cmd(0x36); + st7789_write_data(&madctl, 1); + + st7789_write_cmd(0x21); // INVERT ON (fixes many panels) + + st7789_write_cmd(0x29); // DISPON + vTaskDelay(pdMS_TO_TICKS(20)); +} + +/*rendering*/ + +uint16_t framebuffer[LCD_WIDTH * LCD_HEIGHT]; + +static uint16_t fb_dirty_x0 = LCD_WIDTH; +static uint16_t fb_dirty_y0 = LCD_HEIGHT; +static uint16_t fb_dirty_x1 = 0; +static uint16_t fb_dirty_y1 = 0; + +static inline void fb_mark_dirty(uint16_t x, uint16_t y) { + if (x < fb_dirty_x0) + fb_dirty_x0 = x; + if (y < fb_dirty_y0) + fb_dirty_y0 = y; + if (x > fb_dirty_x1) + fb_dirty_x1 = x; + if (y > fb_dirty_y1) + fb_dirty_y1 = y; +} + +void fb_set_pixel(uint16_t x, uint16_t y, uint16_t color) { + if (x >= LCD_WIDTH || y >= LCD_HEIGHT) + return; + + framebuffer[y * LCD_WIDTH + x] = color; + fb_mark_dirty(x, y); +} + +void st7789_flush_full(void) { + st7789_set_window(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1); + st7789_push_pixels(framebuffer, LCD_WIDTH * LCD_HEIGHT); +} + +void st7789_flush(void) { + if (fb_dirty_x1 < fb_dirty_x0 || fb_dirty_y1 < fb_dirty_y0) + return; // nothing changed + + uint16_t x0 = fb_dirty_x0; + uint16_t y0 = fb_dirty_y0; + uint16_t x1 = fb_dirty_x1; + uint16_t y1 = fb_dirty_y1; + + st7789_set_window(x0, y0, x1, y1); + + for (uint16_t y = y0; y <= y1; y++) { + st7789_push_pixels(&framebuffer[y * LCD_WIDTH + x0], (x1 - x0 + 1)); + } + + // reset dirty region + fb_dirty_x0 = LCD_WIDTH; + fb_dirty_y0 = LCD_HEIGHT; + fb_dirty_x1 = 0; + fb_dirty_y1 = 0; +} + +/* ---------------- DRAWING ---------------- */ + +void st7789_fill(uint16_t color) { + for (int i = 0; i < LCD_WIDTH * LCD_HEIGHT; i++) + framebuffer[i] = color; +} + +void st7789_fill_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, + uint16_t color) { + for (uint16_t yy = 0; yy < h; yy++) { + for (uint16_t xx = 0; xx < w; xx++) { + fb_set_pixel(x + xx, y + yy, color); + } + } +} + +void st7789_draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, + uint16_t color) { + if (w == 0 || h == 0) + return; + + uint16_t x2 = x + w - 1; + uint16_t y2 = y + h - 1; + + // top + bottom + for (uint16_t i = x; i <= x2; i++) { + fb_set_pixel(i, y, color); + fb_set_pixel(i, y2, color); + } + + // left + right + for (uint16_t j = y; j <= y2; j++) { + fb_set_pixel(x, j, color); + fb_set_pixel(x2, j, color); + } +} + +void st7789_blit_rgb565(uint16_t x, uint16_t y, uint16_t w, uint16_t h, + const uint16_t *data) { + for (uint16_t yy = 0; yy < h; yy++) { + uint16_t *dst = &framebuffer[(y + yy) * LCD_WIDTH + x]; + const uint16_t *src = &data[yy * w]; + + memcpy(dst, src, w * sizeof(uint16_t)); + } + + fb_mark_dirty(x, y); + fb_mark_dirty(x + w - 1, y + h - 1); +} + +/* ---------------- TEXT ---------------- */ + +void st7789_draw_char(uint16_t x, uint16_t y, char c, uint16_t fg, uint16_t bg, + bool drawBG, const uint8_t font[][5]) { + if (c < 32 || c > 127) + return; + + const uint8_t *glyph = font[(uint8_t) c]; + + for (uint16_t xx = 0; xx < 5; xx++) { + uint8_t col = glyph[xx]; + + for (uint16_t yy = 0; yy < 8; yy++) { + uint16_t px = x + xx; + uint16_t py = y + yy; + + if (col & (1 << yy)) { + fb_set_pixel(px, py, fg); + } else { + if (drawBG) { // TRANSPARENT + fb_set_pixel(px, py, bg); + } + } + } + } + + fb_mark_dirty(x, y); + fb_mark_dirty(x + 5, y + 7); +} + +void st7789_draw_string(uint16_t xOld, uint16_t yOld, const char *s, + uint16_t fg, uint16_t bg, bool drawBG, const uint8_t font[][5]) { + uint16_t x = xOld; + uint16_t y = yOld; + while (*s) { + if (*s == '\n') { + y += 5; + x = xOld; + s++; + continue; + } + st7789_draw_char(x, y, *s, fg, bg, drawBG, font); + x += 6; + s++; + } +} \ No newline at end of file diff --git a/main/drivers/st7789.h b/main/drivers/st7789.h new file mode 100644 index 0000000..8210391 --- /dev/null +++ b/main/drivers/st7789.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +#define LCD_WIDTH 240 +#define LCD_HEIGHT 135 + +#define X_OFFSET 40 +#define Y_OFFSET 53 + +#define SPI_MAX_CHUNK 4092 + +extern uint16_t framebuffer[LCD_WIDTH * LCD_HEIGHT]; + +void st7789_write_cmd(uint8_t cmd); +void st7789_write_data(const void *data, size_t len); +void st7789_set_window(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye); +void st7789_push_pixels(const uint16_t *pixels, size_t count); +void st7789_init(void); + +void fb_set_pixel(uint16_t x, uint16_t y, uint16_t color); + +void st7789_flush_full(void); + +void st7789_flush(void); + +void st7789_fill(uint16_t color); + +void st7789_fill_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, + uint16_t color); + +void st7789_draw_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, + uint16_t color); + +void st7789_blit_rgb565(uint16_t x, uint16_t y, uint16_t w, uint16_t h, + const uint16_t *data); + +void st7789_fill(uint16_t color); + +void st7789_draw_char(uint16_t x, uint16_t y, char c, uint16_t fg, uint16_t bg, + bool drawBG, const uint8_t font[][5]); + +void st7789_draw_string(uint16_t x, uint16_t y, const char *s, uint16_t fg, + uint16_t bg, bool drawBG, const uint8_t font[][5]); diff --git a/main/drivers/tca8418.c b/main/drivers/tca8418.c new file mode 100644 index 0000000..7882619 --- /dev/null +++ b/main/drivers/tca8418.c @@ -0,0 +1,105 @@ +#include "tca8418.h" +#include "i2c.h" +#include "pins.h" +#include +#include + +KeyboardState_t keyboardState; + +void tca8418_init(void) { + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_KP_GPIO1, 0x7F); + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_KP_GPIO2, 0xFF); + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_KP_GPIO3, 0x00); + + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_CFG, + TCA8418_CFG_INT_ENABLE | TCA8418_CFG_OVERFLOW_MODE); + + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_UNLOCK1, 0x00); + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_UNLOCK2, 0x00); + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_KP_LCK_TIMER, 0x00); + + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_INT_STAT, 0xFF); + memset(&keyboardState, 0, sizeof(keyboardState)); +} + +int tca8418_read(uint8_t *key, uint8_t *pressed) { + uint8_t count; + + // read event counter + i2c_read_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_KEY_LCK_EC, &count); + + count &= 0x0F; + + // no pending events + if (!count) + return 0; + + uint8_t ev; + + // reading this register POPS one FIFO event + i2c_read_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_KEY_EVENT_A, &ev); + + // bit7: + // 0 = press + // 1 = release + *pressed = ((ev & 0x80) != 0); + + // lower 7 bits = key code + *key = ev & 0x7F; + + // sanity check + if (*key >= KEYBOARD_KEYS_COUNT) + return 0; + + // clear ONLY key event interrupt + i2c_write_reg(KEYBOARD_I2C_ADDRESS, TCA8418_REG_INT_STAT, + TCA8418_INT_KEY_EVENT); + + // update key state table + keyboardState.pressedKeys[*key] = *pressed; + + // update modifier state + switch (*key) { + + case KEYBOARD_MOD_FN: + keyboardState.fnPressed = *pressed; + break; + + case KEYBOARD_MOD_ALT: + keyboardState.altPressed = *pressed; + break; + + case KEYBOARD_MOD_CTRL: + keyboardState.ctrlPressed = *pressed; + break; + + case KEYBOARD_MOD_OPT: + keyboardState.optPressed = *pressed; + break; + + case KEYBOARD_MOD_SHIFT: + keyboardState.shiftPressed = *pressed; + break; + + default: + break; + } + + return 1; +} + +char getKeyboardChar(const uint8_t code) { + if (keyboardState.shiftPressed) { + return keymap_shift[code]; + } else { + return keymap_normal[code]; + } +} + +const char *getKeyboardKeyName(const uint8_t code) { + if (keyboardState.shiftPressed) { + return keymap_shift_name[code]; + } else { + return keymap_normal_name[code]; + } +} \ No newline at end of file diff --git a/main/drivers/tca8418.h b/main/drivers/tca8418.h new file mode 100644 index 0000000..b0ed3ca --- /dev/null +++ b/main/drivers/tca8418.h @@ -0,0 +1,459 @@ +#pragma once +// --- System registers --- +#include +#define TCA8418_REG_CFG 0x01 +#define TCA8418_REG_INT_STAT 0x02 +#define TCA8418_REG_KEY_LCK_EC 0x03 +#define TCA8418_REG_KEY_EVENT_A 0x04 +#define TCA8418_REG_KEY_EVENT_B 0x05 +#define TCA8418_REG_KEY_EVENT_C 0x06 +#define TCA8418_REG_KEY_EVENT_D 0x07 +#define TCA8418_REG_KEY_EVENT_E 0x08 +#define TCA8418_REG_KEY_EVENT_F 0x09 +#define TCA8418_REG_KEY_EVENT_G 0x0A +#define TCA8418_REG_KEY_EVENT_H 0x0B +#define TCA8418_REG_KEY_EVENT_I 0x0C +#define TCA8418_REG_KEY_EVENT_J 0x0D +#define TCA8418_REG_KP_LCK_TIMER 0x0E +#define TCA8418_REG_UNLOCK1 0x0F +#define TCA8418_REG_UNLOCK2 0x10 +#define TCA8418_REG_GPIO_INT_STAT1 0x11 +#define TCA8418_REG_GPIO_INT_STAT2 0x12 +#define TCA8418_REG_GPIO_INT_STAT3 0x13 +#define TCA8418_REG_DAT_STAT1 0x14 +#define TCA8418_REG_DAT_STAT2 0x15 +#define TCA8418_REG_DAT_STAT3 0x16 +#define TCA8418_REG_DAT_OUT1 0x17 +#define TCA8418_REG_DAT_OUT2 0x18 +#define TCA8418_REG_DAT_OUT3 0x19 +#define TCA8418_REG_GPIO_INT_EN1 0x1A +#define TCA8418_REG_GPIO_INT_EN2 0x1B +#define TCA8418_REG_GPIO_INT_EN3 0x1C +#define TCA8418_REG_KP_GPIO1 0x1D +#define TCA8418_REG_KP_GPIO2 0x1E +#define TCA8418_REG_KP_GPIO3 0x1F +#define TCA8418_REG_GPI_EM1 0x20 +#define TCA8418_REG_GPI_EM2 0x21 +#define TCA8418_REG_GPI_EM3 0x22 +#define TCA8418_REG_GPIO_DIR1 0x23 +#define TCA8418_REG_GPIO_DIR2 0x24 +#define TCA8418_REG_GPIO_DIR3 0x25 +#define TCA8418_REG_GPIO_INT_LVL1 0x26 +#define TCA8418_REG_GPIO_INT_LVL2 0x27 +#define TCA8418_REG_GPIO_INT_LVL3 0x28 +#define TCA8418_REG_DEBOUNCE_DIS1 0x29 +#define TCA8418_REG_DEBOUNCE_DIS2 0x2A +#define TCA8418_REG_DEBOUNCE_DIS3 0x2B +#define TCA8418_REG_GPIO_PULL1 0x2C +#define TCA8418_REG_GPIO_PULL2 0x2D +#define TCA8418_REG_GPIO_PULL3 0x2E + +// --- Keypad configuration --- + + +// --- Interrupt bits --- +#define TCA8418_INT_KEY_EVENT (1 << 0) +#define TCA8418_INT_GPIO (1 << 1) +#define TCA8418_INT_KP_LOCK (1 << 2) +#define TCA8418_INT_OVR_FLOW (1 << 3) +#define TCA8418_INT_CAD (1 << 4) + +// --- Config bits --- +#define TCA8418_CFG_INT_ENABLE (1 << 0) +#define TCA8418_CFG_GPIO_INT_ENABLE (1 << 1) +#define TCA8418_CFG_LOCK_INT_ENABLE (1 << 2) +#define TCA8418_CFG_OVF_INT_ENABLE (1 << 3) +#define TCA8418_CFG_INT_CFG (1 << 4) +#define TCA8418_CFG_OVERFLOW_MODE (1 << 5) +#define TCA8418_CFG_GPIO_TRACK_LOCKED (1 << 6) +#define TCA8418_CFG_AUTO_INCREMENT (1 << 7) + +void tca8418_init(void); + +int tca8418_read(uint8_t *key, uint8_t *pressed); +/* test + +key= 2 pressed +key= 3 pressed +key= 4 pressed +key=1 5 pressed +key=q 6 pressed +key= 7 pressed +key= 8 pressed + +key=a 11 pressed +key= 12 pressed +key=3 13 pressed +key=e 14 pressed +key=s 15 pressed +key=z 16 pressed +key=4 17 pressed +key=r 18 pressed + +key=5 21 pressed +key=t 22 pressed +key=f 23 pressed +key=c 24 pressed +key=6 25 pressed +key=y 26 pressed +key=g 27 pressed +key=v 28 pressed + +key=h 31 pressed +key=b 32 pressed +key=8 33 pressed +key=i 34 pressed +key=j 35 pressed +key=n 36 pressed +key=9 37 pressed +key=o 38 pressed + +key=0 41 pressed +key=p 42 pressed +key=l 43 pressed +key= 44 pressed +key= 45 pressed +key= 46 pressed +key= 47 pressed +key= 48 pressed + +key= 51 pressed +key= 52 pressed +key= 53 pressed +key= 54 pressed +key= 55 pressed +key= 56 pressed +key= 57 pressed +key= 58 pressed + +key=s 61 pressed +key=2 62 pressed +key=8 63 pressed +key=1 64 pressed +key=2 65 pressed +key=_ 66 pressed +key=s 67 pressed +key=e 68 pressed + +*/ + +typedef enum { + KEYBOARD_GPIO0 = 0, + + KEYBOARD_ESC = 1, + KEYBOARD_TAB = 2, + KEYBOARD_MOD_FN = 3, + KEYBOARD_MOD_CTRL = 4, + KEYBOARD_1 = 5, + KEYBOARD_Q = 6, + KEYBOARD_MOD_SHIFT = 7, + KEYBOARD_MOD_OPT = 8, + + KEYBOARD_2 = 11, + KEYBOARD_W = 12, + KEYBOARD_A = 13, + KEYBOARD_MOD_ALT = 14, + KEYBOARD_3 = 15, + KEYBOARD_E = 16, + KEYBOARD_S = 17, + KEYBOARD_Z = 18, + + KEYBOARD_4 = 21, + KEYBOARD_R = 22, + KEYBOARD_D = 23, + KEYBOARD_X = 24, + KEYBOARD_5 = 25, + KEYBOARD_T = 26, + KEYBOARD_F = 27, + KEYBOARD_C = 28, + + KEYBOARD_6 = 31, + KEYBOARD_Y = 32, + KEYBOARD_G = 33, + KEYBOARD_V = 34, + KEYBOARD_7 = 35, + KEYBOARD_U = 36, + KEYBOARD_H = 37, + KEYBOARD_B = 38, + + KEYBOARD_8 = 41, + KEYBOARD_I = 42, + KEYBOARD_J = 43, + KEYBOARD_N = 44, + KEYBOARD_9 = 45, + KEYBOARD_O = 46, + KEYBOARD_K = 47, + KEYBOARD_M = 48, + + KEYBOARD_0 = 51, + KEYBOARD_P = 52, + KEYBOARD_L = 53, + KEYBOARD_LEFT = 54, //also comma + KEYBOARD_UNDERSCORE = 55, + KEYBOARD_LEFT_BRACKET = 56, + KEYBOARD_UP = 57, //also semicolon + KEYBOARD_DOWN = 58, + + KEYBOARD_EQUALS = 61, + KEYBOARD_RIGHT_BRACKET = 62, + KEYBOARD_APOSTROPHE = 63, + KEYBOARD_RIGHT = 64, //also slash + KEYBOARD_BACKSPACE = 65, + KEYBOARD_BACKSLASH = 66, + KEYBOARD_RETURN = 67, + KEYBOARD_SPACE = 68 +} +KEYMAP_MAP; + +#define KEYBOARD_KEYS_COUNT 80 + +typedef enum { + KEYBOARD_SHIFT_TILDE = KEYBOARD_ESC, + KEYBOARD_SHIFT_EXCLAMATION = KEYBOARD_1, + KEYBOARD_SHIFT_AT = KEYBOARD_2, + KEYBOARD_SHIFT_HASH = KEYBOARD_3, + KEYBOARD_SHIFT_DOLLAR = KEYBOARD_4, + KEYBOARD_SHIFT_PERCENT = KEYBOARD_5, + KEYBOARD_SHIFT_POWER = KEYBOARD_6, + KEYBOARD_SHIFT_AMPERSAND = KEYBOARD_7, + KEYBOARD_SHIFT_STAR = KEYBOARD_8, + KEYBOARD_SHIFT_OPENPARETHESIS = KEYBOARD_9, + KEYBOARD_SHIFT_CLOSEPARENTHESIS = KEYBOARD_0, + KEYBOARD_SHIFT_LESS = KEYBOARD_LEFT, + KEYBOARD_SHIFT_DASH = KEYBOARD_UNDERSCORE, + KEYBOARD_SHIFT_LEFT_CURLY_BRACKET = KEYBOARD_LEFT_BRACKET, + KEYBOARD_SHIFT_COLON = KEYBOARD_UP, + KEYBOARD_SHIFT_GREATER = KEYBOARD_DOWN, + KEYBOARD_SHIFT_PLUS = KEYBOARD_EQUALS, + KEYBOARD_SHIFT_RIGHT_CURLY_BRACKET = KEYBOARD_RIGHT_BRACKET, + KEYBOARD_SHIFT_APOSTROPHES = KEYBOARD_APOSTROPHE, + KEYBOARD_SHIFT_QUESTIONMARK = KEYBOARD_LEFT, //also slash + KEYBOARD_SHIFT_DELETE = KEYBOARD_BACKSPACE, + KEYBOARD_SHIFT_PIPE = KEYBOARD_BACKSLASH, +} KEYMAP_SHIFT; + +static const char keymap_normal[] = { + [KEYBOARD_ESC] = 27, + [KEYBOARD_TAB] = '\t', + [KEYBOARD_SPACE] = ' ', + [KEYBOARD_RETURN] = '\n', + [KEYBOARD_BACKSPACE] = '\b', + + [KEYBOARD_1] = '1', + [KEYBOARD_2] = '2', + [KEYBOARD_3] = '3', + [KEYBOARD_4] = '4', + [KEYBOARD_5] = '5', + [KEYBOARD_6] = '6', + [KEYBOARD_7] = '7', + [KEYBOARD_8] = '8', + [KEYBOARD_9] = '9', + [KEYBOARD_0] = '0', + + [KEYBOARD_Q] = 'q', + [KEYBOARD_W] = 'w', + [KEYBOARD_E] = 'e', + [KEYBOARD_R] = 'r', + [KEYBOARD_T] = 't', + [KEYBOARD_Y] = 'y', + [KEYBOARD_U] = 'u', + [KEYBOARD_I] = 'i', + [KEYBOARD_O] = 'o', + [KEYBOARD_P] = 'p', + + [KEYBOARD_A] = 'a', + [KEYBOARD_S] = 's', + [KEYBOARD_D] = 'd', + [KEYBOARD_F] = 'f', + [KEYBOARD_G] = 'g', + [KEYBOARD_H] = 'h', + [KEYBOARD_J] = 'j', + [KEYBOARD_K] = 'k', + [KEYBOARD_L] = 'l', + + [KEYBOARD_Z] = 'z', + [KEYBOARD_X] = 'x', + [KEYBOARD_C] = 'c', + [KEYBOARD_V] = 'v', + [KEYBOARD_B] = 'b', + [KEYBOARD_N] = 'n', + [KEYBOARD_M] = 'm', + + [KEYBOARD_LEFT] = ',', + [KEYBOARD_RIGHT] = '/', + [KEYBOARD_UP] = ';', + [KEYBOARD_DOWN] = '.', + + [KEYBOARD_UNDERSCORE] = '-', + [KEYBOARD_EQUALS] = '=', + [KEYBOARD_LEFT_BRACKET] = '[', + [KEYBOARD_RIGHT_BRACKET] = ']', + [KEYBOARD_APOSTROPHE] = '\'', + [KEYBOARD_BACKSLASH] = '\\', +}; + +static const char keymap_shift[] = { + [KEYBOARD_ESC] = '~', + + [KEYBOARD_1] = '!', + [KEYBOARD_2] = '@', + [KEYBOARD_3] = '#', + [KEYBOARD_4] = '$', + [KEYBOARD_5] = '%', + [KEYBOARD_6] = '^', + [KEYBOARD_7] = '&', + [KEYBOARD_8] = '*', + [KEYBOARD_9] = '(', + [KEYBOARD_0] = ')', + + [KEYBOARD_Q] = 'Q', + [KEYBOARD_W] = 'W', + [KEYBOARD_E] = 'E', + [KEYBOARD_R] = 'R', + [KEYBOARD_T] = 'T', + [KEYBOARD_Y] = 'Y', + [KEYBOARD_U] = 'U', + [KEYBOARD_I] = 'I', + [KEYBOARD_O] = 'O', + [KEYBOARD_P] = 'P', + + [KEYBOARD_A] = 'A', + [KEYBOARD_S] = 'S', + [KEYBOARD_D] = 'D', + [KEYBOARD_F] = 'F', + [KEYBOARD_G] = 'G', + [KEYBOARD_H] = 'H', + [KEYBOARD_J] = 'J', + [KEYBOARD_K] = 'K', + [KEYBOARD_L] = 'L', + + [KEYBOARD_Z] = 'Z', + [KEYBOARD_X] = 'X', + [KEYBOARD_C] = 'C', + [KEYBOARD_V] = 'V', + [KEYBOARD_B] = 'B', + [KEYBOARD_N] = 'N', + [KEYBOARD_M] = 'M', + + [KEYBOARD_LEFT] = '<', + [KEYBOARD_RIGHT] = '?', + [KEYBOARD_UP] = ':', + [KEYBOARD_DOWN] = '>', + + [KEYBOARD_UNDERSCORE] = '_', + [KEYBOARD_EQUALS] = '+', + [KEYBOARD_LEFT_BRACKET] = '{', + [KEYBOARD_RIGHT_BRACKET] = '}', + [KEYBOARD_APOSTROPHE] = '"', + [KEYBOARD_BACKSLASH] = '|', +}; + +static const char * keymap_normal_name[] = { + [KEYBOARD_ESC] = "ESC", + [KEYBOARD_TAB] = "TAB", + [KEYBOARD_SPACE] = "SPACE", + [KEYBOARD_MOD_FN] = "FN", + [KEYBOARD_MOD_CTRL] = "CTRL", + [KEYBOARD_MOD_SHIFT] = "SHIFT", + [KEYBOARD_MOD_OPT] = "OPT", + [KEYBOARD_MOD_ALT] = "ALT", + + [KEYBOARD_LEFT] = ",", + [KEYBOARD_RIGHT] = "/", + [KEYBOARD_UP] = ";", + [KEYBOARD_DOWN] = ".", + + [KEYBOARD_UNDERSCORE] = "-", + [KEYBOARD_EQUALS] = "=", + [KEYBOARD_LEFT_BRACKET] = "[", + [KEYBOARD_RIGHT_BRACKET] = "]", + [KEYBOARD_APOSTROPHE] = "'", + [KEYBOARD_BACKSLASH] = "\\", + + [KEYBOARD_SHIFT_DELETE] = "DELETE", + [KEYBOARD_RETURN] = "RETURN", + + [KEYBOARD_1] = "1", + [KEYBOARD_2] = "2", + [KEYBOARD_3] = "3", + [KEYBOARD_4] = "4", + [KEYBOARD_5] = "5", + [KEYBOARD_6] = "6", + [KEYBOARD_7] = "7", + [KEYBOARD_8] = "8", + [KEYBOARD_9] = "9", + [KEYBOARD_0] = "0", + + [KEYBOARD_Q] = "q", + [KEYBOARD_W] = "w", + [KEYBOARD_E] = "e", + [KEYBOARD_R] = "r", + [KEYBOARD_T] = "t", + [KEYBOARD_Y] = "y", + [KEYBOARD_U] = "u", + [KEYBOARD_I] = "i", + [KEYBOARD_O] = "o", + [KEYBOARD_P] = "p", + + [KEYBOARD_A] = "a", + [KEYBOARD_S] = "s", + [KEYBOARD_D] = "d", + [KEYBOARD_F] = "f", + [KEYBOARD_G] = "g", + [KEYBOARD_H] = "h", + [KEYBOARD_J] = "j", + [KEYBOARD_K] = "k", + [KEYBOARD_L] = "l", + + [KEYBOARD_Z] = "z", + [KEYBOARD_X] = "x", + [KEYBOARD_C] = "c", + [KEYBOARD_V] = "v", + [KEYBOARD_B] = "b", + [KEYBOARD_N] = "n", + [KEYBOARD_M] = "m", +}; + +static const char * keymap_shift_name[] = { + [KEYBOARD_ESC] = "~", + + [KEYBOARD_1] = "!", + [KEYBOARD_2] = "@", + [KEYBOARD_3] = "#", + [KEYBOARD_4] = "$", + [KEYBOARD_5] = "%", + [KEYBOARD_6] = "^", + [KEYBOARD_7] = "&", + [KEYBOARD_8] = "*", + [KEYBOARD_9] = "(", + [KEYBOARD_0] = ")", + + [KEYBOARD_LEFT] = "<", + [KEYBOARD_RIGHT] = "?", + [KEYBOARD_UP] = ":", + [KEYBOARD_DOWN] = ">", + + [KEYBOARD_UNDERSCORE] = "_", + [KEYBOARD_EQUALS] = "+", + [KEYBOARD_LEFT_BRACKET] = "{", + [KEYBOARD_RIGHT_BRACKET] = "}", + [KEYBOARD_APOSTROPHE] = "\"", + [KEYBOARD_BACKSLASH] = "|", +}; + + +typedef struct { + bool fnPressed; + bool ctrlPressed; + bool shiftPressed; + bool altPressed; + bool optPressed; + //for convenience + bool pressedKeys[KEYBOARD_KEYS_COUNT]; +} KeyboardState_t; + +extern KeyboardState_t keyboardState; + +char getKeyboardChar(const uint8_t code); + +const char * getKeyboardKeyName(const uint8_t code); \ No newline at end of file diff --git a/main/drivers/ws2812.c b/main/drivers/ws2812.c new file mode 100644 index 0000000..8ada61f --- /dev/null +++ b/main/drivers/ws2812.c @@ -0,0 +1,50 @@ +#include "ws2812.h" +#include "esp_log_level.h" +#include "led_strip.h" +#include "pins.h" +#include +#include + +led_strip_handle_t led_strip; +void ws2812_init() { + /// LED strip common configuration + led_strip_config_t strip_config = { + .strip_gpio_num = + WS2812_PIN, // The GPIO that connected to the LED strip's data line + .max_leds = 1, // The number of LEDs in the strip, + .led_model = + LED_MODEL_WS2812, // LED strip model, it determines the bit timing + .color_component_format = + LED_STRIP_COLOR_COMPONENT_FMT_GRB, // The color component format is + // G-R-B + .flags = { + .invert_out = false, // don't invert the output signal + }}; + + /// RMT backend specific configuration + led_strip_rmt_config_t rmt_config = { + .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to + // different power consumption + .resolution_hz = 10 * 1000 * 1000, // RMT counter clock frequency: 10MHz + .mem_block_symbols = + 64, // the memory size of each RMT channel, in words (4 bytes) + .flags = { + .with_dma = + false, // DMA feature is available on chips like ESP32-S3/P4 + }}; + + /// Create the LED strip object + ESP_ERROR_CHECK( + led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); + + if (!led_strip) { + printf("LED strip init failed!\n"); + } else { + printf("LED string init done\n"); + } +} + +void ws2812_send_rgb(uint8_t r, uint8_t g, uint8_t b) { + ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, 0, r, g, b)); + ESP_ERROR_CHECK(led_strip_refresh(led_strip)); +} \ No newline at end of file diff --git a/main/drivers/ws2812.h b/main/drivers/ws2812.h new file mode 100644 index 0000000..653d08d --- /dev/null +++ b/main/drivers/ws2812.h @@ -0,0 +1,6 @@ +#pragma once + +#include +void ws2812_init(); + +void ws2812_send_rgb(uint8_t r, uint8_t g, uint8_t b); diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 0000000..512ed94 --- /dev/null +++ b/main/idf_component.yml @@ -0,0 +1,18 @@ +## IDF Component Manager Manifest File +dependencies: + ## Required IDF version + idf: + version: '>=4.1.0' + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true + espressif/esp_tinyusb: ~2.2.0 + espressif/led_strip: ^3.0.0 diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..093af4c --- /dev/null +++ b/main/main.c @@ -0,0 +1,99 @@ +#include +#include + +#include "driver/gpio.h" +#include "drivers/fonts.h" +#include "drivers/i2c.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "drivers/battery.h" +#include "drivers/pins.h" + +#include "drivers/bmi270.h" +#include "drivers/es8311.h" +#include "drivers/sdcard.h" +#include "drivers/irled.h" +#include "drivers/i2s.h" +#include "drivers/st7789.h" +#include "drivers/tca8418.h" +#include "drivers/ws2812.h" +#include "hal/gpio_types.h" +#include "projdefs.h" + +void app_main(void) { + set_pin_dirs(); + printf("boot\n"); + battery_start_task(); + + gpio_set_level(LCD_BACKLIGHT_AND_RGB_POWER, 1); + + gpio_set_level(IR_LED, 0); + + i2c_init(BUS_I2C_SDA, BUS_I2C_SCL); + + + ws2812_init(); + st7789_init(); + bmi270_init(); + es8311_init(); + tca8418_init(); + initSD(); + ir_pwm_init(); + ir_carrier_off(); + + st7789_fill(0xFFFF); + st7789_fill_rect(1, 1, LCD_WIDTH - 2, LCD_HEIGHT - 2, 0x0000); + + st7789_flush_full(); + + st7789_flush(); + + ws2812_send_rgb(255, 255, 255); + + /* + static int16_t micbuf[512]; + + audio_read(micbuf, 512); + + audio_write(micbuf, 512); + + + */ + audio_beep(); + + while (1) { + + // keyboard + uint8_t key; + uint8_t pressed; + + char buf[64]; + st7789_fill_rect(1, 1, LCD_WIDTH - 2, LCD_HEIGHT - 2, 0x0000); + st7789_draw_string(10, 10, "CARDPUTER TEST", 0xFFFF, 0x0000, false, font5x7); + while (tca8418_read(&key, &pressed)) { + + snprintf(buf, sizeof(buf), "key=%c %s %d %s", getKeyboardChar(key), + getKeyboardKeyName(key), key, pressed ? "pressed" : "released"); + printf("%s\n", buf); + + st7789_draw_string(30, 30, buf, 0x07E0, 0x0000, true, fontHitachi); + } + bmi270_data_t bmiData; + + bmi270_read(&bmiData); + + snprintf(buf, sizeof(buf), "acc %d %d %d gyro %d %d %d\n", + bmiData.ax, bmiData.ay, bmiData.az, + bmiData.gx, bmiData.gy, bmiData.gz); + + st7789_draw_string(30, 60, buf, 0x07E0, 0x0000, true, fontHitachi); + + + snprintf(buf, sizeof(buf), "Battery: %d%%(%.3fV)", getBatteryPercentage(), getBatteryVoltage()); + st7789_draw_string(100, 10, buf, 0x07E0, 0x0000, true, fontHitachi); + st7789_flush(); + + vTaskDelay(pdMS_TO_TICKS(20)); //50 fps max + } +} \ No newline at end of file