Program Design By Zhi-Hern Loh

A 2nd try


This program was designed for a ATMELMega128 MCU connected as specified on the hardware design page.

The program design was organized in the following main groups

bulletSerial I/O handler
bulletSTA013 decoder I/O handler
bulletXmodem receiver (Includes buffering the MP3 data)
bulletUser Interface

The following paragraphs document the design of the MP3 player program. There are explanations and instructions for the usage of the functions included in the main program groups outlined above.

Code used in debugging and development are also documented here.

Serial I/O handler (serial.h)

The serial I/O handler was interrupt based. Strings to be written to the serial interface were stored in a string located in sram. To write to the serial port, the program needed to check a output ready flag(OUT_RDY) and then call a function to write a string to the output buffer. Conversely, input from the serial interface was written to another string a character at a time until a carriage return was detected. Upon the detection of a carriage return, a input ready flag (IN_RDY)  would be set. When the IN_RDY flag is set, the program can read the buffer by calling a specific function.

Writing to the serial interface requires the use of the following functions

bullet S_Printf(unsigned char flash []) - Waits until OUT_RDY then writes a string from flash to output buffer and starts the transmission ISR.
bullet S_Print(unsigned char []) - Same as above but takes string in SRAM.
bullet S_Outf(unsigned chaf flash []) - Without checking OUT_RDY flag, this writes a string from flash to output buffer and starts the transmission ISR.
bullet S_Out(unsigned char []) - Same as above but takes string in SRAM.
bulletInit_Serial() - Initializes the registers for serial I/O.

STA013 decoder handler (STA013.C)

STA013 header (sta013.h)

Using the STA013 requires that the decoder be initialized with a series of about 2000 bytes containing register addresses and data. These 2000 bytes are stored in a .bin file. I used a Intel hex (click here for Intel hex format) version that was also used in the previous MP3 project by another group. CodeVision C's chip programmer can load this Intel hex file and write to the eeprom of the MCU.

Calling STA013_Init() initializes the STA013 by executing the following:

  1. Writing TWBR = 72. This is for setting the I2C clock rate in the Mega128 MCU. The value 72 corresponds to a clock rate (SCL) of 100kHz.  SCL freq = CPU CLK/(16 + 2(TWBR)*4^TWPS)
    where TWPS = prescalar, is set to 0.
  2. Calling STA013_HW_Reset() - Sets the !Reset line low for 1 sec.
  3. Calling Read_Eeprom(). This function reads the configuration values and writes them to the STA013 via the I2C bus.

After the STA013 decoder has been initialized, the following functions can be used:

bullet STA013_Write() - To write a data byte to a specific register in the decoder. For example, to start playing a song we would write STA013_Write(0x72,0x01); and STA013_Write(0x13,0x01); (Ref main.c)
bullet STA013_Audio_Send() - Sends a MP3 byte. This should only be called when DATA_REQ flag is high.
bullet STA013_Audio_Stop() - Sends the commands to stop playback.

Also of interest might be the header file containing mp3 data that was used for debugging. As well as the STA013_Play_MP3() function that played the mp3 data stored in flash memory.

Other functions good for debugging include

bullet Display_Reg() - Given an address, this shows the contents of the register in the STA013.
bullet STA013_Test_Serial_Interface() - Tests the SCKR, SDI and DATA_REQ lines, allows the user to check the output/input port manually.
bullet STA013_Show_Info() - Shows the contents of a specified lists of registers.


Xmodem receiver (Xmodem.c)

Xmodem header (Xmodem.h)

Using the Xmodem protocol is straight forward when we are not playing back a MP3 concurrently. However in this project, the available memory on the Mega128 is insufficient to buffer the entire MP3 song before starting playback. In order to play the song smoothly, I employed a circular buffer to store the MP3 data before sending them to the STA013 decoder.

The Xmodem receiver must then handle both download and playback concurrently to prevent buffer over or under-flows. Thus I could not afford function calls within the receiving function because of this time critical nature. The function calls would have taken too many cycles to get in and out. This resulted in a very long function that polls the UART as well as sends MP3 data bytes to the decoder. The length of the function makes it difficult to read and understand. However the underlying principle of the receiver is similar to the flowchart of the Xmodem protocol.

The external functions in Xmodem.c are

bulletInit_Xmodem() -
  1. Enables SRAM.
  2. Verifies that the addresses in the buffer can be written to.
  3. Sets the buffer pointer and the mp3 data pointer to the start address.
  4. Sets up timer1 so that the timer 1 overflow ISR will ocurr in 1 second if enabled.
  5. Turns off the receive and transmit UART ISRs
  6. Sets EOT_number = Packet_Number = Byte_Number = 0
bulletX_Start_Instant() -
  1. Calls Init_Xmodem()
  2. Disables the UART receive interrupt to prevent it from interfering with the reception of data bytes by X_Poll()
  3. Sends a 'C' to Hyperterm, signalling start of Xmodem transmission.
bulletX_Write_Packet() - This function is called at the end of each verified packet. The packet contents in the SRAM buffer are written to the cyclic buffer containing the rest of the MP3 data. At the same time, the DATA_REQ flag is monitored, and if high, bytes of MP3 data would be sent to the decoder.
bulletX_Poll() - This is the implementation of the Xmodem protocol as defined by the flowchart. X_Poll() returns only when the file transmission is complete or when the user presses the cancel button.


The MP3 data was written into a cyclic buffer. The algorithm is as follows:

  1. The head pointer points to the start of the buffer.
  2. Write some data bytes to the buffer and increment the head pointer by the same number of bytes.
  3. Play some mp3 data making sure that the mp3 data pointer does not overtake the head pointer.
  4. Write more bytes to the buffer and make sure that the head pointer wraps around to the start of the buffer if the end address is reached. Also, the head pointer must not overtake the mp3 data pointer or else the playback will skip.

User Interface

User Interface (ui.c), ui.h

The user interface consists of 4 buttons.

bulletStart - Starts the playback, sends a 'C' to Hyperterm to initiate Xmodem transfer
bulletStop - Stops the playback by sending 2 CAN bytes to Hyperterm
bulletVolume increase
bulletVolume decrease

User prompts and system status are shown on both the LCD and the serial interface. While Xmodem transfer is in progress, the serial interface cannot prompt the user or display information and hence the LCD is used.


Debugging and development code

I wrote a C program for the PC to do convert a .mp3 file to a header file that CodeVision C could read. This header file contained the MP3 data as bytes in a unsigned char array stored in flash. Click to see the code and example header file.

There are also some STA013 function calls that were useful during development.

Home | Design | Results | A 2nd try | Schematics | Code | Files | Links | Contact

For problems or questions regarding this web contact Zhi-Hern Loh.
Last updated: 05/02/02.