├── .gitignore ├── .gitmodules ├── .vscode ├── launch.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── docs ├── case-models.png ├── githubbutton_pp.svg ├── images │ ├── EmptyMemoryCard │ │ └── MEMCARD.MCR │ └── SampleMemoryCard │ │ └── MEMCARD.MCR ├── mini-spi.png ├── pcb.png ├── picomemcard-in-action.jpg ├── wiring-RP2040-Zero.svg └── wiring-pico.svg ├── inc ├── config.h ├── led.h ├── memcard_manager.h ├── memcard_simulator.h ├── memory_card.h ├── pad.h ├── sd_config.h └── tusb_config.h ├── memmap.ld ├── pcb ├── PicoMemcard-pico │ ├── Gerber │ │ ├── PicoMemcard-pico-B_Cu.gbr │ │ ├── PicoMemcard-pico-B_Mask.gbr │ │ ├── PicoMemcard-pico-B_Paste.gbr │ │ ├── PicoMemcard-pico-B_Silkscreen.gbr │ │ ├── PicoMemcard-pico-Edge_Cuts.gbr │ │ ├── PicoMemcard-pico-F_Cu.gbr │ │ ├── PicoMemcard-pico-F_Mask.gbr │ │ ├── PicoMemcard-pico-F_Paste.gbr │ │ ├── PicoMemcard-pico-F_Silkscreen.gbr │ │ ├── PicoMemcard-pico-NPTH-drl_map.ps │ │ ├── PicoMemcard-pico-NPTH.drl │ │ ├── PicoMemcard-pico-PTH-drl_map.ps │ │ ├── PicoMemcard-pico-PTH.drl │ │ └── PicoMemcard-pico-job.gbrjob │ ├── PicoMemcard-pico-backups │ │ └── PicoMemcard-pico-2023-02-05_194258.zip │ ├── PicoMemcard-pico.kicad_pcb │ ├── PicoMemcard-pico.kicad_prl │ ├── PicoMemcard-pico.kicad_pro │ └── PicoMemcard-pico.kicad_sch └── PicoMemcard-rp2040zero │ ├── Gerber │ ├── PicoMemcard-rp2040zero-B_Cu.gbr │ ├── PicoMemcard-rp2040zero-B_Mask.gbr │ ├── PicoMemcard-rp2040zero-B_Paste.gbr │ ├── PicoMemcard-rp2040zero-B_Silkscreen.gbr │ ├── PicoMemcard-rp2040zero-Edge_Cuts.gbr │ ├── PicoMemcard-rp2040zero-F_Cu.gbr │ ├── PicoMemcard-rp2040zero-F_Mask.gbr │ ├── PicoMemcard-rp2040zero-F_Paste.gbr │ ├── PicoMemcard-rp2040zero-F_Silkscreen.gbr │ ├── PicoMemcard-rp2040zero-NPTH-drl_map.ps │ ├── PicoMemcard-rp2040zero-NPTH.drl │ ├── PicoMemcard-rp2040zero-PTH-drl_map.ps │ ├── PicoMemcard-rp2040zero-PTH.drl │ └── PicoMemcard-rp2040zero-job.gbrjob │ ├── PicoMemcard-rp2040zero-backups │ └── PicoMemcard-rp2040zero-2023-02-05_194235.zip │ ├── PicoMemcard-rp2040zero.kicad_pcb │ ├── PicoMemcard-rp2040zero.kicad_prl │ ├── PicoMemcard-rp2040zero.kicad_pro │ └── PicoMemcard-rp2040zero.kicad_sch ├── pico_sdk_import.cmake ├── poc_examples ├── CMakeLists.txt ├── controller_simulator │ ├── CMakeLists.txt │ └── controller_simulator.c └── memcard_sniffer │ ├── CMakeLists.txt │ └── memcard_sniffer.c ├── psxSPI.pio ├── src ├── led.c ├── main.c ├── memcard_manager.c ├── memcard_simulator.c ├── memory_card.c ├── msc_handler.c ├── sd_config.c └── usb_descriptors.c └── ws2812.pio /.gitignore: -------------------------------------------------------------------------------- 1 | # Build directory 2 | build/ 3 | 4 | # Cortex-Debug extension debug artifacts 5 | .vscode/.cortex* 6 | 7 | # FatFS documentation 8 | ff14b/documents 9 | 10 | # VSCode 11 | .vscode/settings.json 12 | 13 | # Clion 14 | /.idea 15 | /cmake-build-debug -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "no-OS-FatFS-SD-SPI-RPi-Pico"] 2 | path = no-OS-FatFS-SD-SPI-RPi-Pico 3 | url = https://github.com/carlk3/no-OS-FatFS-SD-SPI-RPi-Pico.git 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "PicoMemcard", 6 | "device": "RP2040", 7 | "gdbPath": "gdb-multiarch", 8 | "cwd": "${workspaceRoot}", 9 | "executable": "${workspaceRoot}/build/PicoMemcard.elf", 10 | "preLaunchTask": "build", 11 | "request": "launch", 12 | "type": "cortex-debug", 13 | "servertype": "openocd", 14 | "configFiles": [ 15 | "interface/picoprobe.cfg", 16 | "target/rp2040.cfg" 17 | ], 18 | "openOCDLaunchCommands": [ 19 | "transport select swd", 20 | "adapter speed 4000" 21 | ], 22 | "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd", 23 | "runToEntryPoint": "main", 24 | "postRestartCommands": [ 25 | "break main", 26 | "continue" 27 | ] 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "type": "shell", 7 | "command": "cmake --build ${workspaceRoot}/build --config Debug --target all -j 10", 8 | "group": { 9 | "kind": "build", 10 | "isDefault": true 11 | } 12 | }, 13 | ] 14 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | set(PICO_BOARD pico_w) 4 | 5 | include(pico_sdk_import.cmake) 6 | 7 | project(picomemcard_project C CXX ASM) 8 | set(CMAKE_C_STANDARD 11) 9 | set(CMAKE_CXX_STANDARD 17) 10 | pico_sdk_init() 11 | 12 | add_executable(PicoMemcard) 13 | 14 | pico_set_linker_script(PicoMemcard ${CMAKE_SOURCE_DIR}/memmap.ld) 15 | pico_generate_pio_header(PicoMemcard ${CMAKE_CURRENT_LIST_DIR}/psxSPI.pio) 16 | pico_generate_pio_header(PicoMemcard ${CMAKE_CURRENT_LIST_DIR}/ws2812.pio) 17 | 18 | add_definitions(-DNO_PICO_LED) # prevent SD SPI library from using LED 19 | add_subdirectory(no-OS-FatFS-SD-SPI-RPi-Pico/FatFs_SPI PicoMemcard) 20 | add_subdirectory(poc_examples) 21 | 22 | # Example source 23 | target_sources(PicoMemcard PUBLIC 24 | ${CMAKE_SOURCE_DIR}/src/led.c 25 | ${CMAKE_SOURCE_DIR}/src/main.c 26 | ${CMAKE_SOURCE_DIR}/src/memcard_manager.c 27 | ${CMAKE_SOURCE_DIR}/src/memcard_simulator.c 28 | ${CMAKE_SOURCE_DIR}/src/memory_card.c 29 | ${CMAKE_SOURCE_DIR}/src/msc_handler.c 30 | ${CMAKE_SOURCE_DIR}/src/sd_config.c 31 | ${CMAKE_SOURCE_DIR}/src/usb_descriptors.c 32 | ) 33 | 34 | # Example include 35 | target_include_directories(PicoMemcard PUBLIC 36 | ${CMAKE_SOURCE_DIR}/inc 37 | ) 38 | 39 | pico_enable_stdio_uart(PicoMemcard 1) # enable only UART stdio 40 | 41 | target_link_libraries( 42 | PicoMemcard 43 | pico_stdlib 44 | pico_multicore 45 | pico_time 46 | hardware_pio 47 | tinyusb_device 48 | tinyusb_board 49 | FatFs_SPI 50 | 51 | pico_cyw43_arch_none # If you do not need the TCP/IP stack but wish to use the on-board LED on a Pico W 52 | hardware_adc 53 | ) 54 | 55 | pico_add_extra_outputs(PicoMemcard) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PicoMemcard 2 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/A0A2EH2DM) 3 | 4 | 5 | PicoMemcard allows you to build your own supercharged PSX Memory Card that can be connected to your computer via USB in order to transfer saves directly to/from your PSX. You can use it to repurpose broken/counterfeit Memory Cards creating a better one using only a Raspberry Pi Pico. 6 | 7 | ## Features 8 | * Able to faithfully simulate PSX Memory Card 9 | * USB connection to import/export saves 10 | * Allows to copy saves to/from any other memory card (using original PSX file manager) 11 | * Allows to play burned CDs (thanks to [FreePSXBoot]) 12 | * Cheaper than an original memory card 13 | * Can store hudreds of memory card images 14 | 15 | ## Bill of materials 16 | * **Raspberry Pi Pico** (around $5) 17 | * One of: 18 | * Custom [PicoMemcard PCB](#picomemcard-pcb) 19 | * Broken/Counterfeit/Original PSX Memory Card (counterfeit ones can be found on AliExpress for around $2-3) 20 | * PSX/PS2 Controller Cable 21 | * CAT5 network cable and a bit of creativity. 22 | 23 | Basically anything that will allow you to interface with the memory card slot pins will do. If you have a broken contoller you can cut off the cable and use that since controllers and memory cards share the same bus. Of course, plugging your memory card into the controller slot will prevent you from using 2 controllers at the same time. 24 | 25 | [This guy] assembled one using a 3d-printed plastic shell and simple CAT5 network cable. I belive this is the cheapest method anybody has come up with until now. 26 | 27 | In total building a PicoMemcard wil cost you less than buying a used original Memory Card! 28 | 29 | ## Video 30 | [![PicoMemcard](https://img.youtube.com/vi/sPZsESXcDcc/0.jpg)](https://youtu.be/sPZsESXcDcc) 31 | 32 | ## PicoMemcard PCB 33 | 34 | These are the custom PCBs designed and manufactured specifically for this application. They are not strictly required but make it much easier to build PicoMemcard since you don't need to cut up another memory card and all the soldering pads are easily accessible. All you need to do is to solder the Pico/RP2040-Zero on top of the PCB using a soldering iron. 35 | 36 | The Raspberry Pi Pico or RP2040-Zero must sit flush on top of the PCB, fortunately both the Pico and RP2040-Zero provide castellated holes that are easy to solder directly to the PCB's pads. You can use some electrical tape to hold the board in place while you solder the first pins. 37 | 38 | Custom PCBs 39 | 40 | I've created a new version of the original PCBs the major difference are: 41 | * The general size is smaller 42 | * A new micro SD card module is supported. This module is smaller, easier to solder and should solve some of the power related issues that were previously present 43 | * Is fitted for the installation of phisical switches used to switch memory card when PicoMemcard+ is used in systems that do not support switching via controller input (e.g. all PS2 models). 44 | 45 | The KiCad and Gerber files are available in the repository. If you want to support the project you can request a PCB [from here]. 46 | Keep in mind that with the PS2 support release that will eventually happen the PCB may undergo some additional changes before its design is finalized. 47 | 48 | ## PicoMemcard using Memory Card 49 | Raspberry Pi Pico and RP2040-Zero require different pin usage for full compatibility. 50 | 51 | The wiring diagrams below show how to build PicoMemcard by wiring respectively a Pico and an RP2040-Zero to a counterfeit memory card. For the other cases (wiring directly to the PSX or using a controller cable) the pins on Pico and RP2040-Zero are the same, the pinout of the PSX/controller can be found on [psx-spx]. The images show the bottom side of the memory card with the cover removed. 52 | 53 | Pico Wiring Diagram 54 | 55 | RP2040-Zero Wiring Diagram 56 | 57 | The dashed line on the PCB of the memory card is where you should cut a groove deep enough to disconnect the original circuitry from the traces. The yellow squares above the line indicate where you should scrape away the protective film in order to expose the copper traces and solder the wires onto them. 58 | 59 | Finally the area at the bottom of the memory card is where you can cut a hole to feed the wires through connecting them to the Pico. 60 | If you are using an RP2040-Zero you can also cut away part of the original Memory Card circuitry to fit it inside the original shell. 61 | 62 | The connections in the PicoMemcard+ area are optional and only required if you want to build **PicoMemcard+** (using the optional MicroSD expansion board). Also remember to connect both ground and power to your SD card module (see [MicroSD Module](#microsd-module-for-picomemcard) section for more information). 63 | 64 | ## PicoMemcard vs PicoMemcard+ 65 | Since some features cannot be implmented when using only a Pico/RP2040-Zero but require additional hardware, I've decided to split the project in two versions: 66 | * **PicoMemcard** simplest device to build, only requires a Raspberry Pi Pico / RP2040-Zero 67 | * **PicoMemcard+** more complex and powerful device. Supports additional features such as multiple memory card images but requires additional hardware (namely the MicroSD SPI expansion board). 68 | 69 | This approach was choosen because many people want a solution that is as cheap as possible and don't care about additional features. Conversely, others would like to have additional features even if it means spending a bit more money. 70 | 71 | The current release of PicoMemcard+ additionally to all the features of PicoMemcard supports: 72 | * Trasparent write-back: the sync operation performed to save new data no longer reults in the memory card appearing as if was briefly disconnected. 73 | * Multiple memory card image switchable through controller input. 74 | 75 | ## MicroSD Module for PicoMemcard+ 76 | There are many variations of MicroSD expansion boards with different pinouts and interfaces. The only requirement for PicoMemcard+ is that the module must provide an SPI interface. SPI interfaces have at least the following pins: 77 | * Chip Select (CS) (sometime also called Slave Select (SS)). 78 | * Clock (SCK or CLK). 79 | * Master Output Slave Input (MISO). 80 | * Master Input Slave Output (MOSI). 81 | 82 | In addition you will need to connect power and ground to your module, some modules are design to work with 5V others with 3.3V (or both), luckily for us both voltages are available on Pico and RP2040-Zero as shown in the schematic in the section [above](#picomemcard-using-memory-card). Some module provides additional pins that can be left disconnected. 83 | 84 | The new versions of the PCB are designed to use small modules such as this one: 85 | 86 | Smaller MicroSD SPI expansion board 87 | 88 | This is mainly due to the following reasons: 89 | * It comes withouth pre-soldered headers which makes it easier to solder onto the PicoMemcard PCB. 90 | * Its smaller form factor allows for more flexibility. 91 | * It should have less power issue than prevously used modules. 92 | 93 | A good source for these modules is Aliexpress, in general you can search for `MicroSD SPI Expansion Board` and buy the cheapest one you find. 94 | 95 | ## Installation 96 | 1. Download the latest [release] for your board (Raspberry Pi Pico and RP2040-Zero require different binaries). 97 | 2. While pressing the 'BOOTSEL' or 'BOOT' button on your board, plug it into your computer. 98 | 3. Drag and drop the PicoMemcard release onto your Raspberry Pi Pico. 99 | 4. PicoMemcard should appear on your PC as a USB drive. 100 | 5. Upload a memory card image to your PicoMemcard. 101 | 102 | ## Transfering Data 103 | Memory card images must be exactly 128KB (131072 bytes) in size. PicoMemcard and PicoMemcard+ only support files with `.MCR` extensions. However, `.MCR` and `.MCD` extensions are interchangable and can be converted to one another simply via renaming. 104 | For other file formats, try using [MemcardRex] for converting to the desired output. 105 | 106 | * **PicoMemcard** only supports a single image which must be named exactly `MEMCARD.MCR`. 107 | * **PicoMemcard+** supports hundreds of images. Each image must be named `N.MCR` where `N` is an integer number (e.g. `0.MCR`, `1.MCR`...). On boot your previously loaded image will be reloaded, unless it's a fresh card then `0.MCR` will be loaded. 108 | 109 | Inside `docs/images` you can find two memory card images. One has a couple of saves on it so you can test if everything works correctly, the other is completely empty. 110 | 111 | ## Switching/Creating Images 112 | On **PicoMemcard+** you can switch the active memory card image with the following inputs: 113 | * `START + SELECT + DPAD UP` will switch to the next image (e.g from `1.MCR` to `2.MCR`). 114 | * `START + SELECT + DPAD DOWN` will switch to the previous image (e.g from `1.MCR` to `0.MCR`). 115 | 116 | Additionally you can create a new empty memory card image (and automatically switch to it) by pressing `START + SELECT + TRIANGLE`. 117 | 118 | **Attention**: this method only works on PSX if the controller used to provide the input is plugged in the same slot as PicoMemcard (exactly under it). Using a controller from a different slot will have no effect. 119 | 120 | Additionally this method does not work on PS2 Memory Cards and Controllers are wired on a different bus. 121 | 122 | ## Syncing Changes 123 | Generally speaking, new data written to PicoMemcard (e.g. when you save) is permanently stored only after a short period of time (due to hardware limitation). The on board LED indicates whether all changes have been stored or not, in particular: 124 | * On Rapsbery Pi Pico the LED will be on when all changes have been saved, off otherwise. 125 | * On RP2040-Zero the LED will be solid green when all changes have been saved, red otherwise. 126 | 127 | Unlike **PicoMemcard+** that tries to write new changes as soon as possible, **PicoMemcard** will generally do it only after a period of inactivity (around 5 seconds). If you want to force **PicoMemcard** to immediately sync you can press `START + SELECT + TRIANGLE`. 128 | 129 | **Attention**: after you save your game, make sure to wait for the LED to be solid green before turning off the console otherwise you might lose your more recent progress! 130 | 131 | ## 3D-Printed Case 132 | I've finally designed a 3D-printable case for the different PicoMemcard PCBs. It helps inserting correctly the PCB and ensuring that the the connection to the PSX is optimal. The same result, albeit more janky, can be achieved using a folded sheet of paper as a spacer. 133 | 134 | Model of 3D-printed case 135 | 136 | PicoMemcard in Action! 137 | 138 | The cases are designed following a minimalistic approach, they consist of a single piece which holds tightly the PCB using very small clips without requiring any additional hardware. To assemble it, simply slide in the PCB from the back of the case (opposite to the side connecting to the PSX). Cases for the fullsize PCB are designed to support the MicroSD expansion module. 139 | 140 | Here is the download for the STL files: 141 | * [Design by DanGiu](https://www.thingiverse.com/thing:5488778) 142 | 143 | If you don't like this case you can check out other designs many people have already created! I've not tested them personally but here they are: 144 | * [Design by brik1111](https://www.thingiverse.com/thing:5453156) 145 | * [Design by bbsan2k](https://www.thingiverse.com/thing:5460187) 146 | 147 | ## Troubleshooting and LED Indicator 148 | Generally speaking the onboard LED will provide a pretty good indication regarding the status of PicoMemcard. 149 | 150 | In particular, the RP2040-Zero has RGB LED that provides a more clear output. The Pico on the other hand as only a green LED and different blinking patterns indicate different statuses. 151 | 152 | ### PicoMemcard Status 153 | | Status | Pico | RP2040-Zero 154 | | --- | --- | --- | 155 | | Failed to read memory card image | Slow blinking led | Red blinking led 156 | | Data not fully synced (do not turn off PSX)| Led off | Red led (or flashing red and green) | 157 | | Data synced | Led on | Green solid led | 158 | 159 | ### PicoMemcard+ Status 160 | | Status | Pico | RP2040-Zero 161 | | --- | --- | --- | 162 | | Failed to read SD card | Blinking led | Red blinking led 163 | | Data not fully synced (do not turn off PSX)| Led off | Red led (or flashing red and green) | 164 | | Data synced | Led on | Green solid led | 165 | | Memory Card image changed | Three fast blinks | Single blue blink | 166 | | Memory Card image not changed (end of list) | Nine fast blinks | Single orange blink | 167 | | New Memory Card image created | Multiple very fast blinks | Single light blue blink | 168 | 169 | ## General Warnings 170 | I would recommend to never plug PicoMemcard both into the PC (via USB) and the PSX at the same time! Otherwise the 5V provided by USB would end up on the 3.3V rail of the PSX. I'm not really sure if this could cause actual damage but I would avoid risking it. 171 | 172 | If you really need to have the Pico plugged into both the USB and PSX (e.g. for debugging purposes), disconnect the 3.3V line from the VBUS pin. In this way you can power on the Pico using a simple USB phone charger or by plugging it into your PC. 173 | 174 | As a disclamer, I don't take any responsability for what will happen to your console when using PicoMemcard/PicoMemcard+. 175 | 176 | ## Project Updates 177 | ### 5 February 2023 178 | Sorry everybody but I've been quite inactive on the project lately. Due to a change of job IRL I have less time to work for the moment. 179 | Anyway, behind the scenes I've been trying to add support for PS2 memory card but I'm afraid that will require the addition of an extra hardware component unless I am able to develop an efficient cacheing mechanisms or something similar. Anyway I'll keep working on it when I have free time. I have in mind many improvement for the project and I think the future of it is going to be exciting. 180 | 181 | Special thanks to everybody that supported it so far! You are all amazing. 182 | 183 | ## Design 184 | For people interested in understanding how PicoMemcard works I provide a more extensive explanation in [this post] (although now somewhat outdated). 185 | 186 | ## Thanks To 187 | * [psx-spx] and Martin "NO$PSX" Korth - PlayStation Specifications and documented Memory Card protocol and filesystem. 188 | * [Andrew J. McCubbin] - Additional information about Memory Card and Controller communication with PSX. 189 | * [littlefs] - Filesystem designed to work on NOR flash used by many microcontrollers, including the Raspberry Pi Pico. 190 | * [ChaN FatFS] - FAT filesystem implementation for embedded devices. 191 | * [Scoppy] - Use your Raspberry Pi Pico as an oscilloscope, very cheap and accurate. Without this I would have not been able to debug many issues. 192 | * [PulseView] - Used to import, visualize and manipulate the data from Scoppy on a PC. 193 | 194 | [FreePSXBoot]: https://github.com/brad-lin/FreePSXBoot 195 | [psx-spx]: https://psx-spx.consoledev.net/pinouts/#controller-ports-and-memory-card-ports 196 | [Andrew J. McCubbin]: http://www.emudocs.org/PlayStation/psxcont/ 197 | [littlefs]: https://github.com/littlefs-project/littlefs 198 | [ChaN FatFS]: http://elm-chan.org/fsw/ff/00index_e.html 199 | [Scoppy]: https://github.com/fhdm-dev/scoppy 200 | [PulseView]: https://sigrok.org/wiki/PulseView 201 | [release]: https://github.com/dangiu/PicoMemcard/releases/latest 202 | [this post]: https://dangiu.github.io/2022/05/13/picomemcard.html 203 | [from here]: https://forms.gle/f6XHtz6W5fn5qDZV7 204 | [This guy]: https://github.com/MrSVCD/PicoPSX_3D 205 | [MemcardRex]: https://github.com/ShendoXT/memcardrex -------------------------------------------------------------------------------- /docs/case-models.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangiu/PicoMemcard/9ea646810366574740b03e3211b655de870a03dc/docs/case-models.png -------------------------------------------------------------------------------- /docs/githubbutton_pp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 11 | 12 | Created with Sketch. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 26 | 29 | 32 | 36 | 38 | 43 | 46 | 49 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/images/EmptyMemoryCard/MEMCARD.MCR: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangiu/PicoMemcard/9ea646810366574740b03e3211b655de870a03dc/docs/images/EmptyMemoryCard/MEMCARD.MCR -------------------------------------------------------------------------------- /docs/images/SampleMemoryCard/MEMCARD.MCR: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangiu/PicoMemcard/9ea646810366574740b03e3211b655de870a03dc/docs/images/SampleMemoryCard/MEMCARD.MCR -------------------------------------------------------------------------------- /docs/mini-spi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangiu/PicoMemcard/9ea646810366574740b03e3211b655de870a03dc/docs/mini-spi.png -------------------------------------------------------------------------------- /docs/pcb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangiu/PicoMemcard/9ea646810366574740b03e3211b655de870a03dc/docs/pcb.png -------------------------------------------------------------------------------- /docs/picomemcard-in-action.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangiu/PicoMemcard/9ea646810366574740b03e3211b655de870a03dc/docs/picomemcard-in-action.jpg -------------------------------------------------------------------------------- /inc/config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | /* Global configuration options for PicoMemcard */ 5 | #define TUD_MOUNT_TIMEOUT 3000 // max time (in ms) before giving up on MSC mode (USB) and starting memcard simulation 6 | #define MSC_WRITE_SYNC_TIMEOUT 1 * 1000 // time (in ms) expired since last MSC write before exporting RAM disk into LFS 7 | #define IDLE_AUTOSYNC_TIMEOUT 5 * 1000 // time (in ms) the memory card must be inactive before automatic sync from RAM to LFS 8 | #define MAX_MC_FILENAME_LEN 32 // max length of memory card file name (including extension) 9 | #define MAX_MC_IMAGES 255 // maximum number of different mc images 10 | #define MC_RECONNECT_TIME 1000 // time (in ms) the memory card stays disconnected when simulating reconnection 11 | 12 | /* Board targeted by build */ 13 | #define PICO 14 | //#define RP2040ZERO 15 | 16 | /* Invert red and green. Uncomment this if the LED colours for your RP2040 Zero are incorrect. */ 17 | #define INVERT_RED_GREEN 18 | 19 | /* PSX Interface Pinout */ 20 | #ifdef PICO // TODO remove/find way to include this into pio code 21 | //#define PIN_DAT 5 22 | //#define PIN_CMD PIN_DAT + 1 // must be immediately after PIN_DAT 23 | //#define PIN_SEL PIN_CMD + 1 // must be immediately after PIN_CMD 24 | //#define PIN_CLK PIN_SEL + 1 // must be immediately after PIN_SEL 25 | //#define PIN_ACK 9 26 | #endif 27 | 28 | #ifdef RP2040ZERO // TODO remove/find way to include this into pio code 29 | #define PIN_DAT 9 30 | #define PIN_CMD PIN_DAT + 1 // must be immediately after PIN_DAT 31 | #define PIN_SEL PIN_CMD + 1 // must be immediately after PIN_CMD 32 | #define PIN_CLK PIN_SEL + 1 // must be immediately after PIN_SEL 33 | #define PIN_ACK 13 34 | #endif 35 | 36 | /* SD Card Configuration */ 37 | #define BLOCK_SIZE 512 // SD card communicate using only 512 block size for consistency 38 | #define BAUD_RATE 5000 * 1000 39 | #ifdef PICO 40 | #define PIN_MISO 16 41 | #define PIN_MOSI 19 42 | #define PIN_SCK 18 43 | #define PIN_SS 17 44 | #endif 45 | 46 | #ifdef RP2040ZERO 47 | #define PIN_MISO 0 48 | #define PIN_MOSI 3 49 | #define PIN_SCK 2 50 | #define PIN_SS 1 51 | #endif 52 | 53 | #endif -------------------------------------------------------------------------------- /inc/led.h: -------------------------------------------------------------------------------- 1 | #ifndef __LED_H__ 2 | #define __LED_H__ 3 | 4 | #include "pico/stdlib.h" 5 | 6 | void led_init(); 7 | void led_output_sync_status(bool out_of_sync); 8 | void led_blink_error(int amount); 9 | void led_output_mc_change(); 10 | void led_output_end_mc_list(); 11 | void led_output_new_mc(); 12 | 13 | int32_t is_pico_w(); 14 | void init_led(uint32_t pin); 15 | void set_led(uint32_t pin, uint32_t level); 16 | 17 | #endif -------------------------------------------------------------------------------- /inc/memcard_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMCARD_MANAGER_H__ 2 | #define __MEMCARD_MANAGER_H__ 3 | 4 | #include 5 | #include 6 | 7 | /* Error codes */ 8 | #define MM_OK 0 9 | #define MM_ALLOC_FAIL 1 10 | #define MM_INDEX_OUT_OF_BOUNDS 2 11 | #define MM_NO_ENTRY 3 12 | #define MM_BAD_PARAM 4 13 | #define MM_NAME_CONFLICT 5 14 | #define MM_FILE_OPEN_ERR 6 15 | #define MM_FILE_WRITE_ERR 7 16 | 17 | bool memcard_manager_exist(uint8_t* filename); 18 | uint32_t memcard_manager_count(); 19 | uint32_t memcard_manager_get(uint32_t index, uint8_t* out_filename); 20 | #define memcard_manager_get_initial(out_filename) memcard_manager_get(memcard_manager_get_prev_loaded_memcard_index(), (out_filename)) 21 | uint32_t memcard_manager_get_prev_loaded_memcard_index(); 22 | uint32_t memcard_manager_get_next(uint8_t* filename, uint8_t* out_nextfile); 23 | uint32_t memcard_manager_get_prev(uint8_t* filename, uint8_t* out_prevfile); 24 | uint32_t memcard_manager_create(uint8_t* out_filename); 25 | 26 | #endif -------------------------------------------------------------------------------- /inc/memcard_simulator.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef __MEMCARD_SIMULATOR_H__ 4 | #define __MEMCARD_SIMULATOR_H__ 5 | 6 | _Noreturn 7 | int simulate_memory_card(); 8 | 9 | #endif -------------------------------------------------------------------------------- /inc/memory_card.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMORY_CARD_H 2 | #define __MEMORY_CARD_H 3 | 4 | #include 5 | #include 6 | #include "config.h" 7 | 8 | #define MC_SEC_SIZE 128 // size of single sector in bytes 9 | #define MC_SEC_COUNT 1024 // number of sector in one memory card 10 | #define MC_SIZE MC_SEC_SIZE * MC_SEC_COUNT // size of memory card in bytes 11 | #define MC_FLAG_BYTE_DEF 0x08 // bit 3 set = new memory card inserted 12 | 13 | #define MC_ID1 0x5A 14 | #define MC_ID2 0x5D 15 | #define MC_ACK1 0x5C 16 | #define MC_ACK2 0x5D 17 | #define MC_TEST_SEC 0x3f // sector 63 is the "write test" sector 18 | 19 | #define MC_GOOD 0x47 20 | #define MC_BAD_SEC 0xFF 21 | #define MC_BAD_CHK 0x4E 22 | 23 | /* Error codes */ 24 | #define MC_OK 0 25 | #define MC_FILE_OPEN_ERR 1 26 | #define MC_FILE_READ_ERR 2 27 | #define MC_FILE_WRITE_ERR 3 28 | #define MC_FILE_SIZE_ERR 4 29 | #define MC_NO_INIT 5 30 | 31 | typedef struct { 32 | uint8_t flag_byte; 33 | uint8_t* data; 34 | } memory_card_t; 35 | 36 | typedef uint16_t sector_t; 37 | 38 | uint32_t memory_card_init(memory_card_t* mc); 39 | uint32_t memory_card_import(memory_card_t* mc, uint8_t* file_name); 40 | bool memory_card_is_sector_valid(memory_card_t* mc, sector_t sector); 41 | uint8_t* memory_card_get_sector_ptr(memory_card_t* mc, sector_t sector); 42 | void memory_card_reset_seen_flag(memory_card_t* mc); 43 | uint32_t memory_card_sync_sector(memory_card_t* mc, sector_t sector, uint8_t* file_name); 44 | 45 | #endif -------------------------------------------------------------------------------- /inc/pad.h: -------------------------------------------------------------------------------- 1 | #ifndef __PAD_H__ 2 | #define __PAD_H__ 3 | 4 | /* PSX Digital Controller bit position - 0 when pressed, 1 when released */ 5 | #define SELECT_POS 0 6 | #define L3_POS 1 // analog mode only 7 | #define R3_POS 2 // analog mode only 8 | #define START_POS 3 9 | #define UP_POS 4 10 | #define RIGHT_POS 5 11 | #define DOWN_POS 6 12 | #define LEFT_POS 7 13 | #define L2_POS 8 14 | #define R2_POS 9 15 | #define L1_POS 10 16 | #define R1_POS 11 17 | #define TRIANGLE_POS 12 18 | #define CIRCLE_POS 13 19 | #define X_POS 14 20 | #define SQUARE_POS 15 21 | 22 | #define SELECT (uint16_t) ~(1 << SELECT_POS) 23 | #define L3 (uint16_t) ~(1 << L3_POS) 24 | #define R3 (uint16_t) ~(1 << R3_POS) 25 | #define START (uint16_t) ~(1 << START_POS) 26 | #define UP (uint16_t) ~(1 << UP_POS) 27 | #define RIGHT (uint16_t) ~(1 << RIGHT_POS) 28 | #define DOWN (uint16_t) ~(1 << DOWN_POS) 29 | #define LEFT (uint16_t) ~(1 << LEFT_POS) 30 | #define L2 (uint16_t) ~(1 << L2_POS) 31 | #define R2 (uint16_t) ~(1 << R2_POS) 32 | #define L1 (uint16_t) ~(1 << L1_POS) 33 | #define R1 (uint16_t) ~(1 << R1_POS) 34 | #define TRIANGLE (uint16_t) ~(1 << TRIANGLE_POS) 35 | #define CIRCLE (uint16_t) ~(1 << CIRCLE_POS) 36 | #define X (uint16_t) ~(1 << X_POS) 37 | #define SQUARE (uint16_t) ~(1 << SQUARE_POS) 38 | 39 | #endif -------------------------------------------------------------------------------- /inc/sd_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ff.h" 4 | #include "sd_card.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | size_t sd_get_num(); 11 | sd_card_t *sd_get_by_num(size_t num); 12 | 13 | size_t spi_get_num(); 14 | spi_t *spi_get_by_num(size_t num); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /inc/tusb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Ha Thach (tinyusb.org) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #ifndef _TUSB_CONFIG_H_ 27 | #define _TUSB_CONFIG_H_ 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | //-------------------------------------------------------------------- 34 | // COMMON CONFIGURATION 35 | //-------------------------------------------------------------------- 36 | 37 | // defined by board.mk 38 | #ifndef CFG_TUSB_MCU 39 | #error CFG_TUSB_MCU must be defined 40 | #endif 41 | 42 | // RHPort number used for device can be defined by board.mk, default to port 0 43 | #ifndef BOARD_DEVICE_RHPORT_NUM 44 | #define BOARD_DEVICE_RHPORT_NUM 0 45 | #endif 46 | 47 | // RHPort max operational speed can defined by board.mk 48 | // Default to max (auto) speed for MCU with internal HighSpeed PHY 49 | #ifndef BOARD_DEVICE_RHPORT_SPEED 50 | #define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED 51 | #endif 52 | 53 | // Device mode with rhport and speed defined by board.mk 54 | #if BOARD_DEVICE_RHPORT_NUM == 0 55 | #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) 56 | #elif BOARD_DEVICE_RHPORT_NUM == 1 57 | #define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED) 58 | #else 59 | #error "Incorrect RHPort configuration" 60 | #endif 61 | 62 | // This example doesn't use an RTOS 63 | #ifndef CFG_TUSB_OS 64 | #define CFG_TUSB_OS OPT_OS_NONE 65 | #endif 66 | 67 | // CFG_TUSB_DEBUG is defined by compiler in DEBUG build 68 | // #define CFG_TUSB_DEBUG 0 69 | 70 | /* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. 71 | * Tinyusb use follows macros to declare transferring memory so that they can be put 72 | * into those specific section. 73 | * e.g 74 | * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") )) 75 | * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4))) 76 | */ 77 | #ifndef CFG_TUSB_MEM_SECTION 78 | #define CFG_TUSB_MEM_SECTION 79 | #endif 80 | 81 | #ifndef CFG_TUSB_MEM_ALIGN 82 | #define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) 83 | #endif 84 | 85 | //-------------------------------------------------------------------- 86 | // DEVICE CONFIGURATION 87 | //-------------------------------------------------------------------- 88 | 89 | #ifndef CFG_TUD_ENDPOINT0_SIZE 90 | #define CFG_TUD_ENDPOINT0_SIZE 64 91 | #endif 92 | 93 | //------------- CLASS -------------// 94 | #define CFG_TUD_CDC 1 95 | #define CFG_TUD_MSC 1 96 | #define CFG_TUD_HID 0 97 | #define CFG_TUD_MIDI 0 98 | #define CFG_TUD_VENDOR 0 99 | 100 | // CDC FIFO size of TX and RX 101 | #define CFG_TUD_CDC_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) 102 | #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) 103 | 104 | // CDC Endpoint transfer buffer size, more is faster 105 | #define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) 106 | 107 | // MSC Buffer size of Device Mass storage 108 | #define CFG_TUD_MSC_EP_BUFSIZE 512 109 | 110 | #ifdef __cplusplus 111 | } 112 | #endif 113 | 114 | #endif /* _TUSB_CONFIG_H_ */ 115 | -------------------------------------------------------------------------------- /memmap.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 = 0x20000000, LENGTH = 256k 28 | SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k 29 | SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k 30 | } 31 | 32 | ENTRY(_entry_point) 33 | 34 | SECTIONS 35 | { 36 | /* Second stage bootloader is prepended to the image. It must be 256 bytes big 37 | and checksummed. It is usually built by the boot_stage2 target 38 | in the Raspberry Pi Pico SDK 39 | */ 40 | 41 | .flash_begin : { 42 | __flash_binary_start = .; 43 | } > FLASH 44 | 45 | .boot2 : { 46 | __boot2_start__ = .; 47 | KEEP (*(.boot2)) 48 | __boot2_end__ = .; 49 | } > FLASH 50 | 51 | ASSERT(__boot2_end__ - __boot2_start__ == 256, 52 | "ERROR: Pico second stage bootloader must be 256 bytes in size") 53 | 54 | /* The second stage will always enter the image at the start of .text. 55 | The debugger will use the ELF entry point, which is the _entry_point 56 | symbol if present, otherwise defaults to start of .text. 57 | This can be used to transfer control back to the bootrom on debugger 58 | launches only, to perform proper flash setup. 59 | */ 60 | 61 | .text : { 62 | __logical_binary_start = .; 63 | KEEP (*(.vectors)) 64 | KEEP (*(.binary_info_header)) 65 | __binary_info_header_end = .; 66 | KEEP (*(.reset)) 67 | /* TODO revisit this now memset/memcpy/float in ROM */ 68 | /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from 69 | * FLASH ... we will include any thing excluded here in .data below by default */ 70 | *(.init) 71 | *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*) 72 | *(.fini) 73 | /* Pull all c'tors into .text */ 74 | *crtbegin.o(.ctors) 75 | *crtbegin?.o(.ctors) 76 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) 77 | *(SORT(.ctors.*)) 78 | *(.ctors) 79 | /* Followed by destructors */ 80 | *crtbegin.o(.dtors) 81 | *crtbegin?.o(.dtors) 82 | *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) 83 | *(SORT(.dtors.*)) 84 | *(.dtors) 85 | 86 | *(.eh_frame*) 87 | . = ALIGN(4); 88 | } > FLASH 89 | 90 | .rodata : { 91 | *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*) 92 | . = ALIGN(4); 93 | *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*))) 94 | . = ALIGN(4); 95 | } > FLASH 96 | 97 | .ARM.extab : 98 | { 99 | *(.ARM.extab* .gnu.linkonce.armextab.*) 100 | } > FLASH 101 | 102 | __exidx_start = .; 103 | .ARM.exidx : 104 | { 105 | *(.ARM.exidx* .gnu.linkonce.armexidx.*) 106 | } > FLASH 107 | __exidx_end = .; 108 | 109 | /* Machine inspectable binary information */ 110 | . = ALIGN(4); 111 | __binary_info_start = .; 112 | .binary_info : 113 | { 114 | KEEP(*(.binary_info.keep.*)) 115 | *(.binary_info.*) 116 | } > FLASH 117 | __binary_info_end = .; 118 | . = ALIGN(4); 119 | 120 | /* End of .text-like segments */ 121 | __etext = .; 122 | 123 | .ram_vector_table (COPY): { 124 | *(.ram_vector_table) 125 | } > RAM 126 | 127 | .data : { 128 | __data_start__ = .; 129 | *(vtable) 130 | 131 | *(.time_critical*) 132 | 133 | /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */ 134 | *(.text*) 135 | . = ALIGN(4); 136 | *(.rodata*) 137 | . = ALIGN(4); 138 | 139 | *(.data*) 140 | 141 | . = ALIGN(4); 142 | *(.after_data.*) 143 | . = ALIGN(4); 144 | /* preinit data */ 145 | PROVIDE_HIDDEN (__mutex_array_start = .); 146 | KEEP(*(SORT(.mutex_array.*))) 147 | KEEP(*(.mutex_array)) 148 | PROVIDE_HIDDEN (__mutex_array_end = .); 149 | 150 | . = ALIGN(4); 151 | /* preinit data */ 152 | PROVIDE_HIDDEN (__preinit_array_start = .); 153 | KEEP(*(SORT(.preinit_array.*))) 154 | KEEP(*(.preinit_array)) 155 | PROVIDE_HIDDEN (__preinit_array_end = .); 156 | 157 | . = ALIGN(4); 158 | /* init data */ 159 | PROVIDE_HIDDEN (__init_array_start = .); 160 | KEEP(*(SORT(.init_array.*))) 161 | KEEP(*(.init_array)) 162 | PROVIDE_HIDDEN (__init_array_end = .); 163 | 164 | . = ALIGN(4); 165 | /* finit data */ 166 | PROVIDE_HIDDEN (__fini_array_start = .); 167 | *(SORT(.fini_array.*)) 168 | *(.fini_array) 169 | PROVIDE_HIDDEN (__fini_array_end = .); 170 | 171 | *(.jcr) 172 | . = ALIGN(4); 173 | /* All data end */ 174 | __data_end__ = .; 175 | } > RAM AT> FLASH 176 | 177 | .uninitialized_data (COPY): { 178 | . = ALIGN(4); 179 | *(.uninitialized_data*) 180 | } > RAM 181 | 182 | /* Start and end symbols must be word-aligned */ 183 | .scratch_x : { 184 | __scratch_x_start__ = .; 185 | *(.scratch_x.*) 186 | . = ALIGN(4); 187 | __scratch_x_end__ = .; 188 | } > SCRATCH_X AT > FLASH 189 | __scratch_x_source__ = LOADADDR(.scratch_x); 190 | 191 | .scratch_y : { 192 | __scratch_y_start__ = .; 193 | *(.scratch_y.*) 194 | . = ALIGN(4); 195 | __scratch_y_end__ = .; 196 | } > SCRATCH_Y AT > FLASH 197 | __scratch_y_source__ = LOADADDR(.scratch_y); 198 | 199 | .bss : { 200 | . = ALIGN(4); 201 | __bss_start__ = .; 202 | *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*))) 203 | *(COMMON) 204 | . = ALIGN(4); 205 | __bss_end__ = .; 206 | } > RAM 207 | 208 | .heap (COPY): 209 | { 210 | __end__ = .; 211 | end = __end__; 212 | *(.heap*) 213 | __HeapLimit = .; 214 | } > RAM 215 | 216 | /* .stack*_dummy section doesn't contains any symbols. It is only 217 | * used for linker to calculate size of stack sections, and assign 218 | * values to stack symbols later 219 | * 220 | * stack1 section may be empty/missing if platform_launch_core1 is not used */ 221 | 222 | /* by default we put core 0 stack at the end of scratch Y, so that if core 1 223 | * stack is not used then all of SCRATCH_X is free. 224 | */ 225 | .stack1_dummy (COPY): 226 | { 227 | *(.stack1*) 228 | } > SCRATCH_X 229 | .stack_dummy (COPY): 230 | { 231 | *(.stack*) 232 | } > SCRATCH_Y 233 | 234 | .flash_end : { 235 | __flash_binary_end = .; 236 | } > FLASH 237 | 238 | /** 239 | * COPY makes it so that we don't allocate memory for this section, 240 | * we only need this to check if we have enough flash left. 241 | * Avoiding allocating this section means that the resulting binary is much smaller 242 | */ 243 | .lfs (COPY) : { 244 | . = ALIGN(4096); /* align to flash sector */ 245 | __lfs_start = .; 246 | KEEP (*(.lfs)) 247 | __lfs_end = .; 248 | } > FLASH 249 | 250 | /* stack limit is poorly named, but historically is maximum heap ptr */ 251 | __StackLimit = ORIGIN(RAM) + LENGTH(RAM); 252 | __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X); 253 | __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y); 254 | __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy); 255 | __StackBottom = __StackTop - SIZEOF(.stack_dummy); 256 | PROVIDE(__stack = __StackTop); 257 | 258 | /* Check if data + heap + stack exceeds RAM limit */ 259 | ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed") 260 | 261 | ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary") 262 | /* todo assert on extra code */ 263 | } 264 | 265 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-B_Mask.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:52+01:00*% 3 | %TF.ProjectId,PicoMemcard-pico,5069636f-4d65-46d6-9361-72642d706963,1.1.2*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Soldermask,Bot*% 6 | %TF.FilePolarity,Negative*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:52* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10C,2.200000*% 15 | %ADD11O,1.500000X1.500000*% 16 | %ADD12O,1.800000X1.800000*% 17 | %ADD13O,1.700000X1.700000*% 18 | %ADD14R,1.700000X1.700000*% 19 | %ADD15O,1.800000X4.000000*% 20 | %ADD16R,1.000000X1.700000*% 21 | G04 APERTURE END LIST* 22 | D10* 23 | %TO.C,M2*% 24 | X133350000Y-75438000D03* 25 | %TD*% 26 | %TO.C,M2*% 27 | X164846000Y-124968000D03* 28 | %TD*% 29 | D11* 30 | %TO.C,U1*% 31 | X146673000Y-122062000D03* 32 | D12* 33 | X151823000Y-125092000D03* 34 | D11* 35 | X151523000Y-122062000D03* 36 | D12* 37 | X146373000Y-125092000D03* 38 | D13* 39 | X151638000Y-77192000D03* 40 | D14* 41 | X149098000Y-77192000D03* 42 | D13* 43 | X146558000Y-77192000D03* 44 | %TD*% 45 | D15* 46 | %TO.C,J2*% 47 | X147150000Y-109948000D03* 48 | X149650000Y-109948000D03* 49 | X152150000Y-109948000D03* 50 | X154650000Y-109948000D03* 51 | X157150000Y-109948000D03* 52 | X159650000Y-109948000D03* 53 | %TD*% 54 | D16* 55 | %TO.C,1*% 56 | X140280000Y-105916000D03* 57 | X140280000Y-99316000D03* 58 | X136580000Y-105916000D03* 59 | X136580000Y-99316000D03* 60 | %TD*% 61 | %TO.C,2*% 62 | X140280000Y-115568000D03* 63 | X140280000Y-108968000D03* 64 | X136580000Y-115568000D03* 65 | X136580000Y-108968000D03* 66 | %TD*% 67 | %TO.C,3*% 68 | X140280000Y-125220000D03* 69 | X140280000Y-118620000D03* 70 | X136580000Y-125220000D03* 71 | X136580000Y-118620000D03* 72 | %TD*% 73 | M02* 74 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-B_Paste.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:52+01:00*% 3 | %TF.ProjectId,PicoMemcard-pico,5069636f-4d65-46d6-9361-72642d706963,1.1.2*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Paste,Bot*% 6 | %TF.FilePolarity,Positive*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:52* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10O,1.800000X4.000000*% 15 | %ADD11R,1.000000X1.700000*% 16 | G04 APERTURE END LIST* 17 | D10* 18 | %TO.C,J2*% 19 | X147150000Y-109948000D03* 20 | X149650000Y-109948000D03* 21 | X152150000Y-109948000D03* 22 | X154650000Y-109948000D03* 23 | X157150000Y-109948000D03* 24 | X159650000Y-109948000D03* 25 | %TD*% 26 | D11* 27 | %TO.C,1*% 28 | X140280000Y-105916000D03* 29 | X140280000Y-99316000D03* 30 | X136580000Y-105916000D03* 31 | X136580000Y-99316000D03* 32 | %TD*% 33 | %TO.C,2*% 34 | X140280000Y-115568000D03* 35 | X140280000Y-108968000D03* 36 | X136580000Y-115568000D03* 37 | X136580000Y-108968000D03* 38 | %TD*% 39 | %TO.C,3*% 40 | X140280000Y-125220000D03* 41 | X140280000Y-118620000D03* 42 | X136580000Y-125220000D03* 43 | X136580000Y-118620000D03* 44 | %TD*% 45 | M02* 46 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-B_Silkscreen.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:52+01:00*% 3 | %TF.ProjectId,PicoMemcard-pico,5069636f-4d65-46d6-9361-72642d706963,1.1.2*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Legend,Bot*% 6 | %TF.FilePolarity,Positive*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:52* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10C,0.150000*% 15 | %ADD11C,0.100000*% 16 | %ADD12C,0.120000*% 17 | %ADD13C,0.250000*% 18 | %ADD14C,0.160000*% 19 | G04 APERTURE END LIST* 20 | D10* 21 | %TO.C,J2*% 22 | X159002380Y-117914666D02* 23 | X159716666Y-117914666D01* 24 | X159859523Y-117867047D01* 25 | X159954761Y-117771809D01* 26 | X160002380Y-117628952D01* 27 | X160002380Y-117533714D01* 28 | X159097619Y-118343238D02* 29 | X159050000Y-118390857D01* 30 | X159002380Y-118486095D01* 31 | X159002380Y-118724190D01* 32 | X159050000Y-118819428D01* 33 | X159097619Y-118867047D01* 34 | X159192857Y-118914666D01* 35 | X159288095Y-118914666D01* 36 | X159430952Y-118867047D01* 37 | X160002380Y-118295619D01* 38 | X160002380Y-118914666D01* 39 | D11* 40 | X156923809Y-114133714D02* 41 | X157423809Y-114133714D01* 42 | X157066666Y-113967047D01* 43 | X157423809Y-113800380D01* 44 | X156923809Y-113800380D01* 45 | X156923809Y-113562285D02* 46 | X157423809Y-113562285D01* 47 | X156947619Y-113348000D02* 48 | X156923809Y-113276571D01* 49 | X156923809Y-113157523D01* 50 | X156947619Y-113109904D01* 51 | X156971428Y-113086095D01* 52 | X157019047Y-113062285D01* 53 | X157066666Y-113062285D01* 54 | X157114285Y-113086095D01* 55 | X157138095Y-113109904D01* 56 | X157161904Y-113157523D01* 57 | X157185714Y-113252761D01* 58 | X157209523Y-113300380D01* 59 | X157233333Y-113324190D01* 60 | X157280952Y-113348000D01* 61 | X157328571Y-113348000D01* 62 | X157376190Y-113324190D01* 63 | X157400000Y-113300380D01* 64 | X157423809Y-113252761D01* 65 | X157423809Y-113133714D01* 66 | X157400000Y-113062285D01* 67 | X157423809Y-112752761D02* 68 | X157423809Y-112657523D01* 69 | X157400000Y-112609904D01* 70 | X157352380Y-112562285D01* 71 | X157257142Y-112538476D01* 72 | X157090476Y-112538476D01* 73 | X156995238Y-112562285D01* 74 | X156947619Y-112609904D01* 75 | X156923809Y-112657523D01* 76 | X156923809Y-112752761D01* 77 | X156947619Y-112800380D01* 78 | X156995238Y-112848000D01* 79 | X157090476Y-112871809D01* 80 | X157257142Y-112871809D01* 81 | X157352380Y-112848000D01* 82 | X157400000Y-112800380D01* 83 | X157423809Y-112752761D01* 84 | X147423809Y-113943238D02* 85 | X147423809Y-113633714D01* 86 | X147233333Y-113800380D01* 87 | X147233333Y-113728952D01* 88 | X147209523Y-113681333D01* 89 | X147185714Y-113657523D01* 90 | X147138095Y-113633714D01* 91 | X147019047Y-113633714D01* 92 | X146971428Y-113657523D01* 93 | X146947619Y-113681333D01* 94 | X146923809Y-113728952D01* 95 | X146923809Y-113871809D01* 96 | X146947619Y-113919428D01* 97 | X146971428Y-113943238D01* 98 | X147257142Y-113467047D02* 99 | X146923809Y-113348000D01* 100 | X147257142Y-113228952D01* 101 | X147423809Y-113086095D02* 102 | X147423809Y-112776571D01* 103 | X147233333Y-112943238D01* 104 | X147233333Y-112871809D01* 105 | X147209523Y-112824190D01* 106 | X147185714Y-112800380D01* 107 | X147138095Y-112776571D01* 108 | X147019047Y-112776571D01* 109 | X146971428Y-112800380D01* 110 | X146947619Y-112824190D01* 111 | X146923809Y-112871809D01* 112 | X146923809Y-113014666D01* 113 | X146947619Y-113062285D01* 114 | X146971428Y-113086095D01* 115 | X154547619Y-113990857D02* 116 | X154523809Y-113919428D01* 117 | X154523809Y-113800380D01* 118 | X154547619Y-113752761D01* 119 | X154571428Y-113728952D01* 120 | X154619047Y-113705142D01* 121 | X154666666Y-113705142D01* 122 | X154714285Y-113728952D01* 123 | X154738095Y-113752761D01* 124 | X154761904Y-113800380D01* 125 | X154785714Y-113895619D01* 126 | X154809523Y-113943238D01* 127 | X154833333Y-113967047D01* 128 | X154880952Y-113990857D01* 129 | X154928571Y-113990857D01* 130 | X154976190Y-113967047D01* 131 | X155000000Y-113943238D01* 132 | X155023809Y-113895619D01* 133 | X155023809Y-113776571D01* 134 | X155000000Y-113705142D01* 135 | X154571428Y-113205142D02* 136 | X154547619Y-113228952D01* 137 | X154523809Y-113300380D01* 138 | X154523809Y-113348000D01* 139 | X154547619Y-113419428D01* 140 | X154595238Y-113467047D01* 141 | X154642857Y-113490857D01* 142 | X154738095Y-113514666D01* 143 | X154809523Y-113514666D01* 144 | X154904761Y-113490857D01* 145 | X154952380Y-113467047D01* 146 | X155000000Y-113419428D01* 147 | X155023809Y-113348000D01* 148 | X155023809Y-113300380D01* 149 | X155000000Y-113228952D01* 150 | X154976190Y-113205142D01* 151 | X154523809Y-112990857D02* 152 | X155023809Y-112990857D01* 153 | X154523809Y-112705142D02* 154 | X154809523Y-112919428D01* 155 | X155023809Y-112705142D02* 156 | X154738095Y-112990857D01* 157 | X149471428Y-113331333D02* 158 | X149447619Y-113355142D01* 159 | X149423809Y-113426571D01* 160 | X149423809Y-113474190D01* 161 | X149447619Y-113545619D01* 162 | X149495238Y-113593238D01* 163 | X149542857Y-113617047D01* 164 | X149638095Y-113640857D01* 165 | X149709523Y-113640857D01* 166 | X149804761Y-113617047D01* 167 | X149852380Y-113593238D01* 168 | X149900000Y-113545619D01* 169 | X149923809Y-113474190D01* 170 | X149923809Y-113426571D01* 171 | X149900000Y-113355142D01* 172 | X149876190Y-113331333D01* 173 | X149447619Y-113140857D02* 174 | X149423809Y-113069428D01* 175 | X149423809Y-112950380D01* 176 | X149447619Y-112902761D01* 177 | X149471428Y-112878952D01* 178 | X149519047Y-112855142D01* 179 | X149566666Y-112855142D01* 180 | X149614285Y-112878952D01* 181 | X149638095Y-112902761D01* 182 | X149661904Y-112950380D01* 183 | X149685714Y-113045619D01* 184 | X149709523Y-113093238D01* 185 | X149733333Y-113117047D01* 186 | X149780952Y-113140857D01* 187 | X149828571Y-113140857D01* 188 | X149876190Y-113117047D01* 189 | X149900000Y-113093238D01* 190 | X149923809Y-113045619D01* 191 | X149923809Y-112926571D01* 192 | X149900000Y-112855142D01* 193 | X159900000Y-113728952D02* 194 | X159923809Y-113776571D01* 195 | X159923809Y-113848000D01* 196 | X159900000Y-113919428D01* 197 | X159852380Y-113967047D01* 198 | X159804761Y-113990857D01* 199 | X159709523Y-114014666D01* 200 | X159638095Y-114014666D01* 201 | X159542857Y-113990857D01* 202 | X159495238Y-113967047D01* 203 | X159447619Y-113919428D01* 204 | X159423809Y-113848000D01* 205 | X159423809Y-113800380D01* 206 | X159447619Y-113728952D01* 207 | X159471428Y-113705142D01* 208 | X159638095Y-113705142D01* 209 | X159638095Y-113800380D01* 210 | X159423809Y-113490857D02* 211 | X159923809Y-113490857D01* 212 | X159423809Y-113205142D01* 213 | X159923809Y-113205142D01* 214 | X159423809Y-112967047D02* 215 | X159923809Y-112967047D01* 216 | X159923809Y-112848000D01* 217 | X159900000Y-112776571D01* 218 | X159852380Y-112728952D01* 219 | X159804761Y-112705142D01* 220 | X159709523Y-112681333D01* 221 | X159638095Y-112681333D01* 222 | X159542857Y-112705142D01* 223 | X159495238Y-112728952D01* 224 | X159447619Y-112776571D01* 225 | X159423809Y-112848000D01* 226 | X159423809Y-112967047D01* 227 | X151923809Y-114133714D02* 228 | X152423809Y-114133714D01* 229 | X152066666Y-113967047D01* 230 | X152423809Y-113800380D01* 231 | X151923809Y-113800380D01* 232 | X152423809Y-113467047D02* 233 | X152423809Y-113371809D01* 234 | X152400000Y-113324190D01* 235 | X152352380Y-113276571D01* 236 | X152257142Y-113252761D01* 237 | X152090476Y-113252761D01* 238 | X151995238Y-113276571D01* 239 | X151947619Y-113324190D01* 240 | X151923809Y-113371809D01* 241 | X151923809Y-113467047D01* 242 | X151947619Y-113514666D01* 243 | X151995238Y-113562285D01* 244 | X152090476Y-113586095D01* 245 | X152257142Y-113586095D01* 246 | X152352380Y-113562285D01* 247 | X152400000Y-113514666D01* 248 | X152423809Y-113467047D01* 249 | X151947619Y-113062285D02* 250 | X151923809Y-112990857D01* 251 | X151923809Y-112871809D01* 252 | X151947619Y-112824190D01* 253 | X151971428Y-112800380D01* 254 | X152019047Y-112776571D01* 255 | X152066666Y-112776571D01* 256 | X152114285Y-112800380D01* 257 | X152138095Y-112824190D01* 258 | X152161904Y-112871809D01* 259 | X152185714Y-112967047D01* 260 | X152209523Y-113014666D01* 261 | X152233333Y-113038476D01* 262 | X152280952Y-113062285D01* 263 | X152328571Y-113062285D01* 264 | X152376190Y-113038476D01* 265 | X152400000Y-113014666D01* 266 | X152423809Y-112967047D01* 267 | X152423809Y-112848000D01* 268 | X152400000Y-112776571D01* 269 | X151923809Y-112562285D02* 270 | X152423809Y-112562285D01* 271 | D10* 272 | %TO.C,1*% 273 | X138144285Y-103068380D02* 274 | X138715714Y-103068380D01* 275 | X138430000Y-103068380D02* 276 | X138430000Y-102068380D01* 277 | X138525238Y-102211238D01* 278 | X138620476Y-102306476D01* 279 | X138715714Y-102354095D01* 280 | %TO.C,2*% 281 | X138715714Y-111815619D02* 282 | X138668095Y-111768000D01* 283 | X138572857Y-111720380D01* 284 | X138334761Y-111720380D01* 285 | X138239523Y-111768000D01* 286 | X138191904Y-111815619D01* 287 | X138144285Y-111910857D01* 288 | X138144285Y-112006095D01* 289 | X138191904Y-112148952D01* 290 | X138763333Y-112720380D01* 291 | X138144285Y-112720380D01* 292 | %TO.C,3*% 293 | X138763333Y-121372380D02* 294 | X138144285Y-121372380D01* 295 | X138477619Y-121753333D01* 296 | X138334761Y-121753333D01* 297 | X138239523Y-121800952D01* 298 | X138191904Y-121848571D01* 299 | X138144285Y-121943809D01* 300 | X138144285Y-122181904D01* 301 | X138191904Y-122277142D01* 302 | X138239523Y-122324761D01* 303 | X138334761Y-122372380D01* 304 | X138620476Y-122372380D01* 305 | X138715714Y-122324761D01* 306 | X138763333Y-122277142D01* 307 | D12* 308 | %TO.C,J2*% 309 | X143450000Y-107648000D02* 310 | X161350000Y-107648000D01* 311 | X161350000Y-127048000D02* 312 | X143450000Y-127048000D01* 313 | X143450000Y-107648000D02* 314 | X143450000Y-127048000D01* 315 | X161350000Y-127048000D02* 316 | X161350000Y-107648000D01* 317 | X160750000Y-127048000D02* 318 | X145950000Y-127048000D01* 319 | X145950000Y-127048000D02* 320 | X145950000Y-112248000D01* 321 | X145950000Y-112248000D02* 322 | X160750000Y-112248000D01* 323 | X160750000Y-112248000D02* 324 | X160750000Y-127048000D01* 325 | D13* 326 | %TO.C,1*% 327 | X139600000Y-105166000D02* 328 | X137260000Y-105166000D01* 329 | X136770000Y-100446000D02* 330 | X135880000Y-101336000D01* 331 | X136770000Y-104786000D02* 332 | X135880000Y-103896000D01* 333 | X140980000Y-103896000D02* 334 | X140090000Y-104786000D01* 335 | X140980000Y-101336000D02* 336 | X140090000Y-100446000D01* 337 | X137530000Y-100816000D02* 338 | X136530000Y-101816000D01* 339 | X139330000Y-100816000D02* 340 | X137530000Y-100816000D01* 341 | X140230000Y-103616000D02* 342 | X140230000Y-101716000D01* 343 | X140230000Y-101716000D02* 344 | X139330000Y-100816000D01* 345 | X136530000Y-103516000D02* 346 | X137430000Y-104416000D01* 347 | X139430000Y-104416000D02* 348 | X140230000Y-103616000D01* 349 | X140980000Y-103896000D02* 350 | X140980000Y-101336000D01* 351 | X136530000Y-101816000D02* 352 | X136530000Y-103516000D01* 353 | X139600000Y-100066000D02* 354 | X137260000Y-100066000D01* 355 | X135880000Y-103896000D02* 356 | X135880000Y-101336000D01* 357 | X137430000Y-104416000D02* 358 | X139430000Y-104416000D01* 359 | D14* 360 | X141110000Y-105916000D02* 361 | G75* 362 | G03* 363 | X141110000Y-105916000I-80000J0D01* 364 | G01* 365 | D13* 366 | X139710000Y-102616000D02* 367 | G75* 368 | G03* 369 | X139710000Y-102616000I-1280000J0D01* 370 | G01* 371 | %TO.C,2*% 372 | X137530000Y-110468000D02* 373 | X136530000Y-111468000D01* 374 | X140980000Y-113548000D02* 375 | X140980000Y-110988000D01* 376 | X139430000Y-114068000D02* 377 | X140230000Y-113268000D01* 378 | X140980000Y-113548000D02* 379 | X140090000Y-114438000D01* 380 | X137430000Y-114068000D02* 381 | X139430000Y-114068000D01* 382 | X139600000Y-109718000D02* 383 | X137260000Y-109718000D01* 384 | X136770000Y-114438000D02* 385 | X135880000Y-113548000D01* 386 | X140230000Y-113268000D02* 387 | X140230000Y-111368000D01* 388 | X139330000Y-110468000D02* 389 | X137530000Y-110468000D01* 390 | X136770000Y-110098000D02* 391 | X135880000Y-110988000D01* 392 | X135880000Y-113548000D02* 393 | X135880000Y-110988000D01* 394 | X140230000Y-111368000D02* 395 | X139330000Y-110468000D01* 396 | X136530000Y-113168000D02* 397 | X137430000Y-114068000D01* 398 | X136530000Y-111468000D02* 399 | X136530000Y-113168000D01* 400 | X140980000Y-110988000D02* 401 | X140090000Y-110098000D01* 402 | X139600000Y-114818000D02* 403 | X137260000Y-114818000D01* 404 | X139710000Y-112268000D02* 405 | G75* 406 | G03* 407 | X139710000Y-112268000I-1280000J0D01* 408 | G01* 409 | D14* 410 | X141110000Y-115568000D02* 411 | G75* 412 | G03* 413 | X141110000Y-115568000I-80000J0D01* 414 | G01* 415 | D13* 416 | %TO.C,3*% 417 | X137430000Y-123720000D02* 418 | X139430000Y-123720000D01* 419 | X140230000Y-122920000D02* 420 | X140230000Y-121020000D01* 421 | X135880000Y-123200000D02* 422 | X135880000Y-120640000D01* 423 | X136770000Y-119750000D02* 424 | X135880000Y-120640000D01* 425 | X136530000Y-122820000D02* 426 | X137430000Y-123720000D01* 427 | X140980000Y-123200000D02* 428 | X140090000Y-124090000D01* 429 | X140980000Y-123200000D02* 430 | X140980000Y-120640000D01* 431 | X139600000Y-119370000D02* 432 | X137260000Y-119370000D01* 433 | X139430000Y-123720000D02* 434 | X140230000Y-122920000D01* 435 | X140980000Y-120640000D02* 436 | X140090000Y-119750000D01* 437 | X139330000Y-120120000D02* 438 | X137530000Y-120120000D01* 439 | X136770000Y-124090000D02* 440 | X135880000Y-123200000D01* 441 | X137530000Y-120120000D02* 442 | X136530000Y-121120000D01* 443 | X136530000Y-121120000D02* 444 | X136530000Y-122820000D01* 445 | X139600000Y-124470000D02* 446 | X137260000Y-124470000D01* 447 | X140230000Y-121020000D02* 448 | X139330000Y-120120000D01* 449 | X139710000Y-121920000D02* 450 | G75* 451 | G03* 452 | X139710000Y-121920000I-1280000J0D01* 453 | G01* 454 | D14* 455 | X141110000Y-125220000D02* 456 | G75* 457 | G03* 458 | X141110000Y-125220000I-80000J0D01* 459 | G01* 460 | %TD*% 461 | M02* 462 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-Edge_Cuts.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:52+01:00*% 3 | %TF.ProjectId,PicoMemcard-pico,5069636f-4d65-46d6-9361-72642d706963,1.1.2*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Profile,NP*% 6 | %FSLAX46Y46*% 7 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 8 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:52* 9 | %MOMM*% 10 | %LPD*% 11 | G01* 12 | G04 APERTURE LIST* 13 | %TA.AperFunction,Profile*% 14 | %ADD10C,0.200000*% 15 | %TD*% 16 | G04 APERTURE END LIST* 17 | D10* 18 | X161300318Y-64900622D02* 19 | X161300318Y-71700622D01* 20 | X131000000Y-71700000D02* 21 | X130998000Y-127254000D01* 22 | X151000318Y-71700622D02* 23 | G75* 24 | G03* 25 | X153600318Y-71700622I1300000J0D01* 26 | G01* 27 | X140700376Y-64900624D02* 28 | G75* 29 | G03* 30 | X140000725Y-64199987I-673676J26924D01* 31 | G01* 32 | X140700318Y-71700622D02* 33 | G75* 34 | G03* 35 | X143300318Y-71700622I1300000J0D01* 36 | G01* 37 | X167200000Y-71700000D02* 38 | X167198000Y-127254000D01* 39 | X154300318Y-64200623D02* 40 | G75* 41 | G03* 42 | X153599683Y-64900216I-27018J-673577D01* 43 | G01* 44 | X154300318Y-64200622D02* 45 | X160600725Y-64199987D01* 46 | X130998000Y-127254000D02* 47 | X167198000Y-127254000D01* 48 | X144000318Y-64200622D02* 49 | X150300725Y-64199987D01* 50 | X161300376Y-64900624D02* 51 | G75* 52 | G03* 53 | X160600725Y-64199987I-673676J26924D01* 54 | G01* 55 | X135400318Y-64200623D02* 56 | G75* 57 | G03* 58 | X134699683Y-64900216I-27018J-673577D01* 59 | G01* 60 | X144000318Y-64200623D02* 61 | G75* 62 | G03* 63 | X143299683Y-64900216I-27018J-673577D01* 64 | G01* 65 | X163900318Y-71699784D02* 66 | X167200000Y-71700000D01* 67 | X151000376Y-64900624D02* 68 | G75* 69 | G03* 70 | X150300725Y-64199987I-673676J26924D01* 71 | G01* 72 | X132100318Y-71700622D02* 73 | X131000000Y-71700000D01* 74 | X134700318Y-71699784D02* 75 | X134699683Y-64900216D01* 76 | X151000318Y-64900622D02* 77 | X151000318Y-71700622D01* 78 | X135400318Y-64200622D02* 79 | X140000725Y-64199987D01* 80 | X161300282Y-71700622D02* 81 | G75* 82 | G03* 83 | X163900318Y-71699784I1300018J422D01* 84 | G01* 85 | X143300318Y-71700622D02* 86 | X143299683Y-64900216D01* 87 | X140700318Y-64900622D02* 88 | X140700318Y-71700622D01* 89 | X132100282Y-71700622D02* 90 | G75* 91 | G03* 92 | X134700318Y-71699784I1300018J422D01* 93 | G01* 94 | X153600318Y-71700622D02* 95 | X153599683Y-64900216D01* 96 | M02* 97 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-F_Mask.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:52+01:00*% 3 | %TF.ProjectId,PicoMemcard-pico,5069636f-4d65-46d6-9361-72642d706963,1.1.2*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Soldermask,Top*% 6 | %TF.FilePolarity,Negative*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:52* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | G04 Aperture macros list* 15 | %AMRoundRect* 16 | 0 Rectangle with rounded corners* 17 | 0 $1 Rounding radius* 18 | 0 $2 $3 $4 $5 $6 $7 $8 $9 X,Y pos of 4 corners* 19 | 0 Add a 4 corners polygon primitive as box body* 20 | 4,1,4,$2,$3,$4,$5,$6,$7,$8,$9,$2,$3,0* 21 | 0 Add four circle primitives for the rounded corners* 22 | 1,1,$1+$1,$2,$3* 23 | 1,1,$1+$1,$4,$5* 24 | 1,1,$1+$1,$6,$7* 25 | 1,1,$1+$1,$8,$9* 26 | 0 Add four rect primitives between the rounded corners* 27 | 20,1,$1+$1,$2,$3,$4,$5,0* 28 | 20,1,$1+$1,$4,$5,$6,$7,0* 29 | 20,1,$1+$1,$6,$7,$8,$9,0* 30 | 20,1,$1+$1,$8,$9,$2,$3,0*% 31 | G04 Aperture macros list end* 32 | %ADD10C,2.200000*% 33 | %ADD11O,1.500000X1.500000*% 34 | %ADD12O,1.800000X1.800000*% 35 | %ADD13RoundRect,0.425000X1.575000X0.425000X-1.575000X0.425000X-1.575000X-0.425000X1.575000X-0.425000X0*% 36 | %ADD14O,1.700000X1.700000*% 37 | %ADD15RoundRect,0.425000X-0.425000X1.575000X-0.425000X-1.575000X0.425000X-1.575000X0.425000X1.575000X0*% 38 | %ADD16R,1.700000X1.700000*% 39 | %ADD17R,1.400000X6.500000*% 40 | %ADD18R,1.400000X7.300000*% 41 | G04 APERTURE END LIST* 42 | D10* 43 | %TO.C,M2*% 44 | X133350000Y-75438000D03* 45 | %TD*% 46 | %TO.C,M2*% 47 | X164846000Y-124968000D03* 48 | %TD*% 49 | D11* 50 | %TO.C,U1*% 51 | X146673000Y-122062000D03* 52 | D12* 53 | X151823000Y-125092000D03* 54 | D11* 55 | X151523000Y-122062000D03* 56 | D12* 57 | X146373000Y-125092000D03* 58 | D13* 59 | X159298000Y-125292000D03* 60 | X159298000Y-122752000D03* 61 | X159298000Y-120212000D03* 62 | X159298000Y-117672000D03* 63 | X159298000Y-115132000D03* 64 | X159298000Y-112592000D03* 65 | X159298000Y-110052000D03* 66 | X159298000Y-107512000D03* 67 | X159298000Y-104972000D03* 68 | X159298000Y-102432000D03* 69 | X159298000Y-99892000D03* 70 | X159298000Y-97352000D03* 71 | X159298000Y-94812000D03* 72 | X159298000Y-92272000D03* 73 | X159298000Y-89732000D03* 74 | X159298000Y-87192000D03* 75 | X159298000Y-84652000D03* 76 | X159298000Y-82112000D03* 77 | X159298000Y-79572000D03* 78 | X159298000Y-77032000D03* 79 | X138798000Y-77012000D03* 80 | X138798000Y-79552000D03* 81 | X138798000Y-82092000D03* 82 | X138798000Y-84632000D03* 83 | X138798000Y-87172000D03* 84 | X138798000Y-89712000D03* 85 | X138798000Y-92252000D03* 86 | X138798000Y-94792000D03* 87 | X138798000Y-97332000D03* 88 | X138798000Y-99872000D03* 89 | X138798000Y-102412000D03* 90 | X138798000Y-104952000D03* 91 | X138798000Y-107492000D03* 92 | X138798000Y-110032000D03* 93 | X138798000Y-112572000D03* 94 | X138798000Y-115112000D03* 95 | X138798000Y-117652000D03* 96 | X138798000Y-120192000D03* 97 | X138798000Y-122732000D03* 98 | X138798000Y-125272000D03* 99 | D14* 100 | X151638000Y-77192000D03* 101 | D15* 102 | X151638000Y-76092000D03* 103 | D16* 104 | X149098000Y-77192000D03* 105 | D15* 106 | X149098000Y-76092000D03* 107 | D14* 108 | X146558000Y-77192000D03* 109 | D15* 110 | X146558000Y-76092000D03* 111 | %TD*% 112 | D17* 113 | %TO.C,J1*% 114 | X137600000Y-68400000D03* 115 | X139900000Y-68400000D03* 116 | D18* 117 | X145600000Y-68000000D03* 118 | X147900000Y-68000000D03* 119 | X150200000Y-68000000D03* 120 | D17* 121 | X155900000Y-68400000D03* 122 | X158200000Y-68400000D03* 123 | X160500000Y-68400000D03* 124 | %TD*% 125 | M02* 126 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-F_Paste.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:52+01:00*% 3 | %TF.ProjectId,PicoMemcard-pico,5069636f-4d65-46d6-9361-72642d706963,1.1.2*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Paste,Top*% 6 | %TF.FilePolarity,Positive*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:52* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10R,1.400000X6.500000*% 15 | %ADD11R,1.400000X7.300000*% 16 | G04 APERTURE END LIST* 17 | D10* 18 | %TO.C,J1*% 19 | X137600000Y-68400000D03* 20 | X139900000Y-68400000D03* 21 | D11* 22 | X145600000Y-68000000D03* 23 | X147900000Y-68000000D03* 24 | X150200000Y-68000000D03* 25 | D10* 26 | X155900000Y-68400000D03* 27 | X158200000Y-68400000D03* 28 | X160500000Y-68400000D03* 29 | %TD*% 30 | M02* 31 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-NPTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ; DRILL file {KiCad (6.0.5)} date Sun Feb 5 19:42:50 2023 3 | ; FORMAT={-:-/ absolute / metric / decimal} 4 | ; #@! TF.CreationDate,2023-02-05T19:42:50+01:00 5 | ; #@! TF.GenerationSoftware,Kicad,Pcbnew,(6.0.5) 6 | ; #@! TF.FileFunction,NonPlated,1,2,NPTH 7 | FMAT,2 8 | METRIC 9 | ; #@! TA.AperFunction,NonPlated,NPTH,ComponentDrill 10 | T1C1.500 11 | ; #@! TA.AperFunction,NonPlated,NPTH,ComponentDrill 12 | T2C1.800 13 | ; #@! TA.AperFunction,NonPlated,NPTH,ComponentDrill 14 | T3C2.200 15 | % 16 | G90 17 | G05 18 | T1 19 | X146.673Y-122.062 20 | X151.523Y-122.062 21 | T2 22 | X146.373Y-125.092 23 | X151.823Y-125.092 24 | T3 25 | X133.35Y-75.438 26 | X164.846Y-124.968 27 | T0 28 | M30 29 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-PTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ; DRILL file {KiCad (6.0.5)} date Sun Feb 5 19:42:50 2023 3 | ; FORMAT={-:-/ absolute / metric / decimal} 4 | ; #@! TF.CreationDate,2023-02-05T19:42:50+01:00 5 | ; #@! TF.GenerationSoftware,Kicad,Pcbnew,(6.0.5) 6 | ; #@! TF.FileFunction,Plated,1,2,PTH 7 | FMAT,2 8 | METRIC 9 | ; #@! TA.AperFunction,Plated,PTH,ViaDrill 10 | T1C0.200 11 | ; #@! TA.AperFunction,Plated,PTH,ViaDrill 12 | T2C0.400 13 | ; #@! TA.AperFunction,Plated,PTH,ComponentDrill 14 | T3C1.020 15 | % 16 | G90 17 | G05 18 | T1 19 | X132.842Y-87.884 20 | X133.604Y-110.49 21 | X134.366Y-80.772 22 | X134.366Y-92.71 23 | X134.366Y-124.714 24 | X134.62Y-119.888 25 | X134.874Y-117.094 26 | X135.128Y-85.598 27 | X135.128Y-106.172 28 | X135.636Y-102.362 29 | X136.398Y-73.406 30 | X141.986Y-89.408 31 | X142.24Y-86.106 32 | X142.494Y-78.232 33 | X142.494Y-110.998 34 | X142.494Y-123.698 35 | X144.018Y-104.648 36 | X144.526Y-75.692 37 | X144.78Y-72.898 38 | X148.082Y-115.316 39 | X152.654Y-80.772 40 | X152.654Y-89.662 41 | X152.654Y-100.076 42 | X154.432Y-124.714 43 | X154.94Y-115.57 44 | X162.56Y-100.33 45 | X162.56Y-115.824 46 | X162.814Y-81.026 47 | T2 48 | X134.62Y-78.232 49 | X141.986Y-115.062 50 | X150.114Y-72.644 51 | T3 52 | X146.558Y-77.192 53 | X149.098Y-77.192 54 | X151.638Y-77.192 55 | T0 56 | M30 57 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/Gerber/PicoMemcard-pico-job.gbrjob: -------------------------------------------------------------------------------- 1 | { 2 | "Header": { 3 | "GenerationSoftware": { 4 | "Vendor": "KiCad", 5 | "Application": "Pcbnew", 6 | "Version": "(6.0.5)" 7 | }, 8 | "CreationDate": "2023-02-05T19:42:52+01:00" 9 | }, 10 | "GeneralSpecs": { 11 | "ProjectId": { 12 | "Name": "PicoMemcard-pico", 13 | "GUID": "5069636f-4d65-46d6-9361-72642d706963", 14 | "Revision": "1.1.2" 15 | }, 16 | "Size": { 17 | "X": 36.402, 18 | "Y": 63.2545 19 | }, 20 | "LayerNumber": 2, 21 | "BoardThickness": 1.6, 22 | "Finish": "None" 23 | }, 24 | "DesignRules": [ 25 | { 26 | "Layers": "Outer", 27 | "PadToPad": 0.127, 28 | "PadToTrack": 0.127, 29 | "TrackToTrack": 0.2, 30 | "MinLineWidth": 0.254, 31 | "TrackToRegion": 0.508, 32 | "RegionToRegion": 0.508 33 | } 34 | ], 35 | "FilesAttributes": [ 36 | { 37 | "Path": "PicoMemcard-pico-F_Cu.gbr", 38 | "FileFunction": "Copper,L1,Top", 39 | "FilePolarity": "Positive" 40 | }, 41 | { 42 | "Path": "PicoMemcard-pico-B_Cu.gbr", 43 | "FileFunction": "Copper,L2,Bot", 44 | "FilePolarity": "Positive" 45 | }, 46 | { 47 | "Path": "PicoMemcard-pico-F_Paste.gbr", 48 | "FileFunction": "SolderPaste,Top", 49 | "FilePolarity": "Positive" 50 | }, 51 | { 52 | "Path": "PicoMemcard-pico-B_Paste.gbr", 53 | "FileFunction": "SolderPaste,Bot", 54 | "FilePolarity": "Positive" 55 | }, 56 | { 57 | "Path": "PicoMemcard-pico-F_Silkscreen.gbr", 58 | "FileFunction": "Legend,Top", 59 | "FilePolarity": "Positive" 60 | }, 61 | { 62 | "Path": "PicoMemcard-pico-B_Silkscreen.gbr", 63 | "FileFunction": "Legend,Bot", 64 | "FilePolarity": "Positive" 65 | }, 66 | { 67 | "Path": "PicoMemcard-pico-F_Mask.gbr", 68 | "FileFunction": "SolderMask,Top", 69 | "FilePolarity": "Negative" 70 | }, 71 | { 72 | "Path": "PicoMemcard-pico-B_Mask.gbr", 73 | "FileFunction": "SolderMask,Bot", 74 | "FilePolarity": "Negative" 75 | }, 76 | { 77 | "Path": "PicoMemcard-pico-Edge_Cuts.gbr", 78 | "FileFunction": "Profile", 79 | "FilePolarity": "Positive" 80 | } 81 | ], 82 | "MaterialStackup": [ 83 | { 84 | "Type": "Legend", 85 | "Name": "Top Silk Screen" 86 | }, 87 | { 88 | "Type": "SolderPaste", 89 | "Name": "Top Solder Paste" 90 | }, 91 | { 92 | "Type": "SolderMask", 93 | "Thickness": 0.01, 94 | "Name": "Top Solder Mask" 95 | }, 96 | { 97 | "Type": "Copper", 98 | "Thickness": 0.035, 99 | "Name": "F.Cu" 100 | }, 101 | { 102 | "Type": "Dielectric", 103 | "Thickness": 1.51, 104 | "Material": "FR4", 105 | "Name": "F.Cu/B.Cu", 106 | "Notes": "Type: dielectric layer 1 (from F.Cu to B.Cu)" 107 | }, 108 | { 109 | "Type": "Copper", 110 | "Thickness": 0.035, 111 | "Name": "B.Cu" 112 | }, 113 | { 114 | "Type": "SolderMask", 115 | "Thickness": 0.01, 116 | "Name": "Bottom Solder Mask" 117 | }, 118 | { 119 | "Type": "SolderPaste", 120 | "Name": "Bottom Solder Paste" 121 | }, 122 | { 123 | "Type": "Legend", 124 | "Name": "Bottom Silk Screen" 125 | } 126 | ] 127 | } 128 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/PicoMemcard-pico-backups/PicoMemcard-pico-2023-02-05_194258.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangiu/PicoMemcard/9ea646810366574740b03e3211b655de870a03dc/pcb/PicoMemcard-pico/PicoMemcard-pico-backups/PicoMemcard-pico-2023-02-05_194258.zip -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/PicoMemcard-pico.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 36, 4 | "active_layer_preset": "", 5 | "auto_track_width": true, 6 | "hidden_nets": [], 7 | "high_contrast_mode": 0, 8 | "net_color_mode": 1, 9 | "opacity": { 10 | "pads": 1.0, 11 | "tracks": 1.0, 12 | "vias": 1.0, 13 | "zones": 0.6 14 | }, 15 | "ratsnest_display_mode": 0, 16 | "selection_filter": { 17 | "dimensions": true, 18 | "footprints": true, 19 | "graphics": true, 20 | "keepouts": true, 21 | "lockedItems": true, 22 | "otherItems": true, 23 | "pads": true, 24 | "text": true, 25 | "tracks": true, 26 | "vias": true, 27 | "zones": true 28 | }, 29 | "visible_items": [ 30 | 0, 31 | 1, 32 | 2, 33 | 3, 34 | 4, 35 | 5, 36 | 8, 37 | 9, 38 | 10, 39 | 11, 40 | 12, 41 | 13, 42 | 14, 43 | 15, 44 | 16, 45 | 17, 46 | 18, 47 | 19, 48 | 20, 49 | 21, 50 | 22, 51 | 23, 52 | 24, 53 | 25, 54 | 26, 55 | 27, 56 | 28, 57 | 29, 58 | 30, 59 | 32, 60 | 33, 61 | 34, 62 | 35, 63 | 36 64 | ], 65 | "visible_layers": "006f0ff_ffffffff", 66 | "zone_display_mode": 0 67 | }, 68 | "meta": { 69 | "filename": "PicoMemcard-newmodule-pico.kicad_prl", 70 | "version": 3 71 | }, 72 | "project": { 73 | "files": [] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-pico/PicoMemcard-pico.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "design_settings": { 4 | "defaults": { 5 | "board_outline_line_width": 0.09999999999999999, 6 | "copper_line_width": 0.19999999999999998, 7 | "copper_text_italic": false, 8 | "copper_text_size_h": 1.5, 9 | "copper_text_size_v": 1.5, 10 | "copper_text_thickness": 0.3, 11 | "copper_text_upright": false, 12 | "courtyard_line_width": 0.049999999999999996, 13 | "dimension_precision": 4, 14 | "dimension_units": 3, 15 | "dimensions": { 16 | "arrow_length": 1270000, 17 | "extension_offset": 500000, 18 | "keep_text_aligned": true, 19 | "suppress_zeroes": false, 20 | "text_position": 0, 21 | "units_format": 1 22 | }, 23 | "fab_line_width": 0.09999999999999999, 24 | "fab_text_italic": false, 25 | "fab_text_size_h": 1.0, 26 | "fab_text_size_v": 1.0, 27 | "fab_text_thickness": 0.15, 28 | "fab_text_upright": false, 29 | "other_line_width": 0.15, 30 | "other_text_italic": false, 31 | "other_text_size_h": 1.0, 32 | "other_text_size_v": 1.0, 33 | "other_text_thickness": 0.15, 34 | "other_text_upright": false, 35 | "pads": { 36 | "drill": 0.762, 37 | "height": 1.524, 38 | "width": 1.524 39 | }, 40 | "silk_line_width": 0.15, 41 | "silk_text_italic": false, 42 | "silk_text_size_h": 1.0, 43 | "silk_text_size_v": 1.0, 44 | "silk_text_thickness": 0.15, 45 | "silk_text_upright": false, 46 | "zones": { 47 | "45_degree_only": false, 48 | "min_clearance": 0.508 49 | } 50 | }, 51 | "diff_pair_dimensions": [ 52 | { 53 | "gap": 0.0, 54 | "via_gap": 0.0, 55 | "width": 0.0 56 | } 57 | ], 58 | "drc_exclusions": [], 59 | "meta": { 60 | "version": 2 61 | }, 62 | "rule_severities": { 63 | "annular_width": "error", 64 | "clearance": "error", 65 | "copper_edge_clearance": "error", 66 | "courtyards_overlap": "error", 67 | "diff_pair_gap_out_of_range": "error", 68 | "diff_pair_uncoupled_length_too_long": "error", 69 | "drill_out_of_range": "error", 70 | "duplicate_footprints": "warning", 71 | "extra_footprint": "warning", 72 | "footprint_type_mismatch": "error", 73 | "hole_clearance": "error", 74 | "hole_near_hole": "error", 75 | "invalid_outline": "error", 76 | "item_on_disabled_layer": "error", 77 | "items_not_allowed": "error", 78 | "length_out_of_range": "error", 79 | "malformed_courtyard": "error", 80 | "microvia_drill_out_of_range": "error", 81 | "missing_courtyard": "ignore", 82 | "missing_footprint": "warning", 83 | "net_conflict": "warning", 84 | "npth_inside_courtyard": "ignore", 85 | "padstack": "error", 86 | "pth_inside_courtyard": "ignore", 87 | "shorting_items": "error", 88 | "silk_over_copper": "warning", 89 | "silk_overlap": "warning", 90 | "skew_out_of_range": "error", 91 | "through_hole_pad_without_hole": "error", 92 | "too_many_vias": "error", 93 | "track_dangling": "warning", 94 | "track_width": "error", 95 | "tracks_crossing": "error", 96 | "unconnected_items": "error", 97 | "unresolved_variable": "error", 98 | "via_dangling": "warning", 99 | "zone_has_empty_net": "error", 100 | "zones_intersect": "error" 101 | }, 102 | "rules": { 103 | "allow_blind_buried_vias": false, 104 | "allow_microvias": false, 105 | "max_error": 0.005, 106 | "min_clearance": 0.127, 107 | "min_copper_edge_clearance": 0.0, 108 | "min_hole_clearance": 0.25, 109 | "min_hole_to_hole": 0.5, 110 | "min_microvia_diameter": 0.19999999999999998, 111 | "min_microvia_drill": 0.09999999999999999, 112 | "min_silk_clearance": 0.0, 113 | "min_through_hole_diameter": 0.19999999999999998, 114 | "min_track_width": 0.127, 115 | "min_via_annular_width": 0.13, 116 | "min_via_diameter": 0.5, 117 | "solder_mask_clearance": 0.0, 118 | "solder_mask_min_width": 0.0, 119 | "use_height_for_length_calcs": true 120 | }, 121 | "track_widths": [ 122 | 0.0, 123 | 0.254, 124 | 0.5 125 | ], 126 | "via_dimensions": [ 127 | { 128 | "diameter": 0.0, 129 | "drill": 0.0 130 | }, 131 | { 132 | "diameter": 0.5, 133 | "drill": 0.2 134 | } 135 | ], 136 | "zones_allow_external_fillets": false, 137 | "zones_use_no_outline": true 138 | }, 139 | "layer_presets": [] 140 | }, 141 | "boards": [], 142 | "cvpcb": { 143 | "equivalence_files": [] 144 | }, 145 | "erc": { 146 | "erc_exclusions": [], 147 | "meta": { 148 | "version": 0 149 | }, 150 | "pin_map": [ 151 | [ 152 | 0, 153 | 0, 154 | 0, 155 | 0, 156 | 0, 157 | 0, 158 | 1, 159 | 0, 160 | 0, 161 | 0, 162 | 0, 163 | 2 164 | ], 165 | [ 166 | 0, 167 | 2, 168 | 0, 169 | 1, 170 | 0, 171 | 0, 172 | 1, 173 | 0, 174 | 2, 175 | 2, 176 | 2, 177 | 2 178 | ], 179 | [ 180 | 0, 181 | 0, 182 | 0, 183 | 0, 184 | 0, 185 | 0, 186 | 1, 187 | 0, 188 | 1, 189 | 0, 190 | 1, 191 | 2 192 | ], 193 | [ 194 | 0, 195 | 1, 196 | 0, 197 | 0, 198 | 0, 199 | 0, 200 | 1, 201 | 1, 202 | 2, 203 | 1, 204 | 1, 205 | 2 206 | ], 207 | [ 208 | 0, 209 | 0, 210 | 0, 211 | 0, 212 | 0, 213 | 0, 214 | 1, 215 | 0, 216 | 0, 217 | 0, 218 | 0, 219 | 2 220 | ], 221 | [ 222 | 0, 223 | 0, 224 | 0, 225 | 0, 226 | 0, 227 | 0, 228 | 0, 229 | 0, 230 | 0, 231 | 0, 232 | 0, 233 | 2 234 | ], 235 | [ 236 | 1, 237 | 1, 238 | 1, 239 | 1, 240 | 1, 241 | 0, 242 | 1, 243 | 1, 244 | 1, 245 | 1, 246 | 1, 247 | 2 248 | ], 249 | [ 250 | 0, 251 | 0, 252 | 0, 253 | 1, 254 | 0, 255 | 0, 256 | 1, 257 | 0, 258 | 0, 259 | 0, 260 | 0, 261 | 2 262 | ], 263 | [ 264 | 0, 265 | 2, 266 | 1, 267 | 2, 268 | 0, 269 | 0, 270 | 1, 271 | 0, 272 | 2, 273 | 2, 274 | 2, 275 | 2 276 | ], 277 | [ 278 | 0, 279 | 2, 280 | 0, 281 | 1, 282 | 0, 283 | 0, 284 | 1, 285 | 0, 286 | 2, 287 | 0, 288 | 0, 289 | 2 290 | ], 291 | [ 292 | 0, 293 | 2, 294 | 1, 295 | 1, 296 | 0, 297 | 0, 298 | 1, 299 | 0, 300 | 2, 301 | 0, 302 | 0, 303 | 2 304 | ], 305 | [ 306 | 2, 307 | 2, 308 | 2, 309 | 2, 310 | 2, 311 | 2, 312 | 2, 313 | 2, 314 | 2, 315 | 2, 316 | 2, 317 | 2 318 | ] 319 | ], 320 | "rule_severities": { 321 | "bus_definition_conflict": "error", 322 | "bus_entry_needed": "error", 323 | "bus_label_syntax": "error", 324 | "bus_to_bus_conflict": "error", 325 | "bus_to_net_conflict": "error", 326 | "different_unit_footprint": "error", 327 | "different_unit_net": "error", 328 | "duplicate_reference": "error", 329 | "duplicate_sheet_names": "error", 330 | "extra_units": "error", 331 | "global_label_dangling": "warning", 332 | "hier_label_mismatch": "error", 333 | "label_dangling": "error", 334 | "lib_symbol_issues": "warning", 335 | "multiple_net_names": "warning", 336 | "net_not_bus_member": "warning", 337 | "no_connect_connected": "warning", 338 | "no_connect_dangling": "warning", 339 | "pin_not_connected": "error", 340 | "pin_not_driven": "error", 341 | "pin_to_pin": "warning", 342 | "power_pin_not_driven": "error", 343 | "similar_labels": "warning", 344 | "unannotated": "error", 345 | "unit_value_mismatch": "error", 346 | "unresolved_variable": "error", 347 | "wire_dangling": "error" 348 | } 349 | }, 350 | "libraries": { 351 | "pinned_footprint_libs": [], 352 | "pinned_symbol_libs": [] 353 | }, 354 | "meta": { 355 | "filename": "PicoMemcard-newmodule-pico.kicad_pro", 356 | "version": 1 357 | }, 358 | "net_settings": { 359 | "classes": [ 360 | { 361 | "bus_width": 12.0, 362 | "clearance": 0.2, 363 | "diff_pair_gap": 0.25, 364 | "diff_pair_via_gap": 0.25, 365 | "diff_pair_width": 0.2, 366 | "line_style": 0, 367 | "microvia_diameter": 0.3, 368 | "microvia_drill": 0.1, 369 | "name": "Default", 370 | "pcb_color": "rgba(0, 0, 0, 0.000)", 371 | "schematic_color": "rgba(0, 0, 0, 0.000)", 372 | "track_width": 0.25, 373 | "via_diameter": 0.8, 374 | "via_drill": 0.4, 375 | "wire_width": 6.0 376 | } 377 | ], 378 | "meta": { 379 | "version": 2 380 | }, 381 | "net_colors": null 382 | }, 383 | "pcbnew": { 384 | "last_paths": { 385 | "gencad": "", 386 | "idf": "", 387 | "netlist": "", 388 | "specctra_dsn": "", 389 | "step": "PicoMemcard.step", 390 | "vrml": "" 391 | }, 392 | "page_layout_descr_file": "" 393 | }, 394 | "schematic": { 395 | "annotate_start_num": 0, 396 | "drawing": { 397 | "default_line_thickness": 6.0, 398 | "default_text_size": 50.0, 399 | "field_names": [], 400 | "intersheets_ref_own_page": false, 401 | "intersheets_ref_prefix": "", 402 | "intersheets_ref_short": false, 403 | "intersheets_ref_show": false, 404 | "intersheets_ref_suffix": "", 405 | "junction_size_choice": 3, 406 | "label_size_ratio": 0.375, 407 | "pin_symbol_size": 25.0, 408 | "text_offset_ratio": 0.15 409 | }, 410 | "legacy_lib_dir": "", 411 | "legacy_lib_list": [], 412 | "meta": { 413 | "version": 1 414 | }, 415 | "net_format_name": "", 416 | "ngspice": { 417 | "fix_include_paths": true, 418 | "fix_passive_vals": false, 419 | "meta": { 420 | "version": 0 421 | }, 422 | "model_mode": 0, 423 | "workbook_filename": "" 424 | }, 425 | "page_layout_descr_file": "", 426 | "plot_directory": "", 427 | "spice_adjust_passive_values": false, 428 | "spice_external_command": "spice \"%I\"", 429 | "subpart_first_id": 65, 430 | "subpart_id_separator": 0 431 | }, 432 | "sheets": [ 433 | [ 434 | "faa956bb-0e0d-41e1-a5c8-c31a518a76e5", 435 | "" 436 | ] 437 | ], 438 | "text_variables": {} 439 | } 440 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-B_Mask.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:25+01:00*% 3 | %TF.ProjectId,PicoMemcard-rp2040zero,5069636f-4d65-46d6-9361-72642d727032,1.3.1*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Soldermask,Bot*% 6 | %TF.FilePolarity,Negative*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:25* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10C,3.200000*% 15 | %ADD11R,1.000000X1.700000*% 16 | %ADD12O,1.800000X4.000000*% 17 | G04 APERTURE END LIST* 18 | D10* 19 | %TO.C,H2*% 20 | X163530000Y-102070000D03* 21 | %TD*% 22 | %TO.C,H1*% 23 | X134370000Y-75730000D03* 24 | %TD*% 25 | D11* 26 | %TO.C,3*% 27 | X140026000Y-112520000D03* 28 | X140026000Y-105920000D03* 29 | X136326000Y-112520000D03* 30 | X136326000Y-105920000D03* 31 | %TD*% 32 | %TO.C,1*% 33 | X140026000Y-91570000D03* 34 | X140026000Y-84970000D03* 35 | X136326000Y-91570000D03* 36 | X136326000Y-84970000D03* 37 | %TD*% 38 | %TO.C,2*% 39 | X140026000Y-102160000D03* 40 | X140026000Y-95560000D03* 41 | X136326000Y-102160000D03* 42 | X136326000Y-95560000D03* 43 | %TD*% 44 | D12* 45 | %TO.C,J2*% 46 | X145372000Y-97248000D03* 47 | X147872000Y-97248000D03* 48 | X150372000Y-97248000D03* 49 | X152872000Y-97248000D03* 50 | X155372000Y-97248000D03* 51 | X157872000Y-97248000D03* 52 | %TD*% 53 | M02* 54 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-B_Paste.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:25+01:00*% 3 | %TF.ProjectId,PicoMemcard-rp2040zero,5069636f-4d65-46d6-9361-72642d727032,1.3.1*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Paste,Bot*% 6 | %TF.FilePolarity,Positive*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:25* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10R,1.000000X1.700000*% 15 | %ADD11O,1.800000X4.000000*% 16 | G04 APERTURE END LIST* 17 | D10* 18 | %TO.C,3*% 19 | X140026000Y-112520000D03* 20 | X140026000Y-105920000D03* 21 | X136326000Y-112520000D03* 22 | X136326000Y-105920000D03* 23 | %TD*% 24 | %TO.C,1*% 25 | X140026000Y-91570000D03* 26 | X140026000Y-84970000D03* 27 | X136326000Y-91570000D03* 28 | X136326000Y-84970000D03* 29 | %TD*% 30 | %TO.C,2*% 31 | X140026000Y-102160000D03* 32 | X140026000Y-95560000D03* 33 | X136326000Y-102160000D03* 34 | X136326000Y-95560000D03* 35 | %TD*% 36 | D11* 37 | %TO.C,J2*% 38 | X145372000Y-97248000D03* 39 | X147872000Y-97248000D03* 40 | X150372000Y-97248000D03* 41 | X152872000Y-97248000D03* 42 | X155372000Y-97248000D03* 43 | X157872000Y-97248000D03* 44 | %TD*% 45 | M02* 46 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-B_Silkscreen.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:25+01:00*% 3 | %TF.ProjectId,PicoMemcard-rp2040zero,5069636f-4d65-46d6-9361-72642d727032,1.3.1*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Legend,Bot*% 6 | %TF.FilePolarity,Positive*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:25* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10C,0.150000*% 15 | %ADD11C,0.100000*% 16 | %ADD12C,0.250000*% 17 | %ADD13C,0.160000*% 18 | %ADD14C,0.120000*% 19 | G04 APERTURE END LIST* 20 | D10* 21 | %TO.C,3*% 22 | X138509333Y-108672380D02* 23 | X137890285Y-108672380D01* 24 | X138223619Y-109053333D01* 25 | X138080761Y-109053333D01* 26 | X137985523Y-109100952D01* 27 | X137937904Y-109148571D01* 28 | X137890285Y-109243809D01* 29 | X137890285Y-109481904D01* 30 | X137937904Y-109577142D01* 31 | X137985523Y-109624761D01* 32 | X138080761Y-109672380D01* 33 | X138366476Y-109672380D01* 34 | X138461714Y-109624761D01* 35 | X138509333Y-109577142D01* 36 | %TO.C,1*% 37 | X137850285Y-88802380D02* 38 | X138421714Y-88802380D01* 39 | X138136000Y-88802380D02* 40 | X138136000Y-87802380D01* 41 | X138231238Y-87945238D01* 42 | X138326476Y-88040476D01* 43 | X138421714Y-88088095D01* 44 | %TO.C,2*% 45 | X138461714Y-98407619D02* 46 | X138414095Y-98360000D01* 47 | X138318857Y-98312380D01* 48 | X138080761Y-98312380D01* 49 | X137985523Y-98360000D01* 50 | X137937904Y-98407619D01* 51 | X137890285Y-98502857D01* 52 | X137890285Y-98598095D01* 53 | X137937904Y-98740952D01* 54 | X138509333Y-99312380D01* 55 | X137890285Y-99312380D01* 56 | %TO.C,J2*% 57 | X157224380Y-105214666D02* 58 | X157938666Y-105214666D01* 59 | X158081523Y-105167047D01* 60 | X158176761Y-105071809D01* 61 | X158224380Y-104928952D01* 62 | X158224380Y-104833714D01* 63 | X157319619Y-105643238D02* 64 | X157272000Y-105690857D01* 65 | X157224380Y-105786095D01* 66 | X157224380Y-106024190D01* 67 | X157272000Y-106119428D01* 68 | X157319619Y-106167047D01* 69 | X157414857Y-106214666D01* 70 | X157510095Y-106214666D01* 71 | X157652952Y-106167047D01* 72 | X158224380Y-105595619D01* 73 | X158224380Y-106214666D01* 74 | D11* 75 | X152769619Y-101290857D02* 76 | X152745809Y-101219428D01* 77 | X152745809Y-101100380D01* 78 | X152769619Y-101052761D01* 79 | X152793428Y-101028952D01* 80 | X152841047Y-101005142D01* 81 | X152888666Y-101005142D01* 82 | X152936285Y-101028952D01* 83 | X152960095Y-101052761D01* 84 | X152983904Y-101100380D01* 85 | X153007714Y-101195619D01* 86 | X153031523Y-101243238D01* 87 | X153055333Y-101267047D01* 88 | X153102952Y-101290857D01* 89 | X153150571Y-101290857D01* 90 | X153198190Y-101267047D01* 91 | X153222000Y-101243238D01* 92 | X153245809Y-101195619D01* 93 | X153245809Y-101076571D01* 94 | X153222000Y-101005142D01* 95 | X152793428Y-100505142D02* 96 | X152769619Y-100528952D01* 97 | X152745809Y-100600380D01* 98 | X152745809Y-100648000D01* 99 | X152769619Y-100719428D01* 100 | X152817238Y-100767047D01* 101 | X152864857Y-100790857D01* 102 | X152960095Y-100814666D01* 103 | X153031523Y-100814666D01* 104 | X153126761Y-100790857D01* 105 | X153174380Y-100767047D01* 106 | X153222000Y-100719428D01* 107 | X153245809Y-100648000D01* 108 | X153245809Y-100600380D01* 109 | X153222000Y-100528952D01* 110 | X153198190Y-100505142D01* 111 | X152745809Y-100290857D02* 112 | X153245809Y-100290857D01* 113 | X152745809Y-100005142D02* 114 | X153031523Y-100219428D01* 115 | X153245809Y-100005142D02* 116 | X152960095Y-100290857D01* 117 | X155145809Y-101433714D02* 118 | X155645809Y-101433714D01* 119 | X155288666Y-101267047D01* 120 | X155645809Y-101100380D01* 121 | X155145809Y-101100380D01* 122 | X155145809Y-100862285D02* 123 | X155645809Y-100862285D01* 124 | X155169619Y-100648000D02* 125 | X155145809Y-100576571D01* 126 | X155145809Y-100457523D01* 127 | X155169619Y-100409904D01* 128 | X155193428Y-100386095D01* 129 | X155241047Y-100362285D01* 130 | X155288666Y-100362285D01* 131 | X155336285Y-100386095D01* 132 | X155360095Y-100409904D01* 133 | X155383904Y-100457523D01* 134 | X155407714Y-100552761D01* 135 | X155431523Y-100600380D01* 136 | X155455333Y-100624190D01* 137 | X155502952Y-100648000D01* 138 | X155550571Y-100648000D01* 139 | X155598190Y-100624190D01* 140 | X155622000Y-100600380D01* 141 | X155645809Y-100552761D01* 142 | X155645809Y-100433714D01* 143 | X155622000Y-100362285D01* 144 | X155645809Y-100052761D02* 145 | X155645809Y-99957523D01* 146 | X155622000Y-99909904D01* 147 | X155574380Y-99862285D01* 148 | X155479142Y-99838476D01* 149 | X155312476Y-99838476D01* 150 | X155217238Y-99862285D01* 151 | X155169619Y-99909904D01* 152 | X155145809Y-99957523D01* 153 | X155145809Y-100052761D01* 154 | X155169619Y-100100380D01* 155 | X155217238Y-100148000D01* 156 | X155312476Y-100171809D01* 157 | X155479142Y-100171809D01* 158 | X155574380Y-100148000D01* 159 | X155622000Y-100100380D01* 160 | X155645809Y-100052761D01* 161 | X147693428Y-100631333D02* 162 | X147669619Y-100655142D01* 163 | X147645809Y-100726571D01* 164 | X147645809Y-100774190D01* 165 | X147669619Y-100845619D01* 166 | X147717238Y-100893238D01* 167 | X147764857Y-100917047D01* 168 | X147860095Y-100940857D01* 169 | X147931523Y-100940857D01* 170 | X148026761Y-100917047D01* 171 | X148074380Y-100893238D01* 172 | X148122000Y-100845619D01* 173 | X148145809Y-100774190D01* 174 | X148145809Y-100726571D01* 175 | X148122000Y-100655142D01* 176 | X148098190Y-100631333D01* 177 | X147669619Y-100440857D02* 178 | X147645809Y-100369428D01* 179 | X147645809Y-100250380D01* 180 | X147669619Y-100202761D01* 181 | X147693428Y-100178952D01* 182 | X147741047Y-100155142D01* 183 | X147788666Y-100155142D01* 184 | X147836285Y-100178952D01* 185 | X147860095Y-100202761D01* 186 | X147883904Y-100250380D01* 187 | X147907714Y-100345619D01* 188 | X147931523Y-100393238D01* 189 | X147955333Y-100417047D01* 190 | X148002952Y-100440857D01* 191 | X148050571Y-100440857D01* 192 | X148098190Y-100417047D01* 193 | X148122000Y-100393238D01* 194 | X148145809Y-100345619D01* 195 | X148145809Y-100226571D01* 196 | X148122000Y-100155142D01* 197 | X150145809Y-101433714D02* 198 | X150645809Y-101433714D01* 199 | X150288666Y-101267047D01* 200 | X150645809Y-101100380D01* 201 | X150145809Y-101100380D01* 202 | X150645809Y-100767047D02* 203 | X150645809Y-100671809D01* 204 | X150622000Y-100624190D01* 205 | X150574380Y-100576571D01* 206 | X150479142Y-100552761D01* 207 | X150312476Y-100552761D01* 208 | X150217238Y-100576571D01* 209 | X150169619Y-100624190D01* 210 | X150145809Y-100671809D01* 211 | X150145809Y-100767047D01* 212 | X150169619Y-100814666D01* 213 | X150217238Y-100862285D01* 214 | X150312476Y-100886095D01* 215 | X150479142Y-100886095D01* 216 | X150574380Y-100862285D01* 217 | X150622000Y-100814666D01* 218 | X150645809Y-100767047D01* 219 | X150169619Y-100362285D02* 220 | X150145809Y-100290857D01* 221 | X150145809Y-100171809D01* 222 | X150169619Y-100124190D01* 223 | X150193428Y-100100380D01* 224 | X150241047Y-100076571D01* 225 | X150288666Y-100076571D01* 226 | X150336285Y-100100380D01* 227 | X150360095Y-100124190D01* 228 | X150383904Y-100171809D01* 229 | X150407714Y-100267047D01* 230 | X150431523Y-100314666D01* 231 | X150455333Y-100338476D01* 232 | X150502952Y-100362285D01* 233 | X150550571Y-100362285D01* 234 | X150598190Y-100338476D01* 235 | X150622000Y-100314666D01* 236 | X150645809Y-100267047D01* 237 | X150645809Y-100148000D01* 238 | X150622000Y-100076571D01* 239 | X150145809Y-99862285D02* 240 | X150645809Y-99862285D01* 241 | X158122000Y-101028952D02* 242 | X158145809Y-101076571D01* 243 | X158145809Y-101148000D01* 244 | X158122000Y-101219428D01* 245 | X158074380Y-101267047D01* 246 | X158026761Y-101290857D01* 247 | X157931523Y-101314666D01* 248 | X157860095Y-101314666D01* 249 | X157764857Y-101290857D01* 250 | X157717238Y-101267047D01* 251 | X157669619Y-101219428D01* 252 | X157645809Y-101148000D01* 253 | X157645809Y-101100380D01* 254 | X157669619Y-101028952D01* 255 | X157693428Y-101005142D01* 256 | X157860095Y-101005142D01* 257 | X157860095Y-101100380D01* 258 | X157645809Y-100790857D02* 259 | X158145809Y-100790857D01* 260 | X157645809Y-100505142D01* 261 | X158145809Y-100505142D01* 262 | X157645809Y-100267047D02* 263 | X158145809Y-100267047D01* 264 | X158145809Y-100148000D01* 265 | X158122000Y-100076571D01* 266 | X158074380Y-100028952D01* 267 | X158026761Y-100005142D01* 268 | X157931523Y-99981333D01* 269 | X157860095Y-99981333D01* 270 | X157764857Y-100005142D01* 271 | X157717238Y-100028952D01* 272 | X157669619Y-100076571D01* 273 | X157645809Y-100148000D01* 274 | X157645809Y-100267047D01* 275 | X145645809Y-101243238D02* 276 | X145645809Y-100933714D01* 277 | X145455333Y-101100380D01* 278 | X145455333Y-101028952D01* 279 | X145431523Y-100981333D01* 280 | X145407714Y-100957523D01* 281 | X145360095Y-100933714D01* 282 | X145241047Y-100933714D01* 283 | X145193428Y-100957523D01* 284 | X145169619Y-100981333D01* 285 | X145145809Y-101028952D01* 286 | X145145809Y-101171809D01* 287 | X145169619Y-101219428D01* 288 | X145193428Y-101243238D01* 289 | X145479142Y-100767047D02* 290 | X145145809Y-100648000D01* 291 | X145479142Y-100528952D01* 292 | X145645809Y-100386095D02* 293 | X145645809Y-100076571D01* 294 | X145455333Y-100243238D01* 295 | X145455333Y-100171809D01* 296 | X145431523Y-100124190D01* 297 | X145407714Y-100100380D01* 298 | X145360095Y-100076571D01* 299 | X145241047Y-100076571D01* 300 | X145193428Y-100100380D01* 301 | X145169619Y-100124190D01* 302 | X145145809Y-100171809D01* 303 | X145145809Y-100314666D01* 304 | X145169619Y-100362285D01* 305 | X145193428Y-100386095D01* 306 | D12* 307 | %TO.C,3*% 308 | X136516000Y-107050000D02* 309 | X135626000Y-107940000D01* 310 | X139076000Y-107420000D02* 311 | X137276000Y-107420000D01* 312 | X140726000Y-110500000D02* 313 | X140726000Y-107940000D01* 314 | X139346000Y-111770000D02* 315 | X137006000Y-111770000D01* 316 | X137276000Y-107420000D02* 317 | X136276000Y-108420000D01* 318 | X136276000Y-108420000D02* 319 | X136276000Y-110120000D01* 320 | X139346000Y-106670000D02* 321 | X137006000Y-106670000D01* 322 | X137176000Y-111020000D02* 323 | X139176000Y-111020000D01* 324 | X140726000Y-107940000D02* 325 | X139836000Y-107050000D01* 326 | X136516000Y-111390000D02* 327 | X135626000Y-110500000D01* 328 | X139976000Y-110220000D02* 329 | X139976000Y-108320000D01* 330 | X135626000Y-110500000D02* 331 | X135626000Y-107940000D01* 332 | X136276000Y-110120000D02* 333 | X137176000Y-111020000D01* 334 | X140726000Y-110500000D02* 335 | X139836000Y-111390000D01* 336 | X139976000Y-108320000D02* 337 | X139076000Y-107420000D01* 338 | X139176000Y-111020000D02* 339 | X139976000Y-110220000D01* 340 | X139456000Y-109220000D02* 341 | G75* 342 | G03* 343 | X139456000Y-109220000I-1280000J0D01* 344 | G01* 345 | D13* 346 | X140856000Y-112520000D02* 347 | G75* 348 | G03* 349 | X140856000Y-112520000I-80000J0D01* 350 | G01* 351 | D12* 352 | %TO.C,1*% 353 | X137276000Y-86470000D02* 354 | X136276000Y-87470000D01* 355 | X139976000Y-87370000D02* 356 | X139076000Y-86470000D01* 357 | X136516000Y-90440000D02* 358 | X135626000Y-89550000D01* 359 | X139176000Y-90070000D02* 360 | X139976000Y-89270000D01* 361 | X140726000Y-89550000D02* 362 | X139836000Y-90440000D01* 363 | X136276000Y-89170000D02* 364 | X137176000Y-90070000D01* 365 | X139346000Y-85720000D02* 366 | X137006000Y-85720000D01* 367 | X139346000Y-90820000D02* 368 | X137006000Y-90820000D01* 369 | X136276000Y-87470000D02* 370 | X136276000Y-89170000D01* 371 | X140726000Y-86990000D02* 372 | X139836000Y-86100000D01* 373 | X136516000Y-86100000D02* 374 | X135626000Y-86990000D01* 375 | X139076000Y-86470000D02* 376 | X137276000Y-86470000D01* 377 | X135626000Y-89550000D02* 378 | X135626000Y-86990000D01* 379 | X140726000Y-89550000D02* 380 | X140726000Y-86990000D01* 381 | X139976000Y-89270000D02* 382 | X139976000Y-87370000D01* 383 | X137176000Y-90070000D02* 384 | X139176000Y-90070000D01* 385 | D13* 386 | X140856000Y-91570000D02* 387 | G75* 388 | G03* 389 | X140856000Y-91570000I-80000J0D01* 390 | G01* 391 | D12* 392 | X139456000Y-88270000D02* 393 | G75* 394 | G03* 395 | X139456000Y-88270000I-1280000J0D01* 396 | G01* 397 | %TO.C,2*% 398 | X137276000Y-97060000D02* 399 | X136276000Y-98060000D01* 400 | X135626000Y-100140000D02* 401 | X135626000Y-97580000D01* 402 | X139176000Y-100660000D02* 403 | X139976000Y-99860000D01* 404 | X139346000Y-96310000D02* 405 | X137006000Y-96310000D01* 406 | X139976000Y-99860000D02* 407 | X139976000Y-97960000D01* 408 | X136276000Y-99760000D02* 409 | X137176000Y-100660000D01* 410 | X136276000Y-98060000D02* 411 | X136276000Y-99760000D01* 412 | X139346000Y-101410000D02* 413 | X137006000Y-101410000D01* 414 | X140726000Y-97580000D02* 415 | X139836000Y-96690000D01* 416 | X139976000Y-97960000D02* 417 | X139076000Y-97060000D01* 418 | X136516000Y-101030000D02* 419 | X135626000Y-100140000D01* 420 | X139076000Y-97060000D02* 421 | X137276000Y-97060000D01* 422 | X137176000Y-100660000D02* 423 | X139176000Y-100660000D01* 424 | X140726000Y-100140000D02* 425 | X139836000Y-101030000D01* 426 | X140726000Y-100140000D02* 427 | X140726000Y-97580000D01* 428 | X136516000Y-96690000D02* 429 | X135626000Y-97580000D01* 430 | D13* 431 | X140856000Y-102160000D02* 432 | G75* 433 | G03* 434 | X140856000Y-102160000I-80000J0D01* 435 | G01* 436 | D12* 437 | X139456000Y-98860000D02* 438 | G75* 439 | G03* 440 | X139456000Y-98860000I-1280000J0D01* 441 | G01* 442 | D14* 443 | %TO.C,J2*% 444 | X141672000Y-94948000D02* 445 | X141672000Y-114348000D01* 446 | X159572000Y-114348000D02* 447 | X141672000Y-114348000D01* 448 | X141672000Y-94948000D02* 449 | X159572000Y-94948000D01* 450 | X159572000Y-114348000D02* 451 | X159572000Y-94948000D01* 452 | X158972000Y-114348000D02* 453 | X144172000Y-114348000D01* 454 | X144172000Y-114348000D02* 455 | X144172000Y-99548000D01* 456 | X144172000Y-99548000D02* 457 | X158972000Y-99548000D01* 458 | X158972000Y-99548000D02* 459 | X158972000Y-114348000D01* 460 | %TD*% 461 | M02* 462 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-Edge_Cuts.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:25+01:00*% 3 | %TF.ProjectId,PicoMemcard-rp2040zero,5069636f-4d65-46d6-9361-72642d727032,1.3.1*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Profile,NP*% 6 | %FSLAX46Y46*% 7 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 8 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:25* 9 | %MOMM*% 10 | %LPD*% 11 | G01* 12 | G04 APERTURE LIST* 13 | %TA.AperFunction,Profile*% 14 | %ADD10C,0.100000*% 15 | %TD*% 16 | G04 APERTURE END LIST* 17 | D10* 18 | X140550386Y-64100624D02* 19 | G75* 20 | G03* 21 | X139850725Y-63399987I-681186J19424D01* 22 | G01* 23 | X130850000Y-70900000D02* 24 | X131950000Y-70900000D01* 25 | X150850272Y-64100620D02* 26 | G75* 27 | G03* 28 | X150150725Y-63399987I-673572J27020D01* 29 | G01* 30 | X140550318Y-70900622D02* 31 | G75* 32 | G03* 33 | X143150318Y-70900622I1300000J0D01* 34 | G01* 35 | X167050000Y-70899784D02* 36 | X167050000Y-78810000D01* 37 | X140550318Y-64100622D02* 38 | X140550318Y-70900622D01* 39 | X150850318Y-70900622D02* 40 | G75* 41 | G03* 42 | X153450318Y-70900622I1300000J0D01* 43 | G01* 44 | X150850318Y-64100622D02* 45 | X150850318Y-70900622D01* 46 | X161150282Y-70900622D02* 47 | G75* 48 | G03* 49 | X163750318Y-70899784I1300018J422D01* 50 | G01* 51 | X133700000Y-105600000D02* 52 | X133700000Y-114620000D01* 53 | X131950082Y-70900000D02* 54 | G75* 55 | G03* 56 | X134550318Y-70899553I1300118J0D01* 57 | G01* 58 | X167050000Y-90810000D02* 59 | X146010000Y-90810000D01* 60 | X134550318Y-70899553D02* 61 | X134550318Y-64100216D01* 62 | X167050000Y-78810000D02* 63 | X146010000Y-78810000D01* 64 | X163750318Y-70899784D02* 65 | X167050000Y-70899784D01* 66 | X161150318Y-64100622D02* 67 | X161150318Y-70900622D01* 68 | X154150318Y-63400623D02* 69 | G75* 70 | G03* 71 | X153449683Y-64100216I-26918J-673677D01* 72 | G01* 73 | X143150318Y-70900622D02* 74 | X143149683Y-64100216D01* 75 | X146010000Y-90810000D02* 76 | X146010000Y-78810000D01* 77 | X143850318Y-63400611D02* 78 | G75* 79 | G03* 80 | X143149683Y-64100216I-19518J-681089D01* 81 | G01* 82 | X135250318Y-63400630D02* 83 | G75* 84 | G03* 85 | X134550318Y-64100216I-19518J-680470D01* 86 | G01* 87 | X167050000Y-105600000D02* 88 | X164200000Y-105600000D01* 89 | X135250318Y-63400622D02* 90 | X139850725Y-63399987D01* 91 | X154150318Y-63400622D02* 92 | X160450725Y-63399987D01* 93 | X164200000Y-114620000D02* 94 | X164200000Y-105600000D01* 95 | X167050000Y-105600000D02* 96 | X167050000Y-90810000D01* 97 | X130850000Y-105600000D02* 98 | X130850000Y-70900000D01* 99 | X161150272Y-64100620D02* 100 | G75* 101 | G03* 102 | X160450725Y-63399987I-673572J27020D01* 103 | G01* 104 | X130850000Y-105600000D02* 105 | X133700000Y-105600000D01* 106 | X153450318Y-70900622D02* 107 | X153449683Y-64100216D01* 108 | X143850318Y-63400622D02* 109 | X150150725Y-63399987D01* 110 | X164200000Y-114620000D02* 111 | X133700000Y-114620000D01* 112 | M02* 113 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-F_Mask.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:25+01:00*% 3 | %TF.ProjectId,PicoMemcard-rp2040zero,5069636f-4d65-46d6-9361-72642d727032,1.3.1*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Soldermask,Top*% 6 | %TF.FilePolarity,Negative*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:25* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10O,1.500000X2.500000*% 15 | %ADD11O,2.500000X1.500000*% 16 | %ADD12C,3.200000*% 17 | %ADD13R,1.400000X6.500000*% 18 | %ADD14R,1.400000X7.300000*% 19 | G04 APERTURE END LIST* 20 | D10* 21 | %TO.C,U1*% 22 | X165420000Y-92930000D03* 23 | X162880000Y-92930000D03* 24 | X160340000Y-92930000D03* 25 | X157800000Y-92930000D03* 26 | X155260000Y-92930000D03* 27 | X152720000Y-92930000D03* 28 | X150180000Y-92930000D03* 29 | X147640000Y-92930000D03* 30 | X145100000Y-92930000D03* 31 | D11* 32 | X144600000Y-89890000D03* 33 | X144600000Y-87350000D03* 34 | X144600000Y-84810000D03* 35 | X144600000Y-82270000D03* 36 | X144600000Y-79730000D03* 37 | D10* 38 | X145100000Y-76690000D03* 39 | X147640000Y-76690000D03* 40 | X150180000Y-76690000D03* 41 | X152720000Y-76690000D03* 42 | X155260000Y-76690000D03* 43 | X157800000Y-76690000D03* 44 | X160340000Y-76690000D03* 45 | X162880000Y-76690000D03* 46 | X165420000Y-76690000D03* 47 | %TD*% 48 | D12* 49 | %TO.C,H2*% 50 | X163530000Y-102070000D03* 51 | %TD*% 52 | %TO.C,H1*% 53 | X134370000Y-75730000D03* 54 | %TD*% 55 | D13* 56 | %TO.C,J1*% 57 | X137520000Y-67600000D03* 58 | X139820000Y-67600000D03* 59 | D14* 60 | X145520000Y-67200000D03* 61 | X147820000Y-67200000D03* 62 | X150120000Y-67200000D03* 63 | D13* 64 | X155820000Y-67600000D03* 65 | X158120000Y-67600000D03* 66 | X160420000Y-67600000D03* 67 | %TD*% 68 | M02* 69 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-F_Paste.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:25+01:00*% 3 | %TF.ProjectId,PicoMemcard-rp2040zero,5069636f-4d65-46d6-9361-72642d727032,1.3.1*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Paste,Top*% 6 | %TF.FilePolarity,Positive*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:25* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10O,1.500000X2.500000*% 15 | %ADD11O,2.500000X1.500000*% 16 | %ADD12R,1.400000X6.500000*% 17 | %ADD13R,1.400000X7.300000*% 18 | G04 APERTURE END LIST* 19 | D10* 20 | %TO.C,U1*% 21 | X165420000Y-92930000D03* 22 | X162880000Y-92930000D03* 23 | X160340000Y-92930000D03* 24 | X157800000Y-92930000D03* 25 | X155260000Y-92930000D03* 26 | X152720000Y-92930000D03* 27 | X150180000Y-92930000D03* 28 | X147640000Y-92930000D03* 29 | X145100000Y-92930000D03* 30 | D11* 31 | X144600000Y-89890000D03* 32 | X144600000Y-87350000D03* 33 | X144600000Y-84810000D03* 34 | X144600000Y-82270000D03* 35 | X144600000Y-79730000D03* 36 | D10* 37 | X145100000Y-76690000D03* 38 | X147640000Y-76690000D03* 39 | X150180000Y-76690000D03* 40 | X152720000Y-76690000D03* 41 | X155260000Y-76690000D03* 42 | X157800000Y-76690000D03* 43 | X160340000Y-76690000D03* 44 | X162880000Y-76690000D03* 45 | X165420000Y-76690000D03* 46 | %TD*% 47 | D12* 48 | %TO.C,J1*% 49 | X137520000Y-67600000D03* 50 | X139820000Y-67600000D03* 51 | D13* 52 | X145520000Y-67200000D03* 53 | X147820000Y-67200000D03* 54 | X150120000Y-67200000D03* 55 | D12* 56 | X155820000Y-67600000D03* 57 | X158120000Y-67600000D03* 58 | X160420000Y-67600000D03* 59 | %TD*% 60 | M02* 61 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-F_Silkscreen.gbr: -------------------------------------------------------------------------------- 1 | %TF.GenerationSoftware,KiCad,Pcbnew,(6.0.5)*% 2 | %TF.CreationDate,2023-02-05T19:42:25+01:00*% 3 | %TF.ProjectId,PicoMemcard-rp2040zero,5069636f-4d65-46d6-9361-72642d727032,1.3.1*% 4 | %TF.SameCoordinates,Original*% 5 | %TF.FileFunction,Legend,Top*% 6 | %TF.FilePolarity,Positive*% 7 | %FSLAX46Y46*% 8 | G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)* 9 | G04 Created by KiCad (PCBNEW (6.0.5)) date 2023-02-05 19:42:25* 10 | %MOMM*% 11 | %LPD*% 12 | G01* 13 | G04 APERTURE LIST* 14 | %ADD10C,0.220000*% 15 | %ADD11C,0.300000*% 16 | %ADD12C,0.200000*% 17 | %ADD13C,0.150000*% 18 | G04 APERTURE END LIST* 19 | D10* 20 | X145375809Y-102823714D02* 21 | X145375809Y-103633238D01* 22 | X145328190Y-103728476D01* 23 | X145280571Y-103776095D01* 24 | X145185333Y-103823714D01* 25 | X145042476Y-103823714D01* 26 | X144947238Y-103776095D01* 27 | X145375809Y-103442761D02* 28 | X145280571Y-103490380D01* 29 | X145090095Y-103490380D01* 30 | X144994857Y-103442761D01* 31 | X144947238Y-103395142D01* 32 | X144899619Y-103299904D01* 33 | X144899619Y-103014190D01* 34 | X144947238Y-102918952D01* 35 | X144994857Y-102871333D01* 36 | X145090095Y-102823714D01* 37 | X145280571Y-102823714D01* 38 | X145375809Y-102871333D01* 39 | X145852000Y-103490380D02* 40 | X145852000Y-102823714D01* 41 | X145852000Y-102490380D02* 42 | X145804380Y-102538000D01* 43 | X145852000Y-102585619D01* 44 | X145899619Y-102538000D01* 45 | X145852000Y-102490380D01* 46 | X145852000Y-102585619D01* 47 | X146185333Y-102823714D02* 48 | X146566285Y-102823714D01* 49 | X146328190Y-102490380D02* 50 | X146328190Y-103347523D01* 51 | X146375809Y-103442761D01* 52 | X146471047Y-103490380D01* 53 | X146566285Y-103490380D01* 54 | X146899619Y-103490380D02* 55 | X146899619Y-102490380D01* 56 | X147328190Y-103490380D02* 57 | X147328190Y-102966571D01* 58 | X147280571Y-102871333D01* 59 | X147185333Y-102823714D01* 60 | X147042476Y-102823714D01* 61 | X146947238Y-102871333D01* 62 | X146899619Y-102918952D01* 63 | X148232952Y-102823714D02* 64 | X148232952Y-103490380D01* 65 | X147804380Y-102823714D02* 66 | X147804380Y-103347523D01* 67 | X147852000Y-103442761D01* 68 | X147947238Y-103490380D01* 69 | X148090095Y-103490380D01* 70 | X148185333Y-103442761D01* 71 | X148232952Y-103395142D01* 72 | X148709142Y-103490380D02* 73 | X148709142Y-102490380D01* 74 | X148709142Y-102871333D02* 75 | X148804380Y-102823714D01* 76 | X148994857Y-102823714D01* 77 | X149090095Y-102871333D01* 78 | X149137714Y-102918952D01* 79 | X149185333Y-103014190D01* 80 | X149185333Y-103299904D01* 81 | X149137714Y-103395142D01* 82 | X149090095Y-103442761D01* 83 | X148994857Y-103490380D01* 84 | X148804380Y-103490380D01* 85 | X148709142Y-103442761D01* 86 | X149613904Y-103395142D02* 87 | X149661523Y-103442761D01* 88 | X149613904Y-103490380D01* 89 | X149566285Y-103442761D01* 90 | X149613904Y-103395142D01* 91 | X149613904Y-103490380D01* 92 | X150518666Y-103442761D02* 93 | X150423428Y-103490380D01* 94 | X150232952Y-103490380D01* 95 | X150137714Y-103442761D01* 96 | X150090095Y-103395142D01* 97 | X150042476Y-103299904D01* 98 | X150042476Y-103014190D01* 99 | X150090095Y-102918952D01* 100 | X150137714Y-102871333D01* 101 | X150232952Y-102823714D01* 102 | X150423428Y-102823714D01* 103 | X150518666Y-102871333D01* 104 | X151090095Y-103490380D02* 105 | X150994857Y-103442761D01* 106 | X150947238Y-103395142D01* 107 | X150899619Y-103299904D01* 108 | X150899619Y-103014190D01* 109 | X150947238Y-102918952D01* 110 | X150994857Y-102871333D01* 111 | X151090095Y-102823714D01* 112 | X151232952Y-102823714D01* 113 | X151328190Y-102871333D01* 114 | X151375809Y-102918952D01* 115 | X151423428Y-103014190D01* 116 | X151423428Y-103299904D01* 117 | X151375809Y-103395142D01* 118 | X151328190Y-103442761D01* 119 | X151232952Y-103490380D01* 120 | X151090095Y-103490380D01* 121 | X151852000Y-103490380D02* 122 | X151852000Y-102823714D01* 123 | X151852000Y-102918952D02* 124 | X151899619Y-102871333D01* 125 | X151994857Y-102823714D01* 126 | X152137714Y-102823714D01* 127 | X152232952Y-102871333D01* 128 | X152280571Y-102966571D01* 129 | X152280571Y-103490380D01* 130 | X152280571Y-102966571D02* 131 | X152328190Y-102871333D01* 132 | X152423428Y-102823714D01* 133 | X152566285Y-102823714D01* 134 | X152661523Y-102871333D01* 135 | X152709142Y-102966571D01* 136 | X152709142Y-103490380D01* 137 | X153899619Y-102442761D02* 138 | X153042476Y-103728476D01* 139 | X146994857Y-105100380D02* 140 | X146994857Y-104100380D01* 141 | X146994857Y-105052761D02* 142 | X146899619Y-105100380D01* 143 | X146709142Y-105100380D01* 144 | X146613904Y-105052761D01* 145 | X146566285Y-105005142D01* 146 | X146518666Y-104909904D01* 147 | X146518666Y-104624190D01* 148 | X146566285Y-104528952D01* 149 | X146613904Y-104481333D01* 150 | X146709142Y-104433714D01* 151 | X146899619Y-104433714D01* 152 | X146994857Y-104481333D01* 153 | X147899619Y-105100380D02* 154 | X147899619Y-104576571D01* 155 | X147852000Y-104481333D01* 156 | X147756761Y-104433714D01* 157 | X147566285Y-104433714D01* 158 | X147471047Y-104481333D01* 159 | X147899619Y-105052761D02* 160 | X147804380Y-105100380D01* 161 | X147566285Y-105100380D01* 162 | X147471047Y-105052761D01* 163 | X147423428Y-104957523D01* 164 | X147423428Y-104862285D01* 165 | X147471047Y-104767047D01* 166 | X147566285Y-104719428D01* 167 | X147804380Y-104719428D01* 168 | X147899619Y-104671809D01* 169 | X148375809Y-104433714D02* 170 | X148375809Y-105100380D01* 171 | X148375809Y-104528952D02* 172 | X148423428Y-104481333D01* 173 | X148518666Y-104433714D01* 174 | X148661523Y-104433714D01* 175 | X148756761Y-104481333D01* 176 | X148804380Y-104576571D01* 177 | X148804380Y-105100380D01* 178 | X149709142Y-104433714D02* 179 | X149709142Y-105243238D01* 180 | X149661523Y-105338476D01* 181 | X149613904Y-105386095D01* 182 | X149518666Y-105433714D01* 183 | X149375809Y-105433714D01* 184 | X149280571Y-105386095D01* 185 | X149709142Y-105052761D02* 186 | X149613904Y-105100380D01* 187 | X149423428Y-105100380D01* 188 | X149328190Y-105052761D01* 189 | X149280571Y-105005142D01* 190 | X149232952Y-104909904D01* 191 | X149232952Y-104624190D01* 192 | X149280571Y-104528952D01* 193 | X149328190Y-104481333D01* 194 | X149423428Y-104433714D01* 195 | X149613904Y-104433714D01* 196 | X149709142Y-104481333D01* 197 | X150185333Y-105100380D02* 198 | X150185333Y-104433714D01* 199 | X150185333Y-104100380D02* 200 | X150137714Y-104148000D01* 201 | X150185333Y-104195619D01* 202 | X150232952Y-104148000D01* 203 | X150185333Y-104100380D01* 204 | X150185333Y-104195619D01* 205 | X151090095Y-104433714D02* 206 | X151090095Y-105100380D01* 207 | X150661523Y-104433714D02* 208 | X150661523Y-104957523D01* 209 | X150709142Y-105052761D01* 210 | X150804380Y-105100380D01* 211 | X150947238Y-105100380D01* 212 | X151042476Y-105052761D01* 213 | X151090095Y-105005142D01* 214 | X152280571Y-104052761D02* 215 | X151423428Y-105338476D01* 216 | X144661523Y-106710380D02* 217 | X144661523Y-105710380D01* 218 | X145042476Y-105710380D01* 219 | X145137714Y-105758000D01* 220 | X145185333Y-105805619D01* 221 | X145232952Y-105900857D01* 222 | X145232952Y-106043714D01* 223 | X145185333Y-106138952D01* 224 | X145137714Y-106186571D01* 225 | X145042476Y-106234190D01* 226 | X144661523Y-106234190D01* 227 | X145661523Y-106710380D02* 228 | X145661523Y-106043714D01* 229 | X145661523Y-105710380D02* 230 | X145613904Y-105758000D01* 231 | X145661523Y-105805619D01* 232 | X145709142Y-105758000D01* 233 | X145661523Y-105710380D01* 234 | X145661523Y-105805619D01* 235 | X146566285Y-106662761D02* 236 | X146471047Y-106710380D01* 237 | X146280571Y-106710380D01* 238 | X146185333Y-106662761D01* 239 | X146137714Y-106615142D01* 240 | X146090095Y-106519904D01* 241 | X146090095Y-106234190D01* 242 | X146137714Y-106138952D01* 243 | X146185333Y-106091333D01* 244 | X146280571Y-106043714D01* 245 | X146471047Y-106043714D01* 246 | X146566285Y-106091333D01* 247 | X147137714Y-106710380D02* 248 | X147042476Y-106662761D01* 249 | X146994857Y-106615142D01* 250 | X146947238Y-106519904D01* 251 | X146947238Y-106234190D01* 252 | X146994857Y-106138952D01* 253 | X147042476Y-106091333D01* 254 | X147137714Y-106043714D01* 255 | X147280571Y-106043714D01* 256 | X147375809Y-106091333D01* 257 | X147423428Y-106138952D01* 258 | X147471047Y-106234190D01* 259 | X147471047Y-106519904D01* 260 | X147423428Y-106615142D01* 261 | X147375809Y-106662761D01* 262 | X147280571Y-106710380D01* 263 | X147137714Y-106710380D01* 264 | X147899619Y-106710380D02* 265 | X147899619Y-105710380D01* 266 | X148232952Y-106424666D01* 267 | X148566285Y-105710380D01* 268 | X148566285Y-106710380D01* 269 | X149423428Y-106662761D02* 270 | X149328190Y-106710380D01* 271 | X149137714Y-106710380D01* 272 | X149042476Y-106662761D01* 273 | X148994857Y-106567523D01* 274 | X148994857Y-106186571D01* 275 | X149042476Y-106091333D01* 276 | X149137714Y-106043714D01* 277 | X149328190Y-106043714D01* 278 | X149423428Y-106091333D01* 279 | X149471047Y-106186571D01* 280 | X149471047Y-106281809D01* 281 | X148994857Y-106377047D01* 282 | X149899619Y-106710380D02* 283 | X149899619Y-106043714D01* 284 | X149899619Y-106138952D02* 285 | X149947238Y-106091333D01* 286 | X150042476Y-106043714D01* 287 | X150185333Y-106043714D01* 288 | X150280571Y-106091333D01* 289 | X150328190Y-106186571D01* 290 | X150328190Y-106710380D01* 291 | X150328190Y-106186571D02* 292 | X150375809Y-106091333D01* 293 | X150471047Y-106043714D01* 294 | X150613904Y-106043714D01* 295 | X150709142Y-106091333D01* 296 | X150756761Y-106186571D01* 297 | X150756761Y-106710380D01* 298 | X151661523Y-106662761D02* 299 | X151566285Y-106710380D01* 300 | X151375809Y-106710380D01* 301 | X151280571Y-106662761D01* 302 | X151232952Y-106615142D01* 303 | X151185333Y-106519904D01* 304 | X151185333Y-106234190D01* 305 | X151232952Y-106138952D01* 306 | X151280571Y-106091333D01* 307 | X151375809Y-106043714D01* 308 | X151566285Y-106043714D01* 309 | X151661523Y-106091333D01* 310 | X152518666Y-106710380D02* 311 | X152518666Y-106186571D01* 312 | X152471047Y-106091333D01* 313 | X152375809Y-106043714D01* 314 | X152185333Y-106043714D01* 315 | X152090095Y-106091333D01* 316 | X152518666Y-106662761D02* 317 | X152423428Y-106710380D01* 318 | X152185333Y-106710380D01* 319 | X152090095Y-106662761D01* 320 | X152042476Y-106567523D01* 321 | X152042476Y-106472285D01* 322 | X152090095Y-106377047D01* 323 | X152185333Y-106329428D01* 324 | X152423428Y-106329428D01* 325 | X152518666Y-106281809D01* 326 | X152994857Y-106710380D02* 327 | X152994857Y-106043714D01* 328 | X152994857Y-106234190D02* 329 | X153042476Y-106138952D01* 330 | X153090095Y-106091333D01* 331 | X153185333Y-106043714D01* 332 | X153280571Y-106043714D01* 333 | X154042476Y-106710380D02* 334 | X154042476Y-105710380D01* 335 | X154042476Y-106662761D02* 336 | X153947238Y-106710380D01* 337 | X153756761Y-106710380D01* 338 | X153661523Y-106662761D01* 339 | X153613904Y-106615142D01* 340 | X153566285Y-106519904D01* 341 | X153566285Y-106234190D01* 342 | X153613904Y-106138952D01* 343 | X153661523Y-106091333D01* 344 | X153756761Y-106043714D01* 345 | X153947238Y-106043714D01* 346 | X154042476Y-106091333D01* 347 | D11* 348 | X145629714Y-108898571D02* 349 | X145986857Y-109898571D01* 350 | X146344000Y-108898571D01* 351 | X147701142Y-109898571D02* 352 | X146844000Y-109898571D01* 353 | X147272571Y-109898571D02* 354 | X147272571Y-108398571D01* 355 | X147129714Y-108612857D01* 356 | X146986857Y-108755714D01* 357 | X146844000Y-108827142D01* 358 | X148344000Y-109755714D02* 359 | X148415428Y-109827142D01* 360 | X148344000Y-109898571D01* 361 | X148272571Y-109827142D01* 362 | X148344000Y-109755714D01* 363 | X148344000Y-109898571D01* 364 | X148915428Y-108398571D02* 365 | X149844000Y-108398571D01* 366 | X149344000Y-108970000D01* 367 | X149558285Y-108970000D01* 368 | X149701142Y-109041428D01* 369 | X149772571Y-109112857D01* 370 | X149844000Y-109255714D01* 371 | X149844000Y-109612857D01* 372 | X149772571Y-109755714D01* 373 | X149701142Y-109827142D01* 374 | X149558285Y-109898571D01* 375 | X149129714Y-109898571D01* 376 | X148986857Y-109827142D01* 377 | X148915428Y-109755714D01* 378 | X150486857Y-109755714D02* 379 | X150558285Y-109827142D01* 380 | X150486857Y-109898571D01* 381 | X150415428Y-109827142D01* 382 | X150486857Y-109755714D01* 383 | X150486857Y-109898571D01* 384 | X151986857Y-109898571D02* 385 | X151129714Y-109898571D01* 386 | X151558285Y-109898571D02* 387 | X151558285Y-108398571D01* 388 | X151415428Y-108612857D01* 389 | X151272571Y-108755714D01* 390 | X151129714Y-108827142D01* 391 | D12* 392 | X153368952Y-112482380D02* 393 | X153368952Y-113196666D01* 394 | X153321333Y-113339523D01* 395 | X153226095Y-113434761D01* 396 | X153083238Y-113482380D01* 397 | X152988000Y-113482380D01* 398 | X154321333Y-113482380D02* 399 | X153845142Y-113482380D01* 400 | X153845142Y-112482380D01* 401 | X155226095Y-113387142D02* 402 | X155178476Y-113434761D01* 403 | X155035619Y-113482380D01* 404 | X154940380Y-113482380D01* 405 | X154797523Y-113434761D01* 406 | X154702285Y-113339523D01* 407 | X154654666Y-113244285D01* 408 | X154607047Y-113053809D01* 409 | X154607047Y-112910952D01* 410 | X154654666Y-112720476D01* 411 | X154702285Y-112625238D01* 412 | X154797523Y-112530000D01* 413 | X154940380Y-112482380D01* 414 | X155035619Y-112482380D01* 415 | X155178476Y-112530000D01* 416 | X155226095Y-112577619D01* 417 | X155940380Y-112482380D02* 418 | X155940380Y-113196666D01* 419 | X155892761Y-113339523D01* 420 | X155797523Y-113434761D01* 421 | X155654666Y-113482380D01* 422 | X155559428Y-113482380D01* 423 | X156892761Y-113482380D02* 424 | X156416571Y-113482380D01* 425 | X156416571Y-112482380D01* 426 | X157797523Y-113387142D02* 427 | X157749904Y-113434761D01* 428 | X157607047Y-113482380D01* 429 | X157511809Y-113482380D01* 430 | X157368952Y-113434761D01* 431 | X157273714Y-113339523D01* 432 | X157226095Y-113244285D01* 433 | X157178476Y-113053809D01* 434 | X157178476Y-112910952D01* 435 | X157226095Y-112720476D01* 436 | X157273714Y-112625238D01* 437 | X157368952Y-112530000D01* 438 | X157511809Y-112482380D01* 439 | X157607047Y-112482380D01* 440 | X157749904Y-112530000D01* 441 | X157797523Y-112577619D01* 442 | X158511809Y-112482380D02* 443 | X158511809Y-113196666D01* 444 | X158464190Y-113339523D01* 445 | X158368952Y-113434761D01* 446 | X158226095Y-113482380D01* 447 | X158130857Y-113482380D01* 448 | X159464190Y-113482380D02* 449 | X158988000Y-113482380D01* 450 | X158988000Y-112482380D01* 451 | X160368952Y-113387142D02* 452 | X160321333Y-113434761D01* 453 | X160178476Y-113482380D01* 454 | X160083238Y-113482380D01* 455 | X159940380Y-113434761D01* 456 | X159845142Y-113339523D01* 457 | X159797523Y-113244285D01* 458 | X159749904Y-113053809D01* 459 | X159749904Y-112910952D01* 460 | X159797523Y-112720476D01* 461 | X159845142Y-112625238D01* 462 | X159940380Y-112530000D01* 463 | X160083238Y-112482380D01* 464 | X160178476Y-112482380D01* 465 | X160321333Y-112530000D01* 466 | X160368952Y-112577619D01* 467 | X161083238Y-112482380D02* 468 | X161083238Y-113196666D01* 469 | X161035619Y-113339523D01* 470 | X160940380Y-113434761D01* 471 | X160797523Y-113482380D01* 472 | X160702285Y-113482380D01* 473 | X162035619Y-113482380D02* 474 | X161559428Y-113482380D01* 475 | X161559428Y-112482380D01* 476 | X162940380Y-113387142D02* 477 | X162892761Y-113434761D01* 478 | X162749904Y-113482380D01* 479 | X162654666Y-113482380D01* 480 | X162511809Y-113434761D01* 481 | X162416571Y-113339523D01* 482 | X162368952Y-113244285D01* 483 | X162321333Y-113053809D01* 484 | X162321333Y-112910952D01* 485 | X162368952Y-112720476D01* 486 | X162416571Y-112625238D01* 487 | X162511809Y-112530000D01* 488 | X162654666Y-112482380D01* 489 | X162749904Y-112482380D01* 490 | X162892761Y-112530000D01* 491 | X162940380Y-112577619D01* 492 | D13* 493 | %TO.C,J1*% 494 | X147486666Y-71552380D02* 495 | X147486666Y-72266666D01* 496 | X147439047Y-72409523D01* 497 | X147343809Y-72504761D01* 498 | X147200952Y-72552380D01* 499 | X147105714Y-72552380D01* 500 | X148486666Y-72552380D02* 501 | X147915238Y-72552380D01* 502 | X148200952Y-72552380D02* 503 | X148200952Y-71552380D01* 504 | X148105714Y-71695238D01* 505 | X148010476Y-71790476D01* 506 | X147915238Y-71838095D01* 507 | %TD*% 508 | M02* 509 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-NPTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ; DRILL file {KiCad (6.0.5)} date Sun Feb 5 19:42:24 2023 3 | ; FORMAT={-:-/ absolute / metric / decimal} 4 | ; #@! TF.CreationDate,2023-02-05T19:42:24+01:00 5 | ; #@! TF.GenerationSoftware,Kicad,Pcbnew,(6.0.5) 6 | ; #@! TF.FileFunction,NonPlated,1,2,NPTH 7 | FMAT,2 8 | METRIC 9 | ; #@! TA.AperFunction,NonPlated,NPTH,ComponentDrill 10 | T1C3.200 11 | % 12 | G90 13 | G05 14 | T1 15 | X134.37Y-75.73 16 | X163.53Y-102.07 17 | T0 18 | M30 19 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-PTH.drl: -------------------------------------------------------------------------------- 1 | M48 2 | ; DRILL file {KiCad (6.0.5)} date Sun Feb 5 19:42:24 2023 3 | ; FORMAT={-:-/ absolute / metric / decimal} 4 | ; #@! TF.CreationDate,2023-02-05T19:42:24+01:00 5 | ; #@! TF.GenerationSoftware,Kicad,Pcbnew,(6.0.5) 6 | ; #@! TF.FileFunction,Plated,1,2,PTH 7 | FMAT,2 8 | METRIC 9 | ; #@! TA.AperFunction,Plated,PTH,ViaDrill 10 | T1C0.200 11 | ; #@! TA.AperFunction,Plated,PTH,ViaDrill 12 | T2C0.400 13 | % 14 | G90 15 | G05 16 | T1 17 | X148.844Y-76.708 18 | X148.844Y-91.186 19 | X151.384Y-75.946 20 | X153.924Y-75.252 21 | X156.464Y-91.948 22 | X156.972Y-94.673 23 | X156.972Y-100.076 24 | T2 25 | X133.096Y-80.772 26 | X141.478Y-73.914 27 | X142.24Y-92.964 28 | X146.05Y-111.252 29 | X146.304Y-72.136 30 | X150.114Y-71.628 31 | X156.464Y-102.616 32 | X159.004Y-78.232 33 | X161.544Y-75.184 34 | X163.068Y-74.676 35 | X163.83Y-96.52 36 | T0 37 | M30 38 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/Gerber/PicoMemcard-rp2040zero-job.gbrjob: -------------------------------------------------------------------------------- 1 | { 2 | "Header": { 3 | "GenerationSoftware": { 4 | "Vendor": "KiCad", 5 | "Application": "Pcbnew", 6 | "Version": "(6.0.5)" 7 | }, 8 | "CreationDate": "2023-02-05T19:42:25+01:00" 9 | }, 10 | "GeneralSpecs": { 11 | "ProjectId": { 12 | "Name": "PicoMemcard-rp2040zero", 13 | "GUID": "5069636f-4d65-46d6-9361-72642d727032", 14 | "Revision": "1.3.1" 15 | }, 16 | "Size": { 17 | "X": 36.3, 18 | "Y": 51.3205 19 | }, 20 | "LayerNumber": 2, 21 | "BoardThickness": 1.6, 22 | "Finish": "None" 23 | }, 24 | "DesignRules": [ 25 | { 26 | "Layers": "Outer", 27 | "PadToPad": 0.127, 28 | "PadToTrack": 0.127, 29 | "TrackToTrack": 0.2, 30 | "MinLineWidth": 0.254, 31 | "TrackToRegion": 0.508, 32 | "RegionToRegion": 0.508 33 | } 34 | ], 35 | "FilesAttributes": [ 36 | { 37 | "Path": "PicoMemcard-rp2040zero-F_Cu.gbr", 38 | "FileFunction": "Copper,L1,Top", 39 | "FilePolarity": "Positive" 40 | }, 41 | { 42 | "Path": "PicoMemcard-rp2040zero-B_Cu.gbr", 43 | "FileFunction": "Copper,L2,Bot", 44 | "FilePolarity": "Positive" 45 | }, 46 | { 47 | "Path": "PicoMemcard-rp2040zero-F_Paste.gbr", 48 | "FileFunction": "SolderPaste,Top", 49 | "FilePolarity": "Positive" 50 | }, 51 | { 52 | "Path": "PicoMemcard-rp2040zero-B_Paste.gbr", 53 | "FileFunction": "SolderPaste,Bot", 54 | "FilePolarity": "Positive" 55 | }, 56 | { 57 | "Path": "PicoMemcard-rp2040zero-F_Silkscreen.gbr", 58 | "FileFunction": "Legend,Top", 59 | "FilePolarity": "Positive" 60 | }, 61 | { 62 | "Path": "PicoMemcard-rp2040zero-B_Silkscreen.gbr", 63 | "FileFunction": "Legend,Bot", 64 | "FilePolarity": "Positive" 65 | }, 66 | { 67 | "Path": "PicoMemcard-rp2040zero-F_Mask.gbr", 68 | "FileFunction": "SolderMask,Top", 69 | "FilePolarity": "Negative" 70 | }, 71 | { 72 | "Path": "PicoMemcard-rp2040zero-B_Mask.gbr", 73 | "FileFunction": "SolderMask,Bot", 74 | "FilePolarity": "Negative" 75 | }, 76 | { 77 | "Path": "PicoMemcard-rp2040zero-Edge_Cuts.gbr", 78 | "FileFunction": "Profile", 79 | "FilePolarity": "Positive" 80 | } 81 | ], 82 | "MaterialStackup": [ 83 | { 84 | "Type": "Legend", 85 | "Name": "Top Silk Screen" 86 | }, 87 | { 88 | "Type": "SolderPaste", 89 | "Name": "Top Solder Paste" 90 | }, 91 | { 92 | "Type": "SolderMask", 93 | "Thickness": 0.01, 94 | "Name": "Top Solder Mask" 95 | }, 96 | { 97 | "Type": "Copper", 98 | "Thickness": 0.035, 99 | "Name": "F.Cu" 100 | }, 101 | { 102 | "Type": "Dielectric", 103 | "Thickness": 1.51, 104 | "Material": "FR4", 105 | "Name": "F.Cu/B.Cu", 106 | "Notes": "Type: dielectric layer 1 (from F.Cu to B.Cu)" 107 | }, 108 | { 109 | "Type": "Copper", 110 | "Thickness": 0.035, 111 | "Name": "B.Cu" 112 | }, 113 | { 114 | "Type": "SolderMask", 115 | "Thickness": 0.01, 116 | "Name": "Bottom Solder Mask" 117 | }, 118 | { 119 | "Type": "SolderPaste", 120 | "Name": "Bottom Solder Paste" 121 | }, 122 | { 123 | "Type": "Legend", 124 | "Name": "Bottom Silk Screen" 125 | } 126 | ] 127 | } 128 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/PicoMemcard-rp2040zero-backups/PicoMemcard-rp2040zero-2023-02-05_194235.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dangiu/PicoMemcard/9ea646810366574740b03e3211b655de870a03dc/pcb/PicoMemcard-rp2040zero/PicoMemcard-rp2040zero-backups/PicoMemcard-rp2040zero-2023-02-05_194235.zip -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/PicoMemcard-rp2040zero.kicad_prl: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "active_layer": 31, 4 | "active_layer_preset": "", 5 | "auto_track_width": true, 6 | "hidden_nets": [], 7 | "high_contrast_mode": 0, 8 | "net_color_mode": 1, 9 | "opacity": { 10 | "pads": 1.0, 11 | "tracks": 1.0, 12 | "vias": 1.0, 13 | "zones": 0.6 14 | }, 15 | "ratsnest_display_mode": 0, 16 | "selection_filter": { 17 | "dimensions": true, 18 | "footprints": true, 19 | "graphics": true, 20 | "keepouts": true, 21 | "lockedItems": true, 22 | "otherItems": true, 23 | "pads": true, 24 | "text": true, 25 | "tracks": true, 26 | "vias": true, 27 | "zones": true 28 | }, 29 | "visible_items": [ 30 | 0, 31 | 1, 32 | 2, 33 | 3, 34 | 4, 35 | 5, 36 | 8, 37 | 9, 38 | 10, 39 | 11, 40 | 12, 41 | 13, 42 | 14, 43 | 15, 44 | 16, 45 | 17, 46 | 18, 47 | 19, 48 | 20, 49 | 21, 50 | 22, 51 | 23, 52 | 24, 53 | 25, 54 | 26, 55 | 27, 56 | 28, 57 | 29, 58 | 30, 59 | 32, 60 | 33, 61 | 34, 62 | 35, 63 | 36 64 | ], 65 | "visible_layers": "001d23f_ffffffff", 66 | "zone_display_mode": 0 67 | }, 68 | "meta": { 69 | "filename": "PicoMemcard-newmodule.kicad_prl", 70 | "version": 3 71 | }, 72 | "project": { 73 | "files": [] 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /pcb/PicoMemcard-rp2040zero/PicoMemcard-rp2040zero.kicad_pro: -------------------------------------------------------------------------------- 1 | { 2 | "board": { 3 | "design_settings": { 4 | "defaults": { 5 | "board_outline_line_width": 0.09999999999999999, 6 | "copper_line_width": 0.19999999999999998, 7 | "copper_text_italic": false, 8 | "copper_text_size_h": 1.5, 9 | "copper_text_size_v": 1.5, 10 | "copper_text_thickness": 0.3, 11 | "copper_text_upright": false, 12 | "courtyard_line_width": 0.049999999999999996, 13 | "dimension_precision": 4, 14 | "dimension_units": 3, 15 | "dimensions": { 16 | "arrow_length": 1270000, 17 | "extension_offset": 500000, 18 | "keep_text_aligned": true, 19 | "suppress_zeroes": false, 20 | "text_position": 0, 21 | "units_format": 1 22 | }, 23 | "fab_line_width": 0.09999999999999999, 24 | "fab_text_italic": false, 25 | "fab_text_size_h": 1.0, 26 | "fab_text_size_v": 1.0, 27 | "fab_text_thickness": 0.15, 28 | "fab_text_upright": false, 29 | "other_line_width": 0.15, 30 | "other_text_italic": false, 31 | "other_text_size_h": 1.0, 32 | "other_text_size_v": 1.0, 33 | "other_text_thickness": 0.15, 34 | "other_text_upright": false, 35 | "pads": { 36 | "drill": 3.2, 37 | "height": 3.2, 38 | "width": 3.2 39 | }, 40 | "silk_line_width": 0.15, 41 | "silk_text_italic": false, 42 | "silk_text_size_h": 1.0, 43 | "silk_text_size_v": 1.0, 44 | "silk_text_thickness": 0.15, 45 | "silk_text_upright": false, 46 | "zones": { 47 | "45_degree_only": false, 48 | "min_clearance": 0.508 49 | } 50 | }, 51 | "diff_pair_dimensions": [ 52 | { 53 | "gap": 0.0, 54 | "via_gap": 0.0, 55 | "width": 0.0 56 | }, 57 | { 58 | "gap": 0.2032, 59 | "via_gap": 0.2032, 60 | "width": 0.261112 61 | } 62 | ], 63 | "drc_exclusions": [], 64 | "meta": { 65 | "version": 2 66 | }, 67 | "rule_severities": { 68 | "annular_width": "error", 69 | "clearance": "error", 70 | "copper_edge_clearance": "error", 71 | "courtyards_overlap": "error", 72 | "diff_pair_gap_out_of_range": "error", 73 | "diff_pair_uncoupled_length_too_long": "error", 74 | "drill_out_of_range": "error", 75 | "duplicate_footprints": "warning", 76 | "extra_footprint": "warning", 77 | "footprint_type_mismatch": "error", 78 | "hole_clearance": "error", 79 | "hole_near_hole": "error", 80 | "invalid_outline": "error", 81 | "item_on_disabled_layer": "error", 82 | "items_not_allowed": "error", 83 | "length_out_of_range": "error", 84 | "malformed_courtyard": "error", 85 | "microvia_drill_out_of_range": "error", 86 | "missing_courtyard": "ignore", 87 | "missing_footprint": "warning", 88 | "net_conflict": "warning", 89 | "npth_inside_courtyard": "ignore", 90 | "padstack": "error", 91 | "pth_inside_courtyard": "ignore", 92 | "shorting_items": "error", 93 | "silk_over_copper": "warning", 94 | "silk_overlap": "warning", 95 | "skew_out_of_range": "error", 96 | "through_hole_pad_without_hole": "error", 97 | "too_many_vias": "error", 98 | "track_dangling": "warning", 99 | "track_width": "error", 100 | "tracks_crossing": "error", 101 | "unconnected_items": "error", 102 | "unresolved_variable": "error", 103 | "via_dangling": "warning", 104 | "zone_has_empty_net": "error", 105 | "zones_intersect": "error" 106 | }, 107 | "rules": { 108 | "allow_blind_buried_vias": false, 109 | "allow_microvias": false, 110 | "max_error": 0.005, 111 | "min_clearance": 0.127, 112 | "min_copper_edge_clearance": 0.0, 113 | "min_hole_clearance": 0.25, 114 | "min_hole_to_hole": 0.5, 115 | "min_microvia_diameter": 0.19999999999999998, 116 | "min_microvia_drill": 0.09999999999999999, 117 | "min_silk_clearance": 0.0, 118 | "min_through_hole_diameter": 0.19999999999999998, 119 | "min_track_width": 0.127, 120 | "min_via_annular_width": 0.13, 121 | "min_via_diameter": 0.5, 122 | "solder_mask_clearance": 0.0, 123 | "solder_mask_min_width": 0.0, 124 | "use_height_for_length_calcs": true 125 | }, 126 | "track_widths": [ 127 | 0.0, 128 | 0.2, 129 | 0.254, 130 | 0.3, 131 | 0.4, 132 | 0.5, 133 | 0.6, 134 | 1.0 135 | ], 136 | "via_dimensions": [ 137 | { 138 | "diameter": 0.0, 139 | "drill": 0.0 140 | }, 141 | { 142 | "diameter": 0.5, 143 | "drill": 0.2 144 | } 145 | ], 146 | "zones_allow_external_fillets": false, 147 | "zones_use_no_outline": true 148 | }, 149 | "layer_presets": [] 150 | }, 151 | "boards": [], 152 | "cvpcb": { 153 | "equivalence_files": [] 154 | }, 155 | "erc": { 156 | "erc_exclusions": [], 157 | "meta": { 158 | "version": 0 159 | }, 160 | "pin_map": [ 161 | [ 162 | 0, 163 | 0, 164 | 0, 165 | 0, 166 | 0, 167 | 0, 168 | 1, 169 | 0, 170 | 0, 171 | 0, 172 | 0, 173 | 2 174 | ], 175 | [ 176 | 0, 177 | 2, 178 | 0, 179 | 1, 180 | 0, 181 | 0, 182 | 1, 183 | 0, 184 | 2, 185 | 2, 186 | 2, 187 | 2 188 | ], 189 | [ 190 | 0, 191 | 0, 192 | 0, 193 | 0, 194 | 0, 195 | 0, 196 | 1, 197 | 0, 198 | 1, 199 | 0, 200 | 1, 201 | 2 202 | ], 203 | [ 204 | 0, 205 | 1, 206 | 0, 207 | 0, 208 | 0, 209 | 0, 210 | 1, 211 | 1, 212 | 2, 213 | 1, 214 | 1, 215 | 2 216 | ], 217 | [ 218 | 0, 219 | 0, 220 | 0, 221 | 0, 222 | 0, 223 | 0, 224 | 1, 225 | 0, 226 | 0, 227 | 0, 228 | 0, 229 | 2 230 | ], 231 | [ 232 | 0, 233 | 0, 234 | 0, 235 | 0, 236 | 0, 237 | 0, 238 | 0, 239 | 0, 240 | 0, 241 | 0, 242 | 0, 243 | 2 244 | ], 245 | [ 246 | 1, 247 | 1, 248 | 1, 249 | 1, 250 | 1, 251 | 0, 252 | 1, 253 | 1, 254 | 1, 255 | 1, 256 | 1, 257 | 2 258 | ], 259 | [ 260 | 0, 261 | 0, 262 | 0, 263 | 1, 264 | 0, 265 | 0, 266 | 1, 267 | 0, 268 | 0, 269 | 0, 270 | 0, 271 | 2 272 | ], 273 | [ 274 | 0, 275 | 2, 276 | 1, 277 | 2, 278 | 0, 279 | 0, 280 | 1, 281 | 0, 282 | 2, 283 | 2, 284 | 2, 285 | 2 286 | ], 287 | [ 288 | 0, 289 | 2, 290 | 0, 291 | 1, 292 | 0, 293 | 0, 294 | 1, 295 | 0, 296 | 2, 297 | 0, 298 | 0, 299 | 2 300 | ], 301 | [ 302 | 0, 303 | 2, 304 | 1, 305 | 1, 306 | 0, 307 | 0, 308 | 1, 309 | 0, 310 | 2, 311 | 0, 312 | 0, 313 | 2 314 | ], 315 | [ 316 | 2, 317 | 2, 318 | 2, 319 | 2, 320 | 2, 321 | 2, 322 | 2, 323 | 2, 324 | 2, 325 | 2, 326 | 2, 327 | 2 328 | ] 329 | ], 330 | "rule_severities": { 331 | "bus_definition_conflict": "error", 332 | "bus_entry_needed": "error", 333 | "bus_label_syntax": "error", 334 | "bus_to_bus_conflict": "error", 335 | "bus_to_net_conflict": "error", 336 | "different_unit_footprint": "error", 337 | "different_unit_net": "error", 338 | "duplicate_reference": "error", 339 | "duplicate_sheet_names": "error", 340 | "extra_units": "error", 341 | "global_label_dangling": "warning", 342 | "hier_label_mismatch": "error", 343 | "label_dangling": "error", 344 | "lib_symbol_issues": "warning", 345 | "multiple_net_names": "warning", 346 | "net_not_bus_member": "warning", 347 | "no_connect_connected": "warning", 348 | "no_connect_dangling": "warning", 349 | "pin_not_connected": "error", 350 | "pin_not_driven": "error", 351 | "pin_to_pin": "warning", 352 | "power_pin_not_driven": "error", 353 | "similar_labels": "warning", 354 | "unannotated": "error", 355 | "unit_value_mismatch": "error", 356 | "unresolved_variable": "error", 357 | "wire_dangling": "error" 358 | } 359 | }, 360 | "libraries": { 361 | "pinned_footprint_libs": [], 362 | "pinned_symbol_libs": [] 363 | }, 364 | "meta": { 365 | "filename": "PicoMemcard-newmodule.kicad_pro", 366 | "version": 1 367 | }, 368 | "net_settings": { 369 | "classes": [ 370 | { 371 | "bus_width": 12.0, 372 | "clearance": 0.2, 373 | "diff_pair_gap": 0.25, 374 | "diff_pair_via_gap": 0.25, 375 | "diff_pair_width": 0.2, 376 | "line_style": 0, 377 | "microvia_diameter": 0.3, 378 | "microvia_drill": 0.1, 379 | "name": "Default", 380 | "pcb_color": "rgba(0, 0, 0, 0.000)", 381 | "schematic_color": "rgba(0, 0, 0, 0.000)", 382 | "track_width": 0.25, 383 | "via_diameter": 0.8, 384 | "via_drill": 0.4, 385 | "wire_width": 6.0 386 | } 387 | ], 388 | "meta": { 389 | "version": 2 390 | }, 391 | "net_colors": null 392 | }, 393 | "pcbnew": { 394 | "last_paths": { 395 | "gencad": "PicoMemcardRP2040-zero-small.cad", 396 | "idf": "", 397 | "netlist": "", 398 | "specctra_dsn": "", 399 | "step": "PicoMemcardRP2040-zero-small.step", 400 | "vrml": "" 401 | }, 402 | "page_layout_descr_file": "" 403 | }, 404 | "schematic": { 405 | "annotate_start_num": 0, 406 | "drawing": { 407 | "default_line_thickness": 6.0, 408 | "default_text_size": 50.0, 409 | "field_names": [], 410 | "intersheets_ref_own_page": false, 411 | "intersheets_ref_prefix": "", 412 | "intersheets_ref_short": false, 413 | "intersheets_ref_show": false, 414 | "intersheets_ref_suffix": "", 415 | "junction_size_choice": 3, 416 | "label_size_ratio": 0.375, 417 | "pin_symbol_size": 25.0, 418 | "text_offset_ratio": 0.15 419 | }, 420 | "legacy_lib_dir": "", 421 | "legacy_lib_list": [], 422 | "meta": { 423 | "version": 1 424 | }, 425 | "net_format_name": "", 426 | "ngspice": { 427 | "fix_include_paths": true, 428 | "fix_passive_vals": false, 429 | "meta": { 430 | "version": 0 431 | }, 432 | "model_mode": 0, 433 | "workbook_filename": "" 434 | }, 435 | "page_layout_descr_file": "", 436 | "plot_directory": "", 437 | "spice_adjust_passive_values": false, 438 | "spice_external_command": "spice \"%I\"", 439 | "subpart_first_id": 65, 440 | "subpart_id_separator": 0 441 | }, 442 | "sheets": [ 443 | [ 444 | "faa956bb-0e0d-41e1-a5c8-c31a518a76e5", 445 | "" 446 | ] 447 | ], 448 | "text_variables": {} 449 | } 450 | -------------------------------------------------------------------------------- /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 | FetchContent_Declare( 33 | pico_sdk 34 | GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk 35 | GIT_TAG master 36 | ) 37 | if (NOT pico_sdk) 38 | message("Downloading Raspberry Pi Pico SDK") 39 | FetchContent_Populate(pico_sdk) 40 | set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) 41 | endif () 42 | set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) 43 | else () 44 | message(FATAL_ERROR 45 | "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." 46 | ) 47 | endif () 48 | endif () 49 | 50 | get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") 51 | if (NOT EXISTS ${PICO_SDK_PATH}) 52 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") 53 | endif () 54 | 55 | set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) 56 | if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) 57 | message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") 58 | endif () 59 | 60 | set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) 61 | 62 | include(${PICO_SDK_INIT_CMAKE_FILE}) 63 | -------------------------------------------------------------------------------- /poc_examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(controller_simulator) 2 | add_subdirectory(memcard_sniffer) 3 | -------------------------------------------------------------------------------- /poc_examples/controller_simulator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | include(${CMAKE_SOURCE_DIR}/pico_sdk_import.cmake) 4 | 5 | project(controller_simulator C CXX ASM) 6 | set(CMAKE_C_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD 17) 8 | pico_sdk_init() 9 | 10 | add_executable(controller_simulator) 11 | 12 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/psxSPI.pio) 13 | 14 | target_sources(${PROJECT_NAME} PUBLIC 15 | ${CMAKE_CURRENT_SOURCE_DIR}/controller_simulator.c 16 | ) 17 | 18 | pico_enable_stdio_uart(${PROJECT_NAME} 1) 19 | 20 | target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_pio) 21 | 22 | pico_add_extra_outputs(${PROJECT_NAME}) 23 | -------------------------------------------------------------------------------- /poc_examples/controller_simulator/controller_simulator.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file test.c 3 | * @author Daniele Giuliani (danielegiuliani0@gmail.com) 4 | * @brief Testing interaction of PIO and PSX by simulating Joypad 5 | * @version 0.1 6 | * @date 2022-04-08 7 | */ 8 | 9 | #include 10 | #include "pico/stdlib.h" 11 | #include "hardware/pio.h" 12 | #include "hardware/irq.h" 13 | #include "psxSPI.pio.h" 14 | 15 | #define PIN_DAT 5 16 | #define PIN_CMD 6 17 | #define PIN_SEL 7 18 | #define PIN_CLK 8 19 | #define PIN_ACK 9 20 | 21 | #define PIN_LED 25 22 | 23 | #define ID_LO 0x41 24 | #define ID_HI 0x5A 25 | 26 | #define R_PRESSED 0b11011111 27 | #define L_PRESSED 0b01111111 28 | #define NO_PRESSED 0xff 29 | #define SEND_ACK 0b100000000 30 | 31 | 32 | PIO pio = pio0; 33 | 34 | uint smSelMonitor; 35 | uint smCmdReader; 36 | uint smDatWriter; 37 | 38 | uint offsetSelMonitor; 39 | uint offsetCmdReader; 40 | uint offsetDatWriter; 41 | 42 | static uint count = 0; 43 | 44 | /** 45 | * @brief Interrupt handler called when SEL goes high 46 | * Resets cmdReader and datWriter state machines 47 | */ 48 | void pio0_irq0() { 49 | pio_set_sm_mask_enabled(pio, 1 << smCmdReader | 1 << smDatWriter, false); 50 | pio_restart_sm_mask(pio, 1 << smCmdReader | 1 << smDatWriter); 51 | pio_sm_exec(pio, smCmdReader, pio_encode_jmp(offsetCmdReader)); // restart smCmdReader PC 52 | pio_sm_exec(pio, smDatWriter, pio_encode_jmp(offsetDatWriter)); // restart smDatWriter PC 53 | pio_enable_sm_mask_in_sync(pio, 1 << smCmdReader | 1 << smDatWriter); 54 | pio_interrupt_clear(pio0, 0); 55 | } 56 | 57 | void cancel_ack() { 58 | //pio_sm_exec(pio, smAckSender, pio_encode_jmp(offsetCmdReader)); // restart smCmdReader 59 | } 60 | 61 | void process_joy_req(uint8_t next_byte) { 62 | printf("\n%.2x ", next_byte); 63 | write_byte_blocking(pio, smDatWriter, ID_LO); // write lower ID byte 64 | 65 | next_byte = read_byte_blocking(pio, smCmdReader); 66 | if(next_byte != 0x42) { 67 | printf("\nWaiting for %.2x but received %.2x\n", 0x42, next_byte); 68 | return; 69 | } else { 70 | write_byte_blocking(pio, smDatWriter, ID_HI); // write upper ID byte 71 | printf("%.2x ", next_byte); 72 | } 73 | 74 | next_byte = read_byte_blocking(pio, smCmdReader); 75 | if(next_byte != 0x00) { 76 | printf("\nWaiting for %.2x but received %.2x\n", 0x00, next_byte); 77 | return; 78 | } else { 79 | switch (count) { 80 | case 0: 81 | write_byte_blocking(pio, smDatWriter, R_PRESSED); // fake right d-pad being pressed 82 | break; 83 | case 2: 84 | write_byte_blocking(pio, smDatWriter, L_PRESSED); // fake left d-pad being pressed 85 | break; 86 | case 1: 87 | case 3: 88 | default: 89 | write_byte_blocking(pio, smDatWriter, NO_PRESSED); // release all buttons 90 | break; 91 | } 92 | printf("%.2x ", next_byte); 93 | } 94 | 95 | next_byte = read_byte_blocking(pio, smCmdReader); 96 | if(next_byte != 0x00) { 97 | printf("\nWaiting for %.2x but received %.2x\n", 0x00, next_byte); 98 | return; 99 | } else { 100 | write_byte_blocking(pio, smDatWriter, NO_PRESSED); // other buttons are all inactive 101 | printf("%.2x ", next_byte); 102 | } 103 | 104 | next_byte = read_byte_blocking(pio, smCmdReader); 105 | cancel_ack(); // last byte being received, no need to send more data 106 | if(next_byte != 0x00) { 107 | printf("\nWaiting for %.2x but received %.2x\n", 0x00, next_byte); 108 | return; 109 | } else { 110 | printf("%.2x ", next_byte); 111 | } 112 | } 113 | 114 | int main() { 115 | stdio_init_all(); 116 | 117 | printf("\n\nBeginning Execution...\n"); 118 | 119 | /* Setup PIO interrupts */ 120 | irq_set_exclusive_handler(PIO0_IRQ_0, pio0_irq0); 121 | irq_set_enabled(PIO0_IRQ_0, true); 122 | 123 | offsetSelMonitor = pio_add_program(pio, &sel_monitor_program); 124 | offsetCmdReader = pio_add_program(pio, &cmd_reader_program); 125 | offsetDatWriter = pio_add_program(pio, &dat_writer_program); 126 | 127 | smSelMonitor = pio_claim_unused_sm(pio, true); 128 | smCmdReader = pio_claim_unused_sm(pio, true); 129 | smDatWriter = pio_claim_unused_sm(pio, true); 130 | 131 | dat_writer_program_init(pio, smDatWriter, offsetDatWriter, PIN_DAT, PIN_CLK); 132 | cmd_reader_program_init(pio, smCmdReader, offsetCmdReader, PIN_CMD, PIN_ACK); 133 | sel_monitor_program_init(pio, smSelMonitor, offsetSelMonitor, PIN_SEL); 134 | 135 | /* Enable all SM simultaneously */ 136 | uint32_t smMask = (1 << smSelMonitor) | (1 << smCmdReader) | (1 << smDatWriter); 137 | pio_enable_sm_mask_in_sync(pio, smMask); 138 | 139 | uint32_t i = 0; 140 | while(true) { 141 | uint8_t item = read_byte_blocking(pio, smCmdReader); 142 | 143 | if(item == 0x01) 144 | process_joy_req(item); 145 | count = (count + 1) % 4; 146 | 147 | } 148 | } -------------------------------------------------------------------------------- /poc_examples/memcard_sniffer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | include(${CMAKE_SOURCE_DIR}/pico_sdk_import.cmake) 4 | 5 | project(memcard_sniffer C CXX ASM) 6 | set(CMAKE_C_STANDARD 11) 7 | set(CMAKE_CXX_STANDARD 17) 8 | pico_sdk_init() 9 | 10 | add_executable(memcard_sniffer) 11 | 12 | pico_generate_pio_header(${PROJECT_NAME} ${CMAKE_SOURCE_DIR}/psxSPI.pio) 13 | 14 | target_sources(${PROJECT_NAME} PUBLIC 15 | ${CMAKE_CURRENT_SOURCE_DIR}/memcard_sniffer.c 16 | ) 17 | 18 | pico_enable_stdio_uart(${PROJECT_NAME} 1) 19 | 20 | target_link_libraries(${PROJECT_NAME} pico_stdlib hardware_pio) 21 | 22 | pico_add_extra_outputs(${PROJECT_NAME}) 23 | -------------------------------------------------------------------------------- /poc_examples/memcard_sniffer/memcard_sniffer.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file protocol_sniffer.c 3 | * @author Daniele Giuliani (danielegiuliani0@gmail.com) 4 | * @brief Utility used to sniff PSX SPI protocol (CMD and DAT lines) 5 | * @version 0.1 6 | * @date 2022-04-08 7 | */ 8 | 9 | #include 10 | #include "pico/stdlib.h" 11 | #include "hardware/pio.h" 12 | #include "hardware/irq.h" 13 | #include "psxSPI.pio.h" 14 | 15 | #define PIN_DAT 5 16 | #define PIN_CMD 6 17 | #define PIN_SEL 7 18 | #define PIN_CLK 8 19 | #define PIN_ACK 9 20 | 21 | #define BUFF_LEN 4096 22 | 23 | PIO pio = pio0; 24 | 25 | uint smSelMonitor; 26 | uint smCmdReader; 27 | uint smDatReader; 28 | 29 | uint offsetSelMonitor; 30 | uint offsetCmdReader; 31 | uint offsetDatReader; 32 | 33 | uint32_t buffIndex = 0; 34 | uint8_t cmdBuffer[BUFF_LEN]; 35 | uint8_t datBuffer[BUFF_LEN]; 36 | 37 | bool restartProto = false; 38 | 39 | /** 40 | * @brief Interrupt handler called when SEL goes high 41 | * Resets cmdReader and datWriter state machines 42 | */ 43 | void pio0_irq0() { 44 | pio_set_sm_mask_enabled(pio, 1 << smCmdReader | 1 << smDatReader, false); 45 | pio_restart_sm_mask(pio, 1 << smCmdReader | 1 << smDatReader); 46 | pio_sm_exec(pio, smCmdReader, pio_encode_jmp(offsetCmdReader)); // restart smCmdReader PC 47 | pio_sm_exec(pio, smDatReader, pio_encode_jmp(offsetDatReader)); // restart smDatReader PC 48 | pio_interrupt_clear(pio0, 0); 49 | pio_enable_sm_mask_in_sync(pio, 1 << smCmdReader | 1 << smDatReader); 50 | restartProto = true; 51 | } 52 | 53 | int main() { 54 | stdio_init_all(); 55 | 56 | printf("\n\nBeginning Execution...\n"); 57 | 58 | /* Setup PIO interrupts */ 59 | irq_set_exclusive_handler(PIO0_IRQ_0, pio0_irq0); 60 | irq_set_enabled(PIO0_IRQ_0, true); 61 | 62 | offsetSelMonitor = pio_add_program(pio, &sel_monitor_program); 63 | offsetCmdReader = pio_add_program(pio, &cmd_reader_program); 64 | offsetDatReader = pio_add_program(pio, &dat_reader_program); 65 | 66 | smSelMonitor = pio_claim_unused_sm(pio, true); 67 | smCmdReader = pio_claim_unused_sm(pio, true); 68 | smDatReader = pio_claim_unused_sm(pio, true); 69 | 70 | dat_reader_program_init(pio, smDatReader, offsetDatReader, PIN_DAT); 71 | cmd_reader_program_init(pio, smCmdReader, offsetCmdReader, PIN_CMD, PIN_ACK); 72 | sel_monitor_program_init(pio, smSelMonitor, offsetSelMonitor, PIN_SEL); 73 | 74 | /* Enable all SM simultaneously */ 75 | uint32_t smMask = (1 << smSelMonitor) | (1 << smCmdReader) | (1 << smDatReader); 76 | pio_enable_sm_mask_in_sync(pio, smMask); 77 | 78 | /* Samping phase */ 79 | for(int i = 0; i < BUFF_LEN; ++i) { 80 | cmdBuffer[i] = read_byte_blocking(pio, smCmdReader); 81 | datBuffer[i] = read_byte_blocking(pio, smDatReader); 82 | } 83 | 84 | /* Printing results */ 85 | for(int i = 0; i < BUFF_LEN; ++i) { 86 | printf("\t%.2x\t%.2x\n", cmdBuffer[i], datBuffer[i]); 87 | } 88 | } -------------------------------------------------------------------------------- /psxSPI.pio: -------------------------------------------------------------------------------- 1 | ; Author: Daniele Giuliani 2 | ; Interfaces with the modified SPI protocol used by 3 | ; PSX to communicate with controller/memory cards 4 | 5 | .define PUBLIC PIN_DAT 5 6 | .define PUBLIC PIN_CMD 6 7 | .define PUBLIC PIN_SEL 7 8 | .define PUBLIC PIN_CLK 8 9 | .define PUBLIC PIN_ACK 9 10 | 11 | .program cmd_reader 12 | ; Input pins mapping: 13 | ; 0 - CMD 14 | ; Program description: 15 | ; Samples CMD line during rising clock edges, 16 | ; waits for SEL low signal before starting execution 17 | sel_high: 18 | wait 0 gpio PIN_SEL ; wait for SEL to go low 19 | set x, 7 ; set the bit counter 20 | .wrap_target 21 | wait 0 gpio PIN_CLK ; wait for clock to fall 22 | wait 1 gpio PIN_CLK ; wait for rising clock edge 23 | in pins 1 ; sample 1 bit from CMD line 24 | .wrap 25 | 26 | .program dat_reader 27 | ; Input pins mapping: 28 | ; 0 - DAT 29 | ; Program description: 30 | ; Samples DAT line during rising clock edges, 31 | ; waits for SEL pin to be low before starting execution. 32 | ; Can be used for sniffing DAT line used by other hardware. 33 | sel_high: 34 | wait 0 gpio PIN_SEL ; wait for SEL to go low 35 | .wrap_target 36 | wait 0 gpio PIN_CLK ; wait for clock to fall 37 | wait 1 gpio PIN_CLK ; wait for rising clock edge 38 | in pins 1 ; sample 1 bit form DAT line 39 | .wrap 40 | 41 | .program dat_writer 42 | .side_set 1 pindirs 43 | ; Set pins mapping: 44 | ; 0 - DAT 45 | ; Output pins mapping: 46 | ; 0 - DAT 47 | ; Sideset pins mapping: 48 | ; 0 - ACK 49 | ; Program description: 50 | ; Asserts ACK (signaling that the memory card must send something) 51 | ; and outputs bits to the DAT line on falling clock edges. 52 | ; waits for SEL low signal before starting execution. 53 | ; Bits are outputted by changing pin direction: 54 | ; 0 -> set pin as input (Hi-Z) -> output a one 55 | ; 1 -> set pin as output low -> output a zero 56 | set pindirs, 0 side 0 ; release DAT line (set pin as input = Hi-Z) 57 | wait 0 gpio PIN_SEL side 0 ; wait for SEL to go low 58 | .wrap_target 59 | pull side 0 ; manual pull in order to stall SM if TX fifo is empty 60 | nop side 1 [5] ; start ACK 61 | set x, 7 side 0 [5] ; stop ACK delay and set bit counter 62 | sendbit: 63 | wait 1 gpio PIN_CLK side 0 ; stop ACK and check clock is high (sideset completes even if instruction stalls) 64 | wait 0 gpio PIN_CLK side 0 ; wait for falling clock edge 65 | out pindirs 1 side 0 ; output 1 bit 66 | jmp x-- sendbit side 0 ; count and send 8 bits 67 | .wrap 68 | 69 | % c-sdk { 70 | #define SLOW_CLKDIV 50 // 125MHz divided down to 2.5 MHz - we need this so we don't count clocks not meant for us on systems like the PS2 71 | 72 | static inline void cmd_reader_program_init(PIO pio, uint sm, uint offset) { 73 | pio_sm_config c = cmd_reader_program_get_default_config(offset); 74 | 75 | /* Pin Configuration */ 76 | sm_config_set_in_pins(&c, PIN_CMD); 77 | 78 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_CMD, 1, false); 79 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_SEL, 1, false); 80 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_CLK, 1, false); 81 | 82 | /* Fifo Configuration */ 83 | sm_config_set_in_shift(&c, true, true, 8); // shift ISR to right, autopush every 8 bits 84 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); // join RX FIFO 85 | 86 | /* Clock configuration */ 87 | sm_config_set_clkdiv_int_frac(&c, SLOW_CLKDIV, 0x00); 88 | 89 | /* Initialize SM */ 90 | pio_sm_init(pio, sm, offset, &c); 91 | } 92 | 93 | static inline void dat_reader_program_init(PIO pio, uint sm, uint offset) { 94 | pio_sm_config c = dat_reader_program_get_default_config(offset); 95 | 96 | /* Pin Configuration */ 97 | sm_config_set_in_pins(&c, PIN_DAT); 98 | 99 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_DAT, 1, false); 100 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_SEL, 1, false); 101 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_CLK, 1, false); 102 | 103 | /* Fifo Configuration */ 104 | sm_config_set_in_shift(&c, true, true, 8); // shift ISR to right, autopush every 8 bits 105 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); // join RX FIFO 106 | 107 | /* Clock configuration */ 108 | sm_config_set_clkdiv_int_frac(&c, SLOW_CLKDIV, 0x00); 109 | 110 | /* Initialize SM */ 111 | pio_sm_init(pio, sm, offset, &c); 112 | } 113 | 114 | static inline void dat_writer_program_init(PIO pio, uint sm, uint offset) { 115 | pio_sm_config c = dat_writer_program_get_default_config(offset); 116 | 117 | /* Pin Configuration */ 118 | sm_config_set_out_pins(&c, PIN_DAT, 1); // set base OUT pin (DAT) 119 | sm_config_set_set_pins(&c, PIN_DAT, 1); // set base SET pin (DAT) 120 | sm_config_set_sideset_pins(&c, PIN_ACK); // set base SIDESET pin (ACK) 121 | 122 | /* configure DAT pin for open drain (output low but set as input initially) */ 123 | pio_sm_set_pins_with_mask(pio, sm, 0, 1 << PIN_DAT); 124 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_DAT, 1, false); 125 | pio_gpio_init(pio, PIN_DAT); 126 | 127 | /* configure ACK pin for open drain (output low but set as input initially) */ 128 | pio_sm_set_pins_with_mask(pio, sm, 0, 1 << PIN_ACK); 129 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_ACK, 1, false); 130 | pio_gpio_init(pio, PIN_ACK); 131 | 132 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_SEL, 1, false); 133 | pio_sm_set_consecutive_pindirs(pio, sm, PIN_CLK, 1, false); 134 | 135 | /* FIFO Configuration */ 136 | sm_config_set_out_shift(&c, true, true, 8); // shift OSR to right, autopull every 8 bits 137 | sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); // join TX FIFO 138 | 139 | /* Clock configuration */ 140 | sm_config_set_clkdiv_int_frac(&c, SLOW_CLKDIV, 0x00); 141 | 142 | /* Initialize SM */ 143 | pio_sm_init(pio, sm, offset, &c); 144 | } 145 | 146 | static inline uint8_t read_byte_blocking(PIO pio, uint sm) { 147 | return (uint8_t) (pio_sm_get_blocking(pio, sm) >> 24); 148 | } 149 | 150 | static inline void write_byte_blocking(PIO pio, uint sm, uint32_t byte) { 151 | pio_sm_put_blocking(pio, sm, ~byte & 0xFF); // invert bits (0 become 1 setting the output to low) 152 | } 153 | %} -------------------------------------------------------------------------------- /src/led.c: -------------------------------------------------------------------------------- 1 | #include "led.h" 2 | #include "config.h" 3 | #include "hardware/gpio.h" 4 | #include "hardware/pio.h" 5 | #include "hardware/adc.h" 6 | #ifdef PICO 7 | #include "pico/cyw43_arch.h" 8 | #endif 9 | #ifdef RP2040ZERO 10 | #include "ws2812.pio.h" 11 | #endif 12 | 13 | #ifdef PICO 14 | #define PICO_LED_PIN 25 15 | #endif 16 | 17 | static uint smWs2813; 18 | static uint offsetWs2813; 19 | static int32_t picoW = -1; 20 | 21 | #ifdef RP2040ZERO 22 | void ws2812_put_pixel(uint32_t pixel_grb) { 23 | sleep_ms(1); // delay to ensure LED latch will hold data 24 | pio_sm_put(pio1, smWs2813, pixel_grb << 8u); 25 | } 26 | void ws2812_put_rgb(uint8_t red, uint8_t green, uint8_t blue) { 27 | #ifdef INVERT_RED_GREEN 28 | uint32_t mask = (red << 16) | (green << 8) | (blue << 0); 29 | #elif 30 | uint32_t mask = (green << 16) | (red << 8) | (blue << 0); 31 | #endif 32 | ws2812_put_pixel(mask); 33 | } 34 | #endif 35 | 36 | void led_init() { 37 | #ifdef PICO 38 | if (is_pico_w()) { 39 | if (cyw43_arch_init()) { 40 | picoW = 0; 41 | } 42 | } 43 | init_led(PICO_LED_PIN); 44 | #endif 45 | #ifdef RP2040ZERO 46 | offsetWs2813 = pio_add_program(pio1, &ws2812_program); 47 | smWs2813 = pio_claim_unused_sm(pio1, true); 48 | ws2812_program_init(pio1, smWs2813, offsetWs2813, 16, 800000, true); 49 | #endif 50 | } 51 | 52 | void led_output_sync_status(bool out_of_sync) { 53 | #ifdef PICO 54 | set_led(PICO_LED_PIN, !out_of_sync); 55 | #endif 56 | #ifdef RP2040ZERO 57 | if(out_of_sync) { 58 | ws2812_put_rgb(255, 0, 0); 59 | sleep_ms(25); 60 | } else { 61 | ws2812_put_rgb(0, 255, 0); 62 | } 63 | #endif 64 | } 65 | 66 | void led_blink_error(int amount) { 67 | /* ensure led is off */ 68 | #ifdef PICO 69 | set_led(PICO_LED_PIN, false); 70 | #endif 71 | #ifdef RP2040ZERO 72 | ws2812_put_rgb(0, 0, 0); 73 | #endif 74 | sleep_ms(500); 75 | /* start blinking */ 76 | for(int i = 0; i < amount; ++i) { 77 | #ifdef PICO 78 | set_led(PICO_LED_PIN, true); 79 | #endif 80 | #ifdef RP2040ZERO 81 | ws2812_put_rgb(255, 0, 0); 82 | #endif 83 | sleep_ms(500); 84 | #ifdef PICO 85 | set_led(PICO_LED_PIN, false); 86 | #endif 87 | #ifdef RP2040ZERO 88 | ws2812_put_rgb(0, 0, 0); 89 | #endif 90 | sleep_ms(500); 91 | } 92 | } 93 | 94 | void led_output_mc_change() { 95 | #ifdef PICO 96 | set_led(PICO_LED_PIN, false); 97 | sleep_ms(100); 98 | set_led(PICO_LED_PIN, true); 99 | sleep_ms(100); 100 | set_led(PICO_LED_PIN, false); 101 | sleep_ms(100); 102 | #endif 103 | #ifdef RP2040ZERO 104 | ws2812_put_rgb(0, 0, 255); 105 | sleep_ms(100); 106 | ws2812_put_rgb(0, 0, 0); 107 | #endif 108 | } 109 | 110 | void led_output_end_mc_list() { 111 | #ifdef PICO 112 | for(int i = 0; i < 3; ++i) { 113 | set_led(PICO_LED_PIN, false); 114 | sleep_ms(100); 115 | set_led(PICO_LED_PIN, true); 116 | sleep_ms(100); 117 | set_led(PICO_LED_PIN, false); 118 | sleep_ms(100); 119 | } 120 | #endif 121 | #ifdef RP2040ZERO 122 | ws2812_put_rgb(255, 96, 0); // orange 123 | sleep_ms(500); 124 | ws2812_put_rgb(0, 0, 0); 125 | #endif 126 | } 127 | 128 | void led_output_new_mc() { 129 | #ifdef PICO 130 | for(int i = 0; i < 10; ++i) { 131 | set_led(PICO_LED_PIN, false); 132 | sleep_ms(50); 133 | set_led(PICO_LED_PIN, true); 134 | sleep_ms(50); 135 | set_led(PICO_LED_PIN, false); 136 | sleep_ms(50); 137 | } 138 | #endif 139 | #ifdef RP2040ZERO 140 | ws2812_put_rgb(52, 171, 235); // light blue 141 | sleep_ms(1000); 142 | ws2812_put_rgb(0, 0, 0); 143 | #endif 144 | } 145 | 146 | // Attempt to check if device is a Raspberry Pi Pico W 147 | // Based on https://forums.raspberrypi.com/viewtopic.php?t=336884 148 | int32_t is_pico_w() { 149 | if (picoW == -1) { 150 | // When the VSYS_ADC is read on a Pico it will always be > 1V 151 | // On a Pico-W it will be < 1V when GPIO25 is low 152 | #define VSYS_ADC_GPIO 29 153 | #define VSYS_ADC_CHAN 3 154 | #define ONE_VOLT 409 // 1V divide by 3, as 12-bit with 3V3 Vref 155 | #define VSYS_CTL_GPIO 25 // Enables VSYS_ADC on Pico-W 156 | adc_init(); 157 | adc_gpio_init(VSYS_ADC_GPIO); 158 | adc_select_input(VSYS_ADC_CHAN); 159 | // Check to see if we can detect a Pico-W without using any GPIO 160 | if (adc_read() < ONE_VOLT) { 161 | picoW = 1; // Pico W 162 | } 163 | else { 164 | gpio_init(VSYS_CTL_GPIO); // GPIO 165 | gpio_set_dir(VSYS_CTL_GPIO, GPIO_OUT); // output 166 | gpio_put(VSYS_CTL_GPIO, 0); // low 167 | if (adc_read() < ONE_VOLT) { 168 | gpio_put(VSYS_CTL_GPIO, 1); // high 169 | picoW = 1; // Pico W 170 | } else { 171 | picoW = 0; // Pico 172 | } 173 | } 174 | } 175 | return picoW; 176 | } 177 | 178 | void init_led(uint32_t pin) { 179 | if (!is_pico_w() || (pin != 25)) { 180 | gpio_init(pin); 181 | gpio_set_dir(pin, GPIO_OUT); 182 | } 183 | } 184 | 185 | #ifdef PICO 186 | void set_led(uint32_t pin, uint32_t level) { 187 | if ((pin == 25) && is_pico_w()) { 188 | cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, level); 189 | } else { 190 | gpio_put(pin, level); 191 | } 192 | } 193 | #endif -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include "pico/stdio.h" 2 | #include "pico/stdlib.h" 3 | /* SD Card */ 4 | #include "sd_config.h" 5 | /* Time and Timestamps */ 6 | #include "pico/time.h" 7 | /* TinyUSB */ 8 | #include "bsp/board.h" 9 | #include "tusb.h" 10 | /* Memcard Simulation */ 11 | #include "memcard_simulator.h" 12 | /* LED Control */ 13 | #include "led.h" 14 | /* Global Configuration */ 15 | #include "config.h" 16 | 17 | 18 | bool tud_mount_status = false; 19 | 20 | void cdc_task(void); 21 | 22 | /*------------- MAIN -------------*/ 23 | int main(void) { 24 | stdio_init_all(); 25 | led_init(); 26 | 27 | /* Pico connected to PC, initialize USB transfer mode */ 28 | board_init(); 29 | tusb_init(); 30 | 31 | while(true) { 32 | tud_task(); // tinyusb device task 33 | cdc_task(); 34 | 35 | if(to_ms_since_boot(get_absolute_time()) > TUD_MOUNT_TIMEOUT && !tud_mount_status) 36 | break; 37 | } 38 | 39 | /* Pico powered by PSX, initialize memory card simulation */ 40 | simulate_memory_card(); 41 | 42 | return 0; 43 | } 44 | 45 | //--------------------------------------------------------------------+ 46 | // Device callbacks 47 | //--------------------------------------------------------------------+ 48 | 49 | // Invoked when device is mounted 50 | void tud_mount_cb(void) { 51 | tud_mount_status = true; 52 | /* Initialize SD card */ 53 | sd_card_t *p_sd = sd_get_by_num(0); 54 | if (!p_sd) return; 55 | sd_init_card(p_sd); 56 | } 57 | 58 | // Invoked when device is unmounted 59 | void tud_umount_cb(void) {} 60 | 61 | // Invoked when usb bus is suspended 62 | // remote_wakeup_en : if host allow us to perform remote wakeup 63 | // Within 7ms, device must draw an average of current less than 2.5 mA from bus 64 | void tud_suspend_cb(bool remote_wakeup_en) { 65 | (void) remote_wakeup_en; 66 | } 67 | 68 | // Invoked when usb bus is resumed 69 | void tud_resume_cb(void) {} 70 | 71 | //--------------------------------------------------------------------+ 72 | // USB CDC 73 | //--------------------------------------------------------------------+ 74 | void cdc_task(void) { 75 | // connected() check for DTR bit 76 | // Most but not all terminal client set this when making connection 77 | // if ( tud_cdc_connected() ) 78 | { 79 | // connected and there are data available 80 | if ( tud_cdc_available() ) 81 | { 82 | // read datas 83 | char buf[64]; 84 | uint32_t count = tud_cdc_read(buf, sizeof(buf)); 85 | (void) count; 86 | 87 | // Echo back 88 | // Note: Skip echo by commenting out write() and write_flush() 89 | // for throughput test e.g 90 | // $ dd if=/dev/zero of=/dev/ttyACM0 count=10000 91 | tud_cdc_write(buf, count); 92 | tud_cdc_write_flush(); 93 | } 94 | } 95 | } 96 | 97 | // Invoked when cdc when line state changed e.g connected/disconnected 98 | void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { 99 | (void) itf; 100 | (void) rts; 101 | } 102 | 103 | // Invoked when CDC interface received data from host 104 | void tud_cdc_rx_cb(uint8_t itf) { 105 | (void) itf; 106 | } -------------------------------------------------------------------------------- /src/memcard_manager.c: -------------------------------------------------------------------------------- 1 | #include "memcard_manager.h" 2 | #include 3 | #include 4 | #include 5 | #include "sd_config.h" 6 | #include "memory_card.h" 7 | 8 | /* extension for memcard files */ 9 | static const char memcard_file_ext[] = ".MCR"; 10 | 11 | /* filename to store previously loaded memcard index */ 12 | static const char memcard_lastmemcardindex_filename[] = "LastMemcardIndex.dat"; 13 | 14 | bool is_name_valid(uint8_t* filename) { 15 | if(!filename) 16 | return false; 17 | filename = strupr(filename); // convert to upper case 18 | /* check .MCR extension */ 19 | uint8_t* ext = strrchr(filename, '.'); 20 | if(!ext || strcmp(ext, memcard_file_ext)) 21 | return false; 22 | /* check that filename (excluding extension) is only digits */ 23 | uint32_t digit_char_count = strspn(filename, "0123456789"); 24 | if(digit_char_count != strlen(filename) - strlen(memcard_file_ext)) 25 | return false; 26 | return true; 27 | } 28 | 29 | bool is_image_valid(uint8_t* filename) { 30 | if(!filename) 31 | return false; 32 | filename = strupr(filename); // convert to upper case 33 | if(!is_name_valid(filename)) 34 | return false; 35 | FILINFO f_info; 36 | FRESULT f_res = f_stat(filename, &f_info); 37 | if(f_res != FR_OK) 38 | return false; 39 | if(f_info.fsize != MC_SIZE) // check that memory card image has correct size 40 | return false; 41 | return true; 42 | } 43 | 44 | uint32_t update_prev_loaded_memcard_index(uint32_t index) { 45 | /* update the previously loaded memcard index stored on the SD card */ 46 | uint32_t retVal = MM_OK; 47 | FIL data_file; 48 | uint32_t buff_size = 100; 49 | FRESULT res = f_open(&data_file, memcard_lastmemcardindex_filename, FA_CREATE_ALWAYS | FA_WRITE); 50 | if (res == FR_OK) { 51 | /* int to string */ 52 | char str_index[buff_size]; 53 | int index_len = sprintf(str_index, "%d", index); 54 | 55 | /* overwrite the contents with new index */ 56 | UINT bytes_written; 57 | f_write(&data_file, str_index, index_len, &bytes_written); 58 | if (bytes_written < index_len) { 59 | /* error writing to file. disk full? */ 60 | retVal = MM_FILE_WRITE_ERR; 61 | } 62 | f_close(&data_file); 63 | } 64 | 65 | return retVal; 66 | } 67 | 68 | bool memcard_manager_exist(uint8_t* filename) { 69 | if(!filename) 70 | return false; 71 | return is_image_valid(filename); 72 | } 73 | 74 | uint32_t memcard_manager_count() { 75 | FRESULT res; 76 | DIR root; 77 | FILINFO f_info; 78 | res = f_opendir(&root, ""); // open root directory 79 | uint32_t count = 0; 80 | if(res == FR_OK) { 81 | while(true) { 82 | res = f_readdir(&root, &f_info); 83 | if(res != FR_OK || f_info.fname[0] == 0) break; 84 | if(!(f_info.fattrib & AM_DIR)) { // not a directory 85 | if(is_image_valid(f_info.fname)) 86 | ++count; 87 | } 88 | } 89 | } 90 | return count; 91 | } 92 | 93 | uint32_t memcard_manager_get(uint32_t index, uint8_t* out_filename) { 94 | if(!out_filename) 95 | return MM_BAD_PARAM; 96 | if(index < 0 || index > MAX_MC_IMAGES) 97 | return MM_INDEX_OUT_OF_BOUNDS; 98 | uint32_t count = memcard_manager_count(); 99 | if(index >= count) 100 | return MM_INDEX_OUT_OF_BOUNDS; 101 | uint8_t* image_names = malloc(((MAX_MC_FILENAME_LEN + 1) * count)); // allocate space for image names 102 | if(!image_names) 103 | return MM_ALLOC_FAIL; // malloc failed 104 | /* retrive images names */ 105 | FRESULT res; 106 | DIR root; 107 | FILINFO f_info; 108 | res = f_opendir(&root, ""); // open root directory 109 | uint32_t i = 0; 110 | if(res == FR_OK) { 111 | while(true) { 112 | res = f_readdir(&root, &f_info); 113 | if(res != FR_OK || f_info.fname[0] == 0) break; 114 | if(!(f_info.fattrib & AM_DIR)) { // not a directory 115 | if(is_image_valid(f_info.fname)) { 116 | strcpy(&image_names[(MAX_MC_FILENAME_LEN + 1) * i], f_info.fname); 117 | ++i; 118 | } 119 | } 120 | } 121 | } 122 | /* sort names alphabetically */ 123 | qsort(image_names, count, (MAX_MC_FILENAME_LEN + 1), (__compar_fn_t) strcmp); 124 | strcpy(out_filename, &image_names[(MAX_MC_FILENAME_LEN + 1) * index]); 125 | free(image_names); // free allocated memory 126 | return MM_OK; 127 | } 128 | 129 | uint32_t memcard_manager_get_prev_loaded_memcard_index() { 130 | /* read which memcard to load from last session from SD card */ 131 | uint32_t index = 0; 132 | FIL data_file; 133 | uint32_t buff_size = 100; 134 | FRESULT res = f_open(&data_file, memcard_lastmemcardindex_filename, FA_OPEN_EXISTING | FA_READ); 135 | if (res == FR_OK) { 136 | char line[buff_size]; 137 | if (f_gets(line, sizeof(line), &data_file)) { 138 | /* string to int (base 10) */ 139 | index = (uint32_t)strtol(line, (char**)NULL, 10); 140 | } 141 | f_close(&data_file); 142 | } 143 | return index; 144 | } 145 | 146 | uint32_t memcard_manager_get_next(uint8_t* filename, uint8_t* out_nextfile) { 147 | if(!filename || !out_nextfile) 148 | return MM_BAD_PARAM; 149 | uint32_t count = memcard_manager_count(); 150 | uint32_t buff_size = (MAX_MC_FILENAME_LEN + 1) * count; 151 | uint8_t* image_names = malloc(buff_size); // allocate space for image names 152 | if(!image_names) 153 | return MM_ALLOC_FAIL; // malloc failed 154 | /* retrive images names */ 155 | FRESULT res; 156 | DIR root; 157 | FILINFO f_info; 158 | res = f_opendir(&root, ""); // open root directory 159 | uint32_t i = 0; 160 | if(res == FR_OK) { 161 | while(true) { 162 | res = f_readdir(&root, &f_info); 163 | if(res != FR_OK || f_info.fname[0] == 0) break; 164 | if(!(f_info.fattrib & AM_DIR)) { // not a directory 165 | if(is_image_valid(f_info.fname)) { 166 | strcpy(&image_names[(MAX_MC_FILENAME_LEN + 1) * i], f_info.fname); 167 | ++i; 168 | } 169 | } 170 | } 171 | } 172 | /* sort names alphabetically */ 173 | qsort(image_names, count, (MAX_MC_FILENAME_LEN + 1), (__compar_fn_t) strcmp); 174 | /* find current and return following one */ 175 | bool found = false; 176 | for(uint32_t i = 0; i < buff_size; i = i + (MAX_MC_FILENAME_LEN + 1)) { 177 | if(!strcmp(filename, &image_names[i])) { 178 | int32_t next_i = i + (MAX_MC_FILENAME_LEN + 1); 179 | if(next_i < buff_size) { 180 | int32_t new_index = next_i / ((MAX_MC_FILENAME_LEN + 1)); 181 | update_prev_loaded_memcard_index(new_index); 182 | strcpy(out_nextfile, &image_names[next_i]); 183 | found = true; 184 | break; 185 | } 186 | } 187 | } 188 | free(image_names); // free allocated memory 189 | /* return */ 190 | if(found) 191 | return MM_OK; 192 | else 193 | return MM_NO_ENTRY; 194 | } 195 | 196 | uint32_t memcard_manager_get_prev(uint8_t* filename, uint8_t* out_prevfile) { 197 | if(!filename || !out_prevfile) 198 | return MM_BAD_PARAM; 199 | uint32_t count = memcard_manager_count(); 200 | uint32_t buff_size = (MAX_MC_FILENAME_LEN + 1) * count; 201 | uint8_t* image_names = malloc(buff_size); // allocate space for image names 202 | if(!image_names) 203 | return MM_ALLOC_FAIL; // malloc failed 204 | /* retrive images names */ 205 | FRESULT res; 206 | DIR root; 207 | FILINFO f_info; 208 | res = f_opendir(&root, ""); // open root directory 209 | uint32_t i = 0; 210 | if(res == FR_OK) { 211 | while(true) { 212 | res = f_readdir(&root, &f_info); 213 | if(res != FR_OK || f_info.fname[0] == 0) break; 214 | if(!(f_info.fattrib & AM_DIR)) { // not a directory 215 | if(is_image_valid(f_info.fname)) { 216 | strcpy(&image_names[(MAX_MC_FILENAME_LEN + 1) * i], f_info.fname); 217 | ++i; 218 | } 219 | } 220 | } 221 | } 222 | /* sort names alphabetically */ 223 | qsort(image_names, count, (MAX_MC_FILENAME_LEN + 1), (__compar_fn_t) strcmp); 224 | /* find current and return prior one */ 225 | bool found = false; 226 | for(uint32_t i = 0; i < buff_size; i = i + (MAX_MC_FILENAME_LEN + 1)) { 227 | if(!strcmp(filename, &image_names[i])) { 228 | int32_t prev_i = i - (MAX_MC_FILENAME_LEN + 1); 229 | if(prev_i >= 0) { 230 | int32_t new_index = prev_i / (MAX_MC_FILENAME_LEN + 1); 231 | update_prev_loaded_memcard_index(new_index); 232 | strcpy(out_prevfile, &image_names[prev_i]); 233 | found = true; 234 | break; 235 | } 236 | } 237 | } 238 | free(image_names); // free allocated memory 239 | /* return */ 240 | if(found) 241 | return MM_OK; 242 | else 243 | return MM_NO_ENTRY; 244 | } 245 | 246 | uint32_t memcard_manager_create(uint8_t* out_filename) { 247 | if(!out_filename) 248 | return MM_BAD_PARAM; 249 | 250 | uint8_t name[MAX_MC_FILENAME_LEN + 1]; 251 | FIL memcard_image; 252 | 253 | uint8_t memcard_n = 0; 254 | FRESULT f_res; 255 | do { 256 | snprintf(name, MAX_MC_FILENAME_LEN + 1, "%d.MCR", memcard_n++); // Set name to %d.MCR 257 | f_res = f_open(&memcard_image, name, FA_CREATE_NEW | FA_WRITE); // Open new file for writing 258 | } while (f_res == FR_EXIST); // Repeat if file exists. 259 | 260 | strcpy(out_filename, name); // We have a valid name, copy it to out_filename 261 | 262 | if(f_res == FR_OK) { 263 | UINT bytes_written = 0; 264 | uint8_t buffer[MC_SEC_SIZE]; 265 | uint8_t xor; 266 | /* header frame (block 0, sec 0) */ 267 | buffer[0] = 'M'; 268 | buffer[1] = 'C'; 269 | xor = buffer[0] ^ buffer[1]; 270 | for(int i = 2; i < MC_SEC_SIZE - 1; i++) { 271 | buffer[i] = 0; 272 | xor = xor ^ buffer[i]; 273 | } 274 | buffer[MC_SEC_SIZE - 1] = xor; 275 | f_res = f_write(&memcard_image, buffer, MC_SEC_SIZE, &bytes_written); 276 | if(f_res != FR_OK || bytes_written != MC_SEC_SIZE) { 277 | f_close(&memcard_image); 278 | return MM_FILE_WRITE_ERR; 279 | } 280 | /* directory frames (block 0, sec 1..15) */ 281 | buffer[0] = 0xa0; // free block 282 | xor = buffer[0]; 283 | for(int i = 1; i < 8; i++) { 284 | buffer[i] = 0; 285 | xor = xor ^ buffer[i]; 286 | } 287 | buffer[8] = buffer[9] = 0xff; // no next block 288 | xor = xor ^ buffer[8] ^ buffer[9]; 289 | for(int i = 10; i < MC_SEC_SIZE - 1; i++) { 290 | buffer[i] = 0; 291 | xor = xor ^ buffer[i]; 292 | } 293 | buffer[MC_SEC_SIZE - 1] = xor; 294 | for(int i = 0; i < 15; i++) { 295 | f_res = f_write(&memcard_image, buffer, MC_SEC_SIZE, &bytes_written); 296 | if(f_res != FR_OK || bytes_written != MC_SEC_SIZE) { 297 | f_close(&memcard_image); 298 | return MM_FILE_WRITE_ERR; 299 | } 300 | } 301 | /* broken sector list (block 0, sec 16..35) */ 302 | buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0xff; // no broken sector 303 | xor = buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]; 304 | buffer[4] = buffer[5] = buffer[6] = buffer[7] = 0x00; // 0 fill 305 | xor = xor ^ buffer[4] ^ buffer[5] ^ buffer[6] ^ buffer[7]; 306 | buffer[8] = buffer[9] = 0xff; // 1 fill 307 | xor = xor ^ buffer[8] ^ buffer[9]; 308 | for(int i = 10; i < MC_SEC_SIZE - 1; i++) { 309 | buffer[i] = 0x00; 310 | xor = xor ^ buffer[i]; 311 | } 312 | buffer[MC_SEC_SIZE - 1] = xor; 313 | for(int i = 0; i < 20; i++) { 314 | f_res = f_write(&memcard_image, buffer, MC_SEC_SIZE, &bytes_written); 315 | if(f_res != FR_OK || bytes_written != MC_SEC_SIZE) { 316 | f_close(&memcard_image); 317 | return MM_FILE_WRITE_ERR; 318 | } 319 | } 320 | /* broken sector replacement data (block 0, sec 36..55) and unused frames (block 0, sec 56..62) */ 321 | for(int i = 0; i < MC_SEC_SIZE; i++) { 322 | buffer[i] = 0x00; 323 | } 324 | for(int i = 0; i < 27; i++) { 325 | f_res = f_write(&memcard_image, buffer, MC_SEC_SIZE, &bytes_written); 326 | if(f_res != FR_OK || bytes_written != MC_SEC_SIZE) { 327 | f_close(&memcard_image); 328 | return MM_FILE_WRITE_ERR; 329 | } 330 | } 331 | /* test write sector (block 0, sec 63) */ 332 | buffer[0] = 'M'; 333 | buffer[1] = 'C'; 334 | xor = buffer[0] ^ buffer[1]; 335 | for(int i = 2; i < MC_SEC_SIZE - 1; i++) { 336 | buffer[i] = 0; 337 | xor = xor ^ buffer[i]; 338 | } 339 | buffer[MC_SEC_SIZE - 1] = xor; 340 | f_res = f_write(&memcard_image, buffer, MC_SEC_SIZE, &bytes_written); 341 | if(f_res != FR_OK || bytes_written != MC_SEC_SIZE) { 342 | f_close(&memcard_image); 343 | return MM_FILE_WRITE_ERR; 344 | } 345 | /* fill remaining 15 blocks with zeros */ 346 | for(int i = 0; i < MC_SEC_SIZE; i++) { 347 | buffer[i] = 0; 348 | } 349 | for(int i = 0; i < MC_SEC_COUNT - 64; i++) { // 64 are the number of sectors written already (forming block 0) 350 | f_res = f_write(&memcard_image, buffer, MC_SEC_SIZE, &bytes_written); 351 | if(f_res != FR_OK || bytes_written != MC_SEC_SIZE) { 352 | f_close(&memcard_image); 353 | return MM_FILE_WRITE_ERR; 354 | } 355 | } 356 | f_close(&memcard_image); 357 | } else { 358 | return MM_FILE_OPEN_ERR; 359 | } 360 | update_prev_loaded_memcard_index(memcard_n - 1); 361 | return MM_OK; 362 | } -------------------------------------------------------------------------------- /src/memcard_simulator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "memcard_simulator.h" 3 | #include "stdio.h" 4 | #include "pico/multicore.h" 5 | #include "pico/platform.h" // __time_critical_func macro 6 | #include "pico/util/queue.h" 7 | #include "hardware/pio.h" 8 | #include "hardware/irq.h" 9 | #include "psxSPI.pio.h" 10 | #include "memory_card.h" 11 | #include "sd_config.h" 12 | #include "memcard_manager.h" 13 | #include "config.h" 14 | #include "pad.h" 15 | #include "led.h" 16 | 17 | #define MEMCARD_TOP 0x81 18 | #define MEMCARD_READ 0x52 19 | #define MEMCARD_WRITE 0x57 20 | #define MEMCARD_ID 0x53 21 | 22 | #define MEMCARD_PING 0x20 23 | #define MEMCARD_GAMEID 0x21 24 | #define MEMCARD_PREV_CHAN 0x22 25 | #define MEMCARD_NEXT_CHAN 0x23 26 | #define MEMCARD_PREV_CARD 0x24 27 | #define MEMCARD_NEXT_CARD 0x25 28 | #define MEMCARD_NAME 0x26 29 | 30 | #define PAD_TOP 0x01 31 | #define PAD_READ 0x42 32 | 33 | #define SEND(byte) write_byte_blocking(pio0, smDatWriter, byte) 34 | #define ACK() SEND(0xff) // ACK without sending anything by keeping the DAT line always high 35 | #define RECV_CMD() read_byte_blocking(pio0, smCmdReader) 36 | #define RECV_DAT() read_byte_blocking(pio0, smDatReader) 37 | 38 | uint smCmdReader; 39 | uint smDatReader; 40 | uint smDatWriter; 41 | 42 | uint offsetCmdReader; 43 | uint offsetDatWriter; 44 | uint offsetDatReader; 45 | 46 | memory_card_t mc; 47 | bool request_next_mc = false; 48 | bool request_prev_mc = false; 49 | bool request_new_mc = false; 50 | mutex_t write_transaction; 51 | queue_t mc_sector_sync_queue; 52 | const uint8_t id_data[] = {0x04, 0x00, 0x00, 0x80}; 53 | 54 | void simulate_mc_reconnect() { 55 | irq_set_enabled(IO_IRQ_BANK0, false); 56 | pio_restart_sm_mask(pio0, 1 << smCmdReader | 1 << smDatReader | 1 << smDatWriter); 57 | pio_sm_exec(pio0, smCmdReader, pio_encode_jmp(offsetCmdReader)); // restart smCmdReader PC 58 | pio_sm_exec(pio0, smDatReader, pio_encode_jmp(offsetDatReader)); // restart smDatReader PC 59 | pio_sm_exec(pio0, smDatWriter, pio_encode_jmp(offsetDatWriter)); // restart smDatWriter PC 60 | pio_sm_clear_fifos(pio0, smCmdReader); 61 | pio_sm_clear_fifos(pio0, smDatReader); 62 | pio_sm_drain_tx_fifo(pio0, smDatWriter); // drain instead of clear, so that we empty the OSR 63 | printf("Simulating reconnection..."); 64 | led_output_mc_change(); 65 | sleep_ms(MC_RECONNECT_TIME); 66 | printf(" done\n"); 67 | irq_set_enabled(IO_IRQ_BANK0, true); 68 | } 69 | 70 | void process_memcard_cmd() { 71 | SEND(mc.flag_byte); 72 | uint8_t data = RECV_CMD(); 73 | switch(data) { 74 | case MEMCARD_READ: 75 | { 76 | SEND(MC_ID1); 77 | RECV_CMD(); // discard 0-filled data 78 | SEND(MC_ID2); 79 | RECV_CMD(); 80 | SEND(0x00); // send filler 81 | data = RECV_CMD(); 82 | sector_t read_address = data << 8; 83 | SEND(data); // confirm received MSB 84 | data = RECV_CMD(); 85 | read_address |= data; 86 | SEND(MC_ACK1); 87 | RECV_CMD(); 88 | SEND(MC_ACK2); 89 | RECV_CMD(); 90 | uint8_t checksum = ((read_address & 0xFF00) >> 8) ^ (read_address & 0x00FF); 91 | if(!memory_card_is_sector_valid(&mc, read_address)) { 92 | SEND(0xff); // abort transaction 93 | return; 94 | } 95 | SEND((read_address & 0xFF00) >> 8); // confirm MSB 96 | RECV_CMD(); 97 | SEND(read_address & 0x00FF); // confirm LSB 98 | RECV_CMD(); 99 | 100 | /* send data */ 101 | uint8_t* sec_ptr = memory_card_get_sector_ptr(&mc, read_address); 102 | for (uint32_t i = 0; i < MC_SEC_SIZE; i++) { 103 | SEND(sec_ptr[i]); 104 | RECV_CMD(); 105 | checksum ^= sec_ptr[i]; 106 | } 107 | SEND(checksum); 108 | RECV_CMD(); 109 | SEND(MC_GOOD); 110 | RECV_CMD(); 111 | } 112 | break; 113 | case MEMCARD_WRITE: 114 | { 115 | mutex_enter_blocking(&write_transaction); 116 | SEND(MC_ID1); 117 | RECV_CMD(); 118 | SEND(MC_ID2); 119 | RECV_CMD(); 120 | SEND(0x00); 121 | data = RECV_CMD(); 122 | sector_t write_address = data << 8; 123 | SEND(data); // confirm received MSB 124 | data = RECV_CMD(); 125 | write_address |= data; 126 | uint8_t checksum = ((write_address & 0xFF00) >> 8) ^ (write_address & 0x00FF); 127 | if(!memory_card_is_sector_valid(&mc, write_address)) { 128 | SEND(0xff); // abort transaction 129 | return; 130 | } 131 | uint8_t* sec_ptr = memory_card_get_sector_ptr(&mc, write_address); 132 | for(uint32_t i = 0; i < MC_SEC_SIZE; i++) { 133 | SEND(data); // ack previous data 134 | data = RECV_CMD(); // receive new data 135 | checksum ^= data; 136 | sec_ptr[i] = data; 137 | } 138 | SEND(data); // send remaining sector byte 139 | uint8_t recv_checksum = RECV_CMD(); 140 | /* send acks */ 141 | SEND(MC_ACK1); 142 | RECV_CMD(); 143 | SEND(MC_ACK2); 144 | RECV_CMD(); 145 | memory_card_reset_seen_flag(&mc); 146 | if(write_address != MC_TEST_SEC) { 147 | queue_add_blocking(&mc_sector_sync_queue, &write_address); 148 | } 149 | if(checksum == recv_checksum) 150 | SEND(MC_GOOD); 151 | else 152 | SEND(MC_BAD_CHK); 153 | RECV_CMD(); 154 | mutex_exit(&write_transaction); 155 | } 156 | break; 157 | case MEMCARD_ID: 158 | { 159 | SEND(MC_ID1); 160 | RECV_CMD(); 161 | SEND(MC_ID2); 162 | RECV_CMD(); 163 | SEND(0x00); 164 | /* send acks */ 165 | SEND(MC_ACK1); 166 | RECV_CMD(); 167 | SEND(MC_ACK2); 168 | RECV_CMD(); 169 | for(uint32_t i = 0; i < sizeof(id_data); i++) { 170 | SEND(id_data[i]); 171 | RECV_CMD(); 172 | } 173 | } 174 | break; 175 | case MEMCARD_PING: 176 | { 177 | SEND(0x00); // byte 1 reserved 178 | RECV_CMD(); 179 | SEND(0x00); // byte 2 reserved 180 | RECV_CMD(); 181 | SEND(0x27); // card present 182 | RECV_CMD(); 183 | printf("MC Received Ping from PS\n"); 184 | } 185 | break; 186 | case MEMCARD_GAMEID: 187 | { 188 | SEND(0x00); 189 | uint8_t game_id_len = RECV_CMD(); 190 | data = 0x00; 191 | uint8_t game_id[256] = {0}; 192 | /* read game id */ 193 | for(uint32_t i = 0; i < game_id_len; i++) { 194 | SEND(data); // ack previous data 195 | data = RECV_CMD(); 196 | game_id[i] = data; 197 | } 198 | SEND(data); // ack last byte 199 | printf("Game ID: %s\n", game_id); 200 | } 201 | break; 202 | default: 203 | break; 204 | } 205 | } 206 | 207 | void process_pad_cmd() { /* during pad interaction never call SEND() only interested in listening passively */ 208 | if(RECV_CMD() != PAD_READ) // only interested in PSX trying to read pad 209 | return; 210 | RECV_CMD(); // ignore TAP byte 211 | pio_sm_clear_fifos(pio0, smDatReader); // clear out Hi-Z, idlo, and idhi bytes 212 | uint16_t sw_status = RECV_DAT(); 213 | sw_status |= RECV_DAT() << 8; 214 | switch(sw_status) { 215 | case START & SELECT & UP: 216 | request_next_mc = true; 217 | break; 218 | case START & SELECT & DOWN: 219 | request_prev_mc = true; 220 | break; 221 | case START & SELECT & TRIANGLE: 222 | request_new_mc = true; 223 | break; 224 | default: 225 | break; 226 | } 227 | } 228 | 229 | void process_cmd(uint8_t cmd) { 230 | switch (cmd) { 231 | case MEMCARD_TOP: 232 | process_memcard_cmd(); 233 | break; 234 | case PAD_TOP: 235 | process_pad_cmd(); 236 | break; 237 | default: 238 | break; 239 | } 240 | } 241 | 242 | _Noreturn void simulation_thread() { 243 | while(true) { 244 | process_cmd(RECV_CMD()); 245 | } 246 | } 247 | 248 | void __time_critical_func(restart_pio_sm)(void) { 249 | pio_set_sm_mask_enabled(pio0, 1 << smCmdReader | 1 << smDatReader | 1 << smDatWriter, false); 250 | pio_restart_sm_mask(pio0, 1 << smCmdReader | 1 << smDatReader | 1 << smDatWriter); 251 | pio_sm_exec(pio0, smCmdReader, pio_encode_jmp(offsetCmdReader)); // restart smCmdReader PC 252 | pio_sm_exec(pio0, smDatReader, pio_encode_jmp(offsetDatReader)); // restart smDatReader PC 253 | pio_sm_exec(pio0, smDatWriter, pio_encode_jmp(offsetDatWriter)); // restart smDatWriter PC 254 | pio_sm_clear_fifos(pio0, smCmdReader); 255 | pio_sm_clear_fifos(pio0, smDatReader); 256 | pio_sm_drain_tx_fifo(pio0, smDatWriter); // drain instead of clear, so that we empty the OSR 257 | 258 | // resetting and launching core1 here allows to perform the reset of the transaction (e.g. when PSX polls for new MC without completing the read) 259 | multicore_reset_core1(); 260 | multicore_launch_core1(simulation_thread); 261 | pio_enable_sm_mask_in_sync(pio0, 1 << smCmdReader | 1 << smDatReader | 1 << smDatWriter); 262 | } 263 | 264 | void init_pio() { 265 | gpio_set_dir(PIN_DAT, false); 266 | gpio_set_dir(PIN_CMD, false); 267 | gpio_set_dir(PIN_SEL, false); 268 | gpio_set_dir(PIN_CLK, false); 269 | gpio_set_dir(PIN_ACK, false); 270 | gpio_disable_pulls(PIN_DAT); 271 | gpio_disable_pulls(PIN_CMD); 272 | gpio_disable_pulls(PIN_SEL); 273 | gpio_disable_pulls(PIN_CLK); 274 | gpio_disable_pulls(PIN_ACK); 275 | 276 | smCmdReader = pio_claim_unused_sm(pio0, true); 277 | smDatReader = pio_claim_unused_sm(pio0, true); 278 | smDatWriter = pio_claim_unused_sm(pio0, true); 279 | 280 | offsetCmdReader = pio_add_program(pio0, &cmd_reader_program); 281 | offsetDatReader = pio_add_program(pio0, &dat_reader_program); 282 | offsetDatWriter = pio_add_program(pio0, &dat_writer_program); 283 | 284 | cmd_reader_program_init(pio0, smCmdReader, offsetCmdReader); 285 | dat_reader_program_init(pio0, smDatReader, offsetDatReader); 286 | dat_writer_program_init(pio0, smDatWriter, offsetDatWriter); 287 | } 288 | 289 | void __time_critical_func(sel_isr_callback()) { 290 | // TODO refractor comment, also is __time_critical_func needed for speed? we should test if everything works without it! 291 | /* begin inlined call of: gpio_acknowledge_irq(PIN_SEL, GPIO_IRQ_EDGE_RISE); kept in RAM for performance reasons */ 292 | check_gpio_param(PIN_SEL); 293 | iobank0_hw->intr[PIN_SEL / 8] = GPIO_IRQ_EDGE_RISE << (4 * (PIN_SEL % 8)); 294 | /* end of inlined call */ 295 | restart_pio_sm(); 296 | } 297 | 298 | void queue_sync_step(queue_t* queue, uint8_t* mc_file_name) { 299 | uint16_t next_entry; 300 | queue_remove_blocking(queue, &next_entry); 301 | uint32_t status = memory_card_sync_sector(&mc, next_entry, mc_file_name); 302 | if(status != MC_OK) 303 | led_blink_error(status); 304 | } 305 | 306 | _Noreturn int simulate_memory_card() { 307 | mutex_init(&write_transaction); 308 | queue_init(&mc_sector_sync_queue, sizeof(sector_t), MC_SEC_COUNT); // enough space to do complete MC copy 309 | uint8_t mc_file_name[MAX_MC_FILENAME_LEN + 1]; // +1 for null terminator character 310 | 311 | /* Mount and test SD card filesystem */ 312 | sd_card_t *p_sd = sd_get_by_num(0); 313 | if(FR_OK != f_mount(&p_sd->fatfs, "", 1)) { 314 | while(true) 315 | led_blink_error(1); 316 | } 317 | 318 | uint32_t status = memory_card_init(&mc); 319 | if(status != MC_OK) { 320 | while(true) { 321 | led_blink_error(status); 322 | sleep_ms(2000); 323 | } 324 | } 325 | status = memcard_manager_get_initial(mc_file_name); // get initial memory card to load 326 | if(status != MM_OK) { 327 | status = memcard_manager_get(0, mc_file_name); // revert to first mem card if failing to load previously loaded card 328 | if(status != MM_OK) { 329 | while(true) { 330 | led_blink_error(status); 331 | sleep_ms(1000); 332 | } 333 | } 334 | } 335 | status = memory_card_import(&mc, mc_file_name); 336 | if(status != MC_OK) { 337 | while(true) { 338 | led_blink_error(status); 339 | sleep_ms(2000); 340 | } 341 | } 342 | 343 | printf("Initializing PIO..."); 344 | init_pio(); 345 | printf(" done\n"); 346 | 347 | /* Setup SEL interrupt on GPIO */ 348 | // gpio_set_irq_enabled_with_callback(PIN_SEL, GPIO_IRQ_EDGE_RISE, true, my_gpio_callback); // decomposed into: 349 | gpio_set_irq_enabled(PIN_SEL, GPIO_IRQ_EDGE_RISE, true); 350 | irq_set_exclusive_handler(IO_IRQ_BANK0, sel_isr_callback); // instead of normal gpio_set_irq_callback() which has slower handling 351 | irq_set_enabled(IO_IRQ_BANK0, true); 352 | 353 | /* Setup additional GPIO configuration options */ 354 | gpio_set_slew_rate(PIN_DAT, GPIO_SLEW_RATE_FAST); 355 | gpio_set_drive_strength(PIN_DAT, GPIO_DRIVE_STRENGTH_12MA); 356 | 357 | /* SMs are automatically enabled on first SEL reset */ 358 | 359 | /* Launch memory card thread */ 360 | printf("Starting simulation core..."); 361 | multicore_launch_core1(simulation_thread); 362 | printf(" done\n"); 363 | 364 | /* Process sync/switch/creation requests */ 365 | while(true) { 366 | if(!queue_is_empty(&mc_sector_sync_queue)) { 367 | led_output_sync_status(true); 368 | queue_sync_step(&mc_sector_sync_queue, mc_file_name); 369 | } else { 370 | led_output_sync_status(false); 371 | } 372 | if(request_next_mc || request_prev_mc) { 373 | if(request_next_mc && request_prev_mc) { 374 | /* requested change in both directions, do nothing */ 375 | request_next_mc = false; 376 | request_prev_mc = false; 377 | } else { 378 | uint8_t new_file_name[MAX_MC_FILENAME_LEN + 1]; 379 | if(request_next_mc) 380 | status = memcard_manager_get_next(mc_file_name, new_file_name); 381 | else if (request_prev_mc) 382 | status = memcard_manager_get_prev(mc_file_name, new_file_name); 383 | if(status != MM_OK) { 384 | led_output_end_mc_list(); 385 | request_next_mc = false; 386 | request_prev_mc = false; 387 | } else { 388 | mutex_enter_blocking(&write_transaction); 389 | /* ensure latest write operations have been synced */ 390 | led_output_sync_status(true); 391 | while(!queue_is_empty(&mc_sector_sync_queue)) 392 | queue_sync_step(&mc_sector_sync_queue, mc_file_name); 393 | led_output_sync_status(false); 394 | /* switch mc */ 395 | strcpy(mc_file_name, new_file_name); 396 | status = memory_card_import(&mc, mc_file_name); 397 | if(status != MC_OK) 398 | led_blink_error(status); 399 | simulate_mc_reconnect(); 400 | request_next_mc = false; 401 | request_prev_mc = false; 402 | mutex_exit(&write_transaction); 403 | } 404 | } 405 | } else if(request_new_mc) { 406 | mutex_enter_blocking(&write_transaction); 407 | /* ensure latest write operations have been synced */ 408 | led_output_sync_status(true); 409 | while(!queue_is_empty(&mc_sector_sync_queue)) 410 | queue_sync_step(&mc_sector_sync_queue, mc_file_name); 411 | led_output_sync_status(false); 412 | /* create new mc */ 413 | uint8_t new_name[MAX_MC_FILENAME_LEN + 1]; 414 | status = memcard_manager_create(new_name); 415 | if(status == MM_OK) { 416 | led_output_new_mc(); 417 | strcpy(mc_file_name, new_name); 418 | status = memory_card_import(&mc, mc_file_name); // switch to newly created mc image 419 | if(status != MC_OK) 420 | led_blink_error(status); 421 | } else 422 | led_blink_error(status); 423 | simulate_mc_reconnect(); 424 | request_new_mc = false; 425 | mutex_exit(&write_transaction); 426 | } 427 | } 428 | } -------------------------------------------------------------------------------- /src/memory_card.c: -------------------------------------------------------------------------------- 1 | #include "memory_card.h" 2 | #include 3 | #include "config.h" 4 | #include "ff.h" 5 | #include "pico/stdlib.h" 6 | 7 | uint32_t memory_card_init(memory_card_t* mc) { 8 | if(!mc) 9 | return MC_NO_INIT; 10 | mc->flag_byte = MC_FLAG_BYTE_DEF; 11 | mc->data = (uint8_t*) malloc(sizeof(uint8_t) * MC_SIZE); 12 | if(!mc->data) 13 | return MC_NO_INIT; // malloc failed 14 | return MC_OK; 15 | } 16 | 17 | uint32_t memory_card_import(memory_card_t* mc, uint8_t* file_name) { 18 | uint32_t status = MC_OK; 19 | FIL memcard; 20 | 21 | if(mc) { 22 | mc->flag_byte = MC_FLAG_BYTE_DEF; 23 | if(FR_OK == f_open(&memcard, file_name, FA_READ)) { 24 | UINT bytes_read; 25 | if(FR_OK == f_read(&memcard, mc->data, MC_SIZE, &bytes_read)) { 26 | if(MC_SIZE != bytes_read) { 27 | status = MC_FILE_READ_ERR; 28 | } 29 | } else { 30 | status = MC_FILE_SIZE_ERR; 31 | } 32 | f_close(&memcard); 33 | } else { 34 | status = MC_FILE_OPEN_ERR; 35 | } 36 | } else { 37 | status = MC_NO_INIT; 38 | } 39 | 40 | return status; 41 | } 42 | 43 | bool memory_card_is_sector_valid(memory_card_t* mc, sector_t sector) { 44 | (void) mc; 45 | if(sector < 0 || sector >= MC_SEC_COUNT) 46 | return false; 47 | return true; 48 | } 49 | 50 | uint8_t* memory_card_get_sector_ptr(memory_card_t* mc, sector_t sector) { 51 | if(mc) 52 | return &mc->data[sector * MC_SEC_SIZE]; 53 | return NULL; 54 | } 55 | 56 | void memory_card_reset_seen_flag(memory_card_t* mc) { 57 | if(mc) 58 | mc->flag_byte &= ~(1 << 3); 59 | } 60 | 61 | /*** 62 | * Sync memory card modified sectors back into flash storage. 63 | * Does not create concurrency problem as it only reads from the in-RAM copy. 64 | * If a sector is being synced while the in-RAM copy is being modified, 65 | * then there is a transient loss of consistency. Consistency is eventually 66 | * resolved since there will be another entry further down the queue 67 | * enforcing the sync for that same sector to occurr once again. 68 | */ 69 | uint32_t memory_card_sync_sector(memory_card_t* mc, sector_t sector, uint8_t* file_name) { 70 | uint32_t status = MC_OK; 71 | FIL memcard; 72 | 73 | if(FR_OK == f_open(&memcard, file_name, FA_READ | FA_WRITE)) { 74 | UINT bytes_written; 75 | f_lseek(&memcard, (sector * MC_SEC_SIZE)); 76 | if(FR_OK == f_write(&memcard, &mc->data[sector * MC_SEC_SIZE], MC_SEC_SIZE, &bytes_written)) { 77 | if(MC_SEC_SIZE != bytes_written) { 78 | status = MC_FILE_SIZE_ERR; 79 | } 80 | } else { 81 | status = MC_FILE_WRITE_ERR; 82 | } 83 | 84 | f_close(&memcard); 85 | } else { 86 | status = MC_FILE_OPEN_ERR; 87 | } 88 | 89 | return status; 90 | } -------------------------------------------------------------------------------- /src/msc_handler.c: -------------------------------------------------------------------------------- 1 | #include "bsp/board.h" 2 | #include "tusb.h" 3 | #include "config.h" 4 | #include "sd_config.h" 5 | 6 | #define VID "PicoMC" 7 | #define PID "Mass Storage" 8 | #define REV "1.0" 9 | 10 | 11 | /* invoked when received SCSI_CMD_INQUIRY */ 12 | void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) 13 | { 14 | sd_card_t* p_sd = sd_get_by_num(lun); 15 | if (!p_sd) return; 16 | 17 | const char vid[] = VID; 18 | const char pid[] = PID; 19 | const char rev[] = REV; 20 | 21 | memcpy(vendor_id , vid, strlen(vid)); 22 | memcpy(product_id , pid, strlen(pid)); 23 | memcpy(product_rev, rev, strlen(rev)); 24 | } 25 | 26 | /* invoked when received Test Unit Ready command */ 27 | bool tud_msc_test_unit_ready_cb(uint8_t lun) 28 | { 29 | sd_card_t* p_sd = sd_get_by_num(lun); 30 | if (!p_sd) return false; 31 | 32 | if(p_sd->m_Status != 0) { 33 | // Additional Sense 3A-00 is NOT_FOUND 34 | tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00); 35 | return false; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | /* invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size */ 42 | void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) 43 | { 44 | sd_card_t* p_sd = sd_get_by_num(lun); 45 | if (!p_sd) return; 46 | 47 | *block_count = (uint32_t) p_sd->sectors; 48 | *block_size = (uint16_t) BLOCK_SIZE; 49 | } 50 | 51 | /* 52 | invoked when received Start Stop Unit command 53 | - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage 54 | - Start = 1 : active mode, if load_eject = 1 : load disk storage 55 | */ 56 | bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) 57 | { 58 | (void) power_condition; 59 | 60 | if ( load_eject ) 61 | { 62 | if(start) { 63 | return true; 64 | } 65 | } 66 | 67 | return true; 68 | } 69 | 70 | /* callback invoked when received READ10 command */ 71 | int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) 72 | { 73 | sd_card_t* p_sd = sd_get_by_num(lun); 74 | if (!p_sd) return -1; // not valid drive 75 | 76 | if(lba < 0 || lba >= p_sd->sectors) return -1; // invalid sector 77 | if(bufsize != BLOCK_SIZE) return -1; // invalid transfer unit 78 | if(offset != 0) return -1; // cannot read unaligned sectors 79 | 80 | int status = sd_read_blocks(p_sd, (uint8_t*) buffer, (uint64_t) lba, 1); 81 | if(status != SD_BLOCK_DEVICE_ERROR_NONE) return -1; // read failed 82 | 83 | return (int32_t) bufsize; 84 | } 85 | 86 | bool tud_msc_is_writable_cb (uint8_t lun) 87 | { 88 | sd_card_t* p_sd = sd_get_by_num(lun); 89 | if (!p_sd) return false; 90 | return true; 91 | } 92 | 93 | /* callback invoked when received WRITE10 command */ 94 | // Process data in buffer to disk's storage and return number of written bytes 95 | int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) 96 | { 97 | sd_card_t* p_sd = sd_get_by_num(lun); 98 | if (!p_sd) return -1; // not valid drive 99 | 100 | if(lba < 0 || lba >= p_sd->sectors) return -1; // invalid sector 101 | if(bufsize != BLOCK_SIZE) return -1; // invalid transfer unit 102 | if(offset != 0) return -1; // writes must be sector aligned 103 | 104 | int status = sd_write_blocks(p_sd, buffer, lba, 1); 105 | if(status != SD_BLOCK_DEVICE_ERROR_NONE) return -1; // write failed 106 | 107 | return (int32_t) bufsize; 108 | } 109 | 110 | /* 111 | callback invoked when received an SCSI command not in built-in list below 112 | - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE 113 | - READ10 and WRITE10 has their own callbacks 114 | */ 115 | int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) 116 | { 117 | void const* response = NULL; 118 | int32_t resplen = 0; 119 | 120 | // most scsi handled is input 121 | bool in_xfer = true; 122 | 123 | switch(scsi_cmd[0]) { 124 | case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: 125 | resplen = 0; 126 | break; 127 | default: 128 | // Set Sense = Invalid Command Operation 129 | tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); 130 | 131 | // negative means error -> tinyusb could stall and/or response with failed status 132 | resplen = -1; 133 | break; 134 | } 135 | 136 | // return resplen must not larger than bufsize 137 | if(resplen > bufsize) resplen = bufsize; 138 | 139 | if(response && (resplen > 0)) { 140 | if(in_xfer) { 141 | memcpy(buffer, response, (size_t) resplen); 142 | } else { 143 | // SCSI output 144 | } 145 | } 146 | 147 | return (int32_t) resplen; 148 | } -------------------------------------------------------------------------------- /src/sd_config.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "sd_config.h" 3 | #include "ff.h" 4 | #include "diskio.h" 5 | #include "config.h" 6 | 7 | void spi0_dma_isr(); 8 | 9 | static spi_t spis[] = { 10 | { 11 | .hw_inst = spi0, 12 | .miso_gpio = PIN_MISO, 13 | .mosi_gpio = PIN_MOSI, 14 | .sck_gpio = PIN_SCK, 15 | .baud_rate = BAUD_RATE, 16 | 17 | .dma_isr = spi0_dma_isr 18 | }}; 19 | 20 | void spi0_dma_isr() { spi_irq_handler(&spis[0]); } 21 | 22 | static sd_card_t sd_cards[] = { 23 | { 24 | .pcName = "0:", 25 | .spi = &spis[0], 26 | .ss_gpio = PIN_SS, 27 | .use_card_detect = false, 28 | .m_Status = STA_NOINIT 29 | } 30 | }; 31 | 32 | size_t sd_get_num() { return count_of(sd_cards); } 33 | sd_card_t *sd_get_by_num(size_t num) { 34 | if (num <= sd_get_num()) { 35 | return &sd_cards[num]; 36 | } else { 37 | return NULL; 38 | } 39 | } 40 | size_t spi_get_num() { return count_of(spis); } 41 | spi_t *spi_get_by_num(size_t num) { 42 | if (num <= sd_get_num()) { 43 | return &spis[num]; 44 | } else { 45 | return NULL; 46 | } 47 | } -------------------------------------------------------------------------------- /src/usb_descriptors.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019 Ha Thach (tinyusb.org) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | #include "tusb.h" 27 | 28 | /* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. 29 | * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. 30 | * 31 | * Auto ProductID layout's Bitmap: 32 | * [MSB] HID | MSC | CDC [LSB] 33 | */ 34 | #define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) 35 | #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ 36 | _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) 37 | 38 | #define USB_VID 0xCafe 39 | #define USB_BCD 0x0200 40 | 41 | //--------------------------------------------------------------------+ 42 | // Device Descriptors 43 | //--------------------------------------------------------------------+ 44 | tusb_desc_device_t const desc_device = 45 | { 46 | .bLength = sizeof(tusb_desc_device_t), 47 | .bDescriptorType = TUSB_DESC_DEVICE, 48 | .bcdUSB = USB_BCD, 49 | 50 | // Use Interface Association Descriptor (IAD) for CDC 51 | // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) 52 | .bDeviceClass = TUSB_CLASS_MISC, 53 | .bDeviceSubClass = MISC_SUBCLASS_COMMON, 54 | .bDeviceProtocol = MISC_PROTOCOL_IAD, 55 | 56 | .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, 57 | 58 | .idVendor = USB_VID, 59 | .idProduct = USB_PID, 60 | .bcdDevice = 0x0100, 61 | 62 | .iManufacturer = 0x01, 63 | .iProduct = 0x02, 64 | .iSerialNumber = 0x03, 65 | 66 | .bNumConfigurations = 0x01 67 | }; 68 | 69 | // Invoked when received GET DEVICE DESCRIPTOR 70 | // Application return pointer to descriptor 71 | uint8_t const * tud_descriptor_device_cb(void) 72 | { 73 | return (uint8_t const *) &desc_device; 74 | } 75 | 76 | //--------------------------------------------------------------------+ 77 | // Configuration Descriptor 78 | //--------------------------------------------------------------------+ 79 | 80 | enum 81 | { 82 | ITF_NUM_CDC = 0, 83 | ITF_NUM_CDC_DATA, 84 | ITF_NUM_MSC, 85 | ITF_NUM_TOTAL 86 | }; 87 | 88 | #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX 89 | // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number 90 | // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ... 91 | #define EPNUM_CDC_NOTIF 0x81 92 | #define EPNUM_CDC_OUT 0x02 93 | #define EPNUM_CDC_IN 0x82 94 | 95 | #define EPNUM_MSC_OUT 0x05 96 | #define EPNUM_MSC_IN 0x85 97 | 98 | #elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X 99 | // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT 100 | // e.g EP1 OUT & EP1 IN cannot exist together 101 | #define EPNUM_CDC_NOTIF 0x81 102 | #define EPNUM_CDC_OUT 0x02 103 | #define EPNUM_CDC_IN 0x83 104 | 105 | #define EPNUM_MSC_OUT 0x04 106 | #define EPNUM_MSC_IN 0x85 107 | 108 | #elif CFG_TUSB_MCU == OPT_MCU_CXD56 109 | // CXD56 doesn't support a same endpoint number with different direction IN and OUT 110 | // e.g EP1 OUT & EP1 IN cannot exist together 111 | // CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number 112 | // 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN) 113 | #define EPNUM_CDC_NOTIF 0x83 114 | #define EPNUM_CDC_OUT 0x02 115 | #define EPNUM_CDC_IN 0x81 116 | 117 | #define EPNUM_MSC_OUT 0x05 118 | #define EPNUM_MSC_IN 0x84 119 | 120 | #elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X 121 | // FT9XX doesn't support a same endpoint number with different direction IN and OUT 122 | // e.g EP1 OUT & EP1 IN cannot exist together 123 | #define EPNUM_CDC_NOTIF 0x81 124 | #define EPNUM_CDC_OUT 0x02 125 | #define EPNUM_CDC_IN 0x83 126 | 127 | #define EPNUM_MSC_OUT 0x04 128 | #define EPNUM_MSC_IN 0x85 129 | 130 | #else 131 | #define EPNUM_CDC_NOTIF 0x81 132 | #define EPNUM_CDC_OUT 0x02 133 | #define EPNUM_CDC_IN 0x82 134 | 135 | #define EPNUM_MSC_OUT 0x03 136 | #define EPNUM_MSC_IN 0x83 137 | 138 | #endif 139 | 140 | #define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN) 141 | 142 | // full speed configuration 143 | uint8_t const desc_fs_configuration[] = 144 | { 145 | // Config number, interface count, string index, total length, attribute, power in mA 146 | TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), 147 | 148 | // Interface number, string index, EP notification address and size, EP data address (out, in) and size. 149 | TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64), 150 | 151 | // Interface number, string index, EP Out & EP In address, EP size 152 | TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64), 153 | }; 154 | 155 | #if TUD_OPT_HIGH_SPEED 156 | // Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration 157 | 158 | // high speed configuration 159 | uint8_t const desc_hs_configuration[] = 160 | { 161 | // Config number, interface count, string index, total length, attribute, power in mA 162 | TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), 163 | 164 | // Interface number, string index, EP notification address and size, EP data address (out, in) and size. 165 | TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512), 166 | 167 | // Interface number, string index, EP Out & EP In address, EP size 168 | TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512), 169 | }; 170 | 171 | // other speed configuration 172 | uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN]; 173 | 174 | // device qualifier is mostly similar to device descriptor since we don't change configuration based on speed 175 | tusb_desc_device_qualifier_t const desc_device_qualifier = 176 | { 177 | .bLength = sizeof(tusb_desc_device_qualifier_t), 178 | .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, 179 | .bcdUSB = USB_BCD, 180 | 181 | .bDeviceClass = TUSB_CLASS_MISC, 182 | .bDeviceSubClass = MISC_SUBCLASS_COMMON, 183 | .bDeviceProtocol = MISC_PROTOCOL_IAD, 184 | 185 | .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, 186 | .bNumConfigurations = 0x01, 187 | .bReserved = 0x00 188 | }; 189 | 190 | // Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request 191 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. 192 | // device_qualifier descriptor describes information about a high-speed capable device that would 193 | // change if the device were operating at the other speed. If not highspeed capable stall this request. 194 | uint8_t const* tud_descriptor_device_qualifier_cb(void) 195 | { 196 | return (uint8_t const*) &desc_device_qualifier; 197 | } 198 | 199 | // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request 200 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete 201 | // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa 202 | uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) 203 | { 204 | (void) index; // for multiple configurations 205 | 206 | // if link speed is high return fullspeed config, and vice versa 207 | // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG 208 | memcpy(desc_other_speed_config, 209 | (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration, 210 | CONFIG_TOTAL_LEN); 211 | 212 | desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; 213 | 214 | return desc_other_speed_config; 215 | } 216 | 217 | #endif // highspeed 218 | 219 | 220 | // Invoked when received GET CONFIGURATION DESCRIPTOR 221 | // Application return pointer to descriptor 222 | // Descriptor contents must exist long enough for transfer to complete 223 | uint8_t const * tud_descriptor_configuration_cb(uint8_t index) 224 | { 225 | (void) index; // for multiple configurations 226 | 227 | #if TUD_OPT_HIGH_SPEED 228 | // Although we are highspeed, host may be fullspeed. 229 | return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration; 230 | #else 231 | return desc_fs_configuration; 232 | #endif 233 | } 234 | 235 | //--------------------------------------------------------------------+ 236 | // String Descriptors 237 | //--------------------------------------------------------------------+ 238 | 239 | // array of pointer to string descriptors 240 | char const* string_desc_arr [] = 241 | { 242 | (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) 243 | "DanGiu", // 1: Manufacturer 244 | "PicoMemcard Device", // 2: Product 245 | "123456789012", // 3: Serials, should use chip ID 246 | "PicoMemcard CDC", // 4: CDC Interface 247 | "PicoMemcard MSC", // 5: MSC Interface 248 | }; 249 | 250 | static uint16_t _desc_str[32]; 251 | 252 | // Invoked when received GET STRING DESCRIPTOR request 253 | // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete 254 | uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) 255 | { 256 | (void) langid; 257 | 258 | uint8_t chr_count; 259 | 260 | if ( index == 0) 261 | { 262 | memcpy(&_desc_str[1], string_desc_arr[0], 2); 263 | chr_count = 1; 264 | }else 265 | { 266 | // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. 267 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors 268 | 269 | if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; 270 | 271 | const char* str = string_desc_arr[index]; 272 | 273 | // Cap at max char 274 | chr_count = (uint8_t) strlen(str); 275 | if ( chr_count > 31 ) chr_count = 31; 276 | 277 | // Convert ASCII string into UTF-16 278 | for(uint8_t i=0; i