Skip to content

Commit fd236c6

Browse files
kollokolloMarkus Hoffmann
authored andcommitted
Improvements to read also HD Disks (1.4 MBytes).
1 parent 2ba438a commit fd236c6

File tree

1 file changed

+207
-8
lines changed

1 file changed

+207
-8
lines changed

FloppyDriveController.sketch/FloppyDriveController.sketch.ino

Lines changed: 207 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,19 @@
7878

7979

8080

81-
// Paula on the Amiga used to find the SYNC WORDS and then read 0x1900 further WORDS. A dos track is 11968 bytes in size, theritical revolution is 12800 bytes.
82-
#define RAW_TRACKDATA_LENGTH (0x1900*2+0x440) // Paula assumed it was 12868 bytes, so we read that, plus thre size of a sectors
81+
// Paula on the Amiga used to find the SYNC WORDS and then read 0x1900 further WORDS.
82+
// A dos track is 11968 bytes in size, theritical revolution is 12800 bytes.
83+
/* The ATARI ST could format a track with up to 11 Sectors, so the AMIGA settings are OK. */
84+
#define RAW_TRACKDATA_LENGTH (0x1900*2+0x440) // Paula assumed it was 12868 bytes, so we read that, plus the size of a sector, to find overlap
8385

84-
// The current track that the head is over
86+
/* For the HD (1.4 MBytes) Disks the amount of data should be about 26688: */
87+
#define RAW_HD_TRACKDATA_LENGTH (0x1900*2*2+0x440)
88+
89+
90+
/* The current track that the head is over
91+
(at the beginning this would be unknown and so a
92+
seek to Track0 should be done first.
93+
*/
8594
int currentTrack = 0;
8695

8796
// If the drive has been switched on or not
@@ -91,6 +100,9 @@ bool driveEnabled = 0;
91100
bool inWriteMode = 0;
92101

93102

103+
/* Where there should be a HD Disk been read (1) or a DD and SD Disk (0).*/
104+
105+
bool disktypeHD = 0;
94106

95107

96108

@@ -112,6 +124,13 @@ void stepDirectionHead() {
112124
smalldelay(5);
113125
digitalWrite(PIN_MOTOR_STEP,HIGH);
114126
}
127+
// Step the head once. Do it a bit faster...
128+
void stepDirectionHead_fast() {
129+
smalldelay(4);
130+
digitalWrite(PIN_MOTOR_STEP,LOW);
131+
smalldelay(3);
132+
digitalWrite(PIN_MOTOR_STEP,HIGH);
133+
}
115134

116135
// Prepare serial port - We dont want to use the arduino serial library as we want to use faster speeds and no serial interrupts
117136
void prepSerialInterface() {
@@ -276,7 +295,7 @@ bool goToTrack0() {
276295
digitalWrite(PIN_MOTOR_DIR,MOTOR_TRACK_DECREASE); // Set the direction to go backwards
277296
int counter=0;
278297
while (digitalRead(PIN_DETECT_TRACK_0) != LOW) {
279-
stepDirectionHead(); // Keep moving the head until we see the TRACK 0 detection pin
298+
stepDirectionHead_fast(); // Keep moving the head until we see the TRACK 0 detection pin
280299
counter++;
281300
// If this happens we;ve steps twice as many as needed and still havent found track 0
282301
if (counter>170) {
@@ -288,7 +307,7 @@ bool goToTrack0() {
288307
return true;
289308
}
290309

291-
// Goto a specific track. During testing it was easier for the track number to be supplied as two ASCII characters, so I left it like this
310+
// Goto to a specific track. During testing it was easier for the track number to be supplied as two ASCII characters, so I left it like this
292311
bool gotoTrackX() {
293312
// Read the bytes
294313
byte track1 = readByteFromUART();
@@ -562,7 +581,167 @@ void readTrackDataFast() {
562581
TCCR2B = 0; // No Clock (turn off)
563582
}
564583

584+
// Read the track for a HD disk
585+
void readTrackDataFast_HD() {
586+
// Configure timer 2 just as a counter in NORMAL mode
587+
TCCR2A = 0 ; // No physical output port pins and normal operation
588+
TCCR2B = bit(CS20); // Precale = 1
589+
590+
// First wait for the serial port to be available
591+
while(!(UCSR0A & (1<<UDRE0)));
592+
593+
// Signal we're active
594+
digitalWrite(PIN_ACTIVITY_LED,HIGH);
595+
596+
// Force data to be stored in a register
597+
register unsigned char DataOutputByte = 0;
598+
599+
// While the INDEX pin is high wait if the other end requires us to
600+
if (readByteFromUART())
601+
while (PIN_INDEX_PORT & PIN_INDEX_MASK) {};
602+
603+
// Prepare the two counter values as follows:
604+
TCNT2=0; // Reset the counter
605+
606+
register unsigned char counter;
607+
long totalBits=0;
608+
long target = ((long)RAW_HD_TRACKDATA_LENGTH)*(long)8;
609+
610+
while (totalBits<target) {
611+
for (register unsigned char bits=0; bits<4; bits++) {
612+
// Wait while pin is high
613+
614+
while (PIN_READ_DATA_PORT & PIN_READ_DATA_MASK) {};
615+
counter = TCNT2, TCNT2 = 0; // reset - must be done with a COMMA
616+
617+
DataOutputByte<<=2;
618+
619+
// DO NOT USE BRACES HERE, use the "," or the optomiser messes it up
620+
if (counter<40) DataOutputByte|=B00000001,totalBits+=2; else // this accounts for just a '1' or a '01' as two '1' arent allowed in a row
621+
if (counter>55) DataOutputByte|=B00000011,totalBits+=4; else DataOutputByte|=B00000010,totalBits+=3;
622+
623+
// Wait until pin is high again
624+
while (!(PIN_READ_DATA_PORT & PIN_READ_DATA_MASK)) {};
625+
}
626+
UDR0 = DataOutputByte;
627+
}
628+
// Because of the above rules the actual valid two-bit sequences output are 01, 10 and 11, so we use 00 to say "END OF DATA"
629+
writeByteToUART(0);
565630

631+
// turn off the status LED
632+
digitalWrite(PIN_ACTIVITY_LED,LOW);
633+
634+
// Disable the counter
635+
TCCR2B = 0; // No Clock (turn off)
636+
}
637+
638+
static char *i2a(unsigned int i, char *a, unsigned r) {
639+
if(i/r>0) a=i2a(i/r,a,r);
640+
*a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$!?"[i % r];
641+
return a+1;
642+
}
643+
644+
/* Make a statistics of the data seen on a track to determine the density of the media */
645+
646+
void measureTrackData() {
647+
/* for the statistics */
648+
int t1=0;
649+
int t2=0;
650+
int t3=0;
651+
int t4=0;
652+
int t5=0;
653+
int t6=0;
654+
// Configure timer 2 just as a counter in NORMAL mode
655+
TCCR2A = 0 ; // No physical output port pins and normal operation
656+
TCCR2B = bit(CS20); // Precale = 1
657+
658+
// Signal we're active
659+
digitalWrite(PIN_ACTIVITY_LED,HIGH);
660+
661+
// Force data to be stored in a register
662+
register unsigned char DataOutputByte = 0;
663+
664+
// While the INDEX pin is high wait
665+
while (PIN_INDEX_PORT & PIN_INDEX_MASK) {};
666+
667+
// Prepare the two counter values as follows:
668+
TCNT2=0; // Reset the counter
669+
670+
register unsigned char counter;
671+
long totalBits=0;
672+
long target = ((long)RAW_TRACKDATA_LENGTH)*(long)8;
673+
674+
while (totalBits<target) {
675+
for (register unsigned char bits=0; bits<4; bits++) {
676+
// Wait while pin is high
677+
678+
while (PIN_READ_DATA_PORT & PIN_READ_DATA_MASK) {};
679+
counter = TCNT2, TCNT2 = 0; // reset - must be done with a COMMA
680+
681+
DataOutputByte<<=2;
682+
683+
// DO NOT USE BRACES HERE, use the "," or the optomiser messes it up
684+
685+
if (counter<40) t1++;
686+
else if (counter<55) t2++;
687+
else t3++;
688+
689+
if (counter<80) t4++;
690+
else if (counter<112) t5++;
691+
else t6++;
692+
693+
totalBits+=2;
694+
695+
// Wait until pin is high again
696+
while (!(PIN_READ_DATA_PORT & PIN_READ_DATA_MASK)) {};
697+
}
698+
}
699+
700+
// turn off the status LED
701+
digitalWrite(PIN_ACTIVITY_LED,LOW);
702+
703+
// Disable the counter
704+
TCCR2B = 0; // No Clock (turn off)
705+
706+
/* Now output the result: */
707+
char a[8];
708+
*i2a(t1,a,16)=0;
709+
writeByteToUART(a[0]);
710+
writeByteToUART(a[2]);
711+
writeByteToUART(a[3]);
712+
writeByteToUART(a[4]);
713+
writeByteToUART(10);
714+
*i2a(t2,a,16)=0;
715+
writeByteToUART(a[0]);
716+
writeByteToUART(a[2]);
717+
writeByteToUART(a[3]);
718+
writeByteToUART(a[4]);
719+
writeByteToUART(10);
720+
*i2a(t3,a,16)=0;
721+
writeByteToUART(a[0]);
722+
writeByteToUART(a[2]);
723+
writeByteToUART(a[3]);
724+
writeByteToUART(a[4]);
725+
writeByteToUART(10);
726+
*i2a(t4,a,16)=0;
727+
writeByteToUART(a[0]);
728+
writeByteToUART(a[2]);
729+
writeByteToUART(a[3]);
730+
writeByteToUART(a[4]);
731+
writeByteToUART(10);
732+
*i2a(t5,a,16)=0;
733+
writeByteToUART(a[0]);
734+
writeByteToUART(a[2]);
735+
writeByteToUART(a[3]);
736+
writeByteToUART(a[4]);
737+
writeByteToUART(10);
738+
*i2a(t6,a,16)=0;
739+
writeByteToUART(a[0]);
740+
writeByteToUART(a[2]);
741+
writeByteToUART(a[3]);
742+
writeByteToUART(a[4]);
743+
writeByteToUART(10);
744+
}
566745

567746

568747
// The main command loop
@@ -580,7 +759,7 @@ void loop() {
580759
writeByteToUART('V'); // Followed
581760
writeByteToUART('1'); // By
582761
writeByteToUART('.'); // Version
583-
writeByteToUART('3'); // Number
762+
writeByteToUART('4'); // Number
584763
break;
585764

586765
// Command "." means go back to track 0
@@ -615,9 +794,11 @@ void loop() {
615794
break;
616795

617796
// Command "<" Read track from the drive
618-
case '<': if (!driveEnabled) writeByteToUART('0'); else {
797+
case '<': if(!driveEnabled) writeByteToUART('0');
798+
else {
619799
writeByteToUART('1');
620-
readTrackDataFast();
800+
if(disktypeHD) readTrackDataFast_HD();
801+
else readTrackDataFast();
621802
}
622803
break;
623804

@@ -636,6 +817,24 @@ void loop() {
636817
eraseTrack();
637818
}
638819
break;
820+
821+
// Command "H" Set HD disk type
822+
case 'H':
823+
disktypeHD=1;
824+
writeByteToUART('1');
825+
break;
826+
// Command "D" Set DD or SD disk type
827+
case 'D':
828+
disktypeHD=0;
829+
writeByteToUART('1');
830+
break;
831+
// Command "M" measure data timings
832+
case 'M': if(!driveEnabled) writeByteToUART('0');
833+
else {
834+
writeByteToUART('1');
835+
measureTrackData();
836+
}
837+
break;
639838

640839
// Turn off the drive motor
641840
case '-': digitalWrite(PIN_DRIVE_ENABLE_MOTOR,HIGH);

0 commit comments

Comments
 (0)