Hallo ??
Sometimes I have to go away and eat, and stuff like that...I need help, please. Where is the error?
You're looking at the "master" branch, whereas we're using the "/dev/big-screen-t4" one.Looking in the @h4yn0nnym0u5e repository for the referenced ST7735_t3 library, the source for ST7735_t3.cpp currently only goes to line 4782.
So ... did the Arduino sketch start working for you?I imported the working Arduino file into PlatformIO and encountered the same error when compiling. I don't know why grrrrr
_dma_data[_spi_num]._pDMAtx->begin(true);
if ((mcu_x + win_w) <= tft.width() && (mcu_y + win_h) <= tft.height())
{
// open a window onto the screen to paint the pixels into
tft.setAddrWindow(mcu_y, mcu_x, mcu_x + win_w - 1, mcu_y + win_h - 1);
// push all the image block pixels to the screen
while (mcu_pixels--)
tft.pushColor(*pImg++); // Send to TFT 16 bits at a time
}
Not sure how well it would work for you, but the Jpeg decoder I have played with is:This the TJpg_Decoder lib https://github.com/Bodmer/TJpg_Decoder.git
#ifdef __JPEGDEC__
JPEGDEC jpeg;
void processJPGFile(const char *name, bool fErase) {
Serial.println();
Serial.print(F("Loading JPG image '"));
Serial.print(name);
Serial.println('\'');
uint8_t scale = 1;
if (jpeg.open(name, myOpen, myClose, myReadJPG, mySeekJPG, JPEGDraw)) {
int image_width = jpeg.getWidth();
int image_height = jpeg.getHeight();
int decode_options = 0;
Serial.printf("Image size: %dx%d", image_width, image_height);
switch (g_JPGScale) {
case 1:
scale = 1;
decode_options = 0;
break;
case 2:
scale = 2;
decode_options = JPEG_SCALE_HALF;
break;
case 4:
scale = 4;
decode_options = JPEG_SCALE_QUARTER;
break;
case 8:
scale = 8;
decode_options = JPEG_SCALE_EIGHTH;
break;
default:
{
if ((image_width > g_jpg_scale_x_above[SCL_16TH]) || (image_height > g_jpg_scale_y_above[SCL_16TH])) {
decode_options = JPEG_SCALE_EIGHTH | JPEG_SCALE_HALF;
scale = 16;
} else if ((image_width > g_jpg_scale_x_above[SCL_EIGHTH]) || (image_height > g_jpg_scale_y_above[SCL_EIGHTH])) {
decode_options = JPEG_SCALE_EIGHTH;
scale = 8;
} else if ((image_width > g_jpg_scale_x_above[SCL_QUARTER]) || (image_height > g_jpg_scale_y_above[SCL_QUARTER])) {
decode_options = JPEG_SCALE_QUARTER;
scale = 4;
} else if ((image_width > g_jpg_scale_x_above[SCL_HALF]) || (image_height > g_jpg_scale_y_above[SCL_HALF])) {
decode_options = JPEG_SCALE_HALF;
scale = 2;
}
}
}
if (fErase && ((image_width / scale < g_tft_width) || (image_height / scale < g_tft_height))) {
FillScreen((uint16_t)g_background_color);
}
if (g_center_image) {
g_image_offset_x = (g_tft_width - image_width / scale) / 2;
g_image_offset_y = (g_tft_height - image_height / scale) / 2;
} else {
g_image_offset_x = 0;
g_image_offset_y = 0;
}
g_image_scale = scale;
Serial.printf("Scale: 1/%d Image Offsets (%d, %d)\n", g_image_scale, g_image_offset_x, g_image_offset_y);
jpeg.decode(0, 0, decode_options);
jpeg.close();
} else {
Serial.println("Was not a valid jpeg file");
}
}
int32_t myReadJPG(JPEGFILE *handle, uint8_t *buffer, int32_t length) {
if (!myfile) return 0;
return myfile.read(buffer, length);
}
int32_t mySeekJPG(JPEGFILE *handle, int32_t position) {
if (!myfile) return 0;
return myfile.seek(position);
}
int JPEGDraw(JPEGDRAW *pDraw) {
if (g_debug_output) Serial.printf("jpeg draw: x,y=%d,%d, cx,cy = %d,%d\n",
pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight);
writeClippedRect(pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight, pDraw->pPixels);
return 1;
}
#endif
// Function to draw pixels to the display
void JPEGDraw(JPEGDRAW *pDraw) {
//Serial.printf("jpeg draw: x,y=%d,%d, cx,cy = %d,%d\n",
//pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight);
tft.writeRect(pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight, pDraw->pPixels);
}
if (jpeg.open((const char *)name, myOpen, myClose, myRead, mySeek, JPEGDraw))
{
jpeg.decode(0, 0, 0);
jpeg.close();
tft.updateScreenAsync();
}
else
{
Serial.print("error = ");
Serial.println(jpeg.getLastError(), DEC);
}
/*
Jeannie II
Polyphonic DIY Synthesizer/Sampler
(c) by Rolf Degen and Andre' Laska März 2026
*/
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 8
#define TFT_CS 10
#define TFT_RST 9
#define TFT_BL 28 // TFT Backlight
// LED chip 74HC595
#define LED_latchPin 30
#define LED_clockPin 31
#define LED_dataPin 32
#define LED_oePin 29
// Keys Interrupt
int PIN_ENC_INT = 25;
#define BUILTIN_SDCARD 254
#include <Arduino.h>
#include <ST7796_t3.h> // Hardware-specific library
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_MCP23X17.h>
#include <avr/interrupt.h>
#include <JPEGDEC.h>
JPEGDEC jpeg;
// For 3.5" or 4.0" TFT with ST7796
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);
// FrameBuffer is located in Teensy4.1 Ram2
#define TFT_height 320
#define TFT_width 480
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];
// CS SDCARD
#define BUILTIN_SDCARD 254
// this function determines the minimum of two numbers
#define minimum(a, b) (((a) < (b)) ? (a) : (b))
// Timer
elapsedMillis updateScreen_Timer = 0;
elapsedMillis Timer_1 = 0;
elapsedMillis Key_debounce_Timer = 0;
uint32_t LED_States = 0b000000000000000000000000;
Adafruit_MCP23X17 mcp0; // 1st MCP Key 1-16
Adafruit_MCP23X17 mcp1; // 2nd MCP Key 17-24
Adafruit_MCP23X17 mcp3; // 2nd MCP Encoder
boolean enc_action = false;
uint16_t mcp0_Status = 0xFFFF;
uint16_t mcp0_oldStatus = 0xFFFF;
uint16_t mcp1_Status = 0xFFFF;
uint16_t mcp1_oldStatus = 0xFFFF;
uint16_t mcp2_Status = 0xFFFF;
uint16_t mcp2_oldStatus = 0xFFFF;
uint8_t KeyFunction_State[24]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
File myfile;
void *myOpen(const char *filename, int32_t *size)
{
myfile = SD.open(filename);
*size = myfile.size();
return &myfile;
}
void myClose(void *handle)
{
if (myfile)
myfile.close();
}
int32_t myRead(JPEGFILE *handle, uint8_t *buffer, int32_t length)
{
if (!myfile)
return 0;
return myfile.read(buffer, length);
}
int32_t mySeek(JPEGFILE *handle, int32_t position)
{
if (!myfile)
return 0;
return myfile.seek(position);
}
// Jpeg Image draw ---------------------------------------------
void JPEGDraw(JPEGDRAW *pDraw)
{
// Serial.printf("jpeg draw: x,y=%d,%d, cx,cy = %d,%d\n",
// pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight);
tft.writeRect(pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight, pDraw->pPixels);
}
// init LED Status ----------------------------------------------
void init_LEDs()
{
uint32_t data = 1;
uint32_t multipl = 1;
// take the latchPin low so
// the LEDs don't change while you're sending in bits:
for (size_t i = 0; i < 24; i++)
{
digitalWrite(LED_latchPin, LOW);
// shift out highbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (data >> 16));
// shift out middelbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (data >> 8));
// shift out lowbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, data);
// take the latch pin high so the LEDs will light up:
digitalWrite(LED_latchPin, HIGH);
digitalWrite(LED_oePin, HIGH);
delay(15);
multipl *= 2;
data = data + multipl;
}
}
// --------------------------------------------------------------
// set LED
// n = LED-No 0 - 23
// state = 1 = on / 0 = off
// --------------------------------------------------------------
void set_LED(uint8_t n, bool state)
{
uint32_t maske = 0;
if (state)
{
LED_States |= (1 << n); // set LED
}
else
{
maske = ~(1 << n);
LED_States &= maske; // clear LED
}
for (size_t i = 0; i < 24; i++)
{
digitalWrite(LED_latchPin, LOW);
// shift out highbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (LED_States >> 16));
// shift out middelbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (LED_States >> 8));
// shift out lowbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, LED_States);
// take the latch pin high so the LEDs will light up:
digitalWrite(LED_latchPin, HIGH);
digitalWrite(LED_oePin, HIGH);
}
}
// init LED Status ----------------------------------------------
void LEDs_off()
{
uint32_t data = 0xFFFFFF - 1;
uint32_t multipl = 1;
// take the latchPin low so
// the LEDs don't change while you're sending in bits:
for (size_t i = 0; i < 24; i++)
{
digitalWrite(LED_latchPin, LOW);
// shift out highbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (data >> 16));
// shift out middelbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (data >> 8));
// shift out lowbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, data);
// take the latch pin high so the LEDs will light up:
digitalWrite(LED_latchPin, HIGH);
digitalWrite(LED_oePin, HIGH);
delay(15);
multipl *= 2;
data = data - multipl;
}
}
// Rotary Encoder interrupt ------------------------------------
void Encoders_Interrupt()
{
enc_action = true;
}
// Key fuction -------------------------------------------------
void Key1_function(bool state)
{
if (!state)
{
set_LED(22, state);
tft.waitUpdateAsyncComplete();
tft.fillRect(0, 30, 220, 25, ST7735_BLACK);
tft.updateScreenAsync();
}
else
{
set_LED(22, state);
tft.waitUpdateAsyncComplete();
tft.fillRect(0, 30, 220, 25, ST7735_GREEN);
tft.updateScreenAsync();
}
}
void Key2_function(bool state)
{
if (!state)
{
set_LED(23, state);
tft.waitUpdateAsyncComplete();
tft.fillRect(0, 30, 220, 25, ST7735_BLACK);
tft.updateScreenAsync();
}
else
{
set_LED(23, state);
tft.waitUpdateAsyncComplete();
tft.fillRect(0, 30, 220, 25, ST7735_RED);
tft.updateScreenAsync();
}
}
// read Keys ---------------------------------------------------
void read_keys()
{
if (Key_debounce_Timer >= 50) // Key debounce
{
Key_debounce_Timer = 0;
if (enc_action == true)
{
enc_action = false;
mcp0_Status = mcp0.readGPIOAB();
if (mcp0_Status == mcp0_oldStatus)
return;
for (byte i = 0; i < 16; i++)
{
bool n = bitRead(mcp0_Status, i);
if (n != bitRead(mcp0_oldStatus, i))
{
// i = function-no / n = state (low-active)
if (KeyFunction_State[i] == 0 && n == 0)
{
switch (i)
{
case 0:
Key1_function(0);
break;
case 1:
Key2_function(0);
break;
case 8:
Serial.println("KEY 8");
break;
}
KeyFunction_State[i] = 1;
}
else if (KeyFunction_State[i] == 1 && n == 0)
{
switch (i)
{
case 0:
Key1_function(1);
break;
case 1:
Key2_function(1);
break;
}
KeyFunction_State[i] = 0;
}
}
}
mcp0_oldStatus = mcp0_Status;
}
}
}
void setup(void)
{
Serial.begin(9600);
// init io pins
pinMode(TFT_BL, OUTPUT); // TFT Backligth
pinMode(LED_latchPin, OUTPUT); // LED
pinMode(LED_clockPin, OUTPUT); // LED
pinMode(LED_dataPin, OUTPUT); // LED
pinMode(LED_oePin, OUTPUT); // LED
digitalWrite(TFT_BL, LOW); // TFT_BL off
digitalWrite(LED_oePin, LOW); // LED off
// init TFT Touchscreen and 300KB FrameBuffer into Teensy4.1 RAM2
tft.setFrameBuffer(FrameBuffer);
tft.init(320, 480);
tft.setRotation(1);
tft.invertDisplay(true);
tft.useFrameBuffer(true);
tft.fillScreen(ST7735_BLACK);
tft.updateScreenAsync();
init_LEDs(); // all LEDs on
LEDs_off(); // all LEDs off
digitalWrite(TFT_BL, HIGH); // TFT_Backlight on
// init Key/Encoder IO Expander
mcp0.begin_I2C(0x21, &Wire1); // Addr 0x20-0x27
mcp1.begin_I2C(0x22, &Wire1);
// init Wire1 for Encoders
Wire1.begin();
Wire1.setClock(400000UL); // I2C speed 400KHz
// init MPC23017 Expander for Encoders & Keys
mcp0.setupInterrupts(true, false, LOW);
for (size_t i = 0; i < 16; i++)
{
mcp0.pinMode(i, INPUT_PULLUP);
mcp0.setupInterruptPin(i, CHANGE);
}
mcp0.getCapturedInterrupt();
mcp0.readGPIOAB();
mcp0.clearInterrupts();
attachInterrupt(digitalPinToInterrupt(PIN_ENC_INT), Encoders_Interrupt, FALLING);
// init SDcard
tft.setTextColor(ST7735_WHITE);
tft.setTextSize(2);
tft.setCursor(0, 5);
const int chipSelect = BUILTIN_SDCARD;
if (!SD.begin(chipSelect))
{
tft.print(F("SD-Card not connected!"));
tft.updateScreenAsync();
while (1);
}
else
{
tft.print(F("SD-Card initialized"));
tft.updateScreenAsync();
}
delay(1000);
tft.fillScreen(ST7735_BLACK);
tft.setCursor(0, 5);
tft.print(F("Load boot screen.."));
tft.updateScreenAsync();
delay(500);
}
void loop()
{
int filecount = 0;
tft.setCursor(0, 0);
File dir = SD.open("/");
while (true)
{
File entry = dir.openNextFile();
if (!entry)
break;
if (entry.isDirectory() == false)
{
const char *name = entry.name();
const int len = strlen(name);
if (len > 3 && strcasecmp(name + len - 3, "JPG") == 0)
{
Serial.print("File: ");
Serial.println(name);
tft.print("File: ");
tft.println(name);
if (jpeg.open((const char *)name, myOpen, myClose, myRead, mySeek, JPEGDraw))
{
jpeg.decode(0, 0, 0);
jpeg.close();
tft.updateScreenAsync();
}
else
{
Serial.print("error = ");
Serial.println(jpeg.getLastError(), DEC);
}
filecount = filecount + 1;
delay(2000);
tft.fillScreen(ST7735_BLACK);
}
}
entry.close();
}
if (filecount == 0)
{
Serial.println("No .JPG files found");
tft.println("No .JPG files found");
delay(2000);
}
}
if (jpeg.open((const char *)name, myOpen, myClose, myRead, mySeek, JPEGDraw))
{
jpeg.decode(0, 0, 0);
jpeg.close();
tft.updateScreenAsync();
}
else
{
Serial.print("error = ");
Serial.println(jpeg.getLastError(), DEC);
}
filecount = filecount + 1;
delay(2000);
tft.fillScreen(ST7735_BLACK);
/*
Jeannie II
Polyphonic DIY Synthesizer/Sampler
(c) by Rolf Degen and Andre' Laska März 2026
Version 27.03.2026
*/
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 8
#define TFT_CS 10
#define TFT_RST 9
#define TFT_BL 28 // TFT Backlight
// LED chip 74HC595
#define LED_latchPin 30
#define LED_clockPin 31
#define LED_dataPin 32
#define LED_oePin 29
#define LED_Patch 4
#define LED_OSC 5
#define LED_Mixer 6
#define LED_Filter 7
#define LED_ENV 8
// U9 GPIO Pin Register
#define Key_Patch 6
#define Key_OSC 8
#define Key_Mixer 9
// U10 MCP23017 Encoder Pin
#define enc1_A 256 // GPB0
#define enc1_B 512 // GPB1
#define enc2_A 1024 // GPB2
#define enc2_B 2048 // GPB3
#define enc3_A 4096 // GPB4
#define enc3_B 8192 // GPB5
#define enc4_A 16384 // GPB6
#define enc4_B 0 // GPA0
#define enc5_A 1 // GPA1
#define enc5_B 2 // GPA2
#define enc6_A 4 // GPA3
#define enc6_B 8 // GPA4
#define enc7_A 16 // GPA5
#define enc7_B 32 // GPA6
#define on 1
#define off 0
// SDcard
#define BUILTIN_SDCARD 254
#include <Arduino.h>
#include <ST7796_t3.h> // Hardware-specific library
#include <SD.h>
#include <SPI.h>
#include <Wire.h>
#include <avr/interrupt.h>
#include <JPEGDEC.h>
#include <InternalTemperature.h>
#include <GUI.h>
#include <ArduinoJson.h>
#include <FT6336U.h>
#include <st7735_t3_font_OpenSans.h>
#include <Adafruit_MCP23X17.h>
// Jpeg Image encoder
JPEGDEC jpeg;
// For 3.5" TFT with ST7796S
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);
// Touch Controller
#define I2C_SDA 18
#define I2C_SCL 19
#define RST_N_PIN 16
#define INT_N_PIN 33
FT6336U ft6336u(I2C_SDA, I2C_SCL, RST_N_PIN, INT_N_PIN);
// FrameBuffer is located in Teensy4.1 Ram2
#define TFT_height 320
#define TFT_width 480
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];
// CS SDCARD
#define BUILTIN_SDCARD 254
// Timer
elapsedMillis updateScreen_Timer = 0;
elapsedMillis Timer_1 = 0;
elapsedMillis Key_debounce_Timer = 0;
uint32_t LED_States = 0b000000000000000000000000;
Adafruit_MCP23X17 mcp0; // 1st MCP Key 1-16
Adafruit_MCP23X17 mcp1; // 2nd MCP Key 17-24
Adafruit_MCP23X17 mcp3; // 2nd MCP Encoder
uint8_t PIN_KEY_INT = 25; // Keys Interrupt
uint8_t PIN_TS_INT = 33; // Touch controller
uint8_t PIN_ENC_INT = 34; // Encoder Interrupt
boolean key_action = false;
boolean ts_action = false;
boolean enc_action = false;
uint8_t old_ts_event_1 = 0;
uint16_t mcp0_Status = 0xFFFF;
uint16_t mcp0_oldStatus = 0xFFFF;
uint16_t mcp1_Status = 0xFFFF;
uint16_t mcp1_oldStatus = 0xFFFF;
uint16_t mcp2_Status = 0xFFFF;
uint16_t mcp2_oldStatus = 0xFFFF;
uint8_t KeyFunction_State[24]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t loopCount = 0;
uint8_t Menu_page = 1;
// Encoders variable
volatile uint16_t current_GPIO1 = 0;
uint16_t old_GPIO1 = 0;
int16_t Enc_Pos[7]= {0,0,0,0,0,0,0};
uint16_t currentClkState[7] = {0,0,0,0,0,0,0};
uint8_t Enc_B[7] = {0,0,0,0,0,0,0};
uint16_t lastClkState[7] = {0,0,0,0,0,0,0};
unsigned long lastInterruptTime = 0;
int accelerationFactor = 1;
// Special colors
extern uint16_t tab_color_green;
extern uint16_t tab_color_grey;
extern uint16_t tab_color_red;
extern uint16_t light_grey;
extern uint16_t dark_grey;
extern uint16_t text_color_2;
/*
// read file directory -----------------------------------------
FLASHMEM void render_Preset_List(String preset_bank, uint8_t start_entry)
{
JsonDocument doc;
File dataFile;
preset_list_start_pointer = start_entry; // save start_pointer
start_entry += 1;
String nameString_1 = "/PATCH/BANK_" + preset_bank + "/PRESET_";
String nameString_2 = "/Data.json";
uint8_t number_of_entries = 7;
uint8_t count = start_entry + number_of_entries;
uint8_t ID_no = 0;
for (uint8_t i = start_entry; i < count; i++)
{
String countString = String(i);
String filenameString = nameString_1 + countString + nameString_2;
// convert String into char-Array
char filename_[filenameString.length() + 1];
filenameString.toCharArray(filename_, sizeof(filename_));
File dataFile = SD.open(filename_, FILE_READ); // open "Data.json" file
if (!dataFile)
{
Serial.println("error opening Data.json");
return;
}
DeserializationError error = deserializeJson(doc, dataFile);
if (error)
{
Serial.print(F("deserializeJson() Error: "));
Serial.println(error.c_str());
return;
}
const char *patchName = doc["patchName"];
fileNames[ID_no++] = patchName + '\0';
dataFile.close(); // close file
if (ID_no > 128)
{
return;
}
}
}
*/
// CPU Temperature Monitoring ----------------------------------
float CPUtemperature(void)
{
float temp = InternalTemperature.readTemperatureC();
return temp;
}
// Jpeg Image draw ---------------------------------------------
File myfile;
// Function to draw pixels to the display
int JPEGDraw(JPEGDRAW *pDraw)
{
// Serial.printf("jpeg draw: x,y=%d,%d, cx,cy = %d,%d\n",
// pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight);
// for (int i=0; i<pDraw->iWidth*pDraw->iHeight; i++) {
// pDraw->pPixels[i] = __builtin_bswap16(pDraw->pPixels[i]);
// }
tft.writeRect(pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight, pDraw->pPixels);
return 1;
}
void *myOpen(const char *filename, int32_t *size)
{
myfile = SD.open(filename);
*size = myfile.size();
return &myfile;
}
void myClose(void *handle)
{
if (myfile)
myfile.close();
}
int32_t myRead(JPEGFILE *handle, uint8_t *buffer, int32_t length)
{
if (!myfile)
return 0;
return myfile.read(buffer, length);
}
int32_t mySeek(JPEGFILE *handle, int32_t position)
{
if (!myfile)
return 0;
return myfile.seek(position);
}
// init LED Status ----------------------------------------------
void init_LEDs()
{
uint32_t data = 1;
uint32_t multipl = 1;
// take the latchPin low so
// the LEDs don't change while you're sending in bits:
for (size_t i = 0; i < 24; i++)
{
digitalWrite(LED_latchPin, LOW);
// shift out highbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (data >> 16));
// shift out middelbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (data >> 8));
// shift out lowbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, data);
// take the latch pin high so the LEDs will light up:
digitalWrite(LED_latchPin, HIGH);
digitalWrite(LED_oePin, HIGH);
delay(15);
multipl *= 2;
data = data + multipl;
}
}
// --------------------------------------------------------------
// set LED
// n = LED-No 0 - 23
// state = 1 = on / 0 = off
// --------------------------------------------------------------
void set_LED(uint8_t n, bool state)
{
uint32_t maske = 0;
if (state)
{
LED_States |= (1 << n); // set LED
}
else
{
maske = ~(1 << n);
LED_States &= maske; // clear LED
}
for (size_t i = 0; i < 24; i++)
{
digitalWrite(LED_latchPin, LOW);
// shift out highbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (LED_States >> 16));
// shift out middelbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (LED_States >> 8));
// shift out lowbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, LED_States);
// take the latch pin high so the LEDs will light up:
digitalWrite(LED_latchPin, HIGH);
digitalWrite(LED_oePin, HIGH);
}
}
// clear Menu LEDs ----------------------------------------------
void clr_Menu_LEDs(void)
{
set_LED(LED_Patch, off);
set_LED(LED_OSC, off);
set_LED(LED_Mixer, off);
set_LED(LED_Filter, off);
}
// init LED Status ----------------------------------------------
void LEDs_off()
{
uint32_t data = 0xFFFFFF - 1;
uint32_t multipl = 1;
// take the latchPin low so
// the LEDs don't change while you're sending in bits:
for (size_t i = 0; i < 24; i++)
{
digitalWrite(LED_latchPin, LOW);
// shift out highbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (data >> 16));
// shift out middelbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, (data >> 8));
// shift out lowbyte
shiftOut(LED_dataPin, LED_clockPin, MSBFIRST, data);
// take the latch pin high so the LEDs will light up:
digitalWrite(LED_latchPin, HIGH);
digitalWrite(LED_oePin, HIGH);
delay(15);
multipl *= 2;
data = data - multipl;
}
}
// Key interrupt ----------------------------------------------
void Key_Interrupt()
{
key_action = true;
}
// Touchscreen interrupt ---------------------------------------
void Touchscreen_Interrupt()
{
ts_action = true;
mcp1.readGPIO();
}
// Encoder interrupt ----------------------------------------------
void Encoder_Interrupt()
{
enc_action = true;
current_GPIO1 = mcp1.readGPIOAB();
}
// Key fuction -------------------------------------------------
void Key1_function(bool state)
{
if (!state) // state == 0
{
draw_page_1();
// tft.waitUpdateAsyncComplete();
tft.updateScreenAsyncT4();
}
else
{
set_LED(4, state); // state = 1
// tft.waitUpdateAsyncComplete();
draw_page_1();
tft.updateScreenAsyncT4();
}
}
void Key2_function(bool state)
{
if (!state)
{
set_LED(23, state); // state == 0
// tft.waitUpdateAsyncComplete();
// tft.updateScreenAsyncT4();
}
else
{
set_LED(23, state); // state == 1
// tft.waitUpdateAsyncComplete();
draw_page_2();
tft.updateScreenAsyncT4();
}
}
// read Keys ---------------------------------------------------
void read_keys()
{
if (Key_debounce_Timer >= 50) // Key debounce
{
Key_debounce_Timer = 0;
if (key_action == true)
{
key_action = false;
mcp0_Status = mcp0.readGPIOAB();
if (mcp0_Status == mcp0_oldStatus)
return;
for (byte i = 0; i < 16; i++)
{
bool n = bitRead(mcp0_Status, i);
if (n != bitRead(mcp0_oldStatus, i))
{
// i = function-no / n = state (low-active)
if (KeyFunction_State[i] == 0 && n == 0)
{
switch (i)
{
case Key_Patch:
Menu_page = 1;
draw_page_1(); // Patch Menu
clr_Menu_LEDs();
set_LED(LED_Patch, on);
break;
case Key_OSC:
Menu_page = 2;
draw_page_2(); // Osc Menu
clr_Menu_LEDs();
set_LED(LED_OSC, on);
break;
case Key_Mixer:
Menu_page = 3;
draw_page_3(); // Mixer Menu
clr_Menu_LEDs();
set_LED(LED_Mixer, on);
break;
}
KeyFunction_State[i] = 0;
}
/*
else if (KeyFunction_State[i] == 1 && n == 0)
{
switch (i)
{
case 6:
//Key1_function(1);
set_LED(LED_Patch, off);
break;
case 8:
//Key2_function(1);
set_LED(LED_OSC, off);
break;
case 9:
//Key2_function(1);
set_LED(LED_Mixer, off);
break;
}
KeyFunction_State[i] = 0;
}
*/
}
}
mcp0_oldStatus = mcp0_Status;
}
}
}
// read Touchscreen --------------------------------------------
void read_ts (void)
{
if (ts_action)
{
ts_action = false;
uint8_t ts_status = ft6336u.read_td_status();
uint8_t ts_ID_1 = ft6336u.read_touch1_id(); // 1 = 1st touch, 2 = 2nd touch
uint8_t new_ts_event_1 = ft6336u.read_touch1_event(); // 0 = No touching, 1 = touch
if (ts_status >= 0 && ts_ID_1 == 0)
{
if (old_ts_event_1 == 0 && new_ts_event_1 == 2)
{
uint16_t ts_ypos_1 = 319 - ft6336u.read_touch1_x(); // Display rotated 180 degrees
uint16_t ts_xpos_1 = ft6336u.read_touch1_y(); // and x/y exchange
Serial.println(new_ts_event_1);
Serial.print("ts_xpos : ");
Serial.println(ts_xpos_1);
Serial.print("ts_ypos : ");
Serial.println(ts_ypos_1);
// ts_windows
if (ts_xpos_1 >= 0 && ts_xpos_1 <= 109 && ts_ypos_1 >= 0 && ts_ypos_1 <= 50)
{
if (Menu_page != 1)
{
//Serial.println("Patch");
Menu_page = 1;
draw_page_1();
clr_Menu_LEDs();
set_LED(LED_Patch, on);
}
}
else if (ts_xpos_1 >= 110 && ts_xpos_1 <= 227 && ts_ypos_1 >= 0 && ts_ypos_1 <= 50)
{
if (Menu_page != 2)
{
// Serial.println("OSC");
Menu_page = 2;
draw_page_2();
clr_Menu_LEDs();
set_LED(LED_OSC, on);
}
}
else if (ts_xpos_1 >= 228 && ts_xpos_1 <= 340 && ts_ypos_1 >= 0 && ts_ypos_1 <= 50)
{
if (Menu_page != 3)
{
//Serial.println("Mixer");
Menu_page = 3;
draw_page_3();
clr_Menu_LEDs();
set_LED(LED_Mixer, on);
}
}
else if (ts_xpos_1 >= 341 && ts_xpos_1 <= 479 && ts_ypos_1 >= 0 && ts_ypos_1 <= 50)
{
if (Menu_page != 4)
{
//Serial.println("Filter");
Menu_page = 4;
draw_ENV();
clr_Menu_LEDs();
set_LED(LED_ENV, on);
}
}
old_ts_event_1 = new_ts_event_1;
}
else if (old_ts_event_1 == 2 && new_ts_event_1 == 1)
{
old_ts_event_1 = 0;
Serial.println("no touch");
}
}
}
}
// read Encoder ------------------------------------------------
void read_enc(void)
{
if (enc_action)
{
uint8_t encID = 0;
unsigned long interruptTime = millis();
unsigned long timeDiff = interruptTime - lastInterruptTime;
static uint8_t Del_value;
static uint8_t Akt_value;
static uint8_t Dec_value;
enc_action = false;
//tft.waitUpdateAsyncComplete();
// Encoder Acceleration
// If the rotation is fast (< 50 ms), accelerate
if (timeDiff < 100)
{
accelerationFactor = 5;
}
else
{
accelerationFactor = 1;
}
// Check MCP23017 GPIO for activity
uint16_t changesBits = old_GPIO1 ^ current_GPIO1;
// Encoder1 Clk Pin status
if (changesBits == enc1_A)
{
currentClkState[0] = bitRead(current_GPIO1, 8);
encID = 0;
} // Encode1 DT Pin status
else if (changesBits == enc1_B)
{
Enc_B[0] = bitRead(current_GPIO1, 9);
encID = 0;
}
// Encoder1 Clk Pin status
else if (changesBits == enc2_A)
{
currentClkState[1] = bitRead(current_GPIO1, 10);
encID = 1;
} // Encode2 DT Pin status
else if (changesBits == enc2_B)
{
Enc_B[1] = bitRead(current_GPIO1, 11);
encID = 1;
}
// Encoder3 Clk Pin status
else if (changesBits == enc3_A)
{
currentClkState[2] = bitRead(current_GPIO1, 12);
encID = 2;
} // Encode3 DT Pin status
else if (changesBits == enc3_B)
{
Enc_B[2] = bitRead(current_GPIO1, 13);
encID = 2;
}
// print encoder values
if (currentClkState[encID] != lastClkState[encID])
{
if (Enc_B[encID] != currentClkState[encID])
{
Enc_Pos[encID] += accelerationFactor;
if (Enc_Pos[encID] >= 127)
{
Enc_Pos[encID] = 127;
}
}
else
{
Enc_Pos[encID] -= accelerationFactor;
if (Enc_Pos[encID] <= 0)
{
Enc_Pos[encID] = 0;
}
}
//tft.setTextColor(ST7735_WHITE);
//tft.setFont(OpenSans_16);
if (encID == 0)
{
//tft.fillRect(90, 100, 60, 20, ST7735_RED);
//tft.setCursor(100, 101);
Del_value = Enc_Pos[encID];
}
else if (encID == 1)
{
//tft.fillRect(90, 130, 60, 20, ST7735_BLUE);
//tft.setCursor(100, 131);
Akt_value = Enc_Pos[encID];
}
else if (encID == 2)
{
//tft.fillRect(90, 160, 60, 20, tab_color_green);
//tft.setCursor(100, 161);
Dec_value = Enc_Pos[encID];
}
//tft.waitUpdateAsyncComplete();
//tft.print(Enc_Pos[encID]);
tft.fillRect(10,75,456,136, ST7735_BLACK);
draw_env_grid();
draw_envelope(Del_value, Akt_value, Dec_value, 64, 64, ST7735_GREEN);
tft.updateScreenAsyncT4();
}
lastClkState[encID] = currentClkState[encID];
old_GPIO1 = current_GPIO1;
lastInterruptTime = interruptTime;
}
}
// Setup -------------------------------------------------------
void setup(void)
{
Serial.begin(9600);
// init Touchscreen
ft6336u.begin();
ft6336u.write_THRESHOLD(0xBB);
// init CPU Temperature measurement
InternalTemperature.begin();
// init io pins
pinMode(TFT_BL, OUTPUT); // TFT Backligth
pinMode(LED_latchPin, OUTPUT); // LED
pinMode(LED_clockPin, OUTPUT); // LED
pinMode(LED_dataPin, OUTPUT); // LED
pinMode(LED_oePin, OUTPUT); // LED
pinMode(PIN_TS_INT, INPUT_PULLUP); // Interrupt Pin Touchscreen
digitalWrite(TFT_BL, LOW); // TFT_BL off
digitalWrite(LED_oePin, LOW); // LED off
// init TFT Touchscreen and 300KB FrameBuffer into Teensy4.1 RAM2
tft.setFrameBuffer(FrameBuffer);
tft.init(320, 480);
tft.setRotation(1);
tft.invertDisplay(true);
tft.useFrameBuffer(true);
tft.fillScreen(ST7735_BLACK);
tft.updateScreenAsyncT4();
init_LEDs(); // all LEDs on
LEDs_off(); // all LEDs off
digitalWrite(TFT_BL, HIGH); // TFT_Backlight on
// init Key/Encoder IO Expander
mcp0.begin_I2C(0x21, &Wire1); // Addr 0x20-0x27
mcp1.begin_I2C(0x22, &Wire1);
// init Wire1 for Encoders
Wire1.begin();
Wire1.setClock(100000UL); // I2C speed 400KHz
// init MPC23017(1-3) Expander for Encoders & Keys
mcp0.setupInterrupts(true, false, LOW);
for (size_t i = 0; i < 16; i++)
{
mcp0.pinMode(i, INPUT_PULLUP);
mcp0.setupInterruptPin(i, CHANGE);
}
mcp0.getCapturedInterrupt();
mcp0.readGPIOAB();
mcp0.clearInterrupts();
mcp1.setupInterrupts(true, false, LOW);
for (size_t i = 0; i < 16; i++)
{
mcp1.pinMode(i, INPUT_PULLUP);
mcp1.setupInterruptPin(i, CHANGE);
}
mcp1.getCapturedInterrupt();
mcp1.readGPIOAB();
mcp1.clearInterrupts();
delay(10);
// init Key Interrupt
attachInterrupt(digitalPinToInterrupt(PIN_KEY_INT), Key_Interrupt, FALLING);
// init Touchscreen Interrupt
attachInterrupt(digitalPinToInterrupt(PIN_TS_INT), Touchscreen_Interrupt, FALLING);
// init Encoder Interrupt
attachInterrupt(digitalPinToInterrupt(PIN_ENC_INT), Encoder_Interrupt, FALLING);
// init SDcard and load Boot screen
tft.setCursor(5, 5);
tft.setTextSize(2);
while (!SD.begin(BUILTIN_SDCARD))
{
tft.setCursor(5, 5);
tft.fillScreen(ST7735_RED);
Serial.println(F("Unable to access SD Card"));
tft.println(F("Unable to access SD Card"));
tft.updateScreenAsync();
delay(1000);
}
File dir = SD.open("/");
int rc;
rc = (jpeg.open("System/Boot.jpg", myOpen, myClose, myRead, mySeek, JPEGDraw));
if (rc >= 1)
{
Serial.printf("image specs: (%d x %d), %d bpp, pixel type: %d\n", jpeg.getWidth(), jpeg.getHeight(), jpeg.getBpp(), jpeg.getPixelType());
jpeg.decode(0, 0, 0);
jpeg.close();
tft.setTextColor(ST7735_WHITE);
tft.setTextSize(1);
tft.setCursor(390,290);
tft.setFont(OpenSans_10);
tft.print(F("Version 1.0"));
tft.updateScreenAsyncT4();
tft.waitUpdateAsyncComplete();
}
else
{
tft.setCursor(5, 5);
tft.setTextSize(2);
tft.fillScreen(ST7735_RED);
tft.print(F("Jpeg Image error = "));
tft.println(jpeg.getLastError(), DEC);
}
delay(3000);
draw_page_1();
set_LED(LED_Patch, on);
}
void loop()
{
if (tft.asyncUpdateActive() == false)
{
read_keys();
read_ts();
read_enc();
}
}