View this project on CADLAB.io.
A Neotron system powered by the Raspberry Pi Pico, in a micro-ATX form-factor.
The Neotron Pico is based around the idea of the Neotron-32, but using a low-cost Raspberry Pi Pico instead of a Texas Instuments Tiva-C Launchpad. It also stretches out to full micro-ATX size, and adds more expansion slots so that you can easily design and add your own peripherals.



The Raspberry Pi Pico is the core of the Neotron Pico. It uses PIO statemachines to generate 12-bit Super VGA video, and digital 16 bit 48 kHz stereo audio. It also has both I²C and SPI buses. SPI chipselects and IRQs are handled by an SPI-to-GPIO expander. This provides eight chip-selects and eight IRQs, to support up to eight expansion slots or peripherals. The eight chip-selects can be globally disabled, allowing the Pico to talk to either the I/O exander, or the selected expansion slot. The board has an SD Card fitted in the 'Slot 1' position, and the Board Management Controller in the 'Slot 0' position, leaving 'Slot 2' through to 'Slot 7' available for expansion. Each expansion slot has both I²C and SPI, along with unique chip-select and IRQ signals.
The Neotron Pico is designed to run the Neotron OS - a CP/M or MS-DOS alike OS written in Rust. But, being open-hardware, you can program your Neotron Pico to do pretty much anything.
The main processor module is the Raspberry Pi Pico, which features:
The limited I/O on the Pico (we are using half the available pins just for the video output) is supplemented using a Microchip MCP23S17 SPI to GPIO expander, and an octal buffer. See the I/O Expanders section for more details.
| Pin | Name | Signal | Function |
|---|---|---|---|
| 01 | GP0 | VGA_HSYNC | VGA Horizontal Sync (31.5 kHz) |
| 02 | GP1 | VGA_VSYNC | VGA Vertical Sync (60 Hz/70 Hz) |
| 04 | GP2 | VGA_RED0 | Digital VGA signal, Red channel LSB |
| 05 | GP3 | VGA_RED1 | Digital VGA signal, Red channel |
| 06 | GP4 | VGA_RED2 | Digital VGA signal, Red channel |
| 07 | GP5 | VGA_RED3 | Digital VGA signal, Red channel MSB |
| 09 | GP6 | VGA_GREEN0 | Digital VGA signal, Green channel LSB |
| 10 | GP7 | VGA_GREEN1 | Digital VGA signal, Green channel |
| 11 | GP8 | VGA_GREEN2 | Digital VGA signal, Green channel |
| 12 | GP9 | VGA_GREEN3 | Digital VGA signal, Green channel MSB |
| 14 | GP10 | VGA_BLUE0 | Digital VGA signal, Blue channel LSB |
| 15 | GP11 | VGA_BLUE1 | Digital VGA signal, Blue channel |
| 16 | GP12 | VGA_BLUE2 | Digital VGA signal, Blue channel |
| 17 | GP13 | VGA_BLUE3 | Digital VGA signal, Blue channel MSB |
| 19 | GP14 | I2C_SDA | I²C Data |
| 20 | GP15 | I2C_SCL | I²C Clock |
| 21 | GP16 | SPI_CIPO | SPI Data In |
| 22 | GP17 | nSPI_CS_IO | Low selects MCP23S17, High selects Peripherals |
| 24 | GP18 | SPI_CLK | SPI Clock |
| 25 | GP19 | SPI_COPI | SPI Data Out |
| 26 | GP20 | nIRQ_IO | Interrupt Request Input from MCP23S17 |
| 27 | GP21 | nOUTPUT_EN | Enable buffered CS outputs from MCP23S17 |
| 29 | GP22 | I2S_ADC_DATA | Digital Audio Input |
| 31 | GP26 | I2S_DAC_DATA | Digital Audio Output |
| 32 | GP27 | I2S_BIT_CLOCK | Digital Audio Bit Clock (1.536MHz) |
| 34 | GP28 | I2S_LR_CLOCK | Digital Audio Sync (96kHz) |
The Raspberry Pi Silicon RP2040 generates 12-bit VGA video at a range of standard resolutions (including 640x480 @ 60 Hz).
The design could easily be adapted to remove the TPF133A/THS7316 video buffer and the TPD7S019 level shifter/filter, and instead use the 1BitSquared DVI PMOD board if you prefer a DVI output (using an HDMI connector).
The audio subsystem offers 16-bit 48 kHz stereo audio in and out through a classic blue/green/pink triple 3.5mm TRS jack. Input and Output volume can be software controlled.
Power-on Reset sequencing, soft shutdown, voltage monitoring and PS/2 interfacing is handled by a separate STM32F0 SoC.
| Pin | Name | Signal | Function |
|---|---|---|---|
| 02 | PF0 | BUTTON_nPWR | Power Button Input (active low) |
| 03 | PF1 | BUTTON_nRST | Reset Button Input (active low) |
| 06 | PA0 | MON_3V3 | 3.3V rail monitor Input (1.65V nominal) |
| 07 | PA1 | MON_5V | 5.0V rail monitor Input (1.65V nominal) |
| 08 | PA2 | SYS_nRESET | System Reset Output (active low) |
| 09 | PA3 | DC_ON | Enable 5.0V PSU Output (active high) |
| 10 | PA4 | SPI1_nCS | SPI Chip Select Input (active low) |
| 11 | PA5 | SPI1_SCK | SPI Clock Input |
| 12 | PA6 | SPI1_CIPO | SPI Data Output |
| 13 | PA7 | SPI1_COPI | SPI Data Input |
| 14 | PB0 | LED0 | PWM output for first Status LED |
| 15 | PB1 | LED1 | PWM output for second Status LED |
| 18 | PA8 | IRQ_nHOST | Interrupt Output to the Host (active low) |
| 19 | PA9 | I2C1_SCL | I²C Clock |
| 20 | PA10 | I2C1_SDA | I²C Data |
| 21 | PA11 | USART1_CTS | UART Clear-to-Send Output |
| 22 | PA12 | USART1_RTS | UART Ready-to-Receive Input |
| 23 | PA13 | SWDIO | SWD Progamming Data Input |
| 24 | PA14 | SWCLK | SWD Programming Clock Input |
| 25 | PA15 | PS2_CLK0 | Keyboard Clock Input |
| 26 | PB3 | PS2_CLK1 | Mouse Clock Input |
| 27 | PB4 | PS2_DAT0 | Keyboard Data Input |
| 28 | PB5 | PS2_DAT1 | Mouse Data Input |
| 29 | PB6 | USART1_TX | UART Transmit Output |
| 30 | PB7 | USART1_RX | UART Receive Input |
Note that in the above table, the UART signals are wired as Data Terminal Equipment (DTE).
This design should also be pin-compatible with the following SoCs (although the software may need recompiling):
Note that not all STM32 pins are 5V-tolerant, and the PS/2 protocol is a 5V open-collector system, so ensure that whichever part you pick has 5V-tolerant pins (marked FT or FTt in the datasheet) for the PS/2 signals. All of the parts above should be OK, but they haven't been tested. Let us know if you try one!
The Neotron Pico can retain time/date settings when fully powered off, using a Real Time Clock chip and a CR2032 lithium coin cell. This also retains system settings in a very low-power SRAM built into the Real Time Clock chip.
Because we used so many pins on the Pico for Audio and Video, we don't have enough pins to use for Chip Select lines. Each device we wish to communicate with on the SPI bus must have a unique chip select line and so have limited lines means we could only have a limited number of SPI devices.
However, in this design, we cheat and use a Microchip MCP23S17 I/O expander. This is an SPI peripheral with 16 GPIO pins that can be controlled by sending it commands over SPI. It also has an IRQ output which be programmed to fire when the input pins match a certain state. The MCP23S18 (with open-drain outputs) will not work - it has a different pinout.
The problem would come when the Pico has finished talking to our select SPI device - how does it tell the MCP23S17 to release the current chip select, without the SPI bus traffic also going to the currently selected expansion slot? We resolve this by using a simple 8-bit decoder/buffer with an enable pin. This allows the Pico to disconnect all of the chip select signals at once, regardless of the output of the MCP23S17. Once this is disabled, we know we are talking to only the MCP23S17 and the Pico can command it to select the next chip select of interest to us.
Interrupts are also processed through the MCP23S17. We configure the device to provide an IRQ (edge, active low) whenever any of the eight IRQ inputs are active (programmable for edge or level, active high/rising or low/falling). When the Pico receives an IRQ from the MCP23S17, it must do a read of the pins (using SPI) to find out which device actually raised the interrupt. This model is similar to that used in the IBM PC - where the Intel 8088 must talk to an Intel 8259A programmable interrupt controller over the ISA bus to find out which interrupt was raised - except that in our case, our CPU is very fast and our bus is pretty slow, so our interrupt latency isn't very good. Worse, if there is a big SPI transaction happening (such as transferring a 512 byte block from an SD card) when an interrupt fires, the Pico will have to wait for that to complete before it can talk to the MCP23S17 to handle the IRQ. That or it could just drop the SPI transaction mid-way through and re-try it later (if your expansion device can tolerate such rudeness).
``` +------+ +-----+ | |----------/OUTPUT_EN------------->| | | |
$ claude mcp add Neotron-Pico \
-- python -m otcore.mcp_server <graph>