Generally, the ADSP 21xx series DSP chips are programmed in assembly language
for reasons of efficiency and performance. The assembly language syntax for these
chips reminds one of a high-level language, which helps a lot in developing
applications. Typically, someone with experience in wrtiting C programs will feel
at home in this environment. As for complex programs, one has to keep things organized
and orderly as you are in full control of the hardware and there are plenty of details
to keep track of.
One often encounters an involved bit of code, like for example, crunching a
floating-point formula, or perhaps needing double-precision math. For such cases, it would
be nice to have access to a bit of C code. This prompted a little research and
experimentation. It is assumed that you are familiar with the 2181 EZKIT and the tools
that comes with the EVM. Also that you have access to G21, the C-compiler for the 21xx
series. Incidentally, G21 is based on GNU GCC. The source code is available on the net,
so it is technically possible to build a version of G21 for yourself. I will not get
into how to do that, perhaps leave that for another experiment.
Note that the Analog Devices version of G21 will not run in a Windows Dos box, unless you have made
extra efforts in dealing with memory managers needed for the DOS4GW environment.
DOSBOX, a public-domain x86 emulator, however seem to work. Its a little slow, perhaps
reminding one of a 486, but it works. I have been running G21 in DOSEMU under Linux without
any problems. Even downloading code through the serial port works well under DOSEMU.
If you installed the ADI 21xx C package, make sure to update the utilities with those
supplied in the 2181 EZKIT package.
There is an application note, EE-14, that describes C example code, CTIP35, that is
a C version of the Talk-Thru example to run on the 2181 EZKIT. Take a bit of time to
study it as it contains valuable information on how to put a C program together.
Unfortunately, the code from EE-14 does not build correctly under the version 5.1 C-
tools that I have and needed modifications. Here is my version of
CTIP35.ZIP. Of course, keep a copy of the ADSP-2100 Family
C Tools and ADSP 2100 Family Assembler Tools & Simulator Manuals handy.
Reminder that when running a C environment, the system relies heavily on heap and stack
management; the integrity of this environment needs to remain intact. The C run-time
environment needs to be set up correctly and maintained all the time. Assuming we are
going to use the C environment to perform a few once-in-a-while, difficult-to-progam
tasks, definately not to be part of the main heavy-duty processing loops, keep a few
simple rules in mind:
1. The following registers may be modified but must be restored: L0, L1, L5, L6, L7,
M2, and M6.
2. The following registers are reserved and must not be used: L4 and M1.
3. As shown above, the C-environment uses I4, M4 for heap and stack management.
4. I2, L2, I3, L3, and M1 are used for CTIP35's CODEC autobuffering, so be careful.
5. Note the C run-time environment sets the MAC for integer arithmetic.
6. Watch out how a function's local variables are saved on the stack. Its not very
efficient, so avoid if possible. Perhaps use of volatile DM storage is a solution.
The C run-time environment includes an interrupt dispatcher which relies on the
DSP interrupt vectors. Note how this is done in 2181_HDR. You may also want to
look at the included assembly-language listing for CTIP35. Note how an interrupt
service routine is entered with a prologue and exited with an epilogue. For the
"new_sample" ISR:
new_sample_:
{-----------------------------------------------------------------------}
{ FUNCTION PROLOGUE: }
mr1=toppcstack; { get return address }
si=m4;
m4=i4; { new frame ptr <= old stack ptr }
m5=-1;
dm(i4,m5)=si; { save old frame pointer }
dm(i4,m5)=mr1;{ save return address }
{ END FUNCTION PROLOGUE:}
{-----------------------------------------------------------------------}
===========> user code follows here. Note comments. <====================
{-----------------------------------------------------------------------}
{ FUNCTION EPILOGUE: }
i6=m4;
m5=-1;
si=dm(i6,m5); { old frame pointer}
mr1=dm(i6,m5); { return address }
i4=m4; { reset stack pointer }
i6=mr1;
m4=si; { reset frame pointer }
{ END FUNCTION EPILOGUE: new_sample }
jump (i6);
{-----------------------------------------------------------------------}
There are library functions that helps doing all this. Also look at using
the assembly support functions (see "asm_sprt.h").
To my Home Page