Skip to content

Commit

Permalink
Merge pull request arduino#312 from misaz/add_text_animation
Browse files Browse the repository at this point in the history
Add support for scrolling text asynchronously
  • Loading branch information
pennam authored Nov 26, 2024
2 parents c68c140 + 37c23e7 commit 613fc37
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// To use ArduinoGraphics APIs, please include BEFORE Arduino_LED_Matrix and TextAnimation
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
#include "TextAnimation.h"

ArduinoLEDMatrix matrix;

// 100 frames maximum. Compute as maximum length of text you want to print (eg. 20 chars)
// multiplied by font width (eg. 5 for Font_5x7), so 20 chars * 5 px = 100. If you enter lower
// value (or your text get unexpectedly long), animation will be cut and end soon.
TEXT_ANIMATION_DEFINE(anim, 100)

int counter;
bool requestNext = false;

void setup() {
pinMode(LED_BUILTIN, OUTPUT);

matrix.begin();
matrix.beginDraw();

matrix.stroke(0xFFFFFFFF);
matrix.textFont(Font_5x7);
matrix.textScrollSpeed(60);
matrix.setCallback(matrixCallback);

const char text[] = " UNO r4 ";
matrix.beginText(0, 1, 0xFFFFFF);
matrix.println(text);
matrix.endTextAnimation(SCROLL_LEFT, anim);

matrix.loadTextAnimationSequence(anim);
matrix.play();

// now animation play asynchronously. Will call matrixCallback once completed.
}

void matrixCallback() {
// callback is executed in IRQ and should run as fast as possible
requestNext = true;
}

void loop() {
if (requestNext) {
requestNext = false;

matrix.beginText(0, 1, 0xFFFFFF);
matrix.print(" ");
matrix.println(counter);
matrix.endTextAnimation(SCROLL_RIGHT, anim);

if (counter++ >= 20) {
counter = 0;
}

matrix.loadTextAnimationSequence(anim);
matrix.play();
}

delay(500);
digitalWrite(LED_BUILTIN, 0);
delay(500);
digitalWrite(LED_BUILTIN, 1);
}
56 changes: 47 additions & 9 deletions libraries/Arduino_LED_Matrix/src/Arduino_LED_Matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ static uint32_t reverse(uint32_t x)
}

// TODO: this is dangerous, use with care
#define loadSequence(frames) loadWrapper(frames, sizeof(frames))
#define renderBitmap(bitmap, rows, columns) loadPixels(&bitmap[0][0], rows*columns)
#define loadSequence(frames) loadWrapper(frames, sizeof(frames))
#define renderBitmap(bitmap, rows, columns) loadPixels(&bitmap[0][0], rows*columns)
#define endTextAnimation(scrollDirection, anim) endTextToAnimationBuffer(scrollDirection, anim ## _buf, sizeof(anim ## _buf), anim ## _buf_used)
#define loadTextAnimationSequence(anim) loadWrapper(anim ## _buf, anim ## _buf_used)

static uint8_t __attribute__((aligned)) framebuffer[NUM_LEDS / 8];

Expand Down Expand Up @@ -227,11 +229,11 @@ class ArduinoLEDMatrix
return false;
}

void loadPixels(uint8_t *arr, size_t size){
static void loadPixelsToBuffer(uint8_t* arr, size_t size, uint32_t* dst) {
uint32_t partialBuffer = 0;
uint8_t pixelIndex = 0;
uint8_t *frameP = arr;
uint32_t *frameHolderP = _frameHolder;
uint32_t *frameHolderP = dst;
while (pixelIndex < size) {
partialBuffer |= *frameP++;
if ((pixelIndex + 1) % 32 == 0) {
Expand All @@ -240,6 +242,10 @@ class ArduinoLEDMatrix
partialBuffer = partialBuffer << 1;
pixelIndex++;
}
}

void loadPixels(uint8_t *arr, size_t size){
loadPixelsToBuffer(arr, size, _frameHolder);
loadFrame(_frameHolder);
};

Expand All @@ -255,9 +261,9 @@ class ArduinoLEDMatrix

void clear() {
const uint32_t fullOff[] = {
0x00000000,
0x00000000,
0x00000000
0x00000000,
0x00000000,
0x00000000
};
loadFrame(fullOff);
#ifdef MATRIX_WITH_ARDUINOGRAPHICS
Expand All @@ -280,16 +286,48 @@ class ArduinoLEDMatrix
renderBitmap(_canvasBuffer, canvasHeight, canvasWidth);
}

// display the drawing
// display the drawing or capture it to buffer when rendering dynamic anymation
void endDraw() {
ArduinoGraphics::endDraw();
renderBitmap(_canvasBuffer, canvasHeight, canvasWidth);

if (!captureAnimation) {
renderBitmap(_canvasBuffer, canvasHeight, canvasWidth);
} else {
if (captureAnimationHowManyRemains >= 4) {
loadPixelsToBuffer(&_canvasBuffer[0][0], sizeof(_canvasBuffer), captureAnimationFrame);
captureAnimationFrame[3] = _textScrollSpeed;
captureAnimationFrame += 4;
captureAnimationHowManyRemains -= 16;
}
}
}

void endTextToAnimationBuffer(int scrollDirection, uint32_t frames[][4], uint32_t howManyMax, uint32_t& howManyUsed) {
captureAnimationFrame = &frames[0][0];
captureAnimationHowManyRemains = howManyMax;

captureAnimation = true;
ArduinoGraphics::textScrollSpeed(0);
ArduinoGraphics::endText(scrollDirection);
ArduinoGraphics::textScrollSpeed(_textScrollSpeed);
captureAnimation = false;

howManyUsed = howManyMax - captureAnimationHowManyRemains;
}

void textScrollSpeed(unsigned long speed) {
ArduinoGraphics::textScrollSpeed(speed);
_textScrollSpeed = speed;
}

private:
uint32_t* captureAnimationFrame = nullptr;
uint32_t captureAnimationHowManyRemains = 0;
bool captureAnimation = false;
static const byte canvasWidth = 12;
static const byte canvasHeight = 8;
uint8_t _canvasBuffer[canvasHeight][canvasWidth] = {{0}};
unsigned long _textScrollSpeed = 100;
#endif

private:
Expand Down
15 changes: 15 additions & 0 deletions libraries/Arduino_LED_Matrix/src/TextAnimation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "Arduino.h"

#if not __has_include("ArduinoGraphics.h")
#error "TextAnimation work only when ArduinoGraphics is installed and used. Include ArduinoGraphics first."
#endif

#define TEXT_ANIMATION_DECLARE(NAME, MAX_CHARS) \
extern uint32_t NAME ## _buf[MAX_CHARS][4]; \
extern uint32_t NAME ## _buf_used;

#define TEXT_ANIMATION_DEFINE(NAME, MAX_CHARS) \
uint32_t NAME ## _buf[MAX_CHARS][4]; \
uint32_t NAME ## _buf_used = 0;

0 comments on commit 613fc37

Please sign in to comment.