pihwm
A lightweight C library for Raspberry Pi hardware modules.
 All Data Structures Files Functions Groups Pages
pi_pwm.c
Go to the documentation of this file.
1 
28 /* Based on Gert Jan van Loo's example code. */
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <dirent.h>
34 #include <fcntl.h>
35 #include <assert.h>
36 #include <sys/mman.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 #include <unistd.h>
41 
42 #include "pihwm.h"
43 #include "pi_pwm.h"
44 
45 // Registers
46 // TODO: These are already defined in .h, remove?
47 volatile unsigned int *gpio, *pwm, *clk;
48 
59 static int
60 open_memory ()
61 {
62  int mem_fd;
63 
64  mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
65 
66  if ( mem_fd < 0 )
67  {
68  debug("[%s] Can't open /dev/mem. Are you root?\n", __func__);
69  return -1;
70  } else {
71  return mem_fd;
72  }
73 
74 }
75 
84 static volatile unsigned int*
85 map_register (int mem_fd, unsigned int addr)
86 {
87  char *mem;
88  unsigned char *map;
89 
90  // Allocate a chunk of memory
91  if ( (mem = malloc(BLOCK_SIZE + (PAGE_SIZE - 1))) == NULL )
92  {
93  debug("[%s] Can't allocate memory.\n", __func__);
94  return 0;
95  }
96 
97  // Align?
98  if ( (unsigned long) mem % PAGE_SIZE )
99  {
100  mem += PAGE_SIZE - ((unsigned long) mem % PAGE_SIZE);
101  }
102 
103  // Map relevant register address to the allocated memory pointer
104  map = (unsigned char *) mmap ((caddr_t) mem,
105  BLOCK_SIZE, PROT_READ | PROT_WRITE,
106  MAP_SHARED | MAP_FIXED, mem_fd, addr);
107 
108  if ( (long) map < 0 )
109  {
110  debug("[%s] Can't mmap memory.\n", __func__);
111  return 0;
112  } else {
113  return (volatile unsigned int*) map;
114  }
115 
116 }
117 
123 int
125 {
126 
127  int mem_fd;
128 
129  mem_fd = open_memory();
130  if ( mem_fd < 0)
131  {
132  debug("[%s] Can't open /dev/mem.\n", __func__);
133  return -1;
134  }
135 
136  // FIXME: Check return values?
137  gpio = map_register(mem_fd, GPIO_BASE);
138  clk = map_register(mem_fd, CLOCK_BASE);
139  pwm = map_register(mem_fd, PWM_BASE);
140 
141  /* GPIO18= PWM channel-A Funct. 5
142  Setup GPIO18 as PWM output */
143  INP_GPIO(18);
144  SET_GPIO_ALT(18, 5);
145 
146  /* Derive PWM clock direct from X-tal
147  thus any system auto-slow-down-clock-to-save-power does not effect it
148  The values below depends on the X-tal frequency! */
149  PWMCLK_DIV = 0x5A000000 | (32 << 12);/* set pwm div to 32 (19.2/3 = 600KHz) */
150  PWMCLK_CNTL = 0x5A000011; /* Source=osc and enable */
151 
152  /* Make sure it is off and that the B driver (GPIO4) is low */
153  GPIO_CLR0 = 1 << 4; /* Set GPIO 4 LOW */
154 
155  PWM_CONTROL = 0;
156  usleep(100);
157 
158  /* I use 1024 steps for the PWM
159  (Just a nice value which I happen to like) */
160  PWM0_RANGE = PWM_MAX;
161  usleep(100);
162 
163  PWM_CONTROL = PWM0_ENABLE;
164  usleep(100);
165 
166  return 1;
167 
168 }
169 
177 void
178 pwm_mode (unsigned int mode)
179 {
180  PWM_CONTROL = mode;
181 }
182 
183 
191 void
192 pwm_value (unsigned int value)
193 {
194 
195  if ( value < 0 )
196  {
197  value = 0;
198  }
199 
200  if ( value > PWM_MAX )
201  {
202  value = PWM_MAX;
203  }
204 
205  PWM0_DATA = value;
206 }
207 
208 
214 void
216 {
217 
218  GPIO_CLR0 = 1 << 4;
219  pwm_value(0);
220  PWM_CONTROL = 0;
221 
222  // FIXME: Check this.
223  //munmap(pwm, BLOCK_SIZE);
224  //munmap(gpio, BLOCK_SIZE);
225  //munmap(clk, BLOCK_SIZE);
226 }
227