Mostly Doxygened

This commit is contained in:
Phillip Burgess 2023-03-09 12:27:02 -08:00 committed by ladyada
parent 7910e26c6d
commit 0b7be17886
3 changed files with 285 additions and 41 deletions

View file

@ -1,15 +1,19 @@
Special Fork of PicoDVI for RP2040/RP2350 Arduino Philhower Core + Adafruit_GFX
========================================================================
At present this implements a 16-bit color framebuffer to which Adafruit_GFX
drawing operations can be made. Other framebuffer types (8-bit, 1-bit) might
get added later, but probably not every permutation PicoDVI is capable of.
Implements a few framebuffer types to which Adafruit_GFX drawing operations
can be made; not every permutation PicoDVI is capable of, but a useful subset.
WARNING: all video modes require overclocking (performed automatically at
run-time, nothing to select), occasionally over-volting (optionally selected
in sketch code), and higher resolutions may require reducing the QSPI clock
rate (Tools menu in future arduino-pico release). The RP2040 microcontroller
is being run WAY beyond spec and there is a VERY SMALL BUT NONZERO
POSSIBILITY OF PERMANENT DAMAGE. Please see LICENSE file; usual software
disclaimers about liability apply, user accepts risk.
Requires Earle Philhower III RP2040 Arduino core (not the "official" Arduino
RP2040 core). Some resolutions may require slightly higher over-voltage
settings vs. equivalent Pico SDK-built projects. Just speculating there might
be a slightly higher workload when built in Arduino environment, due to
timekeeping interrupts, Serial and any other background stuff.
RP2040 core).
Changes vs main PicoDVI repo:
- Add library.properties file, src and examples directories per Arduino
@ -28,6 +32,7 @@ called: dvi_vertical_repeat and dvi_monochrome_tmds.
- DVI_1BPP_BIT_REVERSE is switched '1' by default (to work with bit order
used by GFXcanvas1 object). Pico SDK-built examples using 1-bit mode are
fixed by changing the corresponding CMakeLists.txt files to set this to 0.
Font data has had bit order reversed to match this layout.
All files from the PicoDVI repo are kept even if not used in this build
(e.g. apps and assets directories, among others) so same repo can still be

View file

