Christmas holidays are over and with it, my loooong days testing the CPC2.3 board are also over. So before I go back to work, here’s the current state of the CPC2. Spoiler: It’s GREAT!
The application used for testing is copyright Firebird and Telecomsoft.
These components have been tested and working:
- Altera/Intel FPGA Cyclone V
- 2 x 16MB PSRAM, one for video and one for the CPC
- ADV7513 HDMI output, in full 24-bit colour
- eMMC (albeit 4GB rather than the eventual 16GB) (*new*)
- Microchip USB3320 USB2 interface (*new*)
- Spansion S25FL256S 32MB NOR-Flash (*new*)
In my last post, I noted that I still couldn’t get the NOR flash programmed with a bitstream image for the FPGA. I thought I’d wired the DI/DO pins backwards, despite triple-checking the connections. It turns out that the Spansion chip wasn’t supported by the Quartus serial flash loader. Programming the chip through the JTAG-indirect method (.jic file) failed for any operation such as erase, blank check or program. Fortunately, Intel has continued to invest in Quartus since the acquisition of Altera. Quartus Prime 19.1 does support the Spansion S25FL256S directly with it’s Generic Serial Flash Interface IP. This means that JIC programming is possible, giving the FPGA an ‘instant-on’ boot up as well as providing a read-only source of ROMs and floppy disk images.
Not working is the ESP32 based WROOM-32. Ironically, I joked with a colleague at work that I wasn’t worried about testing the ESP32 as I ‘knew’ this would work. He laughed as he repeated my words back to me. As the department head for the embedded electronics team, so I probably should have listened to his mocking words! To my credit, the ESP32 worked for a while but stopped working after a few weeks with FLASH errors. I think that hand-soldering these devices is probably not a good idea and I may have damaged the sensitive components under the RF shield with the hot air pencil. I may or may not replace this on the dev board, but it will definitely need to be placed on the top side of the board for the next build so that it goes through the recommended reflow heat profile.
Debugging the WROOM32
Debugging the ESP32 was an exercise in frustration, as I didn’t have a separate UART port to monitor the ESP32 console. Further, the errors kept changing, even without code changes, so I knew something fundamentally weird was going on with this module. There are only 2-power lines, 2-UART lines going to the ESP32 (ignoring the JTAG and programming lines), so if any of these were not connected, it just wouldn’t work at all. The random failures suggested a hardware fault on the WROOM32 board itself.
I resorted up propping hook-up cable into the console UART notches attached to a USB-Serial cable so that I could watch the boot messages come up. Every bump or knock on the workspace dislodged the wires and I had to reconnect them to restart the test again. I expected the application to be providing some sort of error message when trying to broadcast via Bluetooth. What was really surprising was that the application was failing to boot with either CRC failures or application signature failures.
I had to do a lot of reading around the data structure expected by the ESP32 in the flash memory. The boot loader appeared to work, so I tried moving the application to a different memory location. This required an update to the partition table and more reading.
While the default programming instruction (program_esp32) and verification seemed to work, I really wanted to verify for myself that the flash memory contents were exactly what I expected them to be. I used this command to flash the bootloader, partition table and application image to the memory:
openocd -f interface.cfg -f board/esp-wroom-32.cfg -c “init; reset halt; flash erase_address 0x1000 0x3ff000; flash write_bank esp32 build/bootloader/bootloader.bin 0x1000 ; flash write_bank esp32 build/partitions_singleapp.bin 0xc000 ; flash write_bank esp32 build/bt_spp_acceptor_demo.bin 0x100000; exit”
Then I would extract the memory to a file and compare it to the original image using this. Running this will open a server to allow ad-hoc instructions:
openocd -f interface.cfg -f board/esp-wroom-32.cfg
Then;
telnet localhost 4444
Trying 127.0.0.1…
Connected to localhost.
Escape character is ‘^]’.
Open On-Chip Debugger
>
There are a whole bunch of flash commands available, and using help flash will list these. For my purposes, this command would extract the flash memory to a file:
flash read_bank esp32 /tmp/testfile 0x100000 0x????????
where 0x?????? is the length of the application image. I can then use a linux diff command on both this extracted image and the original application file to confirm they are the same and the image is stored correctly across power cycles. I eventually found a location in memory that returned the same image as I uploaded, so removed all debug code and uploaded to a location on the boundary of the 2nd megabyte. The Bluetooth UART worked again, at least for a while.
Writing a ULPI core
In a much earlier build, I had managed to interface to a USB keyboard using a simple USB1.1 interface chip, the USB1T20. This chip is no more than a differential IO port and a Verilog core, such as this one “USB 1.1 Host and Function IP core” from opencores.org is needed to interface with the USB. However, there are very few USB1.1 devices are useful to the CPC2, as many USB game-pads are high-speed USB2.0 and wouldn’t work with this interface chip or core.
The addition of the USB3320 from Microchip adds the necessary high-speed USB functionality to the CPC2, allowing the use of game controllers that only operate at 480Mbps.
Unfortunately, this meant that I had to re-write the low-level logic of the USB interface to support ULPI, which is the interface standard for the chip. Debugging USB without a protocol analyser is a painful process. I ended up writing an application that interfaces to my Bitscope logic analyser to interpret the 2-wire interface signals. If you haven’t seen USB traffic before, it looks something like this:
As you might infer from the sample speed and short data burst, this is a low-speed transfer of a keyboard packet NAK to an IN request. My analysis app produces this for the waveform:
Starting: Attempting to open 1 device…
Starting @0 = 0000000001100101101000000100011010010111100000001010110101101
PID:1001 Addr:1000000 EndP:1000 CRC:11010
PID:IN Addr:1 EndP:1 CRC:11
Starting @35 = 10111100000001010110101101
PID:0101
PID:NAK
Developing the host ULPI core was not as complex as expected. The USB3320 chip is very low-level, so it will just dump whatever data you send to it onto the USB bus. Incoming data from the USB device must be read out from the chip across the 8-bit ULPI bus as it arrives. There’s almost no buffering on the chip itself, so this is not something that can be done in software. The 480MHz high-speed USB bus converts down to a 60MHz parallel bus (480MHz/8bits=60MHz).
My Verilog core adds CRC generation and checking, as well a packet flow and error controls. The firmware level simply needs to request an IN, OUT or SETUP packet and the core takes care of the rest.
The protocol for a simple HID boot keyboard is fairly well defined, so I used this for the initial proof of concept. Hot plugging of the USB is possible without upsetting the CPC2, so it will be possible to switch between a USB keyboard and a gamepad while the CPC2 is running. It may also be possible to add USB-hub support, so multiple peripherals can be connected in the future. Only the firmware will limit this. Code will be posted to GitHub for both the ULPI core and the firmware to manage it. Sorry, there’s no documentation yet. This represents a week of slogging through the USB specifications and lots of head-scratching with help on the low-level specifics from http://www.usbmadesimple.co.uk/ and https://www.beyondlogic.org/usbnutshell.
Boot Splash Screen
Finally, I got to add luxury items, such as the CPC2 boot screen. If you look closely at the video at the top of this page, the boot screen shows the current state during the 3-4 seconds of booting. As the boot process gets more sophisticated, this is quite important so that users don’t feel as though the CPC2 has frozen while it reads KBs of data from storage and loading into memory.
Look closely at the colour bars at the bottom of the boot screen, you’ll see there are 5 of each of the primary colours. Using a look-up table, 216 colours are available with 6 shades of each primary colour available (6x6x6=216) plus the 27 colours of the CPC palette, giving a total of 243 unique colours.
My original plan was to provide an interface to the supervisor through this high-colour alternate screen. However, the memory requirements of such an interface would likely exceed the 64K available to the supervisor code. The new plan is to create a CPC ROM that allows manipulation of the supervisor controls such as mounting disks and manipulating ROM configurations.
The end is (finally) in-sight for this project. A new build will be required to fix the UART, ESP32 and USB mounting post issues, but the basic design is now set and proven.
Still on the essential TODO list is (not in order):
- New board build, correcting the hardware issues
- 3D printed case for the board
- New CPC ROM to manage the disk and ROM configurations
- Debug the CPC2 core to make this hardware and cycle-accurate
- Debug the firmware (still issues with disk management)
- Add USB high-speed support, which is currently untested
- Add support for keyboard/mouse/gamepad composite devices with ad-hoc HID profiles and configurable key mapping
- Create a JTAG pin-probe test harness to allow programming of production devices without soldering a JTAG header onto the board.
This project will never be finished, so here’s my current wish-list:
- New ESP32 software to allow remote management of the CPC as well as uploading and downloading disk images
- Add cassette functionality with both PCM audio and CDT files
- Add WIFI support through the ESP32 for connecting the CPC2 to the internet