added pin number commandline argument
[rpipulser] / pulser.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <assert.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/mman.h>
8
9 #define IOBASEADDR              0x3f000000
10 #define IOSIZE                  16777216
11
12 #define IOREGADDR(x)    ((x) | IOBASEADDR)
13
14 #define REG_GPFSEL0             *((volatile uint32_t*)IOREGADDR(0x200000))
15 #define REG_GPFSEL1             *((volatile uint32_t*)IOREGADDR(0x200004))
16 #define REG_GPFSEL2             *((volatile uint32_t*)IOREGADDR(0x200008))
17 #define REG_GPSET0              *((volatile uint32_t*)IOREGADDR(0x20001c))
18 #define REG_GPSET1              *((volatile uint32_t*)IOREGADDR(0x200020))
19 #define REG_GPCLR0              *((volatile uint32_t*)IOREGADDR(0x200028))
20 #define REG_GPCLR1              *((volatile uint32_t*)IOREGADDR(0x20002c))
21
22 #define FSEL_OUT(x)             (1 << (((x) % 10) * 3))
23
24 void print_usage(const char *argv0);
25
26 int npulses = 1;
27 int freqhz = 1;
28 int duty = 128; /* duty cycle 0-255 */
29 int pin = 24;
30
31 int main(int argc, char **argv)
32 {
33         int i, fd;
34         void *ptr;
35         long ontime, offtime;
36
37         for(i=1; i<argc; i++) {
38                 if(argv[i][0] == '-') {
39                         if(argv[i][2] == 0) {
40                                 switch(argv[i][1]) {
41                                 case 'n':
42                                         if(!argv[++i] || (npulses = atoi(argv[i])) < 1) {
43                                                 fprintf(stderr, "-n must be followed by the number of pulses\n");
44                                                 return 1;
45                                         }
46                                         break;
47
48                                 case 'f':
49                                         if(!argv[++i] || (freqhz = atoi(argv[i])) < 1) {
50                                                 fprintf(stderr, "-f must be followed by the pulse frequency\n");
51                                                 return 1;
52                                         }
53                                         break;
54
55                                 case 'd':
56                                         if(!argv[++i] || (duty = atoi(argv[i])) < 1 || duty >= 256) {
57                                                 fprintf(stderr, "-d must be followed by the duty cycle: 1-255\n");
58                                                 return 1;
59                                         }
60                                         break;
61
62                                 case 'p':
63                                         if(!argv[++i] || (pin = atoi(argv[i])) < 1 || pin >= 28) {
64                                                 fprintf(stderr, "-p must be followed by a BCM pin number: 1-27\n");
65                                                 return 1;
66                                         }
67                                         break;
68
69                                 case 'h':
70                                         print_usage(argv[0]);
71                                         return 0;
72
73                                 default:
74                                         fprintf(stderr, "invalid option: %s\n", argv[i]);
75                                         print_usage(argv[0]);
76                                         return 1;
77                                 }
78                         } else {
79                                 fprintf(stderr, "invalid option: %s\n", argv[i]);
80                                 print_usage(argv[0]);
81                                 return 1;
82                         }
83                 } else {
84                         fprintf(stderr, "unexpected argument: %s\n", argv[i]);
85                         print_usage(argv[0]);
86                         return 1;
87                 }
88         }
89
90
91         if((fd = open("/dev/mem", O_RDWR)) == -1) {
92                 perror("failed to open /dev/mem");
93                 return 1;
94         }
95         if((ptr = mmap((void*)IOBASEADDR, IOSIZE, PROT_READ | PROT_WRITE,
96                                         MAP_SHARED | MAP_FIXED, fd, IOBASEADDR)) == (void*)-1) {
97                 perror("failed to map IO space");
98                 return 1;
99         }
100         assert(ptr == (void*)IOBASEADDR);
101
102         ontime = duty * 1000000 / (freqhz * 256);
103         offtime = 1000000 / freqhz - ontime;
104
105         printf("%d pulses, %d hz, %d/256 duty cycle\n", npulses, freqhz, duty);
106         printf("timing: %ldus on, %ldus off\n", ontime, offtime);
107
108         REG_GPCLR0 = 1 << pin;
109         if(pin < 10) {
110                 REG_GPFSEL0 |= FSEL_OUT(pin);
111         } else if(pin < 20) {
112                 REG_GPFSEL1 |= FSEL_OUT(pin);
113         } else if(pin < 30) {
114                 REG_GPFSEL2 |= FSEL_OUT(pin);
115         }
116
117         for(i=0; i<npulses; i++) {
118                 REG_GPSET0 = 1 << pin;
119                 usleep(ontime);
120                 REG_GPCLR0 = 1 << pin;
121                 usleep(offtime);
122         }
123
124         REG_GPCLR0 = 1 << pin;
125
126         munmap(ptr, IOSIZE);
127         close(fd);
128         return 0;
129 }
130
131 void print_usage(const char *argv0)
132 {
133         printf("Usage: %s [options]\n", argv0);
134         printf("Options:\n");
135         printf(" -n: number of pulses to emit (default: 1)\n");
136         printf(" -f: frequency of pulses in hz (default: 1)\n");
137         printf(" -d: duty cycle [1, 255] (default: 128)\n");
138         printf(" -p: BCM pin number [1, 27] (default: 24)\n");
139         printf(" -h: print usage and exit\n");
140 }