Root/bbl/bbl.c

1/*
2 * bbl.c - Produce a "Knight Rider" effect on the LED board
3 *
4 * Written 2010-2011 by Werner Almesberger <werner@openmoko.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12
13#include <unistd.h>
14#include <stdint.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <signal.h>
18#include <fcntl.h>
19#include <sys/mman.h>
20
21
22#define GPIO_BASE 0x10010000
23
24#define REG(n) (*(volatile uint32_t *) (mem+(n)-GPIO_BASE))
25
26/*
27 * The XBurst CPUs use an interesting concept for setting GPIOs: instead of
28 * writing the value of a pin (0 or 1) directly to an output latch, the latch
29 * is set by writing a 1 to a "set" register and cleared by writing a 1 to a
30 * "clear" register. This way, only an atomic store but no atomic
31 * read-modify-write operations are necessary for changing only part of the
32 * bits on a port.
33 *
34 * The same set/clear mechanism is also used for the other writable registers
35 * affecting GPIOs, e.g., the direction (input/output) and function (GPIO or
36 * MMC) registers.
37 */
38
39#define PDDATS REG(0x10010314) /* port D data set */
40#define PDDATC REG(0x10010318) /* port D data clear */
41#define PDFUNC REG(0x10010348) /* port D function clear */
42#define PDDIRS REG(0x10010364) /* port D direction set */
43#define PDDIRC REG(0x10010368) /* port D direction clear */
44
45#define LEDS 10 /* number of LEDs */
46
47#define GROUP_SEL 11 /* PD11, DAT1 - LED group selection */
48
49#define LED_MASK 0x3f00 /* all the LED groups and GROUP_SEL */
50
51#define DELAY_US 50000
52
53#define PAGE_SIZE 4096
54
55static volatile void *mem;
56
57
58static int map(int group)
59{
60    switch (group) {
61    case 0:
62        return 12; /* PD12, DAT2 */
63    case 1:
64        return 13; /* PD13, DAT3/CD */
65    case 2:
66        return 8; /* PD08, CMD */
67    case 3:
68        return 9; /* PD09, CLK */
69    case 4:
70        return 10; /* PD10, DAT0 */
71    default:
72        abort();
73    }
74}
75
76
77static void set(int n)
78{
79    
80    if (n & 1) {
81        PDDATC = LED_MASK;
82        PDDATS = 1 << map(n >> 1);
83    } else {
84        PDDATS = LED_MASK;
85        PDDATC = 1 << map(n >> 1);
86    }
87}
88
89
90static void die(int sig)
91{
92    PDDIRC = LED_MASK; /* make all MMC pins inputs again */
93    _exit(0);
94}
95
96
97int main(int argc, char **argv)
98{
99    int fd, i;
100
101    fd = open("/dev/mem", O_RDWR | O_SYNC);
102        if (fd < 0) {
103        perror("/dev/mem");
104        exit(1);
105    }
106    mem = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
107        GPIO_BASE);
108    if (mem == MAP_FAILED) {
109        perror("mmap");
110        exit(1);
111    }
112
113    signal(SIGINT, die);
114
115    PDFUNC = LED_MASK; /* make all MMC pins GPIOs */
116    PDDIRS = LED_MASK; /* make all MMC pins outputs */
117
118    while (1) {
119        for (i = 0; i != LEDS-1; i++) {
120            set(i);
121            usleep(DELAY_US);
122        }
123        for (i = LEDS-1; i != 0; i--) {
124            set(i);
125            usleep(DELAY_US);
126        }
127    }
128    return 0;
129}
130

Archive Download this file

Branches:
master



interactive