RTEMS for Nintendo DS
Instruction manual

Matthieu Bucchianeri
Benjamin Ratier
Renaud Voltz
Cedric Gestes


1  Introduction

This manual describes how to create applications for RTEMS on Nintendo DS. The document presents makefiles modifications, defines to use and drivers interfaces.

Contents

2  Preparing RTEMS distribution

FIXME: write this!

3  Writing a basic application

A basic application can be built with no changes in makefiles and configuration files.

The classical Hello World, found at rtems/testsuites/samples/hello/ can be built as-is.

4  Writing a framebuffer application

Writing a framebuffer application requires to include the framebuffer driver by hand, as it is not a standard device supported by RTEMS.

To include such driver, the simplest way is to rewrite manually the driver table. The source or header file containing the configuration directives needs to include the file <rtems/fb.h> and to declare the array Device_drivers. Here is an example:
#include <bsp.h>
#include <rtems/fb.h>
#include <rtems/console.h>
#include <rtems/clockdrv.h>

#define CONFIGURE_HAS_OWN_DEVICE_DRIVER_TABLE

rtems_driver_address_table Device_drivers[] =
{
  CONSOLE_DRIVER_TABLE_ENTRY,
  CLOCK_DRIVER_TABLE_ENTRY,

  /* include framebuffer driver */
  FB_DRIVER_TABLE_ENTRY,

  { NULL,NULL, NULL,NULL,NULL, NULL }
};
As shown above, the other (standard) drivers must be included by hand to.

Accessing the framebuffer is done through the device /dev/fb0.

The following directive must be added:
#include <rtems/mw_fb.h>
The ioctl() operation is necessary to enter and leave the graphic mode and to get the framebuffer information. The Micro FrameBuffer library developed by Rosimildo da Silva offers functions to manipulate the framebuffer. See cpukit/libmisc/mw-fb/ for more information.

4.1  Using the two screens as framebuffers

The instructions described above place one screen in framebuffer mode and leave the other one in console mode. It is also possible to put both screens in framebuffer mode. The second screen works exactly the same way, through the device /dev/fb1.

Please note that while the second screen is in framebuffer mode, the console still runs in background. When leaving the graphic mode, the console is restored.

This feature is not yet finished and should not work correctly.

4.2  Swapping the two screens

Swapping top and bottom screen can be done using the libnds. See section Writing a libnds application for the Makefile changes.

The function in the libnds to swap the screens is:
lcdSwap();

5  Writing a sound application

RTEMS for Nintendo DS includes its own sound interface. Operating with the speaker and the microphone can be done using the device /dev/pcm.

Following directive must be added:
#include <rtems/sound.h>

5.1  Driver initialization

This step is common for using output and input. Like for the framebuffer, the driver must be added by hand.
#include <bsp.h>
#include <rtems/console.h>
#include <rtems/clockdrv.h>
#include <rtems/sound.h>

#define CONFIGURE_HAS_OWN_DEVICE_DRIVER_TABLE

rtems_driver_address_table Device_drivers[] =
{
  CONSOLE_DRIVER_TABLE_ENTRY,
  CLOCK_DRIVER_TABLE_ENTRY,

  /* include sound driver */
  SOUND_DRIVER_TABLE_ENTRY,

  { NULL,NULL, NULL,NULL,NULL, NULL }
};

5.2  Using audio output

Configuring sound output is done through ioctl(). Here is a list of the available operations: Please, note that the above operations applies to newly started sounds. Currently played sounds are not affected.

Playing a sound is done by writing to /dev/pcm. The PCM buffer for one sound must be wrote in one time. The operation does not block. Up to 16 sounds can be played simultaneously. Example:
  int fd = open("/dev/pcm", O_WRONLY);
  int fmt = SOUND_FREQ_11025 | SOUND_FORMAT_8;

  ioctl(fd, SOUND_SFMT, &fmt);
  write(fd, sound1, &sound1_size);
  sleep(1);
  write(fd, sound2, &sound2_size);
Please, note that playing a sound in loop is not supported natively.

5.3  Using the microphone

Configuring sound input and capturing microphone is done through ioctl(). Here is a list of the available operations: The sound format provided by microphone recording is PCM8 at 16384 Hz.

Reading the recorded data is done thought the read() operation. Data can be read in multiple times.

Here is a complete sample of microphone usage.
  int fd = open("/dev/pcm", O_RDWR);
  int fmt = SOUND_FREQ_RECORD | SOUND_FORMAT_8;
  int len = 1000000;

  ioctl(fd, SOUND_SRECLEN, &len);
  /* record for 1 second */
  ioctl(fd, SOUND_STARTREC, 0);
  sleep(1);
  ioctl(fd, SOUND_STOPREC, &len);

  /* read recorded data */
  read(fd, buff, len)
  /* playback */
  ioctl(fd, SOUND_SFMT, &fmt);
  write(fd, buff, len);
Please, note that starting to record erases previously recorded data.

This feature is not yet finished and should not work correctly.

6  Writing a touchscreen/keyboard application

The Nintendo DS contains a touch screen and a few buttons. The DS BSP supports the touch screen as a mouse.

The buttons LEFT and RIGHT on the pad are used as mouse buttons in right-handed configuration, and A and B in right-handed mode.

Holding buttons L or R enables character recognition (see section Using graffiti below).

Enabling the touch screen driver is done by the following code:

To include such driver, the simplest way is to rewrite manually the driver table. The source or header file containing the configuration directives needs to include the file <rtems/fb.h> and to declare the array Device_drivers. Here is an example:
#include <bsp.h>
#include <rtems/touchscreen.h>
#include <rtems/console.h>
#include <rtems/clockdrv.h>

#define CONFIGURE_HAS_OWN_DEVICE_DRIVER_TABLE

rtems_driver_address_table Device_drivers[] =
{
  CONSOLE_DRIVER_TABLE_ENTRY,
  CLOCK_DRIVER_TABLE_ENTRY,

  /* include touchscreen driver */
  TOUCHSCREEN_DRIVER_TABLE_ENTRY,

  { NULL,NULL, NULL,NULL,NULL, NULL }
};
The touchscreen driver needs the clock driver to be enabled.

Next, accessing the touchscreen is done through a message queue notifying mouse movements. Registering the message queue is done through ioctl to device /dev/mouse: Once the queue is registered, mouse actions are notified using a message of type struct MW_UID_MESSAGE. Here are the fields of this structure: These structures are declared in the MicroFramebuffer API.
#include <rtems/mw_uid.h>
Using the MicroFramebuffer library, the code for mouse looks like:
uid_open_queue(name, 0, 10); // 30 messages queue
uid_register_device(open("/dev/mouse", O_RDONLY), name);
...
struct MW_UID_MESSAGE m;
uid_read_message(&m, 0);
Passing the touchscreen from right-handed mode to left-handed mode is also done through ioctl on /dev/mouse:

6.1  Poll-based touchscreen/keys

Reading directly the touchscreen state and the keys state can be done through libnds. See section Writing a libnds application for the Makefile changes.
touchPosition pos = touchReadXY();
int k = keysDown();
See libnds help for more information.

6.2  Using graffiti

RTEMS for Nintendo DS supports graffiti recognition based on PALib1.


PALib graffiti


Graffiti input is activated when the touchscreen driver is enabled and when the key X is pressed.

There are two ways to read graffiti input: Unbuffered means that only the last graffiti is stored. For example, if two graffiti are drawn successively and then a read() is done, only the last graffiti is returned.

Using the unbuffered mode is very easy:
char c = getchar();
This operation is blocking.

The MicroFramebuffer API is more powerful. The source can be found in cpukit/libmisc/mw-fb/.

It uses a message queue to be notified of characters input. Registering the message queue is done through ioctl to device /dev/console: Once the queue is registered, keyboard input are notified using a message of type struct MW_UID_MESSAGE. Here are the fields of this structure: Using the MicroFramebuffer library, the code for character recognition looks like:
uid_open_queue(name, 0, 10); // 10 messages queue
uid_register_device(open("/dev/console", O_RDONLY), name);
...
struct MW_UID_MESSAGE m;
uid_read_message(&m, 0);
This technique is used by MicroWindows and Nano-X.

7  Writing a MicroWindows application

MicroWindows provides a Microsoft Windows compatible API.

Downloads and resources on MicroWindows can be found at http://www.microwindows.org/.

7.1  Preparing MicroWindows/Nano-X

The following instructions have been tested with MicroWindows 0.91.

Untar MicroWindows source distribution.
$ tar xjf microwindows-src-0.91.tar.gz
In the file src/config, change the following definitions:
ARCH                  = RTEMS
RTEMSTOOLSPREFIX      = arm-rtems4.8-
SCREEN_PIXTYPE        = MWPF_TRUECOLOR555
THREADSAFE            = N
SHAREDLIBS            = N
HAVE_JPEG_SUPPORT     = N
HAVE_FNT_SUPPORT      = N
HAVE_FNTGZ_SUPPORT    = N
HAVE_FREETYPE_SUPPORT = N
HAVE_PCF_SUPPORT      = N
HAVE_PCFGZ_SUPPORT    = N
FBVGA                 = N
VTSWITCH              = N
GPMMOUSE              = N
SCANKBD               = N
RTEMS_BUILD           = /path/to/your/rtems/build
RTEMS_BSP             = nds
RTEMS_TARGET          = arm-rtems4.8
Next, the following patch must be applied:
--- drivers/romfont.c
+++ drivers/romfont.c
@@ -12,6 +12,7 @@
  * The environment variable CHARHEIGHT if set will set the assumed rom
  * font character height, which defaults to 14.
  */
+#ifdef FBVGA
 #include <stdlib.h>
 #include "device.h"
 #include "vgaplan4.h"
@@ -181,3 +182,4 @@
   }
 }
 #endif /* NOTUSED*/
+#endif
--- include/windef.h    2008-01-15 03:09:18.000000000 +0100
+++ include/windef.h    2008-01-15 03:04:13.000000000 +0100
@@ -64,11 +64,11 @@
 typedef unsigned char          UCHAR;
 typedef unsigned short                 USHORT;
 typedef unsigned long          ULONG;
-#ifndef __ITRON_TYPES_h_ /* FIXME RTEMS hack*/
+#ifndef _ITRONSYS_TYPES_H /* FIXME RTEMS hack*/
 typedef unsigned int           UINT;
 #endif

-#ifndef __ITRON_TYPES_h_
+#ifndef _ITRONSYS_TYPES_H
 #ifndef COMMON_H        /* MiniGUI hack*/
 typedef int                    BOOL;
 #endif
@@ -80,7 +80,7 @@
 typedef USHORT *               PUSHORT;
 typedef UCHAR *                        PUCHAR;
 typedef char *                 PSZ;
-#ifndef __ITRON_TYPES_h_
+#ifndef _ITRONSYS_TYPES_H
 typedef int                    INT;
 #endif
 typedef unsigned int           *PUINT;
--- mwin/winevent.c  2008-01-15 03:10:13.000000000 +0100
+++ mwin/winevent.c     2008-01-15 03:02:44.000000000 +0100
@@ -14,7 +14,7 @@
 #include <string.h>

 #if !(DOS_TURBOC | DOS_QUICKC | _MINIX | VXWORKS)
-static int
+int
 abs(int n)
 {
        return n >= 0? n: -n;
Then, the source is able to be build.
$ make
Compiling should stop with an error after the line:
Compiling rtems/rtems_init.c ...
This is not a problem, the only required files are in src/lib.
$ ls lib
libmwdrivers.a  libmwfonts.a   libmwin.a     libnano-X.a
libmwengine.a   libmwimages.a  libmwinlib.a

7.2  Running the MicroWindows Minesweeper sample

Now that MicroWindows is built, compiling an RTEMS application to use it is very simple.

The following lines must be added to the Makefile:
AM_CFLAGS += -I$(MWIN)/include -I$(exec_prefix)/nds/lib/include/libnds/
AM_LDFLAGS += -L$(MWIN)/lib
LINK_LIBS +=  -lmwin -lmwinlib -lmwengine -lmwdrivers -lmwfonts -lmwimages -lm
Creating the initial task for the application is more complicated. The following C source can be used as a template:
#define  CONFIGURE_INIT
#include <stdio.h>
#include "rtemscfg.h"
#define ARM9
#include <nds.h>

/* this is the command line options to be passed to the main routine */
char *cc_argv[] =
  {
    "cc_main",    /* arg[ 0 ] -- always the name of the program */
  };
int cc_argc = sizeof(cc_argv) / sizeof(cc_argv[0]);

extern int rtems_main(int argc, char **argv);

/*
 * DESCRIPTION: Init task for any Microwindows/RTEMS application.
 */

void *POSIX_Init( void *argument )
{
#ifdef SWAP_LCD
  lcdSwap();
#endif

  rtems_main(cc_argc, cc_argv);
  pthread_exit(NULL);
  return NULL;
}
The file above includes the file rtemscfg.h which looks like:
#include <bsp.h>

#include <rtems/fb.h>
#include <rtems/console.h>
#include <rtems/clockdrv.h>
#include <rtems/touchscreen.h>

/* comment this line to disable lcd screen swapping. */
#define SWAP_LCD

/* configuration information */
#define CONFIGURE_MAXIMUM_DEVICES                     40
#define CONFIGURE_MAXIMUM_TASKS                       100
#define CONFIGURE_MAXIMUM_TIMERS                      32
#define CONFIGURE_MAXIMUM_SEMAPHORES                  100
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES              20
#define CONFIGURE_MAXIMUM_PARTITIONS                  100
#define CONFIGURE_MAXIMUM_REGIONS                     100
#define CONFIGURE_MAXIMUM_POSIX_MUTEXES               32
#define CONFIGURE_MAXIMUM_POSIX_CONDITION_VARIABLES   32
#define CONFIGURE_MAXIMUM_POSIX_KEYS                  32
#define CONFIGURE_MAXIMUM_POSIX_QUEUED_SIGNALS        10
#define CONFIGURE_MAXIMUM_POSIX_THREADS               128
#define CONFIGURE_MAXIMUM_POSIX_TIMERS                10
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS      200
#define CONFIGURE_MAXIMUM_POSIX_MESSAGE_QUEUES        20
void *POSIX_Init( void *argument );
#define CONFIGURE_POSIX_INIT_THREAD_STACK_SIZE        (384*1024)
#define CONFIGURE_POSIX_INIT_THREAD_TABLE

#define CONFIGURE_HAS_OWN_DEVICE_DRIVER_TABLE

rtems_driver_address_table Device_drivers[] =
{
  CONSOLE_DRIVER_TABLE_ENTRY,
  CLOCK_DRIVER_TABLE_ENTRY,
  FB_DRIVER_TABLE_ENTRY,
  TOUCHSCREEN_DRIVER_TABLE_ENTRY,
  { NULL,NULL, NULL,NULL,NULL, NULL }
};

#include <rtems/confdefs.h>
Of course, the values above can be tuned to fit your needs.

Now, everything is ready to be compiled. Just grab the Mine Sweeper demo from MicroWindows source. Compilation requires to pass the path to MicroWindows source directory.
$ make MWIN=/path/to/microwindows/src
Recalls on mouse and keyboard controls can be found in section Writing a touchscreen/keyboard application.

8  Writing a Nano-X application

Nano-X provides an X-Window compatible API.

Using Nano-X in RTEMS follows exactly the same steps as with MicroWindows (see Preparing MicroWindows/Nano-X).

8.1  Running the xeyes sample

Everything is exactly like described in Running the MicroWindows Minesweeper sample. The only change is in the Makefile:
AM_CFLAGS += -I$(MWIN)/include -I$(exec_prefix)/nds/lib/include/libnds/
AM_LDFLAGS += -L$(MWIN)/lib
LINK_LIBS +=  -lnano-X -lmwengine -lmwdrivers -lmwfonts -lmwimages -lm
Grab the Nano-Xeyes source from MicroWindows source and compile.

Recalls on mouse and keyboard controls can be found in section Writing a touchscreen/keyboard application.

9  Writing a Wi-Fi application

RTEMS includes network features that can be used on Nintendo DS through the WiFi. A Wifi application requires a few definitions.

First, the makefile must modify the linker flags:
CFLAGS_LD += -Wl,--defsym -Wl,HeapSize=0x80000
Using network in RTEMS is not so complicated. Two globals must be declared and the function rtems_bsdnet_initialize_network must be called as in the following code.
#include <bsp.h>

#include <stdlib.h>
#include <stdio.h>
#include <rtems/rtems_bsdnet.h>

/* enable or disable DHCP */
//#define BOOTP

static struct rtems_bsdnet_ifconfig netdriver_config = {
 RTEMS_BSP_NETWORK_DRIVER_NAME,
 RTEMS_BSP_NETWORK_DRIVER_ATTACH,
#ifndef BOOTP
 NULL,
 "192.168.1.10", // static ip address
 "255.255.255.0" // static submask
#endif
};
struct rtems_bsdnet_config rtems_bsdnet_config = {
 &netdriver_config,
#ifdef BOOTP
 rtems_bsdnet_do_bootp,
#else
 NULL,
 0,
 0,
 0,
 "hostname",
 "domaine.name",
 "192.168.1.1", // default gateway
 NULL,
 { "192.168.1.1" } // name servers
#endif
};

rtems_task Init(
  rtems_task_argument ignored
)
{
  printk("Starting network\n");
  rtems_bsdnet_initialize_network ();
  printk("Ok.\n");
  while (1)
    ;
  exit( 0 );
}

/* configuration information */
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER

#define CONFIGURE_RTEMS_INIT_TASKS_TABLE

#define CONFIGURE_EXECUTIVE_RAM_SIZE        (512*1024)
#define CONFIGURE_MAXIMUM_SEMAPHORES        20
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES    20
#define CONFIGURE_MAXIMUM_TASKS            200
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS      20
#define CONFIGURE_INIT

#include <rtems/confdefs.h>
Of course, the CONFIGURE macros above can be tuned.

10  Writing a libnds application

It is possible to use the libnds directly from an application. The following line must be added to the Makefile:
CFLAGS += -I$(exec_prefix)/nds/lib/include/libnds/ -DARM9
Using the libnds requires to include the file nds.h as following:
#include <nds.h>
For help about the libnds features, please visit http://www.devkitpro.org/.


1
http://www.palib.info/

This document was translated from LATEX by HEVEA.