displaying on SSD1306, 128x64 pixels OLED

Dependencies:   microbit

OLED.cpp

Committer:
bvirk
Date:
2020-02-18
Revision:
4:19da6ea94042
Parent:
3:f36427797fd7
Child:
6:c69f08f464b5

File content as of revision 4:19da6ea94042:


#include "MicroBit.h"
#include "MicroBitI2C.h"

#include "mathExt.h"
#include "OLEDGlobals.h"
#include "OLED.h"
#include "cppNorm.h"

/**
 * Create a representation of a 128x64 pixels, ssd1306 compatble OLED display
 *
 **/
OLED::OLED() : 
     i2c(I2C_SDA0,I2C_SCL0)
    ,charX(0)
    ,charY(0)
    ,displayWidth(128)
    ,displayHeight(64 / 8)
    ,screenSize(0) 
    ,pendingNewline(false)
    {}

void OLED::command(uint8_t cmd) {
    char buf[2];
    buf[0] = '\0';
    buf[1] = cmd;
    i2c.write(chipAdress,buf,2);
}
void OLED::init() {
    init(128, 64);
    }
    

void OLED::init(uint8_t width, uint8_t height) {
    command(SSD1306_DISPLAYOFF);
    command(SSD1306_SETDISPLAYCLOCKDIV);
    command(0x80);                                  // the suggested ratio 0x80
    command(SSD1306_SETMULTIPLEX);
    command(0x3F);
    command(SSD1306_SETDISPLAYOFFSET);
    command(0x0);                                   // no offset
    command(SSD1306_SETSTARTLINE | 0x0);            // line #0
    command(SSD1306_CHARGEPUMP);
    command(0x14);
    command(SSD1306_MEMORYMODE);
    command(0x00);                                  // 0x0 act like ks0108
    command(SSD1306_SEGREMAP | 0x1);
    command(SSD1306_COMSCANDEC);
    command(SSD1306_SETCOMPINS);
    command(0x12);
    command(SSD1306_SETCONTRAST);
    command(0xCF);
    command(SSD1306_SETPRECHARGE);
    command(0xF1);
    command(SSD1306_SETVCOMDETECT);
    command(0x40);
    command(SSD1306_DISPLAYALLON_RESUME);
    command(SSD1306_NORMALDISPLAY);
    command(SSD1306_DISPLAYON);
    displayWidth = width;
    displayHeight = height / 8;
    screenSize = displayWidth * displayHeight;
    charX = xOffset;
    charY = yOffset;
    loadStarted = false;
    loadPercent = 0;
    clear();
}

void OLED::clear() {
    loadStarted = false;
    loadPercent = 0;
    command(SSD1306_SETCOLUMNADRESS);
    command(0x00);
    command(displayWidth - 1);
    command(SSD1306_SETPAGEADRESS);
    command(0x00);
    command(displayHeight - 1);
    char data[17];
    data[0] = 0x40; // Data Mode;
    for (int8_t i = 1; i < 17; i++) 
        data[i] = 0x00;
    // send display buffer in 16 byte chunks;
    for (int16_t  i = 0; i < screenSize; i += 16) { 
        i2c.write(chipAdress, data, 17,false);
    }
    charX = xOffset;
    charY = yOffset;
    setTextArea(32,true);
}


void OLED::drawChar(uint8_t x, uint8_t y, uint8_t chr ) {
    command(SSD1306_SETCOLUMNADRESS);
    command(x);
    command(x + 5);
    command(SSD1306_SETPAGEADRESS);
    command(y);
    command(y + 1);
    textArea[x/6][y]=chr;
    char line[2];
    line[0] = 0x40;
    for (int8_t i = 0; i < 6; i++) {
        if (i == 5) 
            line[1] = 0x00;
        else 
            line[1] = font[chr][i];
        i2c.write(chipAdress, line, 2, false);
    }
}


void OLED::setTextArea(uint8_t chr, bool setLine8=false) {
    for (int8_t line = 0; line <= 8; line++)
        if (line < 8 || setLine8)
            for (int8_t xPos = 0; xPos < 22; xPos++)
                textArea[xPos][line]=chr;
}


void OLED::scroll() {
    for (int8_t line = 1; line <= 8; line++)
        for (int8_t xPos = 0; xPos < 22; xPos++)
            drawChar(6*xPos,line-1,textArea[xPos][line]);
}    

void OLED::newLine() {
    charY++;
    charX = xOffset;
    if (charY == 8) {
        charY = 7;
        scroll();
       }
    pendingNewline=false;
}
            
void OLED::write(string str) {
    if (pendingNewline)
        newLine();
    for (uint16_t i = 0; i < str.length(); i++) {
        if (charX > displayWidth - 6) {
            charX = xOffset;
            charY++;
            }
        drawChar(charX, charY, (uint8_t)str.charAt(i));
        charX += 6;
    }
}

void OLED::crwrite(string str) {
    charX=xOffset;
    write(str);
}

void OLED::writeln(string str) {
    write(str);
    pendingNewline=true;
}
 
void OLED::write(float number) {
    write(ftos(number));
}

void OLED::crwrite(float number) {
    charX=xOffset;
    write(ftos(number));
}

void OLED::writeln(float number) {
    write(number);
    pendingNewline=true;

}

/* dont works
void OLED::drawShape(vector<xyPair> & pixels) {
    uint8_t x1 = displayWidth;
    uint8_t y1 = displayHeight * 8;
    uint8_t x2 = 0;
    uint8_t y2 = 0;
    for (int8_t i = 0; i < pixels.size(); i++) {
        if (pixels[i].x < x1)
            x1 = pixels[i].x;
        if (pixels[i].x > x2)
            x2 = pixels[i].x;
        if (pixels[i].y < y1)
            y1 = pixels[i].y;
        if (pixels[i].y > y2)
            y2 = pixels[i].y;
    }
    uint8_t page1 = y1 / 8;
    uint8_t page2 = y2 / 8;
    char line[2];
    line[0] = 0x40;
    for (uint8_t x = x1; x <= x2; x++) {
        for (uint8_t page = page1; page <= page2; page++) {
            line[1] = 0x00;
            for (uint8_t i = 0; i < pixels.size(); i++) 
                if (pixels[i].x == x) 
                    if (pixels[i].y / 8 == page) 
                        line[1] |= 1 << (pixels[i].y % 8);
            if (line[1] != 0x00) {
                command(SSD1306_SETCOLUMNADRESS);
                command(x);
                command(x + 1);
                command(SSD1306_SETPAGEADRESS);
                command(page);
                command(page + 1);
                //line[1] |= pins.i2cReadBuffer(chipAdress, 2)[1]
                i2c.write(chipAdress, line, 2, false);
            }
        } // for page
    } // for x
}

void OLED::drawLine(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
    vector<xyPair> pixels;
    uint8_t kx, ky, c, i;
    uint8_t targetX = x1;
    uint8_t targetY = y1;
    x1 -= x0; kx = 0; 
    if (x1 > 0) 
        kx = +1; 
    if (x1 < 0) { 
        kx = -1; 
        x1 = -x1; 
        } 
    x1++;
    y1 -= y0; ky = 0; 
    if (y1 > 0) 
        ky = +1; 
    if (y1 < 0) { 
        ky = -1; 
        y1 = -y1; 
        }
    y1++;
    if (x1 >= y1) {
        c = x1;
        for (i = 0; i < x1; i++ , x0 += kx) {
            pixels.push_back(xyPair(x0, y0));
            c -= y1; 
            if (c <= 0) { 
                if (i != x1 - 1) 
                    pixels.push_back(xyPair(x0 + kx, y0)); 
                    c += x1; y0 += ky; 
                    if (i != x1 - 1) 
                        pixels.push_back(xyPair(x0, y0)); 
            }
            if (pixels.size() > 20) {
                drawShape(pixels);
                pixels.clear();
                drawLine(x0, y0, targetX, targetY);
                return;
            }
        }
    } else {
        c = y1;
        for (i = 0; i < y1; i++ , y0 += ky) {
            pixels.push_back(xyPair(x0, y0));
            c -= x1; 
            if (c <= 0) { 
                if (i != y1 - 1) 
                    pixels.push_back(xyPair(x0, y0 + ky));
                c += y1;
                x0 += kx; 
                if (i != y1 - 1) 
                    pixels.push_back(xyPair(x0, y0)); 
            }
            if (pixels.size() > 20) {
                drawShape(pixels);
                pixels.clear();
                drawLine(x0, y0, targetX, targetY);
                return;
            }
        }
    }
    drawShape(pixels);
}
void OLED::drawRectangle(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
        drawLine(x0, y0, x1, y0);
        drawLine(x0, y1, x1, y1);
        drawLine(x0, y0, x0, y1);
        drawLine(x1, y0, x1, y1);
    } */
    
void OLED::testOLED(MicroBit & uBit) {
    writeln("the quick brown fox jumped over the lazy dog?");
    uBit.sleep(2000);
    clear();
    writeln("THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG!");
    uBit.sleep(2000);
    clear();
    write("Your magic number is ");
    write(23 * 3);
    writeln("!");
    writeln(1.4);
    writeln(12);
    uBit.sleep(2000); 
    writeln(2.1);
    uBit.sleep(2000); 
    writeln(3);
    /*
    basic.pause(1000)
    for (let i = 0; i < 100; i++) {
        oled.drawLoading(i)
    }
    basic.pause(1000)
    oled.clear()
    oled.drawRectangle(10, 10, 60, 60)
    oled.drawLine(0, 0, 128, 64)
    oled.drawLine(0, 64, 128, 0)
    */
}