From b0c7ed2663328f66c134ae7d612877571b169cc7 Mon Sep 17 00:00:00 2001 From: "Mr.Blinky" Date: Mon, 21 Mar 2022 21:21:15 +0100 Subject: [PATCH] update arduboy core, fx library fixed warning in wiring.c added draw string and numbers functions to fx library added Hello World fx example --- board-package-source/cores/arduboy/wiring.c | 1 + .../helloworld/fxdata/arduboyFont_6x8.png | Bin 0 -> 2431 bytes .../examples/helloworld/fxdata/fxdata.bin | Bin 0 -> 13937 bytes .../examples/helloworld/fxdata/fxdata.h | 22 ++ .../examples/helloworld/fxdata/fxdata.txt | 5 + .../helloworld/fxdata/maskedFont_16x24.png | Bin 0 -> 5187 bytes .../examples/helloworld/helloworld.ino | 83 ++++++++ .../libraries/ArduboyFX/library.properties | 2 +- .../libraries/ArduboyFX/src/ArduboyFX.cpp | 155 +++++++++++++- .../libraries/ArduboyFX/src/ArduboyFX.h | 195 +++++++++++++----- 10 files changed, 411 insertions(+), 52 deletions(-) create mode 100644 board-package-source/libraries/ArduboyFX/examples/helloworld/fxdata/arduboyFont_6x8.png create mode 100644 board-package-source/libraries/ArduboyFX/examples/helloworld/fxdata/fxdata.bin create mode 100644 board-package-source/libraries/ArduboyFX/examples/helloworld/fxdata/fxdata.h create mode 100644 board-package-source/libraries/ArduboyFX/examples/helloworld/fxdata/fxdata.txt create mode 100644 board-package-source/libraries/ArduboyFX/examples/helloworld/fxdata/maskedFont_16x24.png create mode 100644 board-package-source/libraries/ArduboyFX/examples/helloworld/helloworld.ino diff --git a/board-package-source/cores/arduboy/wiring.c b/board-package-source/cores/arduboy/wiring.c index 40363d6..80cc453 100644 --- a/board-package-source/cores/arduboy/wiring.c +++ b/board-package-source/cores/arduboy/wiring.c @@ -272,6 +272,7 @@ unsigned long micros() { "x" (&timer0_overflow_count) : "r18" ); + return m; } void delay(unsigned long ms) diff --git a/board-package-source/libraries/ArduboyFX/examples/helloworld/fxdata/arduboyFont_6x8.png b/board-package-source/libraries/ArduboyFX/examples/helloworld/fxdata/arduboyFont_6x8.png new file mode 100644 index 0000000000000000000000000000000000000000..08ceec36600765f9c1b58063bdfade0f1935df1d GIT binary patch literal 2431 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 literal 0 HcmV?d00001 diff --git a/board-package-source/libraries/ArduboyFX/examples/helloworld/helloworld.ino b/board-package-source/libraries/ArduboyFX/examples/helloworld/helloworld.ino new file mode 100644 index 0000000..f2e7e7d --- /dev/null +++ b/board-package-source/libraries/ArduboyFX/examples/helloworld/helloworld.ino @@ -0,0 +1,83 @@ +/* ***************************************************************************** + * FX Hello world example v1.00 by Mr.Blinky Mar.2022 licenced under CC0 + * ***************************************************************************** + * + * This is a example that shows how you can draw texts from the FX flash chip. + * It will draw some text, number, and a scrolling message using different + * fonts and drawing modes. + * + * Before this example sketch is uploaded and run on the Arduboy FX, make sure + * the fxdata of this sketch has been build and uploaded to the Arduboy FX. + * + * If the Arduboy FX Arduino plugin has been installed you can simply choose the + * 'Build and upload Arduboy FX data' from the Arduino IDE Tools menu. + * + * Alternatively the fxdata.txt script file can be build using the fxdata-build.py + * Phyton script and the fxdata.bin file can be uploaded using the uploader-gui.py, + * fxdata-upload.py or flash-writer.py Python script using the -d switch. + * + ******************************************************************************/ + +#include +#include +#include "fxdata\fxdata.h" + +Arduboy2Base arduboy; + +void setup() +{ + arduboy.begin(); + FX::begin(FX_DATA_PAGE); // Initialize FX flash chip + FX::setFont(arduboyFont, dcmNormal); // select default font + FX::setCursorRange(0,32767); // set cursor left and wrap positions +} + +uint16_t frames = 0; +uint8_t speed = 1; // scrolly speed +int16_t scroll_x = 128; // scrolly position + +uint8_t fontMode = dcmNormal; +int8_t leadingDigits = 5; // number of digits printed including leading zeros +uint8_t str[] = "FX Demo"; // demo text stored in ram. + +void loop() +{ + if(!(arduboy.nextFrame())) return; + arduboy.pollButtons(); + + // draw FX demo string in top left corner + FX::setCursor(0,0); // set cursor to top left positon + FX::setFontMode(dcmNormal); // only change the font mode to normal + FX::drawString(str); // draw string from a buffer (in this case the buffer holds 'FX Demo' text) + + // draw number of displayed frames in top right corner + FX::setCursor(WIDTH - 5 * arduboyFontWidth, 0); // position the cursor + FX::drawNumber(frames, leadingDigits); // draw the frames number + + // draw a scrolly message using a masked font + FX::setCursor(scroll_x, 24); // position the cursor + FX::setFont(maskedFont, dcmMasked | fontMode); // Select the masked font + FX::drawString(helloWorld); // 'print' the message + + //draw 'press any button' text as normal or inverse text + FX::setCursor(13, HEIGHT - arduboyFontHeight); + FX::setFont(arduboyFont, fontMode); + FX::drawString(" Press any button "); // draw an immediate string (string is stored in RAM so it is not recommended to use this method) + + // copy display buffer to OLED display and clear the buffer + FX::display(CLEAR_BUFFER); + + // decrement x for scrolling effect + scroll_x -= speed; + if (scroll_x < -1792) scroll_x = 128; + frames++; + + // handle button changes + if (arduboy.justPressed(0xFF)) frames = 0; // clear frames counter if any new button is pressed + if (arduboy.justPressed(UP_BUTTON)) speed = 2; // faster scrolling speed + if (arduboy.justPressed(DOWN_BUTTON)) speed = 1; // slower scrolling speed + if (arduboy.justPressed(LEFT_BUTTON)) leadingDigits = (leadingDigits == -5) ? 0 : -5; // use leading spaces + if (arduboy.justPressed(RIGHT_BUTTON))leadingDigits = (leadingDigits == 5) ? 0 : 5; // use leading zeros + if (arduboy.justPressed(A_BUTTON)) fontMode = dcmNormal; // Normal drawing mode + if (arduboy.justPressed(B_BUTTON)) fontMode = dcmReverse; // Reverse drawing mode +} diff --git a/board-package-source/libraries/ArduboyFX/library.properties b/board-package-source/libraries/ArduboyFX/library.properties index 3ddb67f..80f9f06 100644 --- a/board-package-source/libraries/ArduboyFX/library.properties +++ b/board-package-source/libraries/ArduboyFX/library.properties @@ -1,5 +1,5 @@ name=ArduboyFX -version=1.0.2 +version=1.0.3 author=Mr.Blinky maintainer=mstr.blinky@gmail.com sentence=The Arduboy FX library. diff --git a/board-package-source/libraries/ArduboyFX/src/ArduboyFX.cpp b/board-package-source/libraries/ArduboyFX/src/ArduboyFX.cpp index e4f536d..87cbde7 100644 --- a/board-package-source/libraries/ArduboyFX/src/ArduboyFX.cpp +++ b/board-package-source/libraries/ArduboyFX/src/ArduboyFX.cpp @@ -3,6 +3,8 @@ uint16_t FX::programDataPage; // program read only data location in flash memory uint16_t FX::programSavePage; // program read and write data location in flash memory +Font FX::font; +Cursor FX::cursor = {0,0,0,WIDTH}; uint8_t FX::writeByte(uint8_t data) @@ -509,7 +511,7 @@ void FX::drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8 " sbrs %[height], 0 \n" " lsr %[rowmask] \n" " dec %[rowmask] \n" - " breq .+4 \n" + " breq .+4 \n" " cpi %[renderheight], 8 \n" // if (renderheight >= 8) rowmask = 0xFF; " brlt .+2 \n" " ldi %[rowmask], 0xFF \n" @@ -715,9 +717,9 @@ void FX::displayPrefetch(uint24_t address, uint8_t* target, uint16_t len, bool c " rjmp .-6 \n" " cbi %[csport], %[csbit] \n" // enableOLED(); "1: \n" // while (true) { - " ld r0, Z ;2 \ \n" // uint8_t displaydata = *ptr; + " ld r0, Z ;2 \n" // uint8_t displaydata = *ptr; " in r24, %[spdr] ;1 /3 \n" // uint8_t targetdata = SPDR; - " out %[spdr], r0 ;1 \ \n" // SPDR = displaydata; + " out %[spdr], r0 ;1 \n" // SPDR = displaydata; " cpse %[clear], r1 ;1-2 \n" // if (clear) displaydata = 0; " mov r0, r1 ;1 \n" " st Z+, r0 ;2 \n" // *ptr++ = displaydata; @@ -727,7 +729,7 @@ void FX::displayPrefetch(uint24_t address, uint8_t* target, uint16_t len, bool c " nop ;1 \n" " st %a[target]+, r24 ;2 /11 \n" "2: \n" - " cpi r30, lo8(%[end]) ;1 \ \n" // if (ptr >= Arduboy2::sBuffer + WIDTH * HEIGHT / 8) break; + " cpi r30, lo8(%[end]) ;1 \n" // if (ptr >= Arduboy2::sBuffer + WIDTH * HEIGHT / 8) break; " cpc r31, r25 ;1 \n" " brcs 1b ;1-2/4 \n" // } "3: \n" @@ -758,7 +760,150 @@ void FX::display() void FX::display(bool clear) { - enableOLED(); + enableOLED(); Arduboy2Base::display(clear); disableOLED(); } + +void FX::setFont(uint24_t address, uint8_t mode) +{ + font.address = address; + font.mode = mode; + seekData(address); + font.width = readPendingUInt16(); + font.height = readPendingLastUInt16(); +} + +void FX::setFontMode(uint8_t mode) +{ + font.mode = mode; +} + +void FX::setCursor(int16_t x, int16_t y) +{ + cursor.x = x; + cursor.y = y; +} + +void FX::setCursorX(int16_t x) +{ + cursor.x = x; +} + +void FX::setCursorY(int16_t y) +{ + cursor.y = y; +} + +void FX::setCursorRange(int16_t left, int16_t wrap) +{ + cursor.left = left; + cursor.wrap = wrap; +} + +void FX::setCursorLeft(int16_t left) +{ + cursor.left = left; +} + +void FX::setCursorWrap(int16_t wrap) +{ + cursor.wrap = wrap; +} + +void FX::drawChar(uint8_t c) +{ + if (c == '\r') return; + uint8_t mode = font.mode; + int16_t x = cursor.x; + int16_t y = cursor.y; + if (c != '\n') + { + drawBitmap(x, y, font.address, c, mode); + if (mode & dcmProportional) + { + seekData(font.address - 256 + c); + x += readEnd(); + } + else + { + x += font.width; + } + } + if ((c == '\n') || (x >= cursor.wrap)) + { + x = cursor.left; + y += font.height; + } + setCursor(x,y); +} + +void FX::drawString(const uint8_t* buffer) +{ + for(;;) + { + uint8_t c = *buffer++; + if (c) drawChar(c); + else break; + } +} + +void FX::drawString(const char* str) +{ + FX::drawString((const uint8_t*)str); +} + +void FX::drawString(uint24_t address) +{ + for(;;) + { + seekData(address++); + uint8_t c = readEnd(); + if (c) drawChar(c); + else break; + } +} + +void FX::drawNumber(int16_t n, int8_t digits) +{ + drawNumber((int32_t)n, digits); +} + +void FX::drawNumber(uint16_t n, int8_t digits) +{ + drawNumber((uint32_t)n, digits); +} + +void FX::drawNumber(int32_t n, int8_t digits) +{ + asm volatile("dbg:\n"); + if (n < 0) + { + n = -n; + drawChar('-'); + } + else if (digits != 0) + { + drawChar(' '); + } + drawNumber((uint32_t)n, digits); +} + +void FX::drawNumber(uint32_t n, int8_t digits) // +{ + uint8_t buf[33]; //max 32 digits + terminator + uint8_t *str = &buf[sizeof(buf) - 1]; + *str = '\0'; + do { + char c = n % 10; + n /= 10; + *--str = c + '0'; + if ((digits > 0) && (--digits == 0)) break; + if ((digits < 0) && (++digits == 0)) break; + } while(n); + while (digits > 0) {--digits; *--str = '0';} + while (digits < 0) {++digits; *--str = ' ';} + drawString(str); +} + + diff --git a/board-package-source/libraries/ArduboyFX/src/ArduboyFX.h b/board-package-source/libraries/ArduboyFX/src/ArduboyFX.h index 25fdefa..d4a6815 100644 --- a/board-package-source/libraries/ArduboyFX/src/ArduboyFX.h +++ b/board-package-source/libraries/ArduboyFX/src/ArduboyFX.h @@ -43,28 +43,64 @@ constexpr uint8_t dbfExtraRow = 7; // ignored (internal use) constexpr uint8_t dbmBlack = _BV(dbfReverseBlack) | // white pixels in bitmap will be drawn as black pixels on display _BV(dbfBlack) | // black pixels in bitmap will not change pixels on display _BV(dbfWhiteBlack); // (same as sprites drawErase) - + constexpr uint8_t dbmWhite = _BV(dbfWhiteBlack); // white pixels in bitmap will be drawn as white pixels on display // black pixels in bitmap will not change pixels on display //(same as sprites drawSelfMasked) - + constexpr uint8_t dbmInvert = _BV(dbfInvert); // when a pixel in bitmap has a different color than on display the // pixel on display will be drawn as white. In all other cases the // pixel will be drawn as black -// additional drawBitmap modes +// additional drawBitmap modes constexpr uint8_t dbmNormal = 0; // White pixels in bitmap will be drawn as white pixels on display constexpr uint8_t dbmOverwrite = 0; // Black pixels in bitmap will be drawn as black pixels on display // (Same as sprites drawOverwrite) - + constexpr uint8_t dbmReverse = _BV(dbfReverseBlack); // White pixels in bitmap will be drawn as black pixels on display // Black pixels in bitmap will be drawn as white pixels on display - + constexpr uint8_t dbmMasked = _BV(dbfMasked); // The bitmap contains a mask that will determine which pixels are // drawn and which pixels remain unchanged on display // (same as sprites drawPlusMask) - + // Note above modes may be combined like (dbmMasked | dbmReverse) - + +// drawChar bit flags (used by modes below) +constexpr uint8_t dcfWhiteBlack = 0; // character is used as mask +constexpr uint8_t dcfInvert = 1; // character is exclusive or-ed with display +constexpr uint8_t dcfBlack = 2; // character will be blackened +constexpr uint8_t dcfReverseBlack = 3; // reverses character data +constexpr uint8_t dcfMasked = 4; // character contains mask data +constexpr uint8_t dcfProportional = 5; // use fonts width table to mimic proportional characters + +//draw Font character modes +constexpr uint8_t dcmBlack = _BV(dcfReverseBlack) | // white pixels in character will be drawn as black pixels on display + _BV(dcfBlack) | // black pixels in character will not change pixels on display + _BV(dcfWhiteBlack); // (same as sprites drawErase) + +constexpr uint8_t dcmWhite = _BV(dcfWhiteBlack); // white pixels in character will be drawn as white pixels on display + // black pixels in character will not change pixels on display + //(same as sprites drawSelfMasked) + +constexpr uint8_t dcmInvert = _BV(dcfInvert); // when a pixel in character has a different color than on display the + // pixel on display will be drawn as white. In all other cases the + // pixel will be drawn as black +// additional drawcharacter modes +constexpr uint8_t dcmNormal = 0; // White pixels in character will be drawn as white pixels on display +constexpr uint8_t dcmOverwrite = 0; // Black pixels in character will be drawn as black pixels on display + // (Same as sprites drawOverwrite) + +constexpr uint8_t dcmReverse = _BV(dcfReverseBlack); // White pixels in character will be drawn as black pixels on display + // Black pixels in character will be drawn as white pixels on display + +constexpr uint8_t dcmMasked = _BV(dcfMasked); // The character contains a mask that will determine which pixels are + +constexpr uint8_t dcmProportional = _BV(dcfProportional); // draw characters with variable spacing. When this mode is used a + // 256 byte width table must precede the font data + +// Note above modes may be combined like (dcmMasked | dcmProportional) + + using uint24_t = __uint24; struct JedecID @@ -80,6 +116,22 @@ struct FXAddress uint8_t offset; }; +struct Font +{ + uint24_t address; + uint8_t mode; + uint8_t width; + uint8_t height; +}; + +struct Cursor +{ + int16_t x; + int16_t y; + int16_t left; + int16_t wrap; +}; + class FX { public: @@ -92,7 +144,7 @@ class FX { CS_PORT |= (1 << CS_BIT); }; - + static inline void enable() __attribute__((always_inline)) // selects external flash memory and allows new commands { FX_PORT &= ~(1 << FX_BIT); @@ -107,16 +159,16 @@ class FX { while ((SPSR & _BV(SPIF)) == 0); } - + static uint8_t writeByte(uint8_t data); // write a single byte to flash memory. - + static inline void writeByteBeforeWait(uint8_t data) __attribute__((always_inline)) { SPDR = data; asm volatile("nop\n"); wait(); } - + static inline void writeByteAfterWait(uint8_t data) __attribute__((always_inline)) { wait(); @@ -128,9 +180,9 @@ class FX static void displayPrefetch(uint24_t address, uint8_t* target, uint16_t len, bool clear); static void display(); // display screen buffer - + static void display(bool clear); // display screen buffer with clear - + static void begin(); // Initializes flash memory. Use only when program does not require data and save areas in flash memory static void begin(uint16_t programDataPage); // Initializes flash memory. Use when program depends on data in flash memory @@ -138,11 +190,11 @@ class FX static void begin(uint16_t datapage, uint16_t savepage); // Initializes flash memory. Use when program depends on both data and save data in flash memory static void readJedecID(JedecID* id); - + static bool detect(); //detect presence of initialized flash memory - + static void noFXReboot(); // flash RGB LED red and wait for DOWN button to exit to bootloader when no initialized external flash memory is present - + static void writeCommand(uint8_t command); // write a single byte flash command static void wakeUp(); // Wake up flash memory from power down mode @@ -154,11 +206,11 @@ class FX static void seekCommand(uint8_t command, uint24_t address);// Write command and selects flash memory address. Required by any read or write command static void seekData(uint24_t address); // selects flashaddress of program data area for reading and starts the first read - + static void seekDataArray(uint24_t address, uint8_t index, uint8_t offset, uint8_t elementSize); static void seekSave(uint24_t address); // selects flashaddress of program save area for reading and starts the first read - + static inline uint8_t readUnsafe() __attribute__((always_inline)) // read flash data without performing any checks and starts the next read. { uint8_t result = SPDR; @@ -172,27 +224,27 @@ class FX disable(); return result; }; - + static uint8_t readPendingUInt8() __attribute__ ((noinline)); //read a prefetched byte from the current flash location - + static uint8_t readPendingLastUInt8() __attribute__ ((noinline)); //read a prefetched byte from the current flash location - + static uint16_t readPendingUInt16() __attribute__ ((noinline)); //read a partly prefetched 16-bit word from the current flash location static uint16_t readPendingLastUInt16() __attribute__ ((noinline)); //read a partly prefetched 16-bit word from the current flash location - + static uint24_t readPendingUInt24() ; //read a partly prefetched 24-bit word from the current flash location - + static uint24_t readPendingLastUInt24() ; //read a partly prefetched 24-bit word from the current flash location - + static uint32_t readPendingUInt32(); //read a partly prefetched a 32-bit word from the current flash location - + static uint32_t readPendingLastUInt32(); //read a partly prefetched a 32-bit word from the current flash location - + static void readBytes(uint8_t* buffer, size_t length);// read a number of bytes from the current flash location - + static void readBytesEnd(uint8_t* buffer, size_t length); // read a number of bytes from the current flash location and end the read command - + static uint8_t readEnd(); //read last pending byte and end read command static void readDataBytes(uint24_t address, uint8_t* buffer, size_t length); @@ -203,18 +255,67 @@ class FX static void writeSavePage(uint16_t page, uint8_t* buffer); - static void drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8_t mode); - + static void drawBitmap(int16_t x, int16_t y, uint24_t address, uint8_t frame, uint8_t mode) __attribute__((noinline)); + static void readDataArray(uint24_t address, uint8_t index, uint8_t offset, uint8_t elementSize, uint8_t* buffer, size_t length); - + static uint8_t readIndexedUInt8(uint24_t address, uint8_t index); - + static uint16_t readIndexedUInt16(uint24_t address, uint8_t index); - + static uint24_t readIndexedUInt24(uint24_t address, uint8_t index); - + static uint32_t readIndexedUInt32(uint24_t address, uint8_t index); - + + /* Draw character functions */ + + static void setFont(uint24_t address, uint8_t mode); + + static void setFontMode(uint8_t mode); + + static void setCursor(int16_t x, int16_t y); + + static void setCursorX(int16_t x); + + static void setCursorY(int16_t y); + + static void setCursorRange(int16_t left, int16_t wrap); + + static void setCursorLeft(int16_t x); + + static void setCursorWrap(int16_t y); + + static void drawChar(uint8_t c); + + static void drawString(const uint8_t* buffer); + + static void drawString(const char* str); + + static void drawString(uint24_t address); + + //static void drawNumber(int8_t n, int8_t digits = 0); // draw a signed 8-bit number + // + //static void drawNumber(unt8_t n, int8_t digits = 0); // draw a unsigned 8-bit number + // + static void drawNumber(int16_t n, int8_t digits = 0); // draw a signed 16-bit number + + static void drawNumber(uint16_t n, int8_t digits = 0); // draw a unsigned 16-bit number + + static void drawNumber(int32_t n, int8_t digits = 0); // draw signed 32-bit number with a fixed number of digits + // digits == 0: No leading characters are added, all digits are drawn + // digits > 0: Leading zeros are added if the number has less than 'digit' digits + // digits < 0: Leading spaces are added if the number has less than 'digit' digits + // Note: Only 'digits' number of digits are drawn regardless if the number has more digits + // The sign character is not counted as a digit. + + static void drawNumber(uint32_t n, int8_t digits = 0); // draw unsigned 32-bit number with a fixed number of digits + // digits == 0: No leading characters are added, all digits are drawn + // digits > 0: Leading zeros are added if the number has less than 'digit' digits + // digits < 0: Leading spaces are added if the number has less than 'digit' digits + // Note: Only 'digits' number of digits are drawn regardless if the number has more digits + + /* general optimized functions */ + static inline uint16_t multiplyUInt8 (uint8_t a, uint8_t b) __attribute__((always_inline)) { #ifdef ARDUINO_ARCH_AVR @@ -230,10 +331,10 @@ class FX ); return result; #else - return (a * b); + return (a * b); #endif } - + static inline uint8_t bitShiftLeftUInt8(uint8_t bit) __attribute__((always_inline)) //fast (1 << (bit & 7)) { #ifdef ARDUINO_ARCH_AVR @@ -243,7 +344,7 @@ class FX "sbrc %[bit], 1 \n" // 1 = 001 => 0000 0010 "ldi %[result], 4 \n" // 2 = 010 => 0000 0100 "sbrc %[bit], 0 \n" // 3 = 011 => 0000 1000 - "lsl %[result] \n" + "lsl %[result] \n" "sbrc %[bit], 2 \n" // 4 = 100 => 0001 0000 "swap %[result] \n" // 5 = 101 => 0010 0000 :[result] "=&d" (result) // 6 = 110 => 0100 0000 @@ -265,7 +366,7 @@ class FX "sbrs %[bit], 1 \n" // 1 = 001 => 0100 0000 "ldi %[result], 4 \n" // 2 = 010 => 0010 0000 "sbrs %[bit], 0 \n" // 3 = 011 => 0001 0000 - "lsl %[result] \n" + "lsl %[result] \n" "sbrs %[bit], 2 \n" // 4 = 100 => 0000 1000 "swap %[result] \n" // 5 = 101 => 0000 0100 :[result] "=&d" (result) // 6 = 110 => 0000 0010 @@ -277,7 +378,7 @@ class FX return 0x80 >> (bit & 7); #endif } - + static inline uint8_t bitShiftLeftMaskUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0xFF << (bit & 7) & 0xFF) { #ifdef ARDUINO_ARCH_AVR @@ -287,12 +388,12 @@ class FX "sbrc %[bit], 1 \n" // 1 = 001 => 1111 1110 = -2 "ldi %[result], 4 \n" // 2 = 010 => 1111 1100 = -4 "sbrc %[bit], 0 \n" // 3 = 011 => 1111 1000 = -8 - "lsl %[result] \n" + "lsl %[result] \n" "sbrc %[bit], 2 \n" // 4 = 100 => 1111 0000 = -16 "swap %[result] \n" // 5 = 101 => 1110 0000 = -32 "neg %[result] \n" // 6 = 110 => 1100 0000 = -64 :[result] "=&d" (result) // 7 = 111 => 1000 0000 = -128 - :[bit] "r" (bit) + :[bit] "r" (bit) : ); return result; @@ -300,17 +401,17 @@ class FX return (0xFF << (bit & 7)) & 0xFF; #endif } - + static inline uint8_t bitShiftRightMaskUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0xFF >> (bit & 7)) { #ifdef ARDUINO_ARCH_AVR uint8_t result; asm volatile( - "ldi %[result], 2 \n" // 0 = 000 => 1111 1111 = 0x00 - 1 + "ldi %[result], 2 \n" // 0 = 000 => 1111 1111 = 0x00 - 1 "sbrs %A[bit], 1 \n" // 1 = 001 => 0111 1111 = 0x80 - 1 "ldi %[result], 8 \n" // 2 = 010 => 0011 1111 = 0x40 - 1 "sbrs %A[bit], 2 \n" // 3 = 011 => 0001 1111 = 0x20 - 1 - "swap %[result] \n" + "swap %[result] \n" "sbrs %A[bit], 0 \n" // 4 = 100 => 0000 1111 = 0x10 - 1 "lsl %[result] \n" // 5 = 101 => 0000 0111 = 0x08 - 1 "dec %[result] \n" // 6 = 110 => 0000 0011 = 0x04 - 1 @@ -323,8 +424,10 @@ class FX return 0xFF >> (bit & 7); #endif } - + static uint16_t programDataPage; // program read only data area in flash memory static uint16_t programSavePage; // program read and write data area in flash memory + static Font font; + static Cursor cursor; }; #endif