E E 2 8 9 October 21, 2009

Lab 2. DSP Speech Capture and Playback

This lab exercise uses Texas Instruments’ integrated development environment (IDE) called Code Composer Studio (CCS) and the DSK6713 digital signal processor (DSP) board to illustrate DSP operations.

The DSK6713 board has a TI TMS320C6713 DSP, memory, an audio coder/decoder (codec), and other hardware. Once the source code is compiled, it can be downloaded to the DSK6713 board and the DSP can execute it.

For this lab exercise, you will need to get the CCS project file and source code file from the network drive: http://www.cems.uvm.edu/~mirchand/classes/EE275/2009/Software/

You can copy the files for the lab to your network drive, then open them from CCS.

Introduction

In this lab exercise, the DSP operation is defined in source code that is compiled for the DSP, loaded to on-board memory, and executed. The DSP digitizes and saves an analog signal and plays it back either backward or forward depending on the state of the on-board switches.

Code Composer Studio organizes files into projects and stores the components specific to the project in a project file. In this lab you will bring up an existing project file, record_play_fw_bw.pjt.

For this project, the source code is written in the C language. You don’t have to understand all the syntax, but you should understand the logic of the code. Since some code remains the same for many applications, the code it is split up into multiple files, and only those files with code specific to the application need to be edited. We’ll look at just the top-level file source file, record_play_fw_bw.c.

In C:

·  Whitespace (spaces, carriage returns, blank lines) is ignored by the compiler.

·  Any characters following ‘//’ on a line are comments, and are ignored by the compiler.

·  Any characters, including carriage return/line feed, between ‘/*’ and ‘*/’ are comments.

·  Statements end with a semicolon ‘;’.

Here’s the top-level code listing. A brief explanation of the meaning of each line follows, with the descriptions of the lines that are more important to the flow and function of the program in bold. Be sure to look at the code, not just the comments.


1 //record_play_fw_bw.c record/play input using external memory

2 #include "dsk6713_aic23.h" //codec support

3 Uint32 fs=DSK6713_AIC23_FREQ_8KHZ; //set sampling rate

4 #define DSK6713_AIC23_INPUT_MIC 0x0015

5 #define DSK6713_AIC23_INPUT_LINE 0x0011

6 Uint16 inputsource=DSK6713_AIC23_INPUT_MIC; // select input

7 #define N 2400000 //large buffer size 300 secs

8 //#define N 80000 //buffer size 10 secs

9 long i, j;

10 short buffer[N];

11 #pragma DATA_SECTION(buffer,".EXT_RAM") //buffer ->external memory

12 void main()

13 {

14 short recording = 0;

15 short playing = 0;

16 for (i=0 ; i<N ; i++) buffer[i] = 0;

17 DSK6713_DIP_init();

18 DSK6713_LED_init();

19 comm_poll(); //init DSK, codec, McBSP

20 while(1) //infinite loop

21 {

22 if(DSK6713_DIP_get(3) == 0) //if SW#3 is pressed

23 {

24 for (i=0 ; i<N ; i++) buffer[i] = 0;

25 i=0;

26 recording = 1;

27 while (recording == 1)

28 {

29 DSK6713_LED_on(3); //turn on LED#3

30 if (i<N) buffer[i++] = input_left_sample(); //input data

31 if (i>2000)

32 if (DSK6713_DIP_get(3) == 1)

33 {

34 j=i; // last buffer index

35 recording = 0;

36 DSK6713_LED_off(3);

37 }

38

39 } // while (recording == 1)

40 } //if

41 if(DSK6713_DIP_get(0)==0) //if SW#0 pressed, play normally

42 {

43 i=0;

44 playing = 1;

45 while (playing == 1)

46 {

47 DSK6713_LED_on(0); //turn on LED#0

48 output_left_sample(buffer[i++]); //input data

49 if (i>=j) i=0;

50 if (i>2000)

51 if (DSK6713_DIP_get(0) == 1)

52 {

53 playing = 0;

54 DSK6713_LED_off(0);

55 }

56 } // while (playing == 1)

57 }

58 if(DSK6713_DIP_get(1)==0) //if SW#1 pressed, play backwards

59 {

60 playing = 1;

61 i=j;

62 while (playing == 1)

63 {

64 DSK6713_LED_on(1); //turn on LED#1

65 output_left_sample(buffer[i--]); //input data

66 if (i<=0) i=j;

67 if (i+2000<j)

68 if (DSK6713_DIP_get(1) == 1)

69 {

70 playing = 0;

71 DSK6713_LED_off(1);

72 }

73 } // while (playing == 1)

74 }

75 }

76 }


