/* * bbl.c - Produce a "Knight Rider" effect on the LED board * * Written 2010-2011 by Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #define GPIO_BASE 0x10010000 #define REG(n) (*(volatile uint32_t *) (mem+(n)-GPIO_BASE)) /* * The XBurst CPUs use an interesting concept for setting GPIOs: instead of * writing the value of a pin (0 or 1) directly to an output latch, the latch * is set by writing a 1 to a "set" register and cleared by writing a 1 to a * "clear" register. This way, only an atomic store but no atomic * read-modify-write operations are necessary for changing only part of the * bits on a port. * * The same set/clear mechanism is also used for the other writable registers * affecting GPIOs, e.g., the direction (input/output) and function (GPIO or * MMC) registers. */ #define PDDATS REG(0x10010314) /* port D data set */ #define PDDATC REG(0x10010318) /* port D data clear */ #define PDFUNC REG(0x10010348) /* port D function clear */ #define PDDIRS REG(0x10010364) /* port D direction set */ #define PDDIRC REG(0x10010368) /* port D direction clear */ #define LEDS 10 /* number of LEDs */ #define GROUP_SEL 11 /* PD11, DAT1 - LED group selection */ #define LED_MASK 0x3f00 /* all the LED groups and GROUP_SEL */ #define DELAY_US 50000 #define PAGE_SIZE 4096 static volatile void *mem; static int map(int group) { switch (group) { case 0: return 12; /* PD12, DAT2 */ case 1: return 13; /* PD13, DAT3/CD */ case 2: return 8; /* PD08, CMD */ case 3: return 9; /* PD09, CLK */ case 4: return 10; /* PD10, DAT0 */ default: abort(); } } static void set(int n) { if (n & 1) { PDDATC = LED_MASK; PDDATS = 1 << map(n >> 1); } else { PDDATS = LED_MASK; PDDATC = 1 << map(n >> 1); } } static void die(int sig) { PDDIRC = LED_MASK; /* make all MMC pins inputs again */ _exit(0); } int main(int argc, char **argv) { int fd, i; fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd < 0) { perror("/dev/mem"); exit(1); } mem = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO_BASE); if (mem == MAP_FAILED) { perror("mmap"); exit(1); } signal(SIGINT, die); PDFUNC = LED_MASK; /* make all MMC pins GPIOs */ PDDIRS = LED_MASK; /* make all MMC pins outputs */ while (1) { for (i = 0; i != LEDS-1; i++) { set(i); usleep(DELAY_US); } for (i = LEDS-1; i != 0; i--) { set(i); usleep(DELAY_US); } } return 0; }