Arduboy2/src/Arduboy2Core.h

522 lines
18 KiB
C
Raw Normal View History

2016-11-21 21:31:10 +00:00
/**
* @file Arduboy2Core.h
* \brief
* The Arduboy2Core class for Arduboy hardware initilization and control.
*/
#ifndef ARDUBOY2_CORE_H
#define ARDUBOY2_CORE_H
#include <Arduino.h>
#include <avr/power.h>
#include <SPI.h>
#include <avr/sleep.h>
#include <limits.h>
// main hardware compile flags
#if !defined(ARDUBOY_10) && !defined(AB_DEVKIT)
2016-11-21 21:31:10 +00:00
/* defaults to Arduboy Release 1.0 if not using a boards.txt file
*
* we default to Arduboy Release 1.0 if a compile flag has not been
* passed to us from a boards.txt file
*
* if you wish to compile for the devkit without using a boards.txt
* file simply comment out the ARDUBOY_10 define and uncomment
* the AB_DEVKIT define like this:
*
* // #define ARDUBOY_10
* #define AB_DEVKIT
2016-02-21 06:38:49 +00:00
*/
#define ARDUBOY_10 //< compile for the production Arduboy v1.0
// #define AB_DEVKIT //< compile for the official dev kit
#endif
#ifdef AB_DEVKIT
#define SAFE_MODE //< include safe mode (44 bytes)
2016-02-21 06:38:49 +00:00
#endif
2016-11-21 21:31:10 +00:00
#define RGB_ON LOW /**< For digitially setting an RGB LED on using digitalWriteRGB() */
#define RGB_OFF HIGH /**< For digitially setting an RGB LED off using digitalWriteRGB() */
#ifdef ARDUBOY_10
#define CS 12
#define DC 4
#define RST 6
2016-11-21 21:31:10 +00:00
#define RED_LED 10 /**< The pin number for the red color in the RGB LED. */
#define GREEN_LED 11 /**< The pin number for the greem color in the RGB LED. */
#define BLUE_LED 9 /**< The pin number for the blue color in the RGB LED. */
#define TX_LED 30 /**< The pin number for the transmit indicator LED. */
#define RX_LED 17 /**< The pin number for the receive indicator LED. */
// pin values for buttons, probably shouldn't use these
#define PIN_LEFT_BUTTON A2
#define PIN_RIGHT_BUTTON A1
#define PIN_UP_BUTTON A0
#define PIN_DOWN_BUTTON A3
#define PIN_A_BUTTON 7
#define PIN_B_BUTTON 8
// bit values for button states
2016-11-21 21:31:10 +00:00
#define LEFT_BUTTON _BV(5) /**< The Left button value for functions requiring a bitmask */
#define RIGHT_BUTTON _BV(6) /**< The Right button value for functions requiring a bitmask */
#define UP_BUTTON _BV(7) /**< The Up button value for functions requiring a bitmask */
#define DOWN_BUTTON _BV(4) /**< The Down button value for functions requiring a bitmask */
#define A_BUTTON _BV(3) /**< The A button value for functions requiring a bitmask */
#define B_BUTTON _BV(2) /**< The B button value for functions requiring a bitmask */
2016-11-21 21:31:10 +00:00
#define PIN_SPEAKER_1 5 /**< The pin number of the first lead of the speaker */
#define PIN_SPEAKER_2 13 /**< The pin number of the second lead of the speaker */
#define PIN_SPEAKER_1_PORT &PORTC
#define PIN_SPEAKER_2_PORT &PORTC
#define PIN_SPEAKER_1_BITMASK _BV(6)
#define PIN_SPEAKER_2_BITMASK _BV(7)
#elif defined(AB_DEVKIT)
#define CS 6
#define DC 4
#define RST 12
// map all LEDs to the single TX LED on DEVKIT
#define RED_LED 17
#define GREEN_LED 17
#define BLUE_LED 17
#define TX_LED 17
#define RX_LED 17
// pin values for buttons, probably shouldn't use these
#define PIN_LEFT_BUTTON 9
#define PIN_RIGHT_BUTTON 5
#define PIN_UP_BUTTON 8
#define PIN_DOWN_BUTTON 10
#define PIN_A_BUTTON A0
#define PIN_B_BUTTON A1
// bit values for button states
#define LEFT_BUTTON _BV(5)
#define RIGHT_BUTTON _BV(2)
#define UP_BUTTON _BV(4)
#define DOWN_BUTTON _BV(6)
#define A_BUTTON _BV(1)
#define B_BUTTON _BV(0)
#define PIN_SPEAKER_1 A2
#define PIN_SPEAKER_1_PORT &PORTF
#define PIN_SPEAKER_1_BITMASK _BV(5)
// SPEAKER_2 is purposely not defined for DEVKIT as it could potentially
// be dangerous and fry your hardware (because of the devkit wiring).
//
// Reference: https://github.com/Arduboy/Arduboy/issues/108
#endif
// OLED hardware (SSD1306)
#define OLED_PIXELS_INVERTED 0xA7 // All pixels inverted
#define OLED_PIXELS_NORMAL 0xA6 // All pixels normal
#define OLED_ALL_PIXELS_ON 0xA5 // all pixels on
#define OLED_PIXELS_FROM_RAM 0xA4 // pixels mapped to display RAM contents
#define OLED_VERTICAL_FLIPPED 0xC0 // reversed COM scan direction
#define OLED_VERTICAL_NORMAL 0xC8 // normal COM scan direction
#define OLED_HORIZ_FLIPPED 0xA0 // reversed segment re-map
#define OLED_HORIZ_NORMAL 0xA1 // normal segment re-map
// -----
2016-11-21 21:31:10 +00:00
#define WIDTH 128 /**< The width of the display in pixels */
#define HEIGHT 64 /**< The height of the display in pixels */
#define COLUMN_ADDRESS_END (WIDTH - 1) & 127 // 128 pixels wide
#define PAGE_ADDRESS_END ((HEIGHT/8)-1) & 7 // 8 pages high
2016-11-21 21:31:10 +00:00
/** \brief
* Lower level functions generally dealing directly with the hardware.
*
* \details
* This class is inherited by Arduboy2Base and thus also Arduboy2, so wouldn't
* normally be used directly by a sketch.
*/
class Arduboy2Core
{
public:
Arduboy2Core();
2016-11-21 21:31:10 +00:00
/** \brief
* Idle the CPU to save power.
*
* \details
* This puts the CPU in _idle_ sleep mode. You should call this as often
* as you can for the best power savings. The timer 0 overflow interrupt
* will wake up the chip every 1ms, so even at 60 FPS a well written
* app should be able to sleep maybe half the time in between rendering
* it's own frames.
*/
void static idle();
2016-11-21 21:31:10 +00:00
/** \brief
* Put the display into data mode.
*
* \details
* When placed in data mode, data that is sent to the display will be
* considered as data to be displayed.
*
* \note
* This is a low level function that is not intended for general use in a
* sketch. It has been made public and documented for use by derived
* classes.
*/
void static LCDDataMode();
2016-11-21 21:31:10 +00:00
/** \brief
* Put the display into command mode.
*
* \details
* When placed in command mode, data that is sent to the display will be
* treated as commands.
*
* See the SSD1306 controller and OLED display documents for available
* commands and command sequences.
2016-02-21 06:38:49 +00:00
*
* Links:
2016-11-21 21:31:10 +00:00
*
* - https://www.adafruit.com/datasheets/SSD1306.pdf
2016-11-21 21:31:10 +00:00
* - http://www.buydisplay.com/download/manual/ER-OLED013-1_Series_Datasheet.pdf
*
* \note
* This is a low level function that is not intended for general use in a
* sketch. It has been made public and documented for use by derived
* classes.
*
* \see sendLCDCommand()
*/
void static LCDCommandMode();
2016-11-21 21:31:10 +00:00
/** \brief
* Get the width of the display in pixels.
*
* \return The width of the display in pixels.
*
* \note
* In most cases, the defined value `WIDTH` would be better to use instead
* of this function.
2016-11-21 21:31:10 +00:00
*/
uint8_t static width();
2016-11-21 21:31:10 +00:00
/** \brief
* Get the height of the display in pixels.
*
2016-11-21 21:31:10 +00:00
* \return The height of the display in pixels.
2016-02-21 06:38:49 +00:00
*
2016-11-21 21:31:10 +00:00
* \note
* In most cases, the defined value `HEIGHT` would be better to use instead
* of this function.
*/
2016-11-21 21:31:10 +00:00
uint8_t static height();
2016-11-21 21:31:10 +00:00
/** \brief
* get current state of all buttons as a bitmask.
*
* \return A bitmask of the state of all the buttons.
*
* \details
* The returned mask contains a bit for each button. For any pressed button,
* its bit will be 1. For released buttons their associated bits will be 0.
*
* The following defined mask values should be used for the buttons:
*
* LEFT_BUTTON, RIGHT_BUTTON, UP_BUTTON, DOWN_BUTTON, A_BUTTON, B_BUTTON
*/
uint8_t static buttonsState();
2016-11-21 21:31:10 +00:00
/** \brief
* Paint 8 pixels vertically to the display.
*
* \param pixels A byte whose bits specify a vertical column of 8 pixels.
*
* \details
* A byte representing a vertical column of 8 pixels is written to the
* display at the current page and column address. The address is then
* incremented. The page/column address will wrap to the start of the
* display (the top left) when it increments past the end (lower right).
*
* The least significant bit represents the top pixel in the column.
* A bit set to 1 is lit, 0 is unlit.
*
* Example:
*
* X = lit pixels, . = unlit pixels
*
* blank() paint8Pixels() 0xFF, 0, 0xF0, 0, 0x0F
* v TOP LEFT corner (8x9) v TOP LEFT corner
* . . . . . . . . (page 1) X . . . X . . . (page 1)
* . . . . . . . . X . . . X . . .
* . . . . . . . . X . . . X . . .
* . . . . . . . . X . . . X . . .
* . . . . . . . . X . X . . . . .
* . . . . . . . . X . X . . . . .
* . . . . . . . . X . X . . . . .
* . . . . . . . . (end of page 1) X . X . . . . . (end of page 1)
* . . . . . . . . (page 2) . . . . . . . . (page 2)
*/
void static paint8Pixels(uint8_t pixels);
2016-11-21 21:31:10 +00:00
/** \brief
* Paints an entire image directly to the display from program memory.
*
* \param image A byte array in program memory representing the entire
* contents of the display.
*
* \details
* The contents of the specified array in program memory is written to the
* display. Each byte in the array represents a vertical column of 8 pixels
* with the least significant bit at the top. The bytes are written starting
* at the top left, progressing horizontally and wrapping at the end of each
* row, to the bottom right. The size of the array must exactly match the
* number of pixels in the entire display.
*
* \see paint8Pixels()
*/
void static paintScreen(const uint8_t *image);
2016-11-21 21:31:10 +00:00
/** \brief
* Paints an entire image directly to the display from an array in RAM.
*
* \param image A byte array in RAM representing the entire contents of
* the display.
* \param clear If `true` the array in RAM will be cleared to zeros upon
* return from this function. If `false` the RAM buffer will remain
* unchanged. (optional; defaults to `false`)
2016-11-21 21:31:10 +00:00
*
* \details
* The contents of the specified array in RAM is written to the display.
* Each byte in the array represents a vertical column of 8 pixels with
* the least significant bit at the top. The bytes are written starting
* at the top left, progressing horizontally and wrapping at the end of
* each row, to the bottom right. The size of the array must exactly
* match the number of pixels in the entire display.
*
* If parameter `clear` is set to `true` the RAM array will be cleared to
* zeros after its contents are written to the display.
*
2016-11-21 21:31:10 +00:00
* \see paint8Pixels()
*/
void static paintScreen(uint8_t image[], bool clear = false);
2016-11-21 21:31:10 +00:00
/** \brief
* Blank the display screen by setting all pixels off.
*
* \details
* All pixels on the screen will be written with a value of 0 to turn
* them off.
*/
void static blank();
2016-11-21 21:31:10 +00:00
/** \brief
* Invert the entire display or set it back to normal.
*
* \param inverse `true` will invert the display. `false` will set the
* display to no-inverted.
*
* Calling this function with a value of `true` will set the display to
* inverted mode. A pixel with a value of 0 will be on and a pixel set to 1
* will be off.
*
* Once in inverted mode, the display will remain this way
* until it is set back to non-inverted mode by calling this function with
* `false`.
*/
2016-03-30 22:58:12 +00:00
void static invert(bool inverse);
2016-11-21 21:31:10 +00:00
/** \brief
* Turn all display pixels on or display the buffer contents.
*
* \param on `true` turns all pixels on. `false` displays the contents
* of the hardware display buffer.
*
* \details
* Calling this function with a value of `true` will override the contents
* of the hardware display buffer and turn all pixels on. The contents of
* the hardware buffer will remain unchanged.
*
* Calling this function with a value of `false` will set the normal state
* of displaying the contents of the hardware display buffer.
*
* \note
* All pixels will be lit even if the display is in inverted mode.
*
* \see invert()
*/
2016-03-30 22:58:12 +00:00
void static allPixelsOn(bool on);
2016-11-21 21:31:10 +00:00
/** \brief
* Flip the display vertically or set it back to normal.
*
* \param flipped `true` will set vertical flip mode. `false` will set
* normal vertical orientation.
*
* \details
* Calling this function with a value of `true` will cause the Y coordinate
* to start at the bottom edge of the display instead of the top,
* effectively flipping the display vertically.
*
* Once in vertical flip mode, it will remain this way until normal
* vertical mode is set by calling this function with a value of `false`.
*
* \see flipHorizontal()
*/
2016-03-30 22:58:12 +00:00
void static flipVertical(bool flipped);
2016-11-21 21:31:10 +00:00
/** \brief
* Flip the display horizontally or set it back to normal.
*
* \param flipped `true` will set horizontal flip mode. `false` will set
* normal horizontal orientation.
*
* \details
* Calling this function with a value of `true` will cause the X coordinate
* to start at the left edge of the display instead of the right,
* effectively flipping the display horizontally.
*
* Once in horizontal flip mode, it will remain this way until normal
* horizontal mode is set by calling this function with a value of `false`.
*
* \see flipVertical()
*/
2016-03-30 22:58:12 +00:00
void static flipHorizontal(bool flipped);
2016-11-21 21:31:10 +00:00
/** \brief
* Send a single command byte to the display.
*
* \param command The command byte to send to the display.
*
* The display will be set to command mode then the specified command
* byte will be sent. The display will then be set to data mode.
* Multi-byte commands can be sent by calling this function multiple times.
*
* \note
* Sending improper commands to the display can place it into invalid or
* unexpected states, possibly even causing physical damage.
*/
void static sendLCDCommand(uint8_t command);
2016-11-21 21:31:10 +00:00
/** \brief
* Set the light output of the RGB LED.
*
* \param red,green,blue The brightness value for each LED.
*
* \details
* The RGB LED is actually individual red, green and blue LEDs placed
* very close together in a single package. By setting the brightness of
* each LED, the RGB LED can show various colors and intensities.
* The brightness of each LED can be set to a value from 0 (fully off)
* to 255 (fully on).
*
* \note
* Certain libraries that take control of the hardware timers may interfere
* with the ability of this function to properly control the RGB LED.
*_ArduboyPlaytune_ is one such library known to do this.
* The digitalWriteRGB() function will still work properly in this case.
*
* \note
* Many of the Kickstarter Arduboys were accidentally shipped with the
* RGB LED installed incorrectly. For these units, the green LED cannot be
* lit. As long as the green led is set to off, setting the red LED will
* actually control the blue LED and setting the blue LED will actually
* control the red LED. If the green LED is turned fully on, none of the
* LEDs will light.
*
* \see digitalWriteRGB()
*/
void static setRGBled(uint8_t red, uint8_t green, uint8_t blue);
2016-11-21 21:31:10 +00:00
/** \brief
* Set the RGB LEDs digitally, to either fully on or fully off.
*
* \param red,green,blue Use value RGB_ON or RGB_OFF to set each LED.
*
* \details
* The RGB LED is actually individual red, green and blue LEDs placed
* very close together in a single package. This function will set each
* LED either on or off, to set the RGB LED to 7 different colors at their
* highest brightness or turn it off.
*
* The colors are as follows:
*
* RED LED GREEN_LED BLUE_LED COLOR
* ------- --------- -------- -----
* RGB_OFF RGB_OFF RGB_OFF OFF
* RGB_OFF RGB_OFF RGB_ON Blue
* RGB_OFF RGB_ON RGB_OFF Green
* RGB_OFF RGB_ON RGB_ON Cyan
* RGB_ON RGB_OFF RGB_OFF Red
* RGB_ON RGB_OFF RGB_ON Magenta
* RGB_ON RGB_ON RGB_OFF Yellow
* RGB_ON RGB_ON RGB_ON White
*
* \note
* Many of the Kickstarter Arduboys were accidentally shipped with the
* RGB LED installed incorrectly. For these units, the green LED cannot be
* lit. As long as the green led is set to off, turning on the red LED will
* actually light the blue LED and turning on the blue LED will actually
* light the red LED. If the green LED is turned on, none of the LEDs
* will light.
*
* \see setRGBled()
*/
void static digitalWriteRGB(uint8_t red, uint8_t green, uint8_t blue);
2016-11-21 21:31:10 +00:00
/** \brief
* Initialize the Arduboy's hardware.
*
* \details
* This function initializes the display, buttons, etc.
*
* This function is called by begin() so isn't normally called within a
* sketch. However, in order to free up some code space, by eliminating
* some of the start up features, it can be called in place of begin().
* The functions that begin() would call after boot() can then be called
* to add back in some of the start up features, if desired.
* See the README file or documentation on the main page for more details.
*
* \see Arduboy2Base::begin()
*/
void static boot();
protected:
2016-11-21 21:31:10 +00:00
/*
* Safe Mode is engaged by holding down both the LEFT button and UP button
2016-11-21 21:31:10 +00:00
* when plugging the device into USB. It puts your device into a tight
* loop and allows it to be reprogrammed even if you have uploaded a very
* broken sketch that interferes with the normal USB triggered auto-reboot
* functionality of the device.
2016-02-21 06:38:49 +00:00
*
* This is most useful on Devkits because they lack a built-in reset
* button.
*/
void static inline safeMode() __attribute__((always_inline));
// internals
void static inline setCPUSpeed8MHz() __attribute__((always_inline));
2016-02-21 06:46:03 +00:00
void static inline bootOLED() __attribute__((always_inline));
void static inline bootPins() __attribute__((always_inline));
void static inline bootPowerSaving() __attribute__((always_inline));
private:
2016-02-21 06:39:41 +00:00
volatile static uint8_t *csport, *dcport;
uint8_t static cspinmask, dcpinmask;
};
#endif