📄 zata.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 + -