Uncanny Eyes is getting expensive

Glad you like the eyes! I'm hoping to have a bit of time now to tweak/improve/add some more eyes, and maybe even work on the rest of the codebase a bit further.

Note, if you use Teensy 1.59 beta 3 with Arduino 1.8.19 or Arduino 2.2.1, you get the following warning:

Thanks for pointing this out, I hadn't seen it at my end (I'm using GCC 11.3.1). Hmm, I understand it's highlighting an ABI compatibility issue between compiler versions but it's not clear to me what the fix is for that warning other than rebuilding the whole codebase? About the best information I could find is this, which seems to suggest just disabling the warning. Any ideas of what I should do about this? (issues like this are one of many reasons I stopped doing much serious C or C++ dev many years ago! :()
 
Glad you like the eyes! I'm hoping to have a bit of time now to tweak/improve/add some more eyes, and maybe even work on the rest of the codebase a bit further.



Thanks for pointing this out, I hadn't seen it at my end (I'm using GCC 11.3.1). Hmm, I understand it's highlighting an ABI compatibility issue between compiler versions but it's not clear to me what the fix is for that warning other than rebuilding the whole codebase? About the best information I could find is this, which seems to suggest just disabling the warning. Any ideas of what I should do about this? (issues like this are one of many reasons I stopped doing much serious C or C++ dev many years ago! :()

No real idea. At heart, I am a C programmer who now has to use simple C++ for work. We've had the same issue with needing -Wno-psabi on the PowerPC port in two cases.

One was a bug that was fixed ages ago that structures were passed differently between different GCC releases. The kicker is we switched from big endian systems to little endian systems along the way, and the little endian systems never had the old GCC with the bug. The big endian systems have been phased out for servers, but the little endian systems were still generating the warning. We finally removed that warning.

The other was we were making fundamental changes (changing the underlying long double implementation from being two doubles to using IEEE 754 128-bit floating point), and we needed to guarantee that the library had the proper support. If the compiler wasn't compiled to use the newer library, and you tried to set the option for IEEE 128-bit floating point, you got the warning. When I was writing tests, where I was looking at the assembler code, and not calling the library, I would use -Wno-psabi in the test options.

But the way to shut up the warning is to add the following to the top of eyes/eyes.h:

Code:
// The G++ with Teensydunio 1.59 beta 3 adds a new warning.   Silence it.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpsabi"

and this at the bottom of eyes/eye.h:

Code:
#pragma GCC diagnostics pop
 
Last edited:
I wanted a nice compact housing for my GC9A01 screens and couldn't find anything suitable, so I recently had a go at designing a 3D printable housing myself, which I then had printed via an online 3D printing service. It's the first time I've done this and the results were a lot better than I expected, with the screens fitting perfectly and the two halves of the cases snapping shut without needing any screws or glue. I ended up with two variants, one that fits a screen with wires soldered directly to it (no header pins), and another that fits a screen with a 90° 7-pin XH2.54 connector attached.

Maybe someone else here will also find these useful, if so here are links to the models:

GC9A01 housing with wires
GC9A01 housing with XH2.54 connector

PXL_20231109_225805094.jpg
PXL_20231109_223623817.jpg


They're also the right size for attaching a 40mm cabachon on to the front. In my case I just attached the cabachon to the housing using a few small dabs of superglue.
 
I wanted a nice compact housing for my GC9A01 screens and couldn't find anything suitable, so I recently had a go at designing a 3D printable housing myself, which I then had printed via an online 3D printing service. It's the first time I've done this and the results were a lot better than I expected, with the screens fitting perfectly and the two halves of the cases snapping shut without needing any screws or glue. I ended up with two variants, one that fits a screen with wires soldered directly to it (no header pins), and another that fits a screen with a 90° 7-pin XH2.54 connector attached.
.
Cool!
 
I'm starting to play with this again. I started with Chris' github repository but made some minor changes so I could use Arduino 2 IDE. last year I gave up because of stuttery sound and recently posted a solution using PSRAM (as one big array) and audio.playmem that does not stutter.

with 23 eyes defined and leaving Chris' code to cycle through the eyes but adding a minimal audio interface, I seem to have plenty of Flash left:
Code:
Memory Usage on Teensy 4.1:
  FLASH: code:114440, data:3375724, headers:8840   free for files:4627460
   RAM1: variables:21408, code:109144, padding:21928   free for local variables:371808
   RAM2: variables:15008  free for malloc/new:509280
 EXTRAM: variables:8388608

The audio.ino tab looks like this:
Code:
#include <SD.h>
#include <Audio.h>

ExFatFile root;
ExFatFile song;

EXTMEM unsigned int extSong[2097151];      //8MB

//this ought to be PROGMEM but bizarro compiler error
char songNames[][33] = {"ExtBuglecallrag.bin",    "ExtCutthecake.bin", "ExtFourbrothers.bin",    "ExtJavajive.bin",    "ExtOops.bin",    "ExtTheohofpleasure.bin",   
"ExtTinygeometries.bin", "ExtCatacombslinguamortua.bin","ExtDuelingbanjos.bin",    "ExtHallelujah.bin","ExtLetspretend.bin",    "ExtRhythminthepews.bin",
"ExtThethoughtstayedfree.bin", "ExtCelestialsodapop.bin    ","ExtEngleberttheelephant.bin","ExtHotfrogsontheloose.bin","ExtNightbaldmtn.bin","ExtThegnome.bin",
"ExtThetrainandtheriver.bin"};

uint8_t numSong =0;
// GUItool: begin automatically generated code
#include <Wire.h>

AudioSynthWaveformDc     dc1;            //xy=1527.381031036377,743.0953025817871
AudioPlayMemory          playMem1;       //xy=1541.6666564941406,567.3809337615967
AudioEffectMultiply      multiply1;      //xy=1853.095272064209,685.952428817749
AudioOutputI2S           i2s1;           //xy=2034.5238167898995,688.8095310756138
AudioConnection          patchCord1(dc1, 0, multiply1, 1);
AudioConnection          patchCord2(playMem1, 0, multiply1, 0);
AudioConnection          patchCord3(multiply1, 0, i2s1, 0);
// GUItool: end automatically generated code

void loadSong( uint8_t n = numSong) {
  song.open(songNames[numSong],FILE_READ);
  if (!song) {
    Serial.printf("%s not found.\n",songNames[numSong]);
    return;
  }
  size_t length = song.fileSize();
  if (length > (4*sizeof(extSong) ) ) {
     length = 4*sizeof(extSong);
  }
  size_t start = millis();
  //Serial.printf("Before [0],[1],[280060],[280061] %x , %x , %x ,%x \n",extBeHappy[0],extBeHappy[1],extBeHappy[280060],extBeHappy[280601]);  size_t start=millis();
  song.read(extSong,length);
  song.close();
  Serial.printf("Read %s to ExtMem. It took %d millis\n",songNames[numSong],millis()-start);
}

void setupAudio(void)
{
  Serial.begin(115200);
  //while (!Serial.available() )   {};
  while (!SD.begin(BUILTIN_SDCARD))
  {
    Serial.println("...waiting for SD card...");
    delay(250);
  }

  Serial.printf("\n");
  loadSong(numSong);
  numSong++;
  /*
  song.open(songNames[numSong],FILE_READ);
  if (!song) Serial.println("Song file not found.");
  size_t length = song.fileSize();
  size_t start = millis();
  //Serial.printf("Before [0],[1],[280060],[280061] %x , %x , %x ,%x \n",extBeHappy[0],extBeHappy[1],extBeHappy[280060],extBeHappy[280601]);  size_t start=millis();
  song.read(extSong,length);
  song.close();
  */
  //Serial.printf("After [0],[1],[280060],[280061] %x , % x, %x ,%x \n",extSong[0],extSong[1],extSong[280060],extSong[280061]);
  Serial.flush();
  pinMode(A0,INPUT);
  AudioMemory(8);
   playMem1.play(extSong);
}


void loopAudio() {
  // put your main code here, to run repeatedly:
  int pot=analogRead(A0);
 // Serial.printf(" pot = %d,  %f\n",pot,pot/750.0);
  dc1.amplitude(pot/750.0);
  if (!playMem1.isPlaying()) {
    loadSong(numSong);
    numSong++;
  if (numSong > sizeof(songNames)){
    numSong = 0;
  }
    playMem1.play(extSong);
  }
}

If I add PROGMEM in front of the songNames array I get this compiler error:
Code:
In file included from /Users/raine001/Documents - MacBook Pro/Arduino/TeensyEyes/config.h:28,
                 from /Users/raine001/Documents - MacBook Pro/Arduino/TeensyEyes/TeensyEyes.ino:65:
/Users/raine001/Documents - MacBook Pro/Arduino/TeensyEyes/src/toonstripe.h: At global scope:
/Users/raine001/Documents - MacBook Pro/Arduino/TeensyEyes/src/toonstripe.h:105:18: error: 'toonstripe::eyeSclera' causes a section type conflict with 'songNames'
  105 |   const uint16_t eyeSclera[eyeScleraWidth * eyeScleraHeight] PROGMEM = {
      |                  ^~~~~~~~~
/Users/raine001/Documents - MacBook Pro/Arduino/TeensyEyes/audio.ino:10:14: note: 'songNames' was declared here
   10 | PROGMEM char songNames[][33] = {"ExtBuglecallrag.bin",  "ExtCutthecake.bin", "ExtFourbrothers.bin",     "ExtJavajive.bin",      "ExtOops.bin",  "ExtTheohofpleasure.bin",
      |              ^~~~~~~~~
Multiple libraries were found for "Audio.h"
  Used: /Users/raine001/Library/Arduino15/packages/teensy/hardware/avr/0.59.4/libraries/Audio
  Not used: /Users/raine001/Documents - MacBook Pro/Arduino/libraries/Audio-feature-buffered-SD
exit status 1

Compilation error: 'toonstripe::eyeSclera' causes a section type conflict with 'songNames'

toonstripe.h's relevant section looks like this:

Code:
  // 1x100, 16 bit 565 RGB
  constexpr uint16_t eyeScleraWidth = 1;
  constexpr uint16_t eyeScleraHeight = 100;
  const uint16_t eyeSclera[eyeScleraWidth * eyeScleraHeight] PROGMEM = {
    0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xFC98, 0xFC98, 0xFC98,
    0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF,
    0xBFDF, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xBFDF, 0xBFDF, 0xBFDF,
    0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98,
    0xFC98, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xFC98, 0xFC98, 0xFC98, 0xFC98,
    0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xFC98, 0xFC98, 0xFC98,
    0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xFC98, 0xFC98,
    0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xFC98, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF,
    0xBFDF, 0xBFDF, 0xBFDF, 0xBFDF
  };

I could understand it if FLASH were full, but that doesn't seem to be the case. I'll be reducing the number of eye definitions. toonstripe is the last eye definition in the list of #includes. When I removed toonstripe, so that spikes was the last eye #included the error was attributed to spikes.

I've got some issues that look to me like stack corruption, so I really want to put that array into PROGMEM and I don't understand why there would be a section conflict.
 
I have another question, trying to understand what is going on with the stack, I've found this (which generates appropriate numbers but a bunch of compiler warnings and only ratchets up as more and more of the words marked at setup are used) and also found, in an old version SD..., FreeStack.h. FreeStack doesn't give correct answers, presumably because it makes different assumptions about where the heap and stack are on the T4.1, but it seems like potentially a better approach--it could give current stack usage rather than max ever used. Is there a version of this approach for the T4.1?
 
I played around with the idea of FreeStack.h this might be accurate; the numbers seem sort of reasonable:
C++:
// brief FreeStack() function.


#if defined(__IMXRT1062__)

extern unsigned long _edata;
extern unsigned long _sbss;
extern unsigned long _ebss;
//  extern unsigned long _flexram_bank_config;
extern unsigned long _estack;

static int FreeStack() {
  char top = 't';
  return ( (uint32_t)&top - (uint32_t)&_ebss  );   //or _edata?
}
#else
#warning FreeStack is not defined for this system.
static int FreeStack() {
  return 0;
}
#endif  // FreeStack_h

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);

}



unsigned int fibonacci_recursive(unsigned int n)
{
    if (n == 0)
    {
        return 0;
     }
     if (n == 1) {
           return 1;
     }
     Serial.printf("n: %d    FreeStack: %d \n",n,FreeStack());
     //Serial.printf("n: %d    FreeStack: %d   _sbss: %x   _estack: %x  _ebss: %x\n",n,FreeStack(),(uint32_t)&_sbss,(uint32_t)&_estack,(uint32_t)&_ebss);
     delay(250);
     return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2);
}

