-
February 25th, 2018, 04:49 PM
#1
[RESOLVED] sysfs GPIO Interrupts
Morning all,
First post on codeguru, I looking forward to learning and contributing!
I'm having some issues with a c++ function I'm using to monitor for GPIO interrupts on a generic Linux device. I'm providing a square wave signal of known frequency to a GPIO pin, but the resultant output of the following code is erroneous. If I set the edge detection method to "falling", the calculated frequency is correct. However, if I use "rising" detection, the frequency output is sporadic and incorrect. I'd like to be able to use "both" for the purpose of calculating duty cycle.
Code:
int gpio::interrupts(string gpioNumber)
{
int fd;
int retval;
struct timeval holder;
struct timeval tvCurrent;
double usPrevious;
double usCurrent;
double diff;
struct pollfd pfd;
char buf[64];
int error = -1;
string openD = "/sys/class/gpio/gpio" + gpioNumber + "/value";
error = fd = open(openD.c_str(), O_RDONLY);
while (error < 0) {
error = fd = open(openD.c_str(), O_RDONLY);
}
pfd.fd = fd;
pfd.events = POLLPRI;
lseek(fd, 0, SEEK_SET);
while(1) {
retval = poll(&pfd, 1, -1);
if (pfd.revents & POLLPRI) {
lseek(fd, 0, SEEK_SET);
retval = read(fd, buf, sizeof buf);
//The following std::cout will be discussed in the following section
//std::cout << "Thread: " << std::this_thread::get_id() << " GPIO: " << gpioNumber << " Value : " << retval << std::endl;
gettimeofday(&tvCurrent, NULL);
//tvPrevious is a list of lists declared in the header
if (tvPrevious[std::stoi(gpioNumber)][0] != 0 && tvPrevious[std::stoi(gpioNumber)][1] != 0) {
usPrevious = (tvPrevious[std::stoi(gpioNumber)][0]*1e6) + tvPrevious[std::stoi(gpioNumber)][1];
usCurrent = (tvCurrent.tv_sec*1e6) + tvCurrent.tv_usec;
diff = (usCurrent - usPrevious)/1e6;
//Replace the previous frequency record for this gpio
//in the existing list. The list is declared in the header
//and initialised in another function
gpioFrequencies.replace(std::stoi(gpioNumber), 1/diff);
emit gpioFrequenciesChanged();
tvPrevious[std::stoi(gpioNumber)][0] = tvCurrent.tv_sec;
tvPrevious[std::stoi(gpioNumber)][1] = tvCurrent.tv_usec;
tvCurrent.tv_sec = 0;
tvCurrent.tv_usec = 0;
} else {
gettimeofday(&holder, NULL);
tvPrevious[std::stoi(gpioNumber)][0] = holder.tv_sec;
tvPrevious[std::stoi(gpioNumber)][1] = holder.tv_usec;
holder.tv_sec = 0;
holder.tv_usec = 0;
}
}
}
return 0;
}
A secondary issue I have with the above code is in reading the gpio value from the /sys/class/gpio/gpioX/value file. The commented std::cout in the above code is used to ensure each gpio is running on a single, detached thread, and to read the value of the gpio's /value file. Whether I use "rising", "falling" or "both" for edge detection, the value of retval is always 2. I expect the value to be either 1 (HIGH) or 0 (LOW).
In summary, my two questions are as follows:
- How can I amend the above code to ensure not only "falling" detection works, but "rising" and "both" as well?
- How can I amend the above code to ensure a successful, valid reading of the /value file once the interrupt has been triggered?
-
February 26th, 2018, 02:06 AM
#2
Re: sysfs GPIO Interrupts
I've managed to address question number 2, by adding the following lines after retval = read(fd, buf, sizeof buf);:
Code:
buf[1]='\0';
string output = string(buf);
output now holds the correct 1 (HIGH) or 0 (LOW) value of the specified GPIO.
-
February 26th, 2018, 05:26 AM
#3
Re: sysfs GPIO Interrupts
I've figured out the issue of the fluctuating frequency measurement as well. It turns out the interrupt was being called for both rising and falling edges, which meant the period measurement was incorrect. Now that I'm able to read the GPIO value correctly, it was pretty easy to identify the issue.
-
February 26th, 2018, 05:39 AM
#4
Re: sysfs GPIO Interrupts
It looks like you are expecting only a single char read from the file? In this case consider
Code:
retval = read(fd, buf, 1);
buf[1] = 0;
if (retval != 1)
cout << "Error reading fd" << endl;
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
February 26th, 2018, 03:53 PM
#5
Re: [RESOLVED] sysfs GPIO Interrupts
Thanks for your input 2kaud. I'm quite new to c++, so will happily play around with alternative methods of reading the GPIO value. I'll give your approach a go this evening.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|