clang-format the lot

This commit is contained in:
Phillip Burgess 2020-04-30 15:30:24 -07:00
parent 40cb6a9cac
commit a51676db5e
5 changed files with 1564 additions and 1515 deletions

View file

@ -64,23 +64,23 @@ extern Protomatter_core *_PM_protoPtr; ///< In core.c (via arch.h)
// arch.h) because it's not architecture-specific. // arch.h) because it's not architecture-specific.
#define _PM_ROW_DELAY 8 ///< Delay time between row address line changes (ms) #define _PM_ROW_DELAY 8 ///< Delay time between row address line changes (ms)
Adafruit_Protomatter::Adafruit_Protomatter(uint16_t bitWidth, uint8_t bitDepth,
Adafruit_Protomatter::Adafruit_Protomatter(
uint16_t bitWidth, uint8_t bitDepth,
uint8_t rgbCount, uint8_t *rgbList, uint8_t rgbCount, uint8_t *rgbList,
uint8_t addrCount, uint8_t *addrList, uint8_t addrCount, uint8_t *addrList,
uint8_t clockPin, uint8_t latchPin, uint8_t oePin, uint8_t clockPin, uint8_t latchPin,
bool doubleBuffer, void *timer) : uint8_t oePin, bool doubleBuffer,
GFXcanvas16(bitWidth, (2 << min(addrCount, 5)) * min(rgbCount, 5)) { void *timer)
if(bitDepth > 6) bitDepth = 6; // GFXcanvas16 color limit (565) : GFXcanvas16(bitWidth, (2 << min(addrCount, 5)) * min(rgbCount, 5)) {
if (bitDepth > 6)
bitDepth = 6; // GFXcanvas16 color limit (565)
// Arguments are passed through to the C _PM_init() function which does // Arguments are passed through to the C _PM_init() function which does
// some input validation and minor allocation. Return value is ignored // some input validation and minor allocation. Return value is ignored
// because we can't really do anything about it in a C++ constructor. // because we can't really do anything about it in a C++ constructor.
// The class begin() function checks rgbPins for NULL to determine // The class begin() function checks rgbPins for NULL to determine
// whether to proceed or indicate an error. // whether to proceed or indicate an error.
(void)_PM_init(&core, bitWidth, bitDepth, rgbCount, rgbList, (void)_PM_init(&core, bitWidth, bitDepth, rgbCount, rgbList, addrCount,
addrCount, addrList, clockPin, latchPin, oePin, doubleBuffer, timer); addrList, clockPin, latchPin, oePin, doubleBuffer, timer);
} }
Adafruit_Protomatter::~Adafruit_Protomatter(void) { Adafruit_Protomatter::~Adafruit_Protomatter(void) {

View file

@ -13,7 +13,7 @@
the drawing operations. the drawing operations.
*/ */
class Adafruit_Protomatter : public GFXcanvas16 { class Adafruit_Protomatter : public GFXcanvas16 {
public: public:
/*! /*!
@brief Adafruit_Protomatter constructor. @brief Adafruit_Protomatter constructor.
@param bitWidth Total width of RGB matrix chain, in pixels. @param bitWidth Total width of RGB matrix chain, in pixels.
@ -59,11 +59,10 @@ class Adafruit_Protomatter : public GFXcanvas16 {
struct (architecture-dependent), or NULL to struct (architecture-dependent), or NULL to
use a default timer ID (also arch-dependent). use a default timer ID (also arch-dependent).
*/ */
Adafruit_Protomatter(uint16_t bitWidth, uint8_t bitDepth, Adafruit_Protomatter(uint16_t bitWidth, uint8_t bitDepth, uint8_t rgbCount,
uint8_t rgbCount, uint8_t *rgbList, uint8_t *rgbList, uint8_t addrCount, uint8_t *addrList,
uint8_t addrCount, uint8_t *addrList,
uint8_t clockPin, uint8_t latchPin, uint8_t oePin, uint8_t clockPin, uint8_t latchPin, uint8_t oePin,
bool doubleBuffer, void *timer=NULL); bool doubleBuffer, void *timer = NULL);
~Adafruit_Protomatter(void); ~Adafruit_Protomatter(void);
/*! /*!
@ -95,7 +94,8 @@ class Adafruit_Protomatter : public GFXcanvas16 {
@return Frame count since previous call to function, as a uint32_t. @return Frame count since previous call to function, as a uint32_t.
*/ */
uint32_t getFrameCount(void); uint32_t getFrameCount(void);
private:
private:
Protomatter_core core; // Underlying C struct Protomatter_core core; // Underlying C struct
void convert_byte(uint8_t *dest); // GFXcanvas16-to-matrix void convert_byte(uint8_t *dest); // GFXcanvas16-to-matrix
void convert_word(uint16_t *dest); // conversion functions void convert_word(uint16_t *dest); // conversion functions

967
arch.h

File diff suppressed because it is too large Load diff

236
core.c
View file

@ -29,10 +29,10 @@
// things hopefully makes function and variable name collisions much less // things hopefully makes function and variable name collisions much less
// likely with one's own code. // likely with one's own code.
#include <stddef.h>
#include <string.h>
#include "core.h" // enums and structs #include "core.h" // enums and structs
#include "arch.h" // Do NOT include this in any other source files #include "arch.h" // Do NOT include this in any other source files
#include <stddef.h>
#include <string.h>
// Overall matrix refresh rate (frames/second) is a function of matrix width // Overall matrix refresh rate (frames/second) is a function of matrix width
// and chain length, number of address lines, number of bit planes, CPU speed // and chain length, number of address lines, number of bit planes, CPU speed
@ -72,22 +72,28 @@ static void blast_byte(Protomatter_core *core, uint8_t *data);
static void blast_word(Protomatter_core *core, uint16_t *data); static void blast_word(Protomatter_core *core, uint16_t *data);
static void blast_long(Protomatter_core *core, uint32_t *data); static void blast_long(Protomatter_core *core, uint32_t *data);
#define _PM_clearReg(x) (*(volatile _PM_PORT_TYPE*)((x).clearReg) = ((x).bit)) ///< Clear non-RGB-data-or-clock control line (_PM_pin type) #define _PM_clearReg(x) \
#define _PM_setReg(x) (*(volatile _PM_PORT_TYPE*)((x).setReg) = ((x).bit)) ///< Set non-RGB-data-or-clock control line (_PM_pin type) (*(volatile _PM_PORT_TYPE *)((x).clearReg) = \
((x).bit)) ///< Clear non-RGB-data-or-clock control line (_PM_pin type)
#define _PM_setReg(x) \
(*(volatile _PM_PORT_TYPE *)((x).setReg) = \
((x).bit)) ///< Set non-RGB-data-or-clock control line (_PM_pin type)
// Validate and populate vital elements of core structure. // Validate and populate vital elements of core structure.
// Does NOT allocate core struct -- calling function must provide that. // Does NOT allocate core struct -- calling function must provide that.
// (In the Arduino C++ library, its part of the Protomatter class.) // (In the Arduino C++ library, its part of the Protomatter class.)
ProtomatterStatus _PM_init(Protomatter_core *core, ProtomatterStatus _PM_init(Protomatter_core *core, uint16_t bitWidth,
uint16_t bitWidth, uint8_t bitDepth, uint8_t bitDepth, uint8_t rgbCount, uint8_t *rgbList,
uint8_t rgbCount, uint8_t *rgbList,
uint8_t addrCount, uint8_t *addrList, uint8_t addrCount, uint8_t *addrList,
uint8_t clockPin, uint8_t latchPin, uint8_t oePin, uint8_t clockPin, uint8_t latchPin, uint8_t oePin,
bool doubleBuffer, void *timer) { bool doubleBuffer, void *timer) {
if(!core) return PROTOMATTER_ERR_ARG; if (!core)
return PROTOMATTER_ERR_ARG;
if(rgbCount > 5) rgbCount = 5; // Max 5 in parallel (32-bit PORT) if (rgbCount > 5)
if(addrCount > 5) addrCount = 5; // Max 5 address lines (A-E) rgbCount = 5; // Max 5 in parallel (32-bit PORT)
if (addrCount > 5)
addrCount = 5; // Max 5 address lines (A-E)
// bitDepth is NOT constrained here, handle in calling function // bitDepth is NOT constrained here, handle in calling function
// (varies with implementation, e.g. GFX lib is max 6 bitplanes, // (varies with implementation, e.g. GFX lib is max 6 bitplanes,
// but might be more or less elsewhere) // but might be more or less elsewhere)
@ -96,9 +102,11 @@ ProtomatterStatus _PM_init(Protomatter_core *core,
// If NULL timer was passed in (the default case for the constructor), // If NULL timer was passed in (the default case for the constructor),
// use default value from arch.h. For example, in the Arduino case it's // use default value from arch.h. For example, in the Arduino case it's
// tied to TC4 specifically. // tied to TC4 specifically.
if(timer == NULL) timer = _PM_TIMER_DEFAULT; if (timer == NULL)
timer = _PM_TIMER_DEFAULT;
#else #else
if(timer == NULL) return PROTOMATTER_ERR_ARG; if (timer == NULL)
return PROTOMATTER_ERR_ARG;
#endif #endif
core->timer = timer; core->timer = timer;
@ -120,10 +128,10 @@ ProtomatterStatus _PM_init(Protomatter_core *core,
// the pin bitmasks. // the pin bitmasks.
rgbCount *= 6; // Convert parallel count to pin count rgbCount *= 6; // Convert parallel count to pin count
if((core->rgbPins = (uint8_t *)_PM_ALLOCATOR(rgbCount * sizeof(uint8_t)))) { if ((core->rgbPins = (uint8_t *)_PM_ALLOCATOR(rgbCount * sizeof(uint8_t)))) {
if((core->addr = (_PM_pin *)_PM_ALLOCATOR(addrCount * sizeof(_PM_pin)))) { if ((core->addr = (_PM_pin *)_PM_ALLOCATOR(addrCount * sizeof(_PM_pin)))) {
memcpy(core->rgbPins, rgbList, rgbCount * sizeof(uint8_t)); memcpy(core->rgbPins, rgbList, rgbCount * sizeof(uint8_t));
for(uint8_t i=0; i<addrCount; i++) { for (uint8_t i = 0; i < addrCount; i++) {
core->addr[i].pin = addrList[i]; core->addr[i].pin = addrList[i];
} }
return PROTOMATTER_OK; return PROTOMATTER_OK;
@ -136,9 +144,10 @@ ProtomatterStatus _PM_init(Protomatter_core *core,
// Allocate display buffers and populate additional elements. // Allocate display buffers and populate additional elements.
ProtomatterStatus _PM_begin(Protomatter_core *core) { ProtomatterStatus _PM_begin(Protomatter_core *core) {
if(!core) return PROTOMATTER_ERR_ARG; if (!core)
return PROTOMATTER_ERR_ARG;
if(!core->rgbPins) { // NULL if copy failed to allocate if (!core->rgbPins) { // NULL if copy failed to allocate
return PROTOMATTER_ERR_MALLOC; return PROTOMATTER_ERR_MALLOC;
} }
@ -158,9 +167,9 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
uint32_t bitMask = 0; uint32_t bitMask = 0;
#endif #endif
for(uint8_t i=0; i<core->parallel * 6; i++) { for (uint8_t i = 0; i < core->parallel * 6; i++) {
uint8_t *p2 = (uint8_t *)_PM_portOutRegister(core->rgbPins[i]); uint8_t *p2 = (uint8_t *)_PM_portOutRegister(core->rgbPins[i]);
if(p2 != port) { if (p2 != port) {
return PROTOMATTER_ERR_PINS; return PROTOMATTER_ERR_PINS;
} }
bitMask |= _PM_portBitMask(core->rgbPins[i]); bitMask |= _PM_portBitMask(core->rgbPins[i]);
@ -173,11 +182,15 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
// register is present) are in the same byte, this can be stored more // register is present) are in the same byte, this can be stored more
// compact than if they're spread across a word or long. // compact than if they're spread across a word or long.
uint8_t byteMask = 0; uint8_t byteMask = 0;
if(bitMask & 0xFF000000) byteMask |= 0b1000; if (bitMask & 0xFF000000)
if(bitMask & 0x00FF0000) byteMask |= 0b0100; byteMask |= 0b1000;
if(bitMask & 0x0000FF00) byteMask |= 0b0010; if (bitMask & 0x00FF0000)
if(bitMask & 0x000000FF) byteMask |= 0b0001; byteMask |= 0b0100;
switch(byteMask) { if (bitMask & 0x0000FF00)
byteMask |= 0b0010;
if (bitMask & 0x000000FF)
byteMask |= 0b0001;
switch (byteMask) {
case 0b0001: // If all PORT bits are in the same byte... case 0b0001: // If all PORT bits are in the same byte...
case 0b0010: case 0b0010:
case 0b0100: case 0b0100:
@ -200,17 +213,19 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
core->numRowPairs = 1 << core->numAddressLines; core->numRowPairs = 1 << core->numAddressLines;
uint8_t chunks = (core->width + (_PM_chunkSize - 1)) / _PM_chunkSize; uint8_t chunks = (core->width + (_PM_chunkSize - 1)) / _PM_chunkSize;
uint16_t columns = chunks * _PM_chunkSize; // Padded matrix width uint16_t columns = chunks * _PM_chunkSize; // Padded matrix width
uint32_t screenBytes = columns * core->numRowPairs * core->numPlanes * uint32_t screenBytes =
core->bytesPerElement; columns * core->numRowPairs * core->numPlanes * core->bytesPerElement;
core->bufferSize = screenBytes; // Bytes per matrix buffer (1 or 2) core->bufferSize = screenBytes; // Bytes per matrix buffer (1 or 2)
if(core->doubleBuffer) screenBytes *= 2; // Total for matrix buffer(s) if (core->doubleBuffer)
screenBytes *= 2; // Total for matrix buffer(s)
uint32_t rgbMaskBytes = core->parallel * 6 * core->bytesPerElement; uint32_t rgbMaskBytes = core->parallel * 6 * core->bytesPerElement;
// Allocate matrix buffer(s). Don't worry about the return type... // Allocate matrix buffer(s). Don't worry about the return type...
// though we might be using words or longs for certain pin configs, // though we might be using words or longs for certain pin configs,
// _PM_ALLOCATOR() by definition always aligns to the longest type. // _PM_ALLOCATOR() by definition always aligns to the longest type.
if(!(core->screenData = (uint8_t *)_PM_ALLOCATOR(screenBytes + rgbMaskBytes))) { if (!(core->screenData =
(uint8_t *)_PM_ALLOCATOR(screenBytes + rgbMaskBytes))) {
return PROTOMATTER_ERR_MALLOC; return PROTOMATTER_ERR_MALLOC;
} }
@ -224,34 +239,33 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
#endif #endif
// Figure out clockMask and rgbAndClockMask, clear matrix buffers // Figure out clockMask and rgbAndClockMask, clear matrix buffers
if(core->bytesPerElement == 1) { if (core->bytesPerElement == 1) {
core->portOffset = _PM_byteOffset(core->rgbPins[0]); core->portOffset = _PM_byteOffset(core->rgbPins[0]);
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
// Clock and rgbAndClockMask are 8-bit values // Clock and rgbAndClockMask are 8-bit values
core->clockMask = _PM_portBitMask(core->clockPin) >> core->clockMask = _PM_portBitMask(core->clockPin) >> (core->portOffset * 8);
(core->portOffset * 8); core->rgbAndClockMask =
core->rgbAndClockMask = (bitMask >> (core->portOffset * 8)) | (bitMask >> (core->portOffset * 8)) | core->clockMask;
core->clockMask;
memset(core->screenData, core->clockMask, screenBytes); memset(core->screenData, core->clockMask, screenBytes);
#else #else
// Clock and rgbAndClockMask are 32-bit values // Clock and rgbAndClockMask are 32-bit values
core->clockMask = _PM_portBitMask(core->clockPin); core->clockMask = _PM_portBitMask(core->clockPin);
core->rgbAndClockMask = bitMask | core->clockMask; core->rgbAndClockMask = bitMask | core->clockMask;
#endif #endif
for(uint8_t i=0; i<core->parallel * 6; i++) { for (uint8_t i = 0; i < core->parallel * 6; i++) {
((uint8_t *)core->rgbMask)[i] = // Pin bitmasks are 8-bit ((uint8_t *)core->rgbMask)[i] = // Pin bitmasks are 8-bit
_PM_portBitMask(core->rgbPins[i]) >> (core->portOffset * 8); _PM_portBitMask(core->rgbPins[i]) >> (core->portOffset * 8);
} }
} else if(core->bytesPerElement == 2) { } else if (core->bytesPerElement == 2) {
core->portOffset = _PM_wordOffset(core->rgbPins[0]); core->portOffset = _PM_wordOffset(core->rgbPins[0]);
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
// Clock and rgbAndClockMask are 16-bit values // Clock and rgbAndClockMask are 16-bit values
core->clockMask = _PM_portBitMask(core->clockPin) >> core->clockMask =
(core->portOffset * 16); _PM_portBitMask(core->clockPin) >> (core->portOffset * 16);
core->rgbAndClockMask = (bitMask >> (core->portOffset * 16)) | core->rgbAndClockMask =
core->clockMask; (bitMask >> (core->portOffset * 16)) | core->clockMask;
uint32_t elements = screenBytes / 2; uint32_t elements = screenBytes / 2;
for(uint32_t i=0; i<elements; i++) { for (uint32_t i = 0; i < elements; i++) {
((uint16_t *)core->screenData)[i] = core->clockMask; ((uint16_t *)core->screenData)[i] = core->clockMask;
} }
#else #else
@ -259,7 +273,7 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
core->clockMask = _PM_portBitMask(core->clockPin); core->clockMask = _PM_portBitMask(core->clockPin);
core->rgbAndClockMask = bitMask | core->clockMask; core->rgbAndClockMask = bitMask | core->clockMask;
#endif #endif
for(uint8_t i=0; i<core->parallel * 6; i++) { for (uint8_t i = 0; i < core->parallel * 6; i++) {
((uint16_t *)core->rgbMask)[i] = // Pin bitmasks are 16-bit ((uint16_t *)core->rgbMask)[i] = // Pin bitmasks are 16-bit
_PM_portBitMask(core->rgbPins[i]) >> (core->portOffset * 16); _PM_portBitMask(core->rgbPins[i]) >> (core->portOffset * 16);
} }
@ -269,11 +283,11 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
core->rgbAndClockMask = bitMask | core->clockMask; core->rgbAndClockMask = bitMask | core->clockMask;
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
uint32_t elements = screenBytes / 4; uint32_t elements = screenBytes / 4;
for(uint32_t i=0; i<elements; i++) { for (uint32_t i = 0; i < elements; i++) {
((uint32_t *)core->screenData)[i] = core->clockMask; ((uint32_t *)core->screenData)[i] = core->clockMask;
} }
#endif #endif
for(uint8_t i=0; i<core->parallel * 6; i++) { for (uint8_t i = 0; i < core->parallel * 6; i++) {
((uint32_t *)core->rgbMask)[i] = // Pin bitmasks are 32-bit ((uint32_t *)core->rgbMask)[i] = // Pin bitmasks are 32-bit
_PM_portBitMask(core->rgbPins[i]); _PM_portBitMask(core->rgbPins[i]);
} }
@ -283,7 +297,7 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
uint32_t minPeriodPerFrame = _PM_timerFreq / _PM_MAX_REFRESH_HZ; uint32_t minPeriodPerFrame = _PM_timerFreq / _PM_MAX_REFRESH_HZ;
uint32_t minPeriodPerLine = minPeriodPerFrame / core->numRowPairs; uint32_t minPeriodPerLine = minPeriodPerFrame / core->numRowPairs;
core->minPeriod = minPeriodPerLine / ((1 << core->numPlanes) - 1); core->minPeriod = minPeriodPerLine / ((1 << core->numPlanes) - 1);
if(core->minPeriod < _PM_minMinPeriod) { if (core->minPeriod < _PM_minMinPeriod) {
core->minPeriod = _PM_minMinPeriod; core->minPeriod = _PM_minMinPeriod;
} }
// Actual frame rate may be lower than this...it's only an estimate // Actual frame rate may be lower than this...it's only an estimate
@ -313,7 +327,7 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
_PM_pinOutput(core->oe.pin); _PM_pinOutput(core->oe.pin);
_PM_pinHigh(core->oe.pin); // Init OE HIGH (disable output) _PM_pinHigh(core->oe.pin); // Init OE HIGH (disable output)
for(uint8_t i=0; i<core->parallel * 6; i++) { for (uint8_t i = 0; i < core->parallel * 6; i++) {
_PM_pinOutput(core->rgbPins[i]); _PM_pinOutput(core->rgbPins[i]);
_PM_pinLow(core->rgbPins[i]); _PM_pinLow(core->rgbPins[i]);
} }
@ -321,23 +335,20 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
core->addrPortToggle = _PM_portToggleRegister(core->addr[0].pin); core->addrPortToggle = _PM_portToggleRegister(core->addr[0].pin);
core->singleAddrPort = 1; core->singleAddrPort = 1;
#endif #endif
for(uint8_t line=0,bit=1; line<core->numAddressLines; line++, bit<<=1) { for (uint8_t line = 0, bit = 1; line < core->numAddressLines;
core->addr[line].setReg = line++, bit <<= 1) {
_PM_portSetRegister(core->addr[line].pin); core->addr[line].setReg = _PM_portSetRegister(core->addr[line].pin);
core->addr[line].clearReg = core->addr[line].clearReg = _PM_portClearRegister(core->addr[line].pin);
_PM_portClearRegister(core->addr[line].pin); core->addr[line].bit = _PM_portBitMask(core->addr[line].pin);
core->addr[line].bit =
_PM_portBitMask(core->addr[line].pin);
_PM_pinOutput(core->addr[line].pin); _PM_pinOutput(core->addr[line].pin);
if(core->prevRow & bit) { if (core->prevRow & bit) {
_PM_pinHigh(core->addr[line].pin); _PM_pinHigh(core->addr[line].pin);
} else { } else {
_PM_pinLow(core->addr[line].pin); _PM_pinLow(core->addr[line].pin);
} }
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
// If address pin on different port than addr 0, no singleAddrPort. // If address pin on different port than addr 0, no singleAddrPort.
if(_PM_portToggleRegister(core->addr[line].pin) != if (_PM_portToggleRegister(core->addr[line].pin) != core->addrPortToggle) {
core->addrPortToggle) {
core->singleAddrPort = 0; core->singleAddrPort = 0;
} }
#endif #endif
@ -360,8 +371,9 @@ ProtomatterStatus _PM_begin(Protomatter_core *core) {
// setting OE pin HIGH and writing all-zero data to matrix shift registers, // setting OE pin HIGH and writing all-zero data to matrix shift registers,
// so it won't halt with lit LEDs. // so it won't halt with lit LEDs.
void _PM_stop(Protomatter_core *core) { void _PM_stop(Protomatter_core *core) {
if((core)) { if ((core)) {
while(core->swapBuffers); // Wait for any pending buffer swap while (core->swapBuffers)
; // Wait for any pending buffer swap
_PM_timerStop(core->timer); // Halt timer _PM_timerStop(core->timer); // Halt timer
_PM_setReg(core->oe); // Set OE HIGH (disable output) _PM_setReg(core->oe); // Set OE HIGH (disable output)
// So, in PRINCIPLE, setting OE high would be sufficient... // So, in PRINCIPLE, setting OE high would be sufficient...
@ -369,11 +381,11 @@ void _PM_stop(Protomatter_core *core) {
// as the onloard LED (which pulses during bootloading) let's // as the onloard LED (which pulses during bootloading) let's
// also clear out the matrix shift registers for good measure. // also clear out the matrix shift registers for good measure.
// Set all RGB pins LOW... // Set all RGB pins LOW...
for(uint8_t i=0; i<core->parallel * 6; i++) { for (uint8_t i = 0; i < core->parallel * 6; i++) {
_PM_pinLow(core->rgbPins[i]); _PM_pinLow(core->rgbPins[i]);
} }
// Clock out bits (just need to toggle clock with RGBs held low) // Clock out bits (just need to toggle clock with RGBs held low)
for(uint32_t i=0; i<core->width; i++) { for (uint32_t i = 0; i < core->width; i++) {
_PM_pinHigh(core->clockPin); _PM_pinHigh(core->clockPin);
_PM_clockHoldHigh; _PM_clockHoldHigh;
_PM_pinLow(core->clockPin); _PM_pinLow(core->clockPin);
@ -386,7 +398,7 @@ void _PM_stop(Protomatter_core *core) {
} }
void _PM_resume(Protomatter_core *core) { void _PM_resume(Protomatter_core *core) {
if((core)) { if ((core)) {
// Init plane & row to max values so they roll over on 1st interrupt // Init plane & row to max values so they roll over on 1st interrupt
core->plane = core->numPlanes - 1; core->plane = core->numPlanes - 1;
core->row = core->numRowPairs - 1; core->row = core->numRowPairs - 1;
@ -401,19 +413,20 @@ void _PM_resume(Protomatter_core *core) {
// Free memory associated with core structure. Does NOT dealloc struct. // Free memory associated with core structure. Does NOT dealloc struct.
void _PM_free(Protomatter_core *core) { void _PM_free(Protomatter_core *core) {
if((core)) { if ((core)) {
_PM_stop(core); _PM_stop(core);
// TO DO: Set all pins back to inputs here? // TO DO: Set all pins back to inputs here?
if(core->screenData) _PM_FREE(core->screenData); if (core->screenData)
if(core->addr) _PM_FREE(core->addr); _PM_FREE(core->screenData);
if(core->rgbPins) { if (core->addr)
_PM_FREE(core->addr);
if (core->rgbPins) {
_PM_FREE(core->rgbPins); _PM_FREE(core->rgbPins);
core->rgbPins = NULL; core->rgbPins = NULL;
} }
} }
} }
// ISR function (in arch.h) calls this function which it extern'd. // ISR function (in arch.h) calls this function which it extern'd.
void _PM_row_handler(Protomatter_core *core) { void _PM_row_handler(Protomatter_core *core) {
@ -430,41 +443,41 @@ void _PM_row_handler(Protomatter_core *core) {
// of the elapsed timer value, for subsequent bitplane timing (each // of the elapsed timer value, for subsequent bitplane timing (each
// plane period is double the previous). Value is filtered slightly to // plane period is double the previous). Value is filtered slightly to
// avoid jitter. // avoid jitter.
if((prevPlane == 1) || (core->numPlanes == 1)) { if ((prevPlane == 1) || (core->numPlanes == 1)) {
core->bitZeroPeriod = ((core->bitZeroPeriod * 7) + elapsed) / 8; core->bitZeroPeriod = ((core->bitZeroPeriod * 7) + elapsed) / 8;
if(core->bitZeroPeriod < core->minPeriod) { if (core->bitZeroPeriod < core->minPeriod) {
core->bitZeroPeriod = core->minPeriod; core->bitZeroPeriod = core->minPeriod;
} }
} }
if(prevPlane == 0) { // Plane 0 just finished loading if (prevPlane == 0) { // Plane 0 just finished loading
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
// If all address lines are on a single PORT (and bit toggle is // If all address lines are on a single PORT (and bit toggle is
// available), do address line change all at once. Even doing all // available), do address line change all at once. Even doing all
// this math takes MUCH less time than the delays required when // this math takes MUCH less time than the delays required when
// doing line-by-line changes. // doing line-by-line changes.
if(core->singleAddrPort) { if (core->singleAddrPort) {
// Make bitmasks of prior and new row bits // Make bitmasks of prior and new row bits
uint32_t priorBits = 0, newBits = 0; uint32_t priorBits = 0, newBits = 0;
for(uint8_t line=0,bit=1; line<core->numAddressLines; for (uint8_t line = 0, bit = 1; line < core->numAddressLines;
line++, bit<<=1) { line++, bit <<= 1) {
if(core->row & bit) { if (core->row & bit) {
newBits |= core->addr[line].bit; newBits |= core->addr[line].bit;
} }
if(core->prevRow & bit) { if (core->prevRow & bit) {
priorBits |= core->addr[line].bit; priorBits |= core->addr[line].bit;
} }
} }
*(volatile _PM_PORT_TYPE*)core->addrPortToggle = newBits ^ priorBits; *(volatile _PM_PORT_TYPE *)core->addrPortToggle = newBits ^ priorBits;
_PM_delayMicroseconds(_PM_ROW_DELAY); _PM_delayMicroseconds(_PM_ROW_DELAY);
} else { } else {
#endif #endif
// Configure row address lines individually, making changes // Configure row address lines individually, making changes
// (with delays) only where necessary. // (with delays) only where necessary.
for(uint8_t line=0,bit=1; line<core->numAddressLines; for (uint8_t line = 0, bit = 1; line < core->numAddressLines;
line++, bit<<=1) { line++, bit <<= 1) {
if((core->row & bit) != (core->prevRow & bit)) { if ((core->row & bit) != (core->prevRow & bit)) {
if(core->row & bit) { // Set addr line high if (core->row & bit) { // Set addr line high
_PM_setReg(core->addr[line]); _PM_setReg(core->addr[line]);
} else { // Set addr line low } else { // Set addr line low
_PM_clearReg(core->addr[line]); _PM_clearReg(core->addr[line]);
@ -479,12 +492,12 @@ void _PM_row_handler(Protomatter_core *core) {
} }
// Advance bitplane index and/or row as necessary // Advance bitplane index and/or row as necessary
if(++core->plane >= core->numPlanes) { // Next data bitplane, or if (++core->plane >= core->numPlanes) { // Next data bitplane, or
core->plane = 0; // roll over bitplane to start core->plane = 0; // roll over bitplane to start
if(++core->row >= core->numRowPairs) { // Next row, or if (++core->row >= core->numRowPairs) { // Next row, or
core->row = 0; // roll over row to start core->row = 0; // roll over row to start
// Switch matrix buffers if due (only if double-buffered) // Switch matrix buffers if due (only if double-buffered)
if(core->swapBuffers) { if (core->swapBuffers) {
core->activeBuffer = 1 - core->activeBuffer; core->activeBuffer = 1 - core->activeBuffer;
core->swapBuffers = 0; // Swapped! core->swapBuffers = 0; // Swapped!
} }
@ -500,17 +513,18 @@ void _PM_row_handler(Protomatter_core *core) {
_PM_timerStart(core->timer, core->bitZeroPeriod << prevPlane); _PM_timerStart(core->timer, core->bitZeroPeriod << prevPlane);
_PM_clearReg(core->oe); // Enable LED output _PM_clearReg(core->oe); // Enable LED output
uint32_t elementsPerLine = _PM_chunkSize * uint32_t elementsPerLine =
((core->width + (_PM_chunkSize - 1)) / _PM_chunkSize); _PM_chunkSize * ((core->width + (_PM_chunkSize - 1)) / _PM_chunkSize);
uint32_t srcOffset = elementsPerLine * uint32_t srcOffset = elementsPerLine *
(core->numPlanes * core->row + core->plane) * core->bytesPerElement; (core->numPlanes * core->row + core->plane) *
if(core->doubleBuffer) { core->bytesPerElement;
if (core->doubleBuffer) {
srcOffset += core->bufferSize * core->activeBuffer; srcOffset += core->bufferSize * core->activeBuffer;
} }
if(core->bytesPerElement == 1) { if (core->bytesPerElement == 1) {
blast_byte(core, (uint8_t *)(core->screenData + srcOffset)); blast_byte(core, (uint8_t *)(core->screenData + srcOffset));
} else if(core->bytesPerElement == 2) { } else if (core->bytesPerElement == 2) {
blast_word(core, (uint16_t *)(core->screenData + srcOffset)); blast_word(core, (uint16_t *)(core->screenData + srcOffset));
} else { } else {
blast_long(core, (uint32_t *)(core->screenData + srcOffset)); blast_long(core, (uint32_t *)(core->screenData + srcOffset));
@ -530,39 +544,41 @@ void _PM_row_handler(Protomatter_core *core) {
// before setting the clock back low. If undefined, nothing goes there. // before setting the clock back low. If undefined, nothing goes there.
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
#define PEW \ #define PEW \
*toggle = *data++; /* Toggle in new data + toggle clock low */ \ *toggle = *data++; /* Toggle in new data + toggle clock low */ \
_PM_clockHoldLow; \ _PM_clockHoldLow; \
*toggle = clock; /* Toggle clock high */ \ *toggle = clock; /* Toggle clock high */ \
_PM_clockHoldHigh; _PM_clockHoldHigh;
#else #else
#define PEW \ #define PEW \
*set = *data++; /* Set RGB data high */ \ *set = *data++; /* Set RGB data high */ \
_PM_clockHoldLow; \ _PM_clockHoldLow; \
*set_full = clock; /* Set clock high */ \ *set_full = clock; /* Set clock high */ \
_PM_clockHoldHigh; \ _PM_clockHoldHigh; \
*clear_full = rgbclock; /* Clear RGB data + clock */ ///< Bitbang one set of RGB data bits to matrix *clear_full = rgbclock; \
/* Clear RGB data + clock */ ///< Bitbang one set of RGB data bits to
///< matrix
#endif #endif
#if _PM_chunkSize == 1 #if _PM_chunkSize == 1
#define PEW_UNROLL PEW #define PEW_UNROLL PEW
#elif _PM_chunkSize == 8 #elif _PM_chunkSize == 8
#define PEW_UNROLL PEW PEW PEW PEW PEW PEW PEW PEW ///< 8-way PEW unroll #define PEW_UNROLL PEW PEW PEW PEW PEW PEW PEW PEW ///< 8-way PEW unroll
#elif _PM_chunkSize == 16 #elif _PM_chunkSize == 16
#define PEW_UNROLL \ #define PEW_UNROLL \
PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW
#elif _PM_chunkSize == 32 #elif _PM_chunkSize == 32
#define PEW_UNROLL \ #define PEW_UNROLL \
PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW \ PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW \
PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW
#elif _PM_chunkSize == 64 #elif _PM_chunkSize == 64
#define PEW_UNROLL \ #define PEW_UNROLL \
PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW \ PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW \
PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW \ PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW \
PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW \ PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW \
PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW PEW
#else #else
#error "Unimplemented _PM_chunkSize value" #error "Unimplemented _PM_chunkSize value"
#endif #endif
// There are THREE COPIES of the following function -- one each for byte, // There are THREE COPIES of the following function -- one each for byte,
@ -577,8 +593,8 @@ static void blast_byte(Protomatter_core *core, uint8_t *data) {
// clock are all within the same byte of a PORT register, else we'd be // clock are all within the same byte of a PORT register, else we'd be
// in the word- or long-blasting functions now. So we just need an // in the word- or long-blasting functions now. So we just need an
// 8-bit pointer to the PORT. // 8-bit pointer to the PORT.
volatile uint8_t *toggle = (volatile uint8_t *)core->toggleReg + volatile uint8_t *toggle =
core->portOffset; (volatile uint8_t *)core->toggleReg + core->portOffset;
#else #else
// No-toggle version is a little different. If here, RGB data is all // No-toggle version is a little different. If here, RGB data is all
// in one byte of PORT register, clock can be any bit in 32-bit PORT. // in one byte of PORT register, clock can be any bit in 32-bit PORT.
@ -596,7 +612,7 @@ static void blast_byte(Protomatter_core *core, uint8_t *data) {
// PORT has already been initialized with RGB data + clock bits // PORT has already been initialized with RGB data + clock bits
// all LOW, so we don't need to initialize that state here. // all LOW, so we don't need to initialize that state here.
while(chunks--) { while (chunks--) {
PEW_UNROLL // _PM_chunkSize RGB+clock writes PEW_UNROLL // _PM_chunkSize RGB+clock writes
} }
@ -614,8 +630,8 @@ static void blast_byte(Protomatter_core *core, uint8_t *data) {
static void blast_word(Protomatter_core *core, uint16_t *data) { static void blast_word(Protomatter_core *core, uint16_t *data) {
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
// See notes above -- except now 16-bit word in PORT. // See notes above -- except now 16-bit word in PORT.
volatile uint16_t *toggle = (volatile uint16_t *)core->toggleReg + volatile uint16_t *toggle =
core->portOffset; (volatile uint16_t *)core->toggleReg + core->portOffset;
#else #else
volatile uint16_t *set; // For RGB data set volatile uint16_t *set; // For RGB data set
volatile _PM_PORT_TYPE *set_full; // For clock set volatile _PM_PORT_TYPE *set_full; // For clock set
@ -627,7 +643,7 @@ static void blast_word(Protomatter_core *core, uint16_t *data) {
#endif #endif
_PM_PORT_TYPE clock = core->clockMask; // Clock bit _PM_PORT_TYPE clock = core->clockMask; // Clock bit
uint8_t chunks = (core->width + (_PM_chunkSize - 1)) / _PM_chunkSize; uint8_t chunks = (core->width + (_PM_chunkSize - 1)) / _PM_chunkSize;
while(chunks--) { while (chunks--) {
PEW_UNROLL // _PM_chunkSize RGB+clock writes PEW_UNROLL // _PM_chunkSize RGB+clock writes
} }
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
@ -655,7 +671,7 @@ static void blast_long(Protomatter_core *core, uint32_t *data) {
#endif #endif
_PM_PORT_TYPE clock = core->clockMask; // Clock bit _PM_PORT_TYPE clock = core->clockMask; // Clock bit
uint8_t chunks = (core->width + (_PM_chunkSize - 1)) / _PM_chunkSize; uint8_t chunks = (core->width + (_PM_chunkSize - 1)) / _PM_chunkSize;
while(chunks--) { while (chunks--) {
PEW_UNROLL // _PM_chunkSize RGB+clock writes PEW_UNROLL // _PM_chunkSize RGB+clock writes
} }
#if defined(_PM_portToggleRegister) #if defined(_PM_portToggleRegister)
@ -669,7 +685,7 @@ static void blast_long(Protomatter_core *core, uint32_t *data) {
// the matrix (since this is difficult to estimate beforehand). // the matrix (since this is difficult to estimate beforehand).
uint32_t _PM_getFrameCount(Protomatter_core *core) { uint32_t _PM_getFrameCount(Protomatter_core *core) {
uint32_t count = 0; uint32_t count = 0;
if((core)) { if ((core)) {
count = core->frameCount; count = core->frameCount;
core->frameCount = 0; core->frameCount = 0;
} }

16
core.h
View file

@ -21,8 +21,8 @@
extern "C" { extern "C" {
#endif #endif
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
/** Status type returned by some functions. */ /** Status type returned by some functions. */
typedef enum { typedef enum {
@ -148,11 +148,11 @@ typedef struct {
PROTOMATTER_ERR_ARG if a bad value (core or timer pointer) was PROTOMATTER_ERR_ARG if a bad value (core or timer pointer) was
passed in. passed in.
*/ */
extern ProtomatterStatus _PM_init(Protomatter_core *core, extern ProtomatterStatus _PM_init(Protomatter_core *core, uint16_t bitWidth,
uint16_t bitWidth, uint8_t bitDepth, uint8_t bitDepth, uint8_t rgbCount,
uint8_t rgbCount, uint8_t *rgbList, uint8_t *rgbList, uint8_t addrCount,
uint8_t addrCount, uint8_t *addrList, uint8_t *addrList, uint8_t clockPin,
uint8_t clockPin, uint8_t latchPin, uint8_t oePin, uint8_t latchPin, uint8_t oePin,
bool doubleBuffer, void *timer); bool doubleBuffer, void *timer);
/*! /*!
@ -246,8 +246,8 @@ extern uint32_t _PM_timerGetCount(void *tptr);
@param width Width of canvas in pixels, as this may be different than @param width Width of canvas in pixels, as this may be different than
the matrix pixel width due to row padding. the matrix pixel width due to row padding.
*/ */
extern void _PM_convert_565(Protomatter_core *core, extern void _PM_convert_565(Protomatter_core *core, uint16_t *source,
uint16_t *source, uint16_t width); uint16_t width);
/*! /*!
@brief Pauses until the next vertical blank to avoid 'tearing' animation @brief Pauses until the next vertical blank to avoid 'tearing' animation