1
0
mirror of https://github.com/fruit-bat/pico-zxspectrum.git synced 2025-04-19 00:04:01 +03:00

Merge pull request #202 from fruit-bat/feature/bobvgalcd

Support for new Bobricius board
This commit is contained in:
fruit-bat 2025-01-28 21:28:57 +00:00 committed by GitHub
commit fe73774aff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 137 additions and 43 deletions

View File

@ -85,6 +85,7 @@ Click on the images below for more information ...
</tr>
</table>
<a href="docs/ZxSpectrumPicomputerZx2Lcd.md"><img src="docs/picozx2lcd.png" width="280"/></a>
<a href="docs/pico_zx48_128.md"><img src="docs/pico_zx48_128_1.png" width="300"/></a>
<a href="docs/ZxSpectrumPicomputerZxLcd.md"><img src="docs/picozxlcd.png" width="280"/></a>
<a href="docs/ZxSpectrumPicomputerVga222Zx.md"><img src="docs/picomputer_picozx.png" width="300"/></a>
@ -103,6 +104,7 @@ Click on the images below for more information ...
| [HDMI breadboard](docs/ZxSpectrumBreadboardHdmiNPinAudio.md) | Some breadboard HDMI options |
| [VGA breadboard](docs/ZxSpectrum4PinAudioVga1111Ps2.md) | Some breadboard VGA options |
| [PICO ZX48/128](docs/pico_zx48_128.md) | ZX Spectrum 48K replacement board by Bobricius |
| [PICOZX2 LCD](docs/ZxSpectrumPicomputerZx2Lcd.md) | ZX Spectrum with LCD and VGA Mk 2 by Bobricius |
| [PICOZX LCD](docs/ZxSpectrumPicomputerZxLcd.md) | ZX Spectrum with LCD and VGA by Bobricius |
| [PICOZX](docs/ZxSpectrumPicomputerVga222Zx.md) | ZX Spectrum with VGA by Bobricius |
| [RetroVGA](docs/ZxSpectrumPicomputerVga.md) | VGA micro-computer by Bobricius |

View File

