ADVERTISEMENT

Stm32.zip

Stm32F103C8T - Błąd bibliotek I2C (arduino/STM32)

Witam mam problem odnośnie jednoczesnego używania wyświetlacza oled SSD1306 - I2C oraz cyfrowego czujnika prądu/mocy INA219 - I2C. Przykłady wgrywane osobno działają jednak przy próbie użycia jednocześnie działa tylko 1 urządzenie zależnie od miejsca inicjalizacji w programie. Domyślam się że jest to spowodowane tym że wyświetlacz korzysta z biblioteki <HardWire.h> a INA219 z <Wire.h>. Czy jest możliwość uruchomienia ich razem ? Czy może użyć 2 linii I2C1, oraz I2C2 mikrokątrolera Stm32F103C8T czy jest taka możliwość jeśli tak to jak ? W załączniku dołączam biblioteki , proszę o pomoc.


Download file - link to post
  • Stm32.zip
    • Wire.h
    • rules.mk
    • Wire.cpp
    • examples
      • i2c_scanner_wire
        • i2c_scanner_wire.ino
      • i2c_scanner_hwire
        • i2c_scanner_hwire.ino
    • HardWire.cpp
    • WireBase.cpp
    • WireBase.h
    • HardWire.h


Stm32.zip > Wire.h

/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the &quot; Software &quot; ), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED &quot; AS IS &quot; , WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/

/**
* @file Wire.h
* @author Trystan Jones &amp; lt; crenn6977@gmail.com &amp; gt;
* @brief Wire library, uses the WireBase to create the primary interface
* while keeping low level interactions invisible to the user.
*/

/*
* Library updated by crenn to follow new Wire system.
* Code was derived from the original Wire for maple code by leaflabs and the
* modifications by gke and ala42.
*/

#ifndef _WIRE_H_
#define _WIRE_H_

#include &quot; WireBase.h &quot;
#include &quot; wirish.h &quot;

/*
* On the Maple, let the default pins be in the same location as the Arduino
* pins
*/
#define SDA PB11 //7
#define SCL PB10 //6

#define SOFT_STANDARD 27
#define SOFT_FAST 0


//#define I2C_DELAY(x) {uint32 time=micros(); while(time &amp; gt; (micros()+x));}
#define I2C_DELAY(x) do{for(int i=0;i &amp; lt; x;i++) {asm volatile( &quot; nop &quot; );}}while(0)

#define BUFFER_LENGTH 32


class TwoWire : public WireBase {
public:
uint8 i2c_delay;
uint8 scl_pin;
uint8 sda_pin;

/*
* Sets the SCL line to HIGH/LOW and allow for clock stretching by slave
* devices
*/
void set_scl(bool);

/*
* Sets the SDA line to HIGH/LOW
*/
void set_sda(bool);

/*
* Creates a Start condition on the bus
*/
void i2c_start();

/*
* Creates a Stop condition on the bus
*/
void i2c_stop();

/*
* Gets an ACK condition from a slave device on the bus
*/
bool i2c_get_ack();

/*
* Creates a ACK condition on the bus
*/
void i2c_send_ack();

/*
* Creates a NACK condition on the bus
*/
void i2c_send_nack();

/*
* Shifts in the data through SDA and clocks SCL for the slave device
*/
uint8 i2c_shift_in();

/*
* Shifts out the data through SDA and clocks SCL for the slave device
*/
void i2c_shift_out(uint8);
protected:
/*
* Processes the incoming I2C message defined by WireBase
*/
uint8 process();
public:
/*
* Accept pin numbers for SCL and SDA lines. Set the delay needed
* to create the timing for I2C's Standard Mode and Fast Mode.
*/
TwoWire(uint8 scl=PB10, uint8 sda=PB11, uint8 delay=SOFT_STANDARD);

/*
* Sets pins SDA and SCL to OUPTUT_OPEN_DRAIN, joining I2C bus as
* master. This function overwrites the default behaviour of
* .begin(uint8) in WireBase
*/
void begin(uint8 = 0x00);

/*
* If object is destroyed, set pin numbers to 0.
*/
~TwoWire();
};

extern TwoWire Wire;

#endif // _WIRE_H_


Stm32.zip > INA219.h

/*
INA219.h - Header file for the Zero-Drift, Bi-directional Current/Power Monitor Arduino Library.

Version: 1.0.0
(c) 2014 Korneliusz Jarzebski
www.jarzebski.pl

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see &amp; lt; http://www.gnu.org/licenses/ &amp; gt; .
*/

#ifndef INA219_h
#define INA219_h

#if ARDUINO &amp; gt; = 100
#include &quot; Arduino.h &quot;
#else
#include &quot; WProgram.h &quot;
#endif

#define INA219_ADDRESS (0x40)

#define INA219_CMD_READ (0x01)

#define INA219_REG_CONFIG (0x00)
#define INA219_REG_SHUNTVOLTAGE (0x01)
#define INA219_REG_BUSVOLTAGE (0x02)
#define INA219_REG_POWER (0x03)
#define INA219_REG_CURRENT (0x04)
#define INA219_REG_CALIBRATION (0x05)

typedef enum
{
INA219_RANGE_16V = 0b0,
INA219_RANGE_32V = 0b1
} ina219_range_t;

typedef enum
{
INA219_GAIN_40MV = 0b00,
INA219_GAIN_80MV = 0b01,
INA219_GAIN_160MV = 0b10,
INA219_GAIN_320MV = 0b11
} ina219_gain_t;

typedef enum
{
INA219_BUS_RES_9BIT = 0b0000,
INA219_BUS_RES_10BIT = 0b0001,
INA219_BUS_RES_11BIT = 0b0010,
INA219_BUS_RES_12BIT = 0b0011
} ina219_busRes_t;

typedef enum
{
INA219_SHUNT_RES_9BIT_1S = 0b0000,
INA219_SHUNT_RES_10BIT_1S = 0b0001,
INA219_SHUNT_RES_11BIT_1S = 0b0010,
INA219_SHUNT_RES_12BIT_1S = 0b0011,
INA219_SHUNT_RES_12BIT_2S = 0b1001,
INA219_SHUNT_RES_12BIT_4S = 0b1010,
INA219_SHUNT_RES_12BIT_8S = 0b1011,
INA219_SHUNT_RES_12BIT_16S = 0b1100,
INA219_SHUNT_RES_12BIT_32S = 0b1101,
INA219_SHUNT_RES_12BIT_64S = 0b1110,
INA219_SHUNT_RES_12BIT_128S = 0b1111
} ina219_shuntRes_t;

