TI 5402 DSK: The Things I Learned the Hard Way

Introduction

I got my 5402 DSK (Developer's Starter Kit) a month and a half ago. My general opinion about this board is that it's a nice, well-engineered board with a lot of possibilities and features. Most of which are hidden, because the documentation is catastrophal.

At first I got the impression that life's going to be easy with this thing. In the beginning it was. But soon I found that there's no manual for this board, just help pages which gives you answers to questions you were supposed to know that you should ask. I had a lot of surprises during this time, some were related to the board, and some to the DSP itself. Some were pleasant, some were less pleasant. A bunch of clear information would have spared me either.

There is a trend in hi-tec companies to publish the information which will make us enthusiastic, and keep the small and dirty details where you can hardly find them. Texas Instruments has been no exception about this. The distributed literature deals extensively with fancy features (some of which are really good!), but when you get to the details, it's hard to find good examples or good documentation. If you've already chosen the DSP and its environment, why bother the top-engineers with writing detailed manuals about the small things?

I looked for the help on the web, but there was nil. So after going through the via dolorosa of finding things myself, I wrote this page. I hope It'll spare a few others some good hours of frustration. It's long, it's tedious, it's full with details, but I'm sure you'll regret it if you won't take the 20 minutes to simply read this page top to bottom.

A word about TI's tech support. It's polite, yes, and you get your answer fairly quickly. But they won't help you with the things that really get you stuck, probably because they won't bother the few guys who really know the answers.

And before starting: This page was written in October 2000, and it reflects my own problems when using a Revision 0 board, with DSK Tools Release 11.1 (which includes Code Composer Studio version 1.1). If there are mistakes or updates, I'm available at [email protected]

Existing documentation

The documentation is the biggest problem about all this. I spent quite a lot of time in trying to find basic information. If you need to know something about the DSP itself, it's probably written somewhere, but a few very crucial facts were simply hidded and buried in tons of details (see below). But that's the easy case: Some very important details about the DSK itself are simply absent. Go and find yourself.

So, if you want to know where to start to look for things, a few tips:

What they didn't tell you about the 5402

There are two things which I discovered too late about this DSP, which might have ruined the project I worked on:

The DSK as a reference design

Let's face it: We have little interest in planning a DSP board. We would love to just copy the existing design, remove the unneeded parts, and make our own board. I'm afraid it won't be that easy this time.

The reason is, that the heart of the device is a CPLD (Programmable Logic Device), and all the tricks are there. There is no documentation about what it does exactly, so sometimes you just have to guess. But even worse: It you want to develop your own board, you're at square one concerning the interface with the bus, booting, interrupts and such. Go read the app. notes, design the logic yourself and hope for good.

And now to my small tips...

Connecting the DSK to your PC

You should have received a "Quick start Guide" with the kit, and if you haven't, it's \docs\spru368.pdf on the CD. There's a section about how to install the software there.

Let's assume that you've installed the software which came on the CD along with the DSK (That is, Code Composer Studio and Parallel port I/O drivers). If you happened to have a scanner installed on your computer, then Windows 98 might have needed reinstallation after crashing at every boot. Too many candidates on one port and a lousy so-called operating system...

If your LPT1: is addressed at 0x378, it's recommended to use it for the board. The DOS utilities assume this address, and it's quite annoying when using another port. I used an A/B switch with my printer & scanner on one side, DSK on the other, and it worked fine.

The tricky part is setting up the CC studio for working with the DSK. Well, tricky if you like to do things yourself. There's a section named "Setting up Code Composer Studio" in the Quick installation Guide. Follow the instructions there carefully, and you're done. It's a sequence I wouldn't have guessed, so if you haven't got the guide in hand, get it now.

CC's default for the parallel port is 0x240, which is somewhat strange, and should be changed to 0x378 in most cases. The Guide tell you to do that.

When all is done, run the CC. If it comes up, it did recognize your DSK and communicated successfully with it. If it didn't find the card, you got a message. If it got stuck, well, it's probably that it found the card, but there were some problems. This happened to me several times. The parallel port connection was OK, the card made the problems. The next section will help you with that.

Basic troubleshooting with the DSK

Sometimes my DSK agreed to connect with the PC, sometimes it didn't. I turned it into a black-magic theory of how the power plug is inserted: A quick and smooth insertion would generally make the DSK cooperative, I found out. But you might not need all this.

The JP2 Jumper Might Be the Reason for All Problems. That jumper determines whether the DSP should boot from the FLASH. If you don't know what's in the FLASH (which is true if you just started...), this jumper should better be in the disable boot place.

So, hold the board with the power cord to the right. The text printed in white on the board should be upright, and the JP2 jumper should be found at the upper edge of the board, slightly to the left. Three pins, and a jumper to connect between two of those. Make sure that the two righmost pins are connected with the jumper. If the jumper is put otherwise, move it. If its absent, it's exactly like if it was in the wrong way, so steal a jumper from somewhere, and put it in place. It will solve a few problems.

Now, let's see if your DSK is alive. Open a DOS window, change directory to C:\ti\c5400\dsk\utilities, and type "evmdsktest 2" if your DSK is on parallel port at I/O 0x378. This is equivalent to typing "evmdsktest 2 -p 888" (0x378=888). Note that the port number is given in decimal. If you need to use another port, convert the port address' hex number to decimal, and use instead of 888. This is what I get when the cable isn't connected, there's no power to the DSK, or when it's severely locked up:

C:\ti\c5400\dsk\utilities>evmdsktest 2 -p 888
PCI2040 C54x EVM/DSK Confidence Test, Version 1.00
Board Index                        : 0

**Error: Cannot connect to device on port 0x378.
ERROR: evmdsk54x_open() failed for board 888, exiting.
and exits. This corresponds to Code Composer saying it can't connect to the board. Retry once. If it still doesn't work, I would suggest checking cables, the port address, port driver and the green LED on the DSK which should be on, saying the board has +5V.

This is the easy case. A different case is when you get:

C:\ti\c5400\dsk\utilities>evmdsktest 2 -p 888
PCI2040 C54x EVM/DSK Confidence Test, Version 1.00
Board Index                        : 0
and the utility is stuck there. Had you tried to run Code Composer, it would probably be stuck now. If this happens, try to power the board on and off, and go again. Is the JP2 jumper set correct?

Now, there's always the case that everything works fine. Then you should get:

C:\ti\c5400\dsk\utilities>evmdsktest 2 -p 888
PCI2040 C54x EVM/DSK Confidence Test, Version 1.00
Board Index                        : 0
Board Type                         : C5402 DSK, Rev 0


Beginning Confidence Test
Press any key to continue (Ctrl-C to abort).
after pressing a key, you get:
Testing Win32 DLL and Low-Level Driver access...........PASSED.

******CPLD Dump

============================================
=          CPLD Register Values            =
============================================
CNTL          : 0x00
STAT1         : 0x00
STAT2         : 0x08
CPLDREV       : 0x00   (0)
SEM0          : 0x00   (Not Owned)
SEM1          : 0x00   (Not Owned)

============================================
=               Board State                =
============================================
DSP Interrupt Mask: NO
DSP NMI           : NO
DSP Reset         : NO
HINT Mask         : NO
User Switch 0     : OFF    User Switch 1     : OFF
Data Memory Select: Off Board
DSP Operating Mode: Controller
DSP Core Voltage  : OK
Daughterboard     : Not Installed
DSP-Host Interrupt: NOT ACTIVE
DSP HREADY        : READY
Semaphore 0       : NO     Semaphore 1       : NO
============================================

***** EVM LED Confidence Tests.
DSP 0: Observe the user LED on the bracket blinking......
at which point the LEDs should start blinking. If they do you may press Ctrl-C to quit the test. At this point, the Code Composer always worked for me. If it doesn't, there's probably a problem with the CC's settings.

Make sure that the LEDs actually blink. If they don't, power the board down and up, and try again. And as usual, pay attention to jumper JP2.

Tips for C programming

How's your memory?

Here are a few tips about how to get things straight with the memory issue. If you want to try if out, be sure you understand the wait-state issue (some info below). Especially note, that if you're running on 100 MHz, writing to ports might be useless unless you've set the wait-states correctly.

Organizing memory and running much faster

This is not an election promise, it actually happened to me. If you're a C programmer, you probably prefer not to get your hands dirty with allocating the memory. You'd prefer to take a template, and if it works, what the heck. But if you're writing a DSP application, you want speed, and if you want speed, you better understand how the memory works on the 5402, and how to allocate it. The details appear in [1], chapter 3 and in section 7.3, but I'm not sure you'll enjoy reading it.
So here are the general guidelines, to make you going.

CPU frequency and wait states

If you just unpacked your DSK board, you'll probably find it with DIP-switches 5 and 6 up, which is the recommended default. In this position, your DSK clocks 40 MHz. In order to run it on 100 MHz, you should have DIPs 4 and 6 up, the rest down.

There is a reason why the board is shipped with 40 MHz clock. At 100 MHz, the SRAM memory and the I/O ports are too slow to catch up with the speed. Don't get tricked by the fact that the SRAM is 10ns, which means it can be accessed at 100 MHz. It takes some additional time for the glue logic to react, and we missed the train already.

The solution is to add wait-states, so that the CPU freezes every time it accesses external memory (on-chip memory accesses remain fast) for a number of cycles, thus giving it time to react. See [1], Sect. 10.3., or the help files.

So if you speed up to 100 MHz, I suggest writing 0x1249 to memory address 0x28 (SWWSR, Software Wait State Register). This will put one wait-state in program, data and I/O spaces. Note that the CPLD I/O registers will not react if you try to access them in 100 MHz mode without setting the wait-states.

If you want to test the CPLD I/O registers, try writing 0x0007 to port 0 (which is CPLD's CNTL1, I/O space, adress 0x0000). This should turn all three LEDs on. Writing zero (0x0000) will turn them all off.

If you want to access the FLASH, you'll need 7 wait states for that memory section. Writing 0x1e49 to 0x28 will do the job.

The Expansion Memory Interface - a small surprise

If you thought about this interface as being just a way to connect to the DSP's address and data bus, then there's a small surprise for you. The expansion memory interface is connected via some buffers to the CPLD, which is in turn connected to the DSP's bus.

If you wondered what the connector is, well, it's a Samtec SFM-140-L2-S-D-L-C. It you want to connect to it, you should get yourself a TFM-140-02-S-D-LC. The "02" in the middle can be changed with "12", "22" or "32" as well. Note that it's supposed to be surface mount soldered to a board (it's exactly like the one you see on the DSK, just male), so if you want to make a cable, prepare to solder pins being 0.05" (1.27 mm) away from each other. If someone knows about something more convenient, please tell me!

Now, just a brief description of the interface: There are 32 data lines (the DSP's data width is 16 bits), and 20 address lines. Additionaly, there are a few regular control lines.

Let's start with the 32 lines. Where did the additional 16 lines come from? Well, the answer is simple: The CPLD allows a 32-bit mode, in which the longer word is written by the DSP in two 16-bit words to subsequent addresses. All is descibed in the help files.

Next we look at the address space. It works like this: A0-A14 are taken from the DSP's address bus, that's simple. But A16-A19 have nothing to do with the DSP's address bus. These bits are simply set by writing to the lower 5 bits of I/O port 2 (which is the CPLD's DMCTRL, Daughterboard Memory Control, see help files). If you don't intend to use more than 32 kW of external memory space, then you have five output lines to put high or low easily from the DSP.

But the most surprising thing about this bus is that the data lines are latched on the last written value. So in fact, if we give up having external daughterboard memory (without loosing the SRAM), we have 32 output lines which are latched on the last written value. If we connect these lines to a D/A's input lines, we can easily produce waveforms in the output.

In order to access the expansion memory interface, we need to enable it (and thus disable the SRAM or FLASH, whichever was on). This is done by setting bit 7 of port 2 (the same DMCTRL mentioned above).

Just to demonstrate this, here's a code snipped which produces a sawtooth wave if you connect a D/A to either D[15:0] or D[31:16].

But before it, a remark: If possible, use a serial interface to your D/A and A/D. It's much more natural on this DSP. There's an D/A and A/D on board with serial interface to try out. For the case of 5 MHz rate and 14 bits, I had no choice. And now back to the code:

void sawtooth()
{
  volatile ioport int port2;	// This already means I/O address 0x0002

  volatile int *IMR=(int *) 0x00;
  volatile int *IFR=(int *) 0x01;
  volatile int *PRD0=(int *) 0x25;
  volatile int *TCR0=(int *) 0x26;

  volatile int *lower=(int *) 0xc000; 
  volatile int *upper=(int *) 0xc001; // Dummy variables in off-board space

  unsigned int i;

  asm("  ssbx intm"); // Disable all interrupts

  *PRD0=19;            // Divide by 20: 5 MHz strobe & interrupt rate
  *TCR0=0x0420;        // Kick off timer, no predivide.

  *IMR=0x08;       // Timer 0 interrupt unmasked for C5402

  port2=0xc0;      // Data memory OFFboard, 32 bit, even addressing
  
  *IFR=*IFR;       // Clear all interrupts

  i=0;

  while (1) {
    asm("  idle 1"); // Wait for interrupt
    *IFR=*IFR;       // Clear all interrupts. It's after the IDLE, so if
                     // the process is too slow, we might catch up...
    *upper=i; 
    *lower=i++;      
  }
}
Just a brief explanation: The timing is done by using the "idle 1" inline assembler instruction, which causes the DSP to wait for any unmasked interrupt. Since only Timer 0 is unmasked, and there are no NMI's, this makes the timing. The "ssbx intm" disables interrupt execution, so the DSP doesn't attempt to run an interrupt routine. This is why the interrupt needs to cleared (*IFR=*IFR), so the next "idle 1" will actually produce a wait.

The data is written to address 0xc001 first, and then 0xc000, as required in for an even-address 32-bit word. Any other pair of odd and even addresses over 0x8000 would do.

Now, even though this seemingly gives a nice solution, many D/A have a clock input, which controls the latching of the data lines. A latching strobe can be taken from the X_TOUT line in the Peripheral Interface, pin 45. Using the code above, this line will be high for 10ns exactly as the CPU goes out of the "idle 1" state, (when Timer 0 gives an interrupt), so it's also the best time to latch the data lines.

Booting from FLASH

This is a very neat feature: Rather than loading your program to the DSK every time, you can boot it up directly from the FLASH memory. Even though it's a very neat feature, the information about how to do this is written in very small letters, and spread out all over.

Let's start with explaining, in general lines, how the boot is done. The details can be read in [10].

When you power-up or press the reset button, the DSP goes through a few stages of deciding where to boot from, if at all. Meanwhile, the CPLD switches all external memory to the FLASH, and tells the DSP to read from address 0x8000, where the beginning of the FLASH resides. The DSP recognizes the boot table's header on the FLASH, (0x10aa for 16-bit boot table, see [10] fig. 7). It sets up a couple of registers (including wait-states) and learns where to start the code from the boot table. After which it starts to copy chunks of memory into RAM.

Two things to note: Even though the boot loader was designed to allow copying into external RAM, it's not possible on the DSK, since the switching between SRAM and FLASH is done via an I/O port, so you can only load to on-chip RAM on the DSK. Second, note that you can boot several blocks of data, so don't worry about having several sections in the linker.

After completing the copying, the bootloader jumps to the address which was given in the boot table. Note that at this stage, the SRAM hasn't been activated (more about this later).

So now we're getting at what you should do to get your code booted. The first thing, is to convince yourself that it's possible. You might lose faith on the way...

Following the help page named "FLASH Utility" (search keyword "flashu"): Change directory to C:\ti\c5400\dsk\utilities. Make sure that your DSK is alive and connected, put the JP2 on to disable boot from FLASH, if it isn't there already, press the reset button, and type:

flashu 2 -l blink02.hex
The help file says that it takes 25 seconds to erase the FLASH, but in my case the utility didn't wait a second, but announced right away that it begins programming. If it stopped at the erase stage, it was only because the DSP was stopped, like after exiting Code Composer without resetting.

When the utility exits, it's the big moment: Pull out JP2, no need to put it in another place, and press reset. LEDs going on and off? If so, you now know it's possible. If not, I can only recommend reading the instructions again, trying again, with a few power on and offs here and there. This should be easy.

It's now time to examine the blink02.hex file a bit. It won't hurt to know a few essentials. The format of the hex file is described in [8] clause 10.11, as Motorola Exorciser Object Format. The boot table's format is explained in [10] clause 2.2.3. So here's how the blink02.hex begins:

S00600004844521B
S123800010AA7FFF8806000005000EE900000500771817006BF8001803FF68F80018FFFEFD
S1238010F7B8F7BEF6B9F4A0F6B7F6B5F6B6F02013E9F1000001F84D052AF2730524F6B8F3
...

Now, let's go through the things you'll need to keep a track on. The remarks for every item apply to what you should expect after making your own hex file.

The first line is a hex-file header, nothing interesting here. Let's concentrate on the second line:

So finally we've reached the stage of preparing a bootable file. Here's the cookbook: I promised to say something about the stack being allocated over 0x4000. This will cause the following problem: When the boot loader finishes, it will jump to your program. Well, not exactly. It will run some initialization routines (at _c_int00), which were linked to your C code, whose job is to set up the environment. Then you hope for a jump to _main.

The first thing the initializion routine does, is to set the stack pointer to where you allocated it. Smart move. Very soon after it calls a subroutine, which is the first use of the stack. But noone bothered to switch us to SRAM instead of FLASH yet, so if your stack is outside the on-chip RAM, it's pointing to FLASH memory. Not good.

My solution was to add a patch to the initialization routine, which does two things: First it sets the wait states, so we're sure that the CPLD's I/O registers will react. Then a zero is sent to port 0, 2 and 4, which puts us on SRAM. And if we're at it, I also set the interrupt vector pointer. Won't hurt.

I also altered the RESET branch, so it would run to my routine first. I did the patch in the vectors.asm file. Here's a listing. My vector.asm begins like this, I've omitted the end.

	.sect ".text"
organize
        STM       #40,AR1
        ST        #1249h,*AR1   ; Set SWWSR - wait states
	STM       #29,AR1      
        LD        #65408,B             
        AND       #_thisRESET,B,B      
        LD        #127,A              
        AND       *AR1,A                
        OR        A,B                  
        STL       B,*AR1       ; Set interrupt vector correctly       
        LD        #0,A         ; Now we write zero to the ports... 
	STM       #8,AR1       ; Memory-mapped AL
        PORTW     *AR1,00H     ; Clear CTRL1
        PORTW     *AR1,02H     ; On-board memory
        PORTW     *AR1,04H     ; Take SRAM, not FLASH

        BD _c_int00                             ; branch to C entry point

        STM #200,SP                             ; stack size of 200 (for very little time)

        .sect ".vectors"

        .ref _c_int00           ; C entry point

        .align  0x80            ; must be aligned on page boundary
	.global _thisRESET

_thisRESET
RESET:                          ; reset vector
        BD organize                             ; branch to my patch instead of _c_int00
        STM #200,SP                             ; stack size of 200
nmi:    RETE                    ; enable interrupts and return from one
                NOP
                NOP
                NOP                     

I hope this will be much easier for you than it was for me!

References:

[1] TMS320C54x DSP Reference Set, Volume 1: CPU and peripherals - SPRU131F
[2] TMS320C54x DSP Reference Set, Volume 2: Mnemonic Instruction Set - SPRU172B
[3] TMS320C54x DSP Reference Set, Volume 3: Algebric Instruction Set - SPRU179B
[4] TMS320C54x DSP Reference Set, Volume 4: Applications Guide - SPRU173
[5] TMS320C54x DSP Reference Set, Volume 5: Enhanced Peripherals - SPRU302
[6] Code Composer Studio User's Guide - SPRU328B
[7] Code Composer Studio: Tutorial - SPRU327A
[8] TMS320C54x Assembly Language Tools User's Guide - SPRU102C
[9] TMS320C54x Optimizing C Compiler User's Guide - SPRU103D
[10] TMS320VC5402 and TMS320UC5402 Bootloader - SPRA618
[11] The TMS320VC5402 Datasheet - SPRS079E
[12] Interfacing the TMS320C5402 DSP to the TLV2541 ADC and the TLV5636 DAC - SLAA098

Hosted by www.Geocities.ws

1