Skip to content

Commit 456cfdc

Browse files
committed
- Added code and script files
- Create a Makefile file - Updated README.md file
1 parent 784b405 commit 456cfdc

File tree

5 files changed

+354
-2
lines changed

5 files changed

+354
-2
lines changed

Gpio.cpp

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#include "Gpio.h"
2+
3+
Gpio::Gpio(bool enable_spi) {
4+
if (this->init_gpio() == NO_ERROR && enable_spi) {
5+
this->init_spi();
6+
}
7+
}
8+
9+
Gpio::~Gpio() {
10+
this->close_gpio();
11+
}
12+
13+
int Gpio::init_gpio() {
14+
int errnum = NO_ERROR;
15+
// Start the BCM2835 Library to access GPIO
16+
if (!bcm2835_init()) {
17+
cerr << "bcm2835_init failed (Are you running as root?)" << endl;
18+
errnum = BCM2835_INIT_ERROR;
19+
exit(errnum);
20+
}
21+
return errnum;
22+
}
23+
24+
int Gpio::init_spi() {
25+
int errnum = NO_ERROR;
26+
// Enable SPI bus
27+
if (!bcm2835_spi_begin()) {
28+
cerr << "bcm2835_spi_begin failed (Are you running as root?)" << endl;
29+
errnum = BCM2835_INIT_SPI_ERROR;
30+
exit(errnum);
31+
}
32+
return errnum;
33+
}
34+
35+
int Gpio::close_gpio() {
36+
int errnum = NO_ERROR;
37+
if (!bcm2835_close()) {
38+
cerr << "bcm2835_close failed (Are you running as root?)" << endl;
39+
errnum = BCM2835_CLOSE_ERROR;
40+
exit(errnum);
41+
}
42+
return errnum;
43+
}
44+
45+
void Gpio::setup_pwm(GpioPwmClock clock) {
46+
std::uint32_t clock_static = static_cast<std::uint32_t>(clock);
47+
48+
bcm2835_pwm_set_clock(clock_static);
49+
}
50+
51+
void Gpio::setup_pin(GpioPin pin) {
52+
std::uint8_t funStatic = static_cast<std::uint8_t>(pin.function);
53+
std::uint8_t pullUpStatic = static_cast<std::uint8_t>(pin.pullUp);
54+
std::uint8_t pinStatic = static_cast<std::uint8_t>(pin.name);
55+
Feature feature = getFeature(pin);
56+
LOG("set_direction(function=%d, pullUp=%d) on pin:%d", unsigned(funStatic), unsigned(pullUpStatic), unsigned(pinStatic));
57+
58+
if (pin.name != GpioPinName::unknown) {
59+
// Set function
60+
if (feature == Feature::io) {
61+
bcm2835_gpio_fsel(pinStatic, funStatic);
62+
} else if (feature == Feature::pwm) {
63+
std::uint8_t channel = get_pwm_channel(pin);
64+
std::uint8_t mode_static = static_cast<std::uint8_t>(pin.pwmMode);
65+
std::uint8_t range = pin.pwmRange;
66+
67+
if (channel >= 0 && pin.pwmMode != GpioPwmMode::unknown) {
68+
bcm2835_pwm_set_mode(channel, mode_static, 1 /* 1=enable */);
69+
}
70+
71+
if (channel >= 0 && range > 0) {
72+
bcm2835_pwm_set_range(channel, range);
73+
}
74+
}
75+
76+
// if specified set PullUp resistor
77+
if (pin.pullUp != GpioPullUp::none) {
78+
LOG("override pull up setting");
79+
bcm2835_gpio_set_pud(pinStatic, pullUpStatic);
80+
} else {
81+
LOG("leave pull up setting as is");
82+
}
83+
} else {
84+
cerr << "setup_pin() pin name not initialised" << endl;
85+
}
86+
}
87+
88+
void Gpio::read(std::list<GpioPin*> pin_list) {
89+
for (GpioPin *pin : pin_list) {
90+
uint8_t pin_static = static_cast<std::uint8_t>(pin->name);
91+
pin->value = bcm2835_gpio_lev(pin_static);
92+
LOG("read pin:%d value:%d", pin_static, pin->value);
93+
}
94+
}
95+
96+
std::list<GpioPin*> Gpio::get_pins_up(std::list<GpioPin*> pins_to_check) {
97+
std::list<GpioPin*> switches_pushed = {};
98+
99+
if (!pins_to_check.empty()) {
100+
read(pins_to_check);
101+
for (GpioPin *pin : pins_to_check) {
102+
// Keep pins up only
103+
if ((pin->value == 0 && pin->pullUp == GpioPullUp::up) || (pin->value != 0 && pin->pullUp != GpioPullUp::up)) {
104+
switches_pushed.push_back(pin);
105+
}
106+
}
107+
}
108+
109+
return switches_pushed;
110+
}
111+
112+
void Gpio::write(GpioPin* pin, uint8_t val) {
113+
std::uint8_t val_static = static_cast<std::uint8_t>(val);
114+
std::uint8_t pin_static = static_cast<std::uint8_t>(pin->name);
115+
std::uint8_t channel = get_pwm_channel(*pin);
116+
117+
if (channel < 0) {
118+
bcm2835_gpio_write(pin_static, val_static);
119+
LOG("write pin:%d value:%d", pin_static, val_static);
120+
} else {
121+
bcm2835_pwm_set_data(channel, val_static);
122+
LOG("write PWM pin:%d value:%d", pin_static, val_static);
123+
}
124+
125+
pin->value = val_static;
126+
}
127+
128+
std::uint8_t Gpio::get_pwm_channel(GpioPin pin) {
129+
std::uint8_t channel = -1;
130+
GpioPinName name = pin.name;
131+
GpioFunction func = pin.function;
132+
133+
if (getFeature(pin) != Feature::pwm) {
134+
channel = -1;
135+
} else if ((name == GpioPinName::gpio13 && func == GpioFunction::alt0) ||
136+
(name == GpioPinName::gpio19 && func == GpioFunction::alt5)) {
137+
channel = 1;
138+
} else if (name == GpioPinName::gpio18 && func == GpioFunction::alt5) {
139+
channel = 0;
140+
}
141+
142+
return channel;
143+
}
144+
145+
Feature Gpio::getFeature(GpioPin pin) {
146+
Feature feature = Feature::unknown;
147+
GpioPinName name = pin.name;
148+
GpioFunction func = pin.function;
149+
150+
if ((name != GpioPinName::unknown && func == GpioFunction::input) ||
151+
(name != GpioPinName::unknown && func == GpioFunction::output)) {
152+
feature = Feature::io;
153+
} else if ((name == GpioPinName::gpio13 && func == GpioFunction::alt0) ||
154+
(name == GpioPinName::gpio19 && func == GpioFunction::alt5) ||
155+
(name == GpioPinName::gpio18 && func == GpioFunction::alt5)) {
156+
feature = Feature::pwm;
157+
}
158+
159+
return feature;
160+
}

Gpio.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#ifndef GPIO_CLASS_H
2+
#define GPIO_CLASS_H
3+
4+
#include <string>
5+
#include <iostream>
6+
#include <list>
7+
#include <sstream>
8+
#include <unistd.h>
9+
#include <errno.h>
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <sys/types.h>
13+
#include <sys/stat.h>
14+
#include <fcntl.h>
15+
#include <signal.h>
16+
#include <bcm2835.h>
17+
18+
using namespace std;
19+
20+
#ifdef DEBUG
21+
#define LOG(...) do { if (DEBUG) { \
22+
printf(__VA_ARGS__); \
23+
printf("\n"); \
24+
}} while (0)
25+
#else
26+
#define LOG(...)
27+
#endif
28+
29+
// Error codes
30+
#define NO_ERROR 0
31+
#define BCM2835_INIT_ERROR -1
32+
#define BCM2835_INIT_SPI_ERROR -2
33+
#define BCM2835_CLOSE_ERROR -3
34+
35+
// Pin names
36+
enum class GpioPinName: std::uint8_t {
37+
unknown = 0xff,
38+
gpio27 = RPI_V2_GPIO_P1_13,
39+
gpio22 = RPI_V2_GPIO_P1_15,
40+
gpio10 = RPI_V2_GPIO_P1_19,
41+
gpio19 = RPI_V2_GPIO_P1_35, /*!< Can be PWM channel 1 in ALT FUN 5 */
42+
gpio18 = RPI_V2_GPIO_P1_12, /*!< Can be PWM channel 0 in ALT FUN 5 */
43+
gpio13 = RPI_V2_GPIO_P1_33, /*!< Can be PWM channel 1 in ALT FUN 0 */
44+
gpio12 = RPI_V2_GPIO_P1_32, /*!< Can be PWM channel 0 in ALT FUN 0 */
45+
gpio4 = RPI_V2_GPIO_P1_07
46+
};
47+
48+
// Functions
49+
enum class GpioFunction: std::uint8_t {
50+
unknown = 0xff,
51+
input = BCM2835_GPIO_FSEL_INPT,
52+
output = BCM2835_GPIO_FSEL_OUTP,
53+
alt0 = BCM2835_GPIO_FSEL_ALT0,
54+
alt1 = BCM2835_GPIO_FSEL_ALT1,
55+
alt2 = BCM2835_GPIO_FSEL_ALT2,
56+
alt3 = BCM2835_GPIO_FSEL_ALT3,
57+
alt4 = BCM2835_GPIO_FSEL_ALT4,
58+
alt5 = BCM2835_GPIO_FSEL_ALT5
59+
};
60+
61+
// Pull up resistor
62+
enum class GpioPullUp: std::uint8_t {
63+
none = 0xff,
64+
off = BCM2835_GPIO_PUD_OFF,
65+
up = BCM2835_GPIO_PUD_UP,
66+
down = BCM2835_GPIO_PUD_DOWN
67+
};
68+
69+
// PWM clock values
70+
enum class GpioPwmClock: std::uint32_t {
71+
KHZ_4_6875 = BCM2835_PWM_CLOCK_DIVIDER_1, /*!< 1 = 4.6875kHz, same as divider 4096 */
72+
KHZ_9_375 = BCM2835_PWM_CLOCK_DIVIDER_2048, /*!< 2048 = 9.375kHz */
73+
KHZ_18_75 = BCM2835_PWM_CLOCK_DIVIDER_1024, /*!< 1024 = 18.75kHz */
74+
KHZ_37_5 = BCM2835_PWM_CLOCK_DIVIDER_512, /*!< 512 = 37.5kHz */
75+
KHZ_75 = BCM2835_PWM_CLOCK_DIVIDER_256, /*!< 256 = 75kHz */
76+
KHZ_150 = BCM2835_PWM_CLOCK_DIVIDER_128, /*!< 128 = 150kHz */
77+
KHZ_300 = BCM2835_PWM_CLOCK_DIVIDER_64, /*!< 64 = 300kHz */
78+
KHZ_600 = BCM2835_PWM_CLOCK_DIVIDER_32, /*!< 32 = 600.0kHz */
79+
MHZ_1_2 = BCM2835_PWM_CLOCK_DIVIDER_16, /*!< 16 = 1.2MHz */
80+
MHZ_2_4 = BCM2835_PWM_CLOCK_DIVIDER_8, /*!< 8 = 2.4MHz */
81+
MHZ_4_8 = BCM2835_PWM_CLOCK_DIVIDER_4, /*!< 4 = 4.8MHz */
82+
MHZ_9_6 = BCM2835_PWM_CLOCK_DIVIDER_2 /*!< 2 = 9.6MHz, fastest you can get */
83+
};
84+
85+
// PWM modes
86+
enum class GpioPwmMode: std::uint8_t {
87+
unknown = 0xff,
88+
balanced = 0,
89+
markspace = 1
90+
};
91+
92+
// GPIO pin
93+
struct GpioPin {
94+
GpioPinName name = GpioPinName::unknown;
95+
GpioFunction function = GpioFunction::unknown;
96+
GpioPullUp pullUp = GpioPullUp::none;
97+
98+
// PWM
99+
GpioPwmMode pwmMode = GpioPwmMode::unknown;
100+
std::uint32_t pwmRange = 255;
101+
102+
std::uint32_t value = 0;
103+
};
104+
105+
enum class Feature {
106+
unknown,
107+
io,
108+
pwm,
109+
spi
110+
};
111+
112+
class Gpio {
113+
public:
114+
Gpio(bool enable_spi = false);
115+
~Gpio();
116+
117+
void setup_pin(GpioPin pin);
118+
void setup_pwm(GpioPwmClock clock);
119+
void read(std::list<GpioPin*> pin_list);
120+
std::list<GpioPin*> get_pins_up(std::list<GpioPin*> pins_to_check);
121+
void write(GpioPin* pin, std::uint8_t val);
122+
123+
private:
124+
int init_gpio();
125+
int init_spi();
126+
int close_gpio();
127+
std::uint8_t get_pwm_channel(GpioPin pin);
128+
Feature getFeature(GpioPin pin);
129+
};
130+
131+
#endif

Makefile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
CC := g++
2+
CCFLAGS := -Wall
3+
DEBUGFLAGS := -DDEBUG
4+
5+
TARGET := Gpio
6+
MAINS := $(addsuffix .o, $(TARGET) )
7+
OBJ := $(MAINS)
8+
DEPS :=
9+
10+
.PHONY: all clean
11+
12+
all: $(TARGET)
13+
14+
debug: CCFLAGS += $(DEBUGFLAGS)
15+
debug: $(TARGET)
16+
17+
clean:
18+
rm -f $(TARGET)
19+
20+
$(TARGET): % : %.cpp $(DEPS)
21+
$(CC) -c -o $@ $< $(CCFLAGS)

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
1-
# raspberrypi_gpio
2-
C++ wrapper around BCM2835 library manage the GPIO port of a Raspberry Pi
1+
# RASPBERRYPI_GPIO
2+
C++ class wrapping [BCM2835](http://www.airspayce.com/mikem/bcm2835) C library which helps to manage the GPIO port of a Raspberry Pi
3+
This class has been testred on a Raspberry Pi Zero W only
4+
5+
# DEPENDENCIES
6+
## BCM2835 LIBRARY
7+
To install `BCM2835` library see instructions [here](http://www.airspayce.com/mikem/bcm2835)
8+
The `bcm2835/install.sh` script helps to download, compile and install the library however there is no guarantee it works on all OS
9+
10+
# COMPILATION
11+
To compile this project there is a *Makefile*. Here are the available make commands:
12+
- `all` - build the project with applying the release configuration
13+
- `debug` - build the project with applying the debug configuration
14+
- `clean` - delete all generated files

bcm2835/install.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/bash
2+
3+
BCM2835="bcm2835-1.62"
4+
5+
echo "INSTALLING BCM2835 V1.62 LIBRARY TO HOME DIRECTORY..."
6+
cd ~
7+
wget http://www.airspayce.com/mikem/bcm2835/${BCM2835}.tar.gz
8+
if [ -f "${BCM2835}.tar.gz" ]; then
9+
tar -zvxf ${BCM2835}.tar.gz
10+
else
11+
echo "ERROR WHILE DOWNLOADING ${BCM2835} LIBRARY"
12+
exit -1
13+
fi
14+
15+
if [ ! -d ${BCM2835} ]; then
16+
echo "ERROR WHILE UNCOMPRESSING ${BCM2835}.tar.gz file"
17+
exit -2
18+
fi
19+
20+
echo "COMPILING LIBRARY..."
21+
cd bcm2835-1.62
22+
./configure
23+
make
24+
25+
echo "INSTALLING LIBRARY..."
26+
sudo make install
27+
28+
echo "DONE"

0 commit comments

Comments
 (0)