Learning SPI & OLED displays.

Status
Not open for further replies.

jim lee

Well-known member
I'm new to the whole SPI thing. What really got me digging into it was the uncannyEyes project that Adafruit has on their website. Bought the parts, 128x128 OLED & Teensy 3.2 processor. Hooked it all up and after some monkeying about, got it all running. The uncannyEyes runs so fast I see no refresh at all. I thought that was really slick. So, I tried writing some test code to the display myself and its really slow!

So, of course I decided to try and steal the eye code..

Having very little luck and my lack of SPI experience is holding me back.

This is the routine I wrote for doing a screen fill of a constant color. Using the same hardware as the uncannyEyes. I basically took the eye draw function, stripped out the color calculation and adapted it to my code. The line "theOLED->fillScreen(inColor->getColor16());" is my original that works, but is slow.

Code:
void adafruit_1431_Obj::fillScreen(colorObj* inColor)     { 

  Serial.println("In fill screen");
  //theOLED->fillScreen(inColor->getColor16());
  
  byte screenX;
  byte screenY;
  word color = inColor->getColor16();
  Serial.println("Gonna make the settings..");
  SPISettings settings(24000000, MSBFIRST, SPI_MODE3); // Teensy 3.1 max SPI
  Serial.println("Settings made, now lets NOT set them..");
  //SPI.beginTransaction(settings);
  Serial.println("Just set the settings");
   
  theOLED->writeCommand(SSD1351_CMD_SETROW);    // Y range
  theOLED->writeData(0); 
  theOLED->writeData(SCREEN_HEIGHT - 1);
  theOLED->writeCommand(SSD1351_CMD_SETCOLUMN); // X range
  theOLED->writeData(0);
  theOLED->writeData(SCREEN_WIDTH  - 1);
  theOLED->writeCommand(SSD1351_CMD_WRITERAM);  // Begin write
  Serial.println("Just sent the block of commands");

  
  digitalWrite(cs, LOW);                       // Chip select
  digitalWrite(dc, HIGH);                       // Data mode
  // Now just issue raw 16-bit values for every pixel...
  Serial.println("Chip select done. Starting loops..");
  
  for(screenY=0; screenY<SCREEN_HEIGHT; screenY++) {
    for(screenX=0; screenX<SCREEN_WIDTH; screenX++) {
      
      // SPI FIFO technique from Paul Stoffregen's ILI9341_t3 library:
      Serial.println("In loop, going to check for space..");
      while(KINETISK_SPI0.SR & 0xC000) Serial.println("Waiting for space.."); // Wait for space in FIFO
      Serial.println("They sid there was space.");
      KINETISK_SPI0.PUSHR = color | SPI_PUSHR_CTAS(1) | SPI_PUSHR_CONT;
    }
  }
  Serial.println("Loops done, cleaning up.");
  
  KINETISK_SPI0.SR |= SPI_SR_TCF;           // Clear transfer flag
  while((KINETISK_SPI0.SR & 0xF000) ||      // Wait for SPI FIFO to drain
       !(KINETISK_SPI0.SR & SPI_SR_TCF));   // Wait for last bit out
  digitalWrite(cs, HIGH);                   // Deselect
  SPI.endTransaction();
  Serial.println("All done, exiting.");
 }

This is as it sits now with trace prints & things commented out that caused it to hang. I need help/info understanding this.

First issue is //SPI.beginTransaction(settings); This caused a hang. What could cause this to hang?

Thanks!

-jim lee
 
Last edited:
First up you reposted 3 hours after your initial post which is a bit optimistic when asking for for free tech support in a place where many are not in your timezone. 24 hours means that most of the regulars will have seen your post and you might think about trying a bump since you'll still miss those who can only pull code apart on weekends. And your problem really needs a specific subset of expertise.

You only posted a subset of the code, so can you provide some context, is it running in your main program block or are you modding the library here?

Re transactions see https://www.pjrc.com/teensy/td_libs_SPI.html, also means you need to make sure you are using the PJRC varient of the SPI library not the generic Arduino one.

There are a whole bunch of ways to speed up draw functions, and while not familiar with the eyes code (you may get more response updating your title to mention uncanny eyes) what appears to be happening there is sending the display an intended draw area and then streaming all the pixels for that area in one go using every single SPI clock to move another pixel bit, rather than starting and stopping the SPI process for each pixel.

In terms of finding out what your code is actually doing suggest using a scope if possible or failing that two LEDs+resistors to confirm that SPI clock and SPI data really are doing stuff when your code is running.
 
Not sure what the No? and Oh well...

Sorry, today I have been busy doing other stuff and have not scanned every message...

