Teensy 3.0 and u8glib

Status
Not open for further replies.
I found my NHD-3.12-25664UCY2 a few days ago. I'm hooking it up now.....

Did you get a chance to do much more work with this display? That's basically what I'm using and it's dismally slow. I need to display a 7 digit number that could count up or down a couple times a second. The display lags behind up to several seconds when fed with the fast changing data. This is using the u8glib library. Reading the other posts about the other displays it seems this is limitation of the library or am I incorrect?
 
Some U8G and Teensy 3 Hardware SPI Success

I picked up a NHD-2.7-12864 this week to play with alongside my Teensy 3. I decided to try U8G because it supports this screen, and I got it (version 1.15) working pretty quickly using software SPI, but I was only getting about 3 fps. I wasn't too bummed...in fact, I was impressed that the U8G lib worked just by dropping it in. Based on the mileage people across the web were getting with Teensy 3 and U8G, I'd figured I'd have had to get my hands at least a little dirty to start seeing results, so I counted myself lucky.

After the buzz passed, I realized that 3 fps wouldn't do, practically speaking. I noticed a link on this forum out to a code repository for an Adafruit_ST7735 Arduino driver, so I popped over there to check it out. After a few hours of code mashing, I was able to adapt the Teensy 3 hardware SPI code from that driver to work in U8G.

I’ve attached the files needed to add the Teensy 3 hardware SPI to U8G, and also my complete U8glib Arduino library folder containing U8G version 1.15 for Arduino and including my tweaks.

  • To use: use the attached files to replace the files of the same name in the U8Glib utility folder
  • Important note: you'll actually need to delete u8g_com_arduino_hw_spi.c and copy in u8g_com_arduino_hw_spi.cpp. I had to change the file to C++ because one of the necessary includes declares a class and confuses the C compiler. Someone with deeper knowledge of the Arduino code stack and the hardware registers could probably make this unnecessary.
  • Also: If you use incompatible pins, the code will fall back to software SPI--but not the U8G software SPI, the software SPI from the Adafruit driver and I have not tested how well or even if it actually works with U8G.

This worked for me. I hope it works for others but no guarantees; quite a bit of this is new to me. Good luck!


Some stats

Code:
[FONT=courier new]-------------------------------------
         FRAMES PER SECOND 
Tested performing a few integer math 
operations and drawing 3 strings to 
the screen using a Teensy 3.0
connected to a NHD-2.7-12864.
-------------------------------------
  MPU Clock  SW1x  SW2x  HW1x  HW2x
  24 MHz      1     1     15    19
  48 MHz      2     2     28    35
  96 MHz      3     3     35    44

SW  Software SPI
HW  Hardware SPI (24 MHz rate)
1x  128 byte buffer (16 screen pages)
2x  256 byte buffer (8 screen pages)
-------------------------------------[/FONT]
 
Hello
Finally i what to try my NHD-2.7-12864 screen with Teensy and U8GLIB, Thanks to your post. Please help me to connect them. I need Teensy pin outs for HW SPI Mode, (SCK = ?, MOSI = ?,
CS =?, A0 = ?)
Thanks in advance
 
Hoss: For the fun of it, I am trying out your changes on the Adafruit 2.8" tft shield and for the most part it appears to be working :)

However when I am running the UTFT_Demo_320x240 modified parameters constructor, it appears like the screen may hang from time to time completely white... Should note, I have been running my teensy 3.1 at 144mhz. The hang is not happening all of the time nor at the same place. It may run through many iterations of the program before the hang, or could happen on the first pass... Trying now at 96mhz... So far it has made it through several passes...

Kurt

Update: It also hung at 96mhz after several iterations
 

Attachments

  • UTFT_Demo_320x240-140525a.zip
    1.9 KB · Views: 205
Last edited:
Hi Kurt, it's great to hear that the tweaks are sort of working for you. :) As far as your particular issue goes, I will say that I really don't have a ton of experience with this stuff, but my first guess would be to try slowing things down. You've said that you've already tried slowing down the CPU clock to no avail, so my next guess would be the SPI clock. The code I pulled from the Adafruit driver defaulted to 6 MHz, but I thought I'd be crafty and up it to 24 MHz (though now that I ran the numbers, even 1 MHz would be enough to reach 30 fps on my display). Unfortunately I don't at the moment know if there's any way to directly interact with the U8G device object, so your best bet is to quick edit the file and change the default.

In the utilities/u8g_com_arduino_hw_spi.cpp file inside the library, inside the u8g_com_arduino_hw_spi_fn function, there's a line that says "ctar = CTAR_24MHz;", Change it to say "ctar = CTAR_6MHz;" and see what happens.

Again, I'm a newbie in this realm, but that would be the first thing I would try.

Hoss
 
Thanks, I will play around some more. In the meantime for the fun of it, I am hacking on my ADAFruit_ILI9341 driver, to add in the ability for hardware SPI. I got the graphictest up and flying, so then I was trying my prototype touch screen code which prints buttons and the like and it does not work. The issue I think is how to handle both SPI devices (display, touch) and potentially a third (microsd). The CS for the touch screen is Pin 8, which is not one of the special processor CS pins. So it probably still needs to run using the software SPI library. Currently added a hack to pass in a flag to constructor to force the use of the SPI library.

So not sure how well you can use the SPI library plus hardware SPI on the same SPI IO lines... Might try to see if one can switch back and forth.

Thanks again
Kurt
 
It'll be interesting to see how that works out. My gut says that as long as you can ensure that there's no chance that hardware SPI and software SPI use the pins simultaneously, you'll be fine.

On the U8G side of things, I also tweaked the library to be able to use a single page buffer per frame instead of 16 for 1x or 8 for 2x, and that further improved the frame to over 90 fps for drawing a couple of strings to the screen at 96MHz MPU clock. It uses quite a bit of memory (for the NHD-2.7, 4KB for the frame buffer at 128x64x4bpp compared to 512B or 1KB for 1x or 2x page buffers), but the Teensy 3.0 has more than enough to still do very cool stuff and the Teensy 3.1 would laugh at it.
 
So far I have gotten it to work with some major hacks. Actually they are both using the hardware SPI, but in different ways. Paul's class objects to emulate the AVR are pretty interesting. I am probably too old of a C programmer (who does use C++) to get used to using all of those operator overrides and the like.

More details in the threads: http://forum.pjrc.com/threads/25718-Adafruit-2-8-quot-TFT-Touch-Shield-for-Arduino-for-Teensy-3-1
and: http://forum.pjrc.com/threads/25884...tiple-implementations-fighting-over-resources

Sounds like you are doing great on this one. May still convert my code over to using this as it has better support for fonts and the like. But then again just doing this to have some fun. Not sure where I will actually use this shield. Maybe I will use it on one of the Hex robots as a secondary input/output device...

Kurt
 
HI all
Hoss Thank you, thank you, and thank you again. I can’t say it enough.

This is blazing-fast on my NHD-3.12-25664UMB3 OLED 256 x 64 ;)
All i had to do is include <SPI.h> Library and setup u8g object,
U8GLIB_NHD31OLED_2X_BW u8g(10, 9); // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are SCK = 13 and MOSI = 11)

