AN #134 - FAT32 WAVE Player



This AN is written by Phil Morelli

Phil used PWM to output the WAVE files. The advantage of using FAT32 is that you can use very large disks.

Operation


The disk must have a valid FAT32 file format and strapped for "master" operation.
The first line of the LCD is reserved for the last opened file or directory.
The second line is reserved for the currently selected file or directory.
The second line to the last line is reserved for directory listing.

If the displayed directory entry is a file, then file size is displayed also.
If the displayed directory entry is a directory, then "DIR" is also displayed.

After power up, the root directory will be displayed on the LCD. Only "valid" files are displayed.
Valid files are all but hidden files.

The user can press the "up" or "down" button to scroll the displayed directory.
If the user keeps their finger on the "up" or "down" button, the directory will keep scrolling.
When the last directory entry is displayed, it will wrap around to the first directory entry.
Wrap from first to last is not supported, it will simply stop at the first directory entry.
Directory entries are displayed in order that they written to the disk.
There is no alpha numeric sorting.

When the desired directory appears on the second line, pressing the "open" button will open that file or directory.
The first line will update with the opened file or directory.
The user can then keep opening directories, but only the last opened directory will be displayed.

To open the parent directory, the user must open the ".." directory entry.
To open the current directory, the user must open the "." directory entry. (Remember the good old days of DOS).

When the play button is pressed, the Wave Player will play the opened file or directory.
Pressing the play button again, will abort the playing.

Non-WAV files, and non-compatible WAV files are skipped, and a message is displayed on the LCD for 1 second.
If playing a directory, all WAV files in the directory are played, and then stops at the end.
In the event of a fatal error (equivalent to the infamous "blue screen of death"), the program will stop, and debugging information is displayed on the LCD and serial port. Since I finished debugging I have not seen this message.

Circuit Description


The circuit is based on the Atmel Mega 162 (U1) RISC processor, with a 62256 (U3) 32k static RAM and 74573 (U2) latch as per the data sheet.
The only difference is that I have connected address lines of the 62256 to make PCB routing easier. After all the 62256 does not care what the absolute address is.

Since serial communication, and ISP (In Circuit Programming) is not a function needed in the end design, that hardware is not included in the circuit. The 74138 (U4) address decoder does what it is called. The decoded addresses are not uniquely addressed.
The marked addresses are the base address.

The LCD is a pretty standard sort of arrangement in 8 bit bus mode. Since the Mega 162 only has an 8 bit data bus and the ATA hard disk is 16 bit, a method of reading the low 8 bits and latching the high 8 bits is needed.
U8 (74573) latches the high 8 bits whenever there is a read of the ATA hard disk.
Then the high 8 bits can be read in another read at the ATAHI8 address.
When performing a 16 bit write to the ATA hard disk, U9 (74573) latches the high 8 bits, then the low 8 bits and high 8 bits can be written to the ATA hard disk.

To perform a read, first the low 8 bits are read from the disk, then the high 8 bits are read from U8. To perform a write, first the high 8 bits are written to U9, and then the low 8 bits are written to the disk. In fact this hardware is not used, since no 16 bit writes are implemented in the software.
I have left the hardware there, in the event I decide to make a Wave Recorder. (Don't hold your breath).

All the 100ohm resistors provide some impedance matching to the ribbon cable connected to the ATA hard disk. They also limit current in the event of a mistake.

The PWM filter is implemented using 2 of MF10 switched capacitor filters. They are biased for single ended supply with R28 and R29. U10 is configured as a notch in mode 2 operation (refer to the data sheet). Its notch frequency is set to 1/50 filter clock. It is used to remove the sample frequency, which is closest to the audio band.

C11 (C20) helps to remove the edge from the PWM output. U11 is configured in mode 3 operation. Its 3dB low pass frequency is set to 1/2 X 1/ 50 filter clock. So at a sample rate of eg, 16kHz we want to implement a 8kHz low pass filter. The 16kHz component will be the largest and hardest to remove. Filter clock will be 50 X 16kHz = 800kHz. U10 will almost completely remove the 16kHz component.

U11 low pass frequency is 1/2 X 1/50 X 800kHz = 8kHz. Sample rates that are not divisible by the crystal frequency do not present a problem, because as long as the ratio of sample rate to notch and cut is 50, the circuit will work. At sample rates of 8kHz, I can just hear the 8kHz sample frequency, but it seems to work pretty good at higher sample rates.

Undesirable features (bugs)


It is possible that you may see "the blue screen of death" (error code 7) if playing wav files with sample rates of >22kHz.
This is because the current file offset is only checked after the FIFO is full, and the ISR is continually taking bytes from the fifo (making it not full).
Adding extra file offset checks just makes matters worse. The only real solution is to add a check for the "Avgbytespersec" and skip playing wav file with values greater than ???(about 88k).
Or a faster processor, or more efficient code.
When playing 16 bit wav files, in order for the sample to "fit under TOP" they must be divided (chop of LSB) to reduce the bits per sample. Doing a real 16 bit divide takes about 200 cycles. To fetch 1 byte from the buffer & disk takes about 120 cycles.
To fetch 4 bytes (16 bit & 2 Ch) takes about 480 cycles. Total is almost 1000 cycles, and I have not counted the overhead of filling the fifo and ISR empting the fifo and checking of the file offset against file size.
At a sample rate of 16k, and a 16MHz clock, gives 1000 cycles in-between interrupts. Does not compute. So I do a "dodgy fast divide" which may put a sample in the compare register that is greater than TOP. This results in a "Clip" that you can hear. If anyone has a better solution, please let me know.

Download source code and files in an134.zip