211 lines
4.4 KiB
C++
211 lines
4.4 KiB
C++
#include "uc8159.hpp"
|
|
|
|
#include <cstdlib>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
namespace pimoroni {
|
|
|
|
enum reg {
|
|
PSR = 0x00,
|
|
PWR = 0x01,
|
|
POF = 0x02,
|
|
PFS = 0x03,
|
|
PON = 0x04,
|
|
BTST = 0x06,
|
|
DSLP = 0x07,
|
|
DTM1 = 0x10,
|
|
DSP = 0x11,
|
|
DRF = 0x12,
|
|
IPC = 0x13,
|
|
PLL = 0x30,
|
|
TSC = 0x40,
|
|
TSE = 0x41,
|
|
TSW = 0x42,
|
|
TSR = 0x43,
|
|
CDI = 0x50,
|
|
LPD = 0x51,
|
|
TCON = 0x60,
|
|
TRES = 0x61,
|
|
DAM = 0x65,
|
|
REV = 0x70,
|
|
FLG = 0x71,
|
|
AMV = 0x80,
|
|
VV = 0x81,
|
|
VDCS = 0x82,
|
|
PWS = 0xE3,
|
|
TSSET = 0xE5
|
|
};
|
|
|
|
bool UC8159::is_busy() {
|
|
if(BUSY == PIN_UNUSED) {
|
|
if(absolute_time_diff_us(get_absolute_time(), timeout) > 0) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return !gpio_get(BUSY);
|
|
}
|
|
|
|
void UC8159::busy_wait(uint minimum_wait_ms) {
|
|
timeout = make_timeout_time_ms(minimum_wait_ms);
|
|
while(is_busy()) {
|
|
tight_loop_contents();
|
|
}
|
|
}
|
|
|
|
void UC8159::reset() {
|
|
gpio_put(RESET, 0); sleep_ms(10);
|
|
gpio_put(RESET, 1); sleep_ms(10);
|
|
busy_wait();
|
|
}
|
|
|
|
void UC8159::init() {
|
|
// configure spi interface and pins
|
|
spi_init(spi, 3'000'000);
|
|
|
|
gpio_set_function(DC, GPIO_FUNC_SIO);
|
|
gpio_set_dir(DC, GPIO_OUT);
|
|
|
|
gpio_set_function(CS, GPIO_FUNC_SIO);
|
|
gpio_set_dir(CS, GPIO_OUT);
|
|
gpio_put(CS, 1);
|
|
|
|
gpio_set_function(RESET, GPIO_FUNC_SIO);
|
|
gpio_set_dir(RESET, GPIO_OUT);
|
|
gpio_put(RESET, 1);
|
|
|
|
gpio_set_function(BUSY, GPIO_FUNC_SIO);
|
|
gpio_set_dir(BUSY, GPIO_IN);
|
|
gpio_set_pulls(BUSY, true, false);
|
|
|
|
gpio_set_function(SCK, GPIO_FUNC_SPI);
|
|
gpio_set_function(MOSI, GPIO_FUNC_SPI);
|
|
};
|
|
|
|
void UC8159::setup() {
|
|
reset();
|
|
busy_wait();
|
|
|
|
uint8_t dimensions[4] = {
|
|
uint8_t(width >> 8),
|
|
uint8_t(width),
|
|
uint8_t(height >> 8),
|
|
uint8_t(height)
|
|
};
|
|
|
|
if (width == 600) {
|
|
if (rotation == ROTATE_0) {
|
|
command(PSR, {0xE3, 0x08});
|
|
} else {
|
|
command(PSR, {0xEF, 0x08});
|
|
}
|
|
} else {
|
|
if (rotation == ROTATE_0) {
|
|
command(PSR, {0xA3, 0x08});
|
|
} else {
|
|
command(PSR, {0xAF, 0x08});
|
|
}
|
|
}
|
|
command(PWR, {0x37, 0x00, 0x23, 0x23});
|
|
command(PFS, {0x00});
|
|
command(BTST, {0xC7, 0xC7, 0x1D});
|
|
command(PLL, {0x3C});
|
|
command(TSC, {0x00});
|
|
command(CDI, {0x37});
|
|
command(TCON, {0x22});
|
|
command(TRES, 4, dimensions);
|
|
command(PWS, {0xAA});
|
|
|
|
sleep_ms(100);
|
|
|
|
command(0x50, {0x37});
|
|
}
|
|
|
|
void UC8159::set_blocking(bool blocking) {
|
|
this->blocking = blocking;
|
|
}
|
|
|
|
void UC8159::power_off() {
|
|
busy_wait();
|
|
command(POF); // turn off
|
|
}
|
|
|
|
void UC8159::command(uint8_t reg, size_t len, const uint8_t *data) {
|
|
gpio_put(CS, 0);
|
|
|
|
gpio_put(DC, 0); // command mode
|
|
spi_write_blocking(spi, ®, 1);
|
|
|
|
if(len > 0) {
|
|
gpio_put(DC, 1); // data mode
|
|
spi_write_blocking(spi, (const uint8_t*)data, len);
|
|
}
|
|
|
|
gpio_put(CS, 1);
|
|
}
|
|
|
|
void UC8159::data(size_t len, const uint8_t *data) {
|
|
gpio_put(CS, 0);
|
|
gpio_put(DC, 1); // data mode
|
|
spi_write_blocking(spi, (const uint8_t*)data, len);
|
|
gpio_put(CS, 1);
|
|
}
|
|
|
|
void UC8159::command(uint8_t reg, std::initializer_list<uint8_t> values) {
|
|
command(reg, values.size(), (uint8_t *)values.begin());
|
|
}
|
|
|
|
void UC8159::update(PicoGraphics *graphics) {
|
|
if(graphics->pen_type != PicoGraphics::PEN_3BIT) return; // Incompatible buffer
|
|
|
|
if(blocking) {
|
|
busy_wait();
|
|
}
|
|
|
|
setup();
|
|
|
|
gpio_put(CS, 0);
|
|
|
|
uint8_t reg = DTM1;
|
|
gpio_put(DC, 0); // command mode
|
|
spi_write_blocking(spi, ®, 1);
|
|
|
|
gpio_put(DC, 1); // data mode
|
|
|
|
// HACK: Output 48 rows of data since our buffer is 400px tall
|
|
// but the display has no offset configuration and H/V scan
|
|
// are reversed.
|
|
// Any garbage data will do.
|
|
// 2px per byte, so we need width * 24 bytes
|
|
if(height == 400 && rotation == ROTATE_0) {
|
|
spi_write_blocking(spi, (uint8_t *)graphics->frame_buffer, width * 24);
|
|
}
|
|
graphics->frame_convert(PicoGraphics::PEN_P4, [this](void *buf, size_t length) {
|
|
if (length > 0) {
|
|
spi_write_blocking(spi, (const uint8_t*)buf, length);
|
|
}
|
|
});
|
|
|
|
gpio_put(CS, 1);
|
|
|
|
busy_wait();
|
|
|
|
command(PON); // turn on
|
|
busy_wait(200);
|
|
|
|
command(DRF); // start display refresh
|
|
busy_wait(200);
|
|
|
|
if(blocking) {
|
|
busy_wait(32 * 1000);
|
|
|
|
command(POF); // turn off
|
|
} else {
|
|
timeout = make_timeout_time_ms(32 * 1000);
|
|
}
|
|
}
|
|
|
|
}
|