Writing NuttX Applications

NuttX provides a POSIX like API for application development. In this article we will see, how to develop simple NuttX applications. This is the third article in the NuttX series, for the previous articles please see:

Hello World

NuttX provides a Hello World example examples/hello, in the apps folder. The application prints the message "Hello World" on the serial console. The contents of hello_main.c is listed below.

#include <nuttx/config.h>  /* 1 */
#include <stdio.h>

int hello_main(int argc, char *argv[]) /* 2 */
{
  printf("Hello, World!!\n");  /* 3 */
  return 0;
}
1 Pulls in the configuration macros. Required in all NuttX applications.
2 The main() function, is give a custom name, because multiple NuttX applications can co-exist in a single NuttX image.
3 The stdout is mapped to the serial console, by default.

We will get to build this first, and then we will modify it, to write more complex applications. Configure Nuttx to build for NX, first. Note that the commands, assume you are in nuttx-dev.

$ pushd nuttx/tools
$ ./configure.sh lm3s6965-ek/nx
$ popd

Edit apps/.config, and modify CONFIGURED_APPS line to add the examples/hello application. This specifies which applications are to be built.

CONFIGURED_APPS += examples/hello

Edit nuttx/.config, and modify CONFIG_USER_ENTRYPOINT line, to specify the entry point as hello_main. This specifies the first application function to be invoked by NuttX.

CONFIG_USER_ENTRYPOINT="hello_main"

Now build NuttX and the application, and execute it in Qemu. You should be able to see the message Hello World on the serial console.

$ pushd nuttx
$ make CONFIG_LM3S_CODESOURCERYL=y CONFIG_LM3S_BUILDROOT=n
$ popd
$ qemu-system-arm -M lm3s6965evb -kernel nuttx/nuttx

Adding an Application

Before we start modifying our Hello World program, we will create a separate copy of the application. This way we will learn how to add new application, to the existing application framework. First copy the hello folder to myhello.

$ cp -a apps/examples/hello apps/examples/myhello

Edit myhello.c and set the main function name to myhello_main. And to ensure, that its our application, that is getting executed, modify the message, for example to Hello NuttX!.

#include <nuttx/config.h>
#include <stdio.h>

int myhello_main(int argc, char *argv[])
{
  printf("Hello NuttX!\n");
  return 0;
}

Edit myhello/Makefile, set APPNAME to myhello. APPNAME should be same as the prefix of the main application function. A configuration macro CONFIG_EXAMPLES_HELLO_BUILTIN is used to specify if, an application should be created as builtin NuttShell application. Change the reference to the macro to CONFIG_EXAMPLES_MYHELLO_BUILTIN.

Edit apps/.config, and change CONFIGURED_APPS to reflect the new application folder.

CONFIGURED_APPS += examples/myhello

Edit nuttx/.config, and modify CONFIG_USER_ENTRYPOINT line, to specify the entry point as myhello_main. Rebuild, and execute in Qemu, you should be able to see the message Hello NuttX!, on the serial console.

$ pushd nuttx
$ make clean
$ make CONFIG_LM3S_CODESOURCERYL=y CONFIG_LM3S_BUILDROOT=n
$ popd

Accessing SD Card

Let’s modify our program to read a file from the SD Card. The complete program is listed below.

#include <nuttx/config.h>
#include <nuttx/spi.h>
#include <nuttx/mmcsd.h>

#include <sys/mount.h>
#include <stdio.h>
#include <errno.h>

int mmcsd_init()
{
        struct spi_dev_s *spi;
        int ret;

        spi = up_spiinitialize(0);
        if (!spi) {
                printf("failed to initialize SPI port 0\n");
                return 1;
        }

        ret = mmcsd_spislotinitialize(0, 0, spi);
        if (ret < 0) {
                printf("failed to bind SPI port 0 to MMC/SD slot 0: %d\n", ret);
                return 1;
        }
}

int myhello_main(int argc, char *argv[])
{
        int ret;
        char buf[80];
        char *retp;
        FILE *fp;

        ret = mmcsd_init();
        if (ret == -1)
                return 1

        ret = mount("/dev/mmcsd0", "/mnt/sd", "vfat", 0, NULL);
        if (ret == -1) {
                perror("error mounting sd card");
                return 1;
        }

        fp = fopen("/mnt/sd/TEST.TXT", "r");
        if (fp == NULL) {
                perror("error opening TEST.TXT");
                return 1;
        }

        while (1) {
                retp = fgets(buf, sizeof(buf), fp);
                if (retp == NULL) {
                        if (ferror(fp))
                                perror("error reading file");
                        break;
                }

                puts(buf);
        }

        fclose(fp);

        return 0;
}

Except for the mmcsd_init() function, the rest of the program should be familiar to a seasoned Unix developer. mmcsd_init() invokes up_spiinitialize(), to initialize the SPI controller driver. The SD card, is connected to the SPI controller, so we initialize the SPI controller driver first. up_spiinitialize() accepts the index of SPI controller as argument, and returns an instance of struct spi_dev_s, which represents an instance of the SPI controller driver.

mmcsd_init() then invokes mmcsd_spislotinitialize(), to initialize the MMC/SD driver. The function accepts 3 arguments. The first argument is the device no., the device no. specifies the number that will appear in the device file name, such as /dev/mmcsd0. The second argument specifies the index of the SD card slot. A single MMC/SD driver can handle more than one MMC/SD slot. The third argument specifies the SPI controller driver, used to access the SD card slot.

Edit nuttx/.config and set CONFIG_FS_FAT to y. We need FAT filesystem to access the SD card.

Rebuild NuttX and the application, and execute in Qemu. The contents of TEST.TXT should be printed on the console (that happens to be the text Hello World).

$ qemu-system-arm -M lm3s6965evb \
                  -kernel nuttx-nsh.elf \
                  -sd sd.img

Concluding Notes

Hope this helps you to get started with application development on NuttX. We will see how to access other interfaces, in up coming articles. Happy Hacking!