New OLED shield for Teensy 3.x and LC

Status
Not open for further replies.
7.327ms seems like a good time to beat. I should go update my SFun order from single ship.

@MM - those are color and 16 times more data? I wonder if that (snow) is a factor of the display design. Sumotoy noted in his readme the ssd1331 color OLED (only 96x64) has a buffer on the display side and fast updates are clear and snow free - though that was only at 20 MHz SPI with an 80 MHz STM32 - it was running 18 times faster with Sumotoy code than Adafruit's. On Teensy it uses Fast SPI. He notes there the 1351 is not nearly as capable.

SSD1331 is a full featured driver for 96x64 oled with a lot of useful registers and an hardware accellerated standalone scroll that I never seen in other drivers. This controller is currently supported.
 
Ok I did my first pass at changing it to use my SPIN object. Needs cleanup to handle more cases where not using hardware CS and DC...

But on my machine with CS/DC on 20, 21 which are hardware pins.

My first pass through looks like page update is now 4.5ms Note: they are running SPI at 1mhz. Can probably push this some. My quick look at the spec looked like the clock could maybe go closer to 10mhz although could not tell if the 100ns was the whole clock speed or not... May try at something like 4mhz or 8mhz and see what happens.
 
Since the Adafruit library runs their SSD1306 driver at 8mhz, I thought I would try this here.
The library already had a setClockRate method, so used it.

So far it appears to work fine at this speed. Now the measured time to update: .5807ms so pretty nice.

Again WIP, I have only tested it on one configuration with the one app... Also a couple debug messages still in to let me know if it is using SPIN code or not.
And again only tested with both CS/DC being hardware SPI pins...

But if anyone wishes to play along, I just forked it from Sparkfun and made a new branch: https://github.com/KurtE/SparkFun_TeensyView_Arduino_Library/tree/Spin-version

Side note: Built using current Stino2017 installed in SubmlimeText3...

Also ordered new TLC from PJRC to be able to solder in same headers as I have on T3.2 to test with...
 
Decided to not to wait for new T-LC. So used a bunch of jumper wires to hook up to a TLC I had sitting around.

First pass was to more or less use same code as original if not on Kinetisk board. In one of the tests I got lazy and did not hook up Logic Analyzer but did a quick and dirty time test:
Code:
      uint32_t start_time = micros();
      oled.display();
      uint32_t delta_time = micros()-start_time;
      Serial.println(delta_time, DEC);
The original code was reporting number sin the 8000+ range.

I did some quick updates to not do beginTransaction/EndTransaction and set/clear CS pin around each output and the test runs were then reporting i the range of:
3000+ so it helped reasonably.

I then build a version of the functions similar to ones used in ili9341_t3 library where instead of calling SPI.transfer, I talk directly to the SPI registers and I make use of the double buffer of it, so that there is already data to output, when the shift register completes an output....

Anyway it appears to work and now I am seeing numbers in the range like: 915
So I am happy with it...

Anyway I pushed this version up to my branch I mentioned above. I also updated my SPIN library for the TLC to return back a pointer to the SPI registers...

Still probably need to clean up and then see if anyone is interested.
 
SparkFun should like that - supposing it actually works :)

It would be interesting to run their FFT example from their video on audio board. Their vid shows loop times of 9-11 ms - if much of that is display time that can go away they'll be impressed when they can get 8 updates for the time of one for raw screen display.

Here is this note on their tutorial page:
Teensy 3.1 to 3.6 (Note: CPU usage at 100% on the 3.1 with both FFTs enabled)

I really like that font in their vid.
 
Thanks I may let them know about my version of their stuff.

This morning I did a little more testing on T-LC including
SPI0 on pin MOSI(11), SCK(13), CS(20), DC(21) - Pins as I have the solder jumpers set - Worked
SPI1 on (21, 20, 3, 5) - Worked

Then setup Jumpers for T3.6 (beta 1 board)
SPI0 on (11, 13, *20, *21) -Both CS/DC on hardware CS - Worked
SPI1 on (21, 20, 32, *31) - 31 is hardware CS - Worked
SPI2 on (52, 53, 51, *55) - Pins connector near SDCard - Worked

Note in all cases Reset on 15 (hardware jumper)

So I have faster speeds and works on all the SPI buses :D

Kurt
 
Good work! SFun split my order so my TeensyViews should ship - $7 charge to 2nd ship the other half when available.

SFun has 7 in stock again! - down to 6 before I posted ...

