Programming the DSP

(New page: {{Midgard article}} == General sources of information == [http://www.ti.com/sc/docs/psheets/man_dsp.htm TI's docs for DSPs]. Do a search down the page for things with c55 in the descrip...)
m (Steps forward: link)
 
(7 intermediate revisions not shown)
Line 1: Line 1:
-
{{Midgard article}}
+
This article outlines the programming and usage of the DSP in the tablets.
== General sources of information ==
== General sources of information ==
 +
[http://www.ti.com/sc/docs/psheets/man_dsp.htm 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.
-
[http://www.ti.com/sc/docs/psheets/man_dsp.htm TI's docs for DSPs]. Do a search down the page for things with c55 in the description to get the the documents that are of interest. Some direct pointers are listed at the end of this page.
+
[http://dspgateway.sourceforge.net DSP Gateway project]. This is used by the [[Nokia 770]], [[Nokia N800|N800]] and [[Nokia N810|N810]] to interface the ARM processor with the DSP.
-
 
+
-
 
+
-
[http://dspgateway.sourceforge.net DSP Gateway project].
+
-
This is used by the Nokia 770 and N800 to interface the ARM processor with the DSP.
+
-
 
+
== Setup the toolchain ==
== Setup the toolchain ==
-
Get the toolchain from [https://www-a.ti.com/downloads/sds_support/targetcontent/LinuxDspTools/index.html 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''.
+
Get the toolchain from [https://www-a.ti.com/downloads/sds_support/targetcontent/LinuxDspTools/index.html 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 <code>/tmp</code> and unpack it:
-
Unpack it:
 
<pre>
<pre>
chmod a+rx /tmp/linuxdsptools_v1_00_00_06.bin
chmod a+rx /tmp/linuxdsptools_v1_00_00_06.bin
Line 21: Line 16:
</pre>
</pre>
-
Select the installation directory under ''/tmp''. Once unpacked, you need to actually install it. Make sure you have expect installed (''sudo aptitude install expect''). You also need java.  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).
+
Select the installation directory under <code>/tmp</code>. Once unpacked, you need to actually install it. Make sure you have <code>expect</code> (<code>sudo aptitude install expect</code>) 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):  
+
Install it under <code>/usr/local/ti_dsptools</code> (use <code>sudo</code> or make otherwise sure you can <code>make</code> the directory):  
<pre>
<pre>
Line 30: Line 25:
</pre>
</pre>
-
Copy the ''avs_kernel.out'' from your device (in /lib/dsp/ these days) to ''/usr/local/ti_dsptools/dspgw''.
+
Copy the <code>avs_kernel.out</code> from your device (in <code>/lib/dsp/</code> these days) to <code>/usr/local/ti_dsptools/dspgw</code>.
-
Now you should be able to compile e.g. [http://tuomas.kulve.fi/blog/2007/08/31/speex-encoder-on-n800s-dsp/ Speex port to DSP GW].
+
Now you should be able to compile (try something like [http://tuomas.kulve.fi/blog/2007/08/31/speex-encoder-on-n800s-dsp/ Speex port to DSP GW]).
-
Check [http://www.gossamer-threads.com/lists/maemo/developers/3938 this thread at gossamer-threads.com] for longer instructions.
+
Check [http://www.gossamer-threads.com/lists/maemo/developers/3938 this thread] for longer instructions.
-
Or email/chat on IRC to lardman/Simon Pickering (s dot g dot pickering at bath dot ac dot uk).
+
Or email/IRC lardman/Simon Pickering (s dot g dot pickering at bath dot ac dot uk).
== Compiling a program ==
== Compiling a program ==
-
Get the DSP Gateway source packages from the [http://dspgateway.sourceforge.net/pub/index.php?Page=Download download page]
+
Get the DSP Gateway source packages from the [http://dspgateway.sourceforge.net/pub/index.php?Page=Download download page]. Download both the ARM-side package (<code>dspgw-3.3-arm.tar.bz2</code>) and the DSP-side package (<code>dspgw-3.3-dsp.tar.bz2</code>). You need version 3.3(.0) not version 3.3.1!
-
 
+
-
Download both the ARM side package (dspgw-3.3.1-arm.tar.bz2) and the DSP side package (dspgw-3.3.1-dsp.tar.bz2).
+
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.
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.1-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 non-arm related). Simple make should be sufficient.
 
-
gen_dummy_kernel is used to generate a dummy kernel based on the DSP kernel on your N800/770 (called avs_kernel.out) against which you will link any modules you create so that they will run on the device. AFAIU, this allows 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.
 
 +
Unpack the tarballs. Go to <code>'dspgw-3.3-arm/host_src/mod_utils</code> and build the <code>coff_unresolve</code> and <code>gen_dummy_kernel</code> tools using your PC native toolchain (the one you use to build anything else not ARM-related). Simple <code>make</code> should be sufficient.
 +
 +
<code>gen_dummy_kernel</code> is used to generate a dummy kernel based on the DSP kernel on your tablet (called <code>avs_kernel.out</code>) 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). <code>coff_unresolve</code> 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.1-dsp/src/apps/demo_mod/Makefile'' to use the tools from the directory where they are. (eg Create a folder for these utilities and place these files there, and use absolute path in Makefile such as this /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).
+
Either copy these tools to your path or adjust <code>dspgw-3.3-dsp/src/apps/demo_mod/Makefile</code> 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 <code>/usr/local/ti_dsptools/gateway/gen_dummy_kernel</code> and <code>/usr/local/ti_dsptools/gateway/coff_unresolve</code>). 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):
To build the demo console (as an example):
-
Build the ARM side of the demo console in ''dspgw-3.3.1-arm/apps/demo'' with ''make demo_console''.
+
Build the ARM side of the demo console in <code>dspgw-3.3-arm/apps/demo<c/ode> with <code>make demo_console</code>.
-
You can either do this inside scratchbox or adjust CC in the Makefile to point to your arm cross compiler, e.g.
+
You can either do this inside scratchbox or adjust CC in the Makefile to point to your arm cross compiler (e.g., <code>/scratchbox/compilers/arm-gcc-3.3.4-glibc-2.3.2/bin/arm-linux-gcc</code>).
-
''/scratchbox/compilers/arm-gcc-3.3.4-glibc-2.3.2/bin/arm-linux-gcc''.
+
-
Get the avs_kernel.out from your N800/770 and place this in the DSP-side build directory (i.e. the directory containing the code to run on the DSP in e.g. ''dspgw-3.3.1-dsp/src/apps/demo_mod/''). The avs_kernel.out file is in the ''/lib/dsp/'' directory.  
+
Get the <code>avs_kernel.out</code> 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 <code>dspgw-3.3-dsp/src/apps/demo_mod/</code>). The <code>avs_kernel.out</code> file is in the <code>/lib/dsp/</code> directory.  
-
Adjust the Makefile (e.g. ''dspgw-3.3.1-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 N800/770).  
+
Adjust the Makefile (e.g., <code>dspgw-3.3-dsp/src/apps/demo_mod/Makefile</code>) to use the <code>avs_kernel.out</code> file to generate the <code>dummy_kernel.obj</code> rather than the default <code>tinkernel.out</code> (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 <code>avs_kernel.out</code> from your tablet).  
-
Run ''make omap1''.
+
Run:
-
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
+
make omap1
 +
The code is compiled into an object file (<code>*.obj</code>), the dummy kernel is created from your <code>avs_kernel.out</code> file by the <code>gen_dummy_kernel</code> 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 <code>coff_unresolve</code> utility you created earlier. You are left with a file named <code>*.o</code>.
=== Install the demo ===
=== 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.
+
After compiling your code, you'll need to place the DSP-side object file (<code>*.o</code>) and linker command file (<code>*.cmd</code>) in <code>/lib/dsp/modules/</code>, you'll also need to make an entry in the <code>/lib/dsp/dsp_dld_avs.conf</code> file to let the DSP know this module exists.
-
e.g.:
 
<pre>
<pre>
-
# echo &quot;demo_console _task_demo_console 1 /lib/dsp/modules/demo_console.o&quot; &gt;&gt; /lib/dsp/dsp_dld_avs.conf
+
# echo "demo_console _task_demo_console 1 /lib/dsp/modules/demo_console.o" >> /lib/dsp/dsp_dld_avs.conf
</pre>
</pre>
-
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:
+
You'll then want to run <code>dsp_dld</code> to restart the DSP and reload the module list. This might complain that it can't find the conf file:
<pre>
<pre>
Line 87: Line 80:
</pre>
</pre>
-
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:
+
If so, you need to create a symlink from the actual file <code>dsp_dld_avs.conf</code>, to the one it expects <code>dsp_dld.conf</code> (both in the <code>/lib/dsp/</code> directory). Then try again and you'll see something like this:
<pre>
<pre>
Line 105: Line 98:
</pre>
</pre>
-
Then copy the ARM-side binary somewhere on the N800/770 (anywhere, but not on the MMC/SD cards as these have no-execute enabled) and run it. E.g.:
+
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.
<pre>
<pre>
Line 119: Line 112:
</pre>
</pre>
-
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.
+
It means you've either not added the module to the <code>/lib/dsp/dsp_dld_avs.conf</code> file (correctly), or you've not run dsp_dld to refresh the DSP. In either case the <code>/dev/dsptask/</code> device hasn't been created as the module couldn't be loaded, hence the <code>open</code> error.
If you see a message like this:
If you see a message like this:
Line 128: Line 121:
</pre>
</pre>
-
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''.
+
Then something is wrong with the code on the DSP side.  Make sure that you added the exact line shown above to <code>/lib/dsp/dsp_dld_avs.conf</code>.
=== Compiling other demos ===
=== 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!):
+
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).
+
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).
+
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).
== Steps forward ==
== 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.
+
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 ([[User:lardman|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).  
+
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 <code>pcm2.o</code>) 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.
+
It appears that this stream class driver is wrapped in some other function calls (i.e., the following functions are called by <code>pcm2.o</code>):
-
 
+
-
I.e. the following functions are called by pcm2.o:
+
<pre>
<pre>
Line 159: Line 150:
</pre>
</pre>
-
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.
+
These <code>_EAP_*</code> functions are built into the <code>avs_kernel.out</code> 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.
-
 
+
<br>Some useful info about writing DSP device drivers and using SIO_* functions can be found [http://www.design-reuse.com/articles/6849/how-to-write-dsp-device-drivers.html here].
-
Another other option is to write a completely new mini-driver + class driver + wrapper implementation. This initially looks like a reasonable task. One requires the [https://www-a.ti.com/downloads/sds_support/targetcontent/ddk/DDK_1_20/index.html DSP/BIOS Driver Developer Kit 1.20] for examples and information about writing drivers, the [Chip Support Library](http://focus.ti.com/docs/toolsw/folders/print/sprc133.html) with which the DDK interfaces, and information about the hardware codec itself.
+
Another option is to write a completely new mini-driver + class driver + wrapper implementation. This initially looks like a reasonable task. One requires the [https://www-a.ti.com/downloads/sds_support/targetcontent/ddk/DDK_1_20/index.html DSP/BIOS Driver Developer Kit 1.20] for examples and information about writing drivers, the [http://focus.ti.com/docs/toolsw/folders/print/sprc133.html Chip Support Library] with which the DDK interfaces, and information about the hardware codec itself.
-
On 770, the codec is called aic23 (see dmesg output). On n800 the codec is called TSC2301 (part of the touch screen chip) (again see your dmesg output, in this e.g. [http://www.internettablettalk.com/forums/showpost.php?p=30655&postcount=46 this thread].  
+
On the 770, the codec is called <code>aic23</code> (see <code>dmesg</code> output). On the N800 the codec is called <code>TSC2301</code> (part of the touch screen chip) (again see your <code>dmesg</code> output—see [http://www.internettablettalk.com/forums/showpost.php?p=30655&postcount=46 this thread].  
-
E.g.:
 
<pre>
<pre>
[ 312.232727] #0: OMAP24xx EAC with codec TSC2301
[ 312.232727] #0: OMAP24xx EAC with codec TSC2301
</pre>
</pre>
-
Data about both of these codecs is available on the Texas Instruments website.
+
Data about both of these codecs is available on the Texas Instruments website. See the page for [http://focus.ti.com/docs/prod/folders/print/tsc2301.html TSC2301]. It includes a data sheet with the [http://focus.ti.com/lit/ds/symlink/tsc2301.pdf info needed to write the mini-driver].
-
 
+
-
See the page for [http://focus.ti.com/docs/prod/folders/print/tsc2301.html TSC2301]. It includes a data sheet with the [http://focus.ti.com/lit/ds/symlink/tsc2301.pdf 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 Ch3 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.
+
 +
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:
For those who want more information about disassembly, take a look at these documents:
-
<pre>
+
{| class="wikitable"
-
spru374g - DSP assembly code memonics
+
| spru374g  
-
spru281f - c/c++ calling conventions (ch6 Run-time environment)
+
| DSP assembly code memonics
-
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)
+
| spru281f  
-
</pre>
+
| c/c++ calling conventions (ch6 Run-time environment)
-
 
+
|-
-
== Tips and Tricks (or why isn't it working?!) ==
+
| 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
 +
|}
 +
== 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're linking against the current <code>avs_kernel</code> (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.
+
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.
+
<code>dbg()</code> function: This function allows one to output messages (like <code>printf</code>) to <code>dmesg</code> 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:
-
You use it like so:
+
-
dbg('this is a message, this is a value=%d', some_value);
+
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.
+
Note that the variable <code>some_value</code> 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.
=== Location of data ===
=== Location of data ===
Line 205: Line 200:
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 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.
+
I didn't investigate this further, but in the <code>avs_kernelcfg.cmd</code> 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.
== Documentation pointers ==
== Documentation pointers ==
Line 213: Line 208:
[http://focus.ti.com/lit/ug/spru281f/spru281f.pdf TMS320C55x Optimizing C/C++ Compiler  User's Guide]
[http://focus.ti.com/lit/ug/spru281f/spru281f.pdf TMS320C55x Optimizing C/C++ Compiler  User's Guide]
-
* p79: 3.2 Performing File-Level Optimization (-O3 Option)
+
* '''p79''': 3.2 Performing File-Level Optimization (-O3 Option)
-
* p80: 3.3 Performing Pro
+
* '''p80''': 3.3 Performing Program-Level Optimization (-pm and -O3 Options)
-
gram-Level Optimization (-pm and -O3 Options)
+
-
 
+
=== ASM with C/C++ ===
=== ASM with C/C++ ===
Line 222: Line 215:
[http://focus.ti.com/lit/ug/spru281f/spru281f.pdf TMS320C55x Optimizing C/C++ Compiler  User's Guide]
[http://focus.ti.com/lit/ug/spru281f/spru281f.pdf TMS320C55x Optimizing C/C++ Compiler  User's Guide]
-
* p83:  3.3.2 Optimization Considerations When Mixing C and Assembly
+
* '''p83''':  3.3.2 Optimization Considerations When Mixing C and Assembly
-
* p176: 6.5 Interfacing C/C++ With Assembly Language
+
* '''p176''': 6.5 Interfacing C/C++ With Assembly Language
-
* p178: Example 6-3. Calling an Assembly Language Function From C
+
* '''p178''': Example 6-3. Calling an Assembly Language Function From C
-
* p181: 6.5.3 Using Inline Assembly Language
+
* '''p181''': 6.5.3 Using Inline Assembly Language
[http://www.ti.com/litv/pdf/spru376a TMS320C55x DSP Programmer's Guide]
[http://www.ti.com/litv/pdf/spru376a TMS320C55x DSP Programmer's Guide]
-
* p76: Table 3-6. TMS320C55x C Compiler Intrinsics
+
* '''p76''': Table 3-6. TMS320C55x C Compiler Intrinsics
-
 
+
=== Misc ===
=== Misc ===
Line 236: Line 228:
[http://focus.ti.com/lit/ug/spru281f/spru281f.pdf TMS320C55x Optimizing C/C++ Compiler  User's Guide]
[http://focus.ti.com/lit/ug/spru281f/spru281f.pdf TMS320C55x Optimizing C/C++ Compiler  User's Guide]
-
* p122: 5.3 Data Types
+
* '''p122''': 5.3 Data Types
 +
 
[[Category:Development]]
[[Category:Development]]
-
[[Category:Midgard wiki]]
+
[[Category:N8x0]]
 +
[[Category:770]]

Latest revision as of 11:33, 15 April 2010

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