From 9ed187bfce3caa5cc036a98a070470363025d817 Mon Sep 17 00:00:00 2001 From: Wayne Venables Date: Fri, 10 Mar 2023 23:17:15 -0800 Subject: [PATCH] Additional Documentation --- GettingStarted.md | 87 +++++++++++++++++++++++++++++++++++ UsageRules.md | 2 +- examples/Readme.md | 96 ++++++++++++++++++++++++++++++++++++++ src/picovga.h | 2 +- vga_config.h | 112 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 GettingStarted.md create mode 100644 examples/Readme.md create mode 100644 vga_config.h diff --git a/GettingStarted.md b/GettingStarted.md new file mode 100644 index 0000000..e8e5fe7 --- /dev/null +++ b/GettingStarted.md @@ -0,0 +1,87 @@ +# Getting Started {#gettingstarted} + +## Installing PicoVGA + +1. Make sure you have the [Pico SDK](https://github.com/raspberrypi/pico-sdk) installed. + +2. Clone the PicoVGA repository +~~~ +git clone https://github.com/codaris/picovga-cmake.git +~~~ + +3. Set `PICOVGA_PATH` to the PicoVGA directory in your environment, or pass it (`-DPICOVGA_PATH=`) to cmake later. + +## Building the Examples + +The PicoVGA project comes with a comprehensive set of example programs that demonstate many of the features of the library. These examples are located in the [`examples`](https://github.com/codaris/picovga-cmake/tree/main/examples) folder of the PicoVGA project. + +To create the makefiles, run this CMake command from the main PicoVGA folder: + +~~~ +cmake . +~~~ + +Then to build all the example projects at once, you run make (please note this might take a long time): + +~~~ +make +~~~ + +This will generate a `.uf2` file for every example program in the root folder of each example. + +If you want to build a single example program, you can run make for just that example: + +~~~ +cd examples/vga_hello +make +~~~ + +If you don't want to mix the build files with the rest of the code, you can specify a separate build folder when running CMake: + +``` + cmake . -Bbuild +``` + +This will generate all the makefiles and build outputs into the `build` folder. + +After you build one or more example files, the compiled output will be generated as `program_name.uf2` file where `program_name` is the name of the example. They are compiled for a VGA monitor and USB serial keyboard input. Load them into the Pico by copying the `uf2` on the Pico when it's in bootloader mode (hold the bootsel button when connecting to your computer). + +Many of the examples use a USB serial connection for controls. + +## Integrating PicoVGA into Your Project + +The easiest way to incorporate the PicoVGA library into a project is to examine or copy the [sample project](https://github.com/codaris/picovga-helloworld). + +To add PicoVGA to an existing project you must do the following: + +1. Copy the `picovga_import.cmake` file from the PicoVGA library folder into the root of your project. + +2. Copy the `vga_config.h` file from the the PicoVGA library folder into the source or include files folder in your project. + +3. Include that file in your `CMakeLists.txt` file: +~~~ +include(picovga_import.cmake) +~~~ + +4. For every target that uses PicoVGA, add PicoVGA to that target with the `add_picovga()` macro in the `CMakeLists.txt` file: +~~~ +# Add PicoVGA to the target (in this case "helloworld") +add_picovga(helloworld) +~~~ + +5. Ensure that the folder containing the `vga_config.h` is included in the target include directories in `CMakeLists.txt`: +~~~ +target_include_directories(helloworld PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/src +) +~~~ + +Run the command `cmake .` to generate the makefiles for the project and `make` to build the project. + +## Configuring PicoVGA + +The `vga_config.h` contains the PicoVGA library settings, such as the size of the render buffers. You usually do not need to pay attention to this file. You usually only have to modify it in the following cases: + +* When you use a display resolution greater than 640x480 pixels. Typically, the configuration file sets the maximum resolution to 640x480. This must be adjusted at higher resolutions to allow the library to reserve larger buffers for rendering functions. +* If there is not enough RAM. There is still some headroom where you can save some memory. First, you can reduce the MAXX, MAXY, and MAXLINE resolution settings down to a real values. Next, you can reduce the number of LAYERS down to the actual value used (in the range of 1 to 4). Finally, you can reduce the number of segments and stripes to the actual value SEGMAX and STRIPMAX (minimum is 1). +* The third case is to use of a large number of display stripes and segments. Normally, the values here are set to 8 stripes (=horizontal strips) and 8 segments (=vertical division of each strip). diff --git a/UsageRules.md b/UsageRules.md index bc2b09b..3e8bcbd 100644 --- a/UsageRules.md +++ b/UsageRules.md @@ -6,7 +6,7 @@ The library always runs on the second core of the processor and the program on t If the second core is not very busy (e.g. when displaying 8-bit graphics that are simply transferred using DMA transfer), it can also be used for the main program work. However, some limitations should be taken into account - the program in the second core should not use interrupts (it would interfere with the rendering function), the interpolation unit should be used with caution (the rendering function does not save its state) and it must not disable interrupts. -An important rule is that all data to be accessed by the PicoVGA library must be stored in the RAM memory. External flash memory is slow and cannot be used for rendering functions. For example, if a flash image is to be displayed, it must first be copied to a buffer in RAM, and then a pointer to the RAM copy of the image will be passed to the rendering function. If a pointer to the image in flash were passed to it, slow access to flash would cause video dropouts. In addition to images, this also applies to fonts and tile patterns, for example. +An important rule is that all data to be accessed by the PicoVGA library **must be stored in the RAM memory**. External flash memory is slow and cannot be used for rendering functions. For example, if a flash image is to be displayed, it must first be copied to a buffer in RAM, and then a pointer to the RAM copy of the image will be passed to the rendering function. If a pointer to the image in flash were passed to it, slow access to flash would cause video dropouts. In addition to images, this also applies to fonts and tile patterns, for example. The limited rendering speed must be taken into account when scheduling screen layout. Some modes render very fast (e.g. 8-bit graphics are just transferred from the frame buffer using DMA) and some modes are very rendering intensive - e.g. rendering sprites in slow mode. When using demanding rendering, some video lines may not render fast enough in the required time and the video image will break (drop out of sync). In such cases, it is necessary to use another mode, or to reduce the rendered area (add other modes, faster ones - e.g. add tile controls on the sides of the screen), reduce the screen resolution or increase the CPU clock speed. Video lines are rendered separately and therefore it is always just content on one video line about, video lines do not affect each other. For example, you can test the speed of sprite rendering by placing all the sprites horizontally next to each other (the most challenging case) and check if the video synchronization fails. diff --git a/examples/Readme.md b/examples/Readme.md new file mode 100644 index 0000000..5b4a148 --- /dev/null +++ b/examples/Readme.md @@ -0,0 +1,96 @@ +# PicoVGA Example Programs + +### Ants + Card game (sound). Two anthills compete for supremacy. The goal is to build a higher castle. Controls: J left, L right, space select card, D discard, H help, Q quit. Can be played against another player or against the computer. + +|![](../www/img/ants_m.jpg) +![](../www/img/ants2_m.jpg) + +### Balloons + +Demonstration of sprite use, flying balloons (43 sprites in total). + +### Draw +Demonstration of drawing graphic elements. For the demonstration, alternate between slow rendering and drawing at maximum speed. + +### Earth + +Rotating globe. Software spherical image transformation. + +### Eggs +Logic game (sound). Based on the game Reversi. The goal is to get as many of your own stones as possible. One player changes stones in the direction of hen-chicken-egg, the other player in the opposite direction. Controls: L right, I up, J left, K down, H help, Q end, P 2 players, D demo, space bar to place stone, Enter ok. Can be played against another player and against the computer. + +### Fifteen +Logic game (sound). The objective is to sort the stones in order from 1 to 15. Controls: L right, I up, J left, K down, Q new game. + +### Flag +Fluttering flag + +### Ghost Racing +Car racing (sound). After passing the first lap (checkpoints are required), a rival "ghost" appears, which copies your previous path. You are competing with yourself. There are a total of 2 ghost opponents in the game (the second one should appear after the second lap). The game is unfinished - I couldn't calculate the correct transformation of the opponents' image into the camera and it is now only very approximate. It's more of a half-finished game for inspiration and to demonstrate 3D terrain projection (tile areas). Controls: I gear up, K gear down, J left, L right. 5 gears can be shifted. Originally, reverse was possible, but it was rather hindering. + +### Gingerbread House +A fairy tale book about a gingerbread house. The program serves as a demonstration of working with images with RLE compression. Control: J previous page, L next page. + +### Hello World +The simplest example of using the PicoVGA library. + +### Hypno +A hypnotic rotating pattern. Example of matrix image transformation. + +### Level Meter +Music spectrum indicator simulation (sound). The program uses a gradient graph level display mode. The input for the display is an array of values. There is no need to generate the indicator image programmatically and so a very fast response to change can be achieved. Random samples are used in the demo. + +### Life +Cell life simulator (cellular automaton). Cells change at each step according to the number of neighboring cells: for 1 or less a cell dies on isolation, for 4 or more a cell dies on overpopulation, for 3 a new cell is created, for 2 there is no change. In the game, you can switch between 10 screens (slots) and transfer the image between them using the clipboard. In each slot there is a predefined definition of popular combinations. Controls: L right, I up, J left, K down, C copy to clipboard, V insert from clipboard, D clear area, space bar change cell, Enter start/stop generation, 0-9 select slot. + +### Lines +Relaxation line pattern generator. + +### Mandelbrot +Fractal pattern generator of Mandelbrot set. Integer mathematics is used to generate the pattern, which makes the redrawing fast. However, it must be taken into account that as the scale of the display increases, increasing accuracy in the number of digits is required. The used integer and float mathematics are sufficient up to a magnification scale of 10^5, double mathematics up to a scale of 10^10. When zooming in further, only colored lines are displayed instead of the pattern. Controls: E up, S left, D right, X down, Q scale up, A scale down, L low resolution selection 132x100, M medium resolution selection 264x200, H high resolution selection 528x400, I switch to integer math (fastest, range up to 10^-5), F switching to float math (slowest, range up to 10^-5), B switching to double math (slowest, range up to 10^-10), O decreasing the number of iteration steps, P increasing the number of iteration steps, U increasing the system clock, T decreasing the system clock, space redraw screen. + +### Matrix Rain +"Matrix code rain" simulation. It uses text-based video mode. + +### Maze +The goal is to find a way out of the maze. The mazes are generated randomly programmatically. Controls: J left, I up, L right, K down, H help (showing the door). + +### Monoscope +Video modes test. The keys 0 to 9 and A to U can be used to switch the display resolution, from 256x192 to 1280x960, for both VGA monitor and PAL/NTSC TV.For the TV, interlaced video is used for higher resolutions (such as broadcast TV), and progressive mode is used for lower resolutions (such as the outputs from 8-bit computers). Can be used to test the display on different devices. The individual test patterns are stored in the program as prepared images with RLE compression. It would be possible to modify the program to use only 1 image, which would be recomputed as needed, but would have to be compressed into RAM with RLE compression when generated, as it would not fit in RAM at full size. + +### Oscilloscope +Demonstration of oscilloscope signal display. The program uses graph and curve display mode. The signal waveform image does not need to be generated in software, only the array of values is passed to the display, and this allows a very fast response to changing values. In the demo the samples are generated programmatically. It also serves as a demonstration of stacking image segments in different modes. The basic oscilloscope image is an 8-bit bitmap (with dithering), consisting of 4 stripes. In place of the screen, 2 elements are used to display graphs. The screen is overlaid by a transparent overlay with a grid. + +### Pac-Man +Popular action game (sound). The game attempts to emulate the original 1980's version of the game by Namco. The logic of ghost behavior, score and level counting is followed. I would like to point out that the sounds and appearance are taken from the original game, they are covered by Namco's copyright, and therefore the game serves only as an inspirational sample. Controls: J left, I up, L right, K down, A pause. + +### Pi +Calculating the number Pi to 4833 digits. After the calculation, the result is checked against the expected sample. + +### Pixels +Random generation of colored pixels. + +### Raytracing +3D pattern generation by ray tracing method. Due to the limited color depth of PicoVGA, raster dithering ("graininess" of the image) is used in the display. + +### Sokoban +Logic game (sound). The goal is to move the crates to the marked fields. The game contains 3000 levels from different authors, along with their solutions. Controls: L right, I up, J left, K down, H help (level solution), R restart level, Q previous level, W next level, P print info. + +### Spheres +Random spheres generation. + +### Spots +Random generation of spots. + +### Tetris +Popular game, stacking blocks (sound). Control: L right, I turn, J left, K lay, A pause. + +### Train +Logic game based on the principle of the Snake (sound). The goal is to collect all objects and pass through the gate. The game has 50 levels, along with their solutions. Controls.: L right, I up, J left, K down, H help (view solution of the level), Enter enter password, Esc back, BS delete character of password. + +### Twister +Twisting of the textured block. It serves as an example of programmatic image deformation, using a hardware interpolator. + +### Water Surface +Simulation of rippling water surface (sound). diff --git a/src/picovga.h b/src/picovga.h index 7f831c9..6762738 100644 --- a/src/picovga.h +++ b/src/picovga.h @@ -130,7 +130,7 @@ typedef unsigned char Bool; * 14 and 16 line fonts in the library. Fonts are exported by the RaspPicoImg utility to *.cpp source text format, * and are added to the program as a byte array. * - * Example of font font_bold_8x8: + * Example of font FontBold8x8: * ![](www/img/font1.jpg) * @{ */ diff --git a/vga_config.h b/vga_config.h new file mode 100644 index 0000000..18a1bd5 --- /dev/null +++ b/vga_config.h @@ -0,0 +1,112 @@ + +// **************************************************************************** +// +// VGA configuration +// +// **************************************************************************** + +// === Configuration +#define LAYERS 4 // total layers 1..4 (1 base layer + 3 overlapped layers) +#define SEGMAX 8 // max. number of video segment per video strip (size of 1 sSegm = 28 bytes) +#define STRIPMAX 8 // max. number of video strips (size of 1 sStrip = sSegm size*SEGMAX+4 = 228 bytes) + // size of sScreen = sStrip size*STRIPMAX+4 = 1828 bytes + +#define MAXX 640 // max. resolution in X direction (must be power of 4) +#define MAXY 480 // max. resolution in Y direction + +#define MAXLINE 700 // max. number of scanlines (including sync and dark lines) + +// === Scanline render buffers (800 pixels: default size of buffers = 2*4*(800+8+800+24)+800 = 13856 bytes +// Requirements by format, base layer 0, 1 wrap X segment: +// GF_GRAPH8 ... control buffer 16 bytes +// GF_TILE8 ... control buffer "width"+8 bytes +// GF_TILE16 ... control buffer "width/2"+8 bytes +// GF_TILE32 ... control buffer "width/4"+8 bytes +// GF_TILE64 ... control buffer "width/8"+8 bytes +// GF_PROGRESS ... control buffer 24 bytes +// other formats: data buffer "width" bytes, control buffer 16 bytes +#define DBUF0_MAX (MAXX+8) // max. size of data buffer of layer 0 +#define CBUF0_MAX ((MAXX+24)/4) // max. size of control buffer of layer 0 + +// Requirements by format, overlapped layer 1..3: +// LAYERMODE_SPRITE* ... data buffer "width"+4 bytes, control buffer 24 bytes +// LAYERMODE_FASTSPRITE* ... data buffer "width"+4 bytes, control buffer up to "width*2"+16 bytes +// other formats ... data buffer 4 bytes, control buffer 24 bytes +#define DBUF1_MAX (MAXX+8) // max. size of data buffer of layer 1 +#define CBUF1_MAX ((MAXX+24)/4) // max. size of control buffer of layer 1 + +#define DBUF2_MAX (MAXX+8) // max. size of data buffer of layer 2 +#define CBUF2_MAX ((MAXX+24)/4) // max. size of control buffer of layer 2 + +#define DBUF3_MAX (MAXX+8) // max. size of data buffer of layer 3 +#define CBUF3_MAX ((MAXX+24)/4) // max. size of control buffer of layer 3 + +#if LAYERS==1 +#define DBUF_MAX DBUF0_MAX // max. size of data buffer +#define CBUF_MAX CBUF0_MAX // max. size of control buffer +#elif LAYERS==2 +#define DBUF_MAX (DBUF0_MAX+DBUF1_MAX) // max. size of data buffer +#define CBUF_MAX (CBUF0_MAX+CBUF1_MAX) // max. size of control buffer +#elif LAYERS==3 +#define DBUF_MAX (DBUF0_MAX+DBUF1_MAX+DBUF2_MAX) // max. size of data buffer +#define CBUF_MAX (CBUF0_MAX+CBUF1_MAX+CBUF2_MAX) // max. size of control buffer +#elif LAYERS==4 +#define DBUF_MAX (DBUF0_MAX+DBUF1_MAX+DBUF2_MAX+DBUF3_MAX) // max. size of data buffer +#define CBUF_MAX (CBUF0_MAX+CBUF1_MAX+CBUF2_MAX+CBUF3_MAX) // max. size of control buffer +#else +#error Unsupported number of layers! +#endif + +// === VGA port pins +// GP0 ... VGA B0 blue +// GP1 ... VGA B1 +// GP2 ... VGA G0 green +// GP3 ... VGA G1 +// GP4 ... VGA G2 +// GP5 ... VGA R0 red +// GP6 ... VGA R1 +// GP7 ... VGA R2 +// GP8 ... VGA SYNC synchronization (inverted: negative SYNC=LOW=0x80, BLACK=HIGH=0x00) +#define VGA_GPIO_FIRST 0 // first VGA GPIO +#define VGA_GPIO_NUM 9 // number of VGA GPIOs, including HSYNC and VSYNC +#define VGA_GPIO_OUTNUM 8 // number of VGA color GPIOs, without HSYNC and VSYNC +#define VGA_GPIO_LAST (VGA_GPIO_FIRST+VGA_GPIO_NUM-1) // last VGA GPIO +#define VGA_GPIO_SYNC 8 // VGA SYNC GPIO + +// VGA PIO and state machines +#define VGA_PIO pio0 // VGA PIO +#define VGA_SM0 0 // VGA state machine of base layer 0 +#define VGA_SM1 1 // VGA state machine of overlapped layer 1 +#define VGA_SM2 2 // VGA state machine of overlapped layer 2 +#define VGA_SM3 3 // VGA state machine of overlapped layer 3 +#define VGA_SM(layer) (VGA_SM0+(layer)) // VGA state machine of the layer + +#if LAYERS==1 +#define VGA_SMALL B0 // mask of all state machines +#elif LAYERS==2 +#define VGA_SMALL (B0+B1) // mask of all state machines +#elif LAYERS==3 +#define VGA_SMALL (B0+B1+B2) // mask of all state machines +#elif LAYERS==4 +#define VGA_SMALL (B0+B1+B2+B3) // mask of all state machines +#else +#error Unsupported number of layers! +#endif + +// VGA DMA +#define VGA_DMA 0 // VGA DMA base channel +#define VGA_DMA_CB0 (VGA_DMA+0) // VGA DMA channel - control block of base layer +#define VGA_DMA_PIO0 (VGA_DMA+1) // VGA DMA channel - copy data of base layer to PIO (raises IRQ0 on quiet) +#define VGA_DMA_CB1 (VGA_DMA+2) // VGA DMA channel - control block of overlapped layer 1 +#define VGA_DMA_PIO1 (VGA_DMA+3) // VGA DMA channel - copy data of overlapped layer 1 to PIO +#define VGA_DMA_CB2 (VGA_DMA+4) // VGA DMA channel - control block of overlapped layer 1 +#define VGA_DMA_PIO2 (VGA_DMA+5) // VGA DMA channel - copy data of overlapped layer 2 to PIO +#define VGA_DMA_CB3 (VGA_DMA+6) // VGA DMA channel - control block of overlapped layer 1 +#define VGA_DMA_PIO3 (VGA_DMA+7) // VGA DMA channel - copy data of overlapped layer 3 to PIO + +#define VGA_DMA_CB(layer) (VGA_DMA_CB0+(layer)*2) // VGA DMA control channel of the layer +#define VGA_DMA_PIO(layer) (VGA_DMA_PIO0+(layer)*2) // VGA DMA data channel of the layer + +#define VGA_DMA_NUM (LAYERS*2) // number of used DMA channels +#define VGA_DMA_FIRST VGA_DMA // first used DMA +#define VGA_DMA_LAST (VGA_DMA_FIRST+VGA_DMA_NUM-1) // last used DMA