mirror of
https://github.com/geekammo/MicroView-Arduino-Library.git
synced 2026-02-22 12:31:22 +01:00
Help further reduce overdriving display inputs
(and fixed a few spelling errors in comments) - Use fast pin change macros for RESET, SS and DC. - Implement MVSPI.packetBegin() and MVSPI.packetEnd() to allow sending multiple byte "packets" while SS remains enabled. - Add 2 and 3 byte command() functions to send multiple command bytes in one packet. - Modify clear() and display() functions to send commands and data in packets. - Do the "wait for SPI transfer complete" just before sending the next byte (plus after the last or only byte) in a packet, so code can be executed while bytes are being sent. - Disable SPI mode when not transmitting, so MOSI (and SCK) will go low. - Keep DC low except when sending data bytes. - Change MVSPI.transfer() to void since nothing can be received from the display.
This commit is contained in:
266
MicroView.cpp
266
MicroView.cpp
@@ -123,119 +123,99 @@ void MicroView::begin() {
|
||||
setColor(WHITE);
|
||||
setDrawMode(NORM);
|
||||
setCursor(0,0);
|
||||
|
||||
RESETLOW;
|
||||
|
||||
// Enable 3.3V power to the display
|
||||
pinMode(OLEDPWR, OUTPUT);
|
||||
digitalWrite(OLEDPWR,HIGH);
|
||||
// Setting up SPI pins
|
||||
pinMode(MOSI, OUTPUT);
|
||||
pinMode(SCK, OUTPUT);
|
||||
|
||||
//pinMode(DC, OUTPUT);
|
||||
pinMode(RESET, OUTPUT);
|
||||
pinMode(SS, INPUT);
|
||||
digitalWrite(SS, HIGH);
|
||||
|
||||
ssport = portOutputRegister(digitalPinToPort(SS));
|
||||
sspinmask = digitalPinToBitMask(SS);
|
||||
ssreg = portModeRegister(digitalPinToPort(SS));
|
||||
|
||||
dcport = portOutputRegister(digitalPinToPort(DC));
|
||||
dcpinmask = digitalPinToBitMask(DC);
|
||||
dcreg = portModeRegister(digitalPinToPort(DC));
|
||||
|
||||
digitalWrite(RESET, HIGH);
|
||||
// VDD (3.3V) goes high at start, lets just chill for 5 ms
|
||||
|
||||
// Give some time for power to stabilise
|
||||
delay(10);
|
||||
|
||||
RESETHIGH;
|
||||
delay(5);
|
||||
// bring reset low
|
||||
digitalWrite(RESET, LOW);
|
||||
|
||||
RESETLOW;
|
||||
|
||||
// Setup SPI frequency
|
||||
MVSPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
// Initialise SPI
|
||||
MVSPI.begin();
|
||||
|
||||
// wait 10ms
|
||||
delay(10);
|
||||
|
||||
delay(5);
|
||||
|
||||
// bring out of reset
|
||||
pinMode(RESET,INPUT_PULLUP);
|
||||
//digitalWrite(RESET, HIGH);
|
||||
RESETHIGH;
|
||||
|
||||
delay(10);
|
||||
|
||||
// Init sequence for 64x48 OLED module
|
||||
command(DISPLAYOFF); // 0xAE
|
||||
|
||||
command(SETDISPLAYCLOCKDIV); // 0xD5
|
||||
command(0x80); // the suggested ratio 0x80
|
||||
|
||||
command(SETMULTIPLEX); // 0xA8
|
||||
command(0x2F);
|
||||
|
||||
command(SETDISPLAYOFFSET); // 0xD3
|
||||
command(0x0); // no offset
|
||||
|
||||
command(SETSTARTLINE | 0x0); // line #0
|
||||
|
||||
command(CHARGEPUMP); // enable charge pump
|
||||
command(0x14);
|
||||
|
||||
command(NORMALDISPLAY); // 0xA6
|
||||
command(DISPLAYALLONRESUME); // 0xA4
|
||||
|
||||
command(DISPLAYOFF); // 0xAE
|
||||
command(SETDISPLAYCLOCKDIV, 0x80); // 0xD5 / the suggested ratio 0x80
|
||||
command(SETMULTIPLEX, 0x2F); // 0xA8
|
||||
command(SETDISPLAYOFFSET, 0x0); // 0xD3 / no offset
|
||||
command(SETSTARTLINE | 0x0); // line #0
|
||||
command(CHARGEPUMP, 0x14); // enable charge pump
|
||||
command(NORMALDISPLAY); // 0xA6
|
||||
command(DISPLAYALLONRESUME); // 0xA4
|
||||
command(SEGREMAP | 0x1);
|
||||
command(COMSCANDEC);
|
||||
command(SETCOMPINS, 0x12); // 0xDA
|
||||
command(SETCONTRAST, 0x8F); // 0x81
|
||||
command(SETPRECHARGE, 0xF1); // 0xd9
|
||||
command(SETVCOMDESELECT, 0x40); // 0xDB
|
||||
command(DISPLAYON); //--turn on oled panel
|
||||
|
||||
command(SETCOMPINS); // 0xDA
|
||||
command(0x12);
|
||||
clear(ALL); // Erase hardware memory inside the OLED controller to avoid random data in memory.
|
||||
|
||||
command(SETCONTRAST); // 0x81
|
||||
command(0x8F);
|
||||
|
||||
command(SETPRECHARGE); // 0xd9
|
||||
command(0xF1);
|
||||
|
||||
command(SETVCOMDESELECT); // 0xDB
|
||||
command(0x40);
|
||||
|
||||
command(DISPLAYON); //--turn on oled panel
|
||||
clear(ALL); // Erase hardware memory inside the OLED controller to avoid random data in memory.
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
/** \brief SPI command.
|
||||
|
||||
Setup DC and SS pins, then send command via SPI to SSD1306 controller.
|
||||
/** \brief Send 1 command byte.
|
||||
|
||||
Send 1 command byte via SPI to SSD1306 controller.
|
||||
*/
|
||||
void MicroView::command(uint8_t c) {
|
||||
// Hardware SPI
|
||||
*dcreg |= dcpinmask; // Set DC pin to OUTPUT
|
||||
*dcport &= ~dcpinmask; // DC pin LOW
|
||||
|
||||
*ssreg |= sspinmask; // Set SS pin to OUTPUT
|
||||
*ssport &= ~sspinmask; // SS LOW
|
||||
|
||||
MVSPI.packetBegin();
|
||||
MVSPI.transfer(c);
|
||||
MVSPI.packetEnd();
|
||||
}
|
||||
|
||||
*ssport |= sspinmask; // SS HIGH
|
||||
*ssreg &= ~sspinmask; // Set SS pin to INPUT
|
||||
|
||||
*dcreg &= ~dcpinmask; // Set DC to INPUT to avoid high voltage over driving the OLED logic
|
||||
/** \brief Send 2 command bytes.
|
||||
|
||||
Send 2 command bytes via SPI to SSD1306 controller.
|
||||
*/
|
||||
void MicroView::command(uint8_t c1, uint8_t c2) {
|
||||
MVSPI.packetBegin();
|
||||
MVSPI.transfer(c1);
|
||||
MVSPI.wait();
|
||||
MVSPI.transfer(c2);
|
||||
MVSPI.packetEnd();
|
||||
}
|
||||
|
||||
/** \brief Send 3 command bytes.
|
||||
|
||||
Send 3 command bytes via SPI to SSD1306 controller.
|
||||
*/
|
||||
void MicroView::command(uint8_t c1, uint8_t c2, uint8_t c3) {
|
||||
MVSPI.packetBegin();
|
||||
MVSPI.transfer(c1);
|
||||
MVSPI.wait();
|
||||
MVSPI.transfer(c2);
|
||||
MVSPI.wait();
|
||||
MVSPI.transfer(c3);
|
||||
MVSPI.packetEnd();
|
||||
}
|
||||
|
||||
/** \brief SPI data.
|
||||
|
||||
Setup DC and SS pins, then send data via SPI to SSD1306 controller.
|
||||
Send 1 data byte via SPI to SSD1306 controller.
|
||||
*/
|
||||
void MicroView::data(uint8_t c) {
|
||||
// Hardware SPI
|
||||
*dcport |= dcpinmask; // DC HIGH
|
||||
|
||||
*ssreg |= sspinmask; // Set SS pin to OUTPUT
|
||||
*ssport &= ~sspinmask; // SS LOW
|
||||
|
||||
MVSPI.packetBegin();
|
||||
DCHIGH;
|
||||
MVSPI.transfer(c);
|
||||
|
||||
*ssport |= sspinmask; // SS HIGH
|
||||
*ssreg &= ~sspinmask; // Set SS pin to INPUT
|
||||
|
||||
*dcreg &= ~dcpinmask; // Set DC to INPUT to avoid high voltage over driving the OLED logic
|
||||
MVSPI.packetEnd();
|
||||
}
|
||||
|
||||
/** \brief Set SSD1306 page address.
|
||||
@@ -243,8 +223,7 @@ void MicroView::data(uint8_t c) {
|
||||
Send page address command and address to the SSD1306 OLED controller.
|
||||
*/
|
||||
void MicroView::setPageAddress(uint8_t add) {
|
||||
add=0xb0|add;
|
||||
command(add);
|
||||
command(SETPAGE|add);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -253,8 +232,7 @@ void MicroView::setPageAddress(uint8_t add) {
|
||||
Send column address command and address to the SSD1306 OLED controller.
|
||||
*/
|
||||
void MicroView::setColumnAddress(uint8_t add) {
|
||||
command((0x10|(add>>4))+0x02);
|
||||
command((0x0f&add));
|
||||
command((SETHIGHCOLUMN|(add>>4))+0x02, SETLOWCOLUMN|(0x0f&add));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -268,9 +246,14 @@ void MicroView::clear(uint8_t mode) {
|
||||
for (int i=0;i<8; i++) {
|
||||
setPageAddress(i);
|
||||
setColumnAddress(0);
|
||||
for (int j=0; j<0x80; j++) {
|
||||
data(0);
|
||||
MVSPI.packetBegin();
|
||||
DCHIGH;
|
||||
MVSPI.transfer(0);
|
||||
for (int j=1; j<0x80; j++) {
|
||||
MVSPI.wait();
|
||||
MVSPI.transfer(0);
|
||||
}
|
||||
MVSPI.packetEnd();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -290,9 +273,14 @@ void MicroView::clear(uint8_t mode, uint8_t c) {
|
||||
for (int i=0;i<8; i++) {
|
||||
setPageAddress(i);
|
||||
setColumnAddress(0);
|
||||
for (int j=0; j<0x80; j++) {
|
||||
data(c);
|
||||
MVSPI.packetBegin();
|
||||
DCHIGH;
|
||||
MVSPI.transfer(c);
|
||||
for (int j=1; j<0x80; j++) {
|
||||
MVSPI.wait();
|
||||
MVSPI.transfer(c);
|
||||
}
|
||||
MVSPI.packetEnd();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -315,11 +303,10 @@ void MicroView::invert(boolean inv) {
|
||||
|
||||
/** \brief Set contrast.
|
||||
|
||||
OLED contract value from 0 to 255. Note: Contrast level is not very obvious.
|
||||
OLED contrast value from 0 to 255. Note: Contrast level is not very obvious.
|
||||
*/
|
||||
void MicroView::contrast(uint8_t contrast) {
|
||||
command(SETCONTRAST); // 0x81
|
||||
command(contrast);
|
||||
command(SETCONTRAST, contrast); // 0x81
|
||||
}
|
||||
|
||||
/** \brief Transfer display memory.
|
||||
@@ -332,9 +319,14 @@ void MicroView::display(void) {
|
||||
for (i=0; i<6; i++) {
|
||||
setPageAddress(i);
|
||||
setColumnAddress(0);
|
||||
for (j=0;j<0x40;j++) {
|
||||
data(screenmemory[i*0x40+j]);
|
||||
MVSPI.packetBegin();
|
||||
DCHIGH;
|
||||
MVSPI.transfer(screenmemory[i*0x40]);
|
||||
for (j=1;j<0x40;j++) {
|
||||
MVSPI.wait();
|
||||
MVSPI.transfer(screenmemory[i*0x40+j]);
|
||||
}
|
||||
MVSPI.packetEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,14 +839,9 @@ size_t MicroView::write(uint8_t c) {
|
||||
if (stop<start) // stop must be larger or equal to start
|
||||
return;
|
||||
scrollStop(); // need to disable scrolling before starting to avoid memory corrupt
|
||||
command(RIGHTHORIZONTALSCROLL);
|
||||
command(0x00);
|
||||
command(start);
|
||||
command(0x7); // scroll speed frames , TODO
|
||||
command(stop);
|
||||
command(0x00);
|
||||
command(0xFF);
|
||||
command(ACTIVATESCROLL);
|
||||
command(RIGHTHORIZONTALSCROLL, 0);
|
||||
command(start, 0x7, stop); // scroll speed frames , TODO
|
||||
command(0x00, 0xFF, ACTIVATESCROLL);
|
||||
}
|
||||
|
||||
/** \brief Vertical flip.
|
||||
@@ -1639,31 +1626,27 @@ size_t MicroView::write(uint8_t c) {
|
||||
|
||||
/** \brief SPI Initialisation.
|
||||
|
||||
Setup SCK, MOSI pins for SPI transmission.
|
||||
Setup SCK, MOSI, SS and DC pins for SPI transmission.
|
||||
*/
|
||||
void MVSPIClass::begin() {
|
||||
// Set SS to high so a connected chip will be "deselected" by default
|
||||
digitalWrite(SS, HIGH);
|
||||
|
||||
// When the SS pin is set as OUTPUT, it can be used as
|
||||
// a general purpose output port (it doesn't influence
|
||||
// SPI operations).
|
||||
pinMode(SS, OUTPUT);
|
||||
|
||||
// Set SS to high so the display will be "deselected" by default
|
||||
SSHIGH;
|
||||
// Warning: if the SS pin ever becomes a LOW INPUT then SPI
|
||||
// automatically switches to Slave, so the data direction of
|
||||
// the SS pin MUST be kept as OUTPUT.
|
||||
SPCR |= _BV(MSTR);
|
||||
SPCR |= _BV(SPE);
|
||||
// automatically switches to Slave.
|
||||
// This should not occur with the MicroView as nothing can drive the pin.
|
||||
|
||||
// Set direction register for SCK and MOSI pin.
|
||||
// MISO pin automatically overrides to INPUT.
|
||||
// By doing this AFTER enabling SPI, we avoid accidentally
|
||||
// clocking in a single bit since the lines go directly
|
||||
// from "input" to SPI control.
|
||||
// http://code.google.com/p/arduino/issues/detail?id=888
|
||||
// Set DC low for command mode, where it should always default to unless
|
||||
// data is being transmitted.
|
||||
DCLOW;
|
||||
|
||||
// Set SCK and MOSI to be outputs and low when SPI is disabled.
|
||||
digitalWrite(SCK, LOW);
|
||||
digitalWrite(MOSI, LOW);
|
||||
pinMode(SCK, OUTPUT);
|
||||
pinMode(MOSI, OUTPUT);
|
||||
|
||||
// Set SPI master mode. Don't enable SPI at this time.
|
||||
SPCR |= _BV(MSTR);
|
||||
}
|
||||
|
||||
/** \brief End SPI. */
|
||||
@@ -1671,7 +1654,36 @@ size_t MicroView::write(uint8_t c) {
|
||||
SPCR &= ~_BV(SPE);
|
||||
}
|
||||
|
||||
/** \brief Set SPI bit order.
|
||||
/** \brief Set up SPI for transmitting
|
||||
|
||||
Pepare the SPI interface for transmitting on or more bytes of
|
||||
commands and/or data.
|
||||
*/
|
||||
void MVSPIClass::packetBegin() {
|
||||
// Enable SPI mode
|
||||
SPCR |= _BV(SPE);
|
||||
|
||||
// Set SS low
|
||||
SSLOW;
|
||||
}
|
||||
|
||||
/** \brief End a SPI packet transmission
|
||||
|
||||
End a SPI packet transmission:
|
||||
- Wait for the last byte to finish being transmitted.
|
||||
- Set DC to command mode (even if already set that way, just in case).
|
||||
- Set SS high.
|
||||
- Disable SPI mode (causing SCK and MOSI to go low).
|
||||
*/
|
||||
void MVSPIClass::packetEnd() {
|
||||
while (!(SPSR & _BV(SPIF)))
|
||||
;
|
||||
DCLOW;
|
||||
SSHIGH;
|
||||
SPCR &= ~_BV(SPE);
|
||||
}
|
||||
|
||||
/** \brief Set SPI bit order.
|
||||
|
||||
Set SPI port bit order with LSBFIRST or MSBFIRST.
|
||||
*/
|
||||
@@ -1686,7 +1698,7 @@ size_t MicroView::write(uint8_t c) {
|
||||
|
||||
/** \brief Set SPI data mode.
|
||||
|
||||
Set the SPI daa mode: clock polarity and phase. mode - SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3.
|
||||
Set the SPI data mode: clock polarity and phase. mode - SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3.
|
||||
*/
|
||||
void MVSPIClass::setDataMode(uint8_t mode)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user