/ Adafruit_Protomatter.cpp
Adafruit_Protomatter.cpp
1 // Arduino-specific wrapper for the Protomatter C library (provides 2 // constructor and so forth, builds on Adafruit_GFX). There should 3 // not be any device-specific #ifdefs here. See notes in core.c and 4 // arch.h regarding portability. 5 6 #include "Adafruit_Protomatter.h" // Also includes core.h & Adafruit_GFX.h 7 8 extern Protomatter_core *_PM_protoPtr; // In core.c (via arch.h) 9 10 // Overall matrix refresh rate (frames/second) is a function of matrix width 11 // and chain length, number of address lines, number of bit planes, CPU speed 12 // and whether or not a GPIO toggle register is available. There is no "this 13 // will run at X-frames-per-second" constant figure. You typically just have 14 // to try it out and perhaps trade off some bit planes for refresh rate until 15 // the image looks good and stable. Anything over 100 Hz is usually passable, 16 // around 250 Hz is where things firm up. And while this could proceed higher 17 // in some situations, the tradeoff is that faster rates use progressively 18 // more CPU time (because it's timer interrupt based and not using DMA or 19 // special peripherals). So a throttle is set here, an approximate maximum 20 // frame rate which the software will attempt to avoid exceeding (but may 21 // refresh slower than this, and in many cases will...just need to set an 22 // upper limit to avoid excessive CPU load). An incredibly long comment block 23 // for a single constant, thank you for coming to my TED talk! 24 #define _PM_MAX_REFRESH_HZ 250 25 26 // Time (in milliseconds) to pause following any change in address lines 27 // (individually or collectively). Some matrices respond slowly there... 28 // must pause on change for matrix to catch up. Defined here (rather than 29 // arch.h) because it's not architecture-specific. 30 #define _PM_ROW_DELAY 8 31 32 33 Adafruit_Protomatter::Adafruit_Protomatter( 34 uint16_t bitWidth, uint8_t bitDepth, 35 uint8_t rgbCount, uint8_t *rgbList, 36 uint8_t addrCount, uint8_t *addrList, 37 uint8_t clockPin, uint8_t latchPin, uint8_t oePin, 38 bool doubleBuffer, void *timer) : 39 GFXcanvas16(bitWidth, (2 << min(addrCount, 5)) * min(rgbCount, 5)) { 40 if(bitDepth > 6) bitDepth = 6; // GFXcanvas16 color limit (565) 41 42 // Arguments are passed through to the C _PM_init() function which does 43 // some input validation and minor allocation. Return value is ignored 44 // because we can't really do anything about it in a C++ constructor. 45 // The class begin() function checks rgbPins for NULL to determine 46 // whether to proceed or indicate an error. 47 (void)_PM_init(&core, bitWidth, bitDepth, rgbCount, rgbList, 48 addrCount, addrList, clockPin, latchPin, oePin, doubleBuffer, timer); 49 } 50 51 Adafruit_Protomatter::~Adafruit_Protomatter(void) { 52 _PM_free(&core); 53 _PM_protoPtr = NULL; 54 } 55 56 ProtomatterStatus Adafruit_Protomatter::begin(void) { 57 _PM_protoPtr = &core; 58 _PM_begin(&core); 59 return PROTOMATTER_OK; 60 } 61 62 // Transfer data from GFXcanvas16 to the matrix framebuffer's weird 63 // internal format. The actual conversion functions referenced below 64 // are in core.c, reasoning is explained there. 65 void Adafruit_Protomatter::show(void) { 66 67 // Destination address is computed in convert function 68 // (based on active buffer value, if double-buffering), 69 // just need to pass in the canvas buffer address and 70 // width in pixels. 71 if(core.bytesPerElement == 1) { 72 _PM_convert_565_byte(&core, getBuffer(), WIDTH); 73 } else if(core.bytesPerElement == 2) { 74 _PM_convert_565_word(&core, getBuffer(), WIDTH); 75 } else { 76 _PM_convert_565_long(&core, getBuffer(), WIDTH); 77 } 78 79 if(core.doubleBuffer) { 80 core.swapBuffers = 1; 81 // To avoid overwriting data on the matrix, don't return 82 // until the timer ISR has performed the swap at the right time. 83 while(core.swapBuffers); 84 } 85 } 86 87 // Returns current value of frame counter and resets its value to zero. 88 // Two calls to this, timed one second apart (or use math with other 89 // intervals), can be used to get a rough frames-per-second value for 90 // the matrix (since this is difficult to estimate beforehand). 91 uint32_t Adafruit_Protomatter::getFrameCount(void) { 92 return _PM_getFrameCount(_PM_protoPtr); 93 }