Home Archives About
moefh.github.io
The Magic Smoke Has Left the Building
New VGA Boards

In the process of creating a new perfboard to connect the Pico to a VGA monitor, I realized that all the VGA DACs I made so far are using only half the voltage range, which results in a very dark image all around.

Here's what I figure happened: the initial schematic I drew for a the DAC used a 75 Ohm resistor to ground, which I initially put there to represent the one inside the monitor (so I could calculate the values for the other resistors). Later, when building the boards, I put that 75 Ohm resistor on the board, so there were TWO 75 Ohm resistors to ground in parallel, which results in everything being roughly half the voltage it's supposed to be. Later, when looking at that schematic, I though I had put that resistor there for impedance matching (which I knew was not really right), so I left it alone.

When I started builiding a perfboard for the Pico (to make it more permanent that the breadboard I had last week), I decided to calculate everything from scratch, and I realized the mistake. My correction still uses a 75 Ohm to ground, but the other resistors have much lower values to compensate. The current drawn from the pins is much larger, but still below 15 mA, so I think that will bo OK for the Pico and the ESP32.

Here's the new schematic for each DAC:

New DAC schematic
New DAC schematic

And here's the Loser Corps screen with the new DACs:

Loser Corps running on the Pico with the new DACs
Loser Corps running on the Pico with the new DACs

Here's the screen with the old DACs for comparison:

Screen with the old DACs
Screen with the old DACs

The new perfboards have the resistors soldered on the main board where the the Pico and the ESP32 are inserted, and the small boards with the VGA connectors have with nothing but female headers with 6 pins to connect to the main board. This way, if I ever want to change DACs again, I don't have to solder wires to the VGA connector (which is a very unpleasant job).

New perfboards
New perfboards

The Pico board has two sets of connections for I2C (for the Wii Nunchuk). I'll add these connections to the ESP32 board later.

Porting Loser Corps to the Raspberry Pi Pico

I decided to take a break from porting Loser Corps to the ESP32, and do something completely different: port Loser Corps to the Raspberry Pi Pico!

Loser Corps rendered on the Raspberry Pi  Pico
Loser Corps rendered on the Raspberry Pi Pico

The Pico is smaller than the ESP32, with about half as much RAM, flash and clock frequency:

ESP32-WROOMFeatureRaspberry Pi Pico
(2x) Tensilica Xtensa LX6Processor(2x) Arm Cortex-M0+
240 MHzClock133 MHz
520 KBRAM264 KB
4 MBFlash2 MB
2.4 GHzWiFinope

The Pico (like the ESP32) can adjust its main clock frequency: 133 MHz is the official maximum, but I'm using it at 125 MHz because that makes VGA signal generation much simpler: the 12.5 MHz pixel clock required for the 320x240 VGA mode is exactly 1/10 of the main clock (well, technically it should be 12.59 MHz, but 12.5 is close enough).

The Pico connected to my homemade DACs and a Wii Nunchuk. Ignore the row of LEDs on the second breadboard, I was using them to debug the output of my PIO program.
The Pico connected to my homemade DACs and a Wii Nunchuk. Ignore the row of LEDs on the second breadboard, I was using them to debug the output of my PIO program.

There are some example programs that output VGA using an official library provided by the Raspberry Pi Foundation, but they don't work with my old CRT monitor. I haven't looked at the library or the examples too closely, but it seems that the pixel clock they use is too far away from the spec for my monitor: 640x480 should be 25.18 MHz, and from what I can tell the examples use 24.0 MHz.

One of the cool things about the Pico is that it has a programmable input/output (PIO) hardware interface, which is basically a tiny specialized processor that can run programs that perform I/O operations independently from the main cores. I used the PIO (fed via DMA) for the VGA output.

After a lot of trial and failure, I went with an extremely simple PIO program: it's just a single instruction that gets data from the DMA and feeds it one byte at a time to 8 output pins. The data has to be prepared exactly the right way so the output is a correctly-timed VGA signal, which is stays right as long as the PIO program runs at a fixed frequency equal to the VGA pixel clock. In practice, this means that the images still need vertical and horizontal sync bits embedded in them, like in the ESP32.

Maybe I will make a more complex PIO program when I get more experience with it. It would be nice to make the program generate the vertical and horizontal sync signals automatically, and free 2 bits of image data for colors: we could have 3:3:2 bits for red:green:blue, increasing the number of colors from 64 to 256. For now, though, the output is exactly the same as the ESP32 (2:2:2), which is nice because I don't have to make new homemade DAC boards to connect to the monitor. Still, a really good advantage of the PIO (even running my brain-dead program) over the I2S bus we use on the ESP32 is that it doesn't scramble the byte order.

Even after everything was running, I ended up with problems with the IRQ handler for the DMA completion (which restarts the DMA to keep the PIO fed with data). When the CPU got too busy (for example, in areas of the map with too many things on the screen), the IRQ was being delayed enough do disrupt the video signal, and my monitor really didn't like it. In the end I managed to make the render loop run entirely without CPU supervision (it runs entirely on DMA shoving data into the PIO), and it only generates and IRQ for frame counting, which the game code uses to synchronize the framebuffer swapping (to avoid screen tearing).

The only parts actually done right now are the rendering and joystick input (Wii nunchuk and classic controller only). The character control and collision detection will be done soon.

Porting Loser Corps to the ESP32 - Part 7

More progress in porting Loser Corps to the ESP32 (see all posts about the port).

The game now sends shots over the network, so players can see each other's shots:

Two players shooting
Two players shooting

(Please excuse me for not showing the two systems and screens side-by-side, it's a pain to move everything around only to take a quick picture.)

Another change: the game runs at 320x240 with WiFi enabled even when compiled under the Arduino IDE, since I found out how to decrease the number of WiFi buffers without recompiling the ESP-IDF WiFi component. It turns out that the number of rx/tx buffers used in WiFi is set in the struct returned by WIFI_INIT_CONFIG_DEFAULT(), which initializes the fields to values defined in the WiFi component configuration. Decreasing the values before passing the struct to esp_wifi_init() does the trick.

To make it work in the Arduino IDE, I just had to stop using the Arduino WiFi object and use the ESP-IDF API directly. One small snag I ran into was that the ESP-IDF version used by the Arduino Core is pretty old, and to initialize the network you had to call tcpip_adapter_init() instead of the current esp_netif_init(). Once I solved that, the network code compiles and runs with no problems. There's just an annoying error that pops out in the serial complaining that I haven't created an event loop, which I think is required for the Arduino Core WiFi object to receive WiFi events. The game seems to run fine without it, though.

As usual, the source code is here: https://github.com/moefh/esp32-loser