EE 476 Final Project: MP3 Player

Nelson Li and Jason Dirner

Spring 2002




Atmel Mega103L/STA013 Interface:

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.

Atmel Mega103L/Hard-Drive Interface:

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 The source code for the Atmel Mega103L/Hard-Drive interface is ide.c.



Atmel Mega103L/STA013 Interface:

Atmel Mega103L/Hard-Drive Interface: