ECE 5760- Final Project
We implemented a fully functional music player, capable of playing music files through the Altera DE2 board. The motivation behind this project is the impact of the music players in this decade. Features like portability and ease of use made the music players a grand success among people.
Our idea is to create a music player using programmable logic and analyze the various processes involved in the system. We designed a music player that plays music files from SD card in real time, while providing user interaction, such as pause music, fast forward and more. Though the initial idea was to implement a music player to play (.mp3) files from the memory, we revised the goal to implement a music player that is capable of playing .wav files (media files). This was performed due to various constraints involved in the design of an mp3 decoder.
High Level Design:
SD CARD Controller:
The basic memory used here is the SD card. The board has a SD card slot, into which the SD card is inserted. The SD card controller is designed to provide the interaction with the SD memory. In order to find the best possible method to interface the SD card with DE2 board, we came across various existing IP cores that could be used to control the SD card at the HAL abstraction level or by physical implementation.
The SD card file system needs to comply with the following requirements:
- FAT 16 file format, implies that the smallest data element is 16 bits long.
- Also, the FAT 16 format partitions the whole memory into blocks of data, each block consisting of 512 bytes.
FAT 16 file system:
The FAT 16 system is required by the SD card Controller to detect the card. This system partitions the whole memory into blocks, where the partitions are performed as given in the diagram below,
We chose to implement the SD card based on SPI mode of communication. In SPI, one bit data transfer is obtained. This allows the design of the interface to be simple and easy. But, it has lesser performance when compared to the SD card bus mode, where parallel data transfer is possible (upto 4 bits). In SPI, the pins used are SD_CLK, SD_DA and SD_CMD. The SD_CLK is used to set and maintain the Clock speed of the SD card, upon which the other pins communicate with the SD card. The SD_CMD pin is basically used to send the commands, CMDxx and ACMDxx being the command representations. Here, CMD refers to general SD card commands, ACMD referring to specific commands and xx stands for the number of a particular command.
SD card controller - SPI mode
Further, each command is transmitted as a frame, of size 6 bytes. Each frame starts with a ‘01’ signal followed by 6 bits of command numbers. Then, 4 bytes of the command argument is sent. Finally, the last byte containing 7 bits of CRC and the stop bit is transmitted. Now, the SD card waits for the response from the SD card, and the possible responses varying with individual commands.
SD card Command structure
This function is used to detect and initialize the SD card. The CMD0 is sent by this function to the SD card and the response I awaited. The response can be only of certain types, such as CRC error, idle etc. Based on the response this function returns a value. In case there is no response from the SD card, it returns a value ‘1’. When the card is detected and initialized, it returns a zero value.
SD_read_block(UINT32 block_number, BYTE *buff) :
This function is used to read a single block of memory in the SD card. By understanding the timing information given below, we can use the read function to read 512 bytes of data.
SD card read operation
SD_read_lba(BYTE *buff,UINT32 lba,UINT32 seccnt) :
This function is used to read multiple blocks from the SD card. First, the CMD17 is sent across to the SD card, which represents the Read command. Next, the data line is monitored for current data transmissions. Then, the function reads byte by byte from the SD card location specified by the ‘lba’ value. After the 512 bytes have been read from the block, it repeats the function for the given number of sectors.
Multiple block read
send_cmd(BYTE *in) :
It is the basic function of the SD card controller. It uses the SPI interface to send and receive information. It is used by other functions to send their commands.
response_R(BYTE s) :
This function waits for response from the SD card and reports it other functions. Hence, it used as a basic function by other high level abstractions.
We require the digital data from the SD card to be given to the analog LINE OUT of the board to get the music. This part of the system is the Audio Codec. The various modules required to carry out this function are:
- The FIFO module: This is a 256 * 16 bits wide buffer used to bridge the NIOS and the DAC. The data from the NIOS is given to this buffer to serialize the data stream.
- I2C interface unit, which controls the flow of data in the codec.
- PPL module, generating a clock frequency of 18.4MHz.
The audio codec generates the AUD_LRCLK in synchronization with the 18.4MHZ clock produced by the audio_pll. At the positive edge of this LRCLK, the data is being latched onto the oAUD_DATA variable, which is then transmitted to the DAC portion in the board. The .wav file is sampled at 48Khz, so the DAC sampling frequency is also set to 48Khz. The deemphasis is set to 48Khz too.
SOPC builder screenshot
The SOPC builder is used to connect the major components of this project, including the Audio Codec, the SD card interface and other peripherals. These components have base addresses assigned to them, by which read and write operations can be performed.
The SMD_CLK,SMD_DAT,SMD_CMD are the PIO used to communicate with the DE2 board via the SOPC builder. Similarly, the Audio codec has been instantiated and the 16 bit data from the NIOS II gets written directly into the audio codec. All these modules operate at 100MHz frequency except for the SD RAM Controller. The SD RAM controller provides the memory for the NIOS II processor.
Basically, this project has a large chunk of functions being implemented on the NIOS II processor. This can be seen from the fact that using a HAL level makes it very easy to use the SD card. Naturally, the music player operation and user interface is built using the NIOS II. Here, the main() function contains the music player. Here, the various SD card functions are called to perform the tasks.
Flow of NIOS code
Basically, the NIOS II top level function controls the operation of the player. Once, the player is started, NIOS processor waits for the SD card to be inserted into the slot. Once the SD card is inserted, the initialization takes place. Here, the file system is detected and the file directories are listed. The file_list(<arguments>) function is used to find all the media and lyric files present in the SD card. This is done by searching through the FAT16 file directory for the file types: .WAV and .LRC. This data is displayed by the LCD and the user is allowed to select the song. Also, the user can choose to play all the songs in from start to end by selecting the SW switch.
The KEY and KEY are used to browse through the playlist to select a particular song. This is made possible by displaying the name of the current song. Once the user browses through the directory and decided to choose a particular song, KEY should be pressed twice to select the song, indicated in the LDC screen. Once a song is selected, it is read from the SD card and sent to the FIFO buffer. The ‘song_position’ value determines the byte address within a song, while ‘song_num’ determines the list of songs. The Switches SW, SW and SW are used to fast- forward, go reverse and pause the song respectively. Also, SW selects the random mode, by which the player outputs songs based on various random factors: the current song data combined with the total number of songs and total number of files, finally a modulo division by the number of songs. Once a song is played completely, the player returns to the main menu. The SW is used to manually reset the player, to make it go to the initial stage.
Now, the current byte address of the song is determined, and the SD_read_lba() function is used to read from the SD card, in order of 512. This 512 bytes value is stored in the buffer named temporary1. Next, the buffer data is transmitted to the Audio_DAC_FIFO. Also, we designed an equalizer, using the LED’s, which displays the power of the sigan(sound), as time progresses.
The VGA controller was implemented using the SOPC builder. The VGA controller was used to display a picture when the music player was started. The BMP image was decoded by the VGA controller once the player started and this command was sent from the NIOS to the VGA controller.
This is the 16*2 character LCD IP core is instantiated in the SOPC builder. It is connected to the top level module of the system, while it is accessed by the NIOS by writing into the base address. It can display upto two lines, ASCII characters. It used in this project to display the status of the music player and the Lyrics at real time.
Seven Segment display Controller:
This module is also instantiated in the SOPC builder, and it is used mainly to display the time with respect to the song being played. Also, it displays the song number, and the total number of songs available in the memory.
Various PIO’s are used to transmit data between the NIOS and the hardware module. The PIO’s are used to get the input from the switches and keys. The
This project was developed in various stages. Our initial idea was to implement the SD card IP core (provided by the Altera University Program IP cores). We could implement the IP core on the SOPC builder but the NIOS program on the HAL platform failed to provide the required results. We were unable to detect the file system of the SD card using this IP core. Hence, we implemented the SD card controller using the SPI interface.
We started on a basic project example provided by Altera/Terasic for DE1 board. This example had audio codec and many other components. But, most of these components such as ISP interface, EPCS controller etc. were not required for this project. Also, this project uses an earlier version of Quartus and SOPC builder. Hence, most of these components could not be upgraded to the SOPC builder that we used. Hence, we just used the SD card SPI interface provided by this example. Thus, we could upgrade the SOPC builder to the current version. By the end of this phase, we designed the components. The Audio codec (Wolfson WM8731) and the VGA controller are the major parts of the SOPC builder.
We started designing the functionality of the player, in NIOS. We tried to read the .wav files initially and send it to the audio codec. We used Slave addressing to transmit the data from NIOS to the audio codec. Similarly, we used the slave addressing to all the peripherals too. We had to understand how to use these addressing modes, to implement them in the NIOS. Then, we designed the function to read the lyrics file. Once this is completed, we began to design the user interface. We implemented the basic functions: Pause, fast-forward, reverse. Next, we implemented the random play, continuous play and the repeat mode. Finally, using the timestamp function, we designed the synchronization between the lyrics and the music.
The final phase consisted of testing the quality of output. The output from the DAC seemed to be distorted from the actual data from the SD card. The quality of the music hence was degraded. We tried to resolve this issue using various debugging methods. We analyzed the output from the DAC channels with the oscilloscope, finding an interesting pattern. We gave a 1000Hz sine wave input from th SD card and observed the output from the LINE_OUT. We found that after certain intervals, the sine wave output was deformed for a very short period. The deformation could be seen as a sharp peak or a flat level output etc. We tested the system with different signals. We passed a 1000KHz sine wave one-channel input. We observed that the output from the DAC was from both channels. Also, the frequency at the output deviated from 1000 KHz. We performed tests by varying the clock input to NIOS and the audio codec. The sampling rates were also modified to 44.1KHz and tested.
Result and Analysis:
The music player was successfully implemented, in real time. The user interface consisted of:
The VGA display, LCD display, seven segment and LED’s were used for showing various functions of the player. The VGA controller was used to display an image when the music player was started. Then, the LCD display showed the playlist and displays the input that the player requires from the user (Ex. Press KEY to select a song). The seven segment display gives the current play time of the song, the current song number being played and total number of songs. The LED’s were used to display the equalizer.
The user controls the music player through various controls such as the song selection (next, previous), play mode (random, continuous, repeat). Also, the user can control the song, while it is being played, pause, fast forward and reverse. Overall, our wav player gives the user almost all the functions that an actual music/mp3 player can have.
The music player was limited by its quality of output from the DAC. This turned out to be having some distortion. It is seen that music involving a range of sounds, with high frequencies could not be played as well as the music involving minimal range of sounds. This could be due to various reasons. First, it might have been due to out of order byte transmissions, so that some parts of the music were distorted. Also, this could be an issue with the SD card access speed. The FIFO buffer could have been emptied by the DAC, before the NIOS could refill it. Also, the NIOS running at 100Mhz could be an issue, since the audio codec is running at 18.4 MHz.
The wav player was designed with interesting features and gave good output. WAV player was an interesting project to implement, and the NIOS and IP cores were important areas that we could explore. We have a good idea of how to use the SOPC builser, the NIOS and the IP cores. Having the freedom to choose our final project gave us a lot of choices and ideas to come up with. Since, the whole system involved Avalon bus, we understood the addressing methods with the Avalon slave and master. By the end of this course, we gained considerable knowledge in FPGA’a , digital design, verilog coding and debugging skills.
IP core Considerations:
We have uitlized terasic/Altera Audio codec, VGA controller and the base project of SD Card reader.
We would like to thank altera/terasic technologies for providing the basic SD card reader project on which we could work. Also, our sincere thanks to Bruce Land for his help throughout the course, and for providing such an unique and effective course, in terms of gaining practical knowledge.
Top module IP cores
User interface in NIOS
3- terasic Introduction to NIOS demo (pdf).