Skip to content

Instantly share code, notes, and snippets.

@angww
Last active March 28, 2021 05:08
Show Gist options
  • Save angww/f6597d58ca39d577fe6f8503c6ce2ba2 to your computer and use it in GitHub Desktop.
Save angww/f6597d58ca39d577fe6f8503c6ce2ba2 to your computer and use it in GitHub Desktop.
This snippet code is to test GPIO on Cubieboard A20
/*
This snippet code is to test GPIO on Cubieboard A20.
The main loop blinks two LEDs waiting a button click (conected in PORT_BTN) via interrupt,
using funcion poll and wont consuming 100% of cpu.
This code was tested with:
* Cubiebord A20 (armv7)
* Armbian 21.02.3 (Ubuntu based)
* Kernel 5.10.21-sunxi
* gcc 9.3.0
Schematic:
+---------------+ LED2
1 | VCC 5V | PH15 | ---<220_Ohm>------------->|--------+
2 | | PH14 | ---<220_Ohm>--------+ |
3 | | PB18 | | LED1 |
. | . | . | BTN +---->|--------+
. | . | . | ___|___ |
. | . | . | +--o o----------------------+
10 | GND | GND | | |
. | . | . | | |
. | . | . | | GND
. | . | . | |
21 | | PE08 | ---+----<2k2_Ohm>----o VCC
22 | | PE09 |
23 | | PE10 |
24 | | PE11 |
+---------------+
* Using 2k2 pull up resistor. Cubieboard have internal pull up in someones PINs, but in this moment I dont
know how configure it.
Pin reference: https://linux-sunxi.org/A20/PIO
Pin reference 2: https://abhinavgupta2812.files.wordpress.com/2013/08/gpio_defination_large.jpg
Pool function reference: https://man7.org/linux/man-pages/man2/ppoll.2.html
Author: Angelo Araujo
Date: 2021-03-27
*/
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/* Main defines. You can change here for your tests */
#define PORT_BTN 238 /* PH14 = 238 */
#define PORT_LED1 239 /* PH15 = 239 */
#define PORT_LED2 136 /* PE08 = 136 */
/* IN OUT used in direction function */
#define IN 1
#define OUT 0
/* NONE BOTH FALLING used in edge funcion */
#define NONE 0
#define BOTH 1
#define FALLING 2
#define RISING 3
/* EXPORT UNERPORT used in export funcion */
#define EXPORT 0
#define UNEXPORT 1
/* Acessory funcion. This converts to string */
#define STR_(X) #X
/* Acessory funcion. This makes sure the argument is expanded before converting to string */
#define STR(X) STR_(X)
/* Wait time test to the things works */
#define WAIT_TIME 1
/* poll wait time */
#define TIME_MS_POLL_WAIT 500
/* Var used to stop loop with ctrl + c (SIGINT) */
static int keepRunning = 1;
/* Acessory funcion. Used to stop main loop. */
void sig_handler(int signo) {
if (signo == SIGINT) {
keepRunning = 0;
}
}
/* Support funcions */
/* Export example: echo 239 > /sys/class/gpio/export */
void gpio_export(int port_num, int export_unexport) {
int fd, w;
char s_port[4], s_path[50];
sprintf(s_path, "/sys/class/gpio/%s", (export_unexport ? "unexport" : "export"));
sprintf(s_port, "%d", port_num);
fd = open(s_path, O_WRONLY);
w = write(fd, s_port, 4);
printf("EXPORT PIN %s exit: %d\n", s_port, w);
if (w == -1) {
printf("errno: %d - %s \n", errno, strerror(errno));
}
close(fd);
}
/* Direction example: echo out > /sys/class/gpio/gpio239/direction */
void gpio_set_direction(int port_num, int in_or_out) {
int fd, w;
char s_path[50];
sprintf(s_path, "/sys/class/gpio/gpio%d/direction", port_num);
fd = open(s_path, O_WRONLY);
w = write(fd, in_or_out == 1 ? "in" : "out", 6);
printf("DIRECTION PIN %d exit: %d\n", port_num, w);
close(fd);
}
/* Edge example: echo both > /sys/class/gpio/gpio239/edge */
void gpio_set_edge(int port_num, int edge) {
int fd, w;
char s_path[50];
sprintf(s_path, "/sys/class/gpio/gpio%d/edge", port_num);
fd = open(s_path, O_WRONLY);
w = write(fd, "both", 5);
printf("EDGE PIN %d exit: %d\n", port_num, w);
close(fd);
}
/* Set value example: echo 1 > /sys/class/gpio/gpio239/value */
void gpio_set_value(int port_num, int value) {
int fd;
char s_path[50], s_value[5];
sprintf(s_path, "/sys/class/gpio/gpio%d/value", port_num);
sprintf(s_value, "%d", value);
fd = open(s_path, O_WRONLY);
write(fd, s_value, 4);
close(fd);
}
int main(){
int i = 0, fd, ret;
char c;
struct pollfd pfd;
/* SINGAL HANDLER */
if (signal(SIGINT, sig_handler) == SIG_ERR) {
printf("\nOps! Can't catch SIGINT.\n");
}
/* Enable GPIO */
gpio_export(PORT_BTN, EXPORT);
gpio_export(PORT_LED1, EXPORT);
gpio_export(PORT_LED2, EXPORT);
/* Set direction of GPIO pins */
gpio_set_direction(PORT_BTN, IN);
gpio_set_direction(PORT_LED1, OUT);
gpio_set_direction(PORT_LED2, OUT);
/* Sleep is needed for correct function. If remove wont work. */
sleep(WAIT_TIME);
gpio_set_edge(PORT_BTN, BOTH);
/* Wait for event, repeat (i) times */
fd = open("/sys/class/gpio/gpio" STR(PORT_BTN) "/value", O_RDONLY);
pfd.fd = fd;
pfd.events = POLLPRI;
/* Main loop, won't consume 100% cpu. */
while (1) {
i++;
/* Blink LEDs inverse */
gpio_set_value(PORT_LED1, (i) % 2);
gpio_set_value(PORT_LED2, (i+1) % 2);
lseek(fd, 0, SEEK_SET);
/* int poll(struct pollfd *fds, nfds_t nfds, int timeout); */
ret = poll(&pfd, 1, TIME_MS_POLL_WAIT);
read(fd, &c, sizeof(c));
printf("%6d : ", i);
if (ret == 0) {
printf("Timeout OK\n");
} else {
if(c == '0') {
printf("-------------------------------------------@@@@@ Push (Readed value of c: %d)\n", c);
/* Set 1. Turn on LEDS on button push for 1 second. */
gpio_set_value(PORT_LED1, 1);
gpio_set_value(PORT_LED2, 1);
sleep(0.7);
}
else {
printf("------------------@@@@@ Release (Readed value of c: %d)\n", c);
}
}
if (keepRunning == 0) {
printf("\n Stoped by Ctrl+C (SIGINT). \n");
break;
}
}
close(fd);
gpio_export(PORT_BTN, UNEXPORT);
gpio_export(PORT_LED1, UNEXPORT);
gpio_export(PORT_LED2, UNEXPORT);
return(0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment