├── .github └── workflows │ ├── firmware.yml │ ├── python.yml │ └── tool.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── benchmark ├── 2mbit_xor_rom.bin ├── CMakeLists.txt ├── full_probes.dsc ├── genrom.py ├── main.cpp ├── measure.py ├── pico_sdk_import.cmake └── probes.dsc ├── docs ├── 270mhz_access_time.png ├── PicoROM.step ├── PicoROM_3D.png ├── PicoROM_Schematic.pdf ├── delay.py ├── header.jpg ├── in_use.jpg ├── pcb_large.png ├── pcb_small.png ├── standalone.jpg ├── upload.gif ├── usb_boot.jpg └── use_collage.jpg ├── firmware ├── .clang-format ├── .gitignore ├── .vscode │ ├── launch.json │ └── settings.json ├── CMakeLists.txt ├── comms.cpp ├── comms.h ├── comms.pio ├── data_bus.pio ├── flash.cpp ├── flash.h ├── main.cpp ├── memmap_firmware.ld ├── pico_link.cpp ├── pico_link.h ├── pico_sdk_import.cmake ├── pio_programs.cpp ├── pio_programs.h ├── rom.cpp ├── rom.h ├── str_util.cpp ├── str_util.h └── system.h ├── hardware ├── 3dshapes │ ├── DHVQFN24_L5.5-W3.5-H0.9-P0.50-BL-EP.step │ ├── DHVQFN24_L5.5-W3.5-H0.9-P0.50-BL-EP.wrl │ ├── USB-C-SMD_GT-USB-7051A.step │ ├── USB-C-SMD_GT-USB-7051A.wrl │ ├── USON-8_L2-W3-H0.6X0.5P.wrl │ ├── V-QFN4525-20_L4.5-W2.5-P0.50-BL.step │ ├── V-QFN4525-20_L4.5-W2.5-P0.50-BL.wrl │ ├── X2QFN-8_L1.5-W1.5-P0.50-BL.step │ └── X2QFN-8_L1.5-W1.5-P0.50-BL.wrl ├── MCU_RaspberryPi_RP2040.lib ├── PicoROM-cache.lib ├── PicoROM-rescue.dcm ├── PicoROM-rescue.lib ├── PicoROM.csv ├── PicoROM.kicad_pcb ├── PicoROM.kicad_pro ├── PicoROM.kicad_sch ├── PicoROM.pretty │ ├── Crystal_SMD_HC49-US.kicad_mod │ ├── DHVQFN24_L5.5-W3.5-P0.50-BL-EP.kicad_mod │ ├── IC_SN74LVC8T245RHLR.kicad_mod │ ├── RP2040-QFN-56.kicad_mod │ ├── USB-C-SMD_GT-USB-7051A.kicad_mod │ ├── USB_Micro-B_Amphenol_10103594-0001LF_Horizontal_modified.kicad_mod │ ├── V-QFN4525-20_L4.5-W2.5-P0.50-BL.kicad_mod │ └── X2QFN-8_L1.5-W1.5-P0.50-BL.kicad_mod ├── PicoROM.pro ├── PicoROM.sch ├── TCA5404 │ ├── 2024-05-06_03-40-37.kicad_sym │ └── footprints.pretty │ │ └── RUG8.kicad_mod ├── fabrication-toolkit-options.json ├── fp-lib-table ├── production │ ├── PicoROM_-_ROM_Emulator_1.5.zip │ ├── PicoROM_-_ROM_Emulator_1.7.zip │ ├── bom.csv │ ├── designators.csv │ ├── netlist.ipc │ └── positions.csv └── sym-lib-table ├── host ├── .gitignore ├── picolink │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── picorom │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── rom_size.rs └── pypicorom │ ├── .env │ └── pyvenv.cfg │ ├── .github │ └── workflows │ │ └── CI.yml │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── pyproject.toml │ └── src │ └── lib.rs └── signal_gen ├── CMakeLists.txt ├── main.cpp └── pico_sdk_import.cmake /.github/workflows/firmware.yml: -------------------------------------------------------------------------------- 1 | name: Firmware CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - '*' 9 | paths: 10 | - 'firmware/**' 11 | - '.github/workflows/firmware.yml' 12 | pull_request: 13 | paths: 14 | - 'firmware/**' 15 | - '.github/workflows/firmware.yml' 16 | workflow_dispatch: 17 | 18 | permissions: 19 | contents: write 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v3 26 | - name: Checkout SDK 27 | run: | 28 | git clone https://github.com/raspberrypi/pico-sdk.git --branch master 29 | cd pico-sdk 30 | git submodule update --init 31 | - name: Setup Build Dependencies 32 | run: sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential libstdc++-arm-none-eabi-newlib 33 | - name: Build 34 | run: | 35 | mkdir build 36 | cd build 37 | export PICO_SDK_PATH=../pico-sdk 38 | cmake ../firmware 39 | make 40 | - uses: actions/upload-artifact@v4 41 | with: 42 | name: firmware 43 | path: | 44 | build/PicoROM*.elf 45 | build/PicoROM*.uf2 46 | if-no-files-found: error 47 | 48 | release: 49 | name: Release 50 | runs-on: ubuntu-latest 51 | if: "startsWith(github.ref, 'refs/tags/')" 52 | needs: [build] 53 | steps: 54 | - uses: actions/download-artifact@v4 55 | with: 56 | name: firmware 57 | - name: Attach firmware 58 | uses: svenstaro/upload-release-action@v2 59 | with: 60 | file_glob: true 61 | file: PicoROM* 62 | 63 | -------------------------------------------------------------------------------- /.github/workflows/python.yml: -------------------------------------------------------------------------------- 1 | # This file is autogenerated by maturin v1.1.0 2 | # To update, run 3 | # 4 | # maturin generate-ci -m host/pypicorom/Cargo.toml github 5 | # 6 | name: Python Module CI 7 | 8 | on: 9 | push: 10 | branches: 11 | - main 12 | tags: 13 | - '*' 14 | paths: 15 | - 'host/**' 16 | - '.github/workflows/python.yml' 17 | pull_request: 18 | paths: 19 | - 'host/**' 20 | - '.github/workflows/python.yml' 21 | workflow_dispatch: 22 | 23 | permissions: 24 | contents: write 25 | 26 | jobs: 27 | linux: 28 | runs-on: ubuntu-latest 29 | strategy: 30 | matrix: 31 | target: [x86_64, armv7] 32 | steps: 33 | - uses: actions/checkout@v3 34 | - uses: actions/setup-python@v4 35 | with: 36 | python-version: '3.10' 37 | - name: Build wheels 38 | uses: PyO3/maturin-action@v1 39 | with: 40 | target: ${{ matrix.target }} 41 | args: --release --out dist --manifest-path host/pypicorom/Cargo.toml 42 | sccache: 'true' 43 | manylinux: auto 44 | - name: Upload wheels 45 | uses: actions/upload-artifact@v4 46 | with: 47 | name: wheel-linux-${{ matrix.target }} 48 | path: dist 49 | windows: 50 | runs-on: windows-latest 51 | strategy: 52 | matrix: 53 | target: [x64] 54 | steps: 55 | - uses: actions/checkout@v3 56 | - uses: actions/setup-python@v4 57 | with: 58 | python-version: '3.10' 59 | architecture: ${{ matrix.target }} 60 | - name: Build wheels 61 | uses: PyO3/maturin-action@v1 62 | with: 63 | target: ${{ matrix.target }} 64 | args: --release --out dist --manifest-path host/pypicorom/Cargo.toml 65 | sccache: 'true' 66 | - name: Upload wheels 67 | uses: actions/upload-artifact@v4 68 | with: 69 | name: wheel-windows-${{ matrix.target }} 70 | path: dist 71 | 72 | macos: 73 | runs-on: macos-latest 74 | strategy: 75 | matrix: 76 | target: [x86_64, aarch64] 77 | steps: 78 | - uses: actions/checkout@v3 79 | - uses: actions/setup-python@v4 80 | with: 81 | python-version: '3.10' 82 | - name: Build wheels 83 | uses: PyO3/maturin-action@v1 84 | with: 85 | target: ${{ matrix.target }} 86 | args: --release --out dist --manifest-path host/pypicorom/Cargo.toml 87 | sccache: 'true' 88 | - name: Upload wheels 89 | uses: actions/upload-artifact@v4 90 | with: 91 | name: wheel-macos-${{ matrix.target }} 92 | path: dist 93 | 94 | sdist: 95 | runs-on: ubuntu-latest 96 | steps: 97 | - uses: actions/checkout@v3 98 | - name: Build sdist 99 | uses: PyO3/maturin-action@v1 100 | with: 101 | command: sdist 102 | args: --out dist --manifest-path host/pypicorom/Cargo.toml 103 | - name: Upload sdist 104 | uses: actions/upload-artifact@v4 105 | with: 106 | name: wheel-sdist 107 | path: dist 108 | 109 | release: 110 | name: Release 111 | runs-on: ubuntu-latest 112 | if: "startsWith(github.ref, 'refs/tags/')" 113 | needs: [windows, macos, linux, sdist] 114 | steps: 115 | - uses: actions/download-artifact@v4 116 | with: 117 | pattern: wheel-* 118 | merge-multiple: true 119 | - name: Attach wheels 120 | uses: svenstaro/upload-release-action@v2 121 | with: 122 | file_glob: true 123 | file: pypicorom* 124 | - name: Publish to PyPI 125 | uses: PyO3/maturin-action@v1 126 | env: 127 | MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} 128 | with: 129 | command: upload 130 | args: --skip-existing * 131 | 132 | -------------------------------------------------------------------------------- /.github/workflows/tool.yml: -------------------------------------------------------------------------------- 1 | name: PicoROM Tool CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | tags: 8 | - '*' 9 | paths: 10 | - 'host/**' 11 | - '.github/workflows/tool.yml' 12 | 13 | pull_request: 14 | paths: 15 | - 'host/**' 16 | - '.github/workflows/tool.yml' 17 | 18 | workflow_dispatch: 19 | 20 | permissions: 21 | contents: write 22 | 23 | env: 24 | CARGO_TERM_COLOR: always 25 | GH_TOKEN: '${{ github.token }}' 26 | 27 | jobs: 28 | build: 29 | name: Build 30 | strategy: 31 | matrix: 32 | include: 33 | - target: x86_64-apple-darwin 34 | host: macos-latest 35 | cross: false 36 | - target: x86_64-pc-windows-msvc 37 | host: windows-latest 38 | cross: false 39 | - target: aarch64-apple-darwin 40 | host: macos-latest 41 | cross: false 42 | - target: armv7-unknown-linux-musleabihf 43 | host: ubuntu-latest 44 | cross: true 45 | - target: x86_64-unknown-linux-musl 46 | host: ubuntu-latest 47 | cross: true 48 | runs-on: ${{ matrix.host }} 49 | steps: 50 | - uses: actions/checkout@v3 51 | - uses: dtolnay/rust-toolchain@stable 52 | with: 53 | targets: ${{ matrix.target }} 54 | - run: cargo install cross --git https://github.com/cross-rs/cross 55 | if: ${{ matrix.cross }} 56 | - run: cross build --release --target ${{ matrix.target }} --manifest-path host/picorom/Cargo.toml --target-dir target 57 | if: ${{ matrix.cross }} 58 | - run: cargo build --release --target ${{ matrix.target }} --manifest-path host/picorom/Cargo.toml --target-dir target 59 | if: ${{ !matrix.cross }} 60 | - run: | 61 | mkdir artifacts 62 | cp target/${{ matrix.target }}/release/picorom.exe artifacts/picorom-${{ matrix.target }}.exe 63 | cp target/${{ matrix.target }}/release/picorom.pdb artifacts/picorom-${{ matrix.target }}.pdb 64 | if: ${{ matrix.host == 'windows-latest' }} 65 | - run: | 66 | mkdir artifacts 67 | cp target/${{ matrix.target }}/release/picorom artifacts/picorom-${{ matrix.target }} 68 | if: ${{ matrix.host != 'windows-latest' }} 69 | - uses: actions/upload-artifact@v4 70 | with: 71 | name: picorom-${{ matrix.target }} 72 | path: artifacts/* 73 | if-no-files-found: error 74 | 75 | release: 76 | name: Release 77 | runs-on: ubuntu-latest 78 | if: "startsWith(github.ref, 'refs/tags/')" 79 | needs: [build] 80 | steps: 81 | - uses: actions/download-artifact@v4 82 | with: 83 | pattern: picorom-* 84 | merge-multiple: true 85 | - name: Attach picorom 86 | uses: svenstaro/upload-release-action@v2 87 | with: 88 | file_glob: true 89 | file: picorom* 90 | 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # For PCBs designed using KiCad: https://www.kicad.org/ 4 | # Format documentation: https://kicad.org/help/file-formats/ 5 | 6 | # Temporary files 7 | *.000 8 | *.bak 9 | *.bck 10 | *.kicad_pcb-bak 11 | *.kicad_sch-bak 12 | *-backups 13 | *.kicad_prl 14 | *.sch-bak 15 | *~ 16 | _autosave-* 17 | *.tmp 18 | *-save.pro 19 | *-save.kicad_pcb 20 | fp-info-cache 21 | 22 | # Netlist files (exported from Eeschema) 23 | *.net 24 | 25 | # Autorouter files (exported from Pcbnew) 26 | *.dsn 27 | *.ses 28 | 29 | build/ 30 | .cache/ 31 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.default.configurationProvider": "ms-vscode.makefile-tools", 3 | "cmake.ignoreCMakeListsMissing": true 4 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Martin Donlon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Header Image](docs/header.jpg) 2 | 3 | # PicoROM 4 | PicoROM is an 8-bit ROM emulator in a DIP-32 compatible form factor. Its main use case (the reason I made it) is for rapid iteration when experimenting with arcade hardware. The PicoROM can emulate ROMs up to 2MBit (256Kbytes) in size and access times of 70ns. Its size allows it to fit into almost any ROM socket regardless of how crowded the board might be. 5 | 6 | ![Header Image](docs/use_collage.jpg) 7 | 8 | Feature Summary 9 | - DIP-32 form factor 10 | - 2MBit (256KByte) storage 11 | - 70ns access time 12 | - USB or board powered 13 | - Reset line 14 | 15 | Fully assembled versions available for purchase from [Tindie.](https://www.tindie.com/products/pbretro/picorom/) 16 | 17 | ## Operation 18 | A PicoROM is controlled by the `picorom` tool on a PC via the USB connection. The `picorom` tool allows you to list PicoROMs attached to the system, rename them, set parameters and (most important of all) upload ROM data. 19 | Each PicoROM device has a name that is used to identify it when running commands. It is not uncommon to have multiple devices connected at once and want to send different data to each one. Arcade boards often have multiple ROMs to both increase the total memory size, to increase the bus width or both. You can get a list of the PicoROMs currently connected using the `picorom list` command: 20 | 21 | ```console 22 | foo:~ $ picorom list 23 | Available PicoROMs: 24 | E66138528361BB3 [/dev/cu.usbmodem101] 25 | E661385490CD014 [/dev/cu.usbmodem102] 26 | ``` 27 | 28 | PicoROMs use a unique hardware ID from their flash memory as their default name. I usually name the PicoROMs based on how they are currently being used. An arcade board might have two ROMs for the main CPU, one for the lower 8-bits and one for the upper, so you could name the PicoROMs `cpu_low` and `cpu_high`. You can then target those PicoROMs in your makefiles or other scripts. You can change a PicoROMs name using the `picorom rename` command. 29 | 30 | ```console 31 | foo:~ $ picorom rename E66138528361BB3 cpu_low 32 | Renamed 'E66138528361BB3' to 'cpu_low' 33 | ``` 34 | 35 | Most `picorom` commands take the form of `picorom ` where `` is the name of the device you are targetting. The single most important and useful `picorom` command is `upload` which uploads a binary image to the PicoROM. 36 | 37 | ```console 38 | foo:~ $ picorom upload cpu_low cpu_low.bin 39 | Uploading ROM [################################################################] Done. 40 | ``` 41 | 42 | Once the upload is complete (which should only take about a second) the PicoROM will start returning this data for any access requests it receives on its address pins. The uploaded data is stored in RAM on the PicoROM so if the device is powered off the data will be lost. You can also store a copy of the data into flash memory, from there it will be loaded into RAM whenever the device starts up. You can do this by either passing the `-s` parameter to the `upload` command or by running the `commit` command. The commit command will copy whatever is currently in RAM into flash memory. 43 | 44 | ```console 45 | foo:~ $ picorom upload cpu_low cpu_low.bin -s 46 | Uploading ROM [################################################################] Done. 47 | Storing to Flash - Done. 48 | 49 | foo:~ $ picorom commit cpu_low 50 | Storing to Flash - Done. 51 | 52 | ``` 53 | 54 | The PicoROM operates in 2Mbit mode by default. So if you upload a smaller image, 1MBit for instance, then that will only occupy half the ROM space and the other half will be undefined. You can instruct the PicoROM to emulate smaller ROM sizes by passing a size parameter to the `upload` command. 55 | 56 | ```console 57 | foo:~ $ picorom upload cpu_low cpu_low_1mbit.bin 1MBit 58 | Uploading ROM [################################################################] Done. 59 | ``` 60 | 61 | ### Reset Control 62 | The PicoROM has an external reset pin that can be used to drive the reset signal of whatever hardware you are working with. The reset pin state is set using the `picorom reset` command. It is a tri-state output so the signal can either be +5V/high (`high`), low/ground (`low`) or high-impedance (`z`). The `reset` command can be used as part of a build script to reset a system when a new ROM image is uploaded. 63 | 64 | ```make 65 | # picorom makefile target to trigger reset and upload ROM image 66 | picorom: cpu_low.bin cpu_high.bin 67 | picorom reset cpu_low low 68 | picorom upload cpu_low cpu_low.bin 69 | picorom upload cpu_high cpu_high.bin 70 | picorom reset cpu_low z 71 | ``` 72 | 73 | ![Upload example](docs/upload.gif) 74 | 75 | How you interface with reset hardware on each system is going to differ and it may not be possible to override the systems reset signal in all cases. The reset pin on the PicoROM does not only have to be used for system resets, it can be treated as a generic controllable output. 76 | 77 | ### Standalone 78 | The PicoROM draws its power from either the USB-C connection or from the 5V VCC input at pin 32. This means that the PicoROM can function like a regular standalone ROM chip without any USB connection. There are is a caveat though. At startup the ROM data needs to be read from flash memory and copied into the static RAM of the RP2040. This process takes approximately 8ms and any ROM accesses will be ignored until it completes. This process itself won't start until the RP2040 itself has powered up and determined that its supply voltage is stable, so there may be additional delays caused by that. Some systems have reset control circuitry that delays full startup of the system until the supply voltage has been stable for a certain amount of time. If this delay is longer than 8ms then a PicoROM will probably function fine. 79 | 80 | | ![Air Assault M107 running standalone with four PicoROMs](docs/standalone.jpg) | 81 | |:-:| 82 | | *Air Assault M107 running standalone with four PicoROMs* | 83 | 84 | The reset signal can be used to mitigate this problem in some cases. You can specify a reset value that will be asserted while the initial copy is happening by setting the `initial_reset` parameter. 85 | 86 | ```console 87 | foo:~ $ picorom set cpu_low initial_reset high 88 | initial_reset=high 89 | ``` 90 | 91 | ## Performance 92 | The worst case access time in 70ns. That is measured as the time from when an address is asserted on the address bus to the time that the data is available on the data bus. In datasheets for ROMs and EPROMs this is often referred to as "Address to Output Delay." The PicoROM is a synchronous device running an instruction loop there is variablity in the access time depending on where in the loop the software is when an address is asserted. 93 | 94 | ![Access time histogram](docs/270mhz_access_time.png) 95 | 96 | The delay from the output and chip enable signals being assert to the data bus becoming active is less variable and has been measured to have a worse case of 40ns. This is usually referred to as "Output Enable to Output Delay" in datasheets. The inverse, the delay from output/chip enable deasserted to the data bus going high-impedance, has not been measured but it is assumed to be the same. 97 | 98 | ## Installation 99 | To use a PicoROM you will need the `picorom` command line application and the PicoROM firmware, both are available as part of a [release](https://github.com/wickerwaka/PicoROM/releases/latest). The `picorom` application is pre-built for Windows, MacOS (ARM and Intel) and Linux (ARMv7 and Intel). In the unlikely case that you platform is not supported you can try building it from source. Copy the correct version of the application into a location that is in your path and rename it to just `picorom` (or `picorom.exe` for Windows users.) The firmware is a `.uf2` file named something like `PicoROM-2MBit-VERSION.uf2`. There are several ways that the firmware file can be loaded onto a PicoROM, but they all involved getting the device into USB boot mode. At the point it will appear as a USB mass storage device and all you need to do is copy the `.uf2` file to it. 100 | 101 | If you are upgrading a device that already has at least firmware version 1.7 installed then you can use the `picorom usb-boot` command to reboot it into USB boot mode and then copy the firmware file to it. You can also use the RP2040 `picotool` to reboot and upload the firmware image. I won't cover that here but you can find instructions on the [picotool github page](https://github.com/raspberrypi/picotool). 102 | 103 | If your PicoROM has gotten into some kind of broken state you can force it into USB boot mode by bridging the `USB` and `GND` connections on the unsoldered header next the the RP2040 and then powering the device on. It's pretty small and hard to see but a small bit of wire should fit in there and make enough contact. 104 | 105 | ![USB Boot header location](docs/usb_boot.jpg) 106 | 107 | Once the firmware has been copied over, power-cycle the PicoROM and then run `picorom list` to ensure it is present. You can use `picorom get` to query the current firmware version to ensure the installation or upgrade was successful. 108 | 109 | 110 | -------------------------------------------------------------------------------- /benchmark/2mbit_xor_rom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/benchmark/2mbit_xor_rom.bin -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | include(pico_sdk_import.cmake) 3 | project(testbench C CXX ASM) 4 | set(CMAKE_C_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD 17) 6 | pico_sdk_init() 7 | 8 | add_executable(testbench 9 | main.cpp 10 | ) 11 | 12 | 13 | pico_enable_stdio_usb(testbench 1) 14 | pico_enable_stdio_uart(testbench 0) 15 | pico_enable_stdio_rtt(testbench 1) 16 | 17 | pico_add_extra_outputs(testbench) 18 | target_link_libraries(testbench 19 | pico_stdlib 20 | pico_multicore 21 | ) 22 | 23 | pico_set_program_name(testbench PicoROMBench) 24 | pico_set_program_url(testbench https://github.com/wickerwaka/PicoROM) 25 | 26 | target_compile_definitions(testbench PRIVATE 27 | PICO_STDIO_ENABLE_CRLF_SUPPORT=0 28 | ) 29 | 30 | pico_define_boot_stage2(boot_div4 "${PICO_SDK_PATH}/src/rp2040/boot_stage2/boot2_w25x10cl.S") 31 | target_compile_definitions(boot_div4 PRIVATE PICO_FLASH_SPI_CLKDIV=4) 32 | 33 | pico_set_boot_stage2(testbench boot_div4) 34 | -------------------------------------------------------------------------------- /benchmark/genrom.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | 4 | data = bytearray([]) 5 | for x in range(4 * 64 * 1024): 6 | v = (( x >> 8 ) ^ x) & 0xff 7 | data.append(v) 8 | 9 | with open("2mbit_xor_rom.bin", "wb") as fp: 10 | fp.write(data) 11 | 12 | -------------------------------------------------------------------------------- /benchmark/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pico/stdlib.h" 3 | #include "hardware/clocks.h" 4 | #include "hardware/structs/syscfg.h" 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | static constexpr uint32_t DATA_MASK = 0x000000ff; 11 | static constexpr uint32_t DATA_SHIFT = 0; 12 | 13 | static constexpr uint32_t ADDR_MASK = 0x047fff00; 14 | static constexpr uint32_t ADDR_SHIFT = 8; 15 | 16 | static constexpr uint32_t CE_SHIFT = 27; 17 | static constexpr uint32_t CE_MASK = 0x1 << CE_SHIFT; 18 | 19 | static constexpr uint32_t OE_SHIFT = 28; 20 | static constexpr uint32_t OE_MASK = 0x1 << OE_SHIFT; 21 | 22 | 23 | template __force_inline void asm_delay() 24 | { 25 | pico_default_asm_volatile( "nop" ); 26 | asm_delay(); 27 | } 28 | 29 | template <> __force_inline void asm_delay<0>() 30 | { 31 | } 32 | 33 | uint32_t make_addr(uint32_t addr) 34 | { 35 | uint32_t exp = ((addr & 0x00008000) << 3) | addr; 36 | 37 | return (exp << ADDR_SHIFT) & ADDR_MASK; 38 | } 39 | 40 | void rom_configure_pins() 41 | { 42 | gpio_init_mask(DATA_MASK | ADDR_MASK | CE_MASK | OE_MASK); 43 | 44 | // Direction 45 | gpio_set_dir_out_masked(ADDR_MASK | CE_MASK | OE_MASK); 46 | gpio_set_dir_in_masked(DATA_MASK); 47 | for( int pin = 0; pin < 31; pin++ ) 48 | { 49 | uint32_t pin_mask = 1 << pin; 50 | 51 | if( pin_mask & DATA_MASK ) 52 | { 53 | gpio_set_input_hysteresis_enabled(pin, false); 54 | syscfg_hw->proc_in_sync_bypass |= 1 << pin; 55 | gpio_set_pulls(pin, false, true); 56 | } 57 | 58 | gpio_set_slew_rate(pin, GPIO_SLEW_RATE_FAST); 59 | //gpio_set_drive_strength(pin, GPIO_DRIVE_STRENGTH_12MA); 60 | } 61 | } 62 | 63 | template uint8_t rom_read(uint32_t address) 64 | { 65 | uint32_t out = make_addr(address); 66 | gpio_put_masked(ADDR_MASK | CE_MASK | OE_MASK, out); 67 | asm_delay(); 68 | uint32_t v = gpio_get_all(); 69 | return (v & DATA_MASK) >> DATA_SHIFT; 70 | } 71 | 72 | template uint8_t rom_read_ce(uint32_t address) 73 | { 74 | uint32_t out = make_addr(address); 75 | gpio_put_masked(ADDR_MASK | CE_MASK | OE_MASK, out | OE_MASK); 76 | busy_wait_at_least_cycles(200); 77 | gpio_put_masked(ADDR_MASK | CE_MASK | OE_MASK, out); 78 | asm_delay(); 79 | uint32_t v = gpio_get_all(); 80 | return (v & DATA_MASK) >> DATA_SHIFT; 81 | } 82 | 83 | 84 | template 85 | constexpr auto func_array_read_ce(std::integer_sequence) { 86 | return std::array{&rom_read_ce...}; 87 | } 88 | 89 | template 90 | constexpr auto func_array_read(std::integer_sequence) { 91 | return std::array{&rom_read...}; 92 | } 93 | 94 | uint8_t rom_read(uint32_t address, int delay) 95 | { 96 | constexpr auto func_array = func_array_read(std::make_integer_sequence{}); 97 | return func_array[delay](address); 98 | } 99 | 100 | uint8_t rom_read_ce(uint32_t address, int delay) 101 | { 102 | constexpr auto func_array = func_array_read_ce(std::make_integer_sequence{}); 103 | return func_array[delay](address); 104 | } 105 | 106 | uint32_t data[16 * 1024]; 107 | 108 | int main() 109 | { 110 | uint8_t results[256]; 111 | stdio_init_all(); 112 | 113 | set_sys_clock_khz(270000, true); 114 | 115 | rom_configure_pins(); 116 | 117 | bool ce_tests = false; 118 | 119 | while (true) 120 | { 121 | int fail_count = 0; 122 | int succeed_count = 0; 123 | //int delay = 30; 124 | for( int delay = 5; delay < 25; delay++ ) 125 | { 126 | bool all_valid = true; 127 | for( int h = 0; h < 256; h++ ) 128 | { 129 | for( int i = 0; i < 256; i++ ) 130 | { 131 | if (ce_tests) 132 | results[i] = rom_read_ce( h << 8 | i, delay); 133 | else 134 | results[i] = rom_read( h << 8 | i, delay); 135 | } 136 | 137 | for( int i = 0; i < 256; i++ ) 138 | { 139 | if( results[i] != ( i ^ h ) ) 140 | { 141 | all_valid = false; 142 | //printf( "%02x != %02x\n", results[i], i ^ h); 143 | } 144 | } 145 | } 146 | 147 | if (!all_valid) 148 | { 149 | printf( "[%s] FAIL with %d delay cycles.\n", ce_tests ? "CE READ" : "READ", delay ); 150 | fail_count++; 151 | } 152 | else 153 | { 154 | printf( "[%s] PASS with %d delay cycles.\n", ce_tests ? "CE READ" : "READ", delay ); 155 | succeed_count++; 156 | } 157 | } 158 | 159 | sleep_ms(1000); 160 | 161 | ce_tests = !ce_tests; 162 | } 163 | } -------------------------------------------------------------------------------- /benchmark/measure.py: -------------------------------------------------------------------------------- 1 | import csv 2 | from collections import namedtuple 3 | from typing import List 4 | import sys 5 | 6 | import matplotlib.pyplot as plt 7 | 8 | State = namedtuple('State', ['time', 'address', 'data']) 9 | 10 | def read_csv(name) -> List[State]: 11 | result = [] 12 | header = None 13 | addr_cols = [] 14 | data_cols = [] 15 | with open(name) as fp: 16 | reader = csv.reader(fp) 17 | for row in reader: 18 | if row[0].startswith(';'): 19 | continue 20 | if not header: 21 | header = [x.strip() for x in row] 22 | addr_cols = [0 for _ in header] 23 | data_cols = [0 for _ in header] 24 | for idx, name in enumerate(header[1:]): 25 | if name[0] == 'D': 26 | data_cols[idx] = 2 ** int(name[1:]) 27 | elif name[0] == 'A': 28 | addr_cols[idx] = 2 ** int(name[1:]) 29 | continue 30 | 31 | addr = 0 32 | data = 0 33 | t = float(row[0]) * 1000000000 34 | for idx, val in enumerate(row[1:]): 35 | i = int(val) 36 | addr += i * addr_cols[idx] 37 | data += i * data_cols[idx] 38 | 39 | result.append( State(t, addr, data) ) 40 | 41 | return result 42 | 43 | 44 | states = read_csv(sys.argv[1]) 45 | 46 | wanted_addr = 0 47 | wanted_data = 0 48 | addr_time = 0 49 | time_delta = [] 50 | for state in states: 51 | if state.address == wanted_addr: 52 | addr_time = state.time 53 | wanted_data = (( wanted_addr >> 8 ) ^ wanted_addr) & 0xff 54 | wanted_addr += 1 55 | wanted_data = wanted_data & 0x0f 56 | wanted_addr = wanted_addr & 0x0f 57 | elif state.data == wanted_data: 58 | time_delta.append(int(state.time - addr_time)) 59 | wanted_data = -1 60 | 61 | delta_min = min(time_delta) 62 | delta_max = max(time_delta) 63 | print(f"Min: {delta_min}, Max: {delta_max}") 64 | 65 | bins = {} 66 | for x in time_delta: 67 | c = bins.get(x, 0) 68 | bins[x] = c + 1 69 | 70 | print(bins) 71 | 72 | plt.hist(time_delta, bins=[x for x in range(30, 80, 2)], align="left") 73 | plt.xlabel("Access Time (ns)") 74 | plt.ylabel("Occurances") 75 | plt.show() 76 | -------------------------------------------------------------------------------- /benchmark/pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) 22 | set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) 23 | message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") 24 | endif () 25 | 26 | if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) 27 | set(PICO_SDK_FETCH_FROM_GIT_TAG "master") 28 | message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") 29 | endif() 30 | 31 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 32 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 33 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 34 | set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") 35 | 36 | if (NOT PICO_SDK_PATH) 37 | if (PICO_SDK_FETCH_FROM_GIT) 38 | include(FetchContent) 39 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 40 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 41 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 42 | endif () 43 | # GIT_SUBMODULES_RECURSE was added in 3.17 44 | if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") 45 | FetchContent_Declare( 46 | pico_sdk 47 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 48 | GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} 49 | GIT_SUBMODULES_RECURSE FALSE 50 | ) 51 | else () 52 | FetchContent_Declare( 53 | pico_sdk 54 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 55 | GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} 56 | ) 57 | endif () 58 | 59 | if (NOT pico_sdk) 60 | message("Downloading Raspberry Pi Pico SDK") 61 | FetchContent_Populate(pico_sdk) 62 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 63 | endif () 64 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 65 | else () 66 | message(FATAL_ERROR 67 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 68 | ) 69 | endif () 70 | endif () 71 | 72 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 73 | if (NOT EXISTS ${PICO_SDK_PATH}) 74 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 75 | endif () 76 | 77 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 78 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 79 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 80 | endif () 81 | 82 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 83 | 84 | include(${PICO_SDK_INIT_CMAKE_FILE}) 85 | -------------------------------------------------------------------------------- /docs/270mhz_access_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/270mhz_access_time.png -------------------------------------------------------------------------------- /docs/PicoROM_3D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/PicoROM_3D.png -------------------------------------------------------------------------------- /docs/PicoROM_Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/PicoROM_Schematic.pdf -------------------------------------------------------------------------------- /docs/delay.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import matplotlib.pyplot as plt 3 | 4 | header = None 5 | prev = [] 6 | rise = {} 7 | delays = [] 8 | with open('166Mhz.csv') as fp: 9 | reader = csv.reader(fp) 10 | for row in reader: 11 | if row[0].startswith(';'): 12 | continue 13 | if not header: 14 | header = [x.strip() for x in row] 15 | prev = [ 1 for _ in header[1:] ] 16 | rise = dict(((x, 0) for x in header[1:])) 17 | continue 18 | 19 | for idx in range(len(prev)): 20 | v = int(row[idx + 1]) 21 | name = header[idx+1] 22 | if prev[idx] == 0 and v == 1: 23 | rise[name] = float(row[0]) 24 | if name == 'D2': 25 | a_rise = rise['A2'] 26 | delays.append((float(row[0]) - a_rise) * 1000000000) 27 | prev[idx] = v 28 | 29 | print(max(delays)) 30 | plt.hist(delays, bins=100) 31 | plt.show() -------------------------------------------------------------------------------- /docs/header.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/header.jpg -------------------------------------------------------------------------------- /docs/in_use.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/in_use.jpg -------------------------------------------------------------------------------- /docs/pcb_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/pcb_large.png -------------------------------------------------------------------------------- /docs/pcb_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/pcb_small.png -------------------------------------------------------------------------------- /docs/standalone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/standalone.jpg -------------------------------------------------------------------------------- /docs/upload.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/upload.gif -------------------------------------------------------------------------------- /docs/usb_boot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/usb_boot.jpg -------------------------------------------------------------------------------- /docs/use_collage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/docs/use_collage.jpg -------------------------------------------------------------------------------- /firmware/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -7 3 | AlignAfterOpenBracket: Align 4 | AlignArrayOfStructures: None 5 | AlignConsecutiveAssignments: None 6 | AlignConsecutiveBitFields: None 7 | AlignConsecutiveDeclarations: 8 | AcrossComments: false 9 | AcrossEmptyLines: false 10 | AlignCompound: false 11 | AlignFunctionPointers: false 12 | Enabled: false 13 | PadOperators: false 14 | AlignConsecutiveMacros: Consecutive 15 | AlignConsecutiveShortCaseStatements: 16 | AcrossComments: false 17 | AcrossEmptyLines: false 18 | AlignCaseArrows: false 19 | AlignCaseColons: false 20 | Enabled: false 21 | AlignConsecutiveTableGenBreakingDAGArgColons: 22 | AcrossComments: false 23 | AcrossEmptyLines: false 24 | AlignCompound: false 25 | AlignFunctionPointers: false 26 | Enabled: false 27 | PadOperators: false 28 | AlignConsecutiveTableGenCondOperatorColons: 29 | AcrossComments: false 30 | AcrossEmptyLines: false 31 | AlignCompound: false 32 | AlignFunctionPointers: false 33 | Enabled: false 34 | PadOperators: false 35 | AlignConsecutiveTableGenDefinitionColons: 36 | AcrossComments: false 37 | AcrossEmptyLines: false 38 | AlignCompound: false 39 | AlignFunctionPointers: false 40 | Enabled: false 41 | PadOperators: false 42 | AlignEscapedNewlines: Right 43 | AlignOperands: DontAlign 44 | AlignTrailingComments: 45 | Kind: Never 46 | OverEmptyLines: 0 47 | AllowAllArgumentsOnNextLine: false 48 | AllowAllParametersOfDeclarationOnNextLine: false 49 | AllowBreakBeforeNoexceptSpecifier: Never 50 | AllowShortBlocksOnASingleLine: Empty 51 | AllowShortCaseExpressionOnASingleLine: true 52 | AllowShortCaseLabelsOnASingleLine: false 53 | AllowShortCompoundRequirementOnASingleLine: false 54 | AllowShortEnumsOnASingleLine: true 55 | AllowShortFunctionsOnASingleLine: Empty 56 | AllowShortIfStatementsOnASingleLine: WithoutElse 57 | AllowShortLambdasOnASingleLine: Empty 58 | AllowShortLoopsOnASingleLine: true 59 | AlwaysBreakAfterDefinitionReturnType: None 60 | AlwaysBreakBeforeMultilineStrings: true 61 | AttributeMacros: 62 | - __capability 63 | BinPackArguments: true 64 | BinPackParameters: true 65 | BitFieldColonSpacing: Both 66 | BraceWrapping: 67 | AfterCaseLabel: false 68 | AfterClass: false 69 | AfterControlStatement: Never 70 | AfterEnum: false 71 | AfterExternBlock: false 72 | AfterFunction: true 73 | AfterNamespace: false 74 | AfterObjCDeclaration: false 75 | AfterStruct: false 76 | AfterUnion: false 77 | BeforeCatch: false 78 | BeforeElse: false 79 | BeforeLambdaBody: false 80 | BeforeWhile: false 81 | IndentBraces: false 82 | SplitEmptyFunction: true 83 | SplitEmptyNamespace: true 84 | SplitEmptyRecord: true 85 | BreakAdjacentStringLiterals: false 86 | BreakAfterAttributes: Leave 87 | BreakAfterJavaFieldAnnotations: false 88 | BreakAfterReturnType: None 89 | BreakArrays: true 90 | BreakBeforeBinaryOperators: None 91 | BreakBeforeBraces: Allman 92 | BreakBeforeConceptDeclarations: Always 93 | BreakBeforeInlineASMColon: OnlyMultiline 94 | BreakBeforeTernaryOperators: false 95 | BreakConstructorInitializers: BeforeComma 96 | BreakFunctionDefinitionParameters: false 97 | BreakInheritanceList: BeforeComma 98 | BreakStringLiterals: true 99 | BreakTemplateDeclarations: MultiLine 100 | ColumnLimit: 0 101 | CommentPragmas: '^ IWYU pragma:' 102 | CompactNamespaces: false 103 | ConstructorInitializerIndentWidth: 4 104 | ContinuationIndentWidth: 6 105 | Cpp11BracedListStyle: false 106 | DerivePointerAlignment: true 107 | DisableFormat: false 108 | EmptyLineAfterAccessModifier: Never 109 | EmptyLineBeforeAccessModifier: Always 110 | ExperimentalAutoDetectBinPacking: false 111 | FixNamespaceComments: true 112 | ForEachMacros: 113 | - foreach 114 | - Q_FOREACH 115 | - BOOST_FOREACH 116 | IfMacros: 117 | - KJ_IF_MAYBE 118 | IncludeBlocks: Preserve 119 | IncludeCategories: 120 | - CaseSensitive: false 121 | Priority: 2 122 | Regex: ^"(llvm|llvm-c|clang|clang-c)/ 123 | SortPriority: 0 124 | - CaseSensitive: false 125 | Priority: 3 126 | Regex: ^(<|"(gtest|gmock|isl|json)/) 127 | SortPriority: 0 128 | - CaseSensitive: false 129 | Priority: 1 130 | Regex: .* 131 | SortPriority: 0 132 | IncludeIsMainRegex: (Test)?$ 133 | IncludeIsMainSourceRegex: '' 134 | IndentAccessModifiers: false 135 | IndentCaseBlocks: false 136 | IndentCaseLabels: true 137 | IndentExternBlock: AfterExternBlock 138 | IndentGotoLabels: true 139 | IndentPPDirectives: None 140 | IndentRequiresClause: false 141 | IndentWidth: 4 142 | IndentWrappedFunctionNames: true 143 | InsertBraces: false 144 | InsertNewlineAtEOF: false 145 | InsertTrailingCommas: None 146 | IntegerLiteralSeparator: 147 | Binary: 0 148 | BinaryMinDigits: 0 149 | Decimal: 0 150 | DecimalMinDigits: 0 151 | Hex: 0 152 | HexMinDigits: 0 153 | JavaScriptQuotes: Single 154 | JavaScriptWrapImports: true 155 | KeepEmptyLines: 156 | AtEndOfFile: false 157 | AtStartOfBlock: true 158 | AtStartOfFile: true 159 | LambdaBodyIndentation: Signature 160 | Language: Cpp 161 | LineEnding: DeriveLF 162 | MacroBlockBegin: '' 163 | MacroBlockEnd: '' 164 | MainIncludeChar: Quote 165 | MaxEmptyLinesToKeep: 2 166 | NamespaceIndentation: Inner 167 | ObjCBinPackProtocolList: Auto 168 | ObjCBlockIndentWidth: 6 169 | ObjCBreakBeforeNestedBlockParam: true 170 | ObjCSpaceAfterProperty: false 171 | ObjCSpaceBeforeProtocolList: true 172 | PPIndentWidth: -1 173 | PackConstructorInitializers: BinPack 174 | PenaltyBreakAssignment: 5 175 | PenaltyBreakBeforeFirstCallParameter: 19 176 | PenaltyBreakComment: 322 177 | PenaltyBreakFirstLessLess: 120 178 | PenaltyBreakOpenParenthesis: 0 179 | PenaltyBreakScopeResolution: 500 180 | PenaltyBreakString: 1000 181 | PenaltyBreakTemplateDeclaration: 10 182 | PenaltyExcessCharacter: 1291991 183 | PenaltyIndentedWhitespace: 0 184 | PenaltyReturnTypeOnItsOwnLine: 60 185 | PointerAlignment: Left 186 | QualifierAlignment: Leave 187 | ReferenceAlignment: Pointer 188 | ReflowComments: false 189 | RemoveBracesLLVM: false 190 | RemoveParentheses: Leave 191 | RemoveSemicolon: false 192 | RequiresClausePosition: OwnLine 193 | RequiresExpressionIndentation: OuterScope 194 | SeparateDefinitionBlocks: Leave 195 | ShortNamespaceLines: 1 196 | SkipMacroDefinitionBody: true 197 | SortIncludes: CaseSensitive 198 | SortJavaStaticImport: Before 199 | SortUsingDeclarations: LexicographicNumeric 200 | SpaceAfterCStyleCast: false 201 | SpaceAfterLogicalNot: false 202 | SpaceAfterTemplateKeyword: false 203 | SpaceAroundPointerQualifiers: Default 204 | SpaceBeforeAssignmentOperators: true 205 | SpaceBeforeCaseColon: false 206 | SpaceBeforeCpp11BracedList: false 207 | SpaceBeforeCtorInitializerColon: false 208 | SpaceBeforeInheritanceColon: true 209 | SpaceBeforeJsonColon: false 210 | SpaceBeforeParens: ControlStatements 211 | SpaceBeforeParensOptions: 212 | AfterControlStatements: true 213 | AfterForeachMacros: true 214 | AfterFunctionDeclarationName: false 215 | AfterFunctionDefinitionName: false 216 | AfterIfMacros: true 217 | AfterOverloadedOperator: false 218 | AfterPlacementOperator: true 219 | AfterRequiresInClause: false 220 | AfterRequiresInExpression: false 221 | BeforeNonEmptyParentheses: false 222 | SpaceBeforeRangeBasedForLoopColon: false 223 | SpaceBeforeSquareBrackets: false 224 | SpaceInEmptyBlock: true 225 | SpacesBeforeTrailingComments: 1 226 | SpacesInAngles: Never 227 | SpacesInContainerLiterals: true 228 | SpacesInLineCommentPrefix: 229 | Maximum: -1 230 | Minimum: 1 231 | SpacesInParens: Never 232 | SpacesInParensOptions: 233 | ExceptDoubleParentheses: false 234 | InCStyleCasts: false 235 | InConditionalStatements: false 236 | InEmptyParentheses: false 237 | Other: false 238 | SpacesInSquareBrackets: false 239 | Standard: Cpp03 240 | StatementAttributeLikeMacros: 241 | - Q_EMIT 242 | StatementMacros: 243 | - Q_UNUSED 244 | - QT_REQUIRE_VERSION 245 | TabWidth: 5 246 | TableGenBreakInsideDAGArg: DontBreak 247 | UseTab: Never 248 | VerilogBreakBetweenInstancePorts: true 249 | WhitespaceSensitiveMacros: 250 | - BOOST_PP_STRINGIZE 251 | - CF_SWIFT_NAME 252 | - NS_SWIFT_NAME 253 | - PP_STRINGIZE 254 | - STRINGIZE 255 | ... 256 | -------------------------------------------------------------------------------- /firmware/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .cache/ 3 | 4 | -------------------------------------------------------------------------------- /firmware/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Pico Debug", 6 | "cwd": "${workspaceRoot}", 7 | "executable": "${command:cmake.launchTargetPath}", 8 | "request": "launch", 9 | "type": "cortex-debug", 10 | "servertype": "openocd", 11 | // This may need to be arm-none-eabi-gdb depending on your system 12 | "gdbPath" : "arm-none-eabi-gdb", 13 | "device": "RP2040", 14 | "configFiles": [ 15 | "interface/cmsis-dap.cfg", 16 | "target/rp2040.cfg" 17 | ], 18 | "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd", 19 | "runToMain": true, 20 | // Work around for stopping at main on restart 21 | "postRestartCommands": [ 22 | "break main", 23 | "continue" 24 | ], 25 | "searchDir": ["/Users/akawaka/Source/openocd/tcl"], 26 | "serverArgs": [ "-c adapter speed 5000" ] 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /firmware/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.mra": "xml", 4 | "*.tcc": "cpp" 5 | }, 6 | 7 | // These settings tweaks to the cmake plugin will ensure 8 | // that you debug using cortex-debug instead of trying to launch 9 | // a Pico binary on the host 10 | "cmake.statusbar.advanced": { 11 | "debug": { 12 | "visibility": "hidden" 13 | }, 14 | "launch": { 15 | "visibility": "hidden" 16 | }, 17 | "build": { 18 | "visibility": "default" 19 | }, 20 | "buildTarget": { 21 | "visibility": "hidden" 22 | } 23 | }, 24 | "cmake.buildBeforeRun": true, 25 | "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", 26 | "cortex-debug.openocdPath": "/Users/akawaka/Source/openocd/src/openocd" 27 | } -------------------------------------------------------------------------------- /firmware/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | include(pico_sdk_import.cmake) 3 | project(rom_emulator C CXX ASM) 4 | set(CMAKE_C_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(VERSION 1.7) 7 | string(REPLACE . _ FILENAME_VERSION ${VERSION}) 8 | 9 | pico_sdk_init() 10 | 11 | 12 | pico_define_boot_stage2(boot_div4 ${PICO_DEFAULT_BOOT_STAGE2_FILE}) 13 | target_compile_definitions(boot_div4 PRIVATE PICO_FLASH_SPI_CLKDIV=4) 14 | 15 | 16 | foreach(BUILD_CONFIG 2MBit 1MBit_Clock) 17 | set(TARGET PicoROM-${BUILD_CONFIG}-${FILENAME_VERSION}) 18 | add_executable(${TARGET} EXCLUDE_FROM_ALL 19 | main.cpp 20 | flash.cpp 21 | pico_link.cpp 22 | rom.cpp 23 | comms.cpp 24 | pio_programs.cpp 25 | str_util.cpp 26 | ) 27 | add_executable(${BUILD_CONFIG} ALIAS ${TARGET}) 28 | 29 | pico_set_float_implementation(${TARGET} none) 30 | pico_set_double_implementation(${TARGET} none) 31 | 32 | pico_generate_pio_header(${TARGET} ${CMAKE_CURRENT_LIST_DIR}/data_bus.pio) 33 | pico_generate_pio_header(${TARGET} ${CMAKE_CURRENT_LIST_DIR}/comms.pio) 34 | 35 | pico_enable_stdio_usb(${TARGET} 1) 36 | pico_enable_stdio_uart(${TARGET} 0) 37 | 38 | pico_set_linker_script(${TARGET} ${CMAKE_CURRENT_LIST_DIR}/memmap_firmware.ld) 39 | 40 | pico_add_extra_outputs(${TARGET}) 41 | target_link_libraries(${TARGET} 42 | pico_stdlib 43 | pico_multicore 44 | pico_bootrom 45 | hardware_flash 46 | hardware_pio 47 | hardware_dma 48 | pico_unique_id 49 | -Wl,--wrap=atexit 50 | ) 51 | 52 | target_compile_definitions(${TARGET} PRIVATE 53 | PICOROM_CONFIG_NAME="${BUILD_CONFIG}" 54 | PICOROM_FIRMWARE_VERSION="${VERSION}" 55 | PICO_HEAP_SIZE=16 56 | PICO_STACK_SIZE=640 57 | PICO_CORE1_STACK_SIZE=4 58 | USB_MAX_ENDPOINTS=4 59 | PICO_STDIO_ENABLE_CRLF_SUPPORT=0 60 | PICO_TIME_DEFAULT_ALARM_POOL_MAX_TIMERS=2 61 | ) 62 | 63 | pico_set_program_name(${TARGET} PicoROM) 64 | pico_set_program_url(${TARGET} https://github.com/wickerwaka/PicoROM) 65 | pico_set_boot_stage2(${TARGET} boot_div4) 66 | pico_set_program_version(${TARGET} ${VERSION}) 67 | endforeach() 68 | 69 | target_compile_definitions(PicoROM-1MBit_Clock-${FILENAME_VERSION} PRIVATE 70 | FEATURE_CLOCK=1 71 | ) 72 | 73 | set_target_properties(PicoROM-2MBit-${FILENAME_VERSION} PROPERTIES EXCLUDE_FROM_ALL FALSE) 74 | -------------------------------------------------------------------------------- /firmware/comms.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "comms.h" 6 | #include "pico_link.h" 7 | #include "pio_programs.h" 8 | #include "system.h" 9 | 10 | #include "hardware/pio.h" 11 | #include "pico/time.h" 12 | 13 | FIFO<32> comms_out_fifo; 14 | FIFO<32> comms_in_fifo; 15 | uint8_t comms_out_deferred_req; 16 | uint8_t comms_out_deferred_ack; 17 | uint8_t comms_in_empty_req; 18 | uint8_t comms_in_empty_ack; 19 | 20 | struct CommsRegisters 21 | { 22 | uint8_t magic[4]; 23 | 24 | // only the least significant byte is relevant for these, using 32-bits to avoid potential atomic issues 25 | uint32_t active; 26 | uint32_t pending; 27 | uint32_t in_seq; 28 | uint32_t out_seq; 29 | uint32_t tick_count; 30 | uint32_t debug1; 31 | uint32_t debug2; 32 | 33 | uint8_t reserved0[256 - (8 * 4)]; 34 | 35 | uint32_t tick_reset; 36 | uint8_t reserved1[256 - (1 * 4)]; 37 | 38 | uint32_t in_byte; 39 | uint8_t reserved2[256 - (1 * 4)]; 40 | 41 | uint8_t out_area[256]; 42 | }; 43 | 44 | static_assert(sizeof(CommsRegisters) == 1024); 45 | 46 | static CommsRegisters *comms_reg = (CommsRegisters *)0x0; 47 | static uint32_t comms_reg_addr = 0; 48 | 49 | void comms_irq_handler() 50 | { 51 | uint32_t addr = pio_sm_get(prg_comms_detect.pio(), prg_comms_detect.sm); 52 | comms_reg->debug2 = addr; 53 | if (addr & 0x100) 54 | { 55 | if (comms_reg) 56 | { 57 | comms_out_fifo.push(addr & 0xff); 58 | if (comms_out_fifo.is_full()) 59 | { 60 | comms_out_deferred_req++; 61 | } 62 | else 63 | { 64 | comms_reg->out_seq++; 65 | } 66 | } 67 | } 68 | else if (addr == 0x000) 69 | { 70 | comms_in_fifo.pop(); 71 | 72 | if (comms_reg) 73 | { 74 | comms_reg->debug1++; 75 | if (comms_in_fifo.is_empty()) 76 | { 77 | comms_in_empty_req++; 78 | comms_reg->pending = 0; 79 | } 80 | else 81 | { 82 | comms_reg->in_byte = comms_in_fifo.peek(); 83 | comms_reg->in_seq++; 84 | } 85 | } 86 | } 87 | } 88 | 89 | static void pio_set_y(PIO p, uint sm, uint32_t v) 90 | { 91 | uint32_t shift_save = p->sm[sm].shiftctrl; 92 | p->sm[sm].shiftctrl &= ~PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_BITS; 93 | 94 | const uint instr_shift = pio_encode_in(pio_y, 4); 95 | const uint instr_mov = pio_encode_mov(pio_y, pio_isr); 96 | for (int i = 7; i >= 0; i--) 97 | { 98 | const uint32_t nibble = (v >> (i * 4)) & 0xf; 99 | pio_sm_exec(p, sm, pio_encode_set(pio_y, nibble)); 100 | pio_sm_exec(p, sm, instr_shift); 101 | } 102 | pio_sm_exec(p, sm, instr_mov); 103 | p->sm[sm].shiftctrl &= shift_save; 104 | } 105 | 106 | static void comms_start_programs(uint32_t addr, CommsRegisters *regs) 107 | { 108 | if (prg_comms_detect.valid()) 109 | { 110 | PRG_LOCAL(prg_comms_detect, p, sm, offset, cfg); 111 | sm_config_set_in_pins(&cfg, 0); 112 | pio_sm_init(p, sm, offset, &cfg); 113 | pio_set_y(p, sm, (addr + 0x200) >> 9); 114 | pio_sm_set_enabled(p, sm, true); 115 | pio_set_irq0_source_enabled(p, (pio_interrupt_source_t)(pis_sm0_rx_fifo_not_empty + sm), true); 116 | irq_set_exclusive_handler(PIO_IRQ_NUM(p, 0), comms_irq_handler); 117 | irq_set_enabled(PIO_IRQ_NUM(p, 0), true); 118 | } 119 | 120 | #if defined(FEATURE_CLOCK) 121 | if (prg_comms_clock.valid()) 122 | { 123 | pio_gpio_init(prg_comms_clock.pio(), CLOCK_PIN); 124 | gpio_set_dir(CLOCK_PIN, false); 125 | gpio_set_input_enabled(CLOCK_PIN, true); 126 | 127 | PRG_LOCAL(prg_comms_clock, p, sm, offset, cfg); 128 | sm_config_set_in_pins(&cfg, 0); 129 | sm_config_set_in_shift(&cfg, true, false, 32); 130 | pio_sm_init(p, sm, offset, &cfg); 131 | pio_set_y(p, sm, addr + offsetof(CommsRegisters, tick_reset)); 132 | pio_sm_set_enabled(p, sm, true); 133 | 134 | dma_channel_config c = dma_channel_get_default_config(DMA_CH_CLOCK_PING); 135 | channel_config_set_transfer_data_size(&c, DMA_SIZE_32); 136 | channel_config_set_read_increment(&c, false); 137 | channel_config_set_write_increment(&c, false); 138 | channel_config_set_dreq(&c, PIO_DREQ_NUM(prg_comms_clock.pio(), prg_comms_clock.sm, false)); 139 | channel_config_set_high_priority(&c, true); 140 | channel_config_set_irq_quiet(&c, true); 141 | channel_config_set_chain_to(&c, DMA_CH_CLOCK_PONG); 142 | dma_channel_configure(DMA_CH_CLOCK_PING, &c, ®s->tick_count, &prg_comms_clock.pio()->rxf[prg_comms_clock.sm], 0xffffffff, false); 143 | channel_config_set_chain_to(&c, DMA_CH_CLOCK_PING); 144 | dma_channel_configure(DMA_CH_CLOCK_PONG, &c, ®s->tick_count, &prg_comms_clock.pio()->rxf[prg_comms_clock.sm], 0xffffffff, true); 145 | } 146 | #endif // FEATURE_CLOCK 147 | } 148 | 149 | static void comms_end_programs() 150 | { 151 | comms_reg->debug1 = 0xff00; 152 | if (prg_comms_detect.valid()) 153 | { 154 | PRG_LOCAL(prg_comms_detect, pio, sm, offset, cfg); 155 | 156 | comms_reg->debug1 = 0xff01; 157 | 158 | pio_sm_set_enabled(pio, sm, false); 159 | comms_reg->debug1 = 0xff02; 160 | pio_sm_clear_fifos(pio, sm); 161 | comms_reg->debug1 = 0xff03; 162 | pio_set_irq0_source_enabled(pio, (pio_interrupt_source_t)(pis_sm0_rx_fifo_not_empty + sm), false); 163 | comms_reg->debug1 = 0xff04; 164 | irq_set_enabled(PIO_IRQ_NUM(pio, 0), false); 165 | comms_reg->debug1 = 0xff05; 166 | } 167 | 168 | #if defined(FEATURE_CLOCK) 169 | if (prg_comms_clock.valid()) 170 | { 171 | PRG_LOCAL(prg_comms_clock, pio, sm, offset, cfg); 172 | 173 | pio_sm_set_enabled(pio, sm, false); 174 | pio_sm_clear_fifos(pio, sm); 175 | dma_channel_abort(DMA_CH_CLOCK_PING); 176 | dma_channel_abort(DMA_CH_CLOCK_PONG); 177 | } 178 | #endif // FEATURE_CLOCK 179 | } 180 | 181 | static void update_comms_out(uint8_t *outbytes, int *outcount, int max_outcount) 182 | { 183 | while (comms_out_deferred_ack != comms_out_deferred_req) 184 | { 185 | comms_reg->out_seq++; 186 | comms_out_deferred_ack++; 187 | } 188 | 189 | while (comms_out_fifo.count() > 0) 190 | { 191 | outbytes[*outcount] = comms_out_fifo.pop(); 192 | (*outcount)++; 193 | 194 | if (*outcount == max_outcount) 195 | { 196 | pl_send_payload(PacketType::CommsData, outbytes, *outcount); 197 | *outcount = 0; 198 | } 199 | } 200 | } 201 | 202 | void comms_begin_session(uint32_t addr, uint8_t *rom_base) 203 | { 204 | comms_out_fifo.clear(); 205 | comms_in_fifo.clear(); 206 | comms_out_deferred_ack = 0; 207 | comms_out_deferred_req = 0; 208 | comms_in_empty_ack = 0; 209 | comms_in_empty_req = 1; 210 | comms_reg_addr = (addr & ADDR_MASK & ~0x3ff); 211 | comms_reg = (CommsRegisters *)(rom_base + comms_reg_addr); 212 | comms_reg->active = 0; 213 | comms_reg->pending = 0; 214 | comms_reg->in_seq = 0; 215 | comms_reg->out_seq = 0; 216 | memcpy(comms_reg->magic, "PICO", 4); 217 | 218 | comms_start_programs(comms_reg_addr, comms_reg); 219 | 220 | comms_reg->active = 1; 221 | } 222 | 223 | void comms_end_session() 224 | { 225 | if (comms_reg == nullptr) return; 226 | 227 | comms_end_programs(); 228 | 229 | comms_reg->active = 0; 230 | comms_reg = nullptr; 231 | } 232 | 233 | bool comms_update(const uint8_t *data, uint32_t len, uint32_t timeout_ms) 234 | { 235 | if (comms_reg == nullptr) return true; 236 | 237 | absolute_time_t end_time = make_timeout_time_ms(timeout_ms); 238 | 239 | uint8_t outbytes[MAX_PKT_PAYLOAD]; 240 | int outcount = 0; 241 | 242 | update_comms_out(outbytes, &outcount, sizeof(outbytes)); 243 | 244 | uint incount = 0; 245 | while (incount < len) 246 | { 247 | comms_reg->pending = 1; 248 | do 249 | { 250 | update_comms_out(outbytes, &outcount, sizeof(outbytes)); 251 | if (absolute_time_diff_us(get_absolute_time(), end_time) < 0) 252 | { 253 | return false; 254 | } 255 | } while (comms_in_fifo.is_full()); 256 | 257 | comms_in_fifo.push(data[incount]); 258 | incount++; 259 | 260 | if (comms_in_empty_ack != comms_in_empty_req) 261 | { 262 | comms_reg->in_byte = comms_in_fifo.peek(); 263 | comms_reg->in_seq++; 264 | comms_in_empty_ack++; 265 | } 266 | } 267 | 268 | if (outcount > 0) 269 | { 270 | pl_send_payload(PacketType::CommsData, outbytes, outcount); 271 | } 272 | 273 | return true; 274 | } 275 | -------------------------------------------------------------------------------- /firmware/comms.h: -------------------------------------------------------------------------------- 1 | #if !defined(COMMS_H) 2 | #define COMMS_H 1 3 | 4 | #include 5 | #include 6 | 7 | #include "hardware/sync.h" 8 | 9 | template 10 | struct FIFO 11 | { 12 | uint32_t head; 13 | uint32_t tail; 14 | uint8_t data[N]; 15 | 16 | FIFO() 17 | { 18 | head = tail = 0; 19 | } 20 | 21 | void clear() 22 | { 23 | tail = head; 24 | } 25 | 26 | uint32_t count() const 27 | { 28 | return head - tail; 29 | } 30 | 31 | bool is_full() const 32 | { 33 | return count() == N; 34 | } 35 | 36 | bool is_empty() const 37 | { 38 | return count() == 0; 39 | } 40 | 41 | void push(uint8_t v) 42 | { 43 | data[head % N] = v; 44 | __dmb(); 45 | head++; 46 | } 47 | 48 | uint8_t pop() 49 | { 50 | uint8_t v = data[tail % N]; 51 | __dmb(); 52 | tail++; 53 | return v; 54 | } 55 | 56 | uint8_t peek() 57 | { 58 | return data[tail % N]; 59 | } 60 | }; 61 | 62 | void comms_begin_session(uint32_t addr, uint8_t *rom_base); 63 | void comms_end_session(); 64 | bool comms_update(const uint8_t *data, uint32_t len, uint32_t timeout_ms); 65 | 66 | #endif // COMMS_H 67 | -------------------------------------------------------------------------------- /firmware/comms.pio: -------------------------------------------------------------------------------- 1 | ; 17 instructions 2 | ; y set by cpu 3 | .program comms_detect 4 | start: 5 | ; loop until oe/cs goes low 6 | mov osr, pins ; move into osr for shifting 7 | out null, 9 ; skip address, outputs 8 | out x, 8 9 | jmp x!=y start 10 | out null, 3 11 | out x, 2 ; oe, cs 12 | jmp x-- start ; loop if oe/cs is not low 13 | 14 | ; validate that the address this matches, go back to start 15 | mov osr, pins ; move saved isr into osr 16 | out isr, 9 ; save lower bits 17 | out x, 8 ; check if upper matches 18 | jmp x!=y start 19 | 20 | ; loop oe/cs goes high 21 | .wrap_target 22 | mov osr, pins 23 | out null, 9 24 | out x, 8 ; addr 25 | jmp x!=y commit 26 | .wrap 27 | 28 | commit: 29 | ; push 8 bits into fifo 30 | push noblock 31 | jmp start 32 | 33 | ; 15 instructions 34 | ; matching address in y, set by cpu 35 | .program comms_clock 36 | normal_loop: 37 | wait 1 pin 17 ; wait for raising clock edge 38 | 39 | ; do increment 40 | mov x, ~isr ; negate isr into x 41 | jmp x-- dummy_jump1 ; decrement (increment) 42 | dummy_jump1: 43 | wait 0 pin 17 ; wait for falling edge 44 | 45 | mov isr, ~x ; negate x into isr 46 | 47 | ; check if addr matches 48 | mov x, pins 49 | jmp x!=y normal_loop ; if address doesn't match 50 | 51 | push noblock ; push ISR and clear it 52 | 53 | ; loop until access ends 54 | .wrap_target 55 | loop_no_access: 56 | wait 1 pin 17 ; wait for raising clock edge 57 | 58 | ; do increment 59 | mov x, ~isr ; negate isr into x 60 | jmp x-- dummy_jump2 ; decrement (increment) 61 | dummy_jump2: 62 | wait 0 pin 17 ; wait for falling edge 63 | 64 | mov isr, ~x ; negate x into isr 65 | 66 | mov x, pins 67 | jmp x!=y normal_loop ; if address doesn't match go back to normal loop 68 | .wrap 69 | 70 | 71 | ; vim:ft=pioasm 72 | 73 | -------------------------------------------------------------------------------- /firmware/data_bus.pio: -------------------------------------------------------------------------------- 1 | 2 | ; Data pin output program 3 | ; 1 op 4 | .program data_output 5 | .wrap_target 6 | out pins, 8 ; pull from fifo and send to data pins 7 | .wrap 8 | 9 | ; OR /OE and /CS and set the buffer OE 10 | ; 4 ops 11 | .program set_output_enable 12 | .origin 0 13 | .side_set 1 14 | mov pc, pins side 0 15 | mov pc, pins side 1 16 | mov pc, pins side 1 17 | mov pc, pins side 1 18 | 19 | ; OR /OE and /CS and set 4 pindirs 20 | ; 4 ops 21 | .program set_pindir 22 | .origin 0 23 | .side_set 4 pindirs 24 | mov pc, pins side 0xf 25 | mov pc, pins side 0 26 | mov pc, pins side 0 27 | mov pc, pins side 0 28 | 29 | 30 | ; Report activity to CPU 31 | ; 8 ops 32 | .program report_data_access 33 | wait_oe: 34 | mov y, pins ; read in all pins 35 | mov osr, y ; move into the osr so we can shift them out 36 | out null, 20 ; skip all the other pins 37 | out x, 2 ; move OE in x 38 | jmp x-- wait_oe ; if /OE or /CS are high, check again 39 | 40 | irq nowait 0 rel ; tell the cpu 41 | 42 | .wrap_target 43 | wait_change: 44 | mov x, pins ; read all pins again 45 | jmp x!=y wait_oe ; if any have changed, restart and check oe again 46 | .wrap 47 | 48 | 49 | ; Output bitstream to TCA5405 expander 50 | ; 1 op 51 | .program write_tca_bits 52 | .wrap_target 53 | out pins, 1 54 | .wrap 55 | 56 | ; vim:ft=pioasm 57 | 58 | -------------------------------------------------------------------------------- /firmware/flash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "hardware/dma.h" 7 | #include "hardware/flash.h" 8 | #include "hardware/structs/ssi.h" 9 | 10 | #include "pico/sync.h" 11 | #include "pico/unique_id.h" 12 | 13 | #include "flash.h" 14 | #include "rom.h" 15 | #include "system.h" 16 | 17 | static constexpr uint FLASH_ROM_OFFSET = FLASH_SIZE - ROM_SIZE; 18 | static constexpr uint FLASH_CFG_OFFSET = FLASH_ROM_OFFSET - FLASH_SECTOR_SIZE; 19 | 20 | static constexpr uint CONFIG_VERSION = 0x00010009; 21 | 22 | const uint8_t *flash_rom_data = (uint8_t *)(XIP_BASE + FLASH_ROM_OFFSET); 23 | const Config *flash_config = (Config *)(XIP_BASE + FLASH_CFG_OFFSET); 24 | static_assert(sizeof(Config) <= FLASH_PAGE_SIZE); 25 | 26 | 27 | void __no_inline_not_in_flash_func(flash_bulk_read)(uint32_t *rxbuf, uint32_t flash_offs, size_t len, 28 | uint dma_chan) 29 | { 30 | // SSI must be disabled to set transfer size. If software is executing 31 | // from flash right now then it's about to have a bad time 32 | ssi_hw->ssienr = 0; 33 | ssi_hw->ctrlr1 = len - 1; // NDF, number of data frames 34 | ssi_hw->dmacr = SSI_DMACR_TDMAE_BITS | SSI_DMACR_RDMAE_BITS; 35 | ssi_hw->ssienr = 1; 36 | // Other than NDF, the SSI configuration used for XIP is suitable for a bulk read too. 37 | 38 | // Configure and start the DMA. Note we are avoiding the dma_*() functions 39 | // as we can't guarantee they'll be inlined 40 | dma_hw->ch[dma_chan].read_addr = (uint32_t)&ssi_hw->dr0; 41 | dma_hw->ch[dma_chan].write_addr = (uint32_t)rxbuf; 42 | dma_hw->ch[dma_chan].transfer_count = len; 43 | // Must enable DMA byteswap because non-XIP 32-bit flash transfers are 44 | // big-endian on SSI (we added a hardware tweak to make XIP sensible) 45 | dma_hw->ch[dma_chan].ctrl_trig = 46 | DMA_CH0_CTRL_TRIG_BSWAP_BITS | 47 | DREQ_XIP_SSIRX << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB | 48 | dma_chan << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB | 49 | DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS | 50 | DMA_CH0_CTRL_TRIG_DATA_SIZE_VALUE_SIZE_WORD << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB | 51 | DMA_CH0_CTRL_TRIG_EN_BITS; 52 | 53 | // Now DMA is waiting, kick off the SSI transfer (mode continuation bits in LSBs) 54 | ssi_hw->dr0 = (flash_offs << 8u) | 0xa0u; 55 | 56 | // Wait for DMA finish 57 | while (dma_hw->ch[dma_chan].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS); 58 | 59 | // Reconfigure SSI before we jump back into flash! 60 | ssi_hw->ssienr = 0; 61 | ssi_hw->ctrlr1 = 0; // Single 32-bit data frame per transfer 62 | ssi_hw->dmacr = 0; 63 | ssi_hw->ssienr = 1; 64 | } 65 | 66 | void flash_save_config(const Config *config) 67 | { 68 | if (!memcmp(config, flash_config, sizeof(Config))) return; 69 | 70 | rom_service_stop(); 71 | uint32_t ints = save_and_disable_interrupts(); 72 | flash_range_erase(FLASH_CFG_OFFSET, FLASH_SECTOR_SIZE); 73 | flash_range_program(FLASH_CFG_OFFSET, (const uint8_t *)config, FLASH_PAGE_SIZE); 74 | restore_interrupts(ints); 75 | rom_service_start(); 76 | } 77 | 78 | 79 | void flash_init_config(Config *config) 80 | { 81 | memcpy(config, flash_config, sizeof(Config)); 82 | 83 | if (config->version == CONFIG_VERSION) return; 84 | 85 | memset(config, 0, sizeof(Config)); 86 | 87 | config->addr_mask = ADDR_MASK; 88 | config->version = CONFIG_VERSION; 89 | config->default_reset = ResetLevel::Z; 90 | config->initial_reset = ResetLevel::Z; 91 | pico_get_unique_board_id_string(config->name, sizeof(config->name)); 92 | 93 | flash_save_config(config); 94 | } 95 | 96 | 97 | void flash_save_rom() 98 | { 99 | rom_service_stop(); 100 | uint32_t ints = save_and_disable_interrupts(); 101 | flash_range_erase(FLASH_ROM_OFFSET, ROM_SIZE); 102 | flash_range_program(FLASH_ROM_OFFSET, rom_get_buffer(), ROM_SIZE); 103 | restore_interrupts(ints); 104 | rom_service_start(); 105 | } 106 | 107 | uint32_t flash_load_rom() 108 | { 109 | uint32_t start_time = time_us_32(); 110 | 111 | uint32_t ints = save_and_disable_interrupts(); 112 | flash_bulk_read((uint32_t *)rom_get_buffer(), FLASH_ROM_OFFSET, ROM_SIZE / 4, DMA_CH_FLASH); 113 | restore_interrupts(ints); 114 | 115 | //memcpy(rom_get_buffer(), flash_rom_data, ROM_SIZE); 116 | 117 | uint32_t flash_load_time = time_us_32() - start_time; 118 | 119 | return flash_load_time; 120 | } 121 | -------------------------------------------------------------------------------- /firmware/flash.h: -------------------------------------------------------------------------------- 1 | #if !defined(FLASH_H) 2 | #define FLASH_H 1 3 | 4 | #include 5 | #include 6 | 7 | enum class ResetLevel : uint8_t 8 | { 9 | Low, 10 | High, 11 | Z 12 | }; 13 | 14 | struct Config 15 | { 16 | uint32_t version; 17 | char name[16]; 18 | char rom_name[16]; 19 | ResetLevel initial_reset; 20 | ResetLevel default_reset; 21 | uint32_t addr_mask; 22 | }; 23 | 24 | void flash_save_config(const Config *config); 25 | void flash_init_config(Config *config); 26 | void flash_save_rom(); 27 | uint32_t flash_load_rom(); 28 | 29 | #endif // FLASH_H 30 | -------------------------------------------------------------------------------- /firmware/memmap_firmware.ld: -------------------------------------------------------------------------------- 1 | /* Based on GCC ARM embedded samples. 2 | Defines the following symbols for use by code: 3 | __exidx_start 4 | __exidx_end 5 | __etext 6 | __data_start__ 7 | __preinit_array_start 8 | __preinit_array_end 9 | __init_array_start 10 | __init_array_end 11 | __fini_array_start 12 | __fini_array_end 13 | __data_end__ 14 | __bss_start__ 15 | __bss_end__ 16 | __end__ 17 | end 18 | __HeapLimit 19 | __StackLimit 20 | __StackTop 21 | __stack (== StackTop) 22 | */ 23 | 24 | MEMORY 25 | { 26 | FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k 27 | RAM(rwx) : ORIGIN = 0x20040000, LENGTH = 8k 28 | BLOCK_RAM(rwx) : ORIGIN = 0x21000000, LENGTH = 256k 29 | } 30 | 31 | ENTRY(_entry_point) 32 | 33 | SECTIONS 34 | { 35 | /* Second stage bootloader is prepended to the image. It must be 256 bytes big 36 | and checksummed. It is usually built by the boot_stage2 target 37 | in the Raspberry Pi Pico SDK 38 | */ 39 | 40 | .flash_begin : { 41 | __flash_binary_start = .; 42 | } > FLASH 43 | 44 | .boot2 : { 45 | __boot2_start__ = .; 46 | KEEP (*(.boot2)) 47 | __boot2_end__ = .; 48 | } > FLASH 49 | 50 | ASSERT(__boot2_end__ - __boot2_start__ == 256, 51 | "ERROR: Pico second stage bootloader must be 256 bytes in size") 52 | 53 | /* The second stage will always enter the image at the start of .text. 54 | The debugger will use the ELF entry point, which is the _entry_point 55 | symbol if present, otherwise defaults to start of .text. 56 | This can be used to transfer control back to the bootrom on debugger 57 | launches only, to perform proper flash setup. 58 | */ 59 | 60 | .text : { 61 | __logical_binary_start = .; 62 | KEEP (*(.vectors)) 63 | KEEP (*(.binary_info_header)) 64 | __binary_info_header_end = .; 65 | KEEP (*(.reset)) 66 | /* TODO revisit this now memset/memcpy/float in ROM */ 67 | /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from 68 | * FLASH ... we will include any thing excluded here in .data below by default */ 69 | *(.init) 70 | *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) 71 | *(.fini) 72 | /* Pull all c'tors into .text */ 73 | *crtbegin.o(.ctors) 74 | *crtbegin?.o(.ctors) 75 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 76 | *(SORT(.ctors.*)) 77 | *(.ctors) 78 | /* Followed by destructors */ 79 | *crtbegin.o(.dtors) 80 | *crtbegin?.o(.dtors) 81 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 82 | *(SORT(.dtors.*)) 83 | *(.dtors) 84 | 85 | *(.eh_frame*) 86 | . = ALIGN(4); 87 | } > FLASH 88 | 89 | .rodata : { 90 | *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) 91 | . = ALIGN(4); 92 | *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) 93 | . = ALIGN(4); 94 | } > FLASH 95 | 96 | .ARM.extab : 97 | { 98 | *(.ARM.extab* .gnu.linkonce.armextab.*) 99 | } > FLASH 100 | 101 | __exidx_start = .; 102 | .ARM.exidx : 103 | { 104 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 105 | } > FLASH 106 | __exidx_end = .; 107 | 108 | /* Machine inspectable binary information */ 109 | . = ALIGN(4); 110 | __binary_info_start = .; 111 | .binary_info : 112 | { 113 | KEEP(*(.binary_info.keep.*)) 114 | *(.binary_info.*) 115 | } > FLASH 116 | __binary_info_end = .; 117 | . = ALIGN(4); 118 | 119 | .ram_vector_table (NOLOAD): { 120 | *(.ram_vector_table) 121 | } > RAM 122 | 123 | .data : { 124 | __data_start__ = .; 125 | *(vtable) 126 | 127 | *(.time_critical*) 128 | 129 | /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ 130 | *(.text*) 131 | . = ALIGN(4); 132 | *(.rodata*) 133 | . = ALIGN(4); 134 | 135 | *(.data*) 136 | 137 | . = ALIGN(4); 138 | *(.after_data.*) 139 | . = ALIGN(4); 140 | /* preinit data */ 141 | PROVIDE_HIDDEN (__mutex_array_start = .); 142 | KEEP(*(SORT(.mutex_array.*))) 143 | KEEP(*(.mutex_array)) 144 | PROVIDE_HIDDEN (__mutex_array_end = .); 145 | 146 | . = ALIGN(4); 147 | /* preinit data */ 148 | PROVIDE_HIDDEN (__preinit_array_start = .); 149 | KEEP(*(SORT(.preinit_array.*))) 150 | KEEP(*(.preinit_array)) 151 | PROVIDE_HIDDEN (__preinit_array_end = .); 152 | 153 | . = ALIGN(4); 154 | /* init data */ 155 | PROVIDE_HIDDEN (__init_array_start = .); 156 | KEEP(*(SORT(.init_array.*))) 157 | KEEP(*(.init_array)) 158 | PROVIDE_HIDDEN (__init_array_end = .); 159 | 160 | . = ALIGN(4); 161 | /* finit data */ 162 | PROVIDE_HIDDEN (__fini_array_start = .); 163 | *(SORT(.fini_array.*)) 164 | *(.fini_array) 165 | PROVIDE_HIDDEN (__fini_array_end = .); 166 | 167 | *(.jcr) 168 | . = ALIGN(4); 169 | /* All data end */ 170 | __data_end__ = .; 171 | } > RAM AT> FLASH 172 | /* __etext is (for backwards compatibility) the name of the .data init source pointer (...) */ 173 | __etext = LOADADDR(.data); 174 | 175 | .uninitialized_data (NOLOAD): { 176 | . = ALIGN(4); 177 | *(.uninitialized_data*) 178 | } > RAM 179 | 180 | __scratch_x_start__ = .; 181 | __scratch_x_end__ = .; 182 | __scratch_x_source__ = .; 183 | __scratch_y_start__ = .; 184 | __scratch_y_end__ = .; 185 | __scratch_y_source__ = .; 186 | 187 | .bss : { 188 | . = ALIGN(4); 189 | __bss_start__ = .; 190 | *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) 191 | *(COMMON) 192 | . = ALIGN(4); 193 | __bss_end__ = .; 194 | } > RAM 195 | 196 | .heap (NOLOAD): 197 | { 198 | __end__ = .; 199 | end = __end__; 200 | KEEP(*(.heap*)) 201 | __HeapLimit = .; 202 | } > RAM 203 | 204 | /* .stack*_dummy section doesn't contains any symbols. It is only 205 | * used for linker to calculate size of stack sections, and assign 206 | * values to stack symbols later 207 | * 208 | * stack1 section may be empty/missing if platform_launch_core1 is not used */ 209 | 210 | .stack1_dummy (NOLOAD): 211 | { 212 | *(.stack1*) 213 | } > RAM 214 | 215 | .stack_dummy (NOLOAD): 216 | { 217 | __StackBottom = .; 218 | KEEP(*(.stack*)) 219 | __StackTop = .; 220 | } > RAM 221 | 222 | .flash_end : { 223 | PROVIDE(__flash_binary_end = .); 224 | } > FLASH 225 | 226 | /* stack limit is poorly named, but historically is maximum heap ptr */ 227 | __StackLimit = ORIGIN(RAM) + LENGTH(RAM); 228 | PROVIDE(__stack = __StackTop); 229 | 230 | /* Check if data + heap + stack exceeds RAM limit */ 231 | ASSERT(__StackTop <= __StackLimit, "region RAM overflowed") 232 | 233 | ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") 234 | /* todo assert on extra code */ 235 | } 236 | 237 | -------------------------------------------------------------------------------- /firmware/pico_link.cpp: -------------------------------------------------------------------------------- 1 | #include "pico_link.h" 2 | 3 | #include "pico/stdlib.h" 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | static uint8_t incoming_buffer[sizeof(Packet)]; 10 | static uint8_t incoming_count; 11 | 12 | static uint8_t activity_count = 0; 13 | static uint8_t activity_report = 0; 14 | 15 | void usb_send(const void *data, size_t len) 16 | { 17 | const uint8_t *ptr = (const uint8_t *)data; 18 | uint32_t remaining = len; 19 | 20 | while (remaining > 0) 21 | { 22 | uint32_t sent = tud_cdc_write(ptr, remaining); 23 | ptr += sent; 24 | remaining -= sent; 25 | tud_task(); 26 | } 27 | 28 | tud_cdc_write_flush(); 29 | 30 | activity_count++; 31 | } 32 | 33 | void pl_send_packet(const Packet *pkt) 34 | { 35 | usb_send(pkt, pkt->size + 2); 36 | } 37 | 38 | void pl_send_null(PacketType type) 39 | { 40 | uint8_t buf[2]; 41 | buf[0] = (uint8_t)type; 42 | buf[1] = 0; 43 | usb_send(buf, 2); 44 | } 45 | 46 | void pl_send_string(PacketType type, const char *s) 47 | { 48 | Packet pkt; 49 | pkt.type = (uint8_t)type; 50 | pkt.size = MIN(MAX_PKT_PAYLOAD, strlen(s)); 51 | strncpy((char *)pkt.payload, s, pkt.size); 52 | usb_send(&pkt, pkt.size + 2); 53 | } 54 | 55 | void pl_send_payload(PacketType type, const void *data, size_t len) 56 | { 57 | Packet pkt; 58 | pkt.type = (uint8_t)type; 59 | pkt.size = MIN(len, MAX_PKT_PAYLOAD); 60 | memcpy(pkt.payload, data, len); 61 | usb_send(&pkt, pkt.size + 2); 62 | } 63 | 64 | void pl_send_debug(const char *s, uint32_t v0, uint32_t v1) 65 | { 66 | Packet pkt; 67 | pkt.type = (uint8_t)PacketType::Debug; 68 | pkt.size = MIN(MAX_PKT_PAYLOAD, strlen(s) + 8); 69 | memcpy(pkt.payload, &v0, sizeof(v0)); 70 | memcpy(pkt.payload + 4, &v1, sizeof(v1)); 71 | strncpy((char *)pkt.payload + 8, s, pkt.size - 8); 72 | usb_send(&pkt, pkt.size + 2); 73 | } 74 | 75 | void pl_send_error(const char *s, uint32_t v0, uint32_t v1) 76 | { 77 | Packet pkt; 78 | pkt.type = (uint8_t)PacketType::Error; 79 | pkt.size = MIN(MAX_PKT_PAYLOAD, strlen(s) + 8); 80 | memcpy(pkt.payload, &v0, sizeof(v0)); 81 | memcpy(pkt.payload + 4, &v1, sizeof(v1)); 82 | strncpy((char *)pkt.payload + 8, s, pkt.size - 8); 83 | usb_send(&pkt, pkt.size + 2); 84 | } 85 | 86 | void pl_wait_for_connection() 87 | { 88 | // Wait for connection 89 | while (!tud_cdc_connected()) 90 | { 91 | tud_task(); 92 | sleep_ms(1); 93 | } 94 | 95 | // Flush input 96 | tud_cdc_read_flush(); 97 | tud_cdc_write_clear(); 98 | 99 | incoming_count = 0; 100 | 101 | activity_count = activity_report = 0; 102 | 103 | // Write preamble 104 | usb_send("PicoROM Hello", 13); 105 | } 106 | 107 | bool pl_is_connected() 108 | { 109 | return tud_cdc_connected(); 110 | } 111 | 112 | const Packet *pl_poll() 113 | { 114 | tud_task(); 115 | 116 | uint32_t space = sizeof(incoming_buffer) - incoming_count; 117 | uint32_t rx_avail = tud_cdc_available(); 118 | 119 | uint32_t read_size = MIN(rx_avail, space); 120 | if (read_size > 0) 121 | { 122 | incoming_count += tud_cdc_read(incoming_buffer + incoming_count, read_size); 123 | } 124 | 125 | if (incoming_count >= 2) 126 | { 127 | Packet *pkt = (Packet *)incoming_buffer; 128 | if ((pkt->size + 2) <= incoming_count) 129 | { 130 | activity_count++; 131 | return pkt; 132 | } 133 | } 134 | 135 | return nullptr; 136 | } 137 | 138 | void pl_consume_packet(const Packet *pkt) 139 | { 140 | uint32_t used = pkt->size + 2; 141 | uint32_t remaining = incoming_count - used; 142 | 143 | if (remaining > 0) 144 | { 145 | memmove(incoming_buffer, incoming_buffer + used, remaining); 146 | } 147 | 148 | incoming_count = remaining; 149 | } 150 | 151 | bool pl_check_activity() 152 | { 153 | if (activity_count != activity_report) 154 | { 155 | activity_report = activity_count; 156 | return true; 157 | } 158 | 159 | return false; 160 | } 161 | -------------------------------------------------------------------------------- /firmware/pico_link.h: -------------------------------------------------------------------------------- 1 | #if !defined(PICO_LINK_H) 2 | #define PICO_LINK_H 1 3 | 4 | #include 5 | #include 6 | 7 | enum class PacketType : uint8_t 8 | { 9 | SetPointer = 3, 10 | GetPointer = 4, 11 | CurPointer = 5, 12 | Write = 6, 13 | Read = 7, 14 | ReadData = 8, 15 | 16 | CommitFlash = 12, 17 | CommitDone = 13, 18 | 19 | SetParameter = 20, 20 | GetParameter = 21, 21 | Parameter = 22, 22 | ParameterError = 23, 23 | QueryParameter = 24, 24 | 25 | CommsStart = 80, 26 | CommsEnd = 81, 27 | CommsData = 82, 28 | 29 | Identify = 0xf8, 30 | Bootsel = 0xf9, 31 | Error = 0xfe, 32 | Debug = 0xff 33 | }; 34 | 35 | static constexpr size_t MAX_PKT_PAYLOAD = 30; 36 | 37 | struct Packet 38 | { 39 | uint8_t type; 40 | uint8_t size; 41 | 42 | uint8_t payload[MAX_PKT_PAYLOAD]; 43 | }; 44 | 45 | void pl_send_null(PacketType type); 46 | void pl_send_string(PacketType type, const char *s); 47 | void pl_send_payload(PacketType type, const void *data, size_t len); 48 | void pl_send_debug(const char *s, uint32_t v0, uint32_t v1); 49 | void pl_send_error(const char *s, uint32_t v0, uint32_t v1); 50 | void pl_send_packet(const Packet *pkt); 51 | 52 | void pl_wait_for_connection(); 53 | bool pl_is_connected(); 54 | const Packet *pl_poll(); 55 | void pl_consume_packet(const Packet *pkt); 56 | 57 | bool pl_check_activity(); 58 | 59 | 60 | #endif // PICO_LINK_H 61 | -------------------------------------------------------------------------------- /firmware/pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) 22 | set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) 23 | message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") 24 | endif () 25 | 26 | if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) 27 | set(PICO_SDK_FETCH_FROM_GIT_TAG "master") 28 | message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") 29 | endif() 30 | 31 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 32 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 33 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 34 | set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") 35 | 36 | if (NOT PICO_SDK_PATH) 37 | if (PICO_SDK_FETCH_FROM_GIT) 38 | include(FetchContent) 39 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 40 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 41 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 42 | endif () 43 | # GIT_SUBMODULES_RECURSE was added in 3.17 44 | if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") 45 | FetchContent_Declare( 46 | pico_sdk 47 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 48 | GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} 49 | GIT_SUBMODULES_RECURSE FALSE 50 | ) 51 | else () 52 | FetchContent_Declare( 53 | pico_sdk 54 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 55 | GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} 56 | ) 57 | endif () 58 | 59 | if (NOT pico_sdk) 60 | message("Downloading Raspberry Pi Pico SDK") 61 | FetchContent_Populate(pico_sdk) 62 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 63 | endif () 64 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 65 | else () 66 | message(FATAL_ERROR 67 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 68 | ) 69 | endif () 70 | endif () 71 | 72 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 73 | if (NOT EXISTS ${PICO_SDK_PATH}) 74 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 75 | endif () 76 | 77 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 78 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 79 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 80 | endif () 81 | 82 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 83 | 84 | include(${PICO_SDK_INIT_CMAKE_FILE}) 85 | -------------------------------------------------------------------------------- /firmware/pio_programs.cpp: -------------------------------------------------------------------------------- 1 | #include "pio_programs.h" 2 | 3 | #include "comms.pio.h" 4 | #include "data_bus.pio.h" 5 | #include 6 | 7 | PIOProgram prg_comms_detect; 8 | PIOProgram prg_comms_clock; 9 | PIOProgram prg_write_tca_bits; 10 | PIOProgram prg_data_output; 11 | PIOProgram prg_set_output_enable; 12 | PIOProgram prg_set_pindir_hi; 13 | PIOProgram prg_set_pindir_lo; 14 | PIOProgram prg_report_data_access; 15 | 16 | 17 | #define add_program(p, s, name, prg) \ 18 | do \ 19 | { \ 20 | prg.pio_index = PIO_NUM(p); \ 21 | prg.sm = s; \ 22 | prg.config_func = name ## _program_get_default_config; \ 23 | prg.offset = pio_add_program(p, &name ## _program); \ 24 | if (prg.offset < 0) return false; \ 25 | } while(false) 26 | 27 | 28 | void pio_programs_reset() 29 | { 30 | pio_clear_instruction_memory(pio0); 31 | pio_clear_instruction_memory(pio1); 32 | 33 | prg_comms_detect.reset(); 34 | prg_comms_clock.reset(); 35 | prg_write_tca_bits.reset(); 36 | prg_data_output.reset(); 37 | prg_set_output_enable.reset(); 38 | prg_set_pindir_hi.reset(); 39 | prg_set_pindir_lo.reset(); 40 | } 41 | 42 | 43 | bool pio_programs_init() 44 | { 45 | pio_programs_reset(); 46 | 47 | add_program(pio0, 0, set_pindir, prg_set_pindir_lo); 48 | prg_set_pindir_hi = prg_set_pindir_lo; 49 | prg_set_pindir_hi.sm = 1; 50 | add_program(pio0, 2, comms_detect, prg_comms_detect); 51 | add_program(pio0, 3, data_output, prg_data_output); 52 | 53 | add_program(pio1, 0, set_output_enable, prg_set_output_enable); 54 | add_program(pio1, 1, report_data_access, prg_report_data_access); 55 | add_program(pio1, 2, comms_clock, prg_comms_clock); 56 | add_program(pio1, 3, write_tca_bits, prg_write_tca_bits); 57 | 58 | return true; 59 | } 60 | -------------------------------------------------------------------------------- /firmware/pio_programs.h: -------------------------------------------------------------------------------- 1 | #if !defined(PIO_PROGRAMS_H) 2 | #define PIO_PROGRAMS_H 1 3 | 4 | #include "hardware/pio.h" 5 | 6 | struct PIOProgram 7 | { 8 | int8_t sm; 9 | int8_t offset; 10 | int8_t pio_index; 11 | pio_sm_config (*config_func)(uint); 12 | 13 | void reset() 14 | { 15 | sm = 0; 16 | offset = -1; 17 | pio_index = PIO_NUM(pio0); 18 | config_func = nullptr; 19 | } 20 | 21 | bool valid() const 22 | { 23 | return offset >= 0; 24 | } 25 | 26 | PIO pio() 27 | { 28 | return PIO_INSTANCE(pio_index); 29 | } 30 | 31 | pio_sm_config config() const 32 | { 33 | if (config_func) 34 | return config_func(offset); 35 | else 36 | return pio_sm_config(); 37 | } 38 | }; 39 | 40 | #define PRG_LOCAL(prg, p, s, o, c) \ 41 | PIO p = prg.pio(); \ 42 | int s = prg.sm; \ 43 | int o = prg.offset; \ 44 | pio_sm_config c = prg.config(); 45 | 46 | extern PIOProgram prg_comms_detect; 47 | extern PIOProgram prg_comms_clock; 48 | extern PIOProgram prg_write_tca_bits; 49 | extern PIOProgram prg_data_output; 50 | extern PIOProgram prg_set_output_enable; 51 | extern PIOProgram prg_set_pindir_hi; 52 | extern PIOProgram prg_set_pindir_lo; 53 | extern PIOProgram prg_report_data_access; 54 | 55 | bool pio_programs_init(); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /firmware/rom.cpp: -------------------------------------------------------------------------------- 1 | #include "hardware/structs/bus_ctrl.h" 2 | #include "hardware/structs/syscfg.h" 3 | #include "pico/multicore.h" 4 | 5 | #include "pio_programs.h" 6 | #include "rom.h" 7 | #include "system.h" 8 | #include 9 | 10 | uint8_t *rom_data = (uint8_t *)0x21000000; // Start of 4 64kb sram banks 11 | 12 | uint32_t core1_stack[8]; 13 | static void __attribute__((noreturn, section(".time_critical.core1_rom_loop"))) rom_loop() 14 | { 15 | register uint32_t r0 __asm__("r0") = (uint32_t)rom_data; 16 | register uint32_t r1 __asm__("r1") = ADDR_MASK; 17 | register uint32_t r2 __asm__("r2") = (uint32_t)&prg_data_output.pio()->txf[prg_data_output.sm]; 18 | 19 | __asm__ volatile( 20 | "ldr r5, =0xd0000004 \n\t" 21 | "loop: \n\t" // Cycles Loop1 Loop2 22 | "ldr r3, [r5] \n\t" // Read GPIO in r3 1 1 8 23 | "and r3, r1 \n\t" // AND with ADDR_MASK 1 2 9 24 | "ldrb r3, [r0, r3] \n\t" // Read from rom_data 2 4 11 25 | "strb r3, [r2] \n\t" // Write to FIFO 1 5 12 26 | "b loop \n\t" // Loop 2 7 27 | : "+r"(r0), "+r"(r1), "+r"(r2) 28 | : 29 | : "r5", "cc", "memory"); 30 | 31 | __builtin_unreachable(); 32 | } 33 | 34 | 35 | static void rom_pio_init_output_program() 36 | { 37 | if (prg_data_output.valid()) 38 | { 39 | PRG_LOCAL(prg_data_output, p, sm, offset, cfg); 40 | // Set the output direction 41 | pio_sm_set_consecutive_pindirs(p, sm, BASE_DATA_PIN, N_DATA_PINS, true); 42 | 43 | // Set output pins and autopull at 8-bits 44 | sm_config_set_out_pins(&cfg, BASE_DATA_PIN, N_DATA_PINS); 45 | sm_config_set_out_shift(&cfg, true, true, N_DATA_PINS); 46 | pio_sm_init(p, sm, offset, &cfg); 47 | pio_sm_set_enabled(p, sm, true); 48 | } 49 | } 50 | 51 | static void rom_pio_init_output_enable_program() 52 | { 53 | if (prg_set_output_enable.valid()) 54 | { 55 | PRG_LOCAL(prg_set_output_enable, p, sm, offset, cfg); 56 | 57 | // set oe pin directions, data pin direction will be set by the state machine 58 | pio_sm_set_consecutive_pindirs(p, sm, BASE_OE_PIN, N_OE_PINS, false); 59 | pio_sm_set_consecutive_pindirs(p, sm, BUF_OE_PIN, 1, true); 60 | 61 | // OE pins as input 62 | sm_config_set_in_pins(&cfg, BASE_OE_PIN); 63 | sm_config_set_sideset_pins(&cfg, BUF_OE_PIN); 64 | 65 | // Data pins as output, but just the direction is set 66 | sm_config_set_out_pins(&cfg, BASE_DATA_PIN, N_DATA_PINS); 67 | 68 | // We set the BUF_OE pin using the SET op 69 | sm_config_set_set_pins(&cfg, BUF_OE_PIN, 1); 70 | 71 | pio_sm_init(p, sm, offset, &cfg); 72 | pio_sm_set_enabled(p, sm, true); 73 | } 74 | } 75 | 76 | static void rom_pio_init_pindirs_program() 77 | { 78 | if (prg_set_pindir_lo.valid()) 79 | { 80 | PRG_LOCAL(prg_set_pindir_lo, p, sm, offset, cfg); 81 | 82 | // OE pins as input 83 | sm_config_set_in_pins(&cfg, BASE_OE_PIN); 84 | sm_config_set_sideset_pins(&cfg, BASE_DATA_PIN); 85 | 86 | pio_sm_init(p, sm, offset, &cfg); 87 | pio_sm_set_enabled(p, sm, true); 88 | } 89 | 90 | if (prg_set_pindir_hi.valid()) 91 | { 92 | PRG_LOCAL(prg_set_pindir_hi, p, sm, offset, cfg); 93 | 94 | // OE pins as input 95 | sm_config_set_in_pins(&cfg, BASE_OE_PIN); 96 | sm_config_set_sideset_pins(&cfg, BASE_DATA_PIN + 4); 97 | 98 | pio_sm_init(p, sm, offset, &cfg); 99 | pio_sm_set_enabled(p, sm, true); 100 | } 101 | } 102 | 103 | 104 | static void rom_pio_init_output_enable_report_program() 105 | { 106 | if (prg_report_data_access.valid()) 107 | { 108 | PRG_LOCAL(prg_report_data_access, p, sm, offset, cfg); 109 | 110 | // This program looks at all input pins 111 | sm_config_set_in_pins(&cfg, 0); 112 | 113 | // Disable interrupts, we manually check the flag and clear it 114 | pio_set_irq0_source_enabled(p, (enum pio_interrupt_source)((uint)pis_interrupt0 + sm), false); 115 | pio_set_irq1_source_enabled(p, (enum pio_interrupt_source)((uint)pis_interrupt0 + sm), false); 116 | pio_interrupt_clear(p, sm); 117 | 118 | pio_sm_init(p, sm, offset, &cfg); 119 | pio_sm_set_enabled(p, sm, true); 120 | } 121 | } 122 | 123 | static void rom_pio_init_tca_program() 124 | { 125 | if (prg_write_tca_bits.valid()) 126 | { 127 | PRG_LOCAL(prg_write_tca_bits, p, sm, offset, cfg); 128 | 129 | // Enable output and set pin high 130 | pio_sm_set_pindirs_with_mask(p, sm, 0xffffffff, TCA_EXPANDER_PIN_MASK); 131 | pio_sm_set_pins_with_mask(p, sm, 0xffffffff, TCA_EXPANDER_PIN_MASK); 132 | 133 | sm_config_set_out_pins(&cfg, TCA_EXPANDER_PIN, 1); 134 | sm_config_set_clkdiv(&cfg, 1000); // divide down to TCA rate 135 | sm_config_set_out_shift(&cfg, true, true, 10); // 4-bits of preample, 5-bits of data, 1-end bit 136 | 137 | pio_sm_init(p, sm, offset, &cfg); 138 | pio_sm_set_enabled(p, sm, true); 139 | } 140 | } 141 | 142 | void rom_init_programs() 143 | { 144 | // Assign data and oe pins to pio 145 | for (uint ofs = 0; ofs < N_DATA_PINS; ofs++) 146 | { 147 | pio_gpio_init(prg_data_output.pio(), BASE_DATA_PIN + ofs); 148 | gpio_set_dir(BASE_DATA_PIN + ofs, true); 149 | gpio_set_drive_strength(BASE_DATA_PIN + ofs, GPIO_DRIVE_STRENGTH_2MA); 150 | gpio_set_input_enabled(BASE_DATA_PIN + ofs, false); 151 | gpio_set_inover(BASE_DATA_PIN + ofs, GPIO_OVERRIDE_LOW); 152 | gpio_set_slew_rate(BASE_DATA_PIN + ofs, GPIO_SLEW_RATE_FAST); 153 | } 154 | 155 | for (uint ofs = 0; ofs < N_OE_PINS; ofs++) 156 | { 157 | gpio_init(BASE_OE_PIN + ofs); 158 | gpio_set_dir(BASE_OE_PIN + ofs, false); 159 | gpio_set_input_hysteresis_enabled(BASE_OE_PIN + ofs, false); 160 | syscfg_hw->proc_in_sync_bypass |= 1 << (BASE_OE_PIN + ofs); 161 | } 162 | 163 | pio_gpio_init(prg_set_output_enable.pio(), BUF_OE_PIN); 164 | gpio_set_drive_strength(BUF_OE_PIN, GPIO_DRIVE_STRENGTH_2MA); 165 | gpio_set_input_enabled(BUF_OE_PIN, false); 166 | gpio_set_inover(BUF_OE_PIN, GPIO_OVERRIDE_LOW); 167 | gpio_set_slew_rate(BUF_OE_PIN, GPIO_SLEW_RATE_FAST); 168 | 169 | pio_gpio_init(prg_write_tca_bits.pio(), TCA_EXPANDER_PIN); 170 | gpio_set_input_enabled(TCA_EXPANDER_PIN, false); 171 | gpio_set_inover(TCA_EXPANDER_PIN, GPIO_OVERRIDE_LOW); 172 | gpio_set_drive_strength(TCA_EXPANDER_PIN, GPIO_DRIVE_STRENGTH_2MA); 173 | 174 | rom_pio_init_output_program(); 175 | rom_pio_init_pindirs_program(); 176 | rom_pio_init_output_enable_program(); 177 | rom_pio_init_output_enable_report_program(); 178 | rom_pio_init_tca_program(); 179 | 180 | tca_set_pins(0x00); 181 | tca_set_pins(0x00); 182 | } 183 | 184 | uint8_t *rom_get_buffer() 185 | { 186 | return rom_data; 187 | } 188 | 189 | void rom_service_start() 190 | { 191 | // give core1 bus priority 192 | bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_PROC1_BITS; 193 | 194 | multicore_reset_core1(); 195 | multicore_launch_core1_with_stack(rom_loop, core1_stack, sizeof(core1_stack)); 196 | } 197 | 198 | void rom_service_stop() 199 | { 200 | multicore_reset_core1(); 201 | } 202 | 203 | bool rom_check_oe() 204 | { 205 | if (pio_interrupt_get(prg_report_data_access.pio(), prg_report_data_access.sm)) 206 | { 207 | pio_interrupt_clear(prg_report_data_access.pio(), prg_report_data_access.sm); 208 | return true; 209 | } 210 | return false; 211 | } 212 | 213 | static uint8_t tca_pins_state = 0x0; 214 | void tca_set_pins(uint8_t pins) 215 | { 216 | uint32_t bitstream = 0b1000001010 | ((pins & 0x1f) << 4); 217 | prg_write_tca_bits.pio()->txf[prg_write_tca_bits.sm] = bitstream; 218 | tca_pins_state = pins; 219 | } 220 | 221 | void tca_set_pin(int pin, bool en) 222 | { 223 | uint8_t new_state = tca_pins_state; 224 | if (en) 225 | new_state |= (1 << pin); 226 | else 227 | new_state &= ~(1 << pin); 228 | 229 | if (new_state != tca_pins_state) 230 | { 231 | tca_set_pins(new_state); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /firmware/rom.h: -------------------------------------------------------------------------------- 1 | #if !defined(ROM_H) 2 | #define ROM_H 1 3 | 4 | #include "hardware/pio.h" 5 | 6 | void rom_init_programs(); 7 | 8 | void rom_service_start(); 9 | void rom_service_stop(); 10 | 11 | uint8_t *rom_get_buffer(); 12 | 13 | bool rom_check_oe(); 14 | 15 | void tca_set_pins(uint8_t pins); 16 | void tca_set_pin(int pin, bool en); 17 | 18 | #endif // ROM_H -------------------------------------------------------------------------------- /firmware/str_util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char *strcpyz(char *dest, size_t dest_size, const char *src) 6 | { 7 | size_t n = dest_size - 1; 8 | strncpy(dest, src, n); 9 | dest[n] = '\0'; 10 | 11 | return dest; 12 | } 13 | 14 | bool streq(const char *a, const char *b) 15 | { 16 | return strcasecmp(a, b) == 0; 17 | } 18 | 19 | // libc stroul uses errno which uses a few 100 bytes for reentrant support 20 | // in newlib which can't afford. 21 | uint32_t strtoul(const char *nptr) 22 | { 23 | const char *p = nptr; 24 | uint32_t n = 0; 25 | int base = 0; 26 | 27 | if (*p == '0') 28 | { 29 | p++; 30 | if (base == 16 && (*p == 'X' || *p == 'x')) 31 | { 32 | p++; 33 | } 34 | else if (base == 2 && (*p == 'B' || *p == 'b')) 35 | { 36 | p++; 37 | } 38 | else if (base == 0) 39 | { 40 | if (*p == 'X' || *p == 'x') 41 | { 42 | base = 16; 43 | p++; 44 | } 45 | else if (*p == 'B' || *p == 'b') 46 | { 47 | base = 2; 48 | p++; 49 | } 50 | else 51 | { 52 | base = 8; 53 | } 54 | } 55 | } 56 | else if (base == 0) 57 | { 58 | base = 10; 59 | } 60 | while (1) 61 | { 62 | int c; 63 | if (*p >= 'A') 64 | c = ((*p - 'A') & (~('a' ^ 'A'))) + 10; 65 | else if (*p <= '9') 66 | c = *p - '0'; 67 | else 68 | break; 69 | if (c < 0 || c >= base) break; 70 | p++; 71 | n = n * base + c; 72 | } 73 | return n; 74 | } 75 | -------------------------------------------------------------------------------- /firmware/str_util.h: -------------------------------------------------------------------------------- 1 | #if !defined(STR_UTIL_H) 2 | #define STR_UTIL_H 1 3 | 4 | #include 5 | #include 6 | 7 | char *strcpyz(char *dest, size_t dest_size, const char *src); 8 | bool streq(const char *a, const char *b); 9 | uint32_t strtoul(const char *nptr); 10 | 11 | #endif // STR_UTIL_H 12 | -------------------------------------------------------------------------------- /firmware/system.h: -------------------------------------------------------------------------------- 1 | #if !defined(SYSTEM_H) 2 | #define SYSTEM_H 1 3 | 4 | #include 5 | 6 | static constexpr uint32_t N_DATA_PINS = 8; 7 | static constexpr uint32_t BASE_DATA_PIN = 22; 8 | static constexpr uint32_t DATA_PIN_MASK = ((1 << N_DATA_PINS) - 1) << BASE_DATA_PIN; 9 | 10 | static constexpr uint32_t N_OE_PINS = 2; 11 | static constexpr uint32_t BASE_OE_PIN = 20; 12 | static constexpr uint32_t OE_PIN_MASK = ((1 << N_OE_PINS) - 1) << BASE_OE_PIN; 13 | 14 | //#define FEATURE_CLOCK 1 15 | 16 | #if defined(FEATURE_CLOCK) 17 | static constexpr uint32_t CLOCK_PIN = 17; 18 | static constexpr uint32_t N_ADDR_PINS = 17; 19 | #else 20 | static constexpr uint32_t N_ADDR_PINS = 18; 21 | #endif 22 | 23 | static constexpr uint32_t BASE_ADDR_PIN = 0; 24 | static constexpr uint32_t ADDR_PIN_MASK = ((1 << N_ADDR_PINS) - 1) << BASE_ADDR_PIN; 25 | 26 | 27 | static constexpr uint32_t BUF_OE_PIN = 19; 28 | static constexpr uint32_t BUF_OE_PIN_MASK = 1 << BUF_OE_PIN; 29 | 30 | static constexpr uint32_t TCA_EXPANDER_PIN = 18; 31 | static constexpr uint32_t TCA_EXPANDER_PIN_MASK = 1 << TCA_EXPANDER_PIN; 32 | 33 | static constexpr uint32_t TCA_LINK_PIN = 1; 34 | static constexpr uint32_t TCA_READ_PIN = 2; 35 | static constexpr uint32_t TCA_RESET_VALUE_PIN = 3; 36 | static constexpr uint32_t TCA_RESET_PIN = 4; 37 | 38 | static constexpr uint32_t ROM_SIZE = 0x40000; 39 | static constexpr uint32_t ADDR_MASK = ((1 << N_ADDR_PINS) - 1); 40 | static constexpr uint32_t FLASH_SIZE = 2 * 1024 * 1024; 41 | 42 | static constexpr uint32_t STATUS_PIO_INIT = 0x00000001; 43 | 44 | static constexpr uint32_t DMA_CH_FLASH = 0; 45 | static constexpr uint32_t DMA_CH_CLOCK_PING = 2; 46 | static constexpr uint32_t DMA_CH_CLOCK_PONG = 3; 47 | 48 | #endif // SYSTEM_H 49 | -------------------------------------------------------------------------------- /hardware/3dshapes/DHVQFN24_L5.5-W3.5-H0.9-P0.50-BL-EP.step: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/hardware/3dshapes/DHVQFN24_L5.5-W3.5-H0.9-P0.50-BL-EP.step -------------------------------------------------------------------------------- /hardware/3dshapes/USB-C-SMD_GT-USB-7051A.step: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/hardware/3dshapes/USB-C-SMD_GT-USB-7051A.step -------------------------------------------------------------------------------- /hardware/3dshapes/V-QFN4525-20_L4.5-W2.5-P0.50-BL.step: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/hardware/3dshapes/V-QFN4525-20_L4.5-W2.5-P0.50-BL.step -------------------------------------------------------------------------------- /hardware/3dshapes/X2QFN-8_L1.5-W1.5-P0.50-BL.step: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/hardware/3dshapes/X2QFN-8_L1.5-W1.5-P0.50-BL.step -------------------------------------------------------------------------------- /hardware/MCU_RaspberryPi_RP2040.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # RP2040 5 | # 6 | DEF RP2040 U 0 40 Y Y 1 F N 7 | F0 "U" -1150 1950 50 H V C CNN 8 | F1 "RP2040" 950 -1950 50 H V C CNN 9 | F2 "RP2040_minimal:RP2040-QFN-56" -750 0 50 H I C CNN 10 | F3 "" -750 0 50 H I C CNN 11 | DRAW 12 | T 0 0 200 100 0 0 0 "Raspberry Pi" Normal 0 C C 13 | T 0 0 0 100 0 0 0 RP2040 Normal 0 C C 14 | S 1150 1900 -1150 -1900 0 1 10 f 15 | X IOVDD 1 350 2000 100 D 50 50 1 1 W 16 | X IOVDD 10 250 2000 100 D 50 50 1 1 W 17 | X GPIO8 11 1250 500 100 L 50 50 1 1 B 18 | X GPIO9 12 1250 400 100 L 50 50 1 1 B 19 | X GPIO10 13 1250 300 100 L 50 50 1 1 B 20 | X GPIO11 14 1250 200 100 L 50 50 1 1 B 21 | X GPIO12 15 1250 100 100 L 50 50 1 1 B 22 | X GPIO13 16 1250 0 100 L 50 50 1 1 B 23 | X GPIO14 17 1250 -100 100 L 50 50 1 1 B 24 | X GPIO15 18 1250 -200 100 L 50 50 1 1 B 25 | X TESTEN 19 -500 -2000 100 U 50 50 1 1 P 26 | X GPIO0 2 1250 1300 100 L 50 50 1 1 B 27 | X XIN 20 -1250 -100 100 R 50 50 1 1 I 28 | X XOUT 21 -1250 -300 100 R 50 50 1 1 P 29 | X IOVDD 22 150 2000 100 D 50 50 1 1 W 30 | X DVDD 23 -700 2000 100 D 50 50 1 1 W 31 | X SWCLK 24 -1250 -1250 100 R 50 50 1 1 O 32 | X SWD 25 -1250 -1350 100 R 50 50 1 1 B 33 | X RUN 26 -1250 -800 100 R 50 50 1 1 I 34 | X GPIO16 27 1250 -300 100 L 50 50 1 1 B 35 | X GPIO17 28 1250 -400 100 L 50 50 1 1 B 36 | X GPIO18 29 1250 -500 100 L 50 50 1 1 B 37 | X GPIO1 3 1250 1200 100 L 50 50 1 1 B 38 | X GPIO19 30 1250 -600 100 L 50 50 1 1 B 39 | X GPIO20 31 1250 -700 100 L 50 50 1 1 B 40 | X GPIO21 32 1250 -800 100 L 50 50 1 1 B 41 | X IOVDD 33 50 2000 100 D 50 50 1 1 W 42 | X GPIO22 34 1250 -900 100 L 50 50 1 1 B 43 | X GPIO23 35 1250 -1000 100 L 50 50 1 1 B 44 | X GPIO24 36 1250 -1100 100 L 50 50 1 1 B 45 | X GPIO25 37 1250 -1200 100 L 50 50 1 1 B 46 | X GPIO26_ADC0 38 1250 -1400 100 L 50 50 1 1 B 47 | X GPIO27_ADC1 39 1250 -1500 100 L 50 50 1 1 B 48 | X GPIO2 4 1250 1100 100 L 50 50 1 1 B 49 | X GPIO28_ADC2 40 1250 -1600 100 L 50 50 1 1 B 50 | X GPIO29_ADC3 41 1250 -1700 100 L 50 50 1 1 B 51 | X IOVDD 42 -50 2000 100 D 50 50 1 1 W 52 | X ADC_AVDD 43 650 2000 100 D 50 50 1 1 W 53 | X VREG_IN 44 -350 2000 100 D 50 50 1 1 W 54 | X VREG_VOUT 45 -500 2000 100 D 50 50 1 1 w 55 | X USB_DM 46 1250 1600 100 L 50 50 1 1 B 56 | X USB_DP 47 1250 1700 100 L 50 50 1 1 B 57 | X USB_VDD 48 500 2000 100 D 50 50 1 1 W 58 | X IOVDD 49 -150 2000 100 D 50 50 1 1 W 59 | X GPIO3 5 1250 1000 100 L 50 50 1 1 B 60 | X DVDD 50 -800 2000 100 D 50 50 1 1 W 61 | X QSPI_SD3 51 -1250 800 100 R 50 50 1 1 B 62 | X QSPI_SCLK 52 -1250 650 100 R 50 50 1 1 O 63 | X QSPI_SD0 53 -1250 1100 100 R 50 50 1 1 B 64 | X QSPI_SD2 54 -1250 900 100 R 50 50 1 1 B 65 | X QSPI_SD1 55 -1250 1000 100 R 50 50 1 1 B 66 | X QSPI_SS 56 -1250 1250 100 R 50 50 1 1 B 67 | X GND 57 0 -2000 100 U 50 50 1 1 W 68 | X GPIO4 6 1250 900 100 L 50 50 1 1 B 69 | X GPIO5 7 1250 800 100 L 50 50 1 1 B 70 | X GPIO6 8 1250 700 100 L 50 50 1 1 B 71 | X GPIO7 9 1250 600 100 L 50 50 1 1 B 72 | ENDDRAW 73 | ENDDEF 74 | # 75 | #End Library 76 | -------------------------------------------------------------------------------- /hardware/PicoROM-cache.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # Connector_Generic_Conn_01x02 5 | # 6 | DEF Connector_Generic_Conn_01x02 J 0 40 Y N 1 F N 7 | F0 "J" 0 100 50 H V C CNN 8 | F1 "Connector_Generic_Conn_01x02" 0 -200 50 H V C CNN 9 | F2 "" 0 0 50 H I C CNN 10 | F3 "" 0 0 50 H I C CNN 11 | $FPLIST 12 | Connector*:*_1x??_* 13 | $ENDFPLIST 14 | DRAW 15 | S -50 -95 0 -105 1 1 6 N 16 | S -50 5 0 -5 1 1 6 N 17 | S -50 50 50 -150 1 1 10 f 18 | X Pin_1 1 -200 0 150 R 50 50 1 1 P 19 | X Pin_2 2 -200 -100 150 R 50 50 1 1 P 20 | ENDDRAW 21 | ENDDEF 22 | # 23 | # Connector_Generic_Conn_02x18_Odd_Even 24 | # 25 | DEF Connector_Generic_Conn_02x18_Odd_Even J 0 40 Y N 1 F N 26 | F0 "J" 50 900 50 H V C CNN 27 | F1 "Connector_Generic_Conn_02x18_Odd_Even" 50 -1000 50 H V C CNN 28 | F2 "" 0 0 50 H I C CNN 29 | F3 "" 0 0 50 H I C CNN 30 | $FPLIST 31 | Connector*:*_2x??_* 32 | $ENDFPLIST 33 | DRAW 34 | S -50 -895 0 -905 1 1 6 N 35 | S -50 -795 0 -805 1 1 6 N 36 | S -50 -695 0 -705 1 1 6 N 37 | S -50 -595 0 -605 1 1 6 N 38 | S -50 -495 0 -505 1 1 6 N 39 | S -50 -395 0 -405 1 1 6 N 40 | S -50 -295 0 -305 1 1 6 N 41 | S -50 -195 0 -205 1 1 6 N 42 | S -50 -95 0 -105 1 1 6 N 43 | S -50 5 0 -5 1 1 6 N 44 | S -50 105 0 95 1 1 6 N 45 | S -50 205 0 195 1 1 6 N 46 | S -50 305 0 295 1 1 6 N 47 | S -50 405 0 395 1 1 6 N 48 | S -50 505 0 495 1 1 6 N 49 | S -50 605 0 595 1 1 6 N 50 | S -50 705 0 695 1 1 6 N 51 | S -50 805 0 795 1 1 6 N 52 | S -50 850 150 -950 1 1 10 f 53 | S 150 -895 100 -905 1 1 6 N 54 | S 150 -795 100 -805 1 1 6 N 55 | S 150 -695 100 -705 1 1 6 N 56 | S 150 -595 100 -605 1 1 6 N 57 | S 150 -495 100 -505 1 1 6 N 58 | S 150 -395 100 -405 1 1 6 N 59 | S 150 -295 100 -305 1 1 6 N 60 | S 150 -195 100 -205 1 1 6 N 61 | S 150 -95 100 -105 1 1 6 N 62 | S 150 5 100 -5 1 1 6 N 63 | S 150 105 100 95 1 1 6 N 64 | S 150 205 100 195 1 1 6 N 65 | S 150 305 100 295 1 1 6 N 66 | S 150 405 100 395 1 1 6 N 67 | S 150 505 100 495 1 1 6 N 68 | S 150 605 100 595 1 1 6 N 69 | S 150 705 100 695 1 1 6 N 70 | S 150 805 100 795 1 1 6 N 71 | X Pin_1 1 -200 800 150 R 50 50 1 1 P 72 | X Pin_10 10 300 400 150 L 50 50 1 1 P 73 | X Pin_11 11 -200 300 150 R 50 50 1 1 P 74 | X Pin_12 12 300 300 150 L 50 50 1 1 P 75 | X Pin_13 13 -200 200 150 R 50 50 1 1 P 76 | X Pin_14 14 300 200 150 L 50 50 1 1 P 77 | X Pin_15 15 -200 100 150 R 50 50 1 1 P 78 | X Pin_16 16 300 100 150 L 50 50 1 1 P 79 | X Pin_17 17 -200 0 150 R 50 50 1 1 P 80 | X Pin_18 18 300 0 150 L 50 50 1 1 P 81 | X Pin_19 19 -200 -100 150 R 50 50 1 1 P 82 | X Pin_2 2 300 800 150 L 50 50 1 1 P 83 | X Pin_20 20 300 -100 150 L 50 50 1 1 P 84 | X Pin_21 21 -200 -200 150 R 50 50 1 1 P 85 | X Pin_22 22 300 -200 150 L 50 50 1 1 P 86 | X Pin_23 23 -200 -300 150 R 50 50 1 1 P 87 | X Pin_24 24 300 -300 150 L 50 50 1 1 P 88 | X Pin_25 25 -200 -400 150 R 50 50 1 1 P 89 | X Pin_26 26 300 -400 150 L 50 50 1 1 P 90 | X Pin_27 27 -200 -500 150 R 50 50 1 1 P 91 | X Pin_28 28 300 -500 150 L 50 50 1 1 P 92 | X Pin_29 29 -200 -600 150 R 50 50 1 1 P 93 | X Pin_3 3 -200 700 150 R 50 50 1 1 P 94 | X Pin_30 30 300 -600 150 L 50 50 1 1 P 95 | X Pin_31 31 -200 -700 150 R 50 50 1 1 P 96 | X Pin_32 32 300 -700 150 L 50 50 1 1 P 97 | X Pin_33 33 -200 -800 150 R 50 50 1 1 P 98 | X Pin_34 34 300 -800 150 L 50 50 1 1 P 99 | X Pin_35 35 -200 -900 150 R 50 50 1 1 P 100 | X Pin_36 36 300 -900 150 L 50 50 1 1 P 101 | X Pin_4 4 300 700 150 L 50 50 1 1 P 102 | X Pin_5 5 -200 600 150 R 50 50 1 1 P 103 | X Pin_6 6 300 600 150 L 50 50 1 1 P 104 | X Pin_7 7 -200 500 150 R 50 50 1 1 P 105 | X Pin_8 8 300 500 150 L 50 50 1 1 P 106 | X Pin_9 9 -200 400 150 R 50 50 1 1 P 107 | ENDDRAW 108 | ENDDEF 109 | # 110 | # Connector_USB_B_Micro 111 | # 112 | DEF Connector_USB_B_Micro J 0 40 Y Y 1 F N 113 | F0 "J" -200 450 50 H V L CNN 114 | F1 "Connector_USB_B_Micro" -200 350 50 H V L CNN 115 | F2 "" 150 -50 50 H I C CNN 116 | F3 "" 150 -50 50 H I C CNN 117 | ALIAS USB_B_Mini 118 | $FPLIST 119 | USB* 120 | $ENDFPLIST 121 | DRAW 122 | C -150 85 25 0 1 10 F 123 | C -25 135 15 0 1 10 F 124 | S -200 -300 200 300 0 1 10 f 125 | S -5 -300 5 -270 0 1 0 N 126 | S 10 50 -20 20 0 1 10 F 127 | S 200 -205 170 -195 0 1 0 N 128 | S 200 -105 170 -95 0 1 0 N 129 | S 200 -5 170 5 0 1 0 N 130 | S 200 195 170 205 0 1 0 N 131 | P 2 0 1 10 -75 85 25 85 N 132 | P 4 0 1 10 -125 85 -100 85 -50 135 -25 135 N 133 | P 4 0 1 10 -100 85 -75 85 -50 35 0 35 N 134 | P 4 0 1 10 25 110 25 60 75 85 25 110 F 135 | P 5 0 1 0 -170 220 -70 220 -80 190 -160 190 -170 220 F 136 | P 9 0 1 0 -185 230 -185 220 -175 190 -175 180 -65 180 -65 190 -55 220 -55 230 -185 230 N 137 | X VBUS 1 300 200 100 L 50 50 1 1 w 138 | X D- 2 300 -100 100 L 50 50 1 1 P 139 | X D+ 3 300 0 100 L 50 50 1 1 P 140 | X ID 4 300 -200 100 L 50 50 1 1 P 141 | X GND 5 0 -400 100 U 50 50 1 1 w 142 | X Shield 6 -100 -400 100 U 50 50 1 1 P 143 | ENDDRAW 144 | ENDDEF 145 | # 146 | # Device_C 147 | # 148 | DEF Device_C C 0 10 N Y 1 F N 149 | F0 "C" 25 100 50 H V L CNN 150 | F1 "Device_C" 25 -100 50 H V L CNN 151 | F2 "" 38 -150 50 H I C CNN 152 | F3 "" 0 0 50 H I C CNN 153 | $FPLIST 154 | C_* 155 | $ENDFPLIST 156 | DRAW 157 | P 2 0 1 20 -80 -30 80 -30 N 158 | P 2 0 1 20 -80 30 80 30 N 159 | X ~ 1 0 150 110 D 50 50 1 1 P 160 | X ~ 2 0 -150 110 U 50 50 1 1 P 161 | ENDDRAW 162 | ENDDEF 163 | # 164 | # Device_Crystal 165 | # 166 | DEF Device_Crystal Y 0 40 N N 1 F N 167 | F0 "Y" 0 150 50 H V C CNN 168 | F1 "Device_Crystal" 0 -150 50 H V C CNN 169 | F2 "" 0 0 50 H I C CNN 170 | F3 "" 0 0 50 H I C CNN 171 | $FPLIST 172 | Crystal* 173 | $ENDFPLIST 174 | DRAW 175 | S -45 100 45 -100 0 1 12 N 176 | P 2 0 1 0 -100 0 -75 0 N 177 | P 2 0 1 20 -75 -50 -75 50 N 178 | P 2 0 1 20 75 -50 75 50 N 179 | P 2 0 1 0 100 0 75 0 N 180 | X 1 1 -150 0 50 R 50 50 1 1 P 181 | X 2 2 150 0 50 L 50 50 1 1 P 182 | ENDDRAW 183 | ENDDEF 184 | # 185 | # Device_R 186 | # 187 | DEF Device_R R 0 0 N Y 1 F N 188 | F0 "R" 80 0 50 V V C CNN 189 | F1 "Device_R" 0 0 50 V V C CNN 190 | F2 "" -70 0 50 V I C CNN 191 | F3 "" 0 0 50 H I C CNN 192 | $FPLIST 193 | R_* 194 | $ENDFPLIST 195 | DRAW 196 | S -40 -100 40 100 0 1 10 N 197 | X ~ 1 0 150 50 D 50 50 1 1 P 198 | X ~ 2 0 -150 50 U 50 50 1 1 P 199 | ENDDRAW 200 | ENDDEF 201 | # 202 | # MCU_RaspberryPi_RP2040_RP2040 203 | # 204 | DEF MCU_RaspberryPi_RP2040_RP2040 U 0 40 Y Y 1 F N 205 | F0 "U" -1150 1950 50 H V C CNN 206 | F1 "MCU_RaspberryPi_RP2040_RP2040" 950 -1950 50 H V C CNN 207 | F2 "RP2040_minimal:RP2040-QFN-56" -750 0 50 H I C CNN 208 | F3 "" -750 0 50 H I C CNN 209 | DRAW 210 | T 0 0 200 100 0 0 0 "Raspberry Pi" Normal 0 C C 211 | T 0 0 0 100 0 0 0 RP2040 Normal 0 C C 212 | S 1150 1900 -1150 -1900 0 1 10 f 213 | X IOVDD 1 350 2000 100 D 50 50 1 1 W 214 | X IOVDD 10 250 2000 100 D 50 50 1 1 W 215 | X GPIO8 11 1250 500 100 L 50 50 1 1 B 216 | X GPIO9 12 1250 400 100 L 50 50 1 1 B 217 | X GPIO10 13 1250 300 100 L 50 50 1 1 B 218 | X GPIO11 14 1250 200 100 L 50 50 1 1 B 219 | X GPIO12 15 1250 100 100 L 50 50 1 1 B 220 | X GPIO13 16 1250 0 100 L 50 50 1 1 B 221 | X GPIO14 17 1250 -100 100 L 50 50 1 1 B 222 | X GPIO15 18 1250 -200 100 L 50 50 1 1 B 223 | X TESTEN 19 -500 -2000 100 U 50 50 1 1 P 224 | X GPIO0 2 1250 1300 100 L 50 50 1 1 B 225 | X XIN 20 -1250 -100 100 R 50 50 1 1 I 226 | X XOUT 21 -1250 -300 100 R 50 50 1 1 P 227 | X IOVDD 22 150 2000 100 D 50 50 1 1 W 228 | X DVDD 23 -700 2000 100 D 50 50 1 1 W 229 | X SWCLK 24 -1250 -1250 100 R 50 50 1 1 O 230 | X SWD 25 -1250 -1350 100 R 50 50 1 1 B 231 | X RUN 26 -1250 -800 100 R 50 50 1 1 I 232 | X GPIO16 27 1250 -300 100 L 50 50 1 1 B 233 | X GPIO17 28 1250 -400 100 L 50 50 1 1 B 234 | X GPIO18 29 1250 -500 100 L 50 50 1 1 B 235 | X GPIO1 3 1250 1200 100 L 50 50 1 1 B 236 | X GPIO19 30 1250 -600 100 L 50 50 1 1 B 237 | X GPIO20 31 1250 -700 100 L 50 50 1 1 B 238 | X GPIO21 32 1250 -800 100 L 50 50 1 1 B 239 | X IOVDD 33 50 2000 100 D 50 50 1 1 W 240 | X GPIO22 34 1250 -900 100 L 50 50 1 1 B 241 | X GPIO23 35 1250 -1000 100 L 50 50 1 1 B 242 | X GPIO24 36 1250 -1100 100 L 50 50 1 1 B 243 | X GPIO25 37 1250 -1200 100 L 50 50 1 1 B 244 | X GPIO26_ADC0 38 1250 -1400 100 L 50 50 1 1 B 245 | X GPIO27_ADC1 39 1250 -1500 100 L 50 50 1 1 B 246 | X GPIO2 4 1250 1100 100 L 50 50 1 1 B 247 | X GPIO28_ADC2 40 1250 -1600 100 L 50 50 1 1 B 248 | X GPIO29_ADC3 41 1250 -1700 100 L 50 50 1 1 B 249 | X IOVDD 42 -50 2000 100 D 50 50 1 1 W 250 | X ADC_AVDD 43 650 2000 100 D 50 50 1 1 W 251 | X VREG_IN 44 -350 2000 100 D 50 50 1 1 W 252 | X VREG_VOUT 45 -500 2000 100 D 50 50 1 1 w 253 | X USB_DM 46 1250 1600 100 L 50 50 1 1 B 254 | X USB_DP 47 1250 1700 100 L 50 50 1 1 B 255 | X USB_VDD 48 500 2000 100 D 50 50 1 1 W 256 | X IOVDD 49 -150 2000 100 D 50 50 1 1 W 257 | X GPIO3 5 1250 1000 100 L 50 50 1 1 B 258 | X DVDD 50 -800 2000 100 D 50 50 1 1 W 259 | X QSPI_SD3 51 -1250 800 100 R 50 50 1 1 B 260 | X QSPI_SCLK 52 -1250 650 100 R 50 50 1 1 O 261 | X QSPI_SD0 53 -1250 1100 100 R 50 50 1 1 B 262 | X QSPI_SD2 54 -1250 900 100 R 50 50 1 1 B 263 | X QSPI_SD1 55 -1250 1000 100 R 50 50 1 1 B 264 | X QSPI_SS 56 -1250 1250 100 R 50 50 1 1 B 265 | X GND 57 0 -2000 100 U 50 50 1 1 W 266 | X GPIO4 6 1250 900 100 L 50 50 1 1 B 267 | X GPIO5 7 1250 800 100 L 50 50 1 1 B 268 | X GPIO6 8 1250 700 100 L 50 50 1 1 B 269 | X GPIO7 9 1250 600 100 L 50 50 1 1 B 270 | ENDDRAW 271 | ENDDEF 272 | # 273 | # Mechanical_MountingHole 274 | # 275 | DEF Mechanical_MountingHole H 0 40 Y Y 1 F N 276 | F0 "H" 0 200 50 H V C CNN 277 | F1 "Mechanical_MountingHole" 0 125 50 H V C CNN 278 | F2 "" 0 0 50 H I C CNN 279 | F3 "" 0 0 50 H I C CNN 280 | $FPLIST 281 | MountingHole* 282 | $ENDFPLIST 283 | DRAW 284 | C 0 0 50 0 1 50 N 285 | ENDDRAW 286 | ENDDEF 287 | # 288 | # Memory_Flash_W25Q128JVS 289 | # 290 | DEF Memory_Flash_W25Q128JVS U 0 20 Y Y 1 F N 291 | F0 "U" -350 350 50 H V C CNN 292 | F1 "Memory_Flash_W25Q128JVS" 300 350 50 H V C CNN 293 | F2 "Package_SO:SOIC-8_5.23x5.23mm_P1.27mm" 0 0 50 H I C CNN 294 | F3 "" 0 0 50 H I C CNN 295 | ALIAS W25Q128JVS 296 | $FPLIST 297 | SOIC*5.23x5.23mm*P1.27mm* 298 | $ENDFPLIST 299 | DRAW 300 | S -400 300 400 -300 0 1 10 f 301 | X ~CS 1 -500 100 100 R 50 50 1 1 I 302 | X DO(IO1) 2 500 100 100 L 50 50 1 1 B 303 | X IO2 3 500 -100 100 L 50 50 1 1 B 304 | X GND 4 0 -400 100 U 50 50 1 1 W 305 | X DI(IO0) 5 500 200 100 L 50 50 1 1 B 306 | X CLK 6 -500 -100 100 R 50 50 1 1 I 307 | X IO3 7 500 -200 100 L 50 50 1 1 B 308 | X VCC 8 0 400 100 D 50 50 1 1 W 309 | ENDDRAW 310 | ENDDEF 311 | # 312 | # Regulator_Linear_NCP1117-3.3_SOT223 313 | # 314 | DEF Regulator_Linear_NCP1117-3.3_SOT223 U 0 10 Y Y 1 F N 315 | F0 "U" -150 125 50 H V C CNN 316 | F1 "Regulator_Linear_NCP1117-3.3_SOT223" 0 125 50 H V L CNN 317 | F2 "Package_TO_SOT_SMD:SOT-223-3_TabPin2" 0 200 50 H I C CNN 318 | F3 "" 100 -250 50 H I C CNN 319 | ALIAS AP1117-18 AP1117-25 AP1117-33 AP1117-50 LD1117S33TR_SOT223 LD1117S12TR_SOT223 LD1117S18TR_SOT223 LD1117S25TR_SOT223 LD1117S50TR_SOT223 NCP1117-12_SOT223 NCP1117-1.5_SOT223 NCP1117-1.8_SOT223 NCP1117-2.0_SOT223 NCP1117-2.5_SOT223 NCP1117-2.85_SOT223 NCP1117-3.3_SOT223 NCP1117-5.0_SOT223 AMS1117-1.5 AMS1117-1.8 AMS1117-2.5 AMS1117-2.85 AMS1117-3.3 AMS1117-5.0 320 | $FPLIST 321 | SOT?223*TabPin2* 322 | $ENDFPLIST 323 | DRAW 324 | S -200 -200 200 75 0 1 10 f 325 | X GND 1 0 -300 100 U 50 50 1 1 W 326 | X VO 2 300 0 100 L 50 50 1 1 w 327 | X VI 3 -300 0 100 R 50 50 1 1 W 328 | ENDDRAW 329 | ENDDEF 330 | # 331 | # power_+1V1 332 | # 333 | DEF power_+1V1 #PWR 0 0 Y Y 1 F P 334 | F0 "#PWR" 0 -150 50 H I C CNN 335 | F1 "power_+1V1" 0 140 50 H V C CNN 336 | F2 "" 0 0 50 H I C CNN 337 | F3 "" 0 0 50 H I C CNN 338 | DRAW 339 | P 2 0 1 0 -30 50 0 100 N 340 | P 2 0 1 0 0 0 0 100 N 341 | P 2 0 1 0 0 100 30 50 N 342 | X +1V1 1 0 0 0 U 50 50 1 1 W N 343 | ENDDRAW 344 | ENDDEF 345 | # 346 | # power_+3V3 347 | # 348 | DEF power_+3V3 #PWR 0 0 Y Y 1 F P 349 | F0 "#PWR" 0 -150 50 H I C CNN 350 | F1 "power_+3V3" 0 140 50 H V C CNN 351 | F2 "" 0 0 50 H I C CNN 352 | F3 "" 0 0 50 H I C CNN 353 | ALIAS +3.3V 354 | DRAW 355 | P 2 0 1 0 -30 50 0 100 N 356 | P 2 0 1 0 0 0 0 100 N 357 | P 2 0 1 0 0 100 30 50 N 358 | X +3V3 1 0 0 0 U 50 50 1 1 W N 359 | ENDDRAW 360 | ENDDEF 361 | # 362 | # power_GND 363 | # 364 | DEF power_GND #PWR 0 0 Y Y 1 F P 365 | F0 "#PWR" 0 -250 50 H I C CNN 366 | F1 "power_GND" 0 -150 50 H V C CNN 367 | F2 "" 0 0 50 H I C CNN 368 | F3 "" 0 0 50 H I C CNN 369 | DRAW 370 | P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N 371 | X GND 1 0 0 0 D 50 50 1 1 W N 372 | ENDDRAW 373 | ENDDEF 374 | # 375 | # power_VBUS 376 | # 377 | DEF power_VBUS #PWR 0 0 Y Y 1 F P 378 | F0 "#PWR" 0 -150 50 H I C CNN 379 | F1 "power_VBUS" 0 150 50 H V C CNN 380 | F2 "" 0 0 50 H I C CNN 381 | F3 "" 0 0 50 H I C CNN 382 | DRAW 383 | P 2 0 1 0 -30 50 0 100 N 384 | P 2 0 1 0 0 0 0 100 N 385 | P 2 0 1 0 0 100 30 50 N 386 | X VBUS 1 0 0 0 U 50 50 1 1 W N 387 | ENDDRAW 388 | ENDDEF 389 | # 390 | #End Library 391 | -------------------------------------------------------------------------------- /hardware/PicoROM-rescue.dcm: -------------------------------------------------------------------------------- 1 | EESchema-DOCLIB Version 2.0 2 | # 3 | #End Doc Library 4 | -------------------------------------------------------------------------------- /hardware/PicoROM-rescue.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # USB_B_Micro-Connector 5 | # 6 | DEF USB_B_Micro-Connector J 0 40 Y Y 1 F N 7 | F0 "J" -200 450 50 H V L CNN 8 | F1 "USB_B_Micro-Connector" -200 350 50 H V L CNN 9 | F2 "" 150 -50 50 H I C CNN 10 | F3 "" 150 -50 50 H I C CNN 11 | $FPLIST 12 | USB* 13 | $ENDFPLIST 14 | DRAW 15 | S -200 -300 200 300 0 1 10 f 16 | C -150 85 25 0 1 10 F 17 | C -25 135 15 0 1 10 F 18 | S -5 -300 5 -270 0 1 0 N 19 | P 2 0 1 10 -75 85 25 85 N 20 | P 4 0 1 10 -125 85 -100 85 -50 135 -25 135 N 21 | P 4 0 1 10 -100 85 -75 85 -50 35 0 35 N 22 | P 4 0 1 10 25 110 25 60 75 85 25 110 F 23 | P 5 0 1 0 -170 220 -70 220 -80 190 -160 190 -170 220 F 24 | P 9 0 1 0 -185 230 -185 220 -175 190 -175 180 -65 180 -65 190 -55 220 -55 230 -185 230 N 25 | S 10 50 -20 20 0 1 10 F 26 | S 200 -205 170 -195 0 1 0 N 27 | S 200 -105 170 -95 0 1 0 N 28 | S 200 -5 170 5 0 1 0 N 29 | S 200 195 170 205 0 1 0 N 30 | X VBUS 1 300 200 100 L 50 50 1 1 w 31 | X D- 2 300 -100 100 L 50 50 1 1 P 32 | X D+ 3 300 0 100 L 50 50 1 1 P 33 | X ID 4 300 -200 100 L 50 50 1 1 P 34 | X GND 5 0 -400 100 U 50 50 1 1 w 35 | X Shield 6 -100 -400 100 U 50 50 1 1 P 36 | ENDDRAW 37 | ENDDEF 38 | # 39 | #End Library 40 | -------------------------------------------------------------------------------- /hardware/PicoROM.csv: -------------------------------------------------------------------------------- 1 | "#","Reference","Qty","Value","Footprint","DNP" 2 | "1","C1, C4","2","1u","Capacitor_SMD:C_0805_2012Metric","" 3 | "2","C2, C3","2","27p","Capacitor_SMD:C_0402_1005Metric","" 4 | "3","C5, C6, C7, C9, C11, C12, C13, C14, C15, C16, C17, C18","12","100n","Capacitor_SMD:C_0402_1005Metric","" 5 | "4","C8, C10","2","1u","Capacitor_SMD:C_0402_1005Metric","" 6 | "5","J1","1","USB_C_Receptacle_USB2.0","Connector_USB:USB_C_Receptacle_G-Switch_GT-USB-7051x","" 7 | "6","J2","1","Conn_01x02","Connector_PinHeader_1.27mm:PinHeader_1x02_P1.27mm_Vertical","" 8 | "7","J3, J4","2","Conn_01x16","Connector_PinHeader_2.54mm:PinHeader_1x16_P2.54mm_Vertical","" 9 | "8","R1, R5","2","1k","Capacitor_SMD:C_0402_1005Metric","" 10 | "9","R2, R8","2","0","Capacitor_SMD:C_0402_1005Metric","" 11 | "10","R3, R4","2","27","Capacitor_SMD:C_0402_1005Metric","" 12 | "11","R6, R7","2","5.1k","Capacitor_SMD:C_0402_1005Metric","" 13 | "12","U1","1","AP2112K-3.3","Package_TO_SOT_SMD:SOT-23-5","" 14 | "13","U2","1","W25Q16JVSNIQ","Package_SO:SOIC-8_3.9x4.9mm_P1.27mm","" 15 | "14","U3","1","RP2040","RP2040_minimal:RP2040-QFN-56","" 16 | "15","U4","1","74LVC245A","Package_DFN_QFN:DHVQFN-20-1EP_2.5x4.5mm_P0.5mm_EP1x3mm","" 17 | "16","Y1","1","445C25D12M00000","Crystal:Crystal_SMD_5032-2Pin_5.0x3.2mm","" 18 | -------------------------------------------------------------------------------- /hardware/PicoROM.pretty/Crystal_SMD_HC49-US.kicad_mod: -------------------------------------------------------------------------------- 1 | (module Crystal_SMD_HC49-US (layer F.Cu) (tedit 5F0C7995) 2 | (descr "SMD Crystal HC-49-SD http://cdn-reichelt.de/documents/datenblatt/B400/xxx-HC49-SMD.pdf, 11.4x4.7mm^2 package") 3 | (tags "SMD SMT crystal") 4 | (attr smd) 5 | (fp_text reference Y1 (at 0 -3.55) (layer F.SilkS) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_text value ABLS-12.000MHZ-B4-T (at 0 3.55) (layer F.Fab) 9 | (effects (font (size 1 1) (thickness 0.15))) 10 | ) 11 | (fp_arc (start 3.015 0) (end 3.015 -2.115) (angle 180) (layer F.Fab) (width 0.1)) 12 | (fp_arc (start -3.015 0) (end -3.015 -2.115) (angle -180) (layer F.Fab) (width 0.1)) 13 | (fp_line (start 6.8 -2.6) (end -6.8 -2.6) (layer F.CrtYd) (width 0.05)) 14 | (fp_line (start 6.8 2.6) (end 6.8 -2.6) (layer F.CrtYd) (width 0.05)) 15 | (fp_line (start -6.8 2.6) (end 6.8 2.6) (layer F.CrtYd) (width 0.05)) 16 | (fp_line (start -6.8 -2.6) (end -6.8 2.6) (layer F.CrtYd) (width 0.05)) 17 | (fp_line (start -6.7 2.55) (end 5.9 2.55) (layer F.SilkS) (width 0.12)) 18 | (fp_line (start -6.7 -2.55) (end -6.7 -1.3) (layer F.SilkS) (width 0.12)) 19 | (fp_line (start 5.9 -2.55) (end -6.7 -2.55) (layer F.SilkS) (width 0.12)) 20 | (fp_line (start -3.015 2.115) (end 3.015 2.115) (layer F.Fab) (width 0.1)) 21 | (fp_line (start -3.015 -2.115) (end 3.015 -2.115) (layer F.Fab) (width 0.1)) 22 | (fp_line (start 5.7 -2.35) (end -5.7 -2.35) (layer F.Fab) (width 0.1)) 23 | (fp_line (start 5.7 2.35) (end 5.7 -2.35) (layer F.Fab) (width 0.1)) 24 | (fp_line (start -5.7 2.35) (end 5.7 2.35) (layer F.Fab) (width 0.1)) 25 | (fp_line (start -5.7 -2.35) (end -5.7 2.35) (layer F.Fab) (width 0.1)) 26 | (fp_text user %R (at 0 0) (layer F.Fab) 27 | (effects (font (size 1 1) (thickness 0.15))) 28 | ) 29 | (fp_line (start -6.7 1.3) (end -6.7 2.55) (layer F.SilkS) (width 0.12)) 30 | (pad 2 smd rect (at 4.5 0) (size 5.6 2.1) (layers F.Cu F.Paste F.Mask)) 31 | (pad 1 smd rect (at -4.5 0) (size 5.6 2.1) (layers F.Cu F.Paste F.Mask)) 32 | (model ${KISYS3DMOD}/Crystal.3dshapes/Crystal_SMD_HC49-SD.wrl 33 | (at (xyz 0 0 0)) 34 | (scale (xyz 1 1 1)) 35 | (rotate (xyz 0 0 0)) 36 | ) 37 | ) 38 | -------------------------------------------------------------------------------- /hardware/PicoROM.pretty/DHVQFN24_L5.5-W3.5-P0.50-BL-EP.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "DHVQFN24_L5.5-W3.5-P0.50-BL-EP" 2 | (version 20240108) 3 | (generator "pcbnew") 4 | (generator_version "8.0") 5 | (layer "F.Cu") 6 | (property "Reference" "REF**" 7 | (at 0 -5.7 0) 8 | (layer "F.SilkS") 9 | (uuid "0959b5e9-28ce-4768-8be3-5af7a7bdbf86") 10 | (effects 11 | (font 12 | (size 1 1) 13 | (thickness 0.15) 14 | ) 15 | ) 16 | ) 17 | (property "Value" "DHVQFN24_L5.5-W3.5-P0.50-BL-EP" 18 | (at 0 5.7 0) 19 | (layer "F.Fab") 20 | (uuid "dc5aac40-d394-4a7e-9e80-5bafe91a463f") 21 | (effects 22 | (font 23 | (size 1 1) 24 | (thickness 0.15) 25 | ) 26 | ) 27 | ) 28 | (property "Footprint" "" 29 | (at 0 0 0) 30 | (layer "F.Fab") 31 | (hide yes) 32 | (uuid "7b15e881-33f5-45f6-81ff-dd1cffa6ab2e") 33 | (effects 34 | (font 35 | (size 1.27 1.27) 36 | (thickness 0.15) 37 | ) 38 | ) 39 | ) 40 | (property "Datasheet" "" 41 | (at 0 0 0) 42 | (layer "F.Fab") 43 | (hide yes) 44 | (uuid "805aaa87-5246-4ed7-8d02-e5f50ba97599") 45 | (effects 46 | (font 47 | (size 1.27 1.27) 48 | (thickness 0.15) 49 | ) 50 | ) 51 | ) 52 | (property "Description" "" 53 | (at 0 0 0) 54 | (layer "F.Fab") 55 | (hide yes) 56 | (uuid "3ae9ac83-f927-4b06-aa47-0f6b6a7c64c1") 57 | (effects 58 | (font 59 | (size 1.27 1.27) 60 | (thickness 0.15) 61 | ) 62 | ) 63 | ) 64 | (attr smd) 65 | (fp_line 66 | (start -2.75 -1.75) 67 | (end -2.75 -1.05) 68 | (stroke 69 | (width 0.1) 70 | (type solid) 71 | ) 72 | (layer "F.SilkS") 73 | (uuid "5b5bf425-16d9-476c-822f-646f1fdfbc38") 74 | ) 75 | (fp_line 76 | (start -2.75 -1.75) 77 | (end -2.55 -1.75) 78 | (stroke 79 | (width 0.1) 80 | (type solid) 81 | ) 82 | (layer "F.SilkS") 83 | (uuid "031cebc0-4d15-47d6-adf1-ea3d6350c22c") 84 | ) 85 | (fp_line 86 | (start -2.75 -0.45) 87 | (end -2.75 0.44) 88 | (stroke 89 | (width 0.1) 90 | (type solid) 91 | ) 92 | (layer "F.SilkS") 93 | (uuid "4a050284-6afb-434a-810c-18a511699c7d") 94 | ) 95 | (fp_line 96 | (start -2.75 1.75) 97 | (end -2.75 1.04) 98 | (stroke 99 | (width 0.1) 100 | (type solid) 101 | ) 102 | (layer "F.SilkS") 103 | (uuid "c62f6c79-8385-46f1-acb5-c9c12436168a") 104 | ) 105 | (fp_line 106 | (start -2.55 1.75) 107 | (end -2.75 1.75) 108 | (stroke 109 | (width 0.1) 110 | (type solid) 111 | ) 112 | (layer "F.SilkS") 113 | (uuid "690a7076-fe36-4c94-987c-7bd44d8a9901") 114 | ) 115 | (fp_line 116 | (start 2.55 -1.75) 117 | (end 2.75 -1.75) 118 | (stroke 119 | (width 0.1) 120 | (type solid) 121 | ) 122 | (layer "F.SilkS") 123 | (uuid "d56ede4f-3988-4a68-a67f-a90ba9a110fe") 124 | ) 125 | (fp_line 126 | (start 2.75 -1.75) 127 | (end 2.75 -1.05) 128 | (stroke 129 | (width 0.1) 130 | (type solid) 131 | ) 132 | (layer "F.SilkS") 133 | (uuid "f5a78e26-ed1f-4bf9-8812-d7fc88643ceb") 134 | ) 135 | (fp_line 136 | (start 2.75 -0.45) 137 | (end 2.75 0.45) 138 | (stroke 139 | (width 0.1) 140 | (type solid) 141 | ) 142 | (layer "F.SilkS") 143 | (uuid "deb21f8f-e158-416d-b642-a36c7d3a37ab") 144 | ) 145 | (fp_line 146 | (start 2.75 1.05) 147 | (end 2.75 1.75) 148 | (stroke 149 | (width 0.1) 150 | (type solid) 151 | ) 152 | (layer "F.SilkS") 153 | (uuid "9328d64b-0752-463a-9aab-9f6f2b4e338b") 154 | ) 155 | (fp_line 156 | (start 2.75 1.75) 157 | (end 2.55 1.75) 158 | (stroke 159 | (width 0.1) 160 | (type solid) 161 | ) 162 | (layer "F.SilkS") 163 | (uuid "2443627e-ac3f-4800-bb09-6f673cbb3f3e") 164 | ) 165 | (fp_circle 166 | (center -2.96 1.15) 167 | (end -2.91 1.15) 168 | (stroke 169 | (width 0.1) 170 | (type solid) 171 | ) 172 | (fill none) 173 | (layer "F.SilkS") 174 | (uuid "530333ff-4a76-4e68-8a67-90100d09c6ab") 175 | ) 176 | (fp_circle 177 | (center -2.79 0.72) 178 | (end -2.67 0.72) 179 | (stroke 180 | (width 0.24) 181 | (type solid) 182 | ) 183 | (fill none) 184 | (layer "Cmts.User") 185 | (uuid "47dcee79-a58d-427f-83e4-77f5f6d0612f") 186 | ) 187 | (fp_circle 188 | (center -2.75 1.75) 189 | (end -2.72 1.75) 190 | (stroke 191 | (width 0.06) 192 | (type solid) 193 | ) 194 | (fill none) 195 | (layer "F.Fab") 196 | (uuid "84c7040d-68db-4514-b2dd-cb32bc34eabd") 197 | ) 198 | (fp_text user "${REFERENCE}" 199 | (at 0 0 0) 200 | (layer "F.Fab") 201 | (uuid "c1bfa327-43e7-485a-aa8c-74f74517ca2f") 202 | (effects 203 | (font 204 | (size 1 1) 205 | (thickness 0.15) 206 | ) 207 | ) 208 | ) 209 | (pad "1" smd rect 210 | (at -2.7 0.74 90) 211 | (size 0.29 0.7) 212 | (layers "F.Cu" "F.Paste" "F.Mask") 213 | (uuid "a355e253-5847-4239-9326-86722b5d049d") 214 | ) 215 | (pad "2" smd rect 216 | (at -2.25 1.7) 217 | (size 0.29 0.7) 218 | (layers "F.Cu" "F.Paste" "F.Mask") 219 | (uuid "6fd0e6fc-36d4-4dcd-b683-d6c1ebae4e60") 220 | ) 221 | (pad "3" smd rect 222 | (at -1.75 1.7) 223 | (size 0.29 0.7) 224 | (layers "F.Cu" "F.Paste" "F.Mask") 225 | (uuid "15ff6a60-156c-4b0e-b8b3-ec87241aa7b1") 226 | ) 227 | (pad "4" smd rect 228 | (at -1.25 1.7) 229 | (size 0.29 0.7) 230 | (layers "F.Cu" "F.Paste" "F.Mask") 231 | (uuid "8d904852-09dd-4d21-a643-cb0106fe548e") 232 | ) 233 | (pad "5" smd rect 234 | (at -0.75 1.7) 235 | (size 0.29 0.7) 236 | (layers "F.Cu" "F.Paste" "F.Mask") 237 | (uuid "48bd3ee1-7bb8-4f2d-aeaa-c7e3bf8db818") 238 | ) 239 | (pad "6" smd rect 240 | (at -0.25 1.7) 241 | (size 0.29 0.7) 242 | (layers "F.Cu" "F.Paste" "F.Mask") 243 | (uuid "dd839867-e74e-4486-bd66-482357f8a763") 244 | ) 245 | (pad "7" smd rect 246 | (at 0.25 1.7) 247 | (size 0.29 0.7) 248 | (layers "F.Cu" "F.Paste" "F.Mask") 249 | (uuid "18fcdc06-223d-4a30-b22f-5764f5419093") 250 | ) 251 | (pad "8" smd rect 252 | (at 0.75 1.7) 253 | (size 0.29 0.7) 254 | (layers "F.Cu" "F.Paste" "F.Mask") 255 | (uuid "36555b90-48f4-4e5b-a196-291a34d3b0bb") 256 | ) 257 | (pad "9" smd rect 258 | (at 1.25 1.7) 259 | (size 0.29 0.7) 260 | (layers "F.Cu" "F.Paste" "F.Mask") 261 | (uuid "329e480a-4a86-4001-9aa6-f6ee1412770e") 262 | ) 263 | (pad "10" smd rect 264 | (at 1.75 1.7) 265 | (size 0.29 0.7) 266 | (layers "F.Cu" "F.Paste" "F.Mask") 267 | (uuid "752aaa30-da48-4dbc-b9d5-7ffefe665cf3") 268 | ) 269 | (pad "11" smd rect 270 | (at 2.25 1.7) 271 | (size 0.29 0.7) 272 | (layers "F.Cu" "F.Paste" "F.Mask") 273 | (uuid "8b3b44fe-428e-44dc-90ff-5e617cae0cc3") 274 | ) 275 | (pad "12" smd rect 276 | (at 2.7 0.75 90) 277 | (size 0.29 0.7) 278 | (layers "F.Cu" "F.Paste" "F.Mask") 279 | (uuid "4a1ed1e0-d76d-4b7a-9c68-bc3763d1a40d") 280 | ) 281 | (pad "13" smd rect 282 | (at 2.7 -0.75 90) 283 | (size 0.29 0.7) 284 | (layers "F.Cu" "F.Paste" "F.Mask") 285 | (uuid "de9a53a6-3329-4e52-8bf2-33089599c2ae") 286 | ) 287 | (pad "14" smd rect 288 | (at 2.25 -1.7 180) 289 | (size 0.29 0.7) 290 | (layers "F.Cu" "F.Paste" "F.Mask") 291 | (uuid "4dbd7ee0-ed3c-4a12-90cf-ca031b3d3947") 292 | ) 293 | (pad "15" smd rect 294 | (at 1.75 -1.7 180) 295 | (size 0.29 0.7) 296 | (layers "F.Cu" "F.Paste" "F.Mask") 297 | (uuid "e9bcf090-a779-49ba-b509-dfee6c94672a") 298 | ) 299 | (pad "16" smd rect 300 | (at 1.25 -1.7 180) 301 | (size 0.29 0.7) 302 | (layers "F.Cu" "F.Paste" "F.Mask") 303 | (uuid "24503ea9-03e3-46fc-abe4-6bd6bd44236e") 304 | ) 305 | (pad "17" smd rect 306 | (at 0.75 -1.7 180) 307 | (size 0.29 0.7) 308 | (layers "F.Cu" "F.Paste" "F.Mask") 309 | (uuid "b1a37135-fe80-4393-8953-ae88dfa5298e") 310 | ) 311 | (pad "18" smd rect 312 | (at 0.25 -1.7 180) 313 | (size 0.29 0.7) 314 | (layers "F.Cu" "F.Paste" "F.Mask") 315 | (uuid "0d068586-4991-4242-86c2-4138c1bbb965") 316 | ) 317 | (pad "19" smd rect 318 | (at -0.25 -1.7 180) 319 | (size 0.29 0.7) 320 | (layers "F.Cu" "F.Paste" "F.Mask") 321 | (uuid "03b4f59f-11c2-4317-88b2-43b2b585eb76") 322 | ) 323 | (pad "20" smd rect 324 | (at -0.75 -1.7 180) 325 | (size 0.29 0.7) 326 | (layers "F.Cu" "F.Paste" "F.Mask") 327 | (uuid "6e5096f3-3573-4177-ba99-c1ed1915668f") 328 | ) 329 | (pad "21" smd rect 330 | (at -1.25 -1.7 180) 331 | (size 0.29 0.7) 332 | (layers "F.Cu" "F.Paste" "F.Mask") 333 | (uuid "7d937585-e5cf-4ffe-9023-9e28dbdda8de") 334 | ) 335 | (pad "22" smd rect 336 | (at -1.75 -1.7 180) 337 | (size 0.29 0.7) 338 | (layers "F.Cu" "F.Paste" "F.Mask") 339 | (uuid "798f0cec-6674-4af6-8dda-596990bdc208") 340 | ) 341 | (pad "23" smd rect 342 | (at -2.25 -1.7 180) 343 | (size 0.29 0.7) 344 | (layers "F.Cu" "F.Paste" "F.Mask") 345 | (uuid "53933684-3458-47bd-b854-a61d3dee7808") 346 | ) 347 | (pad "24" smd rect 348 | (at -2.7 -0.75 270) 349 | (size 0.29 0.7) 350 | (layers "F.Cu" "F.Paste" "F.Mask") 351 | (uuid "8f734e89-c4ad-481a-b18a-f3fc82990319") 352 | ) 353 | (pad "25" smd rect 354 | (at 0 0) 355 | (size 4.1 2.1) 356 | (layers "F.Cu" "F.Paste" "F.Mask") 357 | (uuid "e419f1a5-7cb2-45de-b281-4230a8a90a41") 358 | ) 359 | (model "3dshapes/DHVQFN24_L5.5-W3.5-H0.9-P0.50-BL-EP.wrl" 360 | (offset 361 | (xyz 0 -0 -0) 362 | ) 363 | (scale 364 | (xyz 1 1 1) 365 | ) 366 | (rotate 367 | (xyz 0 0 0) 368 | ) 369 | ) 370 | ) 371 | -------------------------------------------------------------------------------- /hardware/PicoROM.pretty/RP2040-QFN-56.kicad_mod: -------------------------------------------------------------------------------- 1 | (module Pico2040-QFN-56 (layer F.Cu) (tedit 5EF32B43) 2 | (descr "QFN, 56 Pin (http://www.cypress.com/file/416486/download#page=40), generated with kicad-footprint-generator ipc_dfn_qfn_generator.py") 3 | (tags "QFN DFN_QFN") 4 | (attr smd) 5 | (fp_text reference REF** (at 0 -4.82) (layer F.SilkS) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_text value Pico2040-QFN-56 (at 0 4.82) (layer F.Fab) 9 | (effects (font (size 1 1) (thickness 0.15))) 10 | ) 11 | (fp_line (start 2.96 -3.61) (end 3.61 -3.61) (layer F.SilkS) (width 0.12)) 12 | (fp_line (start 3.61 -3.61) (end 3.61 -2.96) (layer F.SilkS) (width 0.12)) 13 | (fp_line (start -2.96 3.61) (end -3.61 3.61) (layer F.SilkS) (width 0.12)) 14 | (fp_line (start -3.61 3.61) (end -3.61 2.96) (layer F.SilkS) (width 0.12)) 15 | (fp_line (start 2.96 3.61) (end 3.61 3.61) (layer F.SilkS) (width 0.12)) 16 | (fp_line (start 3.61 3.61) (end 3.61 2.96) (layer F.SilkS) (width 0.12)) 17 | (fp_line (start -2.96 -3.61) (end -3.61 -3.61) (layer F.SilkS) (width 0.12)) 18 | (fp_line (start -2.5 -3.5) (end 3.5 -3.5) (layer F.Fab) (width 0.1)) 19 | (fp_line (start 3.5 -3.5) (end 3.5 3.5) (layer F.Fab) (width 0.1)) 20 | (fp_line (start 3.5 3.5) (end -3.5 3.5) (layer F.Fab) (width 0.1)) 21 | (fp_line (start -3.5 3.5) (end -3.5 -2.5) (layer F.Fab) (width 0.1)) 22 | (fp_line (start -3.5 -2.5) (end -2.5 -3.5) (layer F.Fab) (width 0.1)) 23 | (fp_line (start -4.12 -4.12) (end -4.12 4.12) (layer F.CrtYd) (width 0.05)) 24 | (fp_line (start -4.12 4.12) (end 4.12 4.12) (layer F.CrtYd) (width 0.05)) 25 | (fp_line (start 4.12 4.12) (end 4.12 -4.12) (layer F.CrtYd) (width 0.05)) 26 | (fp_line (start 4.12 -4.12) (end -4.12 -4.12) (layer F.CrtYd) (width 0.05)) 27 | (fp_text user %R (at 0 0) (layer F.Fab) 28 | (effects (font (size 1 1) (thickness 0.15))) 29 | ) 30 | (pad 57 smd roundrect (at 0 0) (size 3.2 3.2) (layers F.Cu F.Mask) (roundrect_rratio 0.045)) 31 | (pad 57 thru_hole circle (at -1.275 -1.275) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 32 | (pad 57 thru_hole circle (at 0 -1.275) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 33 | (pad 57 thru_hole circle (at 1.275 -1.275) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 34 | (pad 57 thru_hole circle (at -1.275 0) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 35 | (pad 57 thru_hole circle (at 0 0) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 36 | (pad 57 thru_hole circle (at 1.275 0) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 37 | (pad 57 thru_hole circle (at -1.275 1.275) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 38 | (pad 57 thru_hole circle (at 0 1.275) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 39 | (pad 57 thru_hole circle (at 1.275 1.275) (size 0.6 0.6) (drill 0.35) (layers *.Cu)) 40 | (pad "" smd roundrect (at -0.6375 -0.6375) (size 1.084435 1.084435) (layers F.Paste) (roundrect_rratio 0.230535)) 41 | (pad "" smd roundrect (at -0.6375 0.6375) (size 1.084435 1.084435) (layers F.Paste) (roundrect_rratio 0.230535)) 42 | (pad "" smd roundrect (at 0.6375 -0.6375) (size 1.084435 1.084435) (layers F.Paste) (roundrect_rratio 0.230535)) 43 | (pad "" smd roundrect (at 0.6375 0.6375) (size 1.084435 1.084435) (layers F.Paste) (roundrect_rratio 0.230535)) 44 | (pad 1 smd roundrect (at -3.4375 -2.6) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 45 | (pad 2 smd roundrect (at -3.4375 -2.2) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 46 | (pad 3 smd roundrect (at -3.4375 -1.8) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 47 | (pad 4 smd roundrect (at -3.4375 -1.4) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 48 | (pad 5 smd roundrect (at -3.4375 -1) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 49 | (pad 6 smd roundrect (at -3.4375 -0.6) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 50 | (pad 7 smd roundrect (at -3.4375 -0.2) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 51 | (pad 8 smd roundrect (at -3.4375 0.2) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 52 | (pad 9 smd roundrect (at -3.4375 0.6) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 53 | (pad 10 smd roundrect (at -3.4375 1) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 54 | (pad 11 smd roundrect (at -3.4375 1.4) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 55 | (pad 12 smd roundrect (at -3.4375 1.8) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 56 | (pad 13 smd roundrect (at -3.4375 2.2) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 57 | (pad 14 smd roundrect (at -3.4375 2.6) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 58 | (pad 15 smd roundrect (at -2.6 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 59 | (pad 16 smd roundrect (at -2.2 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 60 | (pad 17 smd roundrect (at -1.8 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 61 | (pad 18 smd roundrect (at -1.4 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 62 | (pad 19 smd roundrect (at -1 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 63 | (pad 20 smd roundrect (at -0.6 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 64 | (pad 21 smd roundrect (at -0.2 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 65 | (pad 22 smd roundrect (at 0.2 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 66 | (pad 23 smd roundrect (at 0.6 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 67 | (pad 24 smd roundrect (at 1 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 68 | (pad 25 smd roundrect (at 1.4 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 69 | (pad 26 smd roundrect (at 1.8 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 70 | (pad 27 smd roundrect (at 2.2 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 71 | (pad 28 smd roundrect (at 2.6 3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 72 | (pad 29 smd roundrect (at 3.4375 2.6) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 73 | (pad 30 smd roundrect (at 3.4375 2.2) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 74 | (pad 31 smd roundrect (at 3.4375 1.8) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 75 | (pad 32 smd roundrect (at 3.4375 1.4) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 76 | (pad 33 smd roundrect (at 3.4375 1) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 77 | (pad 34 smd roundrect (at 3.4375 0.6) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 78 | (pad 35 smd roundrect (at 3.4375 0.2) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 79 | (pad 36 smd roundrect (at 3.4375 -0.2) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 80 | (pad 37 smd roundrect (at 3.4375 -0.6) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 81 | (pad 38 smd roundrect (at 3.4375 -1) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 82 | (pad 39 smd roundrect (at 3.4375 -1.4) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 83 | (pad 40 smd roundrect (at 3.4375 -1.8) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 84 | (pad 41 smd roundrect (at 3.4375 -2.2) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 85 | (pad 42 smd roundrect (at 3.4375 -2.6) (size 0.875 0.2) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 86 | (pad 43 smd roundrect (at 2.6 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 87 | (pad 44 smd roundrect (at 2.2 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 88 | (pad 45 smd roundrect (at 1.8 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 89 | (pad 46 smd roundrect (at 1.4 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 90 | (pad 47 smd roundrect (at 1 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 91 | (pad 48 smd roundrect (at 0.6 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 92 | (pad 49 smd roundrect (at 0.2 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 93 | (pad 50 smd roundrect (at -0.2 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 94 | (pad 51 smd roundrect (at -0.6 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 95 | (pad 52 smd roundrect (at -1 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 96 | (pad 53 smd roundrect (at -1.4 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 97 | (pad 54 smd roundrect (at -1.8 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 98 | (pad 55 smd roundrect (at -2.2 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 99 | (pad 56 smd roundrect (at -2.6 -3.4375) (size 0.2 0.875) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25)) 100 | (model ${KISYS3DMOD}/Package_DFN_QFN.3dshapes/QFN-56-1EP_7x7mm_P0.4mm_EP5.6x5.6mm.wrl 101 | (at (xyz 0 0 0)) 102 | (scale (xyz 1 1 1)) 103 | (rotate (xyz 0 0 0)) 104 | ) 105 | ) 106 | -------------------------------------------------------------------------------- /hardware/PicoROM.pretty/USB-C-SMD_GT-USB-7051A.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "USB-C-SMD_GT-USB-7051A" 2 | (version 20240108) 3 | (generator "pcbnew") 4 | (generator_version "8.0") 5 | (layer "F.Cu") 6 | (property "Reference" "REF**" 7 | (at 0 -6.15 0) 8 | (layer "F.SilkS") 9 | (uuid "7e1761df-9aee-4dff-8cfc-881cd0bc7d14") 10 | (effects 11 | (font 12 | (size 1 1) 13 | (thickness 0.15) 14 | ) 15 | ) 16 | ) 17 | (property "Value" "USB-C-SMD_GT-USB-7051A" 18 | (at 0 6.15 0) 19 | (layer "F.Fab") 20 | (uuid "3759abba-f740-4587-bfef-25e7d753bfaa") 21 | (effects 22 | (font 23 | (size 1 1) 24 | (thickness 0.15) 25 | ) 26 | ) 27 | ) 28 | (property "Footprint" "" 29 | (at 0 0 0) 30 | (layer "F.Fab") 31 | (hide yes) 32 | (uuid "b04c7f75-5112-4885-bc24-0c471b063da2") 33 | (effects 34 | (font 35 | (size 1.27 1.27) 36 | (thickness 0.15) 37 | ) 38 | ) 39 | ) 40 | (property "Datasheet" "" 41 | (at 0 0 0) 42 | (layer "F.Fab") 43 | (hide yes) 44 | (uuid "b3f1f122-4cdf-48d7-8d00-bb2c7ed69079") 45 | (effects 46 | (font 47 | (size 1.27 1.27) 48 | (thickness 0.15) 49 | ) 50 | ) 51 | ) 52 | (property "Description" "" 53 | (at 0 0 0) 54 | (layer "F.Fab") 55 | (hide yes) 56 | (uuid "a6645baa-ea3c-40c7-a514-f6b2a507cfd5") 57 | (effects 58 | (font 59 | (size 1.27 1.27) 60 | (thickness 0.15) 61 | ) 62 | ) 63 | ) 64 | (attr smd) 65 | (fp_circle 66 | (center -2.4 -2.15) 67 | (end -2.1 -2.15) 68 | (stroke 69 | (width 0.6) 70 | (type solid) 71 | ) 72 | (fill none) 73 | (layer "F.Paste") 74 | (uuid "3f67c502-6e33-42da-abcb-10e97600ad1f") 75 | ) 76 | (fp_circle 77 | (center -2.4 2.15) 78 | (end -2.1 2.15) 79 | (stroke 80 | (width 0.6) 81 | (type solid) 82 | ) 83 | (fill none) 84 | (layer "F.Paste") 85 | (uuid "2a4fee13-d3fa-4870-ac7b-5cebc0887aa0") 86 | ) 87 | (fp_circle 88 | (center 2.4 -2.15) 89 | (end 2.7 -2.15) 90 | (stroke 91 | (width 0.6) 92 | (type solid) 93 | ) 94 | (fill none) 95 | (layer "F.Paste") 96 | (uuid "d29dd157-fa58-4db9-943d-50dd2bd258b1") 97 | ) 98 | (fp_circle 99 | (center 2.4 2.15) 100 | (end 2.7 2.15) 101 | (stroke 102 | (width 0.6) 103 | (type solid) 104 | ) 105 | (fill none) 106 | (layer "F.Paste") 107 | (uuid "17bc3fd2-f097-40d7-8a0a-9af7c8cb930c") 108 | ) 109 | (fp_line 110 | (start -4.58 -2.29) 111 | (end -4.58 2.41) 112 | (stroke 113 | (width 0.25) 114 | (type solid) 115 | ) 116 | (layer "F.SilkS") 117 | (uuid "27653705-97ac-4318-a89c-01d34402df61") 118 | ) 119 | (fp_line 120 | (start -4.58 2.41) 121 | (end -3.19 2.41) 122 | (stroke 123 | (width 0.25) 124 | (type solid) 125 | ) 126 | (layer "F.SilkS") 127 | (uuid "d2ffa34c-5ab9-4f17-a9d6-1210608537f4") 128 | ) 129 | (fp_line 130 | (start -3.22 -2.29) 131 | (end -4.58 -2.29) 132 | (stroke 133 | (width 0.25) 134 | (type solid) 135 | ) 136 | (layer "F.SilkS") 137 | (uuid "a93dd2e4-2fc6-4610-9b1b-5070592e2088") 138 | ) 139 | (fp_line 140 | (start -1.62 2.41) 141 | (end 1.61 2.41) 142 | (stroke 143 | (width 0.25) 144 | (type solid) 145 | ) 146 | (layer "F.SilkS") 147 | (uuid "6b5ac7c3-ba70-4cc9-869b-c621d292dcfd") 148 | ) 149 | (fp_line 150 | (start 1.58 -2.29) 151 | (end -1.59 -2.29) 152 | (stroke 153 | (width 0.25) 154 | (type solid) 155 | ) 156 | (layer "F.SilkS") 157 | (uuid "52d62a22-2dba-4023-b639-96551afe36ab") 158 | ) 159 | (fp_line 160 | (start 3.18 2.41) 161 | (end 4.57 2.41) 162 | (stroke 163 | (width 0.25) 164 | (type solid) 165 | ) 166 | (layer "F.SilkS") 167 | (uuid "162aa380-bb45-4e90-a74e-ee0ab23d6aa1") 168 | ) 169 | (fp_line 170 | (start 4.57 -2.29) 171 | (end 3.21 -2.29) 172 | (stroke 173 | (width 0.25) 174 | (type solid) 175 | ) 176 | (layer "F.SilkS") 177 | (uuid "1807b676-b38a-4f1e-8eb6-ef5c3ed57d15") 178 | ) 179 | (fp_line 180 | (start 4.57 2.41) 181 | (end 4.57 -2.29) 182 | (stroke 183 | (width 0.25) 184 | (type solid) 185 | ) 186 | (layer "F.SilkS") 187 | (uuid "53cae861-7257-411b-a8d8-1a154418dad4") 188 | ) 189 | (fp_circle 190 | (center -3.75 0) 191 | (end -3.61 0) 192 | (stroke 193 | (width 0.28) 194 | (type solid) 195 | ) 196 | (fill none) 197 | (layer "Cmts.User") 198 | (uuid "4a2b677b-c216-4cd1-a749-da04e36ab6d5") 199 | ) 200 | (fp_circle 201 | (center 3.75 0) 202 | (end 3.89 0) 203 | (stroke 204 | (width 0.28) 205 | (type solid) 206 | ) 207 | (fill none) 208 | (layer "Cmts.User") 209 | (uuid "88f05ef3-2007-4813-a974-f65750ed21c5") 210 | ) 211 | (fp_circle 212 | (center -4.45 -2.3) 213 | (end -4.42 -2.3) 214 | (stroke 215 | (width 0.06) 216 | (type solid) 217 | ) 218 | (fill none) 219 | (layer "F.Fab") 220 | (uuid "48f44138-bd12-41b4-b0a0-990cbd40359d") 221 | ) 222 | (fp_text user "${REFERENCE}" 223 | (at 0 0 0) 224 | (layer "F.Fab") 225 | (uuid "ad272e1d-5d0e-4830-b56d-b556e1afa634") 226 | (effects 227 | (font 228 | (size 1 1) 229 | (thickness 0.15) 230 | ) 231 | ) 232 | ) 233 | (pad "" thru_hole circle 234 | (at -3.75 0) 235 | (size 0.7 0.7) 236 | (drill 0.7) 237 | (layers "*.Cu" "*.Mask") 238 | (remove_unused_layers no) 239 | (uuid "117dacf0-ef89-4090-945e-c816866063b4") 240 | ) 241 | (pad "0" thru_hole circle 242 | (at -2.4 -2.15) 243 | (size 1.2 1.2) 244 | (drill 0.799998) 245 | (layers "*.Cu" "*.Mask") 246 | (remove_unused_layers no) 247 | (uuid "76b1f8fd-0288-4677-91fb-b63e445f0a87") 248 | ) 249 | (pad "0" thru_hole circle 250 | (at -2.4 2.15) 251 | (size 1.2 1.2) 252 | (drill 0.799998) 253 | (layers "*.Cu" "*.Mask") 254 | (remove_unused_layers no) 255 | (uuid "48af4644-0f26-4a2c-831e-15d8af657f42") 256 | ) 257 | (pad "0" thru_hole circle 258 | (at 2.4 -2.15) 259 | (size 1.2 1.2) 260 | (drill 0.799998) 261 | (layers "*.Cu" "*.Mask") 262 | (remove_unused_layers no) 263 | (uuid "eaae53e5-abcb-4ad2-b843-89fea49a1bfa") 264 | ) 265 | (pad "0" thru_hole circle 266 | (at 2.4 2.15 90) 267 | (size 1.2 1.2) 268 | (drill 0.799998) 269 | (layers "*.Cu" "*.Mask") 270 | (remove_unused_layers no) 271 | (uuid "d5903a25-71cb-420b-aea5-cf22f06303d0") 272 | ) 273 | (pad "A1" smd rect 274 | (at -2.77 -0.76) 275 | (size 0.3 1) 276 | (layers "F.Cu" "F.Paste" "F.Mask") 277 | (uuid "54e75c9e-f01f-46bc-9525-4880cc2f5421") 278 | ) 279 | (pad "A4" smd rect 280 | (at -1.98 -0.76) 281 | (size 0.3 1) 282 | (layers "F.Cu" "F.Paste" "F.Mask") 283 | (uuid "6b601fdf-7061-42b4-be66-80c0d05d9a73") 284 | ) 285 | (pad "A5" smd rect 286 | (at -1.18 -0.76) 287 | (size 0.3 1) 288 | (layers "F.Cu" "F.Paste" "F.Mask") 289 | (uuid "97a3144e-eaad-4497-ba14-c0b0a5446b92") 290 | ) 291 | (pad "A6" smd rect 292 | (at -0.39 -0.76) 293 | (size 0.3 1) 294 | (layers "F.Cu" "F.Paste" "F.Mask") 295 | (uuid "579a449d-f909-4314-9d2c-24bb5ff4a330") 296 | ) 297 | (pad "A7" smd rect 298 | (at 0.39 -0.76) 299 | (size 0.3 1) 300 | (layers "F.Cu" "F.Paste" "F.Mask") 301 | (uuid "6793acdb-0d96-4e83-8971-db3bf01c677c") 302 | ) 303 | (pad "A8" smd rect 304 | (at 1.18 -0.76) 305 | (size 0.3 1) 306 | (layers "F.Cu" "F.Paste" "F.Mask") 307 | (uuid "aba4b8db-60c4-4279-b954-e355f5afd271") 308 | ) 309 | (pad "A9" smd rect 310 | (at 1.97 -0.76) 311 | (size 0.3 1) 312 | (layers "F.Cu" "F.Paste" "F.Mask") 313 | (uuid "0e80baca-588d-41ad-b9bf-4c891dd8c68a") 314 | ) 315 | (pad "A12" smd rect 316 | (at 2.77 -0.76) 317 | (size 0.3 1) 318 | (layers "F.Cu" "F.Paste" "F.Mask") 319 | (uuid "78ddbec1-f2a5-44d2-a8f0-8d32072b0603") 320 | ) 321 | (pad "B1" smd rect 322 | (at 2.77 0.76) 323 | (size 0.3 1) 324 | (layers "F.Cu" "F.Paste" "F.Mask") 325 | (uuid "1d4921d1-3d83-44d9-9021-1f43ece0aae1") 326 | ) 327 | (pad "B4" smd rect 328 | (at 1.97 0.76) 329 | (size 0.3 1) 330 | (layers "F.Cu" "F.Paste" "F.Mask") 331 | (uuid "92b377b1-20d6-4c8c-86f8-b4f3b568f8b3") 332 | ) 333 | (pad "B5" smd rect 334 | (at 1.18 0.76) 335 | (size 0.3 1) 336 | (layers "F.Cu" "F.Paste" "F.Mask") 337 | (uuid "b6c05bbe-c3dd-4dca-b4a7-a3723b85b20f") 338 | ) 339 | (pad "B6" smd rect 340 | (at 0.39 0.76) 341 | (size 0.3 1) 342 | (layers "F.Cu" "F.Paste" "F.Mask") 343 | (uuid "49a1c649-dcf2-4877-a4a7-d35a56e9c8a1") 344 | ) 345 | (pad "B7" smd rect 346 | (at -0.39 0.76) 347 | (size 0.3 1) 348 | (layers "F.Cu" "F.Paste" "F.Mask") 349 | (uuid "c126a85d-e2aa-44af-9395-a22ccef6ba62") 350 | ) 351 | (pad "B8" smd rect 352 | (at -1.18 0.76) 353 | (size 0.3 1) 354 | (layers "F.Cu" "F.Paste" "F.Mask") 355 | (uuid "0464c691-ef87-47eb-9d8f-5b5030395d9b") 356 | ) 357 | (pad "B9" smd rect 358 | (at -1.98 0.76) 359 | (size 0.3 1) 360 | (layers "F.Cu" "F.Paste" "F.Mask") 361 | (uuid "17d66a99-2526-4ec3-a3be-40d85f6a72b7") 362 | ) 363 | (pad "B12" smd rect 364 | (at -2.77 0.76) 365 | (size 0.3 1) 366 | (layers "F.Cu" "F.Paste" "F.Mask") 367 | (uuid "9991ece2-4a92-4f0e-a2c1-7b353be61ff4") 368 | ) 369 | (model "/tmp2.3dshapes/USB-C-SMD_GT-USB-7051A.wrl" 370 | (offset 371 | (xyz -0 0 1.2) 372 | ) 373 | (scale 374 | (xyz 1 1 1) 375 | ) 376 | (rotate 377 | (xyz 0 0 0) 378 | ) 379 | ) 380 | ) 381 | -------------------------------------------------------------------------------- /hardware/PicoROM.pretty/USB_Micro-B_Amphenol_10103594-0001LF_Horizontal_modified.kicad_mod: -------------------------------------------------------------------------------- 1 | (module USB_Micro-B_Amphenol_10103594-0001LF_Horizontal_modified (layer F.Cu) (tedit 5F0317C2) 2 | (descr "Micro USB Type B 10103594-0001LF, http://cdn.amphenol-icc.com/media/wysiwyg/files/drawing/10103594.pdf") 3 | (tags "USB USB_B USB_micro USB_OTG") 4 | (attr smd) 5 | (fp_text reference J5 (at -5.365 -2.58 -180) (layer F.SilkS) 6 | (effects (font (size 1 1) (thickness 0.15))) 7 | ) 8 | (fp_text value USB_B_Micro (at -0.025 3.32 -180) (layer F.Fab) 9 | (effects (font (size 1 1) (thickness 0.15))) 10 | ) 11 | (fp_line (start 4.14 1.7) (end -4.13 1.7) (layer F.CrtYd) (width 0.05)) 12 | (fp_line (start 4.14 1.7) (end 4.14 -3.995) (layer F.CrtYd) (width 0.05)) 13 | (fp_line (start -4.13 -3.995) (end -4.13 1.7) (layer F.CrtYd) (width 0.05)) 14 | (fp_line (start -4.13 -3.995) (end 4.14 -3.995) (layer F.CrtYd) (width 0.05)) 15 | (fp_line (start -4.02 1.7) (end 4.02 1.7) (layer Dwgs.User) (width 0.1)) 16 | (fp_line (start -3.775 2.22) (end -3.775 -1.98) (layer F.Fab) (width 0.12)) 17 | (fp_line (start -2.975 -2.73) (end 3.725 -2.73) (layer F.Fab) (width 0.12)) 18 | (fp_line (start 3.725 -2.73) (end 3.725 2.22) (layer F.Fab) (width 0.12)) 19 | (fp_line (start 3.725 2.22) (end -3.775 2.22) (layer F.Fab) (width 0.12)) 20 | (fp_line (start -3.775 -1.98) (end -2.975 -2.73) (layer F.Fab) (width 0.12)) 21 | (fp_line (start -1.325 -3.98) (end -1.725 -4.43) (layer F.SilkS) (width 0.12)) 22 | (fp_line (start -1.725 -4.43) (end -0.925 -4.43) (layer F.SilkS) (width 0.12)) 23 | (fp_line (start -0.925 -4.43) (end -1.325 -3.98) (layer F.SilkS) (width 0.12)) 24 | (fp_line (start 3.825 1.62) (end 3.825 -1.18) (layer F.SilkS) (width 0.12)) 25 | (fp_line (start 3.825 -1.18) (end 4.125 -1.18) (layer F.SilkS) (width 0.12)) 26 | (fp_line (start 4.125 -1.18) (end 4.125 -2.73) (layer F.SilkS) (width 0.12)) 27 | (fp_line (start -3.875 1.62) (end -3.875 -1.18) (layer F.SilkS) (width 0.12)) 28 | (fp_line (start -4.175 -1.18) (end -3.875 -1.18) (layer F.SilkS) (width 0.12)) 29 | (fp_line (start -4.175 -1.18) (end -4.175 -2.73) (layer F.SilkS) (width 0.12)) 30 | (fp_text user %R (at -0.025 -1.13 -180) (layer F.Fab) 31 | (effects (font (size 1 1) (thickness 0.15))) 32 | ) 33 | (fp_text user "PCB edge" (at -0.025 1.12 -180) (layer Dwgs.User) 34 | (effects (font (size 0.5 0.5) (thickness 0.075))) 35 | ) 36 | (pad 6 smd rect (at 0.9625 0.25 90) (size 2.5 1.425) (layers F.Cu F.Paste F.Mask)) 37 | (pad 6 smd rect (at -0.9625 0.25 90) (size 2.5 1.425) (layers F.Cu F.Paste F.Mask)) 38 | (pad 6 thru_hole oval (at 2.725 0 90) (size 1.8 1.3) (drill oval 1.2 0.7) (layers *.Cu *.Mask)) 39 | (pad 6 thru_hole oval (at -2.725 0 90) (size 1.8 1.3) (drill oval 1.2 0.7) (layers *.Cu *.Mask)) 40 | (pad 6 thru_hole oval (at -2.425 -3.03 90) (size 1.45 1.05) (drill oval 1.05 0.65) (layers *.Cu *.Mask)) 41 | (pad 5 smd rect (at 1.3 -2.825 90) (size 1.75 0.4) (layers F.Cu F.Paste F.Mask)) 42 | (pad 4 smd rect (at 0.65 -2.825 90) (size 1.75 0.4) (layers F.Cu F.Paste F.Mask)) 43 | (pad 3 smd rect (at 0 -2.825 90) (size 1.75 0.4) (layers F.Cu F.Paste F.Mask)) 44 | (pad 2 smd rect (at -0.65 -2.825 90) (size 1.75 0.4) (layers F.Cu F.Paste F.Mask)) 45 | (pad 1 smd rect (at -1.3 -2.825 90) (size 1.75 0.4) (layers F.Cu F.Paste F.Mask)) 46 | (pad 6 smd rect (at 2.9 -3.03) (size 2 1.46) (layers F.Cu F.Paste F.Mask)) 47 | (pad 6 smd rect (at -2.9 -3.03) (size 2 1.46) (layers F.Cu F.Paste F.Mask)) 48 | (pad 6 smd rect (at -2.9875 -1.7) (size 1.825 0.7) (layers F.Cu F.Paste F.Mask)) 49 | (pad 6 smd roundrect (at -2.725 -0.425) (size 1.3 3.25) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.296)) 50 | (pad 6 smd roundrect (at 2.725 -0.425) (size 1.3 3.25) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.296)) 51 | (pad 6 smd rect (at 2.9875 -1.7) (size 1.825 0.7) (layers F.Cu F.Paste F.Mask)) 52 | (pad 6 thru_hole oval (at 2.425 -3.03 90) (size 1.45 1.05) (drill oval 1.05 0.65) (layers *.Cu *.Mask)) 53 | (model 10103594.stp 54 | (offset (xyz 0 0.2 2.2)) 55 | (scale (xyz 1 1 1)) 56 | (rotate (xyz 90 0 180)) 57 | ) 58 | ) 59 | -------------------------------------------------------------------------------- /hardware/PicoROM.pretty/V-QFN4525-20_L4.5-W2.5-P0.50-BL.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "V-QFN4525-20_L4.5-W2.5-P0.50-BL" 2 | (version 20240108) 3 | (generator "pcbnew") 4 | (generator_version "8.0") 5 | (layer "F.Cu") 6 | (property "Reference" "REF**" 7 | (at 0 -5.2 0) 8 | (layer "F.SilkS") 9 | (uuid "8c9d5be2-a8b3-4198-9e15-fa27d2b89638") 10 | (effects 11 | (font 12 | (size 1 1) 13 | (thickness 0.15) 14 | ) 15 | ) 16 | ) 17 | (property "Value" "V-QFN4525-20_L4.5-W2.5-P0.50-BL" 18 | (at 0 5.2 0) 19 | (layer "F.Fab") 20 | (uuid "1a5105e4-b0c8-413d-a0cb-0327e75361c1") 21 | (effects 22 | (font 23 | (size 1 1) 24 | (thickness 0.15) 25 | ) 26 | ) 27 | ) 28 | (property "Footprint" "" 29 | (at 0 0 0) 30 | (layer "F.Fab") 31 | (hide yes) 32 | (uuid "848af20e-ee42-4b41-af44-c824cc9ff2ff") 33 | (effects 34 | (font 35 | (size 1.27 1.27) 36 | (thickness 0.15) 37 | ) 38 | ) 39 | ) 40 | (property "Datasheet" "" 41 | (at 0 0 0) 42 | (layer "F.Fab") 43 | (hide yes) 44 | (uuid "8c81b1df-ee75-4634-89dc-13a1883e9ed8") 45 | (effects 46 | (font 47 | (size 1.27 1.27) 48 | (thickness 0.15) 49 | ) 50 | ) 51 | ) 52 | (property "Description" "" 53 | (at 0 0 0) 54 | (layer "F.Fab") 55 | (hide yes) 56 | (uuid "2151f4df-8232-48bd-8472-6497221e773b") 57 | (effects 58 | (font 59 | (size 1.27 1.27) 60 | (thickness 0.15) 61 | ) 62 | ) 63 | ) 64 | (attr smd) 65 | (fp_line 66 | (start -2.25 -1.25) 67 | (end -2.25 -0.61) 68 | (stroke 69 | (width 0.25) 70 | (type solid) 71 | ) 72 | (layer "F.SilkS") 73 | (uuid "f528835a-552b-4895-bde9-bb9c71139b9b") 74 | ) 75 | (fp_line 76 | (start -2.25 -1.25) 77 | (end -2.11 -1.25) 78 | (stroke 79 | (width 0.25) 80 | (type solid) 81 | ) 82 | (layer "F.SilkS") 83 | (uuid "7e4dc598-1a8a-4873-87ef-780ba55bcfca") 84 | ) 85 | (fp_line 86 | (start -2.25 0.61) 87 | (end -2.25 1.25) 88 | (stroke 89 | (width 0.25) 90 | (type solid) 91 | ) 92 | (layer "F.SilkS") 93 | (uuid "e8be2e19-0c99-4e49-9276-e1a530874727") 94 | ) 95 | (fp_line 96 | (start -2.25 1.25) 97 | (end -2.11 1.25) 98 | (stroke 99 | (width 0.25) 100 | (type solid) 101 | ) 102 | (layer "F.SilkS") 103 | (uuid "4278c0c2-152c-40a8-9133-6c65a120e31c") 104 | ) 105 | (fp_line 106 | (start 2.11 -1.25) 107 | (end 2.25 -1.25) 108 | (stroke 109 | (width 0.25) 110 | (type solid) 111 | ) 112 | (layer "F.SilkS") 113 | (uuid "1732ccb5-b706-4d5e-a77b-3aea50c49646") 114 | ) 115 | (fp_line 116 | (start 2.11 1.25) 117 | (end 2.25 1.25) 118 | (stroke 119 | (width 0.25) 120 | (type solid) 121 | ) 122 | (layer "F.SilkS") 123 | (uuid "49ba61d3-361f-4fca-91ae-89332a5bccfc") 124 | ) 125 | (fp_line 126 | (start 2.25 -1.25) 127 | (end 2.25 -0.62) 128 | (stroke 129 | (width 0.25) 130 | (type solid) 131 | ) 132 | (layer "F.SilkS") 133 | (uuid "f66bae93-6f72-461d-a7cf-653b777c6cc3") 134 | ) 135 | (fp_line 136 | (start 2.25 0.62) 137 | (end 2.25 1.25) 138 | (stroke 139 | (width 0.25) 140 | (type solid) 141 | ) 142 | (layer "F.SilkS") 143 | (uuid "edf7a5df-4fd0-4593-badd-72305c36f8ff") 144 | ) 145 | (fp_circle 146 | (center -2.67 0.76) 147 | (end -2.54 0.76) 148 | (stroke 149 | (width 0.25) 150 | (type solid) 151 | ) 152 | (fill none) 153 | (layer "F.SilkS") 154 | (uuid "78dc42f9-4390-4e79-a18c-1b6b19520833") 155 | ) 156 | (fp_circle 157 | (center -2.25 0.25) 158 | (end -2.12 0.25) 159 | (stroke 160 | (width 0.25) 161 | (type solid) 162 | ) 163 | (fill none) 164 | (layer "Cmts.User") 165 | (uuid "6b5a22ca-e933-4ac9-b715-7073d66ded61") 166 | ) 167 | (fp_circle 168 | (center -2.25 1.25) 169 | (end -2.22 1.25) 170 | (stroke 171 | (width 0.06) 172 | (type solid) 173 | ) 174 | (fill none) 175 | (layer "F.Fab") 176 | (uuid "1925ac3a-523e-427d-9479-8e51f7b8b7b1") 177 | ) 178 | (fp_text user "${REFERENCE}" 179 | (at 0 0 0) 180 | (layer "F.Fab") 181 | (uuid "10e203e8-1a3b-45e6-9248-bf2f59fa31a8") 182 | (effects 183 | (font 184 | (size 1 1) 185 | (thickness 0.15) 186 | ) 187 | ) 188 | ) 189 | (pad "1" smd rect 190 | (at -2.25 0.25 180) 191 | (size 0.7 0.25) 192 | (layers "F.Cu" "F.Paste" "F.Mask") 193 | (uuid "553dbdde-530d-48a3-b296-4d450afed6c1") 194 | ) 195 | (pad "2" smd rect 196 | (at -1.75 1.2 90) 197 | (size 0.7 0.25) 198 | (layers "F.Cu" "F.Paste" "F.Mask") 199 | (uuid "627e2c61-8842-4e5b-a235-4e3060e03d3f") 200 | ) 201 | (pad "3" smd rect 202 | (at -1.25 1.2 90) 203 | (size 0.7 0.25) 204 | (layers "F.Cu" "F.Paste" "F.Mask") 205 | (uuid "5f74f7fa-aeb2-4fd1-b630-68758e5beaeb") 206 | ) 207 | (pad "4" smd rect 208 | (at -0.75 1.2 90) 209 | (size 0.7 0.25) 210 | (layers "F.Cu" "F.Paste" "F.Mask") 211 | (uuid "27a78362-ba00-407e-b3b6-d892c188ec80") 212 | ) 213 | (pad "5" smd rect 214 | (at -0.25 1.2 90) 215 | (size 0.7 0.25) 216 | (layers "F.Cu" "F.Paste" "F.Mask") 217 | (uuid "14da0bbb-9cb4-4f42-ac9d-1288e948ad14") 218 | ) 219 | (pad "6" smd rect 220 | (at 0.25 1.2 90) 221 | (size 0.7 0.25) 222 | (layers "F.Cu" "F.Paste" "F.Mask") 223 | (uuid "88a7616d-9238-4256-a3ee-6d5bf1ef30a1") 224 | ) 225 | (pad "7" smd rect 226 | (at 0.75 1.2 90) 227 | (size 0.7 0.25) 228 | (layers "F.Cu" "F.Paste" "F.Mask") 229 | (uuid "79cbcb1c-35f9-459e-9adb-7e357a69d04b") 230 | ) 231 | (pad "8" smd rect 232 | (at 1.25 1.2 90) 233 | (size 0.7 0.25) 234 | (layers "F.Cu" "F.Paste" "F.Mask") 235 | (uuid "e90a34e5-a7e6-40ca-b129-4c3a96831bee") 236 | ) 237 | (pad "9" smd rect 238 | (at 1.75 1.2 90) 239 | (size 0.7 0.25) 240 | (layers "F.Cu" "F.Paste" "F.Mask") 241 | (uuid "a458276d-17a9-4f4f-9c29-0e6a6bbbb76f") 242 | ) 243 | (pad "10" smd rect 244 | (at 2.25 0.25 180) 245 | (size 0.7 0.28) 246 | (layers "F.Cu" "F.Paste" "F.Mask") 247 | (uuid "c411cd9d-9c83-4153-8be1-730a245eb1e2") 248 | ) 249 | (pad "11" smd rect 250 | (at 2.25 -0.25 180) 251 | (size 0.7 0.28) 252 | (layers "F.Cu" "F.Paste" "F.Mask") 253 | (uuid "f36cb2e6-c9cd-4563-b936-42e4a16b84e0") 254 | ) 255 | (pad "12" smd rect 256 | (at 1.75 -1.2 90) 257 | (size 0.7 0.25) 258 | (layers "F.Cu" "F.Paste" "F.Mask") 259 | (uuid "2a4e353c-88df-4d5c-95ff-36eb6fa32048") 260 | ) 261 | (pad "13" smd rect 262 | (at 1.25 -1.2 90) 263 | (size 0.7 0.25) 264 | (layers "F.Cu" "F.Paste" "F.Mask") 265 | (uuid "621250de-47e0-4f9f-99fa-b46d1b4bdd42") 266 | ) 267 | (pad "14" smd rect 268 | (at 0.75 -1.2 90) 269 | (size 0.7 0.25) 270 | (layers "F.Cu" "F.Paste" "F.Mask") 271 | (uuid "2e9d12b3-9fb0-4d1d-9fcd-c8b7bb5ed580") 272 | ) 273 | (pad "15" smd rect 274 | (at 0.25 -1.2 90) 275 | (size 0.7 0.25) 276 | (layers "F.Cu" "F.Paste" "F.Mask") 277 | (uuid "c1b13f2d-9f8c-478c-9eb3-cef0b83c0f9d") 278 | ) 279 | (pad "16" smd rect 280 | (at -0.25 -1.2 90) 281 | (size 0.7 0.25) 282 | (layers "F.Cu" "F.Paste" "F.Mask") 283 | (uuid "d02f47dd-281b-489f-bbaf-3616c1ea7ef5") 284 | ) 285 | (pad "17" smd rect 286 | (at -0.75 -1.2 90) 287 | (size 0.7 0.25) 288 | (layers "F.Cu" "F.Paste" "F.Mask") 289 | (uuid "6b9e0843-4600-466d-b9b2-714e6861ab13") 290 | ) 291 | (pad "18" smd rect 292 | (at -1.25 -1.2 90) 293 | (size 0.7 0.25) 294 | (layers "F.Cu" "F.Paste" "F.Mask") 295 | (uuid "19d1f404-b37b-4e69-8a9b-d9f240c38a57") 296 | ) 297 | (pad "19" smd rect 298 | (at -1.75 -1.2 90) 299 | (size 0.7 0.25) 300 | (layers "F.Cu" "F.Paste" "F.Mask") 301 | (uuid "1db5e90a-d48b-42a4-8c03-0145c921da1d") 302 | ) 303 | (pad "20" smd rect 304 | (at -2.25 -0.25 180) 305 | (size 0.7 0.25) 306 | (layers "F.Cu" "F.Paste" "F.Mask") 307 | (uuid "8c1a971c-f0a0-4d83-89de-977c19be6b5b") 308 | ) 309 | (pad "21" smd rect 310 | (at 0 0 180) 311 | (size 3 1) 312 | (layers "F.Cu" "F.Paste" "F.Mask") 313 | (uuid "814ad4ed-5322-4dd0-a4e1-c1bd6defecdf") 314 | ) 315 | (model "3dshapes/V-QFN4525-20_L4.5-W2.5-P0.50-BL.wrl" 316 | (offset 317 | (xyz 0 -0 -0) 318 | ) 319 | (scale 320 | (xyz 1 1 1) 321 | ) 322 | (rotate 323 | (xyz 0 0 0) 324 | ) 325 | ) 326 | ) 327 | -------------------------------------------------------------------------------- /hardware/PicoROM.pretty/X2QFN-8_L1.5-W1.5-P0.50-BL.kicad_mod: -------------------------------------------------------------------------------- 1 | (footprint "X2QFN-8_L1.5-W1.5-P0.50-BL" 2 | (version 20240108) 3 | (generator "pcbnew") 4 | (generator_version "8.0") 5 | (layer "F.Cu") 6 | (property "Reference" "REF**" 7 | (at 0 -4.66 0) 8 | (layer "F.SilkS") 9 | (uuid "d3a8190a-537e-483f-86ed-d3c17c21a6db") 10 | (effects 11 | (font 12 | (size 1 1) 13 | (thickness 0.15) 14 | ) 15 | ) 16 | ) 17 | (property "Value" "X2QFN-8_L1.5-W1.5-P0.50-BL" 18 | (at 0 4.66 0) 19 | (layer "F.Fab") 20 | (uuid "9d0d637f-56c3-46f9-99c4-ecdefdeb22c7") 21 | (effects 22 | (font 23 | (size 1 1) 24 | (thickness 0.15) 25 | ) 26 | ) 27 | ) 28 | (property "Footprint" "" 29 | (at 0 0 0) 30 | (layer "F.Fab") 31 | (hide yes) 32 | (uuid "27f70f75-8079-45a3-9540-fc5e41026118") 33 | (effects 34 | (font 35 | (size 1.27 1.27) 36 | (thickness 0.15) 37 | ) 38 | ) 39 | ) 40 | (property "Datasheet" "" 41 | (at 0 0 0) 42 | (layer "F.Fab") 43 | (hide yes) 44 | (uuid "f2e31cff-2ac4-4a85-937f-cce117fceb00") 45 | (effects 46 | (font 47 | (size 1.27 1.27) 48 | (thickness 0.15) 49 | ) 50 | ) 51 | ) 52 | (property "Description" "" 53 | (at 0 0 0) 54 | (layer "F.Fab") 55 | (hide yes) 56 | (uuid "aee2511e-e682-471f-804b-8cf3367e6616") 57 | (effects 58 | (font 59 | (size 1.27 1.27) 60 | (thickness 0.15) 61 | ) 62 | ) 63 | ) 64 | (attr smd) 65 | (fp_line 66 | (start -0.88 -0.78) 67 | (end -0.88 -0.39) 68 | (stroke 69 | (width 0.25) 70 | (type solid) 71 | ) 72 | (layer "F.SilkS") 73 | (uuid "96888ac2-c7e1-4a6a-8140-48cf5fefc144") 74 | ) 75 | (fp_line 76 | (start -0.88 0.37) 77 | (end -0.88 0.75) 78 | (stroke 79 | (width 0.25) 80 | (type solid) 81 | ) 82 | (layer "F.SilkS") 83 | (uuid "9dcf67b9-07c1-4acf-924e-b8b87465557f") 84 | ) 85 | (fp_line 86 | (start -0.88 0.75) 87 | (end -0.85 0.75) 88 | (stroke 89 | (width 0.25) 90 | (type solid) 91 | ) 92 | (layer "F.SilkS") 93 | (uuid "041bfb70-2198-48b2-9ac6-f22b9000032b") 94 | ) 95 | (fp_line 96 | (start -0.85 -0.78) 97 | (end -0.88 -0.78) 98 | (stroke 99 | (width 0.25) 100 | (type solid) 101 | ) 102 | (layer "F.SilkS") 103 | (uuid "2345c686-64d2-4d64-b483-8e46802ea6dc") 104 | ) 105 | (fp_line 106 | (start 0.86 0.75) 107 | (end 0.9 0.75) 108 | (stroke 109 | (width 0.25) 110 | (type solid) 111 | ) 112 | (layer "F.SilkS") 113 | (uuid "b47b5c77-b303-4357-8ecc-c8e9e128403e") 114 | ) 115 | (fp_line 116 | (start 0.9 -0.78) 117 | (end 0.86 -0.78) 118 | (stroke 119 | (width 0.25) 120 | (type solid) 121 | ) 122 | (layer "F.SilkS") 123 | (uuid "c45fb898-0368-4602-a3e6-352116d10095") 124 | ) 125 | (fp_line 126 | (start 0.9 -0.39) 127 | (end 0.9 -0.78) 128 | (stroke 129 | (width 0.25) 130 | (type solid) 131 | ) 132 | (layer "F.SilkS") 133 | (uuid "8e0bf39b-c025-4833-bacb-7e61c9b9fd17") 134 | ) 135 | (fp_line 136 | (start 0.9 0.75) 137 | (end 0.9 0.37) 138 | (stroke 139 | (width 0.25) 140 | (type solid) 141 | ) 142 | (layer "F.SilkS") 143 | (uuid "ef9c1e75-b5aa-4829-8c1d-3ce4fbfc54e4") 144 | ) 145 | (fp_circle 146 | (center -1.13 1.13) 147 | (end -1 1.13) 148 | (stroke 149 | (width 0.25) 150 | (type solid) 151 | ) 152 | (fill none) 153 | (layer "F.SilkS") 154 | (uuid "43d3360a-1dfb-4e31-a01d-30ad884d39fd") 155 | ) 156 | (fp_circle 157 | (center -0.51 1.16) 158 | (end -0.41 1.16) 159 | (stroke 160 | (width 0.2) 161 | (type solid) 162 | ) 163 | (fill none) 164 | (layer "Cmts.User") 165 | (uuid "916ac6b9-07e5-4856-af39-0230e72d1e5b") 166 | ) 167 | (fp_circle 168 | (center -0.76 0.75) 169 | (end -0.73 0.75) 170 | (stroke 171 | (width 0.06) 172 | (type solid) 173 | ) 174 | (fill none) 175 | (layer "F.Fab") 176 | (uuid "dd5c3f6f-47eb-4359-9528-3e650f0cfb0c") 177 | ) 178 | (fp_text user "${REFERENCE}" 179 | (at 0 0 0) 180 | (layer "F.Fab") 181 | (uuid "c6a8e0a0-8dea-48b9-b327-a099caab94a3") 182 | (effects 183 | (font 184 | (size 1 1) 185 | (thickness 0.15) 186 | ) 187 | ) 188 | ) 189 | (pad "1" smd rect 190 | (at -0.49 0.66 270) 191 | (size 0.55 0.25) 192 | (layers "F.Cu" "F.Paste" "F.Mask") 193 | (uuid "208ef8b9-57f7-4b5b-8c8e-2408b201977d") 194 | ) 195 | (pad "2" smd rect 196 | (at 0.01 0.66 270) 197 | (size 0.55 0.25) 198 | (layers "F.Cu" "F.Paste" "F.Mask") 199 | (uuid "015c491e-b1fa-4e6b-95bc-a93d3a9a6235") 200 | ) 201 | (pad "3" smd rect 202 | (at 0.51 0.66 270) 203 | (size 0.55 0.25) 204 | (layers "F.Cu" "F.Paste" "F.Mask") 205 | (uuid "037504e6-2d7a-455a-a9bf-818eb9c72e3b") 206 | ) 207 | (pad "4" smd rect 208 | (at 0.65 -0.01) 209 | (size 0.6 0.3) 210 | (layers "F.Cu" "F.Paste" "F.Mask") 211 | (uuid "e4c92105-fa97-4f6b-a044-aa0e2a4ec8af") 212 | ) 213 | (pad "5" smd rect 214 | (at 0.51 -0.66 270) 215 | (size 0.55 0.25) 216 | (layers "F.Cu" "F.Paste" "F.Mask") 217 | (uuid "85b3a2c6-9cb0-464a-b158-3942c852fa31") 218 | ) 219 | (pad "6" smd rect 220 | (at 0.01 -0.66 270) 221 | (size 0.55 0.25) 222 | (layers "F.Cu" "F.Paste" "F.Mask") 223 | (uuid "ac8153ae-f210-41ec-81a3-50854fa8333f") 224 | ) 225 | (pad "7" smd rect 226 | (at -0.49 -0.66 270) 227 | (size 0.55 0.25) 228 | (layers "F.Cu" "F.Paste" "F.Mask") 229 | (uuid "1446c813-0d7c-434b-aea7-c7e188f1c407") 230 | ) 231 | (pad "8" smd rect 232 | (at -0.65 -0.01) 233 | (size 0.6 0.3) 234 | (layers "F.Cu" "F.Paste" "F.Mask") 235 | (uuid "592f48ac-38cd-43da-b711-c93bf49c274e") 236 | ) 237 | (model "3dshapes/X2QFN-8_L1.5-W1.5-P0.50-BL.wrl" 238 | (offset 239 | (xyz 0.01 0.02 -0) 240 | ) 241 | (scale 242 | (xyz 1 1 1) 243 | ) 244 | (rotate 245 | (xyz 0 0 270) 246 | ) 247 | ) 248 | ) 249 | -------------------------------------------------------------------------------- /hardware/PicoROM.pro: -------------------------------------------------------------------------------- 1 | update=15/01/2021 11:42:37 2 | version=1 3 | last_client=kicad 4 | [general] 5 | version=1 6 | RootSch= 7 | BoardNm= 8 | [pcbnew] 9 | version=1 10 | LastNetListRead= 11 | UseCmpFile=1 12 | PadDrill=0.600000000000 13 | PadDrillOvalY=0.600000000000 14 | PadSizeH=1.500000000000 15 | PadSizeV=1.500000000000 16 | PcbTextSizeV=1.500000000000 17 | PcbTextSizeH=1.500000000000 18 | PcbTextThickness=0.300000000000 19 | ModuleTextSizeV=1.000000000000 20 | ModuleTextSizeH=1.000000000000 21 | ModuleTextSizeThickness=0.150000000000 22 | SolderMaskClearance=0.000000000000 23 | SolderMaskMinWidth=0.000000000000 24 | DrawSegmentWidth=0.200000000000 25 | BoardOutlineThickness=0.100000000000 26 | ModuleOutlineThickness=0.150000000000 27 | [cvpcb] 28 | version=1 29 | NetIExt=net 30 | [eeschema] 31 | version=1 32 | LibDir= 33 | [eeschema/libraries] 34 | [schematic_editor] 35 | version=1 36 | PageLayoutDescrFile= 37 | PlotDirectoryName= 38 | SubpartIdSeparator=0 39 | SubpartFirstId=65 40 | NetFmtName= 41 | SpiceAjustPassiveValues=0 42 | LabSize=50 43 | ERC_TestSimilarLabels=1 44 | -------------------------------------------------------------------------------- /hardware/TCA5404/2024-05-06_03-40-37.kicad_sym: -------------------------------------------------------------------------------- 1 | (kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor) 2 | (symbol "TCA5405RUGR" (pin_names (offset 0.254)) (in_bom yes) (on_board yes) 3 | (property "Reference" "U" (id 0) (at 20.32 10.16 0) 4 | (effects (font (size 1.524 1.524))) 5 | ) 6 | (property "Value" "TCA5405RUGR" (id 1) (at 20.32 7.62 0) 7 | (effects (font (size 1.524 1.524))) 8 | ) 9 | (property "Footprint" "RUG8" (id 2) (at 0 0 0) 10 | (effects (font (size 1.27 1.27) italic) hide) 11 | ) 12 | (property "Datasheet" "TCA5405RUGR" (id 3) (at 0 0 0) 13 | (effects (font (size 1.27 1.27) italic) hide) 14 | ) 15 | (property "ki_keywords" "TCA5405RUGR" (id 4) (at 0 0 0) 16 | (effects (font (size 1.27 1.27)) hide) 17 | ) 18 | (property "ki_locked" "" (id 5) (at 0 0 0) 19 | (effects (font (size 1.27 1.27)) hide) 20 | ) 21 | (property "ki_fp_filters" "RUG8" (id 6) (at 0 0 0) 22 | (effects (font (size 1.27 1.27)) hide) 23 | ) 24 | (symbol "TCA5405RUGR_0_1" 25 | (polyline 26 | (pts 27 | (xy 7.62 5.08) 28 | (xy 7.62 -20.32) 29 | ) 30 | (stroke (width 0.127) (type default) (color 0 0 0 0)) 31 | (fill (type none)) 32 | ) 33 | (polyline 34 | (pts 35 | (xy 7.62 -20.32) 36 | (xy 33.02 -20.32) 37 | ) 38 | (stroke (width 0.127) (type default) (color 0 0 0 0)) 39 | (fill (type none)) 40 | ) 41 | (polyline 42 | (pts 43 | (xy 33.02 -20.32) 44 | (xy 33.02 5.08) 45 | ) 46 | (stroke (width 0.127) (type default) (color 0 0 0 0)) 47 | (fill (type none)) 48 | ) 49 | (polyline 50 | (pts 51 | (xy 33.02 5.08) 52 | (xy 7.62 5.08) 53 | ) 54 | (stroke (width 0.127) (type default) (color 0 0 0 0)) 55 | (fill (type none)) 56 | ) 57 | (pin power_in line (at 0 -10.16 0) (length 7.62) 58 | (name "VCC" (effects (font (size 1.27 1.27)))) 59 | (number "1" (effects (font (size 1.27 1.27)))) 60 | ) 61 | (pin input line (at 0 0 0) (length 7.62) 62 | (name "DIN" (effects (font (size 1.27 1.27)))) 63 | (number "2" (effects (font (size 1.27 1.27)))) 64 | ) 65 | (pin power_in line (at 0 -15.24 0) (length 7.62) 66 | (name "GND" (effects (font (size 1.27 1.27)))) 67 | (number "3" (effects (font (size 1.27 1.27)))) 68 | ) 69 | (pin unspecified line (at 40.64 -2.54 180) (length 7.62) 70 | (name "Q0" (effects (font (size 1.27 1.27)))) 71 | (number "4" (effects (font (size 1.27 1.27)))) 72 | ) 73 | (pin unspecified line (at 40.64 -5.08 180) (length 7.62) 74 | (name "Q1" (effects (font (size 1.27 1.27)))) 75 | (number "5" (effects (font (size 1.27 1.27)))) 76 | ) 77 | (pin unspecified line (at 40.64 -7.62 180) (length 7.62) 78 | (name "Q2" (effects (font (size 1.27 1.27)))) 79 | (number "6" (effects (font (size 1.27 1.27)))) 80 | ) 81 | (pin unspecified line (at 40.64 -10.16 180) (length 7.62) 82 | (name "Q3" (effects (font (size 1.27 1.27)))) 83 | (number "7" (effects (font (size 1.27 1.27)))) 84 | ) 85 | (pin unspecified line (at 40.64 -12.7 180) (length 7.62) 86 | (name "Q4" (effects (font (size 1.27 1.27)))) 87 | (number "8" (effects (font (size 1.27 1.27)))) 88 | ) 89 | ) 90 | ) 91 | ) 92 | 93 | -------------------------------------------------------------------------------- /hardware/fabrication-toolkit-options.json: -------------------------------------------------------------------------------- 1 | {"EXTRA_LAYERS": "", "EXTEND_EDGE_CUT": false, "AUTO TRANSLATE": true, "AUTO FILL": true, "EXCLUDE DNP": false} -------------------------------------------------------------------------------- /hardware/fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (version 7) 3 | (lib (name "RP2040_minimal")(type "KiCad")(uri "${KIPRJMOD}/PicoROM.pretty")(options "")(descr "")) 4 | (lib (name "TCA5404")(type "KiCad")(uri "${KIPRJMOD}/TCA5404/footprints.pretty")(options "")(descr "")) 5 | ) 6 | -------------------------------------------------------------------------------- /hardware/production/PicoROM_-_ROM_Emulator_1.5.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/hardware/production/PicoROM_-_ROM_Emulator_1.5.zip -------------------------------------------------------------------------------- /hardware/production/PicoROM_-_ROM_Emulator_1.7.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wickerwaka/PicoROM/ca9395f6f84fdf8a95603dfb70176c07fc4fea5d/hardware/production/PicoROM_-_ROM_Emulator_1.7.zip -------------------------------------------------------------------------------- /hardware/production/bom.csv: -------------------------------------------------------------------------------- 1 | Designator,Footprint,Quantity,Value,LCSC Part # 2 | "C1, C4",0805,2,1u,C28323 3 | "C10, C25, C8",0402,3,1u,C52923 4 | "C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C5, C6, C7, C9",0201,18,100n,C1525 5 | "C2, C3",0402,2,27p,C1557 6 | D1,0603,1,LED,C510027 7 | D2,0603,1,LED,C2922668 8 | D3,0603,1,LED,C2925173 9 | "D4, D5",D_SOD-323,2,NSR0320MW2T1G,C48192 10 | J1,USB_C_Receptacle_G-Switch_GT-USB-7051x,1,USB_C_Receptacle_USB2.0,C2843970 11 | J5,PinHeader_1x05_P1.00mm_Vertical,1,Conn_01x05_Pin, 12 | "R1, R10, R2, R5, R8, R9",0201,6,1k,C270335 13 | R11,0201,1,100k,C270364 14 | "R3, R4",0201,2,27,C273268 15 | "R6, R7",0201,2,5.1k,C473460 16 | U1,SOT-23-5,1,AP2112K-3.3,C51118 17 | U10,DHVQFN24_L5.5-W3.5-P0.50-BL-EP,1,74LVCH8T245,C458263 18 | U2,Winbond_USON-8-1EP_3x2mm_P0.5mm_EP0.2x1.6mm,1,W25Q16JVUXIQ,C2843335 19 | U3,RP2040-QFN-56,1,RP2040,C2040 20 | "U4, U5, U9",V-QFN4525-20_L4.5-W2.5-P0.50-BL,3,74LVCH245,C548916 21 | U7,X2QFN-8_L1.5-W1.5-P0.50-BL,1,TCA5405RUGR,C2674123 22 | U8,SOT-23-5,1,74AHCT1G126,C163712 23 | Y1,Crystal_SMD_5032-2Pin_5.0x3.2mm,1,445C25D12M00000,C148313 24 | -------------------------------------------------------------------------------- /hardware/production/designators.csv: -------------------------------------------------------------------------------- 1 | C1:1 2 | C10:1 3 | C11:1 4 | C12:1 5 | C13:1 6 | C14:1 7 | C15:1 8 | C16:1 9 | C17:1 10 | C18:1 11 | C19:1 12 | C2:1 13 | C20:1 14 | C21:1 15 | C22:1 16 | C23:1 17 | C24:1 18 | C25:1 19 | C3:1 20 | C4:1 21 | C5:1 22 | C6:1 23 | C7:1 24 | C8:1 25 | C9:1 26 | D1:1 27 | D2:1 28 | D3:1 29 | D4:1 30 | D5:1 31 | J1:1 32 | J2:1 33 | J3:1 34 | J4:1 35 | J5:1 36 | R1:1 37 | R10:1 38 | R11:1 39 | R2:1 40 | R3:1 41 | R4:1 42 | R5:1 43 | R6:1 44 | R7:1 45 | R8:1 46 | R9:1 47 | U1:1 48 | U10:1 49 | U2:1 50 | U3:1 51 | U4:1 52 | U5:1 53 | U7:1 54 | U8:1 55 | U9:1 56 | Y1:1 57 | -------------------------------------------------------------------------------- /hardware/production/positions.csv: -------------------------------------------------------------------------------- 1 | Designator,Mid X,Mid Y,Rotation,Layer 2 | C1,16.89,37.531224,270.0,top 3 | C10,-3.715,30.019902,270.0,top 4 | C11,-5.885,31.139902,225.0,top 5 | C12,-6.955,34.825,225.0,bottom 6 | C13,-8.925,39.38,180.0,top 7 | C14,-0.535,31.879902,270.0,top 8 | C15,-1.465,32.319902,270.0,top 9 | C16,-0.18,37.8,45.0,bottom 10 | C17,-2.455,39.95,225.0,bottom 11 | C18,-15.855,33.9,180.0,top 12 | C19,10.345,32.275,0.0,bottom 13 | C2,-13.045,40.35,90.0,top 14 | C20,8.595,39.875,90.0,bottom 15 | C21,7.195,41.08,0.0,top 16 | C22,12.545,34.625,270.0,top 17 | C23,-9.725,34.02,270.0,top 18 | C24,1.82,31.8,0.0,bottom 19 | C25,-16.055,34.8,180.0,top 20 | C3,-13.055,36.55,270.0,top 21 | C4,15.54,34.331224,0.0,top 22 | C5,5.195,34.9,0.0,top 23 | C6,-9.805,38.68,180.0,top 24 | C7,0.005,33.379902,315.0,top 25 | C8,-2.795,30.879902,270.0,top 26 | C9,-5.235,30.479902,225.0,top 27 | D1,12.395,31.2,0.0,top 28 | D2,19.54,29.581224,0.0,top 29 | D3,19.54,41.081224,0.0,top 30 | D4,16.845,35.45,90.0,bottom 31 | D5,14.845,35.45,270.0,bottom 32 | J1,21.24,35.331224,90.0,top 33 | J5,-9.555,40.92,270.0,top 34 | R1,2.37,34.928678,0.0,top 35 | R10,17.255,30.72,180.0,top 36 | R11,-1.75,29.46,0.0,top 37 | R2,17.235,39.92,180.0,top 38 | R3,-0.065,30.499902,180.0,top 39 | R4,-0.055,29.579902,180.0,top 40 | R5,-13.005,38.47,270.0,top 41 | R6,19.975,31.42,180.0,bottom 42 | R7,19.32,39.431224,180.0,bottom 43 | R8,7.945,34.95,270.0,top 44 | R9,12.32,32.425,0.0,top 45 | U1,13.99,37.431224,90.0,top 46 | U10,-12.705,32.1,270.0,top 47 | U2,3.77,33.228678,0.0,top 48 | U3,-4.306878,36.680965,225.0,top 49 | U4,10.245,35.5,90.0,bottom 50 | U5,5.47,31.6,180.0,bottom 51 | U7,5.06,40.2,180.0,top 52 | U8,10.22,35.575,90.0,top 53 | U9,5.345,39.1625,0.0,bottom 54 | Y1,-15.495,38.52,270.0,top 55 | -------------------------------------------------------------------------------- /hardware/sym-lib-table: -------------------------------------------------------------------------------- 1 | (sym_lib_table 2 | (version 7) 3 | (lib (name "MCU_RaspberryPi_RP2040")(type "Legacy")(uri "${KIPRJMOD}/MCU_RaspberryPi_RP2040.lib")(options "")(descr "")) 4 | (lib (name "RP2040_minimal-rescue")(type "Legacy")(uri "${KIPRJMOD}/PicoROM-rescue.lib")(options "")(descr "")) 5 | (lib (name "TCA5404")(type "KiCad")(uri "${KIPRJMOD}/TCA5404/2024-05-06_03-40-37.kicad_sym")(options "")(descr "")) 6 | ) 7 | -------------------------------------------------------------------------------- /host/.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | 3 | -------------------------------------------------------------------------------- /host/picolink/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.95" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" 10 | 11 | [[package]] 12 | name = "autocfg" 13 | version = "1.4.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 16 | 17 | [[package]] 18 | name = "bitflags" 19 | version = "1.3.2" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 22 | 23 | [[package]] 24 | name = "bitflags" 25 | version = "2.8.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 28 | 29 | [[package]] 30 | name = "cfg-if" 31 | version = "1.0.0" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 34 | 35 | [[package]] 36 | name = "core-foundation" 37 | version = "0.10.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" 40 | dependencies = [ 41 | "core-foundation-sys", 42 | "libc", 43 | ] 44 | 45 | [[package]] 46 | name = "core-foundation-sys" 47 | version = "0.8.7" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 50 | 51 | [[package]] 52 | name = "dirs" 53 | version = "5.0.1" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" 56 | dependencies = [ 57 | "dirs-sys", 58 | ] 59 | 60 | [[package]] 61 | name = "dirs-sys" 62 | version = "0.4.1" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" 65 | dependencies = [ 66 | "libc", 67 | "option-ext", 68 | "redox_users", 69 | "windows-sys", 70 | ] 71 | 72 | [[package]] 73 | name = "getrandom" 74 | version = "0.2.15" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 77 | dependencies = [ 78 | "cfg-if", 79 | "libc", 80 | "wasi", 81 | ] 82 | 83 | [[package]] 84 | name = "io-kit-sys" 85 | version = "0.4.1" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" 88 | dependencies = [ 89 | "core-foundation-sys", 90 | "mach2", 91 | ] 92 | 93 | [[package]] 94 | name = "libc" 95 | version = "0.2.169" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 98 | 99 | [[package]] 100 | name = "libredox" 101 | version = "0.1.3" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 104 | dependencies = [ 105 | "bitflags 2.8.0", 106 | "libc", 107 | ] 108 | 109 | [[package]] 110 | name = "mach2" 111 | version = "0.4.2" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" 114 | dependencies = [ 115 | "libc", 116 | ] 117 | 118 | [[package]] 119 | name = "nix" 120 | version = "0.26.4" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" 123 | dependencies = [ 124 | "bitflags 1.3.2", 125 | "cfg-if", 126 | "libc", 127 | ] 128 | 129 | [[package]] 130 | name = "num-derive" 131 | version = "0.4.2" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" 134 | dependencies = [ 135 | "proc-macro2", 136 | "quote", 137 | "syn", 138 | ] 139 | 140 | [[package]] 141 | name = "num-traits" 142 | version = "0.2.19" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 145 | dependencies = [ 146 | "autocfg", 147 | ] 148 | 149 | [[package]] 150 | name = "option-ext" 151 | version = "0.2.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 154 | 155 | [[package]] 156 | name = "picolink" 157 | version = "1.7.1" 158 | dependencies = [ 159 | "anyhow", 160 | "dirs", 161 | "num-derive", 162 | "num-traits", 163 | "serialport", 164 | ] 165 | 166 | [[package]] 167 | name = "proc-macro2" 168 | version = "1.0.93" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 171 | dependencies = [ 172 | "unicode-ident", 173 | ] 174 | 175 | [[package]] 176 | name = "quote" 177 | version = "1.0.38" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 180 | dependencies = [ 181 | "proc-macro2", 182 | ] 183 | 184 | [[package]] 185 | name = "redox_users" 186 | version = "0.4.6" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" 189 | dependencies = [ 190 | "getrandom", 191 | "libredox", 192 | "thiserror", 193 | ] 194 | 195 | [[package]] 196 | name = "scopeguard" 197 | version = "1.2.0" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 200 | 201 | [[package]] 202 | name = "serialport" 203 | version = "4.7.0" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "5ecfc4858c2266c7695d8b8460bbd612fa81bd2e250f5f0dd16195e4b4f8b3d8" 206 | dependencies = [ 207 | "bitflags 2.8.0", 208 | "cfg-if", 209 | "core-foundation", 210 | "core-foundation-sys", 211 | "io-kit-sys", 212 | "mach2", 213 | "nix", 214 | "scopeguard", 215 | "unescaper", 216 | "winapi", 217 | ] 218 | 219 | [[package]] 220 | name = "syn" 221 | version = "2.0.96" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 224 | dependencies = [ 225 | "proc-macro2", 226 | "quote", 227 | "unicode-ident", 228 | ] 229 | 230 | [[package]] 231 | name = "thiserror" 232 | version = "1.0.69" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 235 | dependencies = [ 236 | "thiserror-impl", 237 | ] 238 | 239 | [[package]] 240 | name = "thiserror-impl" 241 | version = "1.0.69" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 244 | dependencies = [ 245 | "proc-macro2", 246 | "quote", 247 | "syn", 248 | ] 249 | 250 | [[package]] 251 | name = "unescaper" 252 | version = "0.1.5" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815" 255 | dependencies = [ 256 | "thiserror", 257 | ] 258 | 259 | [[package]] 260 | name = "unicode-ident" 261 | version = "1.0.15" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" 264 | 265 | [[package]] 266 | name = "wasi" 267 | version = "0.11.0+wasi-snapshot-preview1" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 270 | 271 | [[package]] 272 | name = "winapi" 273 | version = "0.3.9" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 276 | dependencies = [ 277 | "winapi-i686-pc-windows-gnu", 278 | "winapi-x86_64-pc-windows-gnu", 279 | ] 280 | 281 | [[package]] 282 | name = "winapi-i686-pc-windows-gnu" 283 | version = "0.4.0" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 286 | 287 | [[package]] 288 | name = "winapi-x86_64-pc-windows-gnu" 289 | version = "0.4.0" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 292 | 293 | [[package]] 294 | name = "windows-sys" 295 | version = "0.48.0" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 298 | dependencies = [ 299 | "windows-targets", 300 | ] 301 | 302 | [[package]] 303 | name = "windows-targets" 304 | version = "0.48.5" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 307 | dependencies = [ 308 | "windows_aarch64_gnullvm", 309 | "windows_aarch64_msvc", 310 | "windows_i686_gnu", 311 | "windows_i686_msvc", 312 | "windows_x86_64_gnu", 313 | "windows_x86_64_gnullvm", 314 | "windows_x86_64_msvc", 315 | ] 316 | 317 | [[package]] 318 | name = "windows_aarch64_gnullvm" 319 | version = "0.48.5" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 322 | 323 | [[package]] 324 | name = "windows_aarch64_msvc" 325 | version = "0.48.5" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 328 | 329 | [[package]] 330 | name = "windows_i686_gnu" 331 | version = "0.48.5" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 334 | 335 | [[package]] 336 | name = "windows_i686_msvc" 337 | version = "0.48.5" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 340 | 341 | [[package]] 342 | name = "windows_x86_64_gnu" 343 | version = "0.48.5" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 346 | 347 | [[package]] 348 | name = "windows_x86_64_gnullvm" 349 | version = "0.48.5" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 352 | 353 | [[package]] 354 | name = "windows_x86_64_msvc" 355 | version = "0.48.5" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 358 | -------------------------------------------------------------------------------- /host/picolink/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "picolink" 3 | version = "1.7.1" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1" 10 | num-traits = "0.2" 11 | num-derive = "0.4" 12 | dirs = "5.0" 13 | serialport = { version = "4", default-features = false } 14 | 15 | -------------------------------------------------------------------------------- /host/picorom/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "picorom" 3 | version = "1.7.1" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1" 10 | clap = { version = "4", features = ["derive", "string"] } 11 | clap-num = "1" 12 | indicatif = "0.17" 13 | 14 | picolink = { path = "../picolink" } 15 | -------------------------------------------------------------------------------- /host/picorom/src/main.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use clap::{Parser, Subcommand}; 3 | use indicatif; 4 | use indicatif::ProgressBar; 5 | use indicatif::ProgressStyle; 6 | use std::fs; 7 | use std::iter; 8 | use std::path::{Path, PathBuf}; 9 | use std::time::Duration; 10 | 11 | use picolink::*; 12 | 13 | mod rom_size; 14 | use crate::rom_size::*; 15 | 16 | fn read_file(name: &Path, rom_size: RomSize) -> Result> { 17 | let mut data = fs::read(name)?; 18 | if data.len() > rom_size.bytes() { 19 | return Err(anyhow!( 20 | "{:?} larger ({}) than rom size ({})", 21 | name, 22 | data.len(), 23 | rom_size.bytes() 24 | )); 25 | } 26 | 27 | let diff = rom_size.bytes() - data.len(); 28 | data.extend(iter::repeat(0u8).take(diff)); 29 | 30 | Ok(data.repeat(RomSize::MBit(2).bytes() / rom_size.bytes())) 31 | } 32 | 33 | #[derive(Debug, Parser)] // requires `derive` feature 34 | #[command(name = "picorom")] 35 | #[command(about = "PicoROM controller", long_about = None)] 36 | struct Cli { 37 | #[command(subcommand)] 38 | command: Commands, 39 | } 40 | 41 | #[derive(Debug, Subcommand)] 42 | enum Commands { 43 | /// Return a list of currently connected PicoROM devices. 44 | List, 45 | 46 | /// Flash the activity LED on a specific PicoRom 47 | Identify { 48 | /// PicoROM device name. 49 | name: String, 50 | }, 51 | 52 | /// Commit the current ROM image to flash memory 53 | Commit { 54 | /// PicoROM device name. 55 | name: String, 56 | }, 57 | 58 | /// Change the name of a PicoROM device. 59 | Rename { 60 | /// Current name. 61 | current: String, 62 | /// New name to rename it to. 63 | new: String, 64 | }, 65 | 66 | /// Upload a ROM image to a PicoROM 67 | Upload { 68 | /// PicoROM device name. 69 | name: String, 70 | /// Path of file to upload. 71 | source: PathBuf, 72 | /// Emulate a specific ROM size. 73 | #[arg(value_enum, ignore_case=true, default_value_t=RomSize::MBit(2))] 74 | size: RomSize, 75 | /// Store the uploaded image in flash memory also. 76 | #[arg(short, long, default_value_t = false)] 77 | store: bool, 78 | }, 79 | 80 | /// Set the level of the reset pin 81 | Reset { 82 | /// PicoROM device name. 83 | name: String, 84 | 85 | /// Reset level 86 | #[arg(value_parser = clap::builder::PossibleValuesParser::new(["high", "low", "z"]))] 87 | level: String, 88 | }, 89 | 90 | /// Get the value of a parameter 91 | Get { 92 | /// PicoROM device name. 93 | name: String, 94 | 95 | /// Parameter name 96 | param: Option, 97 | }, 98 | 99 | /// Set a parameter to a new value 100 | Set { 101 | /// PicoROM device name. 102 | name: String, 103 | 104 | /// Parameter name 105 | param: String, 106 | 107 | /// Parameter value 108 | value: String, 109 | }, 110 | 111 | /// Reboot the device into USB mode 112 | USBBoot { name: String }, 113 | } 114 | 115 | fn main() -> Result<()> { 116 | let args = Cli::parse(); 117 | 118 | match args.command { 119 | Commands::List => { 120 | let found = enumerate_picos()?; 121 | if found.len() > 0 { 122 | println!("Available PicoROMs:"); 123 | for (k, v) in found.iter() { 124 | println!(" {:16} [{}]", k, v.path); 125 | } 126 | } else { 127 | println!("No PicoROMs found."); 128 | } 129 | } 130 | Commands::Identify { name } => { 131 | let mut pico = find_pico(&name)?; 132 | pico.identify()?; 133 | println!("Requested identification from '{}'", name); 134 | } 135 | Commands::Commit { name } => { 136 | let mut pico = find_pico(&name)?; 137 | let spinner = ProgressBar::new_spinner() 138 | .with_prefix("Storing to Flash") 139 | .with_style( 140 | ProgressStyle::with_template("{prefix:.bold} {spinner} {msg}") 141 | .unwrap() 142 | .tick_chars(r"\|/--"), 143 | ); 144 | spinner.enable_steady_tick(Duration::from_millis(250)); 145 | pico.commit_rom()?; 146 | spinner.finish_with_message("Done."); 147 | } 148 | Commands::Rename { current, new } => { 149 | let mut pico = find_pico(¤t)?; 150 | pico.set_ident(&new)?; 151 | println!("Renamed '{}' to '{}'", current, new); 152 | } 153 | Commands::Upload { 154 | name, 155 | source, 156 | size, 157 | store, 158 | } => { 159 | let mut pico = find_pico(&name)?; 160 | let data = read_file(source.as_path(), size)?; 161 | let progress = ProgressBar::new(data.len() as u64) 162 | .with_prefix("Uploading ROM") 163 | .with_style( 164 | ProgressStyle::with_template("{prefix:.bold} [{wide_bar:.cyan/blue}] {msg:10}") 165 | .unwrap() 166 | .progress_chars("#>-"), 167 | ); 168 | pico.upload(&data, size.mask(), |x| progress.inc(x as u64))?; 169 | progress.finish_with_message("Done."); 170 | if let Some(filename) = source.file_name() { 171 | pico.set_parameter("rom_name", filename.to_string_lossy().as_ref())?; 172 | } 173 | if store { 174 | let spinner = ProgressBar::new_spinner() 175 | .with_prefix("Storing to Flash") 176 | .with_style( 177 | ProgressStyle::with_template("{prefix:.bold} {spinner} {msg}") 178 | .unwrap() 179 | .tick_chars(r"\|/--"), 180 | ); 181 | spinner.enable_steady_tick(Duration::from_millis(250)); 182 | pico.commit_rom()?; 183 | spinner.finish_with_message("Done."); 184 | } 185 | } 186 | Commands::Reset { name, level } => { 187 | let mut pico = find_pico(&name)?; 188 | pico.set_parameter("reset", &level)?; 189 | println!("Setting '{}' reset pin to: {}", name, level); 190 | } 191 | Commands::Get { name, param } => { 192 | let mut pico = find_pico(&name)?; 193 | if let Some(param) = param { 194 | let value = pico.get_parameter(¶m)?; 195 | println!("{}={}", param, value); 196 | } else { 197 | let params = pico.get_parameters()?; 198 | for p in params { 199 | let value = pico.get_parameter(&p)?; 200 | println!("{}={}", p, value); 201 | } 202 | } 203 | } 204 | Commands::Set { name, param, value } => { 205 | let mut pico = find_pico(&name)?; 206 | let newvalue = pico.set_parameter(¶m, &value)?; 207 | println!("{}={}", param, newvalue); 208 | } 209 | 210 | Commands::USBBoot { name } => { 211 | let mut pico = find_pico(&name)?; 212 | println!("Requesting USB boot"); 213 | pico.usb_boot()?; 214 | } 215 | } 216 | 217 | Ok(()) 218 | } 219 | -------------------------------------------------------------------------------- /host/picorom/src/rom_size.rs: -------------------------------------------------------------------------------- 1 | use clap::{builder::PossibleValue, ValueEnum}; 2 | 3 | #[derive(Clone, Debug, Copy)] 4 | pub enum RomSize { 5 | MBit(usize), 6 | KBit(usize), 7 | } 8 | 9 | impl RomSize { 10 | pub fn bytes(&self) -> usize { 11 | match *self { 12 | RomSize::MBit(x) => x * 128 * 1024, 13 | RomSize::KBit(x) => x * 128, 14 | } 15 | } 16 | 17 | pub fn mask(&self) -> u32 { 18 | (self.bytes() as u32) - 1 19 | } 20 | } 21 | 22 | impl ValueEnum for RomSize { 23 | fn value_variants<'a>() -> &'a [Self] { 24 | &[ 25 | RomSize::MBit(2), 26 | RomSize::MBit(1), 27 | RomSize::KBit(512), 28 | RomSize::KBit(256), 29 | RomSize::KBit(128), 30 | RomSize::KBit(64), 31 | RomSize::KBit(32), 32 | RomSize::KBit(16), 33 | RomSize::KBit(8), 34 | ] 35 | } 36 | 37 | fn to_possible_value(&self) -> Option { 38 | match self { 39 | RomSize::MBit(x) => Some(PossibleValue::new(format!("{}MBit", x))), 40 | RomSize::KBit(x) => Some(PossibleValue::new(format!("{}KBit", x))), 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /host/pypicorom/.env/pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /opt/homebrew/opt/python@3.11/bin 2 | include-system-site-packages = false 3 | version = 3.11.4 4 | executable = /opt/homebrew/Cellar/python@3.11/3.11.4_1/Frameworks/Python.framework/Versions/3.11/bin/python3.11 5 | command = /opt/homebrew/opt/python@3.11/bin/python3.11 -m venv /Users/akawaka/Source/rom_emulator/host/pypicorom/.env 6 | -------------------------------------------------------------------------------- /host/pypicorom/.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | # This file is autogenerated by maturin v1.1.0 2 | # To update, run 3 | # 4 | # maturin generate-ci github 5 | # 6 | name: CI 7 | 8 | on: 9 | push: 10 | branches: 11 | - main 12 | - master 13 | tags: 14 | - '*' 15 | pull_request: 16 | workflow_dispatch: 17 | 18 | permissions: 19 | contents: read 20 | 21 | jobs: 22 | linux: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | target: [x86_64, x86, aarch64, armv7, s390x, ppc64le] 27 | steps: 28 | - uses: actions/checkout@v3 29 | - uses: actions/setup-python@v4 30 | with: 31 | python-version: '3.10' 32 | - name: Build wheels 33 | uses: PyO3/maturin-action@v1 34 | with: 35 | target: ${{ matrix.target }} 36 | args: --release --out dist --find-interpreter 37 | sccache: 'true' 38 | manylinux: auto 39 | - name: Upload wheels 40 | uses: actions/upload-artifact@v3 41 | with: 42 | name: wheels 43 | path: dist 44 | 45 | windows: 46 | runs-on: windows-latest 47 | strategy: 48 | matrix: 49 | target: [x64, x86] 50 | steps: 51 | - uses: actions/checkout@v3 52 | - uses: actions/setup-python@v4 53 | with: 54 | python-version: '3.10' 55 | architecture: ${{ matrix.target }} 56 | - name: Build wheels 57 | uses: PyO3/maturin-action@v1 58 | with: 59 | target: ${{ matrix.target }} 60 | args: --release --out dist --find-interpreter 61 | sccache: 'true' 62 | - name: Upload wheels 63 | uses: actions/upload-artifact@v3 64 | with: 65 | name: wheels 66 | path: dist 67 | 68 | macos: 69 | runs-on: macos-latest 70 | strategy: 71 | matrix: 72 | target: [x86_64, aarch64] 73 | steps: 74 | - uses: actions/checkout@v3 75 | - uses: actions/setup-python@v4 76 | with: 77 | python-version: '3.10' 78 | - name: Build wheels 79 | uses: PyO3/maturin-action@v1 80 | with: 81 | target: ${{ matrix.target }} 82 | args: --release --out dist --find-interpreter 83 | sccache: 'true' 84 | - name: Upload wheels 85 | uses: actions/upload-artifact@v3 86 | with: 87 | name: wheels 88 | path: dist 89 | 90 | sdist: 91 | runs-on: ubuntu-latest 92 | steps: 93 | - uses: actions/checkout@v3 94 | - name: Build sdist 95 | uses: PyO3/maturin-action@v1 96 | with: 97 | command: sdist 98 | args: --out dist 99 | - name: Upload sdist 100 | uses: actions/upload-artifact@v3 101 | with: 102 | name: wheels 103 | path: dist 104 | 105 | release: 106 | name: Release 107 | runs-on: ubuntu-latest 108 | if: "startsWith(github.ref, 'refs/tags/')" 109 | needs: [linux, windows, macos, sdist] 110 | steps: 111 | - uses: actions/download-artifact@v3 112 | with: 113 | name: wheels 114 | - name: Publish to PyPI 115 | uses: PyO3/maturin-action@v1 116 | env: 117 | MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} 118 | with: 119 | command: upload 120 | args: --skip-existing * 121 | -------------------------------------------------------------------------------- /host/pypicorom/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | .pytest_cache/ 6 | *.py[cod] 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | .venv/ 14 | env/ 15 | bin/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | include/ 26 | man/ 27 | venv/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | pip-selfcheck.json 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | 45 | # Translations 46 | *.mo 47 | 48 | # Mr Developer 49 | .mr.developer.cfg 50 | .project 51 | .pydevproject 52 | 53 | # Rope 54 | .ropeproject 55 | 56 | # Django stuff: 57 | *.log 58 | *.pot 59 | 60 | .DS_Store 61 | 62 | # Sphinx documentation 63 | docs/_build/ 64 | 65 | # PyCharm 66 | .idea/ 67 | 68 | # VSCode 69 | .vscode/ 70 | 71 | # Pyenv 72 | .python-version -------------------------------------------------------------------------------- /host/pypicorom/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pypicorom" 3 | version = "1.7.1" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [lib] 8 | name = "pypicorom" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | pyo3 = { version = "0.19.0", features = ["anyhow", "abi3-py310"] } 13 | picolink = { path = "../picolink" } 14 | -------------------------------------------------------------------------------- /host/pypicorom/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.1,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "pypicorom" 7 | requires-python = ">=3.10" 8 | classifiers = [ 9 | "Programming Language :: Rust", 10 | "Programming Language :: Python :: Implementation :: CPython", 11 | "Programming Language :: Python :: Implementation :: PyPy", 12 | ] 13 | 14 | 15 | [tool.maturin] 16 | features = ["pyo3/extension-module"] 17 | -------------------------------------------------------------------------------- /host/pypicorom/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::thread::sleep; 2 | use std::time::{Duration, Instant}; 3 | use std::collections::HashMap; 4 | 5 | use picolink::*; 6 | use pyo3::create_exception; 7 | use pyo3::exceptions::PyException; 8 | use pyo3::prelude::*; 9 | 10 | create_exception!( 11 | pypicorom, 12 | CommsStateError, 13 | PyException, 14 | "Invalid comms setup" 15 | ); 16 | 17 | create_exception!( 18 | pypicorom, 19 | CommsTimeoutError, 20 | PyException, 21 | "Communication timeout" 22 | ); 23 | 24 | /// A PicoROM connection. 25 | #[pyclass] 26 | struct PicoROM { 27 | link: PicoLink, 28 | read_buffer: Vec, 29 | comms_active: bool, 30 | } 31 | 32 | impl PicoROM { 33 | fn comms_inactive(&self) -> PyResult<()> { 34 | if self.comms_active { 35 | return Err(CommsStateError::new_err("Comms active.")); 36 | } 37 | Ok(()) 38 | } 39 | 40 | fn comms_active(&self) -> PyResult<()> { 41 | if !self.comms_active { 42 | return Err(CommsStateError::new_err("Comms not active.")); 43 | } 44 | Ok(()) 45 | } 46 | } 47 | 48 | #[pymethods] 49 | impl PicoROM { 50 | /// Get the identifying name 51 | fn get_name(&mut self) -> PyResult { 52 | self.comms_inactive()?; 53 | 54 | Ok(self.link.get_ident()?) 55 | } 56 | 57 | /// Set the identifying name 58 | fn set_name(&mut self, name: String) -> PyResult<()> { 59 | self.comms_inactive()?; 60 | 61 | Ok(self.link.set_ident(&name)?) 62 | } 63 | 64 | /// Commit the current ROM data to flash memory 65 | fn commit(&mut self) -> PyResult<()> { 66 | self.comms_inactive()?; 67 | 68 | Ok(self.link.commit_rom()?) 69 | } 70 | 71 | /// Ask PicoROM to identify itself 72 | fn identify(&mut self) -> PyResult<()> { 73 | self.comms_inactive()?; 74 | 75 | Ok(self.link.identify()?) 76 | } 77 | 78 | /// Get all parameters as a dict 79 | fn parameters(&mut self) -> PyResult> { 80 | let parameters = self.link.get_parameters()?; 81 | let mut param_map = HashMap::new(); 82 | 83 | for p in parameters { 84 | let value = self.link.get_parameter(&p)?; 85 | param_map.insert(p, value); 86 | } 87 | 88 | Ok(param_map) 89 | } 90 | 91 | /// Get a single named parameter 92 | fn get_parameter(&mut self, name: String) -> PyResult { 93 | Ok(self.link.get_parameter(&name)?) 94 | } 95 | 96 | /// Set a single named parameter 97 | fn set_parameter(&mut self, name: String, value: String) -> PyResult { 98 | Ok(self.link.set_parameter(&name, &value)?) 99 | } 100 | 101 | /// Upload ROM data 102 | #[pyo3(signature = (data, mask=0x3ffff), text_signature = "(data, mask=0x3ffff, /)")] 103 | fn upload(&mut self, data: &[u8], mask: u32) -> PyResult<()> { 104 | self.comms_inactive()?; 105 | 106 | self.link.upload(data, mask, |_| {})?; 107 | 108 | Ok(()) 109 | } 110 | 111 | /// Update to a specific address 112 | fn upload_to(&mut self, addr: u32, data: &[u8]) -> PyResult<()> { 113 | self.comms_inactive()?; 114 | 115 | self.link.upload_to(addr, data, |_| {})?; 116 | 117 | Ok(()) 118 | } 119 | 120 | /// Start two-way communications 121 | fn start_comms(&mut self, addr: u32) -> PyResult<()> { 122 | self.comms_inactive()?; 123 | 124 | self.link.send(ReqPacket::CommsStart(addr))?; 125 | self.comms_active = true; 126 | self.read_buffer.clear(); 127 | Ok(()) 128 | } 129 | 130 | /// End two-way communications 131 | fn end_comms(&mut self) -> PyResult<()> { 132 | self.comms_active()?; 133 | 134 | self.link.send(ReqPacket::CommsEnd)?; 135 | self.comms_active = false; 136 | self.read_buffer.clear(); 137 | Ok(()) 138 | } 139 | 140 | /// Read from the communication channel 141 | #[pyo3(signature = (size=-1), text_signature = "(size=-1, /)")] 142 | fn read(&mut self, size: i32) -> PyResult>> { 143 | self.comms_active()?; 144 | 145 | let new_data = self.link.poll_comms(None)?; 146 | self.read_buffer.extend_from_slice(&new_data); 147 | 148 | if self.read_buffer.len() == 0 { 149 | return Ok(None); 150 | } 151 | 152 | let end = if size == -1 { 153 | self.read_buffer.len() 154 | } else { 155 | self.read_buffer.len().min(size as usize) 156 | }; 157 | 158 | Ok(Some(self.read_buffer.drain(0..end).collect())) 159 | } 160 | 161 | /// Read an exact amount with an optional timeout 162 | fn read_exact( 163 | &mut self, 164 | size: usize, 165 | timeout: Option, 166 | py: Python<'_>, 167 | ) -> PyResult> { 168 | self.comms_active()?; 169 | 170 | let end = timeout.map(|x| Instant::now() + Duration::from_secs_f32(x)); 171 | 172 | loop { 173 | let new_data = self.link.poll_comms(None)?; 174 | self.read_buffer.extend_from_slice(&new_data); 175 | 176 | if self.read_buffer.len() < size { 177 | if let Some(end) = end { 178 | if Instant::now() >= end { 179 | return Err(CommsTimeoutError::new_err("read_all timeout")); 180 | } 181 | } 182 | py.check_signals()?; 183 | sleep(Duration::from_micros(10)); 184 | } else { 185 | return Ok(self.read_buffer.drain(0..size).collect()); 186 | } 187 | } 188 | } 189 | 190 | /// Write to the communication channel 191 | fn write(&mut self, data: Vec) -> PyResult { 192 | self.comms_active()?; 193 | 194 | let len = data.len(); 195 | let new_data = self.link.poll_comms(Some(data))?; 196 | self.read_buffer.extend_from_slice(&new_data); 197 | Ok(len) 198 | } 199 | } 200 | 201 | /// Enumerate all available PicoROMs 202 | #[pyfunction] 203 | fn enumerate() -> PyResult> { 204 | let picos = enumerate_picos()?; 205 | Ok(Vec::from_iter(picos.keys().cloned())) 206 | } 207 | 208 | /// Open a connection to the named PicoROM. 209 | #[pyfunction] 210 | fn open(name: &str) -> PyResult { 211 | let pico = find_pico(name)?; 212 | Ok(PicoROM { 213 | link: pico, 214 | read_buffer: Vec::new(), 215 | comms_active: false, 216 | }) 217 | } 218 | 219 | /// Python module for communicating with PicoROMs. 220 | #[pymodule] 221 | fn pypicorom(py: Python, m: &PyModule) -> PyResult<()> { 222 | m.add_function(wrap_pyfunction!(enumerate, m)?)?; 223 | m.add_function(wrap_pyfunction!(open, m)?)?; 224 | m.add_class::()?; 225 | m.add("CommsStateError", py.get_type::())?; 226 | m.add("CommsTimeoutError", py.get_type::())?; 227 | Ok(()) 228 | } 229 | -------------------------------------------------------------------------------- /signal_gen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | include(pico_sdk_import.cmake) 3 | project(rom_emulator C CXX ASM) 4 | set(CMAKE_C_STANDARD 11) 5 | set(CMAKE_CXX_STANDARD 17) 6 | 7 | pico_sdk_init() 8 | 9 | add_executable(PicoROMSignal 10 | main.cpp 11 | ) 12 | 13 | pico_enable_stdio_usb(PicoROMSignal 1) 14 | 15 | pico_add_extra_outputs(PicoROMSignal) 16 | target_link_libraries(PicoROMSignal 17 | pico_stdlib 18 | hardware_pio 19 | ) 20 | -------------------------------------------------------------------------------- /signal_gen/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "pico/stdlib.h" 4 | #include "hardware/gpio.h" 5 | 6 | static constexpr uint32_t BASE_DATA_PIN = 22; 7 | static constexpr uint32_t BUF_OE_PIN = 19; 8 | 9 | int main() 10 | { 11 | for( uint ofs = 0; ofs < 8; ofs++ ) 12 | { 13 | uint gpio = BASE_DATA_PIN + ofs; 14 | 15 | gpio_init(gpio); 16 | gpio_set_dir(gpio, true); 17 | } 18 | 19 | gpio_init(BUF_OE_PIN); 20 | gpio_set_dir(BUF_OE_PIN, true); 21 | 22 | stdio_init_all(); 23 | 24 | gpio_put(BUF_OE_PIN, false); 25 | 26 | uint32_t addr = 0; 27 | 28 | while( true ) 29 | { 30 | gpio_put_masked(0xff << BASE_DATA_PIN, addr << BASE_DATA_PIN); 31 | addr++; 32 | } 33 | } -------------------------------------------------------------------------------- /signal_gen/pico_sdk_import.cmake: -------------------------------------------------------------------------------- 1 | # This is a copy of /external/pico_sdk_import.cmake 2 | 3 | # This can be dropped into an external project to help locate this SDK 4 | # It should be include()ed prior to project() 5 | 6 | if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) 7 | set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) 8 | message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") 9 | endif () 10 | 11 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) 12 | set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) 13 | message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") 14 | endif () 15 | 16 | if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) 17 | set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) 18 | message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") 19 | endif () 20 | 21 | set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") 22 | set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") 23 | set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") 24 | 25 | if (NOT PICO_SDK_PATH) 26 | if (PICO_SDK_FETCH_FROM_GIT) 27 | include(FetchContent) 28 | set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) 29 | if (PICO_SDK_FETCH_FROM_GIT_PATH) 30 | get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") 31 | endif () 32 | # GIT_SUBMODULES_RECURSE was added in 3.17 33 | if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") 34 | FetchContent_Declare( 35 | pico_sdk 36 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 37 | GIT_TAG master 38 | GIT_SUBMODULES_RECURSE FALSE 39 | ) 40 | else () 41 | FetchContent_Declare( 42 | pico_sdk 43 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 44 | GIT_TAG master 45 | ) 46 | endif () 47 | 48 | if (NOT pico_sdk) 49 | message("Downloading Raspberry Pi Pico SDK") 50 | FetchContent_Populate(pico_sdk) 51 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 52 | endif () 53 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 54 | else () 55 | message(FATAL_ERROR 56 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 57 | ) 58 | endif () 59 | endif () 60 | 61 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 62 | if (NOT EXISTS ${PICO_SDK_PATH}) 63 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 64 | endif () 65 | 66 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 67 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 68 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 69 | endif () 70 | 71 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 72 | 73 | include(${PICO_SDK_INIT_CMAKE_FILE}) 74 | --------------------------------------------------------------------------------