void loop() {
  fibonacci_recursive(30);
  // put your main code here, to run repeatedly:

}
 
I tried googling GCC and section type conflict. I found explanations that I can't follow/seem to require more thorough understanding of GCC than us simple Arduino IDE types are ready for.

Here I found this comment: "
This question is an exact duplicate of Inline static data causes a section type conflict, of which I wrote the accepted answer with a detailed explanation and for which the OP's own subsequent solution is nicer. The use of __attribute__ as in the problem is unsupported by GCC.
Mike Kinghan
Sep 14, 2017 at 9:33 "

And I think what he is saying is the better answer is this
C++:
const int* get_data()
{
  static const int data = 123;
  __asm__(
    ".pushsection .custom, \"?\", @progbits" "\n"
    ".quad %c0" "\n"
    ".popsection" "\n"
    : : "i"(&data)
  );

  return & data;
}

inline const int* inline_get_data()
{
  static const int inline_data = 123;
  __asm__(
    ".pushsection .custom, \"?\", @progbits" "\n"
    ".quad %c0" "\n"
    ".popsection" "\n"
    : : "i"(&inline_data)
  );

  return & inline_data;
}

int main()
{
  (void) get_data();
  (void) inline_get_data();
  return 0;
}

But both Kinghan's long, thorough explanation and the shorter solution which seems to be nested inside __asm__ and .pushsection are way beyond my level of understanding. It still seems to me there ought to be a simpler explanation and I can't see why the array of strings would somehow not be seen by the complier as the same sort of thing as the other array of uint16.
 
I had integrated some sound support in my github files (note, I have't pushed binary sounds I created yet), but evidently github turned off svn (subversion) support today and I can no longer do a git push to update the remote directory. This week will likely be busy, so it may be some time before I figure out how to setup github without using git.

Using internal mono binary sounds, I get delays like I saw previously with wav files. I was wanting to see if playing wav files from flash memory instead of SD cards worked better, but I haven't gotten the SD card to work yet.
 
FWIW, I figured out what the problem was with github. I had been accessing github via https, and it was relying on using password authentication (which was recently turned off for security reasons). I re-registered one of my ssh keys with them, and I re-cloned the files using ssh authentication instead of https. I then did the updates I had previously done in my local sandbox, and I did a git push.
 
Hi,

I'm new here in the forum and come from Germany. I've been building decorations and props for Halloween for a few years now.

Two or three years ago I installed the uncanny eyes in a skeleton using a Teensy 3.2. Unfortunately, this microcontroller is no longer available, so I hastily ordered a teensy 4.0 after reading that it's possible to create the eyes with it also.
I need it for a new project.

I'm smarter now and should probably have ordered a Teensy 4.1 instead. However, soldering is not a problem for me, if that is the only difference from the 4.1.

My question now would be, whether anyone has a picture of the circuit diagram for the screens with the Teensy 4.0. I have the following screens to choose from:

1,54" without CS
1,54"

1,67" without CS
1,67"

Are they connected to the Teensy 4.0 in the same way as the 1.44" TFT screens to the 3.2? I read about additional wires that have to be soldered to the teensy 4.0. Where does this have to be done?

teensy 3.2 & 1.44 TFT.jpg



I primarily only need the eyes without any interaction from outside. I read that sound should also be implemented or the ability to change eyes. Although I didn't understand what the sound was supposed to be for.

It could be, that I make the skull (the new project) talk, but I would then do that separately using a Pi Pico.


Must the same libraries integrated for the TFT (ST7789) on the Teensy 4.0 as on the 3.2 (Adafruit_GFX, Adafruit_BusIO, Adafruit-ZeroDMA and Adafruit_ST7789 instead of Adafruit_ST7735)?

I would be happy if you could help me with my eyes.

Greetings
Peer

EDIT:
I just received the 1.54" screens and unpacked them.
They have a CS pin after all.
However, the screens have completely different connections than the 1.44".
How should I connected the two screens to the Teensy 4.0?

1,54 with CS.jpg
 

Attachments

  • teensy 3.2 & 1.44 TFT.jpg
    teensy 3.2 & 1.44 TFT.jpg
    152.4 KB · Views: 45
Last edited:
if you look at Chris' code (in config) you see:
Code:
#ifdef USE_GC9A01A
GC9A01A_Config eyeInfo[] = {
    // CS  DC MOSI SCK RST ROT MIRROR USE_FB ASYNC
       {0,  2, 26, 27, 3,  0, true,  true, true}, // Left display
       {10, 9, 11, 13, 8,  0, false, true, true}, // Right display
};
#elif defined USE_ST7789
ST7789_Config eyeInfo[] = {
    // CS  DC  MOSI SCK RST ROT MIRROR USE_FB ASYNC
    {  -1,  2, 26,   27, 3,  0, true,  true, true}, // Left display
    {  -1,  9, 11,   13, 8,  0, false, true, true}, // Right display
};
#endif

This separates left/right eyes more than what your diagram does. Pins 26 and 27 are on the back of the teensy 4.0, so a little harder to use. I've been using a 4.1 but I think those pins all work with a 4.0.
 
I'll try to expand it later, but there are different Teensy Eyes, based on what display you have.
  • With the original 128x128 TFT LCD displays (that you have) you want a variant of the original code. Look for the example 'uncannyEyes_async_st7735.ino'. Note, that example has been modified for the newer 240x240 display, and you will need to remove defining USE_ST7789 and adjust config.h to the eye pattern that you want. For best results on the Teensy 4.0, you will need to solder wires to several pins under the Teensy 4.0 (at least pins 26 for MOSI1 and pin 27 for SCLK1 -- my modification of the code also uses pins 24 & 25).
  • With the uncannyEyes_async_st7735.ino script, If you undefine ST77XX_ON_SPI_SPI1, you can use the same pinout that you used for the Teensy 3.2, i.e. sharing both displays on the first SPI controller. The eyes will be much slower than on the Teensy 3.2 because the uncanny eyes code used special optimizations in the Teensy 3.x boards. Unfortunately, those optimizations don't exist on the Teensy 4.x boards. If you share the displays on the first SPI bus, you must use displays that have a CS pin.
  • If you have the 128x128 OLED displays, you may need to do some hacking as the uncannyEyes_async_st7735 no longer has the OLED support (the example is in the st7735_t3 library). I recall there was another uncanny eye example code that didn't support 2 SPI ports, but it kept in the OLED display support. Note, I've found the OLED displays often times need the SPI bus to be slower so the data being sent does not overrun what the display can handle.
  • If you have the square 240x240 LCD display you can use the uncannyEyes_async_st7735.ino example. Note, there is only one 240x240 eye in that source base.
  • If you have either the square 240x240 LCD display or the round 240x240 display, you can use Chris's code (which uses platformio, not Arduino) or my adapation of Chris's code that uses Arduino. For two eyes, you will need to solder wires on the Teensy 4.0 to get to the second SPI bus, and you have to run each eye on a different SPI bus. Using Chris's code you have a selection of more eyes, and in fact the code can alternate between the eyes. I've discovered on the Teensy 4.0, that there isn't enough memory to load all of the eyes (but there is with the 4.1 code). Chris's code also has support for the person sensor that Sparkfun sells, which in theory allows the eyes to track a moving person. While Chris has put in optimizations for the display, ultimately a 240x240 display will be slower than a 128x128 display on a Teensy 3.2 due to more data that has to be transmitted to the display.
  • Code bases:
 
Last edited:
First of all thank you for your answers.

I will use the square 240x240 LCD display.

The first thing I tried to do was to draw the wiring between the two TFT's and the teensy by following the pin design from Chris's code.

#elif defined USE_ST7789
ST7789_Config eyeInfo[] = {
// CS DC MOSI SCK RST ROT MIRROR USE_FB ASYNC
{ -1, 2, 26, 27, 3, 0, true, true, true}, // Left display
{ -1, 9, 11, 13, 8, 0, false, true, true}, // Right display
};

teensy 4.0 with tft.jpg


Unfortunately I didn't understand where the CS connections from the TFT's are connected to the teensy.
Or does the "-1" in the code have a different meaning and the wiring is already finished - as shown above?
In the official pin-out, pin 10 is CS.
I have for now put both CS connections on pin 10 and hope this is correct (dashed line)?
Another CS port seams to be on the back of the teensy 4.0 (pin 36).

The support for the Sparkfun person sensor sounds really cool.
Is there a video on how this works or is it still in the development stage?
A picture of how the sensor is connected to the teensy would be helpful.
I my opinion it would be even better if the head turned in the direction where a face was recognized, controlled by a servo.
Is this possible or has anyone already tried it?

Does the alternation between eyes occur automatically and can I switch it off?
I would only need one eye style for my current project.

Greetings
Peer
 
First of all thank you for your answers.

I will use the square 240x240 LCD display.

The first thing I tried to do was to draw the wiring between the two TFT's and the teensy by following the pin design from Chris's code.

#elif defined USE_ST7789
ST7789_Config eyeInfo[] = {
// CS DC MOSI SCK RST ROT MIRROR USE_FB ASYNC
{ -1, 2, 26, 27, 3, 0, true, true, true}, // Left display
{ -1, 9, 11, 13, 8, 0, false, true, true}, // Right display
};



Unfortunately I didn't understand where the CS connections from the TFT's are connected to the teensy.
Or does the "-1" in the code have a different meaning and the wiring is already finished - as shown above?
In the official pin-out, pin 10 is CS.
I have for now put both CS connections on pin 10 and hope this is correct (dashed line)?
Another CS port seams to be on the back of the teensy 4.0 (pin 36).

Each display's CS pin should connect to a separate pin, and then in config.h you edit the code to list that pin. If the device doesn't have a CS pin, then you would put -1 for the CS pin. Some of the square 240x240 displays don't have CS pins.

The role of the CS pin is to enable the device when you have multiple devices on a SPI bus. I.e. on a shared bus, you have the 3 standard SPI pins that all devices use (MOSI, MISO, and SCK), and the CS pin is unique for each device. Essentially the displays are like an old fashioned party line in rural areas, where everybody is on the same line, and the CS pin says who the communications are meant for.

If you are curious, D/C tells the display whether the data being sent out is data or SPI command, and RST resets the display.

My personal setup is:
  • Display #1, MOSI = 26, SCK = 27, CS = 0, D/C = 24, RST = 25
  • Display #2, MOSI = 11, SCK = 13, CS = 22, D/C = 9, RST = 10

In looking at this, I should have reversed the order of the displays, so if you have only one eye, it uses the pins you can get to easily on the Teensy 4.0. Maybe I will reverse now that I looked at the code again.

For Teensy 4.x processors, it doesn't matter what digital pin you use for CS. The CS, D/C, and RST pins have to be unique for each device.

For Teensy 3.x processors using the 128x128 displays there several special CS pins that if you select the appropriate pin for CS and D/C it will allow you to speed up the display, and you use the same MOSI/SCK for both displays.

If you have a Teensy 3.x, this post highlights these special CS and D/C pins: https://forum.pjrc.com/threads/33014-SPI-Chip-Selects-(Teensy-3-1-vs-3-2)?p=96072#post96072. There are 9 special CS pins, but you can only pick certain combinations.

The optimization requires both CS and D/C to have these special SPI pins. On the Teensy 4.0, there is only one special CS pin (10) for the first SPI bus, and one special CS pin (0) for the second SPI display. The Teensy 4.1 added 2 more special pins for the first SPI bus (36, 37) and 1 more special pin for the second SPI bus (38).

As far as I know, none of the libraries use these special pins in the Teensy 4.x. In the original Uncanny Eyes code, they only used the libraries to set up the displays, and the Uncanny Eyes code talked directly to the displays. In the newer code for the Teensy 4.x, all of the special code that talked directly to the device was removed, and the code now uses the libraries to talk to the device. The libraries have some options to speed things up such as using DMA and secondary frame buffers.

I tend to set up Teensys like tinker toys (tm), in that I try to set up pin assignments, so that I can mix and match different things. I also setup a common wiring for displays, so that I can make a cable from the display that has the pins laid out in a standard configuration, so that I can easily switch between 128x128 OLED, 128x128 TFT, 240x240 square, and 240x240 round displays, even though the order of the pins on each display is different.

The support for the Sparkfun person sensor sounds really cool.
Is there a video on how this works or is it still in the development stage?
Chris added the code just before dropping off the list. It should be earlier in this thread.

Also there is this page: https://www.hackster.io/useful-sensors/projects on projects people have done with the sensors.
A picture of how the sensor is connected to the teensy would be helpful.
It is a standard I2C sensor, i.e. you hook up 3.3v, ground, the SCL pin to pin 19, and the SDA pin to pin 18.
I my opinion it would be even better if the head turned in the direction where a face was recognized, controlled by a servo.
Is this possible or has anyone already tried it?
Yep. There is this code for Arduinos from several years ago: https://www.instructables.com/Arduino-Animatronic-Eyes/.

There is also this site that offers Hardware, Electronics, Supplies, Custom Engineering and Technical Assistance for the
Animatronic, Robotic, Electronic Arts, Entertainment Engineer, for theHobbyist and Professional: http://www.bpesolutions.com/bpemodel.html.

Note, I just saved those links when I noticed them, but I haven't looked at them.

Does the alternation between eyes occur automatically and can I switch it off?
I would only need one eye style for my current project.

Greetings
Peer
Its in the code in config.h. Each eye is a separate .h file. You would just reduce the list to the eye that you wanted, and change the count of the number of eyes to 1. If desired, you could eliminate the code that selects the new eye.

In the code that Chris started from on Adafruit, there is support for only one eye, and it is not compiled into the code, but instead it is read from flash memory at boot time. This way you could easily replace the eye you wanted to use without having to recompile it. For example, on the Adafruit Monster M4SK product (basically 2 displays set up for goggles/eyeglasses), there are 3 buttons on the M4SK. The flash memory can hold 4 eyes, and you select which eye you want when the M4SK is turned on, either by pressing no buttons, or pressing one of the 3 buttons on the M4SK.

Here is the Adafruit learning guide for the Monster M4SK: https://learn.adafruit.com/adafruit-monster-m4sk-eyes.

I've always wanted to restore that functionality, using either the SD card in the Teensy 4.1 or using flash memory and MTP so things can be done via USB like you could do with the Monster M4SK. Note, the M4SK is memory limited, and it can only hold one eye at a time.

The Teensy 4.0 is less memory limited, and I found I could hold 8 eyes in it (cat, demon, dragon, hazel, hypnoRed, skull, snake, and toonstripe), while the Teensy 4.1 has more memory, and I could fit all 23 eyes. I could also fit 5 small RAW sound files before running out of program memory.
 
Last edited:
@MichaelMeissner

Hi MichaelMeissner,

thank you for so much information.

I now tried to solder the cables on the back of the teensy 4.0 on the solder pads 26 and 27.
Unfortunately the soldering pad 27 broke. What a pitty.
I have now soldered the cable to connection 37 instead and hope that I can also use it.

A few years ago, with the uncanny eyes on the teensy 3.2, the next step was to download the data (Uncanny_Eyes-master.zip).
In the unpacked folder, the sketch was then transferred to the Arduino IDE by double-clicking on uncannyEyes.ino.

The teensy 4.0 is prepared so far.
I have updatet Adafruit_GFX, Adafruit_BusIO, Adafruit_ZeroDMA and the library for ST7735 and ST7789 to the latest versions.

Which folder do I have to download now, to transfer the correct data to the teensy?

Is this the correct link:
https://github.com/MichaelMeissner/TeensyEyes/tree/main/src/util

Alternatively:
https://github.com/chrismiller/TeensyEyes/tree/main/src

Greetings
Peer
 
It depends. It is somewhat messy.

My sources are in a git tree. There are 2 active branches.

The reason is it made merging of Chris's code into main simpler. Since my 'main' branch is essentially a clone of their/his/her branch, I first do a pull from her/his/their branch. Then I can do a merge to incorporate the changes into the 'meissner2' branch. There was originally a 'meissner' branch, but I messed up the merging, and it was simpler to restart from the original sources.

Chris's branch is: https://github.com/chrismiller/TeensyEyes/tree/main

In all of them, the actual sources are in the 'src' sub-directory, which is what you want to pick up if you aren't interested in the stuff for making new eyes.

Chris only uses platformio, and I only use Arduino.

Platformio can build things in sub-directories, but the Arduino framework doesn't seem to like having sub-directories. So I added a bunch of build-*.cpp files the directory that include the sources in sub-directories so they can be built.

I also re-organized the config.h stuff so that I could have several build directories, each of which was for a different configuration. That way I have a 'config-display.h' file that gives simple #ifdefs that say which feature to use, and the main 'config.h' file uses that. In my build setup, I make a symlink to the appropriate 'config-display-*.h' file, and I can build different eye configurations:
  • ST7789 (square) vs. GC901A (round) display
  • 1 vs. 2 eyes
  • Whether the person sensor is used
  • Whether static sounds are included in the build (note, I don't have the sounds exported at present).

With the old 128x128 sources, I had moved the sources into a library, so the .ino file would just set a few defines, and include the whole library, but so far I haven't done that with these sources, opting instead for using the symlink for config-display.h.

I probably should make a zip file containing all of the sources to make it simpler for people to download.

In terms of pin 37, that won't work unless you also use pin 34. I.e. the 3 SPI buses have specific pins:
  • Pins 11 (MOSI), 12 (MISO), and 13 (SCLK);
  • Pins 26 (MOSI1), 1 (MISO1), and 27 (SCLK2) -- on the Teensy 4.1, pin 39 can also be used for MISO1 if you add code to change MISO1 default;
  • On Teensy 4.0, pins 35 (MOSI2), 34 (MISO2), and 37 (SCK2); (and)
  • On Teensy 4.1, pins 43 (MOSI2), 42 (MISO2), and 45 (SCK2), which you need to access through a shim that brings out the pins in the SD card. Or you can use the pins for the 2 PSram/flash pads, pins 50 (MOSI2), 54 (MISO2), and 49 (SCLK2), providing you add code to change the defaults.
  • With the displays, you don't have to worry about the MISO pins, which are used if the SPI device is transmitting information to the Teensy. I do suspect that even if MISO is not used, you should not use that pin for anything else.
Yeah, I've pulled off the pad on one of my Teensy 4.0's, but fortunately it was pin 28 or 29, and not pins 26 or 27. That is why my default pin assignments skip pins 26 and 27. When the Teensy 4.1 came out, it became easier to move to that, so I didn't have to deal with bringing out the pins underneath the Teensy, but I still have the Teensy 4.0 in one setup.
 
Last edited:
Hello MichaelMeissner,

thank you very much for your detailed answers.

I have now redrawn the wiring.

teensy 4.0 with tft_Ver.1.1.jpg



Are the connections correct now?

If the wiring is OK, I would turn my attention to the software.
However, there are still a few questions for me.
 
Hello MichaelMeissner,

thank you very much for your detailed answers.

I have now redrawn the wiring.

Are the connections correct now?
They look correct, with the proviso I've never used the 3rd SPI bus that is setup for wiring a SD card.

I usually connect the BL pin to 3.3v. In theory, it should handle not being connected, but I figure it is better to be safe.

If the wiring is OK, I would turn my attention to the software.
However, there are still a few questions for me.
Sure, but note I don't know much about the rendering or the display. Chris was the only person I know that dug into how the eye is actually rendered. Others have worked on the display side of things.
 
Such a crap.
I think I destroyed the teensy.
When I connect it to the laptop via USB, it can no longer be found. The LED on the board no longer flashes either.

With the connections at pins 26 and 37 it still worked. After I had already unplugged the teensy, I fixed the cables a little with hot glue.

Today I soldered the cable that actually belonged to pin 26 to pin 35. Now nothing works.
 
Unfortunately nothing happens.
the LED doesn't come on.

I soldered a cable to pin 35.
What would happen, if accidentally pins 34/35 or 35/36 were bridged with solder?

The cable has now come off again.
No change.
 
If you post pictures of the unit that was damaged, maybe a cause could be determined, & potentially a solution identified. Others have caused similar problems in soldering, but were able to revive their damaged Teensy after removing solder balls, opening solder bridges, & touching up bad soldering jobs. Maybe your first Teensy can likewise be saved.

See <this> post for Paul's excellent comments on good soldering, as well as a link to a good tutorial on the same subject (here's the link to Paul's post again...sometimes my phone mangles links when pasting them into the URL tool):

https://forum.pjrc.com/threads/73258-Audio-Tutorial-Assembly-Issue?p=329329&viewfull=1#post329329

Hope that helps . . .

Mark J Culross
KD5RXT
 
Back
Top