Inky 7.3: Direct pen & PSRAM update.

pull/663/head
AndrewCapon 2023-02-01 11:31:49 +00:00 zatwierdzone przez Phil Howard
rodzic b810ffdfdb
commit 0067b101a0
15 zmienionych plików z 648 dodań i 2 usunięć

Wyświetl plik

@ -39,4 +39,6 @@ add_subdirectory(vl53l5cx)
add_subdirectory(pcf85063a)
add_subdirectory(pms5003)
add_subdirectory(sh1107)
add_subdirectory(st7567)
add_subdirectory(st7567)
add_subdirectory(psram_display)
add_subdirectory(uc8159_inky7)

Wyświetl plik

@ -0,0 +1 @@
include(psram_display.cmake)

Wyświetl plik

@ -0,0 +1,10 @@
set(DRIVER_NAME psram_display)
add_library(${DRIVER_NAME} INTERFACE)
target_sources(${DRIVER_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp)
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_spi)

Wyświetl plik

@ -0,0 +1,75 @@
#include "psram_display.hpp"
#include <cstdlib>
#include <math.h>
#include <string.h>
namespace pimoroni {
enum reg {
WRITE = 0x02,
READ = 0x03,
RESET_ENABLE = 0x66,
RESET = 0x99
};
void PSRamDisplay::init() {
uint baud = spi_init(spi, 31'250'000);
printf("PSRam connected at %u\n", baud);
gpio_set_function(CS, GPIO_FUNC_SIO);
gpio_set_dir(CS, GPIO_OUT);
gpio_put(CS, 1);
gpio_set_function(SCK, GPIO_FUNC_SPI);
gpio_set_function(MOSI, GPIO_FUNC_SPI);
gpio_set_function(MISO, GPIO_FUNC_SPI);
gpio_put(CS, 0);
uint8_t command_buffer[2] = {RESET_ENABLE, RESET};
spi_write_blocking(spi, command_buffer, 2);
gpio_put(CS, 1);
}
void PSRamDisplay::write(uint32_t address, size_t len, const uint8_t *data)
{
gpio_put(CS, 0);
uint8_t command_buffer[4] = {WRITE, (uint8_t)((address >> 16) & 0xFF), (uint8_t)((address >> 8) & 0xFF), (uint8_t)(address & 0xFF)};
spi_write_blocking(spi, command_buffer, 4);
spi_write_blocking(spi, data, len);
gpio_put(CS, 1);
}
void PSRamDisplay::write(uint32_t address, size_t len, const uint8_t byte)
{
gpio_put(CS, 0);
uint8_t command_buffer[4] = {WRITE, (uint8_t)((address >> 16) & 0xFF), (uint8_t)((address >> 8) & 0xFF), (uint8_t)(address & 0xFF)};
spi_write_blocking(spi, command_buffer, 4);
SpiSetBlocking(byte, len);
gpio_put(CS, 1);
}
void PSRamDisplay::read(uint32_t address, size_t len, uint8_t *data)
{
gpio_put(CS, 0);
uint8_t command_buffer[4] = {READ, (uint8_t)((address >> 16) & 0xFF), (uint8_t)((address >> 8) & 0xFF), (uint8_t)(address & 0xFF)};
spi_write_blocking(spi, command_buffer, 4);
spi_read_blocking(spi, 0, data, len);
gpio_put(CS, 1);
}
void PSRamDisplay::write_pixel(const Point &p, uint8_t colour)
{
write(pointToAddress(p), 1, colour);
}
void PSRamDisplay::write_pixel_span(const Point &p, uint l, uint8_t colour)
{
write(pointToAddress(p), l, colour);
}
void PSRamDisplay::read_pixel_span(const Point &p, uint l, uint8_t *data)
{
read(pointToAddress(p), l, data);
}
}

Wyświetl plik

@ -0,0 +1,128 @@
#pragma once
#include <cstring>
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "hardware/gpio.h"
#include "common/pimoroni_common.hpp"
#include "common/pimoroni_bus.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
// 8 MB PSRam
namespace pimoroni {
class PSRamDisplay : public IDirectDisplayDriver<uint8_t> {
//--------------------------------------------------
// Variables
//--------------------------------------------------
private:
spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE;
// interface pins with our standard defaults where appropriate
uint CS = 3;
uint DC = PIN_UNUSED;
uint SCK = SPI_DEFAULT_SCK;
uint MOSI = SPI_DEFAULT_MOSI;
uint MISO = SPI_DEFAULT_MISO;
uint32_t start_address = 0;
uint16_t width = 0;
uint16_t height = 0;
absolute_time_t timeout;
bool blocking = false;
public:
enum colour : uint8_t {
BLACK = 0,
WHITE = 1,
GREEN = 2,
BLUE = 3,
RED = 4,
YELLOW = 5,
ORANGE = 6,
CLEAN = 7
};
PSRamDisplay(uint16_t width, uint16_t height) : PSRamDisplay(width, height, {PIMORONI_SPI_DEFAULT_INSTANCE, 3, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, PIN_UNUSED, PIN_UNUSED}) {};
PSRamDisplay(uint16_t width, uint16_t height, SPIPins pins) :
spi(pins.spi),
CS(pins.cs), DC(pins.dc), SCK(pins.sck), MOSI(pins.mosi),
width(width), height(height) {
init();
}
//--------------------------------------------------
// Methods
//--------------------------------------------------
public:
void test(void){
char writeBuffer[1024];
char readBuffer[1024];
uint mb = 8;
for(uint k = 0; k < 1024*mb; k++)
{
sprintf(writeBuffer, "%u", k);
write(k*1024, strlen(writeBuffer)+1, (uint8_t *)writeBuffer);
}
bool bSame = true;
for(uint k = 0; k < 1024*mb && bSame; k++)
{
sprintf(writeBuffer, "%u", k);
read(k*1024, strlen(writeBuffer)+1, (uint8_t *)readBuffer);
bSame = strcmp(writeBuffer, readBuffer) ==0;
printf("[%u] %s == %s ? %s\n", k, writeBuffer, readBuffer, bSame ? "Success" : "Failure");
}
}
void write_pixel(const Point &p, uint8_t colour) override;
void write_pixel_span(const Point &p, uint l, uint8_t colour) override;
void read_pixel_span(const Point &p, uint l, uint8_t *data) override;
int __not_in_flash_func(SpiSetBlocking)(const uint16_t uSrc, size_t uLen)
{
invalid_params_if(SPI, 0 > (int)uLen);
// Deliberately overflow FIFO, then clean up afterward, to minimise amount
// of APB polling required per halfword
for (size_t i = 0; i < uLen; ++i) {
while (!spi_is_writable(spi))
tight_loop_contents();
spi_get_hw(spi)->dr = uSrc;
}
while (spi_is_readable(spi))
(void)spi_get_hw(spi)->dr;
while (spi_get_hw(spi)->sr & SPI_SSPSR_BSY_BITS)
tight_loop_contents();
while (spi_is_readable(spi))
(void)spi_get_hw(spi)->dr;
// Don't leave overrun flag set
spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS;
return (int)uLen;
}
private:
void init();
void write(uint32_t address, size_t len, const uint8_t *data);
void write(uint32_t address, size_t len, const uint8_t byte);
void read(uint32_t address, size_t len, uint8_t *data);
uint32_t pointToAddress(const Point &p)
{
return start_address + (p.y * width) + p.x;
}
};
}

Wyświetl plik

@ -0,0 +1 @@
include(uc8159_inky7.cmake)

Wyświetl plik

@ -0,0 +1,10 @@
set(DRIVER_NAME uc8159_inky7)
add_library(${DRIVER_NAME} INTERFACE)
target_sources(${DRIVER_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp)
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
# Pull in pico libraries that we need
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_spi)

Wyświetl plik

