初始化提交
This commit is contained in:
297
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx.cpp
Normal file
297
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
|
||||
This file contains class and hardware related methods.
|
||||
|
||||
Copyright (C) 2012-14 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include "MD_MAX72xx.h"
|
||||
#include "MD_MAX72xx_lib.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Implements class definition and general methods
|
||||
*/
|
||||
|
||||
MD_MAX72XX::MD_MAX72XX(uint8_t dataPin, uint8_t clkPin, uint8_t csPin, uint8_t numDevices):
|
||||
_dataPin(dataPin), _clkPin(clkPin), _csPin(csPin), _maxDevices(numDevices),
|
||||
_updateEnabled(true), _hardwareSPI(false)
|
||||
{
|
||||
}
|
||||
|
||||
MD_MAX72XX::MD_MAX72XX(uint8_t csPin, uint8_t numDevices):
|
||||
_dataPin(0), _clkPin(0), _csPin(csPin), _maxDevices(numDevices),
|
||||
_updateEnabled(true), _hardwareSPI(true)
|
||||
{
|
||||
}
|
||||
|
||||
void MD_MAX72XX::begin(void)
|
||||
{
|
||||
// initialize the AVR hardware
|
||||
if (_hardwareSPI)
|
||||
{
|
||||
PRINTS("\nHardware SPI");
|
||||
SPI.begin();
|
||||
// Old mode of operations!
|
||||
//SPI.setDataMode(SPI_MODE0);
|
||||
//SPI.setBitOrder(MSBFIRST);
|
||||
//SPI.setClockDivider(SPI_CLOCK_DIV2);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINTS("\nBitBang SPI")
|
||||
pinMode(_dataPin, OUTPUT);
|
||||
pinMode(_clkPin, OUTPUT);
|
||||
}
|
||||
|
||||
// initialise our preferred CS pin (could be same as SS)
|
||||
digitalWrite(_csPin, HIGH);
|
||||
pinMode(_csPin, OUTPUT);
|
||||
|
||||
// object memory and internals
|
||||
setShiftDataInCallback(NULL);
|
||||
setShiftDataOutCallback(NULL);
|
||||
|
||||
_matrix = (deviceInfo_t *)malloc(sizeof(deviceInfo_t) * _maxDevices);
|
||||
_spiData = (uint8_t *)malloc(SPI_DATA_SIZE);
|
||||
|
||||
#if USE_LOCAL_FONT
|
||||
#if USE_INDEX_FONT
|
||||
_fontIndex = (uint16_t *)malloc(sizeof(uint16_t) * ASCII_INDEX_SIZE);
|
||||
#else
|
||||
_fontIndex = NULL;
|
||||
#endif
|
||||
setFont(NULL);
|
||||
#endif // INCLUDE_LOCAL_FONT
|
||||
|
||||
// Initialize the display devices. On initial power-up
|
||||
// - all control registers are reset,
|
||||
// - scan limit is set to one digit (row/col or LED),
|
||||
// - Decoding mode is off,
|
||||
// - intensity is set to the minimum,
|
||||
// - the display is blanked, and
|
||||
// - the MAX7219/MAX7221 is shut down.
|
||||
// The devices need to be set to our library defaults prior using the
|
||||
// display modules.
|
||||
control(TEST, OFF); // no test
|
||||
control(SCANLIMIT, ROW_SIZE-1); // scan limit is set to max on startup
|
||||
control(INTENSITY, MAX_INTENSITY/2); // set intensity to a reasonable value
|
||||
control(DECODE, OFF); // make sure that no decoding happens (warm boot potential issue)
|
||||
clear();
|
||||
control(SHUTDOWN, OFF); // take the modules out of shutdown mode
|
||||
}
|
||||
|
||||
MD_MAX72XX::~MD_MAX72XX(void)
|
||||
{
|
||||
if (_hardwareSPI) SPI.end(); // reset SPI mode
|
||||
|
||||
free(_matrix);
|
||||
free(_spiData);
|
||||
#if USE_LOCAL_FONT && USE_FONT_INDEX
|
||||
if (_fontIndex != NULL) free(_fontIndex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MD_MAX72XX::controlHardware(uint8_t dev, controlRequest_t mode, int value)
|
||||
// control command is for the devices, translate internal request to device bytes
|
||||
// into the transmission buffer
|
||||
{
|
||||
uint8_t opcode = OP_NOOP;
|
||||
uint8_t param = 0;
|
||||
|
||||
// work out data to write
|
||||
switch (mode)
|
||||
{
|
||||
case SHUTDOWN:
|
||||
opcode = OP_SHUTDOWN;
|
||||
param = (value == OFF ? 1 : 0);
|
||||
break;
|
||||
|
||||
case SCANLIMIT:
|
||||
opcode = OP_SCANLIMIT;
|
||||
param = (value > MAX_SCANLIMIT ? MAX_SCANLIMIT : value);
|
||||
break;
|
||||
|
||||
case INTENSITY:
|
||||
opcode = OP_INTENSITY;
|
||||
param = (value > MAX_INTENSITY ? MAX_INTENSITY : value);
|
||||
break;
|
||||
|
||||
case DECODE:
|
||||
opcode = OP_DECODEMODE;
|
||||
param = (value == OFF ? 0 : 0xff);
|
||||
break;
|
||||
|
||||
case TEST:
|
||||
opcode = OP_DISPLAYTEST;
|
||||
param = (value == OFF ? 0 : 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// put our device data into the buffer
|
||||
_spiData[SPI_OFFSET(dev, 0)] = opcode;
|
||||
_spiData[SPI_OFFSET(dev, 1)] = param;
|
||||
}
|
||||
|
||||
void MD_MAX72XX::controlLibrary(controlRequest_t mode, int value)
|
||||
// control command was internal, set required parameters
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case UPDATE:
|
||||
_updateEnabled = (value == ON);
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
break;
|
||||
|
||||
case WRAPAROUND:
|
||||
_wrapAround = (value == ON);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::control(uint8_t startDev, uint8_t endDev, controlRequest_t mode, int value)
|
||||
{
|
||||
if (endDev < startDev) return(false);
|
||||
|
||||
if (mode < UPDATE) // device based control
|
||||
{
|
||||
spiClearBuffer();
|
||||
for (uint8_t i = startDev; i <= endDev; i++)
|
||||
controlHardware(i, mode, value);
|
||||
spiSend();
|
||||
}
|
||||
else // internal control function, doesn't relate to specific device
|
||||
{
|
||||
controlLibrary(mode, value);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::control(uint8_t buf, controlRequest_t mode, int value)
|
||||
// dev is zero based and needs adjustment if used
|
||||
{
|
||||
if (buf > LAST_BUFFER) return(false);
|
||||
|
||||
if (mode < UPDATE) // device based control
|
||||
{
|
||||
spiClearBuffer();
|
||||
controlHardware(buf, mode, value);
|
||||
spiSend();
|
||||
}
|
||||
else // internal control function, doesn't relate to specific device
|
||||
{
|
||||
controlLibrary(mode, value);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void MD_MAX72XX::flushBufferAll()
|
||||
// Only one data byte is sent to a device, so if there are many changes, it is more
|
||||
// efficient to send a data byte all devices at the same time, substantially cutting
|
||||
// the number of communication messages required.
|
||||
{
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++) // all data rows
|
||||
{
|
||||
bool bChange = false; // set to true if we detected a change
|
||||
|
||||
spiClearBuffer();
|
||||
|
||||
for (uint8_t dev = FIRST_BUFFER; dev <= LAST_BUFFER; dev++) // all devices
|
||||
{
|
||||
if (bitRead(_matrix[dev].changed, i))
|
||||
{
|
||||
// put our device data into the buffer
|
||||
_spiData[SPI_OFFSET(dev, 0)] = OP_DIGIT0+i;
|
||||
_spiData[SPI_OFFSET(dev, 1)] = _matrix[dev].dig[i];
|
||||
bChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bChange) spiSend();
|
||||
}
|
||||
|
||||
// mark everything as cleared
|
||||
for (uint8_t dev = FIRST_BUFFER; dev <= LAST_BUFFER; dev++)
|
||||
_matrix[dev].changed = ALL_CLEAR;
|
||||
}
|
||||
|
||||
void MD_MAX72XX::flushBuffer(uint8_t buf)
|
||||
// Use this function when the changes are limited to one device only.
|
||||
// Address passed is a buffer address
|
||||
{
|
||||
PRINT("\nflushBuf: ", buf);
|
||||
PRINTS(" r");
|
||||
|
||||
if (buf > LAST_BUFFER)
|
||||
return;
|
||||
|
||||
for (uint8_t i = 0; i < ROW_SIZE; i++)
|
||||
{
|
||||
if (bitRead(_matrix[buf].changed, i))
|
||||
{
|
||||
PRINT("", i);
|
||||
spiClearBuffer();
|
||||
|
||||
// put our device data into the buffer
|
||||
_spiData[SPI_OFFSET(buf, 0)] = OP_DIGIT0+i;
|
||||
_spiData[SPI_OFFSET(buf, 1)] = _matrix[buf].dig[i];
|
||||
|
||||
spiSend();
|
||||
}
|
||||
}
|
||||
_matrix[buf].changed = ALL_CLEAR;
|
||||
}
|
||||
|
||||
void MD_MAX72XX::spiClearBuffer(void)
|
||||
// Clear out the spi data array
|
||||
{
|
||||
memset(_spiData, OP_NOOP, SPI_DATA_SIZE);
|
||||
}
|
||||
|
||||
void MD_MAX72XX::spiSend()
|
||||
{
|
||||
// initialise the SPI transaction
|
||||
if (_hardwareSPI)
|
||||
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(_csPin, LOW);
|
||||
|
||||
// shift out the data
|
||||
if (_hardwareSPI)
|
||||
{
|
||||
for (int i = 0; i < SPI_DATA_SIZE; i++)
|
||||
SPI.transfer(_spiData[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < SPI_DATA_SIZE; i++)
|
||||
shiftOut(_dataPin, _clkPin, MSBFIRST, _spiData[i]);
|
||||
}
|
||||
|
||||
// end the SPI transaction
|
||||
digitalWrite(_csPin, HIGH);
|
||||
if (_hardwareSPI)
|
||||
SPI.endTransaction();
|
||||
}
|
||||
955
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx.h
Normal file
955
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx.h
Normal file
@@ -0,0 +1,955 @@
|
||||
/**
|
||||
\mainpage Arduino LED Matrix Library
|
||||
The Maxim 72xx LED Controller IC
|
||||
--------------------------------
|
||||
The MAX7219/MAX7221 are compact, serial input/output display drivers that
|
||||
interface microprocessors to 7-segment numeric LED displays of up to 8 digits,
|
||||
bar-graph displays, or 64 individual LEDs. Included on-chip are a BCD code-B
|
||||
decoder, multiplex scan circuitry, segment and digit drivers, and an 8x8 static
|
||||
RAM that stores each digit.
|
||||
|
||||
A 4-wire serial interface (SPI) allows the devices to be cascaded, with
|
||||
communications passed through the first device in the chain to all others. Individual
|
||||
elements may be addressed and updated without rewriting the entire display.
|
||||
|
||||
This library implements functions that allow the MAX72xx to be used
|
||||
for LED matrices (64 individual LEDs), allowing the programmer to use the LED
|
||||
matrix as a pixel device, displaying graphics elements much like any other
|
||||
pixel addressable display.
|
||||
|
||||
Topics
|
||||
------
|
||||
- \subpage pageHardware
|
||||
- \subpage pageSoftware
|
||||
- \subpage pageConnect
|
||||
- \subpage pageFontUtility
|
||||
- \subpage pageRevisionHistory
|
||||
|
||||
Copyright
|
||||
---------
|
||||
Copyright (C) 2012-16 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
\page pageRevisionHistory Revision History
|
||||
Revision History
|
||||
----------------
|
||||
Nov 2017 version 2.9.1
|
||||
- Changed SPI buffer handling and isolation of AVR specific features (eg PROGMEM)
|
||||
- Added MD_MAX72xx_Message_ESP8266 example
|
||||
- Minor source file cleanup
|
||||
- Added Extended ASCII font, vertical rotated font and RobotEyes font in fontbuilder
|
||||
- Modifed fontbuilder output code for consistency with new code
|
||||
- Added getFont(), getMaxFontWidth() methods
|
||||
- Changed example - replaced MD_KeySwitch with new MD_UISwitch library
|
||||
|
||||
Nov 2016 version 2.9.0
|
||||
- Added WordClock example
|
||||
- Deprecated USE_LIBRARY_SPI as no problems reported with new implementation
|
||||
- Changed MD_ branding to new MajicDesigns diamond
|
||||
- Small adjustments to initialisation code
|
||||
|
||||
Mar 2016 version 2.8
|
||||
- Added example _Message_SD and renamed _Message to _Message_Serial
|
||||
- Added Pacman example
|
||||
- Added PushWheel example
|
||||
- Added USE_LIBRARY_SPI to enable library SPI object
|
||||
- Modifed all examples to conditionally include <SPI.h>
|
||||
- FontBuilder modified to handle definitions for double height fonts
|
||||
- New txt2font utility for easier font creattion from a text file
|
||||
- Revised and ro-organised documentation; expanded section on fonts
|
||||
|
||||
April 2015 version 2.7
|
||||
- Changed to Daft Punk example to run without switch
|
||||
- Now supporting IDE Library Manager
|
||||
|
||||
February 2015 version 2.6
|
||||
- Improvements to HW_Mapper utility
|
||||
- Added HW_USE_FC16 for FC-16 display modules
|
||||
- Added USE_HW_OTHER for user defined hardware configuration
|
||||
- Fixed incorrect spelling for HW_REV_COLS in transformbuffer() & corresponding bug
|
||||
- Added PrintText_ML example
|
||||
|
||||
February 2015 version 2.5
|
||||
- Documented process for adding new hardware module type
|
||||
- Fixed PROGMEM definitions for IDE version 1.5.7 compile error
|
||||
- Added Daft Punk example code
|
||||
- Updated HW_Mapper example/utility with built-in instructions
|
||||
- Minor problems with Parola font setting interaction fixed
|
||||
|
||||
April 2014 version 2.4
|
||||
- Improved reliability of initialization code to remove artifacts
|
||||
+ Changed order of hardware initialization for SS, _csPin
|
||||
+ Changed initialisation sequence at begin()
|
||||
+ Fixed memset bug identified by bperrybap
|
||||
- Reworked command SPI transmissions for efficiency
|
||||
- Cleanup up compiler warnings on inline wrapper code functions
|
||||
- Cleaned up examples begin() - better defined library default values
|
||||
- Reviewed and tidied up some documentation
|
||||
|
||||
March 2014 - version 2.3
|
||||
- Extensive rework of the font system
|
||||
+ New font Microsoft Excel VBA based builder tool available
|
||||
+ Removed USE_FONT_ADJUST and related code - replace by builder tool
|
||||
+ Fixed width font has been removed from the library. Definition still available in font builder
|
||||
+ fontype_t definition changed to suit new requirements
|
||||
- Transform zoning implemented (contiguous subset of services)
|
||||
+ Transformation functions, control, clear, setRow methods overloaded with range specifier
|
||||
+ User callback for L/R rotation function syntax added a device parameter
|
||||
+ New Zones example
|
||||
- USE_*_HW hardware types now separated out for future flexibility
|
||||
+ Rework of the library to use new schema for defining hardware characteristics
|
||||
+ New utility code to map out digits and segments for unknown hardware types
|
||||
- Rechecked and reworked examples for new library
|
||||
|
||||
November 2013 - version 2.2
|
||||
- Replaced reference to SPI library with inline code to allow for different select lines
|
||||
- Obsoleted INCLUDE_HARDWARE_SPI conditional compile switch
|
||||
- Fixed legacy code function name error when USE_FONT_ADJUST switch turned on
|
||||
- Implemented USE_PAROLA_HW to allow cheaply available matrix modules to be used in ganged mode
|
||||
- Fixed reversal of bit field for set/get Row/Column functions -> flipped charset data
|
||||
- Added Eyes example program
|
||||
- Upgraded and reorganized documentation
|
||||
|
||||
June 2013 - version 2.1
|
||||
- Include the selection of hardware SPI interface (10x speed improvement)
|
||||
- Tidied up comments
|
||||
|
||||
April 2013 - version 2.0
|
||||
- Major update and rewrite of library code:
|
||||
- Improved speed and efficiency of code
|
||||
- Increased level of abstraction in the library for pixel methods
|
||||
- Increased level of abstraction for character and font methods
|
||||
- Increased number of functions and added variable sized font
|
||||
- Changed defines to enumerated types within the scope of the class
|
||||
- Updated functionality to simplify controlling multiple devices
|
||||
- Changed text and comments to be aligned to doxygen documentation generation
|
||||
|
||||
June 2012 - version 1.0
|
||||
- Incorporated elements of Arduino LedControl (Eberhard Fahle) and MAX7219 libraries
|
||||
- Easier functionality for pixel graphics treatment of 8x8 matrices
|
||||
|
||||
\page pageSoftware Software Library
|
||||
The Library
|
||||
-----------
|
||||
The library implements functions that allow the MAX72xx to be used
|
||||
for LED matrices (64 individual LEDs), allowing the programmer to use the LED
|
||||
matrix as a pixel device, displaying graphics elements much like any other
|
||||
pixel addressable display.
|
||||
|
||||
In this scenario, it is convenient to abstract out the concept of the hardware device
|
||||
and create a uniform and consistent pixel address space, with the libraries determining
|
||||
device and device-element address. Similarly, control of the devices should be uniform
|
||||
and abstracted to a system level.
|
||||
|
||||
The library still retains flexibility for device level control, should the developer
|
||||
require, through the use of overloaded class methods.
|
||||
___
|
||||
|
||||
Conditional Compilation Switches
|
||||
--------------------------------
|
||||
The library allows the run time code to be tailored through the use of compilation
|
||||
switches. The compile options start with USE_ and are documented in the section
|
||||
related to the main header file MD_MAX72xx.h.
|
||||
|
||||
_NOTE_: Compile switches must be edited in the library header file. Arduino header file
|
||||
'mashing' during compilation makes the setting of these switches from user code
|
||||
completely unreliable.
|
||||
|
||||
\page pageConnect System Connections
|
||||
Connections to the Arduino Board (SPI interface)
|
||||
------------------------------------------------
|
||||
The modules are connected through a 4-wire serial interface (SPI), and devices are cascaded,
|
||||
with communications passed through the first device in the chain to all others. The Arduino
|
||||
should be connected to the IN side of the first module in the chain.
|
||||
|
||||
The Arduino interface is implemented with either
|
||||
+ The hardware SPI interface, or
|
||||
+ 3 arbitrary digital outputs that are passed through to the class constructor.
|
||||
|
||||
The AVR hardware SPI interface is fast but fixed to predetermined output pins. The more general
|
||||
software interface uses the Arduino shiftOut() library function, making it slower but allows the
|
||||
use of arbitrary digital pins to send the data to the device. Which mode is enabled depends
|
||||
on the class constructor used.
|
||||
|
||||
The Arduino interface is implemented with 3 digital outputs that are passed through to
|
||||
the class constructor. The digital outputs define the SPI interface as follows:
|
||||
- DIN (MOSI) - the Data IN signal shifts data into the display module. Data is loaded into
|
||||
the device's internal 16-bit shift register on CLK's rising edge.
|
||||
- CLK (SCK) - the CLocK signal that is used to time the data for the device.
|
||||
- LD (SS) - the interface is active when LoaD signal is LOW. Serial data are loaded into the
|
||||
device shift register while LOAD is LOW and latched in on the rising edge.
|
||||
|
||||
The LD signal is used to select the entire device chain. This allows separate LD
|
||||
outputs to control multiple displays sharing the same DIN and CLK signals. The
|
||||
software needs to instantiate a separate object for each display.
|
||||
|
||||
The remaining interface pins are for +5V and GND. The power supply must be able to supply
|
||||
enough current for the number of connected modules.
|
||||
*/
|
||||
#ifndef MD_MAX72xx_h
|
||||
#define MD_MAX72xx_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Main header file for the MD_MAX72xx library
|
||||
*/
|
||||
|
||||
/**
|
||||
\def USE_PAROLA_HW
|
||||
Set to 1 (default) to use the Parola hardware modules. The
|
||||
software was originally designed to operate with this hardware type.
|
||||
*/
|
||||
#define USE_PAROLA_HW 0
|
||||
|
||||
/**
|
||||
\def USE_GENERIC_HW
|
||||
Set to 1 to use 'generic' hardware modules commonly available, with
|
||||
connectors at the top and bottom of the PCB, available from many sources.
|
||||
*/
|
||||
#define USE_GENERIC_HW 0
|
||||
|
||||
/**
|
||||
\def USE_ICSTATION_HW
|
||||
Set to 1 to use ICStation DIY hardware module kits available from
|
||||
http://www.icstation.com/product_info.php?products_id=2609#.UxqVJyxWGHs
|
||||
This hardware must be set up with the input on the RHS.
|
||||
*/
|
||||
#define USE_ICSTATION_HW 0
|
||||
|
||||
/**
|
||||
\def USE_FC16_HW
|
||||
Set to 1 to use FC16 hardware module kits.
|
||||
FC16 modules are similar in format to the ICStation modules but are wired differently.
|
||||
Modules are identified by a FC-16 designation on the PCB
|
||||
*/
|
||||
#define USE_FC16_HW 1
|
||||
|
||||
/**
|
||||
\def USE_OTHER_HW
|
||||
Set to 1 to use other hardware not defined above.
|
||||
Module 0 (Data In) must be set up on the RHS and the CUSTOM hardware defines
|
||||
must be set up in the MD_MAD72xx_lib.h file under for this section, using the HW_Mapper
|
||||
utility to work out what the correct values to use are.
|
||||
*/
|
||||
#define USE_OTHER_HW 0
|
||||
|
||||
/**
|
||||
\def USE_LOCAL_FONT
|
||||
Set to 1 (default) to enable local font in this library and enable
|
||||
loadChar() and related methods. If the library is just used for
|
||||
graphics some FLASH RAM can be saved by not including the code to process
|
||||
font data. The font file is stored in PROGMEM.
|
||||
*/
|
||||
#define USE_LOCAL_FONT 1
|
||||
|
||||
/**
|
||||
\def USE_INDEX_FONT
|
||||
Set to 1 to enable font indexing to speed up font lookups - usually disabled.
|
||||
This will trade off increased stack RAM usage for lookup speed if enabled.
|
||||
When disabled lookups will then become linear searches through PROGMEM.
|
||||
Uses ASCII_INDEX_SIZE elements of uint16_t (512 bytes) if enabled. For most
|
||||
purposes the increase in speed is not needed.
|
||||
|
||||
USE_LOCAL FONT must be enabled for this option to take effect.
|
||||
*/
|
||||
#define USE_INDEX_FONT 0
|
||||
|
||||
// Display parameter constants
|
||||
// Defined values that are used throughout the library to define physical limits
|
||||
#define ROW_SIZE 8 ///< The size in pixels of a row in the device LED matrix array
|
||||
#define COL_SIZE 8 ///< The size in pixels of a column in the device LED matrix array
|
||||
#define MAX_INTENSITY 0xf ///< The maximum intensity value that can be set for a LED array
|
||||
#define MAX_SCANLIMIT 7 ///< The maximum scan limit value that can be set for the devices
|
||||
|
||||
/**
|
||||
* Core object for the MD_MAX72XX library
|
||||
*/
|
||||
class MD_MAX72XX
|
||||
{
|
||||
public:
|
||||
#if USE_LOCAL_FONT
|
||||
/**
|
||||
* Font definition type.
|
||||
*
|
||||
* This type is used in the setFont() method to set the font to be used
|
||||
*/
|
||||
typedef const uint8_t fontType_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Control Request enumerated type.
|
||||
*
|
||||
* This enumerated type is used with the control() method to identify
|
||||
* the control action request.
|
||||
*/
|
||||
enum controlRequest_t
|
||||
{
|
||||
SHUTDOWN = 0, ///< Shut down the MAX72XX. Requires ON/OFF value. Library default is OFF.
|
||||
SCANLIMIT = 1, ///< Set the scan limit for the MAX72XX. Requires numeric value [0..MAX_SCANLIMIT]. Library default is all on.
|
||||
INTENSITY = 2, ///< Set the LED intensity for the MAX72XX. Requires numeric value [0..MAX_INTENSITY]. LIbrary default is MAX_INTENSITY/2.
|
||||
TEST = 3, ///< Set the MAX72XX in test mode. Requires ON/OFF value. Library default is OFF.
|
||||
DECODE = 4, ///< Set the MAX72XX 7 segment decode mode. Requires ON/OFF value. Library default is OFF.
|
||||
UPDATE = 10, ///< Enable or disable auto updates of the devices from the library. Requires ON/OFF value. Library default is ON.
|
||||
WRAPAROUND = 11 ///< Enable or disable wraparound when shifting (circular buffer). Requires ON/OFF value. Library default is OFF.
|
||||
};
|
||||
|
||||
/**
|
||||
* Control Value enumerated type.
|
||||
*
|
||||
* This enumerated type is used with the control() method as the
|
||||
* ON/OFF value for a control request. Other values may be used
|
||||
* if numeric data is required.
|
||||
*/
|
||||
enum controlValue_t
|
||||
{
|
||||
OFF = 0, ///< General OFF status request
|
||||
ON = 1 ///< General ON status request
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformation Types enumerated type.
|
||||
*
|
||||
* This enumerated type is used in the transform() methods to identify a
|
||||
* specific transformation of the display data in the device buffers.
|
||||
*/
|
||||
enum transformType_t
|
||||
{
|
||||
TSL, ///< Transform Shift Left one pixel element
|
||||
TSR, ///< Transform Shift Right one pixel element
|
||||
TSU, ///< Transform Shift Up one pixel element
|
||||
TSD, ///< Transform Shift Down one pixel element
|
||||
TFLR, ///< Transform Flip Left to Right
|
||||
TFUD, ///< Transform Flip Up to Down
|
||||
TRC, ///< Transform Rotate Clockwise 90 degrees
|
||||
TINV ///< Transform INVert (pixels inverted)
|
||||
};
|
||||
|
||||
/**
|
||||
* Class Constructor - arbitrary digital interface.
|
||||
*
|
||||
* Instantiate a new instance of the class. The parameters passed are used to
|
||||
* connect the software to the hardware. Multiple instances may co-exist
|
||||
* but they should not share the same hardware CS pin (SPI interface).
|
||||
*
|
||||
* \param dataPin output on the Arduino where data gets shifted out.
|
||||
* \param clkPin output for the clock signal.
|
||||
* \param csPin output for selecting the device.
|
||||
* \param numDevices number of devices connected. Default is 1 if not supplied.
|
||||
* Memory for device buffers is dynamically allocated based
|
||||
* on this parameter.
|
||||
*/
|
||||
MD_MAX72XX(uint8_t dataPin, uint8_t clkPin, uint8_t csPin, uint8_t numDevices=1);
|
||||
|
||||
/**
|
||||
* Class Constructor - SPI hardware interface.
|
||||
*
|
||||
* Instantiate a new instance of the class. The parameters passed are used to
|
||||
* connect the software to the hardware. Multiple instances may co-exist
|
||||
* but they should not share the same hardware CS pin (SPI interface).
|
||||
* The dataPin and the clockPin are defined by the Arduino hardware definition
|
||||
* (SPI MOSI and SCK signals).
|
||||
*
|
||||
* \param csPin output for selecting the device.
|
||||
* \param numDevices number of devices connected. Default is 1 if not supplied.
|
||||
* Memory for device buffers is dynamically allocated based
|
||||
* on this parameter.
|
||||
*/
|
||||
MD_MAX72XX(uint8_t csPin, uint8_t numDevices=1);
|
||||
|
||||
/**
|
||||
* Initialize the object.
|
||||
*
|
||||
* Initialise the object data. This needs to be called during setup() to initialise new
|
||||
* data for the class that cannot be done during the object creation.
|
||||
*
|
||||
* The LED hardware is initialized to the middle intensity value, all rows showing,
|
||||
* and all LEDs cleared (off). Test, shutdown and decode modes are off. Display updates
|
||||
* are on and wraparound is off.
|
||||
*/
|
||||
void begin(void);
|
||||
|
||||
/**
|
||||
* Class Destructor.
|
||||
*
|
||||
* Released allocated memory and does the necessary to clean up once the object is
|
||||
* no longer required.
|
||||
*/
|
||||
~MD_MAX72XX();
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/** \name Methods for object and hardware control.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Set the control status of the specified parameter for the specified device.
|
||||
*
|
||||
* The device has a number of control parameters that can be set through this method.
|
||||
* The type of control action required is passed through the mode parameter and
|
||||
* should be one of the control actions defined by controlRequest_t. The value that
|
||||
* needs to be supplied on the control action required is one of the defined
|
||||
* actions in controlValue_t or a numeric parameter suitable for the control action.
|
||||
*
|
||||
* \param dev address of the device to control [0..getDeviceCount()-1].
|
||||
* \param mode one of the defined control requests.
|
||||
* \param value parameter value or one of the control status defined.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool control(uint8_t dev, controlRequest_t mode, int value);
|
||||
|
||||
/**
|
||||
* Set the control status of the specified parameter for all devices.
|
||||
*
|
||||
* Invokes the control function for each device in turn. as this is a wrapper for the
|
||||
* control(startDev, endDev, ...) methods, see the documentation for that method.
|
||||
*
|
||||
* \param mode one of the defined control requests.
|
||||
* \param value parameter value or one of the control status defined.
|
||||
* \return No return value.
|
||||
*/
|
||||
inline void control(controlRequest_t mode, int value) { control(0, getDeviceCount()-1, mode, value); };
|
||||
|
||||
/**
|
||||
* Set the control status of the specified parameter for contiguous subset of devices.
|
||||
*
|
||||
* Invokes the control function for each device in turn for the devices in the subset.
|
||||
* See documentation for the control() method.
|
||||
*
|
||||
* \param startDev the first device for the transformation [0..getDeviceCount()-1]
|
||||
* \param endDev the last device for the transformation [0..getDeviceCount()-1]
|
||||
* \param mode one of the defined control requests.
|
||||
* \param value parameter value or one of the control status defined.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool control(uint8_t startDev, uint8_t endDev, controlRequest_t mode, int value);
|
||||
|
||||
/**
|
||||
* Gets the number of devices attached to this class instance.
|
||||
*
|
||||
* \return uint8_t representing the number of devices attached to this object.
|
||||
*/
|
||||
uint8_t getDeviceCount(void) { return(_maxDevices); };
|
||||
|
||||
/**
|
||||
* Gets the maximum number of columns for devices attached to this class instance.
|
||||
*
|
||||
* \return uint16_t representing the number of columns.
|
||||
*/
|
||||
uint16_t getColumnCount(void) { return(_maxDevices*COL_SIZE); };
|
||||
|
||||
/**
|
||||
* Set the Shift Data In callback function.
|
||||
*
|
||||
* The callback function is called from the library when a transform shift left
|
||||
* or shift right operation is executed and the library needs to obtain data for
|
||||
* the end element of the shift (ie, conceptually this is the new data that is
|
||||
* shifted 'into' the display). The callback function is invoked when
|
||||
* - WRAPAROUND is not active, as the data would automatically supplied within the library.
|
||||
* - the call to transform() is global (ie, not for an individual buffer).
|
||||
*
|
||||
* The callback function takes 2 parameters:
|
||||
* - the device number requesting the data [0..getDeviceCount()-1]
|
||||
* - one of the transformation types in transformType_t) that tells the callback function
|
||||
* what shift is being performed
|
||||
* The return value is the data for the column to be shifted into the display.
|
||||
*
|
||||
* \param cb the address of the function to be called from the library.
|
||||
* \return No return data
|
||||
*/
|
||||
void setShiftDataInCallback(uint8_t (*cb)(uint8_t dev, transformType_t t)) { _cbShiftDataIn = cb; };
|
||||
|
||||
/**
|
||||
* Set the Shift Data Out callback function.
|
||||
*
|
||||
* The callback function is called from the library when a transform shift left
|
||||
* or shift right operation is executed and the library is about to discard the data for
|
||||
* the first element of the shift (ie, conceptually this is the data that 'falls' off
|
||||
* the front end of the scrolling display). The callback function is invoked when
|
||||
* - WRAPAROUND is not active, as the data would automatically supplied to the tail end.
|
||||
* - the call to transform() is global (ie, not for an individual buffer).
|
||||
*
|
||||
* The callback function is with supplied 3 parameters, with no return value required:
|
||||
* - the device number that is the source of the data [0..getDeviceCount()-1]
|
||||
* - one of the transformation types transformType_t that tells the callback
|
||||
* function the type of shifting being executed
|
||||
* - the data for the column being shifted out
|
||||
*
|
||||
* \param cb the address of the function to be called from the library.
|
||||
* \return No return data
|
||||
*/
|
||||
void setShiftDataOutCallback(void (*cb)(uint8_t dev, transformType_t t, uint8_t colData)) { _cbShiftDataOut = cb; };
|
||||
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/** \name Methods for graphics and bitmap related abstraction.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Clear all the display data on all the display devices.
|
||||
*
|
||||
* \return No return value.
|
||||
*/
|
||||
inline void clear(void) { clear(0, getDeviceCount()-1); };
|
||||
|
||||
/**
|
||||
* Clear all the display data on a subset of devices.
|
||||
*
|
||||
* endDev must be greater than or equal to startDev.
|
||||
*
|
||||
* \param startDev the first device to clear [0..getDeviceCount()-1]
|
||||
* \param endDev the last device to clear [0..getDeviceCount()-1]
|
||||
* \return No return value.
|
||||
*/
|
||||
void clear(uint8_t startDev, uint8_t endDev);
|
||||
|
||||
/**
|
||||
* Draw a line between two points on the display
|
||||
*
|
||||
* Draw a line between the specified points. The LED will be turned on or
|
||||
* off depending on the value supplied. The column number will be dereferenced
|
||||
* into the device and column within the device, allowing the LEDs to be treated
|
||||
* as a continuous pixel field.
|
||||
*
|
||||
* \param r1 starting row coordinate for the point [0..ROW_SIZE-1].
|
||||
* \param c1 starting column coordinate for the point [0..getColumnCount()-1].
|
||||
* \param r2 ending row coordinate for the point [0..ROW_SIZE-1].
|
||||
* \param c2 ending column coordinate for the point [0..getColumnCount())-1].
|
||||
* \param state true - switch on; false - switch off.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool drawLine(uint8_t r1, uint16_t c1, uint8_t r2, uint16_t c2, bool state);
|
||||
|
||||
/**
|
||||
* Load a bitmap from the display buffers to a user buffer.
|
||||
*
|
||||
* Allows the calling program to read bitmaps (characters or graphic)
|
||||
* elements from the library display buffers. The data buffer
|
||||
* pointer should be a block of uint8_t data of size elements that will
|
||||
* contain the returned data.
|
||||
*
|
||||
* \param col address of the display column [0..getColumnCount()-1].
|
||||
* \param size number of columns of data to return.
|
||||
* \param *pd Pointer to a data buffer [0..size-1].
|
||||
* \return false if parameter errors, true otherwise. If true, data will be in the buffer at *pd.
|
||||
*/
|
||||
bool getBuffer(uint16_t col, uint8_t size, uint8_t *pd);
|
||||
|
||||
/**
|
||||
* Get the LEDS status for the specified column.
|
||||
*
|
||||
* This method operates on a specific buffer
|
||||
*
|
||||
* This method operates on one column, getting the bit field value of
|
||||
* the LEDs in the column. The column is referenced with the absolute column
|
||||
* number (ie, the device number is inferred from the column).
|
||||
*
|
||||
* \param c column which is to be set [0..getColumnCount()-1].
|
||||
* \return uint8_t value with each bit set to 1 if the corresponding LED is lit. 0 is returned for parameter error.
|
||||
*/
|
||||
uint8_t getColumn(uint8_t c) { return getColumn((c / COL_SIZE), c % COL_SIZE); };
|
||||
|
||||
/**
|
||||
* Get the status of a single LED, addressed as a pixel.
|
||||
*
|
||||
* The method will get the status of a specific LED element based on its
|
||||
* coordinate position. The column number is dereferenced into the device
|
||||
* and column within the device, allowing the LEDs to be treated as a
|
||||
* continuous pixel field.
|
||||
*
|
||||
* \param r row coordinate for the point [0..ROW_SIZE-1].
|
||||
* \param c column coordinate for the point [0..getColumnCount()-1].
|
||||
* \return true if LED is on, false if off or parameter errors.
|
||||
*/
|
||||
bool getPoint(uint8_t r, uint16_t c);
|
||||
|
||||
/**
|
||||
* Load a bitfield from the user buffer to a display buffer.
|
||||
*
|
||||
* Allows the calling program to define bitmaps (characters or graphic)
|
||||
* elements and pass them to the library for display. The data buffer
|
||||
* pointer should be a block of uint8_t data of size elements that define
|
||||
* the bitmap.
|
||||
*
|
||||
* \param col address of the display column [0..getColumnCount()-1].
|
||||
* \param size number of columns of data following.
|
||||
* \param *pd Pointer to a data buffer [0..size-1].
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setBuffer(uint16_t col, uint8_t size, uint8_t *pd);
|
||||
|
||||
/**
|
||||
* Set all LEDs in a specific column to a new state.
|
||||
*
|
||||
* This method operates on one column, setting the value of the LEDs in
|
||||
* the column to the specified value bitfield. The column is
|
||||
* referenced with the absolute column number (ie, the device number is
|
||||
* inferred from the column). The method is useful for drawing vertical
|
||||
* lines and patterns when the display is being treated as a pixel field.
|
||||
* The least significant bit of the value is the lowest row number.
|
||||
*
|
||||
* \param c column which is to be set [0..getColumnCount()-1].
|
||||
* \param value each bit set to 1 will light up the corresponding LED.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setColumn(uint8_t c, uint8_t value) { return setColumn((c / COL_SIZE), c % COL_SIZE, value); };
|
||||
|
||||
/**
|
||||
* Set the status of a single LED, addressed as a pixel.
|
||||
*
|
||||
* The method will set the value of a specific LED element based on its
|
||||
* coordinate position. The LED will be turned on or off depending on the
|
||||
* value supplied. The column number is dereferenced into the device and
|
||||
* column within the device, allowing the LEDs to be treated as a
|
||||
* continuous pixel field.
|
||||
*
|
||||
* \param r row coordinate for the point [0..ROW_SIZE-1].
|
||||
* \param c column coordinate for the point [0..getColumnCount()-1].
|
||||
* \param state true - switch on; false - switch off.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setPoint(uint8_t r, uint16_t c, bool state);
|
||||
|
||||
/**
|
||||
* Set all LEDs in a row to a new state on all devices.
|
||||
*
|
||||
* This method operates on all devices, setting the value of the LEDs in
|
||||
* the row to the specified value bit field. The method is useful for
|
||||
* drawing patterns and lines horizontally across on the entire display.
|
||||
* The least significant bit of the value is the lowest column number.
|
||||
*
|
||||
* \param r row which is to be set [0..ROW_SIZE-1].
|
||||
* \param value each bit set to 1 will light up the corresponding LED on each device.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
inline bool setRow(uint8_t r, uint8_t value) { return setRow(0, getDeviceCount()-1, r, value); };
|
||||
|
||||
/**
|
||||
* Set all LEDs in a row to a new state on contiguous subset of devices.
|
||||
*
|
||||
* This method operates on a contiguous subset of devices, setting the value
|
||||
* of the LEDs in the row to the specified value bit field. The method is useful for
|
||||
* drawing patterns and lines horizontally across specific devices only.
|
||||
* endDev must be greater than or equal to startDev.
|
||||
* The least significant bit of the value is the lowest column number.
|
||||
*
|
||||
* \param startDev the first device for the transformation [0..getDeviceCount()-1]
|
||||
* \param endDev the last device for the transformation [0..getDeviceCount()-1]
|
||||
* \param r row which is to be set [0..ROW_SIZE-1].
|
||||
* \param value each bit set to 1 will light up the corresponding LED on each device.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setRow(uint8_t startDev, uint8_t endDev, uint8_t r, uint8_t value);
|
||||
|
||||
/**
|
||||
* Apply a transformation to the data in all the devices.
|
||||
*
|
||||
* The buffers for all devices can be transformed using one of the enumerated
|
||||
* transformations in transformType_t. The transformation is carried across
|
||||
* device boundaries (ie, there is overflow to an adjacent devices if appropriate).
|
||||
*
|
||||
* \param ttype one of the transformation types in transformType_t.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
inline bool transform(transformType_t ttype) { return transform(0, getDeviceCount()-1, ttype); };
|
||||
|
||||
/**
|
||||
* Apply a transformation to the data in contiguous subset of devices.
|
||||
*
|
||||
* The buffers for all devices in the subset can be transformed using one of the enumerated
|
||||
* transformations in transformType_t. The transformation is carried across
|
||||
* device boundaries (ie, there is overflow to an adjacent devices if appropriate).
|
||||
* endDev must be greater than or equal to startDev.
|
||||
*
|
||||
* \param startDev the first device for the transformation [0..getDeviceCount()-1]
|
||||
* \param endDev the last device for the transformation [0..getDeviceCount()-1]
|
||||
* \param ttype one of the transformation types in transformType_t.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool transform(uint8_t startDev, uint8_t endDev, transformType_t ttype);
|
||||
|
||||
/**
|
||||
* Turn auto display updates on or off.
|
||||
*
|
||||
* Turn auto updates on and off, as required. When auto updates are turned OFF the
|
||||
* display will not update after each operation. Display updates can be forced at any
|
||||
* time using using a call to update() with no parameters.
|
||||
*
|
||||
* This function is a convenience wrapper for the more general control() function call.
|
||||
*
|
||||
* \param mode one of the types in controlValue_t (ON/OFF).
|
||||
* \return No return value.
|
||||
*/
|
||||
void update(controlValue_t mode) { control(UPDATE, mode); };
|
||||
|
||||
/**
|
||||
* Force an update of all devices
|
||||
*
|
||||
* Used when auto updates have been turned off through the control
|
||||
* method. This will force all buffered changes to be written to
|
||||
* all the connected devices.
|
||||
*
|
||||
* \return no return value.
|
||||
*/
|
||||
void update(void) { flushBufferAll(); };
|
||||
|
||||
/**
|
||||
* Turn display wraparound on or off.
|
||||
*
|
||||
* When shifting left or right, up or down, the outermost edge is normally lost and a blank
|
||||
* row or column inserted on the opposite side. If this options is enabled, the edge is wrapped
|
||||
* around to the opposite side.
|
||||
*
|
||||
* This function is a convenience wrapper for the more general control() function call.
|
||||
*
|
||||
* \param mode one of the types in controlValue_t (ON/OFF).
|
||||
* \return No return value.
|
||||
*/
|
||||
void wraparound(controlValue_t mode) { control(WRAPAROUND, mode); };
|
||||
/** @} */
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/** \name Methods for managing specific devices or display buffers.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Clear all display data in the specified buffer.
|
||||
*
|
||||
* \param buf address of the buffer to clear [0..getDeviceCount()-1].
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool clear(uint8_t buf);
|
||||
|
||||
/**
|
||||
* Get the state of the LEDs in a specific column.
|
||||
*
|
||||
* This method operates on the specific buffer, returning the bit field value of
|
||||
* the LEDs in the column.
|
||||
*
|
||||
* \param buf address of the display [0..getDeviceCount()-1].
|
||||
* \param c column which is to be set [0..COL_SIZE-1].
|
||||
* \return uint8_t value with each bit set to 1 if the corresponding LED is lit. 0 is returned for parameter error.
|
||||
*/
|
||||
uint8_t getColumn(uint8_t buf, uint8_t c);
|
||||
|
||||
/**
|
||||
* Get the state of the LEDs in a specified row.
|
||||
*
|
||||
* This method operates on the specific buffer, returning the bit field value of
|
||||
* the LEDs in the row.
|
||||
*
|
||||
* \param buf address of the display [0..getDeviceCount()-1].
|
||||
* \param r row which is to be set [0..ROW_SIZE-1].
|
||||
* \return uint8_t value with each bit set to 1 if the corresponding LED is lit. 0 is returned for parameter error.
|
||||
*/
|
||||
uint8_t getRow(uint8_t buf, uint8_t r);
|
||||
|
||||
/**
|
||||
* Set all LEDs in a column to a new state.
|
||||
*
|
||||
* This method operates on a specific buffer, setting the value of the LEDs in
|
||||
* the column to the specified value bit field. The method is useful for
|
||||
* drawing patterns and lines vertically on the display device.
|
||||
* The least significant bit of the value is the lowest column number.
|
||||
*
|
||||
* \param buf address of the display [0..getDeviceCount()-1].
|
||||
* \param c column which is to be set [0..COL_SIZE-1].
|
||||
* \param value each bit set to 1 will light up the corresponding LED.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setColumn(uint8_t buf, uint8_t c, uint8_t value);
|
||||
|
||||
/**
|
||||
* Set all LEDs in a row to a new state.
|
||||
*
|
||||
* This method operates on a specific device, setting the value of the LEDs in
|
||||
* the row to the specified value bit field. The method is useful for
|
||||
* drawing patterns and lines horizontally across the display device.
|
||||
* The least significant bit of the value is the lowest row number.
|
||||
*
|
||||
* \param buf address of the display [0..getDeviceCount()-1].
|
||||
* \param r row which is to be set [0..ROW_SIZE-1].
|
||||
* \param value each bit set to 1 within this byte will light up the corresponding LED.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setRow(uint8_t buf, uint8_t r, uint8_t value);
|
||||
|
||||
/**
|
||||
* Apply a transformation to the data in the specified device.
|
||||
*
|
||||
* The buffer for one device can be transformed using one of the enumerated
|
||||
* transformations in transformType_t. The transformation is limited to the
|
||||
* nominated device buffer only (ie, there is no overflow to an adjacent device).
|
||||
*
|
||||
* \param buf address of the display [0..getBufferCount()-1].
|
||||
* \param ttype one of the transformation types in transformType_t.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool transform(uint8_t buf, transformType_t ttype);
|
||||
|
||||
/**
|
||||
* Force an update of one buffer.
|
||||
*
|
||||
* Used when auto updates have been turned off through the control()
|
||||
* method. This will force all buffered display changes to be written to
|
||||
* the specified device at the same time.
|
||||
* Note that control() messages are not buffered but cause immediate action.
|
||||
*
|
||||
* \param buf address of the display [0..getBufferCount()-1].
|
||||
* \return No return value.
|
||||
*/
|
||||
void update(uint8_t buf) { flushBuffer(buf); };
|
||||
/** @} */
|
||||
|
||||
#if USE_LOCAL_FONT
|
||||
//--------------------------------------------------------------
|
||||
/** \name Methods for font and characters.
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* Load a character from the font data into a user buffer.
|
||||
*
|
||||
* Copy the bitmap for a library font character (current font set by setFont()) and
|
||||
* return it in the data area passed by the user. If the user buffer is not large
|
||||
* enough, only the first size elements are copied to the buffer.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \param c the character to retrieve.
|
||||
* \param size the size of the user buffer in unit8_t units.
|
||||
* \param buf address of the user buffer supplied.
|
||||
* \return width (in columns) of the character, 0 if parameter errors.
|
||||
*/
|
||||
uint8_t getChar(uint8_t c, uint8_t size, uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Load a character from the font data starting at a specific column.
|
||||
*
|
||||
* Load a character from the font table directly into the display at the column
|
||||
* specified. The currently selected font table is used as the source.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \param col column of the display in the range accepted [0..getColumnCount()-1].
|
||||
* \param c the character to display.
|
||||
* \return width (in columns) of the character, 0 if parameter errors.
|
||||
*/
|
||||
uint8_t setChar(uint16_t col, uint8_t c);
|
||||
|
||||
/**
|
||||
* Set the current font table.
|
||||
*
|
||||
* Font data is stored in PROGMEM, in the format described elsewhere in the
|
||||
* documentation. All characters retrieved or used after this call will use
|
||||
* the nominated font (default or user defined). To specify a user defined
|
||||
* character set, pass the PROGMEM address of the font table. Passing a nullptr
|
||||
* resets the font table to the library default table.
|
||||
*
|
||||
* This function also causes the font index table to be recreated if the
|
||||
* library defined value USE_INDEX_TABLE is set to 1.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \param f fontType_t pointer to the table of font data in PROGMEM or nullptr.
|
||||
* \return false if parameter errors, true otherwise.
|
||||
*/
|
||||
bool setFont(fontType_t *f);
|
||||
|
||||
/**
|
||||
* Get the maximum width character for the font.
|
||||
*
|
||||
* Returns the number of columns for the widest character in the currently
|
||||
* selected font table. Useful to allocated buffers of the right size before
|
||||
* loading characters from the font table.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \return number of columns (width) for the widest character.
|
||||
*/
|
||||
uint8_t getMaxFontWidth(void);
|
||||
|
||||
/**
|
||||
* Get the pointer to current font table.
|
||||
*
|
||||
* Returns the pointer to the current font table. Useful if user code needs
|
||||
* to replace the current font temporarily and then restore previous font.
|
||||
*
|
||||
* NOTE: This function is only available if the library defined value
|
||||
* USE_LOCAL_FONT is set to 1.
|
||||
*
|
||||
* \return pointer to the start of the font table in PROGMEM.
|
||||
*/
|
||||
fontType_t *getFont(void) { return(_fontData); };
|
||||
#endif // USE_LOCAL_FONT
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
typedef struct
|
||||
{
|
||||
uint8_t dig[ROW_SIZE]; // data for each digit of the MAX72xx (DIG0-DIG7)
|
||||
uint8_t changed; // one bit for each digit changed ('dirty bit')
|
||||
} deviceInfo_t;
|
||||
|
||||
// SPI interface data
|
||||
uint8_t _dataPin; // DATA is shifted out of this pin ...
|
||||
uint8_t _clkPin; // ... signaled by a CLOCK on this pin ...
|
||||
uint8_t _csPin; // ... and LOADed when the chip select pin is driven HIGH to LOW
|
||||
bool _hardwareSPI; // true if SPI interface is the hardware interface
|
||||
|
||||
// Device buffer data
|
||||
uint8_t _maxDevices; // maximum number of devices in use
|
||||
deviceInfo_t* _matrix;// the current status of the LED matrix (buffers)
|
||||
uint8_t* _spiData; // data buffer for writing to SPI interface
|
||||
|
||||
// User callback function for shifting operations
|
||||
uint8_t (*_cbShiftDataIn)(uint8_t dev, transformType_t t);
|
||||
void (*_cbShiftDataOut)(uint8_t dev, transformType_t t, uint8_t colData);
|
||||
|
||||
// Control data for the library
|
||||
bool _updateEnabled; // update the display when this is true, suspend otherwise
|
||||
bool _wrapAround; // when shifting, wrap left to right and vice versa (circular buffer)
|
||||
|
||||
#if USE_LOCAL_FONT
|
||||
// Font related data
|
||||
fontType_t *_fontData; // pointer to the current font data being used
|
||||
uint16_t *_fontIndex; // font index for faster access to font table offsets
|
||||
|
||||
uint16_t getFontCharOffset(uint8_t c); // find the character in the font data
|
||||
void buildFontIndex(void); // build a font index
|
||||
#endif
|
||||
|
||||
// Private functions
|
||||
void spiSend(void); // do the actual physical communications task
|
||||
void spiClearBuffer(void); // clear the SPI send buffer
|
||||
void controlHardware(uint8_t dev, controlRequest_t mode, int value); // set hardware control commands
|
||||
void controlLibrary(controlRequest_t mode, int value); // set internal control commands
|
||||
|
||||
void flushBuffer(uint8_t buf);// determine what needs to be sent for one device and transmit
|
||||
void flushBufferAll(); // determine what needs to be sent for all devices and transmit
|
||||
|
||||
uint8_t bitReverse(uint8_t b); // reverse the order of bits in the byte
|
||||
bool transformBuffer(uint8_t buf, transformType_t ttype); // internal transform function
|
||||
|
||||
bool copyRow(uint8_t buf, uint8_t rSrc, uint8_t rDest); // copy a row from Src to Dest
|
||||
bool copyColumn(uint8_t buf, uint8_t cSrc, uint8_t cDest);// copy a row from Src to Dest
|
||||
};
|
||||
|
||||
#endif
|
||||
373
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_buf.cpp
Normal file
373
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_buf.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
This file contains methods that act on display buffers.
|
||||
|
||||
Copyright (C) 2012-13 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "MD_MAX72xx.h"
|
||||
#include "MD_MAX72xx_lib.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Implements buffer related methods
|
||||
*/
|
||||
|
||||
bool MD_MAX72XX::clear(uint8_t buf)
|
||||
{
|
||||
if (buf > LAST_BUFFER)
|
||||
return(false);
|
||||
|
||||
memset(_matrix[buf].dig, 0, sizeof(_matrix[buf].dig));
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
uint8_t MD_MAX72XX::bitReverse(uint8_t b)
|
||||
// Reverse the order of bits within a byte.
|
||||
// Returns the reversed byte value.
|
||||
{
|
||||
b = ((b & 0xf0) >> 4) | ((b & 0x0f) << 4);
|
||||
b = ((b & 0xcc) >> 2) | ((b & 0x33) << 2);
|
||||
b = ((b & 0xaa) >> 1) | ((b & 0x55) << 1);
|
||||
|
||||
return(b);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
bool MD_MAX72XX::copyColumn(uint8_t buf, uint8_t cSrc, uint8_t cDest)
|
||||
#else
|
||||
bool MD_MAX72XX::copyRow(uint8_t buf, uint8_t cSrc, uint8_t cDest)
|
||||
#endif
|
||||
// Src and Dest are in pixel coordinates.
|
||||
// if we are just copying rows there is no need to repackage any data
|
||||
{
|
||||
uint8_t maskSrc = 1 << HW_COL(cSrc); // which column of bits is the column data
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\ncopyCol: (", buf);
|
||||
#else
|
||||
PRINT("\ncopyRow: (", buf);
|
||||
#endif
|
||||
PRINT(", ", cSrc);
|
||||
PRINT(", ", cDest);
|
||||
PRINTS(") ");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (cSrc >= COL_SIZE) || (cDest >= COL_SIZE))
|
||||
return(false);
|
||||
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
if (_matrix[buf].dig[i] & maskSrc)
|
||||
bitSet(_matrix[buf].dig[i], HW_COL(cDest));
|
||||
else
|
||||
bitClear(_matrix[buf].dig[i], HW_COL(cDest));
|
||||
}
|
||||
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
uint8_t MD_MAX72XX::getColumn(uint8_t buf, uint8_t c)
|
||||
#else
|
||||
uint8_t MD_MAX72XX::getRow(uint8_t buf, uint8_t c)
|
||||
#endif
|
||||
// c is in pixel coordinates and the return value must be in pixel coordinate order
|
||||
{
|
||||
uint8_t mask = 1 << HW_COL(c); // which column of bits is the column data
|
||||
uint8_t value = 0; // assembles data to be returned to caller
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\ngetCol: (", buf);
|
||||
#else
|
||||
PRINT("\ngetRow: (", buf);
|
||||
#endif
|
||||
PRINT(", ", c);
|
||||
PRINTS(") ");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (c >= COL_SIZE))
|
||||
return(0);
|
||||
|
||||
PRINTX("mask 0x", mask);
|
||||
|
||||
// for each digit data, pull out the column/row bit and place
|
||||
// it in value. The loop creates the data in pixel coordinate order as it goes.
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
if (_matrix[buf].dig[HW_ROW(i)] & mask)
|
||||
bitSet(value, i);
|
||||
}
|
||||
|
||||
PRINTX(" value 0x", value);
|
||||
|
||||
return(value);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
bool MD_MAX72XX::setColumn(uint8_t buf, uint8_t c, uint8_t value)
|
||||
#else
|
||||
bool MD_MAX72XX::setRow(uint8_t buf, uint8_t c, uint8_t value)
|
||||
#endif
|
||||
// c and value are in pixel coordinate order
|
||||
{
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\nsetCol: (", buf);
|
||||
#else
|
||||
PRINT("\nsetRow: (", buf);
|
||||
#endif
|
||||
PRINT(", ", c);
|
||||
PRINTX(") 0x", value);
|
||||
|
||||
if ((buf > LAST_BUFFER) || (c >= COL_SIZE))
|
||||
return(false);
|
||||
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
{
|
||||
if (value & (1 << i)) // mask off next column value passed in and set it in the dig buffer
|
||||
bitSet(_matrix[buf].dig[HW_ROW(i)], HW_COL(c));
|
||||
else
|
||||
bitClear(_matrix[buf].dig[HW_ROW(i)], HW_COL(c));
|
||||
}
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
bool MD_MAX72XX::copyRow(uint8_t buf, uint8_t rSrc, uint8_t rDest)
|
||||
#else
|
||||
bool MD_MAX72XX::copyColumn(uint8_t buf, uint8_t rSrc, uint8_t rDest)
|
||||
#endif
|
||||
// Src and Dest are in pixel coordinates.
|
||||
// if we are just copying digits there is no need to repackage any data
|
||||
{
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\ncopyRow: (", buf);
|
||||
#else
|
||||
PRINT("\ncopyColumn: (", buf);
|
||||
#endif
|
||||
PRINT(", ", rSrc);
|
||||
PRINT(", ", rDest);
|
||||
PRINTS(") ");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (rSrc >= ROW_SIZE) || (rDest >= ROW_SIZE))
|
||||
return(false);
|
||||
|
||||
_matrix[buf].dig[HW_ROW(rDest)] = _matrix[buf].dig[HW_ROW(rSrc)];
|
||||
bitSet(_matrix[buf].changed, HW_ROW(rDest));
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
uint8_t MD_MAX72XX::getRow(uint8_t buf, uint8_t r)
|
||||
#else
|
||||
uint8_t MD_MAX72XX::getColumn(uint8_t buf, uint8_t r)
|
||||
#endif
|
||||
// r is in pixel coordinates for this buffer
|
||||
// returned value is in pixel coordinates
|
||||
{
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\ngetRow: (", buf);
|
||||
#else
|
||||
PRINT("\ngetCol: (", buf);
|
||||
#endif
|
||||
PRINT(", ", r);
|
||||
PRINTS(") ");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (r >= ROW_SIZE))
|
||||
return(0);
|
||||
|
||||
uint8_t value = HW_REV_COLS ? bitReverse(_matrix[buf].dig[HW_ROW(r)]) : _matrix[buf].dig[HW_ROW(r)];
|
||||
|
||||
PRINTX("0x", value);
|
||||
|
||||
return(value);
|
||||
}
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
bool MD_MAX72XX::setRow(uint8_t buf, uint8_t r, uint8_t value)
|
||||
#else
|
||||
bool MD_MAX72XX::setColumn(uint8_t buf, uint8_t r, uint8_t value)
|
||||
#endif
|
||||
// r and value are in pixel coordinates
|
||||
{
|
||||
#if HW_DIG_ROWS
|
||||
PRINT("\nsetRow: (", buf);
|
||||
#else
|
||||
PRINT("\nsetCol: (", buf);
|
||||
#endif
|
||||
PRINT(", ", r);
|
||||
|
||||
PRINTX(") 0x", value);
|
||||
|
||||
if ((buf > LAST_BUFFER) || (r >= ROW_SIZE))
|
||||
return(false);
|
||||
|
||||
_matrix[buf].dig[HW_ROW(r)] = HW_REV_COLS ? bitReverse(value) : value;
|
||||
bitSet(_matrix[buf].changed, HW_ROW(r));
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
bool MD_MAX72XX::transform(uint8_t buf, transformType_t ttype)
|
||||
{
|
||||
if (buf > LAST_BUFFER)
|
||||
return(false);
|
||||
|
||||
if (!transformBuffer(buf, ttype))
|
||||
return(false);
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::transformBuffer(uint8_t buf, transformType_t ttype)
|
||||
{
|
||||
uint8_t t[ROW_SIZE];
|
||||
|
||||
switch (ttype)
|
||||
{
|
||||
//--------------
|
||||
case TSL: // Transform Shift Left one pixel element
|
||||
#if HW_DIG_ROWS
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
#if HW_REV_COLS
|
||||
_matrix[buf].dig[i] >>= 1;
|
||||
#else
|
||||
_matrix[buf].dig[i] <<= 1;
|
||||
#endif
|
||||
#else
|
||||
#warning HW_DIG_ROWS=0
|
||||
for (uint8_t i=ROW_SIZE; i>0; --i)
|
||||
_matrix[buf].dig[i] = _matrix[buf].dig[i-1];
|
||||
#endif
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TSR: // Transform Shift Right one pixel element
|
||||
#if HW_DIG_ROWS
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
#if HW_REV_COLS
|
||||
_matrix[buf].dig[i] <<= 1;
|
||||
#else
|
||||
_matrix[buf].dig[i] >>= 1;
|
||||
#endif
|
||||
#else
|
||||
for (uint8_t i=0; i<ROW_SIZE-1; i++)
|
||||
_matrix[buf].dig[i] = _matrix[buf].dig[i+1];
|
||||
#endif
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TSU: // Transform Shift Up one pixel element
|
||||
if (_wrapAround) // save the first row or a zero row
|
||||
t[0] = getRow(buf, 0);
|
||||
else
|
||||
t[0] = 0;
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
for (uint8_t i=0; i<ROW_SIZE-1; i++)
|
||||
copyRow(buf, i+1, i);
|
||||
#else
|
||||
for (int8_t i=ROW_SIZE-1; i>=0; i--)
|
||||
_matrix[buf].dig[i] <<= 1;
|
||||
#endif
|
||||
setRow(buf, ROW_SIZE-1, t[0]);
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TSD: // Transform Shift Down one pixel element
|
||||
if (_wrapAround) // save the last row or a zero row
|
||||
t[0] = getRow(buf, ROW_SIZE-1);
|
||||
else
|
||||
t[0] = 0;
|
||||
|
||||
#if HW_DIG_ROWS
|
||||
for (uint8_t i=ROW_SIZE; i>0; --i)
|
||||
copyRow(buf, i-1, i);
|
||||
#else
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
_matrix[buf].dig[i] >>= 1;
|
||||
#endif
|
||||
setRow(buf, 0, t[0]);
|
||||
break;
|
||||
|
||||
//--------------
|
||||
#if HW_DIG_ROWS
|
||||
case TFLR: // Transform Flip Left to Right
|
||||
#else
|
||||
case TFUD: // Transform Flip Up to Down
|
||||
#endif
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
_matrix[buf].dig[i] = bitReverse(_matrix[buf].dig[i]);
|
||||
break;
|
||||
|
||||
//--------------
|
||||
#if HW_DIG_ROWS
|
||||
case TFUD: // Transform Flip Up to Down
|
||||
#else
|
||||
case TFLR: // Transform Flip Left to Right
|
||||
#endif
|
||||
for (uint8_t i=0; i<ROW_SIZE/2; i++)
|
||||
{
|
||||
uint8_t t = _matrix[buf].dig[i];
|
||||
_matrix[buf].dig[i] = _matrix[buf].dig[ROW_SIZE-i-1];
|
||||
_matrix[buf].dig[ROW_SIZE-i-1] = t;
|
||||
}
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TRC: // Transform Rotate Clockwise
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
t[i] = getColumn(buf, COL_SIZE-1-i);
|
||||
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
setRow(buf, i, t[i]);
|
||||
break;
|
||||
|
||||
//--------------
|
||||
case TINV: // Transform INVert
|
||||
for (uint8_t i=0; i<ROW_SIZE; i++)
|
||||
_matrix[buf].dig[i] = ~_matrix[buf].dig[i];
|
||||
break;
|
||||
|
||||
default:
|
||||
return(false);
|
||||
}
|
||||
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
|
||||
return(true);
|
||||
}
|
||||
427
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_font.cpp
Normal file
427
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_font.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
|
||||
This file contains methods that work with the fonts and characters defined in the library
|
||||
|
||||
Copyright (C) 2012-14 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "MD_MAX72xx.h"
|
||||
#include "MD_MAX72xx_lib.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Implements font definition and methods
|
||||
*/
|
||||
|
||||
#if USE_LOCAL_FONT
|
||||
// Local font handling functions if the option is enabled
|
||||
|
||||
void MD_MAX72XX::buildFontIndex(void)
|
||||
{
|
||||
uint16_t offset = 0;
|
||||
|
||||
if (_fontIndex == nullptr)
|
||||
return;
|
||||
|
||||
PRINTS("\nBuilding font index");
|
||||
for (uint16_t i=0; i<ASCII_INDEX_SIZE; i++)
|
||||
{
|
||||
_fontIndex[i] = offset;
|
||||
PRINT("\nASCII '", i);
|
||||
PRINT("' offset ", _fontIndex[i]);
|
||||
offset += pgm_read_byte(_fontData+offset);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MD_MAX72XX::getMaxFontWidth(void)
|
||||
{
|
||||
uint8_t max = 0;
|
||||
uint8_t charWidth;
|
||||
uint16_t offset = 0;
|
||||
|
||||
PRINTS("\nFinding max font width");
|
||||
if (_fontData != nullptr)
|
||||
{
|
||||
for (uint16_t i = 0; i < ASCII_INDEX_SIZE; i++)
|
||||
{
|
||||
charWidth = pgm_read_byte(_fontData + offset);
|
||||
/*
|
||||
PRINT("\nASCII '", i);
|
||||
PRINT("' offset ", offset);
|
||||
PRINT("' width ", charWidth);
|
||||
*/
|
||||
if (charWidth > max)
|
||||
{
|
||||
max = charWidth;
|
||||
PRINT(":", max);
|
||||
}
|
||||
offset += charWidth; // skip character data
|
||||
offset++; // skip size byte
|
||||
}
|
||||
}
|
||||
PRINT(" max ", max);
|
||||
|
||||
return(max);
|
||||
}
|
||||
|
||||
uint16_t MD_MAX72XX::getFontCharOffset(uint8_t c)
|
||||
{
|
||||
PRINT("\nfontOffset ASCII ", c);
|
||||
|
||||
if (_fontIndex != nullptr)
|
||||
{
|
||||
PRINTS(" from Table");
|
||||
return(_fontIndex[c]);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINTS(" by Search ");
|
||||
|
||||
uint16_t offset = 0;
|
||||
|
||||
for (uint8_t i=0; i<c; i++)
|
||||
{
|
||||
PRINTS(".");
|
||||
offset += pgm_read_byte(_fontData+offset);
|
||||
offset++; // skip size byte we used above
|
||||
}
|
||||
PRINT(" searched offset ", offset);
|
||||
|
||||
return(offset);
|
||||
}
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::setFont(fontType_t *f)
|
||||
{
|
||||
_fontData = (f == nullptr ? _sysfont_var : f);
|
||||
|
||||
buildFontIndex();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
uint8_t MD_MAX72XX::getChar(uint8_t c, uint8_t size, uint8_t *buf)
|
||||
{
|
||||
PRINT("\ngetChar: '", (char)c);
|
||||
PRINT("' ASC ", c);
|
||||
PRINT(" - bufsize ", size);
|
||||
|
||||
if (buf == nullptr)
|
||||
return(0);
|
||||
|
||||
uint16_t offset = getFontCharOffset(c);
|
||||
size = min(size, pgm_read_byte(_fontData+offset));
|
||||
|
||||
offset++; // skip the size byte
|
||||
|
||||
for (uint8_t i=0; i<size; i++)
|
||||
*buf++ = pgm_read_byte(_fontData+offset+i);
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
uint8_t MD_MAX72XX::setChar(uint16_t col, uint8_t c)
|
||||
{
|
||||
PRINT("\nsetChar: '", c);
|
||||
PRINT("' column ", col);
|
||||
boolean b = _updateEnabled;
|
||||
|
||||
uint16_t offset = getFontCharOffset(c);
|
||||
uint8_t size = pgm_read_byte(_fontData+offset);
|
||||
|
||||
offset++; // skip the size byte
|
||||
|
||||
_updateEnabled = false;
|
||||
for (int8_t i=0; i<size; i++)
|
||||
{
|
||||
uint8_t colData = pgm_read_byte(_fontData+offset+i);
|
||||
setColumn(col--, colData);
|
||||
}
|
||||
_updateEnabled = b;
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
// Standard font - variable spacing
|
||||
MD_MAX72XX::fontType_t PROGMEM _sysfont_var[] =
|
||||
{
|
||||
0, // 0 - 'Empty Cell'
|
||||
5, 0x3e, 0x5b, 0x4f, 0x5b, 0x3e, // 1 - 'Sad Smiley'
|
||||
5, 0x3e, 0x6b, 0x4f, 0x6b, 0x3e, // 2 - 'Happy Smiley'
|
||||
5, 0x1c, 0x3e, 0x7c, 0x3e, 0x1c, // 3 - 'Heart'
|
||||
5, 0x18, 0x3c, 0x7e, 0x3c, 0x18, // 4 - 'Diamond'
|
||||
5, 0x1c, 0x57, 0x7d, 0x57, 0x1c, // 5 - 'Clubs'
|
||||
5, 0x1c, 0x5e, 0x7f, 0x5e, 0x1c, // 6 - 'Spades'
|
||||
4, 0x00, 0x18, 0x3c, 0x18, // 7 - 'Bullet Point'
|
||||
5, 0xff, 0xe7, 0xc3, 0xe7, 0xff, // 8 - 'Rev Bullet Point'
|
||||
4, 0x00, 0x18, 0x24, 0x18, // 9 - 'Hollow Bullet Point'
|
||||
5, 0xff, 0xe7, 0xdb, 0xe7, 0xff, // 10 - 'Rev Hollow BP'
|
||||
5, 0x30, 0x48, 0x3a, 0x06, 0x0e, // 11 - 'Male'
|
||||
5, 0x26, 0x29, 0x79, 0x29, 0x26, // 12 - 'Female'
|
||||
5, 0x40, 0x7f, 0x05, 0x05, 0x07, // 13 - 'Music Note 1'
|
||||
5, 0x40, 0x7f, 0x05, 0x25, 0x3f, // 14 - 'Music Note 2'
|
||||
5, 0x5a, 0x3c, 0xe7, 0x3c, 0x5a, // 15 - 'Snowflake'
|
||||
5, 0x7f, 0x3e, 0x1c, 0x1c, 0x08, // 16 - 'Right Pointer'
|
||||
5, 0x08, 0x1c, 0x1c, 0x3e, 0x7f, // 17 - 'Left Pointer'
|
||||
5, 0x14, 0x22, 0x7f, 0x22, 0x14, // 18 - 'UpDown Arrows'
|
||||
5, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, // 19 - 'Double Exclamation'
|
||||
5, 0x06, 0x09, 0x7f, 0x01, 0x7f, // 20 - 'Paragraph Mark'
|
||||
4, 0x66, 0x89, 0x95, 0x6a, // 21 - 'Section Mark'
|
||||
5, 0x60, 0x60, 0x60, 0x60, 0x60, // 22 - 'Double Underline'
|
||||
5, 0x94, 0xa2, 0xff, 0xa2, 0x94, // 23 - 'UpDown Underlined'
|
||||
5, 0x08, 0x04, 0x7e, 0x04, 0x08, // 24 - 'Up Arrow'
|
||||
5, 0x10, 0x20, 0x7e, 0x20, 0x10, // 25 - 'Down Arrow'
|
||||
5, 0x08, 0x08, 0x2a, 0x1c, 0x08, // 26 - 'Right Arrow'
|
||||
5, 0x08, 0x1c, 0x2a, 0x08, 0x08, // 27 - 'Left Arrow'
|
||||
5, 0x1e, 0x10, 0x10, 0x10, 0x10, // 28 - 'Angled'
|
||||
5, 0x0c, 0x1e, 0x0c, 0x1e, 0x0c, // 29 - 'Squashed #'
|
||||
5, 0x30, 0x38, 0x3e, 0x38, 0x30, // 30 - 'Up Pointer'
|
||||
5, 0x06, 0x0e, 0x3e, 0x0e, 0x06, // 31 - 'Down Pointer'
|
||||
1, 0x00, // 32 - 'Space'
|
||||
1, 0x5f, // 33 - '!'
|
||||
3, 0x07, 0x00, 0x07, // 34 - '"'
|
||||
5, 0x14, 0x7f, 0x14, 0x7f, 0x14, // 35 - '#'
|
||||
5, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // 36 - '$'
|
||||
5, 0x23, 0x13, 0x08, 0x64, 0x62, // 37 - '%'
|
||||
5, 0x36, 0x49, 0x56, 0x20, 0x50, // 38 - '&'
|
||||
3, 0x08, 0x07, 0x03, // 39 - '''
|
||||
3, 0x1c, 0x22, 0x41, // 40 - '('
|
||||
3, 0x41, 0x22, 0x1c, // 41 - ')'
|
||||
5, 0x2a, 0x1c, 0x7f, 0x1c, 0x2a, // 42 - '*'
|
||||
5, 0x08, 0x08, 0x3e, 0x08, 0x08, // 43 - '+'
|
||||
3, 0x80, 0x70, 0x30, // 44 - ','
|
||||
5, 0x08, 0x08, 0x08, 0x08, 0x08, // 45 - '-'
|
||||
2, 0x60, 0x60, // 46 - '.'
|
||||
5, 0x20, 0x10, 0x08, 0x04, 0x02, // 47 - '/'
|
||||
5, 0x3e, 0x51, 0x49, 0x45, 0x3e, // 48 - '0'
|
||||
3, 0x42, 0x7f, 0x40, // 49 - '1'
|
||||
5, 0x72, 0x49, 0x49, 0x49, 0x46, // 50 - '2'
|
||||
5, 0x21, 0x41, 0x49, 0x4d, 0x33, // 51 - '3'
|
||||
5, 0x18, 0x14, 0x12, 0x7f, 0x10, // 52 - '4'
|
||||
5, 0x27, 0x45, 0x45, 0x45, 0x39, // 53 - '5'
|
||||
5, 0x3c, 0x4a, 0x49, 0x49, 0x31, // 54 - '6'
|
||||
5, 0x41, 0x21, 0x11, 0x09, 0x07, // 55 - '7'
|
||||
5, 0x36, 0x49, 0x49, 0x49, 0x36, // 56 - '8'
|
||||
5, 0x46, 0x49, 0x49, 0x29, 0x1e, // 57 - '9'
|
||||
1, 0x14, // 58 - ':'
|
||||
2, 0x80, 0x68, // 59 - ';'
|
||||
4, 0x08, 0x14, 0x22, 0x41, // 60 - '<'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0x14, // 61 - '='
|
||||
4, 0x41, 0x22, 0x14, 0x08, // 62 - '>'
|
||||
5, 0x02, 0x01, 0x59, 0x09, 0x06, // 63 - '?'
|
||||
5, 0x3e, 0x41, 0x5d, 0x59, 0x4e, // 64 - '@'
|
||||
5, 0x7c, 0x12, 0x11, 0x12, 0x7c, // 65 - 'A'
|
||||
5, 0x7f, 0x49, 0x49, 0x49, 0x36, // 66 - 'B'
|
||||
5, 0x3e, 0x41, 0x41, 0x41, 0x22, // 67 - 'C'
|
||||
5, 0x7f, 0x41, 0x41, 0x41, 0x3e, // 68 - 'D'
|
||||
5, 0x7f, 0x49, 0x49, 0x49, 0x41, // 69 - 'E'
|
||||
5, 0x7f, 0x09, 0x09, 0x09, 0x01, // 70 - 'F'
|
||||
5, 0x3e, 0x41, 0x41, 0x51, 0x73, // 71 - 'G'
|
||||
5, 0x7f, 0x08, 0x08, 0x08, 0x7f, // 72 - 'H'
|
||||
3, 0x41, 0x7f, 0x41, // 73 - 'I'
|
||||
5, 0x20, 0x40, 0x41, 0x3f, 0x01, // 74 - 'J'
|
||||
5, 0x7f, 0x08, 0x14, 0x22, 0x41, // 75 - 'K'
|
||||
5, 0x7f, 0x40, 0x40, 0x40, 0x40, // 76 - 'L'
|
||||
5, 0x7f, 0x02, 0x1c, 0x02, 0x7f, // 77 - 'M'
|
||||
5, 0x7f, 0x04, 0x08, 0x10, 0x7f, // 78 - 'N'
|
||||
5, 0x3e, 0x41, 0x41, 0x41, 0x3e, // 79 - 'O'
|
||||
5, 0x7f, 0x09, 0x09, 0x09, 0x06, // 80 - 'P'
|
||||
5, 0x3e, 0x41, 0x51, 0x21, 0x5e, // 81 - 'Q'
|
||||
5, 0x7f, 0x09, 0x19, 0x29, 0x46, // 82 - 'R'
|
||||
5, 0x26, 0x49, 0x49, 0x49, 0x32, // 83 - 'S'
|
||||
5, 0x03, 0x01, 0x7f, 0x01, 0x03, // 84 - 'T'
|
||||
5, 0x3f, 0x40, 0x40, 0x40, 0x3f, // 85 - 'U'
|
||||
5, 0x1f, 0x20, 0x40, 0x20, 0x1f, // 86 - 'V'
|
||||
5, 0x3f, 0x40, 0x38, 0x40, 0x3f, // 87 - 'W'
|
||||
5, 0x63, 0x14, 0x08, 0x14, 0x63, // 88 - 'X'
|
||||
5, 0x03, 0x04, 0x78, 0x04, 0x03, // 89 - 'Y'
|
||||
5, 0x61, 0x59, 0x49, 0x4d, 0x43, // 90 - 'Z'
|
||||
3, 0x7f, 0x41, 0x41, // 91 - '['
|
||||
5, 0x02, 0x04, 0x08, 0x10, 0x20, // 92 - '\'
|
||||
3, 0x41, 0x41, 0x7f, // 93 - ']'
|
||||
5, 0x04, 0x02, 0x01, 0x02, 0x04, // 94 - '^'
|
||||
5, 0x40, 0x40, 0x40, 0x40, 0x40, // 95 - '_'
|
||||
3, 0x03, 0x07, 0x08, // 96 - '`'
|
||||
5, 0x20, 0x54, 0x54, 0x78, 0x40, // 97 - 'a'
|
||||
5, 0x7f, 0x28, 0x44, 0x44, 0x38, // 98 - 'b'
|
||||
5, 0x38, 0x44, 0x44, 0x44, 0x28, // 99 - 'c'
|
||||
5, 0x38, 0x44, 0x44, 0x28, 0x7f, // 100 - 'd'
|
||||
5, 0x38, 0x54, 0x54, 0x54, 0x18, // 101 - 'e'
|
||||
4, 0x08, 0x7e, 0x09, 0x02, // 102 - 'f'
|
||||
5, 0x18, 0xa4, 0xa4, 0x9c, 0x78, // 103 - 'g'
|
||||
5, 0x7f, 0x08, 0x04, 0x04, 0x78, // 104 - 'h'
|
||||
3, 0x44, 0x7d, 0x40, // 105 - 'i'
|
||||
4, 0x40, 0x80, 0x80, 0x7a, // 106 - 'j'
|
||||
4, 0x7f, 0x10, 0x28, 0x44, // 107 - 'k'
|
||||
3, 0x41, 0x7f, 0x40, // 108 - 'l'
|
||||
5, 0x7c, 0x04, 0x78, 0x04, 0x78, // 109 - 'm'
|
||||
5, 0x7c, 0x08, 0x04, 0x04, 0x78, // 110 - 'n'
|
||||
5, 0x38, 0x44, 0x44, 0x44, 0x38, // 111 - 'o'
|
||||
5, 0xfc, 0x18, 0x24, 0x24, 0x18, // 112 - 'p'
|
||||
5, 0x18, 0x24, 0x24, 0x18, 0xfc, // 113 - 'q'
|
||||
5, 0x7c, 0x08, 0x04, 0x04, 0x08, // 114 - 'r'
|
||||
5, 0x48, 0x54, 0x54, 0x54, 0x24, // 115 - 's'
|
||||
4, 0x04, 0x3f, 0x44, 0x24, // 116 - 't'
|
||||
5, 0x3c, 0x40, 0x40, 0x20, 0x7c, // 117 - 'u'
|
||||
5, 0x1c, 0x20, 0x40, 0x20, 0x1c, // 118 - 'v'
|
||||
5, 0x3c, 0x40, 0x30, 0x40, 0x3c, // 119 - 'w'
|
||||
5, 0x44, 0x28, 0x10, 0x28, 0x44, // 120 - 'x'
|
||||
5, 0x4c, 0x90, 0x90, 0x90, 0x7c, // 121 - 'y'
|
||||
5, 0x44, 0x64, 0x54, 0x4c, 0x44, // 122 - 'z'
|
||||
3, 0x08, 0x36, 0x41, // 123 - '{'
|
||||
1, 0x77, // 124 - '|'
|
||||
3, 0x41, 0x36, 0x08, // 125 - '}'
|
||||
5, 0x02, 0x01, 0x02, 0x04, 0x02, // 126 - '~'
|
||||
5, 0x3c, 0x26, 0x23, 0x26, 0x3c, // 127 - 'Hollow Up Arrow'
|
||||
5, 0x1e, 0xa1, 0xa1, 0x61, 0x12, // 128 - 'C sedilla'
|
||||
5, 0x38, 0x42, 0x40, 0x22, 0x78, // 129 - 'u umlaut'
|
||||
5, 0x38, 0x54, 0x54, 0x55, 0x59, // 130 - 'e acute'
|
||||
5, 0x21, 0x55, 0x55, 0x79, 0x41, // 131 - 'a accent'
|
||||
5, 0x21, 0x54, 0x54, 0x78, 0x41, // 132 - 'a umlaut'
|
||||
5, 0x21, 0x55, 0x54, 0x78, 0x40, // 133 - 'a grave'
|
||||
5, 0x20, 0x54, 0x55, 0x79, 0x40, // 134 - 'a acute'
|
||||
5, 0x18, 0x3c, 0xa4, 0xe4, 0x24, // 135 - 'c sedilla'
|
||||
5, 0x39, 0x55, 0x55, 0x55, 0x59, // 136 - 'e accent'
|
||||
5, 0x38, 0x55, 0x54, 0x55, 0x58, // 137 - 'e umlaut'
|
||||
5, 0x39, 0x55, 0x54, 0x54, 0x58, // 138 - 'e grave'
|
||||
3, 0x45, 0x7c, 0x41, // 139 - 'i umlaut'
|
||||
4, 0x02, 0x45, 0x7d, 0x42, // 140 - 'i hat'
|
||||
4, 0x01, 0x45, 0x7c, 0x40, // 141 - 'i grave'
|
||||
5, 0xf0, 0x29, 0x24, 0x29, 0xf0, // 142 - 'A umlaut'
|
||||
5, 0xf0, 0x28, 0x25, 0x28, 0xf0, // 143 - 'A dot'
|
||||
4, 0x7c, 0x54, 0x55, 0x45, // 144 - 'E grave'
|
||||
7, 0x20, 0x54, 0x54, 0x7c, 0x54, 0x54, 0x08, // 145 - 'ae'
|
||||
6, 0x7c, 0x0a, 0x09, 0x7f, 0x49, 0x49, // 146 - 'AE'
|
||||
5, 0x32, 0x49, 0x49, 0x49, 0x32, // 147 - 'o hat'
|
||||
5, 0x30, 0x4a, 0x48, 0x4a, 0x30, // 148 - 'o umlaut'
|
||||
5, 0x32, 0x4a, 0x48, 0x48, 0x30, // 149 - 'o grave'
|
||||
5, 0x3a, 0x41, 0x41, 0x21, 0x7a, // 150 - 'u hat'
|
||||
5, 0x3a, 0x42, 0x40, 0x20, 0x78, // 151 - 'u grave'
|
||||
4, 0x9d, 0xa0, 0xa0, 0x7d, // 152 - 'y umlaut'
|
||||
5, 0x38, 0x45, 0x44, 0x45, 0x38, // 153 - 'O umlaut'
|
||||
5, 0x3c, 0x41, 0x40, 0x41, 0x3c, // 154 - 'U umlaut'
|
||||
5, 0x3c, 0x24, 0xff, 0x24, 0x24, // 155 - 'Cents'
|
||||
5, 0x48, 0x7e, 0x49, 0x43, 0x66, // 156 - 'Pounds'
|
||||
5, 0x2b, 0x2f, 0xfc, 0x2f, 0x2b, // 157 - 'Yen'
|
||||
5, 0xff, 0x09, 0x29, 0xf6, 0x20, // 158 - 'R +'
|
||||
5, 0xc0, 0x88, 0x7e, 0x09, 0x03, // 159 - 'f notation'
|
||||
5, 0x20, 0x54, 0x54, 0x79, 0x41, // 160 - 'a acute'
|
||||
3, 0x44, 0x7d, 0x41, // 161 - 'i acute'
|
||||
5, 0x30, 0x48, 0x48, 0x4a, 0x32, // 162 - 'o acute'
|
||||
5, 0x38, 0x40, 0x40, 0x22, 0x7a, // 163 - 'u acute'
|
||||
4, 0x7a, 0x0a, 0x0a, 0x72, // 164 - 'n accent'
|
||||
5, 0x7d, 0x0d, 0x19, 0x31, 0x7d, // 165 - 'N accent'
|
||||
5, 0x26, 0x29, 0x29, 0x2f, 0x28, // 166
|
||||
5, 0x26, 0x29, 0x29, 0x29, 0x26, // 167
|
||||
5, 0x30, 0x48, 0x4d, 0x40, 0x20, // 168 - 'Inverted ?'
|
||||
5, 0x38, 0x08, 0x08, 0x08, 0x08, // 169 - 'LH top corner'
|
||||
5, 0x08, 0x08, 0x08, 0x08, 0x38, // 170 - 'RH top corner'
|
||||
5, 0x2f, 0x10, 0xc8, 0xac, 0xba, // 171 - '1/2'
|
||||
5, 0x2f, 0x10, 0x28, 0x34, 0xfa, // 172 - '1/4'
|
||||
1, 0x7b, // 173 - '| split'
|
||||
5, 0x08, 0x14, 0x2a, 0x14, 0x22, // 174 - '<<'
|
||||
5, 0x22, 0x14, 0x2a, 0x14, 0x08, // 175 - '>>'
|
||||
5, 0xaa, 0x00, 0x55, 0x00, 0xaa, // 176 - '30% shading'
|
||||
5, 0xaa, 0x55, 0xaa, 0x55, 0xaa, // 177 - '50% shading'
|
||||
5, 0x00, 0x00, 0x00, 0x00, 0xff, // 178 - 'Right side'
|
||||
5, 0x10, 0x10, 0x10, 0x10, 0xff, // 179 - 'Right T'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0xff, // 180 - 'Right T double H'
|
||||
5, 0x10, 0x10, 0xff, 0x00, 0xff, // 181 - 'Right T double V'
|
||||
5, 0x10, 0x10, 0xf0, 0x10, 0xf0, // 182 - 'Top Right double V'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0xfc, // 183 - 'Top Right double H'
|
||||
5, 0x14, 0x14, 0xf7, 0x00, 0xff, // 184 - 'Right T double all'
|
||||
5, 0x00, 0x00, 0xff, 0x00, 0xff, // 185 - 'Right side double'
|
||||
5, 0x14, 0x14, 0xf4, 0x04, 0xfc, // 186 - 'Top Right double'
|
||||
5, 0x14, 0x14, 0x17, 0x10, 0x1f, // 187 - 'Bot Right double'
|
||||
5, 0x10, 0x10, 0x1f, 0x10, 0x1f, // 188 - 'Bot Right double V'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0x1f, // 189 - 'Bot Right double H'
|
||||
5, 0x10, 0x10, 0x10, 0x10, 0xf0, // 190 - 'Top Right'
|
||||
5, 0x00, 0x00, 0x00, 0x1f, 0x10, // 191 - 'Bot Left'
|
||||
5, 0x10, 0x10, 0x10, 0x1f, 0x10, // 192 - 'Bot T'
|
||||
5, 0x10, 0x10, 0x10, 0xf0, 0x10, // 193 - 'Top T'
|
||||
5, 0x00, 0x00, 0x00, 0xff, 0x10, // 194 - 'Left T'
|
||||
5, 0x10, 0x10, 0x10, 0x10, 0x10, // 195 - 'Top side'
|
||||
5, 0x10, 0x10, 0x10, 0xff, 0x10, // 196 - 'Center +'
|
||||
5, 0x00, 0x00, 0x00, 0xff, 0x14, // 197 - 'Left side double H'
|
||||
5, 0x00, 0x00, 0xff, 0x00, 0xff, // 198 - 'Left side double'
|
||||
5, 0x00, 0x00, 0x1f, 0x10, 0x17, // 199 - 'Bot Left double V'
|
||||
5, 0x00, 0x00, 0xfc, 0x04, 0xf4, // 200 - 'Top Left double V'
|
||||
5, 0x14, 0x14, 0x17, 0x10, 0x17, // 201 - 'Bot T double'
|
||||
5, 0x14, 0x14, 0xf4, 0x04, 0xf4, // 202 - 'Top T double'
|
||||
5, 0x00, 0x00, 0xff, 0x00, 0xf7, // 203 - 'Left Side double spl'
|
||||
5, 0x14, 0x14, 0x14, 0x14, 0x14, // 204 - 'Center double'
|
||||
5, 0x14, 0x14, 0xf7, 0x00, 0xf7, // 205 - 'Center + double'
|
||||
5, 0x14, 0x14, 0x14, 0x17, 0x14, // 206 - 'Bot T double H'
|
||||
5, 0x10, 0x10, 0x1f, 0x10, 0x1f, // 207 - 'Bot Right double V'
|
||||
5, 0x14, 0x14, 0x14, 0xf4, 0x14, // 208 - 'Top T double H'
|
||||
5, 0x10, 0x10, 0xf0, 0x10, 0xf0, // 209 - 'Top Right double V'
|
||||
5, 0x00, 0x00, 0x1f, 0x10, 0x1f, // 210 - 'Bot Left double V'
|
||||
5, 0x00, 0x00, 0x00, 0x1f, 0x14, // 211 - 'Bot Right double H'
|
||||
5, 0x00, 0x00, 0x00, 0xfc, 0x14, // 212 - 'Top Right double H'
|
||||
5, 0x00, 0x00, 0xf0, 0x10, 0xf0, // 213 - 'Top Right double V'
|
||||
5, 0x10, 0x10, 0xff, 0x10, 0xff, // 214 - 'Center + double V'
|
||||
5, 0x14, 0x14, 0x14, 0xff, 0x14, // 215 - 'Center + double H'
|
||||
5, 0x10, 0x10, 0x10, 0x10, 0x1f, // 216 - 'Bot Right'
|
||||
5, 0x00, 0x00, 0x00, 0xf0, 0x10, // 217 - 'Top Left'
|
||||
5, 0xff, 0xff, 0xff, 0xff, 0xff, // 218 - 'Full Block'
|
||||
5, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 219 - 'Half Block Bottom'
|
||||
3, 0xff, 0xff, 0xff, // 220 - 'Half Block LHS'
|
||||
5, 0x00, 0x00, 0x00, 0xff, 0xff, // 221 - 'Half Block RHS'
|
||||
5, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, // 222 - 'Half Block Top'
|
||||
5, 0x38, 0x44, 0x44, 0x38, 0x44, // 223 - 'Alpha'
|
||||
5, 0x7c, 0x2a, 0x2a, 0x3e, 0x14, // 224 - 'Beta'
|
||||
5, 0x7e, 0x02, 0x02, 0x06, 0x06, // 225 - 'Gamma'
|
||||
5, 0x02, 0x7e, 0x02, 0x7e, 0x02, // 226 - 'Pi'
|
||||
5, 0x63, 0x55, 0x49, 0x41, 0x63, // 227 - 'Sigma'
|
||||
5, 0x38, 0x44, 0x44, 0x3c, 0x04, // 228 - 'Theta'
|
||||
5, 0x40, 0x7e, 0x20, 0x1e, 0x20, // 229 - 'mu'
|
||||
5, 0x06, 0x02, 0x7e, 0x02, 0x02, // 230 - 'Tau'
|
||||
5, 0x99, 0xa5, 0xe7, 0xa5, 0x99, // 231
|
||||
5, 0x1c, 0x2a, 0x49, 0x2a, 0x1c, // 232
|
||||
5, 0x4c, 0x72, 0x01, 0x72, 0x4c, // 233
|
||||
5, 0x30, 0x4a, 0x4d, 0x4d, 0x30, // 234
|
||||
5, 0x30, 0x48, 0x78, 0x48, 0x30, // 235
|
||||
5, 0xbc, 0x62, 0x5a, 0x46, 0x3d, // 236 - 'Zero Slashed'
|
||||
4, 0x3e, 0x49, 0x49, 0x49, // 237
|
||||
5, 0x7e, 0x01, 0x01, 0x01, 0x7e, // 238
|
||||
5, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, // 239 - '3 Bar Equals'
|
||||
5, 0x44, 0x44, 0x5f, 0x44, 0x44, // 240 - '+/-'
|
||||
5, 0x40, 0x51, 0x4a, 0x44, 0x40, // 241 - '>='
|
||||
5, 0x40, 0x44, 0x4a, 0x51, 0x40, // 242 - '<='
|
||||
5, 0x00, 0x00, 0xff, 0x01, 0x03, // 243 - 'Top of Integral'
|
||||
3, 0xe0, 0x80, 0xff, // 244 - 'Bot of Integral'
|
||||
5, 0x08, 0x08, 0x6b, 0x6b, 0x08, // 245 - 'Divide'
|
||||
5, 0x36, 0x12, 0x36, 0x24, 0x36, // 246 - 'Wavy ='
|
||||
5, 0x06, 0x0f, 0x09, 0x0f, 0x06, // 247 - 'Degree'
|
||||
4, 0x00, 0x00, 0x18, 0x18, // 248 - 'Math Product'
|
||||
4, 0x00, 0x00, 0x10, 0x10, // 249 - 'Short Dash'
|
||||
5, 0x30, 0x40, 0xff, 0x01, 0x01, // 250 - 'Square Root'
|
||||
5, 0x00, 0x1f, 0x01, 0x01, 0x1e, // 251 - 'Superscript n'
|
||||
5, 0x00, 0x19, 0x1d, 0x17, 0x12, // 252 - 'Superscript 2'
|
||||
5, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, // 253 - 'Centered Square'
|
||||
5, 0xff, 0x81, 0x81, 0x81, 0xff, // 254 - 'Full Frame'
|
||||
5, 0xff, 0xff, 0xff, 0xff, 0xff, // 255 - 'Full Block'
|
||||
};
|
||||
|
||||
#endif //INCLUDE_LOCAL_FONT
|
||||
|
||||
529
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_lib.h
Normal file
529
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_lib.h
Normal file
@@ -0,0 +1,529 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
|
||||
This file contains library related definitions and is not visible
|
||||
to user code.
|
||||
|
||||
Copyright (C) 2012-14 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef MDMAX72xxLIB_H
|
||||
#define MDMAX72xxLIB_H
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Includes library definitions
|
||||
*/
|
||||
|
||||
#define MAX_DEBUG 0 ///< Enable or disable (default) debugging output from the MD_MAX72xx library
|
||||
|
||||
#if MAX_DEBUG
|
||||
#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); } ///< Print a string followed by a value (decimal)
|
||||
#define PRINTX(s, v) { Serial.print(F(s)); Serial.print(v, HEX); } ///< Print a string followed by a value (hex)
|
||||
#define PRINTB(s, v) { Serial.print(F(s)); Serial.print(v, BIN); } ///< Print a string followed by a value (binary)
|
||||
#define PRINTS(s) { Serial.print(F(s)); } ///< Print a string
|
||||
#else
|
||||
#define PRINT(s, v) ///< Print a string followed by a value (decimal)
|
||||
#define PRINTX(s, v) ///< Print a string followed by a value (hex)
|
||||
#define PRINTB(s, v) ///< Print a string followed by a value (binary)
|
||||
#define PRINTS(s) ///< Print a string
|
||||
#endif
|
||||
|
||||
// Opcodes for the MAX7221 and MAX7219
|
||||
// All OP_DIGITn are offsets from OP_DIGIT0
|
||||
#define OP_NOOP 0 ///< MAX72xx opcode for NO OP
|
||||
#define OP_DIGIT0 1 ///< MAX72xx opcode for DIGIT0
|
||||
#define OP_DIGIT1 2 ///< MAX72xx opcode for DIGIT1
|
||||
#define OP_DIGIT2 3 ///< MAX72xx opcode for DIGIT2
|
||||
#define OP_DIGIT3 4 ///< MAX72xx opcode for DIGIT3
|
||||
#define OP_DIGIT4 5 ///< MAX72xx opcode for DIGIT4
|
||||
#define OP_DIGIT5 6 ///< MAX72xx opcode for DIGIT5
|
||||
#define OP_DIGIT6 7 ///< MAX72xx opcode for DIGIT6
|
||||
#define OP_DIGIT7 8 ///< MAX72xx opcode for DIGIT7
|
||||
#define OP_DECODEMODE 9 ///< MAX72xx opcode for DECODE MODE
|
||||
#define OP_INTENSITY 10 ///< MAX72xx opcode for SET INTENSITY
|
||||
#define OP_SCANLIMIT 11 ///< MAX72xx opcode for SCAN LIMIT
|
||||
#define OP_SHUTDOWN 12 ///< MAX72xx opcode for SHUT DOWN
|
||||
#define OP_DISPLAYTEST 15 ///< MAX72xx opcode for DISPLAY TEST
|
||||
|
||||
#define ALL_CHANGED 0xff ///< Mask for all rows changed in a buffer structure
|
||||
#define ALL_CLEAR 0x00 ///< Mask for all rows clear in a buffer structure
|
||||
|
||||
#define ASCII_INDEX_SIZE 256 ///< Number of characters in a font table (ASCII maximum)
|
||||
|
||||
// Shortcuts
|
||||
#define SPI_DATA_SIZE (sizeof(uint8_t)*_maxDevices*2) ///< Size of the SPI data buffers
|
||||
#define SPI_OFFSET(i,x) (((LAST_BUFFER-(i))*2)+(x)) ///< SPI data offset for buffer i, digit x
|
||||
#define FIRST_BUFFER 0 ///< First buffer number
|
||||
#define LAST_BUFFER (_maxDevices-1) ///< Last buffer number
|
||||
|
||||
// variables shared in the library
|
||||
extern const uint8_t PROGMEM _sysfont_var[]; ///< System variable pitch font table
|
||||
|
||||
/**
|
||||
\page pageHardware Hardware
|
||||
Supported Hardware
|
||||
------------------
|
||||
This library supports the Parola hardware and the more commonly available LED modules available
|
||||
from many other sources. The circuits for these modules are essentially identical except
|
||||
in the way that the LED matrix is wired to the MAX7219 IC. This difference is accounted for in
|
||||
software when the type of module is selected using the appropriate USE_*_HW compile time switch.
|
||||
|
||||
Hardware supported
|
||||
------------------
|
||||
- \subpage pageParola
|
||||
- \subpage pageGeneric
|
||||
- \subpage pageICStation
|
||||
- \subpage pageFC16
|
||||
- \subpage pageNewHardware
|
||||
|
||||
Connecting Multiple Modules
|
||||
---------------------------
|
||||
Separate modules are connected by the plugging them together edge to edge, with the
|
||||
OUT side of one module plugged to the IN side of the next. More details can be found
|
||||
at the end of each module's hardware section.
|
||||
___
|
||||
|
||||
\page pageParola Parola Custom Module
|
||||
The Parola Module
|
||||
-----------------
|
||||
These custome modules allow a 'lego-like' approach to LED matrix display, using standard 8x8 on
|
||||
LED matrices. The software supports this flexibility through a scalable approach that
|
||||
only requires the definition of the number of modules to adapt existing software to
|
||||
a new configuration.
|
||||
|
||||
![Completed Parola module with and without the LED matrix] (PCB_Actual.jpg "Parola Custom Modules")
|
||||
|
||||
Circuit Schematic
|
||||
-----------------
|
||||
The schematic is the basic application circuit that is found on the MAX7219 datasheet,
|
||||
adapted to the LED matrix. Each Module consists of an 8x8 LED matrix controlled by a
|
||||
MAX7219 LED controller and a few passive components. These controllers can be daisy
|
||||
chained, making them ideal for the purpose.
|
||||
|
||||
![Parola Circuit Schematic] (Circuit_Schematic.jpg "Parola Schematic")
|
||||
|
||||
The PCB design was executed using the autorouting facility in Eagle CAD, and the PCB was
|
||||
manufactured by SeeedStudio. The Eagle CAD files for the layout and the Gerber files
|
||||
suitable for SeeedStudio are found on the [Parola website] (https://github.com/MajicDesigns/MD_Parola).
|
||||
The final design includes edge connections that allow many modules to be connected
|
||||
together into an extended display, one LED module high.
|
||||
|
||||
![PCB layout ready for manufacture] (PCB_Layout.jpg "PCB Design")
|
||||
|
||||
Wiring your own Parola standard matrix
|
||||
--------------------------------------
|
||||
How the LED matrix is wired is important for the library. The matrix used for library
|
||||
development was labelled 1088B and is sometime referred to as a **common anode** matrix.
|
||||
Connections should be made as described in the table below to be consistent with the
|
||||
assumptions in the software library.
|
||||
- Columns are addressed through the segment selection lines
|
||||
- Rows are addressed through the digit selection lines
|
||||
|
||||
MAX Signal|MAX7219 Pin|MAX Signal|MAX7219 Pin|
|
||||
:--------:|----------:|:--------:|----------:|
|
||||
Dig0 (D0) |2 |SegDP |22 |
|
||||
Dig1 (D1) |11 |SegA |14 |
|
||||
Dig2 (D2) |6 |SegB |16 |
|
||||
Dig3 (D3) |7 |SegC |20 |
|
||||
Dig4 (D4) |3 |SegD |23 |
|
||||
Dig5 (D5) |10 |SegE |21 |
|
||||
Dig6 (D6) |5 |SegF |15 |
|
||||
Dig7 (D7) |8 |SegG |17 |
|
||||
|
||||
Segment data is packed on a per-digit basis, with segment G as the least significant bit (bit 0)
|
||||
through to A as bit 6 and DP as bit 7.
|
||||
____
|
||||
|
||||
Module Orientation
|
||||
------------------
|
||||
|
||||
G F E D C B A DP
|
||||
+------------------------+
|
||||
| 7 6 5 4 3 2 1 0 | DIG0
|
||||
| 1 | DIG1
|
||||
| 2 | DIG2
|
||||
| 3 | DIG3
|
||||
| O 4 | DIG4
|
||||
| O O 5 | DIG5
|
||||
| O O O 6 | DIG6
|
||||
| O O O O 7 | DIG7
|
||||
+------------------------+
|
||||
Vcc ---- ---- Vcc
|
||||
DOUT <--- ---< DIN
|
||||
GND ---- ---- GND
|
||||
CS/LD <--- ---< CS/LD
|
||||
CLK <--- ---< CLK
|
||||
|
||||
____
|
||||
|
||||
Module Interconnections
|
||||
-----------------------
|
||||
Parola modules are connected by plugging them together.
|
||||
![Connecting Parola modules] (Modules_conn.jpg "Parola Modules connected")
|
||||
____
|
||||
|
||||
\page pageGeneric Generic Module
|
||||
Generic MAX7219 Module
|
||||
------------------------
|
||||
These modules are commonly available from many suppliers (eg, eBay) at reasonable cost.
|
||||
They are characterized by IN and OUT connectors at the short ends of the rectangular PCB.
|
||||
|
||||
![Generic Module] (Generic_Module.png "Generic Module")
|
||||
____
|
||||
|
||||
Module Orientation
|
||||
------------------
|
||||
|
||||
C C D G V
|
||||
L S I N c
|
||||
K N D c
|
||||
| | | | |
|
||||
V V V | |
|
||||
D7 D6 D5 D4 D3 D2 D1 D0
|
||||
+------------------------+
|
||||
| 7 6 5 4 3 2 1 0 |- DP
|
||||
| 1 |- A
|
||||
| 2 |- B
|
||||
| 3 |- C
|
||||
| O 4 |- D
|
||||
| O O 5 |- E
|
||||
| O O O 6 |- F
|
||||
| O O O O 7 |- G
|
||||
+-----+--+--+--+--+------+
|
||||
| | | | |
|
||||
V V V | |
|
||||
|
||||
C C D G V
|
||||
L S O N c
|
||||
K U D c
|
||||
T
|
||||
|
||||
____
|
||||
|
||||
Module Interconnections
|
||||
-----------------------
|
||||
Generic modules need to be oriented with the MAX7219 IC at the top and connected using
|
||||
short patch cables in a spiral pattern. The display is oriented with the IC at the top.
|
||||
![Connecting Generic modules] (Generic_conn.jpg "Generic Modules connected")
|
||||
____
|
||||
|
||||
\page pageICStation ICStation Module
|
||||
ICStation DIY Kit Module
|
||||
------------------------
|
||||
These modules are available as kits from ICStation (http://www.icstation.com/product_info.php?products_id=2609#.UxqVJyxWGHs).
|
||||
|
||||
![ICStation Module] (ICStation_Module.jpg "ICStation Module")
|
||||
____
|
||||
|
||||
Module Orientation
|
||||
------------------
|
||||
|
||||
G F E D C B A DP
|
||||
+------------------------+
|
||||
| 7 6 5 4 3 2 1 0 | D7
|
||||
CLK <---| 1 | D6 <--- CLK
|
||||
CS <---| 2 | D5 <--- CS
|
||||
DOUT <---| 3 | D4 <--- DIN
|
||||
GND ----| O 4 | D3 ---- GND
|
||||
VCC ----| O O 5 | D2 ---- VCC
|
||||
| O O O 6 | D1
|
||||
| O O O O 7 | D0
|
||||
+------------------------+
|
||||
____
|
||||
|
||||
Module Interconnections
|
||||
-----------------------
|
||||
ICStation Modules are connected using the links supplied with the hardware. The display is
|
||||
oriented with the DIN side on the right.
|
||||
|
||||
![Connecting ICStation modules] (ICStation_conn.jpg "ICStation Modules connected")
|
||||
|
||||
____
|
||||
\page pageFC16 FC-16 Module
|
||||
FC-16 DIY Kit Module
|
||||
----------------------
|
||||
These modules are available as kits from some internet suppliers such as G&C Supermarket on eBay
|
||||
(http://stores.ebay.com.au/gcsupermarkethkcoltd/). They are identifiable by the FC-16 designation
|
||||
silkscreened on the PCB. Most of the available sets of 4 modules connected as one unit are
|
||||
FC-16 type.
|
||||
|
||||
![FC-16 Module] (FC-16_Module.jpg "FC-16 Module")
|
||||
____
|
||||
|
||||
Module Orientation
|
||||
------------------
|
||||
|
||||
DP A B C D E F G
|
||||
+------------------------+
|
||||
| 7 6 5 4 3 2 1 0 | D0
|
||||
CLK <---| 1 | D1 <--- CLK
|
||||
CS <---| 2 | D2 <--- CS
|
||||
DOUT <---| 3 | D3 <--- DIN
|
||||
GND ----| O 4 | D4 ---- GND
|
||||
VCC ----| O O 5 | D5 ---- VCC
|
||||
| O O O 6 | D6
|
||||
| O O O O 7 | D7
|
||||
+------------------------+
|
||||
____
|
||||
|
||||
Module Interconnections
|
||||
-----------------------
|
||||
FC-16 Modules are connected using the links supplied with the hardware. The display is
|
||||
oriented with the DIN side on the right. PCB text may appear upside down.
|
||||
|
||||
![Connecting FC-16 modules] (FC-16_conn.jpg "FC-16 Modules connected")
|
||||
|
||||
____
|
||||
\page pageNewHardware New Hardware Types
|
||||
A word on coordinate systems
|
||||
----------------------------
|
||||
|
||||
Two Cartesian coordinate systems are used in the library
|
||||
- one defines the pixels seen (_display coordinates_), and
|
||||
- an underlying _hardware coordinate_ system based on digits and segments
|
||||
mapping to the MAX72xx hardware control registers.
|
||||
|
||||
Display coordinates always have their origin in the top right corner of a display.
|
||||
- Column numbers increase to the left (as do module numbers)
|
||||
- Row numbers increase down (0..7)
|
||||
|
||||
All user functions are consistent and use display coordinates.
|
||||
|
||||
Display memory buffers are stored in hardware coordinates that depend on
|
||||
the hardware configuration (i.e. the module type). It is the job of the low level
|
||||
library functions to map display to hardware coordinates. Digit 0 is the lowest
|
||||
row/column number and Segment G is the lowest column/row number.
|
||||
|
||||
All the code to do this is in the is in the buffer and pixel modules.
|
||||
All other library modules are use the primitives made available in these modules.
|
||||
|
||||
What needs to change?
|
||||
---------------------
|
||||
|
||||
As there is no standard way of wiring a LED matrix to the MAX72xx IC, each hardware type
|
||||
definition activates a series of coordinate mapping transformations. Possible changes
|
||||
are limited to combinations (8 in total) of
|
||||
- swapping rows and column coordinates (digits and segments in MAX72xx),
|
||||
- a reversal of row indices, and
|
||||
- a reversal of column indices.
|
||||
|
||||
The hardware types defined in MD_MAX72xx.h activate different library code by defining
|
||||
appropriate values for the defines listed below, in the MD_MAX72xx_lib.h file.
|
||||
|
||||
- HW_DIG_ROWS - MAX72xx digits are mapped to rows in on the matrix. If digits are
|
||||
not rows then they are columns!
|
||||
|
||||
- HW_REV_COLS - Normal column coordinates orientation is 0 col on the right side
|
||||
of the display. Set to 1 to reverse this (0 on the left).
|
||||
|
||||
- HW_REV_ROWS - Normal row coordinates orientation is 0 row at top of the display.
|
||||
Set to 1 to reverse this (0 at the bottom).
|
||||
|
||||
Determining the type of mapping
|
||||
-------------------------------
|
||||
The library example code includes a utility called MD_MAX72xx_HW_Mapper.
|
||||
This is test software to map display hardware rows and columns. It uses a
|
||||
generic SPI interface and only one MAX72xx/8x8 LED module required. It is
|
||||
independent of the libraries as the code is used to directly map the display
|
||||
orientation by setting pixels on the display and printing to the serial monitor
|
||||
which MAX72xx hardware component (segment and digit) is being exercised.
|
||||
|
||||
By observing the LED display and the serial monitor you can build a map like the
|
||||
one below. It is worth noting the direction in which the rows and columns are
|
||||
scanned by the utility, as this is the easiest way to work out the row/column
|
||||
reversal values.
|
||||
|
||||
The result of these observations is a grid definition that looks somewhat like:
|
||||
|
||||
DIG0 D1 D2 D3 D4 D5 D6 D7
|
||||
Seg G
|
||||
Seg F
|
||||
Seg E
|
||||
Seg D
|
||||
Seg C
|
||||
Seg B
|
||||
Seg A
|
||||
Seg DP
|
||||
|
||||
From this mapping it is clear
|
||||
- MAX72xx digits map to the columns, HW_DIG_ROWS is 0.
|
||||
- DIG0 is on the left (columns were also scanned left to right), so HW_REV_COLS should be set
|
||||
to 1 to reverse it to the standard 0 on the right.
|
||||
- Seg G is at the top (rows were also top to bottom), so HW_REV_ROWS should be set to 0,
|
||||
as it is already standard with 0 on top.
|
||||
|
||||
Note that in some situations using the module 'upside down' will result in a better configuration
|
||||
than would otherwise be the case. An example of this is the generic module mapping. Also remember
|
||||
that the modules are daisy chained from right to left.
|
||||
|
||||
Having determined the values for the defines, the new mapping can be configured, or matched to
|
||||
an existing hardware type.
|
||||
___
|
||||
|
||||
\page pageFontUtility Create and Modify Fonts
|
||||
|
||||
Font Storage Format
|
||||
-------------------
|
||||
One default font is defined as part of the library in PROGMEM memory. Alternative fonts
|
||||
can be specified to the library. The font builder utilities provide a convenient way to
|
||||
modify existing or develop alternative fonts.
|
||||
|
||||
Fonts are stored as a series of contiguous bytes in the following format:
|
||||
- byte 1 - the number of bytes that form this character (could be zero)
|
||||
- byte 2..n - each byte is a column of the character to be formed, starting with the
|
||||
leftmost column of the character. The least significant bit of the byte is the bottom
|
||||
pixel position of the character matrix (row 7).
|
||||
|
||||
To find a character in the font table, the library looks at the first byte (size),
|
||||
skips 'size'+1 bytes to the next character size byte and repeat until the last or
|
||||
target character is reached.
|
||||
|
||||
The compile-time switch USE_INDEX_FONT enables indexing of the font table for faster access, at
|
||||
the expense of increased RAM usage. If indexing is enabled, a single lookup is required to
|
||||
access the character data, rather than the sequential search described above.
|
||||
|
||||
The support for fonts (methods and data) may be completely disabled if not required through
|
||||
the compile-time switch USE_LOCAL_FONT. This will also disable user defined fonts.
|
||||
|
||||
____
|
||||
|
||||
The txt2font Utility
|
||||
--------------------
|
||||
The txt2font utility is a command line application that converts a text definition of the font
|
||||
into a data file in the right format for MD_MAX72xx to use.
|
||||
|
||||
This utility is as an Win32 executable. Users with other Operating Systems will need to compile
|
||||
a version to work with their OS, using the source code supplied.
|
||||
|
||||
The application is invoked from the command line and only the root name of the file is given as a command
|
||||
line parameter (eg "txt2font fred"). The application will look for and input file with a '.txt' extension
|
||||
(fred.txt) and produce an output file with a '.h' extension (fred.h).
|
||||
|
||||
The txt2font file format is line based. Lines starting with a '.' are directives for the application, all
|
||||
other lines are data for the current character defintion. An example of the beginning of a font
|
||||
definition file is shown below.
|
||||
|
||||
.NAME sys_var_single
|
||||
.HEIGHT 1
|
||||
.WIDTH 0
|
||||
.CHAR 0
|
||||
.NOTE 'Empty Cell'
|
||||
.CHAR 1
|
||||
.NOTE 'Sad Smiley'
|
||||
@@@
|
||||
@@@@@
|
||||
@ @ @
|
||||
@@@@@
|
||||
@@ @@
|
||||
@ @
|
||||
@@@
|
||||
.CHAR 2
|
||||
.NOTE 'Happy Smiley'
|
||||
***
|
||||
|
||||
The directives have the following meaning:
|
||||
- .NAME defines the name for the font and is used in naming the font table variable.
|
||||
The name can appear anywhere in the file. If omitted, a default name is used.
|
||||
- .HEIGHT defines the height for the font. Single height fonts are '1' and double height fonts are '2'.
|
||||
If double height fonts are specified then the range of ASCII character values is restricted to 0..127 as
|
||||
the top and botton halves of the font are stored offset by 128 positions. If omitted, the application
|
||||
assumes single height font.
|
||||
- .WIDTH specifies the width of the font for all the characters defined between this WIDTH and the
|
||||
next WIDTH defintion. 0 means variable width; any other number defines the fixed width. WIDTH may be changed
|
||||
within the file - for example to define a fixed size space (no pixels!) character in a variable width font.
|
||||
- .CHAR ends the defintion of the current character and starts the defintion for the specified ASCII value.
|
||||
Valid parameters are [0..255] for single height, and [0..127] for double height. If a character code is
|
||||
omitted in the font definition file it is assumed to be empty.
|
||||
- .NOTE is an option note that will be added as a comment for the entry in the font data table.
|
||||
|
||||
Any lines not starting with a '.' are data lines for the current character. The font characters are drawn
|
||||
using a non-space character (eg, '*' or '@') wherever a LED needs to be 'on'. The application scans from
|
||||
the top down, so any lines missing at the bottom of the character definition are assumed to be blank.
|
||||
However, blank lines at the top need to be shown. Any extra rows are ignored will cause program errors.
|
||||
|
||||
A number of font definition files are supplied as examples.
|
||||
___
|
||||
|
||||
The FontBuilder Excel/VBA application
|
||||
-------------------------------------
|
||||
FontBuilder is a Microsoft Excel spreadsheet with VBA macros to manage a GUI interface for defining
|
||||
and managing font characters. FontBuilder supports both single and double height fonts. The first tab
|
||||
in the FontBuilder spreadsheet has instructions for use.
|
||||
|
||||
As FontBuilder requires using Microsoft Office products, it does not work environments where
|
||||
these are not available.
|
||||
|
||||
*/
|
||||
|
||||
// *******************************************************************************************
|
||||
// ** Combinations not listed here have probably not been tested and may not work correctly **
|
||||
// *******************************************************************************************
|
||||
#if USE_PAROLA_HW // tested MC 8 March 2014
|
||||
//#pragma message "PAROLA HW selected"
|
||||
#define HW_DIG_ROWS 1 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 1 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 0 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#if USE_GENERIC_HW // tested MC 9 March 2014
|
||||
//#pragma message "GENERIC HW selected"
|
||||
#define HW_DIG_ROWS 0 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 1 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 0 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#if USE_ICSTATION_HW // tested MC 9 March 2014
|
||||
//#pragma message "ICSTATION HW selected"
|
||||
#define HW_DIG_ROWS 1 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 1 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 1 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#if USE_FC16_HW // tested MC 23 Feb 2015
|
||||
//#pragma message "FC16 HW selected"
|
||||
#define HW_DIG_ROWS 1 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 0 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 0 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#if USE_OTHER_HW // user defined custom hardware configuration
|
||||
//#pragma message "OTHER HW selected"
|
||||
#define HW_DIG_ROWS 0 ///< MAX72xx digits are mapped to rows in on the matrix
|
||||
#define HW_REV_COLS 0 ///< Normal orientation is col 0 on the right. Set to 1 if reversed
|
||||
#define HW_REV_ROWS 0 ///< Normal orientation is row 0 at the top. Set to 1 if reversed
|
||||
#endif
|
||||
|
||||
#ifndef HW_DIG_ROWS
|
||||
#error "INVALID or missing hardware selected"
|
||||
#endif
|
||||
|
||||
// Macros to map ROW and COLUMN coordinates
|
||||
#if HW_REV_ROWS
|
||||
#define HW_ROW(r) (7-r) ///< Pixel to hardware coordinate row mapping
|
||||
#else
|
||||
#define HW_ROW(r) (r) ///< Pixel to hardware coordinate row mapping
|
||||
#endif
|
||||
|
||||
#if HW_REV_COLS
|
||||
#define HW_COL(c) (7-c) ///< Pixel to hardware coordinate column mapping
|
||||
#else
|
||||
#define HW_COL(c) (c) ///< Pixel to hardware coordinate column mapping
|
||||
#endif
|
||||
|
||||
#endif
|
||||
284
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_pix.cpp
Normal file
284
arduino-cli/libraries/MD_MAX72XX/src/MD_MAX72xx_pix.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
MD_MAX72xx - Library for using a MAX7219/7221 LED matrix controller
|
||||
|
||||
See header file for comments
|
||||
|
||||
This file contains methods that act on the matrix as a pixel field,
|
||||
generally only acting on the visible device range of the buffered
|
||||
device field (ie, the physical pixel matrix).
|
||||
|
||||
Copyright (C) 2012-14 Marco Colli. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "MD_MAX72xx.h"
|
||||
#include "MD_MAX72xx_lib.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
* \brief Implements pixel related methods
|
||||
*/
|
||||
|
||||
void MD_MAX72XX::clear(uint8_t startDev, uint8_t endDev)
|
||||
{
|
||||
if (endDev < startDev) return;
|
||||
|
||||
for (uint8_t buf = startDev; buf <= endDev; buf++)
|
||||
{
|
||||
memset(_matrix[buf].dig, 0, sizeof(_matrix[buf].dig));
|
||||
_matrix[buf].changed = ALL_CHANGED;
|
||||
}
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::getBuffer(uint16_t col, uint8_t size, uint8_t *pd)
|
||||
{
|
||||
if ((col >= getColumnCount()) || (pd == NULL))
|
||||
return(false);
|
||||
|
||||
for (uint8_t i=0; i<size; i++)
|
||||
*pd++ = getColumn(col--);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::setBuffer(uint16_t col, uint8_t size, uint8_t *pd)
|
||||
{
|
||||
bool b = _updateEnabled;
|
||||
|
||||
if ((col >= getColumnCount()) || (pd == NULL))
|
||||
return(false);
|
||||
|
||||
_updateEnabled = false;
|
||||
for (uint8_t i=0; i<size; i++)
|
||||
setColumn(col--, *pd++);
|
||||
_updateEnabled = b;
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::drawLine(uint8_t r1, uint16_t c1, uint8_t r2, uint16_t c2, bool state)
|
||||
// draw a line between two points using Bresentham's line algorithm
|
||||
{
|
||||
if (r1 >= ROW_SIZE || r2 >= ROW_SIZE || c1 >= (COL_SIZE*_maxDevices) || c2 >= (COL_SIZE*_maxDevices))
|
||||
return(false);
|
||||
|
||||
if (c1 > c2)
|
||||
{
|
||||
uint16_t t;
|
||||
t = c1; c1 = c2; c2 = t; // swap c1/c2
|
||||
t = r1; r1 = r2; r2 = t; // swap r1/r2
|
||||
}
|
||||
|
||||
// Bresentham's line algorithm
|
||||
int16_t dc = abs(c2-c1);
|
||||
int16_t sc = c1<c2 ? 1 : -1;
|
||||
int16_t dr = abs(r2-r1);
|
||||
int16_t sr = r1<r2 ? 1 : -1;
|
||||
int16_t err = (dc>dr ? dc : -dr)/2;
|
||||
int16_t e2;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
setPoint(r1, c1, state);
|
||||
if (c1 == c2 && r1 == r2) break;
|
||||
e2 = err;
|
||||
if (e2 >-dc) { err -= dr; c1 += sc; }
|
||||
if (e2 < dr) { err += dc; r1 += sr; }
|
||||
}
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
// used in getPoint and setPoint!
|
||||
#if HW_DIG_ROWS
|
||||
#define R r
|
||||
#define C c
|
||||
#else
|
||||
#define R c
|
||||
#define C r
|
||||
#endif
|
||||
|
||||
bool MD_MAX72XX::getPoint(uint8_t r, uint16_t c)
|
||||
{
|
||||
uint8_t buf = c/COL_SIZE;
|
||||
|
||||
c %= COL_SIZE;
|
||||
PRINT("\ngetPoint: (", buf);
|
||||
PRINT(", ", r);
|
||||
PRINT(", ", c);
|
||||
PRINTS(")");
|
||||
|
||||
if ((buf > LAST_BUFFER) || (r >= ROW_SIZE) || (c >= COL_SIZE))
|
||||
return(false);
|
||||
|
||||
return(bitRead(_matrix[buf].dig[HW_ROW(R)], HW_COL(C)) == 1);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::setPoint(uint8_t r, uint16_t c, bool state)
|
||||
{
|
||||
uint8_t buf = c/COL_SIZE;
|
||||
c %= COL_SIZE;
|
||||
|
||||
PRINT("\nsetPoint: (", buf);
|
||||
PRINT(", ", r);
|
||||
PRINT(", ", c);
|
||||
PRINT(") = ", state?1:0);
|
||||
|
||||
if ((buf > LAST_BUFFER) || (r >= ROW_SIZE) || (c >= COL_SIZE))
|
||||
return(false);
|
||||
|
||||
if (state)
|
||||
bitSet(_matrix[buf].dig[HW_ROW(R)], HW_COL(C));
|
||||
else
|
||||
bitClear(_matrix[buf].dig[HW_ROW(R)], HW_COL(C));
|
||||
|
||||
bitSet(_matrix[buf].changed, HW_ROW(R));
|
||||
|
||||
if (_updateEnabled) flushBuffer(buf);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
#undef R
|
||||
#undef C
|
||||
|
||||
bool MD_MAX72XX::setRow(uint8_t startDev, uint8_t endDev, uint8_t r, uint8_t value)
|
||||
{
|
||||
bool b = _updateEnabled;
|
||||
|
||||
PRINT("\nsetRow: ", r);
|
||||
|
||||
if ((r >= ROW_SIZE) || (endDev < startDev))
|
||||
return(false);
|
||||
|
||||
_updateEnabled = false;
|
||||
for (uint8_t i = startDev; i <= endDev; i++)
|
||||
setRow(i, r, value);
|
||||
_updateEnabled = b;
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool MD_MAX72XX::transform(uint8_t startDev, uint8_t endDev, transformType_t ttype)
|
||||
{
|
||||
// uint8_t t[ROW_SIZE];
|
||||
uint8_t colData;
|
||||
bool b = _updateEnabled;
|
||||
|
||||
if (endDev < startDev) return(false);
|
||||
|
||||
_updateEnabled = false;
|
||||
|
||||
switch (ttype)
|
||||
{
|
||||
case TSL: // Transform Shift Left one pixel element (with overflow)
|
||||
colData = 0;
|
||||
// if we can call the user function later then we don't need to do anything here
|
||||
// however, warparound mode means we know the data so no need to request from the
|
||||
// callback at all - just save it for later
|
||||
if (_wrapAround)
|
||||
colData = getColumn(((endDev+1)*COL_SIZE)-1);
|
||||
else if (_cbShiftDataOut != NULL)
|
||||
(*_cbShiftDataOut)(endDev, ttype, getColumn(((endDev+1)*COL_SIZE)-1));
|
||||
|
||||
// shift all the buffers along
|
||||
for (int8_t buf = endDev; buf >= startDev; --buf)
|
||||
{
|
||||
transformBuffer(buf, ttype);
|
||||
// handle the boundary condition
|
||||
setColumn(buf, 0, getColumn(buf-1, COL_SIZE-1));
|
||||
}
|
||||
|
||||
// if we have a callback function, now is the time to get the data if we are
|
||||
// not in wraparound mode
|
||||
if (_cbShiftDataIn != NULL && !_wrapAround)
|
||||
colData = (*_cbShiftDataIn)(startDev, ttype);
|
||||
|
||||
setColumn((startDev*COL_SIZE), colData);
|
||||
break;
|
||||
|
||||
|
||||
case TSR: // Transform Shift Right one pixel element (with overflow)
|
||||
// if we can call the user function later then we don't need to do anything here
|
||||
// however, warparound mode means we know the data so no need to request from the
|
||||
// callback at all - just save it for later.
|
||||
colData = 0;
|
||||
if (_wrapAround)
|
||||
colData = getColumn(startDev*COL_SIZE);
|
||||
else if (_cbShiftDataOut != NULL)
|
||||
(*_cbShiftDataOut)(startDev, ttype, getColumn((startDev*COL_SIZE)));
|
||||
|
||||
// shift all the buffers along
|
||||
for (uint8_t buf=startDev; buf<=endDev; buf++)
|
||||
{
|
||||
transformBuffer(buf, ttype);
|
||||
|
||||
// handle the boundary condition
|
||||
setColumn(buf, COL_SIZE-1, getColumn(buf+1, 0));
|
||||
}
|
||||
|
||||
// if we have a callback function, now is the time to get the data if we are
|
||||
// not in wraparound mode
|
||||
if (_cbShiftDataIn != NULL && !_wrapAround)
|
||||
colData = (*_cbShiftDataIn)(endDev, ttype);
|
||||
|
||||
setColumn(((endDev+1)*COL_SIZE)-1, colData);
|
||||
break;
|
||||
|
||||
case TFLR: // Transform Flip Left to Right (use the whole field)
|
||||
// first reverse the device buffers end for end
|
||||
for (uint8_t buf = 0; buf < (endDev - startDev)/2; buf++)
|
||||
{
|
||||
deviceInfo_t t;
|
||||
|
||||
t = _matrix[startDev + buf];
|
||||
_matrix[startDev + buf] = _matrix[endDev - buf];
|
||||
_matrix[endDev - buf] = t;
|
||||
}
|
||||
|
||||
// now reverse the columns in each device
|
||||
for (uint8_t buf = startDev; buf <= endDev; buf++)
|
||||
transformBuffer(buf, ttype);
|
||||
break;
|
||||
|
||||
// These next transformation work the same just by doing the individual devices
|
||||
case TSU: // Transform Shift Up one pixel element
|
||||
case TSD: // Transform Shift Down one pixel element
|
||||
case TFUD: // Transform Flip Up to Down
|
||||
case TRC: // Transform Rotate Clockwise
|
||||
case TINV: // Transform INVert
|
||||
for (uint8_t buf = startDev; buf <= endDev; buf++)
|
||||
transformBuffer(buf, ttype);
|
||||
break;
|
||||
|
||||
default:
|
||||
return(false);
|
||||
}
|
||||
|
||||
_updateEnabled = b;
|
||||
|
||||
if (_updateEnabled) flushBufferAll();
|
||||
|
||||
return(true);
|
||||
}
|
||||
Reference in New Issue
Block a user