Xenomai:Blinking LEDs
From ArmadeusWiki
This tutorial explains how to create a simple Xenomai application. This application will blink the DevFull LED.
Contents |
Application code
#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 #define LED "/dev/gpio/PD31" RT_TASK blink_task; int fd; void blink(void *arg){ 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(int argc, char **argv) { 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.
###### CONFIGURATION ###### DEST_DIR=/tftpboot/local/bin ARMADEUS_BASE_DIR=../ include $(ARMADEUS_BASE_DIR)/Makefile.in XENO=$(ARMADEUS_ROOTFS_DIR)/usr/xenomai CC= arm-linux-gcc LD= arm-linux-ld CXX= arm-linux-g++ AS= arm-linux-as NM= arm-linux-nm AR= arm-linux-ar SIZE= arm-linux-size OBJCOPY= arm-linux-objcopy EXEC=blink_led_xeno_userspace SRC= $(wildcard *.c) 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 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 $< .PHONY: all all: $(EXEC) .PHONY: clean clean: rm -rf $(OBJ) rm -rf $(EXEC) 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 mrproper: clean rm -rf $(DEST_DIR)/$(EXEC)
ARMADEUS_BASE_DIR needs to be adapted to the correct path where the Armadeus buildroot is installed.
DEST_DIR assumes you used an NFS mount on /tftpboot/local as /usr/local on the board.
Compilation, installation and run
$ make
If you setup the NFS as indicated above, you can install the application on your board with :
$ make install
Otherwise you can manually copy blink_led_xeno_userspace exe to your board (/usr/local/bin/).
Running
On your APF, you must change directory to /usr/local/bin and type :
# xeno-load blink_led_xeno_userspace