⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zata.c

📁 &#8226 控制器(CPU): Atmel AT90S8515 AVR &#8226 MP3解码器: STA013 &#8226 音频 DAC: CS4334 &#8226 IDE 接口
💻 C
字号:
/*
    Copyright 2002 Nasif Akand (nasif@yifan.net)
    http://go.to/zipamp
    http://zipamp.virtualave.net

    This file is part of ZipAmp MP3 software.

    ZipAmp is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    ZipAmp is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this code; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/


//This module is the hardware interface to the ATA drives.

//Each NOP operation gives about 125ns delay @ 8.00MHz
//ATA3 spec says max transition delay can be 400ns. 
//But drives now a days are way faster.


/*
 Data type
 byte is unsigned char
 word is unsigned int
 The type byte and word are defined in ztype.h . 
*/

//If using CodeVision then following includes aren't needed.
//#include "zcontrol.h"
//#include "zfat.h"
#include "zata.h"
//#include "ztype.h"
//#include "i2c.h"
//#include "<delay.h>" //CodeVision AVR internal delay routines
//#include "zlcd.h"



unsigned char ReadUpper8(){ 
 //Reads the high byte during 16bit data read

 unsigned char temp;
 DDRC=0;	//PORTC input mode 
 PORTD.5=0;    	//activate buffer, active low
 #asm("nop"); 	//wait for pin trasition
 temp=PINC;	//read the input at PORTC
 PORTD.5=1;	//Deactivate buffer
 return temp;
}             


void WriteAddr(unsigned char address){
 //Writes register value on ATA address bus through 74373 latch             
 
 DDRC=0xFF;	//set PORTC to output mode
 PORTC=address;	//write register address value to PORTC
 PORTD.4=1;	//activate latch, active high
 #asm("nop"); 	//wait for pin trasition
 #asm("nop");
 PORTD.4=0;	//deactivate latch
 DDRC=0x00;     //PORTC read mode
 PORTC=0x00;	//PORTC High Z state
}

void RegWrite(unsigned char reg, unsigned char data){
 //Writes the data byte to the specified ATA register. Uses WriteAddr() function
 
 DDRA=0xFF;	//set Port A as output
 PORTA=data;	//put valid data on Port A
 WriteAddr(reg);
 PORTB.0=0;	//Enable /IOWR
 #asm("nop");	//wait pin transition
 #asm("nop");
 PORTB.0=1;	//Disable /IOWR
 DDRA=0x00;	//set to read mode;
 PORTA=0;	//set to HI Z state
}

unsigned char RegRead(unsigned char reg) {
 //Reads the specified ATA register. Uses WriteAddr() function.
 //Reads only D0..D7
 
 unsigned char temp;
 WriteAddr(reg);
 PORTB.1=0;	//Enable /IORD
 #asm("nop");	//wait for pin transition
 #asm("nop");
 temp=PINA;     //Read D0..D7 from PORTA
 PORTB.1=1;     //Disable /IORD 
 return temp;
}


void ATA_Read_Sectors_LBA(unsigned long lba, unsigned int wordsToRead){
 //Reads specified words from LBA sector. You cannot read a new LBA address unless readPos=0
 //If you want to read a new LBA address, then you must set readPos=0 before calling this function.
 
 if (readPos==0) ATA_Move_Head(lba); //If a new sector has to be read then move head
 ATA_Read(wordsToRead);
}

void ATA_Move_Head(unsigned long lba) {             
//Move head to the sector given by the LBA address. Before we can read the drive head must be
//moved to the appropriate sector.

  byte lo;
  
  #asm("cli"); 		//clear all interrupt.
  WaitTillNotBusy(); 	//Wait until drive is reay

  //Setup all the specific registers with LBA address.   
  RegWrite(DrvHeadReg, LBAMaster + (lba>>24));	//lba bits 24-27  	   
  RegWrite(HiCylReg,lba>>16 );			//lba bits 16-23  	   
  RegWrite(LoCylReg,lba>>8 );			//lba bits 8-15  	   
  RegWrite(SecReg,lba);	   			//lba bits 0-7  	 
  RegWrite(SecCountReg, 1);			//1 sector to be read
    	 
  // Issue Sector read with retry command...
  RegWrite(CmdStsReg, 0x20);      
  
  do {
   lo=RegRead(CmdStsReg);	//Read status register
   if (lo & SR_ERR) {		//if error bit set,
//    error=RegRead(ErrorReg);    //set error variable
//    writestring("Sector READ Error."); //Write Error on LCD
    Halt(1);
   }
  }		
  while ((lo & SR_DRQ) != SR_DRQ);	// Wait for DRQ, meaing wait until disk has data ready for reading
  
  //Data is now ready. 
  //Now we write the IOReg addres on latch so that we can read 16 bit IOReg later.
  WriteAddr(IOReg);
}


void ATA_Read(unsigned int wordsToRead) {
 //Reads 16bit words from the ATA IO register. Before calling this function head must be moved to desired sector.
 
 byte lo,hi; word j;
 
 #asm("cli"); //clear all interrupt.
 
 wordsToRead = (wordsToRead<<1); //wordsToRead*2; multiplied by two because we will read byte by byte

 //This loop reads specified # of words, 1 word = 2 bytes, reads 2 bytes in each iteration
 for (j=0;((j<wordsToRead) && (readPos<512));){	

  PORTB.1=0;			// activate /IORD
  #asm("nop");			// allow pin transition. This is absolutely needed !
  #asm("nop");
  lo = PINA;			// read lo byte
  hi = ReadUpper8();		// read hi byte
  PORTB.1=1;			// deactivate /IORD
  sectorBuffer.data[j++]=lo;	// little endian structure, low byte first
  sectorBuffer.data[j++]=hi;    // Now store high byte
  readPos += 2;                 // Increment readPos by 2, 2byte (1 word) read.

 }

 if (readPos==512)  { 
  readPos=0;  	//One sector has been completely read, thus readPos is set to 0
  sectorPos++; 	//sectorPos incremented to show one sector read has finished.
  headMoved=0;  //Head moved flag is cleared, before next read head must be moved to new sector
 }

}
  
void ATA_Init() {

 unsigned char value=0;
  
 // SRST and nIEN bits
 RegWrite(Interrupt,0x06);
 delay_ms(100);	            // 100mS delay
 
 RegWrite(Interrupt, 0x02); // nIEN bit
 delay_ms(100);		    // 100 mS delay

 do { 
  delay_ms(1000);
  value=RegRead(CmdStsReg); //Read status register
 }
 while (( value & 0xC0) != 0x40 );
 
 //Initialize Standby timer, currently set standby after 5 mins of hard drive inactivity.
 RegWrite(SecCountReg,60); 		//Set 5 mins (60=5mins standby, read ATA documentation)
 RegWrite(DrvHeadReg,LBAMaster); 	//For Master drive
 RegWrite(CmdStsReg,0xE2); 		//Write standby command to command register. */
 WaitTillNotBusy(); 			//Wait until command taken.                
}

void ATA_WriteSector(dword lba) {
//writes on low bytes of first 256 bytes of the sector specified
  byte temp;
  #asm("cli");
  WaitTillNotBusy();
  RegWrite(DrvHeadReg, LBAMaster + (lba>>24));	//lba 24-27  	   
  
  RegWrite(HiCylReg,lba>>16 );			//lba 16-23  	   
  RegWrite(LoCylReg,lba>>8 );			//lba 8-15  	   
  RegWrite(SecReg,lba);	   			//lba 0-7  	 
  RegWrite(SecCountReg, 1);			// 1 sector to be written
    	 
  // Issue Sector write command...
  RegWrite(CmdStsReg, 0x30);
  do {
   temp=RegRead(CmdStsReg);
   if (temp & SR_ERR) {			// if error bit set,
    Halt(2);	  //Sector write error
   }
  }		
  while ((temp & SR_DRQ) != SR_DRQ);	// Wait for DRQ, meaing wait until disk has ready for writing
 /************************************************************** */
                            
 WriteAddr(IOReg);			//set the IO register.
 readPos=0;                    
 DDRA=0xFF; //PORTA output mode
 do { //Write only low byte
  if (readPos<256) PORTA=sectorBuffer.data[readPos]; //Write only Low byteo of first 256 byte of the sector
  PORTB.0=0;	//Enable /IOWR
  #asm("nop");	//wait pin transition
  #asm("nop");
  PORTB.0=1;	//Disable /IOWR
  readPos +=2;  //Increment by 2, word written on each iteration
  //#asm("nop");
 }
 while (readPos<512); //Loop until whole sector written.
 DDRA=0; //Port A input mode.
 WaitTillNotBusy();    
}

void WaitTillNotBusy() {
 //Loop until drive is busy.
  while ((RegRead(CmdStsReg) & SR_BSY) == SR_BSY);
}

void UnBusy() {                             
 //This function was written after I found out that if you stop reading  
 //midway during a sector read, busy LED is not cleared. To clear busy LED
 //you must finish reading a complete sector. This function reads whateven is left of in current sector. 

 while ((headMoved|readPos)!=0) readFile(1);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -