-
Case and future plans
02/28/2024 at 12:06 • 0 commentsI guess every project doesn't have to be brought to perfection. v06x-tiny/esp32 is not perfect but it's pretty great. It supports most essential features of Vector-06c, the sound is not as good as in the desktop v06x but it's fine for most games. There are things that are lacking, for example beeper support, or external ROM or joysticks or who knows what else.
But it runs most of the software, doesn't have a problem with the most demanding demos and all in a ll it's a pretty faithful reimagination of a modern Vector-06c. At this point I think it needs to get a case and a promotion from a pile of boards and wires on my desk to a proper dust collecting piece.
I considered various designs, some with upright screen placement, or even hinged screen like a real laptop. But this is really far beyond my normal mechanical capacity. I need something simple and efficient, IOW quadratisch, praktisch, gut.
I probed AI, hoping to get some useful design hints.:
It's not overly complex, easily printable and should do the job. Waiting for the print to come...
ESP32 "port" was more of a complete rewrite of the original project. In fact it revealed a lot of flaws with the old project. I dare not call this port complete, the code is still a complete nightmare. I need at least to toss files around for any semblance of logical arrangement. But it's something that can be done gradually as the time and inspiration allows.Meanwhile I have a Gowin Tang Nano 9K with exactly the same TFT display. And this could be pretty interesting.
At least on the surface, it seems a fairly decent chip, also packaged on a fairly neat board. Maybe it could become the core of v06x-tiny/fpga, who knows!
-
First OSD
11/26/2023 at 23:02 • 0 commentsSo SD card support has been extremely frustrating, to the point of complete despair. I'm still unable to make it work as I wanted it to, but I guess I managed to discover a narrow path, which if followed carefully allows safe passage from initial directory loading to loading file content, almost always. I'm still unable to show OSD and access SD card at the same time.
In the meantime I have found some really useful bits of code that should be standard in ESP32 SDK but they aren't:
- PSRAM allocator by atanisoft psram_allocator.h: allows allocating data for vectors in PSRAM
- better_readdir() with FatFs FILINFO struct access, allows for quick directory listing: instantly get file sizes
better_readdir() is particularly important because stat() in FatFs is excruciatingly slow, it takes 1-3 seconds just to get one file size. Why? Don't know.
I also made good use of Graphics from @bitluni ESP32Lib. Excellent library, not perfectly optimised but easy to make modifications to. I implemented BGR233 canvas and added clipping. My OSD buffer is thus fairly small as it's in 8-bits. This allows it to be stored in DRAM. It's copied to screen using routine similar to the one that copies the main Vector-06c buffer. That's not ideal because it's fairly CPU-heavy, but I just love it when it's shown next to the main screen.
This also made me add support for 1:1 horizontal scaling of the main screen, which is switched on when OSD is displayed. It could also be made an optional mode without OSD.
Curious bit: a program that only has nops, for example when it's empty RAM, is a worst case for the emulator because this means maximum amount of instructions per scanline. When something like this is executed, the OSD becomes really reluctant to react to user input. Some programs even have flicker at the top left corner of the screen. Something to deal with at some point later.
So far only ROM loading is implemented.
-
Tank capacitors on the Yellow Board (or lack thereof)
11/24/2023 at 20:28 • 0 commentsSo I though that loading files would be a trivial thing. So I implemented some basic ListView-like visual control for the OSD and started debugging it. Strange.. suddenly there are sdcard errors all over the place. Sometimes they are immediately after the start, sometimes later. But most frequently they appear after invoking the OSD. And if I invoke the OSD automatically at the boot time, the errors increase when the program executed by the emulator seems to create a heavier load on the emulator.
I tried a ton of regular things you do when trying to weed out a software error. All my stacks were silly oversized. I juggled around initialisation routines. Moved things between tasks and played with task priorities. Even sacrificed proper screen updates, giving SD card task the highest priority. But alas:
Searching for this kind of stuff also does rarely give useful input because every time it's someone forgot to connect a wire on a breadboard or something. But one of the discussions that I found mentioned power issues. 0x109 and CRC errors tend to be symptomatic to poor power delivery.
I examined the board and found buggerall capacitors:
There are some near the buck-boost converter near the USB-C connector and there's exactly 1 (one) 100nF capacitor near the ESP32 module. That's all. I suddenly remembered how this board sometimes doesn't want to boot, or wants me to plug it to another port on the hub, or seems to boot but then enters some weird loop and you need to replug it again...
Since yesterday I'm a happy owner of a brand new optical stereo microscope which I was eager to try out. Here's what I added:
220 tantalum and 10uF ceramic to the right of R15:
10uF ceramic near the ESP32 module. It has internal caps but it doesn't hurt having more:
All together:
Yes, it did fix the problem. SD card reads, no random inexplicable errors.Update:
although it does seem to help, it's not ideal anyway. There are still errors. They seem to appear less frequently when I power this board with a powerbank rather than USB hub.Update 2:
SD card problems persist and I'm not saying that they can only be explained by aliens, but it's aliens. I don't know if the capacitors helped anything at all now. Stuff is janky as usual.
-
rp2040 SPI slave woes (aka meh, should have used a 555...)
11/20/2023 at 10:49 • 1 commentTL;DR
- I managed to connect both SPI keyboard and SD card to the same SPI bus
- this should not feel like a victory over the forces of darkness, but it does
- never use rp2040 as SPI slave
- PIO is not a golden hammer
- when all hope is lost, try using peripheral registers bypassing SDK stuff
- ESP32 SPI master is very flexible despite its complexity and driver overhead
- should have used a 555
Now for the ranty log...
So the idea was that the mini keyboard uses a Pi Pico as a kind of universal interface adapter, something that you can plug in into a PC and have a little keyboard for your v06x emulator and simultaneously be able to attach it to v06x-mini board via SPI interface and use it with the esp32 hardware emulator. The board layout actually even allows it to be plugged in directly into the original steamy DIP-packagey Vector-06c -- however in this case PiPico should not be soldered down as it's not 5V tolerant and scanning the keyboard would most likely damage it. So it's amazing and should be easy, right?
Oh so wrong...
SPI keyboard matrix scanning
rp2040 SPI peripheral is fundamentally broken in every possible regard, at least when you're trying to implement a slave device. On top of it there's a very raw driver in the SDK which introduces another layer of brokedity. After a day or so trying to figure out why I can't receive 2 bytes, I found out that in order to be able to transfer more than one byte in one CS assertion, you absolutely must use SPI mode 3.
That's not really a problem, why not use mode 3 indeed. After a while though it turns out that in mode 3 somehow the bit position tends to get garbled and it results in a bit-shifted message. I can't figure out a way to consistently deliver it. The only solution that I can find is to automatically reset SPI peripheral on the PiPico if the message is not right. And it seems to work.
So the protocol at this point would be something like this. When a program on the host v06x encounters an OUT instruction that selects columns, it retransmits this selection to the PiPico. E.g. "0xe5 0xfe" to select column 0. Later IN instruction sends a request "0xe6 0x00" and receives rows in return. For some other technical reasons I had to add a third byte to be able to reliably get the data back.
So all of this is minor technical details, something you always deal with when putting relatively unknown pieces together. What matters is that albeit with more complexity and slightly less pretty than initially imagined, stuff works.
SD card
Enter the second peripheral.
So there's also an SD card, which is a must have. There are more free pins on ESP32, but on this board it is connected to the same bus, using all the same wires as the external SPI peripheral, except for the CS pin obviously. That was a known from the beginning, and it should never be a problem. SPI slaves hi-Z their I/O when CS is not asserted and have no impact on the bus whatsoever.
I'm really glad that the Espressif SDK has SD/MMC card and FAT components conveniently standardized. Huge kudos to them for doing that. So I have put together my first little test that would just list files on the card and print them in the console. However, the card would not mount. After verifying all pin connections and some frustrating searching for similar errors, I remembered about the keyboard. Some long troubleshooting hours later I realised that SD card works when I disconnect MISO pin from the keyboard, and only then. No matter what I would do, MISO line connected to PiPico with initialised SPI peripheral (completely regardless of mode) would mean total and complete bus sabotage. Beautiful.
I have long suspected that eventually I would have to use a custom SPI peripheral built using PIO. So this seemed like a good moment to try. But after some research, and much later than I should have, I found that the only example doing that that I could find needs consecutive pins in an arrangement not compatible with the standard SPI peripheral pins. Which I very much need because the board is routed with the standard SPI in mind. So PIO stuff goes out of the window...
My second (third, thwentieth?) idea was to manually control GPIO function, something that the SPI peripheral should do by itself but doesn't. Long story short, I have an interrupt handler that connects MISO to SPI peripheral when CS goes low and disconnects when CS goes back up. This is ridiculously stupid, but it's the only solution that works.
Unfortunately, this switchover in software takes time and even using exclusive ISR handler on GPIO transition I lose several clocks. This is where the super-resourceful ESP32 came to the rescue. Their SPI peripheral apparently was designed by actual people with actual brain working on it, so it has a ton of little tweaks that you don't immediately notice at first -- that is until you really need them and begin reaching for the straws. So there is one such spi_device_interface_config_t.cs_ena_pretrans, which allows you to specify an extra delay between pulling CS low and start of transmission. And it comes to rescue. By adding several clocks here I can compensate for the switchover delay. And magically my keyboard works again, sharing the same bus with SD card.
Then comes the question of being able to correctly transmit actual data in just a single 16-bit transaction (because in mode 0 you can't have more than one word, remember). But it's a relatively minor thing, I just had to abandon using API calls from the SDK and use the peripheral directly. Before a transaction, I prime the transmit buffer with the current state of modifier bits and rows so that the host gets the full status in every transaction.
Should have used a 555....
I don't know if choosing some shift registers over a rp2040 would make things significantly easier. I'm sure it would be very easy for some, I personally would manage to screw up something in this configuration as well. Besides, the keyboard is not just a 8x8 matrix, it's also 5 extra bits for modifier and reset keys and a LED, so that would add even more complexity to the discrete logic solution. I guess in the end my choice of microcontroller is as good as any.
-
512x256 mode support
11/16/2023 at 08:31 • 0 commentsPlatform
I noticed that it's not immediately obvious which hardware platform I'm using, because it's not exceedingly common. It's impossible to remember its name because is "ESP32-8048S050". It's cheap and yellow and it shares DNA with the better known "Cheap yellow display", but it's not the same. This one has a 800x480 IPS screen and it's driven directly by ESP32-S3 LCD peripheral, thus allowing me full control of refresh rate, making it as close to 50Hz CRT as possible.Now for the updates...
mode512
I was afraid it's not going to be possible because of timing constraints.But it turns out it's alright. I already implemented the key optimisation for this in the early stages of porting. The pixeling is done in pairs. So that each pair of pixels, which are always the same in 256-pixel mode, requires only one palette RAM access. So I already had the 2-pixel palette in place.
All I needed to add was some palette processing for the 512-pixel mode. The values for left-pixel would be replicated into every index on the right side, and the values for the right-pixel would be replicated into every index on the left side. When the mode switches, precalculated palette is copied in place swiftly. The main raster loop didn't need to be modified at all !
There's something about this version of BASIC called Бейсик-Корвет that I find magical. It's the font and the fact that it's hi-res and black and white and just a bit of childhood sparkle.
A video short featuring giant hands working tiny keys:
RUS led
This is a feature not really well supported in the emulators. The matter of fact is that it's an output line directly connected to a 8255 pin and as such it is subject to all the regular abuse like PWM. Strangely there are no programs known to me that would implement LED breathing for example. The emulators tend to just take the whatever value and display it at the end of a frame, if they bother to display it at all.In v06x-mini I initially tried to update it immediately, but for now I resorted to just output the state at the end of the frame like other emulators do. The reason for this is very slow SPI communication with ESP32 drivers, which takes at least one FreeRTOS tick to complete. I think implementing SPI link using SPI HAL should not be a problem, but it's a lower-priority task for now.
-
v06x-mini with keyboard
11/15/2023 at 07:27 • 0 commentsThe keyboard is attached via SPI, clocked at 8MHz. Pi Pico is SPI slave. Unlike most emulators that connect a PS/2 or USB keyboard, the keyboard matrix is scanned by the actual software. So each OUT to the column select port is sent over to the keyboard, and each IN from the rows port is then channeled back. There are exceptions for the keys that are off-matrix, those are scanned once per frame because some programs poll them frequently and SPI transactions are slow.
Some takeaway points from this stage:
- implementing an SPI slave sux
- RP2040 SPI can transfer more than one byte without raising CS line only in mode 3
- to send a command and get a response in the same transaction, you need at least 3 bytes
- ESP32 SPI peripheral is abstracted af, I still have no idea how to just send a bloody byte without making a fuss about it
- The minimum wait time for transaction to complete in spi_device_polling_end() and spi_device_polling_transmit() is 1 FreeRTOS tick, which is insane when you're running a tight loop at the beam speed.
- RP2040 SPI in contrary is easy to track down to the registers, but the standard driver and the peripheral hardware seems to be janky af
Please correct me if I'm mistaken in any of the above points, or point to solutions. I'm particularly interested in lower-level, more barebone access to ESP32-S3 SPI peripheral. For example, I can't properly output LED status in due time without hiccupping the main loop because it must wait for a whole FreeRTOS tick. It's not a problem in 100%-o(n) cases because nobody uses keyboard LED for anything useful, but I know that it's not right and it bothers me.
Things that need to be done for this thing to be a useful Vector-06c:- 512 pixel mode
- Beeper support and better 8253 sound
- SD card support
- A case
Not many games use 512 pixel mode. It is essential for everything MicroDOS or CP/M. It's not the most amazing stuff v06c-wise, but it's sometimes also the most advanced stuff. The problem with it is that it 1) adds a conditional to the very very tight loop of the pixel filler and 2) can't use the same pixel-filling trick that I'm using for the regular 256-pixel mode. In other words, I'm not sure if it's possible to do at all.
8253 support is currently limited, beeper is not supported at all. I need to implement them differently, taking notes from the AY implementation from ZX-ESPectrum project.
SD card support is just dead boring because it also means some UI to be usable and that's some completely separate project that I don't really find entertaining.
A case... I have some cardboard boxes.
-
Keyboard
11/10/2023 at 22:03 • 0 commentsIts destined to be used with v06c-mini. Meanwhile...
Bullet points summary:
- The switches are SKPMAME010.
- The original matrix is kept for hypothetical compatibility with the original, but Pi Pico is added for comfort
- Keycaps with engravings are designed in Blender, printed in resin by a commercial 3d printing service
- Engravings are filled in with water-based white paint and fixed using acrylic spray
- QMK firmware for quick PC compatibility
- This is a keyboard for ants
-
Audio: 8253 + AY-3-8912
11/01/2023 at 15:17 • 0 commentsI'm considering this a major milestone because audio can be very resource-hungry in a tight loop of an emulator running on a microcontroller. I had to rework a huge part of v06x in order to make it work on this board. I started with something like 1/4 of desired frame rate and in the end of optimisation I had it running at 65fps instead of required 50. This was very handy because now I can burn those extra cycles on audio support.
v06x has relatively simple sound: it samples outputs on every clock, then the result is downsampled to 48kHz using polyphase rational resampler. So that all strange PWM effects on the 8253 and Beeper sound nice in emulation. Unfortunately it's impossible to call timer on every clock cycle on ESP32 so the audio is processed in chunks and sampled twice per video line, that's 624 samples/frame, or 31200 samples/second.
This works for most regular sounds, but breaks when a music routine goes for a frequency above sample rate. I'm just cutting down those frequencies for now.
AY support is mostly borrowed from the amazing ZX-ESPectrum project. It's cleverly done because it processes the required amount of samples on demand, so only before an OUT instruction and at the frame end. This reduces overhead a lot. Unfortunately because of what I believe is a bug in the LCD driver, I can't fully offset the processing in one fat call without altering my emulator loop significantly. Instead, I broke the processing into 6-line chunks, just like video. This still stresses out the system a bit too much near the top of the screen, but in most cases it's not visible.
I should borrow some of the ideas from ZX-ESPectrum for my 8253 and beeper implementation. But that's for the future. For now I think keyboard support should be the next most important milestone.
-
Updates: mini keyboard and ESP32-S3
10/23/2023 at 08:46 • 0 commentsSome updates on the project that has been mostly dead for a few years.
The mini keyboard
More or less as originally planned, but I printed the keycaps in resin at JLCPCB. Filled in the engravings with gouache water-based paint, wiped off the excess and fixed it with a transparent acrylic spray. The legends look legendary, especially for their tiny size.
The switches are the same as originally planned, SKPMAME010. They feel squishy but for a little toy keyboard they are very nice, they even have pretty decent travel. There is some binding between the caps, but I'm sure it can be sorted out by filing the edges.
The computer
part of it is giving me more trouble. I was having high expectations from the kit commonly named5.0inch ESP32-8048S050, it's available in China for around $35. I liked it because it uses a very nice 800x480 LCD panel that can do 50Hz, which is very desirable for v06c, and ESP32-S3, which has its own LCD panel controller which is flexible enough to do just what I need. It also has most things already in place so I don't have to bother with my own board, rare connectors, SD card slot.. It's all assembled here in one very pretty package, which I can only recommend -- just probably not yet for the purpose of Vector-06c emulation.
The reality of using it is a bit harsh. While I was able to make it scale v06c picture at 50Hz using crude integer nearest-neighbour interpolation, I've been struggling to make v06c emulator work at the required pace. Vector-06c has a programmable palette, which makes it finicky to emulate and these details consume CPU cycles in the main emulation loop. They also don't let the scaler use the bitplane buffer directly, so I can't offload the palette work to the scaler core without losing compatibility with various raster and multicolour effects.
Pictured above, it is running Vector-06c emulation at 50Hz though so there is some promise. There's no I/O and no sound. I can push it to 53Hz. That's some headroom, but not enough to squeeze in 8253 timer/counter. ESP32 was shown to be a good emulation platform previously, but with v06c it could be that it has met its match and we need more power.
Speaking of more power, there is an interesting bit of kit called Tang Nano 9K FPGA Development Board GOWIN GW1NR-9 RISC-V HDMI https://aliexpress.com/item/1005004147687144.html -- it's an FPGA of strange Gowin variety with its strange set of tools, which makes me reluctant to try it. But it seems to have all the oomph needed to run vector06cc (my Vector-06c FPGA emulation project). What makes it really attractive is that it also has a 50-pin RGB panel connector and even ships with a display. Definitely something to keep an eye on.
I think the mini-keyboard part could be valuable on its own. I'll be publishing the design files after I verify that it maybe actually works. Stay tuned. -
Couleurs
07/20/2020 at 19:33 • 2 commentsReady to be ruined by misaligned decals: