yerpa
Joined: 19 Feb 2004 Posts: 58 Location: Wisconsin
|
8-bit wav file player with Xmodem RS-232 for 16F873 |
Posted: Fri Jan 19, 2007 3:51 pm |
|
|
Here it is, offered strictly as-is. Please do not make fun of my nasty coding style! Note that this is a re-post - I forgot to disable HTML last time around.
Code: |
/////////////////////////////////////////////////////////////////////////
//// T2K2v2.C by RPL 15 OCT 2002 ////
//// Program for TONE2002 board, with audio playback, xmodem file ////
//// transfers, and a simple file system. ////
//// ////
/////////////////////////////////////////////////////////////////////////
#include <16f873.h>
#fuses HS, NOWDT, PUT, NOBROWNOUT, NOPROTECT, NOWRT, NOLVP
#use fast_io(A)
/* DEFINE EQUATES FOR PORTS */
#byte PORTA = 5
#byte PORTB = 6
#byte RTCC = 1
#byte TMR0 = 0x01 //Timer 0.
#byte TMR1L = 0x0E //Timer 1 LOW BYTE.
#define EEPROM_SELECT PIN_A2
#define EEPROM_DI PIN_A0
#define EEPROM_DO PIN_A4
#define EEPROM_CLK PIN_A1
#define ACK 0x06
#define CAN 0x18
#define DLE 0x10
#define EOT 0x04
#define NAK 0x15
#define SOH 0x01
#define SYN 0x22
#define XOF 0x13
#define XON 0x11
#define EEPROM_ADDRESS byte
#define EEPROM_SIZE 256
#use delay(Clock=18432000, RESTART_WDT)
#use RS232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
void clr_all_ptrs();
void dir();
byte read_AT45_stat();
void write_AT45_stream128(long page, byte addr2);
void read_AT45_stream128(long page, byte addr2);
void read_AT45_stream64(long page, byte addr2);
byte xmodem();
void hexdump();
// Define static variables...
static byte toggle_lo;
static byte toggle_hi;
static byte softime;
static byte sample;
static byte sptr;
static byte pflag;
static byte sflag;
static byte filenum;
static long file_start;
static long file_end;
static byte rambuf1[64];
static byte rambuf2[64];
// Define constants...
byte const hexlist[16]={'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
// INTERRUPT ROUTINE FOR RTCC...
#INT_RTCC
void time0_handler(void)
{
#asm
sync: btfss 1, 3 //Synchronize (de-jitter) the samples.
goto sync
btfss 1, 0
nop
#endasm
PORTB=sample; // Write sample to DAC.
RTCC=0x4f;
sptr++;
if ((sptr & 0x40)!=0) sample = rambuf2[sptr & 0x3f];
if ((sptr & 0x40)==0) sample = rambuf1[sptr & 0x3f];
if ((sptr & 0x3f)==0) sflag=0;
if (pflag==0) sample=0;
toggle_lo++;
if (toggle_lo==0)
{
toggle_hi++;
softime++;
}
if (toggle_hi & 0x10)
{
output_low(PIN_A3); // Toggle on-board LED.
}
if (!(toggle_hi & 0x10))
{
output_high(PIN_A3);
}
}
main()
{
byte ch, i, temp;
byte ebyte;
long page;
filenum=0;
SET_RTCC(0);
setup_timer_1(T1_INTERNAL); //Free-running.
setup_timer_2(T2_DIV_BY_1, 0x1F, 1); //Not really used.
SETUP_CCP1(CCP_OFF);
SETUP_CCP2(CCP_OFF);
// SETUP_COUNTERS(RTCC_INTERNAL, WDT_18MS);
SETUP_COUNTERS(RTCC_INTERNAL, RTCC_DIV_2);
SETUP_PORT_A(NO_ANALOGS);
SET_TRIS_A(0x10); //Port A0-A3, A5-A7=outputs,
//Port A4=input.
SET_TRIS_B(0x00); //Port B0-B7=outputs.
ENABLE_INTERRUPTS(RTCC_ZERO);
// ENABLE_INTERRUPTS(INT_TIMER1);
SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_8);
SET_TIMER1(0x3F);
ENABLE_INTERRUPTS(GLOBAL);
PORTB=0;
pflag=0;
putc(XON);
printf ("\r\n T2Kv2 \r\n");
top:
printf ("\r\nS=Status, X=Xmodem transfer, H=Hexdump, P=Play.\r\n");
printf ("C=Clear all, D=Directory.\r\n\r\n>");
ch=getc();
if ((ch=='S') || (ch=='s'))
{
printf ("\r\nreading Status...\r\n");
ebyte = read_AT45_stat();
printf ("\r\nStatus=");
if (ebyte & 0x80) putc (0x31);
if (!(ebyte & 0x80)) putc (0x30);
if (ebyte & 0x40) putc (0x31);
if (!(ebyte & 0x40)) putc (0x30);
if (ebyte & 0x20) putc (0x31);
if (!(ebyte & 0x20)) putc (0x30);
if (ebyte & 0x10) putc (0x31);
if (!(ebyte & 0x10)) putc (0x30);
putc (0x020);
if (ebyte & 0x08) putc (0x31);
if (!(ebyte & 0x08)) putc (0x30);
if (ebyte & 0x04) putc (0x31);
if (!(ebyte & 0x04)) putc (0x30);
if (ebyte & 0x02) putc (0x31);
if (!(ebyte & 0x02)) putc (0x30);
if (ebyte & 0x01) putc (0x31);
if (!(ebyte & 0x01)) putc (0x30);
}
if ((ch=='X') || (ch=='x'))
{
ch=0;
read_AT45_stream64(0, 0);
output_high(EEPROM_SELECT);
file_end=0;
for (filenum=0; filenum < 7; filenum++)
{
i=filenum*4;
file_start = rambuf1[i];
file_start <<= 8;
file_start |= rambuf1[i+1];
if (file_start==0) break;
file_end = rambuf1[i+2];
file_end <<= 8;
file_end |= rambuf1[i+3];
}
file_start = file_end + 1;
if (filenum>=6) break;
i = 4 * filenum;
printf ("\r\nStart xmodem file %d transfer now...\r\n", filenum);
ebyte=xmodem();
if (ebyte==0)
{
delay_ms(25);
read_AT45_stream64(0, 0);
rambuf1[i]=(file_start >> 8);
rambuf1[i+1]=(file_start & 0xFF);
rambuf1[i+2]=(file_end >> 8);
rambuf1[i+3]=(file_end & 0xFF);
delay_ms(25);
write_AT45_stream128(0, 0);
output_high(EEPROM_SELECT);
printf ("\r\nTransfer Complete!\r\n");
}
if (ebyte==1) printf ("\r\nTransfer Failed!\r\n");
}
if ((ch=='H') || (ch=='h')) hexdump();
if ((ch=='C') || (ch=='c'))
{
clr_all_ptrs();
printf ("\r\nDone.\r\n");
}
if ((ch=='D') || (ch=='d')) dir();
if ((ch=='P') || (ch=='p')) // PLAY loop is here.
{
ch=0;
while ((ch < 0x30) || (ch > 0x35))
{
printf ("\r\nPick a file number to play (0-5):\r\n");
ch=getc();
}
i=ch-0x30;
i=4*i;
disable_interrupts(global);
read_AT45_stream64(0,0); //Get directory.
file_start=rambuf1[i];
file_start <<= 8;
file_start |= rambuf1[i+1];
file_end=rambuf1[i+2];
file_end <<= 8;
file_end |= rambuf1[i+3];
page=file_start;
if (page==0) break; //If no sample saved, quit.
temp=0;
sptr=0;
read_AT45_stream64(page,temp); //Pre-fill rambuf1[]
temp=1;
read_AT45_stream64(page,temp); //Pre-fill rambuf2[]
sflag=1;
pflag=1;
enable_interrupts(global);
while ((kbhit()==FALSE) && (page <= file_end))
{
if (sflag==0)
{
temp++;
temp &= 0x03;
if ((temp & 0x03)==0) page++;
read_AT45_stream64(page,temp); // Keep buffer loaded with samples.
sflag=1;
}
}
pflag=0;
}
output_low(PIN_A5); //o-scope diagnostic
output_high(PIN_A5);
goto top;
}
// Read AT45DB041B status byte. By RPL.
byte read_AT45_stat() {
byte cmd;
byte i,data;
cmd=0xD7;
output_low(EEPROM_SELECT);
for(i=8;i>0;i--)
{
output_bit(EEPROM_DI, shift_left(&cmd,1,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
for(i=8;i>0;i--)
{
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
shift_left(&data,1,input(EEPROM_DO));
}
output_high(EEPROM_SELECT);
return(data);
}
// Main mem page 128-byte write thru buffer #1 on AT45DB041B chip. By RPL.
// Call with page address (=0-2047) and addr2 (=0 or 1). If addr2==0,
// data is written from rambuf1[] & rambuf2[] to the 1st (128) bytes
// of selected page, but the chip select is not raised at the end, so
// the write operation is not completed. When addr2==1, data is
// written to 2nd (128) bytes of selected page, followed by raising
// the chip select to finish the operation. Warning: Don't do any other
// chip operations after a call with addr2==0. That operation doesn't
// end until a call with addr2==1.
void write_AT45_stream128(long page, byte addr2)
{
byte cmd;
byte i, j;
cmd=0x82;
output_low(EEPROM_SELECT);
if (addr2==0)
{
for(i=8;i>0;i--) // Write command = 0x82 to mem chip.
{
output_bit(EEPROM_DI, shift_left(&cmd,1,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
for(i=4;i>0;i--) // Load (4) "0" (reserved) page bits.
{
output_bit(EEPROM_DI, 0);
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
for(i=5;i>0;i--) // Line up page bit P10
{
shift_left(&page,2,0);
}
for(i=12;i>0;i--) // Load page bits P10-P0 & byte addr
// bit B8. Note B8=0.
{
output_bit(EEPROM_DI, shift_left(&page,2,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
for(i=8;i>0;i--) // Load byte addr bits B7-B0=0.
{
output_bit(EEPROM_DI, 0);
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
}
for(j=0;j<64;j++) // Write 64 bytes of rambuf1[] to mem. chip.
{
cmd=rambuf1[j];
for(i=8;i>0;i--)
{
output_bit(EEPROM_DI, shift_left(&cmd,1,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
}
for(j=0;j<64;j++) // Write 64 bytes of rambuf2[] to mem. chip.
{
cmd=rambuf2[j];
for(i=8;i>0;i--)
{
output_bit(EEPROM_DI, shift_left(&cmd,1,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
}
if (addr2 !=0) output_high(EEPROM_SELECT);
return;
}
// Continuous 128-byte array read from AT45DB041B chip. By RPL.
// Call with page address (0-2047) and addr2 (0 or 1). If addr2==0,
// data is read from the 1st (128) bytes of page and written into
// rambuff1[] & rambuff2[]. If addr2 != 0, data is read from 2nd (128)
// bytes of selected page...
void read_AT45_stream128(long page, byte addr2)
{
byte cmd;
byte i, j;
cmd=0x68;
output_low(EEPROM_SELECT);
for(i=8;i!=0;i--) // Send command to mem chip.
{
output_bit(EEPROM_DI, shift_left(&cmd,1,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
cmd=0;
for(i=4;i!=0;i--) // Load (4) "0" (reserved) page bits.
{
output_bit(EEPROM_DI, 0);
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
for(i=5;i!=0;i--) // Line up page bit P10
{
shift_left(&page,2,0);
}
for(i=12;i!=0;i--) // Load page bits P10-P0 & byte addr
// bit B8. Note B8=0.
{
output_bit(EEPROM_DI, shift_left(&page,2,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
cmd=0;
if (addr2 !=0) cmd = 0x80;
for(i=8;i!=0;i--) // Load byte addr bits B7-B0.
{
output_bit(EEPROM_DI, shift_left(&cmd,1,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
cmd=0;
for(i=32;i!=0;i--) // Load (32) "don't care" bits.
{
output_bit(EEPROM_DI, 0);
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
for(j=0;j<64;j++) // Read 64 bytes into rambuf1[].
{
for(i=8;i!=0;i--)
{
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
shift_left(&rambuf1[j],1,input(EEPROM_DO));
}
}
for(j=0;j<64;j++) // Read 64 bytes into rambuf2[].
{
for(i=8;i!=0;i--)
{
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
shift_left(&rambuf2[j],1,input(EEPROM_DO));
}
}
output_high(EEPROM_SELECT);
return;
}
// Continuous 64-byte array read from AT45DB041B chip. By RPL.
// Call with page address (0-2047) and addr2. If if lo nibble of
// addr2==0, data is read from the 1st (64) bytes of page into rambuf1[].
// If lo nib of addr2==1, data is read from 2nd (64) bytes of page into
// rambuf2[]. If lo nib==2, data read from 3rd (64) bytes of page into
// rambuf1[]. If lo nib==3, data from 4th (64) bytes of page into
// rambuf2[]. If addr2 has hi bit set, data is read into rambuf2[]...
void read_AT45_stream64(long page, byte addr2)
{
byte cmd;
byte i, j;
cmd=0x68;
output_low(EEPROM_SELECT);
for(i=8;i!=0;i--) // Send command to mem chip.
{
output_bit(EEPROM_DI, shift_left(&cmd,1,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
output_bit(EEPROM_DI, 0);
for(i=4;i!=0;i--) // Load (4) "0" (reserved) page bits.
{
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
for(i=5;i!=0;i--) // Line up page bit P10
{
shift_left(&page,2,0);
}
for(i=12;i!=0;i--) // Load page bits P10-P0 & byte addr
// bit B8. Note B8=0.
{
output_bit(EEPROM_DI, shift_left(&page,2,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
if ((addr2 & 0x0f)==0) cmd=0;
if ((addr2 & 0x0f)==1) cmd=0x40;
if ((addr2 & 0x0f)==2) cmd=0x80;
if ((addr2 & 0x0f)==3) cmd=0xC0;
for(i=8;i!=0;i--) // Load byte addr bits B7-B0.
{
output_bit(EEPROM_DI, shift_left(&cmd,1,0));
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
output_bit(EEPROM_DI, 0);
for(i=32;i!=0;i--) // Load (32) "don't care" bits.
{
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
}
if ((addr2==0)||(addr2==2)) // Use rambuf1[]?
{
for(j=0;j<64;j++) // Read 64 bytes into rambuf1[].
{
for(i=8;i!=0;i--)
{
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
shift_left(&rambuf1[j],1,input(EEPROM_DO));
}
}
}
if ((addr2==1)||(addr2==3)) // Use rambuf2[]?
{
for(j=0;j<64;j++) // Read 64 bytes into rambuf2[].
{
for(i=8;i!=0;i--)
{
output_high(EEPROM_CLK);
output_low(EEPROM_CLK);
shift_left(&rambuf2[j],1,input(EEPROM_DO));
}
}
}
output_high(EEPROM_SELECT);
}
// This subroutine runs the upload (receive) part of the xmodem protocol...
byte xmodem()
{
byte i, j, k, seq, csum;
long page;
seq=0;
k=0;
csum=0;
softime=0;
page=file_start;
putc(NAK); //Initiate communication by sending NAKs.
while (kbhit()==FALSE)
{
if (softime >= 0xf0)
{
softime=0;
putc(NAK);
}
}
while(1)
{
i=getc();
while (i!=SOH)
{
i=getc();
if (i==EOT)
{
putc(ACK); //ACK the EOT. Transfer complete.
putc(ACK);
output_high(EEPROM_SELECT); // In case last packet was even #.
file_end=page;
return(0);
}
if (i==CAN) return(1);
}
seq=getc(); //Get packet sequence #.
seq=getc(); //Get complemented packet sequence #.
for (i=0;i<128;i++)
{
j=getc();
if (i<64) rambuf1[i]=j;
if (i>=64) rambuf2[i-64]=j;
}
csum=getc(); //Get checksum.
write_AT45_stream128(page, k);
delay_ms(25);
k++;
k &= 0x01;
if (k==0) page++;
putc(ACK); //ACK the packet.
}
return(1);
}
void hexdump()
{
long page;
byte addr2, i, j, k, m, ch;
page=0;
addr2=0;
putc(0x0d);
putc(0x0a);
k=0;
ch=0;
while ((ch != 'Q') && (ch != 'q'))
{
read_AT45_stream128(page, addr2);
j=0;
while (j < 8)
{
m=k;
if (addr2 != 0) m=k+0x80;
printf ("%4lx-%2x", page, m);
putc(':');
for(i=0;i<16;i++) // Display in hex.
{
ch=rambuf1[k];
if (j >=4) ch=rambuf2[k-64];
ch >>= 4;
ch &= 0x0f;
putc(hexlist[ch]);
ch=rambuf1[k];
if (j >=4) ch=rambuf2[k-64];
ch &= 0x0f;
putc(hexlist[ch]);
putc(0x20);
if (i==7) putc(0x20);
k++;
}
for(i=0;i<5;i++) putc(0x20);
k-=16;
for(i=0;i<16;i++) // Display in ASCII.
{
ch=rambuf1[k];
if (j >=4) ch=rambuf2[k-64];
if (ch < 0x20) ch='.';
if (ch > 0x7e) ch='.';
putc(ch);
k++;
}
putc(0x0d);
putc(0x0a);
j++;
}
printf ("\n\r\M=More, N=skip 100 pages, S=Skip 10 pages, Q=Quit:\r\n");
ch=getc();
k=0;
addr2++;
addr2 &= 0x01;
if (addr2==0) page++;
if ((ch=='N') || (ch=='n'))
{
page+=100;
addr2=0;
}
if ((ch=='S') || (ch=='s'))
{
page+=10;
addr2=0;
}
}
}
// This subroutine clears the 1st page of the AT45DB041B chip.
// The 1st page is used in this app to hold file pointers & file info.
void clr_all_ptrs()
{
byte i;
long j;
for (i=0; i < 64; i++)
{
rambuf1[i]=0;
rambuf2[i]=0;
}
write_AT45_stream128(0, 0); // Clear page 0 (the directory).
write_AT45_stream128(0, 1);
delay_ms(25);
// for (j=0; j<2048; j++)
// {
// write_AT45_stream128(j, 0);
// write_AT45_stream128(j, 1);
// delay_ms(25);
// }
}
// This function displays a simple directory listing.
void dir()
{
byte i, k;
read_AT45_stream128(0, 0);
for (i=0; i<6; i++)
{
k=4*i;
printf ("\r\nFile %d: Start page %2x%2x", i, rambuf1[k], rambuf1[k+1]);
printf (" End page %2x%2x", rambuf1[k+2], rambuf1[k+3]);
}
}
|
Last edited by yerpa on Sun Jan 21, 2007 12:34 pm; edited 1 time in total |
|