If you want to create a simple driver for NuttX this tutorial is just for you.
I created a small board powered by kinetis KL25 and put NuttX to run on it, but this board has 4 LEDs for user interface, then I created a simple driver just to let an application to interact with them directly.
Here is my LED driver source code:
#include <nuttx/config.h> #include <nuttx/arch.h> #include <stdint.h> #include <unistd.h> #include <errno.h> #include <sched.h> #include "kl_gpio.h" /**************************************************************************** * HW access ****************************************************************************/ #define GPIO_LED_1 (GPIO_OUTPUT | GPIO_OUTPUT_ONE | PIN_PORTE | PIN2) #define GPIO_LED_2 (GPIO_OUTPUT | GPIO_OUTPUT_ONE | PIN_PORTE | PIN3) #define GPIO_LED_3 (GPIO_OUTPUT | GPIO_OUTPUT_ONE | PIN_PORTE | PIN4) #define GPIO_LED_4 (GPIO_OUTPUT | GPIO_OUTPUT_ONE | PIN_PORTE | PIN5) /**************************************************************************** * LEDs: Fileops Prototypes and Structures ****************************************************************************/ typedef FAR struct file file_t; static int leds_open(file_t *filep); static int leds_close(file_t *filep); static ssize_t leds_read(file_t *filep, FAR char *buffer, size_t buflen); static ssize_t leds_write(file_t *filep, FAR const char *buf, size_t buflen); static const struct file_operations leds_ops = { leds_open, /* open */ leds_close, /* close */ leds_read, /* read */ leds_write, /* write */ 0, /* seek */ 0, /* ioctl */ }; /**************************************************************************** * LEDs: Fileops ****************************************************************************/ static int leds_open(file_t *filep) { /* Nothing to do here, maybe I should increase a counter like for Linux driver? */ return OK; } static int leds_close(file_t *filep) { /* Nothing to do here, maybe I should decrease a counter like for Linux driver?*/ return OK; } static ssize_t leds_read(file_t *filep, FAR char *buf, size_t buflen) { register uint8_t reg; if(buf == NULL || buflen < 1) /* Well... nothing to do */ return -EINVAL; /* These LEDs are actived by low signal (common anode), then invert signal we read*/ reg = ~(kl_gpioread(GPIO_LED_4)); reg = (reg << 1) | ~(kl_gpioread(GPIO_LED_3)); reg = (reg << 1) | ~(kl_gpioread(GPIO_LED_2)); reg = (reg << 1) | ~(kl_gpioread(GPIO_LED_1)); reg = reg & 0x0F; *buf = (char) reg; return 1; } static ssize_t leds_write(file_t *filep, FAR const char *buf, size_t buflen) { register uint8_t reg; if(buf == NULL || buflen < 1) /* Well... nothing to do */ return -EINVAL; reg = (uint8_t) *buf; printf("Trying to write %d\n", reg); /* These LEDs are actived by low signal (common anode), invert the boolean value */ kl_gpiowrite(GPIO_LED_1, !(reg & 0x01)); kl_gpiowrite(GPIO_LED_2, !(reg & 0x02)); kl_gpiowrite(GPIO_LED_3, !(reg & 0x04)); kl_gpiowrite(GPIO_LED_4, !(reg & 0x08)); return 1; } /**************************************************************************** * Initialize device, add /dev/... nodes ****************************************************************************/ void up_leds(void) { kl_configgpio(GPIO_LED_1); kl_configgpio(GPIO_LED_2); kl_configgpio(GPIO_LED_3); kl_configgpio(GPIO_LED_4); (void)register_driver("/dev/leds", &leds_ops, 0444, NULL); }
I saved this driver file as configs/freedom-kl25z/src/leds_driver.c and added it to Makefile:
ifeq ($(CONFIG_ARCH_LEDS),y) CSRCS += kl_led.c CSRCS += leds_driver.c endif
I’m reusing the same ARCH_LEDS config but you can create a specific config for your driver.
Unfortunately you cannot call up_leds() initialization function from kl_boardinitialize.c because this is called before the RTOS finished initialization. More information click here: http://comments.gmane.org/gmane.comp.embedded.nuttx/3158
I decided to use NSH_ARCHINIT to let nsh initialize my driver. First of all add this define to your config file:
CONFIG_NSH_ARCHINIT=y
Now create the configs/freedom-kl25z/src/up_nsh.c file and add it:
/****************************************************************************
* Name: nsh_archinitialize
*
* Description:
* Perform architecture specific initialization
*
****************************************************************************/
int nsh_archinitialize(void)
{
#ifdef CONFIG_ARCH_LEDS
up_leds();
#endif
return OK;
}
Just compile and flash the firmware inside your board.
Now my application can control the user LEDs.