Programming the DSP
This article outlines the programming and usage of the DSP in the tablets.
Contents |
[edit] General sources of information
TI's docs for DSPs. Do a search down the page for things with c55 in the description to get the documents that are of interest. Some direct pointers are listed at the end of this page.
DSP Gateway project. This is used by the Nokia 770, N800 and N810 to interface the ARM processor with the DSP.
[edit] Setup the toolchain
Get the toolchain from TI's Linux DSP Tools page (you need a free registration to access the page). Select "Linux DSP Tools v1.00" and download it to /tmp
and unpack it:
chmod a+rx /tmp/linuxdsptools_v1_00_00_06.bin /tmp/linuxdsptools_v1_00_00_06.bin
Select the installation directory under /tmp
. Once unpacked, you need to actually install it. Make sure you have expect
(sudo aptitude install expect
) and Java installed. Don't try to install the DSP tools under Scratchbox, as this does not work (i.e. this is an x86 based cross-toolchain for the DSP).
Install it under /usr/local/ti_dsptools
(use sudo
or make otherwise sure you can make
the directory):
cd /tmp/Linux-DSP-Tools-1.00.00.06 ./subpkg_install_linuxdsptools.exp /usr/local/ti_dsptools
Copy the avs_kernel.out
from your device (in /lib/dsp/
these days) to /usr/local/ti_dsptools/dspgw
.
Now you should be able to compile (try something like Speex port to DSP GW).
Check this thread for longer instructions.
Or email/IRC lardman/Simon Pickering (s dot g dot pickering at bath dot ac dot uk).
[edit] Compiling a program
Get the DSP Gateway source packages from the download page. Download both the ARM-side package (dspgw-3.3-arm.tar.bz2
) and the DSP-side package (dspgw-3.3-dsp.tar.bz2
). You need version 3.3(.0) not version 3.3.1!
There is no need to go patching and rebuilding the 770 kernel or fiddling with the DSP kernel as these are both setup to use the DSP Gateway already.
Unpack the tarballs. Go to 'dspgw-3.3-arm/host_src/mod_utils
and build the coff_unresolve
and gen_dummy_kernel
tools using your PC native toolchain (the one you use to build anything else not ARM-related). Simple make
should be sufficient.
gen_dummy_kernel
is used to generate a dummy kernel based on the DSP kernel on your tablet (called avs_kernel.out
) against which you will link any modules you create so that they will run on the device. This should allow any unresolved symbols and function call addresses to be resolved in a static manner, but without needing to link statically (as you then remove the dummy kernel in the step below). coff_unresolve
is then run on the modules you will have just linked against the dummy kernel to remove the sections linked in from the dummy kernel.
Either copy these tools to your path or adjust dspgw-3.3-dsp/src/apps/demo_mod/Makefile
to use the tools from the directory where they are (e.g., create a folder for these utilities and place these files there, and use absolute path in Makefile like /usr/local/ti_dsptools/gateway/gen_dummy_kernel
and /usr/local/ti_dsptools/gateway/coff_unresolve
). The other alternative to having explicit paths in all of your makefiles is to have a bash script that you source before doing DSP development to set relevant paths (add an example here).
To build the demo console (as an example):
Build the ARM side of the demo console in dspgw-3.3-arm/apps/demo<c/ode> with <code>make demo_console
.
You can either do this inside scratchbox or adjust CC in the Makefile to point to your arm cross compiler (e.g., /scratchbox/compilers/arm-gcc-3.3.4-glibc-2.3.2/bin/arm-linux-gcc
).
Get the avs_kernel.out
from your tablet and place this in the DSP-side build directory (i.e., the directory containing the code to run on the DSP in dspgw-3.3-dsp/src/apps/demo_mod/
). The avs_kernel.out
file is in the /lib/dsp/
directory.
Adjust the Makefile (e.g., dspgw-3.3-dsp/src/apps/demo_mod/Makefile
) to use the avs_kernel.out
file to generate the dummy_kernel.obj
rather than the default tinkernel.out
(tinkernel is the name used in all of the documentation for the DSP kernel, it just happens that Nokia decided to name their kernel file differently. You don't need to mess about with the tinkernel source found with the toolchain, all you need is the actual binary avs_kernel.out
from your tablet).
Run:
make omap1
The code is compiled into an object file (*.obj
), the dummy kernel is created from your avs_kernel.out
file by the gen_dummy_kernel
utility you compiled earlier, the object file is linked against the dummy kernel and then the dummy kernel is stripped away from the resulting object file by the coff_unresolve
utility you created earlier. You are left with a file named *.o
.
[edit] Install the demo
After compiling your code, you'll need to place the DSP-side object file (*.o
) and linker command file (*.cmd
) in /lib/dsp/modules/
, you'll also need to make an entry in the /lib/dsp/dsp_dld_avs.conf
file to let the DSP know this module exists.
# echo "demo_console _task_demo_console 1 /lib/dsp/modules/demo_console.o" >> /lib/dsp/dsp_dld_avs.conf
You'll then want to run dsp_dld
to restart the DSP and reload the module list. This might complain that it can't find the conf file:
Nokia-N800-10:~# dsp_dld sending SIGBUS signal to all task users... killing pid 832. killing pid 827. killing pid 1582. Can't open /lib/dsp/dsp_dld.conf
If so, you need to create a symlink from the actual file dsp_dld_avs.conf
, to the one it expects dsp_dld.conf
(both in the /lib/dsp/
directory). Then try again and you'll see something like this:
Nokia-N800-10:~# dsp_dld sending SIGBUS signal to all task users... killing pid 4234. killing pid 4236. killing pid 4235. mapping external memory: adr = 0x028000, size = 0x1000 mapping external memory: adr = 0x100000, size = 0x200000 mapping external memory: adr = 0x400000, size = 0x180000 detected binary version 3.3.0.0 setting DSP reset vector to 0x10389e releasing DSP reset DSP configuration ... succeeded.
Then copy the ARM-side binary somewhere on the tablet (anywhere, but not on any FAT partitions on the flash cards, as these have no-execute enabled) and run it.
Nokia-N800-10:~# ./demo_console Congratulations! DSP is working!
If you see a message like this:
Nokia-N800-10:~# ./demo_console open: No such file or directory
It means you've either not added the module to the /lib/dsp/dsp_dld_avs.conf
file (correctly), or you've not run dsp_dld to refresh the DSP. In either case the /dev/dsptask/
device hasn't been created as the module couldn't be loaded, hence the open
error.
If you see a message like this:
~ $ ./demo_console open: Interrupted system call
Then something is wrong with the code on the DSP side. Make sure that you added the exact line shown above to /lib/dsp/dsp_dld_avs.conf
.
[edit] Compiling other demos
If you decide to copy any code from the DSP Gateway PDF files, bear the following in mind (and also consider that the tarballs contain almost identical code so you might as well use them!):
Any \ characters appears as a ¥ in the PDFs and the ' sometimes comes out as a different character (smart quote) so make sure you check your code if you start getting weird errors (the last one had me scratching my head for a while as they look pretty much the same in my editor).
You'll also need to remove references to the include file. I don't have this, the tarball demos don't have this line either (and are otherwise identical to the PDFs).
[edit] Steps forward
Although video out seems to have been dropped by Nokia with the N800 (and the DSP has become more stable, not sure if not using the framebuffer is the reason, or simply more mature hardware), anyway audio decoding and output is still performed on the DSP, and this is a suitable task for people to get stuck into. Framebuffer access works for the N8x0 and 770. Contact me (lardman) or read the maemo-developers list for more info. I should update this page when I have some time.
A pair of drivers are required to access the audio codec (a low-level mini-driver and a standard high-level class driver). These are obviously already present on the device, but no documentation is available about how to use them directly. In fact it can be seen from the functions called by existing modules (such as pcm2.o
) that it's a stream class driver. Therefore it may be possible to access this class driver directly (there are plenty of examples in the DDK, see below).
It appears that this stream class driver is wrapped in some other function calls (i.e., the following functions are called by pcm2.o
):
_EAP_CC_Mute _EAP_CC_RemoveStream _EAP_CC_RequestStream _EAP_CC_SetPanning _EAP_CC_SetVolume _EAP_CC_UnMute _EAP_clock _EAP_getTicks
These _EAP_*
functions are built into the avs_kernel.out
DSP kernel. It would be useful to have a header file for these functions, and if possible some example code and/or instructions illustrating their use.
Some useful info about writing DSP device drivers and using SIO_* functions can be found here.
Another option is to write a completely new mini-driver + class driver + wrapper implementation. This initially looks like a reasonable task. One requires the DSP/BIOS Driver Developer Kit 1.20 for examples and information about writing drivers, the Chip Support Library with which the DDK interfaces, and information about the hardware codec itself.
On the 770, the codec is called aic23
(see dmesg
output). On the N800 the codec is called TSC2301
(part of the touch screen chip) (again see your dmesg
output—see this thread.
[ 312.232727] #0: OMAP24xx EAC with codec TSC2301
Data about both of these codecs is available on the Texas Instruments website. See the page for TSC2301. It includes a data sheet with the info needed to write the mini-driver.
Unfortunately I'm not sure that it's possible to add in a new mini-driver without re-compiling the DSP kernel (see chapter 3 of spru616a.pdf contained in the DDK - link above). It might be possible to create a dsptask containing the driver, but again, I'm not sure about this.
For those who want more information about disassembly, take a look at these documents:
spru374g | DSP assembly code memonics |
spru281f | c/c++ calling conventions (ch6 Run-time environment) |
spru371f | cpu/register info (ch2 CPU registers, etc.) |
spru280h.pdf | TMS320C55x Assmbly Language Tools User's Guide (ch2 Introduction to |
Common Object File Format | c12 disassembler |
[edit] Tips, tricks and troubleshooting
Check that you're linking against the current avs_kernel
(well the dummy kernel generated from this). If not, it won't load.
Check that you've correctly defined the flags for the task. This is especially easy to miss as the flag names are rather similar (and cryptic). A list can be found in the DSP gateway spec PDF file. Look for the TCFG section.
dbg()
function: This function allows one to output messages (like printf
) to dmesg
from the DSP-side. Before OS2008 you needed to recompile the kernel to enable DSP debugging messages; in OS2008 this is already enabled. You use it like so:
dbg('this is a message, this is a value=%d', some_value);
Note that the variable some_value
must be a short or smaller (16bit or less). If you pass it a 32bit number, as often as not it returns zero (probably due to the strange endianness of the 32bit data type that means the first 16bits are the high bytes). Therefore split your 32bit data into 16bit chunks (or cast if you are sure about the limited range) if you want to see them.
[edit] Location of data
I had some troubles trying to access an array of data defined as a global const int array. The problem was that every element of the array returned 0 rather than the value which was set in it. After messing about for a while it occurred to me that the problem is to do with the location in memory of global const data. Changing the definition from a global const int array to a simple global int array solved the problem and the data could be accessed.
I didn't investigate this further, but in the avs_kernelcfg.cmd
file you can see the locations of the various parts of memory and it may be that to obtain the actual data (rather than a zero) one needs to either use a far function (see the C/C++ manual for the DSP) or make sure the data is in the right section of memory.
[edit] Documentation pointers
[edit] Compiler optimization
TMS320C55x Optimizing C/C++ Compiler User's Guide
- p79: 3.2 Performing File-Level Optimization (-O3 Option)
- p80: 3.3 Performing Program-Level Optimization (-pm and -O3 Options)
[edit] ASM with C/C++
TMS320C55x Optimizing C/C++ Compiler User's Guide
- p83: 3.3.2 Optimization Considerations When Mixing C and Assembly
- p176: 6.5 Interfacing C/C++ With Assembly Language
- p178: Example 6-3. Calling an Assembly Language Function From C
- p181: 6.5.3 Using Inline Assembly Language
TMS320C55x DSP Programmer's Guide
- p76: Table 3-6. TMS320C55x C Compiler Intrinsics
[edit] Misc
TMS320C55x Optimizing C/C++ Compiler User's Guide
- p122: 5.3 Data Types
- This page was last modified on 15 April 2010, at 11:33.
- This page has been accessed 31,137 times.