DIY CD drive based on a computer CDROM

C Source code

Could you help me to write this code to eject the cdrom ?

void write_atapi(unsigned char bytelow, unsigned char bytehigh)
{
TRISA = 0b00000000; // All ports A are output
TRISB = 0b00000000; // All ports B are output
TRISE = 0b00000000; // All ports E are output
TRISC = 0b00000000; // All ports C are output
TRISD = 0b00000000; // All ports D are output

RA1 = 0; // CS0
RA0 = 1; // CS1

RE0 = 1; // DA0
RE1 = 1; // DA1
RE2 = 1; // DA2

PORTD = bytehigh;
PORTC = bytelow;

RA3 = 1; // W

DelayMs(1);

RA3 = 0; // W

}

void read_atapi(int cs0, int cs1, int da0, int da1, int da2, unsigned char bytelow, unsigned char bytehigh)
{
TRISA = 0b00000000; // All ports A are output
TRISB = 0b00000000; // All ports B are output
TRISE = 0b00000000; // All ports E are output
TRISC = 0b11111111; // All ports B are input
TRISD = 0b11111111; // All ports D are input

RA1 = cs0; // CS0
RA0 = cs1; // CS1

RE0 = da0; // DA0
RE1 = da1; // DA1
RE2 = da2; // DA2

RA2 = 1; // R

bytelow = PORTC;
bytehigh = PORTD;

RA2 = 0; // R
}

void check_status()
{
unsigned char bytelow;
unsigned char bytehigh;


while(1)
{
read_atapi(1, 0, 1, 1, 1, bytelow, bytehigh): //try 10011

if (bytelow == 7)
DelayMs(1);

else if (bytelow == 3)
DelayMs(1);

else break;
}

}

void open_tray()
{
check_status();

write_atapi(0x1e, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);

check_status();

write_atapi(0x1b, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x02, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
}

void cdrom()
{
RA5 = 1; // Reset high

open_tray();
}


Andrea Ciuffoli
www.audiodesignguide.com
 
How about ASM?

Open_Tray:
MOV R5,#10
CALL LCD_DELAY
MOV DPTR,#LMESS11 ; Open
MOV A,#1
CALL LCD_PRINT
MOV DPTR,#LMESS12 ; Wait....
MOV A,#2
CALL LCD_PRINT
acall do_packet_cmd
mov packet_cmd,#11011b
mov packet_4,#02h
mov packet_8,#00h
acall send_packet
mov next_track,#1
ret

😀
 
mov packet_cmd,#11011b
this is 1B hex?- makes sense to me

mov packet_4,#02h
mov packet_8,#00h
agreed

If I unroll the code I am looking at I believe the above "packet" is preceded by a single byte pair being sent

"sends ata cmd 0xa0 - atapi packet cmd"
with low CS0, rest high CS1, DA0,DA1, DA2

MCLL?
 
Csource for Audio CDROM

Is this better ?

I see in the assembler source available that in the write both W and R pin of the ATA bus are set to high, why ?

How to set the register in the write and in the read to see if the drive is busy and to send a command like play, eject, stop .. ?

Offcourse now I am starting with eject function but I want all the complete functions.


void write_atapi(unsigned char bytelow, unsigned char bytehigh)
{
TRISA = 0b00000000; // All ports A are output
TRISB = 0b00000000; // All ports B are output
TRISE = 0b00000000; // All ports E are output
TRISC = 0b00000000; // All ports C are output
TRISD = 0b00000000; // All ports D are output

RA1 = 1; // CS0
RA0 = 0; // CS1

RE0 = 1; // DA0
RE1 = 1; // DA1
RE2 = 1; // DA2

PORTD = bytehigh;
PORTC = bytelow;

RA3 = 1; // W
RA2 = 1; // R

DelayMs(1);

RA3 = 0; // W

}

void read_atapi(int cs0, int cs1, int da2, int da1, int da0, unsigned char bytelow, unsigned char bytehigh)
{
TRISA = 0b00000000; // All ports A are output
TRISB = 0b00000000; // All ports B are output
TRISE = 0b00000000; // All ports E are output
TRISC = 0b11111111; // All ports B are input
TRISD = 0b11111111; // All ports D are input

RA1 = cs0; // CS0
RA0 = cs1; // CS1

RE0 = da0; // DA0
RE1 = da1; // DA1
RE2 = da2; // DA2

RA2 = 1; // R

bytelow = PORTC;
bytehigh = PORTD;

RA2 = 0; // R
}

void check_status()
{
unsigned char bytelow;
unsigned char bytehigh;


while(1)
{
read_atapi(1, 0, 1, 1, 0, bytelow, bytehigh); //try 10011

if (bytelow == 7)
DelayMs(1);

else if (bytelow == 3)
DelayMs(1);

else break;
}

}

void open_tray()
{
check_status();

write_atapi(0x1e, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);

check_status();

write_atapi(0x1b, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x02, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
}

void cdrom()
{
ata_reset();


open_tray();
}

void ata_reset()
{
RA5 = 1; // Reset high

DelayMs(200);

RA5 = 0; // Reset low

DelayMs(200);

RA5 = 1; // Reset high

DelayMs(200);

DelayMs(200);
DelayMs(200);
DelayMs(200);
DelayMs(200);

return;
}
 
"I see in the assembler source available that in the write both W and R pin of the ATA bus are set to high, why ?"

The strobes are active low, high is the rest state.
I think some DMA transfers will run on both clock edges but that beyond me...


Can you give me some reference for this packet containing
write_atapi(0x1e, 0x00) ?
maybe its a newer command?

I have been told they have depreciated some useful commands
so its best to try firstime with an older drive
 
C source code for Audio CDROM

void read_atapi(int cs0, int cs1, int da2, int da1, int da0, unsigned char bytelow, unsigned char bytehigh)
{
TRISA = 0b00000000; // All ports A are output
TRISB = 0b00000000; // All ports B are output
TRISE = 0b00000000; // All ports E are output
TRISC = 0b11111111; // All ports B are input
TRISD = 0b11111111; // All ports D are input

RA1 = cs0; // CS0
RA0 = cs1; // CS1

RE0 = da0; // DA0
RE1 = da1; // DA1
RE2 = da2; // DA2

RA2 = 1; // R

bytelow = PORTC;
bytehigh = PORTD;

RA2 = 0; // R
}

void check_status()
{
unsigned char bytelow;
unsigned char bytehigh;


while(1)
{
read_atapi(1, 0, 1, 1, 0, bytelow, bytehigh); //try 10011

if (bytelow == 7)
DelayMs(1);

else if (bytelow == 3)
DelayMs(1);

else break;
}

}

void open_tray()
{
check_status();

//*******************************
//* unlock door
//*******************************
write_atapi(0x1e, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);

check_status();

//*******************************
//* eject cdrom
//*******************************
write_atapi(0x1b, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x02, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
write_atapi(0x00, 0x00);
}
 
I would expect to initialize with similar pseudo code as below
......
set up all you regular stuff

start here

make dio read high
make dio write high

wait a couple of seconds

routine to select device 0
------start routine-----------
low CS0
high CS1
low DA0
high DA1
low DA2

high byte= 0
lowbyte= 0
strobe write
--------end routine-------

;check if cd busy then wait loops here
; read atapi status register

routine to read atapi status

;ATAPI STATUS Register:d7-d0
;BSY,DRDY,DMA,DSC,DRQ,CORR,Reserved,CHECK

------start routine-------
low CS0
high CS1
high DA0
high DA1
high DA2
read cd atapi status and save
--------end routine-------

wait until drq=0 fourth bit and bsy=0 eighth bit
keep reading until above true

routine features_reg - tell it we are not doing dma or ovl fancy stuff
------start routine-----------
low CS0
high CS1
high DA0
low DA1
low DA2

high byte= 0
lowbyte= 0
strobe write
--------end routine-------

rest of the code here....
now we can talk to cd?
 
C source code for Audio DCROM

Could you insert details about how to read atapi status register ?

The my code above is right ?

void check_status()
{
unsigned char bytelow;
unsigned char bytehigh;


while(1)
{
//*****************************************
//* In the call of read_atapi() the params are in the order:
//* cs0, cs1, da2, da1, da0
//*****************************************
read_atapi(1, 0, 1, 1, 0, bytelow, bytehigh);

if (bytelow == 7)
DelayMs(1);

else if (bytelow == 3)
DelayMs(1);

else break;
}
}
 
C source code for Audio CDROM

This is the code following your suggestions, I will try it this morning.

void ata_write(int cs0, int cs1, int da2, int da1, int da0, unsigned char bytelow, unsigned char bytehigh)
{
TRISC = 0b00000000; // All ports C are output
TRISD = 0b00000000; // All ports D are output

RA1 = cs0; // CS0
RA0 = cs1; // CS1
RE0 = da0; // DA0
RE1 = da1; // DA1
RE2 = da2; // DA2

PORTD = bytehigh;
PORTC = bytelow;

RA3 = 0; // W

DelayMs(5);

RA3 = 1; // W

}

void ata_read(int cs0, int cs1, int da2, int da1, int da0, unsigned char bytelow, unsigned char bytehigh)
{
TRISC = 0b11111111; // All ports B are input
TRISD = 0b11111111; // All ports D are input

RA1 = cs0; // CS0
RA0 = cs1; // CS1
RE0 = da0; // DA0
RE1 = da1; // DA1
RE2 = da2; // DA2

RA2 = 0; // R

DelayMs(5);

bytelow = PORTC;
bytehigh = PORTD;

RA2 = 1; // R
}

void check_status()
{
unsigned char bytelow;
unsigned char bytehigh;


while(1)
{
ata_read(0, 1, 1, 1, 1, bytelow, bytehigh); //try 10011

if (bytelow & 0b01000000)
DelayMs(1);

else if (bytelow & 0b00000100)
DelayMs(1);

else break;
}

}

void open_tray()
{
check_status();

//*******************************
//* unlock door
//*******************************
ata_write(0x1e, 0x00);
ata_write(0x00, 0x00);
ata_write(0x00, 0x00);
ata_write(0x00, 0x00);
ata_write(0x00, 0x00);
ata_write(0x00, 0x00);

check_status();

//*******************************
//* eject cdrom
//*******************************
ata_write(0x1b, 0x00);
ata_write(0x00, 0x00);
ata_write(0x02, 0x00);
ata_write(0x00, 0x00);
ata_write(0x00, 0x00);
ata_write(0x00, 0x00);
}

void cdrom()
{
ata_reset();

open_tray();
}

void ata_reset()
{
TRISA = 0b00000000; // All ports A are output
TRISB = 0b00000000; // All ports B are output
TRISE = 0b00000000; // All ports E are output

RA2 = 1; // R
RA3 = 1; // W

RA5 = 1; // Reset high
DelayMs(200);
RA5 = 0; // Reset low
DelayMs(200);
RA5 = 1; // Reset high

//********************************************
//* wait 2 sec
//********************************************
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);

DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);

//********************************************
// select device 0
// cs0 = 0;
// cs1 = 1;
// da2 = 0;
// da1 = 1;
// da0 = 0;
ata_write(0, 1, 0, 1, 0, 0x00, 0x00);

ata_get_status();

//********************************************
// features reg.
// cs0 = 0;
// cs1 = 1;
// da2 = 0;
// da1 = 0;
// da0 = 1;
ata_write(0, 1, 0, 0, 1, 0x00, 0x00);

return;
}
 
C source code for Audio CDROM

In respect to this table which is the line to consider in the startup and command phase ?

--- phase 1 - select device 0 ------
low CS0
high CS1
low DA0
high DA1
low DA2
high byte= 0
lowbyte= 0
strobe write = (W = 0, delay 1ms, W = 1)

--- phase 2 - check state -----
low CS0
high CS1
high DA0
high DA1
high DA2
strobe read ?
save status ?

--- phase 3 - features_reg ------
low CS0
high CS1
high DA0
low DA1
low DA2
high byte= 0
lowbyte= 0
strobe write = (W = 0, delay 1ms, W = 1)


--- phase 4 - unlock tray ------
? CS0
? CS1
? DA0
? DA1
? DA2
high byte= 0x00
lowbyte= 0x1e
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write = (W = 0, delay 1ms, W = 1)


--- phase 5 - check state -----
? CS0
? CS1
? DA0
? DA1
? DA2
strobe read ?

--- phase 6 - eject ------
? CS0
? CS1
? DA0
? DA1
? DA2
high byte= 0x00
lowbyte= 0x1b
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x02
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write = (W = 0, delay 1ms, W = 1)


--- phase 7 - check state -----
? CS0
? CS1
? DA0
? DA1
? DA2
strobe read ?
 

Attachments

  • tab1.gif
    tab1.gif
    24.1 KB · Views: 1,653
Andrea I'm not sure I'm providing any extra value to you?
I don't know C. I have been giving you my understanding based on the elector pandora code (link in this thread) which i have hacked a little.
I believe you know MPASM and should be able to convert to C?
I see you have ssf80xxxx.pdf its the best doc

how to read the status AFAIK

set up the address via
CS0 CS1 DA0 DA1 DA2 - you know this
read strobe low
maybe some delay to settle
now read low byte this is atapi_status
copy the low byte to some variable
read strobe high
read the bits on the saved variable and apply logic
if the bits are not good do it again (wait)

Not sure of you last qustion,
what must you do to be able to get to the point where you can command the drive?

will answer what I can....
 
--- phase 1 - select device 0 ------
low CS0
high CS1
low DA0
high DA1
low DA2
high byte= 0
lowbyte= 0
strobe write = (W = 0, delay 1ms, W = 1)

--- phase 2 - check state -----
low CS0
high CS1
high DA0
high DA1
high DA2
strobe read ?
save status ?

--- phase 3 - features_reg ------
low CS0
high CS1
high DA0
low DA1
low DA2
high byte= 0
lowbyte= 0
strobe write = (W = 0, delay 1ms, W = 1)


--- phase 4 - unlock tray ------
low? CS0
high? CS1
low? DA0
low? DA1
low? DA2

high byte= 0x00
lowbyte= 0x1e
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write = (W = 0, delay 1ms, W = 1)

* btfss INTRQ PORTE,0 ;interrupt line
* goto $-1
* call read_status

wait until INTRQ is high then read atapi status register


--- phase 5 - check state ----- atapi status register
low? CS0
high? CS1
high? DA0
high? DA1
high? DA2

read strobe low
maybe some delay to settle
now read low byte this is atapi_status
copy the low byte to some variable
read strobe high
read the bits on the saved variable and apply logic

If the bits are not good do it again (wait)

--- phase 6 - eject ------
low? CS0
high? CS1
low? DA0
low? DA1
low? DA2
high byte= 0x00
lowbyte= 0x1b
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x02
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write
high byte= 0x00
lowbyte= 0x00
strobe write = (W = 0, delay 1ms, W = 1)

wait until INTRQ is high then read atapi status register

--- phase 7 - check state ----- atapi status register

low? CS0
high? CS1
high? DA0
high? DA1
high? DA2

read strobe low
maybe some delay to settle
now read low byte this is atapi_status
copy the low byte to some variable
read strobe high
read the bits on the saved variable and apply logic

If the bits are not good do it again (wait)
 
hi everyone;

For those who are interested in MUCOP which is originaly from keith wilson, there are some bugs from the original code.

From the Elektor electronics 4/2004 magazine, article of "Pandora Sound and Music Box"(attached file). The source codes provided very usefull, it provide the comment beside the code. To understand further MUCOP's code, comparing with Pandora Sound and Music Box's code is one of the best way.

To fix the bugs; its very easy. From the original Mucop code (ata_wc.asm)
, subroutine of AtaWrite Packet:

clrf AtaDataLsb
movlw ATA_REG_CYLINDERLOW
call AtaWriteRegister

clrf AtaDataLsb
movlw ATA_REG_CYLINDERHIGH
call AtaWriteRegister

As you refer to Pandora's Code under subroutine of toc_cmd

call cd_busy
movlw 0xff
movwf BCOUNT_LOW
call write_bcount_low


We are simply setting the byte count low register to a value higher than the total number of bytes that will ever be needed, so it has no impact on how the drive decides to return the data. In general, the mainthing is to make sure it's not zero.For further info, please refer to INF8020i under ATAPI Byte Count Register (ATA Cylinder High/ Low Register).

so, after the correction is

movlw 0xff
movwf AtaDataLsb
movlw ATA_REG_CYLINDERLOW
call AtaWriteRegister

movlw 0xff
movwf AtaDataLsb
movlw ATA_REG_CYLINDERHIGH
call AtaWriteRegister


Hope that this is usefull for those who doing MUCOP project.

Copyrighted material removed in agreement with advlusj6.