typedef enum
{
INA219_MODE_POWER_DOWN = 0b000,
INA219_MODE_SHUNT_TRIG = 0b001,
INA219_MODE_BUS_TRIG = 0b010,
INA219_MODE_SHUNT_BUS_TRIG = 0b011,
INA219_MODE_ADC_OFF = 0b100,
INA219_MODE_SHUNT_CONT = 0b101,
INA219_MODE_BUS_CONT = 0b110,
INA219_MODE_SHUNT_BUS_CONT = 0b111,
} ina219_mode_t;


class INA219
{
public:

bool begin(uint8_t address = INA219_ADDRESS);
bool configure(ina219_range_t range = INA219_RANGE_32V, ina219_gain_t gain = INA219_GAIN_320MV, ina219_busRes_t busRes = INA219_BUS_RES_12BIT, ina219_shuntRes_t shuntRes = INA219_SHUNT_RES_12BIT_1S, ina219_mode_t mode = INA219_MODE_SHUNT_BUS_CONT);
bool calibrate(float rShuntValue = 0.1, float iMaxExcepted = 2);

ina219_range_t getRange(void);
ina219_gain_t getGain(void);
ina219_busRes_t getBusRes(void);
ina219_shuntRes_t getShuntRes(void);
ina219_mode_t getMode(void);

float readShuntCurrent(void);
float readShuntVoltage(void);
float readBusPower(void);
float readBusVoltage(void);

float getMaxPossibleCurrent(void);
float getMaxCurrent(void);
float getMaxShuntVoltage(void);
float getMaxPower(void);

private:

int8_t inaAddress;
float currentLSB, powerLSB;
float vShuntMax, vBusMax, rShunt;

void writeRegister16(uint8_t reg, uint16_t val);
int16_t readRegister16(uint8_t reg);
};

#endif


Stm32.zip > Wire.cpp

/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the &quot; Software &quot; ), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED &quot; AS IS &quot; , WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/

/**
* @file Wire.cpp
* @author Trystan Jones &amp; lt; crenn6977@gmail.com &amp; gt;
* @brief Wire library, uses the WireBase to create the primary interface
* while keeping low level interactions invisible to the user.
*/

/*
* Library updated by crenn to follow new Wire system.
* Code was derived from the original Wire for maple code by leaflabs and the
* modifications by gke and ala42.
*/
/*
* Updated by Roger Clark. 20141111. Fixed issue when process() returned because of missing ACK (often caused by invalid device address being used), caused SCL to be left
* LOW so that in the next call to process() , the first clock pulse was not sent, because SCL was LOW when it should have been high.
*/

#include &quot; Wire.h &quot;

#define I2C_WRITE 0
#define I2C_READ 1

/* low level conventions:
* - SDA/SCL idle high (expected high)
* - always start with i2c_delay rather than end
*/

void TwoWire::set_scl(bool state){//bool state) {
I2C_DELAY(this- &amp; gt; i2c_delay);
digitalWrite(this- &amp; gt; scl_pin,state);
//Allow for clock stretching - dangerous currently
if (state == HIGH) {
while(digitalRead(this- &amp; gt; scl_pin) == 0);
}
}

void TwoWire::set_sda(bool state) {
I2C_DELAY(this- &amp; gt; i2c_delay);
digitalWrite(this- &amp; gt; sda_pin, state);
}

void TwoWire::i2c_start() {
set_sda(LOW);
set_scl(LOW);
}

void TwoWire::i2c_stop() {
set_sda(LOW);
set_scl(HIGH);
set_sda(HIGH);
}

bool TwoWire::i2c_get_ack() {
set_scl(LOW);
set_sda(HIGH);
set_scl(HIGH);

bool ret = !digitalRead(this- &amp; gt; sda_pin);
set_scl(LOW);
return ret;
}

void TwoWire::i2c_send_ack() {
set_sda(LOW);
set_scl(HIGH);
set_scl(LOW);
}

void TwoWire::i2c_send_nack() {
set_sda(HIGH);
set_scl(HIGH);
set_scl(LOW);
}

uint8 TwoWire::i2c_shift_in() {
uint8 data = 0;
set_sda(HIGH);

int i;
for (i = 0; i &amp; lt; 8; i++) {
set_scl(HIGH);
data |= digitalRead(this- &amp; gt; sda_pin) &amp; lt; &amp; lt; (7-i);
set_scl(LOW);
}

return data;
}

void TwoWire::i2c_shift_out(uint8 val) {
int i;
for (i = 0; i &amp; lt; 8; i++) {
set_sda(!!(val &amp; (1 &amp; lt; &amp; lt; (7 - i)) ) );
set_scl(HIGH);
set_scl(LOW);
}
}

uint8 TwoWire::process() {
itc_msg.xferred = 0;

uint8 sla_addr = (itc_msg.addr &amp; lt; &amp; lt; 1);
if (itc_msg.flags == I2C_MSG_READ) {
sla_addr |= I2C_READ;
}
i2c_start();
// shift out the address we're transmitting to
i2c_shift_out(sla_addr);
if (!i2c_get_ack())
{
i2c_stop();// Roger Clark. 20141110 added to set clock high again, as it will be left in a low state otherwise
return ENACKADDR;
}
// Recieving
if (itc_msg.flags == I2C_MSG_READ) {
while (itc_msg.xferred &amp; lt; itc_msg.length) {
itc_msg.data[itc_msg.xferred++] = i2c_shift_in();
if (itc_msg.xferred &amp; lt; itc_msg.length)
{
i2c_send_ack();
}
else
{
i2c_send_nack();
}
}
}
// Sending
else {
for (uint8 i = 0; i &amp; lt; itc_msg.length; i++) {
i2c_shift_out(itc_msg.data[i]);
if (!i2c_get_ack())
{
i2c_stop();// Roger Clark. 20141110 added to set clock high again, as it will be left in a low state otherwise
return ENACKTRNS;
}
itc_msg.xferred++;
}
}
i2c_stop();
return SUCCESS;
}

// TODO: Add in Error Handling if pins is out of range for other Maples
// TODO: Make delays more capable
TwoWire::TwoWire(uint8 scl, uint8 sda, uint8 delay) : i2c_delay(delay) {
this- &amp; gt; scl_pin=scl;
this- &amp; gt; sda_pin=sda;
}

void TwoWire::begin(uint8 self_addr) {
tx_buf_idx = 0;
tx_buf_overflow = false;
rx_buf_idx = 0;
rx_buf_len = 0;
pinMode(this- &amp; gt; scl_pin, OUTPUT_OPEN_DRAIN);
pinMode(this- &amp; gt; sda_pin, OUTPUT_OPEN_DRAIN);
set_scl(HIGH);
set_sda(HIGH);
}

