This commit is contained in:
2026-05-08 14:56:29 +02:00
commit e4a5ccb043
39 changed files with 2481 additions and 0 deletions
+28
View File
@@ -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 ".")
+153
View File
@@ -0,0 +1,153 @@
#include "hal/adc_types.h"
#include <esp_adc/adc_oneshot.h>
#include <esp_adc/adc_cali.h>
#include <esp_adc/adc_cali_scheme.h>
#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
);
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
float getBatteryVoltage();
int getBatteryPercentage();
void battery_start_task();
+40
View File
@@ -0,0 +1,40 @@
#include "bmi270.h"
#include "FreeRTOS.h"
#include "i2c.h"
#include "pins.h"
#include <stdint.h>
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]);
}
+54
View File
@@ -0,0 +1,54 @@
#pragma once
// --- Core IDs ---
#include <stdint.h>
#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);
+89
View File
@@ -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);
}
+76
View File
@@ -0,0 +1,76 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
// ----------------------
// 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);
+383
View File
@@ -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
};
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#include <stdint.h>
extern const uint8_t font5x7[256][5];
extern const uint8_t fontHitachi[256][5];
+87
View File
@@ -0,0 +1,87 @@
#include "i2c.h"
#include "esp_err.h"
#include <string.h>
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, &reg, 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, &reg, 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, &reg, 1, buf, len, -1);
i2c_master_bus_rm_device(dev);
return err;
}
+16
View File
@@ -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);
+34
View File
@@ -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);
}
+7
View File
@@ -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);
+39
View File
@@ -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);
}
+7
View File
@@ -0,0 +1,7 @@
#pragma once
void ir_pwm_init();
void ir_carrier_on();
void ir_carrier_off();
+33
View File
@@ -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);
}
+57
View File
@@ -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();
+57
View File
@@ -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);
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
void initSD(void);
View File
+1
View File
@@ -0,0 +1 @@
#pragma once
+291
View File
@@ -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 <stdint.h>
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++;
}
}
+45
View File
@@ -0,0 +1,45 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#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]);
+105
View File
@@ -0,0 +1,105 @@
#include "tca8418.h"
#include "i2c.h"
#include "pins.h"
#include <stdint.h>
#include <string.h>
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];
}
}
+459
View File
@@ -0,0 +1,459 @@
#pragma once
// --- System registers ---
#include <stdint.h>
#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);
+50
View File
@@ -0,0 +1,50 @@
#include "ws2812.h"
#include "esp_log_level.h"
#include "led_strip.h"
#include "pins.h"
#include <stdint.h>
#include <stdio.h>
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));
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <stdint.h>
void ws2812_init();
void ws2812_send_rgb(uint8_t r, uint8_t g, uint8_t b);
+18
View File
@@ -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
+99
View File
@@ -0,0 +1,99 @@
#include <stdint.h>
#include <stdio.h>
#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
}
}