Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 160 additions & 22 deletions ST7920_GFX_Library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,37 @@
#include "Adafruit_GFX.h"
#include "ST7920_GFX_Library.h"

uint8_t buff[1024]; //This array serves as primitive "Video RAM" buffer
uint8_t buff[2048] __attribute__ ((aligned (4))); //This array serves as primitive "Video RAM" buffer. Ensure it's 32-bit aligned. Enough for 2 x ST7920s.

static inline void _swap(int16_t* pa, int16_t* pb) {
int16_t t = *pa;
*pa = *pb;
*pb = t;
}

//This display is split into two halfs. Pages are 16bit long and pages are arranged in that way that are lied horizontaly instead of verticaly, unlike SSD1306 OLED, Nokia 5110 LCD, etc.
//After 8 horizonral page is written, it jumps to half of the screen (Y = 32) and continues until 16 lines of page have been written. After that, we have set cursor in new line.
void ST7920::drawPixel(int16_t x, int16_t y, uint16_t color) {
if(x<0 || x>=ST7920_WIDTH || y<0 || y>=ST7920_HEIGHT) return;
uint8_t y0 = 0, x0 = 0; //Define and initilize varilables for skiping rows
uint8_t y0 = 0, x0 = 0; //Define and initilize varilables for skiping rows
uint16_t data, n; //Define variable for sending data itno buffer (basicly, that is one line of page)
uint16_t w = width();
uint16_t h = height();
if ((x < 0) || (x >= w) || (y < 0) || (y >= h)) return;
// Pixel is in-bounds. Rotate coordinates if needed.
switch (getRotation()) {
case 1:
_swap(&x, &y);
x = w - x - 1;
break;
case 2:
x = w - x - 1;
y = h - y - 1;
break;
case 3:
_swap(&x, &y);
y = h - y - 1;
break;
}
if (y > 31) { //If Y coordinate is bigger than 31, that means we have to skip into that row, but we have to do that by adding
y -= 32;
y0 = 16;
Expand All @@ -23,39 +46,48 @@ void ST7920::drawPixel(int16_t x, int16_t y, uint16_t color) {
if (!color) {
buff[n] &= (~data >> 8);
buff[n + 1] &= (~data & 0xFF);
}else{
} else {
buff[n] |= (data >> 8);
buff[n + 1] |= (data & 0xFF);
}
}

ST7920::ST7920(int8_t CS) : Adafruit_GFX(ST7920_WIDTH, ST7920_HEIGHT) {
ST7920::ST7920(uint8_t CS, uint8_t width /* =ST7920_WIDTH */) : Adafruit_GFX(width, ST7920_HEIGHT) {
cs = CS;
buf_len = 1024;
}

void ST7920::begin(void) {
SPI.begin();
pinMode(cs, OUTPUT);
digitalWrite(cs, HIGH);
ST7920Command(B00001100);
ST7920Command(0b00001100);
digitalWrite(cs, LOW);
}

void ST7920::fillScreen(uint16_t color) {
uint32_t* p = (uint32_t*)buff;
uint32_t v = 0;
if (color) v = 0xFFFFFFFF;
for(uint16_t i = 0; i < (buf_len >>2); i++) {
*p++ = v;
}
}


void ST7920::clearDisplay() {
long* p = (long*)&buff;
for (int i = 0; i < 256; i++) {
p[i] = 0;
}
fillScreen(0);
}

void ST7920::display() {
int x = 0, y = 0, n = 0;
uint8_t x = 0, y = 0;
uint16_t n = 0;
digitalWrite(cs, HIGH);
ST7920Command(B00100100); //EXTENDED INSTRUCTION SET
ST7920Command(B00100110); //EXTENDED INSTRUCTION SET
ST7920Command(0b00100100); //EXTENDED INSTRUCTION SET
ST7920Command(0b00100110); //EXTENDED INSTRUCTION SET
for (y = 0; y < 32; y++) {
ST7920Command(0x80 | y);
ST7920Command(0x80 | x);
ST7920Command(0x80); // x always starts at 0.
for (x = 0; x < 16; x++) {
ST7920Data(buff[n]);
ST7920Data(buff[n + 1]);
Expand All @@ -66,26 +98,132 @@ void ST7920::display() {
}

void ST7920::invertDisplay() {
long* p = (long*)&buff;
for(int i = 0; i<256; i++) {
uint32_t* p = (uint32_t*)&buff;
for(uint16_t i = 0; i < (buf_len >> 2); i++) {
p[i] = ~p[i];
}
}

void ST7920::ST7920Data(uint8_t data) { //RS = 1 RW = 0
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE3));
SPI.transfer(B11111010);
SPI.transfer((data & B11110000));
SPI.transfer((data & B00001111) << 4);
SPI.transfer(0b11111010);
SPI.transfer((data & 0b11110000));
SPI.transfer((data & 0b00001111) << 4);
SPI.endTransaction();
delayMicroseconds(38);
}

void ST7920::ST7920Command(uint8_t data) { //RS = 0 RW = 0
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE3));
SPI.transfer(B11111000);
SPI.transfer((data & B11110000));
SPI.transfer((data & B00001111) << 4);
SPI.transfer(0b11111000);
SPI.transfer((data & 0b11110000));
SPI.transfer((data & 0b00001111) << 4);
SPI.endTransaction();
delayMicroseconds(38);
}

// --------------- 192 x 64

//This display is split into two halfs. Pages are 16bit long and pages are arranged in that way that are lied horizontaly instead of verticaly, unlike SSD1306 OLED, Nokia 5110 LCD, etc.
//After 8 horizonral page is written, it jumps to half of the screen (Y = 32) and continues until 16 lines of page have been written. After that, we have set cursor in new line.

// Layout of buf[]:
// - each block of 16 bytes is one scan line of 128 pixels for a particular y value
// - y rows are interleaved between top and bottom halves, so y=0, y=32, y=1, y=33 ...

void ST7920_192::drawPixel(int16_t x, int16_t y, uint16_t color) {
uint16_t w = width();
uint16_t h = height();
if ((x < 0) || (x >= w) || (y < 0) || (y >= h)) return;
// Pixel is in-bounds. Rotate coordinates if needed.
switch (getRotation()) {
case 1:
_swap(&x, &y);
x = w - x - 1;
break;
case 2:
x = w - x - 1;
y = h - y - 1;
break;
case 3:
_swap(&x, &y);
y = h - y - 1;
break;
}
uint8_t x0 = 0;
uint16_t data, n, offset = 0; //Define variable for sending data itno buffer (basicly, that is one line of page)
if (y > 31) { //If Y coordinate is bigger than 31, that means we have to skip into that row, but we have to do that by adding
// Second half needs to hit other controller.
y -= 32;
offset = 1024;
}
x0 = x % 16;
x /= 16;
data = 0x8000 >> x0;
n = offset + (x * 2) + (32 * y);
if (!color) {
buff[n] &= (~data >> 8);
buff[n + 1] &= (~data & 0xFF);
}else{
buff[n] |= (data >> 8);
buff[n + 1] |= (data & 0xFF);
}
}

ST7920_192::ST7920_192(uint8_t CS, uint8_t CK1, uint8_t CK2) : ST7920(CS, ST7920_192_WIDTH) {
ck1 = CK1;
ck2 = CK2;
buf_len = 2048;
}

void ST7920_192::set_chip(uint8_t chip) {
uint8_t ck, not_ck;
if (chip == 1) {
ck = ck1;
not_ck = ck2;
} else {
ck = ck2;
not_ck = ck1;
}
gpio_set_function(not_ck, GPIO_FUNC_SIO);
gpio_set_function(ck, GPIO_FUNC_SPI);
SPI.setSCK(ck);
}

void ST7920_192::begin(void) {
set_chip(1);
SPI.begin();
pinMode(cs, OUTPUT);
digitalWrite(cs, HIGH);
ST7920Command(0b00001100);
digitalWrite(cs, LOW);
// Initialize bottom-half chip.
set_chip(2);
digitalWrite(cs, HIGH);
ST7920Command(0b00001100);
digitalWrite(cs, LOW);
}

void ST7920_192::display() {
uint8_t c = 0, x = 0, y = 0;
uint16_t n = 0;
set_chip(1); // Top rows.
for (c = 0; c < 2; c++) {
digitalWrite(cs, HIGH);
ST7920Command(0b00100100); //EXTENDED INSTRUCTION SET
ST7920Command(0b00100110); //EXTENDED INSTRUCTION SET
for (y = 0; y < 32; y++) {
ST7920Command(0x80 | y);
ST7920Command(0x80); // | x); // Always start at x=0.
for (x = 0; x < 12; x++) { // 12 tiles of 16 pixels = 192 pixels.
ST7920Data(buff[n]);
ST7920Data(buff[n + 1]);
n += 2;
}
// Skip over the last 64 pixels in this row for 192 col display.
n += 8;
}
digitalWrite(cs, LOW);
set_chip(2); // Bottom rows.
}
}
26 changes: 22 additions & 4 deletions ST7920_GFX_Library.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,44 @@

#define ST7920_HEIGHT 64 //64 pixels tall display
#define ST7920_WIDTH 128 //128 pixels wide display
#define ST7920_192_WIDTH 192

#define BLACK 1 //Defines color - Black color -> Bit in buffer is set to one
#define WHITE 0 //Defines color - White color -> Bit in buffer is set to zero

class ST7920 : public Adafruit_GFX {
public:
ST7920(int8_t CS);
ST7920(uint8_t CS, uint8_t width=ST7920_WIDTH);

void begin(void);
void clearDisplay(void);
void fillScreen(uint16_t color);
void clearDisplay(void);
void invertDisplay(void);
void display();

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

private:
int8_t cs;
protected:
uint8_t cs;
uint16_t buf_len;
void ST7920Data(uint8_t data);
void ST7920Command(uint8_t data);

};

class ST7920_192 : public ST7920 {
public:
ST7920_192(uint8_t CS, uint8_t CK1, uint8_t CK2);

void begin(void);
void display();

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

private:
void set_chip(uint8_t chip);
uint8_t ck1;
uint8_t ck2;
};