TwoWire::~TwoWire() {
this- &amp; gt; scl_pin=0;
this- &amp; gt; sda_pin=0;
}

// Declare the instance that the users of the library can use
TwoWire Wire(SCL, SDA, SOFT_STANDARD);
//TwoWire Wire(PB6, PB7, SOFT_STANDARD);


Stm32.zip > license.txt

Software License Agreement (BSD License)

Copyright (c) 2012, Adafruit Industries
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. 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.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 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.


Stm32.zip > WireBase.cpp

/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the &quot; Software &quot; ), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED &quot; AS IS &quot; , WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/

/**
* @file WireBase.cpp
* @author Trystan Jones &amp; lt; crenn6977@gmail.com &amp; gt;
* @brief Wire library, following the majority of the interface from Arduino.
* Provides a 'standard' interface to I2C (two-wire) communication for
* derived classes.
*/

/*
* Library created by crenn to allow a system which would provide users the
* 'standardised' Arduino method for interfacing with I2C devices regardless of
* whether it is I2C hardware or emulating software.
*/

#include &quot; WireBase.h &quot;
#include &quot; wirish.h &quot;

void WireBase::begin(uint8 self_addr) {
tx_buf_idx = 0;
tx_buf_overflow = false;
rx_buf_idx = 0;
rx_buf_len = 0;
}

void WireBase::beginTransmission(uint8 slave_address) {
itc_msg.addr = slave_address;
itc_msg.data = &amp; tx_buf[tx_buf_idx];
itc_msg.length = 0;
itc_msg.flags = 0;
}

void WireBase::beginTransmission(int slave_address) {
beginTransmission((uint8)slave_address);
}

uint8 WireBase::endTransmission(void) {
uint8 retVal;
if (tx_buf_overflow) {
return EDATA;
}
retVal = process();// Changed so that the return value from process is returned by this function see also the return line below
tx_buf_idx = 0;
tx_buf_overflow = false;
return retVal;//SUCCESS;
}

//TODO: Add the ability to queue messages (adding a boolean to end of function
// call, allows for the Arduino style to stay while also giving the flexibility
// to bulk send
uint8 WireBase::requestFrom(uint8 address, int num_bytes) {
if (num_bytes &amp; gt; WIRE_BUFSIZ) {
num_bytes = WIRE_BUFSIZ;
}
itc_msg.addr = address;
itc_msg.flags = I2C_MSG_READ;
itc_msg.length = num_bytes;
itc_msg.data = &amp; rx_buf[rx_buf_idx];
process();
rx_buf_len += itc_msg.xferred;
itc_msg.flags = 0;
return rx_buf_len;
}

uint8 WireBase::requestFrom(int address, int numBytes) {
return WireBase::requestFrom((uint8)address, numBytes);
}

void WireBase::write(uint8 value) {
if (tx_buf_idx == WIRE_BUFSIZ) {
tx_buf_overflow = true;
return;
}
tx_buf[tx_buf_idx++] = value;
itc_msg.length++;
}

void WireBase::write(uint8* buf, int len) {
for (uint8 i = 0; i &amp; lt; len; i++) {
write(buf[i]);
}
}

void WireBase::write(int value) {
write((uint8)value);
}

void WireBase::write(int* buf, int len) {
write((uint8*)buf, (uint8)len);
}

void WireBase::write(char* buf) {
uint8 *ptr = (uint8*)buf;
while (*ptr) {
write(*ptr);
ptr++;
}
}

uint8 WireBase::available() {
return rx_buf_len - rx_buf_idx;
}

uint8 WireBase::read() {
if (rx_buf_idx == rx_buf_len) {
rx_buf_idx = 0;
rx_buf_len = 0;
return 0;
} else if (rx_buf_idx == (rx_buf_len-1)) {
uint8 temp = rx_buf[rx_buf_idx];
rx_buf_idx = 0;
rx_buf_len = 0;
return temp;
}
return rx_buf[rx_buf_idx++];
}


Stm32.zip > WireBase.h

/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the &quot; Software &quot; ), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED &quot; AS IS &quot; , WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/

/**
* @file WireBase.h
* @author Trystan Jones &amp; lt; crenn6977@gmail.com &amp; gt;
* @brief Wire library, following the majority of the interface from Arduino.
* Provides a 'standard' interface to I2C (two-wire) communication for
* derived classes.
*/

/*
* Library created by crenn to allow a system which would provide users the
* 'standardised' Arduino method for interfacing with I2C devices regardless of
* whether it is I2C hardware or emulating software.
*/

#ifndef _WIREBASE_H_
#define _WIREBASE_H_

#include &quot; wirish.h &quot;
#include &amp; lt; libmaple/i2c.h &amp; gt;

#define WIRE_BUFSIZ 32

/* return codes from endTransmission() */
#define SUCCESS 0 /* transmission was successful */
#define EDATA 1 /* too much data */
#define ENACKADDR 2 /* received nack on transmit of address */
#define ENACKTRNS 3 /* received nack on transmit of data */
#define EOTHER 4 /* other error */

class WireBase { // Abstraction is awesome!
protected:
i2c_msg itc_msg;
uint8 rx_buf[WIRE_BUFSIZ]; /* receive buffer */
uint8 rx_buf_idx; /* first unread idx in rx_buf */
uint8 rx_buf_len; /* number of bytes read */

uint8 tx_buf[WIRE_BUFSIZ]; /* transmit buffer */
uint8 tx_buf_idx; // next idx available in tx_buf, -1 overflow
boolean tx_buf_overflow;

// Force derived classes to define process function
virtual uint8 process() = 0;
public:
WireBase() {}
~WireBase() {}

/*
* Initialises the class interface
*/
// Allow derived classes to overwrite begin function
virtual void begin(uint8 = 0x00);

/*
* Sets up the transmission message to be processed
*/
void beginTransmission(uint8);

/*
* Allow only 8 bit addresses to be used
*/
void beginTransmission(int);

/*
* Call the process function to process the message if the TX
* buffer has not overflowed.
*/
uint8 endTransmission(void);

/*
* Request bytes from a slave device and process the request,
* storing into the receiving buffer.
*/
uint8 requestFrom(uint8, int);

/*
* Allow only 8 bit addresses to be used when requesting bytes
*/
uint8 requestFrom(int, int);

/*
* Stack up bytes to be sent when transmitting
*/
void write(uint8);

/*
* Stack up bytes from the array to be sent when transmitting
*/
void write(uint8*, int);

/*
* Ensure that a sending data will only be 8-bit bytes
*/
void write(int);

/*
* Ensure that an array sending data will only be 8-bit bytes
*/
void write(int*, int);

/*
* Stack up bytes from a string to be sent when transmitting
*/
void write(char*);

/*
* Return the amount of bytes that is currently in the receiving buffer
*/
uint8 available();

/*
* Return the value of byte in the receiving buffer that is currently being
* pointed to
*/
uint8 read();
};

#endif // _WIREBASE_H_


Stm32.zip > HardWire.h

/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the &quot; Software &quot; ), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED &quot; AS IS &quot; , WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/

/**
* @file HardWire.h
* @author Trystan Jones &amp; lt; crenn6977@gmail.com &amp; gt;
* @brief Wire library, uses the hardware I2C available in the Maple to
* interact with I2C slave devices.
*/

/*
* Library created by crenn to use the new WireBase system and allow Arduino
* users easy interaction with the I2C Hardware in a familiar method.
*/

#ifndef _HARDWIRE_H_
#define _HARDWIRE_H_

#include &quot; WireBase.h &quot;
#include &quot; wirish.h &quot;
#include &amp; lt; libmaple/i2c.h &amp; gt;

class HardWire : public WireBase {
private:
i2c_dev* sel_hard;
uint8 dev_flags;
protected:
/*
* Processes the incoming I2C message defined by WireBase to the
* hardware. If an error occured, restart the I2C device.
*/
uint8 process();
public:
/*
* Check if devsel is within range and enable selected I2C interface with
* passed flags
*/
HardWire(uint8, uint8 = 0);

/*
* Disables the I2C device and remove the device address.
*/
~HardWire();

void begin(uint8 = 0x00);
};
extern HardWire HWire;
#endif // _HARDWIRE_H_


Stm32.zip > INA219.cpp

/*
INA219.cpp - Class file for the INA219 Zero-Drift, Bi-directional Current/Power Monitor Arduino Library.

Version: 1.0.0
(c) 2014 Korneliusz Jarzebski
www.jarzebski.pl

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see &amp; lt; http://www.gnu.org/licenses/ &amp; gt; .
*/

#if ARDUINO &amp; gt; = 100
#include &quot; Arduino.h &quot;
#else
#include &quot; WProgram.h &quot;
#endif

#include &amp; lt; Wire.h &amp; gt;

#include &quot; INA219.h &quot;

bool INA219::begin(uint8_t address)
{
Wire.begin();
inaAddress = address;
return true;
}

bool INA219::configure(ina219_range_t range, ina219_gain_t gain, ina219_busRes_t busRes, ina219_shuntRes_t shuntRes, ina219_mode_t mode)
{
uint16_t config = 0;

config |= (range &amp; lt; &amp; lt; 13 | gain &amp; lt; &amp; lt; 11 | busRes &amp; lt; &amp; lt; 7 | shuntRes &amp; lt; &amp; lt; 3 | mode);

switch(range)
{
case INA219_RANGE_32V:
vBusMax = 32.0f;
break;
case INA219_RANGE_16V:
vBusMax = 16.0f;
break;
}

switch(gain)
{
case INA219_GAIN_320MV:
vShuntMax = 0.32f;
break;
case INA219_GAIN_160MV:
vShuntMax = 0.16f;
break;
case INA219_GAIN_80MV:
vShuntMax = 0.08f;
break;
case INA219_GAIN_40MV:
vShuntMax = 0.04f;
break;
}

writeRegister16(INA219_REG_CONFIG, config);

return true;
}

bool INA219::calibrate(float rShuntValue, float iMaxExpected)
{
uint16_t calibrationValue;
rShunt = rShuntValue;

float iMaxPossible, minimumLSB;

iMaxPossible = vShuntMax / rShunt;

minimumLSB = iMaxExpected / 32767;

currentLSB = (uint16_t)(minimumLSB * 100000000);
currentLSB /= 100000000;
currentLSB /= 0.0001;
currentLSB = ceil(currentLSB);
currentLSB *= 0.0001;

powerLSB = currentLSB * 20;

calibrationValue = (uint16_t)((0.04096) / (currentLSB * rShunt));

writeRegister16(INA219_REG_CALIBRATION, calibrationValue);

return true;
}

float INA219::getMaxPossibleCurrent(void)
{
return (vShuntMax / rShunt);
}

float INA219::getMaxCurrent(void)
{
float maxCurrent = (currentLSB * 32767);
float maxPossible = getMaxPossibleCurrent();

if (maxCurrent &amp; gt; maxPossible)
{
return maxPossible;
} else
{
return maxCurrent;
}
}

float INA219::getMaxShuntVoltage(void)
{
float maxVoltage = getMaxCurrent() * rShunt;

if (maxVoltage &amp; gt; = vShuntMax)
{
return vShuntMax;
} else
{
return maxVoltage;
}
}

float INA219::getMaxPower(void)
{
return (getMaxCurrent() * vBusMax);
}

float INA219::readBusPower(void)
{
return (readRegister16(INA219_REG_POWER) * powerLSB);
}

float INA219::readShuntCurrent(void)
{
return (readRegister16(INA219_REG_CURRENT) * currentLSB);
}

float INA219::readShuntVoltage(void)
{
float voltage;

voltage = readRegister16(INA219_REG_SHUNTVOLTAGE);

return (voltage / 100000);
}

float INA219::readBusVoltage(void)
{
int16_t voltage;

voltage = readRegister16(INA219_REG_BUSVOLTAGE);
voltage &amp; gt; &amp; gt; = 3;

return (voltage * 0.004);
}

ina219_range_t INA219::getRange(void)
{
uint16_t value;

value = readRegister16(INA219_REG_CONFIG);
value &amp; = 0b0010000000000000;
value &amp; gt; &amp; gt; = 13;

return (ina219_range_t)value;
}

ina219_gain_t INA219::getGain(void)
{
uint16_t value;

value = readRegister16(INA219_REG_CONFIG);
value &amp; = 0b0001100000000000;
value &amp; gt; &amp; gt; = 11;

return (ina219_gain_t)value;
}

ina219_busRes_t INA219::getBusRes(void)
{
uint16_t value;

value = readRegister16(INA219_REG_CONFIG);
value &amp; = 0b0000011110000000;
value &amp; gt; &amp; gt; = 7;

return (ina219_busRes_t)value;
}

ina219_shuntRes_t INA219::getShuntRes(void)
{
uint16_t value;

value = readRegister16(INA219_REG_CONFIG);
value &amp; = 0b0000000001111000;
value &amp; gt; &amp; gt; = 3;

return (ina219_shuntRes_t)value;
}

