diff --git a/board-package-source/libraries/Arduboy/src/core/core.cpp b/board-package-source/libraries/Arduboy/src/core/core.cpp index dc446d7..eaad76b 100644 --- a/board-package-source/libraries/Arduboy/src/core/core.cpp +++ b/board-package-source/libraries/Arduboy/src/core/core.cpp @@ -2,7 +2,7 @@ // need to redeclare these here since we declare them static in .h volatile uint8_t *ArduboyCore::mosiport, - /* *ArduboyCore::csport, */ *ArduboyCore::dcport; + *ArduboyCore::csport, *ArduboyCore::dcport; uint8_t ArduboyCore::mosipinmask, ArduboyCore::cspinmask, ArduboyCore::dcpinmask; @@ -35,7 +35,12 @@ const uint8_t PROGMEM lcdBootProgram[] = { // // Further reading: https://www.adafruit.com/datasheets/SSD1306.pdf -#ifdef OLED_SH1106 +#if defined(GU12864_800B) + 0x24, 0x40, // enable Layer 0, graphic display area on + 0x47, // set brightness + 0x64, 0x00, // set x position 0 + 0x84, // address mode set: X increment +#elif OLED_SH1106 0x8D, 0x14, // Charge Pump Setting v = enable (0x14) 0xA1, // Set Segment Re-map 0xC8, // Set COM Output Scan Direction @@ -217,6 +222,27 @@ void ArduboyCore::bootPins() #endif } +#if defined(GU12864_800B) +void ArduboyCore::displayEnable() +{ + *csport |= cspinmask; + SPCR = _BV(SPE) | _BV(MSTR) | _BV(CPOL) | _BV(CPHA); + LCDCommandMode(); +} + +void ArduboyCore::displayDisable() +{ + SPCR = _BV(SPE) | _BV(MSTR); +} + +void ArduboyCore::displayWrite(uint8_t data) +{ + *csport &= ~cspinmask; + SPI.transfer(data); + *csport |= cspinmask; +} +#endif + void ArduboyCore::bootLCD() { #if defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) @@ -230,13 +256,32 @@ void ArduboyCore::bootLCD() i2c_stop(); #else // setup the ports we need to talk to the OLED - //csport = portOutputRegister(digitalPinToPort(CS)); - *portOutputRegister(digitalPinToPort(CS)) &= ~cspinmask; + csport = portOutputRegister(digitalPinToPort(CS)); cspinmask = digitalPinToBitMask(CS); + *portOutputRegister(digitalPinToPort(CS)) &= ~cspinmask; dcport = portOutputRegister(digitalPinToPort(DC)); dcpinmask = digitalPinToBitMask(DC); SPI.setClockDivider(SPI_CLOCK_DIV2); - #if defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128) || defined(OLED_64X128_ON_128X128) + #if defined(GU12864_800B) + delayShort(1); + digitalWrite(RST, HIGH); + delayShort(10); + displayEnable(); + for (uint8_t i = 0; i < sizeof(lcdBootProgram) + 8; i++) + { + if (i < 8) + { + displayWrite(0x62); // set display area + displayWrite(i); // display area address + LCDDataMode(); + displayWrite(0xFF); // Graphic display + LCDCommandMode(); + } + else + displayWrite(pgm_read_byte(lcdBootProgram + i - 8)); + } + displayDisable(); + #elif defined(OLED_128X64_ON_96X96) || defined(OLED_128X64_ON_128X96) || defined(OLED_128X64_ON_128X128)|| defined(OLED_128X96_ON_128X128) || defined(OLED_96X96_ON_128X128) || defined(OLED_64X128_ON_128X128) LCDDataMode(); for (uint16_t i = 0; i < 8192; i++) SPI.transfer(0); //Clear all display ram #endif @@ -253,14 +298,22 @@ void ArduboyCore::bootLCD() void ArduboyCore::LCDDataMode() { + #if defined(GU12864_800B) + *dcport &= ~dcpinmask; + #else *dcport |= dcpinmask; + #endif // *csport &= ~cspinmask; } void ArduboyCore::LCDCommandMode() { // *csport |= cspinmask; + #if defined(GU12864_800B) + *dcport |= dcpinmask; + #else *dcport &= ~dcpinmask; + #endif // *csport &= ~cspinmask; CS set once at bootLCD } @@ -359,7 +412,24 @@ void ArduboyCore::paint8Pixels(uint8_t pixels) void ArduboyCore::paintScreen(const unsigned char *image) { -#if defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) +#if defined(GU12864_800B) + displayEnable(); + for (uint8_t r = 0; r < (HEIGHT/8); r++) + { + LCDCommandMode(); + displayWrite(0x60); + displayWrite(r); + LCDDataMode(); + for (uint8_t c = 0; c < (WIDTH); c++) + { + *csport &= ~cspinmask; + SPDR = pgm_read_byte(image++); + while (!(SPSR & _BV(SPIF))); + *csport |= cspinmask; + } + } + displayDisable(); +#elif defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) i2c_start(SSD1306_I2C_DATA); for (int i = 0; i < (HEIGHT * WIDTH) / 8; i++) i2c_sendByte(pgm_read_byte(image+i)); @@ -439,7 +509,24 @@ void ArduboyCore::paintScreen(const unsigned char *image) // will be used by any buffer based subclass void ArduboyCore::paintScreen(unsigned char image[]) { -#if defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) +#if defined(GU12864_800B) + displayEnable(); + for (uint8_t r = 0; r < (HEIGHT/8); r++) + { + LCDCommandMode(); + displayWrite(0x60); + displayWrite(r); + LCDDataMode(); + for (uint8_t c = 0; c < (WIDTH); c++) + { + *csport &= ~cspinmask; + SPDR = *(image++); + while (!(SPSR & _BV(SPIF))); + *csport |= cspinmask; + } + } + displayDisable(); +#elif defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) uint16_t length = WIDTH * HEIGHT / 8; uint8_t sda_clr = I2C_PORT & ~((1 << I2C_SDA) | (1 << I2C_SCL)); uint8_t scl = 1 << I2C_SCL; @@ -719,14 +806,37 @@ void ArduboyCore::sendLCDCommand(uint8_t command) // when inverted, a pixel set to 0 will be on void ArduboyCore::invert(boolean inverse) { + #if defined(GU12864_800B) + displayEnable(); + displayWrite(0x24); + if (inverse) displayWrite(0x50); + else displayWrite(0x40); + LCDDataMode(); + displayDisable(); + #else sendLCDCommand(inverse ? OLED_PIXELS_INVERTED : OLED_PIXELS_NORMAL); + #endif } // turn all display pixels on, ignoring buffer contents // or set to normal buffer display void ArduboyCore::allPixelsOn(boolean on) { +#if defined(GU12864_800B) + displayEnable(); + if (on) + { + displayWrite(0x20); + displayWrite(0x50); + } + else + displayWrite(0x24); + displayWrite(0x40); + LCDDataMode(); + displayDisable(); + #else sendLCDCommand(on ? OLED_ALL_PIXELS_ON : OLED_PIXELS_FROM_RAM); + #endif } // flip the display vertically or set to normal diff --git a/board-package-source/libraries/Arduboy/src/core/core.h b/board-package-source/libraries/Arduboy/src/core/core.h index 1f6c66c..a576abd 100644 --- a/board-package-source/libraries/Arduboy/src/core/core.h +++ b/board-package-source/libraries/Arduboy/src/core/core.h @@ -212,7 +212,13 @@ public: * in a frame loop. */ void static idle(); - +#if defined(GU12864_800B) + void static displayEnable(); + + void static displayDisable(); + + void static displayWrite(uint8_t data); +#endif void static LCDDataMode(); //< put the display in data mode /// put the display in command mode @@ -365,7 +371,7 @@ protected: private: - volatile static uint8_t *mosiport, /* *csport, */ *dcport; + volatile static uint8_t *mosiport, *csport, *dcport; uint8_t static mosipinmask, cspinmask, dcpinmask; }; diff --git a/board-package-source/libraries/Arduboy2/keywords.txt b/board-package-source/libraries/Arduboy2/keywords.txt index 87f3f17..b5caf94 100644 --- a/board-package-source/libraries/Arduboy2/keywords.txt +++ b/board-package-source/libraries/Arduboy2/keywords.txt @@ -32,8 +32,6 @@ bootLogoSpritesOverwrite KEYWORD2 bootLogoSpritesSelfMasked KEYWORD2 bootLogoText KEYWORD2 buttonsState KEYWORD2 -checkBatteryState KEYWORD2 -checkBatteryStateLED KEYWORD2 clear KEYWORD2 collide KEYWORD2 cpuLoad KEYWORD2 @@ -167,7 +165,3 @@ RGB_ON LITERAL1 ARDUBOY_NO_USB LITERAL1 -BATTERY_STATE_LOW LITERAL1 -BATTERY_STATE_NORMAL LITERAL1 -BATTERY_STATE_INVALID LITERAL1 -FLASH_LED LITERAL1 \ No newline at end of file diff --git a/board-package-source/libraries/Arduboy2/src/Arduboy2.cpp b/board-package-source/libraries/Arduboy2/src/Arduboy2.cpp index dd55df9..3bfc6eb 100644 --- a/board-package-source/libraries/Arduboy2/src/Arduboy2.cpp +++ b/board-package-source/libraries/Arduboy2/src/Arduboy2.cpp @@ -8,32 +8,12 @@ #include "ab_logo.c" #include "glcdfont.c" -//================================ -//========== class Rect ========== -//================================ - -Rect::Rect(int16_t x, int16_t y, uint8_t width, uint8_t height) - : x(x), y(y), width(width), height(height) -{ -} - -//================================= -//========== class Point ========== -//================================= - -Point::Point(int16_t x, int16_t y) - : x(x), y(y) -{ -} - //======================================== //========== class Arduboy2Base ========== //======================================== uint8_t Arduboy2Base::sBuffer[]; -uint8_t Arduboy2Base::batteryLow = EEPROM.read(EEPROM_BATTERY_LOW); //Low battery bandgap value - 192 - Arduboy2Base::Arduboy2Base() { currentButtonState = 0; @@ -78,16 +58,17 @@ void Arduboy2Base::flashlight() if (!pressed(UP_BUTTON)) { return; } - + #ifdef GU12864_800B + allPixelsOn(true); + #else sendLCDCommand(OLED_ALL_PIXELS_ON); // smaller than allPixelsOn() + #endif digitalWriteRGB(RGB_ON, RGB_ON, RGB_ON); -#ifndef ARDUBOY_CORE // for Arduboy core timer 0 should remain enabled // prevent the bootloader magic number from being overwritten by timer 0 // when a timer variable overlaps the magic number location, for when // flashlight mode is used for upload problem recovery power_timer0_disable(); -#endif while (true) { idle(); @@ -267,11 +248,7 @@ bool Arduboy2Base::everyXFrames(uint8_t frames) bool Arduboy2Base::nextFrame() { -#ifdef ARDUBOY_CORE - uint8_t now = millisChar(); -#else - uint8_t now = (uint8_t) millis(); -#endif + uint8_t now = (uint8_t) timer0_millis; uint8_t frameDurationMs = now - thisFrameStart; if (justRendered) { @@ -867,7 +844,7 @@ void Arduboy2Base::drawBitmap uint8_t color) { // no need to draw at all if we're offscreen - if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1) + if (x+w <= 0 || x > WIDTH-1 || y+h <= 0 || y > HEIGHT-1) return; int8_t yOffset = y & 7; @@ -1200,88 +1177,6 @@ void Arduboy2Base::swap(int16_t& a, int16_t& b) b = temp; } -uint8_t Arduboy2Base::checkBatteryState() -{ - uint8_t state = BATTERY_STATE_INVALID; - asm volatile ( - " ldi r30, lo8(%[prr0]) \n" // if (bit_is_set(PRR0,PRADC)) //ADC power off - " ldi r31, hi8(%[prr0]) \n" // { - " ld r24, z \n" - " lds r25, %[adcsra] \n" - " sbrs r24, %[pradc] \n" - " rjmp 1f \n" - " \n" - " andi r24, ~(1<<%[pradc]) \n" // PRR0 &= ~_BV(PRADC); // ADC power on - " st z, r24 \n" - " ldi r24, %[admuxval] \n" // ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) - " sts %[admux], r24 \n" - " ori r25, 1<<%[adsc] \n" // ADCSRA |= _BV(ADSC) //start conversion - " sts %[adcsra], r25 \n" // } - " ;rjmp 2f \n" // bit is set so continue below to jump to 2f - "1: \n" - " sbrc r25, %[adsc] \n" // else if (!(ADCSRA & _BV(ADSC)) //ADC conversion ready - " rjmp 2f \n" // { - " \n" - " ori r24, 1<<%[pradc] \n" // PRR0 |= _BV(PRADC); // ADC power off - " st z, r24 \n" - " ldi r30, %[adcl] \n" // uint16_t bandgap = ADCL | (ADCH << 8); - " ld r24, z+ \n" - " ld r25, z \n" - " subi r24, 192 \n" // bandgap -= 192; - " sbci r25, 0 \n" - " and r25, r25 \n" // if (bandgap < 256) - " brne 2f \n" // { - " \n" - " ldi %[state],%[normal] \n" // state = BATTERY_STATE_NORMAL; - " lds r25, %[battlow] \n" - " cp r25, r24 \n" - " brcc 2f \n" // if (batteryLow < bandgap) state = BATTERY_STATE_LOW; - " ldi %[state],%[low] \n" // } - "2: \n" // } - :[state] "+d"(state) - :[prr0] "M" (_SFR_MEM_ADDR(PRR0)), - [adcsra] "M" (_SFR_MEM_ADDR(ADCSRA)), - [pradc] "I" (PRADC), - [admuxval] "M" (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)), - [admux] "M" (_SFR_MEM_ADDR(ADMUX)), - [adsc] "I" (ADSC), - [adcl] "M" (_SFR_MEM_ADDR(ADCL)), - [battlow] "" (&batteryLow), - [normal] "I" (BATTERY_STATE_NORMAL), - [low] "I" (BATTERY_STATE_LOW) - : "r24", "r25", "r30", "r31" - ); -#if 0 -// For reference, this is the C++ equivalent - uint8_t state = BATTERY_STATE_UNDEFINED; - if (bit_is_set(PRR0,PRADC)) //only enable when ADC power is disabled - { - PRR0 &= ~_BV(PRADC); // ADC power on - ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); //meassure 1.1V bandgap against AVcc - ADCSRA |= _BV(ADSC); //start conversion - } - else if (!(ADCSRA & _BV(ADSC))) - { - PRR0 |= _BV(PRADC); // ADC power off - uint16_t bandgap = ADCL | (ADCH << 8); - bandgap -= 192; - if (bandgap < 256) - { - state = BATTERY_STATE_NORMAL; - if (batteryLow < (uint8_t)bandgap) state = BATTERY_STATE_LOW; - } - } -#endif - return state; -} - -uint8_t Arduboy2Base::checkBatteryStateLED(bool flash) -{ - uint8_t state = checkBatteryState(); - if (state == BATTERY_STATE_NORMAL | flash) TXLED0; - if (state == BATTERY_STATE_LOW) TXLED1; - return state; -} //==================================== //========== class Arduboy2 ========== diff --git a/board-package-source/libraries/Arduboy2/src/Arduboy2.h b/board-package-source/libraries/Arduboy2/src/Arduboy2.h index b4e6c03..7dfd7a1 100644 --- a/board-package-source/libraries/Arduboy2/src/Arduboy2.h +++ b/board-package-source/libraries/Arduboy2/src/Arduboy2.h @@ -41,8 +41,6 @@ #define EEPROM_VERSION 0 #define EEPROM_SYS_FLAGS 1 #define EEPROM_AUDIO_ON_OFF 2 -#define EEPROM_BANDGAP_CAL 6 //Bandgap calibration value -#define EEPROM_BATTERY_LOW 7 //Battery low threshold #define EEPROM_UNIT_ID 8 // A uint16_t binary unit ID #define EEPROM_UNIT_NAME 10 // An up to 6 character unit name. Cannot contain // 0x00 or 0xFF. Lengths less than 6 are padded @@ -89,10 +87,6 @@ #define CLEAR_BUFFER true /**< Value to be passed to `display()` to clear the screen buffer. */ -#define BATTERY_STATE_LOW 0 -#define BATTERY_STATE_NORMAL 1 -#define BATTERY_STATE_INVALID 0xFF -#define FLASH_LED true //============================================= //========== Rect (rectangle) object ========== @@ -128,7 +122,10 @@ struct Rect * \param width The width of the rectangle. Copied to variable `width`. * \param height The height of the rectangle. Copied to variable `height`. */ - Rect(int16_t x, int16_t y, uint8_t width, uint8_t height); + constexpr Rect(int16_t x, int16_t y, uint8_t width, uint8_t height) + : x(x), y(y), width(width), height(height) + { + } }; //================================== @@ -159,7 +156,10 @@ struct Point * \param x The X coordinate of the point. Copied to variable `x`. * \param y The Y coordinate of the point. Copied to variable `y`. */ - Point(int16_t x, int16_t y); + constexpr Point(int16_t x, int16_t y) + : x(x), y(y) + { + } }; //================================== @@ -1266,60 +1266,6 @@ class Arduboy2Base : public Arduboy2Core */ void writeShowBootLogoLEDsFlag(bool val); - /** \brief - * Returns the battery state. - * \details - * This function is intended as a method to determine a low battery state - * - * Returns the following states: - * - BATTERY_STATE_LOW The battery low threshold has been reached. - * - BATTERY_STATE_NORMAL The battery is considered normal. - * - BATTERY_STATE_INVALID The ADC conversion is not ready yet or the - * result is out of range. - * - * This fucntion depends on the EEPROM_BATTERY_LOW value been set to the - * low batterly bandgap voltage value. The default value (0xFF) will - * disable the EEPROM_BATTERY_LOW state. - * - * example: - * \code{.cpp} - * void loop() { - * if (!arduboy.nextFrame()) return; - * if (arduboy.everyXFrames(FRAMERATE) && arduboy.checkBatteryState() == BATTERY_STATE_LOW) - * { - * batteryLowWarning = true; - * } - * \endcode - * - * \see everyXFrames() - */ - uint8_t checkBatteryState(); - - /** \brief - * Returns battery state and sets TXLED as a low battery indicator - * \param flash defaults to 'false' for no flashing. use 'FLASH_LED' or - * `true` for flashing. - * \details - * This function is intended as a method to determine a low battery state. - * The TXLED is used as a battery low indicator. The TXLED will light up - * continiously by default when the battery state is low. The optional - * FLASH_LED parameter can be passed to make the LED toggle on or off on low - * battery state. - * - * This function is a quick way of adding a low battery indicator to a sketch. - * - * example: - * \code{.cpp} - * void loop() { - * if (!arduboy.nextFrame()) return; - * //turn TXLED alternately on 1 second and off 1 second when battery is low - * if (arduboy.everyXFrames(FRAMERATE)) checkBatteryStateLED(FLASH_LED); - * \endcode - * - * \see checkBatteryState() everyXFrames() - */ - uint8_t checkBatteryStateLED(bool flash = false); - /** \brief * A counter which is incremented once per frame. * @@ -1369,8 +1315,6 @@ class Arduboy2Base : public Arduboy2Core */ static uint8_t sBuffer[(HEIGHT*WIDTH)/8]; - static uint8_t batteryLow; - protected: // helper function for sound enable/disable system control void sysCtrlSound(uint8_t buttons, uint8_t led, uint8_t eeVal); @@ -1712,5 +1656,7 @@ class Arduboy2 : public Print, public Arduboy2Base bool textWrap; }; +extern volatile unsigned long timer0_millis; + #endif diff --git a/board-package-source/libraries/Arduboy2/src/Arduboy2Core.cpp b/board-package-source/libraries/Arduboy2/src/Arduboy2Core.cpp index 25a3ec6..8701fb2 100644 --- a/board-package-source/libraries/Arduboy2/src/Arduboy2Core.cpp +++ b/board-package-source/libraries/Arduboy2/src/Arduboy2Core.cpp @@ -13,8 +13,13 @@ const uint8_t PROGMEM lcdBootProgram[] = { // might prove useful for reference // // Further reading: https://www.adafruit.com/datasheets/SSD1306.pdf - -#if defined(OLED_SH1106) + +#if defined(GU12864_800B) + 0x24, 0x40, // enable Layer 0, graphic display area on + 0x47, // set brightness + 0x64, 0x00, // set x position 0 + 0x84, // address mode set: X increment +#elif defined(OLED_SH1106) 0x8D, 0x14, // Charge Pump Setting v = enable (0x14) 0xA1, // Set Segment Re-map 0xC8, // Set COM Output Scan Direction @@ -321,7 +326,25 @@ void Arduboy2Core::bootPins() void Arduboy2Core::bootOLED() { -#if defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) +#if defined(GU12864_800B) + bitSet(RST_PORT,RST_BIT); + delayShort(10); + displayEnable(); + for (uint8_t i = 0; i < sizeof(lcdBootProgram) + 8; i++) + { + if (i < 8) + { + displayWrite(0x62); // set display area + displayWrite(i); // display area address + LCDDataMode(); + displayWrite(0xFF); // Graphic display + LCDCommandMode(); + } + else + displayWrite(pgm_read_byte(lcdBootProgram + i - 8)); + } + displayDisable(); +#elif defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) i2c_start(SSD1306_I2C_CMD); for (uint8_t i = 0; i < sizeof(lcdBootProgram); i++) i2c_sendByte(pgm_read_byte(lcdBootProgram + i)); @@ -476,10 +499,38 @@ void Arduboy2Core::bootPowerSaving() PRR1 = _BV(PRUSART1); } +#if defined(GU12864_800B) +void Arduboy2Core::displayEnable() +{ + bitSet(CS_PORT,CS_BIT); + SPCR = _BV(SPE) | _BV(MSTR) | _BV(CPOL) | _BV(CPHA); + //bitClear(CS_PORT,CS_BIT); + LCDCommandMode(); +} + +void Arduboy2Core::displayDisable() +{ + //bitSet(CS_PORT,CS_BIT); + SPCR = _BV(SPE) | _BV(MSTR); +} + +void Arduboy2Core::displayWrite(uint8_t data) +{ + bitClear(CS_PORT,CS_BIT); + SPItransfer(data); + bitSet(CS_PORT,CS_BIT); +} +#endif + // Shut down the display void Arduboy2Core::displayOff() { -#if defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) +#if defined(GU12864_800B) + displayEnable(); + displayWrite(0x20); + displayWrite(0x00); + displayDisable(); +#elif defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) i2c_start(SSD1306_I2C_CMD); i2c_sendByte(0xAE); // display off i2c_sendByte(0x8D); // charge pump: @@ -519,7 +570,24 @@ void Arduboy2Core::paint8Pixels(uint8_t pixels) void Arduboy2Core::paintScreen(const uint8_t *image) { -#if defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) +#if defined(GU12864_800B) + displayEnable(); + for (uint8_t r = 0; r < (HEIGHT/8); r++) + { + LCDCommandMode(); + displayWrite(0x60); + displayWrite(r); + LCDDataMode(); + for (uint8_t c = 0; c < (WIDTH); c++) + { + bitClear(CS_PORT,CS_BIT); + SPDR = pgm_read_byte(image++); + while (!(SPSR & _BV(SPIF))); + bitSet(CS_PORT,CS_BIT); + } + } + displayDisable(); +#elif defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) i2c_start(SSD1306_I2C_DATA); for (int i = 0; i < (HEIGHT * WIDTH) / 8; i++) i2c_sendByte(pgm_read_byte(image+i)); @@ -599,7 +667,30 @@ void Arduboy2Core::paintScreen(const uint8_t *image) // will be used by any buffer based subclass void Arduboy2Core::paintScreen(uint8_t image[], bool clear) { -#if defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) +#if defined(GU12864_800B) + displayEnable(); + for (uint8_t r = 0; r < (HEIGHT/8); r++) + { + LCDCommandMode(); + displayWrite(0x60); + displayWrite(r); + LCDDataMode(); + for (uint8_t c = 0; c < (WIDTH); c++) + { + bitClear(CS_PORT,CS_BIT); + if (clear) + { + SPDR = *image; // set the first SPI data byte to get things started + *(image++) = 0; // clear the first image byte + } + else + SPDR = *(image++); + while (!(SPSR & _BV(SPIF))); + bitSet(CS_PORT,CS_BIT); + } + } + displayDisable(); +#elif defined(OLED_SSD1306_I2C) || (OLED_SSD1306_I2CX) uint16_t length = WIDTH * HEIGHT / 8; uint8_t sda_clr = I2C_PORT & ~((1 << I2C_SDA) | (1 << I2C_SCL)); uint8_t scl = 1 << I2C_SCL; @@ -957,7 +1048,7 @@ void Arduboy2Core::sendLCDCommand(uint8_t command) i2c_start(SSD1306_I2C_CMD); i2c_sendByte(command); i2c_stop(); -#else +#else if !defined GU12864_800B LCDCommandMode(); SPItransfer(command); LCDDataMode(); @@ -968,26 +1059,57 @@ void Arduboy2Core::sendLCDCommand(uint8_t command) // when inverted, a pixel set to 0 will be on void Arduboy2Core::invert(bool inverse) { + #if defined(GU12864_800B) + displayEnable(); + displayWrite(0x24); + if (inverse) displayWrite(0x50); + else displayWrite(0x40); + LCDDataMode(); + displayDisable(); + #else sendLCDCommand(inverse ? OLED_PIXELS_INVERTED : OLED_PIXELS_NORMAL); + #endif } // turn all display pixels on, ignoring buffer contents // or set to normal buffer display void Arduboy2Core::allPixelsOn(bool on) { + #if defined(GU12864_800B) + displayEnable(); + if (on) + { + displayWrite(0x20); + displayWrite(0x50); + } + else + displayWrite(0x24); + displayWrite(0x40); + LCDDataMode(); + displayDisable(); + #else sendLCDCommand(on ? OLED_ALL_PIXELS_ON : OLED_PIXELS_FROM_RAM); + #endif } // flip the display vertically or set to normal void Arduboy2Core::flipVertical(bool flipped) { + #ifdef GU12864_800B + //not available + #else sendLCDCommand(flipped ? OLED_VERTICAL_FLIPPED : OLED_VERTICAL_NORMAL); + #endif } // flip the display horizontally or set to normal void Arduboy2Core::flipHorizontal(bool flipped) { + #ifdef GU12864_800B + //not available + #else sendLCDCommand(flipped ? OLED_HORIZ_FLIPPED : OLED_HORIZ_NORMAL); + #endif } /* RGB LED */ @@ -1201,9 +1323,9 @@ void Arduboy2Core::digitalWriteRGB(uint8_t color, uint8_t val) uint8_t Arduboy2Core::buttonsState() { -#ifndef ARDUBOY_CORE uint8_t buttons; - #ifdef ARDUBOY_10 + +#ifdef ARDUBOY_10 // up, right, left, down buttons = ((~PINF) & (_BV(UP_BUTTON_BIT) | _BV(RIGHT_BUTTON_BIT) | @@ -1222,11 +1344,8 @@ uint8_t Arduboy2Core::buttonsState() if (bitRead(A_BUTTON_PORTIN, A_BUTTON_BIT) == 0) { buttons |= A_BUTTON; } // B if (bitRead(B_BUTTON_PORTIN, B_BUTTON_BIT) == 0) { buttons |= B_BUTTON; } - #endif -#else - register uint8_t buttons asm("r24"); - asm volatile("call scan_buttons\n\t" : "=d" (buttons)); -#endif +#endif + return buttons; } @@ -1242,8 +1361,10 @@ void Arduboy2Core::delayShort(uint16_t ms) void Arduboy2Core::exitToBootloader() { -#ifndef ARDUBOY_CORE cli(); + #ifdef ARDUBOY_CORE + asm volatile ("jmp exit_to_bootloader"); + #else // set bootloader magic key // storing two uint8_t instead of one uint16_t saves an instruction // when high and low bytes of the magic key are the same @@ -1254,10 +1375,7 @@ void Arduboy2Core::exitToBootloader() WDTCSR = (_BV(WDCE) | _BV(WDE)); WDTCSR = _BV(WDE); while (true) { } -#else - bootloader_timer = 120; //ms - while (true) { } -#endif + #endif } // Replacement main() that eliminates the USB stack code. diff --git a/board-package-source/libraries/Arduboy2/src/Arduboy2Core.h b/board-package-source/libraries/Arduboy2/src/Arduboy2Core.h index 852b4a5..cdfb31e 100644 --- a/board-package-source/libraries/Arduboy2/src/Arduboy2Core.h +++ b/board-package-source/libraries/Arduboy2/src/Arduboy2Core.h @@ -61,6 +61,9 @@ extern volatile unsigned char bootloader_timer; #define DC_BIT PORTD4 // Display D/C physical bit number #ifdef CART_CS_SDA + #ifdef AB_ALTERNATE_WIRING + #error SDA can not be used as flash chip select when using Pro Micro alternate wiring. Use RX instead. + #endif #define PIN_CART 2 // SDA as alternative flash cart chip select #define CART_BIT PORTD1 #else @@ -462,7 +465,11 @@ class Arduboy2Core */ void static inline LCDDataMode() __attribute__((always_inline)) { + #if defined(GU12864_800B) + bitClear(DC_PORT, DC_BIT); + #else bitSet(DC_PORT, DC_BIT); + #endif } /** \brief * Put the display into command mode. @@ -488,7 +495,11 @@ class Arduboy2Core */ void static inline LCDCommandMode() __attribute__((always_inline)) { + #ifdef GU12864_800B + bitSet(DC_PORT, DC_BIT); + #else bitClear(DC_PORT, DC_BIT); + #endif } /** \brief * Transfer a byte to the display. @@ -972,6 +983,12 @@ class Arduboy2Core void static bootOLED(); void static bootPins(); void static bootPowerSaving(); +#if defined(GU12864_800B) + void static displayWrite(uint8_t d); + void static displayEnable(); + void static displayDisable(); +#endif + }; #endif diff --git a/board-package-source/libraries/Arduboy2/src/Sprites.cpp b/board-package-source/libraries/Arduboy2/src/Sprites.cpp index 1ee839c..f9ef342 100644 --- a/board-package-source/libraries/Arduboy2/src/Sprites.cpp +++ b/board-package-source/libraries/Arduboy2/src/Sprites.cpp @@ -44,83 +44,84 @@ void Sprites::draw(int16_t x, int16_t y, if (bitmap == NULL) return; -// uint8_t width = pgm_read_byte(bitmap); -// uint8_t height = pgm_read_byte(++bitmap); -// bitmap++; -// if (frame > 0 || sprite_frame > 0) { -// frame_offset = (width * ( height / 8 + ( height % 8 == 0 ? 0 : 1))); -// // sprite plus mask uses twice as much space for each frame -// if (drawMode == SPRITE_PLUS_MASK) { -// frame_offset *= 2; -// } else if (mask != NULL) { -// mask += sprite_frame * frame_offset; -// } -// bitmap += frame * frame_offset; -// } -// // if we're detecting the draw mode then base it on whether a mask -// // was passed as a separate object -// if (drawMode == SPRITE_AUTO_MODE) { -// drawMode = mask == NULL ? SPRITE_UNMASKED : SPRITE_MASKED; -// } + uint8_t width = pgm_read_byte(bitmap); + uint8_t height = pgm_read_byte(++bitmap); + bitmap++; + if (frame > 0 || sprite_frame > 0) { + frame_offset = (width * ( height / 8 + ( height % 8 == 0 ? 0 : 1))); + // sprite plus mask uses twice as much space for each frame + if (drawMode == SPRITE_PLUS_MASK) { + frame_offset *= 2; + } else if (mask != NULL) { + mask += sprite_frame * frame_offset; + } + bitmap += frame * frame_offset; + } + + // if we're detecting the draw mode then base it on whether a mask + // was passed as a separate object + if (drawMode == SPRITE_AUTO_MODE) { + drawMode = mask == NULL ? SPRITE_UNMASKED : SPRITE_MASKED; + } // assembly optimisation of above code saving 20(+) bytes - uint8_t width; - uint8_t height; - asm volatile( - " lpm %[width], Z+ \n\t" // width = pgm_read_byte(bitmap++); - " lpm %[height], Z+ \n\t" // height = pgm_read_byte(bitmap++); - " cp %[frame], __zero_reg__ \n\t" // if (frame > 0 || sprite_frame > 0) - " brne 1f \n\t" - " cp %[spr_frame], __zero_reg__ \n\t" - " breq 3f \n\t" - "1: \n\t" - " ldi r20, 7 \n\t" //rows = ((height+7) - " add r20, %[height] \n\t" - " ror r20 \n\t" //include carry for heights > 248 - " lsr r20 \n\t" //rows = (height+7) / 8 - " lsr r20 \n\t" - " cpi %[mode], %[sprite_plus_mask] \n\t" //if (drawMode == SPRITE_PLUS_MASK) rows *= 2 - " brne 2f \n\t" - " lsl r20 \n\t" - "2: \n\t" - " mul r20, %[width] \n\t" //frame offset = rows * width - " movw r20, r0 \n\t" - " mul %[frame] , r20 \n\t" - " add %A[bitmap], r0 \n\t" //bitmap += frame * (frame offset & 0xFF) - " adc %B[bitmap], r1 \n\t" - " mul %[frame] , r21 \n\t" //bitmap += frame * (frame_offset >> 8 )) << 8 - " add %B[bitmap], r0 \n\t" - " \n\t" - " adiw %A[mask], 0 \n\t" //if (mask != NULL) - " breq 3f \n\t" - " \n\t" - " mul %[spr_frame] , r20 \n\t" - " add %A[mask], r0 \n\t" //mask += sprite_frame * (frame offset & 0xFF) - " adc %B[mask], r1 \n\t" - " mul %[spr_frame] , r21 \n\t" //mask += (sprite_frame * (frame_offset >> 8 )) << 8 - " add %B[mask], r0 \n\t" - "3: \n\t" - " clr __zero_reg__ \n\t" - "4: \n\t" - " cpi %[mode], %[sprite_auto_mode] \n\t" //if (drawMode == SPRITE_AUTO_MODE) - " brne 5f \n\t" - " adiw %A[mask], 0 \n\t" //if (mask = NULL) drawMode = SPRITE_UNMASKED - " ldi %[mode], %[sprite_unmasked] \n\t" - " breq 5f \n\t" - " ldi %[mode], %[sprite_masked] \n\t" //else drawMode = SPRITE_PLUS_MASK - "5: \n\t" - : [width] "=&r" (width), - [height] "=&r" (height), - [mask] "+x" (mask), - [bitmap] "+z" (bitmap), - [mode] "+d" (drawMode) - : [frame] "r" (frame), - [spr_frame] "r" (sprite_frame), - [sprite_plus_mask] "M" (SPRITE_PLUS_MASK), - [sprite_auto_mode] "M" (SPRITE_AUTO_MODE), - [sprite_unmasked] "M" (SPRITE_UNMASKED), - [sprite_masked] "M" (SPRITE_MASKED) - : "r20", "r21" - ); +// uint8_t width; +// uint8_t height; +// asm volatile( +// " lpm %[width], Z+ \n\t" // width = pgm_read_byte(bitmap++); +// " lpm %[height], Z+ \n\t" // height = pgm_read_byte(bitmap++); +// " cp %[frame], __zero_reg__ \n\t" // if (frame > 0 || sprite_frame > 0) +// " brne 1f \n\t" +// " cp %[spr_frame], __zero_reg__ \n\t" +// " breq 3f \n\t" +// "1: \n\t" +// " ldi r20, 7 \n\t" //rows = ((height+7) +// " add r20, %[height] \n\t" +// " ror r20 \n\t" //include carry for heights > 248 +// " lsr r20 \n\t" //rows = (height+7) / 8 +// " lsr r20 \n\t" +// " cpi %[mode], %[sprite_plus_mask] \n\t" //if (drawMode == SPRITE_PLUS_MASK) rows *= 2 +// " brne 2f \n\t" +// " lsl r20 \n\t" +// "2: \n\t" +// " mul r20, %[width] \n\t" //frame offset = rows * width +// " movw r20, r0 \n\t" +// " mul %[frame] , r20 \n\t" +// " add %A[bitmap], r0 \n\t" //bitmap += frame * (frame offset & 0xFF) +// " adc %B[bitmap], r1 \n\t" +// " mul %[frame] , r21 \n\t" //bitmap += frame * (frame_offset >> 8 )) << 8 +// " add %B[bitmap], r0 \n\t" +// " \n\t" +// " adiw %A[mask], 0 \n\t" //if (mask != NULL) +// " breq 3f \n\t" +// " \n\t" +// " mul %[spr_frame] , r20 \n\t" +// " add %A[mask], r0 \n\t" //mask += sprite_frame * (frame offset & 0xFF) +// " adc %B[mask], r1 \n\t" +// " mul %[spr_frame] , r21 \n\t" //mask += (sprite_frame * (frame_offset >> 8 )) << 8 +// " add %B[mask], r0 \n\t" +// "3: \n\t" +// " clr __zero_reg__ \n\t" +// "4: \n\t" +// " cpi %[mode], %[sprite_auto_mode] \n\t" //if (drawMode == SPRITE_AUTO_MODE) +// " brne 5f \n\t" +// " adiw %A[mask], 0 \n\t" //if (mask = NULL) drawMode = SPRITE_UNMASKED +// " ldi %[mode], %[sprite_unmasked] \n\t" +// " breq 5f \n\t" +// " ldi %[mode], %[sprite_masked] \n\t" //else drawMode = SPRITE_PLUS_MASK +// "5: \n\t" +// : [width] "=&r" (width), +// [height] "=&r" (height), +// [mask] "+x" (mask), +// [bitmap] "+z" (bitmap), +// [mode] "+d" (drawMode) +// : [frame] "r" (frame), +// [spr_frame] "r" (sprite_frame), +// [sprite_plus_mask] "M" (SPRITE_PLUS_MASK), +// [sprite_auto_mode] "M" (SPRITE_AUTO_MODE), +// [sprite_unmasked] "M" (SPRITE_UNMASKED), +// [sprite_masked] "M" (SPRITE_MASKED) +// : "r20", "r21" +// ); drawBitmap(x, y, bitmap, mask, width, height, drawMode); }