{"id":2307,"date":"2026-01-18T11:42:53","date_gmt":"2026-01-18T02:42:53","guid":{"rendered":"https:\/\/rfsec.ddns.net\/db\/?p=2307"},"modified":"2026-01-18T11:42:53","modified_gmt":"2026-01-18T02:42:53","slug":"raspberry-pi-pico%e3%81%a7%e3%82%b7%e3%83%b3%e3%82%bb%e3%82%b5%e3%82%a4%e3%82%b6%e3%83%bc","status":"publish","type":"post","link":"https:\/\/rfsec.ddns.net\/db\/?p=2307","title":{"rendered":"Raspberry Pi PICO\u3067\u30b7\u30f3\u30bb\u30b5\u30a4\u30b6\u30fc"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<p>Raspberry Pi Pico 2 (RP2350) \u3068\u30bf\u30c3\u30c1\u30d1\u30cd\u30eb\u6db2\u6676\u3001\u305d\u3057\u3066USB MIDI\u30ad\u30fc\u30dc\u30fc\u30c9\u3092\u7d44\u307f\u5408\u308f\u305b\u305f\u81ea\u4f5c\u30b7\u30f3\u30bb\u30b5\u30a4\u30b6\u30fc\u958b\u767a\u306b\u304a\u3051\u308b\u3001\u30c7\u30d0\u30c3\u30b0\u306e\u8a18\u9332\u3092\u8a18\u4e8b\u306b\u307e\u3068\u3081\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">\u3010RP2350\u3011Pico 2\u3067\u30bf\u30c3\u30c1\u30d1\u30cd\u30eb\u6db2\u6676\u30b7\u30f3\u30bb\u3092\u4f5c\u308b\uff1aCST328\u306e\u5ea7\u6a19\u30ba\u30ec\u3068USB Host MIDI\u8a8d\u8b58\u30a8\u30e9\u30fc\u3068\u306e\u95d8\u3044<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\">\u80cc\u666f<\/h2>\n\n\n\n<p>Raspberry Pi Pico 2 (RP2350) \u306b Waveshare\u306e2.8\u30a4\u30f3\u30c1\u30bf\u30c3\u30c1LCD\u3092\u63a5\u7d9a\u3057\u3001\u30dd\u30ea\u30d5\u30a9\u30cb\u30c3\u30af\u30fb\u30b7\u30f3\u30bb\u30b5\u30a4\u30b6\u30fc\u3092\u4f5c\u6210\u3057\u3066\u3044\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>\u97f3\u306e\u751f\u6210\u3084SD\u30ab\u30fc\u30c9\u304b\u3089\u306eMIDI\u30d5\u30a1\u30a4\u30eb\u518d\u751f\u307e\u3067\u306f\u9806\u8abf\u3067\u3057\u305f\u304c\u3001\u300c\u30bf\u30c3\u30c1\u30d1\u30cd\u30eb\u306e\u5ea7\u6a19\u304c\u6b63\u3057\u304f\u53d6\u308c\u306a\u3044\u300d \u554f\u984c\u3068\u3001\u300cUSB MIDI\u30ad\u30fc\u30dc\u30fc\u30c9\u3092\u63a5\u7d9a\u3057\u3066\u3082\u8a8d\u8b58\u3057\u306a\u3044\uff08USB\u30db\u30b9\u30c8\u6a5f\u80fd\uff09\u300d \u3068\u3044\u30462\u3064\u306e\u5927\u304d\u306a\u58c1\u306b\u3076\u3064\u304b\u308a\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>\u3053\u306e\u8a18\u4e8b\u306f\u3001\u305d\u306e\u89e3\u6c7a\u307e\u3067\u306e\u8a66\u884c\u932f\u8aa4\u306e\u30ed\u30b0\u3067\u3059\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u30a8\u30e9\u30fc\u3068\u306e\u6226\u3044\uff1a\u8a66\u884c\u932f\u8aa4\u306e\u30d7\u30ed\u30bb\u30b9<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Round 1: \u30bf\u30c3\u30c1\u5ea7\u6a19\u304c\u30ce\u30b3\u30ae\u30ea\u6ce2\u306b\u306a\u308b<\/h3>\n\n\n\n<p>\u6700\u521d\u306b\u66f8\u3044\u305f\u30b3\u30fc\u30c9\u3067\u306f\u3001\u30bf\u30c3\u30c1\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\uff08CST328\uff09\u304b\u3089I2C\u3067\u5358\u7d14\u306b\u5ea7\u6a19\u30d0\u30a4\u30c8\u3092\u8aad\u307f\u8fbc\u3093\u3067\u3044\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1: \u6700\u521d\u306e\u30b3\u30fc\u30c9\uff08\u629c\u7c8b\uff09<\/h4>\n\n\n\n<p>C++<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u3088\u304f\u3042\u308bI2C\u8aad\u307f\u8fbc\u307f\nWire1.requestFrom(CST_ADDR, 4);\nuint8_t x_h = Wire1.read();\nuint8_t x_l = Wire1.read();\n\/\/ ... \u5358\u7d14\u7d50\u5408 ...\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2: \u767a\u751f\u3057\u305f\u73fe\u8c61<\/h4>\n\n\n\n<p>\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u306f\u51fa\u307e\u305b\u3093\u3067\u3057\u305f\u304c\u3001\u30b7\u30ea\u30a2\u30eb\u30e2\u30cb\u30bf\u3067\u5ea7\u6a19\u3092\u898b\u308b\u3068\u4ee5\u4e0b\u306e\u6319\u52d5\u3092\u793a\u3057\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u6a2a\u65b9\u5411\uff08X\u8ef8\uff09\u306b\u6307\u3092\u52d5\u304b\u3059\u3068\u3001\u5024\u304c <code>0 -> 300 -> 1 ...<\/code> \u306e\u3088\u3046\u306b\u30eb\u30fc\u30d7\u3059\u308b\uff08\u30ce\u30b3\u30ae\u30ea\u6ce2\u72b6\uff09\u3002<\/li>\n\n\n\n<li>\u753b\u9762\u306e\u53f3\u306b\u884c\u304f\u307b\u3069\u5024\u304c\u6e1b\u308b\uff08\u9006\u8ee2\u3057\u3066\u3044\u308b\uff09\u3002<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3: \u539f\u56e0\u306e\u89e3\u8aac<\/h4>\n\n\n\n<p>Waveshare\u306ePython\u30b5\u30f3\u30d7\u30eb\u30b3\u30fc\u30c9\u3092\u78ba\u8a8d\u3057\u305f\u3068\u3053\u308d\u3001\u3053\u306e\u30bf\u30c3\u30c1\u30d1\u30cd\u30eb\u306f <strong>12\u30d3\u30c3\u30c8\u306e\u30c7\u30fc\u30bf\u3092\u5909\u5247\u7684\u306b\u30d1\u30c3\u30ad\u30f3\u30b0\u3057\u3066\u9001\u4fe1<\/strong> \u3057\u3066\u304a\u308a\u3001\u3057\u304b\u3082\u30ec\u30b8\u30b9\u30bf\u30a2\u30c9\u30ec\u30b9\u304c8bit\u3067\u306f\u306a\u304f <strong>16bit (0xD000)<\/strong> \u3067\u30a2\u30af\u30bb\u30b9\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3057\u305f\u3002\u5358\u7d14\u306a\u30d0\u30a4\u30c8\u8aad\u307f\u8fbc\u307f\u3067\u306f\u3001\u4e0a\u4f4d\u30d3\u30c3\u30c8\u3068\u4e0b\u4f4d\u30d3\u30c3\u30c8\u304c\u6b63\u3057\u304f\u7d50\u5408\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3067\u3057\u305f\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 4: \u4fee\u6b63\u3057\u305f\u30b3\u30fc\u30c9\uff08\u30d3\u30c3\u30c8\u6f14\u7b97\u306e\u4fee\u6b63\uff09<\/h4>\n\n\n\n<p>C++<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u30ec\u30b8\u30b9\u30bf\u30dd\u30a4\u30f3\u30bf\u30920xD000\u306b\u30bb\u30c3\u30c8\nWire1.beginTransmission(CST_ADDR);\nWire1.write(0xD0);\nWire1.write(0x00);\nWire1.endTransmission(false); \/\/ Repeated Start\n\n\/\/ \u5909\u5247\u7684\u306a12bit\u30c7\u30b3\u30fc\u30c9\uff08Python\u30b3\u30fc\u30c9\u3092\u79fb\u690d\uff09\n\/\/ buf&#91;3]\u306bX\u3068Y\u306e\u4e0b\u4f4d4\u30d3\u30c3\u30c8\u304c\u6df7\u3056\u3063\u3066\u3044\u308b\nint raw_x = ((int)buf&#91;1] &lt;&lt; 4) | ((buf&#91;3] &amp; 0xF0) &gt;&gt; 4);\nint raw_y = ((int)buf&#91;2] &lt;&lt; 4) | (buf&#91;3] &amp; 0x0F);\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Round 2: \u30dc\u30bf\u30f3\u304c\u9023\u6253\u3055\u308c\u3066\u3057\u307e\u3046\uff08\u30b4\u30fc\u30b9\u30c8\u30bf\u30c3\u30c1\uff09<\/h3>\n\n\n\n<p>\u5ea7\u6a19\u306f\u53d6\u308c\u308b\u3088\u3046\u306b\u306a\u308a\u307e\u3057\u305f\u304c\u3001\u753b\u9762\u4e0a\u306e\u300cNEXT\u300d\u30dc\u30bf\u30f3\u3092\u4e00\u56de\u62bc\u3057\u305f\u3064\u3082\u308a\u304c\u3001\u30da\u30fc\u30b8\u304c2\u30643\u3064\u9032\u3093\u3067\u3057\u307e\u3046\u73fe\u8c61\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1: \u554f\u984c\u306e\u30b3\u30fc\u30c9<\/h4>\n\n\n\n<p>C++<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u30bf\u30c3\u30c1\u3055\u308c\u305f\u77ac\u9593\u3060\u3051\u53cd\u5fdc\u3059\u308b\u3064\u3082\u308a\u3060\u3063\u305f\u304c...\nif (touch.touched) {\n    \/\/ \u51e6\u7406\n}\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2: \u767a\u751f\u3057\u305f\u73fe\u8c61<\/h4>\n\n\n\n<p>\u6307\u3092\u96e2\u3057\u3066\u3082\u3001\u30bf\u30c3\u30c1\u30d1\u30cd\u30eb\u306e\u30ec\u30b8\u30b9\u30bf\u306b\u300c\u6700\u5f8c\u306e\u5ea7\u6a19\u300d\u304c\u6b8b\u308a\u7d9a\u3051\u3001\u30d7\u30ed\u30b0\u30e9\u30e0\u304c\u300c\u307e\u3060\u62bc\u3055\u308c\u3066\u3044\u308b\u300d\u3068\u8aa4\u8a8d\u3057\u3066\u51e6\u7406\u3092\u30eb\u30fc\u30d7\u3055\u305b\u3066\u3044\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3: \u4fee\u6b63\u6848<\/h4>\n\n\n\n<p>\u300c\u9759\u6b62\u753b\u691c\u77e5\uff08\u30b8\u30c3\u30bf\u30fc\u30d5\u30a3\u30eb\u30bf\uff09\u300d\u3068\u300c\u30ea\u30ea\u30fc\u30b9\u5f85\u3061\u30d5\u30e9\u30b0\u300d\u3092\u5c0e\u5165\u3057\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>\u9759\u6b62\u691c\u77e5:<\/strong> \u4eba\u9593\u306e\u6307\u306f\u5fae\u5999\u306b\u9707\u3048\u308b\u305f\u3081\u3001\u5ea7\u6a19\u304c\u5b8c\u5168\u306b\u4e00\u81f4\u3057\u7d9a\u3051\u308b\u5834\u5408\u306f\u300c\u6307\u304c\u306a\u3044\uff08\u30ec\u30b8\u30b9\u30bf\u306e\u30b4\u30df\uff09\u300d\u3068\u5224\u5b9a\u3057\u3066\u7121\u8996\u3002<\/li>\n\n\n\n<li><strong>\u30ea\u30ea\u30fc\u30b9\u5f85\u3061:<\/strong> \u30dc\u30bf\u30f3\u3092\u62bc\u3057\u305f\u5f8c\u3001\u4e00\u5ea6\u6307\u3092\u96e2\u3059\uff08<code>!touched<\/code> \u306b\u306a\u308b\uff09\u307e\u3067\u6b21\u306e\u5165\u529b\u3092\u53d7\u3051\u4ed8\u3051\u306a\u3044\u3088\u3046\u306b\u3057\u307e\u3057\u305f\u3002<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Round 3: MIDI\u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u95a2\u6570\u306e\u30b3\u30f3\u30d1\u30a4\u30eb\u30a8\u30e9\u30fc<\/h3>\n\n\n\n<p>\u6b21\u306b\u3001USB MIDI\u30ad\u30fc\u30dc\u30fc\u30c9\u3092\u63a5\u7d9a\u3059\u308b\u305f\u3081\u306e\u30b3\u30fc\u30c9\u3092\u8ffd\u52a0\u3057\u305f\u3068\u3053\u308d\u3067\u30b3\u30f3\u30d1\u30a4\u30eb\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1: \u8ffd\u52a0\u3057\u305f\u30b3\u30fc\u30c9<\/h4>\n\n\n\n<p>C++<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u53e4\u3044\u30e9\u30a4\u30d6\u30e9\u30ea\u4ed5\u69d8\u306b\u57fa\u3065\u3044\u305f\u8a18\u8ff0\nvoid tuh_midi_mount_cb(uint8_t d, uint8_t in_ep, uint16_t in_packet_size, uint8_t out_ep, uint16_t out_packet_size, void *ptr) {\n    \/\/ ...\n}\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2: \u767a\u751f\u3057\u305f\u30a8\u30e9\u30fc<\/h4>\n\n\n\n<p>Plaintext<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>error: conflicting declaration of C function 'void tuh_midi_mount_cb(...)'\nnote: previous declaration 'void tuh_midi_mount_cb(uint8_t, const tuh_midi_mount_cb_t*)'\n<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3: \u539f\u56e0\u306e\u89e3\u8aac<\/h4>\n\n\n\n<p>\u4f7f\u7528\u3057\u3066\u3044\u308b <code>Adafruit TinyUSB<\/code> \u30e9\u30a4\u30d6\u30e9\u30ea\u306e\u30d0\u30fc\u30b8\u30e7\u30f3\u304c\u4e0a\u304c\u308a\u3001\u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u95a2\u6570\u306e\u5f15\u6570\u306e\u4ed5\u69d8\u304c\u5909\u308f\u3063\u3066\u3044\u307e\u3057\u305f\u3002\u30a8\u30e9\u30fc\u30ed\u30b0\u306e <code>note<\/code> \u306b\u6b63\u89e3\u304c\u66f8\u3044\u3066\u3042\u308a\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 4: \u4fee\u6b63\u3057\u305f\u30b3\u30fc\u30c9<\/h4>\n\n\n\n<p>C++<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6700\u65b0\u306e\u4ed5\u69d8\u306b\u5408\u308f\u305b\u305f\u5f15\u6570\nvoid tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t *mount_cb_data) {\n    usb_mounted = true;\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Round 4: MIDI\u30ad\u30fc\u30dc\u30fc\u30c9\u3092\u8a8d\u8b58\u3057\u306a\u3044\uff08\u6700\u5927\u306e\u5c71\u5834\uff09<\/h3>\n\n\n\n<p>\u30b3\u30f3\u30d1\u30a4\u30eb\u306f\u901a\u308a\u307e\u3057\u305f\u304c\u3001Pico 2 W\u306bUSB\u30ad\u30fc\u30dc\u30fc\u30c9\u3092\u7e4b\u3044\u3067\u3082\u5168\u304f\u53cd\u5fdc\u3057\u307e\u305b\u3093\uff08L\u30c1\u30ab\u306b\u3088\u308b\u30c7\u30d0\u30c3\u30b0\u3067\u3082\u53cd\u5fdc\u306a\u3057\uff09\u3002\u3057\u304b\u3057\u3001\u5358\u7d14\u306a\u30b5\u30f3\u30d7\u30eb\u30b3\u30fc\u30c9\u3067\u306f\u52d5\u4f5c\u3057\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1: \u5931\u6557\u3057\u3066\u3044\u305f\u69cb\u6210<\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Arduino IDE\u8a2d\u5b9a: <code>USB Stack: Adafruit TinyUSB<\/code><\/li>\n\n\n\n<li>\u30b3\u30fc\u30c9: <code>USBDevice.attach()<\/code>\uff08PC\u63a5\u7d9a\u7528\uff09\u3068 <code>USBHost.begin(0)<\/code>\uff08\u30ad\u30fc\u30dc\u30fc\u30c9\u63a5\u7d9a\u7528\uff09\u3092\u6df7\u5728\u3055\u305b\u3066\u3044\u305f\u3002<\/li>\n\n\n\n<li>\u30b3\u30fc\u30c9: <code>Serial1<\/code> (\u30cf\u30fc\u30c9\u30a6\u30a7\u30a2MIDI) \u3092\u521d\u671f\u5316\u3057\u3066\u3044\u305f\u3002<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2: \u767a\u751f\u3057\u305f\u73fe\u8c61<\/h4>\n\n\n\n<p>\u30d7\u30ed\u30b0\u30e9\u30e0\u306f\u8d77\u52d5\u3059\u308b\u304c\u3001USB\u30dd\u30fc\u30c8\u306b\u30ad\u30fc\u30dc\u30fc\u30c9\u3092\u633f\u3057\u3066\u3082 <code>tuh_midi_mount_cb<\/code> \u304c\u547c\u3070\u308c\u306a\u3044\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3: \u539f\u56e0\u306e\u89e3\u8aac<\/h4>\n\n\n\n<p>Pico 2 (RP2350) \u3067USB\u30db\u30b9\u30c8\u6a5f\u80fd\u3092\u4f7f\u3046\u5834\u5408\u3001\u4ee5\u4e0b\u306e\u6761\u4ef6\u304c\u5fc5\u9808\u3067\u3057\u305f\u3002<\/p>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>IDE\u306e\u8a2d\u5b9a:<\/strong> \u30e1\u30cb\u30e5\u30fc\u306e\u300cUSB Stack\u300d\u3067 <strong>&#8220;Adafruit TinyUSB (Host)&#8221;<\/strong> \u3092\u660e\u793a\u7684\u306b\u9078\u3076\u5fc5\u8981\u304c\u3042\u308b\uff08\u7121\u5370\u306eTinyUSB\u3067\u306f\u30c7\u30d0\u30a4\u30b9\u30e2\u30fc\u30c9\u304c\u512a\u5148\u3055\u308c\u308b\u305f\u3081NG\uff09\u3002<\/li>\n\n\n\n<li><strong>\u521d\u671f\u5316\u9806\u5e8f:<\/strong> <code>USBHost.begin(0)<\/code> \u3092 <code>setup()<\/code> \u306e<strong>\u4e00\u756a\u6700\u521d<\/strong>\u306b\u547c\u3076\u5fc5\u8981\u304c\u3042\u308b\u3002<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Step 4: \u6700\u7d42\u7684\u306a\u4fee\u6b63<\/h4>\n\n\n\n<p>IDE\u306e\u8a2d\u5b9a\u3092 <strong>&#8220;Adafruit TinyUSB (Host)&#8221;<\/strong> \u306b\u5909\u66f4\u3057\u3001\u30b3\u30fc\u30c9\u3082USB\u30db\u30b9\u30c8\u5c02\u7528\u306b\u7279\u5316\u3055\u305b\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u5b8c\u6210\u30b3\u30fc\u30c9<\/h2>\n\n\n\n<p>\u3053\u308c\u3089\u5168\u3066\u306e\u554f\u984c\u3092\u89e3\u6c7a\u3057\u3001\u30bf\u30c3\u30c1\u64cd\u4f5c\u3068USB MIDI\u30ad\u30fc\u30dc\u30fc\u30c9\u6f14\u594f\u304c\u4e21\u7acb\u3057\u305f\u6700\u7d42\u30b3\u30fc\u30c9\u3067\u3059\u3002<\/p>\n\n\n\n<p>&lt;details&gt;<\/p>\n\n\n\n<p>&lt;summary&gt;\u30af\u30ea\u30c3\u30af\u3057\u3066\u30b3\u30fc\u30c9\u3092\u5c55\u958b: PolySynth_RP2350_LCD2_Touch_v16_00.ino&lt;\/summary&gt;<\/p>\n\n\n\n<p>C++<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ PolySynth_RP2350_LCD2_Touch_v16_00\n\/\/ Target: Raspberry Pi Pico 2 \/ Pico 2 W (RP2350)\n\/\/ REQUIRED IDE SETTING: Tools &gt; USB Stack &gt; \"Adafruit TinyUSB (Host)\"\n\/\/\n\/\/ Fixes:\n\/\/ 1. Validated for \"TinyUSB (Host)\" build option.\n\/\/ 2. P4 (Visualizer) Touch Fix: Touch is polled continuously, independent of FFT framerate.\n\/\/ 3. MIDI: Host Mode only.\n\n#<strong>define<\/strong> ENABLE_TOUCH \n\n#<strong>include<\/strong> &lt;Arduino.h&gt;\n#<strong>include<\/strong> &lt;I2S.h&gt;\n#<strong>include<\/strong> &lt;SPI.h&gt; \n#<strong>include<\/strong> &lt;Adafruit_GFX.h&gt;\n#<strong>include<\/strong> &lt;Adafruit_ST7789.h&gt;\n#<strong>include<\/strong> &lt;Adafruit_TinyUSB.h&gt; \/\/ \u2605 Must use \"Adafruit TinyUSB (Host)\" setting\n#<strong>include<\/strong> &lt;Wire.h&gt; \n#<strong>include<\/strong> \"hardware\/watchdog.h\" \n#<strong>include<\/strong> &lt;LittleFS.h&gt;\n#<strong>include<\/strong> \"arduinoFFT.h\"\n#<strong>include<\/strong> \"hardware\/vreg.h\"\n#<strong>include<\/strong> \"hardware\/clocks.h\"\n\nconst char* VERSION_STR = \"v16.00 (Host\/P4Fix)\";\n\n\/\/ --- Configuration ---\n#<strong>define<\/strong> SAMPLE_RATE 44100\n#<strong>define<\/strong> POLYPHONY 14\n#<strong>define<\/strong> SINE_SIZE 1024\n#<strong>define<\/strong> AUDIO_BLOCK 64 \n#<strong>define<\/strong> FFT_SAMPLES 512 \n#<strong>define<\/strong> SCOPE_SAMPLES 320\n#<strong>define<\/strong> MAX_MIDI_FILES 20\n#<strong>define<\/strong> MAX_TRACKS 16\n#<strong>define<\/strong> MAX_PAGES 6 \n\n#<strong>define<\/strong> DELAY_LEN 16537\n#<strong>define<\/strong> COMB1_LEN 1601\n#<strong>define<\/strong> COMB2_LEN 1811\n#<strong>define<\/strong> AP_LEN    499\n\n\/\/ --- Colors ---\n#<strong>define<\/strong> C_BLACK   0x0000\n#<strong>define<\/strong> C_WHITE   0xFFFF\n#<strong>define<\/strong> C_CYAN    0x07FF \n#<strong>define<\/strong> C_MAGENTA 0xF81F \n#<strong>define<\/strong> C_ORANGE  0xFD20 \n#<strong>define<\/strong> C_GREEN   0x07E0\n#<strong>define<\/strong> C_YELLOW  0xFFE0\n#<strong>define<\/strong> C_RED     0xF800\n#<strong>define<\/strong> C_GRAY    0x4208\n#<strong>define<\/strong> C_DARK    0x1082\n#<strong>define<\/strong> C_BLUE    0x001F\n\n\/\/ --- Pins ---\n#<strong>define<\/strong> TFT_BL   16  \n#<strong>define<\/strong> TFT_DC   14\n#<strong>define<\/strong> TFT_CS   13  \n#<strong>define<\/strong> TFT_SCLK 10 \n#<strong>define<\/strong> TFT_MOSI 11  \n#<strong>define<\/strong> TFT_RST  15  \n\n#<strong>define<\/strong> TOUCH_SDA 6\n#<strong>define<\/strong> TOUCH_SCL 7\n#<strong>define<\/strong> TOUCH_RST 17 \n\n#<strong>define<\/strong> I2S_BCLK 2  \n#<strong>define<\/strong> I2S_DOUT 4  \n\n#<strong>define<\/strong> CST_ADDR 0x1A\n\n\/\/ --- USB Objects ---\nAdafruit_USBH_Host USBHost;\nvolatile bool midi_active = false;\n\n\/\/ --- Prototypes ---\nvoid triggerNoteOn(uint8_t note, uint8_t velocity, bool is_drum);\nvoid triggerNoteOff(uint8_t note, bool is_drum);\nvoid apply_selection(int idx);\n\nclass CST328 {\npublic:\n    int x = 0, y = 0;\n    int raw_x = 0, raw_y = 0;\n    bool touched = false;\n    \n    int last_raw_x = -1, last_raw_y = -1;\n    int static_count = 0;\n\n    void begin() {\n        Wire1.setSDA(TOUCH_SDA);\n        Wire1.setSCL(TOUCH_SCL);\n        Wire1.begin(); \n        Wire1.setClock(400000);\n        \n        pinMode(TOUCH_RST, OUTPUT);\n        digitalWrite(TOUCH_RST, HIGH); delay(50);\n        digitalWrite(TOUCH_RST, LOW);  delay(20);\n        digitalWrite(TOUCH_RST, HIGH); delay(100);\n    }\n\n    bool read() {\n        Wire1.beginTransmission(CST_ADDR);\n        Wire1.write(0x01); \n        if (Wire1.endTransmission() != 0) return false;\n\n        Wire1.requestFrom(CST_ADDR, 6);\n        if (Wire1.available() &lt; 6) return false;\n\n        uint8_t buf&#91;6];\n        for(int i=0; i&lt;6; i++) buf&#91;i] = Wire1.read();\n\n        int val_A = ((uint16_t)buf&#91;0] &lt;&lt; 4) | ((buf&#91;2] &amp; 0xF0) &gt;&gt; 4); \n        int val_B = ((uint16_t)buf&#91;1] &lt;&lt; 4) | (buf&#91;2] &amp; 0x0F);        \n\n        bool valid_read = (val_A &gt; 0 || val_B &gt; 0);\n        \n        if (valid_read) {\n            if (val_A == last_raw_y &amp;&amp; val_B == last_raw_x) {\n                static_count++;\n            } else {\n                static_count = 0; \n            }\n            last_raw_y = val_A;\n            last_raw_x = val_B;\n\n            if (static_count &gt; 20) {\n                touched = false;\n            } else {\n                touched = true;\n                raw_y = val_A; \n                raw_x = val_B; \n                \n                \/\/ Calibration (Proven)\n                x = map(raw_x, 317, 1, 0, 320); \n                y = map(raw_y, 1, 239, 0, 240);\n                \n                if (x &lt; 0) x = 0; if (x &gt; 320) x = 320;\n                if (y &lt; 0) y = 0; if (y &gt; 240) y = 240;\n            }\n        } else {\n            touched = false;\n            static_count = 0;\n        }\n        return touched;\n    }\n} touch;\n\n\/\/ --- Globals ---\nconst char* ALL_NAMES&#91;] = {\"SINE\", \"SAW\", \"TRI\", \"SQR\", \"NOISE\", \"PIANO\", \"ORGAN\", \"VIOLIN\", \"MBOX\", \"SEA\", \"WIND\"};\nconst uint8_t total_presets = 11;\n\nstruct Voice {\n    int note = -1; float freq = 0, target_freq = 0, ph = 0, mod_ph = 0, env = 0;\n    int stage = 0; bool active = false; bool is_drum = false;\n    float low = 0, band = 0, f_coeff = 0; \n};\n\nstruct MidiTrackState {\n    uint32_t start_offset; uint32_t cursor; uint32_t next_tick; uint8_t running_st; bool active;           \n};\n\nstruct {\n    volatile int page = 0, wave = 0, preset = 0, selected_file_idx = 0;\n    int total_files = 0;\n    volatile float gain = 0.8f, lfo_f = 0.2f, lfo_d = 0.0f, lfo_ph = 0;\n    volatile float a=0.01f, d=0.2f, s=0.6f, r=0.5f, cut=8000.0f, res=0.1f;\n    volatile float glide = 0.0f, fm_idx = 0.0f, chorus = 0.0f;\n    volatile float delay_mix = 0.0f; volatile float reverb_mix = 0.0f;\n    volatile float play_speed = 1.0f;\n    volatile bool playing = false, dirty = true; \n    volatile bool note_active = false;\n    uint32_t current_tick = 0; uint32_t us_per_tick = 1000;\n    volatile bool req_file_reload = false; volatile bool req_panic = false;\n} p;\n\nVoice voices&#91;POLYPHONY];\nfloat sineTbl&#91;SINE_SIZE];\nMidiTrackState tracks&#91;MAX_TRACKS];\nint num_tracks_active = 0;\n\nfloat delayBuf&#91;DELAY_LEN]; int delay_idx = 0;\nfloat comb1Buf&#91;COMB1_LEN]; int c1_idx = 0;\nfloat comb2Buf&#91;COMB2_LEN]; int c2_idx = 0;\nfloat apBuf&#91;AP_LEN];       int ap_idx = 0;\nvolatile int16_t scope_buf&#91;SCOPE_SAMPLES]; \nfloat vReal&#91;FFT_SAMPLES], vImag&#91;FFT_SAMPLES];\nvolatile bool fft_ready = false;\nvolatile int s_ptr = 0; volatile int f_ptr = 0;\nint last_touch_note = -1;\nuint32_t last_btn_action = 0;\n\nbool finger_released = true;\n\nI2S i2s(OUTPUT);\nAdafruit_ST7789 tft = Adafruit_ST7789(&amp;SPI1, TFT_CS, TFT_DC, TFT_RST);\nArduinoFFT&lt;float&gt; FFT = ArduinoFFT&lt;float&gt;(vReal, vImag, FFT_SAMPLES, SAMPLE_RATE);\n\n\/\/ --- File System ---\nchar midi_filenames&#91;MAX_MIDI_FILES]&#91;32];\nFile midiFile;\n\nString formatMidiName(const char* name) {\n    String s = String(name); s.replace(\".mid\", \"\"); s.replace(\".MID\", \"\");\n    if(s.length() &gt; 12) s = s.substring(0, 12);\n    return s;\n}\n\nvoid scanMidiFiles() {\n    p.total_files = 0;\n    Dir dir = LittleFS.openDir(\"\/midi\");\n    if (!dir.next()) dir = LittleFS.openDir(\"\/\"); \n    dir.rewind();\n    while (dir.next() &amp;&amp; p.total_files &lt; MAX_MIDI_FILES) {\n        String n = dir.fileName();\n        if (n.endsWith(\".mid\") || n.endsWith(\".MID\")) {\n            strncpy(midi_filenames&#91;p.total_files], n.c_str(), 31);\n            p.total_files++;\n        }\n    }\n    p.dirty = true;\n}\n\nuint32_t xorshift32() {\n    static uint32_t x = 123456789;\n    x ^= x &lt;&lt; 13; x ^= x &gt;&gt; 17; x ^= x &lt;&lt; 5;\n    return x;\n}\n\n\/\/ --- SOUND ENGINE ---\nvoid triggerNoteOn(uint8_t note, uint8_t velocity, bool is_drum) {\n    float tf = 440.0f * powf(2.0f, (note - 69.0f) \/ 12.0f);\n    for(int i=0; i&lt;POLYPHONY; i++) {\n        if(voices&#91;i].active &amp;&amp; voices&#91;i].note == note &amp;&amp; voices&#91;i].is_drum == is_drum) voices&#91;i].active = false; \n    }\n    for(int i=0; i&lt;POLYPHONY; i++) if(!voices&#91;i].active) {\n        voices&#91;i].note = note; voices&#91;i].target_freq = tf; \n        if(p.glide == 0 || is_drum) voices&#91;i].freq = tf; \n        if(p.glide &gt; 0 &amp;&amp; !is_drum) voices&#91;i].freq = tf; \n        voices&#91;i].ph = 0; voices&#91;i].stage = 1; voices&#91;i].env = 0; \n        voices&#91;i].active = true; voices&#91;i].low = 0; voices&#91;i].band = 0;\n        voices&#91;i].is_drum = is_drum;\n        p.note_active = true; break;\n    }\n}\n\nvoid triggerNoteOff(uint8_t note, bool is_drum) {\n    bool any_active = false;\n    for(int i=0; i&lt;POLYPHONY; i++) {\n        if(voices&#91;i].note == note &amp;&amp; voices&#91;i].active &amp;&amp; voices&#91;i].is_drum == is_drum) voices&#91;i].stage = 4;\n        if(voices&#91;i].active &amp;&amp; voices&#91;i].stage != 4) any_active = true;\n    }\n    p.note_active = any_active;\n}\n\nvoid panic() { \n    for(int i=0; i&lt;POLYPHONY; i++) {\n        voices&#91;i].active = false; voices&#91;i].env = 0.0f; voices&#91;i].stage = 0;\n    }\n    p.note_active = false;\n}\n\n\/\/ --- SEQUENCER ---\nuint32_t readVarLen() {\n    uint32_t val = 0; uint8_t c;\n    do { c = midiFile.read(); val = (val &lt;&lt; 7) | (c &amp; 0x7F); } while (c &amp; 0x80);\n    return val;\n}\nvoid init_sequencer() {\n    if (midiFile) midiFile.close();\n    if (p.total_files == 0) { p.playing = false; p.dirty = true; return; }\n    String path = \"\/midi\/\"; path += midi_filenames&#91;p.selected_file_idx];\n    midiFile = LittleFS.open(path, \"r\");\n    if (!midiFile) midiFile = LittleFS.open(\"\/\" + String(midi_filenames&#91;p.selected_file_idx]), \"r\");\n    if (!midiFile) { p.playing = false; p.dirty = true; return; }\n    midiFile.seek(0); char chunk&#91;4]; midiFile.readBytes(chunk, 4);\n    if (strncmp(chunk, \"MThd\", 4) != 0) { p.playing = false; p.dirty = true; return; }\n    midiFile.seek(10); uint16_t numTrks; midiFile.readBytes((char*)&amp;numTrks, 2); numTrks = __builtin_bswap16(numTrks);\n    uint16_t timeDiv; midiFile.readBytes((char*)&amp;timeDiv, 2); timeDiv = __builtin_bswap16(timeDiv);\n    p.us_per_tick = 500000 \/ timeDiv; \n    num_tracks_active = 0; midiFile.seek(14); \n    while(midiFile.available() &amp;&amp; num_tracks_active &lt; MAX_TRACKS &amp;&amp; num_tracks_active &lt; numTrks) {\n        uint32_t chunkStart = midiFile.position(); midiFile.readBytes(chunk, 4);\n        uint32_t len; midiFile.readBytes((char*)&amp;len, 4); len = __builtin_bswap32(len);\n        if (strncmp(chunk, \"MTrk\", 4) == 0) {\n            tracks&#91;num_tracks_active].start_offset = midiFile.position();\n            tracks&#91;num_tracks_active].cursor = midiFile.position();\n            tracks&#91;num_tracks_active].active = true;\n            tracks&#91;num_tracks_active].running_st = 0;\n            tracks&#91;num_tracks_active].next_tick = readVarLen();\n            tracks&#91;num_tracks_active].cursor = midiFile.position(); \n            num_tracks_active++;\n        }\n        midiFile.seek(chunkStart + 8 + len);\n    }\n    p.current_tick = 0;\n}\nvoid update_sequencer() {\n    if (!p.playing) return;\n    if (!midiFile) { init_sequencer(); if(!p.playing) return; }\n    static uint32_t last_time = 0;\n    if (micros() - last_time &lt; (uint32_t)(p.us_per_tick \/ p.play_speed)) return;\n    last_time = micros();\n    p.current_tick++;\n    bool any_active = false;\n    for (int i = 0; i &lt; num_tracks_active; i++) {\n        if (!tracks&#91;i].active) continue;\n        any_active = true;\n        while (tracks&#91;i].next_tick &lt;= p.current_tick) {\n            midiFile.seek(tracks&#91;i].cursor); \n            uint8_t b = midiFile.read();\n            if (b &gt;= 0x80) { tracks&#91;i].running_st = b; b = midiFile.read(); }\n            uint8_t status = tracks&#91;i].running_st;\n            uint8_t type = status &amp; 0xF0; \n            if (type == 0xF0) { \n                if (status == 0xFF) { \n                    uint8_t metaType = b; uint32_t len = readVarLen();\n                    if (metaType == 0x2F) tracks&#91;i].active = false; else midiFile.seek(midiFile.position() + len);\n                } else if (status == 0xF0 || status == 0xF7) { uint32_t len = readVarLen(); midiFile.seek(midiFile.position() + len); }\n            } else {\n                uint8_t d1 = b; uint8_t d2 = 0; if (type != 0xC0 &amp;&amp; type != 0xD0) d2 = midiFile.read();\n                uint8_t ch = status &amp; 0x0F; bool is_drum = (ch == 9);\n                if (type == 0x90 &amp;&amp; d2 &gt; 0) triggerNoteOn(d1, d2, is_drum);\n                else if (type == 0x80 || (type == 0x90 &amp;&amp; d2 == 0)) triggerNoteOff(d1, is_drum);\n            }\n            if (tracks&#91;i].active) { tracks&#91;i].next_tick += readVarLen(); tracks&#91;i].cursor = midiFile.position(); } else { break; }\n        }\n    }\n    if (!any_active) { p.playing = false; p.req_panic = true; p.dirty = true; }\n}\n\nvoid apply_selection(int idx) {\n    p.preset = constrain(idx, 0, (int)total_presets - 1);\n    p.delay_mix = 0.0f; p.reverb_mix = 0.0f;\n    if (p.preset &lt; 5) {\n        p.wave = p.preset; p.a=0.01; p.d=0.3; p.s=0.8; p.r=0.3; p.cut=8000.0f; p.res=0.1f; p.lfo_d=0.0f; p.glide=0.0f;\n    } else {\n        switch(p.preset) {\n            case 5: p.wave=1; p.a=0.01; p.d=0.5; p.s=0.0; p.r=0.4; p.cut=2800; p.res=0.1; break;\n            case 6: p.wave=3; p.a=0.02; p.d=0.1; p.s=1.0; p.r=0.1; p.cut=4500; p.res=0.0; break;\n            case 7: p.wave=1; p.a=0.30; p.d=0.3; p.s=0.7; p.r=0.6; p.cut=2200; p.res=0.3; p.lfo_f=0.3; p.lfo_d=0.3; p.glide=0.06; break;\n            case 8: p.wave=0; p.a=0.01; p.d=1.5; p.s=0.0; p.r=1.0; p.cut=3500; p.res=0.2; break;\n            case 9: p.wave=4; p.a=2.5; p.d=2.0; p.s=0.4; p.r=2.5; p.cut=600; p.res=0.1; break;\n            case 10: p.wave=4; p.a=1.5; p.d=1.5; p.s=0.5; p.r=2.0; p.cut=1000; p.res=0.88; break;\n        }\n    }\n    if (p.preset == 7) p.reverb_mix = 0.3f;\n    if (p.preset == 9) p.delay_mix = 0.4f;\n    p.dirty = true;\n}\n\n\/\/ UI\nvoid drawCell(int col, int row, const char* label, String valStr, float val, float maxVal, uint16_t color) {\n    int x = (col == 0) ? 5 : 165; int y = 35 + row * 50; int w = 150;\n    tft.setTextColor(C_YELLOW, C_BLACK); tft.setTextSize(1);\n    tft.setCursor(x, y); tft.print(\"K\"); tft.print(col == 0 ? row + 1 : row + 5); tft.print(\" \"); tft.print(label);\n    tft.setTextColor(C_WHITE, C_BLACK); tft.setTextSize(2);\n    tft.setCursor(x, y + 12); tft.print(valStr);\n    int barY = y + 36;\n    if (maxVal &lt;= 1.0f) { \/\/ Toggle\n        uint16_t btnColor = (val &gt; 0.5f) ? color : C_DARK;\n        tft.fillRect(x, barY - 4, w, 14, btnColor);\n        tft.drawRect(x, barY - 4, w, 14, C_WHITE);\n    } else { \/\/ Slider\n        tft.drawRect(x, barY, w, 6, C_GRAY);\n        int fillW = constrain((int)((val \/ maxVal) * (w - 2)), 0, w - 2);\n        tft.fillRect(x + 1, barY + 1, fillW, 4, color);\n    }\n}\n\nvoid drawKeyboard() {\n    int wk_w = 40; int bk_w = 26; int bk_h = 130;\n    int y_start = 40; int h = 200;\n    for(int i=0; i&lt;8; i++) {\n        tft.fillRect(i*wk_w, y_start, wk_w-1, h, C_WHITE);\n        tft.drawRect(i*wk_w, y_start, wk_w-1, h, C_GRAY); \n    }\n    int bk_pos&#91;] = {1, 2, 4, 5, 6}; \n    for(int i=0; i&lt;5; i++) {\n        int cx = bk_pos&#91;i] * wk_w;\n        tft.fillRect(cx - (bk_w\/2), y_start, bk_w, bk_h, C_BLACK);\n    }\n    tft.setTextColor(C_BLACK); tft.setTextSize(1); \n    tft.setCursor(12, 220); tft.print(\"C4\"); tft.setCursor(292, 220); tft.print(\"C5\");\n}\n\nvoid drawSystemPage() {\n    tft.setTextColor(C_WHITE, C_BLACK);\n    tft.setCursor(10, 40); tft.setTextSize(2); tft.print(\"SYSTEM MENU\");\n    \n    tft.setCursor(10, 70); tft.setTextSize(1); tft.setTextColor(C_GRAY); tft.print(\"USB MODE:\");\n    tft.setCursor(160, 70); tft.setTextColor(C_GREEN); tft.print(\"HOST (KEYS)\");\n    \n    \/\/ Version Display\n    tft.setCursor(80, 210); tft.setTextSize(1); tft.setTextColor(C_GRAY);\n    tft.print(\"FIRMWARE: \"); tft.print(VERSION_STR);\n}\n\nvoid handle_touch() {\n    touch.read();\n    if (!touch.touched) {\n        if (last_touch_note != -1) { triggerNoteOff(last_touch_note, false); last_touch_note = -1; }\n        finger_released = true;\n        return;\n    }\n    int tx = touch.x; int ty = touch.y;\n    if (tx == 0 &amp;&amp; ty == 0) return;\n    bool can_trigger_btn = (millis() - last_btn_action &gt; 300);\n\n    if (ty &lt; 50 &amp;&amp; tx &gt; 200) { \/\/ Global Nav\n        if (finger_released) {\n            p.page = (p.page + 1) % MAX_PAGES;\n            if(p.page &gt;= MAX_PAGES) p.page = 0; \n            p.dirty = true; finger_released = false;\n            if (last_touch_note != -1) { triggerNoteOff(last_touch_note, false); last_touch_note = -1; }\n        }\n        return; \n    }\n\n    if (p.page == 4) { \/\/ Keyboard\n        if (tx &lt; 0 || tx &gt; 320 || ty &lt; 40) return; \n        int wk_w = 40; int bk_w = 26; int bk_h = 130 + 40; \n        int base_note = 60; int note = -1;\n        int bk_centers&#91;] = {40, 80, 160, 200, 240}; int bk_notes&#91;] = {1, 3, 6, 8, 10}; \n        bool is_black = false;\n        if (ty &lt; bk_h) { \n            for(int i=0; i&lt;5; i++) {\n                if (tx &gt;= (bk_centers&#91;i] - bk_w\/2) &amp;&amp; tx &lt;= (bk_centers&#91;i] + bk_w\/2)) {\n                    note = base_note + bk_notes&#91;i]; is_black = true; break;\n                }\n            }\n        }\n        if (!is_black) {\n            int wk_idx = tx \/ wk_w; int wk_notes&#91;] = {0, 2, 4, 5, 7, 9, 11, 12};\n            if(wk_idx &gt;= 0 &amp;&amp; wk_idx &lt; 8) note = base_note + wk_notes&#91;wk_idx];\n        }\n        if (note != last_touch_note) {\n            if (last_touch_note != -1) triggerNoteOff(last_touch_note, false);\n            if (note != -1) triggerNoteOn(note, 100, false);\n            last_touch_note = note;\n        }\n    }\n    else if (p.page &lt; 4) { \/\/ Main UI\n        if (tx &lt; 0 || tx &gt; 320 || ty &lt; 35 || ty &gt; 235) return;\n        int row = (ty - 35) \/ 50; int col = (tx &lt; 160) ? 0 : 1;\n        float cellX = (col == 0) ? tx - 5 : tx - 165;\n        float normVal = constrain(cellX \/ 150.0f, 0.0f, 1.0f);\n\n        if (p.page == 0) {\n            if(col==0 &amp;&amp; row==0) apply_selection((int)(normVal * total_presets));\n            if(col==0 &amp;&amp; row==1 &amp;&amp; p.total_files &gt; 0) {\n                int new_idx = constrain((int)(normVal * p.total_files), 0, p.total_files - 1);\n                if (p.selected_file_idx != new_idx) { p.selected_file_idx = new_idx; p.req_file_reload = true; p.dirty = true; }\n            }\n            if(col==0 &amp;&amp; row==2 &amp;&amp; finger_released) { p.playing = !p.playing; if(!p.playing) p.req_panic = true; p.dirty = true; finger_released = false; }\n            if(col==0 &amp;&amp; row==3) { p.play_speed = 0.5f + normVal * 1.5f; p.dirty = true; }\n            if(col==1 &amp;&amp; row==0) { p.wave = (int)(normVal * 5); p.dirty = true; }\n            if(col==1 &amp;&amp; row==1) { p.chorus = normVal; p.dirty = true; }\n            if(col==1 &amp;&amp; row==2 &amp;&amp; finger_released) { p.page = (p.page + 1) % MAX_PAGES; p.dirty = true; finger_released = false; }\n            if(col==1 &amp;&amp; row==3) { p.gain = normVal; p.dirty = true; }\n        }\n        else if (p.page == 1) { \n            if(col==0 &amp;&amp; row==0) p.glide=normVal; if(col==0 &amp;&amp; row==1) p.cut=normVal*8000;\n            if(col==0 &amp;&amp; row==2) p.res=normVal; if(col==0 &amp;&amp; row==3) p.delay_mix=normVal;\n            if(col==1 &amp;&amp; row==0) p.reverb_mix=normVal; if(col==1 &amp;&amp; row==1) p.fm_idx=normVal*5.0f;\n            if(col==1 &amp;&amp; row==2 &amp;&amp; finger_released) { p.page = (p.page + 1) % MAX_PAGES; p.dirty = true; finger_released = false; }\n            if(col==1 &amp;&amp; row==3) p.gain=normVal; p.dirty=true;\n        }\n        else if (p.page == 2) {\n            if(col==0 &amp;&amp; row==0) p.a=normVal*2.0; if(col==0 &amp;&amp; row==1) p.d=normVal*2.0;\n            if(col==0 &amp;&amp; row==2) p.s=normVal; if(col==0 &amp;&amp; row==3) p.r=normVal*2.0;\n            if(col==1 &amp;&amp; row==0) p.lfo_f=normVal; if(col==1 &amp;&amp; row==1) p.lfo_d=normVal;\n            if(col==1 &amp;&amp; row==2 &amp;&amp; finger_released) { p.page = (p.page + 1) % MAX_PAGES; p.dirty = true; finger_released = false; }\n            if(col==1 &amp;&amp; row==3) p.gain=normVal; p.dirty=true;\n        }\n    }\n}\n\nvoid core1_entry() {\n    pinMode(TFT_BL, OUTPUT); digitalWrite(TFT_BL, HIGH);\n    pinMode(TFT_RST, OUTPUT); digitalWrite(TFT_RST, LOW); delay(50); digitalWrite(TFT_RST, HIGH); delay(50);\n\n    tft.init(240, 320); tft.setRotation(1); tft.fillScreen(C_BLACK);\n    tft.setCursor(40, 100); tft.setTextSize(3); tft.setTextColor(C_CYAN); tft.print(\"PolySynth\");\n    tft.setCursor(100, 140); tft.setTextSize(2); tft.setTextColor(C_WHITE); tft.print(VERSION_STR);\n    delay(2000); \n\n    int last_pg = -1; uint32_t last_draw = 0; \n    touch.begin();\n\n    while (1) {\n        \/\/ \u2605 Polling touch frequently is key\n        handle_touch(); \n        \n        int cur_pg = p.page;\n        uint16_t theme = (cur_pg==0)?C_CYAN : (cur_pg==1)?C_MAGENTA : (cur_pg==2)?C_ORANGE : (cur_pg==3)?C_GREEN : (cur_pg==4)?C_WHITE : C_RED;\n        \n        if (cur_pg != last_pg) { tft.fillScreen(C_BLACK); last_pg = cur_pg; p.dirty = true; }\n\n        if (p.dirty &amp;&amp; (millis() - last_draw &gt; 50)) {\n            last_draw = millis();\n            tft.fillRect(0, 0, 320, 25, C_DARK);\n            tft.setTextColor(theme, C_DARK); tft.setTextSize(1); tft.setCursor(10, 8);\n            tft.print(\"P\"); tft.print(cur_pg + 1); tft.print(\" \"); \n            \n            \/\/ \u2605 USB DIAGNOSTIC DISPLAY \u2605\n            tft.setCursor(150, 8); \n            if(usb_mounted) {\n                tft.setTextColor(C_GREEN, C_DARK); tft.print(\"USB:OK \");\n            } else {\n                tft.setTextColor(C_RED, C_DARK); tft.print(\"USB:-- \");\n            }\n            \n            if(midi_rx_activity) {\n                tft.setTextColor(C_YELLOW, C_RED); tft.print(\"MIDI!\");\n                midi_rx_activity = false; \/\/ Reset flash\n            }\n\n            tft.fillRect(260, 0, 60, 25, C_GRAY);\n            tft.setCursor(270, 8); tft.setTextColor(C_WHITE, C_GRAY); tft.print(\"NEXT\");\n\n            if (cur_pg &lt; 3) {\n                 \/\/ ... Same drawing logic as before ...\n                 if(cur_pg==0) {\n                     drawCell(0,0,\"PRESET\",ALL_NAMES&#91;p.preset],p.preset,10,theme);\n                     String fName = \"NO FILES\"; if(p.total_files&gt;0) fName = formatMidiName(midi_filenames&#91;p.selected_file_idx]);\n                     drawCell(0,1,\"FILE\",fName,1,1,(p.total_files&gt;0?theme:C_RED));\n                     drawCell(0,2,\"PLAY\",(p.playing?\"ON\":\"OFF\"),p.playing,1,theme);\n                     drawCell(0,3,\"SPEED\",String((int)(p.play_speed*100))+\"%\",p.play_speed,2.0,theme);\n                     drawCell(1,0,\"WAVE\",ALL_NAMES&#91;p.wave],p.wave,10,theme);\n                     drawCell(1,1,\"CHORUS\",String((int)(p.chorus*100))+\"%\",p.chorus,1.0,theme);\n                     drawCell(1,2,\"PAGE\",\"NEXT\",0,1,C_GRAY);\n                     drawCell(1,3,\"VOL\",String((int)(p.gain*100)),p.gain,1.0,C_WHITE);\n                 } \n                 else if(cur_pg==1) {\n                     drawCell(0,0,\"GLIDE\",String(p.glide,2),p.glide,1.0,theme); drawCell(0,1,\"CUTOFF\",String((int)p.cut),p.cut,12000,theme);\n                     drawCell(0,2,\"RESON\",String(p.res,2),p.res,1.0,theme); drawCell(0,3,\"DELAY\",String((int)(p.delay_mix*100))+\"%\",p.delay_mix,1.0,theme);\n                     drawCell(1,0,\"REVERB\",String((int)(p.reverb_mix*100))+\"%\",p.reverb_mix,1.0,theme); drawCell(1,1,\"FM IDX\",String(p.fm_idx,1),p.fm_idx,5.0,theme);\n                     drawCell(1,2,\"PAGE\",\"NEXT\",0,1,C_GRAY); drawCell(1,3,\"VOL\",String((int)(p.gain*100)),p.gain,1.0,C_WHITE);\n                 }\n                 else if(cur_pg==2) {\n                     drawCell(0,0,\"ATTACK\",String(p.a,2),p.a,2.0,theme); drawCell(0,1,\"DECAY\",String(p.d,2),p.d,2.0,theme);\n                     drawCell(0,2,\"SUSTAIN\",String(p.s,2),p.s,1.0,theme); drawCell(0,3,\"RELEASE\",String(p.r,2),p.r,2.0,theme);\n                     drawCell(1,0,\"LFO F\",String(p.lfo_f*20,1),p.lfo_f,1.0,theme); drawCell(1,1,\"LFO D\",String(p.lfo_d,1),p.lfo_d,1.0,theme);\n                     drawCell(1,2,\"PAGE\",\"NEXT\",0,1,C_GRAY); drawCell(1,3,\"VOL\",String((int)(p.gain*100)),p.gain,1.0,C_WHITE);\n                 }\n            } else if (cur_pg == 4) { drawKeyboard(); } \n            else if (cur_pg == 5) { drawSystemPage(); }\n            p.dirty = false;\n        }\n\n        if (cur_pg == 3) { \n            \/\/ \u2605 Throttled to 66ms (15 FPS) to allow Touch priority\n            if(millis() - last_draw &gt; 66) { \n                tft.fillRect(0, 42, 320, 78, 0); \n                int cy = 81; for (int i = 0; i &lt; SCOPE_SAMPLES - 1; i++) { int y1 = constrain(cy + (scope_buf&#91;i] \/ 500), 42, 118); int y2 = constrain(cy + (scope_buf&#91;i+1] \/ 500), 42, 118); tft.drawLine(i, y1, i+1, y2, C_CYAN); }\n                if (fft_ready) {\n                    tft.fillRect(0, 120, 320, 100, 0); \n                    FFT.windowing(FFTWindow::Hamming, FFTDirection::Forward); FFT.compute(FFTDirection::Forward); FFT.complexToMagnitude();\n                    for (int i=1; i &lt; 161; i++) { int h = (int)constrain(13.0f * log10f(vReal&#91;i] + 1.0f), 0, 90); uint16_t barColor = C_GREEN; if(h&gt;40) barColor=C_YELLOW; if(h&gt;70) barColor=C_RED; tft.fillRect((i-1)*2, 210-h, 2, h, barColor); }\n                    fft_ready = false;\n                }\n            }\n        }\n        \/\/ No heavy delay\n    }\n}\n\n\/\/ ... (Setup\/Loop) ...\nvoid setup() {\n    vreg_set_voltage(VREG_VOLTAGE_1_20); delay(10);\n    set_sys_clock_khz(250000, true);\n    Serial1.setTX(0); Serial1.begin(31250); \n    SPI1.setSCK(TFT_SCLK); SPI1.setTX(TFT_MOSI); SPI1.begin();\n    \n    pinMode(TOUCH_RST, OUTPUT); digitalWrite(TOUCH_RST, HIGH); delay(50); digitalWrite(TOUCH_RST, LOW);  delay(20); digitalWrite(TOUCH_RST, HIGH); delay(100);\n    Wire1.setSDA(TOUCH_SDA); Wire1.setSCL(TOUCH_SCL); Wire1.begin(); Wire1.setClock(400000);\n\n    if(LittleFS.begin()) { scanMidiFiles(); }\n    \n    \/\/ \u2605 USB HOST START (Always ON) \u2605\n    USBHost.begin(0); \n    \n    for (int i=0; i&lt;SINE_SIZE; i++) sineTbl&#91;i] = sinf(2.0f * PI * i \/ SINE_SIZE);\n    i2s.setBCLK(I2S_BCLK); i2s.setDATA(I2S_DOUT); i2s.begin(SAMPLE_RATE);\n    apply_selection(0); \n    multicore_launch_core1(core1_entry); \n}\n\nvoid loop() {\n    \/\/ \u2605 USB HOST TASK \u2605\n    USBHost.task();\n    \n    update_sequencer();\n    if (p.req_panic) { panic(); p.req_panic = false; }\n    if (p.req_file_reload) { if (midiFile) midiFile.close(); p.playing = false; num_tracks_active = 0; p.req_file_reload = false; }\n\n    float lfo_val = sinf(p.lfo_ph) * p.lfo_d * 10.0f;\n    p.lfo_ph += (2.0f * PI * (p.lfo_f * 20.0f)) \/ SAMPLE_RATE;\n    if(p.lfo_ph &gt;= 2.0f * PI) p.lfo_ph -= 2.0f * PI;\n    float g_factor = powf(0.001f, 1.0f \/ (max(p.glide, 0.001f) * SAMPLE_RATE));\n    float q = 1.0f - p.res;\n\n    for (int s=0; s&lt;AUDIO_BLOCK; s++) {\n        float mix = 0;\n        for (int i=0; i&lt;POLYPHONY; i++) {\n            if (voices&#91;i].active) {\n                if (!voices&#91;i].is_drum &amp;&amp; p.glide &gt; 0) voices&#91;i].freq = voices&#91;i].target_freq + (voices&#91;i].freq - voices&#91;i].target_freq) * g_factor;\n                else voices&#91;i].freq = voices&#91;i].target_freq;\n                float mod = 0;\n                if(!voices&#91;i].is_drum &amp;&amp; p.fm_idx &gt; 0) mod = voices&#91;i].freq * p.fm_idx * sinf(voices&#91;i].ph * 2.0f * PI);\n                float target_cut = (p.wave == 4) ? voices&#91;i].freq : p.cut;\n                if (s == 0) voices&#91;i].f_coeff = 2.0f * sinf(PI * constrain(target_cut, 50, 15000) \/ SAMPLE_RATE);\n                \n                float cur_ph = voices&#91;i].ph; float osc_out = 0;\n                if (voices&#91;i].is_drum) { osc_out = (voices&#91;i].note &lt; 40) ? sinf(cur_ph * 20.0f * PI) + (((int32_t)xorshift32()) \/ 2147483648.0f) * 0.3f : ((int32_t)xorshift32()) \/ 2147483648.0f; } \n                else {\n                    if(p.wave==0) osc_out = sineTbl&#91;(int)(cur_ph*SINE_SIZE)%SINE_SIZE];\n                    else if(p.wave==1) osc_out = 2.0f*(cur_ph-0.5f);\n                    else if(p.wave==2) osc_out = (cur_ph &lt; 0.5f) ? (4.0f * cur_ph - 1.0f) : (3.0f - 4.0f * cur_ph);\n                    else if(p.wave==3) osc_out = (cur_ph&lt;0.5f)?0.5f:-0.5f;\n                    else osc_out = ((int32_t)xorshift32()) \/ 2147483648.0f;\n                }\n                voices&#91;i].low += voices&#91;i].f_coeff * voices&#91;i].band;\n                voices&#91;i].band += voices&#91;i].f_coeff * (osc_out - voices&#91;i].low - q * voices&#91;i].band);\n                float env = voices&#91;i].env;\n                if(voices&#91;i].is_drum) env *= (voices&#91;i].note &lt; 40) ? 0.9f : 0.6f;\n                mix += voices&#91;i].low * env * 0.20f;\n                voices&#91;i].ph += (voices&#91;i].freq + mod + lfo_val)\/SAMPLE_RATE;\n                if(voices&#91;i].ph &gt;= 1.0f) voices&#91;i].ph -= 1.0f;\n                \n                float stp = 1.0f \/ SAMPLE_RATE;\n                float atk = voices&#91;i].is_drum ? 0.001f : p.a;\n                float dec = voices&#91;i].is_drum ? 0.1f : p.d;\n                float sus = voices&#91;i].is_drum ? 0.0f : p.s;\n                float rel = voices&#91;i].is_drum ? 0.1f : p.r;\n\n                if (voices&#91;i].stage == 1) { voices&#91;i].env += stp\/max(atk,0.001f); if(voices&#91;i].env&gt;=1.0f) voices&#91;i].stage=2; }\n                else if (voices&#91;i].stage == 2) { voices&#91;i].env -= (stp\/max(dec,0.001f))*(1.0 - sus); if(voices&#91;i].env&lt;=sus) voices&#91;i].stage=3; }\n                else if (voices&#91;i].stage == 4) { voices&#91;i].env -= stp\/max(rel,0.001f); if(voices&#91;i].env&lt;=0) { voices&#91;i].active=false; voices&#91;i].note=-1; } }\n            }\n        }\n        float d_out = delayBuf&#91;delay_idx]; delayBuf&#91;delay_idx] = mix + d_out * (0.5f + p.chorus * 0.2f); delay_idx = (delay_idx + 1) % DELAY_LEN;\n        float dry_plus_delay = mix + d_out * p.delay_mix;\n        float c1 = comb1Buf&#91;c1_idx]; comb1Buf&#91;c1_idx] = dry_plus_delay + c1 * 0.7f; c1_idx = (c1_idx + 1) % COMB1_LEN;\n        float c2 = comb2Buf&#91;c2_idx]; comb2Buf&#91;c2_idx] = dry_plus_delay + c2 * 0.65f; c2_idx = (c2_idx + 1) % COMB2_LEN;\n        float rev_in = c1 + c2;\n        float ap_out = apBuf&#91;ap_idx]; float ap_new = rev_in + ap_out * 0.5f; apBuf&#91;ap_idx] = ap_new; ap_idx = (ap_idx + 1) % AP_LEN;\n        float final_rev = ap_new - rev_in; \n        \n        float output = (dry_plus_delay + final_rev * p.reverb_mix) * p.gain * 12000.0f;\n        int16_t dry_int = (int16_t)constrain(output, -32000, 32000);\n        i2s.write(dry_int); i2s.write(dry_int);\n        \n        if (p.page == 3) {\n            if(s_ptr &lt; SCOPE_SAMPLES) scope_buf&#91;s_ptr++] = dry_int; else s_ptr = 0;\n            if (!fft_ready) { vReal&#91;f_ptr] = (float)dry_int; vImag&#91;f_ptr] = 0; if(++f_ptr &gt;= FFT_SAMPLES) { f_ptr = 0; fft_ready = true; } }\n        }\n    }\n}\n\n\/\/ \u2605 FIXED CALLBACKS (Updated for new library) \u2605\nextern \"C\" {\n\/\/ \u2605 FIXED SIGNATURE: use const tuh_midi_mount_cb_t *\nvoid tuh_midi_mount_cb(uint8_t idx, const tuh_midi_mount_cb_t *mount_cb_data) {\n    usb_mounted = true;\n}\nvoid tuh_midi_unmount_cb(uint8_t idx) {\n    usb_mounted = false;\n}\nvoid tuh_midi_rx_cb(uint8_t d, uint32_t n_p) {\n    uint8_t pkt&#91;4];\n    while (tuh_midi_packet_read(d, pkt)) {\n        midi_rx_activity = true; \n        uint8_t st = pkt&#91;1] &amp; 0xF0, d1 = pkt&#91;2], d2 = pkt&#91;3];\n        float val = d2 \/ 127.0f;\n        \n        if (st == 0x90 &amp;&amp; d2 &gt; 0) {\n            float tf = 440.0f * powf(2.0f, (d1 - 69.0f) \/ 12.0f);\n            for(int i=0; i&lt;POLYPHONY; i++) if(!voices&#91;i].active) {\n                voices&#91;i].note=d1; voices&#91;i].target_freq=tf; \n                if(p.glide==0) voices&#91;i].freq=tf;\n                voices&#91;i].ph=0; voices&#91;i].stage=1; voices&#91;i].env=0; voices&#91;i].active=true;\n                voices&#91;i].low=0; voices&#91;i].band=0; \n                p.note_active = true; break;\n            }\n        } else if (st == 0x80 || (st == 0x90 &amp;&amp; d2 == 0)) {\n            bool any_active = false;\n            for(int i=0; i&lt;POLYPHONY; i++) {\n                if(voices&#91;i].note==d1) voices&#91;i].stage=4;\n                if(voices&#91;i].active &amp;&amp; voices&#91;i].stage!=4) any_active = true;\n            }\n            p.note_active = any_active;\n        }\n        \n        if (st == 0xB0) {\n            if (d1 == 7) { p.page = (d2 * 4) \/ 128; p.dirty = true; }\n            else if (d1 == 8) { p.gain = val; p.dirty = true; }\n            else {\n                switch(p.page) {\n                    case 0:\n                        if(d1==1) apply_selection((d2 * total_presets) \/ 128);\n                        if(d1==2 &amp;&amp; p.total_files&gt;0) { int nx=(d2*p.total_files)\/128; if(p.selected_file_idx!=nx) { p.selected_file_idx=nx; p.req_file_reload=true; p.dirty=true; }}\n                        if(d1==3) { bool q=(d2&gt;64); if(p.playing!=q){p.playing=q; if(!q)p.req_panic=true; p.dirty=true;} }\n                        if(d1==4) { p.play_speed = 0.5f+val*1.5f; p.dirty=true; }\n                        if(d1==5) { p.wave=(d2*5)\/128; p.dirty=true; }\n                        if(d1==6) { p.chorus=val; p.dirty=true; }\n                        break;\n                    case 1:\n                        if(d1==1)p.glide=val; if(d1==2)p.cut=val*8000.0f; \n                        if(d1==3)p.res=val; if(d1==4)p.delay_mix=val; \n                        if(d1==5)p.reverb_mix=val; if(d1==6)p.fm_idx=val*5.0f;\n                        p.dirty = true; break;\n                    case 2:\n                        if(d1==1)p.a=val; if(d1==2)p.d=val; if(d1==3)p.s=val; if(d1==4)p.r=val;\n                        if(d1==5)p.lfo_f=val; if(d1==6)p.lfo_d=val; p.dirty = true; break;\n                }\n            }\n        }\n    }\n}\n}\n<\/code><\/pre>\n\n\n\n<p>&lt;\/details&gt;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u6559\u8a13<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u30bf\u30c3\u30c1\u30d1\u30cd\u30eb\u306e\u30c7\u30fc\u30bf\u4ed5\u69d8\u306f\u30c7\u30fc\u30bf\u30b7\u30fc\u30c8\u3092\u8aad\u3080\u304b\u3001\u30b5\u30f3\u30d7\u30eb\u30b3\u30fc\u30c9\u3092\u5fb9\u5e95\u7684\u306b\u89e3\u6790\u3059\u308b<\/strong>: 8bit\u3060\u3068\u601d\u3044\u8fbc\u3093\u3067\u3044\u305f\u3089\u3001\u5b9f\u306f12bit\u5909\u5247\u30d1\u30c3\u30ad\u30f3\u30b0\u3060\u3063\u305f\u3002<\/li>\n\n\n\n<li><strong>\u30b4\u30fc\u30b9\u30c8\u30bf\u30c3\u30c1\u5bfe\u7b56<\/strong>: \u9759\u96fb\u5bb9\u91cf\u5f0f\u30bf\u30c3\u30c1\u30d1\u30cd\u30eb\u3067\u3082\u3001\u30c9\u30e9\u30a4\u30d0\u30ec\u30d9\u30eb\u3067\u306e\u30c1\u30e3\u30bf\u30ea\u30f3\u30b0\u9664\u53bb\u3084\u9759\u6b62\u753b\u691c\u77e5\u304c\u5fc5\u8981\u306a\u5834\u5408\u304c\u3042\u308b\u3002<\/li>\n\n\n\n<li><strong>USB\u30db\u30b9\u30c8\u6a5f\u80fd\u306fIDE\u8a2d\u5b9a\u304c\u547d<\/strong>: \u30b3\u30fc\u30c9\u304c\u6b63\u3057\u304f\u3066\u3082\u3001\u30b3\u30f3\u30d1\u30a4\u30e9\u306e\u8a2d\u5b9a\uff08USB Stack\uff09\u304c\u9593\u9055\u3063\u3066\u3044\u308c\u3070\u30cf\u30fc\u30c9\u30a6\u30a7\u30a2\u306f\u52d5\u304b\u306a\u3044\u3002\u3053\u308c\u304c\u4eca\u56de\u306e\u6700\u5927\u306e\u843d\u3068\u3057\u7a74\u3067\u3057\u305f\u3002<\/li>\n\n\n\n<li><strong>\u30e9\u30a4\u30d6\u30e9\u30ea\u306e\u66f4\u65b0\u5c65\u6b74<\/strong>: \u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u306e <code>conflicting declaration<\/code> \u306f\u3001API\u4ed5\u69d8\u5909\u66f4\u306e\u8a3c\u62e0\u3002\u30d8\u30c3\u30c0\u30d5\u30a1\u30a4\u30eb\u3092\u78ba\u8a8d\u3059\u308b\u306e\u304c\u4e00\u756a\u306e\u8fd1\u9053\u3002<\/li>\n<\/ul>\n\n\n\n<p>USB \u63a5\u7d9a\u306emidi keyboard\u306e\u8a8d\u8b58\u306b\u82e6\u52b4<\/p>\n\n\n\n<p>Grok\u306e\u6b21\u306e\u30a2\u30c9\u30d0\u30a4\u30b9\u3067\u6551\u308f\u308c\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>Arduino IDE\u306e\u30e9\u30a4\u30d6\u30e9\u30ea\u30d5\u30a9\u30eb\u30c0\u3092\u958b\u304f Windows\u306e\u5834\u5408\uff1a<strong> C:\\Users\\[\u30e6\u30fc\u30b6\u30fc\u540d]\\AppData\\Local\\Arduino15\\packages\\rp2040\\hardware\\rp2040\\[\u30d0\u30fc\u30b8\u30e7\u30f3]\\libraries\\Adafruit_TinyUSB_Arduino\\src\\arduino\\ports\\rp2040\\<\/strong><\/p>\n\n\n\n<p>\u305d\u3053\u306b <strong>tusb_config_rp2040.h<\/strong> \u3068\u3044\u3046\u30d5\u30a1\u30a4\u30eb\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u305d\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u30c6\u30ad\u30b9\u30c8\u30a8\u30c7\u30a3\u30bf\u3067\u958b\u304d\u3001\u4ee5\u4e0b\u306e2\u7b87\u6240\u3092\u4fee\u6b63\uff1a<\/p>\n\n\n\n<p><strong>\u2460 MIDI Host\u3092\u6709\u52b9\u306b\u3059\u308b<\/strong> \u4ee5\u4e0b\u306e\u884c\u3092\u63a2\u3057\u3066\uff08\u306a\u3051\u308c\u3070\u8ffd\u52a0\uff09\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>#define CFG_TUH_MIDI 1<\/strong><\/code><\/pre>\n\n\n\n<p>\uff080 \u306b\u306a\u3063\u3066\u3044\u305f\u30891\u306b\u5909\u66f4\uff09<\/p>\n\n\n\n<p><strong>\u2461 \u5217\u6319\u30d0\u30c3\u30d5\u30a1\u3092\u5927\u304d\u304f\u3059\u308b<\/strong>\uff08MPK mini mk3\u306e\u8a18\u8ff0\u5b50\u304c\u9577\u3044\u305f\u3081\u5fc5\u9808\uff09 \u4ee5\u4e0b\u306e\u884c\u3092\u63a2\u3057\u3066\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>#define CFG_TUH_ENUMERATION_BUFSIZE 512<\/strong><\/code><\/pre>\n\n\n<div class=\"wp-block-ub-content-toggle wp-block-ub-content-toggle-block\" id=\"ub-content-toggle-block-90b00bf4-14f6-473e-bb99-8e5186ad0879\" data-mobilecollapse=\"false\" data-desktopcollapse=\"false\" data-preventcollapse=\"false\" data-showonlyone=\"false\">\n<div class=\"wp-block-ub-content-toggle-accordion\" style=\"border-color: #f1f1f1;\" id=\"ub-content-toggle-panel-block-\">\n\t\t\t<div class=\"wp-block-ub-content-toggle-accordion-title-wrap\" style=\"background-color: #f1f1f1;\" aria-controls=\"ub-content-toggle-panel-0-90b00bf4-14f6-473e-bb99-8e5186ad0879\" tabindex=\"0\">\n\t\t\t<p class=\"wp-block-ub-content-toggle-accordion-title ub-content-toggle-title-90b00bf4-14f6-473e-bb99-8e5186ad0879\" style=\"color: #000000; \"><\/p>\n\t\t\t<div class=\"wp-block-ub-content-toggle-accordion-toggle-wrap right\" style=\"color: #000000;\"><span class=\"wp-block-ub-content-toggle-accordion-state-indicator wp-block-ub-chevron-down open\"><\/span><\/div>\n\t\t<\/div>\n\t\t\t<div role=\"region\" aria-expanded=\"true\" class=\"wp-block-ub-content-toggle-accordion-content-wrap\" id=\"ub-content-toggle-panel-0-90b00bf4-14f6-473e-bb99-8e5186ad0879\"><\/div>\n\t\t<\/div>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Waveshare RP2350-Touch-LCD-2<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u6a5f\u80fd\u30b0\u30eb\u30fc\u30d7<\/th><th>GPIO\u756a\u53f7<\/th><th>\u7528\u9014 \/ \u63a5\u7d9a\u5148<\/th><th>\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9<\/th><th>\u5099\u8003<\/th><\/tr><\/thead><tbody><tr><td><strong>LCD (ST7789T3)<\/strong><\/td><td>GPIO15<\/td><td>LCD_BL (\u30d0\u30c3\u30af\u30e9\u30a4\u30c8 PWM\u5236\u5fa1)<\/td><td>GPIO (PWM)<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>LCD<\/td><td>GPIO16<\/td><td>LCD_DC (Data\/Command)<\/td><td>SPI<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>LCD<\/td><td>GPIO17<\/td><td>LCD_CS (Chip Select)<\/td><td>SPI<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>LCD<\/td><td>GPIO18<\/td><td>LCD_CLK (SCK \/ Clock)<\/td><td>SPI<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>LCD<\/td><td>GPIO19<\/td><td>LCD_DIN (MOSI \/ Data In)<\/td><td>SPI<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>LCD<\/td><td>GPIO20<\/td><td>LCD_RST (Reset)<\/td><td>GPIO<\/td><td>\u5360\u6709<\/td><\/tr><tr><td><strong>Touch (CST816D) + IMU (QMI8658)<\/strong><\/td><td>GPIO12<\/td><td>TP_SDA \/ IMU_SDA (I2C \u30c7\u30fc\u30bf)<\/td><td>I2C<\/td><td>\u5171\u6709<\/td><\/tr><tr><td>Touch \/ IMU<\/td><td>GPIO13<\/td><td>TP_SCL \/ IMU_SCL (I2C \u30af\u30ed\u30c3\u30af)<\/td><td>I2C<\/td><td>\u5171\u6709<\/td><\/tr><tr><td>Touch \/ IMU<\/td><td>GPIO14<\/td><td>TP_INT \/ IMU_INT1 (\u5272\u308a\u8fbc\u307f)<\/td><td>GPIO<\/td><td>\u5171\u6709\uff08\u5272\u308a\u8fbc\u307f\uff09<\/td><\/tr><tr><td><strong>TF\u30ab\u30fc\u30c9 (SD)<\/strong><\/td><td>GPIO24<\/td><td>SD_SCLK (Clock)<\/td><td>SPI<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>TF\u30ab\u30fc\u30c9<\/td><td>GPIO25<\/td><td>SD_CS (Chip Select)<\/td><td>SPI<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>TF\u30ab\u30fc\u30c9<\/td><td>GPIO26<\/td><td>SD_MISO (DO \/ Data Out)<\/td><td>SPI<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>TF\u30ab\u30fc\u30c9<\/td><td>GPIO27<\/td><td>SD_MOSI (DI \/ Data In)<\/td><td>SPI<\/td><td>\u5360\u6709<\/td><\/tr><tr><td><strong>\u30ab\u30e1\u30e9 (DVP)<\/strong><\/td><td>GPIO0<\/td><td>CAM_D0 (Data 0)<\/td><td>Parallel DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO1<\/td><td>CAM_D1<\/td><td>Parallel DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO2<\/td><td>CAM_D2<\/td><td>Parallel DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO3<\/td><td>CAM_D3<\/td><td>Parallel DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO4<\/td><td>CAM_D4<\/td><td>Parallel DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO5<\/td><td>CAM_D5<\/td><td>Parallel DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO6<\/td><td>CAM_D6<\/td><td>Parallel DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO7<\/td><td>CAM_D7<\/td><td>Parallel DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO8<\/td><td>CAM_VSYNC (Vertical Sync)<\/td><td>DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO9<\/td><td>CAM_HREF (Horizontal Reference)<\/td><td>DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO10<\/td><td>CAM_PCLK (Pixel Clock)<\/td><td>DVP<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO11<\/td><td>CAM_XCLK (Master Clock\u51fa\u529b)<\/td><td>GPIO (\u30af\u30ed\u30c3\u30af)<\/td><td>\u5360\u6709<\/td><\/tr><tr><td>\u30ab\u30e1\u30e9<\/td><td>GPIO21<\/td><td>CAM_PWDN (Power Down)<\/td><td>GPIO<\/td><td>\u5360\u6709<\/td><\/tr><tr><td><strong>\u30d0\u30c3\u30c6\u30ea\u30fc\u76e3\u8996<\/strong><\/td><td>GPIO28<\/td><td>BAT_ADC (\u96fb\u6c60\u96fb\u5727 ADC\u5165\u529b)<\/td><td>ADC<\/td><td>\u5360\u6709<\/td><\/tr><\/tbody><\/table><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>Raspberry Pi Pico 2 (RP2350) \u3068\u30bf\u30c3\u30c1\u30d1\u30cd\u30eb\u6db2\u6676\u3001\u305d\u3057\u3066USB MIDI\u30ad\u30fc\u30dc\u30fc\u30c9\u3092\u7d44\u307f\u5408\u308f\u305b\u305f\u81ea\u4f5c\u30b7\u30f3\u30bb\u30b5\u30a4\u30b6\u30fc\u958b\u767a\u306b\u304a\u3051\u308b\u3001\u30c7\u30d0\u30c3\u30b0\u306e\u8a18\u9332\u3092\u8a18\u4e8b\u306b\u307e\u3068\u3081\u307e\u3057\u305f\u3002 \u3010RP2350\u3011Pico  [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[33,32,1,6],"tags":[],"class_list":["post-2307","post","type-post","status-publish","format-standard","hentry","category-midi","category-32","category-uncategorized","category-make"],"featured_image_src":null,"author_info":{"display_name":"mars","author_link":"https:\/\/rfsec.ddns.net\/db\/?author=1"},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=\/wp\/v2\/posts\/2307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2307"}],"version-history":[{"count":2,"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=\/wp\/v2\/posts\/2307\/revisions"}],"predecessor-version":[{"id":2322,"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=\/wp\/v2\/posts\/2307\/revisions\/2322"}],"wp:attachment":[{"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rfsec.ddns.net\/db\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}