Re: [uCsimm] IDE followup

From: Mahmut C. Genceli (yunus@AdvancedRelay.com)
Date: Tue Jan 04 2000 - 02:02:50 EST


Here is a copy

Jason Hihn wrote:
>
> That http://www.magicio.com/cgroen/images/IDE.C has disappeared.
> I was wondering if anyone got their uCSimm to talk to a IDE drive. Also,
> which filesystem did the IDE drive use?
>
> TIA!
> This message resent by the ucsimm@uclinux.com list server http://www.uClinux.com/

//----------------------------------------------------------------------------

// IDE 19960417 CHG

// Small and simple interface for an "standard" IDE Harddisk connected

// to a 8051 cpu, in this case a DS5000, but all other 8051 compatible

// cpu could be used, as long as they have some external RAM, 1KByte or so

//

// This code is provided as is, with NO responsibility by the author !

// ie. this is use on your own risk !!!!!

//

// Code is free to use, the only request i have is, that if you do some

// enhancements, discoveries I would appreciate to get a copy/info on what

// YOU have done !

// That way, we can all help each other with code etc etc etc.

//

// Made by

// Carsten Groen, OZ9AAR

// Kaervaenget 46, Gl. Sole

// DK-8722 Hedensted

// Denmark

// email: cgroen@image.dk

//

//----------------------------------------------------------------------------

#include <reg5000.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <ctype.h>

//----------------------------------------------------------------------------

// Constants...

//----------------------------------------------------------------------------

#define TRUE 1

#define FALSE 0

#define CTRL 0

#define CMD 1

#define DRIVE0 0

//----------------------------------------------------------------------------

// Types

//----------------------------------------------------------------------------

typedef struct {

  unsigned char Heads;

  unsigned int Tracks;

  unsigned int SectorsPerTrack;

  char Model[41];

} tdefDriveInfo;

 

//----------------------------------------------------------------------------

// I/O definitions...

// The IDE harddisk is just connected DIRECTLY to these I/O ports on the 8051

// See pin numbers on IDC connecter on IDE drive in one of the attached files.

// REMEMBER to make a pullup on the P0 port (ex 4.7 K to vcc from each of the

// 8 P0 pins

//----------------------------------------------------------------------------

#define nCS1FX P00

#define nCS3FX P01

#define DA0 P02

#define DA1 P03

#define DA2 P04

#define nDASP P05

#define LSBDATA P1

#define MSBDATA P2

#define nDIOR P06

#define nDIOW P07

#define INTRQ P32

#define IORDY P33

#define RESET P34

 

#define ALLINPUT 0xFF

 

//----------------------------------------------------------------------------

// Variables...

//----------------------------------------------------------------------------

unsigned int Timer10mSec=0; // General timer, tick is 10 mSec

unsigned char SectorBuffer[512];

 

 

//----------------------------------------------------------------------------

// Wait for a specific time in 10 mSec

// Based on a 11.0592 Mhz crystal

//----------------------------------------------------------------------------

void Delay(unsigned char t) {

  unsigned int i;

  if (t==0) return;

  while (t--) for(i=0;i<774; i++);

}

 

//----------------------------------------------------------------------------

// Dump a buffer as a hex listing

//----------------------------------------------------------------------------

void HexDump( void *Dataa, int Len ) {

  unsigned char *Data=Dataa;

  unsigned char Line[80], *CurLine, *CurData;

  int linelen, j;

  unsigned short rc;

  unsigned char tmp;

  printf( "*************** HEX-DUMP ***************\n" );

  while( Len ){

    linelen = Len < 16 ? Len : 16;

    *Line='\0';

    CurLine = Line;

    for( CurData=Data, j=0; j<linelen; j++ ) {

      tmp=*CurData;

      sprintf( CurLine, "%02BX ", tmp);

      CurLine+=3; CurData++;

    }

 

    for( j=linelen; j<17; j++ ) {

      *CurLine =' ';

      CurLine[1]=' ';

      CurLine[2]=' ';

      CurLine+=3;

    }

 

    for( j=0; j<linelen; j++ ) {

      sprintf( CurLine, "%c ", *Data > ' ' ? *Data : '_' );

      Data++;CurLine+=1;

    }

    printf( Line );

    printf("\n");

    Len-=linelen;

  }

  rc = printf( "*************** HEXEND ***************\n" );

}

 

