* @file Jamis_SSD1322.h
*
* This is a partial port of Adafruit's SSD1306 library to the SSD1322
* display.
*
* These displays use SPI to communicate. SPI requires 4 pins (MOSI, SCK,
* select, data/command) and optionally a reset pin.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Limor Fried/Ladyada for Adafruit Industries, with
* contributions from the open source community.
*
* BSD license, all text above, and the splash screen header file,
* must be included in any redistribution.
*
*/
#include "../core/options.h"
#if DSP_MODEL==DSP_SSD1322
#define pgm_read_byte(addr) \
(*(const unsigned char *)(addr))
#include <Adafruit_GFX.h>
#include "SSD1322.h"
#define ssd1322_swap(a, b) \
(((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b)))
#define SSD1322_SELECT digitalWrite(csPin, LOW);
#define SSD1322_DESELECT digitalWrite(csPin, HIGH);
#define SSD1322_MODE_COMMAND digitalWrite(dcPin, LOW);
#define SSD1322_MODE_DATA digitalWrite(dcPin, HIGH);
#if defined(SPI_HAS_TRANSACTION)
#define SPI_TRANSACTION_START spi->beginTransaction(spiSettings)
#define SPI_TRANSACTION_END spi->endTransaction()
#else
#define SPI_TRANSACTION_START
#define SPI_TRANSACTION_END
#endif
#define TRANSACTION_START \
if(spi) { \
SPI_TRANSACTION_START; \
} \
SSD1322_SELECT;
#define TRANSACTION_END \
SSD1322_DESELECT; \
if(spi) { \
SPI_TRANSACTION_END; \
}
@brief Constructor for SPI SSD1306 displays, using native hardware SPI.
@param w
Display width in pixels
@param h
Display height in pixels
@param spi
Pointer to an existing SPIClass instance (e.g. &SPI, the
microcontroller's primary SPI bus).
@param dc_pin
Data/command pin (using Arduino pin numbering), selects whether
display is receiving commands (low) or data (high).
@param rst_pin
Reset pin (using Arduino pin numbering), or -1 if not used
(some displays might be wired to share the microcontroller's
reset pin).
@param cs_pin
Chip-select pin (using Arduino pin numbering) for sharing the
bus with other devices. Active low.
@param bitrate
SPI clock rate for transfers to this display. Default if
unspecified is 8000000UL (8 MHz).
@return Jamis_SSD1322 object.
@note Call the object's begin() function before use -- buffer
allocation is performed there!
*/
Jamis_SSD1322::Jamis_SSD1322(int16_t w, int16_t h, SPIClass *spi,
int8_t dc_pin, int8_t rst_pin, int8_t cs_pin, uint32_t bitrate) :
Adafruit_GFX(w, h), spi(spi ? spi : &SPI), buffer(NULL),
mosiPin(-1), clkPin(-1), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin) {
#ifdef SPI_HAS_TRANSACTION
spiSettings = SPISettings(bitrate, MSBFIRST, SPI_MODE3);
#endif
}
@brief Destructor for Jamis_SSD1322 object.
*/
Jamis_SSD1322::~Jamis_SSD1322(void) {
if(buffer) {
free(buffer);
buffer = NULL;
}
}
inline void Jamis_SSD1322::SPIwrite(uint8_t d) {
spi->transfer(d);
}
void Jamis_SSD1322::ssd1322_command1(uint8_t c) {
SSD1322_MODE_COMMAND
SPIwrite(c);
}
void Jamis_SSD1322::ssd1322_data1(uint8_t c) {
SSD1322_MODE_DATA
SPIwrite(c);
}
@brief Issue a single low-level command directly to the SSD1306
display, bypassing the library.
@param c
Command to issue (0x00 to 0xFF, see datasheet).
@return None (void).
*/
void Jamis_SSD1322::ssd1322_command(uint8_t c) {
TRANSACTION_START
ssd1322_command1(c);
TRANSACTION_END
}
@brief Allocate RAM for image buffer, initialize peripherals and pins.
@param reset
If true, and if the reset pin passed to the constructor is
valid, a hard reset will be performed before initializing the
display. If using multiple SSD1322 displays on the same bus, and
if they all share the same reset pin, you should only pass true
on the first display being initialized, false on all others,
else the already-initialized displays would be reset. Default if
unspecified is true.
@param periphBegin
If true, and if a hardware peripheral is being used (I2C or SPI,
but not software SPI), call that peripheral's begin() function,
else (false) it has already been done in one's sketch code.
Cases where false might be used include multiple displays or
other devices sharing a common bus, or situations on some
platforms where a nonstandard begin() function is available
(e.g. a TwoWire interface on non-default pins, as can be done
on the ESP8266 and perhaps others).
@return true on successful allocation/init, false otherwise.
Well-behaved code should check the return value before
proceeding.
@note MUST call this function before any drawing or updates!
*/
boolean Jamis_SSD1322::begin(boolean reset, boolean periphBegin) {
if((!buffer) && !(buffer = (uint8_t *)malloc( WIDTH * ((HEIGHT) / 2) )))
return false;
clearDisplay();
pinMode(dcPin, OUTPUT);
pinMode(csPin, OUTPUT);
SSD1322_DESELECT
if(periphBegin) spi->begin();
if(reset && (rstPin >= 0)) {
pinMode( rstPin, OUTPUT);
digitalWrite(rstPin, HIGH);
delay(1);
digitalWrite(rstPin, LOW);
delay(10);
digitalWrite(rstPin, HIGH);
}
TRANSACTION_START
ssd1322_command1(0xFD);
ssd1322_data1(0x12);
ssd1322_command1(0xA4);
ssd1322_command1(0xB3);
ssd1322_data1(0x91);
ssd1322_command1(0xCA);
ssd1322_data1(0x3F);
ssd1322_command1(0xA2);
ssd1322_data1(0x00);
ssd1322_command1(0xA1);
ssd1322_data1(0x00);
ssd1322_command1(0xA0);
ssd1322_data1(0x14);
ssd1322_data1(0x11);
ssd1322_command1(0xB5);
ssd1322_data1(0x00);
ssd1322_command1(0xAB);
ssd1322_data1(0x01);
ssd1322_command1(0xB4);
ssd1322_data1(0xA0);
ssd1322_data1(0xB5);
ssd1322_command1(0xC1);
ssd1322_data1(0x7F);
ssd1322_command1(0xC7);
ssd1322_data1(0x0F);
ssd1322_command1(0xB9);
ssd1322_command1(0xB1);
ssd1322_data1(0xE2);
ssd1322_command1(0xD1);
ssd1322_data1(0xA2);
ssd1322_data1(0x20);
ssd1322_command1(0xBB);
ssd1322_data1(0x1F);
ssd1322_command1(0xB6);
ssd1322_data1(0x08);
ssd1322_command1(0xBE);
ssd1322_data1(0x07);
ssd1322_command1(0xA6);
ssd1322_command1(0xA9);
ssd1322_command1(0xAF);
TRANSACTION_END
return true;
}
@brief Set/clear/invert a single pixel. This is also invoked by the
Adafruit_GFX library in generating many higher-level graphics
primitives.
@param x
Column of display -- 0 at left to (screen width - 1) at right.
@param y
Row of display -- 0 at top to (screen height -1) at bottom.
@param color
Pixel color, one of: BLACK, WHITE or INVERT.
@return None (void).
@note Changes buffer contents only, no immediate effect on display.
Follow up with a call to display(), or with other graphics
commands as needed by one's own application.
*/
void Jamis_SSD1322::drawPixel(int16_t x, int16_t y, uint16_t color) {
if((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {
switch(getRotation()) {
case 1:
ssd1322_swap(x, y);
x = WIDTH - x - 1;
break;
case 2:
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
break;
case 3:
ssd1322_swap(x, y);
y = HEIGHT - y - 1;
break;
default: break;
}
buffer[(x >> 1) + (y)*WIDTH/2] &= (x % 2) ? 0xF0 : 0x0F;
buffer[(x >> 1) + (y)*WIDTH/2] |= (color << (!(x & 1) * 4) );
}
}
@brief Clear contents of display buffer (set all pixels to off).
@return None (void).
@note Changes buffer contents only, no immediate effect on display.
Follow up with a call to display(), or with other graphics
commands as needed by one's own application.
*/
void Jamis_SSD1322::clearDisplay(void) {
memset(buffer, 0, WIDTH * ((HEIGHT) / 2));
}
@brief Draw a horizontal line. This is also invoked by the Adafruit_GFX
library in generating many higher-level graphics primitives.
@param x
Leftmost column -- 0 at left to (screen width - 1) at right.
@param y
Row of display -- 0 at top to (screen height -1) at bottom.
@param w
Width of line, in pixels.
@param color
Line color, one of: BLACK, WHITE or INVERT.
@return None (void).
@note Changes buffer contents only, no immediate effect on display.
Follow up with a call to display(), or with other graphics
commands as needed by one's own application.
*/
void Jamis_SSD1322::drawFastHLine(
int16_t x, int16_t y, int16_t w, uint16_t color) {
boolean bSwap = false;
switch(rotation) {
case 1:
bSwap = true;
ssd1322_swap(x, y);
x = WIDTH - x - 1;
break;
case 2:
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
x -= (w-1);
break;
case 3:
bSwap = true;
ssd1322_swap(x, y);
y = HEIGHT - y - 1;
y -= (w-1);
break;
}
if(bSwap) drawFastVLineInternal(x, y, w, color);
else drawFastHLineInternal(x, y, w, color);
}
void Jamis_SSD1322::drawFastHLineInternal(
int16_t x, int16_t y, int16_t w, uint16_t color) {
if((y >= 0) && (y < HEIGHT)) {
if(x < 0) {
w += x;
x = 0;
}
if((x + w) > WIDTH) {
w = (WIDTH - x);
}
if(w > 0) {
uint16_t yOffset = (y)*WIDTH/2;
uint8_t b1 = (x % 2) ? 0xF0 : 0x0F;
while(w--) {
buffer[((x + w) >> 1) + yOffset] &= b1;
buffer[((x + w) >> 1) + yOffset] |= (color << (!((x + w) & 1) * 4) );
}
}
}
}
@brief Draw a vertical line. This is also invoked by the Adafruit_GFX
library in generating many higher-level graphics primitives.
@param x
Column of display -- 0 at left to (screen width -1) at right.
@param y
Topmost row -- 0 at top to (screen height - 1) at bottom.
@param h
Height of line, in pixels.
@param color
Line color, one of: BLACK, WHITE or INVERT.
@return None (void).
@note Changes buffer contents only, no immediate effect on display.
Follow up with a call to display(), or with other graphics
commands as needed by one's own application.
*/
void Jamis_SSD1322::drawFastVLine(
int16_t x, int16_t y, int16_t h, uint16_t color) {
boolean bSwap = false;
switch(rotation) {
case 1:
bSwap = true;
ssd1322_swap(x, y);
x = WIDTH - x - 1;
x -= (h-1);
break;
case 2:
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
y -= (h-1);
break;
case 3:
bSwap = true;
ssd1322_swap(x, y);
y = HEIGHT - y - 1;
break;
}
if(bSwap) drawFastHLineInternal(x, y, h, color);
else drawFastVLineInternal(x, y, h, color);
}
void Jamis_SSD1322::drawFastVLineInternal(
int16_t x, int16_t __y, int16_t __h, uint16_t color) {
if((x >= 0) && (x < WIDTH)) {
if(__y < 0) {
__h += __y;
__y = 0;
}
if((__y + __h) > HEIGHT) {
__h = (HEIGHT - __y);
}
if(__h > 0) {
uint16_t xOffset = (x >> 1);
uint16_t mask = (color << (!(x & 1) * 4) );
uint8_t b1 = (x % 2) ? 0xF0 : 0x0F;
while(__h--) {
buffer[xOffset + (__y+__h)*WIDTH/2] &= b1;
buffer[xOffset + (__y+__h)*WIDTH/2] |= mask;
}
}
}
}
@brief Return color of a single pixel in display buffer.
@param x
Column of display -- 0 at left to (screen width - 1) at right.
@param y
Row of display -- 0 at top to (screen height -1) at bottom.
@return true if pixel is set (usually WHITE, unless display invert mode
is enabled), false if clear (BLACK).
@note Reads from buffer contents; may not reflect current contents of
screen if display() has not been called.
*/
boolean Jamis_SSD1322::getPixel(int16_t x, int16_t y) {
if((x >= 0) && (x < width()) && (y >= 0) && (y < height())) {
switch(getRotation()) {
case 1:
ssd1322_swap(x, y);
x = WIDTH - x - 1;
break;
case 2:
x = WIDTH - x - 1;
y = HEIGHT - y - 1;
break;
case 3:
ssd1322_swap(x, y);
y = HEIGHT - y - 1;
break;
}
return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7)));
}
return false;
}
@brief Get base address of display buffer for direct reading or writing.
@return Pointer to an unsigned 8-bit array, column-major, columns padded
to full byte boundary if needed.
*/
uint8_t *Jamis_SSD1322::getBuffer(void) {
return buffer;
}
@brief Push data currently in RAM to SSD1306 display.
@return None (void).
@note Drawing operations are not visible until this function is
called. Call after each graphics command, or after a whole set
of graphics commands, as best needed by one's own application.
*/
void Jamis_SSD1322::display(void) {
TRANSACTION_START
ssd1322_command1(0x15);
const uint16_t Col0Off = 0x70;
const uint16_t ColDiv = 4;
ssd1322_data1( (Col0Off+0x00)/ColDiv );
ssd1322_data1( (Col0Off+WIDTH-1)/ColDiv );
ssd1322_command1(0x75);
ssd1322_data1(0x00);
ssd1322_data1(HEIGHT-1);
ssd1322_command1(0x5C);
uint16_t count = WIDTH * ((HEIGHT) / 2);
uint8_t *ptr = buffer;
SSD1322_MODE_DATA
while(count--) SPIwrite(*ptr++);
TRANSACTION_END
}
void Jamis_SSD1322::invertDisplay(boolean flag) {
ssd1322_command(flag ? SSD1322_INVERSEDISPLAY : SSD1322_NORMALDISPLAY);
}
#endif