@ -1,3 +1,13 @@
// SPDX-FileCopyrightText: 2023 P Burgess for Adafruit Industries
//
// SPDX-License-Identifier: BSD-3-Clause
/*!
* @file PicoDVI.cpp
*
* Arduino-and-Adafruit-GFX wrapper around Luke Wren's PicoDVI library.
*/
#include "PicoDVI.h"
#include "libdvi/tmds_encode.h"
@ -25,7 +35,10 @@ static struct {
static PicoDVI *dviptr = NULL; // For C access to active C++ object
// Runs on core 1 on startup
/*!
@brief Runs on core 1 on startup; this is how Philhower RP2040 handles
multiprocessing.
*/
void setup1(void) {
while (dviptr == NULL) // Wait for PicoDVI::begin() to start on core 0
yield();
@ -284,10 +297,10 @@ void DVIGFX1::swap(bool copy_framebuffer) {
// TEXT MODE IS A WORK IN PROGRESS
#define FONT_CHAR_WIDTH 8
#define FONT_CHAR_HEIGHT 8
#define FONT_N_CHARS 256
#define FONT_FIRST_ASCII 0
#define FONT_CHAR_WIDTH 8 ///< Character block width, pixels
#define FONT_CHAR_HEIGHT 8 ///< Character block height, pixels
#define FONT_N_CHARS 256 ///< Number of symbols in font
#define FONT_FIRST_ASCII 0 ///< Full CP437 is there, start at 0
#include "font_8x8.h"
DVItext1::DVItext1(const DVIresolution r, const struct dvi_serialiser_cfg &c,

View file

@ -1,3 +1,13 @@
// SPDX-FileCopyrightText: 2023 P Burgess for Adafruit Industries
//
// SPDX-License-Identifier: BSD-3-Clause
/*!
* @file PicoDVI.h
*
* Arduino-and-Adafruit-GFX wrapper around Luke Wren's PicoDVI library.
*/
#pragma once
#include "../software/include/common_dvi_pin_configs.h"
@ -6,93 +16,266 @@
#include "pico/stdlib.h" // In Pico SDK
#include <Adafruit_GFX.h>
// A set list of resolutions keeps things manageable for users,
// avoids some possibly-incompatible argument combos to constructors.
/** A set list of resolutions keeps things manageable for users,
avoids some possibly-incompatible argument combos to constructors. */
enum DVIresolution {
DVI_RES_320x240p60 = 0,
DVI_RES_400x240p60,
DVI_RES_640x480p60,
DVI_RES_800x480p60,
DVI_RES_640x240p60, // "Tall" pixels, e.g. for 80-column text mode
DVI_RES_800x240p60, // " 100-column
DVI_RES_1280x720p30 // Experimenting, plz don't use
DVI_RES_800x240p60, // Same, 100-column
DVI_RES_1280x720p30 // Experimenting, not working, plz don't use
};
extern uint8_t dvi_vertical_repeat; // In libdvi/dvi.c
extern bool dvi_monochrome_tmds; // In libdvi/dvi.c
extern uint8_t dvi_vertical_repeat; ///< In libdvi/dvi.c
extern bool dvi_monochrome_tmds; ///< In libdvi/dvi.c
/*!
@brief A base class used by some of the framebuffer classes that follow.
Wraps essential functionality of the underlying PicoDVI library.
Maybe only rarely (if ever) needed in Arduino sketch code, but
it's here if a project requires working at a lower level to
provide features not present in the framebuffer modes.
*/
class PicoDVI {
public:
PicoDVI(const struct dvi_timing &t = dvi_timing_800x480p_60hz,
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
/*!
@brief PicoDVI constructor. Instantiates a new PicoDVI object (must
follow with a begin() call to alloc buffers and init hardware).
@param t Pointer to dvi_timing struct, one of the supported
resolutions declared in libdvi/dvi_timing.c. Default if not
specified is 640x480p60.
@param c Pointer to dvi_serialiser_cfg struct, which defines pinout.
These are in ../software/include/common_dvi_pin_configs.h.
Default if not specified is adafruit_feather_dvi_cfg.
@param v Core voltage; higher resolution modes require faster
overclocking and potentially higher voltages. This is an
enumeration declared in Pico SDK hardware/vreg.h. Normal
system operation would be 1.1V, default here if not
specified is 1.2V.
*/
PicoDVI(const struct dvi_timing &t = dvi_timing_640x480p_60hz,
const struct dvi_serialiser_cfg &c = adafruit_feather_dvi_cfg,
vreg_voltage v = VREG_VOLTAGE_1_20);
~PicoDVI(void);
/*!
@brief Internal function used during DVI initialization. User code
should not touch this, but it does need to remain public for
C init code to access protected elements.
*/
void _setup(void);
protected:
/*!
@brief Initialize hardware and start video thread.
*/
void begin(void);
vreg_voltage voltage;
struct dvi_inst dvi0;
void (*mainloop)(dvi_inst *) = NULL;
volatile bool wait_begin = true;
vreg_voltage voltage; ///< Core voltage
struct dvi_inst dvi0; ///< DVI instance
void (*mainloop)(dvi_inst *) = NULL; ///< Video mode loop handler
volatile bool wait_begin = true; ///< For synchronizing cores
};
/*!
@brief DVIGFX16 provides a 16-bit color (RGB565) Adafruit_GFX-compatible
framebuffer. Double-buffering is NOT provided even as an option,
there simply isn't adequate RAM.
*/
class DVIGFX16 : public PicoDVI, public GFXcanvas16 {
public:
DVIGFX16(const DVIresolution res = DVI_RES_400x240p60,
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
/*!
@brief DVIGFX16 constructor.
@param res Video mode, from the DVIresolution enumeration. This will
usually be 320x240 or 400x240, there just isn't RAM to
handle anything larger as a pixel-accessible framebuffer.
@param c Pointer to dvi_serialiser_cfg struct, which defines pinout.
These are in ../software/include/common_dvi_pin_configs.h.
Default if not specified is adafruit_feather_dvi_cfg.
@param v Core voltage; higher resolution modes require faster
overclocking and potentially higher voltages. This is an
enumeration declared in Pico SDK hardware/vreg.h. Normal
system operation would be 1.1V, default here if not
specified is 1.2V.
*/
DVIGFX16(const DVIresolution res = DVI_RES_320x240p60,
const struct dvi_serialiser_cfg &c = adafruit_feather_dvi_cfg,
vreg_voltage v = VREG_VOLTAGE_1_20);
~DVIGFX16(void);
/*!
@brief Initialize DVI output for 16-bit color display.
@return true on success, false otherwise (buffer allocation usually).
*/
bool begin(void);
/*!
@brief Convert a 24-bit RGB color (as three 8-bit values) to a packed
16-bit "RGB565" color, as native to PicoDVI and Adafruit_GFX.
@param red Red component, 0-255.
@param green Green component, 0-255.
@param blue Blue component, 0-255.
@return Nearest 16-bit RGB565 equivalent.
*/
uint16_t color565(uint8_t red, uint8_t green, uint8_t blue) {
return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
}
/*!
@brief Scanline-processing function used internally during video
generation. User sketch code should never call this, but it
needs to be public so that C code can access it.
*/
void _scanline_callback(void);
protected:
uint16_t scanline = 2; // First 2 scanlines are set up before DVI start
uint16_t scanline = 2; ///< First 2 scanlines are set up before DVI start
};
/*!
@brief DVIGFX8 provides a 8-bit color-mapped Adafruit_GFX-compatible
framebuffer, with optional double-buffering.
*/
class DVIGFX8 : public PicoDVI, public GFXcanvas8 {
public:
DVIGFX8(const DVIresolution res = DVI_RES_400x240p60, const bool dbuf = false,
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
/*!
@brief DVIGFX8 constructor.
@param res Video mode, from the DVIresolution enumeration.
@param dbuf Double-buffered flag. If true, two 8-bit framebuffers
(each with associated color palette) are allocated, code
can alternate between these for flicker-free animation.
@param c Pointer to dvi_serialiser_cfg struct, which defines pinout.
These are in ../software/include/common_dvi_pin_configs.h.
Default if not specified is adafruit_feather_dvi_cfg.
@param v Core voltage; higher resolution modes require faster
overclocking and potentially higher voltages. This is an
enumeration declared in Pico SDK hardware/vreg.h. Normal
system operation would be 1.1V, default here if not
specified is 1.2V.
*/
DVIGFX8(const DVIresolution res = DVI_RES_320x240p60, const bool dbuf = false,
const struct dvi_serialiser_cfg &c = adafruit_feather_dvi_cfg,
vreg_voltage v = VREG_VOLTAGE_1_20);
~DVIGFX8(void);
/*!
@brief Initialize DVI output for 8-bit colormapped display.
@return true on success, false otherwise (buffer allocation usually).
*/
bool begin(void);
/*!
@brief Get base address of 'back' palette (or single palette in
single-buffered mode), for code that wants to access this.
directly rather than through setColor() and getColor().
@return uint16_t* pointer to 256-entry palette (RGB565 colors).
*/
uint16_t *getPalette(void) { return palette[back_index]; }
/*!
@brief Set one color in the 'back' color palette (or single palette in
single-buffered mode).
@param idx Color index to set, 0-255.
@param color 16-bit "RGB565" color.
*/
void setColor(uint8_t idx, uint16_t color) {
palette[back_index][idx] = color;
}
/*!
@brief Set one color in the 'back' color palette (or single palette in
single-buffered mode). Accepts three 8-bit values, but COLOR
WILL BE QUANTIZED TO 16-BIT RGB565 because that's what PicoDVI
uses. Original 24-bit value is LOST and cannot be accurately
read back by getColor().
@param idx Color index to set, 0-255.
@param red Red component, 0-255.
@param green Green component, 0-255.
@param blue Blue component, 0-255.
*/
void setColor(uint8_t idx, uint8_t red, uint8_t green, uint8_t blue) {
palette[back_index][idx] =
((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
}
/*!
@brief Read one color from the 'back' color palette (or single palette
in single-buffered mode).
@param idx Color index to read, 0-255.
@return 16-bit "RGB565" color.
*/
uint16_t getColor(uint8_t idx) { return palette[back_index][idx]; }
/*!
@brief Swap front/back framebuffers on next vertical sync.
@param copy_framebuffer If true, contents of new 'front' framebuffer
will be duplicated into new 'back' buffer for
updates (useful for code that modifies screen
frame-to-frame, rather than complete regen).
@param copy_palette If true, copies 'front' palette to 'back'.
This is obscure; most code will set up a global
palette once, swap-with-copy once (so front
and back are both using same palette), and not
touch this...but it's there if palette-
animating code needs it.
*/
void swap(bool copy_framebuffer = false, bool copy_palette = false);
/*!
@brief Scanline-processing function used internally during video
generation. User sketch code should never call this, but it
needs to be public so that C code can access it.
*/
void _scanline_callback(void);
protected:
uint16_t palette[2][256]; // [2] for double-buffering
uint16_t *row565[2]; // 2 scanlines of 16-bit RGB565 data
uint16_t scanline = 2; // First 2 scanlines are set up before DVI start
uint8_t rowidx = 1; // Alternate 0/1 for which row565[] is active
bool dbuf = false; // True if double-buffered
uint8_t *buffer_save; // Original canvas buffer pointer
uint8_t back_index = 0; // Which of 2 buffers receives draw ops
volatile bool swap_wait = 0; // For synchronizing fromt/back buffer swap
uint16_t palette[2][256]; ///< [2] for double-buffering
uint16_t *row565[2]; ///< 2 scanlines of 16-bit RGB565 data
uint16_t scanline = 2; ///< 1st 2 scanlines loaded before DVI start
uint8_t rowidx = 1; ///< Alternate 0/1 for which row565[] is active
bool dbuf = false; ///< True if double-buffered
uint8_t *buffer_save; ///< Original canvas buffer pointer
uint8_t back_index = 0; ///< Which of 2 buffers receives draw ops
volatile bool swap_wait = 0; ///< For synchronizing fromt/back buffer swap
};
/*!
@brief DVIGFX1 provides a 1-bit monochrome (black, white) Adafruit_GFX-
compatible framebuffer, with optional double-buffering.
*/
class DVIGFX1 : public PicoDVI, public GFXcanvas1 {
public:
DVIGFX1(const DVIresolution res = DVI_RES_800x480p60, const bool dbuf = false,
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
/*!
@brief DVIGFX1 constructor.
@param res Video mode, from the DVIresolution enumeration. This will
usually be 640x480 or 800x480. Higher settings are not
currently supported.
@param dbuf Double-buffered flag. If true, two 1-bit framebuffers are
allocated, code can alternate between these for flicker-
free animation.
@param c Pointer to dvi_serialiser_cfg struct, which defines pinout.
These are in ../software/include/common_dvi_pin_configs.h.
Default if not specified is adafruit_feather_dvi_cfg.
@param v Core voltage; higher resolution modes require faster
overclocking and potentially higher voltages. This is an
enumeration declared in Pico SDK hardware/vreg.h. Normal
system operation would be 1.1V, default here if not
specified is 1.2V.
*/
DVIGFX1(const DVIresolution res = DVI_RES_640x480p60, const bool dbuf = false,
const struct dvi_serialiser_cfg &c = adafruit_feather_dvi_cfg,
vreg_voltage v = VREG_VOLTAGE_1_20);
~DVIGFX1(void);
/*!
@brief Initialize DVI output for 1-bit monochrome graphics display.
@return true on success, false otherwise (buffer allocation usually).
*/
bool begin(void);
/*!
@brief Swap front/back framebuffers on next vertical sync.
@param copy_framebuffer If true, contents of new 'front' framebuffer
will be duplicated into new 'back' buffer for
updates (useful for code that modifies screen
frame-to-frame, rather than complete regen).
*/
void swap(bool copy_framebuffer = false);
/*!
@brief Video main loop handler invoked by underlying PicoDVI code.
User sketch code should never call this, but it needs to be
public so that C code can access it.
*/
void _mainloop(void);
private:
@ -102,15 +285,58 @@ private:
volatile bool swap_wait = 0; // For syncronizing front/back buffer swap
};
/*!
@brief DVItext1 provides a 1-bit monochrome (black, white) text-only
display. print() and related calls to this display will vertical
scroll when needed. It's very basic and does not provide any ANSI-
like terminal functionality.
*/
class DVItext1 : public PicoDVI, public GFXcanvas16 {
public:
DVItext1(const DVIresolution res = DVI_RES_400x240p60,
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
/*!
@brief DVItext1 constructor.
@param res Video mode, from the DVIresolution enumeration. This is the
pixel resolution; text cells are 8x8 pixels and thus the
number of rows and columns will be less (e.g. 640x240 mode
yields 80x30 characters).
@param c Pointer to dvi_serialiser_cfg struct, which defines pinout.
These are in ../software/include/common_dvi_pin_configs.h.
Default if not specified is adafruit_feather_dvi_cfg.
@param v Core voltage; higher resolution modes require faster
overclocking and potentially higher voltages. This is an
enumeration declared in Pico SDK hardware/vreg.h. Normal
system operation would be 1.1V, default here if not
specified is 1.2V.
*/
DVItext1(const DVIresolution res = DVI_RES_640x240p60,
const struct dvi_serialiser_cfg &c = adafruit_feather_dvi_cfg,
vreg_voltage v = VREG_VOLTAGE_1_20);
~DVItext1(void);
/*!
@brief Initialize DVI output for text display.
@return true on success, false otherwise (buffer allocation usually).
*/
bool begin(void);
/*!
@brief Base character-writing function, allows Arduino print() and
println() calls to work with display. Text will scroll upward
as needed.
@param c ASCII character to write.
@return Number of characters written; always 1.
*/
size_t write(uint8_t c);
/*!
@brief Scanline-processing function used internally during video
generation. User sketch code should never call this, but it
needs to be public so that C code can access it.
@param y Scanline index; 0 to height-1.
*/
void _prepare_scanline(uint16_t y);
/*!
@brief Video main loop handler invoked by underlying PicoDVI code.
User sketch code should never call this, but it needs to be
public so that C code can access it.
*/
void _mainloop(void);
protected: