Revision: 1344 Author: [email protected] Date: Fri Sep 25 22:56:26 2009 Log: added hard disk lib procedures for same easy usage as sd card lib. pata_hd_start_read, pata_hd_read_data, pata_hd_stop_read, also added 18f452 example http://code.google.com/p/jallib/source/detail?r=1344
Added: /trunk/sample/18f452_pata_hard_disk.jal Modified: /trunk/include/external/storage/harddisk/pata_hard_disk.jal /trunk/sample/16f877_pata_hard_disk.jal ======================================= --- /dev/null +++ /trunk/sample/18f452_pata_hard_disk.jal Fri Sep 25 22:56:26 2009 @@ -0,0 +1,200 @@ +-- Title: Hard disk library for communicating with parallel ata hard drives +-- with a 40 pin ide connector. +-- Author: Matthew Schinkel - borntechi.com, copyright (c) 2009, all rights reserved. +-- Adapted-by: +-- Compiler: >=2.4k +-- +-- This file is part of jallib (http://jallib.googlecode.com) +-- Released under the BSD license (http://www.opensource.org/licenses/bsd-license.php) +-- +-- Description: this library provides example usage for pata/ide hard disk drives. +-- includes examples for : spin up / spin down drive +-- : read sectors +-- : identify drive +-- : write sectors +-- +-- Sources: +-- "connecting ide drives by tilmann reh" - http://www.gaby.de/gide/IDE-TCJ.txt +-- IDE hardware reference & information document by alex t. ivopol +-- ATA Attachement with Packet Interface 6 - d1410r3-ATA-ATAPI-6.pdf +-- + +-- include chip +;include 16f877 -- target picmicro +;include 16f877a -- target picmicro +include 18F452 -- target picmicro + +-- this program assumes a 20 mhz resonator or crystal +-- is connected to pins osc1 and osc2. +pragma target osc hs -- hs crystal or resonator +pragma target clock 20_000_000 -- oscillator frequency +-- +pragma target wdt disabled +pragma target lvp disabled +-- + +enable_digital_io() -- disable all analog pins if any + +include delay -- include the delay library + +-- setup uart for communication +const usart_hw_serial = true -- true = rs232, false = spi +const serial_hw_baudrate = 38400 -- set the baudrate +include serial_hardware +serial_hw_init() + +-- setup hard disk library +CONST BYTE PATA_HD_USE_CS0_CS1_PINS = FALSE -- set true if you will use Alternate Status, Digital Output or Drive Address registers +const bit PATA_HD_NO_INVERTER = TRUE -- if true, an external inverter chip is not needed on /iowr, /iord, /cs0, /cs1 pins +-- pin assignments +var volatile byte pata_hd_data_low is portb -- data port (low bits) +var volatile byte pata_hd_data_low_direction is portb_direction +var volatile byte pata_hd_data_high is portd -- data port (high bits) +var volatile byte pata_hd_data_high_direction is portd_direction +var volatile bit pata_hd_a0 is pin_a0 +var volatile bit pata_hd_a0_direction is pin_a0_direction +var volatile bit pata_hd_a1 is pin_a1 +var volatile bit pata_hd_a1_direction is pin_a1_direction +var volatile bit pata_hd_a2 is pin_a2 +var volatile bit pata_hd_a2_direction is pin_a2_direction +var volatile bit pata_hd_iowr is pin_c2 +var volatile bit pata_hd_iowr_direction is pin_c2_direction +var volatile bit pata_hd_iord is pin_c1 +var volatile bit pata_hd_iord_direction is pin_c1_direction +;var volatile bit pata_hd_cs1 is pin_a3 +;var volatile bit pata_hd_cs1_direction is pin_a3_direction +;var volatile bit pata_hd_cs0 is pin_a4 +;var volatile bit pata_hd_cs0_direction is pin_a4_direction + +pata_hd_a0_direction = output -- register select pin +pata_hd_a1_direction = output -- register select pin +pata_hd_a2_direction = output -- register select pin +pata_hd_iowr_direction = output -- used for write pulse +pata_hd_iord_direction = output -- used for read pulse +;pata_hd_cs1_direction = output -- register select pin +;pata_hd_cs0_direction = output -- register select pin + +include pata_hard_disk -- include the parallel ata ide hard disk library +pata_hd_init() -- initialize startup settings + +-- Function for sending hard disk data via serial port, data is read 2 bytes at a time. +procedure send_word(byte in lowbit, byte in highbit) is + serial_hw_write( lowbit ) -- send 1st serial data byte + serial_hw_write( highbit ) -- send 2nd serial data byte +end procedure + +-- Declare variables for this example. +var byte in_a +var byte in_b + +-----main prog---- + +_usec_delay (1_000_000) -- wait for power to stabilize + +-- send "start" to pc / test uart communication +send_word ("S", "T") +send_word ("A", "R") +send_word ("T", 0x20) +send_word (13, 10) +send_word (13, 10) + +-- ---------------------------------------------------------------------------- +-- Example spin up & spin down drive command +-- ---------------------------------------------------------------------------- +for 2 loop + pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_SPIN_UP) -- turn on motor + _USEC_DELAY (5_000_000) -- 5 sec delay + pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_SPIN_DOWN) -- turn off motor + _USEC_DELAY (5_000_000) -- 5 sec delay +END LOOP + +pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_SPIN_UP) -- turn on motor + +_USEC_DELAY (10_000_000) -- wait 10 seconds before next example + + +-- ---------------------------------------------------------------------------- +-- Example read sectors command +-- ---------------------------------------------------------------------------- + +pata_hd_start_read(0) -- get drive ready for reading at sector 0 (boot sector) + +-- Read one sector +for 256 loop -- 256 words, 512 bytes per sector + pata_hd_read_data (in_b, in_a) -- read data + send_word (in_b, in_a) -- send data via serial port +end loop + +-- You will see hard disk LED on during this delay +-- because you did not finnish reading. +_USEC_DELAY (2_000_000) -- 2 second delay + +-- Read 2nd sector. +for 256 loop -- 256 words, 512 bytes per sector + pata_hd_read_data (in_b, in_a) -- read data + send_word (in_b, in_a) -- send data via serial port +end loop + +pata_hd_stop_read() -- tell drive you are done reading +-- hard disk led will turn off at this point. + +_USEC_DELAY (10_000_000) -- wait 10 seconds before next example + +-- ---------------------------------------------------------------------------- +-- Example identify drive command (Read drive information) +-- size of drive, make, model, serial number, etc. +-- ---------------------------------------------------------------------------- + +-- send the identify drive command +pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_IDENTIFY_DRIVE) + +-- check if drive is ready reading and set data ports as inputs +-- this MUST be used before reading since we did not use pata_hd_start_read +pata_hd_data_request(PATA_HD_WAIT_READ) + +-- Read 512 bytes +for 256 loop -- 256 words, 512 bytes per sector + pata_hd_read_data (in_b, in_a) -- read data + send_word (in_a, in_b ) -- send data via serial port +end loop -- drive info high/low bytes are in reverse order + + +_USEC_DELAY (10_000_000) -- wait 10 seconds before next example + +-- ---------------------------------------------------------------------------- +-- Example write sectors command +-- note: this will over write data currently on your drive +-- ---------------------------------------------------------------------------- + +pata_hd_start_write(200) -- tell hd to get ready for reading + +-- now write 1 sector + most of 2nd sector, data will not be written unless 512 bytes are sent +for 256 + 250 loop + pata_hd_write_data(0xCC, 0xDD) -- write data 0xCC, 0xDD over and over +end loop +-- first sector has been written to the disk since 512 bytes where sent, +-- but 2nd sector is not finnished, only 500 bytes sent, +-- so lets finnish the sector with 6 more write pulses (0xFF's as data) +pata_hd_write_to_sector_end(0xFF) + +pata_hd_stop_write() -- tell hd we are done writing + +-- Now read the 1st sector you just wrote, should get 0xCC, 0xDD over and over +pata_hd_start_read(200) -- get drive ready for reading +for 256 + 250 loop -- read 512 bytes + 500 bytes + pata_hd_read_data (in_b, in_a) -- read data + send_word (in_b, in_a) -- send data via serial port +end loop + +-- if you want, you can read back the last 6 bytes that are 0xFF +for 6 loop + pata_hd_read_data (in_b, in_a) -- read data + send_word (in_b, in_a) -- send data via serial port +end loop + +pata_hd_stop_read() -- tell drive we are done reading + +-- We're done, lets turn off the hd motor +pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_SPIN_DOWN) + + ======================================= --- /trunk/include/external/storage/harddisk/pata_hard_disk.jal Fri Jul 10 07:32:57 2009 +++ /trunk/include/external/storage/harddisk/pata_hard_disk.jal Fri Sep 25 22:56:26 2009 @@ -10,49 +10,36 @@ -- Description: this library provides functions for pata/ide hard disk drives. -- -- Sources: --- "connecting ide drives by tilmann reh" - http://www.gaby.de/gide/ide-tcj.txt +-- "connecting ide drives by tilmann reh" - http://www.gaby.de/gide/IDE-TCJ.txt -- IDE hardware reference & information document by alex t. ivopol -- ATA Attachement with Packet Interface 6 - d1410r3-ATA-ATAPI-6.pdf -- --- Notes: If you are not using Alternate Status, Digital Output or Drive Address registers --- pins cs1 & cs0 can be saved by connecting these ide pins to cs0-high, cs1-low --- --- Variable descriptions: --- pata_hd_word_count - counts words read from disk, 256 words in a sector. --- You should read full sectors and MUST write full sectors. +-- Notes: - If you are not using Alternate Status, Digital Output or Drive Address registers +-- pins cs1 & cs0 can be saved by connecting these ide pins to cs0-high, cs1-low +-- at ide connector. normal operation does not require these pins. Set +-- "CONST BYTE PATA_HD_USE_CS0_CS1_PINS = TRUE" if you will be using +-- these registers +-- - You MUST write full sectors of 512 bytes. +-- - this lib does not do error checking -- -- Functions descriptions: --- pata_hd_init - initialize startup settings --- pata_hd_register_write - Select a register and give it a command --- or data. --- pata_hd_register_read - Select a register and get data from it. --- pata_hd_write_pulse - Send a number of write pulses to data register, --- sending 0's as data. --- - Used to get to the end of a sector or to get to a --- certain location in a sector. --- - Increments pata_hd_word_count. --- pata_hd_read_pulse - Send a number of read pulses to data register --- without getting any data. --- - Used to get to the end of a sector or to get to a certain --- location in a sector. --- - Increments pata_hd_word_count. --- pata_hd_go_to_sector - Go to a specific sector. --- - Set sector count value (number of sectors to read) --- pata_hd_set_address - Select lba/chs mode and master/slave drive. --- - set drive sector address --- - Set sector count value (number of sectors to read) --- pata_hd_data_request - Wait for drive to be ready for a data transfer. --- - Sets data pins as inputs or outputs for read/write. --- THIS FUNCTION MUST BE USED BEFORE READING/WRITING SECTORS. --- pata_hd_read_data - Read two bytes from disk. --- - must use pata_hd_data_request(PATA_HD_WAIT_READ) --- before each 256 reads (before reading each sector). --- - There are 512 bytes in a sector --- pata_hd_write_data - Write two bytes to disk --- - must use pata_hd_data_request(PATA_HD_WAIT_WRITE) --- before each 256 writes (before writing each sector). --- Data will not be written unless 256 writes are sent. --- - There are 512 bytes in a sector +-- pata_hd_init - initialize startup settings, recalibrates drive. +-- pata_hd_start_read - Get drive ready for reading at specified sector +-- pata_hd_read_data - Read two bytes from disk. +-- pata_hd_stop_read - Tell drive you are done reading. +-- pata_hd_start_write - Get drive ready for writing at specified sector +-- pata_hd_write_data - Write two bytes to disk +-- - Data will not be written unless 256 writes are sent. +-- - There are 512 bytes in a sector +-- pata_hd_write_to_sector_end - Finnish writing the current sector with input byte. +-- pata_hd_stop_write - Tell drive you are done writing. +-- pata_hd_write_pulse - Send a number of write pulses to data register, +-- sending 0's as data. +-- - Used to get to a certain location in a sector while +-- writing 0's as data +-- pata_hd_read_pulse - Send a number of read pulses to data register +-- without getting any data. +-- - Used to get to a certain location in a sector. -- -- Pin-outs - PATA IDE 40 pin connector -- Power connector - black ground, red +5v, yellow +12v @@ -64,51 +51,19 @@ -- 21,27,20,29,31,32,34, leave not connected -- 3,5,7,9,11,13,15,17 - D0-D7, connect direct to pata_hd_data_low pins -- 18,16,14,12,10,8,6,4 - D8-D15, connect direct to pata_hd_data_high pins --- 23 - /IOW, connect direct to iowr -- see "const bit PATA_HD_NO_INVERTER" --- 25 - /IOR, connect direct to pata_hd_iord -- see "const bit PATA_HD_NO_INVERTER" --- 38 - /cs0, connect direct to pata_hd_cs0 -- see "const bit PATA_HD_NO_INVERTER" --- 37 - /cs1, connect direct to pata_hd_cs1 -- see "const bit PATA_HD_NO_INVERTER" +-- 23 - /IOW, connect direct to iowr -- see constant PATA_HD_NO_INVERTER +-- 25 - /IOR, connect direct to pata_hd_iord -- see constant PATA_HD_NO_INVERTER +-- 38 - /cs0, connect direct to pata_hd_cs0 (or 5v) -- see constant PATA_HD_NO_INVERTER & PATA_HD_USE_CS0_CS1_PINS +-- 37 - /cs1, connect direct to pata_hd_cs1 (or gnd) -- see constant PATA_HD_NO_INVERTER & PATA_HD_USE_CS0_CS1_PINS -- 36 - A2, connect direct to pata_hd_a2 -- 33 - A1, connect direct to pata_hd_a1 -- 35 - A0, connect direct to pata_hd_a0 -- Watch for open drain pins on your pic, use pull-up resistors. -- --- Declare the following pin assignments and variables: --- var volatile byte pata_hd_data_low is portb -- data port (low bits) --- var volatile byte pata_hd_data_low_direction is portb_direction --- var volatile byte pata_hd_data_high is portd -- data port (high bits) --- var volatile byte pata_hd_data_high_direction is portd_direction --- var volatile bit pata_hd_a0 is pin_a0 --- var volatile bit pata_hd_a0_direction is pin_a0_direction --- var volatile bit pata_hd_a1 is pin_a1 --- var volatile bit pata_hd_a1_direction is pin_a1_direction --- var volatile bit pata_hd_a2 is pin_a2 --- var volatile bit pata_hd_a2_direction is pin_a2_direction --- var volatile bit pata_hd_cs1 is pin_a3 --- var volatile bit pata_hd_cs1_direction is pin_a3_direction --- var volatile bit pata_hd_cs0 is pin_a4 --- var volatile bit pata_hd_cs0_direction is pin_a4_direction --- var volatile bit pata_hd_iowr is pin_c2 --- var volatile bit pata_hd_iowr_direction is pin_c2_direction --- var volatile bit pata_hd_iord is pin_c1 --- var volatile bit pata_hd_iord_direction is pin_c1_direction --- --- pata_hd_a0_direction = output -- register select pin --- pata_hd_a1_direction = output -- register select pin --- pata_hd_a2_direction = output -- register select pin --- pata_hd_cs1_direction = output -- register select pin --- pata_hd_cs0_direction = output -- register select pin --- pata_hd_iowr_direction = output -- used for write pulse --- pata_hd_iord_direction = output -- used for read pulse --- --- var byte pata_hd_word_count = 0 -- counts words read so you know where you are in a sector, 256 words per sector. --- const bit PATA_HD_NO_INVERTER = true -- if true, an external inverter chip is not needed for /iowr, /iord, /cs0, /cs1 pins. --- --- include pata_hard_disk -- include the parallel ata ide hard disk library --- pata_hd_init() -- initialize startup settings --- --- - + +-- variables +var byte pata_hd_word_count = 0 -- counts words read from current sector, must be a byte +var byte pata_hd_sector_count = 0 -- counds sectors read, must be a byte. -- readable/writeable registers const PATA_HD_DATA_REG = 8 -- data register @@ -120,8 +75,8 @@ -- readable registers const PATA_HD_ERROR_REG = 9 -- error register -const PATA_HD_STATUS_REG = 15 -- status register -const PATA_HD_ALT_STATUS_REG = 16 -- alternate status +const PATA_HD_STATUS_REG = 15 -- status register (creates interupt) +const PATA_HD_ALT_STATUS_REG = 16 -- alternate status (no interupt) const PATA_HD_ADDRESS_REG = 17 -- drive address -- writeable registers @@ -142,11 +97,16 @@ const BIT PATA_HD_WAIT_READ = 0 -- wait for sector buffer to fill it's contents with data from disk platters const BIT PATA_HD_WAIT_WRITE = 1 -- wait for sector buffer to empty it's contents to disk platters +-- other vars +var dword pata_hd_sector_select = 0 +var bit pata_hd_48_bit_lba_support = false -- currently this lib does not support drives > 137,438,952,960 bytes (28 bit addressing) + -- "IDENTIFY DEVICE bit 10 word 83 indicates support for 48-bit addressing" - in ata8 pdf + -- from "connecting ide drives by tilmann reh" - http://www.gaby.de/gide/ide-tcj.txt -- List of commands and required parameters: --- -------------------------------------------------------------------- --- command type 7 6 5 4 3 2 1 0 hex parameters --- -------------------------------------------------------------------- +-- ----------------------------------------------------------------------------- +-- command type 7 6 5 4 3 2 1 0 hex parameters required +-- ----------------------------------------------------------------------------- -- recalibrate * 0 0 0 1 (rate) 10-1F d -- read sector * 0 0 1 0 0 m l t 20-27 sc,sn,c,d,h -- write sector * 0 0 1 1 0 m l t 30-37 sc,sn,c,d,h @@ -177,35 +137,25 @@ -- sdh (sector size, drive, head) d,h -- status reg. / command reg. - --- ---------------------------------------------------------------------------- --- initialize startup settings --- ---------------------------------------------------------------------------- -procedure pata_hd_init() is begin - -- set startup setting for read/read pins - pata_hd_iowr = low ^ PATA_HD_NO_INVERTER - pata_hd_iord = low ^ PATA_HD_NO_INVERTER -end procedure - -- ---------------------------------------------------------------------------- -- Set register select pins to selected register, for internal use only. -- ---------------------------------------------------------------------------- -procedure pata_hd_select_register(byte in register) is - - -- set register select pins one at a time - var bit bit0 at register : 0 - var bit bit1 at register : 1 - var bit bit2 at register : 2 - var bit bit3 at register : 3 - var bit bit4 at register : 4 - - -- setup data bits - pata_hd_a0 = bit0 - pata_hd_a1 = bit1 - pata_hd_a2 = bit2 +procedure pata_hd_select_register(byte in register) is + -- set register select pins one at a time + var bit bit0 at register : 0 + var bit bit1 at register : 1 + var bit bit2 at register : 2 + var bit bit3 at register : 3 + var bit bit4 at register : 4 + + -- setup data bits + pata_hd_a0 = bit0 + pata_hd_a1 = bit1 + pata_hd_a2 = bit2 + if PATA_HD_USE_CS0_CS1_PINS == TRUE then pata_hd_cs1 = bit3 ^ PATA_HD_NO_INVERTER pata_hd_cs0 = bit4 ^ PATA_HD_NO_INVERTER - + end if end procedure -- ---------------------------------------------------------------------------- @@ -214,23 +164,25 @@ -- ---------------------------------------------------------------------------- procedure pata_hd_data_request(bit in read_write) is begin var bit s - var bit drq at pata_hd_data_low : 3 -- set drq pin to check - s = 0 - - -- set data pins as inputs - pata_hd_data_low_direction = all_input - pata_hd_data_high_direction = all_input + var bit drq at pata_hd_data_low : 3 -- set drq pin to check + s = 0 + + -- set data pins as inputs + pata_hd_data_low_direction = all_input + pata_hd_data_high_direction = all_input pata_hd_select_register (PATA_HD_STATUS_REG) -- select status register - -- wait for drq in status register to be high. - while s == 0 loop - pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse - if drq == high then - s = 1 -- exit loop - end if - pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse - end loop + -- wait for drq in status register to be high. + -- may get stuck in loop if drq never goes high + -- you can modify to check for errors or have a time-out + while s == 0 loop + pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse + if drq == high then + s = 1 -- exit loop + end if + pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse + end loop -- after drive is ready for data transfer, go to the data register pata_hd_select_register (PATA_HD_DATA_REG) @@ -240,9 +192,8 @@ else -- if we are waiting to write data out -- set data ports to outputs pata_hd_data_low_direction = all_output - pata_hd_data_high_direction = all_output + pata_hd_data_high_direction = all_output end if - end procedure -- ---------------------------------------------------------------------------- @@ -251,24 +202,25 @@ -- ---------------------------------------------------------------------------- procedure pata_hd_busy() is begin var bit s - s = 1 - var bit bsy at pata_hd_data_low : 7 -- set bsy pin to check - - -- set data pins as inputs - pata_hd_data_low_direction = all_input - pata_hd_data_high_direction = all_input - - pata_hd_select_register (PATA_HD_STATUS_REG) -- select status register - - -- wait for bsy in status register to be high - while s == 1 loop - pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse - if bsy == low then - s = 0 -- end loop - end if - pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse - end loop - + s = 1 + var bit bsy at pata_hd_data_low : 7 -- set bsy pin to check + + -- set data pins as inputs + pata_hd_data_low_direction = all_input + pata_hd_data_high_direction = all_input + + pata_hd_select_register (PATA_HD_STATUS_REG) -- select status register + + -- wait for bsy in status register to be high + -- may get stuck in loop if bsy never goes low + -- you can modify to check for errors or have a time-out + while s == 1 loop + pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse + if bsy == low then + s = 0 -- end loop + end if + pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse + end loop end procedure -- ---------------------------------------------------------------------------- @@ -276,74 +228,74 @@ -- ---------------------------------------------------------------------------- procedure pata_hd_drive_ready() is begin var bit s - s = 1 - var bit rdy at pata_hd_data_low : 6 -- set rdy pin to check - - -- set data pins as inputs - pata_hd_data_low_direction = all_input - pata_hd_data_high_direction = all_input + s = 1 + var bit rdy at pata_hd_data_low : 6 -- set rdy pin to check + + -- set data pins as inputs + pata_hd_data_low_direction = all_input + pata_hd_data_high_direction = all_input pata_hd_select_register (PATA_HD_STATUS_REG) -- select status register - -- wait for rdy in status register to be high - while s == 1 loop - pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse - if rdy == high then - s = 0 -- end loop - end if - pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse - end loop - + -- wait for rdy in status register to be high + -- may get stuck in loop if rdy never goes high + -- you can modify to check for errors or have a time-out + while s == 1 loop + pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse + if rdy == high then + s = 0 -- end loop + end if + pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse + end loop end procedure -- ---------------------------------------------------------------------------- -- Select a register and give it a command or data. -- ---------------------------------------------------------------------------- procedure pata_hd_register_write(byte in register, byte in low_byte) is begin - var byte high_byte = 0 - - -- registers may not be accessed unless drive is not busy - pata_hd_busy() - - if register == PATA_HD_COMMAND_REG then - -- make sure the drive is up to speed and ready for a command - pata_hd_drive_ready() - end if - - pata_hd_select_register (register) -- select register - - -- set data ports to outputs - pata_hd_data_low_direction = all_output - pata_hd_data_high_direction = all_output - - -- send the data trough the ide interface - pata_hd_data_low = low_byte -- set low data byte - pata_hd_data_high = high_byte -- set high data byte - pata_hd_iowr = high ^ PATA_HD_NO_INVERTER -- send write pulse - pata_hd_iowr = low ^ PATA_HD_NO_INVERTER - + var byte high_byte = 0 + + -- registers may not be accessed unless drive is not busy + pata_hd_busy() + + if register == PATA_HD_COMMAND_REG then + -- make sure the drive is up to speed and ready for a command + pata_hd_drive_ready() + end if + + pata_hd_select_register (register) -- select register + + -- set data ports to outputs + pata_hd_data_low_direction = all_output + pata_hd_data_high_direction = all_output + + -- send the data trough the ide interface + pata_hd_data_low = low_byte -- set low data byte + pata_hd_data_high = high_byte -- set high data byte + pata_hd_iowr = high ^ PATA_HD_NO_INVERTER -- send write pulse + pata_hd_iowr = low ^ PATA_HD_NO_INVERTER end procedure -- ---------------------------------------------------------------------------- -- Select a register and get data from it. -- ---------------------------------------------------------------------------- procedure pata_hd_register_read(byte in register, byte out low_byte) is begin - var byte high_byte - - -- registers may not be accessed unless drive is not busy - pata_hd_busy() - - pata_hd_select_register (register) -- select register - - -- set data ports to inputs - pata_hd_data_low_direction = all_input - pata_hd_data_high_direction = all_input - - -- get the data trough the ide interface - pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse - low_byte = pata_hd_data_low -- get low data byte - high_byte = pata_hd_data_high -- get high data byte - pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse + var byte high_byte + + -- registers may not be accessed unless drive is not busy + pata_hd_busy() + + pata_hd_select_register (register) -- select register + + -- set data ports to inputs + pata_hd_data_low_direction = all_input + pata_hd_data_high_direction = all_input + + -- get the data trough the ide interface + pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse + low_byte = pata_hd_data_low -- get low data byte + high_byte = pata_hd_data_high -- get high data byte + pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse end procedure -- ---------------------------------------------------------------------------- @@ -353,16 +305,15 @@ -- Increment pata_hd_word_count -- ---------------------------------------------------------------------------- procedure pata_hd_write_pulse( byte in z ) is begin - pata_hd_data_low = 0 pata_hd_data_high = 0 - + -- send write pulse z number of times - for z loop - pata_hd_word_count = pata_hd_word_count + 1 -- increment pata_hd_word_count - pata_hd_iowr = high ^ PATA_HD_NO_INVERTER -- send write pulse - pata_hd_iowr = low ^ PATA_HD_NO_INVERTER - end loop + for z loop + pata_hd_word_count = pata_hd_word_count + 1 -- increment pata_hd_word_count + pata_hd_iowr = high ^ PATA_HD_NO_INVERTER -- send write pulse + pata_hd_iowr = low ^ PATA_HD_NO_INVERTER + end loop end procedure -- ---------------------------------------------------------------------------- @@ -372,13 +323,25 @@ -- Increment pata_hd_word_count -- ---------------------------------------------------------------------------- procedure pata_hd_read_pulse(dword in z) is + if pata_hd_word_count == 0 & pata_hd_sector_count == 0 then + pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_READ_SECTOR) -- send the read command to the command register + pata_hd_data_request(PATA_HD_WAIT_READ) -- wait till the drive has data for you + elsif pata_hd_word_count == 0 then + pata_hd_data_request(PATA_HD_WAIT_READ) + end if + + if pata_hd_word_count == 255 then + pata_hd_sector_count = pata_hd_sector_count + 1 + end if + + ;pata_hd_word_count = pata_hd_word_count + 1 -- increment pata_hd_word_count -- send read pulse z number of times - for z loop - pata_hd_word_count = pata_hd_word_count + 1 - pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- send read pulse + for z loop + pata_hd_word_count = pata_hd_word_count + 1 + pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- send read pulse pata_hd_iord = low ^ PATA_HD_NO_INVERTER - end loop + end loop end procedure -- ---------------------------------------------------------------------------- @@ -389,7 +352,6 @@ -- Sector count value of 0 means 256 sectors will be read -- ---------------------------------------------------------------------------- procedure pata_hd_set_address(byte in pata_hd_head_addr, byte in cyl_high_addr, byte in cyl_low_addr, byte in sec_num_addr, byte in sec_count) is - -- select lba or chs mode var volatile byte pata_hd_sdh_val = 0b_1110_0000 var volatile bit pata_hd_lba at pata_hd_sdh_val : 6 @@ -399,13 +361,13 @@ pata_hd_lba = true -- 1 = lba mode, 0 = chs mode (not tested) pata_hd_slave = false -- 0 = master, 1 = slave (not tested) - pata_hd_register_write (PATA_HD_SEC_COUNT_REG,sec_count) -- set sec count register, sectors to read/write + pata_hd_register_write (PATA_HD_SEC_COUNT_REG,sec_count) -- set sec count register, sectors to read/write pata_hd_register_write (PATA_HD_SEC_NUM_REG,sec_num_addr) -- set sec number register address pata_hd_register_write (PATA_HD_CYL_LOW_REG,cyl_low_addr) -- set cyl low register address pata_hd_register_write (PATA_HD_CYL_HIGH_REG,cyl_high_addr) -- set cyl high register address -- set sector/drive/head register, head number -- pata_hd_head_val address can be 0 to 15 - pata_hd_register_write (PATA_HD_SDH_REG,pata_hd_sdh_val + pata_hd_head_addr) + pata_hd_register_write (PATA_HD_SDH_REG,pata_hd_sdh_val + pata_hd_head_addr) end procedure -- ---------------------------------------------------------------------------- @@ -429,34 +391,102 @@ pata_hd_set_address (pata_hd_head_addr,cyl_high_addr,cyl_low_addr,sec_num_addr,sec_count) end procedure +-- ---------------------------------------------------------------------------- +-- Get drive ready for reading at specified address +-- ---------------------------------------------------------------------------- +procedure pata_hd_start_read(dword in address) is + pata_hd_go_to_sector (address,0) + pata_hd_word_count = 0 -- reset number of words read from sector + pata_hd_sector_count = 0 -- reset number of sectors read +end procedure + -- ---------------------------------------------------------------------------- -- Read two bytes from disk. --- must use pata_hd_data_request(PATA_HD_WAIT_READ) before each 256 reads --- (before reading each sector) -- ---------------------------------------------------------------------------- procedure pata_hd_read_data(byte out low_byte, byte out high_byte) is - pata_hd_word_count = pata_hd_word_count + 1 -- increment pata_hd_word_count - - -- get the data trough the ide interface - pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse - low_byte = pata_hd_data_low -- get low data byte - high_byte = pata_hd_data_high -- get high data byte - pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse + if pata_hd_word_count == 0 & pata_hd_sector_count == 0 then -- if we are at beginning of read + pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_READ_SECTOR) -- send the read command to the command register + pata_hd_data_request(PATA_HD_WAIT_READ) -- wait till the drive has data for you + elsif pata_hd_word_count == 0 then -- if we are at beginning of a sector + pata_hd_data_request(PATA_HD_WAIT_READ) -- wait for data to be ready for read + end if + + if pata_hd_word_count == 255 then -- if we are at end of current sector + pata_hd_sector_count = pata_hd_sector_count + 1 -- increase sector count + end if + + pata_hd_word_count = pata_hd_word_count + 1 -- increment words read from current sector + + -- get the data trough the ide interface + pata_hd_iord = high ^ PATA_HD_NO_INVERTER -- start read pulse + low_byte = pata_hd_data_low -- get low data byte + high_byte = pata_hd_data_high -- get high data byte + pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- end read pulse end procedure +-- ---------------------------------------------------------------------------- +-- Tell drive you are done reading +-- ---------------------------------------------------------------------------- +procedure pata_hd_stop_read() is + pata_hd_register_write(PATA_HD_COMMAND_REG, 0xE1) -- set media idle +end procedure + +-- ---------------------------------------------------------------------------- +-- Get drive ready for writing at specified address +-- ---------------------------------------------------------------------------- +procedure pata_hd_start_write(dword in address) is + pata_hd_sector_select = address + pata_hd_word_count = 0 -- reset number of words written to sector + pata_hd_sector_count = 0 -- reset number of sectors written +end procedure + -- ---------------------------------------------------------------------------- -- Write two bytes to disk --- must use pata_hd_data_request(PATA_HD_WAIT_WRITE) before each 256 writes --- (before writing each sector) -- Data will not be written unless 256 writes are sent. -- ---------------------------------------------------------------------------- procedure pata_hd_write_data(byte in low_byte, byte in high_byte) is - pata_hd_word_count = pata_hd_word_count + 1 -- increment pata_hd_word_count - - -- send the data trough the ide interface - pata_hd_data_low = low_byte -- set low data byte - pata_hd_data_high = high_byte -- set high data byte - pata_hd_iowr = high ^ PATA_HD_NO_INVERTER -- send write pulse - pata_hd_iowr = low ^ PATA_HD_NO_INVERTER + if pata_hd_word_count == 0 then -- if we are at beginning of write + pata_hd_go_to_sector (pata_hd_sector_select,1) -- go to the uers selected sector, set to write 1 sector + pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_WRITE_SECTOR) -- send the write command to the command register + pata_hd_data_request(PATA_HD_WAIT_WRITE) -- wait till data is ready to be read + end if + + if pata_hd_word_count == 255 then -- if we are at the end of a sector + pata_hd_sector_count = pata_hd_sector_count + 1 -- increment sectors written + pata_hd_sector_select = pata_hd_sector_select + 1 -- increment the users selected sector + end if + + pata_hd_word_count = pata_hd_word_count + 1 -- increment words written to disk + + -- send the data trough the ide interface + pata_hd_data_low = low_byte -- set low data byte + pata_hd_data_high = high_byte -- set high data byte + pata_hd_iowr = high ^ PATA_HD_NO_INVERTER -- send write pulse + pata_hd_iowr = low ^ PATA_HD_NO_INVERTER end procedure +-- ---------------------------------------------------------------------------- +-- Tell drive you are done writing +-- ---------------------------------------------------------------------------- +ALIAS pata_hd_stop_write is pata_hd_stop_read -- same procedure as stop read + +-- ---------------------------------------------------------------------------- +-- Finnish writing the current sector with input byte. +-- ---------------------------------------------------------------------------- +procedure pata_hd_write_to_sector_end(byte in input_byte) is + var byte x + x = 0 - pata_hd_word_count -- calculate how many words are left to write to current sector + for x loop -- loop till end of sector + pata_hd_write_data(input_byte, input_byte) -- write 2 bytes + end loop +end procedure + +-- ---------------------------------------------------------------------------- +-- initialize startup settings +-- ---------------------------------------------------------------------------- +procedure pata_hd_init() is begin + -- set startup setting for read/read pins + pata_hd_iowr = low ^ PATA_HD_NO_INVERTER -- start write pulse pin low + pata_hd_iord = low ^ PATA_HD_NO_INVERTER -- start read pulse pin low + pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_RECALIBRATE) -- recalibrate the drive +end procedure ======================================= --- /trunk/sample/16f877_pata_hard_disk.jal Mon Aug 17 12:03:37 2009 +++ /trunk/sample/16f877_pata_hard_disk.jal Fri Sep 25 22:56:26 2009 @@ -1,8 +1,8 @@ -- Title: Hard disk library for communicating with parallel ata hard drives -- with a 40 pin ide connector. -- Author: Matthew Schinkel - borntechi.com, copyright (c) 2009, all rights reserved. --- Adapted-by: Albert Faber --- Compiler: >=2.4l +-- Adapted-by: +-- Compiler: >=2.4k -- -- This file is part of jallib (http://jallib.googlecode.com) -- Released under the BSD license (http://www.opensource.org/licenses/bsd-license.php) @@ -14,7 +14,7 @@ -- : write sectors -- -- Sources: --- "connecting ide drives by tilmann reh" - http://www.gaby.de/gide/ide-tcj.txt +-- "connecting ide drives by tilmann reh" - http://www.gaby.de/gide/IDE-TCJ.txt -- IDE hardware reference & information document by alex t. ivopol -- ATA Attachement with Packet Interface 6 - d1410r3-ATA-ATAPI-6.pdf -- @@ -43,36 +43,36 @@ include serial_hardware serial_hw_init() +-- setup hard disk library +CONST BYTE PATA_HD_USE_CS0_CS1_PINS = FALSE -- set true if you will use Alternate Status, Digital Output or Drive Address registers +const bit PATA_HD_NO_INVERTER = TRUE -- if true, an external inverter chip is not needed on /iowr, /iord, /cs0, /cs1 pins -- pin assignments -alias pata_hd_data_low is portb -- data port (low bits) -alias pata_hd_data_low_direction is portb_direction -alias pata_hd_data_high is portd -- data port (high bits) -alias pata_hd_data_high_direction is portd_direction -alias pata_hd_a0 is pin_a0 -alias pata_hd_a0_direction is pin_a0_direction -alias pata_hd_a1 is pin_a1 -alias pata_hd_a1_direction is pin_a1_direction -alias pata_hd_a2 is pin_a2 -alias pata_hd_a2_direction is pin_a2_direction -alias pata_hd_cs1 is pin_a3 -alias pata_hd_cs1_direction is pin_a3_direction -alias pata_hd_cs0 is pin_a4 -alias pata_hd_cs0_direction is pin_a4_direction -alias pata_hd_iowr is pin_c2 -alias pata_hd_iowr_direction is pin_c2_direction -alias pata_hd_iord is pin_c1 -alias pata_hd_iord_direction is pin_c1_direction +var volatile byte pata_hd_data_low is portb -- data port (low bits) +var volatile byte pata_hd_data_low_direction is portb_direction +var volatile byte pata_hd_data_high is portd -- data port (high bits) +var volatile byte pata_hd_data_high_direction is portd_direction +var volatile bit pata_hd_a0 is pin_a0 +var volatile bit pata_hd_a0_direction is pin_a0_direction +var volatile bit pata_hd_a1 is pin_a1 +var volatile bit pata_hd_a1_direction is pin_a1_direction +var volatile bit pata_hd_a2 is pin_a2 +var volatile bit pata_hd_a2_direction is pin_a2_direction +var volatile bit pata_hd_iowr is pin_c2 +var volatile bit pata_hd_iowr_direction is pin_c2_direction +var volatile bit pata_hd_iord is pin_c1 +var volatile bit pata_hd_iord_direction is pin_c1_direction +;var volatile bit pata_hd_cs1 is pin_a3 +;var volatile bit pata_hd_cs1_direction is pin_a3_direction +;var volatile bit pata_hd_cs0 is pin_a4 +;var volatile bit pata_hd_cs0_direction is pin_a4_direction pata_hd_a0_direction = output -- register select pin pata_hd_a1_direction = output -- register select pin pata_hd_a2_direction = output -- register select pin -pata_hd_cs1_direction = output -- register select pin -pata_hd_cs0_direction = output -- register select pin pata_hd_iowr_direction = output -- used for write pulse pata_hd_iord_direction = output -- used for read pulse - -var byte pata_hd_word_count = 0 -- counts words read, 256 words in a sector. -const bit PATA_HD_NO_INVERTER = true -- if true, an external inverter chip is not needed on /iowr, /iord, /cs0, /cs1 pins +;pata_hd_cs1_direction = output -- register select pin +;pata_hd_cs0_direction = output -- register select pin include pata_hard_disk -- include the parallel ata ide hard disk library pata_hd_init() -- initialize startup settings @@ -112,21 +112,13 @@ _USEC_DELAY (10_000_000) -- wait 10 seconds before next example + -- ---------------------------------------------------------------------------- -- Example read sectors command -- ---------------------------------------------------------------------------- -pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_RECALIBRATE) -- recalibrate the drive - --- go to sector 0 (the boot sector) --- and set sector count to read 2 sectors -pata_hd_go_to_sector (0,2) -pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_READ_SECTOR) -- send the read command to the command register - --- hard disk led will turn on at this point - --- check if drive is ready for reading and set data ports as inputs --- this MUST be used before reading each sector -pata_hd_data_request(PATA_HD_WAIT_READ) + +pata_hd_start_read(0) -- get drive ready for reading at sector 0 (boot sector) + -- Read one sector for 256 loop -- 256 words, 512 bytes per sector pata_hd_read_data (in_b, in_a) -- read data @@ -134,18 +126,16 @@ end loop -- You will see hard disk LED on during this delay --- because you did not read 2 sectors yet. +-- because you did not finnish reading. _USEC_DELAY (2_000_000) -- 2 second delay --- check if drive is ready for reading and set data ports as inputs --- this MUST be used before reading each sector -pata_hd_data_request(PATA_HD_WAIT_READ) -- Read 2nd sector. for 256 loop -- 256 words, 512 bytes per sector pata_hd_read_data (in_b, in_a) -- read data send_word (in_b, in_a) -- send data via serial port end loop +pata_hd_stop_read() -- tell drive you are done reading -- hard disk led will turn off at this point. _USEC_DELAY (10_000_000) -- wait 10 seconds before next example @@ -154,11 +144,14 @@ -- Example identify drive command (Read drive information) -- size of drive, make, model, serial number, etc. -- ---------------------------------------------------------------------------- -pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_IDENTIFY_DRIVE) -- recalibrate the drive + +-- send the identify drive command +pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_IDENTIFY_DRIVE) -- check if drive is ready reading and set data ports as inputs --- this MUST be used before reading each sector +-- this MUST be used before reading since we did not use pata_hd_start_read pata_hd_data_request(PATA_HD_WAIT_READ) + -- Read 512 bytes for 256 loop -- 256 words, 512 bytes per sector pata_hd_read_data (in_b, in_a) -- read data @@ -172,64 +165,35 @@ -- Example write sectors command -- note: this will over write data currently on your drive -- ---------------------------------------------------------------------------- -pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_RECALIBRATE) -- recalibrate the drive - --- go to sector 200 --- and set sector count to write 2 sectors -pata_hd_go_to_sector (200,2) -pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_WRITE_SECTOR) -- send the write command to the command register - --- check if drive is ready for next write and set data ports as outputs --- this MUST be used before writing each sector -pata_hd_data_request(PATA_HD_WAIT_WRITE) --- write one sector, data will not be written unless 512 bytes are sent -for 256 loop -- 256 words, 512 bytes per sector - pata_hd_write_data (0xAA, 0xBB) -- write data 0xAA, 0xBB over and over + +pata_hd_start_write(200) -- tell hd to get ready for reading + +-- now write 1 sector + most of 2nd sector, data will not be written unless 512 bytes are sent +for 256 + 250 loop + pata_hd_write_data(0xCC, 0xDD) -- write data 0xCC, 0xDD over and over end loop - --- You will see hard disk LED on during this delay --- because you did not write 2 sectors yet. -_USEC_DELAY (2_000_000) -- 2 second delay - --- check if drive is ready for next write and set data ports as outputs --- this MUST be used before writing each sector -pata_hd_data_request(PATA_HD_WAIT_WRITE) --- now write one more sector, data will not be written unless 512 bytes are sent -for 250 loop - pata_hd_write_data (0xCC, 0xDD) -- write data 0xCC, 0xDD over and over -end loop --- only 250 writes sent so lets finnish the sector with 6 more write pulses (0's as data) -pata_hd_write_pulse (6) - --- hard disk led will turn off at this point. - - - --- Now read the 1st sector you just wrote, should get 0xAA, 0xBB over and over -pata_hd_go_to_sector (200,2) -- go sector 200 -pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_READ_SECTOR) -- send the read command - --- check if drive is ready for reading and set data ports as inputs --- this MUST be used before reading each sector -pata_hd_data_request(PATA_HD_WAIT_READ) --- now get the data -for 256 loop -- 256 words, 512 bytes per sector +-- first sector has been written to the disk since 512 bytes where sent, +-- but 2nd sector is not finnished, only 500 bytes sent, +-- so lets finnish the sector with 6 more write pulses (0xFF's as data) +pata_hd_write_to_sector_end(0xFF) + +pata_hd_stop_write() -- tell hd we are done writing + +-- Now read the 1st sector you just wrote, should get 0xCC, 0xDD over and over +pata_hd_start_read(200) -- get drive ready for reading +for 256 + 250 loop -- read 512 bytes + 500 bytes pata_hd_read_data (in_b, in_a) -- read data send_word (in_b, in_a) -- send data via serial port end loop --- Now read the 2nd sector you just wrote, should get 250 x (0xCC, 0xDD) --- and you will get 6 x (0x00 0x00) at the end of the sector that we wrote. - --- check if drive is ready for reading and set data ports as inputs --- this MUST be used before reading each sector -pata_hd_data_request(PATA_HD_WAIT_READ) --- now get the data -for 256 loop -- 256 words, 512 bytes per sector +-- if you want, you can read back the last 6 bytes that are 0xFF +for 6 loop pata_hd_read_data (in_b, in_a) -- read data send_word (in_b, in_a) -- send data via serial port end loop +pata_hd_stop_read() -- tell drive we are done reading + -- We're done, lets turn off the hd motor pata_hd_register_write (PATA_HD_COMMAND_REG,PATA_HD_SPIN_DOWN) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "jallib" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/jallib?hl=en -~----------~----~----~----~------~----~------~--~---
