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

📄 ata.c

📁 基于AVR的一个嵌入式的FAT32的代码
💻 C
📖 第 1 页 / 共 2 页
字号:
//*****************************************************************************
//
// Title		: IDE-ATA interface driver for hard disks
// Authors		: Project A3670
// File Name	: 'ata.c'
// Date			: April 16, 2004
// Version		: 1.00
// Target MCU	: Atmel AVR Series
// Editor Tabs	: 4
//
// NOTE: The authors in no way will be responsible for damages that you coul'd be using this code.
//       Use this code at your own risk.
//
//       This code is distributed under the GNU Public License
//       which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************

#ifndef WIN32
	#include <avr/io.h>
	#include <avr/interrupt.h>
	#include <avr/signal.h>
	#include <avr/pgmspace.h>
#endif
#include "global.h"
#include "ata.h"

// global variables
typeDriveInfo ataDriveInfo;		// drive information


//*****************************************************************************
// Function: ataInit
// Parameters: none
// Returns: none
//
// Description: Gives a software reset into the ata dispositive
//*****************************************************************************
void ataInit(void)
{
	unsigned char i;
	unsigned char* buffer = (unsigned char*) SECTOR_BUFFER_ADDR;


	DDR_DATAL= 0x00;			// Use DATAL as the input from the hardrive
	DDR_DATAH= 0x00;			// Use DATAH as the input from the hardrive
	PORT_DATAL= 0xFF;			// Enable pullup on DATAL
	PORT_DATAH= 0xFF;			// Enable pullup on DATAH

	DDR_ADDR = 0xDF;			// Use ADDR PORT as the output for the hardrive
  								// But use PORT_ADDR.5 as host interrupt (INPUT)
    PORT_ADDR= 0xc0;            // Initialize PORT_ADDR to c0.


    ataWriteByte(ATA_REG_ACTSTATUS, 0x06);  	 	// Assert Software reboot.
    delay(100);
    ataWriteByte(ATA_REG_ACTSTATUS, 0x00);
    delay(100);

    // Wait until drive clear BUSY Bit in Alternate Status Register
    while(IDE_Wait_State(ATA_SR_BSY) == 1);

	// issue identify command
	ataWriteByte(ATA_REG_HDDEVSEL, 0);
	ataWriteByte(ATA_REG_ACTSTATUS, 0x02);

    while(IDE_Wait_State(ATA_SR_DRDY) == 0);

	ataWriteByte(ATA_REG_CMDSTATUS1, 0xEC);
	// wait for drive to request data transfer

	while(IDE_Wait_State(ATA_SR_DRQ) == 0);

	delay(200); // wait 200 us
	// read in the data
	ataReadDataBuffer(buffer, 512);

	// set local drive info parameters
	ataDriveInfo.cylinders =		*( ((unsigned int*) buffer) + ATA_IDENT_CYLINDERS );
	ataDriveInfo.heads =			*( ((unsigned int*) buffer) + ATA_IDENT_HEADS );
	ataDriveInfo.sectors =			*( ((unsigned int*) buffer) + ATA_IDENT_SECTORS );
	ataDriveInfo.LBAsupport =		*( ((unsigned int*) buffer) + ATA_IDENT_FIELDVALID );
	ataDriveInfo.sizeinsectors =	*( (unsigned long*) (buffer + ATA_IDENT_LBASECTORS*2) );
	// copy model string
	for(i=0; i<40; i+=2)
	{
		// correct for byte order
		ataDriveInfo.model[i  ] = buffer[(ATA_IDENT_MODEL*2) + i + 1];
		ataDriveInfo.model[i+1] = buffer[(ATA_IDENT_MODEL*2) + i    ];
	}
	// terminate string
	ataDriveInfo.model[40] = 0;

	// process and print info
	if(!ataDriveInfo.LBAsupport) {
		// CHS, no LBA support
		// calculate drive size
		ataDriveInfo.sizeinsectors = (unsigned long) ataDriveInfo.cylinders*ataDriveInfo.heads*ataDriveInfo.sectors;
	}
}


//*****************************************************************************
// Function: ataSetDrivePowerMode
// Parameters: DriveNo, mode, timeout
// Returns: none
//
// Description: Sets the Power Mode
//	            Possible modes: ATA_DISKMODE_SPINDOWN
//                              ATA_DISKMODE_SPINUP
//                              ATA_DISKMODE_SETTIMEOUT
//                              ATA_DISKMODE_SLEEP
//*****************************************************************************
void ataSetDrivePowerMode(unsigned char DriveNo, unsigned char mode, unsigned char timeout)
{
	// select drive
	ataDriveSelect(DriveNo);
	// Wait for drive to be ready
	ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);

	// set mode
	switch(mode)
	{
	case ATA_DISKMODE_SPINDOWN:		ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SPINDOWN); break;
	case ATA_DISKMODE_SPINUP:		ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SPINUP); break;
	case ATA_DISKMODE_SETTIMEOUT:
		ataWriteByte(ATA_REG_SECCOUNT, timeout);
		ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_IDLE_5SU);
		break;
	case ATA_DISKMODE_SLEEP:		ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SLEEP); break;
	default:
		break;
	}
}



