The Atmel Mega103L communicated with the STA013 via
the I2C protocol. The I2C protocol is based on 4 commands: start,
stop, read, and write. For each command, the master device (i.e.,
the Atmel Mega103L) is responsible for controlling the clock. A start
condition is indicated by a high to low transition of I2C_SDA (i.e.,
the data line) while I2C_SCL (i.e., the clock) is high. Conversely,
a stop condition is indicated by a low to high transition of I2C_SDA
while I2C_SCL is high.
When writing a byte, the master places each bit serially
onto I2C_SDA while I2C_SCL is low. The slave then samples I2C_SDA
when I2C_SCL goes high. On the ninth clock cycle, the slave pulls
I2C_SCL low to indicate that the byte has been received (i.e., sends
an Ack bit). In order to read a byte, the master provides 8 clock
cycles, sampling I2C_SDA each time I2C_SCL is high. After receiving
all 8 bits, no acknowledgement is sent to the slave. (Note:
All communication done via the I2C protocol is done serially with
the MSB sent first.)
The STA013 was configured and controlled by writing
to its registers. Two functions - sta013_read() and sta013_write()
- were written to read and write to the STA013 registers, respectively.
The algorithm for the sta013_read() function is as follows:
- Start Condition
- Write the STA013 address (0x1000011X) with the
R/W bit (i.e., the eighth bit) cleared to indicate a write (i.e.,
0x86)
- Write the read address
- Start Condition
- Write the STA013 address with the R/W bit set to
indicate a read (i.e., 0x87)
- Read the value of the given address
- Stop condition
Similarly, the algorithm for the sta013_write() function is
as follows:
- Start Condition
- Write the STA013 address with the R/W bit cleared
to indicate a write (i.e., 0x86)
- Write the data
- Stop Condition
In order to configure the STA013, the file p02_0609.bin
had to be loaded onto the chip. This file simply consisted of 2007
address/data pairs. The appropriate registers also had to be loaded
to configure the STA013 to interface with the CS4334 (i.e., registers
PCM_DIVIDER and PCM_CONF) and to run in Multimedia Mode at 14.7456
MHz with a 256 oversampling ratio (i.e., registers PLLCTL, MFSDF,
MFSDF-441, PLLFRAC-H, PLLFRAC-441-H, PLLFRAC-L, PLLFRAC-441-L, PLLCTRL).
The configuration tool cpll.exe (provided by
STMicroelectronics) was used to determine the appropriate values for
this last set of registers (i.e., the PLL Configuration registers).
In Multimedia Mode, the STA013 automatically detected the sampling
rate of the MP3 file it received. This allowed the STA013 to play
MP3 files of varying bit-rates. Finally, the registers SCKL_POL, DATA_REQ_ENABLE,
and REQ_POL had to be loaded to configure the polarity of SCKR (i.e.,
the MP3 data clock) and to enable and set the polarity of DATA_REQ
(i.e., the MP3 data request line).
The pseudocode for the Atmel Mega103L/STA013 interface
is as follows:
- Initialize the MCU (i.e., initialize ports B and
D, configure serial communication via the UART, enable interrupts,
and set initial variable values)
- Reset the STA013
- Load the configuration file (i.e., p02_0609.bin)
onto the STA013
- Load circuit specific settings for the STA013 (i.e.,
CS4334 and PLL configuration)
- Start the STA013 (write 0x01 to the address 0x72,
i.e. the RUN register)
- Main task scheduler
Once in the main task scheduler, MP3 playback could
be started or stopped by pressing either button 0 or 1, respectively.
The Timer 1 Compare/Match A interrupt was used to poll the push buttons
every 50 ms. A debounce state machine was also used to ensure that
only one distinct button push was detected.
When button 0 was pushed, MP3 playback was started
by writing 0x01 to address 0x13 (i.e., the PLAY register) on the STA013.
The STA013 then indicated it wanted MP3 data by pulling the DATA_REQ
line low. To ensure minimum delay when sending data to the STA013,
external interrupt 3 (EXT_INT3) was used. When the DATA_REQ line was
pulled low, this caused external interrupt 3 to fire and begin sending
data to the STA013. To make the interrupt as fast as possible, it
was coded in Assembly language with the compiler directive savereg
(i.e., the directive telling the compiler to save and restore registers
r0-r3 and r20-r31) turned off.
The basic structure of external interrupt 3 is as
follows:
- Save the machine state (i.e., SREG and any modified
registers in the range r0-r3 or r20-r31)
- Load the next byte of MP3 data
- Clock each bit of the MP3 byte (MSB first) onto
the SDI line (i.e., place the data bit onto the SDI line while SCKR
is low and then raise SCKR)
- Increment the MP3 index by 1
- Check bounds on the MP3 index and reset it to 0
if the maximum index has been reached (to infinitely loop the MP3
clip)
- Restore the machine state (i.e., SREG and any stored
registers)
MP3 data was stored in an array of length approximately
32,000. An array this size allotted for an 8 second MP3 file sampled
at 32 kbps, or a 4 second MP3 file sampled at 64 kbps. The file mp3_to_hex.cpp
was written to convert an MP3 file to an array of characters. Any
attempt to store an MP3 file larger than length 32,000 (i.e., an array
of length 64,000) resulted in an uncaught compiler error that prevented
the code from executing once programmed.
Finally, when button 0 was pushed, playback of the
MP3 was stopped by writing 0x00 to address 0x13 (i.e., the PLAY register)
on the STA013. The source code for the Atmel Mega103L/STA013 interface
is mp3.c.
We wanted to use our personal computers to
write MP3 files to the hard-drive, and then connect the drive to the
Atmel Mega103L to transfer information from the drive to the STA013
decoder chip. Therefore, the software interface for the hard-drive was
designed to only read information from the hard-drive.
ATA/IDE is the standard that defines the hardware
and software interface between hard-drives, CD-ROMs, and other storage
devices within the computer. Communication with the hard-drive involved
manipulating values stored within the internal registers. The functions
HDWrite_Reg() and HDRead_data() were written to write
and read data to and from the drive. The address bits CS0 and CS1
(Active Low) in conjunction with Host Address2, Host Address1 and
Host Address0 (Active High) control the address of the registers.
The algorithm for the HDWrite_Reg() function is as follows:
- Assert address bits [5:0]
for 10 µs
- Assert Data Input/Output Write (Active Low) for
10 µs
- Write to the data bus using PORTB
- Negate Data Input/Output Write
Similarly, the algorithm for the HDRead_data()
function is as follows:
- Assert address bits [5:0]
for 10 µs
- Assert Data Input/Output Read (Active Low) for
10 µs
- Read the data bus through PINB
- Negate Data Input/Output Read
Through these functions, we were able to verify that
we could initiate a software reboot, read/write to registers, and
send commands to the drive. We didn't understand enough of the ATA/IDE
interface to read the different hard-drive sectors and the FAT32 table.
For more information regarding reading and writing sectors, refer
to http://www.t13.org. The source
code for the Atmel Mega103L/Hard-Drive interface is ide.c.