Skip to content

File oled_ssd1327.h

File List > dev > oled_ssd1327.h

Go to the documentation of this file

Source Code

#pragma once

#include "per/spi.h"
#include "per/gpio.h"
#include "sys/system.h"

namespace daisy
{
class SSD13274WireSpiTransport
{
  public:
    struct Config
    {
        Config()
        {
            // Initialize using defaults
            Defaults();
        }
        SpiHandle::Config spi_config;
        struct
        {
            Pin dc;    
            Pin reset; 
        } pin_config;
        void Defaults()
        {
            // SPI peripheral config
            spi_config.periph = SpiHandle::Config::Peripheral::SPI_1;
            spi_config.mode   = SpiHandle::Config::Mode::MASTER;
            spi_config.direction
                = SpiHandle::Config::Direction::TWO_LINES_TX_ONLY;
            spi_config.datasize       = 8;
            spi_config.clock_polarity = SpiHandle::Config::ClockPolarity::LOW;
            spi_config.clock_phase    = SpiHandle::Config::ClockPhase::ONE_EDGE;
            spi_config.nss            = SpiHandle::Config::NSS::HARD_OUTPUT;
            spi_config.baud_prescaler = SpiHandle::Config::BaudPrescaler::PS_8;
            // SPI pin config
            spi_config.pin_config.sclk = Pin(PORTG, 11);
            spi_config.pin_config.miso = Pin(PORTX, 0);
            spi_config.pin_config.mosi = Pin(PORTB, 5);
            spi_config.pin_config.nss  = Pin(PORTG, 10);
            // SSD1327 control pin config
            pin_config.dc    = Pin(PORTB, 4);
            pin_config.reset = Pin(PORTB, 15);
        }
    };
    void Init(const Config& config)
    {
        // Initialize both GPIO
        pin_dc_.Init(config.pin_config.dc, GPIO::Mode::OUTPUT);
        pin_reset_.Init(config.pin_config.reset, GPIO::Mode::OUTPUT);

        // Initialize SPI
        spi_.Init(config.spi_config);

        // Reset and Configure OLED.
        pin_reset_.Write(false);
        System::Delay(10);
        pin_reset_.Write(true);
        System::Delay(10);
    };
    void SendCommand(uint8_t cmd)
    {
        pin_dc_.Write(false);
        spi_.BlockingTransmit(&cmd, 1);
    };

    void SendData(uint8_t* buff, size_t size)
    {
        pin_dc_.Write(true);
        spi_.BlockingTransmit(buff, size);
    };

  private:
    SpiHandle spi_;
    GPIO      pin_reset_;
    GPIO      pin_dc_;
};


template <size_t width, size_t height, typename Transport>
class SSD1327Driver
{
  public:
    struct Config
    {
        typename Transport::Config transport_config;
    };

    void Init(Config config)
    {
        color_ = 0x0f;
        transport_.Init(config.transport_config);

        transport_.SendCommand(0x15); // set column address
        transport_.SendCommand(0x00); // start column   0
        transport_.SendCommand(0x3f); // end column 63*2 (two pixels / byte)

        transport_.SendCommand(0x75); // set row address
        transport_.SendCommand(0x00); // start row   0
        transport_.SendCommand(0x7f); // end row   127

        transport_.SendCommand(0x81); // set contrast control
        transport_.SendCommand(0x80);

        transport_.SendCommand(0xa0); // Set Re-map (0x51)
        transport_.SendCommand(
            0x51); // Column Address Remapping, COM Remapping, Splitting of Odd / Even COM Signals

        transport_.SendCommand(0xa1); // start line
        transport_.SendCommand(0x00);

        transport_.SendCommand(0xa2); // display offset
        transport_.SendCommand(0x00);

        transport_.SendCommand(0xa4); // normal display
        transport_.SendCommand(0xa8); // set multiplex ratio
        transport_.SendCommand(0x7f);

        transport_.SendCommand(0xb1); // set phase length
        transport_.SendCommand(0xf1);

        transport_.SendCommand(0xb3); // set dclk
        transport_.SendCommand(
            0x00); // 80Hz:0xc1 / 90Hz:0xe1 / 100Hz:0x00 / 110Hz:0x30 / 120Hz:0x50 / 130Hz:0x70

        transport_.SendCommand(0xab); // Function Selection A
        transport_.SendCommand(0x01);

        transport_.SendCommand(0xb6); // set phase length
        transport_.SendCommand(0x0f);

        transport_.SendCommand(0xbe); // Set VCOMH
        transport_.SendCommand(0x0f);

        transport_.SendCommand(0xbc); // Set Pre-charge voltage
        transport_.SendCommand(0x08);

        transport_.SendCommand(0xd5); // Function Selection B
        transport_.SendCommand(0x62); // Enable second pre-charge

        transport_.SendCommand(0xfd); // unlock command
        transport_.SendCommand(0x12);

        System::Delay(200);           //    wait 200ms
        transport_.SendCommand(0xaf); // turn on display
        Fill(false);
    };

    size_t Width() const { return width; };
    size_t Height() const { return height; };

    void DrawPixel(uint_fast8_t x, uint_fast8_t y, bool on)
    {
        uint8_t  pixel;
        uint32_t line = width / 2;

        if((x >= width) || (y >= height))
            return;

        if(on)
        {
            pixel = buffer_[y * line + (x / 2)];
            if(x % 2)
            {
                pixel &= 0xf0;
                pixel |= color_;
            }
            else
            {
                pixel &= 0x0f;
                pixel |= color_ << 4;
            }
            buffer_[y * line + (x / 2)] = pixel;
        }
        else
        {
            pixel = buffer_[y * line + (x / 2)];
            if(x % 2)
            {
                pixel &= 0xf0;
            }
            else
            {
                pixel &= 0x0f;
            }
            buffer_[y * line + (x / 2)] = pixel;
        }
    };

    void Fill(bool on)
    {
        for(size_t i = 0; i < sizeof(buffer_); i++)
        {
            buffer_[i] = on ? 0xff : 0x00;
        }
    };

    void Update()
    {
        transport_.SendCommand(0x15); // column
        transport_.SendCommand(0x00);
        transport_.SendCommand((width / 2) - 1);

        transport_.SendCommand(0x75); // row
        transport_.SendCommand(0x00);
        transport_.SendCommand(height - 1);

        //write data
        transport_.SendData(buffer_, 8192);
    };

    void Set_Color(uint8_t in_col) { color_ = in_col & 0x0f; };

  protected:
    Transport transport_;
    uint8_t   buffer_[width / 2 * height];
    uint8_t   color_;
};

using SSD13274WireSpi128x128Driver
    = daisy::SSD1327Driver<128, 128, SSD13274WireSpiTransport>;

}; // namespace daisy