Raspberry Pi 3 + OLED 128x64 display

Example code of connecting Raspberry Pi with the Adafruit OLED 128x64 pixels. I am simulating the SPI communication in software.

Video

Please click thumbnail image to start the video

Video on Raspberry Pi 3 + OLED 128x64 display    iconSPI.png

Photo

Raspberry Pi 3 + OLED 128x64 display
Raspberry Pi 3 + OLED 128x64 display
Raspberry Pi 3 + OLED 128x64 display
Raspberry Pi 3 + OLED 128x64 display
Raspberry Pi 3 + OLED 128x64 display
Raspberry Pi 3 + OLED 128x64 display

Sketch

// Raspberry Pi 3 with OLED 128x64 display (software SPI)
// Copyright (C) 2021 https://www.roboticboat.uk
// cac93a5b-3ce1-4477-a224-0395d2a6f3a8
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// 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 <https://www.gnu.org/licenses/>.
// These Terms shall be governed and construed in accordance with the laws of
// England and Wales, without regard to its conflict of law provisions.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h> // bool variable
#include <stdlib.h> // atoi function
#include <unistd.h> // usleep
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define BYTE_SIZE 8
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define OLED_BYTE_ROWS 8 // OLED_HEIGHT/BYTE_SIZE
#define FONT_WIDTH 5
#define FONT_HEIGHT 8
#define HIGH true
#define LOW false
#define INPUT true
#define OUTPUT false
// Allocate memory to store the screen pixels
// On the OLED the screenbuffer appears as a series of 1 bit wide, 8 bit high, vertical bars.
// Starting in the top left, the bars are displayed left to right, then the next row
// I call the 8 bits high row as a ByteRow
static unsigned char screenbuffer[OLED_WIDTH * OLED_BYTE_ROWS] = {0};
static const unsigned char fonttable[] = {
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x1C, 0x22, 0x41, 0x00, // (
0x00, 0x41, 0x22, 0x1C, 0x00, // )
0x2A, 0x1C, 0x7F, 0x1C, 0x2A, // *
0x08, 0x08, 0x3E, 0x08, 0x08, // +
0x00, 0x80, 0x70, 0x30, 0x00, // ,
0x08, 0x08, 0x08, 0x08, 0x08, // -
0x00, 0x00, 0x60, 0x60, 0x00, // .
0x20, 0x10, 0x08, 0x04, 0x02, // /
0x3E, 0x41, 0x41, 0x41, 0x3E, // 0
0x00, 0x00, 0x7F, 0x00, 0x00, // 1
0x72, 0x49, 0x49, 0x49, 0x46, // 2
0x22, 0x41, 0x49, 0x49, 0x36, // 3
0x18, 0x14, 0x12, 0x7F, 0x10, // 4
0x4F, 0x49, 0x49, 0x49, 0x31, // 5
0x3E, 0x49, 0x49, 0x49, 0x32, // 6
0x01, 0x71, 0x09, 0x09, 0x07, // 7
0x36, 0x49, 0x49, 0x49, 0x36, // 8
0x26, 0x49, 0x49, 0x49, 0x3E, // 9
0x00, 0x00, 0x14, 0x00, 0x00, // :
0x00, 0x40, 0x34, 0x00, 0x00, // ;
0x00, 0x08, 0x14, 0x22, 0x41, // <
0x14, 0x14, 0x14, 0x14, 0x14, // =
0x00, 0x41, 0x22, 0x14, 0x08, // >
0x02, 0x01, 0x59, 0x09, 0x06, // ?
0x3E, 0x41, 0x5D, 0x59, 0x4E, // @
0x7E, 0x11, 0x11, 0x11, 0x7E, // A
0x7F, 0x49, 0x49, 0x49, 0x36, // B
0x3E, 0x41, 0x41, 0x41, 0x22, // C
0x7F, 0x41, 0x41, 0x41, 0x3E, // D
0x7F, 0x49, 0x49, 0x49, 0x41, // E
0x7F, 0x09, 0x09, 0x09, 0x01, // F
0x3E, 0x41, 0x41, 0x49, 0x3A, // G
0x7F, 0x08, 0x08, 0x08, 0x7F, // H
0x00, 0x41, 0x7F, 0x41, 0x00, // I
0x20, 0x40, 0x41, 0x3F, 0x01, // J
0x7F, 0x08, 0x14, 0x22, 0x41, // K
0x7F, 0x40, 0x40, 0x40, 0x40, // L
0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
0x7F, 0x04, 0x08, 0x10, 0x7F, // N
0x3E, 0x41, 0x41, 0x41, 0x3E, // O
0x7F, 0x09, 0x09, 0x09, 0x06, // P
0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
0x7F, 0x09, 0x19, 0x29, 0x46, // R
0x26, 0x49, 0x49, 0x49, 0x32, // S
0x01, 0x01, 0x7F, 0x01, 0x01, // T
0x3F, 0x40, 0x40, 0x40, 0x3F, // U
0x1F, 0x20, 0x40, 0x20, 0x1F, // V
0x3F, 0x40, 0x38, 0x40, 0x3F, // W
0x63, 0x14, 0x08, 0x14, 0x63, // X
0x03, 0x04, 0x78, 0x04, 0x03, // Y
0x61, 0x51, 0x49, 0x45, 0x43, // Z
0x00, 0x7F, 0x41, 0x41, 0x41, // [
0x02, 0x04, 0x08, 0x10, 0x20, //
0x00, 0x41, 0x41, 0x41, 0x7F, // ]
0x04, 0x02, 0x01, 0x02, 0x04, // ^
0x40, 0x40, 0x40, 0x40, 0x40, // _
0x00, 0x03, 0x07, 0x08, 0x00, // `
0x20, 0x54, 0x54, 0x78, 0x40, // a
0x7F, 0x28, 0x44, 0x44, 0x38, // b
0x38, 0x44, 0x44, 0x44, 0x28, // c
0x38, 0x44, 0x44, 0x28, 0x7F, // d
0x38, 0x54, 0x54, 0x54, 0x18, // e
0x00, 0x08, 0x7E, 0x09, 0x02, // f
0x18, 0xA4, 0xA4, 0x9C, 0x78, // g
0x7F, 0x08, 0x04, 0x04, 0x78, // h
0x00, 0x44, 0x7D, 0x40, 0x00, // i
0x20, 0x40, 0x40, 0x3D, 0x00, // j
0x7F, 0x10, 0x28, 0x44, 0x00, // k
0x00, 0x41, 0x7F, 0x40, 0x00, // l
0x7C, 0x04, 0x78, 0x04, 0x78, // m
0x7C, 0x08, 0x04, 0x04, 0x78, // n
0x38, 0x44, 0x44, 0x44, 0x38, // o
0xFC, 0x18, 0x24, 0x24, 0x18, // p
0x18, 0x24, 0x24, 0x18, 0xFC, // q
0x7C, 0x08, 0x04, 0x04, 0x08, // r
0x48, 0x54, 0x54, 0x54, 0x24, // s
0x04, 0x04, 0x3F, 0x44, 0x24, // t
0x3C, 0x40, 0x40, 0x20, 0x7C, // u
0x1C, 0x20, 0x40, 0x20, 0x1C, // v
0x3C, 0x40, 0x30, 0x40, 0x3C, // w
0x44, 0x28, 0x10, 0x28, 0x44, // x
0x4C, 0x90, 0x90, 0x90, 0x7C, // y
0x44, 0x64, 0x54, 0x4C, 0x44, // z
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x14, 0x08, 0x14, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00
};
int8_t _i2caddr;
int16_t _positionx;
int16_t _positiony;
unsigned char _textsize = 1;
FILE* sid;
FILE* sclk;
FILE* dc;
FILE* rst;
FILE* cs;
// Define function signatures
void spi_command(unsigned char);
void fastSPIwrite(unsigned char);
void digitalWrite(FILE*, bool);
FILE* pinMode(int, bool);
void setPosition(int16_t, int16_t);
void updateDisplay(void);
void updatePixel(int16_t, int16_t);
void clearDisplay(void);
void println(const char c[]);
void setTextSize(unsigned char s);
void drawChar(int16_t x, int16_t y, unsigned char c, unsigned char size);
size_t writeOLED(unsigned char c);
void begin() ;
int main(){
// Initialize with the SPI (for the 128x64)
// Please note this is software driven SPI
// White wire = GPIO18 = MOSI (note MISO not used)
// Blue wire = GPIO22 = Clock
// Green wire = GPIO27 = Data/Command flag
// Yellow wire = GPIO17 = Reset
// Purple wire = GPIO04 = Chip Select
// Orange wire = 3.3v
// Black wire = GND
begin();
while(1){
clearDisplay();
setPosition(0,0);
setTextSize(4);
println("Hello");
println("Size4");
updateDisplay();
usleep(1000000);
clearDisplay();
setPosition(0,0);
setTextSize(3);
println("Hello");
println("Size 3");
updateDisplay();
usleep(1000000);
clearDisplay();
setPosition(0,0);
setTextSize(2);
println("HelloWorld");
println("0123456789");
println("Size 2");
updateDisplay();
usleep(1000000);
clearDisplay();
setPosition(0,0);
setTextSize(1);
println("HelloWorld");
println("0123456789");
println("ABCDEFGHIJKLMNOPQRSTU");
println("VXWXY");
println("abcdefghijklmnopqrstu");
println("vwxyz");
println("seventh row");
println("Size 1");
updateDisplay();
usleep(1000000);
}
return 0;
}
void spi_command(unsigned char cmd)
{
//startTransmission
digitalWrite(cs, HIGH);
digitalWrite(dc, LOW);
digitalWrite(cs, LOW);
//Send the instructions
fastSPIwrite(cmd);
//endTransmission
digitalWrite(cs, HIGH);
}
void fastSPIwrite(unsigned char d) {
for(unsigned char bit = 0x80; bit; bit >>= 1)
{
digitalWrite(sclk, LOW);
if(d & bit){
digitalWrite(sid, HIGH);
}
else{
digitalWrite(sid, LOW);
}
digitalWrite(sclk, HIGH);
}
}
void begin() {
_positionx = 0;
_positiony = 0;
// Setup the output pins
cs = pinMode(4, OUTPUT); // Purple
rst = pinMode(17, OUTPUT); // Yellow
sid = pinMode(18, OUTPUT); // White - MOSI
sclk = pinMode(22, OUTPUT); // Blue - Clock
dc = pinMode(27, OUTPUT); // Green
// Set reset high
digitalWrite(rst, HIGH);
// VDD (3.3V) goes high at start
usleep(100000);
// Set reset low
digitalWrite(rst, LOW);
// wait 100ms
usleep(100000);
// Set reset high
digitalWrite(rst, HIGH);
// Initialization procedure
// Set Display Off
spi_command(0xAE);
// Set Display Clock Ratio
spi_command(0xD5);
// Set Display Clock Oscillator Frequency
spi_command(0x80);
// Set Multiplex Ratio
spi_command(0xA8);
spi_command(OLED_HEIGHT - 1);
// Set Display Offset
spi_command(0xD3);
spi_command(0x00);
// Set Display Start Line
spi_command(0x40);
// Set Charge Pump Regulator
spi_command(0x8D);
spi_command(0x14);
// Set Low Power Display Mode
spi_command(0xD8);
spi_command(0x05);
// There are 3 different memory addressing mode in SSD1306:
// page, horizontal and vertical addressing mode
spi_command(0x20);
spi_command(0x00);
// Set Segment Re-Map
spi_command(0xA1);
// Set COM Output Scan Direction
spi_command(0xC8);
// Set COM Pins Hardware Configuration
spi_command(0xDA);
// 128x32 display set = 0x02
// 128x64 display set = 0x12. Otherwise alternate blank rows
spi_command(0x12);
// Set Contract Control
spi_command(0x81);
spi_command(0x8F);
// Set Pre-Charge Period
spi_command(0xD9);
spi_command(0xF1);
// Set VCOMH Deselect Level
spi_command(0xDB);
spi_command(0x40);
// Set Entire Display On & Resume
spi_command(0xA4);
// Set Normal/Inverse Display
spi_command(0xA6);
// Set Display On
spi_command(0xAF);
usleep(100000);
// Set Column Address
// This triple byte command specifies column start address and
// end address of the display data RAM
spi_command(0x21);
spi_command(0);
spi_command(OLED_WIDTH-1);
// Set Page Address
// This triple byte command specifies page start address and
// end address of the display data RAM.
spi_command(0x22);
spi_command(0);
spi_command(OLED_HEIGHT/FONT_HEIGHT - 1);
}
void setPosition(int16_t x, int16_t y) {
_positionx = x;
_positiony = y;
}
void updateDisplay(void)
{
//startTransmission
digitalWrite(cs, HIGH);
digitalWrite(dc, HIGH);
digitalWrite(cs, LOW);
for (int16_t i=0; i<(OLED_WIDTH * OLED_BYTE_ROWS); i++)
{
fastSPIwrite(screenbuffer[i]);
}
//endTransmission
digitalWrite(cs, HIGH);
}
size_t writeOLED(unsigned char c) {
if (c == '\r') return 1;
// Newline?
if(c == '\n')
{
// Set to the start of the row
_positionx = 0;
// Move to the next row
_positiony = _positiony + _textsize * FONT_HEIGHT;
}
else
{
// Too far to the right?
if ((_positionx + _textsize * (FONT_WIDTH +1)) > OLED_WIDTH)
{
// Set to the start of the row
_positionx = 0;
// Move to the next row
_positiony = _positiony + _textsize * FONT_HEIGHT;
}
// Print the character to the screen
drawChar(_positionx, _positiony, c, _textsize);
// Advance 1 character position
_positionx = _positionx + _textsize * (FONT_WIDTH +1);
}
return 1;
}
void drawChar(int16_t x, int16_t y, unsigned char c, unsigned char size) {
// Check pixel is within the screen area
if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT) || ((x + size*(FONT_WIDTH+1)-1) < 0) || ((y + size*FONT_HEIGHT-1) < 0)) return;
// Characters are 5 bits wide and have a separating blank bit
for(int8_t i=0; i < FONT_WIDTH; i++ )
{
unsigned char mybyte = pgm_read_byte(&fonttable[c * FONT_WIDTH + i]);
// Loop over the height of the font
for(int8_t j=0; j<FONT_HEIGHT; j++)
{
// Bitwise operator AND
// 1100110x mybyte say.
// 00000001 (e.g. 1) picks up the last digit 'x'
if (mybyte & 1)
{
if (size > 0)
{
// Update one pixel in memory
// x
updatePixel(x + i*size, y + j*size);
}
if (size > 1)
{
// Increase square to be 1 bit wider and 1 bit higher
// x X
// X X
updatePixel(x + i*size+1, y + j*size);
// Bottom row
updatePixel(x + i*size, y + j*size+1);
updatePixel(x + i*size+1, y + j*size+1);
}
if (size > 2)
{
// Increase square to be 1 bit wider and 1 bit higher
// x x X
// x x X
// X X X
updatePixel(x + i*size+2, y + j*size);
updatePixel(x + i*size+2, y + j*size+1);
// Bottom row
updatePixel(x + i*size, y + j*size+2);
updatePixel(x + i*size+1, y + j*size+2);
updatePixel(x + i*size+2, y + j*size+2);
}
if (size >3)
{
// Increase square to be 1 bit wider and 1 bit higher
// x x x X
// x x x X
// x x x X
// X X X X
updatePixel(x + i*size+3, y + j*size);
updatePixel(x + i*size+3, y + j*size+1);
updatePixel(x + i*size+3, y + j*size+2);
// Bottom row
updatePixel(x + i*size, y + j*size+3);
updatePixel(x + i*size+1, y + j*size+3);
updatePixel(x + i*size+2, y + j*size+3);
updatePixel(x + i*size+3, y + j*size+3);
}
if (size >4)
{
// Increase square to be 1 bit wider and 1 bit higher
// x x x x X
// x x x x X
// x x x x X
// x x x x X
// X X X X X
updatePixel(x + i*size+4, y + j*size);
updatePixel(x + i*size+4, y + j*size+1);
updatePixel(x + i*size+4, y + j*size+2);
updatePixel(x + i*size+4, y + j*size+3);
// Bottom row
updatePixel(x + i*size, y + j*size+4);
updatePixel(x + i*size+1, y + j*size+4);
updatePixel(x + i*size+2, y + j*size+4);
updatePixel(x + i*size+3, y + j*size+4);
updatePixel(x + i*size+4, y + j*size+4);
}
}
// Bitwise Right Shift operator
// [variable] >> [number of places]
mybyte >>= 1;
}
}
}
void updatePixel(int16_t x, int16_t y) {
// Pixel is within the screen area
if ((x < 0) || (x >= OLED_WIDTH) || (y < 0) || (y >= OLED_HEIGHT)) return;
// Consider the display as a series of 8 bit high rows. A ByteRow
// Perform integer arithmetic to find the correct ByteRow the pixel is on
int8_t ByteRow = y / BYTE_SIZE;
// The trick here is to find the remainder bits = MOD(y,8) in Excel
// In the 8 bit high bar want to find the position
// Using binary arithmetic interested only in the last 3 bits
// If y=146, binary=10010010, last 3 bits=010, in decimal=2
// Bitwise operator AND
// 11001xyz mybyte say.
// 00000111 (e.g. 7) picks up the last digits 'xyz'
int8_t correctposition = y & (BYTE_SIZE-1);
// Bitwise Left Shift operator
// [variable] << [number of places]
// Shift the on pixel to the correct position within the 8 bit high bar
// Then perform Bitwise | OR (to add the pixel)
screenbuffer[ x + ByteRow * OLED_WIDTH] |= (1 << correctposition);
}
// Clear the screen
void clearDisplay(void)
{
memset(screenbuffer, 0, (OLED_WIDTH * OLED_BYTE_ROWS));
}
void println(const char c[])
{
size_t i;
for (i=0; i< strlen(c); i++){
writeOLED(c[i]);
}
writeOLED('\r');
writeOLED('\n');
}
void setTextSize(unsigned char s) {
_textsize = (s > 0) ? s : 1;
}
//================== PINs ========================
FILE* pinMode(int pinNumber, bool setInputOutput)
{
// Allocate memory
char buf[40] = {0};
// Create file pointer to the pin
// Ensure exclusive use of the pin
FILE* file_pin = fopen("/sys/class/gpio/export","w");
fprintf(file_pin,"%d", pinNumber);
fclose(file_pin);
// Define if the pin is an INPUT or OUTPUT
sprintf(buf,"/sys/class/gpio/gpio%d/direction", pinNumber);
file_pin = fopen(buf,"w");
if (setInputOutput)
{
fprintf(file_pin,"in");
}
else
{
fprintf(file_pin,"out");
}
// Close the file
fclose(file_pin);
// Set the value of the pin.
// Notice that this file is left open to change value in the loop
sprintf(buf,"/sys/class/gpio/gpio%d/value", pinNumber);
if (setInputOutput)
{
// Input so read
file_pin = fopen(buf,"r");
}
else
{
// Output so write
file_pin = fopen(buf,"w");
}
return file_pin;
}
void digitalWrite(FILE* file_pin, bool setHigh)
{
// The function assumes the file is already open
// This is done to save time
if (setHigh)
{
// Turn-on LED
fprintf(file_pin,"1");
}
else
{
// Turn-off LED
fprintf(file_pin,"0");
}
// Update the file (without closing it)
fflush(file_pin);
}
RoboticBoat.uk