Skip to content

Commit

Permalink
Add 2 animated eyes examples
Browse files Browse the repository at this point in the history
Animated_Eyes_1 is an example for a single display
Animated_Eyes_2 is an example for two displays
  • Loading branch information
Bodmer committed Nov 8, 2020
1 parent 975347d commit 24b0eca
Show file tree
Hide file tree
Showing 35 changed files with 260,676 additions and 0 deletions.
140 changes: 140 additions & 0 deletions examples/Generic/Animated_Eyes_1/Animated_Eyes_1.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// An adaption of the "UncannyEyes" sketch (see eye_functions tab)
// for the TFT_eSPI library. As written the sketch is for driving
// one (240x320 minimum) TFT display, showing 2 eyes. See example
// Animated_Eyes_2 for a dual 128x128 TFT display configued sketch.

// The number of displays and chip selects used are defined in the
// config.h tab. The display count can be set to 1. If using one
// TFT and the chip select for that display is already defined in
// the TFT_eSPI library then change the chip select pins to -1 in the
// "config.h" tab.

// The wiring for 2 TFT displays to an ESP32 is described in the
// "wiring" tab of this sketch.

// Configuration settings for the eye, eye style, display count,
// chip selects and x offsets can be defined in the sketch "config.h" tab.

// Performance (frames per second = fps) can be improved by using
// DMA (for SPI displays only) on ESP32 and STM32 processors. Use
// as high a SPI clock rate as is supported by the display. 27MHz
// minimum, some diplays can be operated at higher clock rates in
// the range 40-80MHz.

// Single defaultEye performance for different processors
// No DMA With DMA
// ESP8266 (160MHz CPU) 40MHz SPI 36 fps
// ESP32 27MHz SPI 53 fps 85 fps
// ESP32 40MHz SPI 67 fps 102 fps
// ESP32 80MHz SPI 82 fps 116 fps // Note: Few displays work reliably at 80MHz
// STM32F401 55MHz SPI 44 fps 90 fps
// STM32F446 55MHz SPI 83 fps 155 fps
// STM32F767 55MHz SPI 136 fps 197 fps

// DMA can be used with STM32 and ESP32 processors when the interface
// is SPI, uncomment the next line:
#define USE_DMA

// Load TFT driver library
#include <SPI.h>
#include <TFT_eSPI.h>
TFT_eSPI tft; // A single instance is used for 1 or 2 displays

// A pixel buffer is used during eye rendering
#define BUFFER_SIZE 1024 // 128 to 1024 seems optimum

#ifdef USE_DMA
#define BUFFERS 2 // 2 toggle buffers with DMA
#else
#define BUFFERS 1 // 1 buffer for no DMA
#endif

uint16_t pbuffer[BUFFERS][BUFFER_SIZE]; // Pixel rendering buffer
bool dmaBuf = 0; // DMA buffer selection

// This struct is populated in config.h
typedef struct { // Struct is defined before including config.h --
int8_t select; // pin numbers for each eye's screen select line
int8_t wink; // and wink button (or -1 if none) specified there,
uint8_t rotation; // also display rotation and the x offset
int16_t xposition; // position of eye on the screen
} eyeInfo_t;

#include "config.h" // ****** CONFIGURATION IS DONE IN HERE ******

extern void user_setup(void); // Functions in the user*.cpp files
extern void user_loop(void);

#define SCREEN_X_START 0
#define SCREEN_X_END SCREEN_WIDTH // Badly named, actually the "eye" width!
#define SCREEN_Y_START 0
#define SCREEN_Y_END SCREEN_HEIGHT // Actually "eye" height

// A simple state machine is used to control eye blinks/winks:
#define NOBLINK 0 // Not currently engaged in a blink
#define ENBLINK 1 // Eyelid is currently closing
#define DEBLINK 2 // Eyelid is currently opening
typedef struct {
uint8_t state; // NOBLINK/ENBLINK/DEBLINK
uint32_t duration; // Duration of blink state (micros)
uint32_t startTime; // Time (micros) of last state change
} eyeBlink;

struct { // One-per-eye structure
int16_t tft_cs; // Chip select pin for each display
eyeBlink blink; // Current blink/wink state
int16_t xposition; // x position of eye image
} eye[NUM_EYES];

uint32_t startTime; // For FPS indicator

// INITIALIZATION -- runs once at startup ----------------------------------
void setup(void) {
Serial.begin(115200);
//while (!Serial);
Serial.println("Starting");

#if defined(DISPLAY_BACKLIGHT) && (DISPLAY_BACKLIGHT >= 0)
// Enable backlight pin, initially off
Serial.println("Backlight turned off");
pinMode(DISPLAY_BACKLIGHT, OUTPUT);
digitalWrite(DISPLAY_BACKLIGHT, LOW);
#endif

// User call for additional features
user_setup();

// Initialiase the eye(s), this will set all chip selects low for the tft.init()
initEyes();

// Initialise TFT
Serial.println("Initialising displays");
tft.init();

#ifdef USE_DMA
tft.initDMA();
#endif

// Raise chip select(s) so that displays can be individually configured
digitalWrite(eye[0].tft_cs, HIGH);
if (NUM_EYES > 1) digitalWrite(eye[1].tft_cs, HIGH);

for (uint8_t e = 0; e < NUM_EYES; e++) {
digitalWrite(eye[e].tft_cs, LOW);
tft.setRotation(eyeInfo[e].rotation);
tft.fillScreen(TFT_BLACK);
digitalWrite(eye[e].tft_cs, HIGH);
}

#if defined(DISPLAY_BACKLIGHT) && (DISPLAY_BACKLIGHT >= 0)
Serial.println("Backlight now on!");
analogWrite(DISPLAY_BACKLIGHT, BACKLIGHT_MAX);
#endif

startTime = millis(); // For frame-rate calculation
}

