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

Status
Not open for further replies.

Dean

Member
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/productview.php?pdid=20&catid=1001
1.3" 128x64 OLED Display Module SSD1306 - http://www.wide.hk/products.php?product=1.3"-128x64-OLED-Display-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/viewtopic.php?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.
 
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
 
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.
 
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.
 
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" :confused:
 
Odd.

...Adafruit won't add the patch, on the grounds that "few people need fast updates" :confused:

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!
 
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.
 
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.
 
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.
 
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-Using-C-0x-features-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.
 
.........
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.
 
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.
 
also when i put an oscilloscope on the CS/SS pins the screen goes low for say 5ms but the probe is like 1ms
 
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.
 
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!
 
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.
 
Status
Not open for further replies.
Back
Top