Chri O. Posted July 27, 2021 Share Posted July 27, 2021 (edited) I should mention this is (WIP) Work In Progress!!!! First of all this is based on the New Atari ST/E Mega ST/E hard disk interface & STM32 microcontroller ver.1 but ported to Teensy USB based microcontroller development system. So today (well I think it's night already) I did initial testing of my Teensy hard drive implementation with (MTP experimental) looks like I can drag and drop files from Windows 10 to Micro SD card Atari DOS & TOS compatible formatted but only on the 1st partition regardless of how many partitions you have on the Micro SD card (Drive C only) Anyways this looks promising for easy file transfer. Here is a list of issues I need to fix: 1. Handling 8.3 filename scheme: This one might be complicated or might not be I really need to watch what I copy to the MicroSD card. 2. Fix HDDRIVER by Uweseimet: Currently it works but only in 6 byte command mode I think this has something to do with the command 12 extended Inquiry ICD , Len 7 1F 12 0 0 0 10 0. Getting about 996 kilobytes per second as opposed to the (0xF1) ACSI/SCSI ICD host adapter 10 byte command mode, about 1346 kilobytes per second. By the way Petari's HD driver Works flawlessly @ about 1390 KB/s ACSI/SCSI ICD 10 byte command mode but not tested yet with DOS & TOS compatible formatted partitions. Okay it's getting late I need to get sleep but anyways: This will work on Win XP to Win 10 and @ least Linux Ubuntu, I am not sure about Mac OS because I think they drop support for Media Transfer Protocol a while ago. TODO: Upload some pictures tomorrow ? Edited July 27, 2021 by Chri O. 5 Quote Link to comment Share on other sites More sharing options...
ParanoidLittleMan Posted July 27, 2021 Share Posted July 27, 2021 Looks promising ? Few notes: It is usual that Windows sees only first partition on removable storage. Only latest revisions/updates of Win10 corrected this flaw, and see all partitions. But there are diverse fixes which make older Win versions too see all partitions. Like this one: http://atari.8bitchip.info/profb/cfadisk_x86_x64.zip Basic ACSI protocol uses old, 6 byte commands (SASI), where LBA is 21 bits only, and that's the reason for 1 GB limit. No capacity detect command too. Actually, commands are only 5 bits, since upper 3 bits hold ACSI target # . ICD extension allows usage of SCSI-1 type 10 byte commands, and 32 bit LBA. And of course commands are 8 bit. But which command set is used should not affect transfer speed - since it depends from DMA chip and adapter's speed when media is fast enough (and today SD cards are much faster than our oldie). And of course partition types affect speed not too. Adapter should work well with TTs too, since same DMA chip is used. Driver SW is what needs to support TT - CPU cache and Fast RAM handle. 1 Quote Link to comment Share on other sites More sharing options...
Chri O. Posted July 28, 2021 Author Share Posted July 28, 2021 19 hours ago, ParanoidLittleMan said: But which command set is used should not affect transfer speed - since it depends from DMA chip and adapter's speed when media is fast enough (and today SD cards are much faster than our oldie). I'm not sure what's going on with the old 6 byte command speed yet? I just did some MicroSD card speed testing on my Teensy 3.5 @ 168Mhz FILE_SIZE_MB = 50 BUF_SIZE = 512 bytes write speed and latency speed,max,min,avg KB/Sec,usec,usec,usec 18525.38,50086,26,27 18917.90,3028,26,26 read speed and latency speed,max,min,avg KB/Sec,usec,usec,usec 18719.58,251,27,27 18712.57,251,27,27 Thanks to SDIO Interface Bus on Teensy 3.5. Quote Link to comment Share on other sites More sharing options...
Chri O. Posted July 28, 2021 Author Share Posted July 28, 2021 I am pretty sure I'm doing something stupid here but anyways this is the main loop() {} // Main loop void loop() { blinkled(); mtpd.loop(); // Media Transfer Protocol (MTP) // old API deprecated. // waitCommand(); // Wait for the next command arriving in cmdBuf while (CommandBool == false) { return; } sincePrint = 0; noInterrupts(); // THIS->detachInterrupt(R_W); cmdLen = cmdLen_I; // COPY from CS_ IRQ cmdLen_I for (uint32_t i = 0; i < cmdLen; ++i) { cmdBuf[i] = cmdBuf_I[i]; } CommandBool = false; // RESET interrupts(); #if ACSI_VERBOSE acsiDbg("Len "); acsiDbg(cmdLen); acsiDbg(" Command "); for (uint32_t i = 0; i < cmdLen; ++i) { acsiDbg(' '); acsiDbg(cmdBuf[i], HEX); } acsiDbgln(""); #endif // code for SCSI(6) commands support // https://github.com/atarijookie/ce-atari/blob/master/ultrasatan/UltraSatan/scsi6.c // Command preprocessing uint8_t InquiryTemp = 0; // ALLOCATION LENGTH value // Execute the command switch (cmdBuf[0]) { default: // Unknown command acsiDbg("Unknown command "); for (uint32_t i = 0; i < cmdLen; ++i) { acsiDbg(' '); acsiDbg(cmdBuf[i], HEX); } acsiDbgln(""); //sd->lastSeek = false; // FIX FOR NOW ? sd.lastSeek = false; commandError(); break; case 0x00: // Test drive ready commandSuccess(); Serial.println("Test CMD 0x00 "); break; case 0x0D: // Correction case 0x15: // Mode select case 0x1B: // Skip // Always succeed sd.lastSeek = false; commandSuccess(); break; case 0x04: // Format drive case 0x05: // Verify track case 0x06: // Format track sd.lastSeek = false; commandSuccess(); break; case 0x03: // Request Sense /* Byte 0 |xxxxxxxx| |||||||| ||| -------- Operation Code ----------- Controller Number Byte 1 |xxxxxxxx| |||||||| |||--------- Block Address High ----------- Device Number Byte 2 |xxxxxxxx| |||||||| ----------- Block Address Mid Byte 3 |xxxxxxxx| |||||||| ----------- Block Address Low Byte 4 |xxxxxxxx| |||||||| ----------- Block Count Byte 5 |xxxxxxxx| |||||||| ----------- Control Byte */ // Fill the response with zero bytes for (int b = 0; b < cmdBuf[4]; ++b) { dataBuf[b] = 0; } if (cmdBuf[4] <= 4) { dataBuf[0] = sd.lastErr; // from here now on sd. if (sd.lastSeek) { dataBuf[0] |= 0x80; dataBuf[1] = (sd.lastBlock >> 16) & 0xFF; dataBuf[2] = (sd.lastBlock >> 8) & 0xFF; dataBuf[3] = (sd.lastBlock) & 0xFF; } Serial.println("0x03: // Request Sense Send the response test"); Serial.print("dataBuf[0] "), Serial.println(dataBuf[0]); Serial.print("dataBuf[1] "), Serial.println(dataBuf[1]); Serial.print("dataBuf[2] "), Serial.println(dataBuf[2]); Serial.print("dataBuf[3] "), Serial.println(dataBuf[3]); } else { // Build long response in dataBuf Serial.println("0x03: // Request Sense Build long response in dataBuf"); dataBuf[0] = 0x70; if (sd.lastSeek) { dataBuf[0] |= 0x80; dataBuf[4] = (sd.lastBlock >> 16) & 0xFF; dataBuf[5] = (sd.lastBlock >> 8) & 0xFF; dataBuf[6] = (sd.lastBlock) & 0xFF; } switch (sd.lastErr) { case LASTERR_OK: dataBuf[2] = 0; break; case LASTERR_OPCODE: case LASTERR_INVADDR: case LASTERR_INVARG: case LASTERR_INVLUN: dataBuf[2] = 5; break; default: dataBuf[2] = 4; break; } dataBuf[7] = 14; dataBuf[12] = sd.lastErr; dataBuf[19] = (sd.lastBlock >> 16) & 0xFF; dataBuf[20] = (sd.lastBlock >> 8) & 0xFF; dataBuf[21] = (sd.lastBlock) & 0xFF; } sendDma(cmdBuf[4]); commandSuccess(); break; case 0x08: // Read block // Compute the block number sd.lastBlock = (((int)cmdBuf[1]) << 16) | (((int)cmdBuf[2]) << 8) | (cmdBuf[3]); sd.lastSeek = true; // Do the actual read operation if (sd.readBlocks(sd.lastBlock, cmdBuf[4])) { // ok now ? block + count - 1 >= blocks commandSuccess(); Serial.println("commandSuccess() "); } else { commandError(); Serial.println("commandError() "); } break; /* // Process a read block command inline bool SDC::readBlocks(uint32_t block, uint32_t count) { if (block + count - 1 >= blocks) { //sd->lastErr = LASTERR_INVADDR; sd.lastErr = LASTERR_INVADDR; Serial.println("sd.lastErr = LASTERR_INVADDR; Block out of range"); return false; // Block out of range } */ case 0x0A: // Write block /** Protect block zero from write if nonzero */ // teensy 3.x old SD lib issue. // #define SD_PROTECT_BLOCK_ZERO 1 // in the SD\utility\Sd2Card.h library about line 59 change this define. // to #define SD_PROTECT_BLOCK_ZERO 0 // Compute the block number sd.lastBlock = (((int)cmdBuf[1]) << 16) | (((int)cmdBuf[2]) << 8) | (cmdBuf[3]); sd.lastSeek = true; // Do the actual write operation if (sd.writeBlocks(sd.lastBlock, cmdBuf[4])) commandSuccess(); else commandError(); break; case 0x0B: // Seek /* // Reinitialize the SD card if (!sd.init()) { sd.lastErr = LASTERR_INVADDR; commandError(); //return; break; } */ sd.lastBlock = (((int)cmdBuf[1]) << 16) | (((int)cmdBuf[2]) << 8) | (cmdBuf[3]); sd.lastSeek = true; if (sd.lastBlock >= sd.blocks) { sd.lastErr = LASTERR_INVADDR; commandError(); } else commandSuccess(); break; case 0x12: // Inquiry // Fill the response with zero bytes Serial.println(" Inquiry"); InquiryTemp = cmdBuf[4]; for (uint8_t b = 0; b < cmdBuf[4]; ++b) { dataBuf[b] = 0; } /* http://courses.cs.tau.ac.il/os/orish/src/drivers/block/acsi.c switch (acsi_buffer[0]) { case TYPE_DISK: aip->type = HARDDISK; break; case TYPE_ROM: aip->type = CDROM; aip->read_only = 1; break; default: return DEV_UNKNOWN; } */ if (getLun() > 0) dataBuf[0] = 0x7F; // Unsupported LUN dataBuf[1] = 0x80; // Removable flag, NOT removable = 0, (RMB) bit dataBuf[2] = 0x02; //1; // ACSI version?? , // SCSI level 2 dataBuf[3] = 0x02; // response data format //dataBuf[4] = 31; // Data length dataBuf[4] = InquiryTemp; //- 1; // Data length - ALLOCATION LENGTH // Build the product string with the SD card size sd.getId((char *)dataBuf + 8); // vendor (CHRIS), >=8 <=15 // device name, >=16 <=25 //dataBuf[8] = ('C'); //dataBuf[9] = ('H'); //dataBuf[10] = ('R'); //dataBuf[11] = ('I'); //dataBuf[12] = ('S'); //dataBuf[13] = (' '); //dataBuf[14] = ('O'); //dataBuf[15] = ('.'); // version >=32 <=35 // date string >=36 i<=43 sendDma(cmdBuf[4]); sd.lastSeek = false; commandSuccess(); //return; break; // SCSI INFO https://www.seagate.com/files/staticfiles/support/docs/manual/Interface%20manuals/100293068j.pdf case 0x1A: // Mode sense // Len 6 Command 1A 0 43 0 20 0 // 0 OPERATION CODE (1Ah) // 1 DBD (disable block descriptors) bit: bit 7 to 4 RES, bit3 DBD, bit 2 to 0 RES. --> DBD (disable block descriptors) bit. // 2 PC (Page Control) field: First two bit (PC, Page Control) field, bit 5 to 0 PAGE CODE. // 3 SUBPAGE CODE: The PAGE CODE and SUBPAGE CODE fields specify which mode pages and subpages to return (see table 349) // 4 ALLOCATION LENGTH: The ALLOCATION LENGTH field is defined in 2.2.6. // 5 CONTROL: // // Error // send Status 2 // Success // // cmdBuf[2] 0x43 b01000011 1st 2bit = Page control (PC) field 01= Changeable values // cmdBuf[2] 0x43 b01000011 bit 0 to 5 = PAGE CODE // PC (Page Control) field // The page control (PC) field specifies the type of mode parameter values to be returned in the mode pages. The PC field is defined in table 74 3.11.1.2 // 3.11.1.2 Changeable values // A PC field value of 01b requests that the device server return a mask denoting those mode parameters that are changeable. In // the mask, the bits in the fields of the mode parameters that are changeable all shall be set to one and the bits in the fields of the // mode parameters that are non-changeable (i.e., defined by the logical unit) all shall be set to zero. // If the logical unit does not implement changeable parameters mode pages and the device server receives a MODE SENSE // command with 01b in the PC field, then the command shall be terminated with CHECK CONDITION status, with the sense key set // to ILLEGAL REQUEST, and the additional sense code set to INVALID FIELD IN CDB. // An attempt to change a non-changeable mode parameter using the MODE SELECT command shall result in an error condition // (see 3.7). // The application client should issue a MODE SENSE command with the PC field set to 01b and the PAGE CODE field set to 3Fh to // determine which mode pages are supported, which mode parameters within the mode pages are changeable, and the // supported length of each mode page prior to issuing any MODE SELECT commands. // /* uint32_t length, i, len; uint8_t PageCode, val; //----------------- uint8_t page_control[] = {0x0a, 0x06, 0, 0, 0, 0, 0, 0}; uint8_t page_medium[] = {0x0b, 0x06, 0, 0, 0, 0, 0, 0}; //----------------- PageCode = cmdBuf[2] & 0x3f; // get only page code length = cmdBuf[4]; // how many bytes should be sent */ sd.lastSeek = false; switch (cmdBuf[2]) { // Sub-command case 0x00: for (uint8_t b = 0; b < 16; ++b) { dataBuf[b] = 0; } // Values got from the Hatari emulator dataBuf[1] = 14; dataBuf[3] = 8; // Send the number of blocks of the SD card dataBuf[5] = (sd.blocks >> 16) & 0xFF; dataBuf[6] = (sd.blocks >> 8) & 0xFF; dataBuf[7] = (sd.blocks) & 0xFF; // Sector size middle byte dataBuf[10] = 2; sendDma(16); break; case 0x04: for (uint8_t b = 0; b < 24; ++b) { dataBuf[b] = 0; } // Values got from the Hatari emulator dataBuf[0] = 4; dataBuf[1] = 22; // Send the number of blocks in CHS format dataBuf[2] = (sd.blocks >> 23) & 0xFF; dataBuf[3] = (sd.blocks >> 15) & 0xFF; dataBuf[4] = (sd.blocks >> 7) & 0xFF; // Hardcode 128 heads dataBuf[5] = 128; sendDma(24); break; default: if (getLun() == 0) sd.lastErr = LASTERR_INVARG; commandError(); //return; break; } commandSuccess(); //return; break; //case 0x1E: // Removable MEDIA Eject command ? // TODO // break; case 0x1F: // ICD extended command switch (cmdBuf[1]) { // Sub-command case 0x12: // Inquiry ICD extended, Len 7 1F 12 0 0 0 10 0 // Fill the response with zero bytes Serial.println(" Inquiry"); InquiryTemp = cmdBuf[5]; for (uint8_t b = 0; b < cmdBuf[5]; ++b) { dataBuf[b] = 0; } //if (getLun() > 0) // // dataBuf[1] = 0x7F; // Unsupported LUN dataBuf[2] = 0x80; // Removable flag, NOT removable = 0 dataBuf[3] = 0x02; //1; // ACSI version?? , // SCSI II level 2 dataBuf[4] = 0x02; // response data format //dataBuf[4] = 31; // Data length // todo test - 1 ?? dataBuf[5] = InquiryTemp - 1; // Data length, ALLOCATION LENGTH // Build the product string with the SD card size sd.getId((char *)dataBuf + 8); sendDma(cmdBuf[5]); sd.lastSeek = false; commandSuccess(); break; case 0x25: // Read capacity sd.blocks = SD_MAX_BLOCKS; // // Send the number of blocks of the SD card dataBuf[0] = (sd.blocks >> 24) & 0xFF; dataBuf[1] = (sd.blocks >> 16) & 0xFF; dataBuf[2] = (sd.blocks >> 8) & 0xFF; dataBuf[3] = (sd.blocks) & 0xFF; // Send the block size (which is always 512) dataBuf[4] = 0x00; dataBuf[5] = 0x00; dataBuf[6] = 0x02; dataBuf[7] = 0x00; sendDma(8); commandSuccess(); break; case 0x28: // Read blocks { // Compute the block number int block = (((int)cmdBuf[3]) << 24) | (((int)cmdBuf[4]) << 16) | (((int)cmdBuf[5]) << 8) | (cmdBuf[6]); // LOGICAL BLOCK ADDRESS int count = (((int)cmdBuf[8]) << 8) | (cmdBuf[9]); // TRANSFER LENGTH // Do the actual read operation if (sd.readBlocks(block, count)) commandSuccess(); else commandError(); } //return; break; case 0x2A: // Write blocks // WRITE AND VERIFY (10) 2Eh { // Compute the block number int block = (((int)cmdBuf[3]) << 24) | (((int)cmdBuf[4]) << 16) | (((int)cmdBuf[5]) << 8) | (cmdBuf[6]); int count = (((int)cmdBuf[8]) << 8) | (cmdBuf[9]); // Do the actual write operation if (sd.writeBlocks(block, count)) commandSuccess(); else commandError(); } break; //0x1F: // ICD extended command default: // Unknown command acsiDbg("ICD extended Unknown command "); for (uint32_t i = 0; i < cmdLen; ++i) { acsiDbg(' '); acsiDbg(cmdBuf[i], HEX); } acsiDbgln(""); sd.lastSeek = false; commandError(); //return; break; } break; } // END switch (cmdBuf[0]) // TODO digitalWriteFast(OE_SN74LVC4245A, HIGH); // (active low) SN74LVC4245A -OE, Teensy pin 34, 3-State SN74LVC4245A Octal Bus Transceiver Outputs // -OE (active low) will be enabled when CS and A1 == Low in CS IRQ. //attachInterrupt(CS, CS_IRQhandler, FALLING); // RISING // ->attachInterrupt(R_W, R_W_IRQhandler, RISING); // SN7406 Hex inverter REVERSE LOGIC, bug fix } // END LOOP() Quote Link to comment Share on other sites More sharing options...
Chri O. Posted July 28, 2021 Author Share Posted July 28, 2021 I read the ACSI Commands with interrupt routine. void FASTRUN CS_IRQhandler() { // _CS Chip Select - ATARI is writing command or data to device, or reading handshake or status byte from device. /* TODO set OTHER INTTERUPT A1 ? THIS IS 2 SLOW IN CS INTTERUPT if ((GPIOD_PDIR & 0b000000000000000100000000) == 0) { // we are inside CS (LOW) interrupt handler so all we need is check if A1 Address bit is LOW. // CS_MASK 0b000000000000001000000000 // 0b0000 0000 0000 0010 0000 0000 -PTD 09 port D pin 48 // A1_MASK 0b000000000000000100000000 // 0b0000 0000 0000 0001 0000 0000 -PTD 08 port D pin 47 // _______________________________ // | INPUTS | SN74LVC4245A | https://www.ti.com/lit/ds/symlink/sn74lvc4245a.pdf?HQS=dis-dk-null-digikeymode-dsf-pf-null-wwe&ts=1616938602079 // | OE | DIR | OPERATION | DIR NOTE: Need inverting buffer which produces the state opposite to the R_W on ATARI DB19 pin !!! // |-----------------------------| DIR NOTE: So when its High on Atari its Low on DIR pin; From Teensy to Atari, use SN7406 Hex inverter Buffers With Open-Collector ? // | L | L | B data to A bus | DIR - Inverted HIGH from ATARI A input to Device B input side, ATARI original signal is LOW from ATARI to Device COOMMAND write R/_W low // | L | H | A data to B bus | DIR - Inverted LOW from Device B input to ATARI A input side, ATARI original signal is HIGH from Device to ATARI STATUS read R/_W high ( Device is on B input side ) // | H | X | Isolation | OE - tied to GND LOW -Enabled, TODO: NOTE 1 -OE // ------------------------------- // SN74LVC4245A Pin Configuration and Functions pinout. // ATARI ----_---- Teensy // (5V) VCCA-|1 24|-VCCB (3.3V) , DIR NOTE: Need inverting buffer which produces the state opposite the input for ATARI DIR DB19 pin !!! ( ATARI DIR = LOW from ATARI to Device - HIGH from Device to ATARI ) // DIR-|2 23|-VCCB (3.3V) , ATARI DIR DB19 ACSI connector --> R/W Read/Write - Inverted HIGH from ATARI to Device (A data to B bus), Inverted LOW from Device to ATARI (B data to A bus) //D0(LSB) A1-|3 22|-OE , OE - tied to GND LOW -Enabled, TODO: NOTE 1 -OE // A2-|4 21|-B1 , A1 ~ A8 (5V) From ATARI DB19 ACSI connector, 01 to 08 <-> Data BUS 0-7 INPUT & OUTPUT // A3-|5 20|-B2 , B1 ~ B8 (3.3V) From Device to ATARI (B data to A bus) // A4-|6 19|-B3 // A5-|7 18|-B4 // A6-|8 17|-B5 // A7-|9 16|-B6 //D7(MSB) A8-|10 15|-B7 // GND-|11 14|-B8 // GND-|12 13|-GND // --------- // NOTE 1: TODO -OE pin MCU control when (A1 Address bit LOW) & (_CS Chip Select LOW) enabled & read the data bus 1st byte of new command if correct Controller# leave it enabled else disable. // TODO -OE issue the control circuitry (DIR, OE) is powered by VCCA 5V. // ----- ACSI Command Descriptor Block --------------- // Byte 0 |xxxxxxxx| // |||||||| // |||------ Operation Code // --------- Controller Number digitalWriteFast(OE_SN74LVC4245A, LOW); // (active low) SN74LVC4245A -OE, Teensy pin 34 - enable SN74LVC4245A Octal Bus Transceiver Outputs }*/ GPIO_cs = GPIOD_PDIR; // & 0xFFFFFFFF; // read PORT D including CS PTD 09 pin 48 & A1 PTD 08 pin 47 digitalWriteFast(IRQ, HIGH); // high <-- (CS active low), when CS is low allways set irq high inactive // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ----- Command Phase -----------------------------------Alt+0175¯ ------ // DATA direction: From Atari to Target Device // A1 ¯¯¯¯¯¯¯¯\___________________________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ LOW indicates 1st byte of new command. // IRQ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\___________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\_____ Active low driven by target device to indicate (A) readness to accept another command byte (B) the availability of a byte to be read. // _CS ¯¯¯¯¯¯¯¯¯¯¯¯¯\__________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\__________/¯¯¯¯¯¯¯¯¯¯ // | | | | // R/_W ¯¯¯¯¯¯\______________________/¯¯¯¯¯¯\____________________/¯¯¯¯¯ LOW from ATARI to Device (Write), HIGH from Device to ATARI (Read) // | | | | | | | | // DATA =======><-------VALID--------><====><-------VALID--------><==== 8bit DATA Bus // | | | | | | | | // |<-a->|<--b--->|<-c->| |<-a->|<--b--->|<-c->| // Byte 0 Byte 1 Byte n // Timing // a) 60 ns (max) // b) 250 ns (max) // c) 20 ns (max) // IRQ Active LOW (open-collector) 1K Pullup on ATARI. // // #define CS_MASK 0b000000000000001000000000 // 0b0000 0000 0000 0010 0000 0000 -PTD 09 port D pin 48 // #define A1_MASK 0b000000000000000100000000 // 0b0000 0000 0000 0001 0000 0000 -PTD 08 port D pin 47 // LOW [_CS, R/_W, A1_st] = 1st command byte ACSI dev# + dev opcode //if (((GPIO_cs & A1_MASK) == 0) && ((GPIO_RW & R_W_MASK) == 1)) { // Check the A1 Address bit - When LOW during a _CS write, indicates 1st byte of new command if ((GPIO_cs & A1_MASK) == 0) { // Check the A1 Address bit - When LOW during a _CS write, indicates 1st byte of new command if (((GPIO_cs & 0b0000000011100000) >> (5)) == readerMask) { // Check the device ID CorrectDeviceIdFlag = true; counter = 0; if ((GPIO_cs & 0b00011111) == 0x1F) { // ICD extended command //cmdLen_I = 11; // well this should set flag for icd com. then chek next byte for cmdLen(the first 3 bit) GROUP CODE. isICD = true; // then it's a ICD command cmdLen_I = 7; // ICD extended 6 byte commands } else { isICD = false; cmdLen_I = 6; } } else { CorrectDeviceIdFlag = false; Serial.print("A1 Device ID "), Serial.println((GPIO_cs & 0b0000000011100000) >> (5)); Serial.print("GPIO_cs ID INCORRECT: BIN "), Serial.print( GPIO_cs, BIN ), Serial.print(" HEX "), Serial.println( GPIO_cs, BIN ); } } // Read the next bytes of the command if (CorrectDeviceIdFlag == true) { if (counter < cmdLen_I) { if (counter == 0) { cmdBuf_I[0] = GPIO_cs & 0b00011111; } else if (counter == 1) { if (isICD == true) { cmdBuf_I[counter] = GPIO_cs & 0xff; switch ((GPIO_cs & 0xe0) >> 5) // get the length of the command, Common CDB fields { case 0: cmdLen_I = 7; break; // 6 byte commands case 1: cmdLen_I = 11; break; // 10 byte commands, 1F (25 00100101) READ CAPACITY (10) case 2: cmdLen_I = 11; break; // 10 byte commands //case 3: Reserved [a] case 4: cmdLen_I = 17; break; // 16 byte commands case 5: cmdLen_I = 13; break; // 12 byte commands default: cmdLen_I = 7; break; } } else { cmdBuf_I[counter] = GPIO_cs & 0xff; } } else { cmdBuf_I[counter] = GPIO_cs & 0xff; } counter ++; if (counter < cmdLen_I) { digitalWriteFast(IRQ, LOW); // <-- (active low) //t2.trigger(30); // trigger t2 to switch IRQ ON after 200us, FTM3 module } } if (counter >= cmdLen_I) { CorrectDeviceIdFlag = false; counter = 0; CommandBool = true; // use this for Status Phase ? // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ----- Status Phase ---------------------------------------------------- // DATA direction: From Target Device to Atari // A1 ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ HIGH indicates inactive. // IRQ ______________/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ Active LOW driven by target device to indicate (A) readness to accept another command byte (B) the availability of a byte to be read. // _CS ¯¯¯¯¯¯¯¯¯¯¯¯¯¯\_______________/¯¯¯¯¯¯¯¯¯¯¯ // | | // R/_W _______/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\_____ LOW from ATARI to Device (Write), HIGH from Device to ATARI (Read) // | | | | // DATA =====================><----VALID----><==== 8bit DATA Bus // | | | | // |<-a-->|<--b-->|<-c-->|<-d-->| // Byte 0 // Timing // a) 50 ns (max) // b) 150 ns (max) // c) 100 ns (max) // d) 80 ns (max) // } } } Quote Link to comment Share on other sites More sharing options...
ParanoidLittleMan Posted July 28, 2021 Share Posted July 28, 2021 Sorry, I can not help in Tensy programming, really did not deal with such things. But this: "I read the ACSI Commands with interrupt routine. " - what is freq. of interrupts ? Or interrupt is triggered by ACSI command ? Because max speed possible with DMA chip is 2 MB/sec, that means that 1 sector transfer time then is 250 microSec. If test is with small sector count it will be lower speed because of waiting time, and command processing. Did you try with my speed test prg ? : http://atari.8bitchip.info/ahpt.html And can see some interesting speed results there. Quote Link to comment Share on other sites More sharing options...
Chri O. Posted July 28, 2021 Author Share Posted July 28, 2021 I think I'm having an issue with this coffee stain on my prototyping breadboard. 2 Quote Link to comment Share on other sites More sharing options...
Chri O. Posted July 28, 2021 Author Share Posted July 28, 2021 After playing with some of the wires. 2 Quote Link to comment Share on other sites More sharing options...
snarkdluG Posted July 28, 2021 Share Posted July 28, 2021 Look very nice. Which Teensy are you running it on? Quote Link to comment Share on other sites More sharing options...
Chri O. Posted July 28, 2021 Author Share Posted July 28, 2021 Teensy 3.5, I'm thinking about switching to Teensy 4.1 soon. Quote Link to comment Share on other sites More sharing options...
Chri O. Posted July 28, 2021 Author Share Posted July 28, 2021 CoreMark Benchmark Quote Link to comment Share on other sites More sharing options...
ParanoidLittleMan Posted July 29, 2021 Share Posted July 29, 2021 Very good speeds ? Quote Link to comment Share on other sites More sharing options...
Chri O. Posted August 5, 2021 Author Share Posted August 5, 2021 Just a quick bump I'm switching over to Teensy 4.1. Ok I'm eating my spaghetti now and dealing with this wiring spaghetti. ? Quote Link to comment Share on other sites More sharing options...
Chri O. Posted October 21, 2021 Author Share Posted October 21, 2021 Finally I got this going on Teensy 4.1 still playing with the timings apparently I'm pushing the limits of the Atari ST/e DMA speed ?. I had to slow it down otherwise I was going over 2000 KB/s ? For now I call this the HD brick ?. 2 Quote Link to comment Share on other sites More sharing options...
Chri O. Posted October 21, 2021 Author Share Posted October 21, 2021 Just another test with ICD RATEHD.PRG 1 Quote Link to comment Share on other sites More sharing options...
Chri O. Posted February 10, 2022 Author Share Posted February 10, 2022 (edited) Quick thread bump it's been awhile I've been busy. The HD brick is growing in height now up and running with ASCI output, the plan is to connect this and do some reverse engineering soon. Edited February 10, 2022 by Chri O. 1 Quote Link to comment Share on other sites More sharing options...
Cyprian Posted March 8, 2022 Share Posted March 8, 2022 great project and Teensy 4.1 would allow you to adds more services in additional to HDD emulation 1 1 Quote Link to comment Share on other sites More sharing options...
Chri O. Posted March 9, 2022 Author Share Posted March 9, 2022 Thanks for encouragement, unfortunately life gets in the way all the time as I am full-time heavy duty diesel mechanic I was busy lately trying to finish this rebuild in two weeks (12 hour shifts). Quote Link to comment Share on other sites More sharing options...
Cyprian Posted March 10, 2022 Share Posted March 10, 2022 16 hours ago, Chri O. said: Thanks for encouragement, unfortunately life gets in the way all the time as I am full-time heavy duty diesel mechanic I was busy lately trying to finish this rebuild in two weeks (12 hour shifts). cool, will it fit the ST? 1 Quote Link to comment Share on other sites More sharing options...
Chri O. Posted January 4, 2023 Author Share Posted January 4, 2023 I'm just messing with my Atari ST ACSI hard drive and Media Transfer Protocol (MTP) implementation, copy a file while it is being used by Atari at the same time test. 😁 2 Quote Link to comment Share on other sites More sharing options...
Chri O. Posted February 29 Author Share Posted February 29 PXL_20240229_223501461.mp4 Quick test 😁 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.