//----------------------------------------------------------------------------

// Timer 0 interrupt service function

// executes each 10 mSec @ 11.0592 MHz Crystal Clock

//----------------------------------------------------------------------------

timer0() interrupt 1 using 1 {

  TH0 = 0xDC; // reload timer again

  TL0 = 0x00; // to 10 mSec timeout

  TR0 = 1;

  if (Timer10mSec) Timer10mSec--;

}

//----------------------------------------------------------------------------

// Show state of nDASP, INTRQ and IORDY signals

//----------------------------------------------------------------------------

void ShowInputs(void) {

  printf("Signals from Drive: nDASP=%s, INTRQ=%s, IORDY=%s\n",

         nDASP ? "FALSE":"TRUE", INTRQ ? "TRUE":"FALSE", IORDY ? "TRUE":"FALSE");

}

 

//----------------------------------------------------------------------------

// Select address and CS signals

//----------------------------------------------------------------------------

void SetAddress(unsigned char cs, unsigned char adr) {

  DA0=((adr & 0x01)==0x01);

  DA1=((adr & 0x02)==0x02);

  DA2=((adr & 0x04)==0x04);

  if (cs==CTRL) {

    nCS1FX=1;

    nCS3FX=0;

  } else {

    nCS1FX=0;

    nCS3FX=1;

  }

}

//----------------------------------------------------------------------------

// Read data WORD from Drive

//----------------------------------------------------------------------------

unsigned int ReadWORD(unsigned char cs, unsigned char adr) {

  unsigned int tmp;

  MSBDATA=ALLINPUT;

  LSBDATA=ALLINPUT;

  SetAddress(cs,adr);

  nDIOR=0;

  tmp=(MSBDATA<<8)+LSBDATA;

  nDIOR=1;

  nCS1FX=1;

  nCS3FX=1;

  return tmp;

}

 

//----------------------------------------------------------------------------

// Read data BYTE from Drive

//----------------------------------------------------------------------------

unsigned char ReadBYTE(unsigned char cs, unsigned char adr) {

  unsigned char tmp;

  MSBDATA=ALLINPUT;

  LSBDATA=ALLINPUT;

  SetAddress(cs,adr);

  nDIOR=0;

  tmp=LSBDATA;

  nDIOR=1;

  nCS1FX=1;

  nCS3FX=1;

  return tmp;

}

 

//----------------------------------------------------------------------------

// Write data WORD to Drive

//----------------------------------------------------------------------------

void WriteWORD(unsigned char cs, unsigned char adr, unsigned int dat) {

  SetAddress(cs,adr);

  // OBS MSB/LSB is swapped (see writeSector function)

  MSBDATA=dat;

  LSBDATA=(dat>>8);

  nDIOW=0;

  nDIOW=1;

  nCS1FX=1;

  nCS3FX=1;

}

 

//----------------------------------------------------------------------------

// Write data BYTE to Drive

//----------------------------------------------------------------------------

void WriteBYTE(unsigned char cs, unsigned char adr, unsigned char dat) {

  SetAddress(cs,adr);

  MSBDATA=0;

  LSBDATA=dat;

  nDIOW=0;

  nDIOW=1;

  nCS1FX=1;

  nCS3FX=1;

}

 

//----------------------------------------------------------------------------

// Send Identify Command to Drive, and fetch resulting data

//----------------------------------------------------------------------------

unsigned char IdentifyDrive(bit DriveNo, unsigned char *Buffer,

                            tdefDriveInfo *DriveInfo) {

  unsigned int i;

  unsigned char Tmp;

  WriteBYTE(CMD, 6, 0xA0 + (DriveNo ? 0x10:0x00)); // Select drive

  WriteBYTE(CMD, 1, 0);

  WriteBYTE(CMD, 2, 1);

  WriteBYTE(CMD, 3, 1);

  WriteBYTE(CMD, 4, 0);

  WriteBYTE(CMD, 5, 0);

  WriteBYTE(CMD, 7, 0xEC);

  Timer10mSec=10000;

  while ((ReadBYTE(CMD,7) & 0x08)!=0x08 && Timer10mSec); // Wait for DRQ or timeout

  if (Timer10mSec==0) return 0xFF;

 

  // Fetch the data...

  MSBDATA=ALLINPUT;

  LSBDATA=ALLINPUT;

  // Select address and activate CS

  SetAddress(CMD, 0);

  // Two bytes at a time

  for (i=0; i<512; i+=2) {

    nDIOR=0;

    *(Buffer+i)=LSBDATA;

    *(Buffer+i+1)=MSBDATA;

    nDIOR=1;

  }

  // Disable CS

  nCS1FX=1;

  nCS3FX=1;

  // Extract drive info

  DriveInfo->Heads = (*(Buffer+7)<<8) + *(Buffer+6);

  DriveInfo->Tracks = (*(Buffer+3)<<8) + *(Buffer+2);

  DriveInfo->SectorsPerTrack = (*(Buffer+13)<<8) + *(Buffer+12);

  // Swap bytes, because of 16 bit transfer...

  for (i=0; i<40; i+=2) {

    Tmp=*(Buffer+54+i);

    *(Buffer+54+i)=*(Buffer+55+i);

    *(Buffer+55+i)=Tmp;

  }

  memcpy(DriveInfo->Model, Buffer+54, 80);

  // Terminate string...

  DriveInfo->Model[40]='\0';

  // Return the error register...

  return ReadBYTE(CMD, 1);

}

 

//----------------------------------------------------------------------------

// Read one sector, identified by drive, head, track and sector

// Returns contents of the Error Register (0x00 is no error detected)

//----------------------------------------------------------------------------