Line 1: A comment identifying the name of the file.

Line 2: Identifies to the compiler the header file for the AIC23 coder/decoder (codec) chip that performs the analog-to-digital and digital-to-analog conversions. The header file has information for the compiler about how to interface with the codec.

Line 3: Declares the type and size (unsigned 32-bit integer) of the sampling frequency to use.

Line 4: Defines an easy to remember constant to identify the source as “Microphone”.

Line 5: Defines an easy to remember constant to identify the source as “Line In”.

Line 6: Declares the type and size (unsigned 16-bit integer) of the data from the input source, and sets the input source to be the microphone.

Line 7: Defines a constant for the size of the memory array that holds the digitized audio.

Line 8: A comment with a different size for the memory array.

Line 9: Declares the type (long integer) of the two variables i and j.

Line 10: Declares the type (short integer) and length of the memory array that holds the digitized audio. The array is N short (16-bit) integers. A short integer is sufficient to hold a single sample from one channel of the codec.

Line 11: The pragma directs the compiler to use external memory, that is, memory that is not built into the DSP chip, but is installed on the board.

Line 12: The start of the top-level module, main. Since main doesn’t return a value, its return value is shown as void. Since it doesn’t take an input, the parentheses are empty.

Line 14: Declares the type (short integer) and initializes the variable recording to zero.

Line 15: Declares the type (short integer) and initializes the variable playing to zero.

Line 16: Defines a loop to be executed N times, where each value in the audio buffer is set to zero. The variable i initializes to zero and increments by one after each time through the loop, until it reaches N-1, when the program exits the loop.

Line 17: Calls the function to initialize the switch state.

Line 18: Calls the function to initialize the LED state.

Line 19: Calls the function that initializes communication between the codec and the DSP. This is a polling function, so the DSP has to loop on checking the port (the multichannel buffered serial port, or McBSP) on the codec to see if there is new data available.

Line 20: Defines the start of an endless loop. In C, zero is false, and non-zero is true, so the argument to while is always true, which means the DSP will continue polling forever.

Line 22: Checks to see if switch 3 is pressed. If it is, recording is started.

Line 24: Defines a loop to clear out the buffer. See the description of Line 16.

Line 25: Sets the variable i to zero.

Line 26: Sets the variable recording to 1, to allow the while loop following to run.

Line 27: Defines a loop that will continue until the variable recording is no longer equal to 1.

Line 29: Calls the function that turns on LED 3.

Line 30: Calls the function that reads the input sample from the left channel on the codec and loads the current buffer location with it, then increments the variable i to be ready for the next sample.

Line 31: Checks whether i is greater than 2000. If it is, line 32 is executed.

Line 32: Calls the function that checks whether switch 3 is pressed. If it is not pressed, lines 33 – 37 inclusive are executed.

Line 34: Sets the variable j equal to the value of variable i. The variable j is used later in the program.

Line 35: Sets the variable recording equal to 0. This value will cause the while loop to exit when the program completes this pass through the while loop.

Line 36: Calls the function that turns off LED 3.

Line 41: Calls the function that checks whether switch 0 is pressed. If it is, lines 42 – 57 inclusive will be executed.

Line 43: Sets the variable i to zero.

Line 44: Sets the variable playing to 1, to allow the while loop following to run.

Line 45: Defines a loop that will continue until the variable playing is no longer equal to 1.

Line 47: Calls the function that turns on LED 0.

