Xenomai:Blinking LEDs: Difference between revisions
From ArmadeusWiki
(→Links) |
|||
| (19 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
This tutorial | 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; | |||
rt_task_set_periodic(NULL, TM_NOW, TIMESLEEP); | |||
while(1) { | |||
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 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; | |||
} | } | ||
</source> | </source> | ||
This source | |||
The only differences are on the task creation using API | 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) | ||
</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) | ||
</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) | ||
<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) | ||
</source> | |||
== Makefile == | == Makefile == | ||
The second step is to create a Makefile with specific Xenomai includes.< | 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 ###### | |||
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) | $(CC) -o $@ $^ $(LDFLAGS) | ||
$(OBJ): $(SRC) | |||
$(CC) $(CFLAGS) -o $@ -c $< | $(CC) $(CFLAGS) -o $@ -c $< | ||
all: $(EXEC) | |||
clean: | |||
rm -rf $(OBJ) | rm -rf $(OBJ) | ||
rm -rf $(EXEC) | rm -rf $(EXEC) | ||
rm -f *.c~ *.h~ Makefile~ | 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) | rm -rf $(DEST_DIR)/$(EXEC) | ||
.PHONY: all install clean mrproper | |||
</source> | </source> | ||
'' | *''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 == | ||
<pre class="host"> | |||
$ 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 === | ||
* GPIO driver should be loaded: | |||
<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 | * [[Xenomai | Xenomai installation instructions]] | ||
* [[Xenomai:examples usage | examples | * [[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