/* GPIOCPP version 0.09, march 18, 2017 COPYLEFT - Pieter Suurmond. */ #include #include #include #include #include /* // Only necessary if you uncomment perror()s below. #include // Otherwise, we never write to stderr or stdout, #include // instead, we throw an exception in case of error. */ #include "gpiocpp.h" // Also includes . GPIOCPP::GPIOCPP(uint8_t model, // 1 or 2. const char* path) // "/dev/mem" or "/dev/gpiomem". : blocksize(4*1024) { int fd; uint32_t base_address; if (model == 1) base_address = 0x20000000; // Model 1 = ARMv6. else base_address = 0x3F000000; // Model 2 = ARMv7. base_address += 0x200000; // Start of GPIO controller. if ((fd = open(path, O_RDWR | O_SYNC) ) < 0) { //perror("GPIOCPP() open()"); // Writes to stderr! throw "GPIOCPP() failed to open character device.\n"; } address = static_cast(mmap(NULL, blocksize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, base_address)); if (address == MAP_FAILED) { //perror("GPIOCPP() mmap()"); // Writes to stderr! throw "GPIOCPP() mmap() = MAP_FAILED.\n"; } close(fd); } GPIOCPP::~GPIOCPP() { munmap((void*)address, blocksize); } // When address is volatile, static_cast seems not possible. Munmap() may // fail but destructors in C++ are not allowed to throw. void GPIOCPP::config_pull(uint8_t pin, PULL pull) { // Address offsets (in bytes/4). See BCM2835-ARM-Peripherals.pdf, p91-100: #define GPPUD (37) #define GPPUDCLK0 (38) // Would be nice if the following routine is never interrupted. Even slight- // ly different timing may give unpredictable results! BCM recommends pauses // of 150 cycles (of what?!). 10 us around [GPPUDCLK0] seems to work best. usleep(100000); // 100 milliseconds (BCM does not mention this). address[GPPUD] = static_cast(pull); usleep(10); // 10 microseconds (see bcm2835.c address[GPPUDCLK0] = 1 << pin; // from Mike McCauley: also 10us). usleep(10); // 10 microseconds. address[GPPUD] = static_cast(PULL::OFF); address[GPPUDCLK0] = 0; usleep(100000); // 100 milliseconds (BCM does not mention this). }