Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 18 of 18

Thread: Teensy 3.0 multiple SPI device issue, this is out of my league help!

  1. #1
    Junior Member
    Join Date
    Oct 2013
    Posts
    10

    Teensy 3.0 multiple SPI device issue, this is out of my league help!

    Hello,

    I am trying to design a temperature probe circuit and display the results on an OLED screen, But I am having a problem with getting both the screen and probes working together, I have had them running well individually, but the probe is giving out weird readings when I introduce the screen into the mix, I'm guessing it could be a timing issue and / or library issue??

    I am using the following items

    Teensy 3.0
    Type K probe
    MAX31855K K-Type Thermocouple Sensor Breakout (4ch) - http://playingwithfusion.com/product...=20&catid=1001
    1.3" 128x64 OLED Display Module SSD1306 - http://www.wide.hk/products.php?prod...Module-SSD1306

    I am using a customised library for both screen and Thermocouple, I am trying to use the hardware SPI instead of software

    the OLED is from here https://www.adafruit.com/forums/view...p?f=47&t=29123
    the Thermocouple is a modified version of https://github.com/rocketscream/MAX31855

    THIS IS THE MODIFIED LIBRARY CODE
    Code:
    /*******************************************************************************
    * MAX31855 Library
    * Version: 1.10
    * Date: 24-07-2012
    * Company: Rocket Scream Electronics
    * Website: www.rocketscream.com
    *
    * This is a MAX31855 library for Arduino. Please check our wiki 
    * (www.rocketscream.com/wiki) for more information on using this piece of 
    * library.
    *
    * This library is licensed under Creative Commons Attribution-ShareAlike 3.0 
    * Unported License.
    *
    * Revision  Description
    * ========  ===========
    * 1.10			Added negative temperature support for both junction & thermocouple.
    * 1.00      Initial public release.
    *
    *******************************************************************************/
    
    
    
    #include	"MAX31855H.h"
    #include 	"SPI.h"
    
    MAX31855H::MAX31855H(unsigned char SS)
    {
    
    	// MAX31855H chip select input pin
    	pinMode(SS, OUTPUT);
    	// MAX31855H clock input pin
    	pinMode(SCK, OUTPUT);
    	// MAX31855H clock input pin
    	//pinMode(MISO, INPUT);
    	
    	// Default output pins state
    	digitalWrite(SS, HIGH);
    	digitalWrite(SCK, LOW);
    	//SPI.setClockDivider (SPI_CLOCK_DIV2);
    	SPI.begin();
    }
    
    /*******************************************************************************
    * Name: readThermocouple
    * Description: Read the thermocouple temperature either in Degree Celsius or
    *							 Fahrenheit. Internally, the conversion takes place in the
    *							 background within 100 ms. Values are updated only when the SS
    *							 line is high.
    *
    * Argument  	Description
    * =========  	===========
    * 1. unit   	Unit of temperature required: CELSIUS or FAHRENHEIT
    *
    * Return			Description
    * =========		===========
    *	temperature	Temperature of the thermocouple either in Degree Celsius or 
    *							Fahrenheit. If fault is detected, FAULT_OPEN, FAULT_SHORT_GND or
    *							FAULT_SHORT_VCC will be returned. These fault values are outside
    *							of the temperature range the MAX31855 is capable of.
    *******************************************************************************/	
    double	MAX31855H::readThermocouple(unit_t	unit)
    {
    	unsigned long dataSPI;
    	double temperature;
    	
    	// Initialize temperature
    	temperature = 0;
    	
    	// Shift in 32-bit of data from MAX31855
    	dataSPI = readData();
    	
    	// If fault is detected
    	if (dataSPI & 0x00010000)
    	{
    		// Check for fault type (3 LSB)
    		switch (dataSPI & 0x00000007)
    		{
    			// Open circuit 
    			case 0x01:
    				temperature = FAULT_OPEN;
    				Serial.println("FAULT_OPEN");
    				Serial.println(dataSPI, BIN);
    				break;
    			
    			// Thermocouple short to GND
    			case 0x02:
    				temperature = FAULT_SHORT_GND;
    				Serial.println("FAULT_SHORT_GND");
    				break;
    			
    			// Thermocouple short to VCC	
    			case 0x04:
    				temperature = FAULT_SHORT_VCC;
    				Serial.println("FAULT_SHORT_VCC");
    				break;
    		}
    	}
    	// No fault detected
    	else
    	{
    		// Retrieve thermocouple temperature data and strip redundant data
    		dataSPI = dataSPI >> 18;
    		//Serial.print("postshift bin therm ");
    		//Serial.println(dataSPI, BIN);
    		// Bit-14 is the sign
    		temperature = (dataSPI & 0x00001FFF);
    		
    
    		// Check for negative temperature		
    		if (dataSPI & 0x00002000)
    		{
    			// 2's complement operation
    			// Invert
    			dataSPI = ~dataSPI; 
    			// Ensure operation involves lower 13-bit only
    			temperature = dataSPI & 0x00001FFF;
    			// Add 1 to obtain the positive number
    			temperature += 1;
    			// Make temperature negative
    			temperature *= -1; 
    		}
    		
    		// Convert to Degree Celsius
    		temperature *= 0.25;
    		
    		// If temperature unit in Fahrenheit is desired
    		if (unit == FAHRENHEIT)
    		{
    			// Convert Degree Celsius to Fahrenheit
    			temperature = (temperature * 9.0/5.0)+ 32; 
    		}
    	}
    	return (temperature);
    }
    
    /*******************************************************************************
    * Name: readJunction
    * Description: Read the thermocouple temperature either in Degree Celsius or
    *							 Fahrenheit. Internally, the conversion takes place in the
    *							 background within 100 ms. Values are updated only when the SS
    *							 line is high.
    *
    * Argument  	Description
    * =========  	===========
    * 1. unit   	Unit of temperature required: CELSIUS or FAHRENHEIT
    *
    * Return			Description
    * =========		===========
    *	temperature	Temperature of the cold junction either in Degree Celsius or 
    *							Fahrenheit. 
    *
    *******************************************************************************/
    double	MAX31855H::readJunction(unit_t	unit)
    {
    	double	temperature;
    	unsigned long dataSPI;
    	
    	// Shift in 32-bit of data from MAX31855
    	dataSPI = readData();
    	
    	// Strip fault data bits & reserved bit
    	dataSPI = dataSPI >> 4;
    	//Serial.print("postshift bin junct ");
    	//Serial.println(dataSPI, BIN);
    	// Bit-12 is the sign
    	temperature = (dataSPI & 0x000007FF);
    	
    	// Check for negative temperature
    	if (dataSPI & 0x00000800)
    	{
    		// 2's complement operation
    		// Invert
    		dataSPI = ~dataSPI; 
    		// Ensure operation involves lower 11-bit only
    		temperature = dataSPI & 0x000007FF;
    		// Add 1 to obtain the positive number
    		temperature += 1;	
    		// Make temperature negative
    		temperature *= -1; 
    	}
    	
    	// Convert to Degree Celsius
    	temperature *= 0.0625;
    	
    	// If temperature unit in Fahrenheit is desired
    	if (unit == FAHRENHEIT)
    	{
    		// Convert Degree Celsius to Fahrenheit
    		temperature = (temperature * 9.0/5.0)+ 32; 	
    	}
    	
    	// Return the temperature
    	return (temperature);
    }
    
    /*******************************************************************************
    * Name: readData
    * Description: Shift in 32-bit of data from MAX31855 chip. Minimum clock pulse
    *							 width is 100 ns. No delay is required in this case.
    *
    * Argument  	Description
    * =========  	===========
    * 1. NIL
    *
    * Return			Description
    * =========		===========
    *	data				32-bit of data acquired from the MAX31855 chip.
    *				
    *******************************************************************************/
    unsigned long MAX31855H::readData()
    {
    	int bitCount;
    	unsigned long dataSPI;
    	
    	// Clear data 
    	dataSPI = 0;
    
    	
    	// enable Slave Select
    	digitalWrite(SS, LOW);    // CS is pin 10
    	
    	// Shift in 32-bit of data
    	for (bitCount = 31; bitCount >= 0; bitCount--)
    	{
    		digitalWrite(SCK, HIGH);
    
    		
    		// If data bit is high
    		if (digitalRead(MISO))
    		{
    			// Need to type cast data type to unsigned long, else compiler will 
    			// truncate to 16-bit
    			dataSPI |= ((unsigned long)1 << bitCount);
    		}	
    		
    		digitalWrite(SCK, LOW);
    	}
    
    	// disable Slave Select
    	digitalWrite(SS, HIGH);
    
    	
    	// turn SPI hardware off
    	SPI.end ();
     
    	//READ DEBUG
    	Serial.print("raw SPI bin ");
    	Serial.println(dataSPI, BIN);
    	
    	return(dataSPI);
    }

    Code:
    /*******************************************************************************
    * Thermocouple to serial for MAX31855H example 
    *
    *******************************************************************************/
    // ***** INCLUDES *****
    #include  <MAX31855H.h> // hardware version
    //#include  <MAX31855.h> // original version
    #include  <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306h.h>
    
    // ***** PIN DEFINITIONS *****
    //pins for hardware spi therm
    //
    const  unsigned  char thermocoupleSS = 10;
    MAX31855H  MAX31855H(thermocoupleSS);
    //
    ////pins for original therm
    /*
    const  unsigned  char thermocoupleSO = 12;
    const  unsigned  char thermocoupleCS = 10;
    const  unsigned  char thermocoupleCLK = 13;
    MAX31855  MAX31855(thermocoupleSO, thermocoupleCS, thermocoupleCLK);
    */
    //pins for OLED Screen
    #define OLED_DC 8
    #define OLED_CS 9
    #define OLED_CLK 13
    #define OLED_MOSI 11
    #define OLED_RESET 7
    Adafruit_SSD1306h display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
    
    void  setup()
    {
      Serial.begin(57600);
    
      // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
      display.begin(SSD1306h_SWITCHCAPVCC);
      display.display(); 		// show splashscreen
      delay(2500);
      display.clearDisplay();   // clears the screen and buffer
    }
    
    void  loop()
    {
      //Screen display
      display.display(); 		
      display.clearDisplay();
      display.setTextSize(1);
      display.setTextColor(WHITE);
      // Display Title
      display.setCursor(0,0);
      display.println("OLED MENU SYSTEM");
      //delay(500);
      
      
      double  temperature;
      // Retrieve thermocouple temperature in Degree Celsius
      temperature = MAX31855H.readThermocouple(CELSIUS); //Hardware Spi Therm
      //temperature = MAX31855.readThermocouple(CELSIUS); //Original Therm
      Serial.print("Thermocouple temperature: ");
      Serial.print(temperature);
      Serial.println(" Degree Celsius");
      
      
      display.setCursor(0,10);
      display.print("Probe 1: ");
      display.print(temperature);
      display.println("'C");
      
      delay(250);
    
      /*
      // Retrieve cold junction temperature in Degree Celsius
      temperature = MAX31855H.readJunction(CELSIUS);
      Serial.print("Junction temperature: ");
      Serial.print(temperature);
      Serial.println(" Degree Celsius");
      */
      delay(1000);
    }
    SO WHATS HAPPENING!!

    So when I have the both items plugged in the splash screen shows as it should then goes blank, I then open the serial monitor to show the following results

    raw SPI bin 1000001101000000001100101000000
    Thermocouple temperature: 1050.00 Degree Celsius
    raw SPI bin 1101000000001100101000000
    Thermocouple temperature: 26.00 Degree Celsius
    raw SPI bin 1000001101001000001100101000000
    Thermocouple temperature: 1050.25 Degree Celsius
    raw SPI bin 1000001101000000001100101000000
    Thermocouple temperature: 1050.00 Degree Celsius
    raw SPI bin 1101000000001100101000000
    Thermocouple temperature: 26.00 Degree Celsius
    raw SPI bin 1100001101000000001100101000000
    Thermocouple temperature: 1562.00 Degree Celsius
    raw SPI bin 1101000000001100101000000
    Thermocouple temperature: 26.00 Degree Celsius
    raw SPI bin 1000001101001000001100101000000
    Thermocouple temperature: 1050.25 Degree Celsius
    which doesn't seem right i doubt its over 1000 degrees in here and the screen is still blank

    If i comment out all of the screen related items the temperature returns to how it should

    raw SPI bin 1101000000001100101110000
    Thermocouple temperature: 26.00 Degree Celsius
    raw SPI bin 1101001000001100101000000
    Thermocouple temperature: 26.25 Degree Celsius
    raw SPI bin 1101001000001100100100000
    Thermocouple temperature: 26.25 Degree Celsius
    raw SPI bin 1101001000001100100110000
    Thermocouple temperature: 26.25 Degree Celsius
    If i comment out all of the thermocouple related items and use a mock data (temperature = temperature + 2.5 for the temperature it returns to how it should on the screen.

    So any ideas would be appreciated or anywhere can I look to find this answer would be good as well.

  2. #2
    Junior Member
    Join Date
    Oct 2013
    Posts
    10
    So this code seems to be turning the screen off

    Code:
    // turn SPI hardware off
    	 SPI.end ();
    its in the thermocouple library, but when its commented out, I get no data from the probe

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,120
    SPI has a shared bus and indicates which device it is talking to with chip selects, which are active low (0v means the device is active). You need one pin as chip select for the screen, and another as chip select for the thermocouple. When talking to (or reading from) the thermocouple, set the thermocouple CS low; when writing to the screen, set the screen CS low. Otherwise, they get commands intended for the other device.

    And yes, comment out the ill-advised SPI.end in ther thermocouple library.

  4. #4
    Junior Member
    Join Date
    Oct 2013
    Posts
    15
    Quote Originally Posted by Dean View Post
    So this code seems to be turning the screen off

    Code:
    // turn SPI hardware off
    	 SPI.end ();
    its in the thermocouple library, but when its commented out, I get no data from the probe
    When you have 2 devices on the SPI bus a chip select (CS) signal/pin(or slave select (SS) ) selects which device is being spoken to by the SPI. Make sure that when talking to the display that the chip select signal is active for the display and inactive for the thermocouple and vice versa.

  5. #5
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,120
    You also seem to be using a mixture of hardware SPI and software (bit banged) SPI. Nick Gammon made a hardware SPI version of the Adafruit OLED SSD1306 library, which you can get here. Adafruit won't add the patch, on the grounds that "few people need fast updates"

  6. #6
    Senior Member Constantin's Avatar
    Join Date
    Nov 2012
    Location
    In the yard with a 17' Dia. Ferris Wheel
    Posts
    1,406

    Odd.

    Quote Originally Posted by Nantonos View Post
    ...Adafruit won't add the patch, on the grounds that "few people need fast updates"
    The only reason I can think of is "Not invented here." Sort of like the malloc.c updates that Paul proposed to the Arduino code to fix some of the persistent String issues that the Arduino IDE was experiencing. Anyhow, many thanks for making people aware of Nicks great work!

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,659
    Looks like I really need to add several of Adafruit's libraries onto the list of ones that we officially support for Teensyduino....

    This situation actually reminds me most of the many efforts to improve the Arduino LiquidCrystal library. John Raines, as far as I know, was the first to take this on. The Arduino Team had agreed to merge his changes into Arduino 0019. John made many improvements and increased the speed. I got involved and helped speed it up even more. But when 0019 came, David Mellis told John he needed each individual change as a separate patch. Nearly every line had been touched by that point. Today the LiquidCrystal library is basically the same slow version as before 0019. Very sad.

  8. #8
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,120
    On the one hand, the fact that the LC library is unchanged wrt 0019 is sad. On the other hand, it means a Teensy library can have all the good patches installed and still be "legacy Arduino compatible" - there, I said it - without much in the way of Arduino patches to merge in.

    A T2/T++2/T3 real-SPI version of the OLED library would be a nice thing to have on the Teensy libraries page. cmason already did a good job to make this T3 compatible. The adafruit GFX library also needs some work, and a fork of that would seem like a good idea. They are uninterested in performance patches, it seems (I mailed them with some suggestions about obvious inefficiencies, but they were not interested and said its ok if the GFX library is inefficient becaue display-specific libraries will overload the methods with hardware acellerated ones.

    Well, perhaps. But here is the current situation:
    - clearscreen calls filled rectangle
    - filled rectangle calls horizontal ine, in a loop
    - horizontal line calls line
    - line does bresenham line calculation for arbitrary slope (not needed for horizontal or vertical lines) and per-pixel clip detection.

    So, for a 128x64 display, to draw a full-screen rectangle, it makes 64 calls to horizontal line; each call does 128 pixel clip tests and 128 "is the slope greater or less than 45 degrees" tests. That's 8192 clip tests and 8192 slope tests. Whereas, to produce a filled rectangle, you actually need 4 clip tests (top, bottom, left, right) and zero slope tests.

    A less braindead GFX library would be a nice thing to do. Hardware-specific libraries could still override the methods if the hardware has filled rect support etc.

    To the original poster, sorry to derail your thread into a "why are libraries dumb and resistant to patches" thread. We will try to get your SPI problem sorted as well, honest.

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,659
    If only there were more hours in the day... a LOT more!

    Someday I might fork this one and several others and improve performance. But it's unlikely I'll even start such an effort until after the audio board and a couple other major projects are released.

  10. #10
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    894
    I'm currently working on a device-independent canvas library. You can use it to feed a any display device (using your own code) and I think the interface will be pretty simple. The BitArray class I was playing around with in http://forum.pjrc.com/threads/24418-...in-Teensy-code is part of it. The canvas will check for bounding box stuff as early as possible. The initial drawing capabilities will include lines, non-filled frames, lines, 90 degree arcs and circles. Fonts will be added later, as they're absolutely necessary for almost any reasonable GUI. After that is working well, I might add rounded frames, filling and clipping.

  11. #11
    Junior Member
    Join Date
    Oct 2013
    Posts
    15
    Quote Originally Posted by Nantonos View Post
    .........
    Well, perhaps. But here is the current situation:
    - clearscreen calls filled rectangle
    - filled rectangle calls horizontal ine, in a loop
    - horizontal line calls line
    - line does bresenham line calculation for arbitrary slope (not needed for horizontal or vertical lines) and per-pixel clip detection.

    So, for a 128x64 display, to draw a full-screen rectangle, it makes 64 calls to horizontal line; each call does 128 pixel clip tests and 128 "is the slope greater or less than 45 degrees" tests. That's 8192 clip tests and 8192 slope tests.........

    To the original poster, sorry to derail your thread into a "why are libraries dumb and resistant to patches" thread. We will try to get your SPI problem sorted as well, honest.
    For the fill screen function in my 60fps test I resorted back to a more efficient version that was part of an older library. I think Adafruit rewrote the library with a focus on readability, portability and code space. Nothing wrong with that and because it's open source we can do our own performance tweaks. Looking at the changes for Due support, I noticed the code becomes less readable when you have to add special processor specific code with a bunch of ifdefs everywhere. I say branch the library and make one that is speed optimized for Teensy.

  12. #12
    Junior Member
    Join Date
    Oct 2013
    Posts
    10
    Hello all, so I am already using the nick gammon hardware version of the oled library, i am trying to convert the probe version as well to hardware as the teensy has so many spi pins, but i am pretty new to this all, I have different CS/SS pins for the screen and the probe and share the SCK pin, I will look at the library code for the probe again, I'll see what mods I can make.

  13. #13
    Junior Member
    Join Date
    Oct 2013
    Posts
    10
    also when i put an oscilloscope on the CS/SS pins the screen goes low for say 5ms but the probe is like 1ms

  14. #14
    Senior Member
    Join Date
    Nov 2012
    Location
    Boston, MA, USA
    Posts
    1,120
    Quote Originally Posted by Dean View Post
    I have different CS/SS pins for the screen and the probe and share the SCK pin
    The MISO pin (and MOSI if you are using it) should also be shared.

  15. #15
    Junior Member
    Join Date
    Oct 2013
    Posts
    10
    oled is mosi, probe is Miso

  16. #16
    Junior Member
    Join Date
    Oct 2013
    Posts
    10

    solved

    for those who may be interested, i have resolved this issue, I found a new Max31855 library and modified it to work with hardware spi

    Code:
    /*
       RJM_MAX31855.cpp - Library for reading temperature from a RJM_MAX31855.
    
       This work is licensed under a Creative Commons Attribution-ShareAlike 3.0
       Unported License.  http://creativecommons.org/licenses/by-sa/3.0/
    */
    
    #include "RJM_MAX31855.h"
    #include <SPI.h>
    
    //RJM_MAX31855::RJM_MAX31855(int SCK_pin, int CS_pin, int SO_pin) {
    RJM_MAX31855::RJM_MAX31855(int CS_pin) {
    		
    		CS = CS_pin;
    		//SPI.begin();
    		pinMode(CS, OUTPUT);
    		digitalWrite(CS, HIGH);
    }
    
    double RJM_MAX31855::readProbe(unit_t	unit) {
    		unsigned long data;
    		double temperature;
    		
    		// Initialize temperature
    		temperature = 0;
    		
    		// Shift in 32-bit of data from MAX31855
    		data = spiread();
    		
    		// If fault is detected
    		if (data & 0x00010000)
    		{
    			// Check for fault type (3 LSB)
    			switch (data & 0x00000007)
    			{
    				// Open circuit 
    				case 0x01:
    					temperature = FAULT_OPEN;
    					//Serial.println("FAULT_OPEN");
    					//Serial.println(data, BIN);
    					break;
    				
    				// Thermocouple short to GND
    				case 0x02:
    					temperature = FAULT_SHORT_GND;
    					//Serial.println("FAULT_SHORT_GND");
    					//Serial.println(data, BIN);
    					break;
    				
    				// Thermocouple short to VCC	
    				case 0x04:
    					temperature = FAULT_SHORT_VCC;
    					//Serial.println("FAULT_SHORT_VCC");
    					//Serial.println(data, BIN);
    					break;
    			}
    		}
    		// No fault detected
    		else
    		{
    			// Retrieve thermocouple temperature data and strip redundant data
    			data = data >> 18;
    			// Bit-14 is the sign
    			temperature = (data & 0x00001FFF);
    
    			// Check for negative temperature		
    			if (data & 0x00002000)
    			{
    				// 2's complement operation
    				// Invert
    				data = ~data; 
    				// Ensure operation involves lower 13-bit only
    				temperature = data & 0x00001FFF;
    				// Add 1 to obtain the positive number
    				temperature += 1;
    				// Make temperature negative
    				temperature *= -1; 
    			}
    			
    			// Convert to Degree Celsius
    			temperature *= 0.25;
    			
    			// If temperature unit in Fahrenheit is desired
    			if (unit == FAHRENHEIT)
    			{
    				// Convert Degree Celsius to Fahrenheit
    				temperature = (temperature * 9.0/5.0)+ 32; 
    			}
    		}
    		return (temperature);
    }
    
    double RJM_MAX31855::readCJC(unit_t	unit) {
    	double	temperature;
    	unsigned long data;
    	
    	// Shift in 32-bit of data from MAX31855
    	data = spiread();
    	
    	// Strip fault data bits & reserved bit
    	data = data >> 4;
    	// Bit-12 is the sign
    	temperature = (data & 0x000007FF);
    	
    	// Check for negative temperature
    	if (data & 0x00000800)
    	{
    		// 2's complement operation
    		// Invert
    		data = ~data; 
    		// Ensure operation involves lower 11-bit only
    		temperature = data & 0x000007FF;
    		// Add 1 to obtain the positive number
    		temperature += 1;	
    		// Make temperature negative
    		temperature *= -1; 
    	}
    	
    	// Convert to Degree Celsius
    	temperature *= 0.0625;
    	
    	// If temperature unit in Fahrenheit is desired
    	if (unit == FAHRENHEIT)
    	{
    		// Convert Degree Celsius to Fahrenheit
    		temperature = (temperature * 9.0/5.0)+ 32; 	
    	}
    	
    	// Return the temperature
    	return (temperature);
    }
    
    unsigned long RJM_MAX31855::spiread(void) {
    		
    		int i;
    		unsigned long d = 0;
    		digitalWrite(CS, LOW);
    
    		for (int i = 0; i < 4; i++) {
    			//Serial.print("i =");
    			//Serial.println(i, DEC);
    			d = (d << 8) + SPI.transfer(0x00);
    			//Serial.print("d =");
    			//Serial.println(d, BIN);
    		}
    		digitalWrite(CS, HIGH);
    		
    		//READ DEBUG
    		//Serial.print("raw SPI 16 ");
    		//Serial.println(d, BIN);
    
            return d;
    }
    and used nick gammons hardware spi for the display

    Code:
    /*********************************************************************
    This is a library for our Monochrome OLEDs based on SSD1306h drivers
    
      Pick one up today in the adafruit shop!
      ------> http://www.adafruit.com/category/63_98
    
    These displays use SPI to communicate, 4 or 5 pins are required to  
    interface
    
    http://forum.arduino.cc/index.php/topic,108542
    
    You also need to add this to the start of your sketch:
    
    Code:
    #include <SPI.h>
    
    You also need to use different pin-outs to use the hardware SPI. Replace the defines at the top of the sketch with these ones:
    
    Code:
    #define OLED_DC 8     // pin 9 on CD4050B  (output: pin 10)
    #define OLED_CS 10    // pin 5 on CD4050B  (output: pin 4)
    #define OLED_CLK 13   // pin 11 on CD4050B (output: pin 12)
    #define OLED_MOSI 11  // pin 14 on CD4050B (output: pin 15)
    #define OLED_RESET 7  // pin 3 on CD4050B  (output: pin 2)
    
    The wiring now needs to be:
    
    Code:
    Signal   Chip out --> Arduino pin
    
    Reset      3    -->      7  (was 13)
    CS         5    -->     10  (was 12)
    D/C        9    -->      8  (was 11)
    CLK       11    -->     13  (was 10)
    DAT/MOSI  14    -->     11  (was 9)
    *********************************************************************/
    
    #include <avr/pgmspace.h>
    #include <util/delay.h>
    #include <stdlib.h>
    
    #include <Wire.h>
    #include <SPI.h>
    
    #include "Adafruit_GFX.h"
    #include "Adafruit_SSD1306h.h"
    
    //#include "glcdfont.c"
    
    // a 5x7 font table
    extern uint8_t PROGMEM font[];
    
    // the memory buffer for the LCD
    
    static uint8_t buffer[SSD1306h_LCDHEIGHT * SSD1306h_LCDWIDTH / 8] = { 
    0x00, 0x7C, 0x7C, 0xEC, 0x8C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0xFC, 0xF0,
    0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0xC0, 0xF0, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xFC, 0xFC, 0x7C,
    0x3C, 0x3C, 0x7C, 0xFC, 0xCC, 0x8C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xFC,
    0x7C, 0x7C, 0x3C, 0x3C, 0x7C, 0xFC, 0x8C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x38, 0x70, 0xE0,
    0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,
    0xFC, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x8C, 0xFC, 0xFC, 0x7C, 0x7C, 0x7C, 0x7C,
    0xFC, 0xDC, 0x8C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x1C, 0x1C, 0x1C, 0xDC, 0xFC, 0xFC, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
    0x0F, 0x1F, 0x7E, 0xF8, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0x3C,
    0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x01, 0x03, 0x07, 0x0E, 0x1C, 0x38, 0xF0, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
    0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x80, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x01, 0x07, 0x1F, 0x7F, 0xFC, 0xF0, 0xE0, 0xF0, 0x7C, 0x1F, 0x07, 0x00, 0x00,
    0x00, 0x80, 0xF0, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFC, 0xF0,
    0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0E, 0x1C, 0x38, 0x78, 0xF8, 0xFF,
    0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0x7C, 0x70,
    0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x07, 0x01, 0x00, 0x00, 0x80, 0xE0, 0xF8,
    0xFE, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x01,
    0x01, 0x01, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x80, 0xC0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0x01, 0x07, 0x1E, 0x38, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF8, 0xFE, 0x3F, 0x1F, 0x03,
    0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x80,
    0x80, 0x80, 0xC0, 0xE0, 0x7F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0,
    0x80, 0x80, 0x80, 0x80, 0xC0, 0xF0, 0x7F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0E, 0x3C, 0x78, 0xF0, 0xE0,
    0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0xC0, 0x80, 0x80, 0xC0, 0xC0,
    0xF0, 0x7F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x80, 0x00, 0x00,
    0x00, 0x0F, 0x0F, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0E, 0x0F, 0x0F, 0x0F, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0E, 0x0C, 0x0C, 0x0F, 0x0F, 0x0B, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x0F, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
    0x0F, 0x0F, 0x0F, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0F, 0x0F,
    0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0C, 0x0C, 0x0C, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x03, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
    0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x30, 0x10,
    0x10, 0xFC, 0xFC, 0x00, 0x00, 0xE8, 0xE8, 0x00, 0x60, 0xF0, 0x90, 0xF0, 0x70, 0x10, 0x00, 0xE8,
    0xE8, 0x00, 0x10, 0xF8, 0xF8, 0x10, 0x10, 0x80, 0x90, 0xD0, 0x50, 0xF0, 0xE0, 0x00, 0xFC, 0xFC,
    0x00, 0x00, 0x00, 0xFC, 0xFC, 0x10, 0x10, 0xF0, 0xE0, 0x00, 0x00, 0xE8, 0xE8, 0x00, 0xF0, 0xF0,
    0x30, 0x10, 0x10, 0x00, 0x10, 0xF8, 0xF8, 0x10, 0x10, 0x00, 0xFC, 0xFC, 0x30, 0xF0, 0xE0, 0x00,
    0x00, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0xB0, 0x10, 0x10, 0x10, 0x00, 0xE0, 0xF0, 0x10, 0x10, 0x10,
    0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0xFC, 0xFC,
    0xF0, 0x90, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
    0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x05, 0x07, 0x02, 0x00, 0x01,
    0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01,
    0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00,
    0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
    0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
    0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    
    
    
    // the most basic function, set a single pixel
    void Adafruit_SSD1306h::drawPixel(int16_t x, int16_t y, uint16_t color) {
      if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
        return;
    
      // check rotation, move pixel around if necessary
      switch (getRotation()) {
      case 1:
        swap(x, y);
        x = WIDTH - x - 1;
        break;
      case 2:
        x = WIDTH - x - 1;
        y = HEIGHT - y - 1;
        break;
      case 3:
        swap(x, y);
        y = HEIGHT - y - 1;
        break;
      }  
    
      // x is which column
      if (color == WHITE) 
        buffer[x+ (y/8)*SSD1306h_LCDWIDTH] |= _BV((y%8));  
      else
        buffer[x+ (y/8)*SSD1306h_LCDWIDTH] &= ~_BV((y%8)); 
    }
    
    Adafruit_SSD1306h::Adafruit_SSD1306h(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS) {
      cs = CS;
      rst = RST;
      dc = DC;
      sclk = SCLK;
      sid = SID;
    }
    
    // initializer for I2C - we only indicate the reset pin!
    Adafruit_SSD1306h::Adafruit_SSD1306h(int8_t reset) {
      sclk = dc = cs = sid = -1;
      rst = reset;
    }
      
    
    void Adafruit_SSD1306h::begin(uint8_t vccstate, uint8_t i2caddr) {
    #ifdef SSD1306h_128_64
      constructor(128, 64);
    #endif
    #ifdef SSD1306h_128_32
      constructor(128, 32);
    #endif
    
      _i2caddr = i2caddr;
    
    
      // set pin directions
      if (sid != -1)
      {
        // SPI
        pinMode(sid, OUTPUT);
        pinMode(sclk, OUTPUT);
        pinMode(dc, OUTPUT);
        pinMode(cs, OUTPUT);
        clkport     = portOutputRegister(digitalPinToPort(sclk));
        clkpinmask  = digitalPinToBitMask(sclk);
        mosiport    = portOutputRegister(digitalPinToPort(sid));
        mosipinmask = digitalPinToBitMask(sid);
        csport      = portOutputRegister(digitalPinToPort(cs));
        cspinmask   = digitalPinToBitMask(cs);
        dcport      = portOutputRegister(digitalPinToPort(dc));
        dcpinmask   = digitalPinToBitMask(dc);
    	SPI.begin (); 
    	//SPI.setClockDivider (SPI_CLOCK_DIV2);
      }
      else
      {
        // I2C Init
    	Wire.begin(); // Is this the right place for this?
      }
    
      // Setup reset pin direction (used by both SPI and I2C)  
      pinMode(rst, OUTPUT);
      digitalWrite(rst, HIGH);
      // VDD (3.3V) goes high at start, lets just chill for a ms
      delay(1);
      // bring reset low
      digitalWrite(rst, LOW);
      // wait 10ms
      delay(10);
      // bring out of reset
      digitalWrite(rst, HIGH);
      // turn on VCC (9V?)
    
       #if defined SSD1306h_128_32
        // Init sequence for 128x32 OLED module
        ssd1306h_command(SSD1306h_DISPLAYOFF);                    // 0xAE
        ssd1306h_command(SSD1306h_SETDISPLAYCLOCKDIV);            // 0xD5
        ssd1306h_command(0x80);                                  // the suggested ratio 0x80
        ssd1306h_command(SSD1306h_SETMULTIPLEX);                  // 0xA8
        ssd1306h_command(0x1F);
        ssd1306h_command(SSD1306h_SETDISPLAYOFFSET);              // 0xD3
        ssd1306h_command(0x0);                                   // no offset
        ssd1306h_command(SSD1306h_SETSTARTLINE | 0x0);            // line #0
        ssd1306h_command(SSD1306h_CHARGEPUMP);                    // 0x8D
        if (vccstate == SSD1306h_EXTERNALVCC) 
          { ssd1306h_command(0x10); }
        else 
          { ssd1306h_command(0x14); }
        ssd1306h_command(SSD1306h_MEMORYMODE);                    // 0x20
        ssd1306h_command(0x00);                                  // 0x0 act like ks0108
    	ssd1306h_command(SSD1306h_SEGREMAP | 0x1);
        ssd1306h_command(SSD1306h_COMSCANDEC);
        ssd1306h_command(SSD1306h_SETCOMPINS);                    // 0xDA
        ssd1306h_command(0x02);
        ssd1306h_command(SSD1306h_SETCONTRAST);                   // 0x81
        ssd1306h_command(0x8F);
        ssd1306h_command(SSD1306h_SETPRECHARGE);                  // 0xd9
        if (vccstate == SSD1306h_EXTERNALVCC) 
          { ssd1306h_command(0x22); }
        else 
          { ssd1306h_command(0xF1); }
        ssd1306h_command(SSD1306h_SETVCOMDETECT);                 // 0xDB
        ssd1306h_command(0x40);
        ssd1306h_command(SSD1306h_DISPLAYALLON_RESUME);           // 0xA4
        ssd1306h_command(SSD1306h_NORMALDISPLAY);                 // 0xA6
      #endif
    
      #if defined SSD1306h_128_64
        // Init sequence for 128x64 OLED module
        ssd1306h_command(SSD1306h_DISPLAYOFF);                    // 0xAE
        ssd1306h_command(SSD1306h_SETDISPLAYCLOCKDIV);            // 0xD5
        ssd1306h_command(0x80);                                  // the suggested ratio 0x80
        ssd1306h_command(SSD1306h_SETMULTIPLEX);                  // 0xA8
        ssd1306h_command(0x3F);
        ssd1306h_command(SSD1306h_SETDISPLAYOFFSET);              // 0xD3
        ssd1306h_command(0x0);                                   // no offset
        ssd1306h_command(SSD1306h_SETSTARTLINE | 0x0);            // line #0
        ssd1306h_command(SSD1306h_CHARGEPUMP);                    // 0x8D
        if (vccstate == SSD1306h_EXTERNALVCC) 
          { ssd1306h_command(0x10); }
        else 
          { ssd1306h_command(0x14); }
        ssd1306h_command(SSD1306h_MEMORYMODE);                    // 0x20
        ssd1306h_command(0x00);                                  // 0x0 act like ks0108
        ssd1306h_command(SSD1306h_SEGREMAP | 0x1);
        ssd1306h_command(SSD1306h_COMSCANDEC);
        ssd1306h_command(SSD1306h_SETCOMPINS);                    // 0xDA
        ssd1306h_command(0x12);
        ssd1306h_command(SSD1306h_SETCONTRAST);                   // 0x81
        if (vccstate == SSD1306h_EXTERNALVCC) 
          { ssd1306h_command(0x9F); }
        else 
          { ssd1306h_command(0xCF); }
        ssd1306h_command(SSD1306h_SETPRECHARGE);                  // 0xd9
        if (vccstate == SSD1306h_EXTERNALVCC) 
          { ssd1306h_command(0x22); }
        else 
          { ssd1306h_command(0xF1); }
        ssd1306h_command(SSD1306h_SETVCOMDETECT);                 // 0xDB
        ssd1306h_command(0x40);
        ssd1306h_command(SSD1306h_DISPLAYALLON_RESUME);           // 0xA4
        ssd1306h_command(SSD1306h_NORMALDISPLAY);                 // 0xA6
      #endif
      
      ssd1306h_command(SSD1306h_DISPLAYON);//--turn on oled panel
    }
    
    
    void Adafruit_SSD1306h::invertDisplay(uint8_t i) {
      if (i) {
        ssd1306h_command(SSD1306h_INVERTDISPLAY);
      } else {
        ssd1306h_command(SSD1306h_NORMALDISPLAY);
      }
    }
    
    void Adafruit_SSD1306h::ssd1306h_command(uint8_t c) { 
      if (sid != -1)
      {
        // SPI
        //digitalWrite(cs, HIGH);
        *csport |= cspinmask;
        //digitalWrite(dc, LOW);
        *dcport &= ~dcpinmask;
        //digitalWrite(cs, LOW);
        *csport &= ~cspinmask;
        fastSPIwrite(c);
        //digitalWrite(cs, HIGH);
        *csport |= cspinmask;
      }
      else
      {
        // I2C
        uint8_t control = 0x00;   // Co = 0, D/C = 0
        Wire.beginTransmission(_i2caddr);
        Wire.write(control);
        Wire.write(c);
        Wire.endTransmission();
      }
    }
    
    // startscrollright
    // Activate a right handed scroll for rows start through stop
    // Hint, the display is 16 rows tall. To scroll the whole display, run:
    // display.scrollright(0x00, 0x0F) 
    void Adafruit_SSD1306h::startscrollright(uint8_t start, uint8_t stop){
    	ssd1306h_command(SSD1306h_RIGHT_HORIZONTAL_SCROLL);
    	ssd1306h_command(0X00);
    	ssd1306h_command(start);
    	ssd1306h_command(0X00);
    	ssd1306h_command(stop);
    	ssd1306h_command(0X01);
    	ssd1306h_command(0XFF);
    	ssd1306h_command(SSD1306h_ACTIVATE_SCROLL);
    }
    
    // startscrollleft
    // Activate a right handed scroll for rows start through stop
    // Hint, the display is 16 rows tall. To scroll the whole display, run:
    // display.scrollright(0x00, 0x0F) 
    void Adafruit_SSD1306h::startscrollleft(uint8_t start, uint8_t stop){
    	ssd1306h_command(SSD1306h_LEFT_HORIZONTAL_SCROLL);
    	ssd1306h_command(0X00);
    	ssd1306h_command(start);
    	ssd1306h_command(0X00);
    	ssd1306h_command(stop);
    	ssd1306h_command(0X01);
    	ssd1306h_command(0XFF);
    	ssd1306h_command(SSD1306h_ACTIVATE_SCROLL);
    }
    
    // startscrolldiagright
    // Activate a diagonal scroll for rows start through stop
    // Hint, the display is 16 rows tall. To scroll the whole display, run:
    // display.scrollright(0x00, 0x0F) 
    void Adafruit_SSD1306h::startscrolldiagright(uint8_t start, uint8_t stop){
    	ssd1306h_command(SSD1306h_SET_VERTICAL_SCROLL_AREA);	
    	ssd1306h_command(0X00);
    	ssd1306h_command(SSD1306h_LCDHEIGHT);
    	ssd1306h_command(SSD1306h_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
    	ssd1306h_command(0X00);
    	ssd1306h_command(start);
    	ssd1306h_command(0X00);
    	ssd1306h_command(stop);
    	ssd1306h_command(0X01);
    	ssd1306h_command(SSD1306h_ACTIVATE_SCROLL);
    }
    
    // startscrolldiagleft
    // Activate a diagonal scroll for rows start through stop
    // Hint, the display is 16 rows tall. To scroll the whole display, run:
    // display.scrollright(0x00, 0x0F) 
    void Adafruit_SSD1306h::startscrolldiagleft(uint8_t start, uint8_t stop){
    	ssd1306h_command(SSD1306h_SET_VERTICAL_SCROLL_AREA);	
    	ssd1306h_command(0X00);
    	ssd1306h_command(SSD1306h_LCDHEIGHT);
    	ssd1306h_command(SSD1306h_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
    	ssd1306h_command(0X00);
    	ssd1306h_command(start);
    	ssd1306h_command(0X00);
    	ssd1306h_command(stop);
    	ssd1306h_command(0X01);
    	ssd1306h_command(SSD1306h_ACTIVATE_SCROLL);
    }
    
    void Adafruit_SSD1306h::stopscroll(void){
    	ssd1306h_command(SSD1306h_DEACTIVATE_SCROLL);
    }
    
    void Adafruit_SSD1306h::ssd1306h_data(uint8_t c) {
      if (sid != -1)
      {
        // SPI
        //digitalWrite(cs, HIGH);
        *csport |= cspinmask;
        //digitalWrite(dc, HIGH);
        *dcport |= dcpinmask;
        //digitalWrite(cs, LOW);
        *csport &= ~cspinmask;
        fastSPIwrite(c);
        //digitalWrite(cs, HIGH);
        *csport |= cspinmask;
      }
      else
      {
        // I2C
        uint8_t control = 0x40;   // Co = 0, D/C = 1
        Wire.beginTransmission(_i2caddr);
        Wire.write(control);
        Wire.write(c);
        Wire.endTransmission();
      }
    }
    
    void Adafruit_SSD1306h::display(void) {
      ssd1306h_command(SSD1306h_SETLOWCOLUMN | 0x0);  // low col = 0
      ssd1306h_command(SSD1306h_SETHIGHCOLUMN | 0x0);  // hi col = 0
      ssd1306h_command(SSD1306h_SETSTARTLINE | 0x0); // line #0
    
      if (sid != -1)
      {
        // SPI
        *csport |= cspinmask;
        *dcport |= dcpinmask;
        *csport &= ~cspinmask;
    
        for (uint16_t i=0; i<(SSD1306h_LCDWIDTH*SSD1306h_LCDHEIGHT/8); i++) {
          fastSPIwrite(buffer[i]);
          //ssd1306h_data(buffer[i]);
        }
        // i wonder why we have to do this (check datasheet)
        if (SSD1306h_LCDHEIGHT == 32) {
          for (uint16_t i=0; i<(SSD1306h_LCDWIDTH*SSD1306h_LCDHEIGHT/8); i++) {
            //ssd1306h_data(0);
            fastSPIwrite(0);
          }
        }
        *csport |= cspinmask;
      }
      else
      {
        // save I2C bitrate
        //uint8_t twbrbackup = TWBR;
        //TWBR = 12; // upgrade to 400KHz!
    
        //Serial.println(TWBR, DEC);
        //Serial.println(TWSR & 0x3, DEC);
    
        // I2C
        for (uint16_t i=0; i<(SSD1306h_LCDWIDTH*SSD1306h_LCDHEIGHT/8); i++) {
          // send a bunch of data in one xmission
          Wire.beginTransmission(_i2caddr);
          Wire.write(0x40);
          for (uint8_t x=0; x<16; x++) {
    	Wire.write(buffer[i]);
    	i++;
          }
          i--;
          Wire.endTransmission();
        }
        // i wonder why we have to do this (check datasheet)
        if (SSD1306h_LCDHEIGHT == 32) {
          for (uint16_t i=0; i<(SSD1306h_LCDWIDTH*SSD1306h_LCDHEIGHT/8); i++) {
    	// send a bunch of data in one xmission
    	Wire.beginTransmission(_i2caddr);
    	Wire.write(0x40);
    	for (uint8_t x=0; x<16; x++) {
    	  Wire.write((uint8_t)0x00);
    	  i++;
    	}
    	i--;
    	Wire.endTransmission();
          }
        }
        //TWBR = twbrbackup;
      }
    }
    
    // clear everything
    void Adafruit_SSD1306h::clearDisplay(void) {
      memset(buffer, 0, (SSD1306h_LCDWIDTH*SSD1306h_LCDHEIGHT/8));
    }
    
    
      inline void Adafruit_SSD1306h::fastSPIwrite(uint8_t d){
        
       SPI.transfer (d);
    }
    
    inline void Adafruit_SSD1306h::slowSPIwrite(uint8_t d) {
     for (int8_t i=7; i>=0; i--) {
       digitalWrite(sclk, LOW);
       if (d & _BV(i)) {
         digitalWrite(sid, HIGH);
       } else {
         digitalWrite(sid, LOW);
       }
       digitalWrite(sclk, HIGH);
     }
    }
    the great thing with the new max31855 library is that you can use multiple devices as i have a quad board.

  17. #17
    Hi Dean,
    I am curious about how you got the OLED display to work with the T3. I wanted to use nick gammons hardware spi library but I noticed includes in there of files I do not have. Wire.h for one, and the reference to an avr library "#include <avr/pgmspace.h>". The T3 is an ARM processor so I didn't think AVR stuff would work.

    Thank you for your time!

  18. #18
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    27,659
    Quote Originally Posted by HopWorks View Post
    The T3 is an ARM processor so I didn't think AVR stuff would work.
    I created AVR emulation and workaround for the most commonly used AVR libc feature and AVR hardware registers. Not every AVR feature is supported, but all the ones that are very commonly used "just work" on Teensy3.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •