Skip to content

Commit

Permalink
Merge pull request #24 from ikjordan/hdmimerge
Browse files Browse the repository at this point in the history
Hdmimerge
  • Loading branch information
ikjordan authored Nov 12, 2023
2 parents e907aa3 + 0d8572d commit 86adc12
Show file tree
Hide file tree
Showing 37 changed files with 1,168 additions and 249 deletions.
40 changes: 32 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ project(${PROJECT} C CXX)

OPTION(TIME_SPARE "Set to true to measure idle time" OFF)
OPTION(OVER_VOLT "Set to true to increase the Pico voltage" OFF)
OPTION(HDMI_SOUND "Set to true to deliver sound over hdmi" OFF)

# Look for board file first in local board directory
set(PICO_BOARD_HEADER_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/boards)
Expand All @@ -23,6 +24,8 @@ endif()
# e.g. cmake -DPICO_BOARD=picomitevgaboard
# Set to "olimexpcboard" for Olimex RP2040-PICO-PC board
# e.g. cmake -DPICO_BOARD=olimexpcboard
# Set to "lcdws28board" for Waveshare Pico-ResTouch-LCD-2.8
# e.g. cmake -DPICO_BOARD=lcdws28board

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
Expand Down Expand Up @@ -66,10 +69,13 @@ if ((${PICO_BOARD} STREQUAL "dviboard") OR (${PICO_BOARD} STREQUAL "olimexpcboar
display/display_dvi.c
display/tmds_double.S
display/tmds_double.h)
else()
elseif ((${PICO_BOARD} STREQUAL "lcdws28board"))
set(DISPLAY_SOURCES
display/display_lcd.c)
else ()
set(DISPLAY_SOURCES
display/display_vga.c)
endif()
endif ()

set(USB_SOURCES
usb/hid_app.c
Expand All @@ -87,6 +93,9 @@ add_executable(${PROJECT}

# Determine sound system
if ((${PICO_BOARD} STREQUAL "dviboard") OR (${PICO_BOARD} STREQUAL "vgaboard"))
if ((${PICO_BOARD} STREQUAL "dviboard") AND (${HDMI_SOUND}))
target_compile_definitions(${PROJECT} PRIVATE -DSOUND_HDMI)
else()
# Use I2S loaded by DMA sound
target_compile_definitions(${PROJECT} PRIVATE -DI2S)
# Default to I2S sound. Note that Pimoroni VGA board can also use PWM
Expand All @@ -95,10 +104,16 @@ if ((${PICO_BOARD} STREQUAL "dviboard") OR (${PICO_BOARD} STREQUAL "vgaboard"))
hardware_pio
hardware_dma)
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/src/audio_i2s.pio)
endif()
elseif (NOT (${PICO_BOARD} STREQUAL "olimexpcboard"))
# Unless Olimex (which has channels on different slices) use PWM loaded by DMA sound
target_compile_definitions(${PROJECT} PRIVATE -DSOUND_DMA)
target_link_libraries(${PROJECT} hardware_dma)
target_link_libraries(${PROJECT} hardware_pwm)
elseif (${HDMI_SOUND})
target_compile_definitions(${PROJECT} PRIVATE -DSOUND_HDMI)
else ()
target_link_libraries(${PROJECT} hardware_pwm)
endif()

# Determine video system and name uf2
Expand All @@ -111,15 +126,26 @@ if ((${PICO_BOARD} STREQUAL "dviboard") OR (${PICO_BOARD} STREQUAL "olimexpcboar
target_link_libraries(${PROJECT} libdvi)

if (${PICO_BOARD} STREQUAL "dviboard")
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "picozx81_dvi")
if (${HDMI_SOUND})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "picozx81_dvi_hdmi_sound")
else()
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "picozx81_dvi")
endif()
target_compile_definitions(${PROJECT} PUBLIC
-DDVI_DEFAULT_SERIAL_CONFIG=pimoroni_demo_hdmi_cfg)
else()
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "picozx81_olimexpc")
target_compile_definitions(${PROJECT} PUBLIC
-DDVI_DEFAULT_SERIAL_CONFIG=Olimex_RP2040_PICO_PC_cfg
-DDVI_USE_PIO_CLOCK)
if(${HDMI_SOUND})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "picozx81_olimexpc_hdmi_sound")
else()
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "picozx81_olimexpc")
endif()
endif()
elseif ((${PICO_BOARD} STREQUAL "lcdws28board"))
pico_generate_pio_header(${PROJECT} ${CMAKE_CURRENT_LIST_DIR}/display/st7789_lcd.pio)
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "picozx81_lcdws28")
else()
if (${PICO_BOARD} STREQUAL "vgaboard")
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "picozx81_vga")
Expand All @@ -132,11 +158,11 @@ else()
endif()

if (${TIME_SPARE})
target_compile_definitions(${PROJECT} PRIVATE -DTIME_SPARE)
target_compile_definitions(${PROJECT} PRIVATE -DTIME_SPARE)
endif()

if (${OVER_VOLT})
target_compile_definitions(${PROJECT} PRIVATE -DOVER_VOLT)
target_compile_definitions(${PROJECT} PRIVATE -DOVER_VOLT)
endif()

target_compile_options(${PROJECT} PRIVATE -Wall)
Expand All @@ -146,7 +172,6 @@ target_link_libraries(${PROJECT}
pico_stdlib
sdcard
fatfs
hardware_pwm
tinyusb_host
tinyusb_board)

Expand All @@ -159,4 +184,3 @@ endif()
pico_enable_stdio_usb(${PROJECT} 0)

pico_add_extra_outputs(${PROJECT})

56 changes: 48 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
+ [Developer Notes](#developer-notes)

# Features
+ Supports VGA, HDMI, DVI and LCD displays
+ Runs on the [Pimoroni Pico VGA demo board](https://shop.pimoroni.com/products/pimoroni-pico-vga-demo-base),
the [Pimoroni Pico DVI demo board (HDMI)](https://shop.pimoroni.com/products/pimoroni-pico-dv-demo-base), the [PicoMite VGA board](https://geoffg.net/picomitevga.html) and the [Olimex RP2040-PICO-PC](https://www.olimex.com/Products/MicroPython/RP2040-PICO-PC/open-source-hardware)
the [Pimoroni Pico DVI demo board (HDMI)](https://shop.pimoroni.com/products/pimoroni-pico-dv-demo-base), the [PicoMite VGA board](https://geoffg.net/picomitevga.html) the [Olimex RP2040-PICO-PC](https://www.olimex.com/Products/MicroPython/RP2040-PICO-PC/open-source-hardware) and the
[Waveshare Pico-ResTouch-LCD-2.8](https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8)
+ Supports sound over onboard DAC or PWM when available in hardware
+ Provides an immersive full screen experience, with a very fast boot time and no operating system
+ Simultaneous USB keyboard and joystick support (using a powered USB hub)
Expand All @@ -30,23 +32,45 @@ the [Pimoroni Pico DVI demo board (HDMI)](https://shop.pimoroni.com/products/pim
+ Set-up of emulator (computer type, RAM, Hi-Res graphics, sound, joystick control etc) configurable on a per program basis, using config files
+ Optionally displays graphic of keyboard (taken from [sz81](https://github.com/SegHaxx/sz81)). Can type in code with keyboard visible
+ Can be extended for other board types. Code support included for a custom VGA RGB 332 board similar to that supported by [MCUME](https://github.com/Jean-MarcHarvengt/MCUME)
+ Supports sound over HDMI (experimental)

## Example using a reproduction case
## Examples
### Installed in a reproduction case
The following images are taken with permission from a thread on [SinclairZXWorld](https://sinclairzxworld.com/viewtopic.php?f=3&t=5071&start=20) and show how user `computergui` has used picozx81 together with a case created by user `Spinnetti` to create a replica ZX80

<p align="middle">
<img src="images/open_case.jpg" width="48%" />
<img src="images/in_use.jpg" width="48%" />
</p>

### 3d printed ZX81 USB keyboard, USB joystick and LCD
The left image shows a system with a 3d printed ZX81 case being used as a [USB keyboard](https://github.com/ikjordan/ZX81_USB_KBD). A usb hub allows control via the keyboard and a joystick. The high resolution version of [Galaxians](http://zx81.eu5.org/files/soft/toddy/HR-Galax.zip) is displayed on screen

The right image shows the emulator running [MaxDemo](https://bodo4all.fortunecity.ws/zx/maxdemo.html), which generates a 320 by 240 display, exactly filling the 2.8 inch Waveshare LCD

<p align="middle">
<img src="images/lcd_system.jpg" width="46%" />
<img src="images/lcd.jpg" width="49.2%" />
</p>

### HDMI/DVI Output
To the left [ZX81 Hires Invaders](https://www.perfectlynormalsite.com/hiresinvaders.html) can be seen on a TV connected over HDMI. Sound can also be played over HDMI

To the right can be seen a status page, illustrating some of the configurable options for the emulator

<p align="middle">
<img src="images/invaders.jpg" width="51.0%" />
<img src="images/status.jpg" width="45.15%" />
</p>

# Quick Start
The fastest way to get started is to:
1. Write data onto a Micro SD Card
2. Install the pre-built binary onto your Pico
3. Connect your board to a keyboard and start exploring

## Populate the SD Card
1. Click [here](https://github.com/ikjordan/picozx81/releases/download/V1.0.0/sdcard.zip) to download a zip file containing files and directories to copy to an empty micro SD card
1. Click [here](https://github.com/ikjordan/picozx81/releases/latest/download/sdcard.zip) to download a zip file containing files and directories to copy to an empty micro SD card
2. unzip the file into the root directory of an empty micro SD Card
3. Insert the micro SD Card into your boards micro SD card slot

Expand All @@ -58,6 +82,9 @@ Click on the uf2 name corresponding to your board in the table below to download
| Pimoroni VGA | [`picozx81_vga.uf2`](https://github.com/ikjordan/picozx81/releases/latest/download/picozx81_vga.uf2)|
| Olimex PICO DVI | [`picozx81_olimexpc.uf2`](https://github.com/ikjordan/picozx81/releases/latest/download/picozx81_olimexpc.uf2)|
| PicoMite VGA | [`picozx81_picomitevga.uf2`](https://github.com/ikjordan/picozx81/releases/latest/download/picozx81_picomitevga.uf2)|
| Olimex PICO DVI with HDMI Sound| [`picozx81_olimexpc_hdmi_sound.uf2`](https://github.com/ikjordan/picozx81/releases/latest/download/picozx81_olimexpc_hdmi_sound.uf2)|
| Pimoroni DVI with HDMI Sound| [`picozx81_dvi_hdmi_sound.uf2`](https://github.com/ikjordan/picozx81/releases/latest/download/picozx81_dvi_hdmi_sound.uf2)|
| Waveshare 2.8 LCD | [`picozx81_lcdws28.uf2`](https://github.com/ikjordan/picozx81/releases/latest/download/picozx81_lcdws28.uf2)|


1. Connect your Board to your display using a VGA or HDMI cable, as appropriate for your board
Expand Down Expand Up @@ -120,6 +147,8 @@ The following can be configured:
3. If `NTSC` is set to `On` and `Centre` is set to `Off` then a black vsync bar will be seen at the bottom of the display for programs that generate a typical 192 line display
4. A higher tolerance value set for `VTOL` results in faster screen stabilisation. As for a real TV, a low tolerance level results in vertical sync being lost for some programs, such as [QS Defenda](http://www.zx81stuff.org.uk/zx81/tape/QSDefenda) and [Nova2005](http://web.archive.org/web/20170309171559/http://www.user.dccnet.com/wrigter/index_files/NOVA2005.p). The default value of 100 emulates a TV that very quickly regains vertical lock. Set the value to 15 to emulate a TV that struggles to maintain vertical lock. Run the [Flicker program](examples/ZX81/flicker.p) to see the effects of PAUSE on lock
5. The "Big Bang" ROM can double the speed of BASIC programs
6. The Waveshare LCD 2.8 board has no sound capabilities

### Joystick
In addition a USB joystick can be configured to generated key presses

Expand All @@ -143,7 +172,9 @@ Six extra options apply across all programs and can only be set in the `[default
| AllFiles| When set, all files are initially displayed when the [Load Menu](#f2---load) is selected. When off only files with extensions `.p`, `.o`, `.81` and `.80` are initially displayed|Off|
| MenuBorder | Enables a border area (in characters) for the [Load](#f2---load) and [Pause](#f4---pause) menus, useful when using a display with overscan. Range 0 to 4| 1 |

**Note:** By default the European ZX81 generates frames slightly faster than 50Hz (50.65Hz). Setting `FiveSevenSix` to `Match` enables a display mode slightly faster than the 50Hz TV standard, so that better synchronisation between the frame generates by the emulator and frames sent to the monitor can be achieved. If there are issues with a TV or monitor locking to 50.6 Hz, then `FiveSevenSix` can be set to `On` to generate an exact 50Hz frame rate
**Notes:**
1. By default the European ZX81 generates frames slightly faster than 50Hz (50.65 Hz). Setting `FiveSevenSix` to `Match` enables a display mode slightly faster than the 50Hz TV standard, so that better synchronisation between the frame generates by the emulator and frames sent to the monitor can be achieved. If there are issues with a TV or monitor locking to 50.65 Hz, then `FiveSevenSix` can be set to `On` to generate an exact 50 Hz frame rate
2. The Waveshare LCD 2.8 board has a fixed 320 by 240 resolution. `FiveSevenSix` therefore only sets the framerate for this board (50 Hz, 50.65 Hz or 60 Hz)

### Examples
Examples of the `config.ini` files used to test the programs listed in this [section](#applications-tested) can be found [here](examples)
Expand Down Expand Up @@ -202,9 +233,11 @@ Allows some values to be modified to see the impact of the changes without havin

The changes are *not* written back to the config files, so will be lost when the emulator is rebooted. Exit by pressing `Enter` to action the changes. Press `Escape` to exit without changes
### F8 - Reboot
Allows the impact of changes to display resolution and frequency to be seen without editing config files. If change are made and the menu is then exited by pressing `Enter` the Pico will reboot and use the new display mode. The changes are *not* written back to the main config files, so any changes will be lost on subsequent reboots
Allows the impact of changes to display resolution and frequency to be seen without editing config files. If a change is made and the menu is then exited by pressing `Enter` the Pico will reboot and use the new display mode. The changes are *not* written back to the main config files, so any changes will be lost on subsequent reboots.

On the Waveshare 2.8 LCD board the display resolution is fixed and only the frequency can be changed
## Loading and saving options
The emulator supports the loading `.p`, `.81`, `.o` and `.80` files from micro SD Card. It can save in `.p` and `.o` format.
The emulator supports loading `.p`, `.81`, `.o` and `.80` files from micro SD Card. It can save in `.p` and `.o` format.
Files to be loaded should only contain characters that are in the ZX81 or ZX80 character set
### Load
There are 3 ways to load files:
Expand Down Expand Up @@ -400,8 +433,13 @@ This will be named `picozx81_vga.uf2`
| Olimex PICO DVI |`cmake -DPICO_BOARD=olimexpcboard ..` | `picozx81_olimexpc.uf2`|
| Pimoroni VGA |`cmake -DPICO_BOARD=vgaboard ..` | `picozx81_vga.uf2`|
| Custom 332 VGA|`cmake -DPICO_BOARD=vga332board ..`| `picozx81_vga332.uf2`|
| Pimoroni DVI with HDMI sound|`cmake -DHDMI_SOUND=ON -DPICO_BOARD=dviboard ..` | `picozx81_dvi_hdmi_sound.uf2`|
| Olimex PICO DVI with HDMI sound|`cmake -DHDMI_SOUND=ON -DPICO_BOARD=olimexpcboard ..` | `picozx81_olimexpc_hdmi_sound.uf2`|
| Waveshare Pico-ResTouch-LCD-2.8|`cmake -DPICO_BOARD=lcdws28board ..`| `picozx81_lcdws28.uf2`|

**Note:** The [`buildall`](buildall) script in the root directory of `picozx81` will build `uf2` files for all supported board types
**Notes:**
+ The [`buildall`](buildall) script in the root directory of `picozx81` will build `uf2` files for all supported board types
+ The HDMI sound builds are experimental

6. Upload the `uf2` file to the pico
7. Populate a micro SD Card with files you wish to run. Optionally add `config.ini` files to the SD Card. See [here](examples) for examples of config files
Expand All @@ -416,6 +454,7 @@ This will be named `picozx81_vga.uf2`
**Note:** Testing has shown that all of these hubs can support OTG and power delivery to the Pico simultaneously
+ On rare occasion, some USB keyboards and joysticks fail to be detected when connected via powered hubs. A re-boot of the Pico often results in successful detection
+ The PicoMite VGA board has a PS/2 keyboard socket. Currently this is not supported, a USB keyboard must be used
+ The Waveshare Pico-ResTouch-LCD-2.8 board has touch controller, but the emulator does not support its use
+ The Olimex RP2040-PICO-PC has a stereo audio jack. ~~but the left channel cannot be used with HDMI, so only mono audio through the right channel is possible when using this board~~ The emulator now supports stereo sound on this board
+ The Olimex RP2040-PICO-PC board does not supply 5v to DVI pin 18. This may result in the board not being detected by some TVs. If necessary short the SJ1 connector so 5V is supplied
+ In an ideal world the latest versions of the excellent sz81 or EightyOne emulators would have been ported. An initial port showed that they are too processor intensive for an (overclocked) ARM M0+. An earlier version of sz81 ([2.1.8](https://github.com/ikjordan/sz81_2_1_8)) was used as a basis, with some Z80 timing corrections and back porting of the 207 tstate counter code from the latest sz81 (2.3.12). See [here](#applications-tested) for a list of applications tested
Expand All @@ -442,8 +481,9 @@ The initial port from sz81 2.3.12 onto the Pico ran at approximately 10% of real

Corrections to the tstate timings were made for `ld a,n; ld c,n; ld e,n; ld l,n; set n,(hl); res n,(hl);`
## Possible Future Developments
+ Add support for more LCD displays
+ Add vsync (TV) based sound
+ There are some interesting developments to extend PicoDVI to include audio over the HDMI signal
+ Experimental configurations supporting sound over the HDMI signal are available
+ Use the contents of a string variable to supply a file name to the ZX80 load and save commands
+ Support for USB gamepads as well as joysticks
+ Extend the VGA322 board type to support original DB9 joysticks
Expand Down
72 changes: 72 additions & 0 deletions boards/lcdws28board.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#ifndef _BOARDS_LCDWS28BOARD_H
#define _BOARDS_LCDWS28BOARD_H

// For board detection
#define RASPBERRYPI_LCDWS28BOARD

#define LCDWS28BOARD_SD_CLK_PIN 10
#define LCDWS28BOARD_SD_CMD_PIN 11 // MOSI
#define LCDWS28BOARD_SD_DAT0_PIN 12 // MISO

#define LCDWS28BOARD_LCD_DC_PIN 8
#define LCDWS28BOARD_LCD_CS_PIN 9
#define LCDWS28BOARD_LCD_BL 13
#define LCDWS28BOARD_LCD_RS 15

#define LCDWS28BOARD_SD_CS_PIN 22
#define LCDWS28BOARD_TS_CS_PIN 16

#define LCDWS28BOARD_PWM_L_PIN 28

#ifndef PICO_AUDIO_PWM_L_PIN
#define PICO_AUDIO_PWM_L_PIN LCDWS28BOARD_PWM_L_PIN
#endif

#ifndef PICO_SD_CLK_PIN
#define PICO_SD_CLK_PIN LCDWS28BOARD_SD_CLK_PIN
#endif

#ifndef PICO_SD_CMD_PIN
#define PICO_SD_CMD_PIN LCDWS28BOARD_SD_CMD_PIN
#endif

#ifndef PICO_SD_DAT0_PIN
#define PICO_SD_DAT0_PIN LCDWS28BOARD_SD_DAT0_PIN
#endif

#ifndef PICO_SD_CS_PIN
#define PICO_SD_CS_PIN LCDWS28BOARD_SD_CS_PIN
#endif

#ifndef PICO_LCD_DC_PIN
#define PICO_LCD_DC_PIN LCDWS28BOARD_LCD_DC_PIN
#endif

#ifndef PICO_LCD_CS_PIN
#define PICO_LCD_CS_PIN LCDWS28BOARD_LCD_CS_PIN
#endif

#ifndef PICO_LCD_BL_PIN
#define PICO_LCD_BL_PIN LCDWS28BOARD_LCD_BL
#endif

#ifndef PICO_LCD_RS_PIN
#define PICO_LCD_RS_PIN LCDWS28BOARD_LCD_RS
#endif

#ifndef PICO_TS_TS_PIN
#define PICO_TS_CS_PIN LCDWS28BOARD_TS_CS_PIN
#endif

// No sound output
#define PICO_NO_SOUND

// Share SPI bus
#define PICO_SPI_LCD_SD_SHARE

#define PICO_LCDWS28_BOARD

// lcdws28board has a Pico on it, so default anything we haven't set above
#include "boards/pico.h"

#endif
14 changes: 13 additions & 1 deletion buildall
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ build_uf2()
board=$1"board .."
uf2="picozx81_"$1".uf2"

cmake -DPICO_BOARD=${board}
cmake -DHDMI_SOUND=OFF -DPICO_BOARD=${board}
make -j4
cp ./${uf2} ../uf2/${uf2}
}

build_uf2_hdmi()
{
board=$1"board .."
uf2="picozx81_"$1"_hdmi_sound.uf2"

cmake -DHDMI_SOUND=ON -DPICO_BOARD=${board}
make -j4
cp ./${uf2} ../uf2/${uf2}
}
# Create the directories
mkdir -p build
mkdir -p uf2
Expand All @@ -22,3 +31,6 @@ build_uf2 dvi
build_uf2 picomitevga
build_uf2 olimexpc
build_uf2 vga332
build_uf2 lcdws28
build_uf2_hdmi dvi
build_uf2_hdmi olimexpc
Loading

0 comments on commit 86adc12

Please sign in to comment.