acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

Animated_Eyes_2.ino (5379B)

      1 // An adaption of the "UncannyEyes" sketch (see eye_functions tab)
      2 // for the TFT_eSPI library. As written the sketch is for driving
      3 // two TFT displays.
      4 
      5 // The size of the displayed eye is determined by the screen size and
      6 // resolution. The eye image is 128 pixels wide. In humans the palpebral
      7 // fissure (open eye) width is about 30mm so a low resolution, large
      8 // pixel size display works best to show a scale eye image. Note that
      9 // display manufacturers usually quote the diagonal measurement, so a
     10 // 128 x 128 1.7" display or 128 x 160 2" display is about right.
     11 
     12 // The number of displays and chip selects used are defined in the
     13 // config.h tab. The display count can be set to 1. If using one
     14 // TFT and the chip select for that display is already defined in
     15 // the TFT_eSPI library then change the chip select pins to -1 in the
     16 // "config.h" tab.
     17 
     18 // The wiring for 2 TFT displays to an ESP32 is described in the
     19 // "wiring" tab of this sketch.
     20 
     21 // Configuration settings for the eye, eye style, display count,
     22 // chip selects and x offsets can be defined in the sketch "config.h" tab.
     23 
     24 // Performance (frames per second = fps) can be improved by using
     25 // DMA (for SPI displays only) on ESP32 and STM32 processors. Use
     26 // as high a SPI clock rate as is supported by the display. 27MHz
     27 // minimum, some displays can be operated at higher clock rates in
     28 // the range 40-80MHz.
     29 
     30 // Single defaultEye performance for different processors
     31 //                                  No DMA   With DMA
     32 // ESP8266 (160MHz CPU) 40MHz SPI   36 fps
     33 // ESP32 27MHz SPI                  53 fps     85 fps
     34 // ESP32 40MHz SPI                  67 fps    102 fps
     35 // ESP32 80MHz SPI                  82 fps    116 fps // Note: Few displays work reliably at 80MHz
     36 // STM32F401 55MHz SPI              44 fps     90 fps
     37 // STM32F446 55MHz SPI              83 fps    155 fps
     38 // STM32F767 55MHz SPI             136 fps    197 fps
     39 
     40 // DMA can be used with RP2040, STM32 and ESP32 processors when the interface
     41 // is SPI, uncomment the next line:
     42 //#define USE_DMA
     43 
     44 // Load TFT driver library
     45 #include <SPI.h>
     46 #include <TFT_eSPI.h>
     47 TFT_eSPI tft;           // A single instance is used for 1 or 2 displays
     48 
     49 // A pixel buffer is used during eye rendering
     50 #define BUFFER_SIZE 1024 // 128 to 1024 seems optimum
     51 
     52 #ifdef USE_DMA
     53   #define BUFFERS 2      // 2 toggle buffers with DMA
     54 #else
     55   #define BUFFERS 1      // 1 buffer for no DMA
     56 #endif
     57 
     58 uint16_t pbuffer[BUFFERS][BUFFER_SIZE]; // Pixel rendering buffer
     59 bool     dmaBuf   = 0;                  // DMA buffer selection
     60 
     61 // This struct is populated in config.h
     62 typedef struct {        // Struct is defined before including config.h --
     63   int8_t  select;       // pin numbers for each eye's screen select line
     64   int8_t  wink;         // and wink button (or -1 if none) specified there,
     65   uint8_t rotation;     // also display rotation and the x offset
     66   int16_t xposition;    // position of eye on the screen
     67 } eyeInfo_t;
     68 
     69 #include "config.h"     // ****** CONFIGURATION IS DONE IN HERE ******
     70 
     71 extern void user_setup(void); // Functions in the user*.cpp files
     72 extern void user_loop(void);
     73 
     74 #define SCREEN_X_START 0
     75 #define SCREEN_X_END   SCREEN_WIDTH   // Badly named, actually the "eye" width!
     76 #define SCREEN_Y_START 0
     77 #define SCREEN_Y_END   SCREEN_HEIGHT  // Actually "eye" height
     78 
     79 // A simple state machine is used to control eye blinks/winks:
     80 #define NOBLINK 0       // Not currently engaged in a blink
     81 #define ENBLINK 1       // Eyelid is currently closing
     82 #define DEBLINK 2       // Eyelid is currently opening
     83 typedef struct {
     84   uint8_t  state;       // NOBLINK/ENBLINK/DEBLINK
     85   uint32_t duration;    // Duration of blink state (micros)
     86   uint32_t startTime;   // Time (micros) of last state change
     87 } eyeBlink;
     88 
     89 struct {                // One-per-eye structure
     90   int16_t   tft_cs;     // Chip select pin for each display
     91   eyeBlink  blink;      // Current blink/wink state
     92   int16_t   xposition;  // x position of eye image
     93 } eye[NUM_EYES];
     94 
     95 uint32_t startTime;  // For FPS indicator
     96 
     97 // INITIALIZATION -- runs once at startup ----------------------------------
     98 void setup(void) {
     99   Serial.begin(115200);
    100   //while (!Serial);
    101   Serial.println("Starting");
    102 
    103 #if defined(DISPLAY_BACKLIGHT) && (DISPLAY_BACKLIGHT >= 0)
    104   // Enable backlight pin, initially off
    105   Serial.println("Backlight turned off");
    106   pinMode(DISPLAY_BACKLIGHT, OUTPUT);
    107   digitalWrite(DISPLAY_BACKLIGHT, LOW);
    108 #endif
    109 
    110   // User call for additional features
    111   user_setup();
    112 
    113   // Initialise the eye(s), this will set all chip selects low for the tft.init()
    114   initEyes();
    115 
    116   // Initialise TFT
    117   Serial.println("Initialising displays");
    118   tft.init();
    119 
    120 #ifdef USE_DMA
    121   tft.initDMA();
    122 #endif
    123 
    124   // Raise chip select(s) so that displays can be individually configured
    125   digitalWrite(eye[0].tft_cs, HIGH);
    126   if (NUM_EYES > 1) digitalWrite(eye[1].tft_cs, HIGH);
    127 
    128   for (uint8_t e = 0; e < NUM_EYES; e++) {
    129     digitalWrite(eye[e].tft_cs, LOW);
    130     tft.setRotation(eyeInfo[e].rotation);
    131     tft.fillScreen(TFT_BLACK);
    132     digitalWrite(eye[e].tft_cs, HIGH);
    133   }
    134 
    135 #if defined(DISPLAY_BACKLIGHT) && (DISPLAY_BACKLIGHT >= 0)
    136   Serial.println("Backlight now on!");
    137   analogWrite(DISPLAY_BACKLIGHT, BACKLIGHT_MAX);
    138 #endif
    139 
    140   startTime = millis(); // For frame-rate calculation
    141 }
    142 
    143 // MAIN LOOP -- runs continuously after setup() ----------------------------
    144 void loop() {
    145   updateEye();
    146 }