Skip to content Skip to navigation


You are here: Home » Content » Core File: Introduction to Six-Channel Board for TI EVM320C54



What is a lens?

Definition of a lens


A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

This content is ...

Affiliated with (What does "Affiliated with" mean?)

This content is either by members of the organizations listed or about topics related to the organizations listed. Click each link to see a list of all content affiliated with the organization.

Also in these lenses

  • Lens for Engineering

    This module is included inLens: Lens for Engineering
    By: Sidney Burrus

    Click the "Lens for Engineering" link to see all content selected in this lens.

Recently Viewed

This feature requires Javascript to be enabled.


(What is a tag?)

These tags come from the endorsement, affiliation, and other lenses that include this content.

Core File: Introduction to Six-Channel Board for TI EVM320C54

Module by: Douglas L. Jones, Swaroop Appadwedula, Matthew Berry, Mark Haun, Dima Moussa, Daniel Sachs. E-mail the authors

Summary: The six-channel board for the TI EVM320C54 offers two channels of input and six channels of output at a sample rate of 44.1 kHz. It can also communicate with the PC via a serial port connection. The file thru6.asm exercises these inputs and outputs. The linker provides several sections of memory for storing program instructions and data. Test-vector input and output with vectcore.asm permits careful testing of DSP systems.

The Six Channel Surround Sound Board

The six-channel board attaches to the top of the DSP evaluation module and replaces its onboard, one-channel A/D and D/A with six channels of D/A and two channels of A/D running at a sample rate of 44.1 kHz. Alternatively, the A/D can be disabled and a SP/DIF digital input enabled, allowing PCM digital data from a CD or DVD to be sent directly into the DSP for processing. The two input channels and six output channels all sample at the same time; clock skew between channels is not an issue. By default, the core code reads and writes blocks of 64 samples for each channel of input and output; however, this aggregation can be changed to any value between 1 and 80 samples1. If your code needs a larger aggregation of samples - for instance, for a 256 point FFT - you will need to do this aggregation yourself.

Other features include buffered serial communication code, which allows you to send and receive data from the serial port. This can be used to control your DSP program with a graphical user-interface on the PC; it can also be used to report status back to the PC for applications such as speech recognition.

The core code, core.asm (which requires,, and also initializes the DSP itself. It enables the fractional arithmetic mode for the ALU, programs the wait states for the external memory, and sets the DSP clock to 80 MHz2.

Testing the six-channel sample code

We will start with a sample application, which simply sends the inputs into the outputs--relaying both the audio inputs from the A/D converters to the D/A converters, and any data that comes in on the serial port back to the PC. To familiarize yourself with this sample application, locate a copy of thru6.asm and assemble it.

Once you have done that, start Code Composer. Since we are using the on-chip RAM on the TMS320C549 to hold program code, we need to map that RAM into program space before we can load our code. This can be done by opening the CPU Registers window (the same one you use to look at the ARx registers and the accumulators) and changing the PMST register to 0xFFE0. This sets the OVLY bit to 1, switching the internal RAM into the DSP's program memory space.

Finally, load the thru6.out file, use Code Composer's Reset DSP menu option to reset the DSP, and run the code. Probe at the connections with the function generator and the oscilloscope; inputs and outputs are shown in Figure 1. Note that output channels 1-3 come from input channel 1, and output channels 4-6 come from input channel 2. Figure 1 shows the six-channel board's connector configuration.

Figure 1: Six-Channel Board Analog Inputs and Outputs
Figure 1 (6chan.png)

Also test the serial communications portion of the thru6.asm application. This can be done by starting a provided terminal emulator package (such as Teraterm Pro or HyperTerminal), configuring it to communicate at 38400 bps, with no parity, eight data bits, and one stop bit, and attaching the correct serial port on the computer to the TI TMS320C54x EVM. A serial port is a 9-pin D-shell connector; it is located on the DSP EVM next to the power connector. Typically, there will be two matching D-shell connectors on your computer, often labeled COM1 and COM2; make sure you connect your serial cable to the right one!

Once you have started the terminal emulator, and the emulator has been correctly set to communicate with the DSP board, reload and rerun the thru6.asm application. Once it is running, you should be able to communicate with the DSP by typing text into the terminal emulator's window. Characters that you type should be echoed back; this indicates that the DSP has received and retransmitted the characters. If the DSP is not connected properly or not running, nothing will be displayed as you type. If this happens, check the connections and the terminal emulator configuration, and try again. Due to a terminal emulation quirk, the "Enter" key does not work properly.

After you have verified that the EVM is communicating with the PC, close the terminal window.

Memory Maps and the Linker

Because the DSP has separate program and data spaces, you would expect for the program and data memory to be independent. However, for the DSP to run at its maximum efficiency, it needs to read its code from on-chip RAM instead of going off-chip; off-chip access requires a one- or two-cycle delay whenever an instruction is read. The 32K words of on-chip RAM, however, are a single memory block; we cannot map one part of it into program space and another part of it into data space. It is possible to configure the DSP so that the on-chip RAM is mapped into both program space and data space, allowing code to be executed from the onboard memory and avoiding the extra delay. Figure 2 shows the DSP's memory map with the DSP's on-chip memory mapped into program space.

Figure 2: Hardware Memory Map
Figure 2 (ram2.png)

Because the same on-chip RAM is mapped into both program and data space, you must be careful not to overwrite your code with data or vice versa. To help you, the linker will place the code and data in different parts of the memory map. If you use the .word or .space directives to inform the linker of all of your usage of data memory, you will not accidentally try to reuse memory that has been used to store code or other data. (Remember that .word allocates one memory location and initializes it to the value given as its parameter. .space 16*<words> allocates <words> words of uninitialized storage.) Avoid using syntaxes like stm #2000h,AR3 to point auxiliary registers to specific memory locations directly, as you may accidentally overwrite important code or data. Instead, use syntaxes like stm #hold,AR3, where hold is a label for memory explicitly declared by .word or .space directives.

There are two types of internal memory on the TI TMS320C549 DSP: SARAM (Single Access RAM) and DARAM (Dual Access RAM). The first 8K of internal memory is DARAM; the next 24K is SARAM. The difference between these two types of memory is that while SARAM can only be read or written once in a cycle, DARAM can be read or written twice in a cycle. This is relevant because the TMS320C549 DSP core can access memory up to three times in each cycle: two accesses in Data RAM to read or write operands, and one access in Program RAM to fetch the next instruction. Both DARAM and SARAM are divided into "pages"; access to memory located in different "pages" will never conflict. If, however, two operands are fetched from the same "page" of SARAM (which is divided into 8K word pages: 2000h-3FFFh, 4000h-5FFFFh, and 6000h-7FFFh) in the same cycle, a one-cycle stall will occur while the second memory location is accessed. Due to the pipeline, two memory accesses in the same instruction execute in different cycles. However, if two successive instructions access the same area of SARAM, a stall can occur.

Part of the SARAM (from 6000h to 7FFFh) is used for storing your program code; a small amount of SARAM below 6000h is also used for storing the DSP's stack. Part of the DARAM (from 0800h to 0FFFh) is used for the input and output buffers and is also unavailable. Ensure that any code you write does not use any of these reserved sections of data memory. In addition, the core file reserves six locations in scratch-pad RAM (060h to 065h); do not use these locations in your program code.

Sections and the Linker

You can use the .text directive to declare program code, and the .data directive to declare data. However, there are many more sections defined by the linker control file. Note that the core file uses memory in some of these sections.

You can place program code in the following sections using the .sect directive:

  • .text: (.sect ".text") SARAM between 6000h and 7FFFh (8192 words)
  • .etext: (.sect ".etext") External RAM between 8000h and FEFFh (32,512 words) The test-vector version of the DSP core stores the test vectors in the .etext section.
You can place data in the following sections:
  • .data: (.sect ".data") DARAM between 1000h and 1FFFh (4096 words)
  • .sdata: (.sect ".sdata") SARAM between 2000h and 5EFFh (16,128 words)
  • .ldata: (.sect ".ldata") DARAM between 0080h and 07FFh (1,920 words)
  • .scratch: (.sect ".scratch") Scratchpad RAM between 0060h and 007Fh (32 words)
  • .edata: (.sect ".edata") External RAM between 8000h and FFFFh (32,768 words) (Requires special initialization; if you need to use this memory, load and run the thru6.asm application before you load your application to initialize the EVM properly.)
If you always use these sections to allocate data storage regions instead of setting pointers to arbitrary locations in memory, you will greatly reduce the chances of overwriting your program code or important data stored at other locations in memory. However, the linker cannot prevent your pointers from being incremented past the end of the memory areas you have allocated.

Figure 3 shows the memory regions and sections defined by the linker control file. Note that the sections defined in the linker control file but not listed above are reserved by the core file and should not be used.

Figure 3: Linker Memory Map and Section Names
Figure 3 (linkmap.png)

Using the Core File

To simplify discussion, we have split up the thru6.asm file into two separate files for discussion. One, thru6a.asm contains only the code for using the A/D and D/A converters on the six-channel surround board; the other, ser_echo.asm contains only the code to send and receive data from the serial port.

Using the D/A and A/D converters

Here we will discuss thru6a.asm, which is shown below. ser_echo.asm is discussed in Core File: Serial Port Communication Between MATLAB and TI TMS320C54x.


	  1		.copy "core.asm"
	  3		.sect ".text"
	  4	main
	  5		; Your initialization goes here.
	  7	loop
	  8		; Wait for a new block of 64 samples to come in
	  11		; BlockLen = the number of samples that come from WAITDATA (64)
	  12		stm #BlockLen-1, BRC	; Repeat BlockLen=64 times
	  13		rptb block-1		; ...from here to the "block" label
	  15		ld      *AR6,16, A		; Receive ch1
	  16		mar *+AR6(2)                ; Rcv data is in every other word
	  17		ld      *AR6,16, B		; Receive ch2
	  18		mar *+AR6(2)                ; Rcv data is in every other word
	  20		; Code to process samples goes here.
	  22		sth A, *AR7+		; Store into output buffer, ch1
	  23		sth A, *AR7+		; ch2
	  24		sth A, *AR7+		; ch3
	  26		sth B, *AR7+		; Store into output buffer, ch4
	  27		sth B, *AR7+		; ch5
	  28		sth B, *AR7+		; ch6
	  30	block
	  31		b loop



Line 1 copies in the core code, which initializes the six-channel board and the serial interface, provides the interface macros, and then jumps to "main" in your code. Line 3 declares that what follows should be placed in the program-code area in internal memory.

On Line 4, we find the label "main". This is the entry point for your code; once the DSP has finished initializing the six-channel board and the serial port, the core file jumps to this label.

On Line 9, there is a call to WAITDATA. WAITDATA waits for the next block of 64 samples to arrive from the A/D. When it returns, a pointer to the samples captured by the A/D is returned in AR6 (which can also be referred to as pINBUF); a pointer to the start of the output buffer is returned in AR7 (also pOUTBUF). Note that WAITDATA simply calls the wait_fill subroutine in the core file, which uses the B register internally, along with the DP register and the TC flag; therefore, do not expect the value of B to be preserved across the WAITDATA call.

Lines 12 and 13 set up a block repeat. BlockLen is set by the core code as the length of a block; the repeat instruction therefore repeats for every sample time. Lines 15-18 retrieve one sample from each of the two channels; note that the received data is placed in every other memory location. Lines 22-24 place the first input channel into the first three output channels, and lines 26-28 place the second input channel into the last three output channels. Figure 1 shows the relationship between the channel numbers shown in the code and the inputs and outputs on the six-channel board.

Line 31 branches back to the top, where we wait for the next block to arrive and start over.

Using test vectors

A second version of the core file offers the same interface as the standard core file, but instead of reading input samples from the A/D converters on the six-channel board and sending output samples to the D/A converters, it reads and writes from test vectors generated in MATLAB.

Test vectors provide a method for testing your code with known input. Given this known input and the specifications of the system, we can use simulations to determine the expected output of the system. We can then compare the expected output with the measured output of the system. If the system is functioning properly, the expected output and measured output should match3.

Testing your system with test vectors may seem silly in some cases, because you can see if simple filters work by looking at the output on the oscilloscope as you change the input frequency. However, they become more useful as you write more complicated code. With more complicated DSP algorithms, testing becomes more difficult; when you correct an error that results in one case not working, you may introduce an error that causes another case to work improperly. This may not be immediately visible if you simply look at the oscilloscope and function generator; the oscilloscope does not display the signal continuously and transient errors may be hidden. In addition, it is easy to forget to check all possible input frequencies by sweeping the function generator after making a change.

More importantly, the test vectors also allow you to test signals that cannot be generated or displayed with the oscilloscope and function generator. One important signal that cannot be generated or tested with the function generator and oscilloscope is the impulse function; there is no way to view the impulse response of a filter directly without using test vectors. The unit impulse represents a particularly good test vector because it is easy to compare the actual impulse response of a digital filter against the expected impulse response. Testing using the impulse response also exposes the entire range of digital frequencies, unlike testing using periodic waveforms generated by the function generator.

Lastly, testing using test vectors allows us to isolate the DSP from the analog input and output section. This is useful because the analog sections have some limitations, including imperfect anti-aliasing and anti-imaging filters. Testing using test vectors allows us to ensure that what we see is due only to the digital signal processing system, and not imperfections in the analog signal or electronics.

After generating a test vector in MATLAB, save it to a file that can be brought into your code using the MATLAB command save_test_vector (available as save_test_vector.m):

	  >> save_test_vector('testvect.asm',ch1_in,ch2_in);  % Save test vector


(where ch1_in and ch2_in are the input test vectors for input channel 1 and input channel 2; ch2_in can be omitted, in which case both channels of the test-vector input will have the same data.)

Next, modify your code to include the test-vector support code and the test-vector file you have created. This can be done by replacing the first line of the file (which is a linker directive to copy in core.asm) with two lines. Instead of:

	  .copy	"core.asm"



	  .copy	"testvect.asm"
	  .copy	"vectcore.asm"


Note that, as usual, the whitespace in front of the .copy directive is required. (Download vectcore.asm into your work directory if you do not already have a copy.)

The test vectors occupy the .etext section of program memory between 08000h and 0FEFFh. If you do not use this section, it will not interfere with your program code or data. This memory block is large enough to hold a test vector of up to 4,000 elements. Both channels of input, and all six channels of output, are stored in each test vector element.

Now assemble and load the file, and reset and run as usual. After a few seconds, halt the DSP (using the Halt command under the Debug window) and verify that the DSP has halted at a branch statement that branches to itself: spin b spin.

Next, the test vector should be saved and loaded back into MATLAB. This is done by saving 6k 6 k memory elements (where k k is the length of the test vector in samples, and the 6 corresponds to the six output channels) starting with location 08000h in program memory. Do this by choosing File->Data->Save... in Code Composer, then entering the filename output.dat and pressing Enter. Next, enter 0x8000 in the Address field of the dialog box that appears, 6k 6 k in the Length field, and choosing "Program" from the drop-down menu next to "Page." (Always ensure that you use the correct length - six times the length of the test vector - when you save your results.)

Last, use the read_vector function (available as read_vector.m) to read the saved test vector output into MATLAB. Do this using the following MATLAB command:

	  >> [ch1, ch2, ch3, ch4, ch5, ch6] = read_vector('output.dat');


The MATLAB vectors ch1 through ch6 now contain the output of your program code in response to the input from the test vector.


  1. The upper bound is determined by the amount of memory available to the auto-buffering unit.
  2. The DSP is rated to run at 100 MHz; however, the serial port does not work reliably when the DSP clock speed is greater than 80 MHz.
  3. Will the expected output and the actual output from the DSP system match perfectly? Why or why not?

Content actions

Download module as:

PDF | EPUB (?)

What is an EPUB file?

EPUB is an electronic book format that can be read on a variety of mobile devices.

Downloading to a reading device

For detailed instructions on how to download this content's EPUB to your specific device, click the "(?)" link.

| More downloads ...

Add module to:

My Favorites (?)

'My Favorites' is a special kind of lens which you can use to bookmark modules and collections. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need an account to use 'My Favorites'.

| A lens I own (?)

Definition of a lens


A lens is a custom view of the content in the repository. You can think of it as a fancy kind of list that will let you see content through the eyes of organizations and people you trust.

What is in a lens?

Lens makers point to materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

Who can create a lens?

Any individual member, a community, or a respected organization.

What are tags? tag icon

Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

| External bookmarks