Raspberry Pi – Arduino like IO access

Hi guys, I’ve wrote some functions to control Raspberry Pi IO’s via C code.
The control approach is the same like in Arduino IDE:
void pinMode (unsigned int pinNumber, unsigned int pinFunction)
void digitalWrite (unsigned int pinNumber, unsigned int pinState)
unsigned int digitalRead (unsigned int pinNumber)
Complete C code File:

/*
RASPBERRY PI IO access
www.engsta.com
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include <fcntl.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/time.h>
#include <err.h>
#include <sys/ioctl.h>
#include <time.h>


/*	Pinout:	http://www.raspberry-projects.com/pi/pi-hardware/raspberry-pi-model-b-plus/model-b-plus-io-pins
#						  /////////////	
#		+3V3 OUT 	-o| 1		 2|o-	+5V
#		I2C1 SDA/GPIO2  -o| 3		 4|o-	+5V
#		I2C1 SCL/GPIO3	-o| 5		 6|o-	GND
#		GP CLK0/GPIO14	-o| 7		08|o-	GPIO14/UART0TX
#		GND		-o| 9		10|o-	GPIO15/UART0RX
#		GPIO17		-o| 11		12|o-	GPIO18/PWM0
#		ARM TMS/GPIO27	-o| 13		14|o-	GND
#		GPIO22		-o| 15		16|o-	GPIO23
#		+3V3 OUT	-o| 17		18|o-	GPIO24
#		SPI MOSI/GPIO10	-o| 19		20|o-	GND
#		SPI MISO/GPIO9	-o| 21		22|o-	GPIO25
#		SPI SCLK/GPIO11	-o| 23		22|o-	GPIO8/SPI CS0
#		GND		-o| 25		22|o-	GPIO7/SPI CS1
#		ID_SD(ID EEprom)-o| 27		22|o-	ID_SC(ID EEprom)
#		GPCLK1/GPIO5	-o| 29		22|o-	GND	
#		GPCLK2/GPIO6	-o| 31		32|o-	GPIO12
#		PWM1/GPIO13	-o| 33		34|o-	GND
#		PWM1/GPIO19	-o| 35		36|o-	GPIO16
#		GPIO26		-o| 37		38|o-	GPIO20
#		GND		-o| 39		40|o-	GPIO21/GPCLK1
#						  /////////////  
*/
//####################################################################
// GPIO 
#define MEM_BASE_GPIO_ADDR       0x20200000UL

// GPIO GPIO Register Mem offset
#define GPFSEL0_ADDR_OFFSET		0x00	// GPIO Funktion setup
#define GPFSEL1_ADDR_OFFSET		0x04	// GPIO Funktion setup
#define GPFSEL2_ADDR_OFFSET		0x08	// GPIO Funktion setup
#define GPFSEL3_ADDR_OFFSET		0x0C	// GPIO Funktion setup
#define GPFSEL4_ADDR_OFFSET		0x10	// GPIO Funktion setup
#define GPFSEL5_ADDR_OFFSET		0x14	// GPIO Funktion setup

#define GPSET0_ADDR_OFFSET		0x1C    // Pin Output Set 
#define GPSET1_ADDR_OFFSET		0x20    // Pin Output Set

#define GPCLR0_ADDR_OFFSET		0x28	// Pin Output Clear
#define GPCLR1_ADDR_OFFSET		0x2C	// Pin Output Clear

#define GPLEV0_ADDR_OFFSET		0x34	// Pin Level State register
#define GPLEV1_ADDR_OFFSET		0x38	// Pin Level State register

#define GPPUD_ADDR_OFFSET		0x94	// Pin Pull-up/down Enable
#define GPPUDCLK0_ADDR_OFFSET		0x98	// Pin Pull-up/down ClkIn
#define GPPUDCLK1_ADDR_OFFSET		0x9C	// Pin Pull-up/down ClkIn

// GPIO Option defines for higher level functions
#define INPUT				0		
#define OUTPUT 				1
#define INPUT_PULLUP 			2
#define INPUT_PULLDOWN			3

#define HIGH				1
#define LOW				0

volatile unsigned int* gpio;
bool GPIOMEMMapDoneFlag = false;
int  fd = -1;
void *gpiomemmap;

void 
GPIOMEMMap (void) {
	
   if ((fd = open("/dev/mem", O_RDWR|O_SYNC) ) == -1) {
		printf("can't open /dev/mem \n");
		err(1, "/dev/mem open failed");
   } 
   else {

		gpiomemmap = mmap(NULL,4096,(PROT_READ | PROT_WRITE), MAP_SHARED, fd, MEM_BASE_GPIO_ADDR);
		close(fd); 
	
		if (gpiomemmap == MAP_FAILED) {
		  err(2, "/dev/mem memory map failed");
		} 
		else {
			gpio = (volatile unsigned *)gpiomemmap;
			GPIOMEMMapDoneFlag = true;
	   }
   }
}

