Am Donnerstag, 14. Dezember 2006 14:14 schrieb Jan Kiszka: > Niklaus Giger wrote: > > Hi > > > > To document basic Xenomai/Linux patterns I developed the attached small > > example for our PPC405 board, which just rolls the 8 debug LEDs. > > > > Are there any comments about it? > > I like the idea of having useful generic code patterns like this in the > examples repos. But I also have a few wishes regarding this particular one: > > * I would prefer that generic patterns are coded against POSIX or maybe > Native, not against a special RTOS skin (not everyone know the > VxWorks API by heart ;) ). > > * Try to make use of as less additional patterns beyond the core aspect > as possible. E.g., running the lights in main would avoid quite some > code for init/cleanup. This helps the reader to grab the essence of > the demo. Still, the demo should remain functional! I used the Linux "sleep" function and could eliminate all RT specifics and it still runs, albeit five times slower on my target. > * Please format your code according to kernel style (could be any > style, but we need a standard, so pick that one) Tried, using Documentation/CodingStyle from the kernel. Hope I didn't miss to many thinks > > Shall I put it into the Wiki at http://www.xenomai.org/index.php/Examples > > or does somebody want to commit it to the examples part of the subversion > > trunk? > > I would happily merge a cleaned up version into the repos, e.g. under > the related skin. I hope the attached version satisfy you now. Also added some suggestions made by Stephan Fillod.
> PS: If you want to contribute VxWorks-specific code pattern, you are > welcome as well! Will come to this a little bit later, as I making good progress to port our existing vxWorks application over to Xenomai. In any case, there is ksrc/skins/vxworks/demos/satch.c and the the simulator testsuite under sim/skins/vxworks/testsuite/. But if you open for each skin a directory (what could be a good idea) one could add a README pointing to it. Best regards -- Niklaus Giger
/* * This small examples shows how to access memory directly. * * Copyright (c) 2006 Niklaus Giger <niklaus.giger at member.fsf.org> * * It will only work on PPC405GPr based custom HW board of Nestal Maschinen AG * * It should, however, be easily adapted to similar HW * It will scroll across 8 LEDs (interval 1/2 of second), which are mapped * to some bit of the GPIO of the PPC405GPr processor. * To sleep it uses the Linux sleep a second, so do not expect a real time behaviour. * Compile it with at least -O to expand the inline assembler code. * * You may find another example at http://www.denx.de/wiki/bin/view/\ * PPCEmbedded/DeviceDrivers#Section_AccessingPeripheralsFromUserSpace * Wherefrom we stole the out_32 and iounmap procedures. * * Fillod Stephane recommends: * "Personally, I always access hardware registers through in_[lbe]{8,16,32} * "out_[lbe]{8,16,32} macros, so the code is portable across machines of * "different endianess, and thanks to the integrated memory barriers, * "I known exactly when the CPU will actually perform the I/O with respect * "to the other C instructions." * These macros are defined e.g. asm-ppc/io.h, but only available to the kernel * */ #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <unistd.h> void *mapDirectIoRegister(unsigned long addr, size_t length); int iounmap(volatile void *start, size_t length); void sysLedSet(unsigned char value); #define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) #define HCU3_LED_REGISTER 0xEF600700 volatile unsigned long *ledRegister; #ifdef __PPC__ extern inline void out_32(volatile unsigned long *addr, unsigned val) { __asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val)); } /* etc., cf asm/io.h */ #else extern inline void out_32(volatile unsigned long *addr, unsigned val) { * which shows you how to use PPC assembler code to ensure correct IO ordering. *addr = val & 0xff; } #endif void *mapDirectIoRegister(unsigned long addr, size_t length) { void *map_base, * virtAddr; off_t target = ((unsigned int) addr) & ~MAP_MASK; int fd; if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) { printf("/dev/mem could not be opened.\n"); exit(1); } // Map one page map_base = mmap((void *)target, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target); if(map_base == (void *) -1) { printf("Memory map failed for address 0x%lx\n", addr); return map_base; } virtAddr = (void *) ((unsigned long)map_base + ( (unsigned long)addr & MAP_MASK)); printf("Memory map 0x%lx -> %p offset 0x%lx virtual %p\n", addr, map_base, addr & MAP_MASK, virtAddr); return virtAddr; } int iounmap(volatile void *start, size_t length) { unsigned long ofs_addr; ofs_addr = (unsigned long)start & (getpagesize()-1); /* do some cleanup when you're done with it */ return munmap((void*)start-ofs_addr, length+ofs_addr); } void sysLedSet(unsigned char value) { /* For obscure HW reasons, we have to negated it and shift the value 23 bits to the left */ *ledRegister = (( unsigned long ) ~value << 23) ; out_32(ledRegister, ( unsigned long ) ~value << 23); } int main (int argc, char *argv[]) { unsigned char j; printf("%s: %s %s\n", __FUNCTION__, __DATE__, __TIME__ ); /* HW initialisation */ ledRegister = (unsigned long *)mapDirectIoRegister(HCU3_LED_REGISTER, MAP_SIZE); /* next we set the correct control mask in the GPIO_TCR */ ledRegister[1] = 0x7ffe0000; /* Three State Control */ /* Now scroll our leds and pause a little bit between */ for (j=0; j <= 8; j++) { sleep(1); printf("."); fflush(stdout); sysLedSet(1 << j); } iounmap((volatile void *)HCU3_LED_REGISTER, MAP_SIZE); printf("\n%s:done\n", __FUNCTION__); return 0; }
_______________________________________________ Xenomai-help mailing list [email protected] https://mail.gna.org/listinfo/xenomai-help
