Jump to content
IGNORED

Yet another HD ACSI implementation with Media Transfer Protocol (WIP-Work in progress) ):


Recommended Posts

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 by Chri O.
  • Like 5
Link to comment
Share on other sites

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.

  • Like 1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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()

 

Link to comment
Share on other sites

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)
      //
    }
  }
}

 

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 2 months later...
  • 3 months later...
  • 4 weeks later...
  • 9 months later...
  • 1 year later...

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...