update arduboy core, fx library
fixed warning in wiring.c added draw string and numbers functions to fx library added Hello World fx example
This commit is contained in:
parent
ceb410ee11
commit
b0c7ed2663
|
@ -272,6 +272,7 @@ unsigned long micros() {
|
||||||
"x" (&timer0_overflow_count)
|
"x" (&timer0_overflow_count)
|
||||||
: "r18"
|
: "r18"
|
||||||
);
|
);
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delay(unsigned long ms)
|
void delay(unsigned long ms)
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**** FX data header generated by fxdata-build.py tool version 1.07 ****/
|
||||||
|
|
||||||
|
using uint24_t = __uint24;
|
||||||
|
|
||||||
|
// Initialize FX hardware using FX::begin(FX_DATA_PAGE); in the setup() function.
|
||||||
|
|
||||||
|
constexpr uint16_t FX_DATA_PAGE = 0xffc9;
|
||||||
|
constexpr uint24_t FX_DATA_BYTES = 13937;
|
||||||
|
|
||||||
|
constexpr uint24_t arduboyFont = 0x000000;
|
||||||
|
constexpr uint16_t arduboyFontWidth = 6;
|
||||||
|
constexpr uint16_t arduboyFontHeight = 8;
|
||||||
|
constexpr uint16_t arduboyFontFrames = 256;
|
||||||
|
|
||||||
|
constexpr uint24_t maskedFont = 0x000604;
|
||||||
|
constexpr uint16_t maskedFontWidth = 16;
|
||||||
|
constexpr uint16_t maskedFontHeight = 24;
|
||||||
|
constexpr uint8_t maskedFontFrames = 128;
|
||||||
|
|
||||||
|
constexpr uint24_t helloWorld = 0x003608;
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
image_t arduboyFont = "arduboyFont_6x8.png"
|
||||||
|
image_t maskedFont = "maskedFont_16x24.png"
|
||||||
|
|
||||||
|
string helloWorld = "Hello World! This example uses the FX::drawString() function to draw text from the FX flash chip."
|
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
|
@ -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 <Arduboy2.h>
|
||||||
|
#include <ArduboyFX.h>
|
||||||
|
#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
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
name=ArduboyFX
|
name=ArduboyFX
|
||||||
version=1.0.2
|
version=1.0.3
|
||||||
author=Mr.Blinky
|
author=Mr.Blinky
|
||||||
maintainer=mstr.blinky@gmail.com
|
maintainer=mstr.blinky@gmail.com
|
||||||
sentence=The Arduboy FX library.
|
sentence=The Arduboy FX library.
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
uint16_t FX::programDataPage; // program read only data location in flash memory
|
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
|
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)
|
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"
|
" sbrs %[height], 0 \n"
|
||||||
" lsr %[rowmask] \n"
|
" lsr %[rowmask] \n"
|
||||||
" dec %[rowmask] \n"
|
" dec %[rowmask] \n"
|
||||||
" breq .+4 \n"
|
" breq .+4 \n"
|
||||||
" cpi %[renderheight], 8 \n" // if (renderheight >= 8) rowmask = 0xFF;
|
" cpi %[renderheight], 8 \n" // if (renderheight >= 8) rowmask = 0xFF;
|
||||||
" brlt .+2 \n"
|
" brlt .+2 \n"
|
||||||
" ldi %[rowmask], 0xFF \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"
|
" rjmp .-6 \n"
|
||||||
" cbi %[csport], %[csbit] \n" // enableOLED();
|
" cbi %[csport], %[csbit] \n" // enableOLED();
|
||||||
"1: \n" // while (true) {
|
"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;
|
" 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;
|
" cpse %[clear], r1 ;1-2 \n" // if (clear) displaydata = 0;
|
||||||
" mov r0, r1 ;1 \n"
|
" mov r0, r1 ;1 \n"
|
||||||
" st Z+, r0 ;2 \n" // *ptr++ = displaydata;
|
" 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"
|
" nop ;1 \n"
|
||||||
" st %a[target]+, r24 ;2 /11 \n"
|
" st %a[target]+, r24 ;2 /11 \n"
|
||||||
"2: \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"
|
" cpc r31, r25 ;1 \n"
|
||||||
" brcs 1b ;1-2/4 \n" // }
|
" brcs 1b ;1-2/4 \n" // }
|
||||||
"3: \n"
|
"3: \n"
|
||||||
|
@ -758,7 +760,150 @@ void FX::display()
|
||||||
|
|
||||||
void FX::display(bool clear)
|
void FX::display(bool clear)
|
||||||
{
|
{
|
||||||
enableOLED();
|
enableOLED();
|
||||||
Arduboy2Base::display(clear);
|
Arduboy2Base::display(clear);
|
||||||
disableOLED();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
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(dbfBlack) | // black pixels in bitmap will not change pixels on display
|
||||||
_BV(dbfWhiteBlack); // (same as sprites drawErase)
|
_BV(dbfWhiteBlack); // (same as sprites drawErase)
|
||||||
|
|
||||||
constexpr uint8_t dbmWhite = _BV(dbfWhiteBlack); // white pixels in bitmap will be drawn as white pixels on display
|
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
|
// black pixels in bitmap will not change pixels on display
|
||||||
//(same as sprites drawSelfMasked)
|
//(same as sprites drawSelfMasked)
|
||||||
|
|
||||||
constexpr uint8_t dbmInvert = _BV(dbfInvert); // when a pixel in bitmap has a different color than on display the
|
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 on display will be drawn as white. In all other cases the
|
||||||
// pixel will be drawn as black
|
// 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 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
|
constexpr uint8_t dbmOverwrite = 0; // Black pixels in bitmap will be drawn as black pixels on display
|
||||||
// (Same as sprites drawOverwrite)
|
// (Same as sprites drawOverwrite)
|
||||||
|
|
||||||
constexpr uint8_t dbmReverse = _BV(dbfReverseBlack); // White pixels in bitmap will be drawn as black pixels on display
|
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
|
// 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
|
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
|
// drawn and which pixels remain unchanged on display
|
||||||
// (same as sprites drawPlusMask)
|
// (same as sprites drawPlusMask)
|
||||||
|
|
||||||
// Note above modes may be combined like (dbmMasked | dbmReverse)
|
// 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;
|
using uint24_t = __uint24;
|
||||||
|
|
||||||
struct JedecID
|
struct JedecID
|
||||||
|
@ -80,6 +116,22 @@ struct FXAddress
|
||||||
uint8_t offset;
|
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
|
class FX
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -92,7 +144,7 @@ class FX
|
||||||
{
|
{
|
||||||
CS_PORT |= (1 << CS_BIT);
|
CS_PORT |= (1 << CS_BIT);
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void enable() __attribute__((always_inline)) // selects external flash memory and allows new commands
|
static inline void enable() __attribute__((always_inline)) // selects external flash memory and allows new commands
|
||||||
{
|
{
|
||||||
FX_PORT &= ~(1 << FX_BIT);
|
FX_PORT &= ~(1 << FX_BIT);
|
||||||
|
@ -107,16 +159,16 @@ class FX
|
||||||
{
|
{
|
||||||
while ((SPSR & _BV(SPIF)) == 0);
|
while ((SPSR & _BV(SPIF)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t writeByte(uint8_t data); // write a single byte to flash memory.
|
static uint8_t writeByte(uint8_t data); // write a single byte to flash memory.
|
||||||
|
|
||||||
static inline void writeByteBeforeWait(uint8_t data) __attribute__((always_inline))
|
static inline void writeByteBeforeWait(uint8_t data) __attribute__((always_inline))
|
||||||
{
|
{
|
||||||
SPDR = data;
|
SPDR = data;
|
||||||
asm volatile("nop\n");
|
asm volatile("nop\n");
|
||||||
wait();
|
wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void writeByteAfterWait(uint8_t data) __attribute__((always_inline))
|
static inline void writeByteAfterWait(uint8_t data) __attribute__((always_inline))
|
||||||
{
|
{
|
||||||
wait();
|
wait();
|
||||||
|
@ -128,9 +180,9 @@ class FX
|
||||||
static void displayPrefetch(uint24_t address, uint8_t* target, uint16_t len, bool clear);
|
static void displayPrefetch(uint24_t address, uint8_t* target, uint16_t len, bool clear);
|
||||||
|
|
||||||
static void display(); // display screen buffer
|
static void display(); // display screen buffer
|
||||||
|
|
||||||
static void display(bool clear); // display screen buffer with clear
|
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(); // 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
|
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 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 void readJedecID(JedecID* id);
|
||||||
|
|
||||||
static bool detect(); //detect presence of initialized flash memory
|
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 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 writeCommand(uint8_t command); // write a single byte flash command
|
||||||
|
|
||||||
static void wakeUp(); // Wake up flash memory from power down mode
|
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 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 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 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 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.
|
static inline uint8_t readUnsafe() __attribute__((always_inline)) // read flash data without performing any checks and starts the next read.
|
||||||
{
|
{
|
||||||
uint8_t result = SPDR;
|
uint8_t result = SPDR;
|
||||||
|
@ -172,27 +224,27 @@ class FX
|
||||||
disable();
|
disable();
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint8_t readPendingUInt8() __attribute__ ((noinline)); //read a prefetched byte from the current flash location
|
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 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 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 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 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 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 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 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 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 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 uint8_t readEnd(); //read last pending byte and end read command
|
||||||
|
|
||||||
static void readDataBytes(uint24_t address, uint8_t* buffer, size_t length);
|
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 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 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 uint8_t readIndexedUInt8(uint24_t address, uint8_t index);
|
||||||
|
|
||||||
static uint16_t readIndexedUInt16(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 uint24_t readIndexedUInt24(uint24_t address, uint8_t index);
|
||||||
|
|
||||||
static uint32_t readIndexedUInt32(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))
|
static inline uint16_t multiplyUInt8 (uint8_t a, uint8_t b) __attribute__((always_inline))
|
||||||
{
|
{
|
||||||
#ifdef ARDUINO_ARCH_AVR
|
#ifdef ARDUINO_ARCH_AVR
|
||||||
|
@ -230,10 +331,10 @@ class FX
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
#else
|
#else
|
||||||
return (a * b);
|
return (a * b);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t bitShiftLeftUInt8(uint8_t bit) __attribute__((always_inline)) //fast (1 << (bit & 7))
|
static inline uint8_t bitShiftLeftUInt8(uint8_t bit) __attribute__((always_inline)) //fast (1 << (bit & 7))
|
||||||
{
|
{
|
||||||
#ifdef ARDUINO_ARCH_AVR
|
#ifdef ARDUINO_ARCH_AVR
|
||||||
|
@ -243,7 +344,7 @@ class FX
|
||||||
"sbrc %[bit], 1 \n" // 1 = 001 => 0000 0010
|
"sbrc %[bit], 1 \n" // 1 = 001 => 0000 0010
|
||||||
"ldi %[result], 4 \n" // 2 = 010 => 0000 0100
|
"ldi %[result], 4 \n" // 2 = 010 => 0000 0100
|
||||||
"sbrc %[bit], 0 \n" // 3 = 011 => 0000 1000
|
"sbrc %[bit], 0 \n" // 3 = 011 => 0000 1000
|
||||||
"lsl %[result] \n"
|
"lsl %[result] \n"
|
||||||
"sbrc %[bit], 2 \n" // 4 = 100 => 0001 0000
|
"sbrc %[bit], 2 \n" // 4 = 100 => 0001 0000
|
||||||
"swap %[result] \n" // 5 = 101 => 0010 0000
|
"swap %[result] \n" // 5 = 101 => 0010 0000
|
||||||
:[result] "=&d" (result) // 6 = 110 => 0100 0000
|
:[result] "=&d" (result) // 6 = 110 => 0100 0000
|
||||||
|
@ -265,7 +366,7 @@ class FX
|
||||||
"sbrs %[bit], 1 \n" // 1 = 001 => 0100 0000
|
"sbrs %[bit], 1 \n" // 1 = 001 => 0100 0000
|
||||||
"ldi %[result], 4 \n" // 2 = 010 => 0010 0000
|
"ldi %[result], 4 \n" // 2 = 010 => 0010 0000
|
||||||
"sbrs %[bit], 0 \n" // 3 = 011 => 0001 0000
|
"sbrs %[bit], 0 \n" // 3 = 011 => 0001 0000
|
||||||
"lsl %[result] \n"
|
"lsl %[result] \n"
|
||||||
"sbrs %[bit], 2 \n" // 4 = 100 => 0000 1000
|
"sbrs %[bit], 2 \n" // 4 = 100 => 0000 1000
|
||||||
"swap %[result] \n" // 5 = 101 => 0000 0100
|
"swap %[result] \n" // 5 = 101 => 0000 0100
|
||||||
:[result] "=&d" (result) // 6 = 110 => 0000 0010
|
:[result] "=&d" (result) // 6 = 110 => 0000 0010
|
||||||
|
@ -277,7 +378,7 @@ class FX
|
||||||
return 0x80 >> (bit & 7);
|
return 0x80 >> (bit & 7);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t bitShiftLeftMaskUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0xFF << (bit & 7) & 0xFF)
|
static inline uint8_t bitShiftLeftMaskUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0xFF << (bit & 7) & 0xFF)
|
||||||
{
|
{
|
||||||
#ifdef ARDUINO_ARCH_AVR
|
#ifdef ARDUINO_ARCH_AVR
|
||||||
|
@ -287,12 +388,12 @@ class FX
|
||||||
"sbrc %[bit], 1 \n" // 1 = 001 => 1111 1110 = -2
|
"sbrc %[bit], 1 \n" // 1 = 001 => 1111 1110 = -2
|
||||||
"ldi %[result], 4 \n" // 2 = 010 => 1111 1100 = -4
|
"ldi %[result], 4 \n" // 2 = 010 => 1111 1100 = -4
|
||||||
"sbrc %[bit], 0 \n" // 3 = 011 => 1111 1000 = -8
|
"sbrc %[bit], 0 \n" // 3 = 011 => 1111 1000 = -8
|
||||||
"lsl %[result] \n"
|
"lsl %[result] \n"
|
||||||
"sbrc %[bit], 2 \n" // 4 = 100 => 1111 0000 = -16
|
"sbrc %[bit], 2 \n" // 4 = 100 => 1111 0000 = -16
|
||||||
"swap %[result] \n" // 5 = 101 => 1110 0000 = -32
|
"swap %[result] \n" // 5 = 101 => 1110 0000 = -32
|
||||||
"neg %[result] \n" // 6 = 110 => 1100 0000 = -64
|
"neg %[result] \n" // 6 = 110 => 1100 0000 = -64
|
||||||
:[result] "=&d" (result) // 7 = 111 => 1000 0000 = -128
|
:[result] "=&d" (result) // 7 = 111 => 1000 0000 = -128
|
||||||
:[bit] "r" (bit)
|
:[bit] "r" (bit)
|
||||||
:
|
:
|
||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
|
@ -300,17 +401,17 @@ class FX
|
||||||
return (0xFF << (bit & 7)) & 0xFF;
|
return (0xFF << (bit & 7)) & 0xFF;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t bitShiftRightMaskUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0xFF >> (bit & 7))
|
static inline uint8_t bitShiftRightMaskUInt8(uint8_t bit) __attribute__((always_inline)) //fast (0xFF >> (bit & 7))
|
||||||
{
|
{
|
||||||
#ifdef ARDUINO_ARCH_AVR
|
#ifdef ARDUINO_ARCH_AVR
|
||||||
uint8_t result;
|
uint8_t result;
|
||||||
asm volatile(
|
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
|
"sbrs %A[bit], 1 \n" // 1 = 001 => 0111 1111 = 0x80 - 1
|
||||||
"ldi %[result], 8 \n" // 2 = 010 => 0011 1111 = 0x40 - 1
|
"ldi %[result], 8 \n" // 2 = 010 => 0011 1111 = 0x40 - 1
|
||||||
"sbrs %A[bit], 2 \n" // 3 = 011 => 0001 1111 = 0x20 - 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
|
"sbrs %A[bit], 0 \n" // 4 = 100 => 0000 1111 = 0x10 - 1
|
||||||
"lsl %[result] \n" // 5 = 101 => 0000 0111 = 0x08 - 1
|
"lsl %[result] \n" // 5 = 101 => 0000 0111 = 0x08 - 1
|
||||||
"dec %[result] \n" // 6 = 110 => 0000 0011 = 0x04 - 1
|
"dec %[result] \n" // 6 = 110 => 0000 0011 = 0x04 - 1
|
||||||
|
@ -323,8 +424,10 @@ class FX
|
||||||
return 0xFF >> (bit & 7);
|
return 0xFF >> (bit & 7);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t programDataPage; // program read only data area in flash memory
|
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 uint16_t programSavePage; // program read and write data area in flash memory
|
||||||
|
static Font font;
|
||||||
|
static Cursor cursor;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue