Monday, December 15, 2008

Upgrading to devkitARM r24 (on Linux)

The latest version of the devkitARM toolchain was released last week, and it was a biggie. A whole new API for sprites and backgrounds was added to libnds. A new default ARM7 binary was added that automatically handles wifi, sound and sleep mode. The other big addition was a new fangled sound library that adds mod playback and fancy sound effects.

This is my post on the upgrade process for Bunjalloo on Linux (Ubuntu 8.04 in particular). Hey, if you read all this and get through it, then you could probably help out hacking on Bunjalloo too :-)

A summary for the impatient: not without hassles, but the gain is worth the short term pain.

I assume you have a directory devkitPro somewhere. This will contain devkitARM and libnds. You should set an environment variable DEVKITPRO to point to this directory. Something like this will do:
export DEVKITPRO=$HOME/devkitpro_r24
mkdir -p $DEVKITPRO
I recommend versioning this release at the devkitpro directory level. Release r24 contains some breaking changes and by having the possibility to change between r23 and r24 you may save yourself some headaches. At the very least, it will ensure you don't mix versions, which would be a big no-no.
  1. Download the devkitARM r24 files from the sf.net project page
    • devkitARM_r24-i686-linux.tar.bz2
    • libnds-src-1.3.1.tar.bz2
    • dswifi-src-0.3.5.tar.bz2
    • maxmod-src-1.0.1.tar.bz2
    • default_arm7-src-20081210.tar.bz2
    • nds-examples-20081210.tar.bz2
    • libfat-src-1.0.3.tar.bz2
    I saved them all in $HOME/Downloads, and that's what I've put in this post. Change that path as you need.


  2. Install the devkitARM toolchain. This provides the compiler and C/C++ standard libraries. I usually install it in a versioned file, but if you already have named your devkitpro directory "devkitpro_r24" then there's no need.

    cd $DEVKITPRO
    tar xvf ~/Downloads/devkitARM_r24-1686-linux.tar.bz2
    mv devkitARM devkitARM_r24

  3. The rest of these steps can be done in any directory. I tend to use $DEVKITPRO/vendor for all this build stuff. You can also use the precompiled binaries, but this way you know you have everything you need installed.

  4. Set the DEVKITARM environment variable to point to our installed toolkit
    export DEVKITARM=$DEVKITPRO/devkitARM_r24

  5. Install libnds
    !!! CARE !!! these source tars don't have a top level directory, so you need to create them manually. This is the case for all of the devkitPro tar balls, except the main devkitARM_r24 one. They will splurge their files in the current directory, instead of creating their own top level one. Yuck!
    mkdir libnds-1.3.1
    cd libnds-1.3.1
    tar xjf ~/Downloads/libnds-src-1.3.1.tar.bz2
    Now to compile libnds - if you have DEVKITPRO and DEVKITARM set correctly then this should compile the library succesfully.
    make -j 3 install

  6. libfat is optional, but recommended. Open up the tar, compile and install it too, if you like. libfat for the nds depends on having libnds installed, so you'll have to do step 4 first.

    mkdir libfat-1.0.2
    cd libfat-1.0.2
    tar xvf ~/Downloads/libfat-src-1.0.2.tar.bz2
    make nds-install

  7. Now install dswifi 0.3.5 in a similar way - untar the release files, compile and install. dswifi depends on libnds, so you have to do the previous steps before this one.

    mkdir dswifi-0.3.5
    cd dswifi-0.3.5
    tar xvf ~/Downloads/dswifi-src-0.3.5.tar.bz2
    make -j 3 install


  8. Install maxmod. Again, this depends on libnds and won't compile if you have skipped a step.
    mkdir maxmod-1.0.1
    cd maxmod-1.0.1
    tar xvf ~/Downloads/maxmod-src-1.0.1.tar.bz2
    make -j 3 install-nds


  9. Install the new default ARM7 core. This requires dswifi and maxmod, if either are missing then you will get compile or link errors.

    mkdir default_arm7-20081210
    cd default_arm7-20081210
    tar xvf ~/Downloads/default_arm7-src-20081210.tar.bz2
    make install

  10. Try out the nds examples! Now that everything is installed, you can compile and run some examples.
    mkdir nds-examples-20081210
    cd nds-examples-20081210
    tar xvf ~/Downloads/nds-examples-20081210.tar.bz2
    cd audio/maxmod
    make
    # test the nds files on your DS!
  11. Write your own program :-) This part is a bit trickier!
Now once I had all this installed, I needed to update Bunjalloo to use the new code (Elite DS coming soon!). The first step was to see what would compile without drastic changes. The list of changes required in my code was:
  • Remove irqInit() calls - this is now done by libnds before your main is called
  • Register name changes: DISPLAY_CR -> REG_DISPCNT, BG0_X0 -> REG_BG0HOFS, BG0_CR -> REG_BG0CNT (and their SUB equivalents, where applicable)
  • Function name changes: powerON, powerOFF -> powerOn, powerOff, touchReadXY() -> touchRead(touch_structure)
  • Deprecated header: nds/jtypes.h -> nds/ndstypes.h
  • Look-up table changes: COS[angle] -> cosLerp(angle), SIN[angle] -> sinLerp(angle)
  • Some #defines have gone: BG_16_COLOR -> BG_COLOR_16, BG_256_COLOR -> BG_COLOR_256, SOUND_8BIT -> SOUND_FORMAT_8BIT
  • powerOn/Off now expects a PM_Bits enum value, not an int
Nothing major there... the big breaking changes are on the ARM7 side. Here trying to use your own hand-coded arm7 causes plenty of problems - most of the old inter-processor communications code has been removed from libnds, or has changed completely. Unfortunately, that means it's quite tricky to migrate to the new libnds and use your own ARM7 core. The easiest thing to do here is ignore your ARM7 code completely and use the new default_arm7. There's no one-stop solution, since most IPC code has been built in an ad hoc way, but here are some pointers.

For wifi code, your old wifi init code should be replaced by a single call to Wifi_InitDefault(true/false) - no need to faff about setting up the interrupts and timers. Then you can either now use sockets (if you passed "true", which means connect using the firmware settings) or connect using a detected AP first - all this is documented in the dswifi headers and by the new examples. Pretty neat, and cuts down on maintenance for everyone.

If you have a debug console, then consoleInitDefault() is a bit trickier to update. It has disappeared, pretty much. In most cases consoleDemoInit() will probably suffice. If you are doing anything much more complicated, then you will have to get to grips with the PrintConsole structure. This seems to be quite a powerful new feature, for example it allows printing to both screens from within the same program, but will take a while to get used to. I doubt many people used the old consoleInitDefault in "real" programs, and the new API looks like it might be possible to use the printf stuff on something other than a black/white screen.

Sound has seen a rather large shakeup in this release. The new MaxMod sound engine seems to fill a huge gap in the homebrewer's library arsenal. It isn't without its drawbacks though, if you did just basic NDS sound effects. Previously you could play individual samples by sending the raw data to the playGenericSound() function, after having previously set the sample rate, volume, panning and format via the setGenericSound() function. That has now been completely removed, replaced by new MaxMod sound engine functions. This is a flexible sound and music system, but requires that the sound effects are in a special format. A tool (mmutil) is provided to convert wav and mod file formats to the expected static structure. Alternatively, a more complex streaming system can be used. This latter does not require input sounds to be converted, and is the only way to play sound from a file, but is slightly trickier to use than the straight forward playGenericSound() function.

The sound streaming approach requires you the coder to implement an audio-filling callback and to call the mmUpdateStream() function often enough to keep the sound buffer full. Fortunately there are some good examples of all the MaxMod library's usage in the nds-examples pack, and the new system is a great addition. Besides music, you can do looped samples, proper panning, mixing, etc, etc. Bah, I'm just miffed because I'll have to rewrite some of my SDL sound code ;-)

Needless to say, on the ARM7 side of things the sound handling stuff has completely changed - this alone is a good enough reason to abandon any hand-rolled arm7 code. Added to the new sleep function - no more will-it-wont-it wondering when you close the lid - and all in all I think this is a great release.

7 comments:

  1. maxmod has a pretty simple sound effect system, that's almost as easy as playGenericSound. Here's the very most basic code needed to play a sound effect:

    http://davr.org/ds2/soundeffect.txt


    For the complete code, check out the audio/maxmod/basicsound example included with libnds (or separate, if you're using linux)

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Yeah, I've read the examples. The problem there is that you have to convert the sounds into a soundbank object (the SFX_BOOM is an integer that says the offset in that soundbank). There's no way to just play a raw sound from a plain file without having it in a sound bank, that was my point.

    It's not a big deal really, as I say for 99% of homebrewers it won't make a difference. It only affected me because I compiled for SDL and DS from the same code, now I'd have to alter the way the SDL part works.

    It'd be nice if the soundbank structure was documented at least, maybe, rather than just being a "void *".

    ReplyDelete
  4. Anonymous9:27 pm

    The stock windows devkitpro updater works really well with wine - I just ran that to get everything downloaded and installed, then swapped out the standard devkitARM directory for the linux version. Worked like a charm to get everything up and running on Ubuntu 8.10, although I got stuck for a bit on all the libnds changes. Great tutorial!

    --shin-shoryuken

    ReplyDelete
  5. Anonymous7:17 am

    more tips I'd like to share:

    * tOAM is renamed to OAMTable
    * tOAM::spriteBuffer is renamed OAMTable::oamBuffer

    * lookup registers_alt.h to see all the new names for the display registers

    * for SpriteEntry member variables:

    objMode -> blendMode
    objShape -> shape
    objSize -> size
    colMode -> colorMode

    isRotoscale -> isRotateScale
    rsDouble -> isSizeDouble

    tileIdx -> gfxIndex
    objPriority -> priority
    objPal -> palette

    posX -> x
    posY -> y

    ReplyDelete
  6. Thanks for this post - it saved me DAYS.

    ReplyDelete
  7. thanks for the post, as well. As I feared, I'll have to stick to r21 for a while ...

    ReplyDelete

Note: only a member of this blog may post a comment.