@ -0,0 +1,46 @@
### ZxSpectrumPicomputerZx2Lcd
This is a target written for Bobricius' PICOZX mk 2 with built in LCD
<img src="picozx2lcd.png" width="400"/>
It supports:
* USB keyboard
* Keyboard martix
* USB joysticks
* VGA video (RGB222)
* LCD video (ST7789)
* PWM sound (1 pin)
* SPI SD card
By default, the board starts up using VGA as its display.
To boot into LCD mode hold down the 'fire' button during reset.
Placing lcd.txt on the SD card in the zxspectrum folder changes the default to LCD.
While on the menu...
* SHIFT-Fire = ESC
* RELOAD = Backspace
* SHIFT-RELOAD = Del
#### Circuit Diagrams
None as yet
#### Firmware
| LCD | Colour Encoding | Colour Channel | VGA | Sock | Firmware |
| - | - | - | - | - | - |
| ST7789 | BGR | Normal | 640x480x60Hz | Pico2 | [ZxSpectrumPicomputerZx2Lcd_640x480x60Hz.uf2](/uf2-rp2350-arm-s/ZxSpectrumPicomputerZx2Lcd_640x480x60Hz.uf2) |
| ST7789 | BGR | Normal | 720x576x50Hz | Pico2 | [ZxSpectrumPicomputerZx2Lcd_720x576x50Hz.uf2](/uf2-rp2350-arm-s/ZxSpectrumPicomputerZx2Lcd_720x576x50Hz.uf2) |
#### Build system notes
The make system has some switches to adapt it to different LCD panels:
| Symbol | Description | PICOZX | ILI19341 |
| ------ | ----------- | ------ | -------- |
| LCD_INVERSE | invert the brightness of the RGB color components | undefined | defined |
| LCD_MIRROR_X | Mirror the LCD output horizontally | defined | undefined |
| LCD_RGB | Use RBG order rather than BGR | undefined | defined |
#### References
[ILI9341 datasheet](https://cdn-shop.adafruit.com/datasheets/ILI9341.pdf)<br/>

BIN
docs/picozx2lcd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@ -291,4 +291,17 @@ if (${PICO_BOARD} STREQUAL "pico")
message("Relevant target: ZxSpectrumPicomputer")
add_dependencies(relevant ZxSpectrumPicomputer)
endif()
########################################################################
# Picomputer 2 II (RP2350 Only)
########################################################################
add_custom_target (ZxSpectrumPicomputer2)
add_dependencies (ZxSpectrumPicomputer2
ZxSpectrumPicomputerZx2Lcd_640x480x60Hz
ZxSpectrumPicomputerZx2Lcd_720x576x50Hz
)
if (${PICO_BOARD} STREQUAL "pico2")
message("Relevant target: ZxSpectrumPicomputer2")
add_dependencies(relevant ZxSpectrumPicomputer2)
endif()

View File

@ -38,23 +38,27 @@ PicoOnScreenKeyboard::PicoOnScreenKeyboard(
});
onPaint([=](PicoPen *pen) {
pen->printAt(0, 0, false, getKeyboardLine(0));
pen->printAt(1, 2, false, getKeyboardLine(1));
pen->printAt(2, 4, false, getKeyboardLine(2));
pen->printAt(0, 6, false, getKeyboardLine(3));
});
if (ww() > 42) {
paintRow(pen, 0, 0);
paintRow(pen, 1, 1);
paintRow(pen, 2, 2);
paintRow(pen, 0, 3);
}
else {
paintRow(pen, 0, 0);
paintRow(pen, 0, 1);
paintRow(pen, 0, 2);
paintRow(pen, 0, 3);
}
});
};
const char* PicoOnScreenKeyboard::getKeyboardLine(uint8_t which) {
int Pos=0;
for (int i=0; i < 10; i++) {
Pos+=sprintf(Buff+Pos," %s ",Line[which][i].Name);
void PicoOnScreenKeyboard::paintRow(PicoPen *pen, int32_t ox, uint8_t r) {
const int32_t y = r << 1;
for (int i = 0; i < 10; i++) {
const bool c = r == _y && i == _x;
if (c) pen->setAttrInverse(true);
pen->printAt(ox + (i << 2), y, false, Line[r][i].Name);
if (c) pen->setAttrInverse(false);
}
//Selected symbol
if(which==_y) {
Buff[_x*5]='[';
Buff[_x*5+4]=']';
}
return Buff;
}

View File

@ -10,7 +10,6 @@ class PicoOnScreenKeyboard : public PicoWin {
int8_t _x=0;
int8_t _y=0;
char Buff[52];
#define BIT0 0x01
#define BIT1 0x02
@ -80,12 +79,6 @@ const ZxSpectrumKey Line[4][10]={
}
};
/*
const uint8_t Line[4][10]={{'1','2','3','4','5','6','7','8','9','0'},
{'Q','W','E','R','T','Y','U','I','O','P'},
{'A','S','D','F','G','H','J','K','L','<'},
{'*','Z','X','C','V','B','N','M','*','_'}};
*/
public:
PicoOnScreenKeyboard(int32_t x, int32_t y, int32_t w,int32_t h);
@ -95,5 +88,5 @@ public:
_press = press;
}
const char* getKeyboardLine(uint8_t which);
void paintRow(PicoPen *pen, int32_t ox, uint8_t r);
};

View File