And 16 Bit mode for NHD-3.12-25664UMB3 OLED 256 x 64 pixel resolution
16 Bit mode: U8glib can be put into 16 Bit mode. Remove comment from {{{#define U8G_16BIT 1}}} in ...\arduino-1.0.5\libraries\U8glib\utility\u8g.h

Code:
/*

  FPS.pde
  
  >>> Before compiling: Please remove comment from the constructor of the 
  >>> connected graphics display (see below).
  
  Universal 8bit Graphics Library, http://code.google.com/p/u8glib/
  
  Copyright (c) 2012, olikraus@gmail.com
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, 
  are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this list 
    of conditions and the following disclaimer.
    
  * Redistributions in binary form must reproduce the above copyright notice, this 
    list of conditions and the following disclaimer in the documentation and/or other 
    materials provided with the distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  

  ST7920_192X32, SPI:    FPS: Box=7.6   @=9.8                iFPS: Box=11.4  @=14.7
  ST7920_192X32, 8Bit:   FPS: Box=6.2   @=7.5                iFPS: Box=9.3 @=11.2
  DOGM128 SW SPI:        FPS: Box=5.1   @=5.9  Pix=2.6       iFPS: Box=10.2 @=11.8 Pix=5.2
  DOGM128 HW SPI:        FPS: Box=5.5   @=6.3                iFPS: Box=11.0 @=12.6
  DOGXL160 SW SPI:       FPS: Box=1.7   @=1.9                iFPS: Box=6.9 @=7.7
  DOGXL160 HW SPI:       FPS: Box=1.8   @=2.1               
  
  NHD27OLED_BW,       SW SPI: FPS: Box=3.0  @=3.7
  NHD27OLED_BW,       HW SPI: FPS: Box=3.5  @=4.5
  NHD27OLED_2X_BW,    SW SPI: FPS: Box=3.8  @=4.9
  NHD27OLED_2X_BW,    HW SPI: FPS: Box=4.6  @=6.4
  
  30 Sep 2012
  NHD27OLED_BW, SW SPI: FPS: Clip=9.2 Box=3.9  @=4.4		NEW_CODE
  NHD27OLED_BW, SW SPI: FPS: Clip=9.2 Box=3.6  @=4.5
  NHD27OLED_BW, HW SPI: FPS: Clip=16.3 Box=4.7  @=5.6
  NHD27OLED_2X_BW, SW SPI: FPS: Clip=9.7 Box=4.5  @=5.8
  NHD27OLED_2X_BW, SW SPI: FPS: Clip=18.0 Box=5.8  @=7.9

  1 Oct 2012
  ST7920_192X32, 8Bit:   FPS: Box=7.2   @=10.0                
  DOGM128 SW SPI:         FPS: Box=5.2   @=6.6  Pix=2.6               
  DOGM128 HW SPI:         FPS: Clip=33.2 Box=5.5   @=7.1
  DOGXL160 SW SPI:         FPS: Box=1.7   @=2.0
  DOGXL160 HW SPI:         FPS: Box=1.8   @=2.2

  DOGXL160 GR SW SPI:         FPS: Box=1.1   @=1.3

  1 Mar 2013
  ST7920_192X32_1X, SPI:    FPS: Clip=10.3 Box=5.5  @=7.2 Pix=3.9
  ST7920_192X32_4X, SPI:    FPS: Clip=10.9 Box=6.7  @=8.8 Pix=7.4
  ST7920_192X32_1X, 8Bit:    FPS: Clip=14.2 Box=6.1  @=8.4 Pix=4.2
  ST7920_192X32_4X, 8Bit:    FPS: Clip=14.2 Box=7.8  @=10.7 Pix=8.7
  ST7920_192X32_1X, HW SPI:    FPS: Clip=14.2 Box=6.3  @=8.7 Pix=4.3
  ST7920_192X32_4X, HW SPI:    FPS: Clip=15.3 Box=8.0  @=11.2 Pix=9.0

  2 Jun 2013
  U8GLIB_DOGM128 SW SPI:                                          FPS: Clip=23.9 Box=4.5  @=6.6  Pix=2.1
  U8GLIB_DOGM128_2X SW SPI:                                       FPS: Clip=28.5 Box=6.6  @=9.7  Pix=3.9
  U8GLIB_DOGM128_2X HW SPI:                                       FPS: Clip=40.8 Box=7.1  @=10.8 Pix=4.1
  
  3 Jun 2013
  U8GLIB_ST7920_192X32_1X -Os                             SW SPI  FPS: Clip=11.0 Box=5.4  @=7.1 Pix=3.9  Size=11828
  U8GLIB_ST7920_192X32_1X -O3                             SW SPI  FPS: Clip=10.9 Box=5.6  @=7.5 Pix=4.0  Size=13800
  U8GLIB_ST7920_192X32_1X -Os                             SW SPI  FPS: Clip=16.8 Box=6.7  @=9.6 Pix=4.5  Size=11858  (new seq data output)
  U8GLIB_ST7920_192X32_1X -Os                             HW SPI  FPS: Clip=25.7 Box=7.5  @=11.3 Pix=4.8             (new seq data output)
  
  6 Jun 2013
  U8GLIB_DOGS102 u8g(13, 11, 10, 9);                 STD SW SPI  FPS: Clip=9.5  Box=7.6   @=8.2  Pix=6.2 Size=15652
  U8GLIB_DOGS102 u8g(13, 11, 10, 9);                     SW SPI  FPS: Clip=19.1 Box=12.8  @=14.0 Pix=9.2 Size=15532


  12 Jun 2013
  SSD1351_128X128_332                                        SW SPI FPS: Clip=1.3 Box=0.7  @=0.9 Pix=0.4
  SSD1351_128X128_332                                        HW SPI FPS: Clip=3.6 Box=1.1  @=1.5 Pix=0.5

  24 Jun 2013
  Uno SSD1351_128X128_332                                    SW SPI FPS: Clip=1.4 Box=0.8  @=0.9 Pix=0.4
  
  Uno SSD1351_128X128_332                                    HW SPI FPS: Clip=4.4 Box=1.2  @=1.6 Pix=0.5
  Uno SSD1351_128X128_HICOLOR                                HW SPI FPS: Clip=3.7 Box=0.8  @=1.0 Pix=0.3

  Mega2560 SSD1351_128X128_332                               HW SPI FPS: Clip=4.4 Box=1.2  @=1.6 Pix=0.5
  Mega2560 SSD1351_128X128_4X_332                            HW SPI FPS: Clip=4.6 Box=2.3  @=2.8 Pix=1.5
  Mega2560 SSD1351_128X128_HICOLOR                           HW SPI FPS: Clip=3.6 Box=0.8  @=1.0 Pix=0.3
  Mega2560 SSD1351_128X128_4X_HICOLOR	                     HW SPI FPS: Clip=4.2 Box=1.7  @=2.1 Pix=1.0

  Due SSD1351_128X128_332                                    HW SPI     FPS: Clip=24.6  Box=6.3   @=7.8  Pix=2.8
  Due SSD1351_128X128_4X_332                                 HW SPI     FPS: Clip=28.1  Box=13.0  @=15.1 Pix=8.5
  Due SSD1351_128X128_HICOLOR                                HW SPI     FPS: Clip=20.8  Box=3.4   @=4.5  Pix=1.4
  Due SSD1351_128X128_4X_HICOLOR                             HW SPI     FPS: Clip=26.3  Box=8.9   @=11.1 Pix=4.8

  Due SSD1351_128X128_4X_HICOLOR                             SW SPI     FPS: Clip=0.4   Box=0.4   @=0.4  Pix=0.4
  
  Due DOGS102 u8g(13, 11, 10, 9);                            SW SPI     FPS: Clip=19.1  Box=13.1  @=14.3 Pix=9.4
  Due DOGS102 u8g(10, 9);                                    HW SPI     FPS: Clip=128.9 Box=30.7  @=40.6 Pix=15.4

  Due NHD27OLED_BW u8g(10, 9)                                HW SPI     FPS: Clip=53.0  Box=19.6  @=23.8 Pix=10.6
  Due NHD27OLED_2X_BW u8g(10, 9)                             HW SPI     FPS: Clip=57.0  Box=25.3  @=31.7 Pix=18.1
  Due NHD27OLED_GR u8g(10, 9)                                HW SPI     FPS: Clip=34.1  Box=11.7  @=13.7 Pix=5.6
  Due NHD27OLED_2X_GR u8g(10, 9)                             HW SPI     FPS: Clip=38.1  Box=15.5  @=20.0 Pix=8.8
 
  01 Jun 2014
  16 Bit mode: NHD-3.12-25664UMB3 OLED 256 x 64 pixel resolution
  Teensy 3.0 (CPU SPEED 96Mhz) NHD31OLED_BW u8g(13, 11, 10, 9) SW SPI   FPS: Clip=2.5   Box=2.1   @=2.2  Pix=1.8
  Teensy 3.0 (CPU SPEED 48Mhz) NHD31OLED_BW u8g(10, 9)         HW SPI   FPS: Clip=37.2  Box=7.7   @=10.0 Pix=4.1
  Teensy 3.0 (CPU SPEED 96Mhz) NHD31OLED_BW u8g(10, 9)         HW SPI   FPS: Clip=46.3  Box=9.5   @=11.3 Pix=5.2
  Teensy 3.0 (CPU SPEED 96Mhz) NHD31OLED_2X_BW u8g(10, 9)      HW SPI   FPS: Clip=49.6  Box=13.3  @=16.3 Pix=9.2
  Teensy 3.0 (CPU SPEED 96Mhz) NHD31OLED_2X_GR u8g(10, 9)      HW SPI   FPS: Clip=37.6  Box=8.4   @=10.4 Pix=4.5
  
  Improved performance:
  For Teensy 3.x, there is a digitalWriteFast(pin, value) function that will compile to the fastest possible ARM code
  using only a single bus cycle. http://forum.pjrc.com/threads/23431-Teensy-3-using-IO-pins
  For improved performance replace digitalWrite with digitalWriteFast in ...\arduino-1.0.5\libraries\U8glib\utility\u8g_com_arduino_common.c
  
  Teensy 3.0 (CPU SPEED 96Mhz) NHD31OLED_2X_BW u8g(10, 9)      HW SPI   FPS: Clip=50.7  Box=13.4  @=16.4 Pix=9.2
*/

// SPI Library
#include <SPI.h> //IMPORTANT NOTE: Needed for hw spi on teensy 3.x with Hoss U8G modify Library.
// http://forum.pjrc.com/threads/23445-Teensy-3-0-and-u8glib/page3

#include "U8glib.h"

// setup u8g object, please remove comment from one of the following constructor calls
// IMPORTANT NOTE: The following list is incomplete. The complete list of supported 
// devices with all constructor calls is here: http://code.google.com/p/u8glib/wiki/device
//U8GLIB_NHD27OLED_BW u8g(13, 11, 10, 9);	// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//U8GLIB_NHD27OLED_2X_BW u8g(13, 11, 10, 9);	// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//U8GLIB_NHD27OLED_GR u8g(13, 11, 10, 9);	// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//U8GLIB_NHD27OLED_2X_GR u8g(13, 11, 10, 9);	// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//U8GLIB_NHD27OLED_BW u8g(10,9);              // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)
//U8GLIB_NHD27OLED_2X_BW u8g(10,9);           // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)
//U8GLIB_NHD27OLED_GR u8g(10,9);              // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)
//U8GLIB_NHD27OLED_2X_GR u8g(10,9);           // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)

//U8GLIB_NHD31OLED_BW u8g(13, 11, 10, 9);	// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//U8GLIB_NHD31OLED_2X_BW u8g(13, 11, 10, 9);	// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//U8GLIB_NHD31OLED_GR u8g(13, 11, 10, 9);	// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//U8GLIB_NHD31OLED_2X_GR u8g(13, 11, 10, 9);	// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9
//U8GLIB_NHD31OLED_BW u8g(10,9);	      // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)
//U8GLIB_NHD31OLED_2X_BW u8g(10, 9);          // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)
//U8GLIB_NHD31OLED_GR u8g(10, 9);             // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)
//U8GLIB_NHD31OLED_2X_GR u8g(10, 9);          // HW SPI Com: CS = 10, A0 = 9 (Hardware Pins are  SCK = 13 and MOSI = 11)

/*
 IMPORTANT NOTE: Needed 16 Bit mode for NHD-3.12-25664UMB3 OLED 256 x 64 pixel resolution
 16 Bit mode: U8glib can be put into 16 Bit mode. Remove comment from {{{#define U8G_16BIT 1}}} in ...\arduino-1.0.5\libraries\U8glib\utility\u8g.h
 
    -------------------> My Pinout connections for NHD-3.12-25664UMB3 OLED <------------------------------------ 
    Teensy 3.x <--wire-connection--to-> NHD-3.12-25664UMB3 OLED
                                       4-wire Serial Interface:
    PIN-13 -> SCK -------------------> PIN-7  SCLK  Serial Clock signal.          (Hardware Pins are SCK = 13)
    PIN-11 -> DOUT, MOSI ------------> PIN-8  SDIN  Serial Data Input signal.     (Hardware Pins are MOSI = 11)
    PIN-10 -> CS, Select Device -----> PIN-16 CS    Active LOW Chip Enable signal.
    PIN-9  -> D/C, A0 ---------------> PIN-4  D/C   Register select signal. D/C=0: Command, D/C=1: Data
    PIN-3.3v+(100 mA max)-> /Reset --> PIN-15 /RES  Active LOW Reset signal. (Connect to Teensy 3.x 3.3v+)
    
    PIN-GND --to Uno GND to ---------> PIN-1 VSS    Power Supply Ground (-)
                                       IMPORTANT NOTE: needs 3.3v Power Supply other then teensy (100 mA max). 
                                                       I had been using Arduino Uno 3.3v out (Connect Uno GND to Teensy GND)
    Arduino Uno 3.3v out (+) --------> PIN-2 VDD    Power Supply Supply Voltage for OLED and logic 3.3V (+)
                                       PIN-3 NC     No Connect
                                       PIN-5        VSS Power Supply Ground (-)
                                       PIN-6        VSS Power Supply Ground (-)
                                       PIN-9 NC     No Connect
                                       PIN-10>14    VSS Power Supply Ground (-)
                                       PIN-17 BS1   GND / 4-wire Serial Interface / MPU Interface Select signal.
                                       PIN-18 BS0   GND / 4-wire Serial Interface / MPU Interface Select signal.
                                       PIN-19>22 NC No Connect / Multi-font IC    
 */
 
#define SECONDS 10
uint8_t flip_color = 0;
uint8_t draw_color = 1;

void draw_set_screen(void) {
  // graphic commands to redraw the complete screen should be placed here  
  if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    if ( flip_color == 0 ) 
      u8g.setHiColorByRGB(0,0,0);
    else
      u8g.setHiColorByRGB(255,255,255);
  }
  else {
    u8g.setColorIndex(flip_color);
  }
  u8g.drawBox( 0, 0, u8g.getWidth(), u8g.getHeight() );
}

void draw_clip_test(void) {
  u8g_uint_t i, j, k;
  char buf[3] = "AB";
  k = 0;
  if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
  else {
    u8g.setColorIndex(draw_color);
  }
  u8g.setFont(u8g_font_6x10);
  
  for( i = 0; i  < 6; i++ ) {
    for( j = 1; j  < 8; j++ ) {
      u8g.drawHLine(i-3, k, j);
      u8g.drawHLine(i-3+10, k, j);
      
      u8g.drawVLine(k+20, i-3, j);
      u8g.drawVLine(k+20, i-3+10, j);
      
      k++;
    }
  }
  u8g.drawStr(0-3, 50, buf);
  u8g.drawStr180(0+3, 50, buf);
  
  u8g.drawStr(u8g.getWidth()-3, 40, buf);
  u8g.drawStr180(u8g.getWidth()+3, 40, buf);

  u8g.drawStr90(u8g.getWidth()-10, 0-3, buf);
  u8g.drawStr270(u8g.getWidth()-10, 3, buf);

  u8g.drawStr90(u8g.getWidth()-20, u8g.getHeight()-3, buf);
  u8g.drawStr270(u8g.getWidth()-20, u8g.getHeight()+3, buf);
  
}

void draw_char(void) {
  char buf[2] = "@";
  u8g_uint_t i, j;
  // graphic commands to redraw the complete screen should be placed here  
  if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
  else {
    u8g.setColorIndex(draw_color);
  }
  u8g.setFont(u8g_font_6x10);
  j = 8;
  for(;;) {
    i = 0;
    for(;;) {
      u8g.drawStr( i, j, buf);
      i += 8;
      if ( i > u8g.getWidth() )
        break;
    }
    j += 8;
    if ( j > u8g.getHeight() )
      break;
  }
  
}

void draw_pixel(void) {
  u8g_uint_t x, y, w2, h2;
  if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
  else {
    u8g.setColorIndex(draw_color);
  }
  w2 = u8g.getWidth();
  h2 = u8g.getHeight();
  w2 /= 2;
  h2 /= 2;
  for( y = 0; y < h2; y++ ) {
    for( x = 0; x < w2; x++ ) {
      if ( (x + y) & 1 ) {
        u8g.drawPixel(x,y);
        u8g.drawPixel(x,y+h2);
        u8g.drawPixel(x+w2,y);
        u8g.drawPixel(x+w2,y+h2);
      }
    }
  }
}

// returns unadjusted FPS
uint16_t picture_loop_with_fps(void (*draw_fn)(void)) {
  uint16_t FPS10 = 0;
  uint32_t time;
  
  time = millis() + SECONDS*1000;
  
  // picture loop
  do {
    u8g.firstPage();  
    do {
      draw_fn();
    } while( u8g.nextPage() );
    FPS10++;
    flip_color = flip_color ^ 1;
  } while( millis() < time );
  return FPS10;  
}

const char *convert_FPS(uint16_t fps) {
  static char buf[6];
  strcpy(buf, u8g_u8toa( (uint8_t)(fps/10), 3));
  buf[3] =  '.';
  buf[4] = (fps % 10) + '0';
  buf[5] = '\0';
  return buf;
}

void show_result(const char *s, uint16_t fps) {
  // assign default color value
  if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
  else {
    u8g.setColorIndex(draw_color);
  }
  u8g.setFont(u8g_font_8x13B);
  u8g.firstPage();  
  do {
    u8g.drawStr(0,12, s);
    u8g.drawStr(0,24, convert_FPS(fps));
  } while( u8g.nextPage() );
}

void setup(void) {
  // flip screen, if required
  // u8g.setRot180();
  
  // assign default color value
  if ( u8g.getMode() == U8G_MODE_R3G3B2 ) 
    draw_color = 255;     // white
  else if ( u8g.getMode() == U8G_MODE_GRAY2BIT )
    draw_color = 3;         // max intensity
  else if ( u8g.getMode() == U8G_MODE_BW )
    draw_color = 1;         // pixel on
  else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
    u8g.setHiColorByRGB(255,255,255);
  }
}

void loop(void) {
  uint16_t fps;
  fps = picture_loop_with_fps(draw_clip_test);
  show_result("draw clip test", fps);
  delay(5000);
  fps = picture_loop_with_fps(draw_set_screen);
  show_result("clear screen", fps);
  delay(5000);
  fps = picture_loop_with_fps(draw_char);
  show_result("draw @", fps);
  delay(5000);  
  fps = picture_loop_with_fps(draw_pixel);
  show_result("draw pixel", fps);
  delay(5000);
}
:cool:
 
Hi All

Thank you for all the work, I have successfully ran the ported u8glib in this thread to display graphics on Freetronics OLED128, but I could't able to reach the benchmark fps mentioned above not even close even though it a different display. These are my results

teensy3.0 running @96Mhz
ctar = CTAR_12MHz
U8GLIB_SSD1351_128X128GH_HICOLOR u8g(10, 9, 8); clip:11.7fps clear screen:2.9fps @:3.1 pixels:1.3
U8GLIB_SSD1351_128X128GH_4X_HICOLOR u8g(10, 9, 8); clip:13.2fps clear screen:6.5fps @:7.0 pixels:4
U8GLIB_SSD1351_128X128GH_332 u8g(10, 9, 8); clip:11.0fps clear screen:4.7fps @:5.1 pixels:2.4
U8GLIB_SSD1351_128X128GH_4X_332 u8g(10, 9, 8); clip:14.0fps clear screen:8.5fps @:9.0 pixels:6.3

can it be improved ?

Anshul
 
I am trying to get faster frame speed with my sketch:
Code:
#include <SPI.h>

#include <FreqMeasure2.h>
#include "U8glib.h"
#include <FreqMeasure.h>

int frequency;
int frequency2;
int sum=0;
int count=0;
int sum2=0;
int count2=0;

int rpm;
int mph;

U8GLIB_LM6059_2X u8g(13, 11, 10, 9, 8);		// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9

void draw(void) {
    u8g.setFont(u8g_font_unifont);
    u8g.drawStr( 75, 60, "MPH");
    u8g.drawStr( 90, 31, "RPM");
}
void setup(void) {

  Serial.begin(57600);
  FreqMeasure.begin();
  FreqMeasure2.begin();

u8g.setContrast(130);
 
}

void loop(void) {
    if (FreqMeasure2.available()) {
    // average several reading together
    sum2 = sum2 + FreqMeasure2.read();
    count2 = count2 + 1;
    if (count2 > 30) {
      frequency2 = FreqMeasure2.countToFrequency(sum2 / count2);
      mph = frequency2*0.58; //(freq* 3600s/hr *mile/8000 clicks) 
      Serial.println(mph);
      sum2 = 0;
      count2 = 0;
    }
    }
  if (FreqMeasure.available()) {
    // average several reading together
    sum = sum + FreqMeasure.read();
    count = count + 1;
    if (count > 30) {
      frequency = FreqMeasure.countToFrequency(sum / count);
      rpm = frequency/58; //(58 teeth per flywheel revolution) 
      Serial.println(rpm);
      sum = 0;
      count = 0;
    }
  }  
 
 // picture loop
  u8g.firstPage();

  do {
    draw();
      u8g.setPrintPos(0, 60);
      u8g.setFont(u8g_font_fur49n);
      u8g.print(mph); 
      u8g.setPrintPos(80, 20);
      u8g.setFont(u8g_font_fur14);
      u8g.print(rpm); 
  } 
  while( u8g.nextPage() ); 
}

I am using the modified library Hoss posted with an adafruit ST7565. According to U8g wiki I am using the U8GLIB_LM6059_2X u8g constructor and right now I am wired with:
SID - 11
CS - 10
A0 - 9
RST - 8
SCLK - 13

I am only getting about 1fps. Do i need to do something special to activate hardware SPI mode in the u8glib? any code issues you can see?
 
Hi Michael

Try not specifying the SCK and MOSI pins in the constructor of u8g

U8GLIB_LM6059_2X u8g(10, 9, 8);

Specifying the SCK and MOSI activates the SW SPI

Anshul
 
Hi Michael
Try running this constructor, see if the screen will run in software SPI first.
U8GLIB_64128N u8g(13, 11, 10, 9, 8); //Software SPI Com: SCK = 13, MOSI/[SID] = 11, CS = 10, A0 = 9, reset = 8

Then try Hardware SPI
U8GLIB_64128N u8g(10,9, 8); // HW SPI Com: CS = 10, A0 = 9, reset optional = 8 (Hardware Pins are SCK = 13 and MOSI/[SID] = 11)


Also check out Issue 135: 128x64 Graphic LCD Display module ST7565P Z
http://code.google.com/p/u8glib/issues/detail?id=135&can=1&start=100
 
I picked up a NHD-2.7-12864 this week to play with alongside my Teensy 3.

  • To use: use the attached files to replace the files of the same name in the U8Glib utility folder
  • Important note: you'll actually need to delete u8g_com_arduino_hw_spi.c and copy in u8g_com_arduino_hw_spi.cpp. I had to change the file to C++ because one of the necessary includes declares a class and confuses the C compiler. Someone with deeper knowledge of the Arduino code stack and the hardware registers could probably make this unnecessary.
  • Also: If you use incompatible pins, the code will fall back to software SPI--but not the U8G software SPI, the software SPI from the Adafruit driver and I have not tested how well or even if it actually works with U8G.

This worked for me. I hope it works for others but no guarantees; quite a bit of this is new to me. Good luck!


Hoss, I have an NHD-2.7-12864 as well. I have it successfully working with SW SPI, but I can't get HW SPI to work after downloading and installing the above. I'm running Teensyduino 1.20rc2. I'm using the following U8GLIB constructs (separately of course):

U8GLIB_NHD27OLED_GR u8g(10, 15); // U8GLIB_NHD27OLED_GR(cs, a0 [, reset]) - Hardware SPI
U8GLIB_NHD27OLED_GR u8g(13, 11, 10, 15); // U8GLIB_NHD27OLED_GR(sck, mosi, cs, a0 [, reset]) - Software SPI

What happens using the HW SPI construct is the display initializes (lights up all pixels at varying brightness), then stays on that screen. After a second or so, the display starts flickering.

Any ideas?
 
Hi everyone,

I don't have a tremendous amount of input, I've been fiddling with another platform for the past couple of months. But I would recommend if you're having issues, try using pin combinations that others have had success with. There are definitely some pin combinations that won't work. I think part of the trick is that the CS and A0 pins must be labeled as CS pins on the Teensy pinout (but there are some caveats to this rule). I used SCK = 13, MOSI = 11, CS = 10 and A0 = 20, but I think SCK = 13, MOSI = 11, CS = 10 and A0 = 9 also works.

Hoss
 
Hoss, I have an NHD-2.7-12864 as well. I have it successfully working with SW SPI, but I can't get HW SPI to work after downloading and installing the above. I'm running Teensyduino 1.20rc2. I'm using the following U8GLIB constructs (separately of course):

U8GLIB_NHD27OLED_GR u8g(10, 15); // U8GLIB_NHD27OLED_GR(cs, a0 [, reset]) - Hardware SPI
U8GLIB_NHD27OLED_GR u8g(13, 11, 10, 15); // U8GLIB_NHD27OLED_GR(sck, mosi, cs, a0 [, reset]) - Software SPI

What happens using the HW SPI construct is the display initializes (lights up all pixels at varying brightness), then stays on that screen. After a second or so, the display starts flickering.

Any ideas?

Hi all

Try Teensyduino 1.19.
Teensyduino 1.20rc2 is beta version, perhaps you find some bug in SPI Transactions.:confused:

http://http://forum.pjrc.com/threads/26298-Teensyduino-1-20-Release-Candidate-2-Available
These are the changes since Teensyduino 1.20-rc1:

Add SPI Transactions
Add libraries Adafruit_CC3000, SPIFlash, RadioHead, FastLED
Revert Adafruit_ILI9341 to Adafruit's version (highly optimized version planned reappear with new name)
Libraries ported to use SPI transactions: SD, Ethernet, Adafruit_CC3000, Adafruit_ILI9341, Adafruit_STMPE610, RadioHead
rename Serial1.availableForWrite() to writeBufferFree()
Add Czech keyboard layout to menu
Add yield() function on Teensy 2.0
 
I finally figured out how to make hardware SPI work with the NHD-2.7-18650 display. I had the following statement in the code:

Code:
pinMode(15, OUTPUT);    // Data out to OLED display - SPI2_SI on NHD display

Removing that line fixed it and it now runs great. Not sure why it causes a problem, but it does.
 
Hello guys,
Just updated windows to version 10 and got the following error during compilation.

-----------------------

C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp: In function 'void writecommand(uint8_t)':
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp:460:3: error: 'SPI0' was not declared in this scope
SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0);
^
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp: In function 'void writedata(uint8_t)':
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp:473:3: error: 'SPI0' was not declared in this scope
SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0);
^
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp: In function 'void writedata16(uint16_t)':
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp:486:3: error: 'SPI0' was not declared in this scope
SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1);
^
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp: In function 'void setBitrate(uint32_t)':
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp:552:2: error: 'SPI0' was not declared in this scope
SPI0.MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
^
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp: In function 'uint8_t u8g_com_arduino_hw_spi_fn(u8g_t*, uint8_t, uint8_t, void*)':
C:\Program Files (x86)\Arduino\libraries\U8glib\utility\u8g_com_arduino_hw_spi.cpp:604:17: error: 'SPI0' was not declared in this scope
SPI0.MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
^
Error compiling.
-----------------------