@ -0,0 +1,206 @@
#include "uc8159_inky7.hpp"
#include <cstdlib>
#include <math.h>
#include <string.h>
namespace pimoroni {
enum reg {
PSR = 0x00,
PWR = 0x01,
POF = 0x02,
PFS = 0x03,
PON = 0x04,
BTST1 = 0x05,
BTST2 = 0x06,
DSLP = 0x07,
BTST3 = 0x08,
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,
T_VDCS = 0x84,
AGID = 0x86,
CMDH = 0xAA,
CCSET =0xE0,
PWS = 0xE3,
TSSET = 0xE6 // E5 or E6
};
bool UC8159Inky7::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 UC8159Inky7::busy_wait(uint minimum_wait_ms) {
timeout = make_timeout_time_ms(minimum_wait_ms);
while(is_busy()) {
tight_loop_contents();
}
}
void UC8159Inky7::reset() {
gpio_put(RESET, 0); sleep_ms(10);
gpio_put(RESET, 1); sleep_ms(10);
busy_wait();
}
void UC8159Inky7::init() {
// configure spi interface and pins
spi_init(spi, 20'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 UC8159Inky7::setup() {
reset();
busy_wait();
command(CMDH, {0x49, 0x55, 0x20, 0x08, 0x09, 0x18});
command(PWR, {0x3F, 0x00, 0x32, 0x2A, 0x0E, 0x2A});
if (rotation == ROTATE_0) {
command(PSR, {0x53, 0x69});
} else {
command(PSR, {0x5F, 0x69});
}
//command(PSR, {0x5F, 0x69});
command(PFS, {0x00, 0x54, 0x00, 0x44});
command(BTST1, {0x40, 0x1F, 0x1F, 0x2C});
command(BTST2, {0x6F, 0x1F, 0x16, 0x25});
command(BTST3, {0x6F, 0x1F, 0x1F, 0x22});
command(IPC, {0x00, 0x04});
command(PLL, {0x02});
command(TSE, {0x00});
command(CDI, {0x3F});
command(TCON, {0x02, 0x00});
command(TRES, {0x03, 0x20, 0x01, 0xE0});
command(VDCS, {0x1E});
command(T_VDCS, {0x00});
command(AGID, {0x00});
command(PWS, {0x2F});
command(CCSET, {0x00});
command(TSSET, {0x00});
}
void UC8159Inky7::set_blocking(bool blocking) {
this->blocking = blocking;
}
void UC8159Inky7::power_off() {
busy_wait();
command(POF); // turn off
}
void UC8159Inky7::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, &reg, 1);
if(len > 0) {
gpio_put(DC, 1); // data mode
spi_write_blocking(spi, (const uint8_t*)data, len);
}
gpio_put(CS, 1);
}
void UC8159Inky7::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 UC8159Inky7::command(uint8_t reg, std::initializer_list<uint8_t> values) {
command(reg, values.size(), (uint8_t *)values.begin());
}
void UC8159Inky7::update(PicoGraphics *graphics) {
if(graphics->pen_type != PicoGraphics::PEN_INKY7) 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, &reg, 1);
gpio_put(DC, 1); // data mode
uint totalLength = 0;
gpio_put(CS, 1);
graphics->frame_convert(PicoGraphics::PEN_INKY7, [this, &totalLength](void *buf, size_t length) {
if (length > 0) {
gpio_put(CS, 0);
spi_write_blocking(spi, (const uint8_t*)buf, length);
totalLength += length;
gpio_put(CS, 1);
}
});
gpio_put(DC, 0); // data mode
gpio_put(CS, 1);
busy_wait();
command(PON, {0}); // turn on
busy_wait(200);
command(DRF, {0}); // start display refresh
busy_wait(200);
if(blocking) {
busy_wait(32 * 1000);
command(POF); // turn off
} else {
timeout = make_timeout_time_ms(32 * 1000);
}
}
}

Wyświetl plik

@ -0,0 +1,80 @@
#pragma once
#include <initializer_list>
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "hardware/gpio.h"
#include "common/pimoroni_common.hpp"
#include "common/pimoroni_bus.hpp"
#include "libraries/pico_graphics/pico_graphics.hpp"
namespace pimoroni {
class UC8159Inky7 : public DisplayDriver {
//--------------------------------------------------
// Variables
//--------------------------------------------------
private:
spi_inst_t *spi = PIMORONI_SPI_DEFAULT_INSTANCE;
// interface pins with our standard defaults where appropriate
uint CS = SPI_BG_FRONT_CS;
uint DC = 28; // 27;
uint SCK = SPI_DEFAULT_SCK;
uint MOSI = SPI_DEFAULT_MOSI;
uint BUSY = PIN_UNUSED;
uint RESET = 27; //25;
absolute_time_t timeout;
bool blocking = false;
public:
enum colour : uint8_t {
BLACK = 0,
WHITE = 1,
GREEN = 2,
BLUE = 3,
RED = 4,
YELLOW = 5,
ORANGE = 6,
CLEAN = 7
};
UC8159Inky7(uint16_t width, uint16_t height) : UC8159Inky7(width, height, ROTATE_0, {PIMORONI_SPI_DEFAULT_INSTANCE, SPI_BG_FRONT_CS, SPI_DEFAULT_SCK, SPI_DEFAULT_MOSI, PIN_UNUSED, 28, PIN_UNUSED}) {};
UC8159Inky7(uint16_t width, uint16_t height, SPIPins pins, uint busy=PIN_UNUSED, uint reset=27) : UC8159Inky7(width, height, ROTATE_0, pins, busy, reset) {};
UC8159Inky7(uint16_t width, uint16_t height, Rotation rotation, SPIPins pins, uint busy=PIN_UNUSED, uint reset=27) :
DisplayDriver(width, height, rotation),
spi(pins.spi),
CS(pins.cs), DC(pins.dc), SCK(pins.sck), MOSI(pins.mosi), BUSY(busy), RESET(reset) {
init();
}
//--------------------------------------------------
// Methods
//--------------------------------------------------
public:
void busy_wait(uint minimum_wait_ms=0);
void reset();
void power_off();
bool is_busy() override;
void update(PicoGraphics *graphics) override;
void set_blocking(bool blocking);
private:
void init();
void setup();
void command(uint8_t reg, size_t len, const uint8_t *data);
void command(uint8_t reg, std::initializer_list<uint8_t> values);
void command(uint8_t reg, const uint8_t data) {command(reg, 0, &data);};
void command(uint8_t reg) {command(reg, 0, nullptr);};
void data(size_t len, const uint8_t *data);
};
}

Wyświetl plik

@ -1,3 +1,4 @@
include(inky_frame_jpeg_image.cmake)
include(inky_frame_sleepy_head.cmake)
include(inky_frame_day_planner.cmake)
include(inky_frame_day_planner.cmake)
include(inky_frame7_test.cmake)

Wyświetl plik

@ -0,0 +1,14 @@
set(OUTPUT_NAME inky_frame7_test)
add_executable(
${OUTPUT_NAME}
inky_frame7_test.cpp
)
# Pull in pico libraries that we need
target_link_libraries(${OUTPUT_NAME} pico_stdlib psram_display uc8159_inky7 inky_frame hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics)
pico_enable_stdio_usb(${OUTPUT_NAME} 0)
# create map/bin/hex file etc.
pico_add_extra_outputs(${OUTPUT_NAME})

Wyświetl plik

@ -0,0 +1,39 @@
#include <cstdio>
#include <math.h>
#include <stdio.h>
#include "drivers/psram_display/psram_display.hpp"
#include "drivers/uc8159_inky7/uc8159_inky7.hpp"
using namespace pimoroni;
int main() {
stdio_init_all();
PSRamDisplay ramDisplay(800, 480);
PicoGraphics_PenInky7 graphics(800, 480, ramDisplay);
UC8159Inky7 uc8159(800,400);
graphics.set_pen(1);
graphics.clear();
for(int i =0 ; i < 100 ; i++)
{
uint size = 25 + (rand() % 50);
uint x = rand() % graphics.bounds.w;
uint y = rand() % graphics.bounds.h;
graphics.set_pen(0);
graphics.circle(Point(x, y), size);
graphics.set_pen(2+(i%5));
graphics.circle(Point(x, y), size-2);
}
uc8159.update(&graphics);
while(true)
sleep_ms(1000);
return 0;
}

Wyświetl plik

@ -9,6 +9,7 @@ add_library(pico_graphics
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb332.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb565.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_rgb888.cpp
${CMAKE_CURRENT_LIST_DIR}/pico_graphics_pen_inky7.cpp
)
target_include_directories(pico_graphics INTERFACE ${CMAKE_CURRENT_LIST_DIR})

Wyświetl plik

@ -168,6 +168,7 @@ namespace pimoroni {
PEN_RGB332,
PEN_RGB565,
PEN_RGB888,
PEN_INKY7
};
void *frame_buffer;
@ -486,4 +487,32 @@ namespace pimoroni {
virtual void cleanup() {};
};
template<typename T> class IDirectDisplayDriver {
public:
virtual void write_pixel(const Point &p, T colour) = 0;
virtual void write_pixel_span(const Point &p, uint l, T colour) = 0;
virtual void read_pixel(const Point &p, T &data) {};
virtual void read_pixel_span(const Point &p, uint l, T *data) {};
};
class PicoGraphics_PenInky7 : public PicoGraphics {
public:
RGB src_color;
RGB565 color;
IDirectDisplayDriver<uint8_t> &driver;
PicoGraphics_PenInky7(uint16_t width, uint16_t height, IDirectDisplayDriver<uint8_t> &direct_display_driver);
void set_pen(uint c) override;
void set_pen(uint8_t r, uint8_t g, uint8_t b) override;
void set_thickness(uint t) override {};
int create_pen(uint8_t r, uint8_t g, uint8_t b) override;
void set_pixel(const Point &p) override;
void set_pixel_span(const Point &p, uint l) override;
void frame_convert(PenType type, conversion_callback_func callback) override;
static size_t buffer_size(uint w, uint h) {
return w * h;
}
};
}

Wyświetl plik

@ -0,0 +1,49 @@
#include "pico_graphics.hpp"
namespace pimoroni {
PicoGraphics_PenInky7::PicoGraphics_PenInky7(uint16_t width, uint16_t height, IDirectDisplayDriver<uint8_t> &direct_display_driver)
: PicoGraphics(width, height, nullptr),
driver(direct_display_driver) {
this->pen_type = PEN_INKY7;
}
void PicoGraphics_PenInky7::set_pen(uint c) {
color = c & 0x7;
}
void PicoGraphics_PenInky7::set_pen(uint8_t r, uint8_t g, uint8_t b) {
}
int PicoGraphics_PenInky7::create_pen(uint8_t r, uint8_t g, uint8_t b) {
return 0;
}
void PicoGraphics_PenInky7::set_pixel(const Point &p) {
driver.write_pixel(p, color);
}
void PicoGraphics_PenInky7::set_pixel_span(const Point &p, uint l) {
driver.write_pixel_span(p, l, color);
}
void PicoGraphics_PenInky7::frame_convert(PenType type, conversion_callback_func callback) {
if(type == PEN_INKY7) {
uint byte_count = bounds.w/2;
uint8_t buffer[bounds.w];
for(int32_t r = 0; r < bounds.h; r++)
{
driver.read_pixel_span(Point(0, r), bounds.w, buffer);
// for(int y=0; y < 800; y++)
// buffer[y] = rand() % 7;
// convert byte storage to nibble storage
uint8_t *pDst = buffer;
uint8_t *pSrc = buffer;
for(uint c = 0; c < byte_count; c++)
{
uint8_t nibble = ((*pSrc++) << 4);
nibble |= ((*pSrc++) & 0xf);
*pDst++ = nibble;
}
callback(buffer, byte_count);
}
}
}
}