📄 evm67x.txt
字号:
EC581 DSP Projects: Lab Project #5
Dept. of Electrical and Computer Engineering
Rose-Hulman Institute of Technology
Digital Audio Average Volume Intensity Meter
& DSP-to-PC Communication
Last Modified on March 25, 2002 (KEH)
1. Adding the VU Meter Feature
A volume-unit (VU) meter is an AC voltmeter that indicates the average magnitude of an audio waveform over a specified time interval, such as 30 ms. (The same time frame was used in last week’s digital AGC project, Project 4.) Furthermore, recall that the average magnitude of the frame was already calculated by the AGC program, as the variable AVG_MAG_OF_FRAME. The VU meter typically uses a logarithmic (dB) scale. This is because the human ear has a logarithmic response. In our case, we shall use the average frame magnitude as the VU meter reading.
This week’s project is to modify your digital AGC program so that it will continue to act as a real-time AGC, but at the same time, it must periodically display the VU meter value. This value must be displayed on the PC screen at specified intervals of time.
Unfortunately, if you try to use a “printf( )” function call from within the DSP program to print the average frame magnitude value, the sampling will be temporarily suspended for a short , but noticeable period time, while the printf( ) is periodically displaying the VU value on the PC screen.
Nonetheless, let us start using a printf( ) statement, just to verify that the VU meter is working as expected. Do NOT put the printf( ) inside your interrupt routine, since print statements are slow compared to the time between interrupts = 1 / 8 kHz = 0.125 ms. Instead, you will want to put your print statement inside the idle (infinite) loop at the end of your main function, which has been left empty in previous projects. Inside the idle loop, you will need to continuously monitor the global array pointer index variable (let’s call it index), in order to keep from printing the same average frame magnitude more than once. This global index variable index is used to fill the circular frame buffer inside of the interrupt routine. The procedure is illustrated in Listing 1. As can be seen in this listing, there is an inner while loop that waits (loops) until index = 0 (meaning that the array has wrapped, and a new average magnitude has been calculated by the interrupt routine.) The new VU meter value is now printed. Finally, a second while loop is used to wait until index becomes non-zero before proceeding back to the top of the infinite loop.
Run this program and speak into the microphone. Verify that the VU meter value appears to be responding properly. The only problem with this program is that the AGC function no longer operates continuously. This is because the printf( ) function cannot be interrupted. This problem will be solved in the next section.
Listing 1. Modification of main program’s infinite “idle” loop to allow printing of average frame magnitude values.
while(1) /* End of main program – infinite loop */
{
while(index); /* Wait until circular buffer wraps *
printf("%f7.3\n",ave); /* Print average frame magnitude
for current 30 ms frame */
while(!index); /* Wait until index is non-zero before
going back to top of infinite loop *
}
Demonstrate this program to your lab instructor, and obtain his signature on your program listing. Include this signed listing in your lab report as Attachment A.
2. DSP-to-PC communication and MSVC++ Console Application
In the previous section, you verified that the VU meter value (average frame magnitude) is correctly calculated by the modified AGC program running on the C6x EVM board. Now you are ready to add statements that will send this data down to a companion MSVC++ program that is running on your PC. The MSVC++ program must receive the VU meter value from the DSP program and display it on the PC screen. With this scheme, the DSP program can once again run its AGC algorithm continuously, without the periodic interruptions caused by the execution of the printf( ) statement that were observed in the previous section.
Follow the steps listed below to write the necessary MSVC++ program, and to learn how to modify your DSP’s C-language program so that it can communicate with the PC’s MSVC++ program.
The skills learned in this lab will probably be very relevant to your term DSP project. Most of the term projects will require writing two C-language programs, one for the DSP side and one for the PC side, which communicate data between them.
Steps in writing an MSVC++ console application and in communicating between PC and DSP programs
1) Open Microsoft Visual C++ (MSVC++). (I used MSVC++ Version 6.0.)
2) File -> New -> Projects -> Win32 Console Application
Fill in a project name in the project name box, then hit OK.
3) Check the “Hello World Application”, then hit OK.
4) File -> Open -> Select the .CPP (C++) source file that has the same root name as your project name. This is an example “Hello World” program!
5) To compile it, hit the <F7> special function key at the top of your keyboard.
6) To run it, hit the Ctrl - <F5> key.
7) To get ready to communicate with the EVM board, which runs its own C6x C-language program, you must do 3 things:
a) Add the following include statement at the top of the “.CPP” source file:
#include <evm6xdll.h>
b) Click on
Tools -> Options -> Directories
Then add the following include directory paths for the EVM routines:
C:\ti\c6000\evm6x\dsp\include
C:\ti\c6000\evm6x\include
c) Click on
Project->Add to Project -> Files
Then change “Files of Type” box to “.Lib”, and browse to find
c:\ti\c6000\evm6x\lib\evm6x.lib
d) Make sure that the Windows path includes (if not have your instructor add this).
c:\ti\c6000\evm6x\bin
8) Study the pair of companion programs shown in Appendix A (the C67 EVM DSP card program, lab5a.c) and Appendix B (the Microsoft Visual C++ (MSVC++) PC program, C67HPIDEM.cpp). This pair of programs provides a simple example of how to transfer integers and floating point numbers from the PC to the DSP card as well as from the DSP card to the PC. Software flags are used to synchronize, or “handshake”, the data transfer between the two programs. The transfer is performed using C6x DSP chip’s built-in host port interface (HPI) that interfaces to the PC through an AMCC S5933 PCI bus controller chip. See Section 1.6.1 of the TMS320C6201/6701 EVM Technical Reference Manual (SPRU305.pdf). The HPI is a very flexible interface “memory-mapped” interface that permits specified memory locations on the DSP board to be read or written by the host PC as well as the DSP. The host gains access to DSP card memory via three HPI read-write registers: a 32-bit address register, a 16-bit control register, and a 32-bit data register. The host writes the desired DSP memory address that it wants access to into the HPI Address Register, then the host can read or write data from/to that address in DSP memory space via the HPI Data register, as described in Section 7 of the TMS320C6000 Peripherals Manual (SPRU190C). The details of the operation of the HPI port are encapsulated into MS Windows API functions, such as the evm6x_hpi_read_single( ) and evm6x_hpi_write_single( ) functions, which are documented in Section 2 of the TMS320C6201/6701 EVM Technical Reference Manual (SPRU305.pdf).
From the standpoint of the DSP-side program of Appendix A, data is transferred via DSP card memory locations in the 128-byte range of the on-chip C67 RAM located between addresses 0x80000000 and 0x800000ff. I arbitrarily chose these locations in the C67 DSP address space, and then I “reserved them” by modifying the linker “command file”, instructing the linker NOT to assign this range of locations for any other purposes. Be sure to use this new linker command file in any programs you write that use HPI interface, which I have named linkhpi.cmd, and included in the AFS class directory folder “Lab 5”. Because memory is byte addressable, and data is interchanged in 32-bit (4-byte) chunks, the data transfer addresses must be chosen at 4-byte intervals, and the transfer addresses must be 32-bit-aligned: 0x80000000, 0x80000004, 0x80000008, etc. This demonstration program uses only four of these addresses, one for the DSP SEND flag, which is raised (changed from 0 to 1) when the DSP has data to send to the PC; one for the PC SEND flag, which is raised when the PC has data to send to the DSP; and two for the transfer of data between the PC and DSP.
From the PC-side (MSVC++) program of Appendix B, note that various “evm6x_” API function calls are used to transfer data between the DSP program and the PC program. These functions are described in Section 2 of the TMS320C6201/6701 EVM Technical Reference Manual (SPRU305.pdf).
9) You should now be able to use MSVC++ to compile the C67HPIDEM.CPP PC-side C-language program from the AFS Lab 5 class folder, following the steps outlined previously. This PC-side program, and how it interacts with its companion DSP-side program, will be discussed fully in class, though the comments should be largely “self-explanatory.” Click on Build – Rebuild All to compile the program.
You should separately compile the companion Lab5a.c DSP-side C-language program using the TI Code Composer. Start the DSP program running first, then start the MSVC++ program by clicking on Build – Execute C67HPIDEM.exe from the MSVC++ IDE. You should see that the two integers (5 and 7) were successfully sent to the DSP, processed by the DSP (multiplied together), and then sent back to the PC, where the result was printed (35). Then you should also see that the two floating point numbers (1.5 and 2.5) were likewise successfully processed, yielding a product of 3.75. Note how the ULONG_TO_FLT( ) and the FLT_TO_ULONG( ) functions are used when communicating floating point values, since the evm6x_hpi_read_single( ) and the evm6x_hpi_write_single( ) API functions can only communicate 32-bit long integer bit patterns between the PC and the DSP card memory.
10) Now write a short Microsoft C++ console application that functions as the VU meter display program. First, let it display the average magnitude of a 30 ms segment as an integer value.
11) After you get this to work, change it to display an ASCII-character-oriented bar graph display (row of asterisks.) Include your final listing as Attachment B.
3. Using a MSVC++ Program to start a DSP-side Program
Appendix C shows an example taken from the TMS320C67 User Manual that uses “evm6x_coff_load( )” along with several associated evm6x_ function calls to allows a PC-side MSVC++ program to automatically load a DSP-side program onto the C67 EVM DSP board, without first having to call up the Code Composer II debugging IDE. Of course, it is expected that this program has first been debugged and compiled using Code Composer.
Once you have your VU-Meter working, add these additional function calls to allow the whole thing to be executed from a DOS prompt! Include your listing as Attachment C.
Appendix A. DSP-side C-language example illustrating bi-directional host port interface (HPI) DSP/PC data transfer
//**********************************************************************************
// ECE581 DSP Projects Lab 5A -- Example of Two-Way, handshaked communication
// between the PC and the C67 EVM DSP Card using the Host Peripheral Interface (HPI)
// This demo sends two 32-bit unsigned (ULONG) integers to the DSP.
// The DSP multiplies them together and then sends result back to PC, and PC prints result.
// The demo is then repeated for two 32-bit floating point numbers.
//
// This is the DSP-Side Program (Written to run with TI Code Composer V2)
//**********************************************************************************
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Common.h>
#include <Mcbspdrv.h>
#include <Intr.h>
#include <Board.h>
#include <Codec.h>
#include <Mcbsp.h>
#include <mathf.h>
unsigned int *DSP_SND; /* DSP_SND points to (holds adr of) the DSP_SND_FLG */
unsigned int *PC_SND; /* PC_SND points to PC_SND_FLG */
unsigned int *DATA1; /* DATA1 points to integer data value */
unsigned int *DATA2; /* DATA2 points to integer data value */
float *DATA3; /* DATA3 points to floating point data value */
float *DATA4; /* DATA4 points to floating point data value */
int main()
{ unsigned int a,b,result;
float fa,fb,fresult;
// Initialize pointers to memory locations in reserved area of internal C67 RAM
// This area is reserved by the "LINKHPI.CMD" linker command file.
DSP_SND = (unsigned int *) 0x80000000;
PC_SND = (unsigned int *) 0x80000004;
DATA1 = (unsigned int *) 0x80000008;
DATA2 = (unsigned int *) 0x8000000C;
DATA3 = (float *) 0x80000008; // Note we reuse the data locations to point to floats
// for the second half of the demo program.
DATA4 = (float *) 0x8000000C;
/******************************************************/
/* Initialize EVM */
/******************************************************/
printf("Initializing EVM\n");
evm_init();
printf("Initializing EVM completed\n");
while(1)
{
printf("Waiting for PC_SND flag to be raised\n");
while(!(*PC_SND));
printf("PC_SND flag has been raised by PC-side pgm, so get data from PC side.\n");
a = *DATA1;
b = *DATA2;
printf("The following data was read: a = 0x%x, b = 0x%x\n",a,b);
printf("Now that data has been read from PC side, lower the PC_SND flag.\n");
*PC_SND = 0;
result = a*b;
printf("Put result ( = 0x%x) into DATA1, and raise DSP_SND flag to let PC know result is ready.\n",result);
*DATA1 = result;
*DSP_SND = 1;
printf("Wait for PC to get data by waiting until PC lowers DSP_SND flag.\n");
while(*DSP_SND);
printf("DSP_SND has been lowered by PC-side pgm, transfer of result back to PC completed.\n");
// Repeat demo for floating point numbers..
printf("Waiting for PC_SND flag to be raised\n");
while(!(*PC_SND));
printf("PC_SND flag has been raised by PC-side pgm, so get data from PC side.\n");
fa = *DATA3;
fb = *DATA4;
printf("The following data was read: fa = %f, fb = %f\n",fa,fb);
printf("Now that data has been read from PC side, lower the PC_SND flag.\n");
*PC_SND = 0;
fresult = fa*fb;
printf("Put result ( = %f) into DATA1, and raise DSP_SND flag to let PC know result is ready.\n",fresult);
*DATA3 = fresult;
*DSP_SND = 1;
printf("Wait for PC to get data by waiting until PC lowers DSP_SND flag.\n");
while(*DSP_SND);
printf("DSP_SND has been lowered by PC-side pgm, transfer of result back to PC completed.\n");
}
}
Appendix B. PC-side MSVC++ example illustrating bi-directional DSP/PC host port interface (HPI) data transfer.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -