/*
ESP32-S3 + ILI9341 (240x320) Spiral Animation
-----------------------------------------------
Library required:
- Adafruit GFX Library
- Adafruit ILI9341 Library
Arvind Patil / AI Centre Nandurbar
*/
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <SPI.h>
// ---------- Pin configuration ----------
#define TFT_CS 10
#define TFT_DC 11
#define TFT_RST 12
#define TFT_SCLK 13
#define TFT_MOSI 14
#define TFT_MISO 21
#define BTN_NEXT 0 // BOOT button, active LOW
#define SCREEN_W 240
#define SCREEN_H 320
Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI, TFT_DC, TFT_CS, TFT_RST);
const int cx = SCREEN_W / 2;
const int cy = SCREEN_H / 2;
int spiralIndex = 0;
bool autoAdvance = true;
unsigned long lastAdvance = 0;
const unsigned long ADVANCE_MS = 1400;
bool lastBtnState = HIGH;
// --- Fade effect variables ---
int fadeValue = 0;
int fadeDir = 1; // 1 = fade in, -1 = fade out
// 10 palettes, one per spiral mode (RGB565)
const uint16_t palettes[10][4] = {
{0xFA4A, 0xFEA3, 0x0740, 0x4E5F}, // 1
{0xFCE3, 0xFDF3, 0xCF9E, 0x2E6D}, // 2
{0xF9B1, 0xB8D3, 0x7205, 0x580B}, // 3
{0x07FA, 0x05FD, 0xF7E1, 0xF2DA}, // 4
{0xADFD, 0x43D3, 0x1DAB, 0xF7DE}, // 5
{0xFBA0, 0xFC40, 0xFE80, 0xFF95}, // 6
{0x7996, 0x9A5D, 0xC7BE, 0xE555}, // 7
{0x07FF, 0x1FFF, 0x67FD, 0xB7F6}, // 8
{0xF80D, 0xFACB, 0xFDE0, 0x81DF}, // 9
{0xFFFF, 0x7FFF, 0x0537, 0x01AA} // 10
};
uint16_t colorFor(int mode, int i) {
return palettes[mode % 10][i % 4];
}
void clearScreen() {
tft.fillScreen(ILI9341_BLACK);
}
void drawSpiral(int n, unsigned long timeMs) {
int mode = n % 10;
clearScreen();
float turns = 4.5f + mode * 0.35f;
float maxR = (18.0f + mode * 2.6f) * 1.14f;
const int loops = 220;
for (int i = 0; i < loops; i++) {
float p = (float)i / loops;
float angle = p * TWO_PI * turns + timeMs * 0.0015f * (1 + mode * 0.08f);
float radius = p * maxR * 10.2f;
switch (mode) {
case 1: radius = pow(p, 0.82f) * maxR * 10.5f; break;
case 2: radius = (1 - cos(p * PI * turns)) * 12.0f; break;
case 3: radius = p * maxR * 9.4f + sin(p * 16 + timeMs * 0.002f) * 3.0f; break;
case 4: radius = (p * maxR * 8.8f) * (0.7f + 0.3f * sin(angle * 3)); break;
case 5: radius = p * maxR * 9.8f + cos(p * 22 + timeMs * 0.003f) * 5.0f; break;
case 6: radius = p * maxR * 10.0f + sin(angle * 5) * 2.5f; break;
case 7: radius = p * maxR * 8.7f + sin(p * 30 + timeMs * 0.001f) * 4.0f; break;
case 8: radius = p * maxR * 10.2f; break;
case 9: radius = p * maxR * 9.6f + sin(p * 12 * PI + timeMs * 0.002f) * 6.0f; break;
default: break;
}
int x = cx + (int)(cos(angle) * radius);
int y = cy + (int)(sin(angle) * radius);
if (x < 0 || x >= SCREEN_W || y < 0 || y >= SCREEN_H) continue;
uint16_t c = colorFor(mode, i);
float size = 2.1f - p * 1.6f;
int r = max(1, (int)size);
tft.fillCircle(x, y, r, c);
}
// Header text
tft.setCursor(6, 6);
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(1);
tft.print("Spiral ");
tft.print(n + 1);
tft.print(" / 10");
tft.setCursor(6, 18);
tft.setTextColor(0x7BCF);
tft.print("ESP32-S3 ILI9341 240x320");
// --- Credit line with fade effect ---
fadeValue += fadeDir * 8;
if (fadeValue >= 255) { fadeValue = 255; fadeDir = -1; }
if (fadeValue <= 50) { fadeValue = 50; fadeDir = 1; }
uint16_t fadeColor = tft.color565(fadeValue, fadeValue, 0);
tft.setCursor(10, SCREEN_H - 30);
tft.setTextColor(fadeColor);
tft.setTextSize(2);
tft.print("Arvind Patil Nandurbar - 1 Aug 26");
}
void setup() {
Serial.begin(115200);
pinMode(BTN_NEXT, INPUT_PULLUP);
SPI.begin(TFT_SCLK, TFT_MISO, TFT_MOSI, TFT_CS);
tft.begin();
tft.setRotation(0);
clearScreen();
}
void loop() {
unsigned long now = millis();
bool btn = digitalRead(BTN_NEXT);
if (lastBtnState == HIGH && btn == LOW) {
spiralIndex = (spiralIndex + 1) % 10;
lastAdvance = now;
// Reset fade effect on manual change
fadeValue = 0;
fadeDir = 1;
}
lastBtnState = btn;
if (autoAdvance && now - lastAdvance > ADVANCE_MS) {
spiralIndex = (spiralIndex + 1) % 10;
lastAdvance = now;
// Reset fade effect on auto change
fadeValue = 0;
fadeDir = 1;
}
drawSpiral(spiralIndex, now);
}
https://wokwi.com/projects/471153962940299265