Code:
#include "ILI9341_T4.h"
#define PIN_SCK 13
#define PIN_MISO 12
#define PIN_MOSI 11
#define PIN_DC 10
#define PIN_CS 9
#define PIN_RESET 8
#define PIN_BACKLIGHT 255
#define PIN_TOUCH_CS 7
#define PIN_TOUCH_IRQ 6
#define SPI_SPEED 115000000 /* SPI Speed */
#define LX 320
#define LY 240
ILI9341_T4::DiffBuffStatic<8192> diff1;
ILI9341_T4::DiffBuffStatic<8192> diff2;
DMAMEM uint16_t internal_fb[LX * LY];
ILI9341_T4::ILI9341Driver tft(PIN_CS, PIN_DC, PIN_SCK, PIN_MOSI, PIN_MISO, PIN_RESET, PIN_TOUCH_CS, PIN_TOUCH_IRQ);
#define BUF_LY 40
#include "lvgl.h"
#include "ui.h"
lv_color_t lvgl_buf[LX * BUF_LY]; // memory for lvgl draw buffer (25KB)
lv_disp_draw_buf_t draw_buf; // lvgl 'draw buffer' object
lv_disp_drv_t disp_drv; // lvgl 'display driver'
lv_indev_drv_t touch_indev_drv; // lvgl 'input device driver'
lv_indev_drv_t enc_indev_drv;
lv_disp_t* disp; // pointer to lvgl display object
void my_disp_flush(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) {
const bool redraw_now = lv_disp_flush_is_last(disp); // check if when should update the screen (or just buffer the changes).
tft.updateRegion(redraw_now, (uint16_t*)color_p, area->x1, area->x2, area->y1, area->y2); // update the interval framebuffer and then redraw the screen if requested
lv_disp_flush_ready(disp); // tell lvgl that we are done and that the lvgl draw buffer can be reused immediately
}
void touch_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data) {
int touchX, touchY, touchZ;
bool touched = tft.readTouch(touchX, touchY, touchZ); // read the touchpad
if (!touched) { // nothing
data->state = LV_INDEV_STATE_REL;
} else { // pressed
data->state = LV_INDEV_STATE_PR;
data->point.x = touchX;
data->point.y = touchY;
}
}
#define PIN_BUZZER 27
#define PIN_ENCODE_A 25
#define PIN_ENCODE_B 24
#define PIN_ENCODE_BTN 26
long enc_current_position = 1;
long enc_last_position = 0;
#include <RotaryEncoder.h> // https://github.com/mathertel/RotaryEncoder
RotaryEncoder encoder(PIN_ENCODE_A, PIN_ENCODE_B, RotaryEncoder::LatchMode::TWO03);
void enc_read(lv_indev_drv_t* drv, lv_indev_data_t* data) {
enc_current_position = encoder.getPosition();
data->enc_diff = enc_current_position - enc_last_position;
if (enc_current_position != enc_last_position) {
tone(PIN_BUZZER, 3200, 2);
}
enc_last_position = enc_current_position;
data->state = digitalRead(PIN_ENCODE_BTN) ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;
}
void enc_update() {
encoder.tick();
}
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioPlaySdWav playSdWav1; //xy=514,381
AudioOutputI2S2 i2s2_1; //xy=683,378
AudioConnection patchCord1(playSdWav1, 0, i2s2_1, 0);
AudioConnection patchCord2(playSdWav1, 1, i2s2_1, 1);
void show_err(const char* err, const char* details) {
lv_obj_t* error_label = lv_label_create(lv_scr_act());
lv_label_set_long_mode(error_label, LV_LABEL_LONG_WRAP); /*Break the long lines*/
lv_label_set_recolor(error_label, true); /*Enable re-coloring by commands in the text*/
lv_label_set_text_fmt(error_label, "#d63227 ERROR:# #bababa %s #\n\n"
"#0088ff Details:# %s",
err, details);
lv_obj_set_width(error_label, 280);
lv_obj_set_style_text_align(error_label, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_align(error_label, LV_ALIGN_CENTER, 0, 0);
lv_task_handler();
lv_task_handler();
lv_task_handler();
lv_task_handler();
lv_task_handler();
while (1) { /* Halt the system */
tone(PIN_BUZZER, 300, 200);
delay(300);
tone(PIN_BUZZER, 500, 200);
delay(300);
tone(PIN_BUZZER, 680, 200);
delay(3000);
}
}
void err_tone() {
tone(PIN_BUZZER, 300, 200);
delay(300);
tone(PIN_BUZZER, 500, 200);
delay(300);
tone(PIN_BUZZER, 680, 200);
delay(3000);
}
void setup() {
tone(PIN_BUZZER, 1800, 200);
pinMode(PIN_ENCODE_BTN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PIN_ENCODE_A), enc_update, CHANGE);
attachInterrupt(digitalPinToInterrupt(PIN_ENCODE_B), enc_update, CHANGE);
Serial.begin(9600);
AudioMemory(128);
tft.output(&Serial); // send debug info to serial port.
while (!tft.begin(SPI_SPEED)) err_tone(); // init
tft.setFramebuffer(internal_fb); // set the internal framebuffer
tft.setDiffBuffers(&diff1, &diff2); // set the diff buffers
tft.setRotation(1); // portrait mode 0 : 240x320
tft.setDiffGap(4); // with have large 8K diff buffers so we can use a small gap.
tft.setVSyncSpacing(1); // lvgl is already controlling framerate: we just set this to 1 to minimize screen tearing.
tft.setRefreshRate(100); // 100Hz refresh, why not...
int tft_cal_data[] = { 369, 3672, 3852, 465 };
tft.setTouchCalibration(tft_cal_data);
lv_init();
lv_disp_draw_buf_init(&draw_buf, lvgl_buf, nullptr, LX * BUF_LY);
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = LX;
disp_drv.ver_res = LY;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
disp = lv_disp_drv_register(&disp_drv);
disp->refr_timer->period = 10;
lv_indev_drv_init(&touch_indev_drv);
touch_indev_drv.type = LV_INDEV_TYPE_POINTER;
touch_indev_drv.read_cb = touch_read;
lv_indev_drv_register(&touch_indev_drv);
/* Register encoder indev driver */
lv_indev_drv_init(&enc_indev_drv);
enc_indev_drv.type = LV_INDEV_TYPE_ENCODER;
enc_indev_drv.read_cb = enc_read;
lv_indev_drv_register(&enc_indev_drv);
lv_disp_t* dispp = lv_disp_get_default();
lv_theme_t* theme = lv_theme_default_init(dispp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_LIGHT_BLUE),
true, LV_FONT_DEFAULT);
lv_disp_set_theme(dispp, theme);
if (!(SD.begin(BUILTIN_SDCARD))) {
show_err("Unable to begin the SD card", "Unable to begin the SD card, please check the connections and if the card is inserted.");
}
ui_init();
tone(PIN_BUZZER, 900, 200);
playSdWav1.play("SONG.WAV");
}
void loop() {
lv_task_handler(); // lvgl gui handler
delay(20);
}