From 3a5befa36f57d5f02f33e178d0fc6116983ba47b Mon Sep 17 00:00:00 2001 From: Amy Gale Ruth Bowersox Date: Sun, 1 Dec 2019 14:18:31 -0700 Subject: [PATCH] use the BCM2835 library to abstract out the GPIO details --- src/Makefile | 2 +- src/gpio.c | 194 +++++++++------------------------------------ src/gpio_old.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 159 deletions(-) create mode 100644 src/gpio_old.c diff --git a/src/Makefile b/src/Makefile index de01b8a..08f0b3a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ OBJS=main.o sysinput.o log.o gpio.o msg_queue.o time_func.o -LIBS=-lpthread +LIBS=-lbcm2835 -lpthread upiwin: $(OBJS) gcc -o upiwin $(OBJS) $(LIBS) diff --git a/src/gpio.c b/src/gpio.c index a3496fe..b3143b7 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -4,195 +4,73 @@ #include #include #include +#include #include "log.h" #include "gpio.h" -#define GLINE_BUTTON1 17 -#define GLINE_BUTTON2 22 -#define GLINE_BUTTON3 23 -#define GLINE_BUTTON4 27 +#define GLINE_BUTTON1 17 +#define GLINE_BUTTON2 22 +#define GLINE_BUTTON3 23 +#define GLINE_BUTTON4 27 +#define GLINE_BACKLIGHT 18 #define STATE_BUTTON1 (1 << 0) #define STATE_BUTTON2 (1 << 1) #define STATE_BUTTON3 (1 << 2) #define STATE_BUTTON4 (1 << 3) -#define INPUT 1 /* is really 0 for control register! */ -#define OUTPUT 0 /* is really 1 for control register! */ -#define ALT0 4 - -#define PUD_OFF 0 -#define PUD_DOWN 1 -#define PUD_UP 2 - -#define FSEL_OFFSET 0 -#define SET_OFFSET 7 -#define CLR_OFFSET 10 -#define PINLEVEL_OFFSET 13 -#define EVENT_DETECT_OFFSET 16 -#define RISING_ED_OFFSET 19 -#define FALLING_ED_OFFSET 22 -#define HIGH_DETECT_OFFSET 25 -#define LOW_DETECT_OFFSET 28 -#define PULLUPDN_OFFSET 37 -#define PULLUPDNCLK_OFFSET 38 - -#define PULLUPDN_OFFSET_2711_0 57 -#define PULLUPDN_OFFSET_2711_1 58 -#define PULLUPDN_OFFSET_2711_2 59 -#define PULLUPDN_OFFSET_2711_3 60 -#define PULLUPDN_2711_MAGIC 0x6770696F - -#define BLOCK_SIZE (4*1024) - -static int mem_fd = -1; -static volatile uint32_t *gpio_map = NULL; -static int is_2711 = 0; -static int last_state = 0; - -static void short_wait(void) -{ - int i; - - for (i=0; i<150; i++) - { /* wait 150 cycles */ - asm volatile("nop"); - } -} - -static int setup_the_memmap(void) -{ - if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0) - { - if ((gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0)) == MAP_FAILED) - { - gpio_map = NULL; - close(mem_fd); - Log(LFATAL, "Unable to map /dev/gpiomem (%d)", errno); - return -1; - } - } - - /* ignore the rest of the possibilities for now */ - return 0; -} - -static void set_pullupdn(int gpio, int pud) -{ - if (is_2711) - { /* method for RPi 4 */ - int pullreg = PULLUPDN_OFFSET_2711_0 + (gpio >> 4); - int pullshift = (gpio & 0xF) << 1; - uint32_t pullbits; - unsigned pull = 0; - switch (pud) - { - case PUD_OFF: pull = 0; break; - case PUD_UP: pull = 1; break; - case PUD_DOWN: pull = 2; break; - default: pull = 0; /* keep as "off" */ - } - pullbits = *(gpio_map + pullreg); - pullbits &= ~(3 << pullshift); - pullbits |= (pull << pullshift); - *(gpio_map + pullreg) = pullbits; - } - else - { /* method for older models */ - int clk_offset = PULLUPDNCLK_OFFSET + (gpio / 32); - int shift = gpio % 32; - - if (pud == PUD_DOWN) - { - *(gpio_map + PULLUPDN_OFFSET) = (*(gpio_map + PULLUPDN_OFFSET) & ~3) | PUD_DOWN; - } - else if (pud == PUD_UP) - { - *(gpio_map + PULLUPDN_OFFSET) = (*(gpio_map + PULLUPDN_OFFSET) & ~3) | PUD_UP; - } - else - { /* pud == PUD_OFF */ - *(gpio_map + PULLUPDN_OFFSET) &= ~3; - } - short_wait(); - *(gpio_map + clk_offset) = 1 << shift; - short_wait(); - *(gpio_map + PULLUPDN_OFFSET) &= ~3; - *(gpio_map + clk_offset) = 0; - } -} - -static void setup_gpio_line(int gpio, int direction, int pud) -{ - int offset = FSEL_OFFSET + (gpio / 10); - int shift = (gpio % 10) * 3; - - set_pullupdn(gpio, pud); - if (direction == OUTPUT) - *(gpio_map + offset) = (*(gpio_map + offset) & ~(7 << shift)) | (1 << shift); - else /* direction == INPUT */ - *(gpio_map + offset) = (*(gpio_map + offset) & ~(7 << shift)); -} - -static int gpio_input(int gpio) -{ - int offset, value, mask; - - offset = PINLEVEL_OFFSET + (gpio / 32); - mask = (1 << gpio % 32); - value = *(gpio_map + offset) & mask; - return value; -} - int Gpio_setup(void) { - if (setup_the_memmap() != 0) + if (!bcm2835_init()) + { + Log(LFATAL, "Error initializing BCM2835 library"); return -1; + } - is_2711 = (*(gpio_map + PULLUPDN_OFFSET_2711_3) != PULLUPDN_2711_MAGIC); + /* configure the buttons */ + bcm2835_gpio_set_pud(GLINE_BUTTON1, BCM2835_GPIO_PUD_UP); + bcm2835_gpio_fsel(GLINE_BUTTON1, BCM2835_GPIO_FSEL_INPT); + bcm2835_gpio_set_pud(GLINE_BUTTON2, BCM2835_GPIO_PUD_UP); + bcm2835_gpio_fsel(GLINE_BUTTON2, BCM2835_GPIO_FSEL_INPT); + bcm2835_gpio_set_pud(GLINE_BUTTON3, BCM2835_GPIO_PUD_UP); + bcm2835_gpio_fsel(GLINE_BUTTON3, BCM2835_GPIO_FSEL_INPT); + bcm2835_gpio_set_pud(GLINE_BUTTON4, BCM2835_GPIO_PUD_UP); + bcm2835_gpio_fsel(GLINE_BUTTON4, BCM2835_GPIO_FSEL_INPT); - setup_gpio_line(GLINE_BUTTON1, INPUT, PUD_UP); - setup_gpio_line(GLINE_BUTTON2, INPUT, PUD_UP); - setup_gpio_line(GLINE_BUTTON3, INPUT, PUD_UP); - setup_gpio_line(GLINE_BUTTON4, INPUT, PUD_UP); /* TODO: other setup */ - last_state = 0; return 0; } void Gpio_cleanup(void) { /* TODO: additional cleanup may be required */ - - setup_gpio_line(GLINE_BUTTON1, INPUT, PUD_OFF); - setup_gpio_line(GLINE_BUTTON2, INPUT, PUD_OFF); - setup_gpio_line(GLINE_BUTTON3, INPUT, PUD_OFF); - setup_gpio_line(GLINE_BUTTON4, INPUT, PUD_OFF); - - if (gpio_map) - { - munmap((void *)gpio_map, BLOCK_SIZE); - gpio_map = NULL; - } - if (mem_fd >= 0) - { - close(mem_fd); - mem_fd = -1; - } + + /* close down the button lines */ + bcm2835_gpio_set_pud(GLINE_BUTTON1, BCM2835_GPIO_PUD_OFF); + bcm2835_gpio_fsel(GLINE_BUTTON1, BCM2835_GPIO_FSEL_INPT); + bcm2835_gpio_set_pud(GLINE_BUTTON2, BCM2835_GPIO_PUD_OFF); + bcm2835_gpio_fsel(GLINE_BUTTON2, BCM2835_GPIO_FSEL_INPT); + bcm2835_gpio_set_pud(GLINE_BUTTON3, BCM2835_GPIO_PUD_OFF); + bcm2835_gpio_fsel(GLINE_BUTTON3, BCM2835_GPIO_FSEL_INPT); + bcm2835_gpio_set_pud(GLINE_BUTTON4, BCM2835_GPIO_PUD_OFF); + bcm2835_gpio_fsel(GLINE_BUTTON4, BCM2835_GPIO_FSEL_INPT); + + if (!bcm2835_close()) + Log(LWARN, "Closing BCM2835 library failed"); } int Gpio_read_buttons(void) { int rc = 0; - if (gpio_input(GLINE_BUTTON1) == 0) + if (bcm2835_gpio_lev(GLINE_BUTTON1) == LOW) rc |= STATE_BUTTON1; - if (gpio_input(GLINE_BUTTON2) == 0) + if (bcm2835_gpio_lev(GLINE_BUTTON2) == LOW) rc |= STATE_BUTTON2; - if (gpio_input(GLINE_BUTTON3) == 0) + if (bcm2835_gpio_lev(GLINE_BUTTON3) == LOW) rc |= STATE_BUTTON3; - if (gpio_input(GLINE_BUTTON4) == 0) + if (bcm2835_gpio_lev(GLINE_BUTTON4) == LOW) rc |= STATE_BUTTON4; return rc; } diff --git a/src/gpio_old.c b/src/gpio_old.c new file mode 100644 index 0000000..eb332eb --- /dev/null +++ b/src/gpio_old.c @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "gpio.h" + +#define GLINE_BUTTON1 17 +#define GLINE_BUTTON2 22 +#define GLINE_BUTTON3 23 +#define GLINE_BUTTON4 27 +#define GLINE_BACKLIGHT 18 + +#define STATE_BUTTON1 (1 << 0) +#define STATE_BUTTON2 (1 << 1) +#define STATE_BUTTON3 (1 << 2) +#define STATE_BUTTON4 (1 << 3) + +#define INPUT 1 /* is really 0 for control register! */ +#define OUTPUT 0 /* is really 1 for control register! */ +#define ALT0 4 + +#define PUD_OFF 0 +#define PUD_DOWN 1 +#define PUD_UP 2 + +#define FSEL_OFFSET 0 +#define SET_OFFSET 7 +#define CLR_OFFSET 10 +#define PINLEVEL_OFFSET 13 +#define EVENT_DETECT_OFFSET 16 +#define RISING_ED_OFFSET 19 +#define FALLING_ED_OFFSET 22 +#define HIGH_DETECT_OFFSET 25 +#define LOW_DETECT_OFFSET 28 +#define PULLUPDN_OFFSET 37 +#define PULLUPDNCLK_OFFSET 38 + +#define PULLUPDN_OFFSET_2711_0 57 +#define PULLUPDN_OFFSET_2711_1 58 +#define PULLUPDN_OFFSET_2711_2 59 +#define PULLUPDN_OFFSET_2711_3 60 +#define PULLUPDN_2711_MAGIC 0x6770696F + +#define BLOCK_SIZE (4*1024) + +static int mem_fd = -1; +static volatile uint32_t *gpio_map = NULL; +static int is_2711 = 0; +static int last_state = 0; + +static void short_wait(void) +{ + int i; + + for (i=0; i<150; i++) + { /* wait 150 cycles */ + asm volatile("nop"); + } +} + +static int setup_the_memmap(void) +{ + if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0) + { + if ((gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0)) == MAP_FAILED) + { + gpio_map = NULL; + close(mem_fd); + Log(LFATAL, "Unable to map /dev/gpiomem (%d)", errno); + return -1; + } + } + + /* ignore the rest of the possibilities for now */ + return 0; +} + +static void set_pullupdn(int gpio, int pud) +{ + if (is_2711) + { /* method for RPi 4 */ + int pullreg = PULLUPDN_OFFSET_2711_0 + (gpio >> 4); + int pullshift = (gpio & 0xF) << 1; + uint32_t pullbits; + unsigned pull = 0; + switch (pud) + { + case PUD_OFF: pull = 0; break; + case PUD_UP: pull = 1; break; + case PUD_DOWN: pull = 2; break; + default: pull = 0; /* keep as "off" */ + } + pullbits = *(gpio_map + pullreg); + pullbits &= ~(3 << pullshift); + pullbits |= (pull << pullshift); + *(gpio_map + pullreg) = pullbits; + } + else + { /* method for older models */ + int clk_offset = PULLUPDNCLK_OFFSET + (gpio / 32); + int shift = gpio % 32; + + if (pud == PUD_DOWN) + { + *(gpio_map + PULLUPDN_OFFSET) = (*(gpio_map + PULLUPDN_OFFSET) & ~3) | PUD_DOWN; + } + else if (pud == PUD_UP) + { + *(gpio_map + PULLUPDN_OFFSET) = (*(gpio_map + PULLUPDN_OFFSET) & ~3) | PUD_UP; + } + else + { /* pud == PUD_OFF */ + *(gpio_map + PULLUPDN_OFFSET) &= ~3; + } + short_wait(); + *(gpio_map + clk_offset) = 1 << shift; + short_wait(); + *(gpio_map + PULLUPDN_OFFSET) &= ~3; + *(gpio_map + clk_offset) = 0; + } +} + +static void setup_gpio_line(int gpio, int direction, int pud) +{ + int offset = FSEL_OFFSET + (gpio / 10); + int shift = (gpio % 10) * 3; + + set_pullupdn(gpio, pud); + if (direction == OUTPUT) + *(gpio_map + offset) = (*(gpio_map + offset) & ~(7 << shift)) | (1 << shift); + else /* direction == INPUT */ + *(gpio_map + offset) = (*(gpio_map + offset) & ~(7 << shift)); +} + +static void setup_gpio_alt5(int gpio) +{ + int offset = FSEL_OFFSET + (gpio / 10); + int shift = (gpio % 10) * 3; + + set_pullupdn(gpio, PUD_OFF); + *(gpio_map + offset) = (*(gpio_map + offset) & ~(7 << shift)) | (2 << shift); +} + +static int gpio_input(int gpio) +{ + int offset, value, mask; + + offset = PINLEVEL_OFFSET + (gpio / 32); + mask = (1 << gpio % 32); + value = *(gpio_map + offset) & mask; + return value; +} + +int Gpio_setup(void) +{ + if (setup_the_memmap() != 0) + return -1; + + is_2711 = (*(gpio_map + PULLUPDN_OFFSET_2711_3) != PULLUPDN_2711_MAGIC); + + setup_gpio_line(GLINE_BUTTON1, INPUT, PUD_UP); + setup_gpio_line(GLINE_BUTTON2, INPUT, PUD_UP); + setup_gpio_line(GLINE_BUTTON3, INPUT, PUD_UP); + setup_gpio_line(GLINE_BUTTON4, INPUT, PUD_UP); + /* TODO: other setup */ + + last_state = 0; + return 0; +} + +void Gpio_cleanup(void) +{ + /* TODO: additional cleanup may be required */ + + setup_gpio_line(GLINE_BUTTON1, INPUT, PUD_OFF); + setup_gpio_line(GLINE_BUTTON2, INPUT, PUD_OFF); + setup_gpio_line(GLINE_BUTTON3, INPUT, PUD_OFF); + setup_gpio_line(GLINE_BUTTON4, INPUT, PUD_OFF); + + if (gpio_map) + { + munmap((void *)gpio_map, BLOCK_SIZE); + gpio_map = NULL; + } + if (mem_fd >= 0) + { + close(mem_fd); + mem_fd = -1; + } +} + +int Gpio_read_buttons(void) +{ + int rc = 0; + + if (gpio_input(GLINE_BUTTON1) == 0) + rc |= STATE_BUTTON1; + if (gpio_input(GLINE_BUTTON2) == 0) + rc |= STATE_BUTTON2; + if (gpio_input(GLINE_BUTTON3) == 0) + rc |= STATE_BUTTON3; + if (gpio_input(GLINE_BUTTON4) == 0) + rc |= STATE_BUTTON4; + return rc; +}