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:
Mr.Blinky 2022-03-21 21:21:15 +01:00
parent ceb410ee11
commit b0c7ed2663
10 changed files with 411 additions and 52 deletions

View File

@ -272,6 +272,7 @@ unsigned long micros() {
"x" (&timer0_overflow_count)
: "r18"
);
return m;
}
void delay(unsigned long ms)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -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;

View File

@ -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

View File

@ -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
}

View File

@ -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.

View File

@ -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)
@ -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"
@ -762,3 +764,146 @@ void FX::display(bool clear)
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);
}

View File

@ -65,6 +65,42 @@ constexpr uint8_t dbmMasked = _BV(dbfMasked); // The bitmap contains a
// 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:
@ -203,7 +255,7 @@ 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);
@ -215,6 +267,55 @@ class FX
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
@ -326,5 +427,7 @@ class FX
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