Can some one help me please?
Thanks.
 
Just updated windows to version 10 and got the following error during compilation.

Missing IDE and Teensy install details,constraints - from path you did an IDE 'install'? My assumption is something broke in the IDE & OS interface. Another thing is you may be hitting unintended libs, something PJRC fixed in the IDE so you get a notice about that in current 1.6.5. I've changed to doing an UNZIP setup instead of the installer - having started with 1.6.x beta storm updates in Feb the 'exe' installs were very limiting. The UNZIP to a neutral directory of your choosing isolates the IDE install from it's crude attempt to master the Windows registry and be helpful. The UNZIP method allows multiple version installs to just work without crosstalk AFAIK.

Suggestion: (save any work in the ARDUINO folder), uninstall the IDE. Download and Unzip the IDE - and I assume re-install the current TeensyDuino and any other custom libs [in your sketchbook folder that you indicate in the IDE.] Then if you still see errors the solution may be clearer - with details provided per the forum rule.
 
Thank you defragster
So here is what I did.
Uninstalled latest version of Arduino then downloaded and installed Arduino version 1.0.5 + Teency version 1.19
Downloaded and unzipped Hoss's u8g library from
https://forum.pjrc.com/attachment.php?attachmentid=2033&d=1400770307

Started sketch compilation and finished successfully.
No any SPI0 errors.

Assuming this looks like Hoss's library is not compatible with new version of Arduino.
It will be nice if Hoss or somebody else will take over and resolve that issue.
 
i think "SPI0" may now be "KINETISK_SPI0" .

on a side note, where's this u8g_com_arduino_hw_spi.cpp coming from? google only turns up stuff that looks like it's for arduino due etc.

edit. fwiw, this works for me (SH1106), using spi4teensy though. signals/pins need to be defined in u8g_teensy.cpp resp. via the spi4teensy init
 
Last edited:
HI
Mxxx he is using Hoss (u8glib teensy fix) refer to post #52


Long story short, edit the file (u8g_com_arduino_hw_spi.cpp) in the U8Glib utility folder with this:
NOTE: This is only for Hoss (u8glib teensy fix)
Code:
/*
 
 u8g_com_arduino_hw_spi.c
 
 Universal 8bit Graphics Library
 
 Copyright (c) 2011, olikraus@gmail.com
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without modification,
 are permitted provided that the following conditions are met:
 
 * Redistributions of source code must retain the above copyright notice, this list
 of conditions and the following disclaimer.
 
 * Redistributions in binary form must reproduce the above copyright notice, this
 list of conditions and the following disclaimer in the documentation and/or other
 materials provided with the distribution.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 SPI Clock Cycle Type
 
 SSD1351	  50ns		20 MHz
 SSD1322	300ns		  3.3 MHz
 SSD1327	300ns
 SSD1306	300ns
 ST7565		400ns 		  2.5 MHz
 ST7920		400ns
 
 Arduino DUE
 
 PA25	MISO
 PA26	MOSI	75
 PA27	SCLK	76
 
 
 typedef struct {
 WoReg SPI_CR;        (Spi Offset: 0x00) Control Register
 RwReg SPI_MR;        (Spi Offset: 0x04) Mode Register
 RoReg SPI_RDR;       (Spi Offset: 0x08) Receive Data Register
 WoReg SPI_TDR;       (Spi Offset: 0x0C) Transmit Data Register
 RoReg SPI_SR;        (Spi Offset: 0x10) Status Register
 WoReg SPI_IER;       (Spi Offset: 0x14) Interrupt Enable Register
 WoReg SPI_IDR;       (Spi Offset: 0x18) Interrupt Disable Register
 RoReg SPI_IMR;       (Spi Offset: 0x1C) Interrupt Mask Register
 RoReg Reserved1[4];
 RwReg SPI_CSR[4];    (Spi Offset: 0x30) Chip Select Register
 RoReg Reserved2[41];
 RwReg SPI_WPMR;      (Spi Offset: 0xE4) Write Protection Control Register
 RoReg SPI_WPSR;      (Spi Offset: 0xE8) Write Protection Status Register
 } Spi;
 
 Power Management Controller (PMC)
 arduino-1.5.2/hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/instance/instance_pmc.h
 - enable PIO
 
 REG_PMC_PCER0 = 1UL << ID_PIOA
 - enable SPI
 REG_PMC_PCER0 = 1UL << ID_SPI0
 
 
 - enable PIOA and SPI0
 REG_PMC_PCER0 = (1UL << ID_PIOA) | (1UL << ID_SPI0);
 
 Parallel Input/Output Controller (PIO)
 arduino-1.5.2/hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/instance/instance_pioa.h
 - enable special function of the pin: disable PIO on A26 and A27:
 REG_PIOA_PDR = 0x0c000000
 PIOA->PIO_PDR = 0x0c000000
 
 SPI
 SPI0->SPI_CR = SPI_CR_SPIDIS
 SPI0->SPI_CR = SPI_CR_SWRST ;
 SPI0->SPI_CR = SPI_CR_SWRST ;
 SPI0->SPI_CR = SPI_CR_SPIEN
 
 Bit 0: Master Mode = 1 (active)
 Bit 1: Peripheral Select = 0 (fixed)
 Bit 2: Chip Select Decode Mode = 1 (4 to 16)
 Bit 4: Mode Fault Detection = 1 (disabled)
 Bit 5: Wait Data Read = 0 (disabled)
 Bit 7: Loop Back Mode = 0 (disabled)
 Bit 16-19: Peripheral Chip Select = 0 (chip select 0)
 SPI0->SPI_MR = SPI_MR_MSTR | SPI_MR_PCSDEC | SPI_MR_MODFDIS
 
 Bit 0: Clock Polarity = 0
 Bit 1: Clock Phase = 0
 Bit 4-7: Bits = 0 (8 Bit)
 Bit 8-15: SCBR = 1
 SPI0->SPI_CSR[0] = SPI_CSR_SCBR(x)	Serial Baud Rate
 SCBR / 84000000 > 50 / 1000000000
 SCBR / 84 > 5 / 100
 SCBR  > 50 *84 / 1000 --> SCBR=5
 SCBR  > 300*84 / 1000 --> SCBR=26
 SCBR  > 400*84 / 1000 --> SCBR=34
 
 Arduino Due test code:
 REG_PMC_PCER0 = (1UL << ID_PIOA) | (1UL << ID_SPI0);
 REG_PIOA_PDR = 0x0c000000;
 SPI0->SPI_CR = SPI_CR_SPIDIS;
 SPI0->SPI_CR = SPI_CR_SWRST;
 SPI0->SPI_CR = SPI_CR_SWRST;
 SPI0->SPI_CR = SPI_CR_SPIEN;
 SPI0->SPI_MR = SPI_MR_MSTR | SPI_MR_PCSDEC | SPI_MR_MODFDIS;
 SPI0->SPI_CSR[0] = SPI_CSR_SCBR(30);
 
 for(;;)
 {
 while( (SPI0->SPI_SR & SPI_SR_TDRE) == 0 )
 ;
 SPI0->SPI_TDR = 0x050;
 }
 
 */

#include "u8g.h"

#if defined(ARDUINO)

#if defined(__AVR__)
#define U8G_ARDUINO_ATMEGA_HW_SPI
/* remove the definition for attiny */
#if __AVR_ARCH__ == 2
#undef U8G_ARDUINO_ATMEGA_HW_SPI
#endif
#if __AVR_ARCH__ == 25
#undef U8G_ARDUINO_ATMEGA_HW_SPI
#endif
#endif

#if defined(U8G_ARDUINO_ATMEGA_HW_SPI)

#include <avr/interrupt.h>
#include <avr/io.h>

#if ARDUINO < 100
#include <WProgram.h>

/* fixed pins */
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) // Sanguino.cc board
#define PIN_SCK         7
#define PIN_MISO        6
#define PIN_MOSI        5
#define PIN_CS          4
#else                                   // Arduino Board
#define PIN_SCK 13
#define PIN_MISO  12
#define PIN_MOSI 11
#define PIN_CS 10
#endif // (__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)

#else

#include <Arduino.h>

/* use Arduino pin definitions */
#define PIN_SCK SCK
#define PIN_MISO  MISO
#define PIN_MOSI MOSI
#define PIN_CS SS

#endif



//static uint8_t u8g_spi_out(uint8_t data) U8G_NOINLINE;
static uint8_t u8g_spi_out(uint8_t data)
{
    /* unsigned char x = 100; */
    /* send data */
    SPDR = data;
    /* wait for transmission */
    while (!(SPSR & (1<<SPIF)))
        ;
    /* clear the SPIF flag by reading SPDR */
    return  SPDR;
}


uint8_t u8g_com_arduino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
    switch(msg)
    {
        case U8G_COM_MSG_STOP:
            break;
            
        case U8G_COM_MSG_INIT:
            u8g_com_arduino_assign_pin_output_high(u8g);
            pinMode(PIN_SCK, OUTPUT);
            digitalWrite(PIN_SCK, LOW);
            pinMode(PIN_MOSI, OUTPUT);
            digitalWrite(PIN_MOSI, LOW);
            /* pinMode(PIN_MISO, INPUT); */
            
            pinMode(PIN_CS, OUTPUT);			/* system chip select for the atmega board */
            digitalWrite(PIN_CS, HIGH);
            
            
            
            /*
             SPR1 SPR0
             0	0		fclk/4
             0	1		fclk/16
             1	0		fclk/64
             1	1		fclk/128
             */
            SPCR = 0;
            SPCR =  (1<<SPE) | (1<<MSTR)|(0<<SPR1)|(0<<SPR0)|(0<<CPOL)|(0<<CPHA);
#ifdef U8G_HW_SPI_2X
            SPSR = (1 << SPI2X);  /* double speed, issue 89 */
#else
            if ( arg_val  <= U8G_SPI_CLK_CYCLE_50NS )
            {
                SPSR = (1 << SPI2X);  /* double speed, issue 89 */
            }
#endif
            
            
            break;
            
        case U8G_COM_MSG_ADDRESS:                     /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
            u8g_com_arduino_digital_write(u8g, U8G_PI_A0, arg_val);
            break;
            
        case U8G_COM_MSG_CHIP_SELECT:
            if ( arg_val == 0 )
            {
                /* disable */
                u8g_com_arduino_digital_write(u8g, U8G_PI_CS, HIGH);
            }
            else
            {
                /* enable */
                u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, LOW);
                u8g_com_arduino_digital_write(u8g, U8G_PI_CS, LOW);
            }
            break;
            
        case U8G_COM_MSG_RESET:
            if ( u8g->pin_list[U8G_PI_RESET] != U8G_PIN_NONE )
                u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val);
            break;
            
        case U8G_COM_MSG_WRITE_BYTE:
            u8g_spi_out(arg_val);
            break;
            
        case U8G_COM_MSG_WRITE_SEQ:
        {
            register uint8_t *ptr = arg_ptr;
            while( arg_val > 0 )
            {
                u8g_spi_out(*ptr++);
                arg_val--;
            }
        }
            break;
        case U8G_COM_MSG_WRITE_SEQ_P:
        {
            register uint8_t *ptr = arg_ptr;
            while( arg_val > 0 )
            {
                u8g_spi_out(u8g_pgm_read(ptr));
                ptr++;
                arg_val--;
            }
        }
            break;
    }
    return 1;
}

/* #elif defined(__18CXX) || defined(__PIC32MX) */

#elif defined(__SAM3X8E__)		// Arduino Due, maybe we should better check for __SAM3X8E__

#include <Arduino.h>

/* use Arduino pin definitions */
#define PIN_SCK SCK
#define PIN_MISO  MISO
#define PIN_MOSI MOSI
#define PIN_CS SS


static uint8_t u8g_spi_out(uint8_t data)
{
    /* wait until tx register is empty */
    while( (SPI0->SPI_SR & SPI_SR_TDRE) == 0 )
        ;
    /* send data */
    SPI0->SPI_TDR = (uint32_t)data;
    return  data;
}


uint8_t u8g_com_arduino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
    switch(msg)
    {
        case U8G_COM_MSG_STOP:
            break;
            
        case U8G_COM_MSG_INIT:
            u8g_com_arduino_assign_pin_output_high(u8g);
            u8g_com_arduino_digital_write(u8g, U8G_PI_CS, HIGH);
            
            /* Arduino Due specific code */
            
            /* enable PIOA and SPI0 */
            REG_PMC_PCER0 = (1UL << ID_PIOA) | (1UL << ID_SPI0);
            
            /* disable PIO on A26 and A27 */
            REG_PIOA_PDR = 0x0c000000;
            
            /* reset SPI0 (from sam lib) */
            SPI0->SPI_CR = SPI_CR_SPIDIS;
            SPI0->SPI_CR = SPI_CR_SWRST;
            SPI0->SPI_CR = SPI_CR_SWRST;
            SPI0->SPI_CR = SPI_CR_SPIEN;
            u8g_MicroDelay();
            
            /* master mode, no fault detection, chip select 0 */
            SPI0->SPI_MR = SPI_MR_MSTR | SPI_MR_PCSDEC | SPI_MR_MODFDIS;
            
            /* Polarity, Phase, 8 Bit data transfer, baud rate */
            /* x * 1000 / 84 --> clock cycle in ns
             5 * 1000 / 84 = 58 ns
             SCBR  > 50 *84 / 1000 --> SCBR=5
             SCBR  > 300*84 / 1000 --> SCBR=26
             SCBR  > 400*84 / 1000 --> SCBR=34
             */
            
            if ( arg_val <= U8G_SPI_CLK_CYCLE_50NS )
            {
                SPI0->SPI_CSR[0] = SPI_CSR_SCBR(5) | 1;
            }
            else if ( arg_val <= U8G_SPI_CLK_CYCLE_300NS )
            {
                SPI0->SPI_CSR[0] = SPI_CSR_SCBR(26) | 1;
            }
            else if ( arg_val <= U8G_SPI_CLK_CYCLE_400NS )
            {
                SPI0->SPI_CSR[0] = SPI_CSR_SCBR(34) | 1;
            }
            else
            {
                SPI0->SPI_CSR[0] = SPI_CSR_SCBR(84) | 1;
            }
            
            u8g_MicroDelay();
            break;
            
        case U8G_COM_MSG_ADDRESS:                     /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
            u8g_com_arduino_digital_write(u8g, U8G_PI_A0, arg_val);
            u8g_MicroDelay();
            break;
            
        case U8G_COM_MSG_CHIP_SELECT:
            if ( arg_val == 0 )
            {
                /* disable */
                u8g_MicroDelay();		/* this delay is required to avoid that the display is switched off too early --> DOGS102 with DUE */
                u8g_com_arduino_digital_write(u8g, U8G_PI_CS, HIGH);
                u8g_MicroDelay();
            }
            else
            {
                /* enable */
                //u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, LOW);
                u8g_com_arduino_digital_write(u8g, U8G_PI_CS, LOW);
                u8g_MicroDelay();
            }
            break;
            
        case U8G_COM_MSG_RESET:
            if ( u8g->pin_list[U8G_PI_RESET] != U8G_PIN_NONE )
                u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val);
            break;
            
        case U8G_COM_MSG_WRITE_BYTE:
            u8g_spi_out(arg_val);
            u8g_MicroDelay();
            break;
            
        case U8G_COM_MSG_WRITE_SEQ:
        {
            register uint8_t *ptr = arg_ptr;
            while( arg_val > 0 )
            {
                u8g_spi_out(*ptr++);
                arg_val--;
            }
        }
            break;
        case U8G_COM_MSG_WRITE_SEQ_P:
        {
            register uint8_t *ptr = arg_ptr;
            while( arg_val > 0 )
            {
                u8g_spi_out(u8g_pgm_read(ptr));
                ptr++;
                arg_val--;
            }
        }
            break;
    }
    return 1;
}


/***************************************************************/
/*     Teensy 3.0 & 3.1            SPI0 fix                    */
/***************************************************************/
#elif defined(__MK20DX128__) || defined(__MK20DX256__)

#include <Arduino.h>
#include <limits.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include <SPI.h>

#define _rst (u8g->pin_list[U8G_PI_RESET])
#define _cs (u8g->pin_list[U8G_PI_CS])
#define _rs (u8g->pin_list[U8G_PI_A0])

uint8_t  _sid, _sclk;
uint8_t pcs_data, pcs_command;
uint32_t ctar;
volatile uint8_t *datapin, *clkpin, *cspin, *rspin;
bool hwSPI = false;
bool nextIsCommand = false;
//#endif

inline void writebegin()
{
}

inline void spiwrite(uint8_t c)
{
	for (uint8_t bit = 0x80; bit; bit >>= 1) {
		*datapin = ((c & bit) ? 1 : 0);
		*clkpin = 1;
		*clkpin = 0;
	}
}

void writecommand(uint8_t c)
{
	if (hwSPI) {
            
            // fix KINETISK_SPI0.....
		//SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0);
		//while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
//new       KINETISK_SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0);
		while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full

            
	} else {
		*rspin = 0;
		*cspin = 0;
		spiwrite(c);
		*cspin = 1;
	}
}

void writedata(uint8_t c)
{
	if (hwSPI) {
            
//new		KINETISK_SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0);
		while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full

		//SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0);
		//while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
            
	} else {
		*rspin = 1;
		*cspin = 0;
		spiwrite(c);
		*cspin = 1;
	}
}

void writedata16(uint16_t d)
{
	if (hwSPI) {
            

//new	      KINETISK_SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1);
		while (((KINETISK_SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full

		//SPI0.PUSHR = d | (pcs_data << 16) | SPI_PUSHR_CTAS(1);
		//while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
	} else {
		*rspin = 1;
		*cspin = 0;
		spiwrite(d >> 8);
		spiwrite(d);
		*cspin = 1;
	}
}

inline void write(uint8_t c)
{
    if(nextIsCommand)
        writecommand(c);
    else
        writedata(c);
}

static bool spi_pin_is_cs(uint8_t pin)
{
	if (pin == 2 || pin == 6 || pin == 9) return true;
	if (pin == 10 || pin == 15) return true;
	if (pin >= 20 && pin <= 23) return true;
	return false;
}

static uint8_t spi_configure_cs_pin(uint8_t pin)
{
    switch (pin) {
        case 10: CORE_PIN10_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTC4
        case 2:  CORE_PIN2_CONFIG  = PORT_PCR_MUX(2); return 0x01; // PTD0
        case 9:  CORE_PIN9_CONFIG  = PORT_PCR_MUX(2); return 0x02; // PTC3
        case 6:  CORE_PIN6_CONFIG  = PORT_PCR_MUX(2); return 0x02; // PTD4
        case 20: CORE_PIN20_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTD5
        case 23: CORE_PIN23_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTC2
        case 21: CORE_PIN21_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTD6
        case 22: CORE_PIN22_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTC1
        case 15: CORE_PIN15_CONFIG = PORT_PCR_MUX(2); return 0x10; // PTC0
    }
    return 0;
}

  

#define CTAR_24MHz   (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0) | SPI_CTAR_DBR)
#define CTAR_16MHz   (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0) | SPI_CTAR_DBR)
#define CTAR_12MHz   (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0))
#define CTAR_8MHz    (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0))
#define CTAR_6MHz    (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1))
#define CTAR_4MHz    (SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1))

void setBitrate(uint32_t n)
{
      

	if (n >= 24000000) {
		ctar = CTAR_24MHz;
	} else if (n >= 16000000) {
		ctar = CTAR_16MHz;
	} else if (n >= 12000000) {
		ctar = CTAR_12MHz;
	} else if (n >= 8000000) {
		ctar = CTAR_8MHz;
	} else if (n >= 6000000) {
		ctar = CTAR_6MHz;
	} else {
		ctar = CTAR_4MHz;
	}

	SIM_SCGC6 |= SIM_SCGC6_SPI0;
// fix
	KINETISK_SPI0.MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
	KINETISK_SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7);
	KINETISK_SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15);
	KINETISK_SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;

	//SPI0.MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
	//SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7);
	//SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15);
	//SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
}

static uint8_t u8g_spi_out(uint8_t data)
{
    write(data);
    return 0;
}

uint8_t u8g_com_arduino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
    switch(msg)
    {
        case U8G_COM_MSG_STOP:
            break;
            
        case U8G_COM_MSG_INIT:


            //from https://github.com/PaulStoffregen/Adafruit_ST7735/blob/master/Adafruit_ST7735.cpp
            if (_sid == 0) _sid = 11;
            if (_sclk == 0) _sclk = 13;
            if ( spi_pin_is_cs(_cs) && spi_pin_is_cs(_rs)
                && (_sid == 7 || _sid == 11)
                && (_sclk == 13 || _sclk == 14)
                && !(_cs ==  2 && _rs == 10) && !(_rs ==  2 && _cs == 10)
                && !(_cs ==  6 && _rs ==  9) && !(_rs ==  6 && _cs ==  9)
                && !(_cs == 20 && _rs == 23) && !(_rs == 20 && _cs == 23)
                && !(_cs == 21 && _rs == 22) && !(_rs == 21 && _cs == 22) ) {
                hwSPI = true;
                //uncomment this line to test for hardware SPI
                //the program will take an extra 10 seconds to start up
                //delay(10000);

                if (_sclk == 13) {
                    CORE_PIN13_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE;
                    SPCR.setSCK(13);
                } else {
                    CORE_PIN14_CONFIG = PORT_PCR_MUX(2);
                    SPCR.setSCK(14);
                }
                if (_sid == 11) {
                    CORE_PIN11_CONFIG = PORT_PCR_MUX(2);
                    SPCR.setMOSI(11);
                } else {
                    CORE_PIN7_CONFIG = PORT_PCR_MUX(2);
                    SPCR.setMOSI(7);
                }
                ctar = CTAR_24MHz; //set spi speed 24MHz 
                pcs_data = spi_configure_cs_pin(_cs);
                pcs_command = pcs_data | spi_configure_cs_pin(_rs);
                SIM_SCGC6 |= SIM_SCGC6_SPI0;
// fix
		    KINETISK_SPI0.MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
		    KINETISK_SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7);
		    KINETISK_SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15);
		    KINETISK_SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
                //SPI0.MCR = SPI_MCR_MDIS | SPI_MCR_HALT;
                //SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7);
                //SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15);
                //SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;

            } else {
                hwSPI = false;
                u8g_com_arduino_assign_pin_output_high(u8g);
                cspin = portOutputRegister(digitalPinToPort(_cs));
                rspin = portOutputRegister(digitalPinToPort(_rs));
                clkpin = portOutputRegister(digitalPinToPort(_sclk));
                datapin = portOutputRegister(digitalPinToPort(_sid));
                *cspin = 1;
                *rspin = 0;
                *clkpin = 0;
                *datapin = 0;
                pinMode(_cs, OUTPUT);
                pinMode(_rs, OUTPUT);
                pinMode(_sclk, OUTPUT);
                pinMode(_sid, OUTPUT);
            }
            if (_rst) {
                pinMode(_rst, OUTPUT);
                digitalWriteFast(_rst, HIGH); //digitalWriteFast
                delay(500);
                digitalWriteFast(_rst, LOW);
                delay(500);
                digitalWriteFast(_rst, HIGH);
                delay(500);
            }
            break;
            
        case U8G_COM_MSG_ADDRESS:                     /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
            if(hwSPI)
            {
                nextIsCommand = (arg_val == 0);
            }
            else
                u8g_com_arduino_digital_write(u8g, U8G_PI_A0, arg_val);
            break;
            
        case U8G_COM_MSG_CHIP_SELECT:
            if(!hwSPI)
            {
                if ( arg_val == 0 )
                {
                    /* disable */
                    u8g_com_arduino_digital_write(u8g, U8G_PI_CS, HIGH);
                }
                else
                {
                    /* enable */
                    u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, LOW);
                    u8g_com_arduino_digital_write(u8g, U8G_PI_CS, LOW);
                }
            }
            break;
            
        case U8G_COM_MSG_RESET:
            if ( u8g->pin_list[U8G_PI_RESET] != U8G_PIN_NONE )
                u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val);
            break;
            
        case U8G_COM_MSG_WRITE_BYTE:
            u8g_spi_out(arg_val);
            break;
            
        case U8G_COM_MSG_WRITE_SEQ:
        {
            register uint8_t *ptr = (uint8_t*)arg_ptr;
            while( arg_val > 0 )
            {
                u8g_spi_out(*ptr++);
                arg_val--;
            }
        }
            break;
        case U8G_COM_MSG_WRITE_SEQ_P:
        {
            register uint8_t *ptr = (uint8_t*)arg_ptr;
            while( arg_val > 0 )
            {
                u8g_spi_out(u8g_pgm_read(ptr));
                ptr++;
                arg_val--;
            }
        }
            break;
    }
    return 1;
}

#else

#endif /* U8G_ARDUINO_ATMEGA_HW_SPI */

#else /* ARDUINO */

uint8_t u8g_com_arduino_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
{
    return 1;
}

#endif /* ARDUINO */
 
Great job everyone, yep, this became an issue with a recent release of Teensyduino. Here's my update. View attachment u8g_com_arduino_hw_spi.cpp
Basically, it's the same thing Chris O. posted--the update to Teensyduino changed the names of some of the symbols, but nothing needed to change functionally. Update the file in the U8Glib/utility folder and you should be able to build again.
 
Status
Not open for further replies.
Back
Top