ina219_mode_t INA219::getMode(void)
{
uint16_t value;

value = readRegister16(INA219_REG_CONFIG);
value &amp; = 0b0000000000000111;

return (ina219_mode_t)value;
}

int16_t INA219::readRegister16(uint8_t reg)
{
int16_t value;

Wire.beginTransmission(inaAddress);
#if ARDUINO &amp; gt; = 100
Wire.write(reg);
#else
Wire.send(reg);
#endif
Wire.endTransmission();

delay(1);

Wire.beginTransmission(inaAddress);
Wire.requestFrom(inaAddress, 2);
while(!Wire.available()) {};
#if ARDUINO &amp; gt; = 100
uint8_t vha = Wire.read();
uint8_t vla = Wire.read();
#else
uint8_t vha = Wire.receive();
uint8_t vla = Wire.receive();
#endif;
Wire.endTransmission();

value = vha &amp; lt; &amp; lt; 8 | vla;

return value;
}

void INA219::writeRegister16(uint8_t reg, uint16_t val)
{
uint8_t vla;
vla = (uint8_t)val;
val &amp; gt; &amp; gt; = 8;

Wire.beginTransmission(inaAddress);
#if ARDUINO &amp; gt; = 100
Wire.write(reg);
Wire.write((uint8_t)val);
Wire.write(vla);
#else
Wire.send(reg);
Wire.send((uint8_t)val);
Wire.send(vla);
#endif
Wire.endTransmission();
}


Stm32.zip > Adafruit_SSD1306_STM32.h

/*********************************************************************
This is a library for our Monochrome OLEDs based on SSD1306 drivers

Pick one up today in the adafruit shop!
------ &amp; gt; http://www.adafruit.com/category/63_98

These displays use SPI to communicate, 4 or 5 pins are required to
interface

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above, and the splash screen must be included in any redistribution
*********************************************************************/

#if ARDUINO &amp; gt; = 100
#include &quot; Arduino.h &quot;
#define WIRE_WRITE HWIRE.write
#else
#include &quot; WProgram.h &quot;
#define WIRE_WRITE HWIRE.send
#endif
/*
#ifdef __SAM3X8E__
typedef volatile RwReg PortReg;
typedef uint32_t PortMask;
#else
typedef volatile uint8_t PortReg;
typedef uint8_t PortMask;
#endif
*/
//typedef volatile RwReg PortReg;
// typedef uint32_t PortMask;
#include &amp; lt; SPI.h &amp; gt;
#include &amp; lt; Adafruit_GFX.h &amp; gt;

#define BLACK 0
#define WHITE 1
#define INVERSE 2

#define SSD1306_I2C_ADDRESS 0x3C // 011110+SA0+RW - 0x3C or 0x3D
// Address for 128x32 is 0x3C
// Address for 128x64 is 0x3D (default) or 0x3C (if SA0 is grounded)

/*=========================================================================
SSD1306 Displays
-----------------------------------------------------------------------
The driver is used in multiple displays (128x64, 128x32, etc.).
Select the appropriate display below to create an appropriately
sized framebuffer, etc.

SSD1306_128_64 128x64 pixel display

SSD1306_128_32 128x32 pixel display

SSD1306_96_16

-----------------------------------------------------------------------*/
#define SSD1306_128_64
// #define SSD1306_128_32
// #define SSD1306_96_16
/*=========================================================================*/

#if defined SSD1306_128_64 &amp; &amp; defined SSD1306_128_32
#error &quot; Only one SSD1306 display can be specified at once in SSD1306.h &quot;
#endif
#if !defined SSD1306_128_64 &amp; &amp; !defined SSD1306_128_32 &amp; &amp; !defined SSD1306_96_16
#error &quot; At least one SSD1306 display must be specified in SSD1306.h &quot;
#endif

#if defined SSD1306_128_64
#define SSD1306_LCDWIDTH 128
#define SSD1306_LCDHEIGHT 64
#endif
#if defined SSD1306_128_32
#define SSD1306_LCDWIDTH 128
#define SSD1306_LCDHEIGHT 32
#endif
#if defined SSD1306_96_16
#define SSD1306_LCDWIDTH 96
#define SSD1306_LCDHEIGHT 16
#endif

#define SSD1306_SETCONTRAST 0x81
#define SSD1306_DISPLAYALLON_RESUME 0xA4
#define SSD1306_DISPLAYALLON 0xA5
#define SSD1306_NORMALDISPLAY 0xA6
#define SSD1306_INVERTDISPLAY 0xA7
#define SSD1306_DISPLAYOFF 0xAE
#define SSD1306_DISPLAYON 0xAF

#define SSD1306_SETDISPLAYOFFSET 0xD3
#define SSD1306_SETCOMPINS 0xDA

#define SSD1306_SETVCOMDETECT 0xDB

#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
#define SSD1306_SETPRECHARGE 0xD9

#define SSD1306_SETMULTIPLEX 0xA8

#define SSD1306_SETLOWCOLUMN 0x00
#define SSD1306_SETHIGHCOLUMN 0x10

#define SSD1306_SETSTARTLINE 0x40

#define SSD1306_MEMORYMODE 0x20
#define SSD1306_COLUMNADDR 0x21
#define SSD1306_PAGEADDR 0x22

#define SSD1306_COMSCANINC 0xC0
#define SSD1306_COMSCANDEC 0xC8

#define SSD1306_SEGREMAP 0xA0

#define SSD1306_CHARGEPUMP 0x8D

#define SSD1306_EXTERNALVCC 0x1
#define SSD1306_SWITCHCAPVCC 0x2

// Scrolling #defines
#define SSD1306_ACTIVATE_SCROLL 0x2F
#define SSD1306_DEACTIVATE_SCROLL 0x2E
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3
#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A

class Adafruit_SSD1306 : public Adafruit_GFX {
public:
Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS);
Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS);
Adafruit_SSD1306(int8_t RST);

void begin(uint8_t switchvcc = SSD1306_SWITCHCAPVCC, uint8_t i2caddr = SSD1306_I2C_ADDRESS, bool reset=true);
void ssd1306_command(uint8_t c);
void ssd1306_data(uint8_t c);

void clearDisplay(void);
void invertDisplay(uint8_t i);
void display();

void startscrollright(uint8_t start, uint8_t stop);
void startscrollleft(uint8_t start, uint8_t stop);

void startscrolldiagright(uint8_t start, uint8_t stop);
void startscrolldiagleft(uint8_t start, uint8_t stop);
void stopscroll(void);

void dim(boolean dim);

void drawPixel(int16_t x, int16_t y, uint16_t color);

virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);