// MAIN LOOP -- runs continuously after setup() ----------------------------
void loop() {
updateEye();
}
93 changes: 93 additions & 0 deletions examples/Generic/Animated_Eyes_1/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Pin selections here are based on the original Adafruit Learning System
// guide for the Teensy 3.x project. Some of these pin numbers don't even
// exist on the smaller SAMD M0 & M4 boards, so you may need to make other
// selections:

// GRAPHICS SETTINGS (appearance of eye) -----------------------------------

// If using a SINGLE EYE, you might want this next line enabled, which
// uses a simpler "football-shaped" eye that's left/right symmetrical.
// Default shape includes the caruncle, creating distinct left/right eyes.

//#define SYMMETRICAL_EYELID

// Enable ONE of these #includes -- HUGE graphics tables for various eyes:
#include "data/defaultEye.h" // Standard human-ish hazel eye -OR-
//#include "data/dragonEye.h" // Slit pupil fiery dragon/demon eye -OR-
//#include "data/noScleraEye.h" // Large iris, no sclera -OR-
//#include "data/goatEye.h" // Horizontal pupil goat/Krampus eye -OR-
//#include "data/newtEye.h" // Eye of newt -OR-
//#include "data/terminatorEye.h" // Git to da choppah!
//#include "data/catEye.h" // Cartoonish cat (flat "2D" colors)
//#include "data/owlEye.h" // Minerva the owl (DISABLE TRACKING)
//#include "data/naugaEye.h" // Nauga googly eye (DISABLE TRACKING)
//#include "data/doeEye.h" // Cartoon deer eye (DISABLE TRACKING)

// DISPLAY HARDWARE SETTINGS (screen type & connections) -------------------
#define TFT_COUNT 1 // Number of screens (1 or 2)
#define TFT1_CS -1 // TFT 1 chip select pin (set to -1 to use TFT_eSPI setup)
#define TFT2_CS -1 // TFT 2 chip select pin (set to -1 to use TFT_eSPI setup)
#define TFT_1_ROT 1 // TFT 1 rotation
#define TFT_2_ROT 1 // TFT 2 rotation
#define EYE_1_XPOSITION 0 // x shift for eye 1 image on display
#define EYE_2_XPOSITION 320 - 128 // x shift for eye 2 image on display

#define DISPLAY_BACKLIGHT -1 // Pin for backlight control (-1 for none)
#define BACKLIGHT_MAX 255

// EYE LIST ----------------------------------------------------------------
#define NUM_EYES 2 // Number of eyes to display (1 or 2)

#define BLINK_PIN -1 // Pin for manual blink button (BOTH eyes)
#define LH_WINK_PIN -1 // Left wink pin (set to -1 for no pin)
#define RH_WINK_PIN -1 // Right wink pin (set to -1 for no pin)

// This table contains ONE LINE PER EYE. The table MUST be present with
// this name and contain ONE OR MORE lines. Each line contains THREE items:
// a pin number for the corresponding TFT/OLED display's SELECT line, a pin
// pin number for that eye's "wink" button (or -1 if not used), a screen
// rotation value (0-3) and x position offset for that eye.

#if (NUM_EYES == 2)
eyeInfo_t eyeInfo[] = {
{ TFT1_CS, LH_WINK_PIN, TFT_1_ROT, EYE_1_XPOSITION }, // LEFT EYE chip select and wink pins, rotation and offset
{ TFT2_CS, RH_WINK_PIN, TFT_2_ROT, EYE_2_XPOSITION }, // RIGHT EYE chip select and wink pins, rotation and offset
};
#else
eyeInfo_t eyeInfo[] = {
{ TFT1_CS, LH_WINK_PIN, TFT_1_ROT, EYE_1_XPOSITION }, // EYE chip select and wink pins, rotation and offset
};
#endif

// INPUT SETTINGS (for controlling eye motion) -----------------------------

// JOYSTICK_X_PIN and JOYSTICK_Y_PIN specify analog input pins for manually
// controlling the eye with an analog joystick. If set to -1 or if not
// defined, the eye will move on its own.
// IRIS_PIN speficies an analog input pin for a photocell to make pupils
// react to light (or potentiometer for manual control). If set to -1 or
// if not defined, the pupils will change on their own.
// BLINK_PIN specifies an input pin for a button (to ground) that will
// make any/all eyes blink. If set to -1 or if not defined, the eyes will
// only blink if AUTOBLINK is defined, or if the eyeInfo[] table above
// includes wink button settings for each eye.

//#define JOYSTICK_X_PIN A0 // Analog pin for eye horiz pos (else auto)
//#define JOYSTICK_Y_PIN A1 // Analog pin for eye vert position (")
//#define JOYSTICK_X_FLIP // If defined, reverse stick X axis
//#define JOYSTICK_Y_FLIP // If defined, reverse stick Y axis
#define TRACKING // If defined, eyelid tracks pupil
#define AUTOBLINK // If defined, eyes also blink autonomously

// #define LIGHT_PIN -1 // Light sensor pin
#define LIGHT_CURVE 0.33 // Light sensor adjustment curve
#define LIGHT_MIN 0 // Minimum useful reading from light sensor
#define LIGHT_MAX 1023 // Maximum useful reading from sensor

#define IRIS_SMOOTH // If enabled, filter input from IRIS_PIN
#if !defined(IRIS_MIN) // Each eye might have its own MIN/MAX
#define IRIS_MIN 90 // Iris size (0-1023) in brightest light
#endif
#if !defined(IRIS_MAX)
#define IRIS_MAX 130 // Iris size (0-1023) in darkest light
#endif
Loading

0 comments on commit 24b0eca

Please sign in to comment.