Line 48: Reads buffer location i and calls the function that sends it to the codec to be output on the left channel, then decrements the variable i.

Line 49: Sets the variable i back to 0 if it is larger than the last used buffer index.

Line 50: Checks whether the variable i is greater than 2000. If it is, line 51 is executed.

Line 51: Calls the function that checks whether switch 0 is pressed. If it is not, lines 52 – 54 inclusive are executed.

Line 53: Sets the variable playing to 0. This value will cause the while loop to exit when the program completes this pass through the while loop.

Line 54: Calls the function that turns off LED 0.

Line 58: Calls the function that checks whether switch 1 is pressed. If it is, lines 59 – 74 inclusive will be executed.

Line 60: Sets the variable playing to 1, to allow the while loop following to run.

Line 61: Sets the variable i equal to the value of j. The variable j was set in line 34.

Line 62: Defines a loop that will continue until the variable playing is no longer equal to 1.

Line 64: Calls the function that turns on LED 1.

Line 65: Reads buffer location i and calls the function that sends it to the codec to be output on the left channel, then decrements the variable i.

Line 66: Checks whether the variable i is less than or equal to 0. If it is, it sets i equal to the value of j.

Line 67: Checks whether the variable i is 2000 less than the variable j. If it is, line 68 is executed.

Line 68: Calls the function that checks whether switch 1 is pressed. If it is not, lines 69 – 72 inclusive are executed.

Line 70: Sets the variable playing to 0. This value will cause the while loop to exit when the program completes this pass through the while loop.

Line 71: Calls the function that turns off LED 1.


Caution!

The integrated circuits on the DSP board have gate oxides that are only tens of atoms thick. They can be easily damaged by static charges. Don’t touch the components on the board except for the switch and connectors.

Getting Started

Start CCStudio v3.3 from the desktop icon or from the All Programs list in the start menu, under Texas Instruments -> Code Composer Studio 3.3 -> Code Composer Studio. It takes a few minutes for the CCS window to open.

Load the project from the Project -> Open pulldown menu: navigate to directory listed earlier in the lab and double-click on record_play_fw_bw.pjt. If it can’t load files from the “Support” directory, browse to C:\CCStudio_v3.3\MyProjects\Support\ to locate the files.

In the browser pane at the left of the CCS window, click on the ‘+’ sign next to the project name to expand the tree. Then click on the ‘+’ signs next to Include and Source. You’ll see a list of the files used for the project. You can view the files by double-clicking on the file names to bring up an editor. Don’t make any changes or the project could become uncompilable.

In the lower left corner of the CCS window, you’ll see DISCONNECTED (UNKNOWN). This message indicates that CCS is not connected to the DSP board. Connect from the Debug pulldown menu. The message in the lower left corner should change to HALTED and a Disassembly window will pop up.

The Disassembly window shows the machine code in hexadecimal along with the corresponding readable assembly code instructions. Assembly code describes movement of data into and out of registers in the DSP, a much lower level of abstraction than the C code that this project was written in. Assembly code is typically used for critical parts of a program, for optimization, or for small projects.

Working with the Program

1.  Compile and link the project by clicking on the toolbar button with the three downward-facing red arrows (Rebuild All), or by choosing:

Project -> Rebuild All

You will see messages at the bottom of the CCS window. The last message should be:

0 Errors, 0 Warnings, 0 Remarks

The compiler converts the C code to machine code, a binary representation of the code that the DSP can execute. Linking combines the object files created by the compiler and resolves addresses for branch and jump instructions.

2.  Now that the project is compiled and linked, you need to load it into the DSP memory so the DSP can execute it. Choose:

File -> Load Program... -> Debug -> record_play_fw_bw.out

A Disassembly window will pop up. The arrow points to the current instruction.

3.  Once loaded, you can run the program. Select

Debug -> Run

The message in the lower left corner of the CCS window should change to RUNNING. Nothing will happen because there is no signal that tells the program to record. The DSP is looping, waiting for a switch to be pressed.