//*****************************************************************************
// Function: ataReadDataBuffer
// Parameters: Buffer, numBytes
// Returns: none
//
// Description: The Buffer will be filled with the readed data
//*****************************************************************************
void ataReadDataBuffer(unsigned char *Buffer, unsigned short numBytes)
{
	register unsigned int i asm ("r16");

	DDR_DATAL = 0x00; 		      	// Use the PORT DATAH as an input
	DDR_DATAH = 0x00; 		      	// Use the PORT DATAL as an input
	PORT_DATAL= 0xFF;				// habilita pull-ups
	PORT_DATAH= 0xFF;				// habilita pull-ups
	PORT_ADDR = PORT_ADDR & 0xe0; 		// Clear the lower 5 bits of the address line
	PORT_ADDR = PORT_ADDR | (ATA_REG_DATA & 0x1f); 	// Assert the address Line

	for (i=0; i< numBytes; i+=2)
	{
		cbi(PORT_IDE_RD, PIN_IDE_RD);
	  	__asm volatile ("NOP");
	  	__asm volatile ("NOP");
	  	*(Buffer++)= PIN_DATAL;
	  	*(Buffer++)= PIN_DATAH;
		sbi(PORT_IDE_RD, PIN_IDE_RD);
	}
}


////////////////////
#ifndef ATA_READ_ONLY
//*****************************************************************************
// Function: ataWriteDataBuffer
// Parameters: Buffer, numBytes
// Returns: none
//
// Description: The entire Buffer will be pulled out to the ata dispositive
//*****************************************************************************
void ataWriteDataBuffer(unsigned char *Buffer, unsigned short numBytes)
{
	register unsigned int i asm ("r16");

	DDR_DATAL = 0xFF; 		      	// Use the PORT DATAH as an output
	DDR_DATAH = 0xFF; 		      	// Use the PORT DATAL as an output
	PORT_ADDR = PORT_ADDR & 0xe0; 		// Clear the lower 5 bits of the address line
	PORT_ADDR = PORT_ADDR | (ATA_REG_DATA & 0x1f); 	// Assert the address Line

	for (i=0; i< numBytes; i+=2)
	{
	  	PORT_DATAL= *(Buffer++);
	  	PORT_DATAH= *(Buffer++);
	  	cbi(PORT_IDE_WR, PIN_IDE_WR);
	  	__asm volatile ("NOP");
	  	__asm volatile ("NOP");
		sbi(PORT_IDE_WR, PIN_IDE_WR);
	}
}
#endif
////////////////////


//*****************************************************************************
// Function: ataStatusWait
// Parameters: mask, waitStatus
// Returns: the wait status
//
// Description: Read the Status form the hard disk until the result be equal waitStatus
//*****************************************************************************
unsigned char ataStatusWait(unsigned char mask, unsigned char waitStatus)
{
	register unsigned char status;

	// wait for desired status
	while( ((status = ataReadByte(ATA_REG_ACTSTATUS)) & mask) == waitStatus );
	return status;
}

//*****************************************************************************
// Function: ataReadSectorCHS
// Parameters: Driver, Head, Track, Sector, Buffer
// Returns: on Suscefull returns 0, the result errors otherwise.
//
// Description: Read one Sector (512 Bytes) from the ata dispositive
//*****************************************************************************
unsigned char ataReadSectorsCHS(	unsigned char Drive,
											unsigned char Head,
											unsigned int Track,
											unsigned char Sector,
											unsigned char *Buffer)
{
  	unsigned char temp;

	// Wait for drive to be ready
	temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);

  	// Prepare parameters...
	ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head
	ataWriteByte(ATA_REG_CYLHI, Track>>8);  		// MSB of track
	ataWriteByte(ATA_REG_CYLLO, Track);     		// LSB of track
  	ataWriteByte(ATA_REG_STARTSEC, Sector);    	// sector
	ataWriteByte(ATA_REG_SECCOUNT, 1);			// # of sectors

	// Issue read sector command...
  	ataWriteByte(ATA_REG_CMDSTATUS1, 0x21);

	// Wait for drive to be ready
	temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);

	if (temp & ATA_SR_ERR)
		return 1;

	// Wait for drive to request data transfer
	ataStatusWait(ATA_SR_DRQ, 0);

	// read data from drive
	ataReadDataBuffer(Buffer, 512);

	// Return the error bit from the status register...
	temp = ataReadByte(ATA_REG_CMDSTATUS1);	// read status register

	return (temp & ATA_SR_ERR) ? 1:0;
}


////////////////////
#ifndef ATA_READ_ONLY
//*****************************************************************************
// Function: ataWriteSectorsCHS
// Parameters: Driver, Head, Track, Sector, Buffer
// Returns: on Suscefull returns 0, the result errors otherwise.
//
// Description: Write one Sector (512 Bytes) to the ata dispositive
//*****************************************************************************
unsigned char ataWriteSectorsCHS(unsigned char Drive,
											unsigned char Head,
											unsigned int Track,
											unsigned char Sector,
											unsigned char *Buffer)
{
  	unsigned char temp;

	// Wait for drive to be ready
	temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);

  	// Prepare parameters...
	ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head
	ataWriteByte(ATA_REG_CYLHI, Track>>8);  		// MSB of track
	ataWriteByte(ATA_REG_CYLLO, Track);     		// LSB of track
  	ataWriteByte(ATA_REG_STARTSEC, Sector);    	// sector
	ataWriteByte(ATA_REG_SECCOUNT, 1);			// # of sectors

	// Issue write sector command
  	ataWriteByte(ATA_REG_CMDSTATUS1, 0x31);

	// Wait for drive to request data transfer
	ataStatusWait(ATA_SR_DRQ, 0);

	// write data to drive

⌨️ 快捷键说明

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