Will wire to my AudioBoard T_3.2 to see what it does to their loop timings when I get one if you don't first.

So the nature of the .display() is that it always dumps full screen on any update - not just the changed parts? Tracking dirty might be counter productive - but rectangle update might be fun.
 
Still probably need to clean up and then see if anyone is interested.

I'm interested! I'm pretty busy though so let me know when you're done poking around (or, pull request maybe?). I get all the notifications for the SparkFun_TeensyView_Arduino_Library repo.

I chose to limit the scope of the library to just Teensy products to keep it easier (and more fun) to modify and play around with. I'm glad you've had some success with it!

Also, we should have another 200 or so in a few days.
 
I would have acted sooner if Kurt had let me add his to my order . . . without that motivation I almost waited too long ...

The few in Stock noted above are now gone - and showing : "We are currently planning to build 240 units."

Glad Kurt got his quickly and put his SPI skills to good use :) That display Teensy sized - for better and worse - but looks very clear and being fast it will be handy to have.

Hopefully @GremlinWrangler got one and will build up a nice "oscilliscopeish device" :)
 
Has taken a fair number of tries and certainly doesn't qualify for a thread of it's own yet but progress looks like
SnotAScope.jpg
This is using a different 128/64 OLED

Lots of interesting trad offs in the design so certainly can't be called a scope but liking the shape and weight enough to keep playing with it to get the angles right. At the moment uses the raw ADC with a resistive divider to get 0-5.5V input range and that loads an i2C interface (probing the OLED because it's handy) enough to not get useful readings. Fighting temptation to work out how to dead bug an op amp in there somewhere.
 
Looks interesting, I thought about picking up an 128x64 one from amazon.... I have an I2C version but thought about picking up SPI version to try out the speed differences...
 
Looks interesting, I thought about picking up an 128x64 one from amazon.... I have an I2C version but thought about picking up SPI version to try out the speed differences...

I've played with 128x128 displays using the uncanny eyes program that displays a pair of eyes as fast as possible (using DMA speed-ups). I've found that the generally available TFT displays are a lot faster than the OLED displays. I can run two TFT displays at 240 Mhz on a Teensy 3.6. Unfortunately, for the OLED displays, I have to reduce the clock speed to 24 Mhz (for the Adafruit display) or 48 Mhz (for the New Haven display).

This is the Adafruit TFT display I've been using:

This is the 128x64 display:
 
I'm interested! I'm pretty busy though so let me know when you're done poking around (or, pull request maybe?). I get all the notifications for the SparkFun_TeensyView_Arduino_Library repo.

I chose to limit the scope of the library to just Teensy products to keep it easier (and more fun) to modify and play around with. I'm glad you've had some success with it!

Also, we should have another 200 or so in a few days.
Thanks,

I did some more playing today and I believe I have version that it hopefully works on enough configurations now. So I went ahead and merged all of my changes into one commit. The biggest thing I needed to do today was to make the code work in the default configuration, where DC is on pin 5 which is not a hardware CS pin, so the code that manages the pushing stuff onto the hardware queue had to change in some cases. In particular things like had to changes places that were doing
writecommand_cont to writecommand_last if it was the last command before I started to output data, and likewise with writedata... Then needed to add code that then managed the DC pin... So far it appears to work OK and did not kill performance too bad. Example the code that updated the display when both CS/DC are hardware CS pins was taking maybe 545us and with this change it is taking maybe 555us... (This was on T3.2)...

After these changes I tried again with T3.2 with default pins, plus my hardware setup pins, plus TLC with my pins...

Again This library (https://github.com/KurtE/SparkFun_TeensyView_Arduino_Library/tree/Spin-version) currently relies on my SPIN library (https://github.com/KurtE/SPIN)

Let me know if anyone has a chance to try my version out.

Again I have boosted my version of the test program up to 8mhz: oled.setClockRate(8000000); // Lets try 8mhz
This was called right before the line: oled.begin();
I thought about changing the default to this as I belive it is in spec and Adafruit defaults to this as well.

Kurt
 
Again This library (https://github.com/KurtE/SparkFun_TeensyView_Arduino_Library/tree/Spin-version) currently relies on my SPIN library (https://github.com/KurtE/SPIN)

Let me know if anyone has a chance to try my version out.

Thanks for the pull request!

I'll take a look at this sometime next week and test it out on the various platforms.

Also, 8MHz is a probably a better default, I may make that change as well. I'll even put a scope on it and check out the signal integrity!
 
Kurt: What does reliance on SPIN mean? Does it have a fallback to standard SPI library or will it only run when that is an added include?
I've watched that you are evolving it - but never worked with it yet.
 
SPIN is my simple library to make it easier to support the different SPI busses. I did when I started doing testing on T3.6. I wanted to test the ILI9341_t3 code on all three of the busses. My first pass at this had the code do things like:
Code:
if (_spi_buss == 0) SPI.beginTransfer(...);
else if (_spi_buss == 1) SPI1.beginTransfer(...);
else if (_spi_buss == 2) SPI2.beginTransfer(...);

Then found I wanted to be able to compile on T3.2... So then had to complicate this and add #if code around each of these, which was not nice.

So I thought it sure would be nice if I could instead have function pointers... But SPI and SPI1 and SPI2 are all separate classes, So I created the SPIN code, which at first was simply files in my test project... Most of the beginning part of the class is simply making virtual functions for each of the standard methods...
Code:
/**********************************************************/
/*    SPIN class definition                               */
/**********************************************************/
class SPINClass {
public:
    // Initialize the SPI library
    virtual void begin() = 0;
    virtual void usingInterrupt(uint8_t n) = 0;
    virtual void usingInterrupt(IRQ_NUMBER_t interruptName) = 0;
    virtual void notUsingInterrupt(IRQ_NUMBER_t interruptName) = 0;

    // Before using SPI.transfer() or asserting chip select pins,
    // this function is used to gain exclusive access to the SPI bus
    // and configure the correct settings.
    virtual void beginTransaction(SPISettings settings) = 0;

    // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
    virtual uint8_t transfer(uint8_t data) = 0;
    virtual uint16_t transfer16(uint16_t data) = 0;
    virtual void transfer(void *buf, size_t count) = 0;

    // After performing a group of transfers and releasing the chip select
    // signal, this function allows others to access the SPI bus
    virtual void endTransaction(void) = 0;
    virtual void end() = 0;

    virtual void setBitOrder(uint8_t bitOrder) = 0;
    virtual void setDataMode(uint8_t dataMode) = 0;
    virtual void setClockDivider(uint8_t clockDiv) = 0;

    // Teensy 3.x can use alternate pins for these 3 SPI signals.
    virtual void setMOSI(uint8_t pin) = 0;
    virtual void setMISO(uint8_t pin) = 0;
    virtual void setSCK(uint8_t pin) = 0;
    // Added ones that are not part of SPI (yet)
    virtual bool pinIsMOSI(uint8_t pin) = 0;
    virtual bool pinIsMISO(uint8_t pin) = 0;
    virtual bool pinIsSCK(uint8_t pin) = 0;

    // return true if "pin" has special chip select capability
    virtual uint8_t pinIsChipSelect(uint8_t pin) = 0;
    virtual bool pinIsChipSelect(uint8_t pin1, uint8_t pin2) = 0;
    virtual uint8_t setCS(uint8_t pin) = 0;

    // Add helper functions from ILI9341, which manage SPI FIFO
#if defined(KINETISK)
    virtual KINETISK_SPI_t *kinetisk_spi (void) = 0;

    virtual uint8_t sizeFIFO() = 0;
    virtual void waitFifoNotFull(void) = 0;
    virtual void waitFifoEmpty(void) = 0;
    virtual void waitTransmitComplete(void)  = 0;
    virtual void waitTransmitComplete(uint32_t mcr) = 0;

    // return DMA Channel information 
    virtual uint8_t dmaTXEvent(void) = 0;
    virtual uint8_t dmaRXEvent(void) = 0;
#endif
#if defined(KINETISL)
    virtual KINETISL_SPI_t *kinetisl_spi (void);
#endif    
};
But I then added a few more methods, as I got tired of seeing all of the libraries trying to update to know what are valid MISO, MOSI, SCK pins for the different platforms... So I added methods to check these in the library in the same way as the SPI library has the pinIsChipSelect methods... Actually think it would be nice to propagate these methods back to SPI library...

I also have a method to return a pointer to the SPI register sets. And then needed to change any code that does things like look at:
KINETISK_SPI0.SR to instead use the pointer like _pkinesisk->SR to allow it to work with any of the busses...

I then added some of the code that was in ili9341_t3 library for managing the queue to the library: example waitFifoNotFull
This was a little more interesting as the queue lengths are different for SPI vs SPI1 and SPI2...

Again most of this code is really simple forwarding functions... That is most of the functions are like:
Code:
void SPIN0Class::begin() {SPI.begin(); }
void SPIN0Class::usingInterrupt(uint8_t n) {SPI.usingInterrupt(n); }
void SPIN0Class::usingInterrupt(IRQ_NUMBER_t interruptName) {SPI.usingInterrupt(interruptName); }
void SPIN0Class::notUsingInterrupt(IRQ_NUMBER_t interruptName) {SPI.notUsingInterrupt(interruptName); }

// Before using SPI.transfer() or asserting chip select pins,
// this function is used to gain exclusive access to the SPI bus
// and configure the correct settings.
void SPIN0Class::beginTransaction(SPISettings settings) {SPI.beginTransaction(settings);}

// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
uint8_t SPIN0Class::transfer(uint8_t data) {return SPI.transfer(data);}
uint16_t SPIN0Class::transfer16(uint16_t data) {return SPI.transfer16(data);}
void SPIN0Class::transfer(void *buf, size_t count) {SPI.transfer(buf, count); }
...

void SPIN1Class::begin() {SPI1.begin(); }
void SPIN1Class::usingInterrupt(uint8_t n) {SPI1.usingInterrupt(n); }
void SPIN1Class::usingInterrupt(IRQ_NUMBER_t interruptName) {SPI1.usingInterrupt(interruptName); }
void SPIN1Class::notUsingInterrupt(IRQ_NUMBER_t interruptName) {SPI1.notUsingInterrupt(interruptName); }

// Before using SPI1.transfer() or asserting chip select pins,
// this function is used to gain exclusive access to the SPI bus
// and configure the correct settings.
void SPIN1Class::beginTransaction(SPISettings settings) {SPI1.beginTransaction(settings);}

// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
uint8_t SPIN1Class::transfer(uint8_t data) {return SPI1.transfer(data);}
uint16_t SPIN1Class::transfer16(uint16_t data) {return SPI1.transfer16(data);}
void SPIN1Class::transfer(void *buf, size_t count) {SPI1.transfer(buf, count); }
...
Should mention this also works for TLC board for supporting SPI1.

Again if desired I could build a version that only uses SPI and probably only supports SPI (not SPI1 SPI2)...

One day it might be nice if we could incorporate this or something like this in the main builds ;)
 
In case anyone wishes to try without using SPIN, I put a version up in the Branch: SPI-Only-Version.

This one does not verify the SPI pins and only works on SPI, not SPI1 or SPI2 ...
 
sorry for off-topic but since it has been mentioned in thread, Just as a FYI, it is still possible to have sparkfun ship by usps. i think it's on the first checkout page but one of the checkout pages has a checkbox saying something to the effect, ship to a P.O. BOX, if you check that box it brings up USPS shipping choices. i used it a week ago. Also, if you don't see the choice you want there is a chance customer service can set you up, i've had mixed success with requests but worth a try. i use first class if i can get it since it also arrives to me in 2-3 days like priority mail does.
 
Thanks for the hint. Earlier I sent email to them and received a response, which included:
If for some reason you require Priority Mail we can still send out packages via this method. However, due to the limitations of sending hazardous materials via Priority Mail it is not on the list of available options during checkout.
If you need to use Priority Mail you can click the button that says “Need to Change Something?” at the end of the checkout process. This will allow you to pause the order and leave a note requesting changes. Just keep in mind that there are certain things (like Lithium Ion batteries) we cannot ship via USPS.
I tried this yesterday as I ordered two more of these displays (they are on sale), but did not get this part to work, probably because I used PayPal...
 
Side note: I just pushed up a new branch (Multiple-64-malloc) to play with:
It is off the SPIN branch.

The changes include support for multiple displays (moved screen buffer into object)

Support 64 line displays: As the only 2nd one I have has 64 lines. My order for 2 more Teensyview shipped today.

Constructor takes an optional parameter (32 or 64 default to 32). I did not want this to work like sparkfun library that you have to edit the library to say which size display you have as this implies you can have one type in all projects...

But to handle this by default if you set the option to allow 64 line displays, the screenbuffer for all objects has enough memory for 64 lines, even though your display may only have 32 lines.

So added another option that says use malloc to allocate the buffer which then only allocates the size it needs... If people hate malloc the other way to do this would be to have you pass in a buffer...
 
Status
Not open for further replies.
Back
Top