private:
int8_t _i2caddr, _vccstate, sid, sclk, dc, rst, cs;
void fastSPIwrite(uint8_t c);

boolean hwSPI;
volatile uint32 *mosiport, *clkport, *csport, *dcport;
uint32_t mosipinmask, clkpinmask, cspinmask, dcpinmask;

inline void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline));
inline void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) __attribute__((always_inline));

};


Stm32.zip > Adafruit_SSD1306_STM32.cpp

/*********************************************************************
This is a library for our Monochrome OLEDs based on SSD1306 drivers

Pick one up today in the adafruit shop!
------ &amp; gt; http://www.adafruit.com/category/63_98

These displays use SPI to communicate, 4 or 5 pins are required to
interface

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada for Adafruit Industries.
BSD license, check license.txt for more information
All text above, and the splash screen below must be included in any redistribution
*********************************************************************/

#include &amp; lt; avr/pgmspace.h &amp; gt;
//#ifndef __SAM3X8E__ || __STM32F1__
//#include &amp; lt; util/delay.h &amp; gt;
//#endif
#include &amp; lt; stdlib.h &amp; gt;

//#include &amp; lt; HWIRE.h &amp; gt;
#include &amp; lt; HardWire.h &amp; gt;

HardWire HWIRE(1,I2C_FAST_MODE); // I2c2
#include &quot; Adafruit_GFX.h &quot;
#include &quot; Adafruit_SSD1306_STM32.h &quot;

// the memory buffer for the LCD

static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = {
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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x80, 0xC0, 0xC0, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF,
#if (SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH &amp; gt; 96*16)
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00,
0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8,
0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80,
0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01,
0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF,
0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00,
0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF,
0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF,
0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F,
0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC,
0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03,
0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01,
0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00,
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03,
0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#if (SSD1306_LCDHEIGHT == 64)
0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F,
0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F,
0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00,
0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E,
0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC,
0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06,
0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8,
0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C,
0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F,
0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00,
0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07,
0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07,
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, 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, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
#endif
#endif
};



// the most basic function, set a single pixel
void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) {
if ((x &amp; lt; 0) || (x &amp; gt; = width()) || (y &amp; lt; 0) || (y &amp; gt; = 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
switch (color)
{
case WHITE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 &amp; lt; &amp; lt; (y &amp; 7)); break;
case BLACK: buffer[x+ (y/8)*SSD1306_LCDWIDTH] &amp; = ~(1 &amp; lt; &amp; lt; (y &amp; 7)); break;
case INVERSE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] ^= (1 &amp; lt; &amp; lt; (y &amp; 7)); break;
}

}

Adafruit_SSD1306::Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) {
cs = CS;
rst = RST;
dc = DC;
sclk = SCLK;
sid = SID;
hwSPI = false;
}

// constructor for hardware SPI - we indicate DataCommand, ChipSelect, Reset
Adafruit_SSD1306::Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) {
dc = DC;
rst = RST;
cs = CS;
hwSPI = true;
}

// initializer for I2C - we only indicate the reset pin!
Adafruit_SSD1306::Adafruit_SSD1306(int8_t reset) :
Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) {
sclk = dc = cs = sid = -1;
rst = reset;
}


void Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) {
_vccstate = vccstate;
_i2caddr = i2caddr;

// set pin directions
if (sid != -1){
pinMode(dc, OUTPUT);
pinMode(cs, OUTPUT);
csport = portOutputRegister(digitalPinToPort(cs));
cspinmask = digitalPinToBitMask(cs);
dcport = portOutputRegister(digitalPinToPort(dc));
dcpinmask = digitalPinToBitMask(dc);
if (!hwSPI){
// set pins for software-SPI
pinMode(sid, OUTPUT);
pinMode(sclk, OUTPUT);
clkport = portOutputRegister(digitalPinToPort(sclk));
clkpinmask = digitalPinToBitMask(sclk);
mosiport = portOutputRegister(digitalPinToPort(sid));
mosipinmask = digitalPinToBitMask(sid);
}
if (hwSPI){
SPI.begin ();
//#ifdef __SAM3X8E__
SPI.setClockDivider (9); // 9.3 MHz
//#else
// SPI.setClockDivider (SPI_CLOCK_DIV2); // 8 MHz
//#endif
}
}
else
{
// I2C Init
HWIRE.begin();

#ifdef __SAM3X8E__
// Force 400 KHz I2C, rawr! (Uses pins 20, 21 for SDA, SCL)
TWI1- &amp; gt; TWI_CWGR = 0;
TWI1- &amp; gt; TWI_CWGR = ((VARIANT_MCK / (2 * 400000)) - 4) * 0x101;
#endif
}

if (reset) {
// 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 SSD1306_128_32
// Init sequence for 128x32 OLED module
ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
ssd1306_command(0x80); // the suggested ratio 0x80
ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8
ssd1306_command(0x1F);
ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3
ssd1306_command(0x0); // no offset
ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x10); }
else
{ ssd1306_command(0x14); }
ssd1306_command(SSD1306_MEMORYMODE); // 0x20
ssd1306_command(0x00); // 0x0 act like ks0108
ssd1306_command(SSD1306_SEGREMAP | 0x1);
ssd1306_command(SSD1306_COMSCANDEC);
ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
ssd1306_command(0x02);
ssd1306_command(SSD1306_SETCONTRAST); // 0x81
ssd1306_command(0x8F);
ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x22); }
else
{ ssd1306_command(0xF1); }
ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB
ssd1306_command(0x40);
ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
#endif

#if defined SSD1306_128_64
// Init sequence for 128x64 OLED module
ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
ssd1306_command(0x80); // the suggested ratio 0x80
ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8
ssd1306_command(0x3F);
ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3
ssd1306_command(0x0); // no offset
ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x10); }
else
{ ssd1306_command(0x14); }
ssd1306_command(SSD1306_MEMORYMODE); // 0x20
ssd1306_command(0x00); // 0x0 act like ks0108
ssd1306_command(SSD1306_SEGREMAP | 0x1);
ssd1306_command(SSD1306_COMSCANDEC);
ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
ssd1306_command(0x12);
ssd1306_command(SSD1306_SETCONTRAST); // 0x81
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x9F); }
else
{ ssd1306_command(0xCF); }
ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x22); }
else
{ ssd1306_command(0xF1); }
ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB
ssd1306_command(0x40);
ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
#endif

#if defined SSD1306_96_16
// Init sequence for 96x16 OLED module
ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE
ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
ssd1306_command(0x80); // the suggested ratio 0x80
ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8
ssd1306_command(0x0F);
ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3
ssd1306_command(0x00); // no offset
ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0
ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x10); }
else
{ ssd1306_command(0x14); }
ssd1306_command(SSD1306_MEMORYMODE); // 0x20
ssd1306_command(0x00); // 0x0 act like ks0108
ssd1306_command(SSD1306_SEGREMAP | 0x1);
ssd1306_command(SSD1306_COMSCANDEC);
ssd1306_command(SSD1306_SETCOMPINS); // 0xDA
ssd1306_command(0x2); //ada x12
ssd1306_command(SSD1306_SETCONTRAST); // 0x81
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x10); }
else
{ ssd1306_command(0xAF); }
ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9
if (vccstate == SSD1306_EXTERNALVCC)
{ ssd1306_command(0x22); }
else
{ ssd1306_command(0xF1); }
ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB
ssd1306_command(0x40);
ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4
ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6
#endif

ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel
}


void Adafruit_SSD1306::invertDisplay(uint8_t i) {
if (i) {
ssd1306_command(SSD1306_INVERTDISPLAY);
} else {
ssd1306_command(SSD1306_NORMALDISPLAY);
}
}

void Adafruit_SSD1306::ssd1306_command(uint8_t c) {
if (sid != -1)
{
// SPI
//digitalWrite(cs, HIGH);
*csport |= cspinmask;
//digitalWrite(dc, LOW);
*dcport &amp; = ~dcpinmask;
//digitalWrite(cs, LOW);
*csport &amp; = ~cspinmask;
fastSPIwrite(c);
//digitalWrite(cs, HIGH);
*csport |= cspinmask;
}
else
{
// I2C
uint8_t control = 0x00; // Co = 0, D/C = 0
HWIRE.beginTransmission(_i2caddr);
WIRE_WRITE(control);
WIRE_WRITE(c);
HWIRE.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_SSD1306::startscrollright(uint8_t start, uint8_t stop){
ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL);
ssd1306_command(0X00);
ssd1306_command(start);
ssd1306_command(0X00);
ssd1306_command(stop);
ssd1306_command(0X00);
ssd1306_command(0XFF);
ssd1306_command(SSD1306_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_SSD1306::startscrollleft(uint8_t start, uint8_t stop){
ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL);
ssd1306_command(0X00);
ssd1306_command(start);
ssd1306_command(0X00);
ssd1306_command(stop);
ssd1306_command(0X00);
ssd1306_command(0XFF);
ssd1306_command(SSD1306_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_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){
ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
ssd1306_command(0X00);
ssd1306_command(SSD1306_LCDHEIGHT);
ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
ssd1306_command(0X00);
ssd1306_command(start);
ssd1306_command(0X00);
ssd1306_command(stop);
ssd1306_command(0X01);
ssd1306_command(SSD1306_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_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){
ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
ssd1306_command(0X00);
ssd1306_command(SSD1306_LCDHEIGHT);
ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
ssd1306_command(0X00);
ssd1306_command(start);
ssd1306_command(0X00);
ssd1306_command(stop);
ssd1306_command(0X01);
ssd1306_command(SSD1306_ACTIVATE_SCROLL);
}

void Adafruit_SSD1306::stopscroll(void){
ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
}

// Dim the display
// dim = true: display is dimmed
// dim = false: display is normal
void Adafruit_SSD1306::dim(boolean dim) {
uint8_t contrast;

if (dim) {
contrast = 0; // Dimmed display
} else {
if (_vccstate == SSD1306_EXTERNALVCC) {
contrast = 0x9F;
} else {
contrast = 0xCF;
}
}
// the range of contrast to too small to be really useful
// it is useful to dim the display
ssd1306_command(SSD1306_SETCONTRAST);
ssd1306_command(contrast);
}

void Adafruit_SSD1306::ssd1306_data(uint8_t c) {
if (sid != -1)
{
// SPI
//digitalWrite(cs, HIGH);
*csport |= cspinmask;
//digitalWrite(dc, HIGH);
*dcport |= dcpinmask;
//digitalWrite(cs, LOW);
*csport &amp; = ~cspinmask;
fastSPIwrite(c);
//digitalWrite(cs, HIGH);
*csport |= cspinmask;
}
else
{
// I2C
uint8_t control = 0x40; // Co = 0, D/C = 1
HWIRE.beginTransmission(_i2caddr);
WIRE_WRITE(control);
WIRE_WRITE(c);
HWIRE.endTransmission();
}
}

void Adafruit_SSD1306::display(void) {
ssd1306_command(SSD1306_COLUMNADDR);
ssd1306_command(0); // Column start address (0 = reset)
ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset)

ssd1306_command(SSD1306_PAGEADDR);
ssd1306_command(0); // Page start address (0 = reset)
#if SSD1306_LCDHEIGHT == 64
ssd1306_command(7); // Page end address
#endif
#if SSD1306_LCDHEIGHT == 32
ssd1306_command(3); // Page end address
#endif
#if SSD1306_LCDHEIGHT == 16
ssd1306_command(1); // Page end address
#endif

if (sid != -1)
{
// SPI
*csport |= cspinmask;
*dcport |= dcpinmask;
*csport &amp; = ~cspinmask;

for (uint16_t i=0; i &amp; lt; (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {
fastSPIwrite(buffer[i]);
//ssd1306_data(buffer[i]);
}
*csport |= cspinmask;
}
else
{
// save I2C bitrate
/*
#ifndef __SAM3X8E__
uint8_t twbrbackup = TWBR;
TWBR = 12; // upgrade to 400KHz!
#endif
*/
//Serial.println(TWBR, DEC);
//Serial.println(TWSR &amp; 0x3, DEC);

// I2C
for (uint16_t i=0; i &amp; lt; (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {
// send a bunch of data in one xmission
HWIRE.beginTransmission(_i2caddr);
WIRE_WRITE(0x40);
for (uint8_t x=0; x &amp; lt; 16; x++) {
WIRE_WRITE(buffer[i]);
i++;
}
i--;
HWIRE.endTransmission();
}
/*
#ifndef __SAM3X8E__
TWBR = twbrbackup;
#endif
*/
}
}

// clear everything
void Adafruit_SSD1306::clearDisplay(void) {
memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8));
}


inline void Adafruit_SSD1306::fastSPIwrite(uint8_t d) {

if(hwSPI) {
(void)SPI.transfer(d);
} else {
for(uint8_t bit = 0x80; bit; bit &amp; gt; &amp; gt; = 1) {
*clkport &amp; = ~clkpinmask;
if(d &amp; bit) *mosiport |= mosipinmask;
else *mosiport &amp; = ~mosipinmask;
*clkport |= clkpinmask;
}
}
//*csport |= cspinmask;
}

void Adafruit_SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
boolean bSwap = false;
switch(rotation) {
case 0:
// 0 degree rotation, do nothing
break;
case 1:
// 90 degree rotation, swap x &amp; y for rotation, then invert x
bSwap = true;
swap(x, y);
x = WIDTH - x - 1;
break;
case 2:
// 180 degree rotation, invert x and y - then shift y around for height.
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
x -= (w-1);
break;
case 3:
// 270 degree rotation, swap x &amp; y for rotation, then invert y and adjust y for w (not to become h)
bSwap = true;
swap(x, y);
y = HEIGHT - y - 1;
y -= (w-1);
break;
}

if(bSwap) {
drawFastVLineInternal(x, y, w, color);
} else {
drawFastHLineInternal(x, y, w, color);
}
}

void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) {
// Do bounds/limit checks
if(y &amp; lt; 0 || y &amp; gt; = HEIGHT) { return; }

// make sure we don't try to draw below 0
if(x &amp; lt; 0) {
w += x;
x = 0;
}

// make sure we don't go off the edge of the display
if( (x + w) &amp; gt; WIDTH) {
w = (WIDTH - x);
}

// if our width is now negative, punt
if(w &amp; lt; = 0) { return; }

// set up the pointer for movement through the buffer
register uint8_t *pBuf = buffer;
// adjust the buffer pointer for the current row
pBuf += ((y/8) * SSD1306_LCDWIDTH);
// and offset x columns in
pBuf += x;

register uint8_t mask = 1 &amp; lt; &amp; lt; (y &amp; 7);

switch (color)
{
case WHITE: while(w--) { *pBuf++ |= mask; }; break;
case BLACK: mask = ~mask; while(w--) { *pBuf++ &amp; = mask; }; break;
case INVERSE: while(w--) { *pBuf++ ^= mask; }; break;
}
}

void Adafruit_SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
bool bSwap = false;
switch(rotation) {
case 0:
break;
case 1:
// 90 degree rotation, swap x &amp; y for rotation, then invert x and adjust x for h (now to become w)
bSwap = true;
swap(x, y);
x = WIDTH - x - 1;
x -= (h-1);
break;
case 2:
// 180 degree rotation, invert x and y - then shift y around for height.
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
y -= (h-1);
break;
case 3:
// 270 degree rotation, swap x &amp; y for rotation, then invert y
bSwap = true;
swap(x, y);
y = HEIGHT - y - 1;
break;
}

if(bSwap) {
drawFastHLineInternal(x, y, h, color);
} else {
drawFastVLineInternal(x, y, h, color);
}
}


void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) {

// do nothing if we're off the left or right side of the screen
if(x &amp; lt; 0 || x &amp; gt; = WIDTH) { return; }

// make sure we don't try to draw below 0
if(__y &amp; lt; 0) {
// __y is negative, this will subtract enough from __h to account for __y being 0
__h += __y;
__y = 0;

}

// make sure we don't go past the height of the display
if( (__y + __h) &amp; gt; HEIGHT) {
__h = (HEIGHT - __y);
}

// if our height is now negative, punt
if(__h &amp; lt; = 0) {
return;
}

// this display doesn't need ints for coordinates, use local byte registers for faster juggling
register uint8_t y = __y;
register uint8_t h = __h;


// set up the pointer for fast movement through the buffer
register uint8_t *pBuf = buffer;
// adjust the buffer pointer for the current row
pBuf += ((y/8) * SSD1306_LCDWIDTH);
// and offset x columns in
pBuf += x;

// do the first partial byte, if necessary - this requires some masking
register uint8_t mod = (y &amp; 7);
if(mod) {
// mask off the high n bits we want to set
mod = 8-mod;

// note - lookup table results in a nearly 10% performance improvement in fill* functions
// register uint8_t mask = ~(0xFF &amp; gt; &amp; gt; (mod));
static uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE };
register uint8_t mask = premask[mod];

// adjust the mask if we're not going to reach the end of this byte
if( h &amp; lt; mod) {
mask &amp; = (0XFF &amp; gt; &amp; gt; (mod-h));
}

switch (color)
{
case WHITE: *pBuf |= mask; break;
case BLACK: *pBuf &amp; = ~mask; break;
case INVERSE: *pBuf ^= mask; break;
}

// fast exit if we're done here!
if(h &amp; lt; mod) { return; }

h -= mod;

pBuf += SSD1306_LCDWIDTH;
}


// write solid bytes while we can - effectively doing 8 rows at a time
if(h &amp; gt; = 8) {
if (color == INVERSE) { // separate copy of the code so we don't impact performance of the black/white write version with an extra comparison per loop
do {
*pBuf=~(*pBuf);

// adjust the buffer forward 8 rows worth of data
pBuf += SSD1306_LCDWIDTH;

// adjust h &amp; y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
h -= 8;
} while(h &amp; gt; = 8);
}
else {
// store a local value to work with
register uint8_t val = (color == WHITE) ? 255 : 0;

do {
// write our value in
*pBuf = val;

// adjust the buffer forward 8 rows worth of data
pBuf += SSD1306_LCDWIDTH;

// adjust h &amp; y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
h -= 8;
} while(h &amp; gt; = 8);
}
}

// now do the final partial byte, if necessary
if(h) {
mod = h &amp; 7;
// this time we want to mask the low bits of the byte, vs the high bits we did above
// register uint8_t mask = (1 &amp; lt; &amp; lt; mod) - 1;
// note - lookup table results in a nearly 10% performance improvement in fill* functions
static uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F };
register uint8_t mask = postmask[mod];
switch (color)
{
case WHITE: *pBuf |= mask; break;
case BLACK: *pBuf &amp; = ~mask; break;
case INVERSE: *pBuf ^= mask; break;
}
}
}


Stm32.zip > README.txt

This is a library for our Monochrome OLEDs based on SSD1306 drivers

Pick one up today in the adafruit shop!
------ &amp; gt; http://www.adafruit.com/category/63_98

These displays use SPI to communicate, 4 or 5 pins are required to
interface

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada for Adafruit Industries.
Scrolling code contributed by Michael Gregg
BSD license, check license.txt for more information
All text above must be included in any redistribution

To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_SSD1306. Check that the Adafruit_SSD1306 folder contains Adafruit_SSD1306.cpp and Adafruit_SSD1306.h

Place the Adafruit_SSD1306 library folder your &amp; lt; arduinosketchfolder &amp; gt; /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE.

You will also have to download the Adafruit GFX Graphics core which does all the circles, text, rectangles, etc. You can get it from
https://github.com/adafruit/Adafruit-GFX-Library
and download/install that library as well