Raspberry Pi GPIO Library  0.3
Library allowing for control of the Raspberry Pi's GPIO pins.
gpio.c
Go to the documentation of this file.
1 
28 #include "gpio.h"
29 
30 /* Local / internal prototypes */
31 static errStatus gpioValidatePin(int gpioNumber);
32 
33 /**** Globals ****/
35 static volatile uint32_t * gGpioMap = NULL;
36 
38 static tPcbRev pcbRev = pcbRevError;
39 
45 {
46  int mem_fd = 0;
47  errStatus rtn = ERROR_DEFAULT;
48 
49  if ((mem_fd = open("/dev/mem", O_RDWR)) < 0)
50  {
51  dbgPrint(DBG_INFO, "open() failed. /dev/mem. errno %s.", strerror(errno));
52  rtn = ERROR_EXTERNAL;
53  }
54 
55  else if ((gGpioMap = (volatile uint32_t *)mmap(NULL,
57  PROT_READ|PROT_WRITE,
58  MAP_SHARED,
59  mem_fd,
60  GPIO_BASE)) == MAP_FAILED)
61  {
62  dbgPrint(DBG_INFO, "mmap() failed. errno: %s.", strerror(errno));
63  rtn = ERROR_EXTERNAL;
64  }
65 
66  /* Close the fd, we have now mapped it */
67  else if (close(mem_fd) != OK)
68  {
69  dbgPrint(DBG_INFO, "close() failed. errno: %s.", strerror(errno));
70  rtn = ERROR_EXTERNAL;
71  }
72 
73  else
74  {
75  FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
76  if (cpuinfo)
77  {
78  char* line = NULL;
79  ssize_t linelen;
80  size_t foo;
81 
82  while (((linelen = getline(&line, &foo, cpuinfo)) >= 0))
83  {
84  if (strstr(line, "Revision") == line)
85  {
86  char* rev = strstr(line, ":");
87  if (rev)
88  {
89  long revision = strtol(rev + 1, NULL, 16);
90 
91  if (revision <= 3)
92  {
93  pcbRev = pcbRev1;
94  }
95 
96  else
97  {
98  pcbRev = pcbRev2;
99  }
100  }
101  }
102  } /* while */
103  if (pcbRev != pcbRevError)
104  {
105  rtn = OK;
106  }
107  else
108  {
109  dbgPrint(DBG_INFO, "did not find revision in cpuinfo.");
110  rtn = ERROR_EXTERNAL;
111  }
112 
113  if (line)
114  {
115  free(line);
116  }
117  fclose(cpuinfo);
118  }
119  else
120  {
121  dbgPrint(DBG_INFO, "can't open /proc/cpuinfo. errno: %s.", strerror(errno));
122  rtn = ERROR_EXTERNAL;
123  }
124  }
125 
126  return rtn;
127 }
128 
129 
135 {
136  errStatus rtn = ERROR_DEFAULT;
137 
138  if (gGpioMap == NULL)
139  {
140  dbgPrint(DBG_INFO, "gGpioMap was NULL. Ensure gpioSetup() was called successfully.");
141  rtn = ERROR_NULL;
142  }
143 
144  else if (munmap((void *)gGpioMap, GPIO_MAP_SIZE) != OK)
145  {
146  dbgPrint(DBG_INFO, "mummap() failed. errno %s.", strerror(errno));
147  rtn = ERROR_EXTERNAL;
148  }
149 
150  else
151  {
152  gGpioMap = NULL;
153  rtn = OK;
154  }
155  return rtn;
156 }
157 
158 
164 errStatus gpioSetFunction(int gpioNumber, eFunction function)
165 {
166  errStatus rtn = ERROR_DEFAULT;
167 
168  if (gGpioMap == NULL)
169  {
170  dbgPrint(DBG_INFO, "gGpioMap was NULL. Ensure gpioSetup() called successfully.");
171  rtn = ERROR_NULL;
172  }
173 
174  else if (function < eFunctionMin || function > eFunctionMax)
175  {
176  dbgPrint(DBG_INFO, "eFunction was out of range. %d", function);
177  rtn = ERROR_RANGE;
178  }
179 
180  else if ((rtn = gpioValidatePin(gpioNumber)) != OK)
181  {
182  dbgPrint(DBG_INFO, "gpioValidatePin() failed. Ensure pin %d is valid.", gpioNumber);
183  }
184 
185  else
186  {
187  /* Clear what ever function bits currently exist - this puts the pin
188  * into input mode.*/
189  *(gGpioMap + (gpioNumber / 10)) &= ~(GPFSEL_BITS << ((gpioNumber % 10) * 3));
190 
191  /* Set the three pins for the pin to the desired value */
192  *(gGpioMap + (gpioNumber / 10)) |= (function << ((gpioNumber % 10) * 3));
193 
194  rtn = OK;
195  }
196 
197  return rtn;
198 }
199 
200 
208 errStatus gpioSetPin(int gpioNumber, eState state)
209 {
210  errStatus rtn = ERROR_DEFAULT;
211 
212  if (gGpioMap == NULL)
213  {
214  dbgPrint(DBG_INFO, "gGpioMap was NULL. Ensure gpioSetup() was called successfully.");
215  rtn = ERROR_NULL;
216  }
217 
218  else if ((rtn = gpioValidatePin(gpioNumber)) != OK)
219  {
220  dbgPrint(DBG_INFO, "gpioValidatePin() failed. Ensure pin %d is valid.", gpioNumber);
221  }
222 
223  else if (state == high)
224  {
225  /* The offsets are all in bytes. Divide by sizeof uint32_t to allow
226  * pointer addition. */
227  GPIO_GPSET0 = 0x1 << gpioNumber;
228  rtn = OK;
229  }
230 
231  else if (state == low)
232  {
233  /* The offsets are all in bytes. Divide by sizeof uint32_t to allow
234  * pointer addition. */
235  GPIO_GPCLR0 = 0x1 << gpioNumber;
236  rtn = OK;
237  }
238 
239  else
240  {
241  dbgPrint(DBG_INFO,"state %d should have been %d or %d", state, low, high);
242  rtn = ERROR_RANGE;
243  }
244 
245  return rtn;
246 }
247 
248 
255 errStatus gpioReadPin(int gpioNumber, eState * state)
256 {
257  errStatus rtn = ERROR_DEFAULT;
258 
259  if (gGpioMap == NULL)
260  {
261  dbgPrint(DBG_INFO, "gGpioMap was NULL. Ensure gpioSetup() was called successfully.");
262  rtn = ERROR_NULL;
263  }
264 
265  else if (state == NULL)
266  {
267  dbgPrint(DBG_INFO, "Parameter state was NULL.");
268  rtn = ERROR_NULL;
269  }
270 
271  else if ((rtn = gpioValidatePin(gpioNumber)) != OK)
272  {
273  dbgPrint(DBG_INFO, "gpioValidatePin() failed. Pin %d isn't valid.", gpioNumber);
274  }
275 
276  else
277  {
278  /* Check if the appropriate bit is high */
279  if (GPIO_GPLEV0 & (0x1 << gpioNumber))
280  {
281  *state = high;
282  }
283 
284  else
285  {
286  *state = low;
287  }
288 
289  rtn = OK;
290  }
291 
292  return rtn;
293 }
294 
302 errStatus gpioSetPullResistor(int gpioNumber, eResistor resistorOption)
303 {
304  errStatus rtn = ERROR_DEFAULT;
305  struct timespec sleepTime;
306 
307  if (gGpioMap == NULL)
308  {
309  dbgPrint(DBG_INFO, "gGpioMap was NULL. Ensure gpioSetup() was called successfully.");
310  rtn = ERROR_NULL;
311  }
312 
313  else if ((rtn = gpioValidatePin(gpioNumber)) != OK)
314  {
315  dbgPrint(DBG_INFO, "gpioValidatePin() failed. Pin %d isn't valid.", gpioNumber);
316  }
317 
318  else if (resistorOption < pullDisable || resistorOption > pullup)
319  {
320  dbgPrint(DBG_INFO, "resistorOption value: %d was out of range.", resistorOption);
321  rtn = ERROR_RANGE;
322  }
323 
324  else
325  {
326  sleepTime.tv_sec = 0;
327  sleepTime.tv_nsec = 1000 * RESISTOR_SLEEP_US;
328 
329  /* Set the GPPUD register with the desired resistor type */
330  GPIO_GPPUD = resistorOption;
331  /* Wait for control signal to be set up */
332  nanosleep(&sleepTime, NULL);
333  /* Clock the control signal for desired resistor */
334  GPIO_GPPUDCLK0 = (0x1 << gpioNumber);
335  /* Hold to set */
336  nanosleep(&sleepTime, NULL);
337  GPIO_GPPUD = 0;
338  GPIO_GPPUDCLK0 = 0;
339 
340  rtn = OK;
341  }
342 
343 
344  return rtn;
345 }
346 
356 errStatus gpioGetI2cPins(int * gpioNumberScl, int * gpioNumberSda)
357 {
358  errStatus rtn = ERROR_DEFAULT;
359 
360  if (gGpioMap == NULL)
361  {
362  dbgPrint(DBG_INFO, "gGpioMap was NULL. Ensure gpioSetup() was called successfully.");
363  rtn = ERROR_NULL;
364  }
365 
366  else if (gpioNumberScl == NULL)
367  {
368  dbgPrint(DBG_INFO, "Parameter gpioNumberScl is NULL.");
369  rtn = ERROR_NULL;
370  }
371 
372  else if (gpioNumberSda == NULL)
373  {
374  dbgPrint(DBG_INFO, "Parameter gpioNumberSda is NULL.");
375  rtn = ERROR_NULL;
376  }
377 
378  else if (pcbRev == pcbRev1)
379  {
380  *gpioNumberScl = REV1_SCL;
381  *gpioNumberSda = REV1_SDA;
382  rtn = OK;
383  }
384 
385  else if (pcbRev == pcbRev2)
386  {
387  *gpioNumberScl = REV2_SCL;
388  *gpioNumberSda = REV2_SDA;
389  rtn = OK;
390  }
391 
392  return rtn;
393 }
394 
395 
396 #undef ERROR
397 
399 #define ERROR(x) #x,
400 
405 const char * gpioErrToString(errStatus error)
406 {
407  static const char * errorString[] = { ERRORS };
408 
409  if (error < 0 || error >= ERROR_MAX)
410  {
411  return "InvalidError";
412  }
413 
414  else
415  {
416  return errorString[error];
417  }
418 }
419 
420 
439 int dbgPrint(FILE * stream, const char * file, int line, const char * format, ...)
440 {
441  va_list arguments;
442  int rtn = 0;
443  int tempRtn = 0;
444 
445  if (stream != NULL)
446  {
447  if ((tempRtn = fprintf(stream,"[%s:%d] ", file, line)) < 0)
448  {
449  return tempRtn;
450  }
451  rtn += tempRtn;
452 
453  va_start(arguments, format);
454  if ((tempRtn = vfprintf(stream, format, arguments)) < 0)
455  {
456  return tempRtn;
457  }
458  rtn += tempRtn;
459  va_end(arguments);
460 
461  if ((tempRtn = fprintf(stream,"\n")) < 0)
462  {
463  return tempRtn;
464  }
465  rtn += tempRtn;
466 
467  }
468  return rtn;
469 }
470 
471 /****************************** Internal Functions ******************************/
472 
480 static errStatus gpioValidatePin(int gpioNumber)
481 {
482  errStatus rtn = ERROR_INVALID_PIN_NUMBER;
483  int index = 0;
484  /* TODO REV1 and REV2 have the same pincount. REV2 technically has more if
485  * P5 is supported. If there is a REV3 the size of this array will need to
486  * be addressed. */
487  static uint32_t validPins[REV2_PINCNT] = {0};
488  static uint32_t pinCnt = 0;
489 
490  if (pinCnt == 0)
491  {
492  if (pcbRev == pcbRevError)
493  {
494  rtn = ERROR_RANGE;
495  }
496 
497  else if (pcbRev == pcbRev1)
498  {
499  const uint32_t validPinsForRev1[REV1_PINCNT] = REV1_PINS;
500  memcpy(validPins, validPinsForRev1, sizeof(validPinsForRev1));
501  pinCnt = REV1_PINCNT;
502  }
503  else if (pcbRev == pcbRev2)
504  {
505  const uint32_t validPinsForRev2[REV2_PINCNT] = REV2_PINS;
506  memcpy(validPins, validPinsForRev2, sizeof(validPinsForRev2));
507  pinCnt = REV2_PINCNT;
508  }
509  }
510 
511  for (index = 0; index < pinCnt; index++)
512  {
513  if (gpioNumber == validPins[index])
514  {
515  rtn = OK;
516  break;
517  }
518  }
519 
520  return rtn;
521 }
522 
523 
errStatus gpioReadPin(int gpioNumber, eState *state)
Reads the current state of a gpio pin.
Definition: gpio.c:255
#define REV1_PINCNT
Pin count on a PCB rev1 Raspberry Pi.
Definition: rpiGpio.h:124
errStatus gpioSetup(void)
Maps the memory used for GPIO access. This function must be called prior to any of the other GPIO cal...
Definition: gpio.c:44
errStatus gpioSetPin(int gpioNumber, eState state)
Sets a pin to high or low.
Definition: gpio.c:208
#define REV2_SCL
The BCM2835 pin number of SCL on rev2 Raspberry Pi.
Definition: rpiGpio.h:140
#define GPIO_MAP_SIZE
Definition: gpio.h:44
static errStatus gpioValidatePin(int gpioNumber)
Internal function which Validates that the pin gpioNumber is valid for the Raspberry Pi...
Definition: gpio.c:480
#define REV2_SDA
The BCM2835 pin number of SDA on rev2 Raspberry Pi.
Definition: rpiGpio.h:138
errStatus
The enum of possible errors returned from gpio functions. Errors themselves are defined in the macro ...
Definition: rpiGpio.h:63
Contains defines for gpio.c.
Definition: rpiGpio.h:70
eResistor
The enum for possible pull resistors.
Definition: rpiGpio.h:75
#define REV2_PINCNT
Pin count on a PCB rev2 Raspberry Pi.
Definition: rpiGpio.h:126
eState
The enum of possible pin states in input/output modes.
Definition: rpiGpio.h:69
#define RESISTOR_SLEEP_US
Definition: gpio.h:51
#define REV1_SDA
The BCM2835 pin number of SDA on rev1 Raspberry Pi.
Definition: rpiGpio.h:134
const char * gpioErrToString(errStatus error)
Debug function which converts an error from errStatus to a string.
Definition: gpio.c:405
Definition: rpiGpio.h:78
#define GPIO_GPLEV0
GPIO_GPLEV0 register.
Definition: gpio.h:58
#define GPIO_GPCLR0
GPIO_GPCLR0 register.
Definition: gpio.h:56
#define REV2_PINS
Definition: rpiGpio.h:131
tPcbRev
valid PCB revision values
Definition: rpiGpio.h:143
#define ERRORS
The list of errors which may be returned from gpio functions.
Definition: rpiGpio.h:35
#define GPIO_BASE
Definition: bcm2835_gpio.h:78
Definition: rpiGpio.h:71
static volatile uint32_t * gGpioMap
Pointer which will be mmap&#39;d to the GPIO memory in /dev/mem.
Definition: gpio.c:35
errStatus gpioCleanup(void)
Unmaps the memory used for the gpio pins. This function should be called when finished with the GPIO ...
Definition: gpio.c:134
errStatus gpioSetPullResistor(int gpioNumber, eResistor resistorOption)
Allows configuration of the internal resistor at a GPIO pin.
Definition: gpio.c:302
int dbgPrint(FILE *stream, const char *file, int line, const char *format,...)
Debug function wrapper for fprintf().
Definition: gpio.c:439
#define DBG_INFO
Macro which covers the first three arguments of dbgPrint.
Definition: rpiGpio.h:118
eFunction
The enum of pin functions available.
Definition: rpiGpio.h:85
#define GPIO_GPPUDCLK0
GPIO_GPPUDCLK0 register.
Definition: gpio.h:62
#define GPFSEL_BITS
Definition: bcm2835_gpio.h:129
#define REV1_PINS
Definition: rpiGpio.h:129
errStatus gpioGetI2cPins(int *gpioNumberScl, int *gpioNumberSda)
Get the correct I2C pins.
Definition: gpio.c:356
#define GPIO_GPSET0
GPSET_0 register.
Definition: gpio.h:54
errStatus gpioSetFunction(int gpioNumber, eFunction function)
Sets the functionality of the desired pin.
Definition: gpio.c:164
#define REV1_SCL
The BCM2835 pin number of SCL on rev1 Raspberry Pi.
Definition: rpiGpio.h:136
static tPcbRev pcbRev
PCB revision that executable is being run on.
Definition: gpio.c:38
#define GPIO_GPPUD
GPIO_GPPUD register.
Definition: gpio.h:60