Difference between revisions of "Xenomai:Blinking LEDs"

From ArmadeusWiki
Jump to: navigation, search
(Links)
m (Application code)
 
(19 intermediate revisions by 2 users not shown)
Line 1: Line 1:
This tutorial explain how to create a simple xenomai application. This application has to goal to doing blinking the led.
+
This tutorial explains how to create a simple Xenomai application. This application will blink the [[APF9328DevFull]] user LED (connected to pin 31 of i.MXL portD; on the APF27 you would use pin 14 of portF).
  
 
== Application code ==
 
== Application code ==
 +
<pre class="host">
 +
$ mkdir xeno_led
 +
$ vim xeno_led/blink.c
 +
</pre>
 +
 
<source lang="C">
 
<source lang="C">
 
#include <stdio.h>
 
#include <stdio.h>
Line 16: Line 21:
 
#include <native/timer.h>
 
#include <native/timer.h>
  
#define TIMESLEEP 1000000000
+
#define TIMESLEEP 1000000000 /* 1 sec */
#define LED "/dev/gpio/PD31"
+
#define LED "/dev/gpio/PD31" /* APF9328 */
 +
#define LED "/dev/gpio/PF14" /* APF27 */
  
 
RT_TASK blink_task;
 
RT_TASK blink_task;
 
int fd;
 
int fd;
  
void blink(void *arg){
+
void blink(void *arg __attribute__((__unused__)))
  int iomask = 0x00;
+
{
 +
    int iomask = 0x00;
 
    
 
    
  rt_task_set_periodic(NULL, TM_NOW, TIMESLEEP);
+
    rt_task_set_periodic(NULL, TM_NOW, TIMESLEEP);
 
    
 
    
  while(1){
+
    while(1) {
rt_task_wait_period(NULL);
+
        rt_task_wait_period(NULL);
 
         write(fd,&iomask,sizeof(iomask));
 
         write(fd,&iomask,sizeof(iomask));
         iomask^=1;
+
         iomask ^= 1;
  }
+
    }
 
}
 
}
  
 
void catch_signal() {}
 
void catch_signal() {}
  
int main(int argc, char **argv) {
+
int main(void)
 +
{
 +
    signal(SIGTERM, catch_signal);
 +
    signal(SIGINT, catch_signal);
 
    
 
    
  signal(SIGTERM, catch_signal);
+
    /* Avoids memory swapping for this program */
  signal(SIGINT, catch_signal);
+
    mlockall(MCL_CURRENT|MCL_FUTURE);
 
+
  /* Avoids memory swapping for this program */
+
  mlockall(MCL_CURRENT|MCL_FUTURE);
+
  
  /* led device opening */
+
    /* led device opening */
  if ((fd = open(LED, O_WRONLY))<0) {
+
    if ((fd = open(LED, O_WRONLY)) < 0) {
    printf("Open error on %s\n",LED);
+
        printf("Open error on %s\n",LED);
    exit(0);
+
        exit(0);
  }
+
    }
  /* Task Creation */
+
    /* Task Creation */
  rt_task_create(&blink_task, "blinkLed", 0, 99, 0);   
+
    rt_task_create(&blink_task, "blinkLed", 0, 99, 0);   
  rt_task_start(&blink_task, &blink, NULL);
+
    rt_task_start(&blink_task, &blink, NULL);
  getchar();
+
    getchar();
  rt_task_delete(&blink_task);
+
    rt_task_delete(&blink_task);
  close(fd);
+
    close(fd);
  return 0;
+
 
 +
    return 0;
 
}
 
}
 
</source>
 
</source>
This source is so equivalent to a classical application with threads and nanosleep() function.<br>
+
 
The only differences are on the task creation using API xenomai.
+
This source looks very like a classical Linux application with threads and nanosleep() function.<br>
 +
The only differences are on the task creation using Xenomai API:
 +
* Create a new task with ''stksize'' stack size, ''prio'' level of priority and ''mode'' type of creation:
 +
<source lang="C">
 
  int rt_task_create(RT_TASK * task, const char * name, int stksize, int prio, int mode)
 
  int rt_task_create(RT_TASK * task, const char * name, int stksize, int prio, int mode)
Create a new task with stksize size of stack, prio level of priority and mode type of creation.
+
</source>
 +
* Launch the new task with ''entry'' function and ''cookie'' parameters:
 +
<source lang="C">
 
  int rt_task_start (RT_TASK *task, void(*entry)(void *cookie), void *cookie)
 
  int rt_task_start (RT_TASK *task, void(*entry)(void *cookie), void *cookie)
Launch the new task with entry function and cookie parameter.
+
</source>
  int rt_task_set_periodic (RT_TASK *task, RTIME idate, RTIME period)  
+
* set for the ''task'' periodic, idate time for the first release (time in nanoseconds)
set for the ''task'' periodic, idate time for the first release, time on nanoseconds
+
<source lang="C">
 +
  int rt_task_set_periodic (RT_TASK *task, RTIME idate, RTIME period)
 +
</source>
 +
* To block the task during the previously set period:
 +
<source lang="C">
 
  int rt_task_wait_period (unsigned long *overruns_r)
 
  int rt_task_wait_period (unsigned long *overruns_r)
To block the task during a period of TIMESLEEP ns.
+
</source>
  
 
== Makefile ==
 
== Makefile ==
  
The second step is to create a Makefile with specific Xenomai includes.<br>
+
The second step is to create a Makefile with specific Xenomai includes.
 +
<pre class="host">
 +
$ vim xeno_led/Makefile
 +
</pre>
  
 
<source lang="bash">
 
<source lang="bash">
###### CONFIGURATION ######
+
###### CONFIGURATION ######
DEST_DIR=/tftpboot/local/bin
+
DEST_DIR=/tftpboot/local/bin
ARMADEUS_BASE_DIR=../
+
ARMADEUS_BASE_DIR=../
include $(ARMADEUS_BASE_DIR)/Makefile.in
+
include $(ARMADEUS_BASE_DIR)/Makefile.in
  
XENO=$(ARMADEUS_ROOTFS_DIR)/usr/xenomai
+
XENO=$(ARMADEUS_ROOTFS_DIR)/usr/xenomai
  
CC= arm-linux-gcc
+
CC:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-gcc
LD= arm-linux-ld
+
LD:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-ld
CXX= arm-linux-g++
+
CXX:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-g++
AS= arm-linux-as
+
AS:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-as
NM= arm-linux-nm
+
NM:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-nm
AR= arm-linux-ar
+
AR:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-ar
SIZE= arm-linux-size
+
SIZE:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-size
OBJCOPY= arm-linux-objcopy
+
OBJCOPY:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-objcopy
  
EXEC=blink_led_xeno_userspace
+
EXEC=blink_led_xeno_userspace
  
SRC= $(wildcard *.c)
+
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
+
OBJ= $(SRC:.c=.o)
EXEC= $(APPLICATIONS)
+
CFLAGS=-g -W -Wall -I$(XENO)/include -I$(XENO)/include/native  -I$(XENO)/include/rtdm -D_GNU_SOURCE -D_REENTRANT
CFLAGS=-g -W -Wall -I$(XENO)/include -I$(XENO)/include/native  -I$(XENO)/include/rtdm -D_GNU_SOURCE -D_REENTRANT
+
LDFLAGS=-L$(XENO)/lib -Xlinker -rpath $(XENO)/lib -Xlinker $(XENO)/lib/libnative.a $(XENO)/lib/librtdm.a -lpthread -lnative -lrtdm
LDFLAGS=-L$(XENO)/lib -Xlinker -rpath $(XENO)/lib -Xlinker $(XENO)/lib/libnative.a $(XENO)/lib/librtdm.a -     lpthread -lnative -lrtdm
+
 
$(EXEC) : $(OBJ)
+
$(EXEC): $(OBJ)
 
$(CC) -o $@ $^ $(LDFLAGS)
 
$(CC) -o $@ $^ $(LDFLAGS)
$(OBJ): $(SRC)
+
 
 +
$(OBJ): $(SRC)
 
$(CC) $(CFLAGS) -o $@ -c $<
 
$(CC) $(CFLAGS) -o $@ -c $<
  
.PHONY: all
+
all: $(EXEC)
all: $(EXEC)
+
 
.PHONY: clean
+
clean:
clean:
+
 
rm -rf $(OBJ)
 
rm -rf $(OBJ)
 
rm -rf $(EXEC)
 
rm -rf $(EXEC)
 
rm -f *.c~ *.h~ Makefile~
 
rm -f *.c~ *.h~ Makefile~
.PHONY: install
 
install: $(EXEC)
 
        mkdir $(DEST_DIR)/$(EXEC)
 
        echo "$(EXEC):native:!./$(EXEC);popall:control_c" > /$(DEST_DIR)/$(EXEC)/.runinfo
 
cp $(EXEC) $(DEST_DIR)/$(EXEC)
 
  
.PHONY: mrproper
+
install: $(EXEC)
mrproper: clean
+
@mkdir -p $(DEST_DIR)/$(EXEC)
 +
echo "$(EXEC):native:!./$(EXEC);popall:control_c" > $(DEST_DIR)/$(EXEC)/.runinfo
 +
cp -f $(EXEC) $(DEST_DIR)/$(EXEC)
 +
 
 +
mrproper: clean
 
rm -rf $(DEST_DIR)/$(EXEC)
 
rm -rf $(DEST_DIR)/$(EXEC)
 +
 +
.PHONY: all install clean mrproper
 
</source>
 
</source>
'' ''ARMADEUS_BASE_DIR'' has needed to be adapted to the correct path on where is installed the Armadeus buildroot.''<br>
+
 
'' DEST_DIR assume you used an nfs mount on tftpboot/local for /usr/local on the board.''
+
*''ARMADEUS_BASE_DIR'': needs to be adapted to the correct path where the Armadeus SDK is installed, relatively to your example dir or as an absolute path.
 +
*''DEST_DIR'': directory where the executables will be installed when doing ''make install''. Here it assumes you used an [[NFS]] exported dir ''/tftpboot/local'', mount as ''/usr/local'' on the board.
  
 
== Compilation, installation and run ==
 
== Compilation, installation and run ==
For to have the application installed on your board, you need to type :
+
<pre class="host">
$ make install
+
$ make -C xeno_led
 +
</pre>
 +
* If you setup the NFS as indicated above, you can install the application on your board with:
 +
<pre class="host">
 +
$ make install -C xeno_led
 +
</pre>
 +
* Otherwise you can install the executable to your board (through TFTP for example):
 +
<pre class="host">
 +
$ make install -C xeno_led/ DEST_DIR=/tftpboot
 +
</pre>
 +
<pre class="apf">
 +
# mkdir -p /usr/local/bin/blink_led_xeno_userspace
 +
# tftp -g -r blink_led_xeno_userspace/blink_led_xeno_userspace -l /usr/local/bin/blink_led_xeno_userspace/blink_led_xeno_userspace 192.168.1.2
 +
# tftp -g -r blink_led_xeno_userspace/.runinfo -l /usr/local/bin/blink_led_xeno_userspace/.runinfo 192.168.1.2
 +
# chmod a+x /usr/local/bin/blink_led_xeno_userspace/blink_led_xeno_userspace
 +
</pre>
 +
 
 
=== Running ===
 
=== Running ===
On your board, you must you placed on ''/usr/local/bin'' and type :
+
* GPIO driver should be loaded:
$ xeno-load blink_led_xeno_userspace
+
<pre class="apf">
 +
# loadgpio.sh
 +
</pre>
 +
* And you should be able to blink the LED from command line following [[GPIO_Driver#Examples|these instructions]]
 +
* Then, you must change directory to ''/usr/local/bin'' and type :
 +
<pre class="apf">
 +
# xeno-load blink_led_xeno_userspace
 +
</pre>
 +
 
 
== Links ==
 
== Links ==
* [[Xenomai | Xenomai install instructions]]
+
* [[Xenomai | Xenomai installation instructions]]
* [[Xenomai:examples usage | examples usage]]
+
* [[Xenomai:examples usage | Using Armadeus Xenomai custom examples]]
 
* [http://www.xenomai.org/documentation/branches/v2.4.x/html/api/ Xenomai API page ]
 
* [http://www.xenomai.org/documentation/branches/v2.4.x/html/api/ Xenomai API page ]
  
 
[[Category:Software]]
 
[[Category:Software]]
 
[[Category:Real-Time]]
 
[[Category:Real-Time]]

Latest revision as of 15:47, 15 February 2010

This tutorial explains how to create a simple Xenomai application. This application will blink the APF9328DevFull user LED (connected to pin 31 of i.MXL portD; on the APF27 you would use pin 14 of portF).

Application code

$ mkdir xeno_led
$ vim xeno_led/blink.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/mman.h>

#include <native/task.h>
#include <native/timer.h>

#define TIMESLEEP 1000000000 /* 1 sec */
#define LED "/dev/gpio/PD31" /* APF9328 */
#define LED "/dev/gpio/PF14" /* APF27 */

RT_TASK blink_task;
int fd;

void blink(void *arg __attribute__((__unused__)))
{
    int iomask = 0x00;
  
    rt_task_set_periodic(NULL, TM_NOW, TIMESLEEP);
  
    while(1) {
        rt_task_wait_period(NULL);
        write(fd,&iomask,sizeof(iomask));
        iomask ^= 1;
    }
}

void catch_signal() {}

int main(void)
{  
    signal(SIGTERM, catch_signal);
    signal(SIGINT, catch_signal);
  
    /* Avoids memory swapping for this program */
    mlockall(MCL_CURRENT|MCL_FUTURE);

    /* led device opening */
    if ((fd = open(LED, O_WRONLY)) < 0) {
        printf("Open error on %s\n",LED);
        exit(0);
    }
    /* Task Creation */
    rt_task_create(&blink_task, "blinkLed", 0, 99, 0);  
    rt_task_start(&blink_task, &blink, NULL);
    getchar();
    rt_task_delete(&blink_task);
    close(fd);

    return 0;
}

This source looks very like a classical Linux application with threads and nanosleep() function.
The only differences are on the task creation using Xenomai API:

  • Create a new task with stksize stack size, prio level of priority and mode type of creation:
 int rt_task_create(RT_TASK * task, const char * name, int stksize, int prio, int mode)
  • Launch the new task with entry function and cookie parameters:
 int rt_task_start (RT_TASK *task, void(*entry)(void *cookie), void *cookie)
  • set for the task periodic, idate time for the first release (time in nanoseconds)
 int rt_task_set_periodic (RT_TASK *task, RTIME idate, RTIME period)
  • To block the task during the previously set period:
 int rt_task_wait_period (unsigned long *overruns_r)

Makefile

The second step is to create a Makefile with specific Xenomai includes.

$ vim xeno_led/Makefile
###### CONFIGURATION ######
DEST_DIR=/tftpboot/local/bin
ARMADEUS_BASE_DIR=../
include $(ARMADEUS_BASE_DIR)/Makefile.in

XENO=$(ARMADEUS_ROOTFS_DIR)/usr/xenomai

CC:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-gcc
LD:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-ld
CXX:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-g++
AS:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-as
NM:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-nm
AR:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-ar
SIZE:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-size
OBJCOPY:=$(ARMADEUS_TOOLCHAIN_PATH)/arm-linux-objcopy

EXEC=blink_led_xeno_userspace

SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)
CFLAGS=-g -W -Wall -I$(XENO)/include -I$(XENO)/include/native  -I$(XENO)/include/rtdm -D_GNU_SOURCE -D_REENTRANT
LDFLAGS=-L$(XENO)/lib -Xlinker -rpath $(XENO)/lib -Xlinker $(XENO)/lib/libnative.a $(XENO)/lib/librtdm.a -lpthread -lnative -lrtdm

$(EXEC): $(OBJ)
	$(CC) -o $@ $^ $(LDFLAGS)

$(OBJ): $(SRC)
	$(CC) $(CFLAGS) -o $@ -c $<

all: $(EXEC)

clean:
	rm -rf $(OBJ)
	rm -rf $(EXEC)
	rm -f *.c~ *.h~ Makefile~

install: $(EXEC)
	@mkdir -p $(DEST_DIR)/$(EXEC)
	echo "$(EXEC):native:!./$(EXEC);popall:control_c" > $(DEST_DIR)/$(EXEC)/.runinfo
	cp -f $(EXEC) $(DEST_DIR)/$(EXEC)

mrproper: clean
	rm -rf $(DEST_DIR)/$(EXEC)

.PHONY: all install clean mrproper
  • ARMADEUS_BASE_DIR: needs to be adapted to the correct path where the Armadeus SDK is installed, relatively to your example dir or as an absolute path.
  • DEST_DIR: directory where the executables will be installed when doing make install. Here it assumes you used an NFS exported dir /tftpboot/local, mount as /usr/local on the board.

Compilation, installation and run

$ make -C xeno_led
  • If you setup the NFS as indicated above, you can install the application on your board with:
$ make install -C xeno_led
  • Otherwise you can install the executable to your board (through TFTP for example):
$ make install -C xeno_led/ DEST_DIR=/tftpboot
# mkdir -p /usr/local/bin/blink_led_xeno_userspace
# tftp -g -r blink_led_xeno_userspace/blink_led_xeno_userspace -l /usr/local/bin/blink_led_xeno_userspace/blink_led_xeno_userspace 192.168.1.2
# tftp -g -r blink_led_xeno_userspace/.runinfo -l /usr/local/bin/blink_led_xeno_userspace/.runinfo 192.168.1.2
# chmod a+x /usr/local/bin/blink_led_xeno_userspace/blink_led_xeno_userspace

Running

  • GPIO driver should be loaded:
# loadgpio.sh
  • And you should be able to blink the LED from command line following these instructions
  • Then, you must change directory to /usr/local/bin and type :
# xeno-load blink_led_xeno_userspace

Links