Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
MK4001MTD-USB-Bridge — RP2040 펌웨어로, 도시바 MK4001MTD 0.85인치 SDIO 마이크로드라이브를 USB 대용량 저장 장치로 브리징하며, PIO 가속 읽기/쓰기 및 불량 섹터 복구 기능을 갖춘 전체 SDIO-ATA 프로토콜 스택을 처음부터 구현합니다. | Kitploit
도구/GitHubGitHub/will127534/mk4001mtd-usb-bridge
Embedded Systems SecurityReverse EngineeringData RecoveryHardware HackingHardware SecurityHardware & IoT SecurityFirmware Analysis
GitHubwill127534/mk4001mtd-usb-bridge

MK4001MTD-USB-Bridge

RP2040 펌웨어로, 도시바 MK4001MTD 0.85인치 SDIO 마이크로드라이브를 USB 대용량 저장 장치로 브리징하며, PIO 가속 읽기/쓰기 및 불량 섹터 복구 기능을 갖춘 전체 SDIO-ATA 프로토콜 스택을 처음부터 구현합니다.

저장소 보기
42121개월 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

MK4001MTD USB 브리지

Toshiba MK4001MTD 0.85인치 SDIO 마이크로드라이브를 USB 대용량 저장 장치로 연결하는 RP2040 Pico 펌웨어. _DSC1170 _DSC1354

MK4001MTD는 4GB 마이크로드라이브로, 원래 Nokia N91 뮤직폰 및 일부 MP3 플레이어나 USB 드라이브 같은 기기에 사용되었으며, 당시 플래시 저장 장치는 꽤 비쌌습니다.

이 드라이브가 MMC 프로토콜을 사용한다는 소개를 본 적이 있을 수 있지만, 이는 사실 잘못된 정보입니다. 저는 이 문제를 한동안 조사해 왔습니다. 8비트 MMCplus 카드 리더기를 만들어 보기도 하고 다양한 SD/MMC 리더기를 테스트해 보았지만 성공하지 못했습니다. 최후의 수단으로 Nokia N91을 구입하여 로직 트레이스를 캡처하고 실제로 어떤 프로토콜을 사용하는지 확인했습니다.

아래는 제 8비트 MMCPlus 리더 보드와 함께 사용하려고 시도했을 때의 사진입니다. 결과적으로 MMC가 아니었습니다 :( _DSC0484

그래서 결국 N91을 구입하여 트레이스를 수집했습니다: _DSC1093 _DSC1131

표준 ATA/CF 마이크로드라이브와 달리, SDIO 인터페이스를 사용하며 ATA 명령이 CMD52/CMD53을 통해 터널링됩니다. 이 프로토콜을 지원하는 기존 드라이버가 없기 때문에, 이 펌웨어는 처음부터 전체 스택을 구현합니다.

이것은 저에게 놀라운 점이었습니다. SDIO-to-ATA 표준인 CE-ATA가 존재하기 때문입니다. 하지만 출시 타임라인을 자세히 살펴보면, CE-ATA는 이 드라이브보다 나중에 나왔습니다. 결과적으로 이 드라이브는 전적으로 SDIO 명령에 의존하며 CE-ATA는 사용할 수 없습니다. CE-ATA는 두 개의 새로운 명령 CMD60/CMD61과 CMD12/39를 사용하지만, 트레이스에서 볼 수 있듯이 이 드라이브는 이러한 명령을 전혀 사용하지 않습니다.

두 번째 하드웨어 관련 사항은, 돌아다니는 또 다른 잘못된 정보—즉, 이 드라이브가 8비트 MMCPlus 카드라는 주장—이 사실이 아닐 뿐만 아니라 핀 배치도 MMC 표준을 따르지 않는다는 점입니다. Nokia N91 서비스 매뉴얼에서 핀 배치에 대한 일부 문서를 찾을 수 있습니다. 핀 번호는 MMCPlus 표준을 따르지만 핀 매핑은 그렇지 않습니다. 직접 배선할 때 중요한 세부 사항입니다. 동일한 MMC 커넥터를 사용하지만 핀 매핑이 다릅니다. 하드웨어 섹션에서 자세히 설명합니다.

마지막으로, 이 프로젝트는 Claude/OpenClaw와 공동 개발되었습니다. 제가 로직 트레이스를 수동으로 수집하고 OpenClaw가 개발을 반복할 수 있도록 폐쇄 루프 테스트 스테이션을 설정했습니다. 트레이스를 분석하고 기능을 구현한 것입니다. 문서는 주로 Claude가 작성할 예정이며, 제가 인라인으로 노트를 추가하겠습니다. 또한 제가 직접 문서를 읽고 다시 확인했으며, 신뢰할 수 있고 따라하기 쉬울 것입니다.

N91 트레이스 분석에 대한 통찰은 /docs/N91_TRACE_ANALYSIS.md에 있습니다. N91 서비스 매뉴얼과 원시 로직 트레이스도 함께 넣었습니다.

블로그 게시물에서 더 자세한 내용을 확인하세요: https://www.willwhang.dev/Reading-MK4001MTD/ 실제 동작 영상: https://youtu.be/GC4xil3_Bbc

상태

PIO 가속 읽기/쓰기 및 아이들 전원 관리 기능을 갖춘 완전한 기능의 USB 대용량 저장 장치.

작동 방식

아키텍처

root@kitploit:~
USB 호스트 ←→ USB MSC (TinyUSB) ←→ ATA 레이어 ←→ SDIO 레이어 (PIO) ←→ MK4001MTD

펌웨어는 네 개의 레이어로 구성됩니다:

  1. USB MSC (msc_device.c) — TinyUSB Mass Storage Class. SCSI READ(10)/WRITE(10)를 ATA 섹터 연산으로 변환합니다. 32KB EP 버퍼, USB 전송당 최대 64섹터 일괄 처리. 드라이브 I/O는 양방향으로 USB와 중첩되어, 실제 ATA-USB 브리지와 캐싱 디스크처럼 동작합니다. 순차 읽기 프리페처는 이전 청크가 호스트로 스트리밍되는 동안 다음 청크를 가져오고, 쓰기는 USB가 다음 조각을 수신하는 동안 스테이징되어 플러시됩니다. 장치는 쓰기 캐시(캐싱 모드 페이지, WCE=1 — 호스트는 "쓰기 캐시: 활성화됨"을 보고 fsync/언마운트/서스펜드 시 SYNCHRONIZE CACHE를 발행하며, 펌웨어는 이를 처리합니다)를 광고합니다. 실패한 백그라운드 플러시는 다음 WRITE 또는 SYNCHRONIZE CACHE에서 MEDIUM ERROR로 표시됩니다. 알려진 불량 섹터에 대한 쓰기는 엄격한 동기 경로를 취합니다.

  2. ATA-over-SDIO (ata_sdio.c) — ATA 명령(IDENTIFY, READ SECTORS, WRITE SECTORS)을 구현하며, ATA 레지스터를 CMD52를 통해 SDIO 함수 1 주소 공간에 매핑하고 CMD53을 통해 섹터 데이터를 전송합니다. CMD, 데이터, ATA 레벨에서 3단계 재시도 로직.

  3. PIO SDIO (sdio_pio.c, sdio.pio) — RP2040의 PIO 주변 장치를 사용한 하드웨어 가속 SDIO (4비트 버스, 10MHz, 입력 동기화기 우회로 비트당 4 PIO 사이클). 동적 프로그램 스와핑을 통해 단일 상태 머신을 공유하는 세 가지 PIO 프로그램:

    • CMD tx/rx (24개 명령어) — SDIO 명령 전송 및 응답 수신
    • DAT 읽기 (12개 명령어) — 바이트 스와핑 DMA(CPU 재패킹 없음)를 통해 4비트 DAT 버스에서 데이터 블록 읽기; 블록 N의 CRC는 블록 N+1이 스트리밍되는 동안 검증
    • DAT 쓰기 (14개 명령어) — DMA를 통해 4비트 DAT 버스에 데이터 블록 쓰기, 내장 CRC 상태 수신 및 busy-wait 포함; 블록 N+1의 니블 스트림은 블록 N이 전송되는 동안 구축
  4. 핀/전원 (sdio_hw.c) — GPIO 초기화 및 HDD 전원 제어. 모든 SDIO 통신은 PIO를 사용합니다.

인간 노트: 흥미롭게도 Claude는 PIO에서 SDIO를 구현하는 것을 매우 꺼려했고, PIO와 비트뱅잉 사이를 왔다 갔다 하면서 많은 개발 주기가 낭비되었습니다.

SDIO-ATA 프로토콜

MK4001MTD는 하나의 I/O 함수를 가진 SDIO 카드로 자신을 식별합니다. 표준 SDIO 카드 초기화(CMD5/CMD3/CMD7)가 버스를 설정한 후, ATA 레지스터는 SDIO 명령을 통해 접근됩니다:

레지스터 접근 (CMD52): 각 ATA 레지스터는 함수 1 주소에 매핑됩니다:

데이터 전송 (CMD53): 섹터 데이터는 DATA 레지스터(주소 0x00)를 대상으로 블록 모드에서 CMD53을 발행하여 전송됩니다. 다중 섹터 읽기의 경우, block_count=N인 단일 CMD53이 한 번의 SDIO 다중 블록 트랜잭션으로 N × 512바이트를 전송합니다.

인터럽트 신호: 드라이브는 SDIO 인터럽트(CCCR 레지스터 0x05의 INT_PENDING 비트 1)를 어설션하여 섹터 준비를 알립니다. ATA STATUS 레지스터를 읽으면 인터럽트가 지워집니다.

읽기 경로 (다중 블록 PIO)

16섹터 읽기의 경우:

root@kitploit:~
1. PIO CMD52를 통해 ATA 레지스터 쓰기:
     SECCOUNT=16, LBA_LO/MID/HI, DEV/HEAD=0xE0, CMD=0x20

2. CMD52를 통해 STATUS 폴링, DRQ(비트 3)가 설정될 때까지

3. PIO를 DAT 읽기 프로그램으로 교체
4. CMD53 전송: block_mode=1, fn=1, addr=0x0000, block_count=16

5. PIO DAT 읽기: 16개 블록 각각에 대해:
   a. 시작 비트(모든 DAT 라인 로우) 대기
   b. PIO RX FIFO에서 버퍼로 1024 니블(512바이트) DMA
   c. SM이 CRC+종료 니블 클록을 마칠 때까지 대기(SM PC 폴링)
   d. 니블 → 바이트 인플레이스 재패킹

6. PIO를 CMD 프로그램으로 교체

쓰기 경로 (다중 블록 PIO)

16섹터 쓰기의 경우:

root@kitploit:~
1. PIO CMD52를 통해 ATA 레지스터 쓰기:
     SECCOUNT=16, LBA, DEV/HEAD=0xE0, CMD=0x30

2. CMD52를 통해 STATUS 폴링, DRQ(비트 3)가 설정될 때까지
   (STATUS 0xD8 = BSY+DRQ는 N91 트레이스에 따라 DRQ-준비로 처리)

3. PIO를 DAT 쓰기 프로그램으로 교체
4. CMD53 전송: block_mode=1, fn=1, addr=0x0000, block_count=16

5. PIO DAT 쓰기: 16개 블록 각각에 대해:
   a. DAT 라인별로 CRC16-CCITT 사전 계산 (4개의 독립 CRC)
   b. 니블 스트림 구축: 시작(0x0) + 데이터(1024 니블) + CRC(16) + 종료(0xF)
   c. 니블 스트림을 PIO TX FIFO로 DMA
   d. PIO가 모든 니블을 클록 아웃한 후:
      - DAT를 입력으로 전환
      - 카드의 CRC 상태를 위해 16사이클 클록
      - 카드가 busy를 해제할 때까지 DAT0 폴링
      - 블록 완료를 알리기 위해 IRQ 0 발생

6. PIO를 CMD 프로그램으로 교체

PIO 프로그램 스와핑

RP2040 PIO는 블록당 32개의 명령어 슬롯이 있습니다. 세 프로그램은 총 55개의 명령어이므로 공존할 수 없습니다. 대신 PIO0의 단일 SM0를 사용하고, PIO 명령어 메모리에 직접 쓰기하여 프로그램을 교체합니다:

root@kitploit:~
static void load_program_raw(const pio_program_t *program) {
    for (uint i = 0; i < program->length; i++)
        pio->instr_mem[FIXED_OFFSET + i] = program->instructions[i];
}

이것은 SDK의 pio_add_program/pio_remove_program 할당자를 우회합니다. 프로그램 교체는 약 1µs가 소요됩니다. 각 교체 후에는 핀 매핑, 시프트 방향 및 클록 분배기를 설정하는 프로그램별 재초기화가 이어집니다.

전원 관리

Nokia N91 로직 트레이스 분석 결과, 공격적인 전원 관리가 드러났습니다:

  • 아이들 모드: I/O가 없어도 약 7.5초마다 STANDBY IMMEDIATE (0xE0)를 실행합니다. 각 대기는 전체 SDIO 재초기화(CMD5 재시도 → CMD3 → CMD7 → CCCR 설정)를 유발합니다. 한 아이들 세션에서 28개의 대기 사이클이 관찰되었습니다.
  • 활성 모드: I/O 버스트 사이에 대기 발행(USB 드라이브 파일 작업 중 24사이클).
  • 다른 전원 명령(IDLE, SLEEP, CHECK POWER MODE) 또는 CCCR 전원 레지스터 접근은 관찰되지 않았습니다.

펌웨어는 구성 가능한 아이들 타임아웃으로 이 동작을 복제합니다:

root@kitploit:~
#define IDLE_STANDBY_MS 5000  // main.c

두 가지 경로가 HDD 전원 게이팅을 트리거합니다:

  1. 아이들 타임아웃 (5초) — 메인 루프가 I/O 활동 없음을 감지
  2. USB 서스펜드 — 호스트가 USB 포트를 서스펜드

두 경로 모두 ATA STANDBY IMMEDIATE (0xE0)를 전송하여 쓰기 캐시를 플러시하고 헤드를 주차한 다음 GP9를 통해 전원을 차단합니다.

깨우기 시퀀스 (게이트 후 첫 READ/WRITE에 의해 트리거):

  1. HDD 전원 켜기, 레일 안정화를 위해 500ms 대기
  2. PIO 기반 SDIO 재초기화: CMD5 (OCR) → 10ms 안정화 → CMD3 (RCA) → CMD7 (선택)
  3. 고속 PIO 클록으로 전환, CMD52를 통해 CCCR 구성(4비트 버스, 512B 블록, fn1 활성화)
  4. fn1 준비 폴링 (CCCR IO_READY 비트 1)
  5. N91 스타일 30ms DRDY 상태 폴링, 드라이브가 ATA 준비될 때까지

불량 섹터 처리

다중 섹터 전송이 불량 섹터에 도달하면:

  1. 청크 읽기 실패 → 오류 복구 (IO_ABORT + fn1 리셋, ~500ms)
  2. 정확히 실패한 블록을 식별하기 위해 섹터별 I/O로 폴백
  3. ATA 레이어는 일반적인 DRQ 시간 초과로 실패를 축소하지 않고 최종 STATUS/ERROR 비트를 캡처할 수 있을 만큼 충분히 오래 대기
  4. 복구되지 않은 블록은 즉시 SCSI 명령을 MEDIUM ERROR(읽기: 03/11/00, 쓰기: 03/0C/00)로 실패시킴
  5. 불량 섹터 LBA 캐시 → 읽기 반복은 드라이브를 다시 때리지 않고 빠르게 실패 (호스트 재시도 폭풍에 대한 안티-해머 보호)
  6. 쓰기는 항상 미디어에 도달, SBC에 따름 — 캐시된 불량 LBA에 대한 성공적인 쓰기는 캐시에서 해당 LBA를 제거, 마치 드라이브가 보류 중인 섹터를 지우는 것과 정확히 같음

6번은 학술적이지 않습니다. 이 드라이브에는 LBA 1952에 오래된 읽을 수 없는 섹터가 있었습니다(READ: ST=0x51 ERR ERR=0x40 UNC). 브리지가 쓰기가 실제로 도달할 수 있게 한 후, 드라이브가 섹터를 다시 쓰고 이후로 깔끔하게 읽혔습니다:

root@kitploit:~
[ATA] FAST-RD: ST=0x51 ERR ERR=0x40 UNC LBA=1952
[MSC] BAD SECTOR read LBA=1952
[MSC] Bad sector LBA=1952 repaired by write

빌드

필수 조건

  • Raspberry Pi Pico SDK — 순정, 수정 없음, 2.2.0에 고정
  • ARM 툴체인 (arm-none-eabi-gcc)
  • CMake

SDK 버전은 고정되어 있습니다: PICO_SDK_PATH가 설정된 경우(환경 변수 또는 CMake 변수) 해당 경로가 사용되고 버전이 고정 버전과 일치하는지 확인됩니다. 일치하지 않으면 설정이 실패하고 지침이 표시됩니다(-DMK4001_ALLOW_SDK_MISMATCH=ON으로 재정의 가능). PICO_SDK_PATH가 전혀 없으면 고정된 SDK 릴리스가 구성 시 자동으로 GitHub에서 가져와지므로, 단순히 git clone && cmake && make만으로 완전히 재현 가능합니다.

펌웨어는 패치된 TinyUSB MSC 클래스 드라이버가 필요합니다(읽기/쓰기 오류 시 앱 센스 데이터 보존 + WCE=1인 캐싱 모드 페이지). 해당 파일은 이 저장소에 벤더링되어 lib/tinyusb_patched/msc_device.c에 있습니다. 빌드는 SDK 사본 대신 이 파일을 자동으로 컴파일하므로 SDK 수정이 전혀 필요 없습니다. 업스트림 TinyUSB(pico-sdk 2.2.0에 번들된 0.18.0)와의 차이는 lib/tinyusb_patched/에 있습니다. SDK 고정은 이 벤더링된 파일이 SDK의 TinyUSB를 추적해야 하기 때문에 존재합니다.

빌드 및 플래시

root@kitploit:~
cd /home/pi/mk4001_bridge/build
cmake ..
make -j4

sudo openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg \
  -c "adapter speed 1000" -c "init" -c "reset halt" -c "sleep 200" \
  -c "program /home/pi/mk4001_bridge/build/mk4001_bridge.elf verify" \
  -c "reset run" -c "exit"

하드웨어 배선

참고: 이 특정 Pico 장치에서는 GP0과 GP1이 죽었습니다. 모든 SDIO 핀 할당이 +2만큼 이동되었습니다.

인간 노트: Claude는 여기서 실수했습니다. 자신의 빌드 구성에서 GP0과 GP1이 UART 터미널에 사용되고 있다는 것을 깨닫지 못했기 때문입니다. 계속 잊어버려서 결국 SDIO GPIO를 해당 UART에서 이동시켰습니다.

HDD_PWR은 필수가 아닙니다. 드라이브를 사용하기 위해 전원을 껐다 켤 필요는 없으며, 많은 부분이 하드코딩되어 있을 때 HDD를 리셋하는 개발 편의 기능에 가깝습니다. 즉, 전원 절약이 필요하다면 해당 신호를 사용할 수 있지만, 웜 리셋은 문제없이 처리할 수 있습니다.

UART를 통해 디버그 메시지를 볼 수 있습니다. USB-CDC를 통해 나오지 않는 이유는 Claude가 초기 개발 중에 연결이 끊기거나 불안정해지지 않는 별도의 UART-to-USB 로깅 링크를 설정하는 것이 더 쉬웠기 때문입니다.

UART 로그는 드라이브가 활성 상태인 동안 30초마다 드라이브 온도도 보고합니다([TEMP] drive temperature: 29 C). 센서는 Toshiba 벤더 명령 0xC2를 리버스 엔지니어링하여 발견되었습니다. N91은 드라이브 세션 시작 시마다 이를 읽어 HDD 작동 온도 제한을 적용합니다. 자세한 내용은 docs/N91_TRACE_ANALYSIS.md §4에 있습니다.

로그 예시:

root@kitploit:~
========================================
  MK4001MTD USB Bridge v0.11
  SDIO-ATA → USB Mass Storage (PIO)
========================================

[MAIN] Pre-delay 5000ms...
[PIO] Init OK: clkdiv=3.12 (~10.0 MHz), CMD@0
[MAIN] Power cycling HDD...
[SDIO] HDD power OFF
[SDIO] HDD power ON
[MAIN] SDIO init (PIO)...
[SDIO] CMD5 ready (OCR=0x901F8000)
[SDIO] RCA=0x0001
[SDIO] fn1 ready (attempt 0)
[MAIN] ATA IDENTIFY...
[ATA] IDENTIFY complete
Model:    [TOSHIBA MK4001MTD]
Serial:   [           763B004HA]
Firmware: [VH173A]
Sectors:  7862400 (3839 MB)
SMART:    not supported (supported=0, enabled=0)
IDENTIFY: W0=0040 W47=0000 W49=0000 W59=0000
  ATA W80=0000  Cmd W82=0000 W83=0000 W84=0000
  En  W85=0000 W86=0000 W87=0000  W89=0008 W128=0001

[DIAG] === Drive Diagnostics ===
[DIAG] Standard SMART: not supported (IDENTIFY W82 bit0 = 0)
[DIAG] Toshiba vendor CMD 0xC2:
  FEAT=0x01 unknown_01                       → SC=00 LBA=02/00/00 ST=50
  FEAT=0x02 unknown_02                       → SC=00 LBA=02/00/00 ST=50
  FEAT=0x03 unknown_03                       → SC=00 LBA=02/00/00 ST=50
  FEAT=0x04 unknown_04                       → SC=00 LBA=02/00/00 ST=50
  FEAT=0x10 diag_10 (LBA_LO varies)          → SC=00 LBA=00/00/00 ST=50
  FEAT=0x11 diag_11                          → SC=00 LBA=00/00/00 ST=50
  FEAT=0x12 diag_12 (LBA_LO varies)          → SC=00 LBA=01/00/00 ST=50
  FEAT=0x20 query_20 (N91: SC=0xFF always)   → SC=FE LBA=00/FF/00 ST=50
  FEAT=0x21 query_21 (N91: SC varies per boot) → SC=1B LBA=00/FF/00 ST=50

[MAIN] MBR: valid 0x55AA
[MAIN] Warming up...
[MAIN] PIO OK, STATUS=0x50
[MAIN] Drive: 7862400 sectors (3839 MB)
[MAIN] Ready.
[PWR] Idle 5000ms → STANDBY + power gate
[PWR] STANDBY IMMEDIATE → power gate
[SDIO] HDD power OFF

마지막으로, 실제 드라이브에 대한 배선입니다. _DSC1176-2 다음은 N91 회로도의 일부로, 핀 번호를 매핑할 수 있습니다. image

참고로 이 드라이브는 3V 드라이브이지만 3.3V도 괜찮다고 생각합니다. 주로 레벨 시프팅 작업을 줄이기 위한 것입니다.

이 드라이브 전용으로 설계된 HW는 /hardware에 있습니다! image

소스 파일

버전 기록

테스트

root@kitploit:~
# 장치 확인
lsblk -dno NAME,MODEL | grep MK4001

# 파일 시스템 테스트 — 마운트, 파일 복사, 확인
sudo mount /dev/sdX1 /mnt/mk4001
cp /tmp/testfile /mnt/mk4001/
sync
md5sum /tmp/testfile /mnt/mk4001/testfile    # 일치해야 함
sudo umount /mnt/mk4001

# 속도 벤치마크 (원시 장치, 마운트하지 마세요 — 파일 시스템 손상됨)
# 파일 시스템 너머 또는 파티션되지 않은 드라이브의 안전한 오프셋 사용
sudo dd if=/dev/sdX of=/dev/null bs=64k count=128 iflag=direct     # 읽기
sudo dd if=/dev/zero of=/dev/sdX bs=64k count=64 oflag=direct seek=1024  # 쓰기 (FS 너머 오프셋)

인간 노트, 재미있는 사실: 속도 테스트를 처음 시작할 때 실제로 드라이브에 직접 dd 명령을 사용하여 파일 시스템을 손상시켰습니다..... 다행히 개발 중에는 그렇게 중요하지 않았지만, OpenClaw로 설정을 다룰 때는 항상 염두에 두세요.

라이선스

신경 쓰지 않습니다.

도구 다운로드
지표값
읽기 속도~985 kB/s (USB full-speed 제한)
쓰기 속도~920 kB/s (USB full-speed 제한, 광고된 쓰기 캐시)
순수 SDIO 측 속도~2.35 MB/s 읽기 / ~2.15 MB/s 쓰기 (드라이브 제한)
용량3.75 GB (7,862,400 섹터)
파일 시스템FAT32 확인됨 (마운트/언마운트/fsck 깨끗함)
데이터 무결성쓰기+읽기백 확인됨; 모든 4개 DAT 라인에 블록별 CRC16
아이들 대기5초 아이들 또는 USB 서스펜드 → STANDBY IMMEDIATE + 전원 게이트
주소레지스터용도
0x00DATA섹터 데이터용 CMD53 대상
0x01ERR/FEAT오류 (읽기) / 기능 (쓰기)
0x02SECCOUNT섹터 수
0x03LBA_LOLBA 비트 0-7
0x04LBA_MIDLBA 비트 8-15
0x05LBA_HILBA 비트 16-23
0x06DEV/HEAD장치/헤드 + LBA 비트 24-27
0x07CMD/STATUS명령 (쓰기) / 상태 (읽기)
Pico GPIO기능참고
GP2SDIO_CLK호스트 클록 출력
GP3SDIO_CMD양방향 명령 라인
GP4SDIO_DAT0데이터 비트 0
GP5SDIO_DAT1데이터 비트 1
GP6SDIO_DAT2데이터 비트 2
GP7SDIO_DAT3데이터 비트 3
GP9HDD_EN드라이브 전원 활성화 (HIGH=켜짐)
GP12UART TX디버그 출력 @ 115200
GP13UART RX디버그 입력
GP16LED: HDD 전원액티브 로우
GP17LED: HDD 정상액티브 로우
GP18LED: 읽기액티브 로우
GP19LED: 쓰기액티브 로우
파일줄목적
main.c210초기화, 아이들 대기, USB 서스펜드/재개
msc_device.c400USB MSC 콜백, 전원 게이트 웨이크, 불량 섹터 캐시
ata_sdio.c390ATA 명령, 오류 복구, 벤더 진단
sdio_pio.c635PIO SDIO: CMD52, CMD53 읽기/쓰기, 프로그램 교체, CRC16
sdio_hw.c45핀 초기화 + HDD 전원 제어
sdio.pio200PIO 어셈블리 + C SDK 초기화 도우미
led.h37LED 도우미 (GP16–GP19, 액티브 로우)
usb_descriptors.c77USB 장치/구성/문자열 디스크립터
tusb_config.h20TinyUSB 구성 (MSC, 32KB EP 버퍼)
버전읽기쓰기주요 변경 사항
v0.1–v0.3105 kB/s93 kB/s비트뱅 SDIO, CRC16, 재시도 로직
v0.5374 kB/s—단일 SM PIO, 직접 명령어 메모리 교체
v0.6583 kB/s93 kB/s다중 블록 CMD53 읽기, CRC 클록 드레인 수정
v0.8588 kB/s274 kB/sPIO 쓰기, OSR 플러시 수정
v0.9475 kB/s371 kB/s64섹터 청크, CRC16 읽기 검증
v0.10453 kB/s329 kB/sLED 재매핑, HDD EN 핀, GP12/GP13의 UART
v0.11~450 kB/s~340 kB/sHDD 전원 게이트, PIO 웨이크, 불량 섹터 감지, USB 서스펜드
v0.12~985 kB/s~920 kB/s드라이브/USB 오버랩 (읽기 프리페치 + 지연 쓰기를 포함한 광고된 쓰기 캐시), 파이프라인 PIO 블록, bswap DMA, 4사이클 PIO 루프, SBC 스타일 불량 섹터 의미론 (쓰기-복구), 벤더링된 TinyUSB MSC 드라이버