void 
pinMode (unsigned int pinNumber, unsigned int pinFunction) {
	
	if(!GPIOMEMMapDoneFlag) GPIOMEMMap();
		int i;
	switch (pinFunction) {
		
		case INPUT:
				// disable pull-up/down control bits for responding GPIO
				*(gpio+GPPUD_ADDR_OFFSET/4) &= 0xFFFFFFFC;	// wrtite 0b00 to GPPUD Register
				// wait at least 150 cycles
					for ( i= 0; i < 100; i++);	// shall be changed to timer based version
				// clear clock
				*((gpio+GPPUDCLK0_ADDR_OFFSET/4)+ (pinNumber/32)) &= ~(1 << (pinNumber % 32));
				// wait at least 150 cycles
					for ( i= 0; i < 100; i++);	// shall be changed to timer based version
				// clear responding register bitset to 0b000 for Input 
				*((gpio+GPFSEL0_ADDR_OFFSET/4)+ (pinNumber/10)) &= ~((1 << (3*(pinNumber % 10))) | (1 << (3*(pinNumber % 10)+1)) | (1 << (3*(pinNumber % 10)+2)));
		
			break;
			
		case OUTPUT:
				// disable pull-up/down control bits for responding GPIO
				*(gpio+GPPUD_ADDR_OFFSET/4) &= 0xFFFFFFFC;	// wrtite 0b00 to GPPUD Register
				// wait at least 150 cycles
					for ( i= 0; i < 100; i++);	// shall be changed to timer based version
				// clear clock
				*((gpio+GPPUDCLK0_ADDR_OFFSET/4)+ (pinNumber/32)) &= ~(1 << (pinNumber % 32));
				// wait at least 150 cycles
					for ( i= 0; i < 100; i++);	// shall be changed to timer based version
				
				// clear current bit setup, set register bitset to 0b000  
				*((gpio+GPFSEL0_ADDR_OFFSET/4)+ (pinNumber/10)) &= ~((1 << (3*(pinNumber % 10))) | (1 << (3*(pinNumber % 10)+1)) | (1 << (3*(pinNumber % 10)+2)));
				// set responding register bitset to 0b001 for output 
				*((gpio+GPFSEL0_ADDR_OFFSET/4)+ (pinNumber/10)) = (1 << (3*(pinNumber % 10)));
			break;
			
		case INPUT_PULLUP:
				// clear the responding GPFSEL register bitset to 0b000 for Input 
				*((gpio+GPFSEL0_ADDR_OFFSET/4)+ (pinNumber/10)) &= ~((1 << (3*(pinNumber % 10))) | (1 << (3*(pinNumber % 10)+1)) | (1 << (3*(pinNumber % 10)+2)));
		
				// enable pull-up for responding GPIO
				*(gpio+GPPUD_ADDR_OFFSET/4) |= 0x00000002;	// wrtite 0b10 to GPPUD Register
				// wait at least 150 cycles
					for ( i= 0; i < 100; i++);
				// clock in the control signal of responding GPIO
				*((gpio+GPPUDCLK0_ADDR_OFFSET/4)+ (pinNumber/32)) = (1 << pinNumber);
				// wait at least 150 cycles
					for ( i= 0; i < 100; i++);	// shall be changed to timer based version
				// clear GPPUD register
				*((gpio+GPPUD_ADDR_OFFSET/4)+ (pinNumber/10)) &= 0xFFFFFFFC;	// wrtite 0b00 to GPPUD Register
				// clear clock
				*((gpio+GPPUDCLK0_ADDR_OFFSET/4)+ (pinNumber/32)) &= ~(1 << (pinNumber % 32));
				
			break;
			
			
		case INPUT_PULLDOWN:
				// clear the responding GPFSEL register bitset to 0b000 for Input 
				*((gpio+GPFSEL0_ADDR_OFFSET/4)+ (pinNumber/10)) &= ~((1 << (3*(pinNumber % 10))) | (1 << (3*(pinNumber % 10)+1)) | (1 << (3*(pinNumber % 10)+2)));
		
				// enable pull-up for responding GPIO
				*(gpio+GPPUD_ADDR_OFFSET/4) |= 0x00000001;	// wrtite 0b10 to GPPUD Register
				// wait at least 150 cycles
					for ( i= 0; i < 100; i++);
				// clock in the control signal of responding GPIO
				*((gpio+GPPUDCLK0_ADDR_OFFSET/4)+ (pinNumber/32)) = (1 << pinNumber);
				// wait at least 150 cycles
					for ( i= 0; i < 100; i++);	// shall be changed to timer based version
				// clear GPPUD register
				*((gpio+GPPUD_ADDR_OFFSET/4)+ (pinNumber/10)) &= 0xFFFFFFFC;	// wrtite 0b00 to GPPUD Register
				// clear clock
				*((gpio+GPPUDCLK0_ADDR_OFFSET/4)+ (pinNumber/32)) &= ~(1 << (pinNumber % 32));
				
			break;
			
			default:
		
			break;
	}
}

void 
digitalWrite (unsigned int pinNumber, unsigned int pinState) {
	
	if (pinState) {
		*((gpio+GPSET0_ADDR_OFFSET/4)+ (unsigned int)(pinNumber/32)) = (1 << (pinNumber % 32));
	}
	else {
		*((gpio+GPCLR0_ADDR_OFFSET/4)+ (unsigned int)(pinNumber/32)) = (1 << (pinNumber % 32));
	}
}

unsigned int 
digitalRead (unsigned int pinNumber){
	if(*((gpio+GPLEV0_ADDR_OFFSET/4)+ (unsigned int)(pinNumber/32)) & (1 << pinNumber % 32)) {
		return 1;
	}
	else {
		return 0;
	}
}

void 
delayMicrosecondsHard (unsigned int howLong) {
	struct timeval tNow, tLong, tEnd ;
	gettimeofday (&tNow, NULL) ;
	tLong.tv_sec = howLong / 1000000 ;
	tLong.tv_usec = howLong % 1000000 ;
	timeradd (&tNow, &tLong, &tEnd) ;
	while (timercmp (&tNow, &tEnd, <)) gettimeofday (&tNow, NULL);
}

void 
delay (unsigned int ms) {
	delayMicrosecondsHard(ms * 1000);
}





Click to rate this post!
[Total: 2 Average: 5]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.