@ -61,7 +61,7 @@ static const char *fext(const char *filename) {
return dot + 1;
}
void ZxSpectrumMenu::setWizLayout(int32_t margin, int32_t cols1, int32_t cols2) {
void ZxSpectrumMenu::setWizLayout(int32_t margin, int32_t cols1, int32_t cols2, int32_t w) {
_wizCol1Width = cols1;
_wizCol2Width = cols2;
_wizLeftMargin = margin;
@ -76,6 +76,7 @@ void ZxSpectrumMenu::setWizLayout(int32_t margin, int32_t cols1, int32_t cols2)
_mouse.move(0, 0, _wizCols, _mouse.wh());
_devices.move(0, 2, _wizCols, _devices.wh());
_tzxSelect.move(0, 0, _wizCols, _tzxSelect.wh());
_keyboard.move(0 , 0, w, 10),
repaint();
}
@ -138,7 +139,7 @@ ZxSpectrumMenu::ZxSpectrumMenu(
_systemBootSelOp("Boot select"),
_volume(0, 0, 16, 16),
_keyboard(((SZ_FRAME_COLS-54)/2)-2 , 0, 52, 30),
_keyboard(((SZ_FRAME_COLS-44)/2)-2 , 0, 52, 10),
_devices(0, 2, _wizCols, 2),

View File

@ -131,7 +131,7 @@ public:
void nextSnap(int d);
void quickSave(int slot);
void quickLoad(int slot);
void setWizLayout(int32_t margin, int32_t cols1, int32_t cols2);
void setWizLayout(int32_t margin, int32_t cols1, int32_t cols2, int32_t w);
void initialise();
void saveSettings();
void loadSettings();

View File

@ -188,6 +188,8 @@ foreach(target
ZxSpectrumPicomputerZxInverseLcd_720x576x50Hz
ZxSpectrumPicomputerZxILI9341Lcd_720x576x50Hz
ZxSpectrumPicomputerZxILI9341Lcd_640x480x60Hz
ZxSpectrumPicomputerZx2Lcd_720x576x50Hz
ZxSpectrumPicomputerZx2Lcd_640x480x60Hz
)
add_executable(${target}
${picomputer_zx_lcd_src}
@ -253,3 +255,22 @@ target_compile_definitions(ZxSpectrumPicomputerZxILI9341Lcd_640x480x60Hz PRIVATE
LCD_RGB
)
target_compile_definitions(ZxSpectrumPicomputerZx2Lcd_720x576x50Hz PRIVATE
${picomputer_zx_lcd_common_defines}
${zxspectrum_zx_lcd_720x576x50Hz_defines}
LCD_MIRROR_X
REAL_ZXKEYBOARD
REAL_ZXKEYBOARD_BOB
HID_KEY_MOD_SAVE=2
PICO_STARTUP_VGA
)
target_compile_definitions(ZxSpectrumPicomputerZx2Lcd_640x480x60Hz PRIVATE
${picomputer_zx_lcd_common_defines}
${zxspectrum_zx_lcd_640x480x60Hz_defines}
LCD_MIRROR_X
REAL_ZXKEYBOARD
REAL_ZXKEYBOARD_BOB
HID_KEY_MOD_SAVE=2
PICO_STARTUP_VGA
)

View File

@ -48,13 +48,15 @@
#define LED_PIN 25
#define VREG_VSEL VREG_VOLTAGE_1_20
struct semaphore dvi_start_sem;
#ifdef PICOMPUTER_PICOZX_LCD
#ifdef PICO_STARTUP_VGA
static bool useVga = true;
#else
static bool useVga = false;
#endif
#endif
static SdCardFatFsSpi sdCard0(0);
@ -197,19 +199,21 @@ void __not_in_flash_func(process_joystick)() {
}
}
static PIO pio = pio0;
static uint sm = 0;
void __not_in_flash_func(setMenuState)(bool showMenu) {
picomputerJoystick.enabled(!showMenu);
pzx_menu_mode(showMenu);
}
static PIO pio = pio0;
static uint sm = 0;
#ifdef PICOMPUTER_PICOZX_LCD
void __not_in_flash_func(ZxScanlineVgaRenderLoopCallbackLine)(uint32_t y) {
pzx_keyscan_row();
}
void __not_in_flash_func(ZxScanlineVgaRenderLoopCallbackMenu)(bool state) {
setMenuState(showMenu);
}
#endif
@ -233,7 +237,7 @@ void __not_in_flash_func(core1_main)() {
#endif
picoRootWin.move(0,0,40,30);
picoRootWin.setWizLayout(0, 12, 18);
picoRootWin.setWizLayout(0, 12, 18, 40);
// Start up the LCD
st7789_init(pio, sm);
@ -364,7 +368,6 @@ int main() {
picoRootWin.snapLoaded([&](const char *name) {
showMenu = false;
toggleMenu = false;
setMenuState(showMenu);
}
);
// TZX tape option handlers
@ -379,7 +382,6 @@ int main() {
picoRootWin.showTzxOptions();
showMenu = true;
toggleMenu = false;
setMenuState(showMenu);
}
);
picoRootWin.tzxOption(
@ -387,7 +389,6 @@ int main() {
zxSpectrum.tzxOption(option);
showMenu = false;
toggleMenu = false;
setMenuState(showMenu);
}
);
snapFileLoop.set(&picoRootWin);
@ -408,9 +409,14 @@ int main() {
pzx_keyscan_init();
#ifdef PICOMPUTER_PICOZX_LCD
#ifdef PICO_STARTUP_VGA
useVga = !pzx_fire_raw();
ZxSpectrumFatSpiExists swap_option(&sdCard0, "zxspectrum", "lcd.txt");
#else
useVga = pzx_fire_raw();
ZxSpectrumFatSpiExists vgaoption(&sdCard0, "zxspectrum", "vga.txt");
useVga |= vgaoption.exists();
ZxSpectrumFatSpiExists swap_option(&sdCard0, "zxspectrum", "vga.txt");
#endif
if (swap_option.exists()) useVga = !useVga;
#endif
sem_init(&dvi_start_sem, 0, 1);

View File

@ -21,7 +21,6 @@
#include "ZxSpectrumPicomputerJoystick.h"
#include "ZxSpectrumHidMouse.h"
#include "bsp/board.h"
#include "tusb.h"
#include <pico/printf.h>
@ -38,9 +37,6 @@
#include "hid_app.h"
#define LED_PIN 25
#define SPK_PIN 9
#define VREG_VSEL VREG_VOLTAGE_1_20
struct semaphore dvi_start_sem;
@ -185,6 +181,10 @@ void __not_in_flash_func(process_joystick)() {
}
}
void __not_in_flash_func(setMenuState)(bool showMenu) {
picomputerJoystick.enabled(!showMenu);
pzx_menu_mode(showMenu);
}
void __not_in_flash_func(ZxScanlineVgaRenderLoopCallbackLine)(uint32_t y) {
pzx_keyscan_row();
}
@ -243,7 +243,7 @@ void __not_in_flash_func(main_loop)(){
}
}
int main(){
int main() {
pico_set_core_voltage();
ZxScanlineVgaRenderLoopInit();
@ -258,6 +258,7 @@ int main(){
picoRootWin.snapLoaded([&](const char *name) {
showMenu = false;
toggleMenu = false;
setMenuState(showMenu);
}
);
// TZX tape option handlers
@ -272,6 +273,7 @@ int main(){
picoRootWin.showTzxOptions();
showMenu = true;
toggleMenu = false;
setMenuState(showMenu);
}
);
picoRootWin.tzxOption(
@ -279,6 +281,7 @@ int main(){
zxSpectrum.tzxOption(option);
showMenu = false;
toggleMenu = false;
setMenuState(showMenu);
}
);
snapFileLoop.set(&picoRootWin);

View File

@ -84,6 +84,10 @@ void __not_in_flash_func(pzx_menu_mode)(bool m) {
#endif
}
bool pzx_menu_mode() {
return menu != 0;
}
// Keyboard Matrix Arrays [INDEX][ROWS][COLS]
#ifdef PICOMPUTER_PICOZX
#define JOYSTICK_OFFSET 2

View File

@ -7,5 +7,6 @@ void __not_in_flash_func(pzx_keyscan_row)();
uint8_t __not_in_flash_func(pzx_kempston)();
void __not_in_flash_func(pzx_keyscan_get_hid_reports)(hid_keyboard_report_t const **curr, hid_keyboard_report_t const **prev);
void __not_in_flash_func(pzx_menu_mode)(bool menu);
bool pzx_menu_mode();
bool pzx_fire_raw();