Library for drawing on the Hexiwear's OLED - more features being actively worked on

Dependents:   Hexidraw_Demo Hexiwear-FinalProject_v2

Discussion: https://developer.mbed.org/forum/team-4615-Hexiwear-community/topic/26595/

Hexidraw is a library for drawing on the Hexiwear's OLED. Be aware that it is not very optimized, so drawing may be slow, especially when drawing on large areas of the screen.

Please see the wiki for API documentation.

Features:

  • Screen fill with a color
  • Drawing filled rectangles
  • Drawing circles with a set radius and line width
  • Setting individual pixels
  • Turning on and off the OLED's sleep mode
  • Drawing images

Example project: https://developer.mbed.org/users/keithm01/code/Hexidraw_Demo/

Files at this revision

API Documentation at this revision

Comitter:
keithm01
Date:
Sat Aug 20 16:34:55 2016 +0000
Parent:
3:e8bbba5c43ba
Child:
5:00876457cad4
Commit message:
Added optional display buffer for faster drawing. Started looking at adding font support

Changed in this revision

hexidraw.cpp Show annotated file Show diff for this revision Revisions of this file
hexidraw.h Show annotated file Show diff for this revision Revisions of this file
--- a/hexidraw.cpp	Fri Aug 19 22:24:54 2016 +0000
+++ b/hexidraw.cpp	Sat Aug 20 16:34:55 2016 +0000
@@ -15,7 +15,13 @@
     _cs(oled_cs_pin),
     _reset(oled_rst_pin),
     _dc(oled_dc_pin)
-{}
+{
+    if(USE_BUFFER) {
+        for(uint16_t i = 0; i < OLED_WIDTH * OLED_HEIGHT; ++ i) {
+            displayBuffer[i] = BLACK;
+        }
+    }
+}
 
 void OLED::begin()
 {
@@ -150,6 +156,29 @@
     writeCommand(0xAF);
 }
 
+void OLED::draw()
+{
+    if(USE_BUFFER) {
+        writeCommand(OLED_CMD_SET_COLUMN);
+        writeData(16);
+        writeData(111);
+        writeCommand(OLED_CMD_SET_ROW);
+        writeData(0);
+        writeData(95);
+        writeCommand(OLED_CMD_WRITERAM);
+
+        _dc = 1;
+        _cs = 0;
+
+        for(uint32_t i = 0; i < OLED_WIDTH * OLED_HEIGHT; ++ i) {
+            writeData(displayBuffer[i] >> 8);
+            writeData(displayBuffer[i]);
+        }
+
+        _cs = 1;
+    }
+}
+
 void OLED::cursor(int x, int y)   //goTo
 {
     if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return;
@@ -171,17 +200,20 @@
     // Bounds check.
     if ((x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) return;
     if ((x < 0) || (y < 0)) return;
+    if(!USE_BUFFER) {
+        cursor(x, y);
 
-    cursor(x, y);
+        writeCommand(OLED_CMD_WRITERAM);
+        _dc = 1;
+        _cs = 0;
 
-    writeCommand(OLED_CMD_WRITERAM);
-    _dc = 1;
-    _cs = 0;
+        writeData(color >> 8);
+        writeData(color);
 
-    writeData(color >> 8);
-    writeData(color);
-
-    _cs = 1;
+        _cs = 1;
+    } else {
+        displayBuffer[x+OLED_WIDTH*y] = color;
+    }
 }
 
 void OLED::clear (uint16_t color)
@@ -203,25 +235,29 @@
     if (x+w > OLED_WIDTH) {
         w = OLED_WIDTH - x - 1;
     }
-
-    x+= OLED_COL_OFFSET;
+    if(!USE_BUFFER) {
+        x+= OLED_COL_OFFSET;
 
-    // set location
-    writeCommand(OLED_CMD_SET_COLUMN);
-    writeData(x);
-    writeData(x+(w-1));
-    //writeData(x-1);
-    writeCommand(OLED_CMD_SET_ROW);
-    writeData(y);
-    writeData(y+(h-1));
-    //writeData(y-1);
-    // fill!
-    writeCommand(OLED_CMD_WRITERAM);
+        // set location
+        writeCommand(OLED_CMD_SET_COLUMN);
+        writeData(x);
+        writeData(x+(w-1));
+        writeCommand(OLED_CMD_SET_ROW);
+        writeData(y);
+        writeData(y+(h-1));
+        // fill!
+        writeCommand(OLED_CMD_WRITERAM);
 
-    for (uint16_t i=0; i < w*h; i++) {
-        //writeData(fillcolor >> 8);
-        writeData(fillcolor >> 8);
-        writeData(fillcolor);
+        for (uint16_t i=0; i < w*h; i++) {
+            writeData(fillcolor >> 8);
+            writeData(fillcolor);
+        }
+    } else {
+        for(uint16_t _w = 0; _w < w; ++_w) {
+            for(uint16_t _h = 0; _h < h; ++_h) {
+                displayBuffer[((x+_w)+OLED_WIDTH*(y+_h))] = fillcolor;
+            }
+        }
     }
 }
 
@@ -233,30 +269,68 @@
             float degInRad = i*DEG2RAD;
             uint16_t x2 = x + cos(degInRad) * (radius+r);
             uint16_t y2 = y + sin(degInRad) * (radius+r);
-
-            pixel(x2, y2, color);
+            if(USE_BUFFER) {
+                displayBuffer[((x2)+OLED_WIDTH*(y2))] = color;
+            } else {
+                pixel(x2, y2, color);
+            }
         }
     }
 }
 
-void OLED::image (uint16_t x, uint16_t y, const uint8_t* image, uint32_t image_data_size)
+void buffer_swap(
+    uint16_t* imgDst,
+    const uint8_t* imgSrc,
+    uint16_t imgSize
+)
+{
+    for ( int var = 0; var < imgSize; var++ ) {
+        *imgDst = *imgSrc << 8;
+        imgSrc++;
+        *imgDst |= *imgSrc;
+        imgDst++;
+        imgSrc++;
+    }
+}
+
+
+void OLED::image (uint16_t x, uint16_t y, const uint8_t* image)
 {
-//    cursor(x, y);
-    
-    writeCommand(OLED_CMD_WRITERAM);
-    _dc = 1;
-    _cs = 0;
+    x+= OLED_COL_OFFSET;
+    //cursor(x, y);
+
+    uint16_t w = image[2];
+    uint16_t h = image[4];
+
+    uint16_t image_data_size = w * h * OLED_BYTES_PER_PIXEL;
 
-    const uint8_t* buffer = OLED_SKIP_IMAGE_HEADER(image);
+    if(!USE_BUFFER) {
+        writeCommand(OLED_CMD_SET_COLUMN);
+        writeData(x);
+        writeData(x+(w-1));
+        writeCommand(OLED_CMD_SET_ROW);
+        writeData(y);
+        writeData(y+(h-1));
 
-    for ( uint32_t i = 0; i < image_data_size; i++) {
-        _spi.write(*buffer);
-        buffer += 1;
+        writeCommand(OLED_CMD_WRITERAM);
+        _dc = 1;
+        _cs = 0;
+
+        const uint8_t* buffer = OLED_SKIP_IMAGE_HEADER(image);
+
+        for ( uint32_t i = 0; i < image_data_size; i++) {
+            _spi.write(*buffer);
+            buffer += 1;
+        }
+
+    } else {
+        const uint8_t* buffer = OLED_SKIP_IMAGE_HEADER(image);
+        buffer_swap(displayBuffer, buffer, image_data_size);
     }
 
-    _cs = 1;
 }
 
+
 void OLED::dim()
 {
     for ( int i = 0; i < 16; i++ ) {
@@ -266,6 +340,78 @@
     }
 }
 
+void OLED::hline(uint16_t x, uint16_t y, uint16_t width, uint16_t color, uint16_t thickness)
+{
+    if(!USE_BUFFER) {
+        //x+= OLED_COL_OFFSET;
+        // set location
+        writeCommand(OLED_CMD_SET_COLUMN);
+        writeData(x);
+        writeData(x+width-1);
+        writeCommand(OLED_CMD_SET_ROW);
+        writeData(y);
+        writeData(y+thickness-1);
+        // fill!
+        writeCommand(OLED_CMD_WRITERAM);
+
+        for (uint16_t i=0; i < width*thickness; i++) {
+            writeData(color >> 8);
+            writeData(color);
+        }
+    } else {
+
+        for (uint16_t w=0; w < width; w++) {
+            for (uint16_t h=0; h < thickness; h++) {
+                displayBuffer[((x+w)+OLED_WIDTH*(y+h))] = color;
+            }
+        }
+    }
+
+}
+
+void OLED::vline(uint16_t x, uint16_t y, uint16_t height, uint16_t color, uint16_t thickness)
+{
+    if(!USE_BUFFER) {
+        x+= OLED_COL_OFFSET;
+        // set location
+        writeCommand(OLED_CMD_SET_COLUMN);
+        writeData(x);
+        writeData(x+thickness-1);
+        writeCommand(OLED_CMD_SET_ROW);
+        writeData(y);
+        writeData(y+height-1);
+        // fill!
+        writeCommand(OLED_CMD_WRITERAM);
+
+        for (uint16_t i=0; i < height*thickness; i++) {
+            writeData(color >> 8);
+            writeData(color);
+        }
+    } else {
+        for (uint16_t w=0; w < thickness; w++) {
+            for (uint16_t h=0; h < height; h++) {
+                displayBuffer[((x+w)+OLED_WIDTH*(y+h))] = color;
+            }
+        }
+    }
+}
+
+void OLED::text(uint16_t x, uint16_t y, const uint8_t* text, const uint8_t* font, uint16_t color)
+{
+
+    x += OLED_COL_OFFSET;
+    uint8_t pad = 2;
+
+    uint8_t firstChar = font[2];
+    uint8_t charHeight    = font[6];    
+    
+    uint16_t current_char = 0;
+    while(text[current_char] != 0) {
+        
+        ++current_char;
+    }
+}
+
 uint16_t Color565(uint8_t r, uint8_t g, uint8_t b)
 {
     uint16_t c;
--- a/hexidraw.h	Fri Aug 19 22:24:54 2016 +0000
+++ b/hexidraw.h	Sat Aug 20 16:34:55 2016 +0000
@@ -23,6 +23,8 @@
     #define OLED_SPI_CHUNK (511)
     
     #define OLED_SKIP_IMAGE_HEADER( imgPtr ) ( (const uint8_t*)(imgPtr) + OLED_BMP_HEADER_BYTE_SIZE )
+    
+    #define USE_BUFFER 1
         
     /* borrowed from the Adafruit library at:
         https://developer.mbed.org/teams/ELLA-Robotics-Inc/code/Adafruit_GFX_1351/ 
@@ -43,10 +45,15 @@
             void dim();
             void clear(uint16_t color);
             void circle(uint16_t x, uint16_t y, uint16_t radius, uint16_t color, uint16_t width = 1);
-            void image (uint16_t x, uint16_t y, const uint8_t* image, uint32_t image_data_size = OLED_IMAGE_SIZE + OLED_BMP_HEADER_BYTE_SIZE);
+            void image (uint16_t x, uint16_t y, const uint8_t* image);
+            void hline(uint16_t x, uint16_t y, uint16_t width, uint16_t color, uint16_t thickness = 1);
+            void vline(uint16_t x, uint16_t y, uint16_t height, uint16_t color, uint16_t thickness = 1);
+            void draw();
         private:
             SPI _spi;
             DigitalOut _cs, _dc, _reset;
+            uint16_t displayBuffer[OLED_WIDTH * OLED_HEIGHT];
+            void text(uint16_t x, uint16_t y, const uint8_t* text, const uint8_t* font, uint16_t color = WHITE);
         };
 
 #endif
\ No newline at end of file