├── .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 | [](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 | [](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 |
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 |
54 |
55 |
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 |
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 |
135 |
136 |
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 |
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