Hello,
I am trying to set up some GPIOs for usage for sending and reading information.
Since I’m new to Torizon first I decided to start with getting the example code from Toradex git running.
I changes some of the printing functions to use C++ libraries. This is the code I use:
#include <iostream>
#include <cstring>
#include <gpiod.h>
#include <unistd.h>
struct gpiod_line* get_gpio_line(char* bank, int gpio) {
struct gpiod_chip* chip;
struct gpiod_line* line;
// open the GPIO bank
chip = gpiod_chip_open_by_name(bank);
if (chip == nullptr) {
return nullptr;
}
// open the GPIO line
line = gpiod_chip_get_line(chip, gpio);
if (line == nullptr) {
return nullptr;
}
return line;
}
int main(int argc, char* argv[]) {
struct gpiod_line* output_line;
struct gpiod_line* input_line;
struct gpiod_line_event event;
int line_value = 0;
int ret;
char chip[32];
unsigned int offset;
// check the arguments
std::cout << "1" << std::endl;
if (!(argc == 3 || argc == 5)) {
std::cout << "Usage by bank/pin number:\n"
"gpio-event INPUT-BANK-NUMBER INPUT-GPIO-NUMBER OUTPUT-BANK-NUMBER OUTPUT-GPIO-NUMBER\n"
"Usage by SODIMM name:\n"
"gpio-event INPUT-SODIMM-NAME OUTPUT-SODIMM-NAME\n";
return EXIT_FAILURE;
}
if (argc == 5) {
std::cout << "2" << std::endl;
char gpio_chip[10];
snprintf(gpio_chip, sizeof(gpio_chip), "gpiochip%s", argv[1]);
input_line = get_gpio_line(gpio_chip, atoi(argv[2]));
snprintf(gpio_chip, sizeof(gpio_chip), "gpiochip%s", argv[3]);
output_line = get_gpio_line(gpio_chip, atoi(argv[4]));
}
else {
if (gpiod_ctxless_find_line(argv[1], chip, sizeof(chip), &offset) <= 0) {
std::cout << "Error finding GPIO" << std::endl;
return EXIT_FAILURE;
}
std::cout << "3" << std::endl;
input_line = get_gpio_line(chip, offset);
if (input_line == nullptr) {
std::cout << "Error setting gpiod" << std::endl;
return EXIT_FAILURE;
}
std::cout << "4" << std::endl;
if (gpiod_ctxless_find_line(argv[2], chip, sizeof(chip), &offset) <= 0) {
std::cout << "Error finding GPIO" << std::endl;
return EXIT_FAILURE;
}
std::cout << "4" << std::endl;
output_line = get_gpio_line(chip, offset);
if (output_line == nullptr) {
std::cout << "Error setting gpiod" << std::endl;
return EXIT_FAILURE;
}
std::cout << "5" << std::endl;
}
ret = gpiod_line_request_rising_edge_events(input_line, "gpio-test");
if (ret < 0) {
std::cout << "Request events failed" << std::endl;
return EXIT_FAILURE;
}
std::cout << "6" << std::endl;
ret = gpiod_line_request_output(output_line, "gpio-test",
GPIOD_LINE_ACTIVE_STATE_HIGH);
if (ret < 0) {
std::cout << "Request output failed" << std::endl;
return EXIT_FAILURE;
}
std::cout << "7" << std::endl;
while (true) {
gpiod_line_event_wait(input_line, nullptr);
if (gpiod_line_event_read(input_line, &event) != 0)
continue;
std::cout << "8" << std::endl;
// this should always be a rising event
if (event.event_type != GPIOD_LINE_EVENT_RISING_EDGE)
continue;
std::cout << "9" << std::endl;
// toggle output
line_value = !line_value;
std::cout << "Setting pin to " << line_value << std::endl;
gpiod_line_set_value(output_line, line_value);
std::cout << "10" << std::endl;
}
std::cout << "11" << std::endl;
return EXIT_SUCCESS;
}
But when I run it I get the following error:
Usage by bank/pin number:
gpio-event INPUT-BANK-NUMBER INPUT-GPIO-NUMBER OUTPUT-BANK-NUMBER OUTPUT-GPIO-NUMBER
Usage by SODIMM name:
gpio-event INPUT-SODIMM-NAME OUTPUT-SODIMM-NAME
[Inferior 1 (process 37) exited with code 01]
I am not sure what am I doing wrong as I am fairly new to Torizon and Docker.
I ried following the tutorial on GPIO usage and adding the following line to the Dockerfile:
docker run --rm -it --init --device /dev/gpiochip1 yourdockerhubuser/arm32v7-c-gpiod
like this at the bottom:
# ARG CROSS_SDK_BASE_TAG=2.7-bullseye
ARG CROSS_SDK_BASE_TAG=3.0.2-20230323-bookworm
ARG BASE_VERSION=2.5-bullseye
##
# Board architecture
# arm or arm64
##
ARG IMAGE_ARCH=armhf
##
# Application Name
##
ARG APP_EXECUTABLE=pesho
# BUILD ------------------------------------------------------------------------
FROM torizon/debian-cross-toolchain-${IMAGE_ARCH}:${CROSS_SDK_BASE_TAG} As Build
ARG IMAGE_ARCH
ARG COMPILER_ARCH
ENV IMAGE_ARCH ${IMAGE_ARCH}
# __deps__
RUN apt-get -q -y update && \
apt-get -q -y install libcurl4-gnutls-dev:armhf \
apt-get -q -y install \
# DOES NOT REMOVE THIS LABEL: this is used for VS Code automation
# __torizon_packages_dev_start__
# __torizon_packages_dev_end__
# DOES NOT REMOVE THIS LABEL: this is used for VS Code automation
libgpiod-dev:armhf \
libgpiod2:armhf \
libpthread-stubs0-dev:armhf \
&& \
apt-get clean && apt-get autoremove && \
rm -rf /var/lib/apt/lists/*
# __deps__
COPY . /app
WORKDIR /app
# RUN echo arm-linux-gnueabihf-g++ --version
RUN if [ "$IMAGE_ARCH" = "arm64" ] ; then \
make ARCH=. CC=aarch64-linux-gnu-g++ ; \
elif [ "$IMAGE_ARCH" = "arm" ] ; then \
make ARCH=. CC=arm-linux-gnueabihf-g++ ; \
elif [ "$IMAGE_ARCH" = "amd64" ] ; then \
make ARCH=. CC=x86_64-linux-gnu-g++ ; \
fi
# BUILD ------------------------------------------------------------------------
# DEPLOY ------------------------------------------------------------------------
FROM --platform=linux/${IMAGE_ARCH} torizonextras/debian:${BASE_VERSION} AS Deploy
ARG IMAGE_ARCH
ARG APP_EXECUTABLE
ENV APP_EXECUTABLE ${APP_EXECUTABLE}
RUN apt-get -y update && apt-get install -y --no-install-recommends \
# DOES NOT REMOVE THIS LABEL: this is used for VS Code automation
# __torizon_packages_prod_start__
# __torizon_packages_prod_end__
# DOES NOT REMOVE THIS LABEL: this is used for VS Code automation
&& apt-get clean && apt-get autoremove && rm -rf /var/lib/apt/lists/*
# Allow the user torizon use GPIOs
RUN usermod -a -G gpio torizon
# copy the build
COPY --from=Build /app/bin /app
# ADD YOUR ARGUMENTS HERE
CMD [ "./app/pesho", "--rm", "-it", "--init", "--device", "/dev/gpiochip1", "yourdockerhubuser/arm32v7-c-gpiod"]
#CMD [ "./app/pesho", "--rm", "-it", "--init", "--device", "/dev/gpiochip1", "pesho/arm32v7-c-gpiod"]
# DEPLOY ------------------------------------------------------------------------
As it can be seen I also include the libgpiod-dev:armhf \ libgpiod2:armhf \
and
RUN usermod -a -G gpio torizon
.
The Makefile has the following configurations:
# tool macros
CC := g++
CCFLAGS := -Iincludes/ -I/usr/include/x86_64-linux-gnu
DBGFLAGS := -g
LDFLAGS := -lcurl -lgpiod -lpthread
CCOBJFLAGS := $(CCFLAGS) -c
ARCH :=
# path macros
BIN_PATH := $(ARCH)/bin
OBJ_PATH := $(ARCH)/obj
SRC_PATH := src
DBG_PATH := $(ARCH)/debug
# compile macros
TARGET_NAME := pesho
TARGET := $(BIN_PATH)/$(TARGET_NAME)
TARGET_DEBUG := $(DBG_PATH)/$(TARGET_NAME)
# src files & obj files
SRC := $(foreach x, $(SRC_PATH), $(wildcard $(addprefix $(x)/*,.c*)))
OBJ := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
OBJ_DEBUG := $(addprefix $(DBG_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))
# clean files list
DISTCLEAN_LIST := $(OBJ) \
$(OBJ_DEBUG)
CLEAN_LIST := $(TARGET) \
$(TARGET_DEBUG) \
$(DISTCLEAN_LIST)
# default rule
default: makedir all
# non-phony targets
$(TARGET): $(OBJ)
$(CC) $(CCFLAGS) -o $@ $(OBJ) $(LDFLAGS)
$(OBJ_PATH)/%.o: $(SRC_PATH)/%.c*
$(CC) $(CCOBJFLAGS) -o $@ $<
$(DBG_PATH)/%.o: $(SRC_PATH)/%.c*
$(CC) $(CCOBJFLAGS) $(DBGFLAGS) -o $@ $<
$(TARGET_DEBUG): $(OBJ_DEBUG)
$(CC) $(CCFLAGS) $(DBGFLAGS) $(OBJ_DEBUG) -o $@ $(LDFLAGS)
# phony rules
.PHONY: makedir
makedir:
@mkdir -p $(BIN_PATH) $(OBJ_PATH) $(DBG_PATH)
.PHONY: all
all: $(TARGET)
.PHONY: debug
debug: $(TARGET_DEBUG)
.PHONY: clean
clean:
@echo CLEAN $(CLEAN_LIST)
@rm -f $(CLEAN_LIST)
.PHONY: distclean
distclean:
@echo CLEAN $(CLEAN_LIST)
@rm -f $(DISTCLEAN_LIST)