diff --git a/.cproject b/.cproject index b30f521..3add275 100644 --- a/.cproject +++ b/.cproject @@ -1,17 +1,34 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/clock/CMakeLists.txt b/components/clock/CMakeLists.txt new file mode 100644 index 0000000..34a99b2 --- /dev/null +++ b/components/clock/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "clock.c" + INCLUDE_DIRS "." + REQUIRES ) \ No newline at end of file diff --git a/components/clock/clock.c b/components/clock/clock.c new file mode 100644 index 0000000..6ec8348 --- /dev/null +++ b/components/clock/clock.c @@ -0,0 +1,58 @@ +/* + * clock.c + * + * Created on: Apr 23, 2020 + * Author: chris + */ + +#include "clock.h" + +const char* TAG = "clock"; + +void time_sync_notification_cb(struct timeval *tv) +{ + ESP_LOGI(TAG, "Synchronized time to PTB!"); +} + +esp_err_t init_clock() +{ + ESP_LOGI(TAG, "Initializing SNTP"); + esp_event_loop_create_default(); + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, "ptbtime1.ptb.de"); + sntp_set_time_sync_notification_cb(time_sync_notification_cb); + sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED); + sntp_init(); + + // wait for time to be set + time_t now = 0; + struct tm timeinfo = { 0 }; + int retry = 0; + const int retry_count = 10; + while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) { + ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); + vTaskDelay(2000 / portTICK_PERIOD_MS); + } + time(&now); + localtime_r(&now, &timeinfo); + + setenv("TZ", "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", 1); + tzset(); + + return ESP_OK; +} + +void get_time(time_str_t* res) +{ + time_t now; + struct tm timeinfo; + time(&now); + localtime_r(&now, &timeinfo); + + char date_str[64]; + char time_str[64]; + strftime(date_str, sizeof(date_str), "%d.%m.%Y", &timeinfo); + strftime(time_str, sizeof(time_str), "%H:%M:%S", &timeinfo); + strcpy(res->date_str, date_str); + strcpy(res->time_str, time_str); +} diff --git a/components/clock/clock.h b/components/clock/clock.h new file mode 100644 index 0000000..e395bdf --- /dev/null +++ b/components/clock/clock.h @@ -0,0 +1,28 @@ +/* + * clock.h + * + * Created on: Apr 23, 2020 + * Author: chris + */ + +#ifndef COMPONENTS_CLOCK_CLOCK_H_ +#define COMPONENTS_CLOCK_CLOCK_H_ + +#include +#include +#include +#include +#include +#include +#include "esp_event.h" + +typedef struct { + char date_str[64]; + char time_str[64]; +} time_str_t; + +esp_err_t init_clock(); + +void get_time(time_str_t* res); + +#endif /* COMPONENTS_CLOCK_CLOCK_H_ */ diff --git a/components/display/CMakeLists.txt b/components/display/CMakeLists.txt new file mode 100644 index 0000000..c471279 --- /dev/null +++ b/components/display/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "display.c" + INCLUDE_DIRS "." + REQUIRES tft clock) \ No newline at end of file diff --git a/components/display/display.c b/components/display/display.c new file mode 100644 index 0000000..31923e5 --- /dev/null +++ b/components/display/display.c @@ -0,0 +1,347 @@ +/* + * display.c + * + * Created on: 19 Apr 2020 + * Author: Chris + */ + +#include "display.h" + +#include "tftspi.h" +#include "tft.h" + +#define SPI_BUS TFT_VSPI_HOST + +typedef struct { + int datetimeW; + int datetimeA; + int dateTimeLeft; + int datetimeBaseline; + int innenW; + int aussenW; + int locA; + int tempW; + int degCW; + int tempA; + int humW; + int percentW; + int humA; + int pressW; + int pressA; + int hpaW; + int datetimebarH; + int margin; + int borderVMargin; + int innenBaseline; + int aussenBaseline; + int pressBaseline; + int humBaseline; + int tempBaseline; + int unitMaxW; + int unitW; + int ioW; + int unitLeft; + int innenLeft; + int aussenLeft; +} layout_t; + +static layout_t layout; + +layout_t create_layout() +{ + layout_t layout; + int screenW = tft_width; + int screenH = tft_height; + layout.datetimebarH = 20; // Can be calculated too + layout.margin = 5; + layout.borderVMargin = 10; + + TFT_setFont(SMALL_FONT, NULL); + layout.datetimebarH = 20; + layout.datetimeW = TFT_getStringWidth("25.12.2031 08:31:11"); + layout.datetimeA = TFT_getfontheight(); + layout.dateTimeLeft = (screenW - layout.datetimeW) / 2; + layout.datetimeBaseline = (layout.datetimebarH - layout.datetimeA) / 2; + + TFT_setFont(UBUNTU16_FONT, NULL); + layout.innenW = TFT_getStringWidth("Innen"); + layout.aussenW = TFT_getStringWidth("Aussen"); + layout.locA = TFT_getfontheight(); + + TFT_setFont(DEJAVU18_FONT, NULL); + layout.tempW = TFT_getStringWidth("-35.2"); + layout.degCW = TFT_getStringWidth(" C"); + layout.tempA = TFT_getfontheight(); + + TFT_setFont(UBUNTU16_FONT, NULL); + layout.humW = TFT_getStringWidth("25.2"); + layout.percentW = TFT_getStringWidth("%"); + layout.humA = TFT_getfontheight(); + + layout.pressW = TFT_getStringWidth("1281"); + layout.pressA = TFT_getfontheight(); + layout.hpaW = TFT_getStringWidth("hPa"); + + layout.innenBaseline = layout.datetimebarH + layout.borderVMargin; + layout.aussenBaseline = layout.innenBaseline; + layout.pressBaseline = screenH - layout.borderVMargin - layout.pressA; + layout.humBaseline = layout.pressBaseline - layout.pressA - layout.margin; + layout.tempBaseline = (layout.humBaseline - layout.humA + layout.innenBaseline) / 2 + + 0.5*layout.tempA - 1; + + int unitMaxW = layout.degCW; + if (layout.percentW > unitMaxW) unitMaxW = layout.percentW; + if (layout.hpaW > unitMaxW) unitMaxW = layout.hpaW; + layout.unitW = 2*layout.margin + unitMaxW; + layout.ioW = (screenW - layout.unitW) / 2; + layout.unitLeft = screenW - layout.unitW + layout.margin; + layout.innenLeft = layout.margin; + layout.aussenLeft = layout.innenLeft + layout.ioW; + + ESP_LOGI("main", "innen: %d x %d, aussen: %d x %d", layout.innenW, + layout.locA, layout.aussenW, layout.locA); + ESP_LOGI("main", "temps: %d x %d, unit: %d x %d", layout.tempW, + layout.tempA, layout.degCW, layout.tempA); + ESP_LOGI("main", "hum: %d x %d, unit: %d x %d", layout.humW, layout.humA, + layout.percentW, layout.humA); + ESP_LOGI("main", "press: %d x %d, unit: %d x %d", layout.pressW, layout.pressA, + layout.hpaW, layout.pressA); + + ESP_LOGI("main", "Baselines - innen: %d, aussen: %d, press: %d, hum: %d, temp: %d", + layout.innenBaseline, layout.aussenBaseline, + layout.pressBaseline, layout.humBaseline, layout.tempBaseline); + ESP_LOGI("main", "Width - units: %d, i/o: %d", layout.unitW, layout.ioW); + ESP_LOGI("main", "Left - units: %d", layout.unitLeft); + return layout; +} + +uint8_t interpolation(int32_t arg) { + int32_t i32_val = arg * 256 / 1000; + uint8_t u8_val = (uint8_t)i32_val; + return u8_val; +} + +color_t temp_color(int32_t temp_raw) { + color_t col = { 0 }; + if (temp_raw >= 3500) + col.r = 255; + else if (temp_raw < 3500 && temp_raw > 2500) { + int32_t diff = 3500 - temp_raw; + col.r = 255; + col.g = interpolation(diff); + } + else if (temp_raw == 2500) { + col.r = 255; + col.g = 255; + } + else if (temp_raw < 2500 && temp_raw > 1500) { + int32_t diff = temp_raw - 1500; + col.r = interpolation(diff); + col.g = 255; + } + else if (temp_raw == 1500) + col.g = 255; + else if (temp_raw < 1500 && temp_raw > 500) { + int32_t diff = 1500 - temp_raw; + col.g = 255; + col.b = interpolation(diff); + } + else if (temp_raw == 500) { + col.g = 255; + col.b = 255; + } + else if (temp_raw < 500 && temp_raw > -500) { + int32_t diff = temp_raw + 500; + col.g = interpolation(diff); + col.b = 255; + } + else if (temp_raw == -500) + col.b = 255; + else if (temp_raw < -500 && temp_raw > -1500) { + int32_t diff = -500 - temp_raw; + col.r = interpolation(diff); + col.b = 255; + } + else if (temp_raw <= -1500) { + col.r = 255; + col.b = 255; + } + return col; +} + +void print_temp1(int32_t temp_raw) +{ + // Calc temperature pre and post comma values + int32_t temp_pre = temp_raw / 100; + int32_t temp_post = (abs(temp_raw) % 100) / 10; + char temp_str[12]; + sprintf(temp_str, "% 2.2d,%.1d", temp_pre, temp_post); + + TFT_setFont(DEJAVU18_FONT, NULL); + tft_fg = temp_color(temp_raw); + TFT_print(temp_str, layout.innenLeft, layout.tempBaseline); +} + +void print_temp2(int32_t temp_raw) +{ + // Calc temperature pre and post comma values + int32_t temp_pre = temp_raw / 100; + int32_t temp_post = (abs(temp_raw) % 100) / 10; + char temp_str[12]; + sprintf(temp_str, "% 2.2d,%.1d", temp_pre, temp_post); + + TFT_setFont(DEJAVU18_FONT, NULL); + tft_fg = temp_color(temp_raw); + TFT_print(temp_str, layout.aussenLeft, layout.tempBaseline); +} + +void print_press1(uint32_t pressure_raw) +{ + // Calc pressure values + uint32_t press = pressure_raw / 100; + char press_str[12]; + sprintf(press_str, "%d", press); + TFT_setFont(UBUNTU16_FONT, NULL); + tft_fg = TFT_WHITE; + TFT_print(press_str, layout.innenLeft, layout.pressBaseline); +} + +void print_press2(uint32_t pressure_raw) +{ + // Calc pressure values + uint32_t press = pressure_raw / 100; + char press_str[12]; + sprintf(press_str, "%d", press); + TFT_setFont(UBUNTU16_FONT, NULL); + tft_fg = TFT_WHITE; + TFT_print(press_str, layout.aussenLeft, layout.pressBaseline); +} + +void print_humid1(uint32_t humidity_raw) +{ + // Calc humidity pre and post comma values + uint32_t humid_pre = humidity_raw / 1024; + uint32_t humid_post = (humidity_raw - humid_pre*1024) * 10 / 1024; + char humid_str[12]; + sprintf(humid_str, "%2.2d,%.1d", humid_pre, humid_post); + TFT_setFont(UBUNTU16_FONT, NULL); + tft_fg = TFT_WHITE; + TFT_print(humid_str, layout.innenLeft, layout.humBaseline); +} + +void print_humid2(uint32_t humidity_raw) +{ + // Calc humidity pre and post comma values + uint32_t humid_pre = humidity_raw / 1024; + uint32_t humid_post = (humidity_raw - humid_pre*1024) * 10 / 1024; + char humid_str[12]; + sprintf(humid_str, "%2.2d,%.1d", humid_pre, humid_post); + TFT_setFont(UBUNTU16_FONT, NULL); + tft_fg = TFT_WHITE; + TFT_print(humid_str, layout.aussenLeft, layout.humBaseline); +} + +void print_time(time_str_t time) +{ + TFT_setFont(SMALL_FONT, NULL); + char datetime_str[129]; + sprintf(datetime_str, "%s %s", time.date_str, time.time_str); + TFT_print(datetime_str, layout.dateTimeLeft, layout.datetimeBaseline); +} + +void display_data(int32_t temp_raw, uint32_t pressure_raw, uint32_t humidity_raw, + int32_t temp2_raw, uint32_t pressure2_raw, uint32_t humidity2_raw, + time_str_t time) +{ + // HEADER + tft_fg = TFT_WHITE; + TFT_drawFastHLine(0, 20, 160, TFT_WHITE); + + // IN OUT LABEL + TFT_setFont(UBUNTU16_FONT, NULL); + TFT_print("Innen", layout.innenLeft, layout.innenBaseline); + TFT_print("Aussen", layout.aussenLeft, layout.aussenBaseline); + + // VALUES + print_temp1(temp_raw); + print_temp2(temp2_raw); + print_humid1(humidity_raw); + print_humid2(humidity2_raw); + print_press1(pressure_raw); + print_press2(pressure2_raw); + print_time(time); + + // UNIT LABELS + TFT_setFont(DEJAVU18_FONT, NULL); + tft_fg = TFT_WHITE; + TFT_print(" C", layout.unitLeft, layout.tempBaseline); + TFT_drawCircle(layout.unitLeft+3, layout.tempBaseline+3, 3, TFT_WHITE); + TFT_setFont(UBUNTU16_FONT, NULL); + TFT_print("%", layout.unitLeft, layout.humBaseline); + TFT_print("hPa", layout.unitLeft, layout.pressBaseline); +} + +void update_data(int32_t temp_raw, uint32_t pressure_raw, uint32_t humidity_raw, + int32_t temp2_raw, uint32_t pressure2_raw, uint32_t humidity2_raw, + time_str_t time) +{ + // VALUES + print_temp1(temp_raw); + print_temp2(temp2_raw); + print_humid1(humidity_raw); + print_humid2(humidity2_raw); + print_press1(pressure_raw); + print_press2(pressure2_raw); + print_time(time); +} + +esp_err_t init_display() +{ + tft_max_rdclock = 4000000; + TFT_PinsInit(); + spi_lobo_device_handle_t spi; + + spi_lobo_bus_config_t buscfg={ + .miso_io_num=PIN_NUM_MISO, + .mosi_io_num=PIN_NUM_MOSI, + .sclk_io_num=PIN_NUM_CLK, + .quadwp_io_num=-1, + .quadhd_io_num=-1, + .max_transfer_sz = 6*1024, + }; + spi_lobo_device_interface_config_t devcfg={ + .clock_speed_hz=8000000, + .mode=0, + .spics_io_num=-1, + .spics_ext_io_num=PIN_NUM_CS, + .flags=LB_SPI_DEVICE_HALFDUPLEX, + }; + esp_err_t ret; + ret=spi_lobo_bus_add_device(SPI_BUS, &buscfg, &devcfg, &spi); + if (ret != ESP_OK) + { + return ret; + } + tft_disp_spi = spi; + + TFT_display_init(); + + tft_max_rdclock = find_rd_speed(); + + spi_lobo_set_speed(spi, DEFAULT_SPI_CLOCK); + + tft_font_rotate = 0; + tft_text_wrap = 0; + tft_font_transparent = 0; + tft_font_forceFixed = 0; + tft_gray_scale = 0; + TFT_setGammaCurve(DEFAULT_GAMMA_CURVE); + TFT_setRotation(LANDSCAPE_FLIP); + TFT_setFont(DEFAULT_FONT, NULL); + TFT_resetclipwin(); + tft_image_debug = 0; + + layout = create_layout(); + + return ESP_OK; +} diff --git a/components/display/display.h b/components/display/display.h new file mode 100644 index 0000000..8e19dbf --- /dev/null +++ b/components/display/display.h @@ -0,0 +1,25 @@ +/* + * display.h + * + * Created on: 19 Apr 2020 + * Author: Chris + */ + +#ifndef COMPONENTS_DISPLAY_DISPLAY_H_ +#define COMPONENTS_DISPLAY_DISPLAY_H_ + +#include +#include +#include +#include +#include "clock.h" + +esp_err_t init_display(); +void display_data(int32_t temp_raw, uint32_t pressure_raw, uint32_t humidity_raw, + int32_t temp2_raw, uint32_t pressure2_raw, uint32_t humidity2_raw, + time_str_t time); +void update_data(int32_t temp_raw, uint32_t pressure_raw, uint32_t humidity_raw, + int32_t temp2_raw, uint32_t pressure2_raw, uint32_t humidity2_raw, + time_str_t time); + +#endif /* COMPONENTS_DISPLAY_DISPLAY_H_ */ diff --git a/components/sensors/CMakeLists.txt b/components/sensors/CMakeLists.txt new file mode 100644 index 0000000..68a867f --- /dev/null +++ b/components/sensors/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "bme280.c" "sensors.c" + INCLUDE_DIRS "." + REQUIRES driver ) \ No newline at end of file diff --git a/main/bme280.c b/components/sensors/bme280.c similarity index 100% rename from main/bme280.c rename to components/sensors/bme280.c diff --git a/main/bme280.h b/components/sensors/bme280.h similarity index 100% rename from main/bme280.h rename to components/sensors/bme280.h diff --git a/main/bme280_defs.h b/components/sensors/bme280_defs.h similarity index 100% rename from main/bme280_defs.h rename to components/sensors/bme280_defs.h diff --git a/components/sensors/sensors.c b/components/sensors/sensors.c new file mode 100644 index 0000000..ee251c7 --- /dev/null +++ b/components/sensors/sensors.c @@ -0,0 +1,145 @@ +/* + * sensors.c + * + * Created on: 20 Apr 2020 + * Author: Chris + */ + +#include "sensors.h" + +static struct bme280_dev* dev; +static struct bme280_dev* dev2; + +void i2c_setup() +{ + printf("Setting up I2C driver on port 1... "); + i2c_config_t config; + config.mode = I2C_MODE_MASTER; + config.sda_io_num = 33; + config.sda_pullup_en = GPIO_PULLUP_ENABLE; + config.scl_io_num = 32; + config.scl_pullup_en = GPIO_PULLUP_ENABLE; + config.master.clk_speed = 100000; + i2c_param_config(I2C_NUM_0, &config); + printf("Set driver parameters... "); + esp_err_t err = i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0); + if (err == ESP_OK) + printf("Driver installed!\n"); + else if (err == ESP_ERR_INVALID_ARG) + printf("Driver install failed, invalid arguments!\n"); + else + printf("Driver install failed!\n"); +} + +int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, dev_id << 1 | I2C_MASTER_WRITE, 1); + i2c_master_write_byte(cmd, reg_addr, 1); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, dev_id << 1 | I2C_MASTER_READ, 1); + if (len > 1) { + i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK); + } + i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK); + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 500 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return 0; +} + +int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) { + //printf("Writing to bus: dev_id=%x, reg_addr=%x, data=%p, length=%u\n", dev_id, reg_addr, data, len); + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (dev_id << 1) | I2C_MASTER_WRITE, 1); + i2c_master_write_byte(cmd, reg_addr, 1); + i2c_master_write(cmd, data, len, 1); + i2c_master_stop(cmd); + i2c_master_cmd_begin(I2C_NUM_0, cmd, 500 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + return 0; +} + +void i2c_delay(uint32_t period) { + vTaskDelay(period / portTICK_PERIOD_MS); +} + +void i2c_shutdown() +{ + printf("Shutting down I�C bus... "); + esp_err_t err = i2c_driver_delete(I2C_NUM_0); + if (err == ESP_ERR_INVALID_ARG) + printf("Failed, invalid arguments!\n"); + else + printf("Success!\n"); +} + +void read_sensor(int32_t* temp, uint32_t* pressure, uint32_t* humidity) { + + uint8_t settings_sel; + uint32_t req_delay; + struct bme280_data comp_data; + dev->settings.osr_h = BME280_OVERSAMPLING_16X; + dev->settings.osr_p = BME280_OVERSAMPLING_16X; + dev->settings.osr_t = BME280_OVERSAMPLING_16X; + dev->settings.filter = BME280_FILTER_COEFF_16; + + settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL | BME280_OSR_HUM_SEL | BME280_FILTER_SEL; + bme280_set_sensor_settings(settings_sel, dev); + + req_delay = 12*bme280_cal_meas_delay(&(dev->settings)); + + bme280_set_sensor_mode(BME280_FORCED_MODE, dev); + dev->delay_ms(req_delay / portTICK_PERIOD_MS); + bme280_get_sensor_data(BME280_ALL, &comp_data, dev); + *temp = comp_data.temperature; + *pressure = comp_data.pressure; + *humidity = comp_data.humidity; +} + +void read_sensor2(int32_t* temp, uint32_t* pressure, uint32_t* humidity) { + + uint8_t settings_sel; + uint32_t req_delay; + struct bme280_data comp_data; + + dev2->settings.osr_h = BME280_OVERSAMPLING_16X; + dev2->settings.osr_p = BME280_OVERSAMPLING_16X; + dev2->settings.osr_t = BME280_OVERSAMPLING_16X; + dev2->settings.filter = BME280_FILTER_COEFF_16; + + settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL | BME280_OSR_HUM_SEL | BME280_FILTER_SEL; + bme280_set_sensor_settings(settings_sel, dev2); + + req_delay = 12*bme280_cal_meas_delay(&(dev2->settings)); + + bme280_set_sensor_mode(BME280_FORCED_MODE, dev2); + dev2->delay_ms(req_delay / portTICK_PERIOD_MS); + bme280_get_sensor_data(BME280_ALL, &comp_data, dev2); + *temp = comp_data.temperature; + *pressure = comp_data.pressure; + *humidity = comp_data.humidity; +} + +void init_sensors() +{ + // INIT SENSOR + i2c_setup(); + dev = malloc(sizeof(struct bme280_dev)); + dev->dev_id = 0x76; + dev->intf = BME280_I2C_INTF; + dev->read = i2c_read; + dev->write = i2c_write; + dev->delay_ms = i2c_delay; + bme280_init(dev); + + // INIT SENSOR2 + dev2 = malloc(sizeof(struct bme280_dev)); + dev2->dev_id = 0x77; + dev2->intf = BME280_I2C_INTF; + dev2->read = i2c_read; + dev2->write = i2c_write; + dev2->delay_ms = i2c_delay; + bme280_init(dev2); +} diff --git a/components/sensors/sensors.h b/components/sensors/sensors.h new file mode 100644 index 0000000..b23870d --- /dev/null +++ b/components/sensors/sensors.h @@ -0,0 +1,19 @@ +/* + * sensors.h + * + * Created on: 20 Apr 2020 + * Author: Chris + */ + +#ifndef COMPONENTS_SENSORS_SENSORS_H_ +#define COMPONENTS_SENSORS_SENSORS_H_ + +#include "bme280.h" +#include "bme280_defs.h" +#include "driver/i2c.h" + +void init_sensors(); +void read_sensor2(int32_t* temp, uint32_t* pressure, uint32_t* humidity); +void read_sensor(int32_t* temp, uint32_t* pressure, uint32_t* humidity); + +#endif /* COMPONENTS_SENSORS_SENSORS_H_ */ diff --git a/components/server/CMakeLists.txt b/components/server/CMakeLists.txt new file mode 100644 index 0000000..3b99613 --- /dev/null +++ b/components/server/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "server.c" + INCLUDE_DIRS "." + REQUIRES esp_http_server freertos) \ No newline at end of file diff --git a/components/server/server.c b/components/server/server.c new file mode 100644 index 0000000..745e996 --- /dev/null +++ b/components/server/server.c @@ -0,0 +1,70 @@ +/* + * server.c + * + * Created on: 21 Apr 2020 + * Author: Chris + */ + +#include "server.h" + +static const char *TAG = "server"; +char cur_value_str[255] = "No measurements yet!"; + +void server_set_values(int32_t temp_raw, uint32_t pressure_raw, uint32_t humidity_raw, + int32_t temp2_raw, uint32_t pressure2_raw, uint32_t humidity2_raw) +{ + sprintf(cur_value_str, "

%d %d %d

%d %d %d

", + temp_raw, pressure_raw, humidity_raw, temp2_raw, pressure2_raw, humidity2_raw); +} + +static esp_err_t get_handler(httpd_req_t *req) +{ + char* buf; + size_t buf_len; + + /* Get header value string length and allocate memory for length + 1, + * extra byte for null termination */ + buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1; + if (buf_len > 1) { + buf = malloc(buf_len); + /* Copy null terminated value string into buffer */ + if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) { + ESP_LOGI(TAG, "Found header => Host: %s", buf); + } + free(buf); + } + + const char* resp_str = cur_value_str; + httpd_resp_send(req, resp_str, strlen(resp_str)); + + return ESP_OK; +} + +static httpd_uri_t uri = { + .uri = "/", + .method = HTTP_GET, + .handler = get_handler, +}; + +static httpd_handle_t start_webserver(void) +{ + httpd_handle_t server = NULL; + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + + // Start the httpd server + ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); + if (httpd_start(&server, &config) == ESP_OK) { + // Set URI handlers + ESP_LOGI(TAG, "Registering URI handlers"); + httpd_register_uri_handler(server, &uri); + return server; + } + + ESP_LOGI(TAG, "Error starting server!"); + return NULL; +} + +void init_server() +{ + start_webserver(); +} diff --git a/components/server/server.h b/components/server/server.h new file mode 100644 index 0000000..af7e702 --- /dev/null +++ b/components/server/server.h @@ -0,0 +1,23 @@ +/* + * server.h + * + * Created on: 21 Apr 2020 + * Author: Chris + */ + +#ifndef COMPONENTS_SERVER_SERVER_H_ +#define COMPONENTS_SERVER_SERVER_H_ + +#include +#include +#include +#include +#include +#include +#include + +void init_server(); +void server_set_values(int32_t temp_raw, uint32_t pressure_raw, uint32_t humidity_raw, + int32_t temp2_raw, uint32_t pressure2_raw, uint32_t humidity2_raw); + +#endif /* COMPONENTS_SERVER_SERVER_H_ */ diff --git a/components/spidriver/CMakeLists.txt b/components/spidriver/CMakeLists.txt new file mode 100644 index 0000000..2422429 --- /dev/null +++ b/components/spidriver/CMakeLists.txt @@ -0,0 +1,2 @@ +FILE(GLOB SOURCES *.c) +idf_component_register(SRCS ${SOURCES} INCLUDE_DIRS ".") diff --git a/components/spidriver/component.mk b/components/spidriver/component.mk new file mode 100644 index 0000000..0f76ee5 --- /dev/null +++ b/components/spidriver/component.mk @@ -0,0 +1,7 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + +COMPONENT_SRCDIRS := . +COMPONENT_ADD_INCLUDEDIRS := . diff --git a/components/spidriver/spi_master_lobo.c b/components/spidriver/spi_master_lobo.c new file mode 100644 index 0000000..6aa7725 --- /dev/null +++ b/components/spidriver/spi_master_lobo.c @@ -0,0 +1,1137 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/* +---------------------------------------- +Non DMA version of the spi_master driver +---------------------------------------- +------------------------------------------------------------------------------------ +Based on esp-idf 'spi_master', modified by LoBo (https://github.com/loboris) 03/2017 +------------------------------------------------------------------------------------ + +* Transfers data to SPI device in direct mode, not using DMA +* All configuration options (bus, device, transaction) are the same as in spi_master driver +* Transfers uses the semaphore (taken in select function & given in deselect function) to protect the transfer +* Number of the devices attached to the bus which uses hardware CS can be 3 ('NO_CS') +* Additional devices which uses software CS can be attached to the bus, up to 'NO_DEV' +* 'spi_bus_initialize' & 'spi_bus_remove' functions are removed, spi bus is initiated/removed in spi_lobo_bus_add_device/spi_lobo_bus_remove_device when needed +* 'spi_lobo_bus_add_device' function has added parameter 'bus_config' and automatically initializes spi bus device if not already initialized +* 'spi_lobo_bus_remove_device' automatically removes spi bus device if no other devices are attached to it. +* Devices can have individual bus_configs, so different mosi, miso, sck pins can be configured for each device + Reconfiguring the bus is done automaticaly in 'spi_lobo_device_select' function +* 'spi_lobo_device_select' & 'spi_lobo_device_deselect' functions handles devices configuration changes and software CS +* Some helper functions are added ('spi_lobo_get_speed', 'spi_lobo_set_speed', ...) +* All structures are available in header file for easy creation of user low level spi functions. See **tftfunc.c** source for examples. +* Transimt and receive lenghts are limited only by available memory + + +Main driver's function is 'spi_lobo_transfer_data()' + + * TRANSMIT 8-bit data to spi device from 'trans->tx_buffer' or 'trans->tx_data' (trans->lenght/8 bytes) + * and RECEIVE data to 'trans->rx_buffer' or 'trans->rx_data' (trans->rx_length/8 bytes) + * Lengths must be 8-bit multiples! + * If trans->rx_buffer is NULL or trans->rx_length is 0, only transmits data + * If trans->tx_buffer is NULL or trans->length is 0, only receives data + * If the device is in duplex mode (LB_SPI_DEVICE_HALFDUPLEX flag NOT set), data are transmitted and received simultaneously. + * If the device is in half duplex mode (LB_SPI_DEVICE_HALFDUPLEX flag IS set), data are received after transmission + * 'address', 'command' and 'dummy bits' are transmitted before data phase IF set in device's configuration + * and IF 'trans->length' and 'trans->rx_length' are NOT both 0 + * If configured, devices 'pre_cb' callback is called before and 'post_cb' after the transmission + * If device was not previously selected, it will be selected before transmission and deselected after transmission. + +*/ + +/* + Replace this include with + #include "driver/spi_master_lobo.h" + if the driver is located in esp-isf/components +*/ +#include "freertos/FreeRTOS.h" +#include +#include "soc/spi_reg.h" +#include "soc/dport_reg.h" +#include "esp_log.h" +#include "freertos/semphr.h" +#include "driver/uart.h" +#include "driver/gpio.h" +#include "spi_master_lobo.h" +#include "driver/periph_ctrl.h" + +static spi_lobo_host_t *spihost[3] = {NULL}; + + +static const char *SPI_TAG = "spi_lobo_master"; +#define SPI_CHECK(a, str, ret_val) \ + if (!(a)) { \ + ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ + return (ret_val); \ + } + +/* + Stores a bunch of per-spi-peripheral data. +*/ +typedef struct { + const uint8_t spiclk_out; //GPIO mux output signals + const uint8_t spid_out; + const uint8_t spiq_out; + const uint8_t spiwp_out; + const uint8_t spihd_out; + const uint8_t spid_in; //GPIO mux input signals + const uint8_t spiq_in; + const uint8_t spiwp_in; + const uint8_t spihd_in; + const uint8_t spics_out[3]; // /CS GPIO output mux signals + const uint8_t spiclk_native; //IO pins of IO_MUX muxed signals + const uint8_t spid_native; + const uint8_t spiq_native; + const uint8_t spiwp_native; + const uint8_t spihd_native; + const uint8_t spics0_native; + const uint8_t irq; //irq source for interrupt mux + const uint8_t irq_dma; //dma irq source for interrupt mux + const periph_module_t module; //peripheral module, for enabling clock etc + spi_dev_t *hw; //Pointer to the hardware registers +} spi_signal_conn_t; + +/* + Bunch of constants for every SPI peripheral: GPIO signals, irqs, hw addr of registers etc +*/ +static const spi_signal_conn_t io_signal[3]={ + { + .spiclk_out=SPICLK_OUT_IDX, + .spid_out=SPID_OUT_IDX, + .spiq_out=SPIQ_OUT_IDX, + .spiwp_out=SPIWP_OUT_IDX, + .spihd_out=SPIHD_OUT_IDX, + .spid_in=SPID_IN_IDX, + .spiq_in=SPIQ_IN_IDX, + .spiwp_in=SPIWP_IN_IDX, + .spihd_in=SPIHD_IN_IDX, + .spics_out={SPICS0_OUT_IDX, SPICS1_OUT_IDX, SPICS2_OUT_IDX}, + .spiclk_native=6, + .spid_native=8, + .spiq_native=7, + .spiwp_native=10, + .spihd_native=9, + .spics0_native=11, + .irq=ETS_SPI1_INTR_SOURCE, + .irq_dma=ETS_SPI1_DMA_INTR_SOURCE, + .module=PERIPH_SPI_MODULE, + .hw=&SPI1 + }, { + .spiclk_out=HSPICLK_OUT_IDX, + .spid_out=HSPID_OUT_IDX, + .spiq_out=HSPIQ_OUT_IDX, + .spiwp_out=HSPIWP_OUT_IDX, + .spihd_out=HSPIHD_OUT_IDX, + .spid_in=HSPID_IN_IDX, + .spiq_in=HSPIQ_IN_IDX, + .spiwp_in=HSPIWP_IN_IDX, + .spihd_in=HSPIHD_IN_IDX, + .spics_out={HSPICS0_OUT_IDX, HSPICS1_OUT_IDX, HSPICS2_OUT_IDX}, + .spiclk_native=14, + .spid_native=13, + .spiq_native=12, + .spiwp_native=2, + .spihd_native=4, + .spics0_native=15, + .irq=ETS_SPI2_INTR_SOURCE, + .irq_dma=ETS_SPI2_DMA_INTR_SOURCE, + .module=PERIPH_HSPI_MODULE, + .hw=&SPI2 + }, { + .spiclk_out=VSPICLK_OUT_IDX, + .spid_out=VSPID_OUT_IDX, + .spiq_out=VSPIQ_OUT_IDX, + .spiwp_out=VSPIWP_OUT_IDX, + .spihd_out=VSPIHD_OUT_IDX, + .spid_in=VSPID_IN_IDX, + .spiq_in=VSPIQ_IN_IDX, + .spiwp_in=VSPIWP_IN_IDX, + .spihd_in=VSPIHD_IN_IDX, + .spics_out={VSPICS0_OUT_IDX, VSPICS1_OUT_IDX, VSPICS2_OUT_IDX}, + .spiclk_native=18, + .spid_native=23, + .spiq_native=19, + .spiwp_native=22, + .spihd_native=21, + .spics0_native=5, + .irq=ETS_SPI3_INTR_SOURCE, + .irq_dma=ETS_SPI3_DMA_INTR_SOURCE, + .module=PERIPH_VSPI_MODULE, + .hw=&SPI3 + } +}; + + +//====================================================================================================== + +#define DMA_CHANNEL_ENABLED(dma_chan) (BIT(dma_chan-1)) + +typedef void(*dmaworkaround_cb_t)(void *arg); + +//Set up a list of dma descriptors. dmadesc is an array of descriptors. Data is the buffer to point to. +//-------------------------------------------------------------------------------------------- +void spi_lobo_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx) +{ + int n = 0; + while (len) { + int dmachunklen = len; + if (dmachunklen > SPI_MAX_DMA_LEN) dmachunklen = SPI_MAX_DMA_LEN; + if (isrx) { + //Receive needs DMA length rounded to next 32-bit boundary + dmadesc[n].size = (dmachunklen + 3) & (~3); + dmadesc[n].length = (dmachunklen + 3) & (~3); + } else { + dmadesc[n].size = dmachunklen; + dmadesc[n].length = dmachunklen; + } + dmadesc[n].buf = (uint8_t *)data; + dmadesc[n].eof = 0; + dmadesc[n].sosf = 0; + dmadesc[n].owner = 1; + dmadesc[n].qe.stqe_next = &dmadesc[n + 1]; + len -= dmachunklen; + data += dmachunklen; + n++; + } + dmadesc[n - 1].eof = 1; //Mark last DMA desc as end of stream. + dmadesc[n - 1].qe.stqe_next = NULL; +} + + +/* +Code for workaround for DMA issue in ESP32 v0/v1 silicon +*/ + + +static volatile int dmaworkaround_channels_busy[2] = {0, 0}; +static dmaworkaround_cb_t dmaworkaround_cb; +static void *dmaworkaround_cb_arg; +static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED; +static int dmaworkaround_waiting_for_chan = 0; +static bool spi_periph_claimed[3] = {true, false, false}; +static uint8_t spi_dma_chan_enabled = 0; +static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED; + +//-------------------------------------------------------------------------------------------- +bool IRAM_ATTR spi_lobo_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg) +{ + int otherchan = (dmachan == 1) ? 2 : 1; + bool ret; + portENTER_CRITICAL(&dmaworkaround_mux); + if (dmaworkaround_channels_busy[otherchan-1]) { + //Other channel is busy. Call back when it's done. + dmaworkaround_cb = cb; + dmaworkaround_cb_arg = arg; + dmaworkaround_waiting_for_chan = otherchan; + ret = false; + } else { + //Reset DMA + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); + ret = true; + } + portEXIT_CRITICAL(&dmaworkaround_mux); + return ret; +} + +//------------------------------------------------------- +bool IRAM_ATTR spi_lobo_dmaworkaround_reset_in_progress() +{ + return (dmaworkaround_waiting_for_chan != 0); +} + +//----------------------------------------------------- +void IRAM_ATTR spi_lobo_dmaworkaround_idle(int dmachan) +{ + portENTER_CRITICAL(&dmaworkaround_mux); + dmaworkaround_channels_busy[dmachan-1] = 0; + if (dmaworkaround_waiting_for_chan == dmachan) { + //Reset DMA + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_DMA_RST); + dmaworkaround_waiting_for_chan = 0; + //Call callback + dmaworkaround_cb(dmaworkaround_cb_arg); + + } + portEXIT_CRITICAL(&dmaworkaround_mux); +} + +//---------------------------------------------------------------- +void IRAM_ATTR spi_lobo_dmaworkaround_transfer_active(int dmachan) +{ + portENTER_CRITICAL(&dmaworkaround_mux); + dmaworkaround_channels_busy[dmachan-1] = 1; + portEXIT_CRITICAL(&dmaworkaround_mux); +} + +//Returns true if this peripheral is successfully claimed, false if otherwise. +//----------------------------------------------------- +bool spi_lobo_periph_claim(spi_lobo_host_device_t host) +{ + bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], false, true); + if (ret) periph_module_enable(io_signal[host].module); + return ret; +} + +//Returns true if this peripheral is successfully freed, false if otherwise. +//----------------------------------------------- +bool spi_lobo_periph_free(spi_lobo_host_device_t host) +{ + bool ret = __sync_bool_compare_and_swap(&spi_periph_claimed[host], true, false); + if (ret) periph_module_disable(io_signal[host].module); + return ret; +} + +//----------------------------------------- +bool spi_lobo_dma_chan_claim (int dma_chan) +{ + bool ret = false; + assert( dma_chan == 1 || dma_chan == 2 ); + + portENTER_CRITICAL(&spi_dma_spinlock); + if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) { + // get the channel only when it's not claimed yet. + spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan); + ret = true; + } + periph_module_enable( PERIPH_SPI_DMA_MODULE ); + portEXIT_CRITICAL(&spi_dma_spinlock); + + return ret; +} + +//--------------------------------------- +bool spi_lobo_dma_chan_free(int dma_chan) +{ + assert( dma_chan == 1 || dma_chan == 2 ); + assert( spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan) ); + + portENTER_CRITICAL(&spi_dma_spinlock); + spi_dma_chan_enabled &= ~DMA_CHANNEL_ENABLED(dma_chan); + if ( spi_dma_chan_enabled == 0 ) { + //disable the DMA only when all the channels are freed. + periph_module_disable( PERIPH_SPI_DMA_MODULE ); + } + portEXIT_CRITICAL(&spi_dma_spinlock); + + return true; +} + + +//====================================================================================================== + + +//---------------------------------------------------------------------------------------------------------------- +static esp_err_t spi_lobo_bus_initialize(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, int init) +{ + bool native=true, spi_chan_claimed, dma_chan_claimed; + + if (init > 0) { + /* ToDo: remove this when we have flash operations cooperating with this */ + SPI_CHECK(host!=TFT_SPI_HOST, "SPI1 is not supported", ESP_ERR_NOT_SUPPORTED); + + SPI_CHECK(host>=TFT_SPI_HOST && host<=TFT_VSPI_HOST, "invalid host", ESP_ERR_INVALID_ARG); + SPI_CHECK(spihost[host]==NULL, "host already in use", ESP_ERR_INVALID_STATE); + } + else { + SPI_CHECK(spihost[host]!=NULL, "host not in use", ESP_ERR_INVALID_STATE); + } + + SPI_CHECK(bus_config->mosi_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "spid pin invalid", ESP_ERR_INVALID_ARG); + SPI_CHECK(bus_config->sclk_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->sclk_io_num), "spiclk pin invalid", ESP_ERR_INVALID_ARG); + SPI_CHECK(bus_config->miso_io_num<0 || GPIO_IS_VALID_GPIO(bus_config->miso_io_num), "spiq pin invalid", ESP_ERR_INVALID_ARG); + SPI_CHECK(bus_config->quadwp_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadwp_io_num), "spiwp pin invalid", ESP_ERR_INVALID_ARG); + SPI_CHECK(bus_config->quadhd_io_num<0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->quadhd_io_num), "spihd pin invalid", ESP_ERR_INVALID_ARG); + + if (init > 0) { + spi_chan_claimed=spi_lobo_periph_claim(host); + SPI_CHECK(spi_chan_claimed, "host already in use", ESP_ERR_INVALID_STATE); + + //spihost[host]=malloc(sizeof(spi_lobo_host_t)); + spihost[host]=heap_caps_malloc(sizeof(spi_lobo_host_t), MALLOC_CAP_DMA); + if (spihost[host]==NULL) return ESP_ERR_NO_MEM; + memset(spihost[host], 0, sizeof(spi_lobo_host_t)); + // Create semaphore + spihost[host]->spi_lobo_bus_mutex = xSemaphoreCreateMutex(); + if (!spihost[host]->spi_lobo_bus_mutex) return ESP_ERR_NO_MEM; + } + + spihost[host]->cur_device = -1; + memcpy(&spihost[host]->cur_bus_config, bus_config, sizeof(spi_lobo_bus_config_t)); + + //Check if the selected pins correspond to the native pins of the peripheral + if (bus_config->mosi_io_num >= 0 && bus_config->mosi_io_num!=io_signal[host].spid_native) native=false; + if (bus_config->miso_io_num >= 0 && bus_config->miso_io_num!=io_signal[host].spiq_native) native=false; + if (bus_config->sclk_io_num >= 0 && bus_config->sclk_io_num!=io_signal[host].spiclk_native) native=false; + if (bus_config->quadwp_io_num >= 0 && bus_config->quadwp_io_num!=io_signal[host].spiwp_native) native=false; + if (bus_config->quadhd_io_num >= 0 && bus_config->quadhd_io_num!=io_signal[host].spihd_native) native=false; + + spihost[host]->no_gpio_matrix=native; + if (native) { + //All SPI native pin selections resolve to 1, so we put that here instead of trying to figure + //out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway. + if (bus_config->mosi_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], 1); + if (bus_config->miso_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], 1); + if (bus_config->quadwp_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], 1); + if (bus_config->quadhd_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], 1); + if (bus_config->sclk_io_num > 0) PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], 1); + } else { + //Use GPIO + if (bus_config->mosi_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(bus_config->mosi_io_num, io_signal[host].spid_out, false, false); + gpio_matrix_in(bus_config->mosi_io_num, io_signal[host].spid_in, false); + } + if (bus_config->miso_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT); + gpio_matrix_out(bus_config->miso_io_num, io_signal[host].spiq_out, false, false); + gpio_matrix_in(bus_config->miso_io_num, io_signal[host].spiq_in, false); + } + if (bus_config->quadwp_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(bus_config->quadwp_io_num, io_signal[host].spiwp_out, false, false); + gpio_matrix_in(bus_config->quadwp_io_num, io_signal[host].spiwp_in, false); + } + if (bus_config->quadhd_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(bus_config->quadhd_io_num, io_signal[host].spihd_out, false, false); + gpio_matrix_in(bus_config->quadhd_io_num, io_signal[host].spihd_in, false); + } + if (bus_config->sclk_io_num>0) { + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], PIN_FUNC_GPIO); + gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(bus_config->sclk_io_num, io_signal[host].spiclk_out, false, false); + } + } + periph_module_enable(io_signal[host].module); + spihost[host]->hw=io_signal[host].hw; + + if (init > 0) { + dma_chan_claimed=spi_lobo_dma_chan_claim(init); + if ( !dma_chan_claimed ) { + spi_lobo_periph_free( host ); + SPI_CHECK(dma_chan_claimed, "dma channel already in use", ESP_ERR_INVALID_STATE); + } + spihost[host]->dma_chan = init; + //See how many dma descriptors we need and allocate them + int dma_desc_ct=(bus_config->max_transfer_sz+SPI_MAX_DMA_LEN-1)/SPI_MAX_DMA_LEN; + if (dma_desc_ct==0) dma_desc_ct=1; //default to 4k when max is not given + spihost[host]->max_transfer_sz = dma_desc_ct*SPI_MAX_DMA_LEN; + + spihost[host]->dmadesc_tx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA); + spihost[host]->dmadesc_rx=heap_caps_malloc(sizeof(lldesc_t)*dma_desc_ct, MALLOC_CAP_DMA); + if (!spihost[host]->dmadesc_tx || !spihost[host]->dmadesc_rx) goto nomem; + + //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset. + spi_lobo_dmaworkaround_idle(spihost[host]->dma_chan); + + // Reset DMA + spihost[host]->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST; + spihost[host]->hw->dma_out_link.start=0; + spihost[host]->hw->dma_in_link.start=0; + spihost[host]->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST); + spihost[host]->hw->dma_conf.out_data_burst_en=1; + + //Reset timing + spihost[host]->hw->ctrl2.val=0; + + //Disable unneeded ints + spihost[host]->hw->slave.rd_buf_done=0; + spihost[host]->hw->slave.wr_buf_done=0; + spihost[host]->hw->slave.rd_sta_done=0; + spihost[host]->hw->slave.wr_sta_done=0; + spihost[host]->hw->slave.rd_buf_inten=0; + spihost[host]->hw->slave.wr_buf_inten=0; + spihost[host]->hw->slave.rd_sta_inten=0; + spihost[host]->hw->slave.wr_sta_inten=0; + + //Force a transaction done interrupt. This interrupt won't fire yet because we initialized the SPI interrupt as + //disabled. This way, we can just enable the SPI interrupt and the interrupt handler will kick in, handling + //any transactions that are queued. + spihost[host]->hw->slave.trans_inten=1; + spihost[host]->hw->slave.trans_done=1; + + //Select DMA channel. + DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, init, (host * 2)); + } + return ESP_OK; + +nomem: + if (spihost[host]) { + free(spihost[host]->dmadesc_tx); + free(spihost[host]->dmadesc_rx); + } + free(spihost[host]); + spi_lobo_periph_free(host); + return ESP_ERR_NO_MEM; +} + +//--------------------------------------------------------------------------- +static esp_err_t spi_lobo_bus_free(spi_lobo_host_device_t host, int dofree) +{ + if ((host == TFT_SPI_HOST) || (host > TFT_VSPI_HOST)) return ESP_ERR_NOT_SUPPORTED; // invalid host + + if (spihost[host] == NULL) return ESP_ERR_INVALID_STATE; // host not in use + + if (dofree) { + for (int x=0; xdevice[x] != NULL) return ESP_ERR_INVALID_STATE; // not all devices freed + } + } + if ( spihost[host]->dma_chan > 0 ) { + spi_lobo_dma_chan_free ( spihost[host]->dma_chan ); + } + spihost[host]->hw->slave.trans_inten=0; + spihost[host]->hw->slave.trans_done=0; + spi_lobo_periph_free(host); + + if (dofree) { + vSemaphoreDelete(spihost[host]->spi_lobo_bus_mutex); + free(spihost[host]->dmadesc_tx); + free(spihost[host]->dmadesc_rx); + free(spihost[host]); + spihost[host] = NULL; + } + return ESP_OK; +} + +//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +esp_err_t spi_lobo_bus_add_device(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, spi_lobo_device_interface_config_t *dev_config, spi_lobo_device_handle_t *handle) +{ + if ((host == TFT_SPI_HOST) || (host > TFT_VSPI_HOST)) return ESP_ERR_NOT_SUPPORTED; // invalid host + + if (spihost[host] == NULL) { + esp_err_t ret = spi_lobo_bus_initialize(host, bus_config, 1); + if (ret) return ret; + } + + int freecs, maxdev; + int apbclk=APB_CLK_FREQ; + + if (spihost[host] == NULL) return ESP_ERR_INVALID_STATE; + + if (dev_config->spics_io_num >= 0) { + if (!GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_io_num)) return ESP_ERR_INVALID_ARG; + if (dev_config->spics_ext_io_num > 0) dev_config->spics_ext_io_num = -1; + } + else { + //if ((dev_config->spics_ext_io_num <= 0) || (!GPIO_IS_VALID_OUTPUT_GPIO(dev_config->spics_ext_io_num))) return ESP_ERR_INVALID_ARG; + } + + //ToDo: Check if some other device uses the same 'spics_ext_io_num' + + if (dev_config->clock_speed_hz == 0) return ESP_ERR_INVALID_ARG; + if (dev_config->spics_io_num > 0) maxdev = NO_CS; + else maxdev = NO_DEV; + + for (freecs=0; freecsdevice[freecs], NULL, (spi_lobo_device_t *)1)) break; + } + if (freecs == maxdev) return ESP_ERR_NOT_FOUND; + + // The hardware looks like it would support this, but actually setting cs_ena_pretrans when transferring in full + // duplex mode does absolutely nothing on the ESP32. + if ((dev_config->cs_ena_pretrans != 0) && (dev_config->flags & LB_SPI_DEVICE_HALFDUPLEX)) return ESP_ERR_INVALID_ARG; + + // Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections. + if (((dev_config->flags & LB_SPI_DEVICE_HALFDUPLEX)==0) && (dev_config->clock_speed_hz > ((apbclk*2)/5)) && (!spihost[host]->no_gpio_matrix)) return ESP_ERR_INVALID_ARG; + + //Allocate memory for device + spi_lobo_device_t *dev=malloc(sizeof(spi_lobo_device_t)); + if (dev==NULL) return ESP_ERR_NO_MEM; + + memset(dev, 0, sizeof(spi_lobo_device_t)); + spihost[host]->device[freecs]=dev; + + if (dev_config->duty_cycle_pos==0) dev_config->duty_cycle_pos=128; + dev->host=spihost[host]; + dev->host_dev = host; + + //We want to save a copy of the dev config in the dev struct. + memcpy(&dev->cfg, dev_config, sizeof(spi_lobo_device_interface_config_t)); + //We want to save a copy of the bus config in the dev struct. + memcpy(&dev->bus_config, bus_config, sizeof(spi_lobo_bus_config_t)); + + //Set CS pin, CS options + if (dev_config->spics_io_num > 0) { + if (spihost[host]->no_gpio_matrix &&dev_config->spics_io_num == io_signal[host].spics0_native && freecs==0) { + //Again, the cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define. + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], 1); + } else { + //Use GPIO matrix + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dev_config->spics_io_num], PIN_FUNC_GPIO); + gpio_set_direction(dev_config->spics_io_num, GPIO_MODE_OUTPUT); + gpio_matrix_out(dev_config->spics_io_num, io_signal[host].spics_out[freecs], false, false); + } + } + else if (dev_config->spics_ext_io_num >= 0) { + gpio_set_direction(dev_config->spics_ext_io_num, GPIO_MODE_OUTPUT); + gpio_set_level(dev_config->spics_ext_io_num, 1); + } + if (dev_config->flags & LB_SPI_DEVICE_CLK_AS_CS) { + spihost[host]->hw->pin.master_ck_sel |= (1<hw->pin.master_ck_sel &= (1<flags & LB_SPI_DEVICE_POSITIVE_CS) { + spihost[host]->hw->pin.master_cs_pol |= (1<hw->pin.master_cs_pol &= (1<host->device[x] == handle) handle->host->device[x]=NULL; + } + + // Check if all devices are removed from this host and free the bus if yes + for (x=0; xhost_dev]->device[x] !=NULL) break; + } + if (x == NO_DEV) { + free(handle); + spi_lobo_bus_free(handle->host_dev, 1); + } + else free(handle); + + return ESP_OK; +} + +//----------------------------------------------------------------- +static int IRAM_ATTR spi_freq_for_pre_n(int fapb, int pre, int n) { + return (fapb / (pre * n)); +} + +/* + * Set the SPI clock to a certain frequency. Returns the effective frequency set, which may be slightly + * different from the requested frequency. + */ +//----------------------------------------------------------------------------------- +static int IRAM_ATTR spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) { + int pre, n, h, l, eff_clk; + + //In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value. + if (hz>((fapb/4)*3)) { + //Using Fapb directly will give us the best result here. + hw->clock.clkcnt_l=0; + hw->clock.clkcnt_h=0; + hw->clock.clkcnt_n=0; + hw->clock.clkdiv_pre=0; + hw->clock.clk_equ_sysclk=1; + eff_clk=fapb; + } else { + //For best duty cycle resolution, we want n to be as close to 32 as possible, but + //we also need a pre/n combo that gets us as close as possible to the intended freq. + //To do this, we bruteforce n and calculate the best pre to go along with that. + //If there's a choice between pre/n combos that give the same result, use the one + //with the higher n. + int bestn=-1; + int bestpre=-1; + int besterr=0; + int errval; + for (n=1; n<=64; n++) { + //Effectively, this does pre=round((fapb/n)/hz). + pre=((fapb/n)+(hz/2))/hz; + if (pre<=0) pre=1; + if (pre>8192) pre=8192; + errval=abs(spi_freq_for_pre_n(fapb, pre, n)-hz); + if (bestn==-1 || errval<=besterr) { + besterr=errval; + bestn=n; + bestpre=pre; + } + } + + n=bestn; + pre=bestpre; + l=n; + //This effectively does round((duty_cycle*n)/256) + h=(duty_cycle*n+127)/256; + if (h<=0) h=1; + + hw->clock.clk_equ_sysclk=0; + hw->clock.clkcnt_n=n-1; + hw->clock.clkdiv_pre=pre-1; + hw->clock.clkcnt_h=h-1; + hw->clock.clkcnt_l=l-1; + eff_clk=spi_freq_for_pre_n(fapb, pre, n); + } + return eff_clk; +} + + + +//------------------------------------------------------------------------------------ +esp_err_t IRAM_ATTR spi_lobo_device_select(spi_lobo_device_handle_t handle, int force) +{ + if (handle == NULL) return ESP_ERR_INVALID_ARG; + + if ((handle->cfg.selected == 1) && (!force)) return ESP_OK; // already selected + + int i; + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + + // find device's host bus + for (i=0; idevice[i] == handle) break; + } + if (i == NO_DEV) return ESP_ERR_INVALID_ARG; + + if (!(xSemaphoreTake(host->spi_lobo_bus_mutex, SPI_SEMAPHORE_WAIT))) return ESP_ERR_INVALID_STATE; + + // Check if previously used device's bus device is the same + if (memcmp(&host->cur_bus_config, &handle->bus_config, sizeof(spi_lobo_bus_config_t)) != 0) { + // device has different bus configuration, we need to reconfigure the bus + esp_err_t err = spi_lobo_bus_free(1, 0); + if (err) { + xSemaphoreGive(host->spi_lobo_bus_mutex); + return err; + } + err = spi_lobo_bus_initialize(i, &handle->bus_config, -1); + if (err) { + xSemaphoreGive(host->spi_lobo_bus_mutex); + return err; + } + } + + //Reconfigure according to device settings, but only if the device changed or forced. + if ((force) || (host->device[host->cur_device] != handle)) { + //Assumes a hardcoded 80MHz Fapb for now. ToDo: figure out something better once we have clock scaling working. + int apbclk=APB_CLK_FREQ; + + //Speeds >=40MHz over GPIO matrix needs a dummy cycle, but these don't work for full-duplex connections. + if (((handle->cfg.flags & LB_SPI_DEVICE_HALFDUPLEX) == 0) && (handle->cfg.clock_speed_hz > ((apbclk*2)/5)) && (!host->no_gpio_matrix)) { + // set speed to 32 MHz + handle->cfg.clock_speed_hz = (apbclk*2)/5; + } + + int effclk=spi_set_clock(host->hw, apbclk, handle->cfg.clock_speed_hz, handle->cfg.duty_cycle_pos); + //Configure bit order + host->hw->ctrl.rd_bit_order=(handle->cfg.flags & LB_SPI_DEVICE_RXBIT_LSBFIRST)?1:0; + host->hw->ctrl.wr_bit_order=(handle->cfg.flags & LB_SPI_DEVICE_TXBIT_LSBFIRST)?1:0; + + //Configure polarity + //SPI iface needs to be configured for a delay in some cases. + int nodelay=0; + int extra_dummy=0; + if (host->no_gpio_matrix) { + if (effclk >= apbclk/2) { + nodelay=1; + } + } else { + if (effclk >= apbclk/2) { + nodelay=1; + extra_dummy=1; //Note: This only works on half-duplex connections. spi_lobo_bus_add_device checks for this. + } else if (effclk >= apbclk/4) { + nodelay=1; + } + } + if (handle->cfg.mode==0) { + host->hw->pin.ck_idle_edge=0; + host->hw->user.ck_out_edge=0; + host->hw->ctrl2.miso_delay_mode=nodelay?0:2; + } else if (handle->cfg.mode==1) { + host->hw->pin.ck_idle_edge=0; + host->hw->user.ck_out_edge=1; + host->hw->ctrl2.miso_delay_mode=nodelay?0:1; + } else if (handle->cfg.mode==2) { + host->hw->pin.ck_idle_edge=1; + host->hw->user.ck_out_edge=1; + host->hw->ctrl2.miso_delay_mode=nodelay?0:1; + } else if (handle->cfg.mode==3) { + host->hw->pin.ck_idle_edge=1; + host->hw->user.ck_out_edge=0; + host->hw->ctrl2.miso_delay_mode=nodelay?0:2; + } + + //Configure bit sizes, load addr and command + host->hw->user.usr_dummy=(handle->cfg.dummy_bits+extra_dummy)?1:0; + host->hw->user.usr_addr=(handle->cfg.address_bits)?1:0; + host->hw->user.usr_command=(handle->cfg.command_bits)?1:0; + host->hw->user1.usr_addr_bitlen=handle->cfg.address_bits-1; + host->hw->user1.usr_dummy_cyclelen=handle->cfg.dummy_bits+extra_dummy-1; + host->hw->user2.usr_command_bitlen=handle->cfg.command_bits-1; + //Configure misc stuff + host->hw->user.doutdin=(handle->cfg.flags & LB_SPI_DEVICE_HALFDUPLEX)?0:1; + host->hw->user.sio=(handle->cfg.flags & LB_SPI_DEVICE_3WIRE)?1:0; + + host->hw->ctrl2.setup_time=handle->cfg.cs_ena_pretrans-1; + host->hw->user.cs_setup=handle->cfg.cs_ena_pretrans?1:0; + host->hw->ctrl2.hold_time=handle->cfg.cs_ena_posttrans-1; + host->hw->user.cs_hold=(handle->cfg.cs_ena_posttrans)?1:0; + + //Configure CS pin + host->hw->pin.cs0_dis=(i==0)?0:1; + host->hw->pin.cs1_dis=(i==1)?0:1; + host->hw->pin.cs2_dis=(i==2)?0:1; + + host->cur_device = i; + } + + if ((handle->cfg.spics_io_num < 0) && (handle->cfg.spics_ext_io_num > 0)) { + gpio_set_level(handle->cfg.spics_ext_io_num, 0); + } + + handle->cfg.selected = 1; + + return ESP_OK; +} + +//--------------------------------------------------------------------------- +esp_err_t IRAM_ATTR spi_lobo_device_deselect(spi_lobo_device_handle_t handle) +{ + if (handle == NULL) return ESP_ERR_INVALID_ARG; + + if (handle->cfg.selected == 0) return ESP_OK; // already deselected + + int i; + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + + for (i=0; idevice[i] == handle) break; + } + if (i == NO_DEV) return ESP_ERR_INVALID_ARG; + + if (host->device[host->cur_device] == handle) { + if ((handle->cfg.spics_io_num < 0) && (handle->cfg.spics_ext_io_num > 0)) { + gpio_set_level(handle->cfg.spics_ext_io_num, 1); + } + } + + handle->cfg.selected = 0; + xSemaphoreGive(host->spi_lobo_bus_mutex); + + return ESP_OK; +} + +//-------------------------------------------------------------------------------- +esp_err_t IRAM_ATTR spi_lobo_device_TakeSemaphore(spi_lobo_device_handle_t handle) +{ + if (!(xSemaphoreTake(handle->host->spi_lobo_bus_mutex, SPI_SEMAPHORE_WAIT))) return ESP_ERR_INVALID_STATE; + else return ESP_OK; +} + +//--------------------------------------------------------------------------- +void IRAM_ATTR spi_lobo_device_GiveSemaphore(spi_lobo_device_handle_t handle) +{ + xSemaphoreTake(handle->host->spi_lobo_bus_mutex, portMAX_DELAY); +} + +//---------------------------------------------------------- +uint32_t spi_lobo_get_speed(spi_lobo_device_handle_t handle) +{ + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + uint32_t speed = 0; + if (spi_lobo_device_select(handle, 0) == ESP_OK) { + if (host->hw->clock.clk_equ_sysclk == 1) speed = 80000000; + else speed = 80000000/(host->hw->clock.clkdiv_pre+1)/(host->hw->clock.clkcnt_n+1); + } + spi_lobo_device_deselect(handle); + return speed; +} + +//-------------------------------------------------------------------------- +uint32_t spi_lobo_set_speed(spi_lobo_device_handle_t handle, uint32_t speed) +{ + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + uint32_t newspeed = 0; + if (spi_lobo_device_select(handle, 0) == ESP_OK) { + spi_lobo_device_deselect(handle); + handle->cfg.clock_speed_hz = speed; + if (spi_lobo_device_select(handle, 1) == ESP_OK) { + if (host->hw->clock.clk_equ_sysclk == 1) newspeed = 80000000; + else newspeed = 80000000/(host->hw->clock.clkdiv_pre+1)/(host->hw->clock.clkcnt_n+1); + } + } + spi_lobo_device_deselect(handle); + + return newspeed; +} + +//------------------------------------------------------------- +bool spi_lobo_uses_native_pins(spi_lobo_device_handle_t handle) +{ + return handle->host->no_gpio_matrix; +} + +//------------------------------------------------------------------- +void spi_lobo_get_native_pins(int host, int *sdi, int *sdo, int *sck) +{ + *sdo = io_signal[host].spid_native; + *sdi = io_signal[host].spiq_native; + *sck = io_signal[host].spiclk_native; +} + +/* +When using 'spi_lobo_transfer_data' function we can have several scenarios: + +A: Send only (trans->rxlength = 0) +B: Receive only (trans->txlength = 0) +C: Send & receive (trans->txlength > 0 & trans->rxlength > 0) +D: No operation (trans->txlength = 0 & trans->rxlength = 0) + +*/ +//---------------------------------------------------------------------------------------------------------- +esp_err_t IRAM_ATTR spi_lobo_transfer_data(spi_lobo_device_handle_t handle, spi_lobo_transaction_t *trans) { + if (!handle) return ESP_ERR_INVALID_ARG; + + // *** For now we can only handle 8-bit bytes transmission + if (((trans->length % 8) != 0) || ((trans->rxlength % 8) != 0)) return ESP_ERR_INVALID_ARG; + + spi_lobo_host_t *host=(spi_lobo_host_t*)handle->host; + esp_err_t ret; + uint8_t do_deselect = 0; + const uint8_t *txbuffer = NULL; + uint8_t *rxbuffer = NULL; + + if (trans->flags & LB_SPI_TRANS_USE_TXDATA) { + // Send data from 'trans->tx_data' + txbuffer=(uint8_t*)&trans->tx_data[0]; + } else { + // Send data from 'trans->tx_buffer' + txbuffer=(uint8_t*)trans->tx_buffer; + } + if (trans->flags & LB_SPI_TRANS_USE_RXDATA) { + // Receive data to 'trans->rx_data' + rxbuffer=(uint8_t*)&trans->rx_data[0]; + } else { + // Receive data to 'trans->rx_buffer' + rxbuffer=(uint8_t*)trans->rx_buffer; + } + + // ** Set transmit & receive length in bytes + uint32_t txlen = trans->length / 8; + uint32_t rxlen = trans->rxlength / 8; + + if (txbuffer == NULL) txlen = 0; + if (rxbuffer == NULL) rxlen = 0; + if ((rxlen == 0) && (txlen == 0)) { + // ** NOTHING TO SEND or RECEIVE, return + return ESP_ERR_INVALID_ARG; + } + + // If using 'trans->tx_data' and/or 'trans->rx_data', maximum 4 bytes can be sent/received + if ((txbuffer == &trans->tx_data[0]) && (txlen > 4)) return ESP_ERR_INVALID_ARG; + if ((rxbuffer == &trans->rx_data[0]) && (rxlen > 4)) return ESP_ERR_INVALID_ARG; + + // --- Wait for SPI bus ready --- + while (host->hw->cmd.usr); + + // ** If the device was not selected, select it + if (handle->cfg.selected == 0) { + ret = spi_lobo_device_select(handle, 0); + if (ret) return ret; + do_deselect = 1; // We will deselect the device after the operation ! + } + + // ** Call pre-transmission callback, if any + if (handle->cfg.pre_cb) handle->cfg.pre_cb(trans); + + // Test if operating in full duplex mode + uint8_t duplex = 1; + if (handle->cfg.flags & LB_SPI_DEVICE_HALFDUPLEX) duplex = 0; // Half duplex mode ! + + uint32_t bits, rdbits; + uint32_t wd; + uint8_t bc, rdidx; + uint32_t rdcount = rxlen; // Total number of bytes to read + uint32_t count = 0; // number of bytes transmitted + uint32_t rd_read = 0; // Number of bytes read so far + + host->hw->user.usr_mosi_highpart = 0; // use the whole spi buffer + + // ** Check if address phase will be used + host->hw->user2.usr_command_value=trans->command; + if (handle->cfg.address_bits>32) { + host->hw->addr=trans->address >> 32; + host->hw->slv_wr_status=trans->address & 0xffffffff; + } else { + host->hw->addr=trans->address & 0xffffffff; + } + + // Check if we have to transmit some data + if (txlen > 0) { + host->hw->user.usr_mosi = 1; + uint8_t idx; + bits = 0; // remaining bits to send + idx = 0; // index to spi hw data_buf (16 32-bit words, 64 bytes, 512 bits) + + // ** Transmit 'txlen' bytes + while (count < txlen) { + wd = 0; + for (bc=0;bc<32;bc+=8) { + wd |= (uint32_t)txbuffer[count] << bc; + count++; // Increment sent data count + bits += 8; // Increment bits count + if (count == txlen) break; // If all transmit data pushed to hw spi buffer break from the loop + } + host->hw->data_buf[idx] = wd; + idx++; + if (idx == 16) { + // hw SPI buffer full (all 64 bytes filled, START THE TRANSSACTION + host->hw->mosi_dlen.usr_mosi_dbitlen=bits-1; // Set mosi dbitlen + + if ((duplex) && (rdcount > 0)) { + // In full duplex mode we are receiving while sending ! + host->hw->miso_dlen.usr_miso_dbitlen = bits-1; // Set miso dbitlen + host->hw->user.usr_miso = 1; + } + else { + host->hw->miso_dlen.usr_miso_dbitlen = 0; // In half duplex mode nothing will be received + host->hw->user.usr_miso = 0; + } + + // ** Start the transaction *** + host->hw->cmd.usr=1; + // Wait the transaction to finish + while (host->hw->cmd.usr); + + if ((duplex) && (rdcount > 0)) { + // *** in full duplex mode transfer received data to input buffer *** + rdidx = 0; + while (bits > 0) { + wd = host->hw->data_buf[rdidx]; + rdidx++; + for (bc=0;bc<32;bc+=8) { // get max 4 bytes + rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF); + rdcount--; + bits -= 8; + if (rdcount == 0) { + bits = 0; + break; // Finished reading data + } + } + } + } + bits = 0; // nothing in hw spi buffer yet + idx = 0; // start from the beginning of the hw spi buffer + } + } + // *** All transmit data are sent or pushed to hw spi buffer + // bits > 0 IF THERE ARE SOME DATA STILL WAITING IN THE HW SPI TRANSMIT BUFFER + if (bits > 0) { + // ** WE HAVE SOME DATA IN THE HW SPI TRANSMIT BUFFER + host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1; // Set mosi dbitlen + + if ((duplex) && (rdcount > 0)) { + // In full duplex mode we are receiving while sending ! + host->hw->miso_dlen.usr_miso_dbitlen = bits-1; // Set miso dbitlen + host->hw->user.usr_miso = 1; + } + else { + host->hw->miso_dlen.usr_miso_dbitlen = 0; // In half duplex mode nothing will be received + host->hw->user.usr_miso = 0; + } + + // ** Start the transaction *** + host->hw->cmd.usr=1; + // Wait the transaction to finish + while (host->hw->cmd.usr); + + if ((duplex) && (rdcount > 0)) { + // *** in full duplex mode transfer received data to input buffer *** + rdidx = 0; + while (bits > 0) { + wd = host->hw->data_buf[rdidx]; + rdidx++; + for (bc=0;bc<32;bc+=8) { // get max 4 bytes + rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF); + rdcount--; + bits -= 8; + if (bits == 0) break; + if (rdcount == 0) { + bits = 0; + break; // Finished reading data + } + } + } + } + } + //if (duplex) rdcount = 0; // In duplex mode receive only as many bytes as was transmitted + } + + // ------------------------------------------------------------------------ + // *** If rdcount = 0 we have nothing to receive and we exit the function + // This is true if no data receive was requested, + // or all the data was received in Full duplex mode during the transmission + // ------------------------------------------------------------------------ + if (rdcount > 0) { + // ---------------------------------------------------------------------------------------------------------------- + // *** rdcount > 0, we have to receive some data + // This is true if we operate in Half duplex mode when receiving after transmission is done, + // or not all data was received in Full duplex mode during the transmission (trans->rxlength > trans->txlength) + // ---------------------------------------------------------------------------------------------------------------- + host->hw->user.usr_mosi = 0; // do not send + host->hw->user.usr_miso = 1; // do receive + while (rdcount > 0) { + if (rdcount <= 64) rdbits = rdcount * 8; + else rdbits = 64 * 8; + + // Load receive buffer + host->hw->mosi_dlen.usr_mosi_dbitlen=0; + host->hw->miso_dlen.usr_miso_dbitlen=rdbits-1; + + // ** Start the transaction *** + host->hw->cmd.usr=1; + // Wait the transaction to finish + while (host->hw->cmd.usr); + + // *** transfer received data to input buffer *** + rdidx = 0; + while (rdbits > 0) { + wd = host->hw->data_buf[rdidx]; + rdidx++; + for (bc=0;bc<32;bc+=8) { + rxbuffer[rd_read++] = (uint8_t)((wd >> bc) & 0xFF); + rdcount--; + rdbits -= 8; + if (rdcount == 0) { + rdbits = 0; + break; + } + } + } + } + } + + // ** Call post-transmission callback, if any + if (handle->cfg.post_cb) handle->cfg.post_cb(trans); + + if (do_deselect) { + // Spi device was selected in this function, we have to deselect it now + ret = spi_lobo_device_deselect(handle); + if (ret) return ret; + } + + return ESP_OK; +} diff --git a/components/spidriver/spi_master_lobo.h b/components/spidriver/spi_master_lobo.h new file mode 100644 index 0000000..bca00ca --- /dev/null +++ b/components/spidriver/spi_master_lobo.h @@ -0,0 +1,354 @@ +// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#ifndef _DRIVER_SPI_MASTER_LOBO_H_ +#define _DRIVER_SPI_MASTER_LOBO_H_ + +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "soc/spi_struct.h" + +#include "esp_intr_alloc.h" +#include "esp32/rom/lldesc.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +//Maximum amount of bytes that can be put in one DMA descriptor +#define SPI_MAX_DMA_LEN (4096-4) + +/** + * @brief Enum with the three SPI peripherals that are software-accessible in it + */ +typedef enum { + TFT_SPI_HOST=0, ///< SPI1, SPI; Cannot be used in this driver! + TFT_HSPI_HOST=1, ///< SPI2, HSPI + TFT_VSPI_HOST=2 ///< SPI3, VSPI +} spi_lobo_host_device_t; + + +/** + * @brief This is a configuration structure for a SPI bus. + * + * You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the + * GPIO matrix to route the signals. An exception is made when all signals either can be routed through + * the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds. + */ +typedef struct { + int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used. + int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used. + int sclk_io_num; ///< GPIO pin for Spi CLocK signal, or -1 if not used. + int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used. + int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used. + int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0. +} spi_lobo_bus_config_t; + + +#define LB_SPI_DEVICE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first +#define LB_SPI_DEVICE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first +#define LB_SPI_DEVICE_BIT_LSBFIRST (SPI_TXBIT_LSBFIRST|SPI_RXBIT_LSBFIRST); ///< Transmit and receive LSB first +#define LB_SPI_DEVICE_3WIRE (1<<2) ///< Use spiq for both sending and receiving data +#define LB_SPI_DEVICE_POSITIVE_CS (1<<3) ///< Make CS positive during a transaction instead of negative +#define LB_SPI_DEVICE_HALFDUPLEX (1<<4) ///< Transmit data before receiving it, instead of simultaneously +#define LB_SPI_DEVICE_CLK_AS_CS (1<<5) ///< Output clock on CS line if CS is active + +#define SPI_ERR_OTHER_CONFIG 7001 + +typedef struct spi_lobo_transaction_t spi_lobo_transaction_t; +typedef void(*spi_lobo_transaction_cb_t)(spi_lobo_transaction_t *trans); + +/** + * @brief This is a configuration for a SPI slave device that is connected to one of the SPI buses. + */ +typedef struct { + uint8_t command_bits; ///< Amount of bits in command phase (0-16) + uint8_t address_bits; ///< Amount of bits in address phase (0-64) + uint8_t dummy_bits; ///< Amount of dummy bits to insert between address and data phase + uint8_t mode; ///< SPI mode (0-3) + uint8_t duty_cycle_pos; ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128. + uint8_t cs_ena_pretrans; ///< Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions. + uint8_t cs_ena_posttrans; ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16) + int clock_speed_hz; ///< Clock speed, in Hz + int spics_io_num; ///< CS GPIO pin for this device, handled by hardware; set to -1 if not used + int spics_ext_io_num; ///< CS GPIO pin for this device, handled by software (spi_lobo_device_select/spi_lobo_device_deselect); only used if spics_io_num=-1 + uint32_t flags; ///< Bitwise OR of LB_SPI_DEVICE_* flags + spi_lobo_transaction_cb_t pre_cb; ///< Callback to be called before a transmission is started. This callback from 'spi_lobo_transfer_data' function. + spi_lobo_transaction_cb_t post_cb; ///< Callback to be called after a transmission has completed. This callback from 'spi_lobo_transfer_data' function. + uint8_t selected; ///< **INTERNAL** 1 if the device's CS pin is active +} spi_lobo_device_interface_config_t; + + +#define LB_SPI_TRANS_MODE_DIO (1<<0) ///< Transmit/receive data in 2-bit mode +#define LB_SPI_TRANS_MODE_QIO (1<<1) ///< Transmit/receive data in 4-bit mode +#define LB_SPI_TRANS_MODE_DIOQIO_ADDR (1<<2) ///< Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO +#define LB_SPI_TRANS_USE_RXDATA (1<<3) ///< Receive into rx_data member of spi_lobo_transaction_t instead into memory at rx_buffer. +#define LB_SPI_TRANS_USE_TXDATA (1<<4) ///< Transmit tx_data member of spi_lobo_transaction_t instead of data at tx_buffer. Do not set tx_buffer when using this. + +/** + * This structure describes one SPI transmission + */ +struct spi_lobo_transaction_t { + uint32_t flags; ///< Bitwise OR of LB_SPI_TRANS_* flags + uint16_t command; ///< Command data. Specific length was given when device was added to the bus. + uint64_t address; ///< Address. Specific length was given when device was added to the bus. + size_t length; ///< Total data length to be transmitted to the device, in bits; if 0, no data is transmitted + size_t rxlength; ///< Total data length to be received from the device, in bits; if 0, no data is received + void *user; ///< User-defined variable. Can be used to store eg transaction ID or data to be used by pre_cb and/or post_cb callbacks. + union { + const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase + uint8_t tx_data[4]; ///< If SPI_USE_TXDATA is set, data set here is sent directly from this variable. + }; + union { + void *rx_buffer; ///< Pointer to receive buffer, or NULL for no MISO phase + uint8_t rx_data[4]; ///< If SPI_USE_RXDATA is set, data is received directly to this variable + }; +}; + +#define NO_CS 3 // Number of CS pins per SPI host +#define NO_DEV 6 // Number of spi devices per SPI host; more than 3 devices can be attached to the same bus if using software CS's +#define SPI_SEMAPHORE_WAIT 2000 // Time in ms to wait for SPI mutex + +typedef struct spi_lobo_device_t spi_lobo_device_t; + +typedef struct { + spi_lobo_device_t *device[NO_DEV]; + intr_handle_t intr; + spi_dev_t *hw; + //spi_lobo_transaction_t *cur_trans; + int cur_device; + lldesc_t *dmadesc_tx; + lldesc_t *dmadesc_rx; + bool no_gpio_matrix; + int dma_chan; + int max_transfer_sz; + QueueHandle_t spi_lobo_bus_mutex; + spi_lobo_bus_config_t cur_bus_config; +} spi_lobo_host_t; + +struct spi_lobo_device_t { + spi_lobo_device_interface_config_t cfg; + spi_lobo_host_t *host; + spi_lobo_bus_config_t bus_config; + spi_lobo_host_device_t host_dev; +}; + +typedef spi_lobo_device_t* spi_lobo_device_handle_t; ///< Handle for a device on a SPI bus +typedef spi_lobo_host_t* spi_lobo_host_handle_t; +typedef spi_lobo_device_interface_config_t* spi_lobo_device_interface_config_handle_t; + + +/** + * @brief Add a device. This allocates a CS line for the device, allocates memory for the device structure and hooks + * up the CS pin to whatever is specified. + * + * This initializes the internal structures for a device, plus allocates a CS pin on the indicated SPI master + * peripheral and routes it to the indicated GPIO. All SPI master devices have three hw CS pins and can thus control + * up to three devices. Software handled CS pin can also be used for additional devices on the same SPI bus. + * + * ### If selected SPI host device bus is not yet initialized, it is initialized first with 'bus_config' function ### + * + * @note While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are + * supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz. + * + * @param host SPI peripheral to allocate device on (HSPI or VSPI) + * @param dev_config SPI interface protocol config for the device + * @param bus_config Pointer to a spi_lobo_bus_config_t struct specifying how the host device bus should be initialized + * @param handle Pointer to variable to hold the device handle + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_NOT_FOUND if host doesn't have any free CS slots + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on success + */ +esp_err_t spi_lobo_bus_add_device(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, spi_lobo_device_interface_config_t *dev_config, spi_lobo_device_handle_t *handle); + +/** + * @brief Remove a device from the SPI bus. If after removal no other device is attached to the spi bus device, it is freed. + * + * @param handle Device handle to free + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_ERR_INVALID_STATE if device already is freed + * - ESP_OK on success + */ +esp_err_t spi_lobo_bus_remove_device(spi_lobo_device_handle_t handle); + + +/** + * @brief Return the actuall SPI bus speed for the spi device in Hz + * + * Some frequencies cannot be set, for example 30000000 will actually set SPI clock to 26666666 Hz + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @return + * - actuall SPI clock + */ +uint32_t spi_lobo_get_speed(spi_lobo_device_handle_t handle); + +/** + * @brief Set the new clock speed for the device, return the actuall SPI bus speed set, in Hz + * This function can be used after the device is initialized + * + * Some frequencies cannot be set, for example 30000000 will actually set SPI clock to 26666666 Hz + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * @param speed New device spi clock to be set in Hz + * + * @return + * - actuall SPI clock + * - 0 if speed cannot be set + */ +uint32_t spi_lobo_set_speed(spi_lobo_device_handle_t handle, uint32_t speed); + +/** + * @brief Select spi device for transmission + * + * It configures spi bus with selected spi device parameters if previously selected device was different than the current + * If device's spics_io_num=-1 and spics_ext_io_num > 0 'spics_ext_io_num' pin is set to active state (low) + * + * spi bus device's semaphore is taken before selecting the device + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * @param force configure spi bus even if the previous device was the same + * + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_OK on success + */ +esp_err_t spi_lobo_device_select(spi_lobo_device_handle_t handle, int force); + +/** + * @brief De-select spi device + * + * If device's spics_io_num=-1 and spics_ext_io_num > 0 'spics_ext_io_num' pin is set to inactive state (high) + * + * spi bus device's semaphore is given after selecting the device + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP_OK on success + */ +esp_err_t spi_lobo_device_deselect(spi_lobo_device_handle_t handle); + + +/** + * @brief Check if spi bus uses native spi pins + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @return + * - true if native spi pins are used + * - false if spi pins are routed through gpio matrix + */ +bool spi_lobo_uses_native_pins(spi_lobo_device_handle_t handle); + +/** + * @brief Get spi bus native spi pins + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @return + * places spi bus native pins in provided pointers + */ +void spi_lobo_get_native_pins(int host, int *sdi, int *sdo, int *sck); + +/** + * @brief Transimit and receive data to/from spi device based on transaction data + * + * TRANSMIT 8-bit data to spi device from 'trans->tx_buffer' or 'trans->tx_data' (trans->lenght/8 bytes) + * and RECEIVE data to 'trans->rx_buffer' or 'trans->rx_data' (trans->rx_length/8 bytes) + * Lengths must be 8-bit multiples! + * If trans->rx_buffer is NULL or trans->rx_length is 0, only transmits data + * If trans->tx_buffer is NULL or trans->length is 0, only receives data + * If the device is in duplex mode (LB_SPI_DEVICE_HALFDUPLEX flag NOT set), data are transmitted and received simultaneously. + * If the device is in half duplex mode (LB_SPI_DEVICE_HALFDUPLEX flag IS set), data are received after transmission + * 'address', 'command' and 'dummy bits' are transmitted before data phase IF set in device's configuration + * and IF 'trans->length' and 'trans->rx_length' are NOT both 0 + * If device was not previously selected, it will be selected before transmission and deselected after transmission. + * + * @param handle Device handle obtained using spi_lobo_bus_add_device + * + * @param trans Pointer to variable containing the description of the transaction that is executed + * + * @return + * - ESP_ERR_INVALID_ARG if parameter is invalid + * - ESP error code if device cannot be selected + * - ESP_OK on success + * + */ +esp_err_t spi_lobo_transfer_data(spi_lobo_device_handle_t handle, spi_lobo_transaction_t *trans); + + +/* + * SPI transactions uses the semaphore (taken in select function) to protect the transfer + */ +esp_err_t spi_lobo_device_TakeSemaphore(spi_lobo_device_handle_t handle); +void spi_lobo_device_GiveSemaphore(spi_lobo_device_handle_t handle); + + +/** + * @brief Setup a DMA link chain + * + * This routine will set up a chain of linked DMA descriptors in the array pointed to by + * ``dmadesc``. Enough DMA descriptors will be used to fit the buffer of ``len`` bytes in, and the + * descriptors will point to the corresponding positions in ``buffer`` and linked together. The + * end result is that feeding ``dmadesc[0]`` into DMA hardware results in the entirety ``len`` bytes + * of ``data`` being read or written. + * + * @param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ``len`` bytes + * @param len Length of buffer + * @param data Data buffer to use for DMA transfer + * @param isrx True if data is to be written into ``data``, false if it's to be read from ``data``. + */ +void spi_lobo_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx); + +/** + * @brief Check if a DMA reset is requested but has not completed yet + * + * @return True when a DMA reset is requested but hasn't completed yet. False otherwise. + */ +bool spi_lobo_dmaworkaround_reset_in_progress(); + + +/** + * @brief Mark a DMA channel as idle. + * + * A call to this function tells the workaround logic that this channel will + * not be affected by a global SPI DMA reset. + */ +void spi_lobo_dmaworkaround_idle(int dmachan); + +/** + * @brief Mark a DMA channel as active. + * + * A call to this function tells the workaround logic that this channel will + * be affected by a global SPI DMA reset, and a reset like that should not be attempted. + */ +void spi_lobo_dmaworkaround_transfer_active(int dmachan); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/tft/CMakeLists.txt b/components/tft/CMakeLists.txt new file mode 100644 index 0000000..a5f8712 --- /dev/null +++ b/components/tft/CMakeLists.txt @@ -0,0 +1,4 @@ +FILE(GLOB SOURCES *.c) +idf_component_register(SRCS ${SOURCES} + INCLUDE_DIRS "." + REQUIRES spidriver) diff --git a/components/tft/DefaultFont.c b/components/tft/DefaultFont.c new file mode 100644 index 0000000..3e3c2a0 --- /dev/null +++ b/components/tft/DefaultFont.c @@ -0,0 +1,333 @@ +// Default font + +// ======================================================================== +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// Header Format: +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset (start Y of visible pixels) +// Width (width of the visible pixels) +// Height (height of the visible pixels) +// xOffset (start X of visible pixels) +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. +// ======================================================================== + +// dejavu +// Point Size : 12 +// Memory usage : 1158 bytes +// # characters : 95 + +const unsigned char tft_DefaultFont[] = +{ +0x00, 0x0B, 0x86, 0x04, + +// ' ' +0x20,0x0A,0x00,0x00,0x00,0x04, + +// '!' +0x21,0x01,0x01,0x09,0x02,0x05, +0xFD,0x80, +// '"' +0x22,0x01,0x03,0x03,0x01,0x05, +0xB6,0x80, +// '#' +0x23,0x02,0x08,0x08,0x01,0x0A, +0x12,0x14,0x7F,0x24,0x24,0xFE,0x28,0x48, +// '$' +0x24,0x01,0x06,0x0B,0x02,0x08, +0x21,0xCA,0xA8,0xE0,0xE2,0xAA,0x70,0x82,0x00, +// '%' +0x25,0x01,0x0A,0x09,0x00,0x0B, +0x61,0x24,0x89,0x22,0x50,0x6D,0x82,0x91,0x24,0x49,0x21,0x80, +// '&' +0x26,0x01,0x09,0x09,0x01,0x0A, +0x30,0x24,0x10,0x0C,0x05,0x14,0x4A,0x19,0x8C,0x7B,0x00, +// ''' +0x27,0x01,0x01,0x03,0x01,0x03, +0xE0, +// '(' +0x28,0x00,0x03,0x0B,0x01,0x05, +0x69,0x49,0x24,0x48,0x80, +// ')' +0x29,0x00,0x03,0x0B,0x01,0x05, +0x89,0x12,0x49,0x4A,0x00, +// '*' +0x2A,0x01,0x05,0x06,0x01,0x06, +0x25,0x5C,0xEA,0x90, +// '+' +0x2B,0x03,0x07,0x07,0x01,0x0A, +0x10,0x20,0x47,0xF1,0x02,0x04,0x00, +// ',' +0x2C,0x08,0x01,0x03,0x01,0x04, +0xE0, +// '-' +0x2D,0x06,0x03,0x01,0x01,0x04, +0xE0, +// '.' +0x2E,0x08,0x01,0x02,0x01,0x04, +0xC0, +// '/' +0x2F,0x01,0x04,0x0A,0x00,0x04, +0x11,0x22,0x24,0x44,0x88, +// '0' +0x30,0x01,0x06,0x09,0x01,0x08, +0x79,0x28,0x61,0x86,0x18,0x52,0x78, +// '1' +0x31,0x01,0x05,0x09,0x01,0x08, +0xE1,0x08,0x42,0x10,0x84,0xF8, +// '2' +0x32,0x01,0x07,0x09,0x01,0x08, +0x79,0x18,0x10,0x20,0x82,0x08,0x20,0xFC, +// '3' +0x33,0x01,0x06,0x09,0x01,0x08, +0x7A,0x10,0x41,0x38,0x30,0x63,0x78, +// '4' +0x34,0x01,0x06,0x09,0x01,0x08, +0x18,0x62,0x92,0x4A,0x2F,0xC2,0x08, +// '5' +0x35,0x01,0x06,0x09,0x01,0x08, +0xFA,0x08,0x3C,0x0C,0x10,0x63,0x78, +// '6' +0x36,0x01,0x06,0x09,0x01,0x08, +0x39,0x18,0x3E,0xCE,0x18,0x53,0x78, +// '7' +0x37,0x01,0x06,0x09,0x01,0x08, +0xFC,0x10,0x82,0x10,0x42,0x08,0x40, +// '8' +0x38,0x01,0x06,0x09,0x01,0x08, +0x7B,0x38,0x73,0x7B,0x38,0x73,0x78, +// '9' +0x39,0x01,0x06,0x09,0x01,0x08, +0x7B,0x28,0x61,0xCD,0xD0,0x62,0x70, +// ':' +0x3A,0x04,0x01,0x06,0x01,0x04, +0xCC, +// ';' +0x3B,0x04,0x01,0x07,0x01,0x04, +0xCE, +// '<' +0x3C,0x03,0x08,0x06,0x01,0x0A, +0x03,0x1E,0xE0,0xE0,0x1E,0x03, +// '=' +0x3D,0x05,0x08,0x03,0x01,0x0A, +0xFF,0x00,0xFF, +// '>' +0x3E,0x03,0x08,0x06,0x01,0x0A, +0xC0,0x78,0x07,0x07,0x78,0xC0, +// '?' +0x3F,0x01,0x05,0x09,0x00,0x06, +0x74,0x42,0x22,0x10,0x04,0x20, +// '@' +0x40,0x01,0x0B,0x0B,0x01,0x0D, +0x1F,0x06,0x19,0x01,0x46,0x99,0x13,0x22,0x64,0x54,0x6C,0x40,0x04,0x10,0x7C,0x00, +// 'A' +0x41,0x01,0x08,0x09,0x00,0x08, +0x18,0x18,0x24,0x24,0x24,0x42,0x7E,0x42,0x81, +// 'B' +0x42,0x01,0x06,0x09,0x01,0x08, +0xFA,0x18,0x61,0xFA,0x18,0x61,0xF8, +// 'C' +0x43,0x01,0x06,0x09,0x01,0x08, +0x39,0x18,0x20,0x82,0x08,0x11,0x38, +// 'D' +0x44,0x01,0x07,0x09,0x01,0x09, +0xF9,0x0A,0x0C,0x18,0x30,0x60,0xC2,0xF8, +// 'E' +0x45,0x01,0x06,0x09,0x01,0x08, +0xFE,0x08,0x20,0xFE,0x08,0x20,0xFC, +// 'F' +0x46,0x01,0x05,0x09,0x01,0x07, +0xFC,0x21,0x0F,0xC2,0x10,0x80, +// 'G' +0x47,0x01,0x07,0x09,0x01,0x09, +0x3C,0x86,0x04,0x08,0xF0,0x60,0xA1,0x3C, +// 'H' +0x48,0x01,0x07,0x09,0x01,0x09, +0x83,0x06,0x0C,0x1F,0xF0,0x60,0xC1,0x82, +// 'I' +0x49,0x01,0x01,0x09,0x01,0x03, +0xFF,0x80, +// 'J' +0x4A,0x01,0x03,0x0B,0xFF,0x03, +0x24,0x92,0x49,0x27,0x00, +// 'K' +0x4B,0x01,0x07,0x09,0x01,0x07, +0x85,0x12,0x45,0x0C,0x14,0x24,0x44,0x84, +// 'L' +0x4C,0x01,0x05,0x09,0x01,0x06, +0x84,0x21,0x08,0x42,0x10,0xF8, +// 'M' +0x4D,0x01,0x08,0x09,0x01,0x0A, +0x81,0xC3,0xC3,0xA5,0xA5,0x99,0x99,0x81,0x81, +// 'N' +0x4E,0x01,0x07,0x09,0x01,0x09, +0xC3,0x86,0x8D,0x19,0x31,0x62,0xC3,0x86, +// 'O' +0x4F,0x01,0x07,0x09,0x01,0x09, +0x38,0x8A,0x0C,0x18,0x30,0x60,0xA2,0x38, +// 'P' +0x50,0x01,0x06,0x09,0x01,0x08, +0xFA,0x38,0x63,0xFA,0x08,0x20,0x80, +// 'Q' +0x51,0x01,0x07,0x0B,0x01,0x09, +0x38,0x8A,0x0C,0x18,0x30,0x60,0xA2,0x38,0x10,0x10, +// 'R' +0x52,0x01,0x07,0x09,0x01,0x08, +0xF9,0x1A,0x14,0x6F,0x91,0x21,0x42,0x82, +// 'S' +0x53,0x01,0x06,0x09,0x01,0x08, +0x7B,0x18,0x30,0x78,0x30,0x63,0x78, +// 'T' +0x54,0x01,0x07,0x09,0x00,0x07, +0xFE,0x20,0x40,0x81,0x02,0x04,0x08,0x10, +// 'U' +0x55,0x01,0x07,0x09,0x01,0x09, +0x83,0x06,0x0C,0x18,0x30,0x60,0xA2,0x38, +// 'V' +0x56,0x01,0x0A,0x09,0xFF,0x08, +0x40,0x90,0x22,0x10,0x84,0x21,0x04,0x81,0x20,0x30,0x0C,0x00, +// 'W' +0x57,0x01,0x0B,0x09,0x00,0x0B, +0x84,0x28,0x89,0x11,0x27,0x22,0xA8,0x55,0x0E,0xE0,0x88,0x11,0x00, +// 'X' +0x58,0x01,0x07,0x09,0x00,0x07, +0xC6,0x88,0xA1,0xC1,0x07,0x0A,0x22,0x82, +// 'Y' +0x59,0x01,0x07,0x09,0x00,0x07, +0x82,0x89,0x11,0x43,0x82,0x04,0x08,0x10, +// 'Z' +0x5A,0x01,0x07,0x09,0x01,0x09, +0xFE,0x04,0x10,0x41,0x04,0x10,0x40,0xFE, +// '[' +0x5B,0x01,0x02,0x0B,0x02,0x05, +0xEA,0xAA,0xAC, +// '\' +0x5C,0x01,0x04,0x0A,0x00,0x04, +0x88,0x44,0x42,0x22,0x11, +// ']' +0x5D,0x01,0x02,0x0B,0x01,0x05, +0xD5,0x55,0x5C, +// '^' +0x5E,0x01,0x08,0x03,0x01,0x0A, +0x18,0x24,0x42, +// '_' +0x5F,0x0C,0x06,0x01,0x00,0x06, +0xFC, +// '`' +0x60,0x00,0x03,0x02,0x01,0x06, +0x44, +// 'a' +0x61,0x03,0x06,0x07,0x01,0x08, +0x7A,0x30,0x5F,0x86,0x37,0x40, +// 'b' +0x62,0x00,0x06,0x0A,0x01,0x08, +0x82,0x08,0x2E,0xCA,0x18,0x61,0xCE,0xE0, +// 'c' +0x63,0x03,0x05,0x07,0x01,0x07, +0x72,0x61,0x08,0x25,0xC0, +// 'd' +0x64,0x00,0x06,0x0A,0x01,0x08, +0x04,0x10,0x5D,0xCE,0x18,0x61,0xCD,0xD0, +// 'e' +0x65,0x03,0x06,0x07,0x01,0x08, +0x39,0x38,0x7F,0x81,0x13,0x80, +// 'f' +0x66,0x00,0x04,0x0A,0x00,0x04, +0x34,0x4F,0x44,0x44,0x44, +// 'g' +0x67,0x03,0x06,0x0A,0x01,0x08, +0x77,0x38,0x61,0x87,0x37,0x41,0x4C,0xE0, +// 'h' +0x68,0x00,0x06,0x0A,0x01,0x08, +0x82,0x08,0x2E,0xC6,0x18,0x61,0x86,0x10, +// 'i' +0x69,0x01,0x01,0x09,0x01,0x03, +0xBF,0x80, +// 'j' +0x6A,0x01,0x02,0x0C,0x00,0x03, +0x45,0x55,0x56, +// 'k' +0x6B,0x00,0x06,0x0A,0x01,0x07, +0x82,0x08,0x22,0x92,0x8E,0x28,0x92,0x20, +// 'l' +0x6C,0x00,0x01,0x0A,0x01,0x03, +0xFF,0xC0, +// 'm' +0x6D,0x03,0x09,0x07,0x01,0x0B, +0xB3,0x66,0x62,0x31,0x18,0x8C,0x46,0x22, +// 'n' +0x6E,0x03,0x06,0x07,0x01,0x08, +0xBB,0x18,0x61,0x86,0x18,0x40, +// 'o' +0x6F,0x03,0x06,0x07,0x01,0x08, +0x7B,0x38,0x61,0x87,0x37,0x80, +// 'p' +0x70,0x03,0x06,0x0A,0x01,0x08, +0xBB,0x28,0x61,0x87,0x3B,0xA0,0x82,0x00, +// 'q' +0x71,0x03,0x06,0x0A,0x01,0x08, +0x77,0x38,0x61,0x87,0x37,0x41,0x04,0x10, +// 'r' +0x72,0x03,0x04,0x07,0x01,0x05, +0xBC,0x88,0x88,0x80, +// 's' +0x73,0x03,0x06,0x07,0x01,0x07, +0x72,0x28,0x1C,0x0A,0x27,0x00, +// 't' +0x74,0x01,0x04,0x09,0x00,0x05, +0x44,0xF4,0x44,0x44,0x30, +// 'u' +0x75,0x03,0x06,0x07,0x01,0x08, +0x86,0x18,0x61,0x86,0x37,0x40, +// 'v' +0x76,0x03,0x08,0x07,0xFF,0x06, +0x42,0x42,0x24,0x24,0x24,0x18,0x18, +// 'w' +0x77,0x03,0x09,0x07,0x00,0x09, +0x88,0xC4,0x57,0x4A,0xA5,0x51,0x10,0x88, +// 'x' +0x78,0x03,0x06,0x07,0x00,0x06, +0x85,0x24,0x8C,0x49,0x28,0x40, +// 'y' +0x79,0x03,0x08,0x0A,0xFF,0x06, +0x42,0x42,0x24,0x24,0x14,0x18,0x08,0x08,0x10,0x60, +// 'z' +0x7A,0x03,0x05,0x07,0x00,0x05, +0xF8,0x44,0x44,0x43,0xE0, +// '{' +0x7B,0x01,0x05,0x0B,0x02,0x08, +0x19,0x08,0x42,0x60,0x84,0x21,0x06, +// '|' +0x7C,0x01,0x01,0x0C,0x02,0x04, +0xFF,0xF0, +// '}' +0x7D,0x01,0x05,0x0B,0x01,0x08, +0xC1,0x08,0x42,0x0C,0x84,0x21,0x30, +// '~' +0x7E,0x04,0x08,0x03,0x01,0x0A, +0x00,0x71,0x8E, + +// Terminator +0xFF +}; diff --git a/components/tft/DejaVuSans18.c b/components/tft/DejaVuSans18.c new file mode 100644 index 0000000..b9e6ba9 --- /dev/null +++ b/components/tft/DejaVuSans18.c @@ -0,0 +1,322 @@ +// ============================================================================ +// Proportional font Header Format: +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. +// ============================================================================ + +// DejaVuSans +// Point Size : 18 +// Memory usage : 1828 bytes +// # characters : 95 + +const unsigned char tft_Dejavu18[] = +{ +0x00, 0x12, 0x00, 0x00, + +// ' ' +0x20,0x0E,0x00,0x00,0x00,0x06, + +// '!' +0x21,0x01,0x02,0x0D,0x03,0x07, +0xFF,0xFF,0xC3,0xC0, +// '"' +0x22,0x01,0x06,0x05,0x01,0x08, +0xCF,0x3C,0xF3,0xCC, +// '#' +0x23,0x00,0x0C,0x0E,0x01,0x0F, +0x04,0x40,0x44,0x0C,0xC0,0xC8,0x7F,0xF7,0xFF,0x09,0x81,0x90,0xFF,0xEF,0xFE,0x13,0x03,0x30,0x32,0x02,0x20, +// '$' +0x24,0x00,0x0A,0x11,0x01,0x0B, +0x08,0x02,0x03,0xE1,0xFC,0xE9,0x32,0x0F,0x81,0xF8,0x0F,0x02,0x60,0x9A,0x2E,0xFF,0x1F,0x80,0x80,0x20,0x08,0x00, +// '%' +0x25,0x01,0x0F,0x0D,0x01,0x11, +0x78,0x10,0x90,0x43,0x31,0x86,0x62,0x0C,0xC8,0x19,0x10,0x1E,0x4F,0x01,0x12,0x02,0x66,0x08,0xCC,0x31,0x98,0x41,0x21,0x03,0xC0, +// '&' +0x26,0x01,0x0C,0x0D,0x01,0x0D, +0x0F,0x01,0xF8,0x30,0x83,0x00,0x38,0x03,0xC0,0x7E,0x6C,0x76,0xC3,0xCC,0x18,0xE1,0xC7,0xFE,0x3E,0x70, +// ''' +0x27,0x01,0x02,0x05,0x01,0x04, +0xFF,0xC0, +// '(' +0x28,0x00,0x04,0x10,0x02,0x07, +0x32,0x66,0x4C,0xCC,0xCC,0xC4,0x66,0x23, +// ')' +0x29,0x00,0x04,0x10,0x01,0x07, +0xC4,0x66,0x23,0x33,0x33,0x32,0x66,0x4C, +// '*' +0x2A,0x01,0x07,0x08,0x01,0x09, +0x11,0x25,0x51,0xC3,0x8A,0xA4,0x88, +// '+' +0x2B,0x02,0x0C,0x0C,0x02,0x0F, +0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x0F,0xFF,0xFF,0xF0,0x60,0x06,0x00,0x60,0x06,0x00,0x60, +// ',' +0x2C,0x0C,0x03,0x04,0x01,0x06, +0x6D,0x40, +// '-' +0x2D,0x08,0x05,0x02,0x01,0x07, +0xFF,0xC0, +// '.' +0x2E,0x0C,0x02,0x02,0x02,0x06, +0xF0, +// '/' +0x2F,0x01,0x06,0x0F,0x00,0x06, +0x0C,0x31,0x86,0x18,0xE3,0x0C,0x31,0xC6,0x18,0x63,0x0C,0x00, +// '0' +0x30,0x01,0x09,0x0D,0x01,0x0B, +0x3E,0x3F,0x98,0xD8,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xD8,0xCF,0xE3,0xE0, +// '1' +0x31,0x01,0x08,0x0D,0x02,0x0B, +0x38,0xF8,0xD8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0xFF, +// '2' +0x32,0x01,0x09,0x0D,0x01,0x0B, +0x7C,0x7F,0x21,0xC0,0x60,0x30,0x30,0x18,0x18,0x18,0x18,0x18,0x1F,0xEF,0xF0, +// '3' +0x33,0x01,0x09,0x0D,0x01,0x0B, +0x7E,0x7F,0xA0,0xE0,0x30,0x39,0xF0,0xFC,0x07,0x01,0x80,0xE0,0xFF,0xE7,0xE0, +// '4' +0x34,0x01,0x0A,0x0D,0x01,0x0B, +0x07,0x01,0xC0,0xB0,0x6C,0x13,0x08,0xC6,0x31,0x0C,0xFF,0xFF,0xF0,0x30,0x0C,0x03,0x00, +// '5' +0x35,0x01,0x08,0x0D,0x01,0x0B, +0x7E,0x7E,0x60,0x60,0x7C,0x7E,0x47,0x03,0x03,0x03,0x87,0xFE,0x7C, +// '6' +0x36,0x01,0x09,0x0D,0x01,0x0B, +0x1E,0x1F,0x9C,0x5C,0x0C,0x06,0xF3,0xFD,0xC7,0xC1,0xE0,0xD8,0xEF,0xE1,0xE0, +// '7' +0x37,0x01,0x08,0x0D,0x01,0x0B, +0xFF,0xFF,0x06,0x06,0x06,0x0E,0x0C,0x0C,0x1C,0x18,0x18,0x38,0x30, +// '8' +0x38,0x01,0x09,0x0D,0x01,0x0B, +0x3E,0x3F,0xB8,0xF8,0x3E,0x39,0xF1,0xFD,0xC7,0xC1,0xE0,0xF8,0xEF,0xE3,0xE0, +// '9' +0x39,0x01,0x09,0x0D,0x01,0x0B, +0x3C,0x3F,0xB8,0xD8,0x3C,0x1F,0x1D,0xFE,0x7B,0x01,0x81,0xD1,0xCF,0xC3,0xC0, +// ':' +0x3A,0x05,0x02,0x09,0x02,0x06, +0xF0,0x03,0xC0, +// ';' +0x3B,0x05,0x03,0x0B,0x01,0x06, +0x6C,0x00,0x03,0x6A,0x00, +// '<' +0x3C,0x04,0x0B,0x0A,0x02,0x0F, +0x00,0x20,0x3C,0x1F,0x1F,0x0F,0x81,0xF0,0x0F,0x80,0x3E,0x01,0xE0,0x04, +// '=' +0x3D,0x05,0x0B,0x06,0x02,0x0F, +0xFF,0xFF,0xFC,0x00,0x00,0x0F,0xFF,0xFF,0xC0, +// '>' +0x3E,0x04,0x0B,0x0A,0x02,0x0F, +0x80,0x1E,0x01,0xF0,0x07,0xC0,0x3E,0x07,0xC3,0xE3,0xE0,0xF0,0x10,0x00, +// '?' +0x3F,0x01,0x07,0x0D,0x01,0x0A, +0x79,0xFA,0x38,0x30,0x61,0x86,0x18,0x30,0x60,0x01,0x83,0x00, +// '@' +0x40,0x01,0x10,0x10,0x01,0x12, +0x07,0xE0,0x1F,0xF8,0x3C,0x1C,0x70,0x06,0x60,0x07,0xE3,0x63,0xC7,0xE3,0xC6,0x63,0xC6,0x66,0xC7,0xFC,0xE3,0x70,0x60,0x00,0x70,0x00,0x3C,0x30,0x1F,0xF0,0x07,0xC0, +// 'A' +0x41,0x01,0x0C,0x0D,0x00,0x0C, +0x06,0x00,0x60,0x0F,0x00,0xF0,0x19,0x81,0x98,0x19,0x83,0x0C,0x3F,0xC7,0xFE,0x60,0x66,0x06,0xC0,0x30, +// 'B' +0x42,0x01,0x09,0x0D,0x02,0x0C, +0xFC,0x7F,0xB0,0xD8,0x6C,0x37,0xF3,0xF9,0x86,0xC1,0xE0,0xF0,0xFF,0xEF,0xE0, +// 'C' +0x43,0x01,0x0B,0x0D,0x01,0x0D, +0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x9F,0xF0,0xFC, +// 'D' +0x44,0x01,0x0B,0x0D,0x02,0x0E, +0xFE,0x1F,0xF3,0x07,0x60,0x6C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1B,0x07,0x7F,0xCF,0xE0, +// 'E' +0x45,0x01,0x08,0x0D,0x02,0x0B, +0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF, +// 'F' +0x46,0x01,0x08,0x0D,0x02,0x0A, +0xFF,0xFF,0xC0,0xC0,0xC0,0xFE,0xFE,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, +// 'G' +0x47,0x01,0x0B,0x0D,0x01,0x0E, +0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x87,0xF0,0xFE,0x03,0xC0,0x6C,0x0D,0xC1,0x9F,0xE0,0xF8, +// 'H' +0x48,0x01,0x0A,0x0D,0x02,0x0E, +0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xFF,0xFF,0xFF,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xC0, +// 'I' +0x49,0x01,0x02,0x0D,0x02,0x06, +0xFF,0xFF,0xFF,0xC0, +// 'J' +0x4A,0x01,0x05,0x11,0xFF,0x06, +0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0xFE,0xE0, +// 'K' +0x4B,0x01,0x0B,0x0D,0x02,0x0C, +0xC1,0x98,0x63,0x18,0x66,0x0D,0x81,0xE0,0x3C,0x06,0xC0,0xCC,0x18,0xC3,0x0C,0x60,0xCC,0x0C, +// 'L' +0x4C,0x01,0x08,0x0D,0x02,0x0A, +0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF, +// 'M' +0x4D,0x01,0x0C,0x0D,0x02,0x10, +0xE0,0x7F,0x0F,0xF0,0xFD,0x8B,0xD9,0xBD,0x9B,0xCF,0x3C,0xF3,0xC6,0x3C,0x63,0xC0,0x3C,0x03,0xC0,0x30, +// 'N' +0x4E,0x01,0x0A,0x0D,0x02,0x0E, +0xE0,0xF8,0x3F,0x0F,0xC3,0xD8,0xF6,0x3C,0xCF,0x1B,0xC6,0xF0,0xFC,0x3F,0x07,0xC1,0xC0, +// 'O' +0x4F,0x01,0x0C,0x0D,0x01,0x0E, +0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80, +// 'P' +0x50,0x01,0x08,0x0D,0x02,0x0B, +0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0, +// 'Q' +0x51,0x01,0x0C,0x0F,0x01,0x0E, +0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,0x18,0x00,0xC0, +// 'R' +0x52,0x01,0x0A,0x0D,0x02,0x0D, +0xFC,0x3F,0x8C,0x73,0x0C,0xC3,0x31,0xCF,0xE3,0xF0,0xC6,0x30,0xCC,0x33,0x06,0xC1,0xC0, +// 'S' +0x53,0x01,0x0A,0x0D,0x01,0x0B, +0x3E,0x1F,0xCE,0x13,0x00,0xC0,0x1F,0x03,0xF0,0x0E,0x01,0x80,0x68,0x3B,0xFC,0x7E,0x00, +// 'T' +0x54,0x01,0x0C,0x0D,0x00,0x0C, +0xFF,0xFF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00, +// 'U' +0x55,0x01,0x0A,0x0D,0x02,0x0E, +0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x36,0x19,0xFE,0x1E,0x00, +// 'V' +0x56,0x01,0x0C,0x0D,0x00,0x0C, +0xC0,0x36,0x06,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,0x06,0x00, +// 'W' +0x57,0x01,0x11,0x0D,0x01,0x13, +0xC1,0xC1,0xE0,0xE0,0xD8,0xF8,0xCC,0x6C,0x66,0x36,0x33,0x1B,0x18,0xD8,0xD8,0x6C,0x6C,0x36,0x36,0x1F,0x1F,0x07,0x07,0x03,0x83,0x81,0xC1,0xC0, +// 'X' +0x58,0x01,0x0B,0x0D,0x01,0x0D, +0x70,0xE6,0x18,0xE6,0x0D,0xC0,0xF0,0x1C,0x03,0x80,0x78,0x1B,0x07,0x30,0xC7,0x30,0x6E,0x0E, +// 'Y' +0x59,0x01,0x0C,0x0D,0x00,0x0C, +0xE0,0x76,0x06,0x30,0xC1,0x98,0x19,0x80,0xF0,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00, +// 'Z' +0x5A,0x01,0x0B,0x0D,0x01,0x0D, +0xFF,0xFF,0xFC,0x07,0x01,0xC0,0x30,0x0E,0x03,0x80,0xE0,0x18,0x06,0x01,0xC0,0x7F,0xFF,0xFE, +// '[' +0x5B,0x00,0x04,0x10,0x01,0x07, +0xFF,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFF, +// '\' +0x5C,0x01,0x06,0x0F,0x00,0x06, +0xC3,0x06,0x18,0x61,0xC3,0x0C,0x30,0xE1,0x86,0x18,0x30,0xC0, +// ']' +0x5D,0x00,0x04,0x10,0x02,0x07, +0xFF,0x33,0x33,0x33,0x33,0x33,0x33,0xFF, +// '^' +0x5E,0x01,0x0B,0x05,0x02,0x0F, +0x0E,0x03,0xE0,0xC6,0x30,0x6C,0x06, +// '_' +0x5F,0x10,0x09,0x02,0x00,0x09, +0xFF,0xFF,0xC0, +// '`' +0x60,0x00,0x04,0x03,0x02,0x09, +0xC6,0x30, +// 'a' +0x61,0x04,0x08,0x0A,0x01,0x0A, +0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B, +// 'b' +0x62,0x00,0x09,0x0E,0x02,0x0B, +0xC0,0x60,0x30,0x18,0x0D,0xE7,0xFB,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x7F,0xF6,0xF0, +// 'c' +0x63,0x04,0x08,0x0A,0x01,0x09, +0x1E,0x7F,0x61,0xC0,0xC0,0xC0,0xC0,0x61,0x7F,0x1E, +// 'd' +0x64,0x00,0x09,0x0E,0x01,0x0B, +0x01,0x80,0xC0,0x60,0x33,0xDB,0xFF,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x77,0xF9,0xEC, +// 'e' +0x65,0x04,0x0A,0x0A,0x01,0x0B, +0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0, +// 'f' +0x66,0x00,0x07,0x0E,0x00,0x06, +0x1E,0x7C,0xC1,0x8F,0xFF,0xCC,0x18,0x30,0x60,0xC1,0x83,0x06,0x00, +// 'g' +0x67,0x04,0x09,0x0E,0x01,0x0B, +0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x68,0x67,0xF1,0xF0, +// 'h' +0x68,0x00,0x08,0x0E,0x02,0x0B, +0xC0,0xC0,0xC0,0xC0,0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3, +// 'i' +0x69,0x00,0x02,0x0E,0x02,0x05, +0xF0,0xFF,0xFF,0xF0, +// 'j' +0x6A,0x00,0x04,0x12,0x00,0x05, +0x33,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0xEC, +// 'k' +0x6B,0x00,0x09,0x0E,0x02,0x0A, +0xC0,0x60,0x30,0x18,0x0C,0x36,0x33,0x31,0xB0,0xF0,0x78,0x36,0x19,0x8C,0x66,0x18, +// 'l' +0x6C,0x00,0x02,0x0E,0x02,0x05, +0xFF,0xFF,0xFF,0xF0, +// 'm' +0x6D,0x04,0x0E,0x0A,0x02,0x11, +0xDC,0x7B,0xFB,0xEE,0x79,0xF0,0xC3,0xC3,0x0F,0x0C,0x3C,0x30,0xF0,0xC3,0xC3,0x0F,0x0C,0x30, +// 'n' +0x6E,0x04,0x08,0x0A,0x02,0x0B, +0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3, +// 'o' +0x6F,0x04,0x0A,0x0A,0x01,0x0B, +0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80, +// 'p' +0x70,0x04,0x09,0x0E,0x02,0x0B, +0xDE,0x7F,0xB8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0xFF,0x6F,0x30,0x18,0x0C,0x06,0x00, +// 'q' +0x71,0x04,0x09,0x0E,0x01,0x0B, +0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x60,0x30,0x18,0x0C, +// 'r' +0x72,0x04,0x06,0x0A,0x02,0x08, +0xDF,0xFE,0x30,0xC3,0x0C,0x30,0xC3,0x00, +// 's' +0x73,0x04,0x08,0x0A,0x01,0x08, +0x7C,0xFE,0xC2,0xE0,0x7C,0x1E,0x06,0x86,0xFE,0x78, +// 't' +0x74,0x01,0x06,0x0D,0x01,0x07, +0x61,0x86,0x3F,0xFD,0x86,0x18,0x61,0x86,0x1F,0x3C, +// 'u' +0x75,0x04,0x08,0x0A,0x02,0x0B, +0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B, +// 'v' +0x76,0x04,0x0C,0x0A,0x00,0x0B, +0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60, +// 'w' +0x77,0x04,0x0F,0x0A,0x01,0x10, +0x63,0x8C,0xC7,0x19,0x8E,0x31,0xB6,0xC3,0x6D,0x86,0xDB,0x0F,0x1E,0x0E,0x38,0x1C,0x70,0x38,0xE0, +// 'x' +0x78,0x04,0x0A,0x0A,0x01,0x0B, +0xE1,0xD8,0x63,0x30,0xCC,0x1E,0x07,0x83,0x30,0xCC,0x61,0xB8,0x70, +// 'y' +0x79,0x04,0x0C,0x0E,0x00,0x0B, +0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80, +// 'z' +0x7A,0x04,0x08,0x0A,0x01,0x09, +0xFF,0xFF,0x06,0x0C,0x1C,0x38,0x30,0x70,0xFF,0xFF, +// '{' +0x7B,0x00,0x08,0x11,0x02,0x0B, +0x0F,0x1F,0x18,0x18,0x18,0x18,0x38,0xF0,0xF0,0x38,0x18,0x18,0x18,0x18,0x18,0x1F,0x0F, +// '|' +0x7C,0x00,0x02,0x12,0x02,0x06, +0xFF,0xFF,0xFF,0xFF,0xF0, +// '}' +0x7D,0x00,0x08,0x11,0x02,0x0B, +0xF0,0xF8,0x18,0x18,0x18,0x18,0x1C,0x0F,0x0F,0x1C,0x18,0x18,0x18,0x18,0x18,0xF8,0xF0, +// '~' +0x7E,0x05,0x0B,0x05,0x02,0x0F, +0x00,0x0F,0x87,0xFF,0xC3,0xE0,0x00, + +// Terminator +0xFF +}; diff --git a/components/tft/DejaVuSans24.c b/components/tft/DejaVuSans24.c new file mode 100644 index 0000000..aa7e2f1 --- /dev/null +++ b/components/tft/DejaVuSans24.c @@ -0,0 +1,331 @@ +// ======================================================================== +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// Header Format: +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. +// ======================================================================== + +// dejavu +// Point Size : 24 +// Memory usage : 2724 bytes +// # characters : 95 + +const unsigned char tft_Dejavu24[] = +{ +0x00, 0x17, 0x00, 0x00, + +// ' ' +0x20,0x13,0x00,0x00,0x00,0x08, + +// '!' +0x21,0x01,0x02,0x12,0x04,0x0A, +0xFF,0xFF,0xFF,0x03,0xF0, +// '"' +0x22,0x01,0x06,0x07,0x02,0x0B, +0xCF,0x3C,0xF3,0xCF,0x3C,0xC0, +// '#' +0x23,0x01,0x10,0x12,0x02,0x14, +0x03,0x08,0x03,0x18,0x03,0x18,0x03,0x18,0x02,0x18,0x7F,0xFF,0x7F,0xFF,0x06,0x30,0x04,0x30,0x0C,0x20,0x0C,0x60,0xFF,0xFE,0xFF,0xFE,0x18,0x40,0x18,0xC0,0x18,0xC0,0x18,0xC0,0x10,0xC0, +// '$' +0x24,0x01,0x0B,0x16,0x02,0x0F, +0x04,0x00,0x80,0x10,0x0F,0xC7,0xFD,0xC8,0xB1,0x06,0x20,0xE4,0x0F,0x80,0xFE,0x03,0xE0,0x4E,0x08,0xC1,0x1E,0x27,0xFF,0xC7,0xE0,0x10,0x02,0x00,0x40,0x08,0x00, +// '%' +0x25,0x01,0x14,0x12,0x01,0x17, +0x3C,0x03,0x06,0x60,0x60,0xC3,0x06,0x0C,0x30,0xC0,0xC3,0x1C,0x0C,0x31,0x80,0xC3,0x38,0x0C,0x33,0x00,0x66,0x63,0xC3,0xC6,0x66,0x00,0xCC,0x30,0x1C,0xC3,0x01,0x8C,0x30,0x38,0xC3,0x03,0x0C,0x30,0x60,0xC3,0x06,0x06,0x60,0xC0,0x3C, +// '&' +0x26,0x01,0x10,0x12,0x01,0x13, +0x07,0xC0,0x1F,0xE0,0x38,0x20,0x30,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x1C,0x00,0x3E,0x00,0x77,0x06,0xE3,0x86,0xC1,0xCC,0xC0,0xFC,0xC0,0x78,0xE0,0x78,0x70,0xFC,0x3F,0xCE,0x0F,0x87, +// ''' +0x27,0x01,0x02,0x07,0x02,0x07, +0xFF,0xFC, +// '(' +0x28,0x01,0x05,0x15,0x02,0x09, +0x19,0x8C,0xC6,0x31,0x18,0xC6,0x31,0x8C,0x61,0x0C,0x63,0x0C,0x61,0x80, +// ')' +0x29,0x01,0x05,0x15,0x02,0x09, +0xC3,0x18,0x63,0x18,0x43,0x18,0xC6,0x31,0x8C,0x46,0x31,0x98,0xCC,0x00, +// '*' +0x2A,0x01,0x0B,0x0A,0x00,0x0C, +0x04,0x00,0x83,0x11,0xBA,0xE1,0xF0,0x3E,0x1D,0x76,0x23,0x04,0x00,0x80, +// '+' +0x2B,0x03,0x10,0x10,0x03,0x14, +0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0xFF,0xFF,0xFF,0xFF,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80, +// ',' +0x2C,0x10,0x03,0x06,0x02,0x08, +0x6D,0xBD,0x80, +// '-' +0x2D,0x0B,0x06,0x02,0x01,0x09, +0xFF,0xF0, +// '.' +0x2E,0x10,0x02,0x03,0x03,0x08, +0xFC, +// '/' +0x2F,0x01,0x08,0x14,0x00,0x08, +0x03,0x07,0x06,0x06,0x06,0x0C,0x0C,0x0C,0x18,0x18,0x18,0x18,0x30,0x30,0x30,0x60,0x60,0x60,0xE0,0xC0, +// '0' +0x30,0x01,0x0C,0x12,0x02,0x0F, +0x0F,0x03,0xFC,0x70,0xE6,0x06,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x60,0x67,0x0E,0x3F,0xC0,0xF0, +// '1' +0x31,0x01,0x0A,0x12,0x03,0x0F, +0x3C,0x3F,0x0C,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0, +// '2' +0x32,0x01,0x0C,0x12,0x02,0x0F, +0x3F,0x0F,0xF8,0xC1,0xC0,0x0E,0x00,0x60,0x06,0x00,0x60,0x0C,0x01,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xEF,0xFE, +// '3' +0x33,0x01,0x0C,0x12,0x02,0x0F, +0x3F,0x07,0xFC,0x41,0xC0,0x06,0x00,0x60,0x06,0x00,0x60,0x0C,0x1F,0x81,0xFC,0x00,0xE0,0x07,0x00,0x30,0x03,0x00,0x78,0x0E,0xFF,0xC3,0xF0, +// '4' +0x34,0x01,0x0D,0x12,0x01,0x0F, +0x01,0xC0,0x1E,0x00,0xB0,0x0D,0x80,0xCC,0x06,0x60,0x63,0x03,0x18,0x30,0xC3,0x06,0x18,0x31,0x81,0x8F,0xFF,0xFF,0xFC,0x03,0x00,0x18,0x00,0xC0,0x06,0x00, +// '5' +0x35,0x01,0x0B,0x12,0x02,0x0F, +0x7F,0xCF,0xF9,0x80,0x30,0x06,0x00,0xC0,0x1F,0xC3,0xFC,0x41,0xC0,0x1C,0x01,0x80,0x30,0x06,0x00,0xC0,0x3C,0x0E,0xFF,0x8F,0xC0, +// '6' +0x36,0x01,0x0C,0x12,0x02,0x0F, +0x07,0xC1,0xFE,0x38,0x27,0x00,0x60,0x0C,0x00,0xCF,0x8D,0xFC,0xF8,0xEF,0x07,0xE0,0x3E,0x03,0xE0,0x36,0x03,0x70,0x77,0x8E,0x3F,0xC0,0xF8, +// '7' +0x37,0x01,0x0B,0x12,0x02,0x0F, +0xFF,0xFF,0xFC,0x03,0x00,0x60,0x1C,0x03,0x00,0x60,0x18,0x03,0x00,0xE0,0x18,0x03,0x00,0xC0,0x18,0x07,0x00,0xC0,0x18,0x06,0x00, +// '8' +0x38,0x01,0x0C,0x12,0x02,0x0F, +0x1F,0x87,0xFE,0x70,0xEC,0x03,0xC0,0x3C,0x03,0xC0,0x37,0x0E,0x3F,0xC3,0xFC,0x70,0xEC,0x03,0xC0,0x3C,0x03,0xC0,0x37,0x0E,0x7F,0xE1,0xF8, +// '9' +0x39,0x01,0x0C,0x12,0x02,0x0F, +0x1F,0x03,0xFC,0x71,0xCE,0x0E,0xC0,0x6C,0x07,0xC0,0x7C,0x07,0xE0,0xF7,0x1F,0x3F,0xB1,0xF3,0x00,0x30,0x06,0x00,0xE4,0x1C,0x7F,0x83,0xE0, +// ':' +0x3A,0x07,0x02,0x0C,0x03,0x08, +0xFC,0x00,0x3F, +// ';' +0x3B,0x07,0x03,0x0F,0x02,0x08, +0x6D,0x80,0x00,0x0D,0xB7,0xB0, +// '<' +0x3C,0x05,0x0F,0x0D,0x03,0x14, +0x00,0x02,0x00,0x3C,0x03,0xF0,0x3F,0x01,0xF8,0x1F,0x80,0x3C,0x00,0x7E,0x00,0x1F,0x80,0x0F,0xC0,0x03,0xF0,0x00,0xF0,0x00,0x20, +// '=' +0x3D,0x08,0x0F,0x07,0x03,0x14, +0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0x80, +// '>' +0x3E,0x05,0x0F,0x0D,0x03,0x14, +0x80,0x01,0xE0,0x01,0xF8,0x00,0x7E,0x00,0x3F,0x00,0x0F,0xC0,0x07,0x80,0x3F,0x03,0xF0,0x1F,0x81,0xF8,0x07,0x80,0x08,0x00,0x00, +// '?' +0x3F,0x01,0x09,0x12,0x02,0x0D, +0x3E,0x3F,0xB0,0xF0,0x30,0x18,0x0C,0x0C,0x0E,0x0E,0x0E,0x06,0x03,0x01,0x80,0x00,0x00,0x30,0x18,0x0C,0x00, +// '@' +0x40,0x02,0x15,0x15,0x02,0x18, +0x00,0xFC,0x00,0x3F,0xF8,0x03,0xC0,0xF0,0x38,0x01,0xC3,0x80,0x07,0x38,0x79,0x99,0x8F,0xEC,0xFC,0x71,0xE3,0xC7,0x07,0x1E,0x30,0x18,0xF1,0x80,0xC7,0x8C,0x06,0x3C,0x70,0x73,0x71,0xC7,0xB9,0x8F,0xEF,0x8E,0x1E,0x70,0x38,0x00,0x00,0xE0,0x04,0x03,0xC0,0xE0,0x0F,0xFE,0x00,0x0F,0x80,0x00, +// 'A' +0x41,0x01,0x10,0x12,0x00,0x10, +0x03,0xC0,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x06,0x60,0x06,0x60,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x18,0x18,0x18,0x18,0x38,0x1C,0x3F,0xFC,0x3F,0xFC,0x60,0x06,0x60,0x06,0x60,0x06,0xC0,0x03, +// 'B' +0x42,0x01,0x0C,0x12,0x02,0x10, +0xFF,0x0F,0xFC,0xC0,0xEC,0x06,0xC0,0x6C,0x06,0xC0,0x6C,0x0C,0xFF,0x8F,0xFC,0xC0,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x06,0xFF,0xEF,0xF8, +// 'C' +0x43,0x01,0x0E,0x12,0x01,0x11, +0x07,0xE0,0x7F,0xE3,0xC1,0xDC,0x01,0x60,0x01,0x80,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x60,0x01,0x80,0x07,0x00,0x4F,0x07,0x1F,0xF8,0x1F,0x80, +// 'D' +0x44,0x01,0x0F,0x12,0x02,0x12, +0xFF,0x81,0xFF,0xE3,0x01,0xE6,0x00,0xEC,0x00,0xD8,0x01,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80,0x0F,0x00,0x1E,0x00,0x3C,0x00,0xF8,0x01,0xB0,0x07,0x60,0x3C,0xFF,0xF1,0xFF,0x00, +// 'E' +0x45,0x01,0x0B,0x12,0x02,0x0F, +0xFF,0xFF,0xFF,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xDF,0xFB,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xFF,0xFC, +// 'F' +0x46,0x01,0x0A,0x12,0x02,0x0E, +0xFF,0xFF,0xFC,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xFF,0xBF,0xEC,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x00, +// 'G' +0x47,0x01,0x0F,0x12,0x01,0x13, +0x07,0xE0,0x3F,0xF0,0xE0,0x73,0x80,0x26,0x00,0x1C,0x00,0x30,0x00,0x60,0x00,0xC0,0x7F,0x80,0xFF,0x00,0x1E,0x00,0x36,0x00,0x6C,0x00,0xDC,0x01,0x9E,0x07,0x1F,0xFC,0x0F,0xE0, +// 'H' +0x48,0x01,0x0D,0x12,0x02,0x12, +0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xFF,0xFF,0xFF,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xC0, +// 'I' +0x49,0x01,0x02,0x12,0x02,0x07, +0xFF,0xFF,0xFF,0xFF,0xF0, +// 'J' +0x4A,0x01,0x06,0x17,0xFE,0x07, +0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x1B,0xEF,0x00, +// 'K' +0x4B,0x01,0x0F,0x12,0x02,0x10, +0xC0,0x71,0x81,0xC3,0x07,0x06,0x1C,0x0C,0x70,0x19,0xC0,0x37,0x00,0x7C,0x00,0xF8,0x01,0xB0,0x03,0x38,0x06,0x38,0x0C,0x38,0x18,0x38,0x30,0x38,0x60,0x38,0xC0,0x39,0x80,0x38, +// 'L' +0x4C,0x01,0x0B,0x12,0x02,0x0D, +0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xFF,0xFC, +// 'M' +0x4D,0x01,0x10,0x12,0x02,0x15, +0xE0,0x07,0xF0,0x0F,0xF0,0x0F,0xF8,0x1F,0xD8,0x1B,0xD8,0x1B,0xCC,0x33,0xCC,0x33,0xCC,0x33,0xC6,0x63,0xC6,0x63,0xC7,0xE3,0xC3,0xC3,0xC3,0xC3,0xC1,0x83,0xC0,0x03,0xC0,0x03,0xC0,0x03, +// 'N' +0x4E,0x01,0x0D,0x12,0x02,0x12, +0xE0,0x1F,0x80,0xFC,0x07,0xF0,0x3D,0x81,0xE6,0x0F,0x30,0x78,0xC3,0xC6,0x1E,0x18,0xF0,0xC7,0x83,0x3C,0x19,0xE0,0x6F,0x03,0x78,0x0F,0xC0,0x7E,0x01,0xC0, +// 'O' +0x4F,0x01,0x10,0x12,0x01,0x13, +0x07,0xE0,0x1F,0xF8,0x3C,0x3C,0x70,0x0E,0x60,0x06,0x60,0x06,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x60,0x06,0x60,0x06,0x70,0x0E,0x3C,0x3C,0x1F,0xF8,0x07,0xE0, +// 'P' +0x50,0x01,0x0B,0x12,0x02,0x0E, +0xFF,0x1F,0xFB,0x07,0x60,0x3C,0x07,0x80,0xF0,0x1E,0x0E,0xFF,0xDF,0xE3,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x00, +// 'Q' +0x51,0x01,0x10,0x15,0x01,0x13, +0x07,0xE0,0x1F,0xF8,0x3C,0x3C,0x70,0x0E,0x60,0x06,0x60,0x06,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x60,0x07,0x60,0x06,0x70,0x0E,0x3C,0x3C,0x1F,0xF8,0x07,0xF0,0x00,0x38,0x00,0x18,0x00,0x0C, +// 'R' +0x52,0x01,0x0D,0x12,0x02,0x11, +0xFF,0x07,0xFE,0x30,0x31,0x80,0xCC,0x06,0x60,0x33,0x01,0x98,0x18,0xFF,0xC7,0xFC,0x30,0x71,0x81,0x8C,0x06,0x60,0x33,0x01,0xD8,0x06,0xC0,0x36,0x00,0xC0, +// 'S' +0x53,0x01,0x0C,0x12,0x02,0x0F, +0x1F,0x87,0xFE,0x70,0x6C,0x00,0xC0,0x0C,0x00,0xC0,0x07,0x00,0x7F,0x01,0xFC,0x00,0xE0,0x07,0x00,0x30,0x03,0x00,0x3C,0x0E,0xFF,0xE3,0xF8, +// 'T' +0x54,0x01,0x0E,0x12,0x00,0x0F, +0xFF,0xFF,0xFF,0xF0,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00, +// 'U' +0x55,0x01,0x0D,0x12,0x02,0x12, +0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0D,0x80,0xCE,0x0E,0x3F,0xE0,0x7C,0x00, +// 'V' +0x56,0x01,0x10,0x12,0x00,0x10, +0xC0,0x03,0x60,0x06,0x60,0x06,0x60,0x06,0x30,0x0C,0x30,0x0C,0x38,0x1C,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x06,0x60,0x06,0x60,0x07,0x60,0x03,0xC0,0x03,0xC0,0x03,0xC0, +// 'W' +0x57,0x01,0x16,0x12,0x01,0x18, +0xC0,0x78,0x0F,0x01,0xE0,0x36,0x07,0x81,0x98,0x1E,0x06,0x60,0xEC,0x19,0x83,0x30,0x63,0x0C,0xC3,0x0C,0x33,0x0C,0x30,0xCE,0x30,0xC6,0x18,0xC1,0x98,0x66,0x06,0x61,0x98,0x19,0x86,0x60,0x6C,0x0D,0x80,0xF0,0x3C,0x03,0xC0,0xF0,0x0F,0x03,0xC0,0x38,0x07,0x00, +// 'X' +0x58,0x01,0x0F,0x12,0x01,0x11, +0x70,0x0E,0x60,0x18,0x60,0x60,0xE1,0xC0,0xC7,0x00,0xCC,0x01,0xF0,0x01,0xE0,0x03,0x80,0x07,0x80,0x1F,0x00,0x37,0x00,0xC6,0x03,0x86,0x0E,0x0E,0x18,0x0C,0x60,0x0D,0xC0,0x1C, +// 'Y' +0x59,0x01,0x0E,0x12,0x00,0x0F, +0xE0,0x1D,0x80,0x63,0x03,0x0E,0x1C,0x18,0x60,0x33,0x00,0xFC,0x01,0xE0,0x07,0x80,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00, +// 'Z' +0x5A,0x01,0x0E,0x12,0x01,0x10, +0xFF,0xFF,0xFF,0xF0,0x01,0x80,0x0E,0x00,0x70,0x01,0x80,0x0C,0x00,0x60,0x03,0x80,0x1C,0x00,0x60,0x03,0x00,0x18,0x00,0xE0,0x07,0x00,0x18,0x00,0xFF,0xFF,0xFF,0xF0, +// '[' +0x5B,0x01,0x05,0x15,0x02,0x09, +0xFF,0xF1,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0xFF,0x80, +// '\' +0x5C,0x01,0x08,0x14,0x00,0x08, +0xC0,0xE0,0x60,0x60,0x60,0x30,0x30,0x30,0x18,0x18,0x18,0x18,0x0C,0x0C,0x0C,0x06,0x06,0x06,0x07,0x03, +// ']' +0x5D,0x01,0x05,0x15,0x02,0x09, +0xFF,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC7,0xFF,0x80, +// '^' +0x5E,0x01,0x0F,0x07,0x03,0x14, +0x03,0x80,0x0F,0x80,0x3B,0x80,0xE3,0x83,0x83,0x8E,0x03,0xB8,0x03,0x80, +// '_' +0x5F,0x17,0x0C,0x02,0x00,0x0C, +0xFF,0xFF,0xFF, +// '`' +0x60,0x00,0x06,0x04,0x02,0x0C, +0x60,0xC1,0x83, +// 'a' +0x61,0x06,0x0B,0x0D,0x01,0x0E, +0x3F,0x0F,0xF9,0x03,0x00,0x30,0x06,0x3F,0xDF,0xFF,0x03,0xC0,0x78,0x1F,0x87,0xBF,0xF3,0xE6, +// 'b' +0x62,0x01,0x0C,0x12,0x02,0x0F, +0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0xF8,0xFF,0xCF,0x0E,0xE0,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xE0,0x6F,0x0E,0xFF,0xCC,0xF8, +// 'c' +0x63,0x06,0x0A,0x0D,0x01,0x0D, +0x0F,0x8F,0xF7,0x05,0x80,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x18,0x07,0x04,0xFF,0x0F,0x80, +// 'd' +0x64,0x01,0x0C,0x12,0x01,0x0F, +0x00,0x30,0x03,0x00,0x30,0x03,0x00,0x31,0xF3,0x3F,0xF7,0x0F,0x60,0x7C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x77,0x0F,0x3F,0xF1,0xF3, +// 'e' +0x65,0x06,0x0C,0x0D,0x01,0x0E, +0x0F,0x83,0xFC,0x70,0xE6,0x07,0xC0,0x3F,0xFF,0xFF,0xFC,0x00,0xC0,0x06,0x00,0x70,0x23,0xFE,0x0F,0xC0, +// 'f' +0x66,0x01,0x08,0x12,0x01,0x08, +0x0F,0x1F,0x38,0x30,0x30,0xFF,0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30, +// 'g' +0x67,0x06,0x0C,0x12,0x01,0x0F, +0x1F,0x33,0xFF,0x70,0xF6,0x07,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x07,0x70,0xF3,0xFF,0x1F,0x30,0x03,0x00,0x72,0x0E,0x3F,0xC1,0xF8, +// 'h' +0x68,0x01,0x0B,0x12,0x02,0x0F, +0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x9F,0x3F,0xF7,0x87,0xE0,0x78,0x0F,0x01,0xE0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x0C, +// 'i' +0x69,0x01,0x02,0x12,0x02,0x07, +0xFC,0x3F,0xFF,0xFF,0xF0, +// 'j' +0x6A,0x01,0x05,0x17,0xFF,0x07, +0x18,0xC6,0x00,0x0C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x33,0xFB,0x80, +// 'k' +0x6B,0x01,0x0C,0x12,0x02,0x0E, +0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x1C,0xC3,0x8C,0x70,0xCE,0x0D,0xC0,0xF8,0x0F,0x80,0xDC,0x0C,0xE0,0xC7,0x0C,0x38,0xC1,0xCC,0x0E, +// 'l' +0x6C,0x01,0x02,0x12,0x02,0x06, +0xFF,0xFF,0xFF,0xFF,0xF0, +// 'm' +0x6D,0x06,0x14,0x0D,0x02,0x18, +0xCF,0x87,0xCF,0xFC,0xFE,0xF0,0xF8,0x7E,0x07,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x30, +// 'n' +0x6E,0x06,0x0B,0x0D,0x02,0x0F, +0xCF,0x9F,0xFB,0xC3,0xF0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x0F,0x01,0xE0,0x3C,0x06, +// 'o' +0x6F,0x06,0x0C,0x0D,0x01,0x0E, +0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80, +// 'p' +0x70,0x06,0x0C,0x12,0x02,0x0F, +0xCF,0x8F,0xFC,0xF0,0xEE,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x3E,0x06,0xF0,0xEF,0xFC,0xCF,0x8C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00, +// 'q' +0x71,0x06,0x0C,0x12,0x01,0x0F, +0x1F,0x33,0xFF,0x70,0xF6,0x07,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x07,0x70,0xF3,0xFF,0x1F,0x30,0x03,0x00,0x30,0x03,0x00,0x30,0x03, +// 'r' +0x72,0x06,0x08,0x0D,0x02,0x0A, +0xCF,0xFF,0xF0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, +// 's' +0x73,0x06,0x0B,0x0D,0x01,0x0C, +0x3F,0x0F,0xF3,0x82,0x60,0x0C,0x00,0xF0,0x0F,0xC0,0x3C,0x00,0xC0,0x1A,0x07,0x7F,0xC7,0xF0, +// 't' +0x74,0x02,0x08,0x11,0x00,0x09, +0x30,0x30,0x30,0x30,0xFF,0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x1F,0x0F, +// 'u' +0x75,0x06,0x0B,0x0D,0x02,0x0F, +0xC0,0x78,0x0F,0x01,0xE0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1F,0x87,0xBF,0xF3,0xE6, +// 'v' +0x76,0x06,0x0D,0x0D,0x01,0x0F, +0xC0,0x1B,0x01,0x98,0x0C,0xC0,0x63,0x06,0x18,0x30,0x63,0x03,0x18,0x18,0xC0,0x6C,0x03,0x60,0x1F,0x00,0x70,0x00, +// 'w' +0x77,0x06,0x12,0x0D,0x01,0x14, +0xC1,0xE0,0xF0,0x78,0x36,0x1E,0x19,0x87,0x86,0x63,0x31,0x9C,0xCC,0xE3,0x33,0x30,0xCC,0xCC,0x36,0x1B,0x07,0x87,0x81,0xE1,0xE0,0x78,0x78,0x1C,0x0E,0x00, +// 'x' +0x78,0x06,0x0D,0x0D,0x01,0x0F, +0xE0,0x3B,0x83,0x8E,0x38,0x31,0x80,0xD8,0x07,0xC0,0x1C,0x01,0xF0,0x1D,0xC0,0xC6,0x0C,0x18,0xE0,0xEE,0x03,0x80, +// 'y' +0x79,0x06,0x0D,0x12,0x01,0x0F, +0xC0,0x1B,0x01,0x98,0x0C,0xE0,0xE3,0x06,0x18,0x70,0x63,0x03,0x18,0x0D,0x80,0x6C,0x03,0xE0,0x0E,0x00,0x70,0x03,0x00,0x18,0x01,0x80,0x7C,0x03,0xC0,0x00, +// 'z' +0x7A,0x06,0x0B,0x0D,0x01,0x0D, +0xFF,0xFF,0xFC,0x03,0x00,0xE0,0x38,0x0E,0x03,0x80,0xE0,0x38,0x0E,0x01,0x80,0x7F,0xFF,0xFE, +// '{' +0x7B,0x01,0x09,0x16,0x03,0x0F, +0x03,0x83,0xC3,0x81,0x80,0xC0,0x60,0x30,0x18,0x0C,0x0E,0x3E,0x1F,0x01,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0xC0,0x78,0x1C, +// '|' +0x7C,0x01,0x02,0x18,0x03,0x08, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +// '}' +0x7D,0x01,0x09,0x16,0x03,0x0F, +0xE0,0x78,0x0E,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0E,0x03,0xE1,0xF1,0xC0,0xC0,0x60,0x30,0x18,0x0C,0x06,0x07,0x0F,0x07,0x00, +// '~' +0x7E,0x09,0x0F,0x05,0x03,0x14, +0x00,0x00,0x7C,0x05,0xFE,0x1E,0x1F,0xE0,0x0F,0x80, + +// Terminator +0xFF +}; diff --git a/components/tft/Kconfig b/components/tft/Kconfig new file mode 100644 index 0000000..cdea9bd --- /dev/null +++ b/components/tft/Kconfig @@ -0,0 +1,157 @@ +menu "TFT Display" + +config TFT_PREDEFINED_DISPLAY_TYPE + int + default 0 if TFT_PREDEFINED_DISPLAY_TYPE0 + default 1 if TFT_PREDEFINED_DISPLAY_TYPE1 + default 2 if TFT_PREDEFINED_DISPLAY_TYPE2 + default 3 if TFT_PREDEFINED_DISPLAY_TYPE3 + default 4 if TFT_PREDEFINED_DISPLAY_TYPE4 + default 5 if TFT_PREDEFINED_DISPLAY_TYPE5 + + choice + prompt "Select predefined display configuration" + default TFT_PREDEFINED_DISPLAY_TYPE0 + help + Select predefined display configuration + + config TFT_PREDEFINED_DISPLAY_TYPE0 + bool "None" + config TFT_PREDEFINED_DISPLAY_TYPE1 + bool "ESP-WROVER-KIT v3 Display (ST7789V)" + config TFT_PREDEFINED_DISPLAY_TYPE4 + bool "ESP-WROVER-KIT v4.1 Display (ILI9341)" + config TFT_PREDEFINED_DISPLAY_TYPE2 + bool "Adafruit TFT Feather Display" + config TFT_PREDEFINED_DISPLAY_TYPE3 + bool "M5Stack TFT Display" + config TFT_PREDEFINED_DISPLAY_TYPE5 + bool "TTGO T-DISPLAY (ST7789V)" + endchoice + +if TFT_PREDEFINED_DISPLAY_TYPE0 + +config TFT_DISPLAY_CONTROLLER_MODEL + int + default 0 if TFT_DISPLAY_CONTROLLER_ILI9341 + default 1 if TFT_DISPLAY_CONTROLLER_ILI9488 + default 2 if TFT_DISPLAY_CONTROLLER_ST7789V + default 3 if TFT_DISPLAY_CONTROLLER_ST7735 + default 4 if TFT_DISPLAY_CONTROLLER_ST7735R + default 5 if TFT_DISPLAY_CONTROLLER_ST7735B + + choice + prompt "Select a display controller model." + default TFT_DISPLAY_CONTROLLER_ILI9341 + help + Select the controller for your display. If an TFT_PREDEFINED_DISPLAY_TYPE is set, this will be overridden. + + config TFT_DISPLAY_CONTROLLER_ILI9341 + bool "ILI9341" + config TFT_DISPLAY_CONTROLLER_ILI9488 + bool "ILI9488" + config TFT_DISPLAY_CONTROLLER_ST7789V + bool "ST7789V" + config TFT_DISPLAY_CONTROLLER_ST7735 + bool "ST7735" + config TFT_DISPLAY_CONTROLLER_ST7735R + bool "ST7735R" + config TFT_DISPLAY_CONTROLLER_ST7735B + bool "ST7735B" + endchoice + +config TFT_DISPLAY_WIDTH + int "TFT display width in pixels." + default 240 + help + The smaller dimension (in portrait). + +config TFT_DISPLAY_HEIGHT + int "TFT display height in pixels." + default 320 + help + The smaller dimension (in portrait). + +config TFT_RGB_BGR + bool "RGB (Red Green Blue)" + default n + help + Is the display RGB rather than GBR? + +config TFT_TOUCH_CONTROLLER + int + default 0 if TFT_TOUCH_CONTROLLER0 + default 1 if TFT_TOUCH_CONTROLLER1 + default 2 if TFT_TOUCH_CONTROLLER2 + + choice + prompt "Select touch controller." + default TFT_TOUCH_CONTROLLER0 + help + Select predefined display configuration + + config TFT_TOUCH_CONTROLLER0 + bool "None" + config TFT_TOUCH_CONTROLLER1 + bool "XPT2046" + config TFT_TOUCH_CONTROLLER2 + bool "STMPE610" + endchoice + +config TFT_INVERT_ROTATION1 + bool "Invert rotation1." + default n + help + If text is backwards on your display, try enabling this. + +config TFT_PIN_NUM_MOSI + int "GPIO for MOSI (Master Out Slave In)" + default 23 + help + If not using a predefined display type, configure the MOSI pin here. + +config TFT_PIN_NUM_MISO + int "GPIO for MISO (Master In Slave Out)" + default 19 + help + If not using a predefined display type, configure the MISO pin here. + +config TFT_PIN_NUM_CLK + int "GPIO for CLK (SCK / Serial Clock)" + default 18 + help + If not using a predefined display type, configure the SCK pin here. + +config TFT_PIN_NUM_CS + int "GPIO for CS (Slave Select)" + default 5 + help + If not using a predefined display type, configure the CS pin here. + +config TFT_PIN_NUM_DC + int "GPIO for DC (Data \ Command)" + default 26 + help + If not using a predefined display type, configure the DC pin here. + +config TFT_PIN_NUM_TCS + int "GPIO for TCS (Touchscreen)" + default 25 + help + Optional. If not using a predefined display type, configure the TCS (touch screen) pin here. + +config TFT_PIN_NUM_RST + int "GPIO for Reset" + default 0 + help + Optional. If not using a predefined display type, configure the reset pin here. + +config TFT_PIN_NUM_BCKL + int "GPIO for Back-light control" + default 0 + help + Optional. If not using a predefined display type, configure the blacklight pin here. + +endif + +endmenu diff --git a/components/tft/SmallFont.c b/components/tft/SmallFont.c new file mode 100644 index 0000000..663f59c --- /dev/null +++ b/components/tft/SmallFont.c @@ -0,0 +1,120 @@ +// SmallFont.c +// Font type : Full (95 characters) +// Font size : 8x12 pixels +// Memory usage : 1144 bytes + +#if defined(__AVR__) + #include + #define fontdatatype const uint8_t +#elif defined(__PIC32MX__) + #define PROGMEM + #define fontdatatype const unsigned char +#elif defined(__arm__) + #define PROGMEM + #define fontdatatype const unsigned char +#endif + +const unsigned char tft_SmallFont[1144] = +{ +0x08,0x0C,0x20,0x5F, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // +0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, // ! +0x00,0x28,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // " +0x00,0x00,0x28,0x28,0xFC,0x28,0x50,0xFC,0x50,0x50,0x00,0x00, // # +0x00,0x20,0x78,0xA8,0xA0,0x60,0x30,0x28,0xA8,0xF0,0x20,0x00, // $ +0x00,0x00,0x48,0xA8,0xB0,0x50,0x28,0x34,0x54,0x48,0x00,0x00, // % +0x00,0x00,0x20,0x50,0x50,0x78,0xA8,0xA8,0x90,0x6C,0x00,0x00, // & +0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' +0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x04,0x00, // ( +0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x40,0x00, // ) +0x00,0x00,0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,0x00,0x00, // * +0x00,0x00,0x20,0x20,0x20,0xF8,0x20,0x20,0x20,0x00,0x00,0x00, // + +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80, // , +0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, // - +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, // . +0x00,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x00, // / + +0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, // 0 +0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // 1 +0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x40,0x80,0xF8,0x00,0x00, // 2 +0x00,0x00,0x70,0x88,0x08,0x30,0x08,0x08,0x88,0x70,0x00,0x00, // 3 +0x00,0x00,0x10,0x30,0x50,0x50,0x90,0x78,0x10,0x18,0x00,0x00, // 4 +0x00,0x00,0xF8,0x80,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,0x00, // 5 +0x00,0x00,0x70,0x90,0x80,0xF0,0x88,0x88,0x88,0x70,0x00,0x00, // 6 +0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x20,0x20,0x20,0x00,0x00, // 7 +0x00,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00, // 8 +0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x48,0x70,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x20,0x00,0x00, // : +0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x20,0x00, // ; +0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, // < +0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00,0x00,0x00, // = +0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, // > +0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00, // ? + +0x00,0x00,0x70,0x88,0x98,0xA8,0xA8,0xB8,0x80,0x78,0x00,0x00, // @ +0x00,0x00,0x20,0x20,0x30,0x50,0x50,0x78,0x48,0xCC,0x00,0x00, // A +0x00,0x00,0xF0,0x48,0x48,0x70,0x48,0x48,0x48,0xF0,0x00,0x00, // B +0x00,0x00,0x78,0x88,0x80,0x80,0x80,0x80,0x88,0x70,0x00,0x00, // C +0x00,0x00,0xF0,0x48,0x48,0x48,0x48,0x48,0x48,0xF0,0x00,0x00, // D +0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x48,0xF8,0x00,0x00, // E +0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x40,0xE0,0x00,0x00, // F +0x00,0x00,0x38,0x48,0x80,0x80,0x9C,0x88,0x48,0x30,0x00,0x00, // G +0x00,0x00,0xCC,0x48,0x48,0x78,0x48,0x48,0x48,0xCC,0x00,0x00, // H +0x00,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, // I +0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0xE0,0x00, // J +0x00,0x00,0xEC,0x48,0x50,0x60,0x50,0x50,0x48,0xEC,0x00,0x00, // K +0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x44,0xFC,0x00,0x00, // L +0x00,0x00,0xD8,0xD8,0xD8,0xD8,0xA8,0xA8,0xA8,0xA8,0x00,0x00, // M +0x00,0x00,0xDC,0x48,0x68,0x68,0x58,0x58,0x48,0xE8,0x00,0x00, // N +0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, // O + +0x00,0x00,0xF0,0x48,0x48,0x70,0x40,0x40,0x40,0xE0,0x00,0x00, // P +0x00,0x00,0x70,0x88,0x88,0x88,0x88,0xE8,0x98,0x70,0x18,0x00, // Q +0x00,0x00,0xF0,0x48,0x48,0x70,0x50,0x48,0x48,0xEC,0x00,0x00, // R +0x00,0x00,0x78,0x88,0x80,0x60,0x10,0x08,0x88,0xF0,0x00,0x00, // S +0x00,0x00,0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // T +0x00,0x00,0xCC,0x48,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00, // U +0x00,0x00,0xCC,0x48,0x48,0x50,0x50,0x30,0x20,0x20,0x00,0x00, // V +0x00,0x00,0xA8,0xA8,0xA8,0x70,0x50,0x50,0x50,0x50,0x00,0x00, // W +0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x50,0x50,0xD8,0x00,0x00, // X +0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // Y +0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x40,0x48,0xF8,0x00,0x00, // Z +0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, // [ +0x00,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x00,0x00, // +0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, // ] +0x00,0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^ +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, // _ + +0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ` +0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x38,0x48,0x3C,0x00,0x00, // a +0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0x70,0x00,0x00, // b +0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x40,0x40,0x38,0x00,0x00, // c +0x00,0x00,0x18,0x08,0x08,0x38,0x48,0x48,0x48,0x3C,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x78,0x40,0x38,0x00,0x00, // e +0x00,0x00,0x1C,0x20,0x20,0x78,0x20,0x20,0x20,0x78,0x00,0x00, // f +0x00,0x00,0x00,0x00,0x00,0x3C,0x48,0x30,0x40,0x78,0x44,0x38, // g +0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0xEC,0x00,0x00, // h +0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, // i +0x00,0x00,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0xE0, // j +0x00,0x00,0xC0,0x40,0x40,0x5C,0x50,0x70,0x48,0xEC,0x00,0x00, // k +0x00,0x00,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, // l +0x00,0x00,0x00,0x00,0x00,0xF0,0xA8,0xA8,0xA8,0xA8,0x00,0x00, // m +0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0xEC,0x00,0x00, // n +0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00, // o + +0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0x70,0x40,0xE0, // p +0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x1C, // q +0x00,0x00,0x00,0x00,0x00,0xD8,0x60,0x40,0x40,0xE0,0x00,0x00, // r +0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x30,0x08,0x78,0x00,0x00, // s +0x00,0x00,0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00, // t +0x00,0x00,0x00,0x00,0x00,0xD8,0x48,0x48,0x48,0x3C,0x00,0x00, // u +0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x00,0x00, // v +0x00,0x00,0x00,0x00,0x00,0xA8,0xA8,0x70,0x50,0x50,0x00,0x00, // w +0x00,0x00,0x00,0x00,0x00,0xD8,0x50,0x20,0x50,0xD8,0x00,0x00, // x +0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x20,0xC0, // y +0x00,0x00,0x00,0x00,0x00,0x78,0x10,0x20,0x20,0x78,0x00,0x00, // z +0x00,0x18,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x18,0x00, // { +0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, // | +0x00,0x60,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x60,0x00, // } +0x40,0xA4,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ +}; diff --git a/components/tft/Ubuntu16.c b/components/tft/Ubuntu16.c new file mode 100644 index 0000000..4f75855 --- /dev/null +++ b/components/tft/Ubuntu16.c @@ -0,0 +1,331 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// Ubuntu16.c +// Point Size : 16 +// Memory usage : 1433 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +const unsigned char tft_Ubuntu16[] = +{ +0x00, 0x10, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x0D,0x00,0x00,0x00,0x04, + +// '!' +0x21,0x02,0x01,0x0B,0x01,0x04, +0xFC,0x60, +// '"' +0x22,0x00,0x04,0x04,0x01,0x07, +0x99,0x99, +// '#' +0x23,0x02,0x09,0x0B,0x01,0x0B, +0x11,0x08,0x84,0x5F,0xF2,0x21,0x10,0x89,0xFF,0x44,0x22,0x11,0x00, +// '$' +0x24,0x00,0x07,0x10,0x01,0x09, +0x10,0x20,0xF6,0x08,0x10,0x18,0x08,0x0C,0x0C,0x08,0x3F,0xC2,0x04,0x00, +// '%' +0x25,0x02,0x0C,0x0B,0x01,0x0E, +0x70,0x4D,0x88,0x89,0x08,0x90,0xDA,0x07,0x4E,0x05,0xB0,0x91,0x09,0x11,0x1B,0x20,0xE0, +// '&' +0x26,0x02,0x0A,0x0B,0x01,0x0B, +0x3C,0x18,0x84,0x21,0x08,0x2C,0x0C,0x04,0x8A,0x10,0x83,0x30,0xC7,0xC8, +// ''' +0x27,0x00,0x01,0x04,0x01,0x04, +0xF0, +// '(' +0x28,0x00,0x04,0x10,0x01,0x05, +0x02,0x44,0x48,0x88,0x88,0x84,0x44,0x20, +// ')' +0x29,0x00,0x04,0x10,0x00,0x05, +0x04,0x22,0x21,0x11,0x11,0x12,0x22,0x40, +// '*' +0x2A,0x02,0x09,0x06,0x00,0x08, +0x08,0x24,0x8F,0x83,0x81,0x41,0x10, +// '+' +0x2B,0x05,0x07,0x07,0x01,0x09, +0x10,0x20,0x47,0xF1,0x02,0x04,0x00, +// ',' +0x2C,0x0B,0x02,0x05,0x00,0x04, +0x54,0x80, +// '-' +0x2D,0x08,0x04,0x01,0x01,0x06, +0xF0, +// '.' +0x2E,0x0B,0x01,0x02,0x01,0x04, +0xC0, +// '/' +0x2F,0x00,0x07,0x10,0x00,0x06, +0x02,0x08,0x10,0x20,0x81,0x02,0x08,0x10,0x40,0x81,0x04,0x08,0x10,0x40, +// '0' +0x30,0x02,0x07,0x0B,0x01,0x09, +0x38,0x8B,0x1C,0x18,0x30,0x60,0xC1,0x86,0x88,0xE0, +// '1' +0x31,0x02,0x04,0x0B,0x01,0x09, +0x13,0x59,0x11,0x11,0x11,0x10, +// '2' +0x32,0x02,0x06,0x0B,0x01,0x09, +0x7A,0x30,0x41,0x08,0x21,0x08,0x42,0x0F,0xC0, +// '3' +0x33,0x02,0x07,0x0B,0x01,0x09, +0x78,0x08,0x08,0x10,0x47,0x01,0x01,0x02,0x0B,0xE0, +// '4' +0x34,0x02,0x07,0x0B,0x01,0x09, +0x04,0x18,0x51,0x22,0x48,0xA1,0x7F,0x04,0x08,0x10, +// '5' +0x35,0x02,0x07,0x0B,0x01,0x09, +0x7E,0x81,0x02,0x07,0x81,0x80,0x81,0x02,0x0B,0xE0, +// '6' +0x36,0x02,0x07,0x0B,0x01,0x09, +0x1C,0x61,0x00,0x0F,0x90,0xA0,0xC1,0x82,0x88,0xE0, +// '7' +0x37,0x02,0x07,0x0B,0x01,0x09, +0xFE,0x04,0x10,0x40,0x82,0x04,0x08,0x20,0x40,0x80, +// '8' +0x38,0x02,0x07,0x0B,0x01,0x09, +0x39,0x8A,0x0C,0x14,0x47,0x11,0x41,0x83,0x89,0xE0, +// '9' +0x39,0x02,0x07,0x0B,0x01,0x09, +0x38,0x8A,0x0C,0x18,0x28,0x4F,0x81,0x04,0x11,0xC0, +// ':' +0x3A,0x05,0x01,0x08,0x01,0x04, +0xC3, +// ';' +0x3B,0x05,0x02,0x0B,0x00,0x04, +0x50,0x05,0x48, +// '<' +0x3C,0x05,0x08,0x07,0x01,0x09, +0x02,0x0C,0x30,0x60,0x30,0x0C,0x02, +// '=' +0x3D,0x06,0x07,0x04,0x01,0x09, +0xFE,0x00,0x07,0xF0, +// '>' +0x3E,0x05,0x09,0x07,0x00,0x09, +0x40,0x1C,0x01,0x80,0x70,0x61,0xC1,0x00, +// '?' +0x3F,0x02,0x06,0x0B,0x01,0x07, +0x78,0x30,0x41,0x18,0xC2,0x00,0x00,0x82,0x00, +// '@' +0x40,0x02,0x0D,0x0D,0x01,0x0F, +0x0F,0x81,0x83,0x10,0x0C,0x8F,0xA8,0x84,0xC8,0x26,0x41,0x32,0x09,0x88,0x5A,0x3F,0x90,0x00,0x60,0x00,0xFC,0x00, +// 'A' +0x41,0x02,0x0B,0x0B,0x00,0x0B, +0x04,0x01,0xC0,0x28,0x08,0x81,0x10,0x61,0x08,0x21,0xFC,0x60,0x48,0x0B,0x00,0x80, +// 'B' +0x42,0x02,0x08,0x0B,0x01,0x0A, +0xF8,0x86,0x82,0x82,0x86,0xFC,0x82,0x81,0x81,0x82,0xFC, +// 'C' +0x43,0x02,0x09,0x0B,0x01,0x0B, +0x1F,0x10,0x10,0x10,0x08,0x04,0x02,0x01,0x00,0x40,0x30,0x07,0xC0, +// 'D' +0x44,0x02,0x09,0x0B,0x01,0x0B, +0xFC,0x41,0x20,0x50,0x18,0x0C,0x06,0x03,0x01,0x81,0x41,0x3F,0x00, +// 'E' +0x45,0x02,0x07,0x0B,0x01,0x09, +0xFF,0x02,0x04,0x08,0x1F,0xA0,0x40,0x81,0x03,0xF8, +// 'F' +0x46,0x02,0x07,0x0B,0x01,0x09, +0xFF,0x02,0x04,0x08,0x1F,0xA0,0x40,0x81,0x02,0x00, +// 'G' +0x47,0x02,0x09,0x0B,0x01,0x0B, +0x1F,0x10,0x10,0x10,0x08,0x04,0x02,0x03,0x01,0x40,0xB0,0x47,0xE0, +// 'H' +0x48,0x02,0x09,0x0B,0x01,0x0B, +0x80,0xC0,0x60,0x30,0x18,0x0F,0xFE,0x03,0x01,0x80,0xC0,0x60,0x20, +// 'I' +0x49,0x02,0x01,0x0B,0x01,0x03, +0xFF,0xE0, +// 'J' +0x4A,0x02,0x07,0x0B,0x00,0x08, +0x02,0x04,0x08,0x10,0x20,0x40,0x81,0x02,0x09,0xE0, +// 'K' +0x4B,0x02,0x09,0x0B,0x01,0x0A, +0x81,0x41,0x23,0x12,0x0A,0x06,0x02,0xC1,0x10,0x86,0x40,0xA0,0x20, +// 'L' +0x4C,0x02,0x07,0x0B,0x01,0x08, +0x81,0x02,0x04,0x08,0x10,0x20,0x40,0x81,0x03,0xF8, +// 'M' +0x4D,0x02,0x0B,0x0B,0x01,0x0D, +0x40,0x4C,0x19,0x01,0x28,0xA5,0x14,0x94,0xB2,0x9C,0x33,0x84,0x30,0x06,0x00,0x80, +// 'N' +0x4E,0x02,0x09,0x0B,0x01,0x0B, +0x80,0xE0,0x68,0x32,0x19,0x0C,0x46,0x13,0x05,0x82,0xC0,0xE0,0x20, +// 'O' +0x4F,0x02,0x0B,0x0B,0x01,0x0D, +0x1F,0x04,0x11,0x01,0x40,0x18,0x03,0x00,0x60,0x0C,0x01,0x40,0x44,0x10,0x7C,0x00, +// 'P' +0x50,0x02,0x08,0x0B,0x01,0x0A, +0xFC,0x82,0x81,0x81,0x81,0x82,0xFC,0x80,0x80,0x80,0x80, +// 'Q' +0x51,0x02,0x0B,0x0E,0x01,0x0D, +0x1F,0x04,0x11,0x01,0x40,0x18,0x03,0x00,0x60,0x0C,0x01,0x40,0x44,0x10,0x78,0x02,0x00,0x30,0x01,0x80, +// 'R' +0x52,0x02,0x09,0x0B,0x01,0x0A, +0xFC,0x41,0x20,0x50,0x28,0x14,0x13,0xF1,0x08,0x82,0x40,0xA0,0x20, +// 'S' +0x53,0x02,0x08,0x0B,0x01,0x09, +0x3C,0xC2,0x80,0x80,0x40,0x1C,0x06,0x02,0x02,0x06,0x78, +// 'T' +0x54,0x02,0x09,0x0B,0x00,0x09, +0xFF,0x84,0x02,0x01,0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00, +// 'U' +0x55,0x02,0x09,0x0B,0x01,0x0B, +0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xA0,0x8F,0x80, +// 'V' +0x56,0x02,0x09,0x0B,0x00,0x09, +0x80,0xE0,0xD0,0x48,0x26,0x21,0x10,0x88,0x28,0x14,0x0E,0x02,0x00, +// 'W' +0x57,0x02,0x0D,0x0B,0x00,0x0D, +0x80,0x0E,0x10,0xD0,0x84,0x8E,0x24,0x51,0x22,0x88,0xA2,0x85,0x14,0x38,0xE0,0xC2,0x04,0x10, +// 'X' +0x58,0x02,0x09,0x0B,0x00,0x09, +0xC1,0xA0,0x88,0x86,0xC1,0x40,0x60,0x70,0x6C,0x22,0x20,0xB0,0x60, +// 'Y' +0x59,0x02,0x09,0x0B,0x00,0x09, +0x80,0xA0,0x90,0x44,0x41,0x40,0xA0,0x20,0x10,0x08,0x04,0x02,0x00, +// 'Z' +0x5A,0x02,0x07,0x0B,0x01,0x09, +0xFE,0x04,0x10,0x41,0x02,0x08,0x00,0x41,0x03,0xF8, +// '[' +0x5B,0x00,0x03,0x10,0x02,0x05, +0xF2,0x49,0x24,0x92,0x49,0x27, +// '\' +0x5C,0x00,0x07,0x10,0x00,0x06, +0x80,0x81,0x02,0x02,0x04,0x08,0x08,0x10,0x10,0x20,0x40,0x40,0x81,0x01, +// ']' +0x5D,0x00,0x03,0x10,0x00,0x05, +0xE4,0x92,0x49,0x24,0x92,0x4F, +// '^' +0x5E,0x02,0x07,0x06,0x01,0x09, +0x10,0x70,0xA2,0x24,0x50,0x40, +// '_' +0x5F,0x0F,0x08,0x01,0x00,0x08, +0xFF, +// '`' +0x60,0x01,0x04,0x03,0x01,0x06, +0x86,0x10, +// 'a' +0x61,0x05,0x06,0x08,0x01,0x08, +0x78,0x30,0x5F,0xC6,0x18,0x5F, +// 'b' +0x62,0x01,0x07,0x0C,0x01,0x09, +0x81,0x02,0x04,0x0F,0x90,0xA0,0xC1,0x83,0x06,0x17,0xC0, +// 'c' +0x63,0x05,0x06,0x08,0x01,0x08, +0x3D,0x08,0x20,0x82,0x04,0x0F, +// 'd' +0x64,0x01,0x07,0x0C,0x01,0x09, +0x02,0x04,0x08,0x13,0xE8,0x60,0xC1,0x83,0x05,0x09,0xF0, +// 'e' +0x65,0x05,0x07,0x08,0x01,0x09, +0x3C,0x8A,0x0F,0xF8,0x10,0x10,0x1E, +// 'f' +0x66,0x01,0x05,0x0C,0x01,0x06, +0x7E,0x21,0x0F,0xC2,0x10,0x84,0x21,0x00, +// 'g' +0x67,0x05,0x07,0x0B,0x01,0x09, +0x3E,0x86,0x0C,0x18,0x30,0x50,0x9F,0x02,0x0B,0xE0, +// 'h' +0x68,0x01,0x07,0x0C,0x01,0x09, +0x81,0x02,0x04,0x0F,0x90,0xE0,0xC1,0x83,0x06,0x0C,0x10, +// 'i' +0x69,0x01,0x03,0x0C,0x00,0x03, +0x48,0x04,0x92,0x49,0x20, +// 'j' +0x6A,0x01,0x04,0x0F,0xFF,0x03, +0x22,0x00,0x22,0x22,0x22,0x22,0x22,0xC0, +// 'k' +0x6B,0x01,0x06,0x0C,0x01,0x08, +0x82,0x08,0x20,0x8A,0x4A,0x30,0xA2,0x48,0xA1, +// 'l' +0x6C,0x01,0x04,0x0C,0x01,0x04, +0x88,0x88,0x88,0x88,0x88,0x86, +// 'm' +0x6D,0x05,0x0B,0x08,0x01,0x0D, +0xFB,0xD1,0x8E,0x10,0xC2,0x18,0x43,0x08,0x61,0x0C,0x21, +// 'n' +0x6E,0x05,0x07,0x08,0x01,0x09, +0xFD,0x0E,0x0C,0x18,0x30,0x60,0xC1, +// 'o' +0x6F,0x05,0x08,0x08,0x01,0x0A, +0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C, +// 'p' +0x70,0x05,0x07,0x0B,0x01,0x09, +0xF9,0x0A,0x0C,0x18,0x30,0x61,0x7C,0x81,0x02,0x00, +// 'q' +0x71,0x05,0x07,0x0B,0x01,0x09, +0x3E,0x86,0x0C,0x18,0x30,0x50,0x9F,0x02,0x04,0x08, +// 'r' +0x72,0x05,0x05,0x08,0x01,0x06, +0xFC,0x21,0x08,0x42,0x10, +// 's' +0x73,0x05,0x05,0x08,0x01,0x07, +0x7C,0x20,0xC3,0x04,0x3E, +// 't' +0x74,0x02,0x05,0x0B,0x01,0x07, +0x84,0x21,0xF8,0x42,0x10,0x84,0x1E, +// 'u' +0x75,0x05,0x07,0x08,0x01,0x09, +0x83,0x06,0x0C,0x18,0x30,0x50,0xBF, +// 'v' +0x76,0x05,0x07,0x08,0x00,0x07, +0x83,0x05,0x12,0x22,0x85,0x0E,0x08, +// 'w' +0x77,0x05,0x0D,0x08,0x00,0x0D, +0x82,0x0C,0x10,0x51,0xC4,0x8A,0x26,0x5B,0x14,0x50,0xE3,0x82,0x08, +// 'x' +0x78,0x05,0x08,0x08,0x00,0x08, +0xC3,0x66,0x24,0x18,0x18,0x24,0x42,0xC3, +// 'y' +0x79,0x05,0x07,0x0B,0x00,0x07, +0x82,0x89,0x12,0x22,0x85,0x04,0x08,0x10,0x43,0x00, +// 'z' +0x7A,0x05,0x06,0x08,0x01,0x08, +0xFC,0x10,0x84,0x21,0x08,0x3F, +// '{' +0x7B,0x00,0x05,0x10,0x00,0x05, +0x19,0x08,0x42,0x10,0x98,0x61,0x08,0x42,0x10,0x83, +// '|' +0x7C,0x00,0x01,0x10,0x02,0x05, +0xFF,0xFF, +// '}' +0x7D,0x00,0x05,0x10,0x00,0x05, +0xC1,0x08,0x42,0x10,0x83,0x31,0x08,0x42,0x10,0x98, +// '~' +0x7E,0x07,0x07,0x02,0x01,0x09, +0x73,0x18, + +// Terminator +0xFF +}; diff --git a/components/tft/comic24.c b/components/tft/comic24.c new file mode 100644 index 0000000..2e534c9 --- /dev/null +++ b/components/tft/comic24.c @@ -0,0 +1,331 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// comic.c +// Point Size : 24 +// Memory usage : 2814 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +unsigned char tft_Comic24[] = +{ +0x00, 0x19, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x15,0x00,0x00,0x00,0x07, + +// '!' +0x21,0x02,0x02,0x14,0x01,0x06, +0xFF,0xFF,0xFF,0xFC,0x2D, +// '"' +0x22,0x03,0x06,0x08,0x02,0x0A, +0xCF,0x3C,0xF3,0xCF,0x3C,0xF3, +// '#' +0x23,0x03,0x14,0x12,0x01,0x14, +0x01,0x81,0x80,0x18,0x18,0x01,0x81,0x80,0x30,0x30,0x03,0x03,0x07,0xFF,0xFF,0x7F,0xFF,0xF0,0x60,0x60,0x06,0x06,0x00,0xC0,0xC0,0x0C,0x0C,0x0F,0xFF,0xFE,0xFF,0xFF,0xE1,0x81,0x80,0x18,0x18,0x03,0x83,0x00,0x30,0x30,0x03,0x03,0x00, +// '$' +0x24,0x00,0x0B,0x19,0x02,0x11, +0x0C,0x01,0x80,0x30,0x0F,0x83,0xFC,0xD9,0xBB,0x06,0x60,0xCC,0x19,0x83,0xB0,0x3F,0x83,0xFC,0x1B,0x83,0x18,0x63,0x0C,0x71,0x9F,0x37,0x7F,0xC3,0xF0,0x18,0x03,0x00,0x60,0x0C,0x00, +// '%' +0x25,0x01,0x11,0x14,0x02,0x14, +0x00,0x00,0x00,0x0C,0x0E,0x0E,0x0F,0x86,0x0C,0x67,0x06,0x33,0x03,0x19,0x80,0xF9,0x80,0x38,0xC0,0x00,0xE0,0x00,0x60,0x00,0x70,0x00,0x31,0xE0,0x39,0xF8,0x19,0xCE,0x1C,0xC3,0x0C,0x61,0x86,0x39,0xC6,0x0F,0xC3,0x03,0xC0, +// '&' +0x26,0x03,0x0F,0x13,0x01,0x10, +0x01,0xC0,0x07,0xC0,0x19,0x80,0x33,0x00,0x6E,0x00,0xF8,0x01,0xE0,0x07,0x80,0x1F,0x8C,0x73,0x19,0xC3,0x37,0x07,0xEC,0x07,0xD8,0x07,0x30,0x0E,0x38,0x7E,0x3F,0xEC,0x3F,0x0C,0x00,0x18, +// ''' +0x27,0x03,0x02,0x06,0x03,0x09, +0xFF,0xF0, +// '(' +0x28,0x02,0x07,0x18,0x01,0x09, +0x06,0x1C,0x71,0xC3,0x0E,0x18,0x30,0xE1,0x83,0x06,0x0C,0x18,0x30,0x60,0xE0,0xC1,0x83,0x83,0x83,0x87,0x83, +// ')' +0x29,0x02,0x06,0x18,0x02,0x09, +0xC3,0x86,0x0C,0x30,0x61,0x86,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x61,0x86,0x31,0xCE,0x30, +// '*' +0x2A,0x03,0x0B,0x09,0x01,0x0D, +0x0C,0x01,0x83,0xBF,0xFF,0xF3,0xFC,0x3C,0x0F,0xC3,0x9C,0x61,0x80, +// '+' +0x2B,0x09,0x0A,0x0A,0x00,0x0C, +0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,0xC0,0x30,0x0C,0x03,0x00, +// ',' +0x2C,0x13,0x04,0x06,0x02,0x07, +0x37,0x66,0xEC, +// '-' +0x2D,0x0E,0x08,0x02,0x01,0x0A, +0xFF,0xFF, +// '.' +0x2E,0x12,0x03,0x03,0x02,0x06, +0xFF,0x80, +// '/' +0x2F,0x01,0x0A,0x15,0x01,0x0C, +0x00,0x00,0x30,0x0C,0x06,0x01,0x80,0x60,0x30,0x0C,0x06,0x01,0x80,0xC0,0x30,0x18,0x06,0x03,0x00,0xC0,0x60,0x18,0x0E,0x03,0x00,0xC0,0x00, +// '0' +0x30,0x03,0x0D,0x12,0x01,0x0F, +0x0F,0x80,0xFF,0x0E,0x18,0xE0,0x66,0x03,0x70,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x03,0xB0,0x19,0x81,0xC7,0x1C,0x3F,0xC0,0x7C,0x00, +// '1' +0x31,0x03,0x06,0x12,0x03,0x0B, +0x10,0xC7,0x3C,0xB0,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0xFF,0xF0, +// '2' +0x32,0x03,0x0B,0x12,0x02,0x0F, +0x1F,0x07,0xFB,0xC3,0xE0,0x30,0x06,0x00,0xC0,0x38,0x0E,0x07,0x81,0xE0,0xF8,0x3C,0x07,0x01,0xC0,0x30,0x06,0x00,0xFF,0xDF,0xFC, +// '3' +0x33,0x03,0x0B,0x12,0x02,0x0F, +0x1F,0x0F,0xF9,0xC3,0x80,0x30,0x06,0x00,0xC0,0x78,0x7E,0x0F,0x80,0x78,0x03,0x80,0x30,0x06,0x00,0xF0,0x1F,0x0E,0x7F,0x83,0xE0, +// '4' +0x34,0x03,0x0D,0x12,0x02,0x0F, +0x01,0xC0,0x0E,0x00,0xF0,0x0F,0x80,0x6C,0x07,0x60,0x33,0x03,0x98,0x38,0xC1,0x86,0x1C,0x31,0xFF,0xFF,0xFF,0x80,0x60,0x03,0x00,0x18,0x00,0xC0,0x06,0x00, +// '5' +0x35,0x02,0x0C,0x13,0x02,0x0F, +0x00,0x0F,0xFE,0xFF,0xE6,0x00,0x60,0x0E,0x00,0xEF,0x8F,0xFC,0xF8,0x6E,0x07,0xC0,0x30,0x03,0x00,0x30,0x03,0x00,0x7C,0x06,0xE1,0xE7,0xFC,0x3F,0x00, +// '6' +0x36,0x03,0x0C,0x12,0x01,0x0F, +0x03,0x00,0x70,0x0E,0x01,0xC0,0x38,0x03,0x00,0x60,0x06,0xF8,0xFF,0xEE,0x0E,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x77,0x0E,0x3F,0xC1,0xF8, +// '7' +0x37,0x02,0x0D,0x13,0x01,0x0F, +0x00,0x07,0xFF,0xFF,0xFE,0x00,0xE0,0x0E,0x00,0x60,0x06,0x00,0x30,0x03,0x80,0x18,0x01,0xC0,0x0C,0x00,0x60,0x07,0x00,0x30,0x03,0x80,0x18,0x00,0xC0,0x04,0x00, +// '8' +0x38,0x02,0x0C,0x13,0x01,0x0F, +0x00,0x00,0xFC,0x3F,0xE3,0x07,0x60,0x36,0x03,0x60,0x37,0x8F,0x3F,0xE1,0xFE,0x38,0xE7,0x07,0x60,0x36,0x03,0x60,0x36,0x03,0x30,0x63,0xFE,0x0F,0x80, +// '9' +0x39,0x03,0x0D,0x13,0x01,0x0F, +0x0F,0x01,0xFE,0x1C,0x38,0xC0,0xCC,0x07,0x60,0x1B,0x00,0xD8,0x06,0xE0,0x73,0x87,0x8F,0xF8,0x3E,0xC0,0x0E,0x00,0x60,0x07,0x00,0xF0,0x1F,0x03,0xE0,0x1C,0x00, +// ':' +0x3A,0x09,0x03,0x0B,0x02,0x07, +0xFF,0x80,0x00,0xFF,0x80, +// ';' +0x3B,0x09,0x04,0x0E,0x02,0x07, +0xEE,0xE0,0x00,0x00,0x03,0x7E,0xCC, +// '<' +0x3C,0x09,0x07,0x0A,0x01,0x09, +0x06,0x1C,0x71,0xC7,0x1E,0x1E,0x0E,0x0E,0x0C, +// '=' +0x3D,0x0A,0x09,0x09,0x01,0x0C, +0xFF,0xFF,0xC0,0x00,0x00,0x00,0x03,0xFF,0xFF,0x00,0x00, +// '>' +0x3E,0x08,0x08,0x0B,0x01,0x0A, +0x60,0x70,0x38,0x3C,0x1E,0x0F,0x06,0x0C,0x38,0x70,0xC0, +// '?' +0x3F,0x04,0x0B,0x12,0x01,0x0D, +0x1E,0x0F,0xE3,0xC6,0x60,0x60,0x06,0x00,0xC0,0x18,0x07,0x01,0xE0,0xF8,0x3E,0x0F,0x01,0x80,0x00,0x00,0x01,0x80,0x30,0x06,0x00, +// '@' +0x40,0x02,0x13,0x14,0x01,0x16, +0x03,0xF8,0x01,0xFF,0xC0,0x78,0x3C,0x1C,0x01,0xC3,0x00,0x1C,0xC1,0xC1,0x98,0xF8,0x1E,0x3C,0x03,0xC6,0x30,0x79,0x8E,0x0F,0x31,0xC1,0xE6,0x78,0x6C,0x7F,0xFC,0xC7,0x3E,0x18,0x00,0x01,0x80,0x00,0x38,0x00,0x03,0xC0,0xE0,0x1F,0xFC,0x00,0xFE,0x00, +// 'A' +0x41,0x03,0x0E,0x12,0x01,0x11, +0x00,0x80,0x07,0x00,0x1C,0x00,0xF0,0x03,0xC0,0x1D,0x80,0x76,0x03,0x98,0x0E,0x20,0x70,0xC1,0xFF,0x0F,0xFC,0x7C,0x19,0xC0,0x67,0x01,0xB8,0x07,0xE0,0x0F,0x00,0x30, +// 'B' +0x42,0x03,0x0B,0x13,0x03,0x0F, +0x7C,0x1F,0xE3,0x0E,0x60,0xEC,0x0D,0x81,0xB0,0x36,0x0E,0xC3,0x9F,0xE3,0xFC,0x61,0xEC,0x0F,0x80,0xF0,0x1E,0x0E,0xC7,0xDF,0xE3,0xF0,0x00, +// 'C' +0x43,0x03,0x0D,0x12,0x01,0x0E, +0x01,0xF8,0x3F,0xC3,0xC6,0x38,0x31,0x80,0x1C,0x01,0xC0,0x0C,0x00,0x60,0x06,0x00,0x30,0x01,0x80,0x0C,0x00,0x60,0x19,0x81,0xCE,0x3C,0x3F,0xC0,0xF8,0x00, +// 'D' +0x44,0x03,0x0D,0x12,0x02,0x11, +0x60,0x07,0xC0,0x37,0x81,0x8F,0x0C,0x1C,0x60,0x73,0x01,0xD8,0x06,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x1B,0x01,0xDC,0x1C,0xFF,0xC1,0xF8,0x00, +// 'E' +0x45,0x03,0x0D,0x12,0x02,0x0F, +0xFF,0xF7,0xFF,0xF0,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x7E,0xFF,0xF7,0xE0,0x30,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x00,0x7F,0xF1,0xFF,0x80, +// 'F' +0x46,0x03,0x0C,0x12,0x02,0x0F, +0xFF,0xCF,0xFF,0xC0,0x7C,0x00,0xC0,0x0C,0x00,0xC0,0x0D,0xFE,0xFF,0xEF,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00, +// 'G' +0x47,0x03,0x0F,0x12,0x01,0x10, +0x03,0xE0,0x0F,0xF0,0x38,0xE0,0xE0,0x03,0x80,0x06,0x00,0x18,0x00,0x30,0x00,0x61,0xFF,0x9F,0xFF,0x3C,0x36,0x00,0x6C,0x01,0x98,0x07,0x30,0x0C,0x30,0x70,0x7F,0xC0,0x3E,0x00, +// 'H' +0x48,0x03,0x0F,0x12,0x02,0x12, +0xC0,0x03,0x80,0x0F,0x00,0x1E,0x00,0x3C,0x00,0x78,0x00,0xF0,0x01,0xE0,0x03,0xC0,0xFF,0xFF,0xFF,0xFC,0x1E,0x00,0x3C,0x00,0x78,0x00,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80,0x0C, +// 'I' +0x49,0x03,0x0C,0x12,0x00,0x0D, +0xFF,0xEF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0xFF,0xFF,0xFF, +// 'J' +0x4A,0x03,0x0E,0x12,0x01,0x10, +0x1F,0xFC,0x7F,0xF0,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0xC0,0xC3,0x06,0x0E,0x18,0x1C,0x60,0x3F,0x80,0x3C,0x00, +// 'K' +0x4B,0x03,0x0C,0x12,0x03,0x0F, +0xC0,0x6C,0x0E,0xC1,0xCC,0x38,0xC7,0x0C,0xE0,0xDC,0x0F,0x80,0xF0,0x0F,0x00,0xF8,0x0F,0xC0,0xDE,0x0C,0xF0,0xC7,0x8C,0x1E,0xC0,0xFC,0x07, +// 'L' +0x4C,0x03,0x0B,0x12,0x01,0x0D, +0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xEF,0xFC, +// 'M' +0x4D,0x03,0x13,0x13,0x01,0x15, +0x0C,0x06,0x01,0x80,0xC0,0x78,0x3C,0x0F,0x07,0x81,0xE0,0xF0,0x3C,0x1E,0x07,0x83,0xC1,0xD8,0xEC,0x3B,0x1D,0x87,0x63,0xB0,0xCC,0xE6,0x38,0xDC,0x47,0x1B,0x8C,0xE3,0xF1,0xB8,0x3C,0x37,0x07,0x86,0xE0,0xF0,0x7C,0x1E,0x0F,0x01,0x81,0x80, +// 'N' +0x4E,0x03,0x11,0x12,0x01,0x13, +0x60,0x01,0x38,0x00,0xDE,0x00,0x6F,0x00,0x37,0xC0,0x1B,0x70,0x0D,0x9C,0x06,0xCF,0x03,0x63,0x81,0xB0,0xE0,0xD8,0x38,0x6C,0x0E,0x36,0x03,0x9B,0x00,0xED,0x80,0x3E,0xC0,0x0F,0x60,0x03,0xB0,0x00,0xC0, +// 'O' +0x4F,0x03,0x11,0x12,0x01,0x13, +0x01,0xF8,0x03,0xFF,0x07,0x81,0xC3,0x00,0x63,0x00,0x1B,0x80,0x0D,0x80,0x07,0xC0,0x03,0xC0,0x01,0xE0,0x00,0xF0,0x00,0xF8,0x00,0x6C,0x00,0x33,0x00,0x31,0xC0,0x38,0x70,0x78,0x1F,0xF8,0x03,0xF0,0x00, +// 'P' +0x50,0x03,0x0B,0x12,0x01,0x0D, +0xFE,0x1F,0xF3,0x0F,0x60,0x7C,0x07,0x80,0xF0,0x1E,0x06,0xC3,0xDF,0xF3,0xF8,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x00, +// 'Q' +0x51,0x03,0x14,0x17,0x01,0x15, +0x01,0xF8,0x00,0x7F,0xE0,0x1E,0x07,0x03,0x80,0x18,0x30,0x01,0xC6,0x00,0x0C,0x60,0x00,0xEC,0x00,0x06,0xC0,0x00,0x6C,0x00,0x06,0xC0,0x00,0x6C,0x00,0x06,0x60,0xE0,0xE7,0x0F,0x0C,0x38,0x79,0xC1,0xC3,0xF8,0x0F,0xFF,0x00,0x3F,0x78,0x00,0x03,0xC0,0x00,0x1E,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x20, +// 'R' +0x52,0x02,0x0D,0x13,0x01,0x0F, +0x00,0x03,0xE0,0x3F,0xC1,0x8F,0x0C,0x0E,0x60,0x33,0x00,0xD8,0x06,0xC0,0x36,0x03,0xB0,0x79,0xFF,0x8F,0xF0,0x7F,0x83,0x1F,0x18,0x3C,0xC0,0xF6,0x01,0xF0,0x06, +// 'S' +0x53,0x03,0x0F,0x13,0x01,0x11, +0x01,0xF0,0x07,0xF8,0x18,0x70,0x60,0x01,0x80,0x03,0x00,0x06,0x00,0x0E,0x00,0x0F,0xF0,0x07,0xF0,0x00,0xF0,0x00,0x70,0x00,0x60,0x00,0xD8,0x01,0xB8,0x06,0x78,0x3C,0x7F,0xE0,0x3F,0x00, +// 'T' +0x54,0x02,0x0F,0x13,0x01,0x10, +0x00,0x01,0xFF,0xFD,0xFF,0xF8,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00, +// 'U' +0x55,0x03,0x11,0x12,0x01,0x12, +0x60,0x03,0x30,0x01,0x98,0x00,0xCC,0x00,0x66,0x00,0x33,0x00,0x19,0x80,0x0C,0xC0,0x06,0x60,0x03,0x30,0x01,0x98,0x01,0xCC,0x00,0xC7,0x00,0x61,0x80,0x70,0xE0,0x30,0x38,0x38,0x0F,0xF8,0x01,0xF0,0x00, +// 'V' +0x56,0x03,0x0E,0x13,0x02,0x10, +0x80,0x0F,0x00,0x3C,0x01,0xB0,0x06,0x60,0x31,0x80,0xC6,0x03,0x0C,0x18,0x30,0x60,0xC1,0x81,0x8C,0x06,0x30,0x0D,0x80,0x36,0x00,0xF8,0x01,0xC0,0x07,0x00,0x08,0x00,0x00,0x00, +// 'W' +0x57,0x03,0x17,0x12,0x01,0x19, +0xC0,0x20,0x0F,0xC0,0x60,0x19,0x81,0xC0,0x23,0x03,0x80,0xC6,0x07,0x01,0x86,0x1E,0x03,0x0C,0x36,0x0C,0x18,0x6C,0x18,0x11,0x98,0x60,0x33,0x30,0xC0,0x66,0x61,0x80,0xD8,0x66,0x01,0xB0,0xCC,0x01,0xC1,0xB0,0x03,0x83,0x60,0x07,0x07,0x80,0x0C,0x07,0x00,0x08,0x0E,0x00, +// 'X' +0x58,0x03,0x10,0x12,0x01,0x11, +0x60,0x03,0x70,0x07,0x38,0x0E,0x1C,0x1C,0x0C,0x1C,0x0E,0x38,0x07,0x70,0x03,0xE0,0x01,0xC0,0x03,0xC0,0x07,0xE0,0x07,0x70,0x0E,0x38,0x1C,0x18,0x38,0x1C,0x70,0x0E,0xE0,0x07,0xC0,0x03, +// 'Y' +0x59,0x03,0x0F,0x13,0x00,0x10, +0x60,0x06,0xE0,0x1D,0xC0,0x31,0xC0,0xE1,0xC1,0x83,0x83,0x03,0x8C,0x07,0x18,0x07,0x70,0x0F,0xC0,0x0F,0x80,0x0F,0x00,0x1C,0x00,0x38,0x00,0x60,0x01,0xC0,0x03,0x00,0x06,0x00,0x08,0x00, +// 'Z' +0x5A,0x03,0x0F,0x12,0x01,0x11, +0xFF,0xFF,0xFF,0xFC,0x00,0xF0,0x03,0x80,0x0E,0x00,0x3C,0x00,0xF0,0x03,0xC0,0x07,0x00,0x1E,0x00,0x38,0x00,0xE0,0x03,0xC0,0x07,0x00,0x1C,0x00,0x70,0x00,0xFF,0xFF,0xFF,0xFC, +// '[' +0x5B,0x01,0x07,0x1A,0x01,0x09, +0x00,0xFD,0xFB,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x3F,0x7E,0x00, +// '\' +0x5C,0x03,0x0B,0x14,0x02,0x0D, +0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x60,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x20,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x60, +// ']' +0x5D,0x01,0x07,0x1A,0x02,0x09, +0x01,0xFB,0xF0,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x7E,0xFC,0x00, +// '^' +0x5E,0x02,0x0A,0x06,0x02,0x0E, +0x0C,0x07,0x83,0xF1,0xCE,0xE1,0xF0,0x30, +// '_' +0x5F,0x16,0x0F,0x04,0x00,0x0F, +0x00,0x01,0xFF,0xFF,0xFF,0xF8,0x00,0x00, +// '`' +0x60,0x02,0x05,0x06,0x02,0x0D, +0xC7,0x1C,0x63,0x8C, +// 'a' +0x61,0x09,0x0B,0x0C,0x01,0x0C, +0x0F,0x87,0xF9,0xE3,0x30,0x6E,0x0D,0x81,0xB0,0x36,0x06,0xC0,0xCC,0x39,0xFF,0x9F,0x30, +// 'b' +0x62,0x02,0x0C,0x13,0x01,0x0E, +0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x78,0x7F,0xC7,0x8E,0x60,0x76,0x03,0x60,0x36,0x03,0x60,0x36,0x06,0x70,0xE7,0xFC,0x7F,0x00, +// 'c' +0x63,0x09,0x0A,0x0C,0x01,0x0C, +0x0F,0x07,0xF3,0x0D,0x80,0x60,0x30,0x0C,0x03,0x00,0xC0,0x1C,0x33,0xFC,0x7C, +// 'd' +0x64,0x02,0x0C,0x13,0x01,0x0E, +0x00,0x20,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x61,0xF6,0x3F,0xE7,0x0E,0x60,0x6C,0x06,0xC0,0x6C,0x06,0xC0,0x6E,0x06,0x70,0xE3,0xFE,0x1F,0x60, +// 'e' +0x65,0x09,0x0B,0x0C,0x01,0x0D, +0x1F,0x07,0xF9,0xC7,0x30,0xEC,0x79,0xBE,0x3E,0x07,0x00,0xC0,0x6E,0x1D,0xFF,0x0F,0x80, +// 'f' +0x66,0x02,0x0A,0x14,0x01,0x0C, +0x03,0x83,0xE0,0xE0,0x70,0x18,0x06,0x01,0x83,0xFF,0xFF,0xC6,0x01,0x80,0x60,0x18,0x06,0x01,0x80,0x60,0x18,0x06,0x01,0x80,0x60, +// 'g' +0x67,0x09,0x0A,0x13,0x02,0x0D, +0x0F,0x0F,0xF7,0x0D,0x83,0xC0,0xF0,0x3C,0x1F,0x07,0xC1,0xD8,0xF7,0xEC,0xF3,0x00,0xC0,0x30,0x18,0x06,0x03,0xBF,0xC7,0xE0, +// 'h' +0x68,0x02,0x0B,0x13,0x01,0x0E, +0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x1E,0x6F,0xEF,0x8D,0xE1,0xB8,0x36,0x06,0xC0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0x80, +// 'i' +0x69,0x04,0x02,0x11,0x03,0x07, +0xF0,0x3F,0xFF,0xFF,0xC0, +// 'j' +0x6A,0x04,0x08,0x18,0x00,0x0A, +0x03,0x03,0x00,0x00,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0xC3,0xE3,0x77,0x7E,0x1C, +// 'k' +0x6B,0x03,0x0B,0x13,0x02,0x0E, +0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x36,0x0E,0xC7,0x99,0xE3,0x70,0x7E,0x0F,0xE1,0xCE,0x30,0xE6,0x0E,0xC0,0xF8,0x08,0x00,0x00, +// 'l' +0x6C,0x02,0x02,0x13,0x03,0x07, +0xFF,0xFF,0xFF,0xFF,0xFC, +// 'm' +0x6D,0x09,0x10,0x0C,0x01,0x12, +0x67,0x3C,0x6F,0xFE,0x7D,0xEE,0x79,0x86,0x71,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86, +// 'n' +0x6E,0x09,0x0B,0x0C,0x01,0x0D, +0x63,0x8D,0xF9,0xF1,0xBC,0x37,0x06,0xE0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0xB0,0x30, +// 'o' +0x6F,0x09,0x0C,0x0C,0x01,0x0D, +0x0F,0x81,0xFC,0x38,0xC3,0x06,0x60,0x66,0x06,0x60,0x66,0x06,0x60,0xE3,0x1C,0x1F,0x80,0xF0, +// 'p' +0x70,0x08,0x0A,0x14,0x02,0x0D, +0xC0,0x33,0xCF,0xFB,0xC6,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x7C,0x1B,0xFC,0xFE,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00, +// 'q' +0x71,0x08,0x0A,0x14,0x01,0x0C, +0x00,0x03,0xF3,0xFD,0xE3,0x60,0xF8,0x3C,0x0F,0x03,0xC0,0xF0,0x76,0x1D,0xFF,0x1F,0x80,0x60,0x18,0x06,0x01,0x80,0x60,0x18,0x06, +// 'r' +0x72,0x09,0x09,0x0C,0x01,0x0B, +0xCF,0x6F,0xFE,0x7C,0x3C,0x1E,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x00, +// 's' +0x73,0x09,0x09,0x0C,0x02,0x0C, +0x03,0x9F,0xDE,0x7C,0x3E,0x07,0xF0,0xFC,0x07,0x01,0xE0,0xFF,0xC7,0xC0, +// 't' +0x74,0x05,0x0A,0x10,0x00,0x0A, +0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30, +// 'u' +0x75,0x09,0x0B,0x0C,0x01,0x0C, +0xC0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0xB0,0x36,0x06,0xC0,0xD8,0x19,0xFF,0x1F,0x60, +// 'v' +0x76,0x09,0x0B,0x0D,0x01,0x0C, +0xC0,0x78,0x1F,0x83,0x30,0x67,0x1C,0x63,0x0C,0xE0,0xD8,0x1E,0x03,0xC0,0x30,0x06,0x00,0x00, +// 'w' +0x77,0x09,0x0F,0x0D,0x01,0x11, +0xC1,0x87,0x83,0x0F,0x0E,0x1E,0x1C,0x66,0x7C,0xCC,0xD9,0x99,0x36,0x36,0x6C,0x7C,0xD8,0x70,0xE0,0xE1,0xC0,0x83,0x80,0x00,0x00, +// 'x' +0x78,0x09,0x0D,0x0D,0x01,0x0E, +0x60,0x1B,0x81,0xCE,0x1C,0x39,0xC0,0xFC,0x03,0xC0,0x3C,0x03,0xF0,0x39,0xC3,0x87,0x38,0x1D,0x80,0x70,0x01,0x80, +// 'y' +0x79,0x09,0x0C,0x13,0x00,0x0D, +0xC0,0x3E,0x07,0x60,0x67,0x0C,0x30,0xC3,0x98,0x19,0x81,0xD8,0x0F,0x00,0xF0,0x06,0x00,0x60,0x0C,0x00,0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x30,0x00, +// 'z' +0x7A,0x09,0x0B,0x0C,0x01,0x0D, +0xFF,0xFF,0xFC,0x07,0x00,0xC0,0x30,0x0C,0x03,0x80,0xE0,0x38,0x0E,0x03,0xFF,0xFF,0xF0, +// '{' +0x7B,0x02,0x08,0x18,0x01,0x09, +0x0F,0x1F,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x60,0xE0,0xE0,0x70,0x30,0x30,0x30,0x30,0x30,0x38,0x18,0x1F,0x07, +// '|' +0x7C,0x01,0x02,0x18,0x04,0x0A, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +// '}' +0x7D,0x02,0x08,0x18,0x01,0x09, +0x70,0xF8,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x06,0x07,0x07,0x0E,0x0C,0x0C,0x0C,0x0C,0x0C,0x1C,0x18,0xF8,0xE0, +// '~' +0x7E,0x0B,0x0C,0x05,0x01,0x0E, +0x38,0x37,0xE3,0xE7,0x7C,0x3E,0x01,0xC0, + +// Terminator +0xFF +}; diff --git a/components/tft/component.mk b/components/tft/component.mk new file mode 100644 index 0000000..0f76ee5 --- /dev/null +++ b/components/tft/component.mk @@ -0,0 +1,7 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + +COMPONENT_SRCDIRS := . +COMPONENT_ADD_INCLUDEDIRS := . diff --git a/components/tft/def_small.c b/components/tft/def_small.c new file mode 100644 index 0000000..54101cd --- /dev/null +++ b/components/tft/def_small.c @@ -0,0 +1,332 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// def_small.c +// Point Size : 9 +// Memory usage : 928 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + + +unsigned char tft_def_small[] = +{ +0x00, 0x08, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x08,0x00,0x00,0x00,0x03, + +// '!' +0x21,0x01,0x01,0x07,0x01,0x03, +0xFA, +// '"' +0x22,0x01,0x03,0x02,0x01,0x04, +0xB4, +// '#' +0x23,0x01,0x06,0x07,0x01,0x08, +0x28,0xAF,0xCA,0xFD,0x45,0x00, +// '$' +0x24,0x01,0x06,0x08,0x00,0x06, +0x21,0xEA,0x38,0x38,0xAF,0x08, +// '%' +0x25,0x01,0x08,0x07,0x00,0x09, +0x44,0xA4,0xA8,0x5A,0x15,0x25,0x22, +// '&' +0x26,0x01,0x06,0x07,0x01,0x08, +0x31,0x04,0x19,0x9E,0x66,0xC0, +// ''' +0x27,0x01,0x01,0x02,0x01,0x02, +0xC0, +// '(' +0x28,0x00,0x02,0x08,0x01,0x04, +0x4A,0xA1, +// ')' +0x29,0x00,0x02,0x08,0x01,0x04, +0x85,0x52, +// '*' +0x2A,0x01,0x05,0x04,0x00,0x05, +0xAB,0x9D,0x50, +// '+' +0x2B,0x03,0x05,0x05,0x01,0x08, +0x21,0x3E,0x42,0x00, +// ',' +0x2C,0x07,0x01,0x02,0x01,0x03, +0xC0, +// '-' +0x2D,0x05,0x02,0x01,0x01,0x03, +0xC0, +// '.' +0x2E,0x07,0x01,0x01,0x01,0x03, +0x80, +// '/' +0x2F,0x01,0x03,0x07,0x00,0x03, +0x25,0x25,0x20, +// '0' +0x30,0x01,0x04,0x07,0x01,0x06, +0x69,0x99,0x99,0x60, +// '1' +0x31,0x01,0x03,0x07,0x02,0x06, +0xC9,0x24,0xB8, +// '2' +0x32,0x01,0x05,0x07,0x01,0x06, +0x64,0x84,0x44,0x43,0xC0, +// '3' +0x33,0x01,0x04,0x07,0x01,0x06, +0x69,0x16,0x11,0x60, +// '4' +0x34,0x01,0x05,0x07,0x01,0x06, +0x11,0x94,0xA9,0x7C,0x40, +// '5' +0x35,0x01,0x04,0x07,0x01,0x06, +0xF8,0x8E,0x11,0xE0, +// '6' +0x36,0x01,0x04,0x07,0x01,0x06, +0x7C,0x8E,0x99,0x60, +// '7' +0x37,0x01,0x04,0x07,0x01,0x06, +0xF1,0x22,0x24,0x40, +// '8' +0x38,0x01,0x04,0x07,0x01,0x06, +0x69,0x96,0x99,0x60, +// '9' +0x39,0x01,0x04,0x07,0x01,0x06, +0x69,0x97,0x13,0xE0, +// ':' +0x3A,0x03,0x01,0x05,0x01,0x03, +0x88, +// ';' +0x3B,0x03,0x01,0x06,0x01,0x03, +0x8C, +// '<' +0x3C,0x03,0x06,0x05,0x01,0x08, +0x04,0xEE,0x0E,0x04, +// '=' +0x3D,0x04,0x06,0x03,0x01,0x08, +0xFC,0x0F,0xC0, +// '>' +0x3E,0x03,0x06,0x05,0x01,0x08, +0x81,0xC1,0xDC,0x80, +// '?' +0x3F,0x01,0x04,0x07,0x01,0x05, +0xE1,0x24,0x40,0x40, +// '@' +0x40,0x01,0x08,0x08,0x01,0x0A, +0x3C,0x42,0x9D,0xA5,0xA5,0x9E,0x40,0x38, +// 'A' +0x41,0x01,0x06,0x07,0x00,0x06, +0x30,0xC4,0x92,0x7A,0x18,0x40, +// 'B' +0x42,0x01,0x05,0x07,0x01,0x07, +0xF4,0x63,0xE8,0xC7,0xC0, +// 'C' +0x43,0x01,0x05,0x07,0x01,0x07, +0x72,0x61,0x08,0x25,0xC0, +// 'D' +0x44,0x01,0x05,0x07,0x01,0x07, +0xF4,0xE3,0x18,0xCF,0xC0, +// 'E' +0x45,0x01,0x04,0x07,0x01,0x06, +0xF8,0x8F,0x88,0xF0, +// 'F' +0x46,0x01,0x04,0x07,0x01,0x06, +0xF8,0x8F,0x88,0x80, +// 'G' +0x47,0x01,0x05,0x07,0x01,0x07, +0x76,0x61,0x38,0xE5,0xC0, +// 'H' +0x48,0x01,0x05,0x07,0x01,0x07, +0x8C,0x63,0xF8,0xC6,0x20, +// 'I' +0x49,0x01,0x01,0x07,0x01,0x03, +0xFE, +// 'J' +0x4A,0x01,0x02,0x09,0x00,0x03, +0x55,0x55,0x80, +// 'K' +0x4B,0x01,0x05,0x07,0x01,0x06, +0x8C,0xA9,0x8A,0x4A,0x20, +// 'L' +0x4C,0x01,0x04,0x07,0x01,0x05, +0x88,0x88,0x88,0xF0, +// 'M' +0x4D,0x01,0x06,0x07,0x01,0x08, +0x87,0x3C,0xED,0xB6,0x18,0x40, +// 'N' +0x4E,0x01,0x05,0x07,0x01,0x07, +0x8E,0x73,0x59,0xCE,0x20, +// 'O' +0x4F,0x01,0x05,0x07,0x01,0x07, +0x76,0xE3,0x18,0xED,0xC0, +// 'P' +0x50,0x01,0x04,0x07,0x01,0x06, +0xE9,0x9E,0x88,0x80, +// 'Q' +0x51,0x01,0x05,0x08,0x01,0x07, +0x76,0xE3,0x18,0xE9,0xC2, +// 'R' +0x52,0x01,0x05,0x07,0x01,0x06, +0xE4,0xA5,0xCA,0x4A,0x20, +// 'S' +0x53,0x01,0x06,0x07,0x01,0x07, +0x72,0x28,0x1C,0x0A,0x27,0x00, +// 'T' +0x54,0x01,0x05,0x07,0x00,0x05, +0xF9,0x08,0x42,0x10,0x80, +// 'U' +0x55,0x01,0x05,0x07,0x01,0x07, +0x8C,0x63,0x18,0xC5,0xC0, +// 'V' +0x56,0x01,0x06,0x07,0x00,0x06, +0x86,0x14,0x92,0x48,0xC3,0x00, +// 'W' +0x57,0x01,0x09,0x07,0xFF,0x07, +0x49,0x24,0x8A,0x85,0x43,0xE0,0xA0,0x50, +// 'X' +0x58,0x01,0x06,0x07,0x00,0x06, +0xCD,0x23,0x0C,0x31,0x28,0xC0, +// 'Y' +0x59,0x01,0x05,0x07,0x00,0x05, +0x8A,0x9C,0x42,0x10,0x80, +// 'Z' +0x5A,0x01,0x05,0x07,0x00,0x05, +0xF8,0x44,0x44,0x43,0xE0, +// '[' +0x5B,0x01,0x02,0x08,0x01,0x04, +0xEA,0xAB, +// '\' +0x5C,0x01,0x03,0x07,0x00,0x03, +0x91,0x24,0x48, +// ']' +0x5D,0x01,0x02,0x08,0x01,0x04, +0xD5,0x57, +// '^' +0x5E,0x01,0x06,0x02,0x01,0x08, +0x31,0x20, +// '_' +0x5F,0x09,0x05,0x01,0x00,0x05, +0xF8, +// '`' +0x60,0x00,0x02,0x02,0x01,0x05, +0x90, +// 'a' +0x61,0x03,0x04,0x05,0x01,0x06, +0x61,0x79,0xF0, +// 'b' +0x62,0x00,0x04,0x08,0x01,0x06, +0x88,0x8E,0x99,0x9E, +// 'c' +0x63,0x03,0x04,0x05,0x01,0x06, +0x78,0x88,0x70, +// 'd' +0x64,0x00,0x04,0x08,0x01,0x06, +0x11,0x17,0x99,0x97, +// 'e' +0x65,0x03,0x04,0x05,0x01,0x06, +0x69,0xF8,0x70, +// 'f' +0x66,0x00,0x04,0x08,0x00,0x03, +0x34,0x4E,0x44,0x44, +// 'g' +0x67,0x03,0x04,0x07,0x01,0x06, +0x79,0x99,0x71,0x60, +// 'h' +0x68,0x00,0x04,0x08,0x01,0x06, +0x88,0x8E,0x99,0x99, +// 'i' +0x69,0x01,0x01,0x07,0x01,0x03, +0xBE, +// 'j' +0x6A,0x01,0x02,0x09,0x00,0x03, +0x45,0x55,0x80, +// 'k' +0x6B,0x00,0x04,0x08,0x01,0x05, +0x88,0x89,0xAC,0xA9, +// 'l' +0x6C,0x00,0x01,0x08,0x01,0x03, +0xFF, +// 'm' +0x6D,0x03,0x07,0x05,0x01,0x09, +0xED,0x26,0x4C,0x99,0x20, +// 'n' +0x6E,0x03,0x04,0x05,0x01,0x06, +0xE9,0x99,0x90, +// 'o' +0x6F,0x03,0x04,0x05,0x01,0x06, +0x69,0x99,0x60, +// 'p' +0x70,0x03,0x04,0x07,0x01,0x06, +0xE9,0x99,0xE8,0x80, +// 'q' +0x71,0x03,0x04,0x07,0x01,0x06, +0x79,0x99,0x71,0x10, +// 'r' +0x72,0x03,0x03,0x05,0x01,0x04, +0xF2,0x48, +// 's' +0x73,0x03,0x04,0x05,0x01,0x05, +0x68,0x62,0xE0, +// 't' +0x74,0x02,0x04,0x06,0x00,0x04, +0x4F,0x44,0x47, +// 'u' +0x75,0x03,0x04,0x05,0x01,0x06, +0x99,0x99,0x70, +// 'v' +0x76,0x03,0x07,0x05,0xFF,0x05, +0x44,0x98,0xA1,0xC1,0x00, +// 'w' +0x77,0x03,0x07,0x05,0x00,0x07, +0x93,0x76,0xBA,0x24,0x40, +// 'x' +0x78,0x03,0x05,0x05,0x00,0x05, +0x8A,0x88,0xA8,0x80, +// 'y' +0x79,0x03,0x07,0x07,0xFF,0x05, +0x44,0x88,0xA1,0xC1,0x02,0x18,0x00, +// 'z' +0x7A,0x03,0x04,0x05,0x01,0x06, +0xF1,0x24,0xF0, +// '{' +0x7B,0x01,0x03,0x08,0x01,0x05, +0x69,0x64,0x93, +// '|' +0x7C,0x01,0x01,0x09,0x01,0x03, +0xFF,0x80, +// '}' +0x7D,0x01,0x03,0x08,0x01,0x05, +0xC9,0x34,0x96, +// '~' +0x7E,0x03,0x06,0x03,0x01,0x08, +0x01,0x91,0x80, + +// Terminator +0xFF +}; diff --git a/components/tft/minya24.c b/components/tft/minya24.c new file mode 100644 index 0000000..6bab953 --- /dev/null +++ b/components/tft/minya24.c @@ -0,0 +1,331 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// minya24.c +// Point Size : 24 +// Memory usage : 2807 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +unsigned char tft_minya24[] = +{ +0x00, 0x15, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x13,0x00,0x00,0x00,0x07, + +// '!' +0x21,0x02,0x05,0x12,0x00,0x05, +0x11,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x42,0x01,0xCE,0x73,0x80, +// '"' +0x22,0x01,0x06,0x08,0x00,0x06, +0x01,0xA6,0xDB,0x6D,0xB6,0xC0, +// '#' +0x23,0x04,0x0C,0x0E,0x00,0x0B, +0x04,0x80,0x6C,0x0C,0x80,0xD8,0x7F,0xE7,0xFE,0x1B,0x01,0xB0,0x7F,0xE7,0xFC,0x12,0x03,0x20,0x32,0x00,0x00, +// '$' +0x24,0x02,0x0A,0x11,0x00,0x0B, +0x04,0x01,0x61,0xF8,0xFE,0x65,0x19,0x06,0x40,0xF0,0x1F,0x01,0xE0,0x4C,0x93,0x7C,0xCF,0xE0,0x60,0x10,0x04,0x00, +// '%' +0x25,0x01,0x0D,0x14,0x01,0x0F, +0x00,0x01,0xC1,0x1F,0x19,0x8C,0xCC,0x6C,0x63,0x61,0x36,0x0F,0xB0,0x1B,0x00,0x18,0x01,0x80,0x0C,0x00,0xCE,0x06,0xF8,0x6C,0x66,0x63,0x33,0x13,0x0F,0x98,0x38,0x00,0x00, +// '&' +0x26,0x02,0x0E,0x11,0x00,0x0D, +0x0E,0x00,0x7C,0x01,0xB0,0x06,0xC0,0x1E,0x00,0x38,0x00,0xC3,0x07,0x8C,0x37,0x60,0xCD,0x86,0x1E,0x18,0x70,0x41,0xE1,0x07,0xC6,0x33,0x9F,0x86,0x38,0x00, +// ''' +0x27,0x02,0x03,0x08,0x00,0x03, +0x6D,0xB6,0xD8, +// '(' +0x28,0x01,0x05,0x14,0x02,0x07, +0x00,0x8E,0x66,0x33,0x18,0xC6,0x31,0x8C,0x61,0x0C,0x63,0x8C,0x00, +// ')' +0x29,0x01,0x06,0x15,0x00,0x07, +0x01,0x86,0x0C,0x18,0x61,0x82,0x08,0x30,0xC2,0x08,0x61,0x86,0x30,0xC6,0x10,0x00, +// '*' +0x2A,0x04,0x0A,0x0D,0x01,0x0B, +0x08,0x03,0x04,0xC1,0xF6,0x7F,0x07,0x81,0xC0,0xF8,0x3F,0x1B,0xCC,0xD8,0x30,0x0C,0x00, +// '+' +0x2B,0x06,0x0A,0x0A,0x01,0x0B, +0x00,0x03,0x00,0xC0,0x30,0x7F,0xBF,0xE0,0xC0,0x30,0x0C,0x00,0x00, +// ',' +0x2C,0x10,0x05,0x07,0x00,0x05, +0x33,0x9C,0x63,0x20,0x00, +// '-' +0x2D,0x09,0x07,0x02,0x00,0x07, +0x7D,0xF8, +// '.' +0x2E,0x10,0x04,0x04,0x01,0x05, +0x6E,0xE6, +// '/' +0x2F,0x01,0x0C,0x13,0x00,0x0B, +0x00,0x00,0x06,0x00,0x60,0x0C,0x00,0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x60,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x30,0x06,0x00,0x40,0x00, +// '0' +0x30,0x08,0x0B,0x0B,0x00,0x0B, +0x0E,0x03,0xE0,0xC6,0x30,0x66,0x0C,0xC0,0x98,0x33,0x06,0x61,0xC7,0xF0,0x7C,0x00, +// '1' +0x31,0x08,0x0A,0x0D,0x00,0x09, +0x04,0x1F,0x03,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x07,0xF9,0xFE,0x00,0x00, +// '2' +0x32,0x06,0x0A,0x0E,0x00,0x0A, +0x0E,0x07,0xC3,0x30,0xCC,0x03,0x01,0x80,0x60,0x30,0x18,0x0C,0x03,0x01,0xF8,0x7F,0xC0,0x20, +// '3' +0x33,0x08,0x09,0x10,0x00,0x08, +0x78,0x3F,0x81,0x81,0x81,0xC0,0xC0,0xE0,0x78,0x06,0x01,0x01,0x80,0xC0,0xE1,0xE0,0xC0,0x00, +// '4' +0x34,0x03,0x0B,0x13,0x00,0x0A, +0x00,0x00,0xC0,0x18,0x03,0x00,0x60,0x08,0x03,0x00,0x60,0x0D,0x83,0x20,0x64,0x18,0x83,0x10,0xC6,0x1F,0xF3,0xFE,0x03,0x00,0x60,0x0C,0x00, +// '5' +0x35,0x09,0x0A,0x0E,0x00,0x0A, +0x3F,0x8F,0xE3,0x00,0x80,0x60,0x1F,0x87,0xF0,0x06,0x01,0x80,0x60,0x19,0x86,0x7F,0x07,0x80, +// '6' +0x36,0x03,0x0A,0x12,0x00,0x0A, +0x00,0x01,0x80,0xE0,0x30,0x18,0x06,0x03,0x00,0xC0,0x60,0x1B,0x87,0xF1,0x86,0x61,0x90,0x66,0x19,0x86,0x3F,0x07,0x80, +// '7' +0x37,0x09,0x0A,0x0E,0x00,0x0A, +0x7F,0x9F,0xF0,0x18,0x0C,0x06,0x01,0x80,0xC0,0x30,0x18,0x06,0x01,0x80,0x40,0x10,0x0C,0x00, +// '8' +0x38,0x03,0x0B,0x11,0x00,0x0B, +0x0F,0x07,0xF0,0xC3,0x30,0x66,0x0C,0x63,0x87,0xE0,0xF8,0x39,0xCE,0x19,0x81,0x30,0x34,0x06,0xC1,0x98,0x71,0xFC,0x1F,0x00, +// '9' +0x39,0x07,0x0A,0x11,0x00,0x0A, +0x1E,0x0F,0xC6,0x19,0x86,0x41,0x98,0x66,0x18,0xFE,0x1D,0x80,0x40,0x30,0x0C,0x06,0x03,0x01,0xC0,0x20,0x00,0x00, +// ':' +0x3A,0x0A,0x05,0x0A,0x00,0x05, +0x33,0x9C,0x60,0x00,0xCE,0x71,0x80, +// ';' +0x3B,0x09,0x05,0x0D,0x00,0x06, +0x33,0xDE,0x60,0x00,0x0E,0x73,0x8C,0xC0,0x00, +// '<' +0x3C,0x06,0x0A,0x0C,0x00,0x09, +0x00,0x00,0xE0,0x70,0x38,0x1C,0x1C,0x03,0x00,0x70,0x0E,0x01,0xC0,0x10,0x00, +// '=' +0x3D,0x09,0x08,0x06,0x01,0x0A, +0xFF,0xFE,0x00,0x00,0x7F,0xFF, +// '>' +0x3E,0x06,0x0A,0x0C,0x00,0x09, +0x00,0x18,0x03,0x80,0x70,0x0E,0x00,0xE0,0x30,0x38,0x1C,0x0E,0x02,0x00,0x00, +// '?' +0x3F,0x02,0x09,0x12,0x00,0x09, +0x1E,0x1F,0x98,0x6C,0x30,0x18,0x18,0x38,0x30,0x30,0x18,0x0C,0x02,0x01,0x00,0x00,0x60,0x78,0x3C,0x0C,0x00, +// '@' +0x40,0x02,0x11,0x11,0x00,0x11, +0x01,0xF0,0x03,0xFE,0x03,0x03,0x83,0x00,0xC3,0x04,0x31,0x1F,0x19,0x9F,0x0C,0xCC,0x86,0x4C,0x43,0x24,0x21,0x12,0x39,0x89,0xF7,0x84,0x71,0x83,0x00,0x00,0xC1,0x80,0x3F,0xC0,0x0F,0x80,0x00, +// 'A' +0x41,0x02,0x12,0x13,0x00,0x10, +0x00,0x00,0x01,0xF0,0x00,0x7E,0x00,0x03,0x80,0x01,0xA0,0x00,0x6C,0x00,0x1B,0x00,0x0C,0x40,0x03,0x18,0x01,0x86,0x00,0x61,0x80,0x1F,0xE0,0x0F,0xFC,0x03,0x03,0x01,0x80,0xC0,0x60,0x10,0x18,0x1F,0x9F,0xC7,0xEF,0xF8,0x00, +// 'B' +0x42,0x02,0x0E,0x13,0x00,0x0E, +0x7F,0x81,0xFF,0x81,0x86,0x06,0x18,0x18,0xC0,0x66,0x01,0xFC,0x07,0xFC,0x1C,0x30,0x60,0x61,0x81,0x86,0x06,0x18,0x18,0x60,0x61,0x81,0x06,0x0C,0x18,0xE0,0xFE,0x03,0xE0,0x00, +// 'C' +0x43,0x02,0x0F,0x12,0x00,0x0F, +0x03,0xF0,0x1F,0xE0,0x70,0xC1,0x80,0x83,0x00,0x04,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x06,0x00,0x0E,0x01,0x0E,0x0E,0x0F,0xF8,0x07,0xE0, +// 'D' +0x44,0x02,0x0F,0x13,0x00,0x0F, +0x3F,0xC0,0x7F,0xE0,0x60,0xE0,0xC0,0xC1,0x80,0xC3,0x01,0x86,0x03,0x0C,0x02,0x18,0x04,0x30,0x08,0x60,0x30,0xC0,0x61,0x80,0x83,0x03,0x06,0x0C,0x0C,0x38,0x18,0xE0,0xFF,0x81,0xF8,0x00, +// 'E' +0x45,0x02,0x0D,0x13,0x00,0x0D, +0x3F,0xF1,0xFF,0x86,0x0C,0x30,0x61,0x80,0x0C,0x40,0x62,0x03,0xF0,0x1F,0x80,0xC4,0x06,0x20,0x30,0x01,0x80,0x0C,0x00,0x60,0xC3,0x06,0x7F,0xF3,0xFF,0x80,0x00, +// 'F' +0x46,0x01,0x0E,0x13,0x00,0x0E, +0x00,0x01,0xFF,0xE7,0xFF,0x86,0x06,0x18,0x18,0x63,0x01,0x8C,0x03,0xF0,0x0F,0xC0,0x63,0x01,0x8C,0x06,0x30,0x18,0x00,0x60,0x01,0x80,0x06,0x00,0x3F,0x81,0xFE,0x00,0x00,0x00, +// 'G' +0x47,0x01,0x11,0x14,0x00,0x11, +0x00,0x00,0x03,0xC8,0x03,0xFC,0x03,0x0E,0x03,0x03,0x01,0x00,0x01,0x80,0x00,0xC0,0x00,0x60,0x03,0x30,0x3F,0xD8,0x1F,0x0C,0x01,0x86,0x00,0xC3,0x80,0x60,0xC0,0x30,0x70,0x38,0x1C,0x3C,0x07,0xF6,0x01,0xF3,0x80,0x01,0xE0, +// 'H' +0x48,0x01,0x10,0x13,0x00,0x10, +0x00,0x00,0x7C,0x0F,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x08,0x0C,0x08,0x0F,0xF8,0x0F,0xF8,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x1A,0x7C,0x1F,0x7C,0x10, +// 'I' +0x49,0x02,0x08,0x13,0x00,0x08, +0x7E,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E, +// 'J' +0x4A,0x01,0x0C,0x14,0x00,0x0B, +0x00,0x00,0x7E,0x07,0xE0,0x18,0x01,0x80,0x18,0x01,0x80,0x18,0x00,0x80,0x08,0x00,0x80,0x18,0x61,0x84,0x18,0x41,0x8C,0x18,0xC3,0x06,0x70,0x7E,0x01,0x80, +// 'K' +0x4B,0x02,0x11,0x13,0x00,0x10, +0x7E,0x7E,0x3F,0x3E,0x06,0x06,0x03,0x06,0x01,0x86,0x00,0xC6,0x00,0x66,0x00,0x37,0x00,0x1F,0x80,0x0E,0x60,0x06,0x10,0x03,0x0C,0x01,0x06,0x00,0x81,0x00,0x60,0x80,0x30,0x66,0x7E,0x1B,0x3F,0x0F,0x80,0x01,0x80, +// 'L' +0x4C,0x02,0x0D,0x11,0x00,0x0D, +0x7E,0x03,0xF0,0x06,0x00,0x30,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x00,0xC0,0x06,0x00,0x30,0x01,0x81,0x0C,0x08,0x60,0x4F,0xFF,0x7F,0xF8, +// 'M' +0x4D,0x02,0x14,0x12,0x00,0x13, +0x7C,0x07,0x87,0xC0,0x7C,0x0C,0x06,0x00,0xE0,0xE0,0x0E,0x0E,0x00,0xE0,0xE0,0x1B,0x1E,0x01,0xB1,0x60,0x0B,0x16,0x00,0x9B,0x60,0x09,0xA6,0x00,0x9E,0x60,0x08,0xE6,0x00,0x8C,0x60,0x08,0xC6,0x03,0x8C,0x7E,0x78,0x47,0xE0,0x00,0x00, +// 'N' +0x4E,0x01,0x12,0x13,0x00,0x12, +0x00,0x00,0x1F,0x03,0xF3,0xC0,0x7C,0x38,0x10,0x0E,0x04,0x03,0xC1,0x00,0xB0,0x40,0x26,0x10,0x09,0x84,0x02,0x31,0x00,0x8C,0x40,0x21,0x90,0x08,0x74,0x06,0x0F,0x01,0x81,0xC0,0x60,0x70,0x78,0x0C,0x3E,0x03,0x00,0x00,0x40, +// 'O' +0x4F,0x02,0x11,0x12,0x00,0x11, +0x03,0xE0,0x07,0xFC,0x07,0x07,0x06,0x01,0x82,0x00,0x63,0x00,0x11,0x80,0x0C,0x80,0x06,0x40,0x03,0x20,0x01,0x98,0x00,0xCC,0x00,0x66,0x00,0x31,0x80,0x30,0xE0,0x18,0x38,0x18,0x0F,0xF8,0x01,0xF0,0x00, +// 'P' +0x50,0x02,0x0C,0x12,0x00,0x0C, +0x7F,0x07,0xFC,0x10,0x61,0x03,0x10,0x31,0x03,0x10,0x31,0x06,0x10,0xE1,0xFC,0x1E,0x01,0x00,0x18,0x01,0x80,0x18,0x01,0x80,0x7E,0x07,0xF0, +// 'Q' +0x51,0x02,0x13,0x15,0x00,0x11, +0x07,0xE0,0x01,0xFE,0x00,0x60,0x70,0x18,0x06,0x06,0x00,0x60,0xC0,0x0C,0x18,0x00,0xC2,0x00,0x18,0x40,0x03,0x08,0x0C,0x61,0x83,0xCC,0x30,0xCD,0x83,0x09,0xE0,0x60,0x3C,0x06,0x07,0x00,0x7F,0xE3,0x07,0xEC,0x40,0x01,0x98,0x00,0x33,0x00,0x03,0xC0,0x00,0x30, +// 'R' +0x52,0x02,0x0F,0x13,0x00,0x0F, +0x7F,0x80,0xFF,0xE0,0x60,0xE0,0xC0,0x61,0x80,0xC3,0x01,0x86,0x07,0x0C,0x1C,0x1F,0xF0,0x3F,0x80,0x66,0x00,0xC4,0x01,0x8C,0x63,0x18,0xC6,0x11,0x8C,0x33,0x7E,0x7C,0xFC,0x70,0x00,0x00, +// 'S' +0x53,0x01,0x0D,0x13,0x00,0x0D, +0x00,0x60,0x7B,0x07,0xF8,0x71,0xC3,0x06,0x18,0x00,0xC0,0x03,0x80,0x0E,0x00,0x1C,0x00,0x78,0x00,0xC0,0x03,0x30,0x19,0x80,0xCC,0x06,0x30,0x70,0xFF,0x03,0xE0, +// 'T' +0x54,0x01,0x0F,0x12,0x00,0x0F, +0x00,0x00,0xFF,0xF9,0xFF,0xF3,0x18,0x66,0x30,0xCC,0x61,0x90,0xC3,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x0F,0xE0,0x1F,0xC0, +// 'U' +0x55,0x02,0x10,0x11,0x00,0x0F, +0x7C,0x7E,0x7C,0x7E,0x30,0x08,0x30,0x08,0x30,0x08,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x10,0x08,0x18,0x18,0x18,0x18,0x0C,0x30,0x0F,0xF0,0x03,0xC0, +// 'V' +0x56,0x01,0x10,0x12,0x00,0x10, +0x00,0x7E,0xFE,0x7E,0x7E,0x18,0x18,0x30,0x18,0x30,0x18,0x20,0x08,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x40,0x0C,0xC0,0x04,0xC0,0x04,0xC0,0x06,0x80,0x07,0x80,0x07,0x80,0x03,0x00,0x03,0x00, +// 'W' +0x57,0x01,0x14,0x13,0x00,0x14, +0x00,0x00,0x0F,0xC4,0xFF,0xF0,0x4F,0xE3,0x06,0x10,0x30,0xE3,0x01,0x8E,0x30,0x18,0xE3,0x01,0x8E,0x30,0x19,0xA3,0x01,0x9A,0x20,0x09,0xA6,0x00,0xD2,0x60,0x0D,0x36,0x00,0xF3,0x40,0x0F,0x34,0x00,0x63,0xC0,0x06,0x1C,0x00,0x61,0x80,0x00,0x18,0x00, +// 'X' +0x58,0x01,0x10,0x13,0x00,0x10, +0x00,0x00,0x7F,0x7F,0x7E,0x7E,0x0C,0x30,0x06,0x20,0x06,0x60,0x03,0xC0,0x01,0x80,0x01,0x80,0x03,0x80,0x02,0xC0,0x06,0x40,0x04,0x60,0x0C,0x60,0x18,0x30,0x18,0x30,0x7C,0x30,0xFC,0xFE,0x00,0xFF, +// 'Y' +0x59,0x01,0x11,0x13,0x00,0x10, +0x00,0x00,0x7F,0x3F,0xBF,0x07,0x03,0x03,0x00,0xC1,0x00,0x31,0x80,0x18,0x80,0x06,0xC0,0x01,0xC0,0x00,0xE0,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x07,0x80,0x03,0xF8,0x00,0x7C,0x00, +// 'Z' +0x5A,0x02,0x0E,0x12,0x00,0x0D, +0x7F,0xF9,0xFF,0xE6,0x03,0x18,0x18,0x60,0xC1,0x07,0x00,0x18,0x00,0xC0,0x06,0x00,0x18,0x00,0xC0,0x06,0x00,0x18,0x30,0xC0,0xC3,0x03,0x1F,0xFE,0x7F,0xF8,0x00,0x60, +// '[' +0x5B,0x01,0x08,0x14,0x01,0x08, +0x00,0x7C,0x7C,0x40,0x40,0x40,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x7E,0x00, +// '\' +0x5C,0x01,0x0A,0x13,0x00,0x0A, +0x00,0x10,0x06,0x01,0x80,0x30,0x0C,0x01,0x80,0x60,0x0C,0x03,0x00,0x60,0x18,0x06,0x00,0xC0,0x30,0x06,0x01,0x80,0x60,0x08, +// ']' +0x5D,0x01,0x08,0x14,0x00,0x08, +0x00,0x7C,0x7E,0x04,0x04,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x7C,0xFC, +// '^' +0x5E,0x03,0x0B,0x0B,0x00,0x0B, +0x00,0x00,0x40,0x18,0x03,0x00,0xF0,0x32,0x0C,0x63,0x86,0x60,0xC0,0x0C,0x00,0x00, +// '_' +0x5F,0x15,0x11,0x02,0xFF,0x0F, +0x7F,0xFF,0x3F,0xFF,0x80, +// '`' +0x60,0x00,0x06,0x07,0x00,0x06, +0x01,0x87,0x0C,0x18,0x20,0x00, +// 'a' +0x61,0x06,0x0C,0x0D,0x00,0x0B, +0x0E,0x03,0xF0,0x31,0x06,0x10,0x23,0x80,0xF8,0x3D,0x87,0x10,0x61,0x0C,0x18,0x63,0xA7,0xFE,0x1C,0xC0, +// 'b' +0x62,0x01,0x0C,0x14,0x00,0x0C, +0x00,0x07,0xC0,0x3C,0x01,0x80,0x18,0x01,0x80,0x18,0x01,0x98,0x1F,0xC1,0xC6,0x18,0x21,0x83,0x10,0x31,0x03,0x18,0x31,0x83,0x18,0x6F,0xC6,0xF7,0xC0,0x30, +// 'c' +0x63,0x06,0x0B,0x0D,0x00,0x0B, +0x06,0x03,0xF0,0xC7,0x31,0xE4,0x1C,0x80,0x30,0x06,0x00,0x60,0x0C,0x01,0xC3,0x1F,0xC0,0xF0, +// 'd' +0x64,0x01,0x0D,0x13,0x00,0x0D, +0x00,0x00,0x1E,0x00,0xF0,0x01,0x80,0x0C,0x00,0x60,0x03,0x01,0x98,0x3E,0x81,0x9C,0x18,0x60,0xC3,0x04,0x08,0x60,0x41,0x02,0x0C,0x30,0x71,0x91,0xFF,0x87,0x1C, +// 'e' +0x65,0x07,0x0B,0x0C,0x00,0x0B, +0x0F,0x03,0xF0,0xC3,0x30,0x66,0x1C,0xDE,0x1E,0x03,0x00,0x60,0x06,0x18,0x7E,0x07,0x80, +// 'f' +0x66,0x02,0x0A,0x12,0x00,0x08, +0x07,0x07,0xE1,0xB8,0x4E,0x10,0x04,0x07,0xE1,0xF8,0x18,0x06,0x01,0x80,0x60,0x18,0x06,0x01,0x81,0xF8,0x7E,0x00,0x00, +// 'g' +0x67,0x05,0x0A,0x12,0x00,0x0A, +0x00,0x00,0x20,0x18,0x7E,0x3F,0x18,0x64,0x09,0x02,0x61,0x9F,0xC1,0xE0,0x0C,0x01,0x84,0x67,0x19,0x8C,0x7E,0x0F,0x00, +// 'h' +0x68,0x02,0x0E,0x12,0x00,0x0D, +0x78,0x01,0xE0,0x01,0x80,0x06,0x00,0x19,0xC0,0x2F,0x80,0xE6,0x07,0x08,0x18,0x20,0x60,0x81,0x82,0x06,0x08,0x18,0x20,0x60,0x81,0x82,0x1F,0x9E,0x7E,0x78,0x00,0x00, +// 'i' +0x69,0x02,0x08,0x11,0x00,0x08, +0x30,0x78,0x78,0x30,0x00,0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7F, +// 'j' +0x6A,0x02,0x09,0x15,0xFE,0x07, +0x06,0x07,0x03,0x81,0xC0,0x00,0xF8,0x7C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x99,0x8F,0xC3,0xC0, +// 'k' +0x6B,0x02,0x0D,0x12,0x00,0x0D, +0x78,0x03,0xC0,0x06,0x00,0x37,0xC1,0xBC,0x0C,0xC0,0x6C,0x03,0xC0,0x1C,0x00,0xC0,0x07,0x00,0x3E,0x01,0xB8,0x08,0x61,0xC1,0xCF,0x07,0x00,0x10,0x00,0x00, +// 'l' +0x6C,0x02,0x08,0x12,0x00,0x08, +0x78,0x78,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,0x00, +// 'm' +0x6D,0x08,0x14,0x0D,0x00,0x14, +0x40,0xC3,0x0F,0xBE,0xF8,0x1E,0x78,0xC1,0xC7,0x0C,0x18,0x20,0xC1,0x82,0x0C,0x10,0x20,0xC1,0x82,0x08,0x18,0x60,0x81,0x84,0x18,0x7E,0x71,0xE7,0xE7,0x9E,0x00,0x00,0x00, +// 'n' +0x6E,0x06,0x0E,0x0E,0x00,0x0D, +0x79,0xC1,0xEF,0x81,0xE6,0x07,0x08,0x18,0x30,0x60,0xC1,0x82,0x06,0x08,0x18,0x20,0x60,0x81,0x82,0x1F,0x1E,0x7E,0x78,0x00,0x00, +// 'o' +0x6F,0x08,0x0B,0x0C,0x00,0x0C, +0x0F,0x03,0xF8,0xC3,0x30,0x36,0x06,0x80,0xD0,0x1B,0x03,0x60,0x66,0x18,0xFE,0x07,0x80, +// 'p' +0x70,0x07,0x0B,0x10,0x00,0x0B, +0x07,0x1F,0xF1,0xE3,0x18,0x23,0x06,0x60,0xCC,0x19,0x82,0x30,0xC6,0x18,0xFE,0x1B,0x83,0x00,0x60,0x1C,0x07,0x80, +// 'q' +0x71,0x06,0x0D,0x11,0x00,0x0B, +0x0C,0x01,0xF7,0x0C,0xF8,0xC3,0x04,0x18,0x20,0x41,0x02,0x08,0x10,0x60,0x83,0x04,0x0C,0x60,0x7F,0x01,0xE8,0x00,0xC0,0x06,0xC0,0x1E,0x00,0xE0, +// 'r' +0x72,0x08,0x0A,0x0D,0x00,0x09, +0x77,0x3F,0xE3,0xB8,0xCE,0x33,0x0C,0x03,0x00,0xC0,0x30,0x04,0x07,0xC1,0xF0,0x00,0x00, +// 's' +0x73,0x05,0x0A,0x0E,0x00,0x0A, +0x03,0x00,0xC1,0xF0,0xFC,0x63,0x18,0x47,0x00,0xF8,0x07,0x80,0x64,0x19,0x86,0x7F,0x07,0x80, +// 't' +0x74,0x02,0x09,0x13,0x00,0x09, +0x30,0x18,0x0C,0x06,0x02,0x07,0xE3,0xF8,0x40,0x20,0x10,0x08,0x04,0x02,0x11,0x18,0x84,0x62,0x33,0x0F,0x83,0x00, +// 'u' +0x75,0x06,0x0E,0x0E,0x00,0x0D, +0x00,0x03,0xE7,0xC7,0x9F,0x0C,0x30,0x30,0xC0,0xC3,0x03,0x0C,0x0C,0x30,0x30,0xC0,0xC3,0x03,0x0C,0x0E,0x7C,0x1F,0xF8,0x3C,0x00, +// 'v' +0x76,0x07,0x0E,0x0D,0x00,0x0D, +0x01,0xFB,0xF3,0xEF,0xC6,0x06,0x18,0x18,0x60,0x31,0x00,0xCC,0x01,0x30,0x06,0x80,0x0A,0x00,0x38,0x00,0xE0,0x01,0x00, +// 'w' +0x77,0x08,0x11,0x0D,0x00,0x11, +0x04,0x1F,0xFF,0x6F,0xBE,0x31,0x83,0x1C,0xC1,0x9E,0x40,0x4D,0x20,0x34,0xB0,0x1A,0x78,0x05,0x3C,0x03,0x8E,0x01,0x86,0x00,0x43,0x00,0x00,0x00, +// 'x' +0x78,0x08,0x0D,0x0D,0x00,0x0D, +0x0C,0xFB,0xE7,0xDE,0x18,0x31,0x80,0xD8,0x03,0x80,0x18,0x01,0xE0,0x19,0x81,0x8C,0x0E,0x7D,0xF3,0xE4,0x00,0x00, +// 'y' +0x79,0x06,0x0F,0x11,0x00,0x0D, +0x7C,0x01,0xF8,0x00,0xC3,0xF0,0xC7,0xE1,0x82,0x01,0x0C,0x03,0x18,0x06,0x20,0x06,0xC0,0x0D,0x00,0x0E,0x00,0x18,0x00,0x30,0x06,0xC0,0x1F,0x00,0x3E,0x00,0x30,0x00, +// 'z' +0x7A,0x08,0x0B,0x0B,0x00,0x0B, +0x7F,0xCF,0xF9,0x86,0x31,0x86,0x60,0x1C,0x07,0x00,0xC6,0x30,0xCF,0xF9,0xFF,0x00, +// '{' +0x7B,0x02,0x09,0x12,0x00,0x08, +0x07,0x07,0x83,0x01,0x01,0x80,0xC0,0x60,0xE0,0x70,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x1F,0x03,0x80, +// '|' +0x7C,0x02,0x03,0x12,0x01,0x05, +0x49,0x24,0x92,0x6D,0xB6,0xDB,0x6C, +// '}' +0x7D,0x02,0x07,0x11,0x00,0x07, +0x30,0xF0,0x20,0x41,0x83,0x02,0x06,0x0E,0x18,0x60,0xC0,0x81,0x83,0x3C,0x78, +// '~' +0x7E,0x09,0x0D,0x04,0x00,0x0D, +0x18,0x03,0xF1,0x98,0xFC,0x83,0xC0, + +// Terminator +0xFF +}; \ No newline at end of file diff --git a/components/tft/stmpe610.h b/components/tft/stmpe610.h new file mode 100644 index 0000000..6a52454 --- /dev/null +++ b/components/tft/stmpe610.h @@ -0,0 +1,71 @@ +/* + STMPE610 Touch controller constants +*/ + +#ifndef _STMPE610_H +#define _STMPE610_H + +#include + +#define STMPE610_SPI_MODE 1 + +// Identification registers +#define STMPE610_REG_CHP_ID 0x00 // 16-bit +#define STMPE610_REG_ID_VER 0x02 + +// System registers +#define STMPE610_REG_SYS_CTRL1 0x03 +#define STMPE610_REG_SYS_CTRL2 0x04 +#define STMPE610_REG_SPI_CFG 0x08 + +// Interrupt control registers +#define STMPE610_REG_INT_CTRL 0x09 +#define STMPE610_REG_INT_EN 0x0A +#define STMPE610_REG_INT_STA 0x0B +#define STMPE610_REG_GPIO_INT_EN 0x0C +#define STMPE610_REG_GPIO_INT_STA 0x0D +#define STMPE610_REG_ADC_INT_EN 0x0E +#define STMPE610_REG_ADC_INT_STA 0x0F + +// GPIO registers +#define STMPE610_REG_GPIO_SET_PIN 0x10 +#define STMPE610_REG_GPIO_CLR_PIN 0x11 +#define STMPE610_REG_GPIO_MP_STA 0x12 +#define STMPE610_REG_GPIO_DIR 0x13 +#define STMPE610_REG_GPIO_ED 0x14 +#define STMPE610_REG_GPIO_RE 0x15 +#define STMPE610_REG_GPIO_FE 0x16 +#define STMPE610_REG_GPIO_AF 0x17 + +// ADC registers +#define STMPE610_REG_ADC_CTRL1 0x20 +#define STMPE610_REG_ADC_CTRL2 0x21 +#define STMPE610_REG_ADC_CAPT 0x22 +#define STMPE610_REG_ADC_DATA_CH0 0x30 // 16-bit +#define STMPE610_REG_ADC_DATA_CH1 0x32 // 16-bit +#define STMPE610_REG_ADC_DATA_CH4 0x38 // 16-bit +#define STMPE610_REG_ADC_DATA_CH5 0x3A // 16-bit +#define STMPE610_REG_ADC_DATA_CH6 0x3C // 16-bit +#define STMPE610_REG_ADC_DATA_CH7 0x3E // 16-bit + +// Touchscreen registers +#define STMPE610_REG_TSC_CTRL 0x40 +#define STMPE610_REG_TSC_CFG 0x41 +#define STMPE610_REG_WDW_TR_X 0x42 // 16-bit +#define STMPE610_REG_WDW_TR_Y 0x44 // 16-bit +#define STMPE610_REG_WDW_BL_X 0x46 // 16-bit +#define STMPE610_REG_WDW_BL_Y 0x48 // 16-bit +#define STMPE610_REG_FIFO_TH 0x4A +#define STMPE610_REG_FIFO_STA 0x4B +#define STMPE610_REG_FIFO_SIZE 0x4C +#define STMPE610_REG_TSC_DATA_X 0x4D // 16-bit +#define STMPE610_REG_TSC_DATA_Y 0x4F // 16-bit +#define STMPE610_REG_TSC_DATA_Z 0x51 +#define STMPE610_REG_TSC_DATA_XYZ 0x52 // 32-bit +#define STMPE610_REG_TSC_FRACT_XYZ 0x56 +#define STMPE610_REG_TSC_DATA 0x57 +#define STMPE610_REG_TSC_I_DRIVE 0x58 +#define STMPE610_REG_TSC_SHIELD 0x59 + + +#endif /* _STMPE610_H */ diff --git a/components/tft/tft.c b/components/tft/tft.c new file mode 100644 index 0000000..e4498d5 --- /dev/null +++ b/components/tft/tft.c @@ -0,0 +1,2950 @@ +/* TFT module + * + * Author: LoBo (loboris@gmail.com, loboris.github) + * + * Module supporting SPI TFT displays based on ILI9341 & ILI9488 controllers +*/ + +#include +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "tft.h" +#include +#include "esp32/rom/tjpgd.h" + + +#define DEG_TO_RAD 0.01745329252 +#define deg_to_rad 0.01745329252 + 3.14159265359 +#define swap(a, b) { int16_t t = a; a = b; b = t; } + +#if !defined(max) +#define max(A,B) ( (A) > (B) ? (A):(B)) +#endif +#if !defined(min) +#define min(A,B) ( (A) < (B) ? (A):(B)) +#endif + +// Embedded fonts +extern uint8_t tft_SmallFont[]; +extern uint8_t tft_DefaultFont[]; +extern uint8_t tft_Dejavu18[]; +extern uint8_t tft_Dejavu24[]; +extern uint8_t tft_Ubuntu16[]; +extern uint8_t tft_Comic24[]; +extern uint8_t tft_minya24[]; +extern uint8_t tft_tooney32[]; +extern uint8_t tft_def_small[]; + +// ==== Color definitions constants ============== +const color_t TFT_BLACK = { 0, 0, 0 }; +const color_t TFT_NAVY = { 0, 0, 128 }; +const color_t TFT_DARKGREEN = { 0, 128, 0 }; +const color_t TFT_DARKCYAN = { 0, 128, 128 }; +const color_t TFT_MAROON = { 128, 0, 0 }; +const color_t TFT_PURPLE = { 128, 0, 128 }; +const color_t TFT_OLIVE = { 128, 128, 0 }; +const color_t TFT_LIGHTGREY = { 192, 192, 192 }; +const color_t TFT_DARKGREY = { 128, 128, 128 }; +const color_t TFT_BLUE = { 0, 0, 255 }; +const color_t TFT_GREEN = { 0, 255, 0 }; +const color_t TFT_CYAN = { 0, 255, 255 }; +const color_t TFT_RED = { 252, 0, 0 }; +const color_t TFT_MAGENTA = { 252, 0, 255 }; +const color_t TFT_YELLOW = { 252, 252, 0 }; +const color_t TFT_WHITE = { 252, 252, 252 }; +const color_t TFT_ORANGE = { 252, 164, 0 }; +const color_t TFT_GREENYELLOW = { 172, 252, 44 }; +const color_t TFT_PINK = { 252, 192, 202 }; +// =============================================== + +// ============================================================== +// ==== Set default values of global variables ================== +uint8_t tft_orientation = LANDSCAPE;// screen tft_orientation +uint16_t tft_font_rotate = 0; // font rotation +uint8_t tft_font_transparent = 0; +uint8_t tft_font_forceFixed = 0; +uint8_t tft_text_wrap = 0; // character wrapping to new line +color_t tft_fg = { 0, 255, 0}; +color_t tft_bg = { 0, 0, 0}; +uint8_t tft_image_debug = 0; + +float tft_angleOffset = DEFAULT_ANGLE_OFFSET; + +int tft_x = 0; +int tft_y = 0; + +uint32_t tft_tp_calx = 7472920; +uint32_t tft_tp_caly = 122224794; + +dispWin_t tft_dispWin = { + .x1 = TFT_STATIC_WIDTH_OFFSET, + .y1 = TFT_STATIC_HEIGHT_OFFSET, + .x2 = DEFAULT_TFT_DISPLAY_WIDTH + TFT_STATIC_WIDTH_OFFSET, + .y2 = DEFAULT_TFT_DISPLAY_HEIGHT + TFT_STATIC_HEIGHT_OFFSET, +}; + +Font tft_cfont = { + .font = tft_DefaultFont, + .x_size = 0, + .y_size = 0x0B, + .offset = 0, + .numchars = 95, + .bitmap = 1, +}; + +uint8_t tft_font_buffered_char = 1; +uint8_t tft_font_line_space = 0; +// ============================================================== + + +typedef struct { + uint8_t charCode; + int adjYOffset; + int width; + int height; + int xOffset; + int xDelta; + uint16_t dataPtr; +} propFont; + +static dispWin_t dispWinTemp; + +static uint8_t *userfont = NULL; +static int TFT_OFFSET = 0; +static propFont fontChar; +static float _arcAngleMax = DEFAULT_ARC_ANGLE_MAX; + + +// ========================================================================= +// ** All drawings are clipped to 'tft_dispWin' ** +// ** All x,y coordinates in public functions are relative to clip window ** +// =========== : Public functions +// ----------- : Local functions +// ========================================================================= + + +// Compare two colors; return 0 if equal +//============================================ +int TFT_compare_colors(color_t c1, color_t c2) +{ + if ((c1.r & 0xFC) != (c2.r & 0xFC)) return 1; + if ((c1.g & 0xFC) != (c2.g & 0xFC)) return 1; + if ((c1.b & 0xFC) != (c2.b & 0xFC)) return 1; + + return 0; +} + +// draw color pixel on screen +//------------------------------------------------------------------------ +static void _drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) { + + if ((x < tft_dispWin.x1) || (y < tft_dispWin.y1) || (x > tft_dispWin.x2) || (y > tft_dispWin.y2)) return; + drawPixel(x, y, color, sel); +} + +//==================================================================== +void TFT_drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) { + + _drawPixel(x+tft_dispWin.x1, y+tft_dispWin.y1, color, sel); +} + +//=========================================== +color_t TFT_readPixel(int16_t x, int16_t y) { + + if ((x < tft_dispWin.x1) || (y < tft_dispWin.y1) || (x > tft_dispWin.x2) || (y > tft_dispWin.y2)) return TFT_BLACK; + + return readPixel(x, y); +} + +//-------------------------------------------------------------------------- +static void _drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) { + // clipping + if ((x < tft_dispWin.x1) || (x > tft_dispWin.x2) || (y > tft_dispWin.y2)) return; + if (y < tft_dispWin.y1) { + h -= (tft_dispWin.y1 - y); + y = tft_dispWin.y1; + } + if (h < 0) h = 0; + if ((y + h) > (tft_dispWin.y2+1)) h = tft_dispWin.y2 - y + 1; + if (h == 0) h = 1; + TFT_pushColorRep(x, y, x, y+h-1, color, (uint32_t)h); +} + +//-------------------------------------------------------------------------- +static void _drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) { + // clipping + if ((y < tft_dispWin.y1) || (x > tft_dispWin.x2) || (y > tft_dispWin.y2)) return; + if (x < tft_dispWin.x1) { + w -= (tft_dispWin.x1 - x); + x = tft_dispWin.x1; + } + if (w < 0) w = 0; + if ((x + w) > (tft_dispWin.x2+1)) w = tft_dispWin.x2 - x + 1; + if (w == 0) w = 1; + + TFT_pushColorRep(x, y, x+w-1, y, color, (uint32_t)w); +} + +//====================================================================== +void TFT_drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color) { + _drawFastVLine(x+tft_dispWin.x1, y+tft_dispWin.y1, h, color); +} + +//====================================================================== +void TFT_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color) { + _drawFastHLine(x+tft_dispWin.x1, y+tft_dispWin.y1, w, color); +} + +// Bresenham's algorithm - thx wikipedia - speed enhanced by Bodmer this uses +// the eficient FastH/V Line draw routine for segments of 2 pixels or more +//---------------------------------------------------------------------------------- +static void _drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color) +{ + if (x0 == x1) { + if (y0 <= y1) _drawFastVLine(x0, y0, y1-y0, color); + else _drawFastVLine(x0, y1, y0-y1, color); + return; + } + if (y0 == y1) { + if (x0 <= x1) _drawFastHLine(x0, y0, x1-x0, color); + else _drawFastHLine(x1, y0, x0-x1, color); + return; + } + + int steep = 0; + if (abs(y1 - y0) > abs(x1 - x0)) steep = 1; + if (steep) { + swap(x0, y0); + swap(x1, y1); + } + if (x0 > x1) { + swap(x0, x1); + swap(y0, y1); + } + + int16_t dx = x1 - x0, dy = abs(y1 - y0); + int16_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0; + + if (y0 < y1) ystep = 1; + + // Split into steep and not steep for FastH/V separation + if (steep) { + for (; x0 <= x1; x0++) { + dlen++; + err -= dy; + if (err < 0) { + err += dx; + if (dlen == 1) _drawPixel(y0, xs, color, 1); + else _drawFastVLine(y0, xs, dlen, color); + dlen = 0; y0 += ystep; xs = x0 + 1; + } + } + if (dlen) _drawFastVLine(y0, xs, dlen, color); + } + else + { + for (; x0 <= x1; x0++) { + dlen++; + err -= dy; + if (err < 0) { + err += dx; + if (dlen == 1) _drawPixel(xs, y0, color, 1); + else _drawFastHLine(xs, y0, dlen, color); + dlen = 0; y0 += ystep; xs = x0 + 1; + } + } + if (dlen) _drawFastHLine(xs, y0, dlen, color); + } +} + +//============================================================================== +void TFT_drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color) +{ + _drawLine(x0+tft_dispWin.x1, y0+tft_dispWin.y1, x1+tft_dispWin.x1, y1+tft_dispWin.y1, color); +} + +// fill a rectangle +//-------------------------------------------------------------------------------- +static void _fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) { + // clipping + if ((x >= tft_dispWin.x2) || (y > tft_dispWin.y2)) return; + + if (x < tft_dispWin.x1) { + w -= (tft_dispWin.x1 - x); + x = tft_dispWin.x1; + } + if (y < tft_dispWin.y1) { + h -= (tft_dispWin.y1 - y); + y = tft_dispWin.y1; + } + if (w < 0) w = 0; + if (h < 0) h = 0; + + if ((x + w) > (tft_dispWin.x2+1)) w = tft_dispWin.x2 - x + 1; + if ((y + h) > (tft_dispWin.y2+1)) h = tft_dispWin.y2 - y + 1; + if (w == 0) w = 1; + if (h == 0) h = 1; + TFT_pushColorRep(x, y, x+w-1, y+h-1, color, (uint32_t)(h*w)); +} + +//============================================================================ +void TFT_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color) { + _fillRect(x+tft_dispWin.x1, y+tft_dispWin.y1, w, h, color); +} + +//================================== +void TFT_fillScreen(color_t color) { + TFT_pushColorRep(TFT_STATIC_X_OFFSET, TFT_STATIC_Y_OFFSET, tft_width + TFT_STATIC_X_OFFSET -1, tft_height + TFT_STATIC_Y_OFFSET -1, color, (uint32_t)(tft_height*tft_width)); +} + +//================================== +void TFT_fillWindow(color_t color) { + TFT_pushColorRep(tft_dispWin.x1, tft_dispWin.y1, tft_dispWin.x2, tft_dispWin.y2, + color, (uint32_t)((tft_dispWin.x2-tft_dispWin.x1+1) * (tft_dispWin.y2-tft_dispWin.y1+1))); +} + +// ^^^============= Basics drawing functions ================================^^^ + + +// ================ Graphics drawing functions ================================== + +//----------------------------------------------------------------------------------- +static void _drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color) { + _drawFastHLine(x1,y1,w, color); + _drawFastVLine(x1+w-1,y1,h, color); + _drawFastHLine(x1,y1+h-1,w, color); + _drawFastVLine(x1,y1,h, color); +} + +//=============================================================================== +void TFT_drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color) { + _drawRect(x1+tft_dispWin.x1, y1+tft_dispWin.y1, w, h, color); +} + +//------------------------------------------------------------------------------------------------- +static void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, color_t color) +{ + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + disp_select(); + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (cornername & 0x4) { + _drawPixel(x0 + x, y0 + y, color, 0); + _drawPixel(x0 + y, y0 + x, color, 0); + } + if (cornername & 0x2) { + _drawPixel(x0 + x, y0 - y, color, 0); + _drawPixel(x0 + y, y0 - x, color, 0); + } + if (cornername & 0x8) { + _drawPixel(x0 - y, y0 + x, color, 0); + _drawPixel(x0 - x, y0 + y, color, 0); + } + if (cornername & 0x1) { + _drawPixel(x0 - y, y0 - x, color, 0); + _drawPixel(x0 - x, y0 - y, color, 0); + } + } + disp_deselect(); +} + +// Used to do circles and roundrects +//---------------------------------------------------------------------------------------------------------------- +static void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, color_t color) +{ + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + int16_t ylm = x0 - r; + + while (x < y) { + if (f >= 0) { + if (cornername & 0x1) _drawFastVLine(x0 + y, y0 - x, 2 * x + 1 + delta, color); + if (cornername & 0x2) _drawFastVLine(x0 - y, y0 - x, 2 * x + 1 + delta, color); + ylm = x0 - y; + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + if ((x0 - x) > ylm) { + if (cornername & 0x1) _drawFastVLine(x0 + x, y0 - y, 2 * y + 1 + delta, color); + if (cornername & 0x2) _drawFastVLine(x0 - x, y0 - y, 2 * y + 1 + delta, color); + } + } +} + +// Draw a rounded rectangle +//============================================================================================= +void TFT_drawRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color) +{ + x += tft_dispWin.x1; + y += tft_dispWin.y1; + + // smarter version + _drawFastHLine(x + r, y, w - 2 * r, color); // Top + _drawFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom + _drawFastVLine(x, y + r, h - 2 * r, color); // Left + _drawFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right + + // draw four corners + drawCircleHelper(x + r, y + r, r, 1, color); + drawCircleHelper(x + w - r - 1, y + r, r, 2, color); + drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); + drawCircleHelper(x + r, y + h - r - 1, r, 8, color); +} + +// Fill a rounded rectangle +//============================================================================================= +void TFT_fillRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color) +{ + x += tft_dispWin.x1; + y += tft_dispWin.y1; + + // smarter version + _fillRect(x + r, y, w - 2 * r, h, color); + + // draw four corners + fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color); + fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color); +} + + + + +//----------------------------------------------------------------------------------------------- +static void _drawLineByAngle(int16_t x, int16_t y, int16_t angle, uint16_t length, color_t color) +{ + _drawLine( + x, + y, + x + length * cos((angle + tft_angleOffset) * DEG_TO_RAD), + y + length * sin((angle + tft_angleOffset) * DEG_TO_RAD), color); +} + +//--------------------------------------------------------------------------------------------------------------- +static void _DrawLineByAngle(int16_t x, int16_t y, int16_t angle, uint16_t start, uint16_t length, color_t color) +{ + _drawLine( + x + start * cos((angle + tft_angleOffset) * DEG_TO_RAD), + y + start * sin((angle + tft_angleOffset) * DEG_TO_RAD), + x + (start + length) * cos((angle + tft_angleOffset) * DEG_TO_RAD), + y + (start + length) * sin((angle + tft_angleOffset) * DEG_TO_RAD), color); +} + +//=========================================================================================================== +void TFT_drawLineByAngle(uint16_t x, uint16_t y, uint16_t start, uint16_t len, uint16_t angle, color_t color) +{ + x += tft_dispWin.x1; + y += tft_dispWin.y1; + + if (start == 0) _drawLineByAngle(x, y, angle, len, color); + else _DrawLineByAngle(x, y, angle, start, len, color); +} + + +// Draw a triangle +//-------------------------------------------------------------------------------------------------------------------- +static void _drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) +{ + _drawLine(x0, y0, x1, y1, color); + _drawLine(x1, y1, x2, y2, color); + _drawLine(x2, y2, x0, y0, color); +} + +//================================================================================================================ +void TFT_drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) +{ + x0 += tft_dispWin.x1; + y0 += tft_dispWin.y1; + x1 += tft_dispWin.x1; + y1 += tft_dispWin.y1; + x2 += tft_dispWin.x1; + y2 += tft_dispWin.y1; + + _drawLine(x0, y0, x1, y1, color); + _drawLine(x1, y1, x2, y2, color); + _drawLine(x2, y2, x0, y0, color); +} + +// Fill a triangle +//-------------------------------------------------------------------------------------------------------------------- +static void _fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) +{ + int16_t a, b, y, last; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) { + swap(y0, y1); swap(x0, x1); + } + if (y1 > y2) { + swap(y2, y1); swap(x2, x1); + } + if (y0 > y1) { + swap(y0, y1); swap(x0, x1); + } + + if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if(x1 < a) a = x1; + else if(x1 > b) b = x1; + if(x2 < a) a = x2; + else if(x2 > b) b = x2; + _drawFastHLine(a, y0, b-a+1, color); + return; + } + + int16_t + dx01 = x1 - x0, + dy01 = y1 - y0, + dx02 = x2 - x0, + dy02 = y2 - y0, + dx12 = x2 - x1, + dy12 = y2 - y1; + int32_t + sa = 0, + sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if(y1 == y2) last = y1; // Include y1 scanline + else last = y1-1; // Skip it + + for(y=y0; y<=last; y++) { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if(a > b) swap(a,b); + _drawFastHLine(a, y, b-a+1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = dx12 * (y - y1); + sb = dx02 * (y - y0); + for(; y<=y2; y++) { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + /* longhand: + a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if(a > b) swap(a,b); + _drawFastHLine(a, y, b-a+1, color); + } +} + +//================================================================================================================ +void TFT_fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color) +{ + _fillTriangle( + x0 + tft_dispWin.x1, y0 + tft_dispWin.y1, + x1 + tft_dispWin.x1, y1 + tft_dispWin.y1, + x2 + tft_dispWin.x1, y2 + tft_dispWin.y1, + color); +} + +//==================================================================== +void TFT_drawCircle(int16_t x, int16_t y, int radius, color_t color) { + x += tft_dispWin.x1; + y += tft_dispWin.y1; + int f = 1 - radius; + int ddF_x = 1; + int ddF_y = -2 * radius; + int x1 = 0; + int y1 = radius; + + disp_select(); + _drawPixel(x, y + radius, color, 0); + _drawPixel(x, y - radius, color, 0); + _drawPixel(x + radius, y, color, 0); + _drawPixel(x - radius, y, color, 0); + while(x1 < y1) { + if (f >= 0) { + y1--; + ddF_y += 2; + f += ddF_y; + } + x1++; + ddF_x += 2; + f += ddF_x; + _drawPixel(x + x1, y + y1, color, 0); + _drawPixel(x - x1, y + y1, color, 0); + _drawPixel(x + x1, y - y1, color, 0); + _drawPixel(x - x1, y - y1, color, 0); + _drawPixel(x + y1, y + x1, color, 0); + _drawPixel(x - y1, y + x1, color, 0); + _drawPixel(x + y1, y - x1, color, 0); + _drawPixel(x - y1, y - x1, color, 0); + } + disp_deselect(); +} + +//==================================================================== +void TFT_fillCircle(int16_t x, int16_t y, int radius, color_t color) { + x += tft_dispWin.x1; + y += tft_dispWin.y1; + + _drawFastVLine(x, y-radius, 2*radius+1, color); + fillCircleHelper(x, y, radius, 3, 0, color); +} + +//---------------------------------------------------------------------------------------------------------------- +static void _draw_ellipse_section(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, color_t color, uint8_t option) +{ + disp_select(); + // upper right + if ( option & TFT_ELLIPSE_UPPER_RIGHT ) _drawPixel(x0 + x, y0 - y, color, 0); + // upper left + if ( option & TFT_ELLIPSE_UPPER_LEFT ) _drawPixel(x0 - x, y0 - y, color, 0); + // lower right + if ( option & TFT_ELLIPSE_LOWER_RIGHT ) _drawPixel(x0 + x, y0 + y, color, 0); + // lower left + if ( option & TFT_ELLIPSE_LOWER_LEFT ) _drawPixel(x0 - x, y0 + y, color, 0); + disp_deselect(); +} + +//===================================================================================================== +void TFT_drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option) +{ + x0 += tft_dispWin.x1; + y0 += tft_dispWin.y1; + + uint16_t x, y; + int32_t xchg, ychg; + int32_t err; + int32_t rxrx2; + int32_t ryry2; + int32_t stopx, stopy; + + rxrx2 = rx; + rxrx2 *= rx; + rxrx2 *= 2; + + ryry2 = ry; + ryry2 *= ry; + ryry2 *= 2; + + x = rx; + y = 0; + + xchg = 1; + xchg -= rx; + xchg -= rx; + xchg *= ry; + xchg *= ry; + + ychg = rx; + ychg *= rx; + + err = 0; + + stopx = ryry2; + stopx *= rx; + stopy = 0; + + while( stopx >= stopy ) { + _draw_ellipse_section(x, y, x0, y0, color, option); + y++; + stopy += rxrx2; + err += ychg; + ychg += rxrx2; + if ( 2*err+xchg > 0 ) { + x--; + stopx -= ryry2; + err += xchg; + xchg += ryry2; + } + } + + x = 0; + y = ry; + + xchg = ry; + xchg *= ry; + + ychg = 1; + ychg -= ry; + ychg -= ry; + ychg *= rx; + ychg *= rx; + + err = 0; + + stopx = 0; + + stopy = rxrx2; + stopy *= ry; + + while( stopx <= stopy ) { + _draw_ellipse_section(x, y, x0, y0, color, option); + x++; + stopx += ryry2; + err += xchg; + xchg += ryry2; + if ( 2*err+ychg > 0 ) { + y--; + stopy -= rxrx2; + err += ychg; + ychg += rxrx2; + } + } +} + +//----------------------------------------------------------------------------------------------------------------------- +static void _draw_filled_ellipse_section(uint16_t x, uint16_t y, uint16_t x0, uint16_t y0, color_t color, uint8_t option) +{ + // upper right + if ( option & TFT_ELLIPSE_UPPER_RIGHT ) _drawFastVLine(x0+x, y0-y, y+1, color); + // upper left + if ( option & TFT_ELLIPSE_UPPER_LEFT ) _drawFastVLine(x0-x, y0-y, y+1, color); + // lower right + if ( option & TFT_ELLIPSE_LOWER_RIGHT ) _drawFastVLine(x0+x, y0, y+1, color); + // lower left + if ( option & TFT_ELLIPSE_LOWER_LEFT ) _drawFastVLine(x0-x, y0, y+1, color); +} + +//===================================================================================================== +void TFT_fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option) +{ + x0 += tft_dispWin.x1; + y0 += tft_dispWin.y1; + + uint16_t x, y; + int32_t xchg, ychg; + int32_t err; + int32_t rxrx2; + int32_t ryry2; + int32_t stopx, stopy; + + rxrx2 = rx; + rxrx2 *= rx; + rxrx2 *= 2; + + ryry2 = ry; + ryry2 *= ry; + ryry2 *= 2; + + x = rx; + y = 0; + + xchg = 1; + xchg -= rx; + xchg -= rx; + xchg *= ry; + xchg *= ry; + + ychg = rx; + ychg *= rx; + + err = 0; + + stopx = ryry2; + stopx *= rx; + stopy = 0; + + while( stopx >= stopy ) { + _draw_filled_ellipse_section(x, y, x0, y0, color, option); + y++; + stopy += rxrx2; + err += ychg; + ychg += rxrx2; + if ( 2*err+xchg > 0 ) { + x--; + stopx -= ryry2; + err += xchg; + xchg += ryry2; + } + } + + x = 0; + y = ry; + + xchg = ry; + xchg *= ry; + + ychg = 1; + ychg -= ry; + ychg -= ry; + ychg *= rx; + ychg *= rx; + + err = 0; + + stopx = 0; + + stopy = rxrx2; + stopy *= ry; + + while( stopx <= stopy ) { + _draw_filled_ellipse_section(x, y, x0, y0, color, option); + x++; + stopx += ryry2; + err += xchg; + xchg += ryry2; + if ( 2*err+ychg > 0 ) { + y--; + stopy -= rxrx2; + err += ychg; + ychg += rxrx2; + } + } +} + + +// ==== ARC DRAWING =================================================================== + +//--------------------------------------------------------------------------------------------------------------------------------- +static void _fillArcOffsetted(uint16_t cx, uint16_t cy, uint16_t radius, uint16_t thickness, float start, float end, color_t color) +{ + //float sslope = (float)cos_lookup(start) / (float)sin_lookup(start); + //float eslope = (float)cos_lookup(end) / (float)sin_lookup(end); + float sslope = (cos(start/_arcAngleMax * 2 * PI) * _arcAngleMax) / (sin(start/_arcAngleMax * 2 * PI) * _arcAngleMax) ; + float eslope = (cos(end/_arcAngleMax * 2 * PI) * _arcAngleMax) / (sin(end/_arcAngleMax * 2 * PI) * _arcAngleMax); + + if (end == 360) eslope = -1000000; + + int ir2 = (radius - thickness) * (radius - thickness); + int or2 = radius * radius; + + disp_select(); + for (int x = -radius; x <= radius; x++) { + for (int y = -radius; y <= radius; y++) { + int x2 = x * x; + int y2 = y * y; + + if ( + (x2 + y2 < or2 && x2 + y2 >= ir2) && + ( + (y > 0 && start < 180 && x <= y * sslope) || + (y < 0 && start > 180 && x >= y * sslope) || + (y < 0 && start <= 180) || + (y == 0 && start <= 180 && x < 0) || + (y == 0 && start == 0 && x > 0) + ) && + ( + (y > 0 && end < 180 && x >= y * eslope) || + (y < 0 && end > 180 && x <= y * eslope) || + (y > 0 && end >= 180) || + (y == 0 && end >= 180 && x < 0) || + (y == 0 && start == 0 && x > 0) + ) + ) + _drawPixel(cx+x, cy+y, color, 0); + } + } + disp_deselect(); +} + + +//=========================================================================================================================== +void TFT_drawArc(uint16_t cx, uint16_t cy, uint16_t r, uint16_t th, float start, float end, color_t color, color_t fillcolor) +{ + cx += tft_dispWin.x1; + cy += tft_dispWin.y1; + + if (th < 1) th = 1; + if (th > r) th = r; + + int f = TFT_compare_colors(fillcolor, color); + + float astart = fmodf(start, _arcAngleMax); + float aend = fmodf(end, _arcAngleMax); + + astart += tft_angleOffset; + aend += tft_angleOffset; + + if (astart < 0) astart += (float)360; + if (aend < 0) aend += (float)360; + + if (aend == 0) aend = (float)360; + + if (astart > aend) { + _fillArcOffsetted(cx, cy, r, th, astart, _arcAngleMax, fillcolor); + _fillArcOffsetted(cx, cy, r, th, 0, aend, fillcolor); + if (f) { + _fillArcOffsetted(cx, cy, r, 1, astart, _arcAngleMax, color); + _fillArcOffsetted(cx, cy, r, 1, 0, aend, color); + _fillArcOffsetted(cx, cy, r-th, 1, astart, _arcAngleMax, color); + _fillArcOffsetted(cx, cy, r-th, 1, 0, aend, color); + } + } + else { + _fillArcOffsetted(cx, cy, r, th, astart, aend, fillcolor); + if (f) { + _fillArcOffsetted(cx, cy, r, 1, astart, aend, color); + _fillArcOffsetted(cx, cy, r-th, 1, astart, aend, color); + } + } + if (f) { + _drawLine(cx + (r-th) * cos(astart * DEG_TO_RAD), cy + (r-th) * sin(astart * DEG_TO_RAD), + cx + (r-1) * cos(astart * DEG_TO_RAD), cy + (r-1) * sin(astart * DEG_TO_RAD), color); + _drawLine(cx + (r-th) * cos(aend * DEG_TO_RAD), cy + (r-th) * sin(aend * DEG_TO_RAD), + cx + (r-1) * cos(aend * DEG_TO_RAD), cy + (r-1) * sin(aend * DEG_TO_RAD), color); + } +} + +//============================================================================================================= +void TFT_drawPolygon(int cx, int cy, int sides, int diameter, color_t color, color_t fill, int rot, uint8_t th) +{ + cx += tft_dispWin.x1; + cy += tft_dispWin.y1; + + int deg = rot - tft_angleOffset; + int f = TFT_compare_colors(fill, color); + + if (sides < MIN_POLIGON_SIDES) sides = MIN_POLIGON_SIDES; // This ensures the minimum side number + if (sides > MAX_POLIGON_SIDES) sides = MAX_POLIGON_SIDES; // This ensures the maximum side number + + int Xpoints[sides], Ypoints[sides]; // Set the arrays based on the number of sides entered + int rads = 360 / sides; // This equally spaces the points. + + for (int idx = 0; idx < sides; idx++) { + Xpoints[idx] = cx + sin((float)(idx*rads + deg) * deg_to_rad) * diameter; + Ypoints[idx] = cy + cos((float)(idx*rads + deg) * deg_to_rad) * diameter; + } + + // Draw the polygon on the screen. + if (f) { + for(int idx = 0; idx < sides; idx++) { + if((idx+1) < sides) _fillTriangle(cx,cy,Xpoints[idx],Ypoints[idx],Xpoints[idx+1],Ypoints[idx+1], fill); + else _fillTriangle(cx,cy,Xpoints[idx],Ypoints[idx],Xpoints[0],Ypoints[0], fill); + } + } + + if (th) { + for (int n=0; n 0) { + for (int idx = 0; idx < sides; idx++) { + Xpoints[idx] = cx + sin((float)(idx*rads + deg) * deg_to_rad) * (diameter-n); + Ypoints[idx] = cy + cos((float)(idx*rads + deg) * deg_to_rad) * (diameter-n); + } + } + for(int idx = 0; idx < sides; idx++) { + if( (idx+1) < sides) + _drawLine(Xpoints[idx],Ypoints[idx],Xpoints[idx+1],Ypoints[idx+1], color); // draw the lines + else + _drawLine(Xpoints[idx],Ypoints[idx],Xpoints[0],Ypoints[0], color); // finishes the last line to close up the polygon. + } + } + } +} + +/* +// Similar to the Polygon function. +//===================================================================================== +void TFT_drawStar(int cx, int cy, int diameter, color_t color, bool fill, float factor) +{ + cx += tft_dispWin.x1; + cy += tft_dispWin.y1; + + factor = constrain(factor, 1.0, 4.0); + uint8_t sides = 5; + uint8_t rads = 360 / sides; + + int Xpoints_O[sides], Ypoints_O[sides], Xpoints_I[sides], Ypoints_I[sides];//Xpoints_T[5], Ypoints_T[5]; + + for(int idx = 0; idx < sides; idx++) { + // makes the outer points + Xpoints_O[idx] = cx + sin((float)(idx*rads + 72) * deg_to_rad) * diameter; + Ypoints_O[idx] = cy + cos((float)(idx*rads + 72) * deg_to_rad) * diameter; + // makes the inner points + Xpoints_I[idx] = cx + sin((float)(idx*rads + 36) * deg_to_rad) * ((float)(diameter)/factor); + // 36 is half of 72, and this will allow the inner and outer points to line up like a triangle. + Ypoints_I[idx] = cy + cos((float)(idx*rads + 36) * deg_to_rad) * ((float)(diameter)/factor); + } + + for(int idx = 0; idx < sides; idx++) { + if((idx+1) < sides) { + if(fill) {// this part below should be self explanatory. It fills in the star. + _fillTriangle(cx,cy,Xpoints_I[idx],Ypoints_I[idx],Xpoints_O[idx],Ypoints_O[idx], color); + _fillTriangle(cx,cy,Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx+1],Ypoints_I[idx+1], color); + } + else { + _drawLine(Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx+1],Ypoints_I[idx+1], color); + _drawLine(Xpoints_I[idx],Ypoints_I[idx],Xpoints_O[idx],Ypoints_O[idx], color); + } + } + else { + if(fill) { + _fillTriangle(cx,cy,Xpoints_I[0],Ypoints_I[0],Xpoints_O[idx],Ypoints_O[idx], color); + _fillTriangle(cx,cy,Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx],Ypoints_I[idx], color); + } + else { + _drawLine(Xpoints_O[idx],Ypoints_O[idx],Xpoints_I[idx],Ypoints_I[idx], color); + _drawLine(Xpoints_I[0],Ypoints_I[0],Xpoints_O[idx],Ypoints_O[idx], color); + } + } + } +} +*/ + +// ================ Font and string functions ================================== + +//-------------------------------------------------------- +static int load_file_font(const char * fontfile, int info) +{ + int err = 0; + char err_msg[256] = {'\0'}; + + if (userfont != NULL) { + free(userfont); + userfont = NULL; + } + + struct stat sb; + + // Open the file + FILE *fhndl = fopen(fontfile, "r"); + if (!fhndl) { + sprintf(err_msg, "Error opening font file '%s'", fontfile); + err = 1; + goto exit; + } + + // Get file size + if (stat(fontfile, &sb) != 0) { + sprintf(err_msg, "Error getting font file size"); + err = 2; + goto exit; + } + int fsize = sb.st_size; + if (fsize < 30) { + sprintf(err_msg, "Error getting font file size"); + err = 3; + goto exit; + } + + userfont = malloc(fsize+4); + if (userfont == NULL) { + sprintf(err_msg, "Font memory allocation error"); + fclose(fhndl); + err = 4; + goto exit; + } + + int read = fread(userfont, 1, fsize, fhndl); + + fclose(fhndl); + + if (read != fsize) { + sprintf(err_msg, "Font read error"); + err = 5; + goto exit; + } + + userfont[read] = 0; + if (strstr((char *)(userfont+read-8), "RPH_font") == NULL) { + sprintf(err_msg, "Font ID not found"); + err = 6; + goto exit; + } + + // Check size + int size = 0; + int numchar = 0; + int width = userfont[0]; + int height = userfont[1]; + uint8_t first = 255; + uint8_t last = 0; + //int offst = 0; + int pminwidth = 255; + int pmaxwidth = 0; + + if (width != 0) { + // Fixed font + numchar = userfont[3]; + first = userfont[2]; + last = first + numchar - 1; + size = ((width * height * numchar) / 8) + 4; + } + else { + // Proportional font + size = 4; // point at first char data + uint8_t charCode; + int charwidth; + + do { + charCode = userfont[size]; + charwidth = userfont[size+2]; + + if (charCode != 0xFF) { + numchar++; + if (charwidth != 0) size += ((((charwidth * userfont[size+3])-1) / 8) + 7); + else size += 6; + + if (info) { + if (charwidth > pmaxwidth) pmaxwidth = charwidth; + if (charwidth < pminwidth) pminwidth = charwidth; + if (charCode < first) first = charCode; + if (charCode > last) last = charCode; + } + } + else size++; + } while ((size < (read-8)) && (charCode != 0xFF)); + } + + if (size != (read-8)) { + sprintf(err_msg, "Font size error: found %d expected %d)", size, (read-8)); + err = 7; + goto exit; + } + + if (info) { + if (width != 0) { + printf("Fixed width font:\r\n size: %d width: %d height: %d characters: %d (%d~%d)\n", + size, width, height, numchar, first, last); + } + else { + printf("Proportional font:\r\n size: %d width: %d~%d height: %d characters: %d (%d~%d)\n", + size, pminwidth, pmaxwidth, height, numchar, first, last); + } + } + +exit: + if (err) { + if (userfont) { + free(userfont); + userfont = NULL; + } + if (info) printf("Error: %d [%s]\r\n", err, err_msg); + } + return err; +} + +//------------------------------------------------ +int compile_font_file(char *fontfile, uint8_t dbg) +{ + int err = 0; + char err_msg[128] = {'\0'}; + char outfile[128] = {'\0'}; + size_t len; + struct stat sb; + FILE *ffd = NULL; + FILE *ffd_out = NULL; + char *sourcebuf = NULL; + + len = strlen(fontfile); + + // check here that filename end with ".c". + if ((len < 3) || (len > 125) || (strcmp(fontfile + len - 2, ".c") != 0)) { + sprintf(err_msg, "not a .c file"); + err = 1; + goto exit; + } + + sprintf(outfile, "%s", fontfile); + sprintf(outfile+strlen(outfile)-1, "fon"); + + // Open the source file + if (stat(fontfile, &sb) != 0) { + sprintf(err_msg, "Error opening source file '%s'", fontfile); + err = 2; + goto exit; + } + // Open the file + ffd = fopen(fontfile, "rb"); + if (!ffd) { + sprintf(err_msg, "Error opening source file '%s'", fontfile); + err = 3; + goto exit; + } + + // Open the font file + ffd_out= fopen(outfile, "wb"); + if (!ffd_out) { + sprintf(err_msg, "error opening destination file"); + err = 4; + goto exit; + } + + // Get file size + int fsize = sb.st_size; + if (fsize <= 0) { + sprintf(err_msg, "source file size error"); + err = 5; + goto exit; + } + + sourcebuf = malloc(fsize+4); + if (sourcebuf == NULL) { + sprintf(err_msg, "memory allocation error"); + err = 6; + goto exit; + } + char *fbuf = sourcebuf; + + int rdsize = fread(fbuf, 1, fsize, ffd); + fclose(ffd); + ffd = NULL; + + if (rdsize != fsize) { + sprintf(err_msg, "error reading from source file"); + err = 7; + goto exit; + } + + *(fbuf+rdsize) = '\0'; + + fbuf = strchr(fbuf, '{'); // beginning of font data + char *fend = strstr(fbuf, "};"); // end of font data + + if ((fbuf == NULL) || (fend == NULL) || ((fend-fbuf) < 22)) { + sprintf(err_msg, "wrong source file format"); + err = 8; + goto exit; + } + + fbuf++; + *fend = '\0'; + char hexstr[5] = {'\0'}; + int lastline = 0; + + fbuf = strstr(fbuf, "0x"); + int size = 0; + char *nextline; + char *numptr; + + int bptr = 0; + + while ((fbuf != NULL) && (fbuf < fend) && (lastline == 0)) { + nextline = strchr(fbuf, '\n'); // beginning of the next line + if (nextline == NULL) { + nextline = fend-1; + lastline++; + } + else nextline++; + + while (fbuf < nextline) { + numptr = strstr(fbuf, "0x"); + if ((numptr == NULL) || ((fbuf+4) > nextline)) numptr = strstr(fbuf, "0X"); + if ((numptr != NULL) && ((numptr+4) <= nextline)) { + fbuf = numptr; + if (bptr >= 128) { + // buffer full, write to file + if (fwrite(outfile, 1, 128, ffd_out) != 128) goto error; + bptr = 0; + size += 128; + } + memcpy(hexstr, fbuf, 4); + hexstr[4] = 0; + outfile[bptr++] = (uint8_t)strtol(hexstr, NULL, 0); + fbuf += 4; + } + else fbuf = nextline; + } + fbuf = nextline; + } + + if (bptr > 0) { + size += bptr; + if (fwrite(outfile, 1, bptr, ffd_out) != bptr) goto error; + } + + // write font ID + sprintf(outfile, "RPH_font"); + if (fwrite(outfile, 1, 8, ffd_out) != 8) goto error; + + fclose(ffd_out); + ffd_out = NULL; + + // === Test compiled font === + sprintf(outfile, "%s", fontfile); + sprintf(outfile+strlen(outfile)-1, "fon"); + + uint8_t *uf = userfont; // save userfont pointer + userfont = NULL; + if (load_file_font(outfile, 1) != 0) { + sprintf(err_msg, "Error compiling file!"); + err = 10; + } + else { + free(userfont); + sprintf(err_msg, "File compiled successfully."); + } + userfont = uf; // restore userfont + + goto exit; + +error: + sprintf(err_msg, "error writing to destination file"); + err = 9; + +exit: + if (sourcebuf) free(sourcebuf); + if (ffd) fclose(ffd); + if (ffd_out) fclose(ffd_out); + + if (dbg) printf("%s\r\n", err_msg); + + return err; +} + + +// ----------------------------------------------------------------------------------------- +// Individual Proportional Font Character Format: +// ----------------------------------------------------------------------------------------- +// Character Code +// yOffset (start Y of visible pixels) +// Width (width of the visible pixels) +// Height (height of the visible pixels) +// xOffset (start X of visible pixels) +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] +// ----------------------------------------------------------------------------------------- + +//--------------------------------------------------------------------------------------------- +// Character drawing rectangle is (0, 0) (xDelta-1, tft_cfont.y_size-1) +// Character visible pixels rectangle is (xOffset, yOffset) (xOffset+Width-1, yOffset+Height-1) +//--------------------------------------------------------------------------------------------- + +//---------------------------------- +void getFontCharacters(uint8_t *buf) +{ + if (tft_cfont.bitmap == 2) { + //For 7 segment font only characters 0,1,2,3,4,5,6,7,8,9, . , - , : , / are available. + for (uint8_t n=0; n < 11; n++) { + buf[n] = n + 0x30; + } + buf[11] = '.'; + buf[12] = '-'; + buf[13] = '/'; + buf[14] = '\0'; + return; + } + + if (tft_cfont.x_size > 0) { + for (uint8_t n=0; n < tft_cfont.numchars; n++) { + buf[n] = tft_cfont.offset + n; + } + buf[tft_cfont.numchars] = '\0'; + return; + } + + uint16_t tempPtr = 4; // point at first char data + uint8_t cc, cw, ch, n; + + n = 0; + cc = tft_cfont.font[tempPtr++]; + while (cc != 0xFF) { + tft_cfont.numchars++; + tempPtr++; + cw = tft_cfont.font[tempPtr++]; + ch = tft_cfont.font[tempPtr++]; + tempPtr++; + tempPtr++; + if (cw != 0) { + // packed bits + tempPtr += (((cw * ch)-1) / 8) + 1; + } + buf[n++] = cc; + cc = tft_cfont.font[tempPtr++]; + } + buf[n] = '\0'; +} + +// Set max width & height of the proportional font +//----------------------------- +static void getMaxWidthHeight() +{ + uint16_t tempPtr = 4; // point at first char data + uint8_t cc, cw, ch, cd, cy; + + tft_cfont.numchars = 0; + tft_cfont.max_x_size = 0; + + cc = tft_cfont.font[tempPtr++]; + while (cc != 0xFF) { + tft_cfont.numchars++; + cy = tft_cfont.font[tempPtr++]; + cw = tft_cfont.font[tempPtr++]; + ch = tft_cfont.font[tempPtr++]; + tempPtr++; + cd = tft_cfont.font[tempPtr++]; + cy += ch; + if (cw > tft_cfont.max_x_size) tft_cfont.max_x_size = cw; + if (cd > tft_cfont.max_x_size) tft_cfont.max_x_size = cd; + if (ch > tft_cfont.y_size) tft_cfont.y_size = ch; + if (cy > tft_cfont.y_size) tft_cfont.y_size = cy; + if (cw != 0) { + // packed bits + tempPtr += (((cw * ch)-1) / 8) + 1; + } + cc = tft_cfont.font[tempPtr++]; + } + tft_cfont.size = tempPtr; +} + +// Return the Glyph data for an individual character in the proportional font +//------------------------------------ +static uint8_t getCharPtr(uint8_t c) { + uint16_t tempPtr = 4; // point at first char data + + do { + fontChar.charCode = tft_cfont.font[tempPtr++]; + if (fontChar.charCode == 0xFF) return 0; + + fontChar.adjYOffset = tft_cfont.font[tempPtr++]; + fontChar.width = tft_cfont.font[tempPtr++]; + fontChar.height = tft_cfont.font[tempPtr++]; + fontChar.xOffset = tft_cfont.font[tempPtr++]; + fontChar.xOffset = fontChar.xOffset < 0x80 ? fontChar.xOffset : -(0xFF - fontChar.xOffset); + fontChar.xDelta = tft_cfont.font[tempPtr++]; + + if (c != fontChar.charCode && fontChar.charCode != 0xFF) { + if (fontChar.width != 0) { + // packed bits + tempPtr += (((fontChar.width * fontChar.height)-1) / 8) + 1; + } + } + } while ((c != fontChar.charCode) && (fontChar.charCode != 0xFF)); + + fontChar.dataPtr = tempPtr; + if (c == fontChar.charCode) { + if (tft_font_forceFixed > 0) { + // fix width & offset for forced fixed width + fontChar.xDelta = tft_cfont.max_x_size; + fontChar.xOffset = (fontChar.xDelta - fontChar.width) / 2; + } + } + else return 0; + + return 1; +} + +/* +//----------------------- +static void _testFont() { + if (tft_cfont.x_size) { + printf("FONT TEST: fixed font\r\n"); + return; + } + uint16_t tempPtr = 4; // point at first char data + uint8_t c = 0x20; + for (c=0x20; c <0xFF; c++) { + fontChar.charCode = tft_cfont.font[tempPtr++]; + if (fontChar.charCode == 0xFF) break; + if (fontChar.charCode != c) { + printf("FONT TEST: last sequential char: %d, expected %d\r\n", fontChar.charCode, c); + break; + } + c = fontChar.charCode; + fontChar.adjYOffset = tft_cfont.font[tempPtr++]; + fontChar.width = tft_cfont.font[tempPtr++]; + fontChar.height = tft_cfont.font[tempPtr++]; + fontChar.xOffset = tft_cfont.font[tempPtr++]; + fontChar.xOffset = fontChar.xOffset < 0x80 ? fontChar.xOffset : -(0xFF - fontChar.xOffset); + fontChar.xDelta = tft_cfont.font[tempPtr++]; + + if (fontChar.charCode != 0xFF) { + if (fontChar.width != 0) { + // packed bits + tempPtr += (((fontChar.width * fontChar.height)-1) / 8) + 1; + } + } + } + printf("FONT TEST: W=%d H=%d last char: %d [%c]; length: %d\r\n", tft_cfont.max_x_size, tft_cfont.y_size, c, c, tempPtr); +} +*/ + +//=================================================== +void TFT_setFont(uint8_t font, const char *font_file) +{ + tft_cfont.font = NULL; + + if (font == FONT_7SEG) { + tft_cfont.bitmap = 2; + tft_cfont.x_size = 24; + tft_cfont.y_size = 6; + tft_cfont.offset = 0; + tft_cfont.color = tft_fg; + } + else { + if (font == USER_FONT) { + if (load_file_font(font_file, 0) != 0) tft_cfont.font = tft_DefaultFont; + else tft_cfont.font = userfont; + } + else if (font == DEJAVU18_FONT) tft_cfont.font = tft_Dejavu18; + else if (font == DEJAVU24_FONT) tft_cfont.font = tft_Dejavu24; + else if (font == UBUNTU16_FONT) tft_cfont.font = tft_Ubuntu16; + else if (font == COMIC24_FONT) tft_cfont.font = tft_Comic24; + else if (font == MINYA24_FONT) tft_cfont.font = tft_minya24; + else if (font == TOONEY32_FONT) tft_cfont.font = tft_tooney32; + else if (font == SMALL_FONT) tft_cfont.font = tft_SmallFont; + else if (font == DEF_SMALL_FONT) tft_cfont.font = tft_def_small; + else tft_cfont.font = tft_DefaultFont; + + tft_cfont.bitmap = 1; + tft_cfont.x_size = tft_cfont.font[0]; + tft_cfont.y_size = tft_cfont.font[1]; + if (tft_cfont.x_size > 0) { + tft_cfont.offset = tft_cfont.font[2]; + tft_cfont.numchars = tft_cfont.font[3]; + tft_cfont.size = tft_cfont.x_size * tft_cfont.y_size * tft_cfont.numchars; + } + else { + tft_cfont.offset = 4; + getMaxWidthHeight(); + } + //_testFont(); + } +} + +// ----------------------------------------------------------------------------------------- +// Individual Proportional Font Character Format: +// ----------------------------------------------------------------------------------------- +// Character Code +// yOffset (start Y of visible pixels) +// Width (width of the visible pixels) +// Height (height of the visible pixels) +// xOffset (start X of visible pixels) +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] +// ----------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- +// Character drawing rectangle is (0, 0) (xDelta-1, tft_cfont.y_size-1) +// Character visible pixels rectangle is (xOffset, yOffset) (xOffset+Width-1, yOffset+Height-1) +//--------------------------------------------------------------------------------------------- + +// print non-rotated proportional character +// character is already in fontChar +//---------------------------------------------- +static int printProportionalChar(int x, int y) { + uint8_t ch = 0; + int i, j, char_width; + + char_width = ((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta); + + if ((tft_font_buffered_char) && (!tft_font_transparent)) { + int len, bufPos; + + // === buffer Glyph data for faster sending === + len = char_width * tft_cfont.y_size; + color_t *color_line = heap_caps_malloc(len*3, MALLOC_CAP_DMA); + if (color_line) { + // fill with background color + for (int n = 0; n < len; n++) { + color_line[n] = tft_bg; + } + // set character pixels to foreground color + uint8_t mask = 0x80; + for (j=0; j < fontChar.height; j++) { + for (i=0; i < fontChar.width; i++) { + if (((i + (j*fontChar.width)) % 8) == 0) { + mask = 0x80; + ch = tft_cfont.font[fontChar.dataPtr++]; + } + if ((ch & mask) != 0) { + // visible pixel + bufPos = ((j + fontChar.adjYOffset) * char_width) + (fontChar.xOffset + i); // bufY + bufX + color_line[bufPos] = tft_fg; + /* + bufY = (j + fontChar.adjYOffset) * char_width; + bufX = fontChar.xOffset + i; + if ((bufX < 0) || (bufX > char_width)) { + printf("[%c] X ERR: %d\r\n", fontChar.charCode, bufX); + } + bufPos = bufY + bufX; + if ((bufPos < len) && (bufPos > 0)) color_line[bufPos] = tft_fg; + else printf("[%c] ERR: %d > %d W=%d H=%d bufX=%d bufY=%d X=%d Y=%d\r\n", + fontChar.charCode, bufPos, len, char_width, tft_cfont.y_size, bufX, bufY, fontChar.xOffset + i, j + fontChar.adjYOffset); + */ + } + mask >>= 1; + } + } + // send to display in one transaction + disp_select(); + send_data(x, y, x+char_width-1, y+tft_cfont.y_size-1, len, color_line); + disp_deselect(); + free(color_line); + + return char_width; + } + } + + int cx, cy; + + if (!tft_font_transparent) _fillRect(x, y, char_width+1, tft_cfont.y_size, tft_bg); + + // draw Glyph + uint8_t mask = 0x80; + disp_select(); + for (j=0; j < fontChar.height; j++) { + for (i=0; i < fontChar.width; i++) { + if (((i + (j*fontChar.width)) % 8) == 0) { + mask = 0x80; + ch = tft_cfont.font[fontChar.dataPtr++]; + } + + if ((ch & mask) !=0) { + cx = (uint16_t)(x+fontChar.xOffset+i); + cy = (uint16_t)(y+j+fontChar.adjYOffset); + _drawPixel(cx, cy, tft_fg, 0); + } + mask >>= 1; + } + } + disp_deselect(); + + return char_width; +} + +// non-rotated fixed width character +//---------------------------------------------- +static void printChar(uint8_t c, int x, int y) { + uint8_t i, j, ch, fz, mask; + uint16_t k, temp, cx, cy, len; + + // fz = bytes per char row + fz = tft_cfont.x_size/8; + if (tft_cfont.x_size % 8) fz++; + + // get character position in buffer + temp = ((c-tft_cfont.offset)*((fz)*tft_cfont.y_size))+4; + + if ((tft_font_buffered_char) && (!tft_font_transparent)) { + // === buffer Glyph data for faster sending === + len = tft_cfont.x_size * tft_cfont.y_size; + color_t *color_line = heap_caps_malloc(len*3, MALLOC_CAP_DMA); + if (color_line) { + // fill with background color + for (int n = 0; n < len; n++) { + color_line[n] = tft_bg; + } + // set character pixels to foreground color + for (j=0; j>= 1; + } + } + temp += (fz); + } + // send to display in one transaction + disp_select(); + send_data(x, y, x+tft_cfont.x_size-1, y+tft_cfont.y_size-1, len, color_line); + disp_deselect(); + free(color_line); + + return; + } + } + + if (!tft_font_transparent) _fillRect(x, y, tft_cfont.x_size, tft_cfont.y_size, tft_bg); + + disp_select(); + for (j=0; j>= 1; + } + } + temp += (fz); + } + disp_deselect(); +} + +// print rotated proportional character +// character is already in fontChar +//--------------------------------------------------- +static int rotatePropChar(int x, int y, int offset) { + uint8_t ch = 0; + double radian = tft_font_rotate * DEG_TO_RAD; + float cos_radian = cos(radian); + float sin_radian = sin(radian); + + uint8_t mask = 0x80; + disp_select(); + for (int j=0; j < fontChar.height; j++) { + for (int i=0; i < fontChar.width; i++) { + if (((i + (j*fontChar.width)) % 8) == 0) { + mask = 0x80; + ch = tft_cfont.font[fontChar.dataPtr++]; + } + + int newX = (int)(x + (((offset + i) * cos_radian) - ((j+fontChar.adjYOffset)*sin_radian))); + int newY = (int)(y + (((j+fontChar.adjYOffset) * cos_radian) + ((offset + i) * sin_radian))); + + if ((ch & mask) != 0) _drawPixel(newX,newY,tft_fg, 0); + else if (!tft_font_transparent) _drawPixel(newX,newY,tft_bg, 0); + + mask >>= 1; + } + } + disp_deselect(); + + return fontChar.xDelta+1; +} + +// rotated fixed width character +//-------------------------------------------------------- +static void rotateChar(uint8_t c, int x, int y, int pos) { + uint8_t i,j,ch,fz,mask; + uint16_t temp; + int newx,newy; + double radian = tft_font_rotate*0.0175; + float cos_radian = cos(radian); + float sin_radian = sin(radian); + int zz; + + if( tft_cfont.x_size < 8 ) fz = tft_cfont.x_size; + else fz = tft_cfont.x_size/8; + temp=((c-tft_cfont.offset)*((fz)*tft_cfont.y_size))+4; + + disp_select(); + for (j=0; j>= 1; + } + } + temp+=(fz); + } + disp_deselect(); + // calculate x,y for the next char + tft_x = (int)(x + ((pos+1) * tft_cfont.x_size * cos_radian)); + tft_y = (int)(y + ((pos+1) * tft_cfont.x_size * sin_radian)); +} + +//---------------------- +static int _7seg_width() +{ + return (2 * (2 * tft_cfont.y_size + 1)) + tft_cfont.x_size; +} + +//----------------------- +static int _7seg_height() +{ + return (3 * (2 * tft_cfont.y_size + 1)) + (2 * tft_cfont.x_size); +} + +// Returns the string width in pixels. +// Useful for positions strings on the screen. +//=============================== +int TFT_getStringWidth(char* str) +{ + int strWidth = 0; + + if (tft_cfont.bitmap == 2) strWidth = ((_7seg_width()+2) * strlen(str)) - 2; // 7-segment font + else if (tft_cfont.x_size != 0) strWidth = strlen(str) * tft_cfont.x_size; // fixed width font + else { + // calculate the width of the string of proportional characters + char* tempStrptr = str; + while (*tempStrptr != 0) { + if (getCharPtr(*tempStrptr++)) { + strWidth += (((fontChar.width > fontChar.xDelta) ? fontChar.width : fontChar.xDelta) + 1); + } + } + strWidth--; + } + return strWidth; +} + +//=============================================== +void TFT_clearStringRect(int x, int y, char *str) +{ + int w = TFT_getStringWidth(str); + int h = TFT_getfontheight(); + TFT_fillRect(x+tft_dispWin.x1, y+tft_dispWin.y1, w, h, tft_bg); +} + +//============================================================================== +/** + * bit-encoded bar position of all digits' bcd segments + * + * 6 + * +-----+ + * 3 | . | 2 + * +--5--+ + * 1 | . | 0 + * +--.--+ + * 4 + */ +static const uint16_t font_bcd[] = { + 0x200, // 0010 0000 0000 // - + 0x080, // 0000 1000 0000 // . + 0x06C, // 0100 0110 1100 // /, degree + 0x05f, // 0000 0101 1111, // 0 + 0x005, // 0000 0000 0101, // 1 + 0x076, // 0000 0111 0110, // 2 + 0x075, // 0000 0111 0101, // 3 + 0x02d, // 0000 0010 1101, // 4 + 0x079, // 0000 0111 1001, // 5 + 0x07b, // 0000 0111 1011, // 6 + 0x045, // 0000 0100 0101, // 7 + 0x07f, // 0000 0111 1111, // 8 + 0x07d, // 0000 0111 1101 // 9 + 0x900 // 1001 0000 0000 // : +}; + +//----------------------------------------------------------------------------------------------- +static void barVert(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, color_t outline) { + _fillTriangle(x+1, y+2*w, x+w, y+w+1, x+2*w-1, y+2*w, color); + _fillTriangle(x+1, y+2*w+l+1, x+w, y+3*w+l, x+2*w-1, y+2*w+l+1, color); + _fillRect(x, y+2*w+1, 2*w+1, l, color); + if (tft_cfont.offset) { + _drawTriangle(x+1, y+2*w, x+w, y+w+1, x+2*w-1, y+2*w, outline); + _drawTriangle(x+1, y+2*w+l+1, x+w, y+3*w+l, x+2*w-1, y+2*w+l+1, outline); + _drawRect(x, y+2*w+1, 2*w+1, l, outline); + } +} + +//---------------------------------------------------------------------------------------------- +static void barHor(int16_t x, int16_t y, int16_t w, int16_t l, color_t color, color_t outline) { + _fillTriangle(x+2*w, y+2*w-1, x+w+1, y+w, x+2*w, y+1, color); + _fillTriangle(x+2*w+l+1, y+2*w-1, x+3*w+l, y+w, x+2*w+l+1, y+1, color); + _fillRect(x+2*w+1, y, l, 2*w+1, color); + if (tft_cfont.offset) { + _drawTriangle(x+2*w, y+2*w-1, x+w+1, y+w, x+2*w, y+1, outline); + _drawTriangle(x+2*w+l+1, y+2*w-1, x+3*w+l, y+w, x+2*w+l+1, y+1, outline); + _drawRect(x+2*w+1, y, l, 2*w+1, outline); + } +} + +//-------------------------------------------------------------------------------------------- +static void _draw7seg(int16_t x, int16_t y, int8_t num, int16_t w, int16_t l, color_t color) { + /* TODO: clipping */ + if (num < 0x2D || num > 0x3A) return; + + int16_t c = font_bcd[num-0x2D]; + int16_t d = 2*w+l+1; + + // === Clear unused segments === + if (!(c & 0x001)) barVert(x+d, y+d, w, l, tft_bg, tft_bg); + if (!(c & 0x002)) barVert(x, y+d, w, l, tft_bg, tft_bg); + if (!(c & 0x004)) barVert(x+d, y, w, l, tft_bg, tft_bg); + if (!(c & 0x008)) barVert(x, y, w, l, tft_bg, tft_bg); + if (!(c & 0x010)) barHor(x, y+2*d, w, l, tft_bg, tft_bg); + if (!(c & 0x020)) barHor(x, y+d, w, l, tft_bg, tft_bg); + if (!(c & 0x040)) barHor(x, y, w, l, tft_bg, tft_bg); + + if (!(c & 0x080)) { + // low point + _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, tft_bg); + if (tft_cfont.offset) _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, tft_bg); + } + if (!(c & 0x100)) { + // down middle point + _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, tft_bg); + if (tft_cfont.offset) _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, tft_bg); + } + if (!(c & 0x800)) { + // up middle point + _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, tft_bg); + if (tft_cfont.offset) _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, tft_bg); + } + if (!(c & 0x200)) { + // middle, minus + _fillRect(x+2*w+1, y+d, l, 2*w+1, tft_bg); + if (tft_cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, tft_bg); + } + + // === Draw used segments === + if (c & 0x001) barVert(x+d, y+d, w, l, color, tft_cfont.color); // down right + if (c & 0x002) barVert(x, y+d, w, l, color, tft_cfont.color); // down left + if (c & 0x004) barVert(x+d, y, w, l, color, tft_cfont.color); // up right + if (c & 0x008) barVert(x, y, w, l, color, tft_cfont.color); // up left + if (c & 0x010) barHor(x, y+2*d, w, l, color, tft_cfont.color); // down + if (c & 0x020) barHor(x, y+d, w, l, color, tft_cfont.color); // middle + if (c & 0x040) barHor(x, y, w, l, color, tft_cfont.color); // up + + if (c & 0x080) { + // low point + _fillRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, color); + if (tft_cfont.offset) _drawRect(x+(d/2), y+2*d, 2*w+1, 2*w+1, tft_cfont.color); + } + if (c & 0x100) { + // down middle point + _fillRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, color); + if (tft_cfont.offset) _drawRect(x+(d/2), y+d+2*w+1, 2*w+1, l/2, tft_cfont.color); + } + if (c & 0x800) { + // up middle point + _fillRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, color); + if (tft_cfont.offset) _drawRect(x+(d/2), y+(2*w)+1+(l/2), 2*w+1, l/2, tft_cfont.color); + } + if (c & 0x200) { + // middle, minus + _fillRect(x+2*w+1, y+d, l, 2*w+1, color); + if (tft_cfont.offset) _drawRect(x+2*w+1, y+d, l, 2*w+1, tft_cfont.color); + } +} +//============================================================================== + +//====================================== +void TFT_print(char *st, int x, int y) { + int stl, i, tmpw, tmph, fh; + uint8_t ch; + + if (tft_cfont.bitmap == 0) return; // wrong font selected + + // ** Rotated strings cannot be aligned + if ((tft_font_rotate != 0) && ((x <= CENTER) || (y <= CENTER))) return; + + if ((x < LASTX) || (tft_font_rotate == 0)) TFT_OFFSET = 0; + + if ((x >= LASTX) && (x < LASTY)) x = tft_x + (x-LASTX); + else if (x > CENTER) x += tft_dispWin.x1; + + if (y >= LASTY) y = tft_y + (y-LASTY); + else if (y > CENTER) y += tft_dispWin.y1; + + // ** Get number of characters in string to print + stl = strlen(st); + + // ** Calculate CENTER, RIGHT or BOTTOM position + tmpw = TFT_getStringWidth(st); // string width in pixels + fh = tft_cfont.y_size; // font height + if ((tft_cfont.x_size != 0) && (tft_cfont.bitmap == 2)) { + // 7-segment font + fh = (3 * (2 * tft_cfont.y_size + 1)) + (2 * tft_cfont.x_size); // 7-seg character height + } + + if (x == RIGHT) x = tft_dispWin.x2 - tmpw + tft_dispWin.x1; + else if (x == CENTER) x = (((tft_dispWin.x2 - tft_dispWin.x1 + 1) - tmpw) / 2) + tft_dispWin.x1; + + if (y == BOTTOM) y = tft_dispWin.y2 - fh + tft_dispWin.y1; + else if (y==CENTER) y = (((tft_dispWin.y2 - tft_dispWin.y1 + 1) - (fh/2)) / 2) + tft_dispWin.y1; + + if (x < tft_dispWin.x1) x = tft_dispWin.x1; + if (y < tft_dispWin.y1) y = tft_dispWin.y1; + if ((x > tft_dispWin.x2) || (y > tft_dispWin.y2)) return; + + tft_x = x; + tft_y = y; + + // ** Adjust y position + tmph = tft_cfont.y_size; // font height + // for non-proportional fonts, char width is the same for all chars + tmpw = tft_cfont.x_size; + if (tft_cfont.x_size != 0) { + if (tft_cfont.bitmap == 2) { // 7-segment font + tmpw = _7seg_width(); // character width + tmph = _7seg_height(); // character height + } + } + else TFT_OFFSET = 0; // fixed font; offset not needed + + if ((tft_y + tmph - 1) > tft_dispWin.y2) return; + + int offset = TFT_OFFSET; + + for (i=0; i (tft_dispWin.y2-tmph)) break; + tft_x = tft_dispWin.x1; + } + } + + else { // ==== other characters ==== + if (tft_cfont.x_size == 0) { + // for proportional font get character data to 'fontChar' + if (getCharPtr(ch)) tmpw = fontChar.xDelta; + else continue; + } + + // check if character can be displayed in the current line + if ((tft_x+tmpw) > (tft_dispWin.x2)) { + if (tft_text_wrap == 0) break; + tft_y += tmph + tft_font_line_space; + if (tft_y > (tft_dispWin.y2-tmph)) break; + tft_x = tft_dispWin.x1; + } + + // Let's print the character + if (tft_cfont.x_size == 0) { + // == proportional font + if (tft_font_rotate == 0) tft_x += printProportionalChar(tft_x, tft_y) + 1; + else { + // rotated proportional font + offset += rotatePropChar(x, y, offset); + TFT_OFFSET = offset; + } + } + else { + if (tft_cfont.bitmap == 1) { + // == fixed font + if ((ch < tft_cfont.offset) || ((ch-tft_cfont.offset) > tft_cfont.numchars)) ch = tft_cfont.offset; + if (tft_font_rotate == 0) { + printChar(ch, tft_x, tft_y); + tft_x += tmpw; + } + else rotateChar(ch, x, y, i); + } + else if (tft_cfont.bitmap == 2) { + // == 7-segment font == + _draw7seg(tft_x, tft_y, ch, tft_cfont.y_size, tft_cfont.x_size, tft_fg); + tft_x += (tmpw + 2); + } + } + } + } +} + + +// ================ Service functions ========================================== + +// Change the screen rotation. +// Input: m new rotation value (0 to 3) +//================================= +void TFT_setRotation(uint8_t rot) { + if (rot > 3) { + uint8_t madctl = (rot & 0xF8); // for testing, manually set MADCTL register + if (disp_select() == ESP_OK) { + disp_spi_transfer_cmd_data(TFT_MADCTL, &madctl, 1); + disp_deselect(); + } + } + else { + tft_orientation = rot; + _tft_setRotation(rot); + } + + tft_dispWin.x1 = TFT_STATIC_X_OFFSET; + tft_dispWin.y1 = TFT_STATIC_Y_OFFSET; + tft_dispWin.x2 = tft_width + TFT_STATIC_X_OFFSET -1; + tft_dispWin.y2 = tft_height + TFT_STATIC_Y_OFFSET -1; + + TFT_fillScreen(tft_bg); +} + +// Send the command to invert all of the colors. +// Input: i 0 to disable inversion; non-zero to enable inversion +//========================================== +void TFT_invertDisplay(const uint8_t mode) { + if (disp_select() == ESP_OK) { + if ( mode == INVERT_ON ) disp_spi_transfer_cmd(TFT_INVONN); + else disp_spi_transfer_cmd(TFT_INVOFF); + disp_deselect(); + } +} + +// Select gamma curve +// Input: gamma = 0~3 +//================================== +void TFT_setGammaCurve(uint8_t gm) { + uint8_t gamma_curve = (uint8_t)1 << (gm & (uint8_t)0x03); + if (disp_select() == ESP_OK) { + disp_spi_transfer_cmd_data(TFT_CMD_GAMMASET, &gamma_curve, 1); + disp_deselect(); + } +} + +//=========================================================== +color_t HSBtoRGB(float _hue, float _sat, float _brightness) { + float red = 0.0; + float green = 0.0; + float blue = 0.0; + + if (_sat == 0.0) { + red = _brightness; + green = _brightness; + blue = _brightness; + } else { + if (_hue == 360.0) { + _hue = 0; + } + + int slice = (int)(_hue / 60.0); + float hue_frac = (_hue / 60.0) - slice; + + float aa = _brightness * (1.0 - _sat); + float bb = _brightness * (1.0 - _sat * hue_frac); + float cc = _brightness * (1.0 - _sat * (1.0 - hue_frac)); + + switch(slice) { + case 0: + red = _brightness; + green = cc; + blue = aa; + break; + case 1: + red = bb; + green = _brightness; + blue = aa; + break; + case 2: + red = aa; + green = _brightness; + blue = cc; + break; + case 3: + red = aa; + green = bb; + blue = _brightness; + break; + case 4: + red = cc; + green = aa; + blue = _brightness; + break; + case 5: + red = _brightness; + green = aa; + blue = bb; + break; + default: + red = 0.0; + green = 0.0; + blue = 0.0; + break; + } + } + + color_t color; + color.r = ((uint8_t)(red * 255.0)) & 0xFC; + color.g = ((uint8_t)(green * 255.0)) & 0xFC; + color.b = ((uint8_t)(blue * 255.0)) & 0xFC; + + return color; +} +//===================================================================== +void TFT_setclipwin(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) +{ + tft_dispWin.x1 = x1 + TFT_STATIC_X_OFFSET; + tft_dispWin.y1 = y1 + TFT_STATIC_Y_OFFSET; + tft_dispWin.x2 = x2 + TFT_STATIC_X_OFFSET; + tft_dispWin.y2 = y2 + TFT_STATIC_Y_OFFSET; + + if (tft_dispWin.x2 >= tft_width + TFT_STATIC_X_OFFSET) tft_dispWin.x2 = tft_width + TFT_STATIC_X_OFFSET -1; + if (tft_dispWin.y2 >= tft_height + TFT_STATIC_Y_OFFSET) tft_dispWin.y2 = tft_height + TFT_STATIC_Y_OFFSET -1; + if (tft_dispWin.x1 > tft_dispWin.x2) tft_dispWin.x1 = tft_dispWin.x2; + if (tft_dispWin.y1 > tft_dispWin.y2) tft_dispWin.y1 = tft_dispWin.y2; +} + +//===================== +void TFT_resetclipwin() +{ + tft_dispWin.x2 = tft_width + TFT_STATIC_X_OFFSET -1; + tft_dispWin.y2 = tft_height + TFT_STATIC_Y_OFFSET -1; + tft_dispWin.x1 = TFT_STATIC_X_OFFSET; + tft_dispWin.y1 = TFT_STATIC_Y_OFFSET; +} + +//========================================================================== +void set_7seg_font_atrib(uint8_t l, uint8_t w, int outline, color_t color) { + if (tft_cfont.bitmap != 2) return; + + if (l < 6) l = 6; + if (l > 40) l = 40; + if (w < 1) w = 1; + if (w > (l/2)) w = l/2; + if (w > 12) w = 12; + + tft_cfont.x_size = l; + tft_cfont.y_size = w; + tft_cfont.offset = outline; + tft_cfont.color = color; +} + +//========================================== +int TFT_getfontsize(int *width, int* height) +{ + if (tft_cfont.bitmap == 1) { + if (tft_cfont.x_size != 0) *width = tft_cfont.x_size; // fixed width font + else *width = tft_cfont.max_x_size; // proportional font + *height = tft_cfont.y_size; + } + else if (tft_cfont.bitmap == 2) { + // 7-segment font + *width = _7seg_width(); + *height = _7seg_height(); + } + else { + *width = 0; + *height = 0; + return 0; + } + return 1; +} + +//===================== +int TFT_getfontheight() +{ + if (tft_cfont.bitmap == 1) return tft_cfont.y_size; // Bitmap font + else if (tft_cfont.bitmap == 2) return _7seg_height(); // 7-segment font + return 0; +} + +//==================== +void TFT_saveClipWin() +{ + dispWinTemp.x1 = tft_dispWin.x1; + dispWinTemp.y1 = tft_dispWin.y1; + dispWinTemp.x2 = tft_dispWin.x2; + dispWinTemp.y2 = tft_dispWin.y2; +} + +//======================= +void TFT_restoreClipWin() +{ + tft_dispWin.x1 = dispWinTemp.x1; + tft_dispWin.y1 = dispWinTemp.y1; + tft_dispWin.x2 = dispWinTemp.x2; + tft_dispWin.y2 = dispWinTemp.y2; +} + + +// ================ JPG SUPPORT ================================================ +// User defined device identifier +typedef struct { + FILE *fhndl; // File handler for input function + int x; // image top left point X position + int y; // image top left point Y position + uint8_t *membuff; // memory buffer containing the image + uint32_t bufsize; // size of the memory buffer + uint32_t bufptr; // memory buffer current position + color_t *linbuf[2]; // memory buffer used for display output + uint8_t linbuf_idx; +} JPGIODEV; + + +// User defined call-back function to input JPEG data from file +//--------------------- +static UINT tjd_input ( + JDEC* jd, // Decompression object + BYTE* buff, // Pointer to the read buffer (NULL:skip) + UINT nd // Number of bytes to read/skip from input stream +) +{ + int rb = 0; + // Device identifier for the session (5th argument of jd_prepare function) + JPGIODEV *dev = (JPGIODEV*)jd->device; + + if (buff) { // Read nd bytes from the input strem + rb = fread(buff, 1, nd, dev->fhndl); + return rb; // Returns actual number of bytes read + } + else { // Remove nd bytes from the input stream + if (fseek(dev->fhndl, nd, SEEK_CUR) >= 0) return nd; + else return 0; + } +} + +// User defined call-back function to input JPEG data from memory buffer +//------------------------- +static UINT tjd_buf_input ( + JDEC* jd, // Decompression object + BYTE* buff, // Pointer to the read buffer (NULL:skip) + UINT nd // Number of bytes to read/skip from input stream +) +{ + // Device identifier for the session (5th argument of jd_prepare function) + JPGIODEV *dev = (JPGIODEV*)jd->device; + if (!dev->membuff) return 0; + if (dev->bufptr >= (dev->bufsize + 2)) return 0; // end of stream + + if ((dev->bufptr + nd) > (dev->bufsize + 2)) nd = (dev->bufsize + 2) - dev->bufptr; + + if (buff) { // Read nd bytes from the input strem + memcpy(buff, dev->membuff + dev->bufptr, nd); + dev->bufptr += nd; + return nd; // Returns number of bytes read + } + else { // Remove nd bytes from the input stream + dev->bufptr += nd; + return nd; + } +} + +// User defined call-back function to output RGB bitmap to display device +//---------------------- +static UINT tjd_output ( + JDEC* jd, // Decompression object of current session + void* bitmap, // Bitmap data to be output + JRECT* rect // Rectangular region to output +) +{ + // Device identifier for the session (5th argument of jd_prepare function) + JPGIODEV *dev = (JPGIODEV*)jd->device; + + // ** Put the rectangular into the display device ** + int x; + int y; + int dleft, dtop, dright, dbottom; + BYTE *src = (BYTE*)bitmap; + + int left = rect->left + dev->x; + int top = rect->top + dev->y; + int right = rect->right + dev->x; + int bottom = rect->bottom + dev->y; + + if ((left > tft_dispWin.x2) || (top > tft_dispWin.y2)) return 1; // out of screen area, return + if ((right < tft_dispWin.x1) || (bottom < tft_dispWin.y1)) return 1;// out of screen area, return + + if (left < tft_dispWin.x1) dleft = tft_dispWin.x1; + else dleft = left; + if (top < tft_dispWin.y1) dtop = tft_dispWin.y1; + else dtop = top; + if (right > tft_dispWin.x2) dright = tft_dispWin.x2; + else dright = right; + if (bottom > tft_dispWin.y2) dbottom = tft_dispWin.y2; + else dbottom = bottom; + + if ((dleft > tft_dispWin.x2) || (dtop > tft_dispWin.y2)) return 1; // out of screen area, return + if ((dright < tft_dispWin.x1) || (dbottom < tft_dispWin.y1)) return 1; // out of screen area, return + + uint32_t len = ((dright-dleft+1) * (dbottom-dtop+1)); // calculate length of data + + + if ((len > 0) && (len <= JPG_IMAGE_LINE_BUF_SIZE)) { + uint8_t *dest = (uint8_t *)(dev->linbuf[dev->linbuf_idx]); + + for (y = top; y <= bottom; y++) { + for (x = left; x <= right; x++) { + // Clip to display area + if ((x >= dleft) && (y >= dtop) && (x <= dright) && (y <= dbottom)) { + *dest++ = (*src++) & 0xFC; + *dest++ = (*src++) & 0xFC; + *dest++ = (*src++) & 0xFC; + } + else src += 3; // skip + } + } + wait_trans_finish(1); + send_data(dleft, dtop, dright, dbottom, len, dev->linbuf[dev->linbuf_idx]); + dev->linbuf_idx = ((dev->linbuf_idx + 1) & 1); + } + else { + wait_trans_finish(1); + printf("Data size error: %d jpg: (%d,%d,%d,%d) disp: (%d,%d,%d,%d)\r\n", len, left,top,right,bottom, dleft,dtop,dright,dbottom); + return 0; // stop decompression + } + + return 1; // Continue to decompression +} + +// tft.jpgimage(X, Y, scale, file_name, buf, size] +// X & Y can be < 0 ! +//================================================================================== +void TFT_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size) +{ + JPGIODEV dev; + struct stat sb; + char *work = NULL; // Pointer to the working buffer (must be 4-byte aligned) + UINT sz_work = 3800; // Size of the working buffer (must be power of 2) + JDEC jd; // Decompression object (70 bytes) + JRESULT rc; + + dev.linbuf[0] = NULL; + dev.linbuf[1] = NULL; + dev.linbuf_idx = 0; + + dev.fhndl = NULL; + if (fname == NULL) { + // image from buffer + dev.membuff = buf; + dev.bufsize = size; + dev.bufptr = 0; + } + else { + // image from file + dev.membuff = NULL; + dev.bufsize = 0; + dev.bufptr = 0; + + if (stat(fname, &sb) != 0) { + if (tft_image_debug) printf("File error: %ss\r\n", strerror(errno)); + goto exit; + } + + dev.fhndl = fopen(fname, "r"); + if (!dev.fhndl) { + if (tft_image_debug) printf("Error opening file: %s\r\n", strerror(errno)); + goto exit; + } + } + + if (scale > 3) scale = 3; + + work = malloc(sz_work); + if (work) { + if (dev.membuff) rc = jd_prepare(&jd, tjd_buf_input, (void *)work, sz_work, &dev); + else rc = jd_prepare(&jd, tjd_input, (void *)work, sz_work, &dev); + if (rc == JDR_OK) { + if (x == CENTER) x = ((tft_dispWin.x2 - tft_dispWin.x1 + 1 - (int)(jd.width >> scale)) / 2) + tft_dispWin.x1; + else if (x == RIGHT) x = tft_dispWin.x2 + 1 - (int)(jd.width >> scale); + + if (y == CENTER) y = ((tft_dispWin.y2 - tft_dispWin.y1 + 1 - (int)(jd.height >> scale)) / 2) + tft_dispWin.y1; + else if (y == BOTTOM) y = tft_dispWin.y2 + 1 - (int)(jd.height >> scale); + + if (x < ((tft_dispWin.x2-1) * -1)) x = (tft_dispWin.x2-1) * -1; + if (y < ((tft_dispWin.y2-1)) * -1) y = (tft_dispWin.y2-1) * -1; + if (x > (tft_dispWin.x2-1)) x = tft_dispWin.x2 - 1; + if (y > (tft_dispWin.y2-1)) y = tft_dispWin.y2-1; + + dev.x = x; + dev.y = y; + + dev.linbuf[0] = heap_caps_malloc(JPG_IMAGE_LINE_BUF_SIZE*3, MALLOC_CAP_DMA); + if (dev.linbuf[0] == NULL) { + if (tft_image_debug) printf("Error allocating line buffer #0\r\n"); + goto exit; + } + dev.linbuf[1] = heap_caps_malloc(JPG_IMAGE_LINE_BUF_SIZE*3, MALLOC_CAP_DMA); + if (dev.linbuf[1] == NULL) { + if (tft_image_debug) printf("Error allocating line buffer #1\r\n"); + goto exit; + } + + // Start to decode the JPEG file + disp_select(); + rc = jd_decomp(&jd, tjd_output, scale); + disp_deselect(); + + if (rc != JDR_OK) { + if (tft_image_debug) printf("jpg decompression error %d\r\n", rc); + } + if (tft_image_debug) printf("Jpg size: %dx%d, position; %d,%d, scale: %d, bytes used: %d\r\n", jd.width, jd.height, x, y, scale, jd.sz_pool); + } + else { + if (tft_image_debug) printf("jpg prepare error %d\r\n", rc); + } + } + else { + if (tft_image_debug) printf("work buffer allocation error\r\n"); + } + +exit: + if (work) free(work); // free work buffer + if (dev.linbuf[0]) free(dev.linbuf[0]); + if (dev.linbuf[1]) free(dev.linbuf[1]); + if (dev.fhndl) fclose(dev.fhndl); // close input file +} + + +//==================================================================================== +int TFT_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size) +{ + FILE *fhndl = NULL; + struct stat sb; + int i, err=0; + int img_xsize, img_ysize, img_xstart, img_xlen, img_ystart, img_ylen; + int img_pos, img_pix_pos, scan_lines, rd_len; + uint8_t tmpc; + uint16_t wtemp; + uint32_t temp; + int disp_xstart, disp_xend, disp_ystart, disp_yend; + uint8_t buf[56]; + char err_buf[64]; + uint8_t *line_buf[2] = {NULL,NULL}; + uint8_t lb_idx = 0; + uint8_t *scale_buf = NULL; + uint8_t scale_pix; + uint16_t co[3] = {0,0,0}; // RGB sum + uint8_t npix; + + if (scale > 7) scale = 7; + scale_pix = scale+1; // scale factor ( 1~8 ) + + if (fname) { + // * File name is given, reading image from file + if (stat(fname, &sb) != 0) { + sprintf(err_buf, "opening file"); + err = -1; + goto exit; + } + size = sb.st_size; + fhndl = fopen(fname, "r"); + if (!fhndl) { + sprintf(err_buf, "opening file"); + err = -2; + goto exit; + } + + i = fread(buf, 1, 54, fhndl); // read header + } + else { + // * Reading image from buffer + if ((imgbuf) && (size > 54)) { + memcpy(buf, imgbuf, 54); + i = 54; + } + else i = 0; + } + + sprintf(err_buf, "reading header"); + if (i != 54) {err = -3; goto exit;} + + // ** Check image header and get image properties + if ((buf[0] != 'B') || (buf[1] != 'M')) {err=-4; goto exit;} // accept only images with 'BM' id + + memcpy(&temp, buf+2, 4); // file size + if (temp != size) {err=-5; goto exit;} + + memcpy(&img_pos, buf+10, 4); // start of pixel data + + memcpy(&temp, buf+14, 4); // BMP header size + if (temp != 40) {err=-6; goto exit;} + + memcpy(&wtemp, buf+26, 2); // the number of color planes + if (wtemp != 1) {err=-7; goto exit;} + + memcpy(&wtemp, buf+28, 2); // the number of bits per pixel + if (wtemp != 24) {err=-8; goto exit;} + + memcpy(&temp, buf+30, 4); // the compression method being used + if (temp != 0) {err=-9; goto exit;} + + memcpy(&img_xsize, buf+18, 4); // the bitmap width in pixels + memcpy(&img_ysize, buf+22, 4); // the bitmap height in pixels + + + // * scale image dimensions + + img_xlen = img_xsize / scale_pix; // image display horizontal size + img_ylen = img_ysize / scale_pix; // image display vertical size + + if (x == CENTER) x = ((tft_dispWin.x2 - tft_dispWin.x1 + 1 - img_xlen) / 2) + tft_dispWin.x1; + else if (x == RIGHT) x = tft_dispWin.x2 + 1 - img_xlen; + + if (y == CENTER) y = ((tft_dispWin.y2 - tft_dispWin.y1 + 1 - img_ylen) / 2) + tft_dispWin.y1; + else if (y == BOTTOM) y = tft_dispWin.y2 + 1 - img_ylen; + + if ((x < ((tft_dispWin.x2 + 1) * -1)) || (x > (tft_dispWin.x2 + 1)) || (y < ((tft_dispWin.y2 + 1) * -1)) || (y > (tft_dispWin.y2 + 1))) { + sprintf(err_buf, "out of display area (%d,%d", x, y); + err = -10; + goto exit; + } + + // ** set display and image areas + if (x < tft_dispWin.x1) { + disp_xstart = tft_dispWin.x1; + img_xstart = -x; // image pixel line X offset + img_xlen += x; + } + else { + disp_xstart = x; + img_xstart = 0; + } + if (y < tft_dispWin.y1) { + disp_ystart = tft_dispWin.y1; + img_ystart = -y; // image pixel line Y offset + img_ylen += y; + } + else { + disp_ystart = y; + img_ystart = 0; + } + disp_xend = disp_xstart + img_xlen - 1; + disp_yend = disp_ystart + img_ylen - 1; + if (disp_xend > tft_dispWin.x2) { + disp_xend = tft_dispWin.x2; + img_xlen = disp_xend - disp_xstart + 1; + } + if (disp_yend > tft_dispWin.y2) { + disp_yend = tft_dispWin.y2; + img_ylen = disp_yend - disp_ystart + 1; + } + + if ((img_xlen < 8) || (img_ylen < 8) || (img_xstart >= (img_xsize-2)) || ((img_ysize - img_ystart) < 2)) { + sprintf(err_buf, "image too small"); + err = -11; + goto exit; + } + + // ** Allocate memory for 2 lines of image pixels + line_buf[0] = heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA); + if (line_buf[0] == NULL) { + sprintf(err_buf, "allocating line buffer #1"); + err=-12; + goto exit; + } + + line_buf[1] = heap_caps_malloc(img_xsize*3, MALLOC_CAP_DMA); + if (line_buf[1] == NULL) { + sprintf(err_buf, "allocating line buffer #2"); + err=-13; + goto exit; + } + + if (scale) { + // Allocate memory for scale buffer + rd_len = img_xlen * 3 * scale_pix; + scale_buf = malloc(rd_len*scale_pix); + if (scale_buf == NULL) { + sprintf(err_buf, "allocating scale buffer"); + err=-14; + goto exit; + } + } + else rd_len = img_xlen * 3; + + // ** ***************************************************** ** + // ** BMP images are stored in file from LAST to FIRST line ** + // ** ***************************************************** ** + + /* Used variables: + img_xsize horizontal image size in pixels + img_ysize number of image lines + img_xlen image display horizontal scaled size in pixels + img_ylen image display vertical scaled size in pixels + img_xstart first pixel in line to be displayed + img_ystart first image line to be displayed + img_xlen number of pixels in image line to be displayed, starting with 'img_xstart' + img_ylen number of lines in image to be displayed, starting with 'img_ystart' + rd_len length of color data which are read from image line in bytes + */ + + // Set position in image to the first color data (beginning of the LAST line) + img_pos += (img_ystart * (img_xsize*3)); + if (fhndl) { + if (fseek(fhndl, img_pos, SEEK_SET) != 0) { + sprintf(err_buf, "file seek at %d", img_pos); + err = -15; + goto exit; + } + } + + if (tft_image_debug) printf("BMP: image size: (%d,%d) scale: %d disp size: (%d,%d) img xofs: %d img yofs: %d at: %d,%d; line buf: 2* %d scale buf: %d\r\n", + img_xsize, img_ysize, scale_pix, img_xlen, img_ylen, img_xstart, img_ystart, disp_xstart, disp_ystart, img_xsize*3, ((scale) ? (rd_len*scale_pix) : 0)); + + // * Select the display + disp_select(); + + while ((disp_yend >= disp_ystart) && ((img_pos + (img_xsize*3)) <= size)) { + if (img_pos > size) { + sprintf(err_buf, "EOF reached: %d > %d", img_pos, size); + err = -16; + goto exit1; + } + if (scale == 0) { + // Read the line of color data into color buffer + if (fhndl) { + i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file + if (i != (img_xsize*3)) { + sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3); + err = -16; + goto exit1; + } + } + else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3); + + if (img_xstart > 0) memmove(line_buf[lb_idx], line_buf[lb_idx]+(img_xstart*3), rd_len); + // Convert colors BGR-888 (BMP) -> RGB-888 (DISPLAY) === + for (i=0; i < rd_len; i += 3) { + tmpc = line_buf[lb_idx][i+2] & 0xfc; // save R + line_buf[lb_idx][i+2] = line_buf[lb_idx][i] & 0xfc; // B -> R + line_buf[lb_idx][i] = tmpc; // R -> B + line_buf[lb_idx][i+1] &= 0xfc; // G + } + img_pos += (img_xsize*3); + } + else { + // scale image, read 'scale_pix' lines and find the average color + for (scan_lines=0; scan_lines size) break; + if (fhndl) { + i = fread(line_buf[lb_idx], 1, img_xsize*3, fhndl); // read line from file + if (i != (img_xsize*3)) { + sprintf(err_buf, "file read at %d (%d<>%d)", img_pos, i, img_xsize*3); + err = -17; + goto exit1; + } + } + else memcpy(line_buf[lb_idx], imgbuf+img_pos, img_xsize*3); + img_pos += (img_xsize*3); + + // copy only data which are displayed to scale buffer + memcpy(scale_buf + (rd_len * scan_lines), line_buf[lb_idx]+img_xstart, rd_len); + } + + // Populate display line buffer + for (int n=0;n<(img_xlen*3);n += 3) { + memset(co, 0, sizeof(co)); // initialize color sum + npix = 0; // initialize number of pixels in scale rectangle + + // sum all pixels in scale rectangle + for (int sc_line=0; sc_line RGB-888 (DISPLAY) + line_buf[lb_idx][n+2] = (uint8_t)(co[0] / npix); // B + line_buf[lb_idx][n+1] = (uint8_t)(co[1] / npix); // G + line_buf[lb_idx][n] = (uint8_t)(co[2] / npix); // R + } + } + + wait_trans_finish(1); + send_data(disp_xstart, disp_yend, disp_xend, disp_yend, img_xlen, (color_t *)line_buf[lb_idx]); + lb_idx = (lb_idx + 1) & 1; // change buffer + + disp_yend--; + } + err = 0; +exit1: + disp_deselect(); +exit: + if (scale_buf) free(scale_buf); + if (line_buf[0]) free(line_buf[0]); + if (line_buf[1]) free(line_buf[1]); + if (fhndl) fclose(fhndl); + if ((err) && (tft_image_debug)) printf("Error: %d [%s]\r\n", err, err_buf); + + return err; +} + + +// ============= Touch panel functions ========================================= + +#if USE_TOUCH == TOUCH_TYPE_XPT2046 +//------------------------------------------------------- +static int tp_get_data_xpt2046(uint8_t type, int samples) +{ + if (tft_ts_spi == NULL) return 0; + + int n, result, val = 0; + uint32_t i = 0; + uint32_t vbuf[18]; + uint32_t minval, maxval, dif; + + if (samples < 3) samples = 1; + if (samples > 18) samples = 18; + + // one dummy read + result = touch_get_data(type); + + // read data + while (i < 10) { + minval = 5000; + maxval = 0; + // get values + for (n=0;n maxval) maxval = result; + } + if (result < 0) break; + dif = maxval - minval; + if (dif < 40) break; + i++; + } + if (result < 0) return -1; + + if (samples > 2) { + // remove one min value + for (n = 0; n < samples; n++) { + if (vbuf[n] == minval) { + vbuf[n] = 5000; + break; + } + } + // remove one max value + for (n = 0; n < samples; n++) { + if (vbuf[n] == maxval) { + vbuf[n] = 5000; + break; + } + } + for (n = 0; n < samples; n++) { + if (vbuf[n] < 5000) val += vbuf[n]; + } + val /= (samples-2); + } + else val = vbuf[0]; + + return val; +} + +//----------------------------------------------- +static int TFT_read_touch_xpt2046(int *x, int* y) +{ + int res = 0, result = -1; + if (spi_lobo_device_select(tft_ts_spi, 0) != ESP_OK) return 0; + + result = tp_get_data_xpt2046(0xB0, 3); // Z; pressure; touch detect + if (result <= 50) goto exit; + + // touch panel pressed + result = tp_get_data_xpt2046(0xD0, 10); + if (result < 0) goto exit; + + *x = result; + + result = tp_get_data_xpt2046(0x90, 10); + if (result < 0) goto exit; + + *y = result; + res = 1; +exit: + spi_lobo_device_deselect(tft_ts_spi); + return res; +} +#endif + +//============================================= +int TFT_read_touch(int *x, int* y, uint8_t raw) +{ + *x = 0; + *y = 0; + if (tft_ts_spi == NULL) return 0; + #if USE_TOUCH == TOUCH_TYPE_NONE + return 0; + #else + int result = -1; + int X=0, Y=0; + + #if USE_TOUCH == TOUCH_TYPE_XPT2046 + uint32_t tft_tp_calx = TP_CALX_XPT2046; + uint32_t tft_tp_caly = TP_CALY_XPT2046; + result = TFT_read_touch_xpt2046(&X, &Y); + if (result == 0) return 0; + #elif USE_TOUCH == TOUCH_TYPE_STMPE610 + uint32_t tft_tp_calx = TP_CALX_STMPE610; + uint32_t tft_tp_caly = TP_CALY_STMPE610; + uint16_t Xx, Yy, Z=0; + result = stmpe610_get_touch(&Xx, &Yy, &Z); + if (result == 0) return 0; + X = Xx; + Y = Yy; + #else + return 0; + #endif + + if (raw) { + *x = X; + *y = Y; + return 1; + } + + // Calibrate the result + int tmp; + int xleft = (tft_tp_calx >> 16) & 0x3FFF; + int xright = tft_tp_calx & 0x3FFF; + int ytop = (tft_tp_caly >> 16) & 0x3FFF; + int ybottom = tft_tp_caly & 0x3FFF; + + if (((xright - xleft) <= 0) || ((ybottom - ytop) <= 0)) return 0; + + #if USE_TOUCH == TOUCH_TYPE_XPT2046 + int width = tft_width; + int height = tft_height; + X = ((X - xleft) * height) / (xright - xleft); + Y = ((Y - ytop) * width) / (ybottom - ytop); + + if (X < 0) X = 0; + if (X > height-1) X = height-1; + if (Y < 0) Y = 0; + if (Y > width-1) Y = width-1; + + switch (tft_orientation) { + case PORTRAIT: + tmp = X; + X = width - Y - 1; + Y = tmp; + break; + case PORTRAIT_FLIP: + tmp = X; + X = Y; + Y = height - tmp - 1; + break; + case LANDSCAPE_FLIP: + X = height - X - 1; + Y = width - Y - 1; + break; + } + #elif USE_TOUCH == TOUCH_TYPE_STMPE610 + int width = tft_width; + int height = tft_height; + if (tft_width > tft_height) { + width = tft_height; + height = tft_width; + } + X = ((X - xleft) * width) / (xright - xleft); + Y = ((Y - ytop) * height) / (ybottom - ytop); + + if (X < 0) X = 0; + if (X > width-1) X = width-1; + if (Y < 0) Y = 0; + if (Y > height-1) Y = height-1; + + switch (tft_orientation) { + case PORTRAIT_FLIP: + X = width - X - 1; + Y = height - Y - 1; + break; + case LANDSCAPE: + tmp = X; + X = Y; + Y = width - tmp -1; + break; + case LANDSCAPE_FLIP: + tmp = X; + X = height - Y -1; + Y = tmp; + break; + } + #endif + *x = X; + *y = Y; + return 1; + #endif +} + diff --git a/components/tft/tft.h b/components/tft/tft.h new file mode 100644 index 0000000..8249f20 --- /dev/null +++ b/components/tft/tft.h @@ -0,0 +1,688 @@ +/* + * High level TFT functions + * Author: LoBo 04/2017, https://github/loboris + * + */ + +#ifndef _TFT_H_ +#define _TFT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "tftspi.h" + +typedef struct { + uint16_t x1; + uint16_t y1; + uint16_t x2; + uint16_t y2; +} dispWin_t; + +typedef struct { + uint8_t *font; + uint8_t x_size; + uint8_t y_size; + uint8_t offset; + uint16_t numchars; + uint16_t size; + uint8_t max_x_size; + uint8_t bitmap; + color_t color; +} Font; + + +//========================================================================================== +// ==== Global variables =================================================================== +//========================================================================================== +extern uint8_t tft_orientation; // current screen tft_orientation +extern uint16_t tft_font_rotate; // current font tft_font_rotate angle (0~395) +extern uint8_t tft_font_transparent; // if not 0 draw fonts transparent +extern uint8_t tft_font_forceFixed; // if not zero force drawing proportional fonts with fixed width +extern uint8_t tft_font_buffered_char; +extern uint8_t tft_font_line_space; // additional spacing between text lines; added to font height +extern uint8_t tft_text_wrap; // if not 0 wrap long text to the new line, else clip +extern color_t tft_fg; // current foreground color for fonts +extern color_t tft_bg; // current background for non transparent fonts +extern dispWin_t tft_dispWin; // display clip window +extern float tft_angleOffset; // angle offset for arc, polygon and line by angle functions +extern uint8_t tft_image_debug; // print debug messages during image decode if set to 1 + +extern Font tft_cfont; // Current font structure + +extern int tft_x; // X position of the next character after TFT_print() function +extern int tft_y; // Y position of the next character after TFT_print() function + +extern uint32_t tft_tp_calx; // touch screen X calibration constant +extern uint32_t tft_tp_caly; // touch screen Y calibration constant +// ========================================================================================= + + +// Buffer is created during jpeg decode for sending data +// Total size of the buffer is 2 * (JPG_IMAGE_LINE_BUF_SIZE * 3) +// The size must be multiple of 256 bytes !! +#define JPG_IMAGE_LINE_BUF_SIZE 512 + +// --- Constants for ellipse function --- +#define TFT_ELLIPSE_UPPER_RIGHT 0x01 +#define TFT_ELLIPSE_UPPER_LEFT 0x02 +#define TFT_ELLIPSE_LOWER_LEFT 0x04 +#define TFT_ELLIPSE_LOWER_RIGHT 0x08 + +// Constants for Arc function +// number representing the maximum angle (e.g. if 100, then if you pass in start=0 and end=50, you get a half circle) +// this can be changed with setArcParams function at runtime +#define DEFAULT_ARC_ANGLE_MAX 360 +// rotational offset in degrees defining position of value 0 (-90 will put it at the top of circle) +// this can be changed with setAngleOffset function at runtime +#define DEFAULT_ANGLE_OFFSET -90 + +#define PI 3.14159265359 + +#define MIN_POLIGON_SIDES 3 +#define MAX_POLIGON_SIDES 60 + +// === Color names constants === +extern const color_t TFT_BLACK; +extern const color_t TFT_NAVY; +extern const color_t TFT_DARKGREEN; +extern const color_t TFT_DARKCYAN; +extern const color_t TFT_MAROON; +extern const color_t TFT_PURPLE; +extern const color_t TFT_OLIVE; +extern const color_t TFT_LIGHTGREY; +extern const color_t TFT_DARKGREY; +extern const color_t TFT_BLUE; +extern const color_t TFT_GREEN; +extern const color_t TFT_CYAN; +extern const color_t TFT_RED; +extern const color_t TFT_MAGENTA; +extern const color_t TFT_YELLOW; +extern const color_t TFT_WHITE; +extern const color_t TFT_ORANGE; +extern const color_t TFT_GREENYELLOW; +extern const color_t TFT_PINK; + +// === Color invert constants === +#define INVERT_ON 1 +#define INVERT_OFF 0 + +// === Special coordinates constants === +#define CENTER -9003 +#define RIGHT -9004 +#define BOTTOM -9004 + +#define LASTX 7000 +#define LASTY 8000 + +// === Embedded fonts constants === +#define DEFAULT_FONT 0 +#define DEJAVU18_FONT 1 +#define DEJAVU24_FONT 2 +#define UBUNTU16_FONT 3 +#define COMIC24_FONT 4 +#define MINYA24_FONT 5 +#define TOONEY32_FONT 6 +#define SMALL_FONT 7 +#define DEF_SMALL_FONT 8 +#define FONT_7SEG 9 +#define USER_FONT 10 // font will be read from file + + + +// ===== PUBLIC FUNCTIONS ========================================================================= + + +/* + * Draw pixel at given x,y coordinates + * + * Params: + * x: horizontal position + * y: vertical position + * color: pixel color + * sel: if not 0 activate CS before and deactivat after sending pixel data to display + * when sending multiple pixels it is faster to activate the CS first, + * send all pixels an deactivate CS after all pixela was sent +*/ +//------------------------------------------------------------------- +void TFT_drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel); + +/* + * Read pixel color value from display GRAM at given x,y coordinates + * + * Params: + * x: horizontal position + * y: vertical position + * + * Returns: + * pixel color at x,y +*/ +//------------------------------------------ +color_t TFT_readPixel(int16_t x, int16_t y); + +/* + * Draw vertical line at given x,y coordinates + * + * Params: + * x: horizontal start position + * y: vertical start position + * h: line height in pixels + * color: line color +*/ +//--------------------------------------------------------------------- +void TFT_drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color); + +/* + * Draw horizontal line at given x,y coordinates + * + * Params: + * x: horizontal start position + * y: vertical start position + * w: line width in pixels + * color: line color +*/ +//--------------------------------------------------------------------- +void TFT_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color); + +/* + * Draw line on screen + * + * Params: + * x0: horizontal start position + * y0: vertical start position + * x1: horizontal end position + * y1: vertical end position + * color: line color +*/ +//------------------------------------------------------------------------------- +void TFT_drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color); + + +/* + * Draw line on screen from (x,y) point at given angle + * Line drawing angle starts at lower right quadrant of the screen and is offseted by + * 'tft_angleOffset' global variable (default: -90 degrees) + * + * Params: + * x: horizontal start position + * y: vertical start position + * start: start offset from (x,y) + * len: length of the line + * angle: line angle in degrees + * color: line color +*/ +//----------------------------------------------------------------------------------------------------------- +void TFT_drawLineByAngle(uint16_t x, uint16_t y, uint16_t start, uint16_t len, uint16_t angle, color_t color); + +/* + * Fill given rectangular screen region with color + * + * Params: + * x: horizontal rect start position + * y: vertical rect start position + * w: rectangle width + * h: rectangle height + * color: fill color +*/ +//--------------------------------------------------------------------------- +void TFT_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color); + +/* + * Draw rectangle on screen + * + * Params: + * x: horizontal rect start position + * y: vertical rect start position + * w: rectangle width + * h: rectangle height + * color: rect line color +*/ +//------------------------------------------------------------------------------ +void TFT_drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color); + +/* + * Draw rectangle with rounded corners on screen + * + * Params: + * x: horizontal rect start position + * y: vertical rect start position + * w: rectangle width + * h: rectangle height + * r: corner radius + * color: rectangle color +*/ +//---------------------------------------------------------------------------------------------- +void TFT_drawRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color); + +/* + * Fill given rectangular screen region with rounded corners with color + * + * Params: + * x: horizontal rect start position + * y: vertical rect start position + * w: rectangle width + * h: rectangle height + * r: corner radius + * color: fill color +*/ +//---------------------------------------------------------------------------------------------- +void TFT_fillRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color); + +/* + * Fill the whole screen with color + * + * Params: + * color: fill color +*/ +//-------------------------------- +void TFT_fillScreen(color_t color); + +/* + * Fill the current clip window with color + * + * Params: + * color: fill color +*/ +//--------------------------------- +void TFT_fillWindow(color_t color); + +/* + * Draw triangle on screen + * + * Params: + * x0: first triangle point x position + * y0: first triangle point y position + * x0: second triangle point x position + * y0: second triangle point y position + * x0: third triangle point x position + * y0: third triangle point y position + * color: triangle color +*/ +//----------------------------------------------------------------------------------------------------------------- +void TFT_drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color); + +/* + * Fill triangular screen region with color + * + * Params: + * x0: first triangle point x position + * y0: first triangle point y position + * x0: second triangle point x position + * y0: second triangle point y position + * x0: third triangle point x position + * y0: third triangle point y position + * color: fill color +*/ +//----------------------------------------------------------------------------------------------------------------- +void TFT_fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color); + +/* + * Draw circle on screen + * + * Params: + * x: circle center x position + * y: circle center x position + * r: circle radius + * color: circle color +*/ +//------------------------------------------------------------------- +void TFT_drawCircle(int16_t x, int16_t y, int radius, color_t color); + +/* + * Fill circle on screen with color + * + * Params: + * x: circle center x position + * y: circle center x position + * r: circle radius + * color: circle fill color +*/ +//------------------------------------------------------------------- +void TFT_fillCircle(int16_t x, int16_t y, int radius, color_t color); + +/* + * Draw ellipse on screen + * + * Params: + * x0: ellipse center x position + * y0: ellipse center x position + * rx: ellipse horizontal radius + * ry: ellipse vertical radius + * option: drawing options, multiple options can be combined + 1 (TFT_ELLIPSE_UPPER_RIGHT) draw upper right corner + 2 (TFT_ELLIPSE_UPPER_LEFT) draw upper left corner + 4 (TFT_ELLIPSE_LOWER_LEFT) draw lower left corner + 8 (TFT_ELLIPSE_LOWER_RIGHT) draw lower right corner + to draw the whole ellipse use option value 15 (1 | 2 | 4 | 8) + * + * color: circle color +*/ +//------------------------------------------------------------------------------------------------------ +void TFT_drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option); + +/* + * Fill elliptical region on screen + * + * Params: + * x0: ellipse center x position + * y0: ellipse center x position + * rx: ellipse horizontal radius + * ry: ellipse vertical radius + * option: drawing options, multiple options can be combined + 1 (TFT_ELLIPSE_UPPER_RIGHT) fill upper right corner + 2 (TFT_ELLIPSE_UPPER_LEFT) fill upper left corner + 4 (TFT_ELLIPSE_LOWER_LEFT) fill lower left corner + 8 (TFT_ELLIPSE_LOWER_RIGHT) fill lower right corner + to fill the whole ellipse use option value 15 (1 | 2 | 4 | 8) + * + * color: fill color +*/ +//------------------------------------------------------------------------------------------------------ +void TFT_fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option); + + +/* + * Draw circle arc on screen + * Arc drawing angle starts at lower right quadrant of the screen and is offseted by + * 'tft_angleOffset' global variable (default: -90 degrees) + * + * Params: + * cx: arc center X position + * cy: arc center Y position + * th: thickness of the drawn arc + * ry: arc vertical radius + * start: arc start angle in degrees + * end: arc end angle in degrees + * color: arc outline color + * fillcolor: arc fill color +*/ +//---------------------------------------------------------------------------------------------------------------------------- +void TFT_drawArc(uint16_t cx, uint16_t cy, uint16_t r, uint16_t th, float start, float end, color_t color, color_t fillcolor); + + +/* + * Draw polygon on screen + * + * Params: + * cx: polygon center X position + * cy: arc center Y position + * sides: number of polygon sides; MAX_POLIGON_SIDES ~ MAX_POLIGON_SIDES (3 ~ 60) + * diameter: diameter of the circle inside which the polygon is drawn + * color: polygon outline color + * fill: polygon fill color; if same as color, polygon is not filled + * deg: polygon rotation angle; 0 ~ 360 + * th: thickness of the polygon outline +*/ +//-------------------------------------------------------------------------------------------------------------- +void TFT_drawPolygon(int cx, int cy, int sides, int diameter, color_t color, color_t fill, int deg, uint8_t th); + + +//-------------------------------------------------------------------------------------- +//void TFT_drawStar(int cx, int cy, int diameter, color_t color, bool fill, float factor); + + +/* + * Set the font used for writing the text to display. + * + * ------------------------------------------------------------------------------------ + * For 7 segment font only characters 0,1,2,3,4,5,6,7,8,9, . , - , : , / are available. + * Character ‘/‘ draws the degree sign. + * ------------------------------------------------------------------------------------ + * + * Params: + * font: font number; use defined font names + * font_file: pointer to font file name; NULL for embeded fonts + */ +//---------------------------------------------------- +void TFT_setFont(uint8_t font, const char *font_file); + +/* + * Returns current font height & width in pixels. + * + * Params: + * width: pointer to returned font width + * height: pointer to returned font height + */ +//------------------------------------------- +int TFT_getfontsize(int *width, int* height); + + +/* + * Returns current font height in pixels. + * + */ +//---------------------- +int TFT_getfontheight(); + +/* + * Write text to display. + * + * Rotation of the displayed text depends on 'tft_font_rotate' variable (0~360) + * if 'tft_font_transparent' variable is set to 1, no background pixels will be printed + * + * If the text does not fit the screen width it will be clipped (if tft_text_wrap=0), + * or continued on next line (if tft_text_wrap=1) + * + * Two special characters are allowed in strings: + * ‘\r’ CR (0x0D), clears the display to EOL + * ‘\n’ LF (ox0A), continues to the new line, x=0 + * + * Params: + * st: pointer to null terminated string to be printed + * x: horizontal position of the upper left point in pixels + * Special values can be entered: + * CENTER, centers the text + * RIGHT, right justifies the text + * LASTX, continues from last X position; offset can be used: LASTX+n + * y: vertical position of the upper left point in pixels + * Special values can be entered: + * CENTER, centers the text + * BOTTOM, bottom justifies the text + * LASTY, continues from last Y position; offset can be used: LASTY+n + * + */ +//------------------------------------- +void TFT_print(char *st, int x, int y); + +/* + * Set atributes for 7 segment vector font + * == 7 segment font must be the current font to this function to have effect == + * + * Params: + * l: 6~40; distance between bars in pixels + * w: 1~12, max l/2; bar width in pixels + * outline: draw font outline if set to 1 + * color: font outline color, only used if outline=1 + * + */ +//------------------------------------------------------------------------- +void set_7seg_font_atrib(uint8_t l, uint8_t w, int outline, color_t color); + +/* + * Sets the clipping area coordinates. + * All writing to screen is clipped to that area. + * Starting x & y in all functions will be adjusted to the clipping area. + * + * Params: + * x1,y1: upper left point of the clipping area + * x2,y2: bottom right point of the clipping area + * + */ +//---------------------------------------------------------------------- +void TFT_setclipwin(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); + +/* + * Resets the clipping area to full screen (0,0),(_wodth,tft_height) + * + */ +//---------------------- +void TFT_resetclipwin(); + +/* + * Save current clipping area to temporary variable + * + */ +//--------------------- +void TFT_saveClipWin(); + +/* + * Restore current clipping area from temporary variable + * + */ +//------------------------ +void TFT_restoreClipWin(); + +/* + * Set the screen rotation + * Also resets the clip window and clears the screen with current background color + * + * Params: + * rot: 0~3; screen rotation; use defined rotation constants: + * PORTRAIT, LANDSCAPE, PORTRAIT_FLIP, LANDSCAPE_FLIP + * + */ +//-------------------------------- +void TFT_setRotation(uint8_t rot); + +/* + * Set inverted/normal colors + * + * Params: + * mode: 0 or 1; use defined constants: INVERT_ON or INVERT_OFF + * + */ +//----------------------------------------- +void TFT_invertDisplay(const uint8_t mode); + +/* + * Select gamma curve + * Params: + * gamma: gama curve, values 0~3 + */ +//================================= +void TFT_setGammaCurve(uint8_t gm); + +/* + * Compare two color structures + * Returns 0 if equal, 1 if not equal + * + * Params: + * c1, c2: colors to be compared + */ +//--------------------------------------------- +int TFT_compare_colors(color_t c1, color_t c2); + +/* + * returns the string width in pixels. + * Useful for positions strings on the screen. + */ +//-------------------------------- +int TFT_getStringWidth(char* str); + + +/* + * Fills the rectangle occupied by string with current background color + */ +void TFT_clearStringRect(int x, int y, char *str); + +/* + * Converts the components of a color, as specified by the HSB model, + * to an equivalent set of values for the default RGB model. + + * The color structure that is returned by HSBtoRGB encodes the value of a color as R, G & B component + * + * Params: + * _hue: float; any number, the floor of this number is subtracted from it to create a fraction between 0 and 1. + * This fractional number is then multiplied by 360 to produce the hue angle in the HSB color model. + * _sat: float; 0 ~ 1.0 + * _brightness: float; 0 ~ 1.0 + * +*/ +//---------------------------------------------------------- +color_t HSBtoRGB(float _hue, float _sat, float _brightness); + +/* + * Decodes and displays JPG image + * Limits: + * Baseline only. Progressive and Lossless JPEG format are not supported. + * Image size: Up to 65520 x 65520 pixels + * Color space: YCbCr three components only. Gray scale image is not supported. + * Sampling factor: 4:4:4, 4:2:2 or 4:2:0. + * + * Params: + * x: image left position; constants CENTER & RIGHT can be used; negative value is accepted + * y: image top position; constants CENTER & BOTTOM can be used; negative value is accepted + * scale: image scale factor: 0~3; if scale>0, image is scaled by factor 1/(2^scale) (1/2, 1/4 or 1/8) + * fname: pointer to the name of the file from which the image will be read + * if set to NULL, image will be read from memory buffer pointed to by 'buf' + * buf: pointer to the memory buffer from which the image will be read; used if fname=NULL + * size: size of the memory buffer from which the image will be read; used if fname=NULL & buf!=NULL + * + */ +//----------------------------------------------------------------------------------- +void TFT_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size); + +/* + * Decodes and displays BMP image + * Only uncompressed RGB 24-bit with no color space information BMP images can be displayed + * + * Params: + * x: image left position; constants CENTER & RIGHT can be used; negative value is accepted + * y: image top position; constants CENTER & BOTTOM can be used; negative value is accepted + * scale: image scale factor: 0~7; if scale>0, image is scaled by factor 1/(scale+1) + * fname: pointer to the name of the file from which the image will be read + * if set to NULL, image will be read from memory buffer pointed to by 'imgbuf' + * imgbuf: pointer to the memory buffer from which the image will be read; used if fname=NULL + * size: size of the memory buffer from which the image will be read; used if fname=NULL & imgbuf!=NULL + * + */ +//------------------------------------------------------------------------------------- +int TFT_bmp_image(int x, int y, uint8_t scale, char *fname, uint8_t *imgbuf, int size); + +/* + * Get the touch panel coordinates. + * The coordinates are adjusted to screen tft_orientation if raw=0 + * + * Params: + * x: pointer to X coordinate + * y: pointer to Y coordinate + * raw: if 0 returns calibrated screen coordinates; if 1 returns raw touch controller coordinates + * + * Returns: + * 0 if touch panel is not touched; x=y=0 + * 1 if touch panel is touched; x&y are the valid coordinates + */ +//---------------------------------------------- +int TFT_read_touch(int *x, int* y, uint8_t raw); + + +/* + * Compile font c source file to .fnt file + * which can be used in TFT_setFont() function to select external font + * Created file have the same name as source file and extension .fnt + * + * Params: + * fontfile: pointer to c source font file name; must have .c extension + * dbg: if set to 1, prints debug information + * + * Returns: + * 0 on success + * err no on error + * + */ +//------------------------------------------------ +int compile_font_file(char *fontfile, uint8_t dbg); + +/* + * Get all font's characters to buffer + */ +void getFontCharacters(uint8_t *buf); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/tft/tftspi.c b/components/tft/tftspi.c new file mode 100644 index 0000000..d9e6e2b --- /dev/null +++ b/components/tft/tftspi.c @@ -0,0 +1,947 @@ +/* + * Author: LoBo (loboris@gmail.com, loboris.github) + * + * Module supporting SPI TFT displays based on ILI9341 & ILI9488 controllers + * + * HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS + * USING DIRECT or DMA SPI TRANSFER MODEs + * +*/ + +#include +#include "tftspi.h" +#include "freertos/task.h" +#include "soc/spi_reg.h" +#include "driver/gpio.h" + + +// ==================================================== +// ==== Global variables, default values ============== + +// Converts colors to grayscale if set to 1 +uint8_t tft_gray_scale = 0; +// Spi clock for reading data from display memory in Hz +uint32_t tft_max_rdclock = 8000000; + +// Default display dimensions +int tft_width = DEFAULT_TFT_DISPLAY_WIDTH; +int tft_height = DEFAULT_TFT_DISPLAY_HEIGHT; + +// Display type, DISP_TYPE_ILI9488 or DISP_TYPE_ILI9341 +uint8_t tft_disp_type = DEFAULT_DISP_TYPE; + +// Spi device handles for display and touch screen +spi_lobo_device_handle_t tft_disp_spi = NULL; +spi_lobo_device_handle_t tft_ts_spi = NULL; + +// ==================================================== + + +static color_t *trans_cline = NULL; +static uint8_t _dma_sending = 0; + +// RGB to GRAYSCALE constants +// 0.2989 0.5870 0.1140 +#define GS_FACT_R 0.2989 +#define GS_FACT_G 0.4870 +#define GS_FACT_B 0.2140 + + + +// ==== Functions ===================== + +//------------------------------------------------------ +esp_err_t IRAM_ATTR wait_trans_finish(uint8_t free_line) +{ + // Wait for SPI bus ready + while (tft_disp_spi->host->hw->cmd.usr); + if ((free_line) && (trans_cline)) { + free(trans_cline); + trans_cline = NULL; + } + if (_dma_sending) { + //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset. + if (tft_disp_spi->host->dma_chan) spi_lobo_dmaworkaround_idle(tft_disp_spi->host->dma_chan); + + // Reset DMA + tft_disp_spi->host->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST; + tft_disp_spi->host->hw->dma_out_link.start=0; + tft_disp_spi->host->hw->dma_in_link.start=0; + tft_disp_spi->host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST); + tft_disp_spi->host->hw->dma_conf.out_data_burst_en=1; + _dma_sending = 0; + } + return ESP_OK; +} + +//------------------------------- +esp_err_t IRAM_ATTR disp_select() +{ + wait_trans_finish(1); + return spi_lobo_device_select(tft_disp_spi, 0); +} + +//--------------------------------- +esp_err_t IRAM_ATTR disp_deselect() +{ + wait_trans_finish(1); + return spi_lobo_device_deselect(tft_disp_spi); +} + +//--------------------------------------------------------------------------------------------------- +static void IRAM_ATTR _spi_transfer_start(spi_lobo_device_handle_t spi_dev, int wrbits, int rdbits) { + // Load send buffer + spi_dev->host->hw->user.usr_mosi_highpart = 0; + spi_dev->host->hw->mosi_dlen.usr_mosi_dbitlen = wrbits-1; + spi_dev->host->hw->user.usr_mosi = 1; + if (rdbits) { + spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = rdbits; + spi_dev->host->hw->user.usr_miso = 1; + } + else { + spi_dev->host->hw->miso_dlen.usr_miso_dbitlen = 0; + spi_dev->host->hw->user.usr_miso = 0; + } + // Start transfer + spi_dev->host->hw->cmd.usr = 1; + // Wait for SPI bus ready + while (spi_dev->host->hw->cmd.usr); +} + +// Send 1 byte display command, display must be selected +//------------------------------------------------ +void IRAM_ATTR disp_spi_transfer_cmd(int8_t cmd) { + // Wait for SPI bus ready + while (tft_disp_spi->host->hw->cmd.usr); + + // Set DC to 0 (command mode); + gpio_set_level(PIN_NUM_DC, 0); + + tft_disp_spi->host->hw->data_buf[0] = (uint32_t)cmd; + _spi_transfer_start(tft_disp_spi, 8, 0); +} + +// Send command with data to display, display must be selected +//---------------------------------------------------------------------------------- +void IRAM_ATTR disp_spi_transfer_cmd_data(int8_t cmd, uint8_t *data, uint32_t len) { + // Wait for SPI bus ready + while (tft_disp_spi->host->hw->cmd.usr); + + // Set DC to 0 (command mode); + gpio_set_level(PIN_NUM_DC, 0); + + tft_disp_spi->host->hw->data_buf[0] = (uint32_t)cmd; + _spi_transfer_start(tft_disp_spi, 8, 0); + + if ((len == 0) || (data == NULL)) return; + + // Set DC to 1 (data mode); + gpio_set_level(PIN_NUM_DC, 1); + + uint8_t idx=0, bidx=0; + uint32_t bits=0; + uint32_t count=0; + uint32_t wd = 0; + while (count < len) { + // get data byte from buffer + wd |= (uint32_t)data[count] << bidx; + count++; + bits += 8; + bidx += 8; + if (count == len) { + tft_disp_spi->host->hw->data_buf[idx] = wd; + break; + } + if (bidx == 32) { + tft_disp_spi->host->hw->data_buf[idx] = wd; + idx++; + bidx = 0; + wd = 0; + } + if (idx == 16) { + // SPI buffer full, send data + _spi_transfer_start(tft_disp_spi, bits, 0); + + bits = 0; + idx = 0; + bidx = 0; + } + } + if (bits > 0) _spi_transfer_start(tft_disp_spi, bits, 0); +} + +// Set the address window for display write & read commands, display must be selected +//--------------------------------------------------------------------------------------------------- +static void IRAM_ATTR disp_spi_transfer_addrwin(uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2) { + uint32_t wd; + + taskDISABLE_INTERRUPTS(); + // Wait for SPI bus ready + while (tft_disp_spi->host->hw->cmd.usr); + gpio_set_level(PIN_NUM_DC, 0); + + tft_disp_spi->host->hw->data_buf[0] = (uint32_t)TFT_CASET; + tft_disp_spi->host->hw->user.usr_mosi_highpart = 0; + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7; + tft_disp_spi->host->hw->user.usr_mosi = 1; + tft_disp_spi->host->hw->miso_dlen.usr_miso_dbitlen = 0; + tft_disp_spi->host->hw->user.usr_miso = 0; + + tft_disp_spi->host->hw->cmd.usr = 1; // Start transfer + + wd = (uint32_t)(x1>>8); + wd |= (uint32_t)(x1&0xff) << 8; + wd |= (uint32_t)(x2>>8) << 16; + wd |= (uint32_t)(x2&0xff) << 24; + + while (tft_disp_spi->host->hw->cmd.usr); // wait transfer end + gpio_set_level(PIN_NUM_DC, 1); + tft_disp_spi->host->hw->data_buf[0] = wd; + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 31; + tft_disp_spi->host->hw->cmd.usr = 1; // Start transfer + + while (tft_disp_spi->host->hw->cmd.usr); + gpio_set_level(PIN_NUM_DC, 0); + tft_disp_spi->host->hw->data_buf[0] = (uint32_t)TFT_PASET; + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7; + tft_disp_spi->host->hw->cmd.usr = 1; // Start transfer + + wd = (uint32_t)(y1>>8); + wd |= (uint32_t)(y1&0xff) << 8; + wd |= (uint32_t)(y2>>8) << 16; + wd |= (uint32_t)(y2&0xff) << 24; + + while (tft_disp_spi->host->hw->cmd.usr); + gpio_set_level(PIN_NUM_DC, 1); + + tft_disp_spi->host->hw->data_buf[0] = wd; + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 31; + tft_disp_spi->host->hw->cmd.usr = 1; // Start transfer + while (tft_disp_spi->host->hw->cmd.usr); + taskENABLE_INTERRUPTS(); +} + +// Convert color to gray scale +//---------------------------------------------- +static color_t IRAM_ATTR color2gs(color_t color) +{ + color_t _color; + float gs_clr = GS_FACT_R * color.r + GS_FACT_G * color.g + GS_FACT_B * color.b; + if (gs_clr > 255) gs_clr = 255; + + _color.r = (uint8_t)gs_clr; + _color.g = (uint8_t)gs_clr; + _color.b = (uint8_t)gs_clr; + + return _color; +} + +// Set display pixel at given coordinates to given color +//------------------------------------------------------------------------ +void IRAM_ATTR drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel) +{ + if (!(tft_disp_spi->cfg.flags & LB_SPI_DEVICE_HALFDUPLEX)) return; + + if (sel) { + if (disp_select()) return; + } + else wait_trans_finish(1); + + uint32_t wd = 0; + color_t _color = color; + if (tft_gray_scale) _color = color2gs(color); + + taskDISABLE_INTERRUPTS(); + disp_spi_transfer_addrwin(x, x+1, y, y+1); + + // Send RAM WRITE command + gpio_set_level(PIN_NUM_DC, 0); + tft_disp_spi->host->hw->data_buf[0] = (uint32_t)TFT_RAMWR; + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7; + tft_disp_spi->host->hw->cmd.usr = 1; // Start transfer + while (tft_disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready + + wd = (uint32_t)_color.r; + wd |= (uint32_t)_color.g << 8; + wd |= (uint32_t)_color.b << 16; + + // Set DC to 1 (data mode); + gpio_set_level(PIN_NUM_DC, 1); + + tft_disp_spi->host->hw->data_buf[0] = wd; + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 23; + tft_disp_spi->host->hw->cmd.usr = 1; // Start transfer + while (tft_disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready + + taskENABLE_INTERRUPTS(); + if (sel) disp_deselect(); +} + +//----------------------------------------------------------- +static void IRAM_ATTR _dma_send(uint8_t *data, uint32_t size) +{ + //Fill DMA descriptors + spi_lobo_dmaworkaround_transfer_active(tft_disp_spi->host->dma_chan); //mark channel as active + spi_lobo_setup_dma_desc_links(tft_disp_spi->host->dmadesc_tx, size, data, false); + tft_disp_spi->host->hw->user.usr_mosi_highpart=0; + tft_disp_spi->host->hw->dma_out_link.addr=(int)(&tft_disp_spi->host->dmadesc_tx[0]) & 0xFFFFF; + tft_disp_spi->host->hw->dma_out_link.start=1; + tft_disp_spi->host->hw->user.usr_mosi_highpart=0; + + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = (size * 8) - 1; + + _dma_sending = 1; + // Start transfer + tft_disp_spi->host->hw->cmd.usr = 1; +} + +//--------------------------------------------------------------------------- +static void IRAM_ATTR _direct_send(color_t *color, uint32_t len, uint8_t rep) +{ + uint32_t cidx = 0; // color buffer index + uint32_t wd = 0; + int idx = 0; + int bits = 0; + int wbits = 0; + + taskDISABLE_INTERRUPTS(); + color_t _color = color[0]; + if ((rep) && (tft_gray_scale)) _color = color2gs(color[0]); + + while (len) { + // ** Get color data from color buffer ** + if (rep == 0) { + if (tft_gray_scale) _color = color2gs(color[cidx]); + else _color = color[cidx]; + } + + wd |= (uint32_t)_color.r << wbits; + wbits += 8; + if (wbits == 32) { + bits += wbits; + wbits = 0; + tft_disp_spi->host->hw->data_buf[idx++] = wd; + wd = 0; + } + wd |= (uint32_t)_color.g << wbits; + wbits += 8; + if (wbits == 32) { + bits += wbits; + wbits = 0; + tft_disp_spi->host->hw->data_buf[idx++] = wd; + wd = 0; + } + wd |= (uint32_t)_color.b << wbits; + wbits += 8; + if (wbits == 32) { + bits += wbits; + wbits = 0; + tft_disp_spi->host->hw->data_buf[idx++] = wd; + wd = 0; + } + len--; // Decrement colors counter + if (rep == 0) cidx++; // if not repeating color, increment color buffer index + } + if (bits) { + while (tft_disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1; // set number of bits to be sent + tft_disp_spi->host->hw->cmd.usr = 1; // Start transfer + } + taskENABLE_INTERRUPTS(); +} + +// ================================================================ +// === Main function to send data to display ====================== +// If rep==true: repeat sending color data to display 'len' times +// If rep==false: send 'len' color data from color buffer to display +// ** Device must already be selected and address window set ** +// ================================================================ +//---------------------------------------------------------------------------------------------- +static void IRAM_ATTR _TFT_pushColorRep(color_t *color, uint32_t len, uint8_t rep, uint8_t wait) +{ + if (len == 0) return; + if (!(tft_disp_spi->cfg.flags & LB_SPI_DEVICE_HALFDUPLEX)) return; + + // Send RAM WRITE command + gpio_set_level(PIN_NUM_DC, 0); + tft_disp_spi->host->hw->data_buf[0] = (uint32_t)TFT_RAMWR; + tft_disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7; + tft_disp_spi->host->hw->cmd.usr = 1; // Start transfer + while (tft_disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready + + gpio_set_level(PIN_NUM_DC, 1); // Set DC to 1 (data mode); + + if ((len*24) <= 512) { + + _direct_send(color, len, rep); + + } + else if (rep == 0) { + // ==== use DMA transfer ==== + // ** Prepare data + if (tft_gray_scale) { + for (int n=0; n 0) { + wait_trans_finish(0); + _direct_send(color, ((to_send > 21) ? 21 : to_send), rep); + to_send -= 21; + } + */ + + buf_colors = ((len > (tft_width*2)) ? (tft_width*2) : len); + buf_bytes = buf_colors * 3; + + // Prepare color buffer of maximum 2 color lines + trans_cline = heap_caps_malloc(buf_bytes, MALLOC_CAP_DMA); + if (trans_cline == NULL) return; + + // Prepare fill color + if (tft_gray_scale) _color = color2gs(color[0]); + else _color = color[0]; + + // Fill color buffer with fill color + for (uint32_t i=0; i 0) { + wait_trans_finish(0); + _dma_send((uint8_t *)trans_cline, ((to_send > buf_colors) ? buf_bytes : (to_send*3))); + to_send -= buf_colors; + } + } + + if (wait) wait_trans_finish(1); +} + +// Write 'len' color data to TFT 'window' (x1,y2),(x2,y2) +//------------------------------------------------------------------------------------------- +void IRAM_ATTR TFT_pushColorRep(int x1, int y1, int x2, int y2, color_t color, uint32_t len) +{ + if (disp_select() != ESP_OK) return; + + // ** Send address window ** + disp_spi_transfer_addrwin(x1, x2, y1, y2); + + _TFT_pushColorRep(&color, len, 1, 1); + + disp_deselect(); +} + +// Write 'len' color data to TFT 'window' (x1,y2),(x2,y2) from given buffer +// ** Device must already be selected ** +//----------------------------------------------------------------------------------- +void IRAM_ATTR send_data(int x1, int y1, int x2, int y2, uint32_t len, color_t *buf) +{ + // ** Send address window ** + disp_spi_transfer_addrwin(x1, x2, y1, y2); + _TFT_pushColorRep(buf, len, 0, 0); +} + +// Reads 'len' pixels/colors from the TFT's GRAM 'window' +// 'buf' is an array of bytes with 1st byte reserved for reading 1 dummy byte +// and the rest is actually an array of color_t values +//-------------------------------------------------------------------------------------------- +int IRAM_ATTR read_data(int x1, int y1, int x2, int y2, int len, uint8_t *buf, uint8_t set_sp) +{ + spi_lobo_transaction_t t; + uint32_t current_clock = 0; + + memset(&t, 0, sizeof(t)); //Zero out the transaction + memset(buf, 0, len*sizeof(color_t)); + + if (set_sp) { + if (disp_deselect() != ESP_OK) return -1; + // Change spi clock if needed + current_clock = spi_lobo_get_speed(tft_disp_spi); + if (tft_max_rdclock < current_clock) spi_lobo_set_speed(tft_disp_spi, tft_max_rdclock); + } + + if (disp_select() != ESP_OK) return -2; + + // ** Send address window ** + disp_spi_transfer_addrwin(x1, x2, y1, y2); + + // ** GET pixels/colors ** + disp_spi_transfer_cmd(TFT_RAMRD); + + t.length=0; //Send nothing + t.tx_buffer=NULL; + t.rxlength=8*((len*3)+1); //Receive size in bits + t.rx_buffer=buf; + //t.user = (void*)1; + + esp_err_t res = spi_lobo_transfer_data(tft_disp_spi, &t); // Receive using direct mode + + disp_deselect(); + + if (set_sp) { + // Restore spi clock if needed + if (tft_max_rdclock < current_clock) spi_lobo_set_speed(tft_disp_spi, current_clock); + } + + return res; +} + +// Reads one pixel/color from the TFT's GRAM at position (x,y) +//----------------------------------------------- +color_t IRAM_ATTR readPixel(int16_t x, int16_t y) +{ + uint8_t color_buf[sizeof(color_t)+1] = {0}; + + read_data(x, y, x+1, y+1, 1, color_buf, 1); + + color_t color; + color.r = color_buf[1]; + color.g = color_buf[2]; + color.b = color_buf[3]; + return color; +} + +// get 16-bit data from touch controller for specified type +// ** Touch device must already be selected ** +//---------------------------------------- +int IRAM_ATTR touch_get_data(uint8_t type) +{ + /* + esp_err_t ret; + spi_lobo_transaction_t t; + memset(&t, 0, sizeof(t)); //Zero out the transaction + uint8_t rxdata[2] = {0}; + + // send command byte & receive 2 byte response + t.rxlength=8*2; + t.rx_buffer=&rxdata; + t.command = type; + + ret = spi_lobo_transfer_data(tft_ts_spi, &t); // Transmit using direct mode + + if (ret != ESP_OK) return -1; + return (((int)(rxdata[0] << 8) | (int)(rxdata[1])) >> 4); + */ + spi_lobo_device_select(tft_ts_spi, 0); + + tft_ts_spi->host->hw->data_buf[0] = type; + _spi_transfer_start(tft_ts_spi, 24, 24); + uint16_t res = (uint16_t)(tft_ts_spi->host->hw->data_buf[0] >> 8); + + spi_lobo_device_deselect(tft_ts_spi); + + return res; +} + +// ==== STMPE610 =============================================================== + + +// ----- STMPE610 -------------------------------------------------------------------------- + +// Send 1 byte display command, display must be selected +//--------------------------------------------------------- +static void IRAM_ATTR stmpe610_write_reg(uint8_t reg, uint8_t val) { + + spi_lobo_device_select(tft_ts_spi, 0); + + tft_ts_spi->host->hw->data_buf[0] = (val << 8) | reg; + _spi_transfer_start(tft_ts_spi, 16, 0); + + spi_lobo_device_deselect(tft_ts_spi); +} + +//----------------------------------------------- +static uint8_t IRAM_ATTR stmpe610_read_byte(uint8_t reg) { + spi_lobo_device_select(tft_ts_spi, 0); + + tft_ts_spi->host->hw->data_buf[0] = (reg << 8) | (reg | 0x80); + _spi_transfer_start(tft_ts_spi, 16, 16); + uint8_t res = tft_ts_spi->host->hw->data_buf[0] >> 8; + + spi_lobo_device_deselect(tft_ts_spi); + return res; +} + +//----------------------------------------- +static uint16_t IRAM_ATTR stmpe610_read_word(uint8_t reg) { + spi_lobo_device_select(tft_ts_spi, 0); + + tft_ts_spi->host->hw->data_buf[0] = ((((reg+1) << 8) | ((reg+1) | 0x80)) << 16) | (reg << 8) | (reg | 0x80); + _spi_transfer_start(tft_ts_spi, 32, 32); + uint16_t res = (uint16_t)(tft_ts_spi->host->hw->data_buf[0] & 0xFF00); + res |= (uint16_t)(tft_ts_spi->host->hw->data_buf[0] >> 24); + + spi_lobo_device_deselect(tft_ts_spi); + return res; +} + +//----------------------- +uint32_t stmpe610_getID() +{ + uint16_t tid = stmpe610_read_word(0); + uint8_t tver = stmpe610_read_byte(2); + return (tid << 8) | tver; +} + +//================== +void stmpe610_Init() +{ + stmpe610_write_reg(STMPE610_REG_SYS_CTRL1, 0x02); // Software chip reset + vTaskDelay(10 / portTICK_RATE_MS); + + stmpe610_write_reg(STMPE610_REG_SYS_CTRL2, 0x04); // Temperature sensor clock off, GPIO clock off, touch clock on, ADC clock on + + stmpe610_write_reg(STMPE610_REG_INT_EN, 0x00); // Don't Interrupt on INT pin + + stmpe610_write_reg(STMPE610_REG_ADC_CTRL1, 0x48); // ADC conversion time = 80 clock ticks, 12-bit ADC, internal voltage refernce + vTaskDelay(2 / portTICK_RATE_MS); + stmpe610_write_reg(STMPE610_REG_ADC_CTRL2, 0x01); // ADC speed 3.25MHz + stmpe610_write_reg(STMPE610_REG_GPIO_AF, 0x00); // GPIO alternate function - OFF + stmpe610_write_reg(STMPE610_REG_TSC_CFG, 0xE3); // Averaging 8, touch detect delay 1ms, panel driver settling time 1ms + stmpe610_write_reg(STMPE610_REG_FIFO_TH, 0x01); // FIFO threshold = 1 + stmpe610_write_reg(STMPE610_REG_FIFO_STA, 0x01); // FIFO reset enable + stmpe610_write_reg(STMPE610_REG_FIFO_STA, 0x00); // FIFO reset disable + stmpe610_write_reg(STMPE610_REG_TSC_FRACT_XYZ, 0x07); // Z axis data format + stmpe610_write_reg(STMPE610_REG_TSC_I_DRIVE, 0x01); // max 50mA touchscreen line current + stmpe610_write_reg(STMPE610_REG_TSC_CTRL, 0x30); // X&Y&Z, 16 reading window + stmpe610_write_reg(STMPE610_REG_TSC_CTRL, 0x31); // X&Y&Z, 16 reading window, TSC enable + stmpe610_write_reg(STMPE610_REG_INT_STA, 0xFF); // Clear all interrupts + stmpe610_write_reg(STMPE610_REG_INT_CTRL, 0x00); // Level interrupt, disable interrupts +} + +//=========================================================== +int stmpe610_get_touch(uint16_t *x, uint16_t *y, uint16_t *z) +{ + if (!(stmpe610_read_byte(STMPE610_REG_TSC_CTRL) & 0x80)) return 0; + + // Get touch data + uint8_t fifo_size = stmpe610_read_byte(STMPE610_REG_FIFO_SIZE); + while (fifo_size < 2) { + if (!(stmpe610_read_byte(STMPE610_REG_TSC_CTRL) & 0x80)) return 0; + fifo_size = stmpe610_read_byte(STMPE610_REG_FIFO_SIZE); + } + while (fifo_size > 120) { + if (!(stmpe610_read_byte(STMPE610_REG_TSC_CTRL) & 0x80)) return 0; + *x = stmpe610_read_word(STMPE610_REG_TSC_DATA_X); + *y = stmpe610_read_word(STMPE610_REG_TSC_DATA_Y); + *z = stmpe610_read_byte(STMPE610_REG_TSC_DATA_Z); + fifo_size = stmpe610_read_byte(STMPE610_REG_FIFO_SIZE); + } + for (uint8_t i=0; i < (fifo_size-1); i++) { + *x = stmpe610_read_word(STMPE610_REG_TSC_DATA_X); + *y = stmpe610_read_word(STMPE610_REG_TSC_DATA_Y); + *z = stmpe610_read_byte(STMPE610_REG_TSC_DATA_Z); + } + + *x = 4096 - *x; + /* + // Clear the rest of the fifo + { + stmpe610_write_reg(STMPE610_REG_FIFO_STA, 0x01); // FIFO reset enable + stmpe610_write_reg(STMPE610_REG_FIFO_STA, 0x00); // FIFO reset disable + } + */ + return 1; +} + +// ==== STMPE610 =========================================================================== + + +// Find maximum spi clock for successful read from display RAM +// ** Must be used AFTER the display is initialized ** +//====================== +uint32_t find_rd_speed() +{ + esp_err_t ret; + color_t color; + uint32_t max_speed = 1000000; + uint32_t change_speed, cur_speed; + int line_check; + color_t *color_line = NULL; + uint8_t *line_rdbuf = NULL; + uint8_t gs = tft_gray_scale; + + tft_gray_scale = 0; + cur_speed = spi_lobo_get_speed(tft_disp_spi); + + color_line = malloc(tft_width*3); + if (color_line == NULL) goto exit; + + line_rdbuf = malloc((tft_width*3)+1); + if (line_rdbuf == NULL) goto exit; + + color_t *rdline = (color_t *)(line_rdbuf+1); + + // Fill test line with colors + color = (color_t){0xEC,0xA8,0x74}; + for (int x=0; x height + if (tft_width < tft_height) { + tmp = tft_width; + tft_width = tft_height; + tft_height = tmp; + } + } + else { + // in portrait modes must be width < height + if (tft_width > tft_height) { + tmp = tft_width; + tft_width = tft_height; + tft_height = tmp; + } + } + #if TFT_INVERT_ROTATION + switch (rotation) { + case PORTRAIT: + madctl = (MADCTL_MV | TFT_RGB_BGR); + break; + case LANDSCAPE: + madctl = (MADCTL_MX | TFT_RGB_BGR); + break; + case PORTRAIT_FLIP: + madctl = (MADCTL_MV | TFT_RGB_BGR); + break; + case LANDSCAPE_FLIP: + madctl = (MADCTL_MY | TFT_RGB_BGR); + break; + } + #elif TFT_INVERT_ROTATION1 + switch (rotation) { + case PORTRAIT: + madctl = (MADCTL_MY | MADCTL_MX | TFT_RGB_BGR); + break; + case LANDSCAPE: + madctl = (MADCTL_MY | MADCTL_MV | TFT_RGB_BGR); + break; + case PORTRAIT_FLIP: + madctl = (TFT_RGB_BGR); + break; + case LANDSCAPE_FLIP: + madctl = (MADCTL_MX | MADCTL_MV | TFT_RGB_BGR); + break; + } + #elif TFT_INVERT_ROTATION2 + switch (rotation) { + case PORTRAIT: + madctl = (MADCTL_MX | MADCTL_MV | TFT_RGB_BGR); + break; + case LANDSCAPE: + madctl = (TFT_RGB_BGR); + break; + case PORTRAIT_FLIP: + madctl = (MADCTL_MY | MADCTL_MV | TFT_RGB_BGR); + break; + case LANDSCAPE_FLIP: + madctl = (MADCTL_MY | MADCTL_MX | TFT_RGB_BGR); + break; + } + #else + switch (rotation) { + case PORTRAIT: + madctl = (MADCTL_MX | TFT_RGB_BGR); + break; + case LANDSCAPE: + madctl = (MADCTL_MV | TFT_RGB_BGR); + break; + case PORTRAIT_FLIP: + madctl = (MADCTL_MY | TFT_RGB_BGR); + break; + case LANDSCAPE_FLIP: + madctl = (MADCTL_MX | MADCTL_MY | MADCTL_MV | TFT_RGB_BGR); + break; + } + #endif + if (send) { + if (disp_select() == ESP_OK) { + disp_spi_transfer_cmd_data(TFT_MADCTL, &madctl, 1); + disp_deselect(); + } + } + +} + +//================= +void TFT_PinsInit() +{ + // Route all used pins to GPIO control + gpio_pad_select_gpio(PIN_NUM_CS); + gpio_pad_select_gpio(PIN_NUM_MISO); + gpio_pad_select_gpio(PIN_NUM_MOSI); + gpio_pad_select_gpio(PIN_NUM_CLK); + gpio_pad_select_gpio(PIN_NUM_DC); + + gpio_set_direction(PIN_NUM_MISO, GPIO_MODE_INPUT); + gpio_set_pull_mode(PIN_NUM_MISO, GPIO_PULLUP_ONLY); + gpio_set_direction(PIN_NUM_CS, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_NUM_MOSI, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_NUM_CLK, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT); + gpio_set_level(PIN_NUM_DC, 0); +#if USE_TOUCH + gpio_pad_select_gpio(PIN_NUM_TCS); + gpio_set_direction(PIN_NUM_TCS, GPIO_MODE_OUTPUT); +#endif +#if PIN_NUM_BCKL + gpio_pad_select_gpio(PIN_NUM_BCKL); + gpio_set_direction(PIN_NUM_BCKL, GPIO_MODE_OUTPUT); + gpio_set_level(PIN_NUM_BCKL, PIN_BCKL_OFF); +#endif + +#if PIN_NUM_RST + gpio_pad_select_gpio(PIN_NUM_RST); + gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT); + gpio_set_level(PIN_NUM_RST, 0); +#endif +} + +// Initialize the display +// ==================== +void TFT_display_init() +{ + esp_err_t ret; + +#if PIN_NUM_RST + //Reset the display + gpio_set_level(PIN_NUM_RST, 0); + vTaskDelay(20 / portTICK_RATE_MS); + gpio_set_level(PIN_NUM_RST, 1); + vTaskDelay(150 / portTICK_RATE_MS); +#endif + + ret = disp_select(); + assert(ret==ESP_OK); + //Send all the initialization commands + if (tft_disp_type == DISP_TYPE_ILI9341) { + commandList(tft_disp_spi, ILI9341_init); + } + else if (tft_disp_type == DISP_TYPE_ILI9488) { + commandList(tft_disp_spi, ILI9488_init); + } + else if (tft_disp_type == DISP_TYPE_ST7789V) { + commandList(tft_disp_spi, ST7789V_init); + } + else if (tft_disp_type == DISP_TYPE_ST7735) { + commandList(tft_disp_spi, STP7735_init); + } + else if (tft_disp_type == DISP_TYPE_ST7735R) { + commandList(tft_disp_spi, STP7735R_init); + commandList(tft_disp_spi, Rcmd2green); + commandList(tft_disp_spi, Rcmd3); + } + else if (tft_disp_type == DISP_TYPE_ST7735B) { + commandList(tft_disp_spi, STP7735R_init); + commandList(tft_disp_spi, Rcmd2red); + commandList(tft_disp_spi, Rcmd3); + uint8_t dt = 0xC0; + disp_spi_transfer_cmd_data(TFT_MADCTL, &dt, 1); + } + else assert(0); + + ret = disp_deselect(); + assert(ret==ESP_OK); + + // Clear screen + _tft_setRotation(PORTRAIT); + TFT_pushColorRep(TFT_STATIC_WIDTH_OFFSET, TFT_STATIC_HEIGHT_OFFSET, tft_width + TFT_STATIC_WIDTH_OFFSET -1, tft_height + TFT_STATIC_HEIGHT_OFFSET -1, (color_t){0,0,0}, (uint32_t)(tft_height*tft_width)); + + ///Enable backlight +#if PIN_NUM_BCKL + gpio_set_level(PIN_NUM_BCKL, PIN_BCKL_ON); +#endif +} + + diff --git a/components/tft/tftspi.h b/components/tft/tftspi.h new file mode 100644 index 0000000..fb689b0 --- /dev/null +++ b/components/tft/tftspi.h @@ -0,0 +1,751 @@ +/* + * + * HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS USING DIRECT TRANSFER MODE + * +*/ + +#ifndef _TFTSPI_H_ +#define _TFTSPI_H_ + +#include "tftspi.h" +#include "spi_master_lobo.h" +#include "sdkconfig.h" +#include "stmpe610.h" + +#define TOUCH_TYPE_NONE 0 +#define TOUCH_TYPE_XPT2046 1 +#define TOUCH_TYPE_STMPE610 2 + +#define TP_CALX_XPT2046 7472920 +#define TP_CALY_XPT2046 122224794 + +#define TP_CALX_STMPE610 21368532 +#define TP_CALY_STMPE610 11800144 + +// === Screen tft_orientation constants === +#define PORTRAIT 0 +#define LANDSCAPE 1 +#define PORTRAIT_FLIP 2 +#define LANDSCAPE_FLIP 3 + +#define DISP_TYPE_ILI9341 0 +#define DISP_TYPE_ILI9488 1 +#define DISP_TYPE_ST7789V 2 +#define DISP_TYPE_ST7735 3 +#define DISP_TYPE_ST7735R 4 +#define DISP_TYPE_ST7735B 5 + + + +#if CONFIG_TFT_PREDEFINED_DISPLAY_TYPE == 1 + +// ** Set the correct configuration for ESP-WROVER-KIT v3 +// -------------------------------------------------------- +#define DEFAULT_DISP_TYPE DISP_TYPE_ST7789V +#define DEFAULT_TFT_DISPLAY_WIDTH 240 +#define DEFAULT_TFT_DISPLAY_HEIGHT 320 +#define DISP_COLOR_BITS_24 0x66 +#define DEFAULT_GAMMA_CURVE 0 +#define DEFAULT_SPI_CLOCK 26000000 +#define TFT_INVERT_ROTATION 0 +#define TFT_INVERT_ROTATION1 1 +#define TFT_RGB_BGR 0x00 + +#define USE_TOUCH TOUCH_TYPE_NONE + +#define PIN_NUM_MISO 25 // SPI MISO +#define PIN_NUM_MOSI 23 // SPI MOSI +#define PIN_NUM_CLK 19 // SPI CLOCK pin +#define PIN_NUM_CS 22 // Display CS pin +#define PIN_NUM_DC 21 // Display command/data pin +#define PIN_NUM_TCS 0 // Touch screen CS pin + +#define PIN_NUM_RST 18 // GPIO used for RESET control +#define PIN_NUM_BCKL 5 // GPIO used for backlight control +#define PIN_BCKL_ON 0 // GPIO value for backlight ON +#define PIN_BCKL_OFF 1 // GPIO value for backlight OFF +// -------------------------------------------------------- + +#elif CONFIG_TFT_PREDEFINED_DISPLAY_TYPE == 2 + +// ** Set the correct configuration for Adafruit TFT Feather +// --------------------------------------------------------- +#define DEFAULT_DISP_TYPE DISP_TYPE_ILI9341 +#define DEFAULT_TFT_DISPLAY_WIDTH 240 +#define DEFAULT_TFT_DISPLAY_HEIGHT 320 +#define DISP_COLOR_BITS_24 0x66 +#define DEFAULT_GAMMA_CURVE 0 +#define DEFAULT_SPI_CLOCK 26000000 +#define TFT_INVERT_ROTATION 0 +#define TFT_INVERT_ROTATION1 0 +#define TFT_RGB_BGR 0x08 + +#define USE_TOUCH TOUCH_TYPE_STMPE610 + +#define PIN_NUM_MISO 19 // SPI MISO +#define PIN_NUM_MOSI 18 // SPI MOSI +#define PIN_NUM_CLK 5 // SPI CLOCK pin +#define PIN_NUM_CS 15 // Display CS pin +#define PIN_NUM_DC 33 // Display command/data pin +#define PIN_NUM_TCS 32 // Touch screen CS pin (NOT used if USE_TOUCH=0) + +#define PIN_NUM_RST 0 // GPIO used for RESET control (#16) +#define PIN_NUM_BCKL 0 // GPIO used for backlight control +#define PIN_BCKL_ON 0 // GPIO value for backlight ON +#define PIN_BCKL_OFF 1 // GPIO value for backlight OFF +// --------------------------------------------------------- + +#elif CONFIG_TFT_PREDEFINED_DISPLAY_TYPE == 3 + +// ** Set the correct configuration for M5Stack TFT +// --------------------------------------------------------- +#define DEFAULT_DISP_TYPE DISP_TYPE_ILI9341 +#define DEFAULT_TFT_DISPLAY_WIDTH 320 +#define DEFAULT_TFT_DISPLAY_HEIGHT 240 +#define DISP_COLOR_BITS_24 0x66 +#define DEFAULT_GAMMA_CURVE 0 +#define DEFAULT_SPI_CLOCK 26000000 +#define TFT_INVERT_ROTATION 0 +#define TFT_INVERT_ROTATION1 0 +#define TFT_INVERT_ROTATION2 1 // Adapte M5Stack TFT +#define TFT_RGB_BGR 0x08 + +#define USE_TOUCH TOUCH_TYPE_NONE + +#define PIN_NUM_MISO 19 // SPI MISO +#define PIN_NUM_MOSI 23 // SPI MOSI +#define PIN_NUM_CLK 18 // SPI CLOCK pin +#define PIN_NUM_CS 14 // Display CS pin +#define PIN_NUM_DC 27 // Display command/data pin +#define PIN_NUM_TCS 0 // Touch screen CS pin (NOT used if USE_TOUCH=0) + +#define PIN_NUM_RST 33 // GPIO used for RESET control (#16) +#define PIN_NUM_BCKL 32 // GPIO used for backlight control +#define PIN_BCKL_ON 1 // GPIO value for backlight ON +#define PIN_BCKL_OFF 0 // GPIO value for backlight OFF +// --------------------------------------------------------- + +#elif CONFIG_TFT_PREDEFINED_DISPLAY_TYPE == 4 + +// ** Set the correct configuration for ESP-WROVER-KIT v4.1 +// -------------------------------------------------------- +#define DEFAULT_DISP_TYPE DISP_TYPE_ILI9341 +#define DEFAULT_TFT_DISPLAY_WIDTH 240 +#define DEFAULT_TFT_DISPLAY_HEIGHT 320 +#define DISP_COLOR_BITS_24 0x66 +#define DEFAULT_GAMMA_CURVE 0 +#define DEFAULT_SPI_CLOCK 26000000 +#define TFT_INVERT_ROTATION 0 +#define TFT_INVERT_ROTATION1 0 +#define TFT_INVERT_ROTATION2 0 +#define TFT_RGB_BGR 0x08 + +#define USE_TOUCH TOUCH_TYPE_NONE + +#define PIN_NUM_MISO 25 // SPI MISO +#define PIN_NUM_MOSI 23 // SPI MOSI +#define PIN_NUM_CLK 19 // SPI CLOCK pin +#define PIN_NUM_CS 22 // Display CS pin +#define PIN_NUM_DC 21 // Display command/data pin +#define PIN_NUM_TCS 0 // Touch screen CS pin + +#define PIN_NUM_RST 18 // GPIO used for RESET control +#define PIN_NUM_BCKL 5 // GPIO used for backlight control +#define PIN_BCKL_ON 0 // GPIO value for backlight ON +#define PIN_BCKL_OFF 1 // GPIO value for backlight OFF +// -------------------------------------------------------- +#elif CONFIG_TFT_PREDEFINED_DISPLAY_TYPE == 5 +//CONFIG FOR TTGO T-DISPLAY +#define DEFAULT_DISP_TYPE DISP_TYPE_ST7789V +#define DEFAULT_TFT_DISPLAY_WIDTH 135 +#define DEFAULT_TFT_DISPLAY_HEIGHT 240 + +//Need to be defined together so they can be swapped for x;y when rotating +#define TFT_STATIC_WIDTH_OFFSET 53 +#define TFT_STATIC_HEIGHT_OFFSET 40 + +#define DISP_COLOR_BITS_24 0x66 +#define DEFAULT_GAMMA_CURVE 0 +#define DEFAULT_SPI_CLOCK 20000000 +#define TFT_INVERT_ROTATION 0 +#define TFT_INVERT_ROTATION1 1 +#define TFT_RGB_BGR 0x00 +//To be used by user application for initialization +#define TFT_START_COLORS_INVERTED + +#define USE_TOUCH TOUCH_TYPE_NONE + +#define PIN_NUM_MISO 0 // SPI MISO +#define PIN_NUM_MOSI 19 // SPI MOSI +#define PIN_NUM_CLK 18 // SPI CLOCK pin +#define PIN_NUM_CS 5 // Display CS pin +#define PIN_NUM_DC 16 // Display command/data pin +#define PIN_NUM_TCS 0 // Touch screen CS pin + +#define PIN_NUM_RST 23 // GPIO used for RESET control +#define PIN_NUM_BCKL 4 // GPIO used for backlight control +#define PIN_BCKL_ON 1 // GPIO value for backlight ON +#define PIN_BCKL_OFF 0 // GPIO value for backlight OFF +//END TTGO T_DISPLAY + +#else + +// Configuration for other boards, set the correct values for the display used +//---------------------------------------------------------------------------- +#define DISP_COLOR_BITS_24 0x66 +//#define DISP_COLOR_BITS_16 0x55 // Do not use! + +#define TFT_INVERT_ROTATION 0 +#define TFT_INVERT_ROTATION1 CONFIG_TFT_INVERT_ROTATION1 + +// ################################################ +// ### SET TO 0X00 FOR DISPLAYS WITH RGB MATRIX ### +// ### SET TO 0X08 FOR DISPLAYS WITH BGR MATRIX ### +// ### For ESP-WROWER-KIT set to 0x00 ### +// ################################################ + +#if CONFIG_TFT_RGB_BGR +#define TFT_RGB_BGR 0x00 +#else +#define TFT_RGB_BGR 0x08 +#endif + +// ############################################################## +// ### Define ESP32 SPI pins to which the display is attached ### +// ############################################################## + +// The pins configured here are the native spi pins for HSPI interface +// Any other valid pin combination can be used + +#define PIN_NUM_MISO CONFIG_TFT_PIN_NUM_MISO +#define PIN_NUM_MOSI CONFIG_TFT_PIN_NUM_MOSI +#define PIN_NUM_CLK CONFIG_TFT_PIN_NUM_CLK +#define PIN_NUM_CS CONFIG_TFT_PIN_NUM_CS +#define PIN_NUM_DC CONFIG_TFT_PIN_NUM_DC +#define PIN_NUM_TCS CONFIG_TFT_PIN_NUM_TCS +#define PIN_NUM_RST CONFIG_TFT_PIN_NUM_RST +#define PIN_NUM_BCKL CONFIG_TFT_PIN_NUM_BCKL + +#define PIN_BCKL_ON 0 // GPIO value for backlight ON +#define PIN_BCKL_OFF 1 // GPIO value for backlight OFF +// -------------------------------------------------------------- + +#define USE_TOUCH CONFIG_TFT_TOUCH_CONTROLLER + +// ####################################################################### +// Default display width (smaller dimension) and height (larger dimension) +// ####################################################################### +#define DEFAULT_TFT_DISPLAY_WIDTH CONFIG_TFT_DISPLAY_WIDTH +#define DEFAULT_TFT_DISPLAY_HEIGHT CONFIG_TFT_DISPLAY_HEIGHT +// ####################################################################### + +#define DEFAULT_GAMMA_CURVE 0 +#define DEFAULT_SPI_CLOCK 26000000 + +#if defined(CONFIG_TFT_DISPLAY_CONTROLLER_MODEL) +#define DEFAULT_DISP_TYPE CONFIG_TFT_DISPLAY_CONTROLLER_MODEL +#else +#define DEFAULT_DISP_TYPE DISP_TYPE_ILI9341 +#endif +//---------------------------------------------------------------------------- + +#endif // CONFIG_PREDEFINED_DISPLAY_TYPE + +// Define offset generation, or ignore offsets if none are needed +#ifdef TFT_STATIC_WIDTH_OFFSET +#define TFT_STATIC_X_OFFSET (tft_orientation & 1 ? TFT_STATIC_HEIGHT_OFFSET : TFT_STATIC_WIDTH_OFFSET) +#define TFT_STATIC_Y_OFFSET (tft_orientation & 1 ? TFT_STATIC_WIDTH_OFFSET : TFT_STATIC_HEIGHT_OFFSET) +#else +#define TFT_STATIC_WIDTH_OFFSET 0 +#define TFT_STATIC_X_OFFSET 0 +#define TFT_STATIC_HEIGHT_OFFSET 0 +#define TFT_STATIC_Y_OFFSET 0 +#endif + + +// ############################################################## +// #### Global variables #### +// ############################################################## + +// ==== Converts colors to grayscale if 1 ======================= +extern uint8_t tft_gray_scale; + +// ==== Spi clock for reading data from display memory in Hz ==== +extern uint32_t tft_max_rdclock; + +// ==== Display dimensions in pixels ============================ +extern int tft_width; +extern int tft_height; + +// ==== Display type, DISP_TYPE_ILI9488 or DISP_TYPE_ILI9341 ==== +extern uint8_t tft_disp_type; + +// ==== Spi device handles for display and touch screen ========= +extern spi_lobo_device_handle_t tft_disp_spi; +extern spi_lobo_device_handle_t tft_ts_spi; + +// ############################################################## + +// 24-bit color type structure +typedef struct __attribute__((__packed__)) { +//typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} color_t ; + +// ==== Display commands constants ==== +#define TFT_INVOFF 0x20 +#define TFT_INVONN 0x21 +#define TFT_DISPOFF 0x28 +#define TFT_DISPON 0x29 +#define TFT_MADCTL 0x36 +#define TFT_PTLAR 0x30 +#define TFT_ENTRYM 0xB7 + +#define TFT_CMD_NOP 0x00 +#define TFT_CMD_SWRESET 0x01 +#define TFT_CMD_RDDID 0x04 +#define TFT_CMD_RDDST 0x09 + +#define TFT_CMD_SLPIN 0x10 +#define TFT_CMD_SLPOUT 0x11 +#define TFT_CMD_PTLON 0x12 +#define TFT_CMD_NORON 0x13 + +#define TFT_CMD_RDMODE 0x0A +#define TFT_CMD_RDMADCTL 0x0B +#define TFT_CMD_RDPIXFMT 0x0C +#define TFT_CMD_RDIMGFMT 0x0D +#define TFT_CMD_RDSELFDIAG 0x0F + +#define TFT_CMD_GAMMASET 0x26 + +#define TFT_CMD_FRMCTR1 0xB1 +#define TFT_CMD_FRMCTR2 0xB2 +#define TFT_CMD_FRMCTR3 0xB3 +#define TFT_CMD_INVCTR 0xB4 +#define TFT_CMD_DFUNCTR 0xB6 + +#define TFT_CMD_PWCTR1 0xC0 +#define TFT_CMD_PWCTR2 0xC1 +#define TFT_CMD_PWCTR3 0xC2 +#define TFT_CMD_PWCTR4 0xC3 +#define TFT_CMD_PWCTR5 0xC4 +#define TFT_CMD_VMCTR1 0xC5 +#define TFT_CMD_VMCTR2 0xC7 + +#define TFT_CMD_RDID1 0xDA +#define TFT_CMD_RDID2 0xDB +#define TFT_CMD_RDID3 0xDC +#define TFT_CMD_RDID4 0xDD + +#define TFT_CMD_GMCTRP1 0xE0 +#define TFT_CMD_GMCTRN1 0xE1 + +#define TFT_CMD_POWERA 0xCB +#define TFT_CMD_POWERB 0xCF +#define TFT_CMD_POWER_SEQ 0xED +#define TFT_CMD_DTCA 0xE8 +#define TFT_CMD_DTCB 0xEA +#define TFT_CMD_PRC 0xF7 +#define TFT_CMD_3GAMMA_EN 0xF2 + +#define ST_CMD_VCOMS 0xBB +#define ST_CMD_FRCTRL2 0xC6 +#define ST_CMD_PWCTR1 0xD0 + +#define ST7735_FRMCTR1 0xB1 +#define ST7735_FRMCTR2 0xB2 +#define ST7735_FRMCTR3 0xB3 +#define ST7735_INVCTR 0xB4 +#define ST7735_DISSET5 0xB6 + +#define ST7735_PWCTR1 0xC0 +#define ST7735_PWCTR2 0xC1 +#define ST7735_PWCTR3 0xC2 +#define ST7735_PWCTR4 0xC3 +#define ST7735_PWCTR5 0xC4 +#define ST7735_VMCTR1 0xC5 + +#define ST7735_RDID1 0xDA +#define ST7735_RDID2 0xDB +#define ST7735_RDID3 0xDC +#define ST7735_RDID4 0xDD +#define ST7735_NOP 0x00 +#define ST7735_SWRESET 0x01 +#define ST7735_RDDID 0x04 +#define ST7735_RDDST 0x09 + +#define ST7735_SLPIN 0x10 +#define ST7735_SLPOUT 0x11 +#define ST7735_PTLON 0x12 +#define ST7735_NORON 0x13 +#define ST7735_PWCTR6 0xFC +#define ST7735_GMCTRP1 0xE0 +#define ST7735_GMCTRN1 0xE1 + +#define MADCTL_MY 0x80 +#define MADCTL_MX 0x40 +#define MADCTL_MV 0x20 +#define MADCTL_ML 0x10 +#define MADCTL_MH 0x04 + +#define TFT_CASET 0x2A +#define TFT_PASET 0x2B +#define TFT_RAMWR 0x2C +#define TFT_RAMRD 0x2E +#define TFT_CMD_PIXFMT 0x3A + +#define TFT_CMD_DELAY 0x80 + + +// Initialization sequence for ILI7749 +// ==================================== +static const uint8_t ST7789V_init[] = { +#if PIN_NUM_RST + 15, // 15 commands in list +#else + 16, // 16 commands in list + TFT_CMD_SWRESET, TFT_CMD_DELAY, // 1: Software reset, no args, w/delay + 200, // 200 ms delay +#endif + TFT_CMD_FRMCTR2, 5, 0x0c, 0x0c, 0x00, 0x33, 0x33, + TFT_ENTRYM, 1, 0x45, + ST_CMD_VCOMS, 1, 0x2B, + TFT_CMD_PWCTR1, 1, 0x2C, + TFT_CMD_PWCTR3, 2, 0x01, 0xff, + TFT_CMD_PWCTR4, 1, 0x11, + TFT_CMD_PWCTR5, 1, 0x20, + ST_CMD_FRCTRL2, 1, 0x0f, + ST_CMD_PWCTR1, 2, 0xA4, 0xA1, + TFT_CMD_GMCTRP1, 14, 0xD0, 0x00, 0x05, 0x0E, 0x15, 0x0D, 0x37, 0x43, 0x47, 0x09, 0x15, 0x12, 0x16, 0x19, + TFT_CMD_GMCTRN1, 14, 0xD0, 0x00, 0x05, 0x0D, 0x0C, 0x06, 0x2D, 0x44, 0x40, 0x0E, 0x1C, 0x18, 0x16, 0x19, + TFT_MADCTL, 1, (MADCTL_MX | TFT_RGB_BGR), // Memory Access Control (tft_orientation) + TFT_CMD_PIXFMT, 1, DISP_COLOR_BITS_24, // *** INTERFACE PIXEL FORMAT: 0x66 -> 18 bit; 0x55 -> 16 bit + TFT_CMD_SLPOUT, TFT_CMD_DELAY, 120, // Sleep out, // 120 ms delay + TFT_DISPON, TFT_CMD_DELAY, 120, +}; + +// Initialization sequence for ILI7341 +// ==================================== +static const uint8_t ILI9341_init[] = { +#if PIN_NUM_RST + 23, // 24 commands in list +#else + 24, // 24 commands in list + TFT_CMD_SWRESET, TFT_CMD_DELAY, // 1: Software reset, no args, w/delay + 250, // 200 ms delay +#endif + TFT_CMD_POWERA, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + TFT_CMD_POWERB, 3, 0x00, 0XC1, 0X30, + 0xEF, 3, 0x03, 0x80, 0x02, + TFT_CMD_DTCA, 3, 0x85, 0x00, 0x78, + TFT_CMD_DTCB, 2, 0x00, 0x00, + TFT_CMD_POWER_SEQ, 4, 0x64, 0x03, 0X12, 0X81, + TFT_CMD_PRC, 1, 0x20, + TFT_CMD_PWCTR1, 1, 0x23, //Power control VRH[5:0] + TFT_CMD_PWCTR2, 1, 0x10, //Power control SAP[2:0];BT[3:0] + TFT_CMD_VMCTR1, 2, 0x3e, 0x28, //VCM control + TFT_CMD_VMCTR2, 1, 0x86, //VCM control2 + TFT_MADCTL, 1, // Memory Access Control (tft_orientation) + (MADCTL_MX | TFT_RGB_BGR), + // *** INTERFACE PIXEL FORMAT: 0x66 -> 18 bit; 0x55 -> 16 bit + TFT_CMD_PIXFMT, 1, DISP_COLOR_BITS_24, + TFT_INVOFF, 0, + TFT_CMD_FRMCTR1, 2, 0x00, 0x18, + TFT_CMD_DFUNCTR, 4, 0x08, 0x82, 0x27, 0x00, // Display Function Control + TFT_PTLAR, 4, 0x00, 0x00, 0x01, 0x3F, + TFT_CMD_3GAMMA_EN, 1, 0x00, // 3Gamma Function: Disable (0x02), Enable (0x03) + TFT_CMD_GAMMASET, 1, 0x01, //Gamma curve selected (0x01, 0x02, 0x04, 0x08) + TFT_CMD_GMCTRP1, 15, //Positive Gamma Correction + 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, + TFT_CMD_GMCTRN1, 15, //Negative Gamma Correction + 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, + TFT_CMD_SLPOUT, TFT_CMD_DELAY, // Sleep out + 200, // 120 ms delay + TFT_DISPON, TFT_CMD_DELAY, 200, +}; + +// Initialization sequence for ILI9488 +// ==================================== +static const uint8_t ILI9488_init[] = { +#if PIN_NUM_RST + 17, // 17 commands in list +#else + 18, // 18 commands in list + TFT_CMD_SWRESET, TFT_CMD_DELAY, // 1: Software reset, no args, w/delay + 200, // 200 ms delay +#endif + 0xE0, 15, 0x00, 0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F, + 0xE1, 15, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F, + 0xC0, 2, //Power Control 1 + 0x17, //Vreg1out + 0x15, //Verg2out + + 0xC1, 1, //Power Control 2 + 0x41, //VGH,VGL + + 0xC5, 3, //Power Control 3 + 0x00, + 0x12, //Vcom + 0x80, + +#if TFT_INVERT_ROTATION + TFT_MADCTL, 1, (MADCTL_MV | TFT_RGB_BGR), // Memory Access Control (tft_orientation), set to portrait +#else + TFT_MADCTL, 1, (MADCTL_MX | TFT_RGB_BGR), // Memory Access Control (tft_orientation), set to portrait +#endif + + // *** INTERFACE PIXEL FORMAT: 0x66 -> 18 bit; + TFT_CMD_PIXFMT, 1, DISP_COLOR_BITS_24, + + 0xB0, 1, // Interface Mode Control + 0x00, // 0x80: SDO NOT USE; 0x00 USE SDO + + 0xB1, 1, //Frame rate + 0xA0, //60Hz + + 0xB4, 1, //Display Inversion Control + 0x02, //2-dot + + 0xB6, 2, //Display Function Control RGB/MCU Interface Control + 0x02, //MCU + 0x02, //Source,Gate scan direction + + 0xE9, 1, // Set Image Function + 0x00, // Disable 24 bit data + + 0x53, 1, // Write CTRL Display Value + 0x28, // BCTRL && DD on + + 0x51, 1, // Write Display Brightness Value + 0x7F, // + + 0xF7, 4, // Adjust Control + 0xA9, + 0x51, + 0x2C, + 0x02, // D7 stream, loose + + + 0x11, TFT_CMD_DELAY, //Exit Sleep + 120, + 0x29, 0, //Display on + +}; + + +// Initialization commands for 7735B screens +// ------------------------------------ +static const uint8_t STP7735_init[] = { +#if PIN_NUM_RST + 16, // 17 commands in list +#else + 17, // 18 commands in list: + ST7735_SLPOUT, TFT_CMD_DELAY, // 2: Out of sleep mode, no args, w/delay + 255, // 255 = 500 ms delay +#endif + TFT_CMD_PIXFMT, 1+TFT_CMD_DELAY, // 3: Set color mode, 1 arg + delay: + 0x06, // 18-bit color 6-6-6 color format + 10, // 10 ms delay + ST7735_FRMCTR1, 3+TFT_CMD_DELAY, // 4: Frame rate control, 3 args + delay: + 0x00, // fastest refresh + 0x06, // 6 lines front porch + 0x03, // 3 lines back porch + 10, // 10 ms delay + TFT_MADCTL , 1 , // 5: Memory access ctrl (directions), 1 arg: + 0x08, // Row addr/col addr, bottom to top refresh + ST7735_DISSET5, 2 , // 6: Display settings #5, 2 args, no delay: + 0x15, // 1 clk cycle nonoverlap, 2 cycle gate + // rise, 3 cycle osc equalize + 0x02, // Fix on VTL + ST7735_INVCTR , 1 , // 7: Display inversion control, 1 arg: + 0x0, // Line inversion + ST7735_PWCTR1 , 2+TFT_CMD_DELAY, // 8: Power control, 2 args + delay: + 0x02, // GVDD = 4.7V + 0x70, // 1.0uA + 10, // 10 ms delay + ST7735_PWCTR2 , 1 , // 9: Power control, 1 arg, no delay: + 0x05, // VGH = 14.7V, VGL = -7.35V + ST7735_PWCTR3 , 2 , // 10: Power control, 2 args, no delay: + 0x01, // Opamp current small + 0x02, // Boost frequency + ST7735_VMCTR1 , 2+TFT_CMD_DELAY, // 11: Power control, 2 args + delay: + 0x3C, // VCOMH = 4V + 0x38, // VCOML = -1.1V + 10, // 10 ms delay + ST7735_PWCTR6 , 2 , // 12: Power control, 2 args, no delay: + 0x11, 0x15, + ST7735_GMCTRP1,16 , // 13: Magical unicorn dust, 16 args, no delay: + 0x09, 0x16, 0x09, 0x20, // (seriously though, not sure what + 0x21, 0x1B, 0x13, 0x19, // these config values represent) + 0x17, 0x15, 0x1E, 0x2B, + 0x04, 0x05, 0x02, 0x0E, + ST7735_GMCTRN1,16+TFT_CMD_DELAY, // 14: Sparkles and rainbows, 16 args + delay: + 0x0B, 0x14, 0x08, 0x1E, // (ditto) + 0x22, 0x1D, 0x18, 0x1E, + 0x1B, 0x1A, 0x24, 0x2B, + 0x06, 0x06, 0x02, 0x0F, + 10, // 10 ms delay + TFT_CASET , 4 , // 15: Column addr set, 4 args, no delay: + 0x00, 0x02, // XSTART = 2 + 0x00, 0x81, // XEND = 129 + TFT_PASET , 4 , // 16: Row addr set, 4 args, no delay: + 0x00, 0x02, // XSTART = 1 + 0x00, 0x81, // XEND = 160 + ST7735_NORON , TFT_CMD_DELAY, // 17: Normal display on, no args, w/delay + 10, // 10 ms delay + TFT_DISPON , TFT_CMD_DELAY, // 18: Main screen turn on, no args, w/delay + 255 // 255 = 500 ms delay +}; + +// Init for 7735R, part 1 (red or green tab) +// -------------------------------------- +static const uint8_t STP7735R_init[] = { +#if PIN_NUM_RST + 14, // 14 commands in list +#else + 15, // 15 commands in list: + ST7735_SWRESET, TFT_CMD_DELAY, // 1: Software reset, 0 args, w/delay + 150, // 150 ms delay +#endif + ST7735_SLPOUT , TFT_CMD_DELAY, // 2: Out of sleep mode, 0 args, w/delay + 255, // 500 ms delay + ST7735_FRMCTR1, 3 , // 3: Frame rate ctrl - normal mode, 3 args: + 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) + ST7735_FRMCTR2, 3 , // 4: Frame rate control - idle mode, 3 args: + 0x01, 0x2C, 0x2D, // Rate = fosc/(1x2+40) * (LINE+2C+2D) + ST7735_FRMCTR3, 6 , // 5: Frame rate ctrl - partial mode, 6 args: + 0x01, 0x2C, 0x2D, // Dot inversion mode + 0x01, 0x2C, 0x2D, // Line inversion mode + ST7735_INVCTR , 1 , // 6: Display inversion ctrl, 1 arg, no delay: + 0x07, // No inversion + ST7735_PWCTR1 , 3 , // 7: Power control, 3 args, no delay: + 0xA2, + 0x02, // -4.6V + 0x84, // AUTO mode + ST7735_PWCTR2 , 1 , // 8: Power control, 1 arg, no delay: + 0xC5, // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD + ST7735_PWCTR3 , 2 , // 9: Power control, 2 args, no delay: + 0x0A, // Opamp current small + 0x00, // Boost frequency + ST7735_PWCTR4 , 2 , // 10: Power control, 2 args, no delay: + 0x8A, // BCLK/2, Opamp current small & Medium low + 0x2A, + ST7735_PWCTR5 , 2 , // 11: Power control, 2 args, no delay: + 0x8A, 0xEE, + ST7735_VMCTR1 , 1 , // 12: Power control, 1 arg, no delay: + 0x0E, + TFT_INVOFF , 0 , // 13: Don't invert display, no args, no delay + TFT_MADCTL , 1 , // 14: Memory access control (directions), 1 arg: + 0xC0, // row addr/col addr, bottom to top refresh, RGB order + TFT_CMD_PIXFMT , 1+TFT_CMD_DELAY, // 15: Set color mode, 1 arg + delay: + 0x06, // 18-bit color 6-6-6 color format + 10 // 10 ms delay +}; + +// Init for 7735R, part 2 (green tab only) +// --------------------------------------- +static const uint8_t Rcmd2green[] = { + 2, // 2 commands in list: + TFT_CASET , 4 , // 1: Column addr set, 4 args, no delay: + 0x00, 0x02, // XSTART = 0 + 0x00, 0x7F+0x02, // XEND = 129 + TFT_PASET , 4 , // 2: Row addr set, 4 args, no delay: + 0x00, 0x01, // XSTART = 0 + 0x00, 0x9F+0x01 // XEND = 160 +}; + +// Init for 7735R, part 2 (red tab only) +// ------------------------------------- +static const uint8_t Rcmd2red[] = { + 2, // 2 commands in list: + TFT_CASET , 4 , // 1: Column addr set, 4 args, no delay: + 0x00, 0x00, // XSTART = 0 + 0x00, 0x7F, // XEND = 127 + TFT_PASET , 4 , // 2: Row addr set, 4 args, no delay: + 0x00, 0x00, // XSTART = 0 + 0x00, 0x9F // XEND = 159 +}; + +// Init for 7735R, part 3 (red or green tab) +// ----------------------------------------- +static const uint8_t Rcmd3[] = { + 4, // 4 commands in list: + ST7735_GMCTRP1, 16 , // 1: Magical unicorn dust, 16 args, no delay: + 0x02, 0x1c, 0x07, 0x12, + 0x37, 0x32, 0x29, 0x2d, + 0x29, 0x25, 0x2B, 0x39, + 0x00, 0x01, 0x03, 0x10, + ST7735_GMCTRN1, 16 , // 2: Sparkles and rainbows, 16 args, no delay: + 0x03, 0x1d, 0x07, 0x06, + 0x2E, 0x2C, 0x29, 0x2D, + 0x2E, 0x2E, 0x37, 0x3F, + 0x00, 0x00, 0x02, 0x10, + ST7735_NORON , TFT_CMD_DELAY, // 3: Normal display on, no args, w/delay + 10, // 10 ms delay + TFT_DISPON , TFT_CMD_DELAY, // 4: Main screen turn on, no args w/delay + 100 // 100 ms delay +}; + + +// ==== Public functions ========================================================= + +// == Low level functions; usually not used directly == +esp_err_t wait_trans_finish(uint8_t free_line); +void disp_spi_transfer_cmd(int8_t cmd); +void disp_spi_transfer_cmd_data(int8_t cmd, uint8_t *data, uint32_t len); +void drawPixel(int16_t x, int16_t y, color_t color, uint8_t sel); +void send_data(int x1, int y1, int x2, int y2, uint32_t len, color_t *buf); +void TFT_pushColorRep(int x1, int y1, int x2, int y2, color_t data, uint32_t len); +int read_data(int x1, int y1, int x2, int y2, int len, uint8_t *buf, uint8_t set_sp); +color_t readPixel(int16_t x, int16_t y); +int touch_get_data(uint8_t type); + + +// Deactivate display's CS line +//======================== +esp_err_t disp_deselect(); + +// Activate display's CS line and configure SPI interface if necessary +//====================== +esp_err_t disp_select(); + + +// Find maximum spi clock for successful read from display RAM +// ** Must be used AFTER the display is initialized ** +//====================== +uint32_t find_rd_speed(); + + +// Change the screen rotation. +// Input: m new rotation value (0 to 3) +//================================= +void _tft_setRotation(uint8_t rot); + +// Initialize all pins used by display driver +// ** MUST be executed before SPI interface initialization +//================= +void TFT_PinsInit(); + +// Perform display initialization sequence +// Sets tft_orientation to landscape; clears the screen +// * All pins must be configured +// * SPI interface must already be setup +// * 'tft_disp_type', 'COLOR_BITS', 'tft_width', 'tft_height' variables must be set +//====================== +void TFT_display_init(); + +//=================== +void stmpe610_Init(); + +//============================================================ +int stmpe610_get_touch(uint16_t *x, uint16_t *y, uint16_t *z); + +//======================== +uint32_t stmpe610_getID(); + +// =============================================================================== + +#endif diff --git a/components/tft/tooney32.c b/components/tft/tooney32.c new file mode 100644 index 0000000..753fb2d --- /dev/null +++ b/components/tft/tooney32.c @@ -0,0 +1,331 @@ +// This comes with no warranty, implied or otherwise + +// This data structure was designed to support Proportional fonts +// on Arduinos. It can however handle any ttf font that has been converted +// using the conversion program. These could be fixed width or proportional +// fonts. Individual characters do not have to be multiples of 8 bits wide. +// Any width is fine and does not need to be fixed. + +// The data bits are packed to minimize data requirements, but the tradeoff +// is that a header is required per character. + +// tooney32.c +// Point Size : 32 +// Memory usage : 5470 bytes +// # characters : 95 + +// Header Format (to make Arduino UTFT Compatible): +// ------------------------------------------------ +// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00) +// Character Height +// First Character (Reserved. 0x00) +// Number Of Characters (Reserved. 0x00) + +unsigned char tft_tooney32[] = +{ +0x00, 0x20, 0x00, 0x00, + +// Individual Character Format: +// ---------------------------- +// Character Code +// Adjusted Y Offset +// Width +// Height +// xOffset +// xDelta (the distance to move the cursor. Effective width of the character.) +// Data[n] + +// NOTE: You can remove any of these characters if they are not needed in +// your application. The first character number in each Glyph indicates +// the ASCII character code. Therefore, these do not have to be sequential. +// Just remove all the content for a particular character to save space. + +// ' ' +0x20,0x1E,0x00,0x00,0x00,0x09, + +// '!' +0x21,0x09,0x0B,0x16,0x00,0x0B, +0x3F,0xC8,0x07,0x81,0x70,0x27,0x00,0xE0,0x1C,0x21,0x84,0x30,0x86,0x10,0xC2,0x18,0x43,0xF0,0x61,0x0C,0x13,0x02,0x60,0x4E,0x09,0xE2,0x1F,0x81,0xE0,0x00,0x00, +// '"' +0x22,0x05,0x0E,0x0A,0xFF,0x0D, +0x04,0x30,0x2D,0x61,0x8C,0x44,0x71,0x31,0x88,0xCE,0x42,0x72,0x18,0xC8,0x7B,0xC0,0xC6,0x00, +// '#' +0x23,0x07,0x18,0x16,0x00,0x18, +0x00,0xFF,0xF8,0x01,0x83,0x08,0x01,0x82,0x08,0x01,0x82,0x08,0x0F,0x06,0x0F,0x10,0x00,0x01,0x30,0x00,0x01,0x30,0x00,0x00,0x20,0x00,0x02,0x7E,0x0C,0x1E,0x7E,0x0C,0x1E,0x60,0x00,0x02,0x60,0x00,0x00,0x40,0x00,0x04,0x40,0x00,0x04,0xC0,0x00,0x04,0xFC,0x10,0x78,0xFC,0x30,0x78,0x08,0x30,0x40,0x18,0x30,0x40,0x1F,0xFF,0x80,0x1F,0xFF,0x80, +// '$' +0x24,0x09,0x0F,0x14,0x00,0x0F, +0x01,0x80,0x04,0xF8,0x18,0x08,0x20,0x10,0xC0,0x41,0x00,0x86,0x01,0x0C,0x12,0x18,0x38,0x30,0x60,0xA0,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x10,0x30,0x20,0x6E,0x40,0xFF,0x81,0x9E,0x00,0x18,0x00, +// '%' +0x25,0x07,0x17,0x16,0x00,0x17, +0x0F,0x81,0xF8,0x20,0x84,0x10,0x80,0x98,0x42,0x00,0x21,0x0C,0x01,0x82,0x18,0x43,0x08,0x30,0x04,0x10,0x70,0x18,0x40,0xE0,0x21,0x00,0xF1,0x82,0x00,0xFF,0x0F,0xC0,0xFC,0x10,0x40,0x18,0x40,0x40,0x21,0x80,0x40,0x82,0x00,0x83,0x0C,0x21,0x04,0x18,0x02,0x18,0x78,0x04,0x21,0x30,0x10,0xC2,0x78,0xC3,0xF8,0x7F,0x07,0xE0,0x7C,0x00, +// '&' +0x26,0x08,0x17,0x17,0x00,0x17, +0x01,0xF6,0x00,0x04,0x1A,0x00,0x10,0x04,0x00,0x40,0x10,0x01,0x00,0x40,0x06,0x00,0x80,0x0C,0x1A,0x00,0x18,0x1F,0xC0,0x30,0x18,0xF8,0x60,0x08,0x09,0x80,0x00,0x33,0x00,0x00,0xCC,0x0C,0x01,0x18,0x3C,0x04,0x30,0x30,0x07,0x60,0x00,0x01,0xE0,0x00,0x07,0xC0,0x00,0x09,0xC0,0x0C,0x23,0xC0,0x38,0x03,0xE1,0xF8,0x03,0xFF,0x70,0x01,0xF8,0x60,0x00, +// ''' +0x27,0x05,0x09,0x0A,0xFF,0x08, +0x06,0x05,0x86,0x23,0x13,0x11,0x90,0x90,0xC8,0x78,0x18,0x00, +// '(' +0x28,0x05,0x0D,0x1D,0x00,0x0D, +0x03,0x00,0x34,0x01,0x90,0x08,0x40,0x81,0x88,0x1C,0xC1,0xC4,0x08,0x60,0x83,0x04,0x10,0x41,0x82,0x0C,0x10,0x60,0x83,0x04,0x18,0x20,0xC0,0x06,0x04,0x38,0x20,0xC0,0x87,0x06,0x38,0x1C,0xE0,0x67,0x86,0x1C,0x60,0x76,0x01,0xE0,0x0E,0x00,0x60,0x00, +// ')' +0x29,0x05,0x0D,0x1D,0x00,0x0D, +0x01,0x00,0x10,0x01,0x20,0x11,0x03,0x04,0x30,0x11,0xE0,0x8F,0x82,0x1C,0x10,0x70,0x81,0x82,0x0E,0x10,0x30,0x81,0x84,0x0C,0x20,0x61,0x02,0x08,0x10,0x01,0x84,0x08,0x20,0x81,0x18,0x11,0x80,0x8E,0x08,0x78,0x80,0xE4,0x03,0xE0,0x0E,0x00,0x30,0x00, +// '*' +0x2A,0x09,0x0C,0x0D,0x01,0x0D, +0x07,0x00,0x88,0x18,0xE4,0x11,0xC0,0x1F,0x8E,0xC0,0x1C,0x11,0xC8,0xBF,0x8E,0x7D,0xC1,0xE0,0x0C,0x00, +// '+' +0x2B,0x09,0x15,0x14,0x00,0x15, +0x00,0x7C,0x00,0x04,0x10,0x00,0x60,0x80,0x07,0x04,0x00,0x38,0x20,0x01,0xC1,0x00,0xFE,0x0F,0xCC,0x00,0x01,0xE0,0x00,0x0F,0x00,0x00,0x78,0x00,0x03,0xFF,0x07,0xFF,0xF8,0x3F,0x7F,0xC1,0xF0,0x0E,0x08,0x00,0x70,0x40,0x03,0x82,0x00,0x1F,0xF0,0x00,0xFE,0x00,0x03,0xE0,0x00, +// ',' +0x2C,0x17,0x09,0x0B,0x00,0x09, +0x1E,0x10,0x98,0x38,0x1C,0x0F,0x0B,0xC4,0xE4,0x32,0x1E,0x0E,0x00, +// '-' +0x2D,0x11,0x09,0x06,0x00,0x09, +0x1B,0x90,0x50,0x39,0x2F,0xE7,0xF0, +// '.' +0x2E,0x16,0x09,0x09,0x00,0x09, +0x1E,0x10,0x90,0x38,0x1C,0x0F,0x07,0xCC,0xFC,0x3C,0x00, +// '/' +0x2F,0x09,0x11,0x19,0x00,0x11, +0x00,0x3F,0x80,0x30,0x40,0x30,0x20,0x18,0x20,0x18,0x10,0x0C,0x08,0x06,0x08,0x06,0x04,0x03,0x04,0x03,0x02,0x01,0x81,0x00,0xC1,0x00,0xC0,0x80,0x60,0x00,0x60,0x40,0x30,0x20,0x18,0x20,0x18,0x10,0x0C,0x08,0x06,0x08,0x06,0x04,0x03,0x04,0x03,0xFE,0x01,0xFE,0x00,0xFE,0x00,0x00, +// '0' +0x30,0x08,0x17,0x17,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00, +// '1' +0x31,0x09,0x0D,0x16,0x00,0x0D, +0x00,0x30,0x06,0x40,0xC4,0x18,0x43,0x02,0x20,0x13,0xC0,0x9E,0x04,0x30,0x21,0x81,0x0C,0x08,0x60,0x43,0x02,0x18,0x10,0xC0,0x86,0x04,0x30,0x21,0x81,0x98,0x03,0xFF,0xE7,0xFE,0x00,0x00, +// '2' +0x32,0x08,0x12,0x17,0x00,0x12, +0x00,0xF0,0x00,0x81,0x00,0xC0,0x20,0xE0,0x04,0x40,0x01,0x38,0x00,0x2F,0x84,0x08,0xF9,0x82,0x1F,0xE0,0x81,0xF0,0x00,0x1C,0x10,0x06,0x04,0x01,0x03,0x80,0xC0,0xD0,0x20,0x04,0x18,0x01,0x0C,0x00,0x43,0x00,0x11,0x80,0x04,0x60,0x01,0x3F,0xFF,0x4F,0xFF,0xE0,0x00,0x30, +// '3' +0x33,0x08,0x12,0x17,0x00,0x12, +0x0C,0x00,0x05,0xFF,0xE3,0x00,0x08,0xC0,0x02,0x30,0x01,0x0C,0x00,0x43,0x00,0x10,0xC0,0x0C,0x37,0x01,0x0F,0x80,0x23,0xE0,0x08,0x10,0x01,0x0F,0xE0,0x43,0xF8,0x10,0x4E,0x04,0x23,0x01,0x10,0x00,0x08,0x00,0x24,0x00,0x13,0x00,0x08,0xFC,0x0C,0x1F,0xFE,0x00,0xFE,0x00, +// '4' +0x34,0x09,0x12,0x16,0x00,0x12, +0x00,0x0E,0x00,0x04,0x80,0x06,0x20,0x03,0x08,0x01,0x82,0x00,0xC0,0x80,0x40,0x20,0x20,0x08,0x10,0x03,0x88,0x20,0x94,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0xFE,0x09,0xFF,0x83,0x80,0x60,0xC0,0x30,0x10,0x0F,0xF8,0x03,0xFC,0x00,0x00,0x00, +// '5' +0x35,0x08,0x11,0x17,0x00,0x11, +0x00,0x03,0x00,0xFF,0x40,0x80,0x20,0xC0,0x10,0x60,0x08,0x30,0x04,0x30,0x02,0x18,0x1D,0x0C,0x07,0x06,0x01,0x82,0x00,0x43,0x00,0x11,0xFC,0x08,0xFF,0x04,0x17,0x82,0x18,0x01,0x18,0x00,0x08,0x00,0x8C,0x00,0x8C,0x00,0xC7,0xC1,0xC3,0xFF,0x80,0xBF,0x00, +// '6' +0x36,0x08,0x13,0x17,0x00,0x13, +0x00,0x7F,0xC0,0x30,0x08,0x18,0x01,0x06,0x00,0x41,0x80,0x10,0x60,0x02,0x08,0x0C,0x83,0x00,0x30,0x60,0x01,0x18,0x00,0x13,0x00,0x01,0x60,0x00,0x0C,0x00,0x03,0x80,0xC0,0x78,0x3C,0x0F,0x03,0x01,0x60,0x00,0x0E,0x00,0x08,0xE0,0x02,0x1E,0x00,0x81,0xF0,0x60,0x1F,0xF8,0x00,0xFC,0x00, +// '7' +0x37,0x08,0x12,0x17,0x00,0x12, +0x0C,0x00,0x0D,0xFF,0xF3,0x00,0x04,0xC0,0x02,0x30,0x00,0x8C,0x00,0x43,0x00,0x10,0xDC,0x08,0x3F,0x02,0x0E,0x81,0x00,0x60,0x40,0x10,0x20,0x0C,0x08,0x02,0x04,0x01,0x81,0x00,0x40,0x80,0x30,0x20,0x10,0x10,0x0F,0x04,0x03,0xF1,0x00,0x3F,0x40,0x03,0xE0,0x00,0x30,0x00, +// '8' +0x38,0x08,0x12,0x17,0x00,0x12, +0x01,0xF0,0x00,0x83,0x00,0xC0,0x20,0x20,0x08,0x10,0x01,0x0C,0x18,0x43,0x06,0x10,0xC0,0x04,0x38,0x01,0x0C,0x00,0x42,0x00,0x09,0x80,0x01,0xC0,0x00,0x70,0x3C,0x1C,0x0F,0x07,0x00,0x01,0xE0,0x00,0x9C,0x00,0x27,0x80,0x30,0xF8,0x38,0x1F,0xFC,0x01,0xFC,0x00,0x00,0x00, +// '9' +0x39,0x08,0x13,0x17,0x00,0x13, +0x01,0xF8,0x00,0xC0,0xC0,0x20,0x04,0x08,0x00,0x42,0x00,0x08,0xC0,0x00,0x90,0x18,0x16,0x07,0x81,0xC0,0x60,0x38,0x00,0x07,0x80,0x00,0xF0,0x00,0x17,0x00,0x02,0xF0,0x00,0x0F,0x80,0x10,0xE6,0x02,0x08,0x00,0x83,0x00,0x20,0x40,0x0C,0x10,0x03,0x06,0xC1,0xC0,0xFF,0xE0,0x1F,0xF0,0x00, +// ':' +0x3A,0x0E,0x09,0x11,0x00,0x09, +0x0E,0x10,0x90,0x38,0x1C,0x0F,0x07,0xC4,0xFC,0x3C,0x19,0x98,0x38,0x1C,0x0F,0x07,0xCC,0xFC,0x3C,0x00, +// ';' +0x3B,0x0F,0x09,0x13,0x00,0x09, +0x0E,0x10,0x98,0x38,0x1C,0x0F,0x07,0xC4,0xFC,0x3E,0x19,0x98,0x38,0x1C,0x0F,0x03,0xC4,0xE4,0x32,0x1E,0x0E,0x00, +// '<' +0x3C,0x0A,0x13,0x13,0x00,0x13, +0x00,0x00,0xC0,0x00,0x64,0x00,0x60,0x80,0x30,0x10,0x38,0x02,0x18,0x03,0x8C,0x01,0xE3,0x01,0xF0,0xE0,0xF8,0x1C,0x06,0x03,0x80,0x18,0x7E,0x00,0xCF,0xF0,0x06,0x7F,0xC0,0x43,0xFE,0x08,0x0F,0xF9,0x00,0x7F,0xE0,0x01,0xF8,0x00,0x0C,0x00, +// '=' +0x3D,0x0D,0x14,0x0E,0x00,0x14, +0x3F,0xFF,0xE6,0x00,0x01,0xE0,0x00,0x1E,0x00,0x01,0xE0,0x00,0x1F,0xFF,0xFE,0xFF,0xFF,0xE6,0x00,0x01,0x60,0x00,0x1E,0x00,0x01,0xE0,0x00,0x1F,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF8, +// '>' +0x3E,0x0A,0x13,0x13,0x00,0x13, +0x38,0x00,0x0C,0xC0,0x03,0x87,0x00,0x70,0x18,0x0E,0x00,0xE1,0xF8,0x03,0x3F,0xC0,0x19,0xFF,0x01,0x0F,0xF8,0x20,0x3C,0x04,0x0C,0x00,0x86,0x00,0xE3,0x00,0x78,0xC0,0x7C,0x38,0x3E,0x07,0x3E,0x00,0xFF,0x00,0x1F,0x00,0x03,0x80,0x00,0x00, +// '?' +0x3F,0x08,0x11,0x16,0x00,0x11, +0x00,0xF0,0x01,0x82,0x01,0x00,0x81,0x00,0x23,0x00,0x0B,0x00,0x05,0xC0,0x02,0xF8,0xC1,0x3F,0x40,0x87,0xE0,0x80,0xE0,0x40,0x30,0x40,0x18,0x20,0x0F,0xE0,0x07,0x30,0x03,0x04,0x03,0x02,0x01,0x81,0x00,0xE0,0x80,0x78,0x80,0x1F,0x80,0x07,0x80, +// '@' +0x40,0x09,0x16,0x16,0x00,0x16, +0x00,0x3F,0x00,0x06,0x03,0x00,0x23,0xFB,0x01,0x3F,0xFC,0x09,0x81,0xF8,0x48,0x7F,0xE2,0x44,0x13,0xD9,0x23,0x8F,0x41,0x1E,0x1F,0x2C,0x51,0x7C,0xE0,0xC5,0xF3,0x8B,0x06,0xCE,0x28,0x3B,0x38,0xE2,0xEE,0x71,0x4D,0x19,0xE3,0x88,0x73,0xFF,0xD1,0xE7,0x9F,0xA3,0xC7,0xF1,0x07,0xE0,0x38,0x07,0xFF,0x80,0x07,0xF8,0x00, +// 'A' +0x41,0x08,0x19,0x17,0x00,0x19, +0x00,0x0C,0x00,0x00,0x09,0x00,0x00,0x08,0x80,0x00,0x0C,0x20,0x00,0x04,0x08,0x00,0x06,0x04,0x00,0x02,0x01,0x00,0x03,0x00,0xC0,0x03,0x00,0x20,0x01,0x00,0x08,0x01,0x80,0x04,0x00,0x80,0x01,0x00,0xC0,0xC0,0x40,0xC0,0x60,0x20,0x40,0x00,0x08,0x60,0x00,0x06,0x40,0x00,0x00,0xF0,0x00,0x00,0xFE,0x1F,0xE1,0xCF,0xCF,0xF1,0x81,0xF4,0x1B,0x80,0x3E,0x0F,0x00,0x0E,0x06,0x00, +// 'B' +0x42,0x09,0x13,0x15,0x00,0x13, +0x3F,0xFC,0x0C,0x00,0x61,0xC0,0x06,0x38,0x00,0x43,0x00,0x04,0x60,0x60,0x8C,0x0C,0x11,0x81,0x02,0x30,0x00,0x46,0x00,0x08,0xC0,0x00,0x98,0x18,0x13,0x03,0x02,0x60,0x60,0x4C,0x00,0x09,0x80,0x01,0x30,0x00,0x44,0x00,0x11,0x80,0x0E,0x3F,0xFF,0x07,0xFF,0x80, +// 'C' +0x43,0x08,0x16,0x17,0x00,0x16, +0x00,0x7E,0x00,0x06,0x02,0x00,0x60,0x06,0x02,0x00,0x06,0x10,0x00,0x00,0xC0,0x00,0x22,0x00,0x01,0x18,0x0F,0x18,0x40,0x7E,0xC3,0x02,0x3E,0x0C,0x08,0xF0,0x30,0x21,0x80,0xC0,0x83,0x03,0x81,0x1A,0x0E,0x03,0xC4,0x18,0x00,0x08,0x70,0x00,0x19,0xE0,0x00,0x23,0xC0,0x01,0x87,0x80,0x1E,0x0F,0xC1,0xE0,0x0F,0xFE,0x00,0x0F,0xC0,0x00, +// 'D' +0x44,0x09,0x16,0x15,0xFF,0x15, +0x1F,0xFE,0x00,0x80,0x06,0x07,0x00,0x06,0x1C,0x00,0x0C,0x30,0x00,0x10,0xC0,0x00,0x23,0x00,0x00,0x8C,0x0F,0x01,0x30,0x3E,0x04,0xC0,0xF8,0x13,0x03,0xE0,0x4C,0x0F,0x01,0x30,0x00,0x04,0xC0,0x00,0x23,0x00,0x00,0x8C,0x00,0x04,0x30,0x00,0x20,0x80,0x01,0x06,0x00,0x18,0x1F,0xFF,0x80,0x3F,0xF0,0x00, +// 'E' +0x45,0x08,0x11,0x17,0x00,0x11, +0x00,0x01,0x0F,0xFF,0x48,0x00,0x2C,0x00,0x17,0x00,0x0B,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x1A,0x98,0x01,0x8C,0x00,0x86,0x00,0x43,0x00,0x31,0x80,0xD4,0xC0,0x02,0x60,0x01,0x30,0x00,0x98,0x00,0x4C,0x00,0x24,0x00,0x17,0xFF,0xEB,0xFF,0xF8,0x00,0x08, +// 'F' +0x46,0x08,0x11,0x16,0xFF,0x10, +0x00,0x01,0x0F,0xFF,0x48,0x00,0x2E,0x00,0x17,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x3A,0x98,0x01,0x8C,0x00,0xC6,0x00,0x43,0x00,0x21,0x81,0xD0,0xC0,0xF0,0x60,0x70,0x30,0x20,0x18,0x10,0x08,0x02,0x0C,0x01,0x07,0xFF,0x03,0xFF,0x00, +// 'G' +0x47,0x08,0x16,0x17,0x00,0x16, +0x00,0x7F,0x00,0x06,0x03,0x00,0x60,0x03,0x82,0x00,0x02,0x10,0x00,0x08,0xC0,0x00,0xC2,0x00,0x06,0x18,0x07,0x30,0x40,0x3C,0x83,0x01,0x3C,0x0C,0x04,0xFF,0xB0,0x14,0x02,0xC0,0x78,0x1B,0x80,0xE0,0x4E,0x01,0x81,0x18,0x00,0x04,0x70,0x00,0x11,0xE0,0x00,0x43,0xC0,0x01,0x07,0x80,0x18,0x0F,0x81,0xC0,0x1F,0xFC,0x00,0x0F,0xC0,0x00, +// 'H' +0x48,0x09,0x16,0x15,0x00,0x16, +0x3F,0xC7,0xF9,0x00,0xE0,0x1E,0x03,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x80,0xF0,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x00,0x09,0x80,0x00,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x3C,0x09,0x80,0xF0,0x26,0x02,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x00,0x20,0x1F,0xFF,0xFF,0xFF,0xF7,0xFC,0x00,0x00,0x00, +// 'I' +0x49,0x09,0x0B,0x15,0x00,0x0B, +0x3F,0xC8,0x07,0x81,0x70,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x4C,0x09,0x81,0x30,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x48,0x07,0x00,0xFF,0xEF,0xF8, +// 'J' +0x4A,0x09,0x0F,0x16,0x00,0x0F, +0x03,0xFC,0x08,0x04,0x38,0x08,0x70,0x10,0x60,0x20,0xC0,0x41,0x80,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x08,0x30,0x10,0xA0,0x23,0x00,0x44,0x00,0x98,0x01,0x20,0x00,0xC0,0x09,0x00,0x27,0xC1,0x8F,0xFE,0x0F,0xF0,0x00, +// 'K' +0x4B,0x08,0x17,0x18,0x00,0x17, +0x00,0x01,0x80,0x7F,0xEE,0x81,0x80,0x38,0x87,0x81,0xE0,0x8F,0x03,0x80,0x86,0x06,0x00,0x8C,0x08,0x07,0x18,0x00,0x1C,0x30,0x00,0x70,0x60,0x01,0x00,0xC0,0x02,0x01,0x80,0x02,0x03,0x00,0x04,0x06,0x04,0x04,0x0C,0x0C,0x04,0x18,0x18,0x06,0x30,0x38,0x00,0x60,0x78,0x09,0x00,0x30,0x26,0x00,0x71,0x8F,0xFF,0xE4,0x0F,0xFC,0xD0,0x00,0x01,0xC0,0x00,0x00,0x00, +// 'L' +0x4C,0x09,0x11,0x16,0x00,0x11, +0x3F,0xF0,0x30,0x04,0x1C,0x06,0x0E,0x02,0x03,0x01,0x01,0x80,0x80,0xC0,0x40,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,0xC6,0x03,0xD3,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x00,0xB0,0x00,0x58,0x00,0x2F,0xFF,0xD7,0xFF,0xF0,0x00,0x30, +// 'M' +0x4D,0x09,0x20,0x16,0x00,0x1F, +0x00,0xF8,0x1F,0x00,0x01,0x84,0x30,0x80,0x01,0x82,0x61,0x00,0x01,0x82,0x40,0x00,0x01,0x81,0xC0,0x80,0x01,0x01,0x80,0x80,0x03,0x00,0x80,0x40,0x02,0x00,0x00,0x40,0x06,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x0C,0x00,0x00,0x10,0x08,0x00,0x00,0x10,0x18,0x08,0x08,0x08,0x10,0x18,0x18,0x08,0x30,0x1C,0x1C,0x04,0x60,0x3C,0x3C,0x02,0x70,0x2E,0x2E,0x06,0x7C,0x27,0x4E,0x3C,0x3F,0x27,0xC6,0xF0,0x07,0xC3,0x8F,0x80,0x01,0x83,0x06,0x00, +// 'N' +0x4E,0x09,0x17,0x15,0x00,0x17, +0x3F,0x07,0xFC,0xC1,0x10,0x07,0xC1,0x78,0x1F,0x81,0xF0,0x23,0x01,0xE0,0x46,0x01,0xC0,0x8C,0x01,0x81,0x18,0x01,0x02,0x30,0x00,0x04,0x60,0x00,0x08,0xC0,0x00,0x11,0x80,0x00,0x23,0x02,0x00,0x46,0x06,0x00,0x8C,0x0E,0x01,0x18,0x1E,0x02,0x30,0x3F,0x04,0x60,0x3F,0x0B,0x00,0x2F,0x17,0xFF,0x8F,0xEF,0xFE,0x0F,0x80, +// 'O' +0x4F,0x08,0x17,0x17,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00, +// 'P' +0x50,0x09,0x13,0x15,0x00,0x13, +0x3F,0xFC,0x08,0x00,0x43,0x80,0x06,0x70,0x00,0x46,0x00,0x04,0xC0,0x00,0x18,0x00,0x0B,0x01,0x81,0x60,0x30,0x2C,0x04,0x05,0x80,0x00,0x30,0x00,0x26,0x00,0x08,0xC0,0x02,0x18,0x01,0x83,0x01,0xE0,0x60,0x30,0x08,0x04,0x03,0x00,0x80,0x7F,0xE0,0x07,0xF8,0x00, +// 'Q' +0x51,0x09,0x17,0x1C,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x00,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x01,0x08,0x00,0x01,0x30,0x1E,0x02,0x40,0x7E,0x03,0x81,0x1E,0x07,0x02,0x1C,0x0E,0x04,0x18,0x1C,0x04,0x20,0x3C,0x07,0x80,0x78,0x00,0x01,0x30,0x00,0x02,0x70,0x00,0x04,0xF0,0x00,0x10,0xF0,0x00,0x70,0xF0,0x00,0x00,0xFC,0x00,0x40,0xFF,0x81,0x00,0x3F,0x84,0x00,0x0F,0x10,0x00,0x06,0x40,0x00,0x0F,0x00,0x00,0x1C,0x00,0x00,0x00,0x00, +// 'R' +0x52,0x09,0x18,0x17,0x00,0x18, +0x3F,0xFE,0x00,0x60,0x01,0x80,0x70,0x00,0x40,0x70,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x10,0x10,0x30,0x18,0x10,0x30,0x10,0x10,0x30,0x00,0x10,0x30,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x1E,0x30,0x00,0x0A,0x30,0x18,0x06,0x30,0x1C,0x0C,0x20,0x0E,0x18,0x7F,0xFF,0x30,0x7F,0xE7,0x20,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x03,0x00, +// 'S' +0x53,0x07,0x11,0x19,0x00,0x11, +0x00,0x06,0x00,0x02,0x80,0x1E,0x40,0x10,0x20,0x30,0x10,0x30,0x08,0x10,0x04,0x18,0x01,0x08,0x00,0x8C,0x0F,0x46,0x07,0xA3,0x01,0xE1,0xC0,0xE1,0xE0,0x41,0x70,0x21,0x80,0x10,0xC0,0x08,0x70,0x08,0x38,0x04,0x0C,0x04,0x06,0x04,0x03,0x3C,0x01,0xFC,0x00,0xF0,0x00,0x30,0x00,0x00, +// 'T' +0x54,0x08,0x12,0x16,0x01,0x13, +0x30,0x01,0x93,0xFF,0xDC,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0x00,0x01,0xCC,0x07,0x7F,0x01,0xFF,0xC0,0x79,0xB0,0x1C,0x0C,0x04,0x03,0x01,0x00,0xC0,0x40,0x30,0x10,0x0C,0x04,0x03,0x01,0x00,0xC0,0x60,0x60,0x08,0x1F,0xFC,0x07,0xFE,0x00, +// 'U' +0x55,0x09,0x19,0x16,0xFF,0x18, +0x1F,0xF1,0xFF,0x10,0x05,0x00,0x9C,0x07,0xC0,0xCE,0x02,0xE0,0x43,0x01,0x30,0x21,0x80,0x98,0x10,0xC0,0x4C,0x08,0x60,0x26,0x04,0x30,0x13,0x02,0x18,0x09,0x81,0x0C,0x04,0xC0,0x86,0x02,0x60,0x43,0x01,0x30,0x21,0xC0,0x70,0x10,0xE0,0x00,0x10,0x30,0x00,0x08,0x1C,0x00,0x08,0x0F,0x00,0x08,0x03,0xC0,0x08,0x00,0xFC,0x18,0x00,0x1F,0xF8,0x00,0x03,0xF0,0x00, +// 'V' +0x56,0x07,0x19,0x18,0x00,0x19, +0x00,0xC1,0xC0,0x01,0x91,0x98,0x03,0x18,0xC3,0x06,0x04,0x60,0x64,0x02,0x20,0x1F,0x00,0xB0,0x1B,0xC0,0x70,0x0C,0xF0,0x10,0x08,0x38,0x00,0x08,0x0E,0x00,0x04,0x07,0x00,0x04,0x01,0xC0,0x06,0x00,0xE0,0x02,0x00,0x38,0x02,0x00,0x1C,0x01,0x00,0x07,0x01,0x00,0x03,0x81,0x80,0x00,0xE0,0x80,0x00,0x30,0x80,0x00,0x1C,0x40,0x00,0x06,0x40,0x00,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0x60,0x00, +// 'W' +0x57,0x07,0x20,0x18,0x00,0x20, +0x00,0x60,0x03,0x80,0x01,0x90,0x06,0x60,0x0E,0x10,0xC6,0x1C,0x38,0x11,0xA6,0x07,0x60,0x11,0x26,0x01,0x78,0x12,0x1C,0x06,0x78,0x0E,0x1C,0x04,0x3C,0x0C,0x08,0x08,0x1C,0x00,0x08,0x10,0x0C,0x00,0x00,0x10,0x0E,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x07,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x03,0x80,0x00,0x80,0x03,0x80,0x00,0x80,0x01,0xC0,0x81,0x00,0x01,0xC1,0xC0,0x00,0x00,0xE1,0xC2,0x00,0x00,0xE2,0xE4,0x00,0x00,0x74,0xE4,0x00,0x00,0x7C,0x78,0x00,0x00,0x38,0x78,0x00,0x00,0x30,0x30,0x00, +// 'X' +0x58,0x05,0x19,0x1D,0x00,0x18, +0x00,0x01,0x80,0x00,0x01,0x20,0x00,0x61,0x8C,0x00,0x48,0xC3,0x00,0x44,0x40,0x60,0x43,0x60,0x10,0xC0,0xE0,0x18,0xC0,0x30,0x1C,0xC0,0x00,0x18,0x7C,0x00,0x08,0x1F,0x00,0x08,0x03,0x80,0x08,0x00,0xE0,0x04,0x00,0x38,0x02,0x00,0x0C,0x01,0x80,0x04,0x00,0x60,0x06,0x00,0x10,0x02,0x00,0x07,0x03,0x00,0x00,0x41,0x01,0x00,0x63,0x00,0xC0,0x62,0x00,0xF0,0x63,0x80,0x7C,0x61,0xF0,0x4E,0x60,0x7C,0x63,0xE0,0x0F,0x91,0xE0,0x01,0xF0,0x40,0x00,0x70,0x00,0x00,0x00,0x00,0x00, +// 'Y' +0x59,0x06,0x19,0x1B,0x00,0x19, +0x00,0x00,0x60,0x00,0xC0,0x48,0x00,0x80,0x62,0x00,0x88,0x20,0xC0,0x82,0x30,0x11,0x80,0xB0,0x01,0x80,0x30,0x0D,0x80,0x00,0x0C,0xF8,0x00,0x08,0x3E,0x00,0x04,0x07,0x80,0x04,0x01,0xE0,0x04,0x00,0x78,0x04,0x00,0x1C,0x02,0x00,0x0C,0x02,0x00,0x04,0x02,0x00,0x04,0x02,0x00,0x06,0x01,0x00,0x0E,0x01,0x00,0x0C,0x01,0x00,0x07,0x01,0x00,0x03,0xC0,0x80,0x01,0xF0,0x80,0x00,0x3E,0x00,0x00,0x0F,0xC0,0x00,0x03,0xE0,0x00,0x00,0x40,0x00,0x00, +// 'Z' +0x5A,0x08,0x13,0x17,0xFF,0x12, +0x0C,0x00,0x02,0xFF,0xFC,0xC0,0x01,0x98,0x00,0x23,0x00,0x04,0x60,0x01,0x0C,0x00,0x21,0x80,0x08,0x37,0x01,0x07,0xE0,0x60,0xF8,0x08,0x03,0x01,0x00,0x40,0x70,0x18,0x0D,0x02,0x00,0x20,0xC0,0x04,0x18,0x00,0x86,0x00,0x10,0xC0,0x02,0x10,0x00,0x47,0xFF,0xE8,0xFF,0xFE,0x00,0x01,0x80, +// '[' +0x5B,0x04,0x0B,0x20,0x00,0x0B, +0x00,0x40,0x19,0xFD,0x60,0x2C,0x05,0x80,0xB0,0x16,0x0E,0xC1,0xD8,0x33,0x04,0x60,0x8C,0x11,0x82,0x30,0x46,0x08,0xC1,0x18,0x23,0x04,0x60,0x8C,0x11,0x82,0xB0,0x76,0x02,0xC0,0x58,0x0B,0x01,0x60,0x2F,0xFD,0xFF,0x80,0x60,0x00, +// '\' +0x5C,0x09,0x11,0x18,0x00,0x11, +0x3F,0x00,0x30,0x40,0x38,0x10,0x1E,0x08,0x0F,0x04,0x03,0x81,0x01,0xE0,0x80,0x70,0x20,0x3C,0x10,0x1E,0x08,0x07,0x02,0x03,0xC1,0x00,0xE0,0x40,0x78,0x20,0x3C,0x08,0x0F,0x04,0x07,0x82,0x01,0xC0,0x80,0xF0,0x40,0x38,0x10,0x1E,0x08,0x0F,0xFC,0x03,0xFC,0x01,0xFC, +// ']' +0x5D,0x04,0x0C,0x1F,0xFF,0x0B, +0x30,0x02,0xFF,0x60,0x16,0x01,0x60,0x16,0x01,0x60,0x16,0xC1,0x7C,0x16,0xC1,0x6C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x13,0xC1,0x6C,0x16,0x01,0x60,0x16,0x01,0x60,0x16,0x01,0x7F,0xE7,0xFE,0x60,0x00, +// '^' +0x5E,0x1E,0x00,0x00,0x00,0x09, + +// '_' +0x5F,0x20,0x10,0x04,0x00,0x10, +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +// '`' +0x60,0x00,0x0A,0x09,0x00,0x0B, +0x00,0x06,0x02,0x61,0x8C,0x60,0xBF,0x17,0xFC,0x3E,0x03,0x00, +// 'a' +0x61,0x08,0x19,0x17,0x00,0x19, +0x00,0x0C,0x00,0x00,0x09,0x00,0x00,0x08,0x80,0x00,0x0C,0x20,0x00,0x04,0x08,0x00,0x06,0x04,0x00,0x02,0x01,0x00,0x03,0x00,0xC0,0x03,0x00,0x20,0x01,0x00,0x08,0x01,0x80,0x04,0x00,0x80,0x01,0x00,0xC0,0xC0,0x40,0xC0,0x60,0x20,0x40,0x00,0x08,0x60,0x00,0x06,0x40,0x00,0x00,0xF0,0x00,0x00,0xFE,0x1F,0xE1,0xCF,0xCF,0xF1,0x81,0xF4,0x1B,0x80,0x3E,0x0F,0x00,0x0E,0x06,0x00, +// 'b' +0x62,0x09,0x13,0x15,0x00,0x13, +0x3F,0xFC,0x0C,0x00,0x61,0xC0,0x06,0x38,0x00,0x43,0x00,0x04,0x60,0x60,0x8C,0x0C,0x11,0x81,0x02,0x30,0x00,0x46,0x00,0x08,0xC0,0x00,0x98,0x18,0x13,0x03,0x02,0x60,0x60,0x4C,0x00,0x09,0x80,0x01,0x30,0x00,0x44,0x00,0x11,0x80,0x0E,0x3F,0xFF,0x07,0xFF,0x80, +// 'c' +0x63,0x08,0x16,0x17,0x00,0x16, +0x00,0x7E,0x00,0x06,0x02,0x00,0x60,0x06,0x02,0x00,0x06,0x10,0x00,0x00,0xC0,0x00,0x22,0x00,0x01,0x18,0x0F,0x18,0x40,0x7E,0xC3,0x02,0x3E,0x0C,0x08,0xF0,0x30,0x21,0x80,0xC0,0x83,0x03,0x81,0x1A,0x0E,0x03,0xC4,0x18,0x00,0x08,0x70,0x00,0x19,0xE0,0x00,0x23,0xC0,0x01,0x87,0x80,0x1E,0x0F,0xC1,0xE0,0x0F,0xFE,0x00,0x0F,0xC0,0x00, +// 'd' +0x64,0x09,0x16,0x15,0xFF,0x15, +0x1F,0xFE,0x00,0x80,0x06,0x07,0x00,0x06,0x1C,0x00,0x0C,0x30,0x00,0x10,0xC0,0x00,0x23,0x00,0x00,0x8C,0x0F,0x01,0x30,0x3E,0x04,0xC0,0xF8,0x13,0x03,0xE0,0x4C,0x0F,0x01,0x30,0x00,0x04,0xC0,0x00,0x23,0x00,0x00,0x8C,0x00,0x04,0x30,0x00,0x20,0x80,0x01,0x06,0x00,0x18,0x1F,0xFF,0x80,0x3F,0xF0,0x00, +// 'e' +0x65,0x08,0x11,0x17,0x00,0x11, +0x00,0x01,0x0F,0xFF,0x48,0x00,0x2C,0x00,0x17,0x00,0x0B,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x1A,0x98,0x01,0x8C,0x00,0x86,0x00,0x43,0x00,0x31,0x80,0xD4,0xC0,0x02,0x60,0x01,0x30,0x00,0x98,0x00,0x4C,0x00,0x24,0x00,0x17,0xFF,0xEB,0xFF,0xF8,0x00,0x08, +// 'f' +0x66,0x08,0x11,0x16,0xFF,0x10, +0x00,0x01,0x0F,0xFF,0x48,0x00,0x2E,0x00,0x17,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x3A,0x98,0x01,0x8C,0x00,0xC6,0x00,0x43,0x00,0x21,0x81,0xD0,0xC0,0xF0,0x60,0x70,0x30,0x20,0x18,0x10,0x08,0x02,0x0C,0x01,0x07,0xFF,0x03,0xFF,0x00, +// 'g' +0x67,0x08,0x16,0x17,0x00,0x16, +0x00,0x7F,0x00,0x06,0x03,0x00,0x60,0x03,0x82,0x00,0x02,0x10,0x00,0x08,0xC0,0x00,0xC2,0x00,0x06,0x18,0x07,0x30,0x40,0x3C,0x83,0x01,0x3C,0x0C,0x04,0xFF,0xB0,0x14,0x02,0xC0,0x78,0x1B,0x80,0xE0,0x4E,0x01,0x81,0x18,0x00,0x04,0x70,0x00,0x11,0xE0,0x00,0x43,0xC0,0x01,0x07,0x80,0x18,0x0F,0x81,0xC0,0x1F,0xFC,0x00,0x0F,0xC0,0x00, +// 'h' +0x68,0x09,0x16,0x15,0x00,0x16, +0x3F,0xC7,0xF9,0x00,0xE0,0x1E,0x03,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x80,0xF0,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x00,0x09,0x80,0x00,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x3C,0x09,0x80,0xF0,0x26,0x02,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x00,0x20,0x1F,0xFF,0xFF,0xFF,0xF7,0xFC,0x00,0x00,0x00, +// 'i' +0x69,0x09,0x0B,0x15,0x00,0x0B, +0x3F,0xC8,0x07,0x81,0x70,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x4C,0x09,0x81,0x30,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x48,0x07,0x00,0xFF,0xEF,0xF8, +// 'j' +0x6A,0x09,0x0F,0x16,0x00,0x0F, +0x03,0xFC,0x08,0x04,0x38,0x08,0x70,0x10,0x60,0x20,0xC0,0x41,0x80,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x08,0x30,0x10,0xA0,0x23,0x00,0x44,0x00,0x98,0x01,0x20,0x00,0xC0,0x09,0x00,0x27,0xC1,0x8F,0xFE,0x0F,0xF0,0x00, +// 'k' +0x6B,0x08,0x17,0x18,0x00,0x17, +0x00,0x01,0x80,0x7F,0xEE,0x81,0x80,0x38,0x87,0x81,0xE0,0x8F,0x03,0x80,0x86,0x06,0x00,0x8C,0x08,0x07,0x18,0x00,0x1C,0x30,0x00,0x70,0x60,0x01,0x00,0xC0,0x02,0x01,0x80,0x02,0x03,0x00,0x04,0x06,0x04,0x04,0x0C,0x0C,0x04,0x18,0x18,0x06,0x30,0x38,0x00,0x60,0x78,0x09,0x00,0x30,0x26,0x00,0x71,0x8F,0xFF,0xE4,0x0F,0xFC,0xD0,0x00,0x01,0xC0,0x00,0x00,0x00, +// 'l' +0x6C,0x09,0x11,0x16,0x00,0x11, +0x3F,0xF0,0x30,0x04,0x1C,0x06,0x0E,0x02,0x03,0x01,0x01,0x80,0x80,0xC0,0x40,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,0xC6,0x03,0xD3,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x00,0xB0,0x00,0x58,0x00,0x2F,0xFF,0xD7,0xFF,0xF0,0x00,0x30, +// 'm' +0x6D,0x09,0x20,0x16,0x00,0x1F, +0x00,0xF8,0x1F,0x00,0x01,0x84,0x30,0x80,0x01,0x82,0x61,0x00,0x01,0x82,0x40,0x00,0x01,0x81,0xC0,0x80,0x01,0x01,0x80,0x80,0x03,0x00,0x80,0x40,0x02,0x00,0x00,0x40,0x06,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x0C,0x00,0x00,0x10,0x08,0x00,0x00,0x10,0x18,0x08,0x08,0x08,0x10,0x18,0x18,0x08,0x30,0x1C,0x1C,0x04,0x60,0x3C,0x3C,0x02,0x70,0x2E,0x2E,0x06,0x7C,0x27,0x4E,0x3C,0x3F,0x27,0xC6,0xF0,0x07,0xC3,0x8F,0x80,0x01,0x83,0x06,0x00, +// 'n' +0x6E,0x09,0x17,0x15,0x00,0x17, +0x3F,0x07,0xFC,0xC1,0x10,0x07,0xC1,0x78,0x1F,0x81,0xF0,0x23,0x01,0xE0,0x46,0x01,0xC0,0x8C,0x01,0x81,0x18,0x01,0x02,0x30,0x00,0x04,0x60,0x00,0x08,0xC0,0x00,0x11,0x80,0x00,0x23,0x02,0x00,0x46,0x06,0x00,0x8C,0x0E,0x01,0x18,0x1E,0x02,0x30,0x3F,0x04,0x60,0x3F,0x0B,0x00,0x2F,0x17,0xFF,0x8F,0xEF,0xFE,0x0F,0x80, +// 'o' +0x6F,0x08,0x17,0x17,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00, +// 'p' +0x70,0x09,0x13,0x15,0x00,0x13, +0x3F,0xFC,0x08,0x00,0x43,0x80,0x06,0x70,0x00,0x46,0x00,0x04,0xC0,0x00,0x18,0x00,0x0B,0x01,0x81,0x60,0x30,0x2C,0x04,0x05,0x80,0x00,0x30,0x00,0x26,0x00,0x08,0xC0,0x02,0x18,0x01,0x83,0x01,0xE0,0x60,0x30,0x08,0x04,0x03,0x00,0x80,0x7F,0xE0,0x07,0xF8,0x00, +// 'q' +0x71,0x09,0x17,0x1C,0x00,0x17, +0x00,0x7E,0x00,0x03,0x01,0x00,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x01,0x08,0x00,0x01,0x30,0x1E,0x02,0x40,0x7E,0x03,0x81,0x1E,0x07,0x02,0x1C,0x0E,0x04,0x18,0x1C,0x04,0x20,0x3C,0x07,0x80,0x78,0x00,0x01,0x30,0x00,0x02,0x70,0x00,0x04,0xF0,0x00,0x10,0xF0,0x00,0x70,0xF0,0x00,0x00,0xFC,0x00,0x40,0xFF,0x81,0x00,0x3F,0x84,0x00,0x0F,0x10,0x00,0x06,0x40,0x00,0x0F,0x00,0x00,0x1C,0x00,0x00,0x00,0x00, +// 'r' +0x72,0x09,0x18,0x17,0x00,0x18, +0x3F,0xFE,0x00,0x60,0x01,0x80,0x70,0x00,0x40,0x70,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x10,0x10,0x30,0x18,0x10,0x30,0x10,0x10,0x30,0x00,0x10,0x30,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x1E,0x30,0x00,0x0A,0x30,0x18,0x06,0x30,0x1C,0x0C,0x20,0x0E,0x18,0x7F,0xFF,0x30,0x7F,0xE7,0x20,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x03,0x00, +// 's' +0x73,0x07,0x11,0x19,0x00,0x11, +0x00,0x06,0x00,0x02,0x80,0x1E,0x40,0x10,0x20,0x30,0x10,0x30,0x08,0x10,0x04,0x18,0x01,0x08,0x00,0x8C,0x0F,0x46,0x07,0xA3,0x01,0xE1,0xC0,0xE1,0xE0,0x41,0x70,0x21,0x80,0x10,0xC0,0x08,0x70,0x08,0x38,0x04,0x0C,0x04,0x06,0x04,0x03,0x3C,0x01,0xFC,0x00,0xF0,0x00,0x30,0x00,0x00, +// 't' +0x74,0x08,0x12,0x16,0x01,0x13, +0x30,0x01,0x93,0xFF,0xDC,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0x00,0x01,0xCC,0x07,0x7F,0x01,0xFF,0xC0,0x79,0xB0,0x1C,0x0C,0x04,0x03,0x01,0x00,0xC0,0x40,0x30,0x10,0x0C,0x04,0x03,0x01,0x00,0xC0,0x60,0x60,0x08,0x1F,0xFC,0x07,0xFE,0x00, +// 'u' +0x75,0x09,0x19,0x16,0xFF,0x18, +0x1F,0xF1,0xFF,0x10,0x05,0x00,0x9C,0x07,0xC0,0xCE,0x02,0xE0,0x43,0x01,0x30,0x21,0x80,0x98,0x10,0xC0,0x4C,0x08,0x60,0x26,0x04,0x30,0x13,0x02,0x18,0x09,0x81,0x0C,0x04,0xC0,0x86,0x02,0x60,0x43,0x01,0x30,0x21,0xC0,0x70,0x10,0xE0,0x00,0x10,0x30,0x00,0x08,0x1C,0x00,0x08,0x0F,0x00,0x08,0x03,0xC0,0x08,0x00,0xFC,0x18,0x00,0x1F,0xF8,0x00,0x03,0xF0,0x00, +// 'v' +0x76,0x07,0x19,0x18,0x00,0x19, +0x00,0xC1,0xC0,0x01,0x91,0x98,0x03,0x18,0xC3,0x06,0x04,0x60,0x64,0x02,0x20,0x1F,0x00,0xB0,0x1B,0xC0,0x70,0x0C,0xF0,0x10,0x08,0x38,0x00,0x08,0x0E,0x00,0x04,0x07,0x00,0x04,0x01,0xC0,0x06,0x00,0xE0,0x02,0x00,0x38,0x02,0x00,0x1C,0x01,0x00,0x07,0x01,0x00,0x03,0x81,0x80,0x00,0xE0,0x80,0x00,0x30,0x80,0x00,0x1C,0x40,0x00,0x06,0x40,0x00,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0x60,0x00, +// 'w' +0x77,0x07,0x20,0x18,0x00,0x20, +0x00,0x60,0x03,0x80,0x01,0x90,0x06,0x60,0x0E,0x10,0xC6,0x1C,0x38,0x11,0xA6,0x07,0x60,0x11,0x26,0x01,0x78,0x12,0x1C,0x06,0x78,0x0E,0x1C,0x04,0x3C,0x0C,0x08,0x08,0x1C,0x00,0x08,0x10,0x0C,0x00,0x00,0x10,0x0E,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x07,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x03,0x80,0x00,0x80,0x03,0x80,0x00,0x80,0x01,0xC0,0x81,0x00,0x01,0xC1,0xC0,0x00,0x00,0xE1,0xC2,0x00,0x00,0xE2,0xE4,0x00,0x00,0x74,0xE4,0x00,0x00,0x7C,0x78,0x00,0x00,0x38,0x78,0x00,0x00,0x30,0x30,0x00, +// 'x' +0x78,0x05,0x19,0x1D,0x00,0x18, +0x00,0x01,0x80,0x00,0x01,0x20,0x00,0x61,0x8C,0x00,0x48,0xC3,0x00,0x44,0x40,0x60,0x43,0x60,0x10,0xC0,0xE0,0x18,0xC0,0x30,0x1C,0xC0,0x00,0x18,0x7C,0x00,0x08,0x1F,0x00,0x08,0x03,0x80,0x08,0x00,0xE0,0x04,0x00,0x38,0x02,0x00,0x0C,0x01,0x80,0x04,0x00,0x60,0x06,0x00,0x10,0x02,0x00,0x07,0x03,0x00,0x00,0x41,0x01,0x00,0x63,0x00,0xC0,0x62,0x00,0xF0,0x63,0x80,0x7C,0x61,0xF0,0x4E,0x60,0x7C,0x63,0xE0,0x0F,0x91,0xE0,0x01,0xF0,0x40,0x00,0x70,0x00,0x00,0x00,0x00,0x00, +// 'y' +0x79,0x06,0x19,0x1B,0x00,0x19, +0x00,0x00,0x60,0x00,0xC0,0x48,0x00,0x80,0x62,0x00,0x88,0x20,0xC0,0x82,0x30,0x11,0x80,0xB0,0x01,0x80,0x30,0x0D,0x80,0x00,0x0C,0xF8,0x00,0x08,0x3E,0x00,0x04,0x07,0x80,0x04,0x01,0xE0,0x04,0x00,0x78,0x04,0x00,0x1C,0x02,0x00,0x0C,0x02,0x00,0x04,0x02,0x00,0x04,0x02,0x00,0x06,0x01,0x00,0x0E,0x01,0x00,0x0C,0x01,0x00,0x07,0x01,0x00,0x03,0xC0,0x80,0x01,0xF0,0x80,0x00,0x3E,0x00,0x00,0x0F,0xC0,0x00,0x03,0xE0,0x00,0x00,0x40,0x00,0x00, +// 'z' +0x7A,0x08,0x13,0x17,0xFF,0x12, +0x0C,0x00,0x02,0xFF,0xFC,0xC0,0x01,0x98,0x00,0x23,0x00,0x04,0x60,0x01,0x0C,0x00,0x21,0x80,0x08,0x37,0x01,0x07,0xE0,0x60,0xF8,0x08,0x03,0x01,0x00,0x40,0x70,0x18,0x0D,0x02,0x00,0x20,0xC0,0x04,0x18,0x00,0x86,0x00,0x10,0xC0,0x02,0x10,0x00,0x47,0xFF,0xE8,0xFF,0xFE,0x00,0x01,0x80, +// '{' +0x7B,0x05,0x0D,0x1F,0x01,0x0E, +0x00,0x10,0x0E,0x81,0x04,0x10,0x21,0x81,0x08,0x08,0xC0,0x46,0x0E,0x30,0x71,0x83,0x0C,0x10,0x60,0x84,0x04,0x60,0x23,0x02,0x18,0x08,0xC0,0x47,0x82,0x3C,0x10,0x60,0x83,0x05,0x18,0x38,0xC0,0x46,0x02,0x38,0x11,0xC0,0x87,0x84,0x1F,0xE0,0x7F,0x00,0x30,0x00,0x00, +// '|' +0x7C,0x1E,0x00,0x00,0x00,0x09, + +// '}' +0x7D,0x04,0x0E,0x1F,0x00,0x0F, +0x30,0x00,0xBC,0x06,0x0C,0x18,0x08,0x60,0x21,0x80,0x46,0x01,0x1F,0x04,0x7C,0x11,0xB0,0x44,0xC1,0x03,0x04,0x0C,0x0C,0x30,0x10,0xE0,0x43,0x81,0x04,0x04,0x30,0x70,0xC1,0x03,0x04,0x0C,0x10,0xF0,0x46,0xC1,0x18,0x04,0x60,0x11,0x80,0x86,0x04,0x18,0x60,0x7F,0x81,0xF8,0x06,0x00,0x00, +// '~' +0x7E,0x1E,0x00,0x00,0x00,0x09, + + +// Terminator +0xFF +}; diff --git a/components/u8g2 b/components/u8g2 deleted file mode 160000 index 5acf0c6..0000000 --- a/components/u8g2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5acf0c652d1ab7fe54d897e809bbb8905f32eca7 diff --git a/components/wifi/CMakeLists.txt b/components/wifi/CMakeLists.txt new file mode 100644 index 0000000..98cbc38 --- /dev/null +++ b/components/wifi/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "wifi.c" + INCLUDE_DIRS "." + REQUIRES nvs_flash) \ No newline at end of file diff --git a/main/Kconfig.projbuild b/components/wifi/Kconfig similarity index 75% rename from main/Kconfig.projbuild rename to components/wifi/Kconfig index 7e23439..1b07f08 100644 --- a/main/Kconfig.projbuild +++ b/components/wifi/Kconfig @@ -1,5 +1,5 @@ # put here your custom config value -menu "Example Configuration" +menu "WIFI AP Configuration" config ESP_WIFI_SSID string "WiFi SSID" default "myssid" @@ -11,4 +11,8 @@ config ESP_WIFI_PASSWORD default "mypassword" help WiFi password (WPA or WPA2) for the example to use. + +config ESP_WIFI_RETRIES + int "WiFi connection retries" + default 5 endmenu diff --git a/components/wifi/wifi.c b/components/wifi/wifi.c new file mode 100644 index 0000000..3fbdec1 --- /dev/null +++ b/components/wifi/wifi.c @@ -0,0 +1,95 @@ +/* + * wifi.c + * + * Created on: 21 Apr 2020 + * Author: Chris + */ + +#include "wifi.h" + +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +static EventGroupHandle_t s_wifi_event_group; +static const char *TAG = "wifi station"; +static int s_retry_num = 0; + +static void event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < CONFIG_ESP_WIFI_RETRIES) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } else { + xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); + } + ESP_LOGI(TAG,"connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + ESP_LOGI(TAG, "got ip:%s", + ip4addr_ntoa(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } +} + +void init_wifi_sta() +{ + //Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + s_wifi_event_group = xEventGroupCreate(); + + tcpip_adapter_init(); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = CONFIG_ESP_WIFI_SSID, + .password = CONFIG_ESP_WIFI_PASSWORD + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); + ESP_ERROR_CHECK(esp_wifi_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + //tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &info); + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID:%s", + CONFIG_ESP_WIFI_SSID); + } else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to SSID:%s", + CONFIG_ESP_WIFI_SSID); + } else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); + } + +} diff --git a/components/wifi/wifi.h b/components/wifi/wifi.h new file mode 100644 index 0000000..563764c --- /dev/null +++ b/components/wifi/wifi.h @@ -0,0 +1,20 @@ +/* + * wifi.h + * + * Created on: 21 Apr 2020 + * Author: Chris + */ + +#ifndef COMPONENTS_WIFI_WIFI_H_ +#define COMPONENTS_WIFI_WIFI_H_ + +#include +#include +#include +#include "freertos/event_groups.h" +#include +#include "nvs_flash.h" + +void init_wifi_sta(); + +#endif /* COMPONENTS_WIFI_WIFI_H_ */ diff --git a/doc/display.pdf b/doc/display.pdf deleted file mode 100644 index bcb1511..0000000 Binary files a/doc/display.pdf and /dev/null differ diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 60f0e66..e6c20ac 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -2,7 +2,7 @@ set(COMPONENT_REQUIRES ) set(COMPONENT_PRIV_REQUIRES ) -set(COMPONENT_SRCS "main.c" "u8g2_esp32_hal.c" "bme280.c") +set(COMPONENT_SRCS "main.c") set(COMPONENT_ADD_INCLUDEDIRS "") register_component() diff --git a/main/main.c b/main/main.c index 50c43ec..65d3c69 100644 --- a/main/main.c +++ b/main/main.c @@ -1,516 +1,39 @@ -#include "bme280.h" -#include "bme280_defs.h" -#include "driver/i2c.h" -#include -#include "u8g2_esp32_hal.h" -#include -#include -#include "freertos/event_groups.h" -#include "nvs_flash.h" -#include -#include - -#define WIFI_SSID "Netzknecht" -#define WIFI_PASS "***REMOVED***" -#define WIFI_RETRIES 10 - -static EventGroupHandle_t s_wifi_event_group; -#define WIFI_CONNECTED_BIT BIT0 -#define WIFI_FAIL_BIT BIT1 - -static const char *TAG = "wifi station"; -static int s_retry_num = 0; - -char cur_value_str[255]; - -/* An HTTP GET handler */ -static esp_err_t hello_get_handler(httpd_req_t *req) -{ - char* buf; - size_t buf_len; - - /* Get header value string length and allocate memory for length + 1, - * extra byte for null termination */ - buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1; - if (buf_len > 1) { - buf = malloc(buf_len); - /* Copy null terminated value string into buffer */ - if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK) { - ESP_LOGI(TAG, "Found header => Host: %s", buf); - } - free(buf); - } - - buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-2") + 1; - if (buf_len > 1) { - buf = malloc(buf_len); - if (httpd_req_get_hdr_value_str(req, "Test-Header-2", buf, buf_len) == ESP_OK) { - ESP_LOGI(TAG, "Found header => Test-Header-2: %s", buf); - } - free(buf); - } - - buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-1") + 1; - if (buf_len > 1) { - buf = malloc(buf_len); - if (httpd_req_get_hdr_value_str(req, "Test-Header-1", buf, buf_len) == ESP_OK) { - ESP_LOGI(TAG, "Found header => Test-Header-1: %s", buf); - } - free(buf); - } - - /* Read URL query string length and allocate memory for length + 1, - * extra byte for null termination */ - buf_len = httpd_req_get_url_query_len(req) + 1; - if (buf_len > 1) { - buf = malloc(buf_len); - if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) { - ESP_LOGI(TAG, "Found URL query => %s", buf); - char param[32]; - /* Get value of expected key from query string */ - if (httpd_query_key_value(buf, "query1", param, sizeof(param)) == ESP_OK) { - ESP_LOGI(TAG, "Found URL query parameter => query1=%s", param); - } - if (httpd_query_key_value(buf, "query3", param, sizeof(param)) == ESP_OK) { - ESP_LOGI(TAG, "Found URL query parameter => query3=%s", param); - } - if (httpd_query_key_value(buf, "query2", param, sizeof(param)) == ESP_OK) { - ESP_LOGI(TAG, "Found URL query parameter => query2=%s", param); - } - } - free(buf); - } - - /* Set some custom headers */ - httpd_resp_set_hdr(req, "Custom-Header-1", "Custom-Value-1"); - httpd_resp_set_hdr(req, "Custom-Header-2", "Custom-Value-2"); - /* Send response with custom headers and body set as the - * string passed in user context*/ - const char* resp_str = cur_value_str; - httpd_resp_send(req, resp_str, strlen(resp_str)); - - /* After sending the HTTP response the old HTTP request - * headers are lost. Check if HTTP request headers can be read now. */ - if (httpd_req_get_hdr_value_len(req, "Host") == 0) { - ESP_LOGI(TAG, "Request headers lost"); - } - return ESP_OK; -} - -static httpd_uri_t hello = { - .uri = "/hello", - .method = HTTP_GET, - .handler = hello_get_handler, - /* Let's pass response string in user - * context to demonstrate it's usage */ - .user_ctx = "Hello World!" -}; - -static httpd_handle_t start_webserver(void) -{ - httpd_handle_t server = NULL; - httpd_config_t config = HTTPD_DEFAULT_CONFIG(); - - // Start the httpd server - ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); - if (httpd_start(&server, &config) == ESP_OK) { - // Set URI handlers - ESP_LOGI(TAG, "Registering URI handlers"); - httpd_register_uri_handler(server, &hello); - return server; - } - - ESP_LOGI(TAG, "Error starting server!"); - return NULL; -} - -static void stop_webserver(httpd_handle_t server) -{ - // Stop the httpd server - httpd_stop(server); -} - -static void disconnect_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) -{ - httpd_handle_t* server = (httpd_handle_t*) arg; - if (*server) { - ESP_LOGI(TAG, "Stopping webserver"); - stop_webserver(*server); - *server = NULL; - } -} - -static void connect_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) -{ - httpd_handle_t* server = (httpd_handle_t*) arg; - if (*server == NULL) { - ESP_LOGI(TAG, "Starting webserver"); - *server = start_webserver(); - } -} - -static void event_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) -{ - if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { - esp_wifi_connect(); - } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { - if (s_retry_num < WIFI_RETRIES) { - esp_wifi_connect(); - s_retry_num++; - ESP_LOGI(TAG, "retry to connect to the AP"); - } else { - xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); - } - ESP_LOGI(TAG,"connect to the AP fail"); - } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; - ESP_LOGI(TAG, "got ip:%s", - ip4addr_ntoa(&event->ip_info.ip)); - s_retry_num = 0; - xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); - } -} - -void wifi_init_sta() -{ - s_wifi_event_group = xEventGroupCreate(); - - tcpip_adapter_init(); - - ESP_ERROR_CHECK(esp_event_loop_create_default()); - - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - - //tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); - //tcpip_adapter_ip_info_t info; - //ip4_addr_t gw; - //gw.addr = ipaddr_addr("192.168.0.1"); - //info.gw = gw; - //ip4_addr_t ip; - //ip.addr = ipaddr_addr("192.168.0.110"); - //info.ip = ip; - //ip4_addr_t netmask; - //netmask.addr = ipaddr_addr("255.255.255.0"); - //info.netmask = netmask; - //tcpip_adapter_sta_start(0, &info); - - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); - - wifi_config_t wifi_config = { - .sta = { - .ssid = WIFI_SSID, - .password = WIFI_PASS - }, - }; - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); - ESP_ERROR_CHECK(esp_wifi_start() ); - - ESP_LOGI(TAG, "wifi_init_sta finished."); - - /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum - * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ - EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, - WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - - //tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &info); - /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually - * happened. */ - if (bits & WIFI_CONNECTED_BIT) { - ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", - WIFI_SSID, WIFI_PASS); - } else if (bits & WIFI_FAIL_BIT) { - ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", - WIFI_SSID, WIFI_PASS); - } else { - ESP_LOGE(TAG, "UNEXPECTED EVENT"); - } - - ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler)); - ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler)); - vEventGroupDelete(s_wifi_event_group); -} - -void i2c_setup() -{ - printf("Setting up I�C driver on port 1... "); - i2c_config_t config; - config.mode = I2C_MODE_MASTER; - config.sda_io_num = 33; - config.sda_pullup_en = GPIO_PULLUP_ENABLE; - config.scl_io_num = 32; - config.scl_pullup_en = GPIO_PULLUP_ENABLE; - config.master.clk_speed = 100000; - i2c_param_config(I2C_NUM_0, &config); - printf("Set driver parameters... "); - esp_err_t err = i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0); - if (err == ESP_OK) - printf("Driver installed!\n"); - else if (err == ESP_ERR_INVALID_ARG) - printf("Driver install failed, invalid arguments!\n"); - else - printf("Driver install failed!\n"); -} - -int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) { - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, dev_id << 1 | I2C_MASTER_WRITE, 1); - i2c_master_write_byte(cmd, reg_addr, 1); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, dev_id << 1 | I2C_MASTER_READ, 1); - if (len > 1) { - i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK); - } - i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK); - i2c_master_stop(cmd); - i2c_master_cmd_begin(I2C_NUM_0, cmd, 500 / portTICK_RATE_MS); - i2c_cmd_link_delete(cmd); - return 0; -} - -int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len) { - //printf("Writing to bus: dev_id=%x, reg_addr=%x, data=%p, length=%u\n", dev_id, reg_addr, data, len); - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (dev_id << 1) | I2C_MASTER_WRITE, 1); - i2c_master_write_byte(cmd, reg_addr, 1); - i2c_master_write(cmd, data, len, 1); - i2c_master_stop(cmd); - i2c_master_cmd_begin(I2C_NUM_0, cmd, 500 / portTICK_RATE_MS); - i2c_cmd_link_delete(cmd); - return 0; -} - -void i2c_delay(uint32_t period) { - vTaskDelay(period / portTICK_PERIOD_MS); -} - -void i2c_shutdown() -{ - printf("Shutting down I�C bus... "); - esp_err_t err = i2c_driver_delete(I2C_NUM_0); - if (err == ESP_ERR_INVALID_ARG) - printf("Failed, invalid arguments!\n"); - else - printf("Success!\n"); -} - -void read_sensor(struct bme280_dev* dev, int32_t* temp, uint32_t* pressure, uint32_t* humidity) { - - uint8_t settings_sel; - uint32_t req_delay; - struct bme280_data comp_data; - - dev->settings.osr_h = BME280_OVERSAMPLING_16X; - dev->settings.osr_p = BME280_OVERSAMPLING_16X; - dev->settings.osr_t = BME280_OVERSAMPLING_16X; - dev->settings.filter = BME280_FILTER_COEFF_16; - - settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL | BME280_OSR_HUM_SEL | BME280_FILTER_SEL; - bme280_set_sensor_settings(settings_sel, dev); - - req_delay = 12*bme280_cal_meas_delay(&(dev->settings)); - - /* Continuously stream sensor data */ - bme280_set_sensor_mode(BME280_FORCED_MODE, dev); - /* Wait for the measurement to complete and print data @25Hz */ - dev->delay_ms(req_delay / portTICK_PERIOD_MS); - bme280_get_sensor_data(BME280_ALL, &comp_data, dev); - *temp = comp_data.temperature; - *pressure = comp_data.pressure; - *humidity = comp_data.humidity; -} - -void read_sensor2(struct bme280_dev* dev, int32_t* temp, uint32_t* pressure, uint32_t* humidity) { - - uint8_t settings_sel; - uint32_t req_delay; - struct bme280_data comp_data; - - dev->settings.osr_h = BME280_OVERSAMPLING_16X; - dev->settings.osr_p = BME280_OVERSAMPLING_16X; - dev->settings.osr_t = BME280_OVERSAMPLING_16X; - dev->settings.filter = BME280_FILTER_COEFF_16; - - settings_sel = BME280_OSR_PRESS_SEL | BME280_OSR_TEMP_SEL | BME280_OSR_HUM_SEL | BME280_FILTER_SEL; - bme280_set_sensor_settings(settings_sel, dev); - /*Calculate the minimum delay required between consecutive measurement based upon the sensor enabled - * and the oversampling configuration. */ - req_delay = 12*bme280_cal_meas_delay(&(dev->settings)); - - bme280_set_sensor_mode(BME280_FORCED_MODE, dev); - /* Wait for the measurement to complete and print data @25Hz */ - dev->delay_ms(req_delay / portTICK_PERIOD_MS); - bme280_get_sensor_data(BME280_ALL, &comp_data, dev); - *temp = comp_data.temperature; - *pressure = comp_data.pressure; - *humidity = comp_data.humidity; -} - -void print_data(u8g2_t* u8g2, int32_t temp_raw, uint32_t pressure_raw, uint32_t humidity_raw, - int32_t temp2_raw, uint32_t pressure2_raw, uint32_t humidity2_raw) { - // Calc temperature pre and post comma values - int32_t temp_pre = temp_raw / 100; - int32_t temp_post = (abs(temp_raw) % 100) / 10; - int32_t temp2_pre = temp2_raw / 100; - int32_t temp2_post = (abs(temp2_raw) % 100) / 10; - - // Calc pressure values - uint32_t press = pressure_raw / 100; - uint32_t press2 = pressure2_raw / 100; - - // Calc humidity pre and post comma values - uint32_t humid_pre = humidity_raw / 1024; - uint32_t humid_post = (humidity_raw - humid_pre*1024) * 10 / 1024; - uint32_t humid2_pre = humidity2_raw / 1024; - uint32_t humid2_post = (humidity2_raw - humid2_pre*1024) * 10 / 1024; - - // Format temperatures - char temp_str[2*(sizeof(int)*8+1)+5] = ""; // "" - char temp_pre_str[sizeof(int)*8+1]; - itoa(temp_pre, temp_pre_str, 10); - char temp_post_str[sizeof(int)*8+1]; - itoa(temp_post, temp_post_str, 10); - char temp2_pre_str[sizeof(int)*8+1]; - itoa(temp2_pre, temp2_pre_str, 10); - char temp2_post_str[sizeof(int)*8+1]; - itoa(temp2_post, temp2_post_str, 10); - if (temp_pre < 10) - strcat(temp_str, " "); // Add space if first temperatur is just one digit long " " - strcat(temp_str, temp_pre_str); // " 1" - strcat(temp_str, ","); // " 1," - strcat(temp_str, temp_post_str); // " 1,3" - strcat(temp_str, " "); // " 1,3 " - if (temp2_pre >= 0) - strcat(temp_str, " "); // Add space if there is no minus sign " 1,3 " - if (temp2_pre < 10) - strcat(temp_str, " "); // Add space if second temperatur is just one digit long " 1,3 " - strcat(temp_str, temp2_pre_str); // " 1,3 7" - strcat(temp_str, ","); // " 1,3 7," - strcat(temp_str, temp2_post_str); // " 1,3 7,2" - strcat(temp_str, " �C"); // " 1,3 7,2 �C" - - // Format temperatures - char humid_str[2*(sizeof(int)*8+1)+5] = ""; // "" - char humid_pre_str[sizeof(int)*8+1]; - itoa(humid_pre, humid_pre_str, 10); - char humid_post_str[sizeof(int)*8+1]; - itoa(humid_post, humid_post_str, 10); - char humid2_pre_str[sizeof(int)*8+1]; - itoa(humid2_pre, humid2_pre_str, 10); - char humid2_post_str[sizeof(int)*8+1]; - itoa(humid2_post, humid2_post_str, 10); - strcat(humid_str, humid_pre_str); // "12" - strcat(humid_str, ","); // "12," - strcat(humid_str, humid_post_str); // "12,5" - strcat(humid_str, " "); // "12,5 " - strcat(humid_str, humid2_pre_str); // "12,5 45" - strcat(humid_str, ","); // "12,5 45," - strcat(humid_str, humid2_post_str); // "12,5 45,23" - strcat(humid_str, " %"); // "12,5 45,23 %" - - // Format pressure - char pressure_str[2*(sizeof(int)*8+1)+5] = ""; // "" - char press1_str[sizeof(int)*8+1]; - itoa(press, press1_str, 10); - char press2_str[sizeof(int)*8+1]; - itoa(press2, press2_str, 10); - if (press < 1000) - strcat(pressure_str, " "); - strcat(pressure_str, press1_str); - strcat(pressure_str, " "); - if (press2 < 1000) - strcat(pressure_str, " "); - strcat(pressure_str, press2_str); - strcat(pressure_str, " hPa"); - - u8g2_ClearBuffer(u8g2); - u8g2_SetFont(u8g2, u8g2_font_profont17_mf); - int8_t fontheight = u8g2_GetAscent(u8g2); - int8_t fontmargin = abs(u8g2_GetDescent(u8g2))+2; - u8g2_DrawStr(u8g2, 0, fontheight, " IN OUT "); - u8g2_DrawStr(u8g2, 0, 2*fontheight + fontmargin, temp_str); - u8g2_DrawStr(u8g2, 0, 3*fontheight + 2*fontmargin, humid_str); - u8g2_DrawStr(u8g2, 0, 4*fontheight + 3*fontmargin, pressure_str); - u8g2_SendBuffer(u8g2); -} +#include "display.h" +#include "sensors.h" +#include "wifi.h" +#include "server.h" +#include "clock.h" +#include void app_main(void) { - int32_t temp = 0; + int32_t temp = -12; uint32_t pressure = 0; uint32_t humidity = 0; int32_t temp2 = 0; uint32_t pressure2 = 0; uint32_t humidity2 = 0; - - // INIT SENSOR - i2c_setup(); - struct bme280_dev dev; - dev.dev_id = 0x76; - dev.intf = BME280_I2C_INTF; - dev.read = i2c_read; - dev.write = i2c_write; - dev.delay_ms = i2c_delay; - bme280_init(&dev); - - // INIT SENSOR2 - struct bme280_dev dev2; - dev2.dev_id = 0x77; - dev2.intf = BME280_I2C_INTF; - dev2.read = i2c_read; - dev2.write = i2c_write; - dev2.delay_ms = i2c_delay; - bme280_init(&dev2); - - // INIT DISPLAY - u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT; - u8g2_esp32_hal.sda = 18; - u8g2_esp32_hal.scl = 19; - - u8g2_esp32_hal_init(u8g2_esp32_hal); - u8g2_t u8g2; - u8g2_Setup_ssd1306_i2c_128x64_vcomh0_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, - u8g2_esp32_gpio_and_delay_cb); - u8x8_SetI2CAddress(&u8g2.u8x8,0x3C << 1); - u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this, - u8g2_SetPowerSave(&u8g2, 0); // wake up display - - // INIT WIFI - //Initialize NVS - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); - wifi_init_sta(); - - // INIT WEBSERVER - static httpd_handle_t server = NULL; - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server)); - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server)); - server = start_webserver(); - + time_str_t time; + + init_sensors(); + init_display(); + init_wifi_sta(); + init_server(); + init_clock(); + + /* Draw the whole screen one time */ + get_time(&time); + read_sensor(&temp, &pressure, &humidity); + read_sensor2(&temp2, &pressure2, &humidity2); + display_data(temp, pressure, humidity, temp2, pressure2, humidity2, time); while (1) { - read_sensor(&dev, &temp, &pressure, &humidity); - read_sensor(&dev2, &temp2, &pressure2, &humidity2); - printf("%i �c, %i hPa, %i %%\r\n", temp, pressure, humidity); - printf("%i �c, %i hPa, %i %%\r\n", temp2, pressure2, humidity2); - print_data(&u8g2, temp, pressure, humidity, temp2, pressure2, humidity2); - vTaskDelay(250 / portTICK_PERIOD_MS); + get_time(&time); + read_sensor(&temp, &pressure, &humidity); + read_sensor2(&temp2, &pressure2, &humidity2); + server_set_values(temp, pressure, humidity, temp2, pressure2, humidity2); + update_data(temp, pressure, humidity, temp2, pressure2, humidity2, time); + vTaskDelay(500 / portTICK_PERIOD_MS); } } diff --git a/main/u8g2_esp32_hal.c b/main/u8g2_esp32_hal.c deleted file mode 100644 index 72ae016..0000000 --- a/main/u8g2_esp32_hal.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include - -#include "sdkconfig.h" -#include "esp_log.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "u8g2_esp32_hal.h" - -static const char *TAG = "u8g2_hal"; -static const unsigned int I2C_TIMEOUT_MS = 1000; - -static i2c_cmd_handle_t handle_i2c; // I2C handle. -static u8g2_esp32_hal_t u8g2_esp32_hal; // HAL state data. - -#undef ESP_ERROR_CHECK -#define ESP_ERROR_CHECK(x) do { esp_err_t rc = (x); if (rc != ESP_OK) { ESP_LOGE("err", "esp_err_t = %d", rc); assert(0 && #x);} } while(0); - -/* - * Initialze the ESP32 HAL. - */ -void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param) { - u8g2_esp32_hal = u8g2_esp32_hal_param; -} // u8g2_esp32_hal_init - -/* - * HAL callback function as prescribed by the U8G2 library. This callback is invoked - * to handle I2C communications. - */ -uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { - //ESP_LOGD(TAG, "i2c_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr); - - switch(msg) { - case U8X8_MSG_BYTE_SET_DC: { - if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) { - gpio_set_level(u8g2_esp32_hal.dc, arg_int); - } - break; - } - - case U8X8_MSG_BYTE_INIT: { - if (u8g2_esp32_hal.sda == U8G2_ESP32_HAL_UNDEFINED || - u8g2_esp32_hal.scl == U8G2_ESP32_HAL_UNDEFINED) { - break; - } - - i2c_config_t conf; - conf.mode = I2C_MODE_MASTER; - ESP_LOGI(TAG, "sda_io_num %d", u8g2_esp32_hal.sda); - conf.sda_io_num = u8g2_esp32_hal.sda; - conf.sda_pullup_en = GPIO_PULLUP_ENABLE; - ESP_LOGI(TAG, "scl_io_num %d", u8g2_esp32_hal.scl); - conf.scl_io_num = u8g2_esp32_hal.scl; - conf.scl_pullup_en = GPIO_PULLUP_ENABLE; - ESP_LOGI(TAG, "clk_speed %d", I2C_MASTER_FREQ_HZ); - conf.master.clk_speed = I2C_MASTER_FREQ_HZ; - ESP_LOGI(TAG, "i2c_param_config %d", conf.mode); - ESP_ERROR_CHECK(i2c_param_config(I2C_MASTER_NUM, &conf)); - ESP_LOGI(TAG, "i2c_driver_install %d", I2C_MASTER_NUM); - ESP_ERROR_CHECK(i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0)); - break; - } - - case U8X8_MSG_BYTE_SEND: { - uint8_t* data_ptr = (uint8_t*)arg_ptr; - ESP_LOG_BUFFER_HEXDUMP(TAG, data_ptr, arg_int, ESP_LOG_VERBOSE); - - while( arg_int > 0 ) { - ESP_ERROR_CHECK(i2c_master_write_byte(handle_i2c, *data_ptr, ACK_CHECK_EN)); - data_ptr++; - arg_int--; - } - break; - } - - case U8X8_MSG_BYTE_START_TRANSFER: { - uint8_t i2c_address = u8x8_GetI2CAddress(u8x8); - handle_i2c = i2c_cmd_link_create(); - ESP_LOGD(TAG, "Start I2C transfer to %02X.", i2c_address>>1); - ESP_ERROR_CHECK(i2c_master_start(handle_i2c)); - ESP_ERROR_CHECK(i2c_master_write_byte(handle_i2c, i2c_address | I2C_MASTER_WRITE, ACK_CHECK_EN)); - break; - } - - case U8X8_MSG_BYTE_END_TRANSFER: { - ESP_LOGD(TAG, "End I2C transfer."); - ESP_ERROR_CHECK(i2c_master_stop(handle_i2c)); - ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, handle_i2c, I2C_TIMEOUT_MS / portTICK_RATE_MS)); - i2c_cmd_link_delete(handle_i2c); - break; - } - } - return 0; -} // u8g2_esp32_i2c_byte_cb - -/* - * HAL callback function as prescribed by the U8G2 library. This callback is invoked - * to handle callbacks for GPIO and delay functions. - */ -uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { - ESP_LOGD(TAG, "gpio_and_delay_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr); - - switch(msg) { - // Initialize the GPIO and DELAY HAL functions. If the pins for DC and RESET have been - // specified then we define those pins as GPIO outputs. - case U8X8_MSG_GPIO_AND_DELAY_INIT: { - uint64_t bitmask = 0; - if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) { - bitmask = bitmask | (1ull<