/* Nelson Li Jason Dirner EE 476 Final Project MP3 Player */ #include #include #include #define begin { #define end } // Timer 1 Constants #define prescale64 3 #define clear_on_match 8 // ATA- ATAPI Reg Addresses #define REG_ALT_STAT 0x16 #define REG_DRV_ADDR 0x17 #define REG_DATA 0x08 #define REG_ERROR 0x09 #define REG_SECT_CNT 0x0a #define REG_SECT_NUM 0x0b #define REG_CYL_LOW 0x0c #define REG_CYL_HIGH 0x0d #define REG_DRV_HEAD 0x0e #define REG_STAT_CMD 0x0f //ATA Status Register Bits #define ST_BSY 0x80 #define ST_DRDY 0x40 #define ST_DWF 0x20 #define ST_DSC 0x10 #define ST_DRQ 0x08 #define ST_CORR 0x04 #define ST_IDX 0x02 #define ST_ERR 0x01 void Initialize(void); // Initialize the MCU void soft_reset(void); // Reboot the Drive and set initial values unsigned char HDWrite_Reg(unsigned char Address, unsigned char data); unsigned char HDRead_data(unsigned char Addr); unsigned char HDWait_State(unsigned char test_bit); unsigned char HDRead_Sectors(unsigned int Head, unsigned int Cyl_High, unsigned int Cyl_Low, unsigned int Sector, unsigned int numSectors); unsigned char Data_In; // Input Data unsigned char Data_Error; // Data Error unsigned char Write_Error; // Write Error unsigned char temp; // temp variable unsigned int i,j,k,l; // Loop Variables unsigned char Buffer[50]; // Buffer Data unsigned int Buffersize; // Buffersize /* 1 Host Reset (VDD) 21 DMA Request (VDD) 2 22 3 Data[7] (PinB7) 23 Host I/O Write (PortD6) 4 Data[8] 24 5 Data[6] (PinB6) 25 Host I/O Read (PortD7) 6 Data[9] 26 7 Data[5] (PinB5) 27 I/O Channel Ready 8 Data[10] 28 Cable Select (OPTIONAL) 9 Data[4] (PinB4) 29 DMA Acknowledge (VDD) 10 Data[11] 30 11 Data[3] (PinB3) 31 Host Interrupt Request (PortD5) 12 Data[12] 32 Host 16 bit I/O 13 Data[2] (PinB2) 33 Host Address Bit 0 (PortD0) 14 Data[13] 34 Pass Diagnostics 15 Data[1] (PinB1) 35 Host Address Bit 1 (PortD1) 16 Data[14] 36 Host Address Bit 2 (PortD2) 17 Data[0] (PinB0) 37 Host Chip select 0 (PortD4) 18 Data[15] 38 Host Chip select 1 (PortD3) 19 39 Drive Active/Drive 1 Present 20 40 */ //---------------------------------------------------------------- // Main Task Scheduler void main(void) begin unsigned int init = 0; //TEMPORARY Initialize(); soft_reset(); Data_Error = HDRead_Sectors(0,0,0,1,1); if (Data_Error != 0) printf("Error Reading Data %d\r\n", Data_Error); while(1) begin // Parse the first 50 sectors. if (init == 0) begin init++; printf("Jump Boot 0x%x\r\n",Buffer[0]); // Should Equal 0xEB or 0xE9 end end end //---------------------------------------------------------------- // Read Data from the Hardrive /* * 0 - Read All Data * 1 - Error Writing Drive/Head Register * 2 - No Data Ready to be Transmitted * 3 - Number of sectors read > Buffer size */ unsigned char HDRead_Sectors(unsigned int Head, unsigned int Cyl_High, unsigned int Cyl_Low, unsigned int Sector, unsigned int numSectors) begin // Prepare parameters... Write_Error = HDWrite_Reg( REG_DRV_HEAD, 0x77 ); Write_Error = HDWrite_Reg( REG_ERROR, 0xef ); // Set 8 bit mode // Write CHS Mode, Drive, and Head information Write_Error = HDWrite_Reg( REG_DRV_HEAD, (0xa0 | (Head & 0x0f)) ); if (Write_Error != 0) begin printf("Error Writing Drive/Head Register %d\r\n",Write_Error); printf("Error Register 0x%x\r\n",HDRead_data(REG_ERROR)); return 1; end while ( HDWait_State(ST_DRDY) != 1); // Wait until not busy and drive ready // LSB of Cylinder Write_Error = HDWrite_Reg(REG_CYL_LOW, Cyl_Low); if (Write_Error != 0) begin printf("Error Writing Cylinder Low Register %d\r\n",Write_Error); printf("Error Register 0x%x\r\n",HDRead_data(REG_ERROR)); return 1; end // MSB of Cylinder Write_Error = HDWrite_Reg(REG_CYL_HIGH,Cyl_High); if (Write_Error != 0) begin printf("Error Writing Cylinder High Register %d\r\n",Write_Error); printf("Error Register 0x%x\r\n",HDRead_data(REG_ERROR)); return 1; end // Starting Sector Number Write_Error = HDWrite_Reg(REG_SECT_NUM,Sector); if (Write_Error != 0) begin printf("Error Writing Sector Number Register %d\r\n",Write_Error); printf("Error Register 0x%x\r\n",HDRead_data(REG_ERROR)); return 1; end // Number of Sectors to Read Write_Error = HDWrite_Reg(REG_SECT_CNT,numSectors); if (Write_Error != 0) begin printf("Error Writing Number of Sector Register %d\r\n",Write_Error); printf("Error Register 0x%x\r\n",HDRead_data(REG_ERROR)); return 1; end // Issue read sector command... // Initialize Drive Parameters HDWrite_Reg(REG_STAT_CMD, 0x91); printf("ALT_STAT_CMD = 0x%x\r\n",HDRead_data(REG_ALT_STAT)); // HDWrite_Reg(REG_STAT_CMD, 0xc4); HDWrite_Reg(REG_STAT_CMD, 0x20); //Read Sector Command if (Write_Error != 0) begin printf("Error Writing Command to Read. %d\r\n",Write_Error); printf("Error Register 0x%x\r\n",HDRead_data(REG_ERROR)); return 1; end printf("Error Register = 0x%x\r\n", HDRead_data(REG_ERROR)); delay_us(5); // Wait 5 uS k = 0; // For each sector requested, Read Data for (i=0; i Buffersize) begin printf("Buffersize too small, Number of Sectors Read: %d\r\n", i); return 3; end DDRD = DDRD & 0xdf; // Use PIND.5 as input // loop reading until Host Interrupt is set while ( PIND.5 != 1 ) begin printf("Host Interrupt = %d\r\n",PIND.5); end // Read Status Register to reset Host Interrupt Write_Error = HDRead_data(REG_STAT_CMD); if ( (Write_Error & 0x08) == 1) begin printf(" No Data Ready to be trasmitted\r\n"); return 2; end else if ( (Write_Error & 0x01) == 1) begin Write_Error = HDRead_data(REG_ERROR); printf("Error Reading Sector %d : 0x%x\r\n", numSectors, Write_Error); return 2; end Buffer[k++] = HDRead_data(REG_DATA); end return 0; end //---------------------------------------------------------------- // Wait Status - Check to status Register unsigned char HDWait_State(unsigned char test_bit) begin temp = HDRead_data(REG_ALT_STAT); // Test a bit in the status register k = 0x0f; while(((temp & test_bit) != test_bit) && (k > 0) ) begin k--; temp = HDRead_data(REG_ALT_STAT); delay_ms(1); end if(k>0) return 1; else return 0; end //---------------------------------------------------------------- // Write to Hardive registers to setup data transfer unsigned char HDWrite_Reg(unsigned char address, unsigned char data) begin DDRB = 0xff; // Use PORTB an an output PORTD = PORTD & 0xe0; // Clear the Lower 5 bits of the Address Line PORTD = PORTD | (address & 0x1f); // Assert the Address line PORTB = data; // Output the data delay_us(1); PORTD.6 = 0; // Assert DIOW delay_us(1); PORTD.6 = 1; // Negate DIOW return HDWait_State(ST_ERR); end //---------------------------------------------------------------- // Read the Harddrive data registers unsigned char HDRead_data(unsigned char Addr) begin Data_In = 0; DDRB = 0x00; // Use the PORTB as an input PORTD = PORTD & 0xe0; // Clear the lower 5 bits of the address line PORTD = PORTD | (Addr & 0x1f); // Assert the address Line PORTD.7 = 0; // Assert DIOR delay_us(1); Data_In = PINB; PORTD.7 = 1; // Negate DIOR delay_us(1); return (Data_In); end //---------------------------------------------------------------- // software reset of the drive void soft_reset(void) begin printf("ATA Software Reset\r\n"); HDWrite_Reg(REG_ALT_STAT, 4); // Assert Software reboot. // Wait until drive clear BUSY Bit in Alternate Status Register while(HDWait_State(ST_BSY) == 1) begin end delay_us(10); HDWrite_Reg(REG_ALT_STAT, 0); delay_us(10); end //---------------------------------------------------------------- // Initialize the MCU void Initialize(void) begin DDRB = 0x00; // Use PortB as the input from the hardrive DDRD = 0xdf; // Use PortD as the output for the hardrive // But use PORD.5 as host interrupt (INPUT) PORTD = 0xc0; // Initialize port D to c0. // Serial Setup UCR = 0x18; UBRR = 25; // Variable Initialization Data_Error = 0; // Data Read Error Data_In = 0; // Initialize Data_in to zero Write_Error = 0; Buffersize = 50; // Set Buffersize to 512 Bytes for (l = 0; l < Buffersize;l++) begin // Initialize Buffer to zero Buffer[l] = 0; end putsf("\r\nMP3 Player version 1.0\r\n"); // Turn interrupts on #asm ; sei #endasm end