산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

Arduino Amiga 플로피 디스크 리더(V1)

구성품 및 소모품

저항 1k 옴
× 1
브레드보드(일반)
× 1
점퍼 와이어(일반)
× 1
SparkFun 브레드보드 전원 공급 장치 5V/3.3V
× 1
Arduino UNO
또는 Pro Mini
× 1

앱 및 온라인 서비스

Arduino IDE

이 프로젝트 정보

<울>
  • 나의 목표: Windows 10 및 기타 운영 체제 내에서 Amiga DD 플로피 디스크의 데이터를 복구하는 간단하고 저렴한 오픈 소스 방법을 만듭니다.
  • <울>
  • 내 솔루션: Arduino + Windows 애플리케이션
  • <울>
  • 이유: 미래를 위해 이러한 디스크의 데이터를 보존합니다. 또한 일반 PC는 Amiga 디스크가 쓰여지는 방식 때문에 읽을 수 없습니다.
  • 프로젝트 웹사이트:http://amiga.robsmithdev.co.uk/

    이것은 프로젝트의 V1입니다. V2에는 향상된 읽기 및 쓰기 기능이 포함되어 있습니다!

    아미가 체험

    내 경력은 Amiga, 특히 부모님이 10살 때 크리스마스 선물로 사주신 A500+ 덕분입니다. 처음에는 게임을 했으나 얼마 지나지 않아 다른 무엇을 할 수 있는지 궁금해지기 시작했습니다. 나는 Deluxe Paint III를 가지고 놀고 Workbench에 대해 배웠습니다.

    Amiga 500 Plus:

    매달 인기 있는 Amiga Format 잡지를 구입했습니다. 한 달 동안 AMOS를 무료로 사용할 수 있었습니다. Amiga 형식을 입력했습니다. AMOS에서 게임 작성 AMOS Professional이 나중에 표지에 실렸을 때의 경쟁, 그리고 In Pipe Line으로 12명의 (내 생각에) 우승자 중 하나였습니다. . 그래도 상을 받으려면 그들을 쫓아야 했습니다!

    아모스 - 창조주:

    배경

    계속해서 GCSE 및 A-Level 프로젝트의 일부로 사용했습니다(PC의 Turbo Pascal과 호환되는 Highspeed Pascal 덕분에)

    어쨌든 그것은 오래전 일이고 디스크 상자가 있고 더 이상 작동하지 않는 A500+가 있으므로 보존과 향수를 위해 이 디스크를 컴퓨터에 백업하는 것을 생각했습니다.

    Amiga Forever 웹사이트에는 하드웨어를 포함하고 PC에서 2개의 플로피 드라이브를 남용하는 훌륭한 옵션 목록이 있습니다. 슬프게도 이들 중 어느 것도 최신 하드웨어에 대한 옵션이 아니며 KryoFlux/Catweasel 컨트롤러는 너무 비쌉니다. 대부분이 비공개 소스라는 사실에 정말 놀랐습니다.

    전자 제품에 크게 관심을 갖고 Atmel 장치를 가지고 놀았습니다(AT89C4051 ) 대학에서 나는 Arduino를 살펴보기로 결정했습니다(GreatScott 시작하는 것이 얼마나 쉬운지 보여주는 영감을 얻기 위해) 이것이 가능한지 궁금했습니다.

    그래서 Arduino 플로피 드라이브 읽기를 검색했습니다. 코드를 남용한 모든 프로젝트를 건너뛴 후 음악 재생 드라이브, 나는 정말로 어떤 해결책도 찾지 못했습니다. 나는 그것이 불가능할 것이라고 제안하는 몇 개의 그룹에서 몇 가지 토론을 발견했습니다. FPGA를 기반으로 하는 프로젝트를 찾았는데 이 프로젝트는 매우 흥미롭게 읽었지만 내가 가고자 하는 방향이 아니었기 때문에 유일한 선택은 솔루션을 직접 구축하는 것이었습니다.

    연구

    이 프로젝트를 시작했을 때 나는 플로피 드라이브가 어떻게 작동하는지, 데이터가 어떻게 인코딩되는지 전혀 몰랐습니다. 다음 웹사이트는 무슨 일이 일어나고 어떻게 작동하는지 이해하는 데 매우 중요했습니다.

    <울>
  • techtravels.org(및 이 페이지)
  • <울>
  • Laurent Clévy의 .ADF(Amiga Disk File) 형식 FAQ
  • <울>
  • 아미가 포에버
  • <울>
  • 위키피디아 - Amiga 디스크 파일
  • <울>
  • 영어 Amiga 보드
  • <울>
  • QEEWiki - ATmega168/328의 카운터
  • <울>
  • 플로피 드라이브 핀 배치
  • <울>
  • 플로피 디스크 형식 목록
  • 가정

    연구를 바탕으로 이제 데이터가 디스크에 기록되는 방식과 디스크가 회전하는 방식을 이론적으로 알게 되었습니다.

    나는 몇 가지 숫자를 계산하기 시작했습니다. 이중 밀도 디스크가 (300rpm) 회전한 속도와 데이터가 저장되는 방식(80트랙, 트랙당 11섹터, 섹터당 512바이트, MFM을 사용하여 인코딩됨)을 기반으로 데이터를 정확하게 읽을 수 있어야 했습니다. 500Khz에서 데이터를 샘플링합니다. Arduino가 16Mhz에서만 실행되는 것을 고려하면 상당히 빠릅니다.

    다음 시도에서 나는 Arduino 측면에 대해서만 이야기하고 있습니다. 디코딩으로 이동합니다.

    시도 1:

    먼저 하드웨어와 플로피 드라이브에 대한 인터페이스를 수집해야 했습니다. 직장에 있는 오래된 PC에서 플로피 드라이브를 가져와서 동시에 IDE 케이블을 움켜쥐었습니다.

    아래는 해방된의 사진입니다. 구형 PC의 플로피 드라이브:

    드라이브의 핀 배치를 연구하면서 몇 개의 전선만 필요하다는 것을 깨달았고 드라이브를 살펴본 후 12v 입력도 사용하지 않는다는 것을 깨달았습니다.

    드라이브를 선택하고 모터를 활성화하여 드라이브 회전을 달성했습니다. 머리를 움직이는 것은 간단했습니다. /DIR을 설정했습니다. 핀 하이 또는 로우, 펄스 /STEP 핀. /TRK00을 모니터링하여 헤드가 트랙 0(첫 번째 트랙)에 도달했는지 알 수 있습니다. 핀.

    /INDEX에 대해 궁금했습니다. 핀. 이것은 회전할 때마다 한 번씩 펄스합니다. Amiga는 트랙의 시작 부분을 찾기 위해 이것을 사용하지 않기 때문에 나는 그것을 필요로 하지 않았고 그것을 무시할 수 있었습니다. 그 다음에는 읽을 디스크의 면(/SIDE1 ) 및 연결 /RDATA .

    높은 데이터 속도 요구 사항으로 인해 내 첫 번째 생각은 이 속도에 대한 요구 사항을 줄임으로써 문제를 덜 수 있는 방법을 찾는 것이었습니다.

    계획은 2개의 8비트 시프트 레지스터(SN74HC594N ) 필요한 샘플링 주파수를 8배로 줄이려면 Ebay에서 Pro Mini atmega328 Board 5V 16M Arduino Compatible Nano라고 부르는 것을 사용했습니다. (그래서 그것이 공식적으로 무엇인지 모르지만 이것은 Uno에서 작동합니다!) 이 병렬 버퍼링 직렬/USART 인터페이스를 사용하여 데이터를 PC로 보냅니다. 저는 이것이 500Kbaud보다 빠르게 실행되어야 한다는 것을 알고 있었습니다(모든 직렬 오버헤드도 포함됨).

    sn74hc594.pdf

    표준 Arduino 직렬 라이브러리를 버린 후 uptp 2M baud로 Arduino에서 USART를 구성할 수 있고 F2DI 브레이크아웃 보드 중 하나를 사용하여 정말 기뻤습니다(eBay에서는 FTDI FT232RL용 기본 브레이크아웃 보드라고 불렀습니다. Arduino용 USB-직렬 IC - 아래 참조) 이 속도로(62.5Khz) 데이터를 주고 받을 수 있지만 정확하게 해야 합니다.

    Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf

    Arduino 보드의 인터페이스에 완벽하게 맞는 FTDI 브레이크아웃 보드:

    먼저 Arduino를 사용하여 8비트 시프트 레지스터에서 8비트 클럭 중 하나만 높게 설정했습니다. 다른 하나는 플로피 드라이브에서 직접 피드를 받았습니다(따라서 직렬에서 병렬로 변환 제공).

    다음은 당시 내가 만든 브레드보드의 미친 사진입니다.

    나는 Arduinos 타이머 중 하나를 사용하여 출력 핀 중 하나에서 500Khz 신호를 생성했으며 하드웨어가 이것을 관리하므로 매우 정확합니다! - 어쨌든 제 멀티미터는 정확히 500khz로 측정했습니다.

    코드는 작동했고 62.5khz에서 전체 8비트 데이터를 클럭하여 Arduino CPU를 거의 활용하지 못했습니다. 그러나 나는 의미있는 것을받지 못했습니다. 이 시점에서 플로피 드라이브에서 나오는 실제 데이터를 자세히 살펴봐야 한다는 것을 깨달았습니다. 그래서 eBay에서 값싼 구형 오실로스코프(Gould OS300 20Mhz 오실로스코프)를 구입하여 무슨 일이 일어나고 있는지 확인했습니다.

    오실로스코프가 도착하기를 기다리는 동안 다른 것을 시도해 보기로 했습니다.

    시프트 레지스터에서 데이터를 읽는 데 사용되는 코드 조각:

    무효 readTrackData() { 바이트 연산; for (int a=0; a<5632; a++) { // "바이트" 시작 마커를 기다립니다. while (digitalRead(PIN_BYTE_READ_SIGNAL)==LOW) {}; // 바이트 읽기 op=0; if (digitalRead(DATA_LOWER_NIBBLE_PB0)==HIGH) op|=1; if (digitalRead(DATA_LOWER_NIBBLE_PB1)==HIGH) op|=2; if (digitalRead(DATA_LOWER_NIBBLE_PB2)==HIGH) op|=4; if (digitalRead(DATA_LOWER_NIBBLE_PB3)==HIGH) op|=8; if (digitalRead(DATA_UPPER_NIBBLE_A0)==HIGH) op|=16; if (digitalRead(DATA_UPPER_NIBBLE_A1)==HIGH) op|=32; if (digitalRead(DATA_UPPER_NIBBLE_A2)==HIGH) 연산|=64; if (digitalRead(DATA_UPPER_NIBBLE_A3)==HIGH) 연산|=128; writeByteToUART(op); // 하이가 다시 떨어질 때까지 기다립니다. while (digitalRead(PIN_BYTE_READ_SIGNAL)==HIGH) {}; }} 

    시도 2:

    좋은 아이디어가 도움이 되지 않았지만 시프트 레지스터로 결정했습니다. 한 번에 8비트를 쉽게 읽을 수 있었지만 처음에는 모든 비트가 올바르게 클럭된 것인지 확신할 수 없었습니다. 문서를 읽으면 데이터가 높고 낮음보다는 짧은 펄스에 가깝다는 것을 알 수 있습니다.

    시프트 레지스터를 제거하고 이전에 설정한 500Khz 신호를 사용하여 인터럽트(ISR)에서 드라이브의 펄스를 확인하려고 하면 어떻게 되는지 궁금했습니다. ISR을 생성하도록 아두이노를 재구성했고, 아두이노 라이브러리가 방해가 되는 문제를 통과한 후(내가 원하는 ISR을 사용하여) 타이머 2로 옮겼습니다.

    나는 전역 단일 바이트를 왼쪽으로 1비트 이동한 다음 플로피 드라이브 데이터 라인에 연결된 핀이 LOW이면 짧은 ISR을 작성했습니다. (펄스가 낮아짐) OR 1을 추가하겠습니다. 이 작업을 8번 할 때마다 완성된 바이트를 USART에 썼습니다.

    이것은 예상대로 진행되지 않았습니다! Arduino는 매우 불규칙하고 이상하게 동작하기 시작했습니다. 나는 곧 ISR이 호출 사이의 시간보다 실행하는 데 더 많은 시간이 걸린다는 것을 깨달았습니다. 나는 Arduino의 속도를 기반으로 2µSec마다 펄스를 수신할 수 있으며 모든 C 명령1 시계 기계 코드 주기로 변환 나는 최대 32개의 명령을 가질 수 있다는 것을 깨달았다. 슬프게도 대부분은 하나 이상의 명령이었고 인터넷 검색 후에 ISR 시작에 대한 오버헤드가 어쨌든 방대하다는 것을 깨달았습니다. digitalRead 기능이 매우 느리다는 것은 말할 것도 없습니다.

    나는 digitalRead를 버렸다 포트 핀에 직접 액세스하기 위한 기능! 이것은 여전히 ​​도움이되지 않았고 충분히 빠르지 않았습니다. 포기할 준비가 되지 않았기 때문에 이 접근 방식을 보류하고 다른 방법을 시도해 보기로 했습니다.

    이 시점에서 내가 구매한 오실로스코프가 도착했고 작동했습니다! 나보다 나이가 많을 것 같은 딱딱하고 오래된 오실로스코프! 그러나 여전히 완벽하게 작업을 수행했습니다. (오실로스코프가 무엇인지 모르는 경우 EEVblog #926 - Introduction To The Oscilloscope를 확인하고 전자공학에 관심이 있다면 몇 가지를 더 보고 EEVBlog 웹사이트를 둘러보는 것이 좋습니다.

    새로 구입한 딱딱한 구형 오실로스코프(Gould OS300 20Mhz):

    500Khz 신호를 한 채널에 연결하고 플로피 드라이브의 출력을 다른 채널에 연결한 후 뭔가 잘못되었다는 것이 분명했습니다. 500Khz 신호는 그것을 트리거로 사용하는 완벽한 구형파였으며 플로피 데이터가 도처에있었습니다. 펄스는 볼 수 있었지만 더 흐릿했습니다. 마찬가지로 플로피 드라이브 신호에서 트리거하면 500Khz 신호 구형파 신호가 여기저기에 있고 동기화되지 않았습니다.

    두 채널에서 트리거되는 오실로스코프의 트레이스 사진. 잘 보이지 않지만 채널에서는 그렇지 않습니다. 트리거되는 수천 개의 희미한 유령선:

    개별적으로 500Khz에서 두 신호의 펄스를 측정할 수 있었습니다. 이는 마치 두 신호가 같은 속도로 실행되고 있지만 트리거되지 않으므로 두 신호를 제대로 볼 수 있는 것처럼 이해가 되지 않는 것이므로 문제가 있는 것입니다.

    방아쇠 수준으로 많은 플레이를 한 후에 나는 무슨 일이 일어나고 있는지 알아낼 수 있었습니다. 내 신호는 완벽한 500Khz였지만 플로피 드라이브 신호를 보면 간격이 올바르게 지정되었지만 항상 그런 것은 아닙니다. 펄스 그룹 사이에 오류 드리프트가 있었고 신호를 완전히 동기화하지 못하게 하는 데이터 간격도 있었습니다.

    이전 연구를 기억하면 드라이브는 300rpm으로 회전해야 했지만 실제로는 정확히 300rpm이 아닐 수도 있고 데이터를 쓴 드라이브도 정확히 300rpm이 아닐 수도 있습니다. 그런 다음 섹터와 섹터 갭 사이의 간격이 있습니다. 분명히 동기화 문제가 있었고 읽기 시작 시 500Khz 신호를 플로피 드라이브에 동기화해도 작동하지 않았습니다.

    또한 풀업 저항을 변경하여 수정할 수 있지만 플로피 드라이브의 펄스가 매우 짧다는 것을 발견했으며 타이밍이 정확하지 않으면 Arduino가 펄스를 모두 놓칠 수 있습니다.

    대학교(University of Leicester)에 다닐 때 임베디드 시스템이라는 모듈을 수강했습니다. 우리는 Atmel 8051 마이크로컨트롤러를 연구했습니다. 프로젝트 중 하나는 시뮬레이션된 기상 관측소(로터리 엔코더)에서 펄스를 계산하는 것이었습니다. 그 당시에는 핀을 일정한 간격으로 샘플링했지만 정확하지 않았습니다.

    모듈 강사, Prof Pont 하드웨어 카운터를 사용해야 한다고 제안했습니다. 장치의 기능(한 번은 있는지조차 몰랐습니다.)

    ATMega328의 데이터시트를 확인했고 세 개의 타이머 각각이 외부 입력에서 트리거된 펄스를 계산하도록 구성할 수 있는지 확인했습니다. 이것은 속도가 더 이상 문제가 되지 않는다는 것을 의미했습니다. 내가 실제로 알아야 할 것은 펄스가 2µSec 시간 창 내에 발생했는지 여부였습니다.

    시도 3:

    첫 번째 펄스가 감지되었을 때 500khz 타이머를 재설정하도록 Arduino 스케치를 조정하고 500khz 타이머가 오버플로된 시간을 다시 설정하여 펄스가 감지되었는지 확인하기 위해 카운터 값을 확인했습니다. 그런 다음 동일한 비트 시프팅 시퀀스를 수행하고 8비트마다 USART에 1바이트를 기록했습니다.

    데이터가 들어오고 PC에서 분석하기 시작했습니다. 데이터에서 유효한 데이터처럼 보이는 것이 무엇인지 보기 시작했습니다. 이상한 동기화 단어 또는 0xAAAA 시퀀스 그룹이 나타나지만 신뢰할 수 있는 것은 없습니다. 내가 뭔가를 하고 있다는 것을 알았지만 여전히 뭔가를 놓치고 있었습니다.

    시도 4:

    데이터를 읽을 때 드라이브의 데이터가 500khz 신호와 동기화/위상을 벗어날 수 있다는 것을 깨달았습니다. 읽기 시작할 때마다 20바이트만 읽어서 이를 확인했습니다.

    이 동기화 문제를 처리하는 방법에 대해 읽으면서 Phase Locked Loop 또는 PLL이라는 문구를 우연히 발견했습니다. 아주 간단한 용어로, 우리가 하고 있는 일에 대해 위상 고정 루프는 클럭 주파수(500khz)를 동적으로 조정하여 신호의 주파수 드리프트와 변동을 보상합니다.

    타이머의 해상도가 충분히 높지 않아서(예:444khz, 470khz, 500khz, 533khz, 571khz 등) 이를 적절히 수행하려면 훨씬 더 빠르게 실행하는 코드가 필요할 것입니다.

    Arduino 타이머는 미리 정의된 수(이 경우 500khz의 경우 16)까지 계산하여 작동합니다. ) 그런 다음 오버플로 레지스터를 설정하고 0부터 다시 시작합니다. 실제 카운터 값은 언제든지 읽고 쓸 수 있습니다.

    타이머가 오버플로 될 때까지 루프에서 기다리도록 스케치를 조정하고 오버플로되면 이전과 같이 펄스를 확인했습니다. 이번에는 언제 루프 내에서 펄스가 감지되면 타이머 카운터 값을 미리 정의된 위상으로 재설정합니다. 각 펄스와 타이머를 효과적으로 재동기화합니다.

    나는 타이머 카운터에 쓴 값을 선택하여 감지 펄스(절반)에서 1µSec에서 오버플로하여 다음에 타이머가 오버플로될 때 펄스가 2µSec 간격이 되도록 선택했습니다.

    이것은 효과가 있었다! 나는 이제 디스크에서 거의 완벽한 데이터를 읽고 있었습니다. 여전히 성가신 체크섬 오류가 많이 발생했습니다. 유효한 헤더 및 데이터 체크섬이 있는 11개 섹터를 모두 가질 때까지 드라이브에서 동일한 트랙을 계속해서 다시 읽어 대부분의 문제를 해결했습니다.

    이 시점에서 궁금해서 모든 것을 다시 오실로스코프에 연결하여 지금 무슨 일이 일어나고 있는지 확인했습니다. 그리고 추측한 대로 두 트레이스가 서로 동기화 상태를 유지하고 있었기 때문에 이제 두 트레이스를 볼 수 있었습니다.

    누군가 저에게 최고의 디지털 오실로스코프(예:키사이트 오실로스코프 중 하나)를 기증하고 싶다면 이 내용을 좀 더 명확하게 보고 싶습니다. 정말 감사합니다!

    시도 5:

    이 부분을 개선할 수 있는지 궁금합니다. 코드, 특히 내부 읽기 루프(아래 참조)를 살펴보면 오버플로를 기다리는 동안 루프가 있었고 내부 if 동기화할 펄스를 찾고 있습니다.

    데이터를 읽고 동기화하는 데 사용되는 코드 조각:

    register bool done =false;// 500khz 오버플로 기다림 while (!(TIFR2&_BV(TOV2))) { // 500khz 펄스를 기다리는 동안 하강 에지가 감지되었습니다. if ((TCNT0) &&(!done)) { // 펄스 감지, 펄스와 동기화하도록 타이머 카운터를 재설정 TCNT2=phase; // 펄스가 다시 하이가 될 때까지 기다립니다. while (!(PIN_RAW_FLOPPYDATA_PORT &PIN_RAW_FLOPPYDATA_MASK)) {}; 완료 =사실; }}// 오버플로 플래그 재설정TIFR2|=_BV(TOV2); // 드라이브에서 펄스를 감지했습니까?if (TCNT0) { DataOutputByte|=1; TCNT0=0;} 

    위의 루프에서 어떤 명령어가 실행되었는지에 따라 펄스 감지와 쓰기 사이의 시간이 TCNT2=phase;라는 것을 깨달았습니다. 몇 가지 명령을 실행하는 데 걸리는 시간에 따라 변경될 수 있습니다.

    이것이 데이터에 약간의 오류/지터를 일으킬 수 있고 또한 위의 루프를 사용하면 실제로 드라이브에서 펄스를 놓칠 수 있다는 것을 깨닫고(따라서 재동기화 비트가 누락됨) 이전 시도, ISR(인터럽트).

    데이터 펄스를 Arduino의 두 번째 핀에 연결했습니다. 데이터는 이제 COUNTER0 트리거와 INT0 핀에 연결되었습니다. INT0은 가장 높은 인터럽트 우선순위 중 하나이므로 트리거와 호출되는 ISR 사이의 지연을 최소화해야 하며 이것이 내가 실제로 관심이 있는 유일한 인터럽트이므로 다른 모든 인터럽트는 비활성화됩니다.

    필요한 모든 인터럽트는 위의 재동기화 코드를 수행하는 것이었습니다. 이것은 코드를 다음과 같이 변경했습니다.

    // 500khz 오버플로 대기 while (!(TIFR2&_BV(TOV2))) {} // 오버플로 플래그 재설정TIFR2|=_BV(TOV2); // 드라이브에서 펄스를 감지했습니까?if (TCNT0) { DataOutputByte|=1; TCNT0=0;} 

    ISR은 다음과 같았습니다. (호출에 오버헤드가 추가되기 때문에 나는 attachInterrupt를 사용하지 않았습니다.)

    휘발성 바이트 targetPhase;ISR(INT0_vect) { TCNT2=targetPhase;} 

    이것을 컴파일하면 충분히 빠르게 실행하기에는 너무 많은 코드가 생성됩니다. 실제로 위를 분해하면 다음과 같이 생성됩니다.

    push r1push r0in r0, 0x3f; 63push r0eor r1, r1push r24 lds r24, 0x0102; 0x800102 sts 0x00B2, r24; 0x8000b2 팝 r24pop r0out 0x3f, r0; 63pop r0pop r1reti 

    코드를 분석하면서 실제로 필요한 지침이 몇 개 밖에 없다는 것을 깨달았습니다. 컴파일러가 내가 bash한 레지스터를 추적할 것이라는 점에 주목하여 ISR을 다음과 같이 변경했습니다.

     휘발성 바이트 targetPhase asm("targetPhase");ISR(INT0_vect) { asm volatile("lds __tmp_reg__, targetPhase"); asm 휘발성("sts %0, __tmp_reg__" ::"M"(_SFR_MEM_ADDR(TCNT2)));} 

    분해하여 다음 지침을 생성했습니다.

    push r1push r0in r0, 0x3f; 63push r0eor r1, r1lds r0, 0x0102; 0x800102 sts 0x00B2, r0; 0x8000b2 팝 r0out 0x3f, r0; 63pop r0pop r1reti 

    여전히 너무 많은 지시. 컴파일러가 많은 추가 지침을 추가하고 있다는 것을 알았습니다. 내 응용 프로그램에는 실제로 그럴 필요가 없었습니다. 그래서 ISR() 두 번째 매개변수 ISR_NAKED를 우연히 발견했습니다. 이것을 추가하면 컴파일러가 특수 코드를 추가하는 것을 방지할 수 있지만 레지스터, 스택을 유지 관리하고 인터럽트에서 올바르게 반환해야 합니다. 또한 SREG 레지스터를 유지 관리해야 하지만 호출해야 하는 명령이 수정되지 않았기 때문에 이에 대해 걱정할 필요가 없었습니다.

    이로 인해 ISR 코드가 다음과 같이 변경되었습니다.

    ISR(INT0_vect, ISR_NAKED) { asm volatile("푸시 __tmp_reg__"); // tmp_register 유지 asm volatile("lds __tmp_reg__, targetPhase"); // 위상 값을 tmp_register에 복사 asm volatile("sts %0, __tmp_reg__" ::"M" (_SFR_MEM_ADDR(TCNT2))); // tmp_register를 TCNT2가 있는 메모리 위치에 복사 asm volatile("pop __tmp_reg__"); // tmp_register를 복원합니다. asm volatile("reti"); // 그리고 ISR 종료} 

    컴파일러가 다음으로 변환한 항목:

    push r0lds r0, 0x0102; 0x800102 sts 0x00B2, r0; 0x8000b2 팝 r0reti 

    다섯 가지 지침! 이론상 실행하는 데 0.3125µSec가 소요되는 완벽하거나 최소한 가능한 빠른 속도입니다! 이것은 이제 펄스 후 시간이 일정한 기간에 재동기화가 발생해야 함을 의미합니다. 아래는 무슨 일이 일어나고 있는지에 대한 타이밍 다이어그램입니다. 다음은 클럭 신호가 없는 직렬 데이터 피드에서 데이터를 복구하는 방법입니다.

    이것은 결과를 약간 향상시켰습니다. 아직 완벽하지 않습니다. 어떤 디스크는 매번 완벽하게 읽고, 어떤 디스크는 시간이 오래 걸리고 계속 재시도해야 합니다. 디스크 중 일부가 너무 오랫동안 거기에 앉아 있어서 자기력이 드라이브 앰프가 감당할 수 없을 정도로 낮은 수준으로 저하되었기 때문인지 확실하지 않습니다. PC의 플로피 디스크 드라이브와 관련이 있는 것인지 궁금하여 가지고 있는 외부 Amiga 플로피 디스크 드라이브에 연결했지만 결과는 동일했습니다.

    시도 6:

    할 수 있는 다른 일이 있는지 궁금했습니다. 아마도 드라이브의 신호가 내가 생각했던 것보다 더 시끄러웠을 것입니다. 추가 정보를 읽은 후 슈미트 트리거에 공급되는 1Kohm 풀업 저항이 표준이라는 것을 발견했습니다.

    SN74HCT14N Hex Schmitt Trigger를 설치하고 하강 에지 대신 상승 에지에서 트리거하도록 스케치를 재구성한 후 시도해 보았지만 실제로 눈에 띄는 차이는 없었습니다. 아마도 흡수할 때마다 하나 이상의 펄스를 찾고 있었던 것 같습니다. 어쨌든 소음. 그래서 우리는 방법 5번을 고수할 것입니다!

    sn74hct14.pdf

    내 최종 브레드보드 솔루션은 다음과 같습니다.

    위의 배선은 라이브 스케치와 약간 다릅니다. 회로도를 쉽게 만들기 위해 Arduino 핀 중 일부를 다시 주문했습니다.

    시도 7:

    읽지 않은 디스크 중 일부에 대해서는 약간 불만족스러웠습니다. 때때로 디스크가 플로피 드라이브에 제대로 들어가지 않았습니다. 셔터의 스프링이 도움이 되지 않았나 봅니다.

    디스크에서 실제 수신된 MFM 데이터에 오류가 있는지 감지하기 시작했습니다.

    MFM 인코딩이 작동하는 방식에 대한 규칙에서 다음과 같이 몇 가지 간단한 규칙을 적용할 수 있음을 깨달았습니다.

    <울>
  • 서로 '1' 비트가 두 개 있을 수 없습니다.
  • <울>
  • 서로 '0' 비트가 세 개 이상 있을 수 없습니다.
  • 먼저 MFM 데이터를 디코딩할 때 두 개의 '1'이 연속적으로 있는지 확인했습니다. 만약 그렇다면 데이터가 시간이 지남에 따라 약간 흐려졌다고 가정하고 두 번째 '1'을 무시했습니다.

    이 규칙을 적용하면 문자 그대로 오류가 발생하도록 남겨진 5비트의 세 가지 상황이 있습니다. 이것은 내가 데이터를 개선할 수 있는 새로운 영역이 될 것입니다.

    하지만 대부분 MFM 오류가 감지되지 않았다는 사실에 놀랐습니다. 오류가 발견되지 않으면 일부 디스크가 읽지 않는 이유가 약간 혼란스럽습니다.

    이것은 추가 조사가 필요한 영역입니다.

    디코딩

    MFM이 작동하는 방식을 읽은 후 어떻게 올바르게 정렬되었는지 완전히 확신할 수 없었습니다.

    처음에는 드라이브가 켜기 및 끄기 비트에 대해 1과 0을 출력한다고 생각했습니다. 이것은 사실이 아닙니다. 드라이브는 모든 위상 전환, 즉 데이터가 0에서 1로, 또는 1에서 0으로 바뀔 때마다 펄스를 출력합니다.

    이것을 읽은 후 플립플롭 토글에 입력하여 이것을 다시 1과 0으로 변환해야 하는지, 아니면 데이터를 읽고 섹터를 검색해야 하는지, 그리고 아무 것도 발견되지 않으면 데이터를 반전하고 다시 시도해야 하는지 궁금했습니다!

    이것은 사실이 아니며 훨씬 간단합니다. 펄스는 실제로 RAW MFM 데이터이며 디코딩 알고리즘에 직접 입력할 수 있습니다. 이제 나는 이것을 이해하고 드라이브에서 버퍼를 스캔하고 동기화 단어 0x4489를 검색하는 코드를 작성하기 시작했습니다. 놀랍게도 찾았습니다!

    내가 수행한 연구에서 0xAAAAAAAAA44894489를 실제로 검색해야 한다는 것을 깨달았습니다. (연구의 메모는 또한 위의 시퀀스를 찾을 수 없다는 것을 의미하는 초기 Amiga 코드에 몇 가지 버그가 있다고 제안했습니다. 그래서 대신 0x2AAAAAAA44894489를 검색했습니다. 0x7FFFFFFFFFFFFFF으로 데이터를 AND한 후 ).

    예상대로 11 Amiga 섹터의 실제 시작에 해당하는 각 트랙에서 최대 11개를 찾았습니다. 그런 다음 섹터 정보를 디코딩할 수 있는지 확인하기 위해 뒤따르는 바이트를 읽기 시작했습니다.

    MFM 디코딩을 돕기 위해 위의 참조 중 하나에서 코드의 일부를 가져왔습니다. 바퀴를 재발명해도 소용이 없겠죠?

    헤더와 데이터를 읽은 후 디스크에 ADF 파일로 쓰기를 시도했습니다. 표준 ADF 파일 형식은 매우 간단합니다. 문자 그대로 각 섹터(디스크의 양쪽에서)의 512바이트만 순서대로 기록됩니다. 그것을 작성하고 ADFOpus로 열려고 시도한 후 혼합된 결과를 얻었고 때로는 파일을 열었고 때로는 실패했습니다. 데이터에 분명히 오류가 있었습니다. 헤더의 체크섬 필드를 보기 시작하여 유효하지 않은 체크섬이 있는 섹터를 거부하고 11개의 유효한 체크섬이 있을 때까지 읽기를 반복했습니다.

    일부 디스크의 경우 첫 번째 읽기에서 모두 11개였으며 일부는 여러 번 시도했지만 다른 위상 값도 있었습니다.

    마침내 나는 유효한 ADF 파일을 쓸 수 있었습니다. 어떤 디스크는 오랜 시간이 걸리고 어떤 디스크는 말 그대로 Amiga가 읽을 수 있는 속도였습니다. Amiga가 더 이상 작동하지 않아 이 디스크가 제대로 읽히는지 실제로 확인할 수 없었습니다. 다락방의 상자에 몇 년 동안 보관되어 있었기 때문에 성능이 저하되었을 수 있습니다.

    다음은 무엇입니까?

    다음은 이미 발생했습니다 - V2는 여기에서 사용할 수 있습니다. 읽기 및 쓰기 지원이 향상되었습니다!

    음, 첫째, GNU General Public License V3에 따라 전체 프로젝트를 무료로 오픈 소스로 만들었습니다. 우리가 Amiga를 보존할 수 있는 희망을 갖고 싶다면 특권을 위해 서로를 찢지 않아야 하며, 게다가 내가 일한 최고의 플랫폼에 되돌려주고 싶습니다. 또한 사람들이 이것을 개발하고 더 발전시켜 계속 공유하기를 바랍니다.

    다음에는 다른 형식을 살펴보고 싶습니다. ADF 파일은 좋지만 AmigaDOS 형식의 디스크에서만 작동합니다. 사용자 정의 복사 방지 및 이 형식에서 단순히 지원할 수 없는 비표준 섹터 형식이 있는 타이틀이 많이 있습니다.

    Wikipedia에 따르면 또 다른 디스크 파일 형식인 FDI 형식이 있습니다. 문서화되어 있는 보편적인 형식입니다. 이 형식의 장점은 트랙 데이터를 가능한 한 원본에 가깝게 저장하려고 하므로 위의 문제가 해결되기를 바랍니다!

    나는 또한 소프트웨어 보존 협회, 특히 CAPS(공식적으로는 클래식 아미가 보존 협회 ) 및 IPF 형식입니다. 약간의 독서 후에 나는 매우 실망했고 모든 것이 닫혀 있었고 디스크 판독 하드웨어를 판매하기 위해 이 형식을 사용하는 것처럼 느껴졌습니다.

    그래서 내 초점은 FDI에있을 것입니다! 체재. 여기서 나의 유일한 관심사는 데이터 무결성입니다. 읽기가 유효한지 확인하기 위해 확인할 체크섬은 없지만 이를 해결할 몇 가지 아이디어가 있습니다!

    그리고 마지막으로 디스크 쓰기 옵션(FDI 및 ADF 지원 가능)을 추가하는 방법도 살펴보겠습니다. 추가하기가 그렇게 어렵지 않아야 하기 때문입니다.

    <섹션 클래스="섹션 컨테이너 섹션 축소 가능" id="코드">

    코드

    GitHub 저장소
    Arduino 스케치 및 Windows 소스 코드https://github.com/RobSmithDev/ArduinoFloppyDiskReader

    회로도


    제조공정

    1. 애니메이션
    2. 플로피 디스크
    3. Arduino 스파이봇
    4. FlickMote
    5. 수제 TV B-Gone
    6. 마스터 시계
    7. 나를 찾기
    8. Arduino Power
    9. Tech-TicTacToe
    10. Arduino Amiga 플로피 디스크 리더(V1)