kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			
		
			
				
	
	
		
			211 wiersze
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			211 wiersze
		
	
	
		
			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);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
}
 |