unsigned char ReadSector(unsigned char Drive,

                unsigned char Head, unsigned int Track, unsigned char Sector,

                unsigned char *Buffer) {

  unsigned int i;

  // Prepare parameters...

  WriteBYTE(CMD,6, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head

  WriteBYTE(CMD,5, Track>>8); // MSB of track

  WriteBYTE(CMD,4, Track); // LSB of track

  WriteBYTE(CMD,3, Sector); // sector

  WriteBYTE(CMD,2, 0x01); // 1 sector

  // Issue read sector command...

  WriteBYTE(CMD,7, 0x20); // Read sector(s) command

  Timer10mSec=10000;

  while ((ReadBYTE(CMD,7) & 0x08)!=0x08 && Timer10mSec); // Wait for DRQ or timeout

  if (Timer10mSec==0) return 0xFF;

 

  // Fetch the sector...

  MSBDATA=ALLINPUT;

  LSBDATA=ALLINPUT;

  // Select address and activate CS

  SetAddress(CMD, 0);

  // Two bytes at a time

  for (i=0; i<512; i+=2) {

    nDIOR=0;

    *(Buffer+i)=LSBDATA;

    *(Buffer+i+1)=MSBDATA;

    nDIOR=1;

  }

  // Disable CS

  nCS1FX=1;

  nCS3FX=1;

  // Return the error register...

  return ReadBYTE(CMD, 1);

}

 

//----------------------------------------------------------------------------

// Write one sector, identified by drive, head, track and sector

// Returns contents of the Error Register (0x00 is no error detected)

//----------------------------------------------------------------------------

unsigned char WriteSector(unsigned char Drive,

                unsigned char Head, unsigned int Track, unsigned char Sector,

                unsigned char *Buffer) {

  unsigned int i;

  // Prepare parameters...

  WriteBYTE(CMD,6, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head

  WriteBYTE(CMD,5, Track>>8); // MSB of track

  WriteBYTE(CMD,4, Track); // LSB of track

  WriteBYTE(CMD,3, Sector); // sector

  WriteBYTE(CMD,2, 0x01); // 1 sector

  // Issue write sector command...

  WriteBYTE(CMD,7, 0x30); // Write sector(s) command

  Timer10mSec=10000;

  while ((ReadBYTE(CMD,7) & 0x08)!=0x08 && Timer10mSec); // Wait for DRQ or timeout

  if (Timer10mSec==0) return 0xFF;

 

  // Select address and activate CS

  SetAddress(CMD, 0);

  // write sector data...

  for (i=0; i<512; i+=2) {

    LSBDATA=*(Buffer+i);

    MSBDATA=*(Buffer+i+1);

    nDIOW=0;

    nDIOW=1;

  }

  // Disable CS

  nCS1FX=1;

  nCS3FX=1;

  Timer10mSec=10000;

  while ((ReadBYTE(CMD,7) & 0xC0)!=0x40 && Timer10mSec); // Wait for DRDY and NOT BUSY

  if (Timer10mSec==0) return 0xFF; // or timeout

 

  // Return the error register...

  return ReadBYTE(CMD, 1);

}

//----------------------------------------------------------------------------

// Set drive mode (STANDBY, IDLE)

//----------------------------------------------------------------------------

#define STANDBY 0

#define IDLE 1

#define SLEEP 2

 

unsigned char SetMode(bit DriveNo, unsigned char Mode, bit PwrDown) {

  WriteBYTE(CMD, 6, 0xA0 + (DriveNo ? 0x10:0x00)); // Select drive

  WriteBYTE(CMD, 2, (PwrDown ? 0x01:0x00)); // Enable automatic power down

  switch (Mode) {

    case STANDBY: WriteBYTE(CMD,7, 0xE2); break;

    case IDLE: WriteBYTE(CMD,7, 0xE3); break;

    // NOTE: To recover from sleep, either issue a soft or hardware reset !

    // (But not on all drives, f.ex seagate ST3655A it's not nessecary to reset

    // but only to go in Idle mode, But on a Conner CFA170A it's nessecary with

    // a reset)

    case SLEEP: WriteBYTE(CMD,7, 0xE6); break;

  }

  Timer10mSec=10000;

  while ((ReadBYTE(CMD,7) & 0xC0)!=0x40 && Timer10mSec); // Wait for DRDY & NOT BUSY

  if (Timer10mSec==0) return 0xFF; // or timeout

 

  // Return the error register...

  return ReadBYTE(CMD, 1);

}

 

//----------------------------------------------------------------------------

// Show all IDE registers

//----------------------------------------------------------------------------

void ShowRegisters(bit DriveNo) {

  WriteBYTE(CMD,6, 0xA0 + (DriveNo ? 0x10:0x00)); // Select drive

  printf("Reg 0=%02BX 1=%02BX 2=%02BX 3=%02BX 4=%02BX 5=%02BX 6=%02BX 7=%02BX \n",

    ReadBYTE(CMD, 0), ReadBYTE(CMD, 1), ReadBYTE(CMD, 2), ReadBYTE(CMD, 3),

    ReadBYTE(CMD, 4), ReadBYTE(CMD, 5), ReadBYTE(CMD, 6), ReadBYTE(CMD, 7));

}

 

//----------------------------------------------------------------------------

// Main part

//----------------------------------------------------------------------------

void main() {

  unsigned int i;

  char cmdbuf[15];

  tdefDriveInfo DriveInfo;

  int Head=0, Track=0, Sector=1;

 

 //------------------------------

 // Initialize outputs...

 //------------------------------

  nCS1FX=1;

  nCS3FX=1;

  DA0 =0;

  DA1 =0;

  DA2 =0;

  nDIOR =1;

  nDIOW =1;

  RESET =0; // Reset drive

 //------------------------------

 // configure inputs...

 //------------------------------

  nDASP =1;

  LSBDATA =ALLINPUT;

  MSBDATA =ALLINPUT;

  INTRQ =1;

  IORDY =1;

 //------------------------------

 // Configure onchip resources...

 //------------------------------

  TMOD |= 0x01; // TMOD: timer 0, mode 1, 16 timer

  TH0 = 0xDC; // Set timeout period for Timer 0

  TL0 = 0x00; // to 10 mSec timeout

  ET0 = 1; // Enable Timer 0 interrupts

  TR0 = 1; // Start timer 0

 

  SCON = 0x50; // SCON: mode 1, 8-bit UART, enable rcvr */

  TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit reload */

  TH1 = 0xFD; // TH1: reload value for 9.6 Kbaud */

  PCON = 0x00; // PCON: Double baudrate, 19.2 Kbaud */

  TR1 = 1; // TR1: timer 1 run */

//ES = 1; // ES: Enable serial port int */

  TI = 1; // TI: set TI to send first char of UART */

  EA = 1; // Global int enable

 

 //----------------------------------------------------------------------------

 // Let things settle, and after that, remove RESET from drive

 //----------------------------------------------------------------------------

  Delay(10);

  RESET=1; // Remove reset to drive

 //----------------------------------------------------------------------------

 // ?

 //----------------------------------------------------------------------------

  printf("--------------------------------------------\n");

  printf("---------IDE EXERCISER (c) CHG 1996---------\n");

  printf("--------------------------------------------\n");

  ShowInputs();

 

  printf("Waiting for Initial DRDY & NOT BUSY from drive\n");

  WriteBYTE(CMD,6, 0xA0); // Set drive/Head register, ie. select drive 0

  while ((ReadBYTE(CMD,7) & 0xC0)!=0x40); // Wait for DRDY and NOT BUSY

  printf("Drive is ready!\n");

  

  printf("Spinning drive up (Going to IDLE mode)\n");

  printf("SetMode=%02bX\n", SetMode(DRIVE0, IDLE, TRUE));

  printf("Drive is ready!\n");

 

  printf("ReadSector=%02bX\n", ReadSector(DRIVE0, 0, 0, 1, SectorBuffer));

  HexDump(SectorBuffer, 512);

  for (i=0; i<512; i++) SectorBuffer[i]=i;

 

  printf("WriteSector=%02bX\n", WriteSector(DRIVE0, 0, 0, 1, SectorBuffer));

  printf("ReadSector=%02bX\n", ReadSector(DRIVE0, 0, 0, 1, SectorBuffer));

  HexDump(SectorBuffer, 512);

 

  while (1) {

    printf ("\nCommand: ");

    gets(cmdbuf, sizeof(cmdbuf));

    for (i=0; cmdbuf[i]!=0; i++) cmdbuf[i] = toupper(cmdbuf[i]);

    for (i = 0; cmdbuf[i] == ' '; i++); /* skip blanks */

 

    switch (cmdbuf[i]) {

      case 'S': SetMode(DRIVE0, STANDBY, TRUE); break;

      case 'I': SetMode(DRIVE0, IDLE, TRUE); break;

      case 'D': IdentifyDrive(DRIVE0, SectorBuffer, &DriveInfo);

                HexDump(SectorBuffer, 256);

                printf("Model = %s\n", DriveInfo.Model);

                printf("Heads = %bu\n",DriveInfo.Heads);

                printf("Tracks = %u\n", DriveInfo.Tracks);

                printf("Sectors/Track = %u\n", DriveInfo.SectorsPerTrack);

 

        break;

      case 'R': ShowRegisters(DRIVE0); break;

      case '?':

                printf("--------------------------------------------\n");

                printf("---------IDE EXERCISER (c) CHG 1996---------\n");

                printf("--------------------------------------------\n");

                printf("Commands:\n");

                printf(" S go to Standby mode\n");

                printf(" I go to Idle mode\n");

                printf(" D Identify drive\n");

                printf(" R Show all registers\n");

                printf(" G <Head>,<Track>,<Sector> Read sector\n");

                printf("--------------------------------------------\n");

        break;

      case 'G':

        sscanf (&cmdbuf[i+1], "%d,%d,%d",

                 &Head, &Track, &Sector);

        printf("ReadSector=%02bX\n", ReadSector(DRIVE0, Head, Track, Sector, SectorBuffer));

        HexDump(SectorBuffer, 512);

        printf("Head=%d, Track=%d, Sector=%d\n", Head, Track, Sector);

        break;

    }

  }

}

This message resent by the ucsimm@uclinux.com list server http://www.uClinux.com/



This archive was generated by hypermail 2b30 : Sun Apr 07 2002 - 00:01:33 EST