I did not see anything obvious, but a lot of your tests for is the queues full or empty is different than how it is done in the ili9341_t3 library. So if it were me, I would borrow some of the inline functions from that library, like:
waitFifoEmpty, waitFifoNotFull, waitTransmitComplete, and maybe some of the others like writecommand_cont, writecommand_last, writedata...

I did this with my SPIN library when I was trying to make a version of some of these libraries that can work with the different SPI busses on T3.5/6... I added many of these like functions to classes as they can be different on different busses, where for example on T3.6 the SPI 0 object has this fifo of 4 entries, but SPI1 and SPI2 have a fifo of 1 entry.

Again sorry, I have not fully checked out your code included, but is what I would do.

Good Luck
 
No need to say sorry, as GremlinWrangler up there said. Like all forum users I'm basically looking for a free handout.

The Adafruit fill a screen with solid color method seems a lot slower than the uncannyEyes stuff, so I tried to patch that call with an altered version of uncannyEyes draw routine. Its been a long day, EVERYTHING I tried failed. In the end I even broke my OLED screen. Some days you just fight the tide. Anyway, after getting nowhere, I went back to using the Adafruit stuff. So, I can go back to work on functionality and stop this mad sidetrack for performance.

Thank you for the info. and links. I have some reading to do tonight. Its obvious I'm going to need to understand SPI a lot better before trying to supercharge it.

-jim lee
 
The uncannyEyes runs so fast I see no refresh at all. I thought that was really slick. So, I tried writing some test code to the display myself and its really slow!

Phil Burgess is among the most talented engineers developing projects in the marker community. He and I have talked in person about this project. I know Phil has invested a tremendous amount of work into greatly optimizing this program, not just at the low SPI level, but with the algorithms too.

You can learn these techniques too. Anyone can, really. Just understand this particular case is one of the most skilled people putting in a *lot* of hard work.
 
I can see a lot of work went into it. He can derive the eye & output it WAY faster than I could just output out a solid color. As the day progressed I saw it more and more. And, my goals became less and less rigorous. By mid afternoon all I wanted was to send multiple bytes without doing chip selects & mode stuff for each byte and I even failed that. So I went back to what worked. I'm going to give it a rest for now.

The other thing this exercise with the Teensy uncovered for me was there's 2 stashes of library files. The library folder in my sketch folder and another that you can't see on Macs in the Arduino package itself. This was causing all sorts of issues when the Teensy installer stuffed the internal folder with all the same Adafruit libraries I already had in my library folder. Suddenly I have multiple definitions of everything. What's the deal with that? Is this some new twist with the IDE?

Maybe today the tide will flow in my direction.

-jim lee
 
Don't give up. But do give it some time. When you get stuck, spend a little time to condense just the problem into a small but complete program anyone can copy and paste into Arduino. The more concise the example, the less time it takes any of us to look at it... but the most critical part is that it is a complete program than can be copied into Arduino and verified or even run on real hardware to see the problem. That's how we work here on this forum, and it does take a little more work to ask a question this way, but it usually works out really well in the end.

The Arduino IDE actually pulls libs from 3 places, your sketchbook libraries folder, then Teensyduino's libraries folder, and then from a folder of libraries built into Arduino.
 
Oh, I'm not giving up. What I'm doing is rewriting an old screen management/windowing/event/drawing structure to run with new hardware. In the past it's been just bent, hammered and tweaked to run whatever was going on at the time. I'm setting it up so you can drop in new screen hardware and it "just works" sort of. If there's any old Mac developers out there reading this, think powerPlant from Code Warrior for Arduino. The original version of this actually ran on an UNO. But, it limited what you could do seeing as it was pretty big. I was able to create a nifty little RPN calculator on an UNO with an Adafruit Cap touch screen. The full version runs on my Mac. But couldn't quite fit all the buttons into RAM. When I bought the Teensy for the eye project, I realized "Hey! I could fit my calculator into this!" So the rewrite started.

So that's where I'm coming from. The SPI supercharging idea was a side track to the huge nonsense I'm working on. Sadly, now I've allowed myself to write for the teensy, I doubt I'll ever get this to fit on an UNO again. :(

-jim lee
 
Success!

I can't draw fast like the cool kids, but I do now have the beginnings of a tiny OS that runs in the background of your sketches. So if you want your sketch to have a little more pizzaz, this is the ticket!

IMG_2219.jpg

-jim lee
 
Last edited:
@PaulStoffregen : Checked my "work" USB cable today. Its dead. Can't upload to my TrinketPros at all. In fact, some of my "dead" trinkets suddenly got well when I brought in the new cable and tested it. So, I guess it was slowly dying and picked that time to die all the way.

Thanks again for all the help!

-jim lee
 
Status
Not open for further replies.
Back
Top