Interrupts in C
The IO Pi Plus is a 32 channel MCP23017 GPIO expander for the Raspberry Pi
27/03/2020
Posted by:
Robspalu
I am having problems with interrupts in C.
I have modified the demo-iopiread2 module, to use interrupts, but I dont seem to see them. A previous user also asked about interrupts some time back, and he seemd to use WiringPiISR?, which seemed a bit odd.
Below is the modified demo code:
int main(int argc, char **argv){
char isr1 = 0;
char isr2 = 0;
setvbuf (stdout, NULL, _IONBF, 0); // needed to print to the command line
IOPi_init(0x20); // initialise one of the io pi buses on i2c address 0x20, default address for bus 1
set_port_direction(0x20,0, 0xFF); // set bank 0 to be inputs
set_port_direction(0x20,1, 0xFF); // set bank 1 to be inputs
set_port_pullups(0x20, 0, 0xFF); // enable internal pullups for bank 0
invert_port(0x20,0,0xFF); // invert output so bank will read as 0
set_port_pullups(0x20, 1, 0xFF); // enable internal pullups for bank 0
invert_port(0x20,1,0xFF); // invert output so bank will read as 0
set_interrupt_defaults(0x20,0,0);// Set Interrupt default Port 0
set_interrupt_defaults(0x20,1,0);// Set Interrupt default Port 1
set_interrupt_type(0x20,0,0);// Set Interrupt type to state change Port 0
set_interrupt_type(0x20,1,0);// Set Interrupt type to state change Port 1
set_interrupt_on_port(0x20,0,0);// Enable Interrupts Port 0
set_interrupt_on_port(0x20,1,0);// Enable Interrupts Port 1
//reset_interrupts(0x20);
while (1){
clearscreen();
isr1 = read_interrupt_status(0x20,0); // Read Port 0 Interrupt status
isr2 = read_interrupt_status(0x20,1); // Read Port 1 Interrupt status
printf("ISR Port 0 %x \n", isr1); // Interrupt Status Port 0
printf("Port 0 %x \n", read_port(0x20,0)); // grounding a pins 1 to 8 will change the value
printf("ISR Port 1 %x \n", isr2); // Interrupt Status Port1
printf("Port 1 %x \n", read_port(0x20,1)); // grounding a pins 1 to 8 will change the value
usleep(200000); // sleep 0.2 seconds
}
return (0);
Can anyone spot the problem
Thanks Dave
27/03/2020
Posted by:
andrew
The set_interrupt_on_port needs a value of 0xFF for the third parameter to enable the interrupt for all pins. Where you used a value of 0 you were disabling the interrupts instead of enabling them.
Try changing the two set_interrupt_on_port() lines to the code below.
set_interrupt_on_port(0x20,0,0xFF);// Enable Interrupts Port 0
set_interrupt_on_port(0x20,1,0xFF);// Enable Interrupts Port 1
27/03/2020
Posted by:
Robspalu
Thanks for the suggestion, unfortunatley still no value for interrupt status reported when input state changes, but read_port correctly shows status.
Any other suggestions ?
Thanks Dave
27/03/2020
Posted by:
andrew
I tried your code and the interrupt is triggering but where your loop is repeating every 0.2 seconds it only flashed up on the screen for a fraction of a second before disappearing again so it was easy to miss.
I have translated the interrupt demo from our python library to C.
#include
#include
#include
#include
#include "ABE_IoPi.h"
void clearscreen ()
{
printf("\033[2J\033[1;1H");
}
int main(int argc, char **argv)
{
setvbuf(stdout, NULL, _IONBF, 0); // needed to print to the command line
// initialise one of the io pi buses on i2c address 0x20, default address for bus 1
IOPi_init(0x20);
// Set all pins on the IO bus to be inputs with internal pull-ups enabled.
set_port_pullups(0x20, 0, 0xFF);
set_port_pullups(0x20, 1, 0xFF);
set_port_direction(0x20, 0, 0xFF);
set_port_direction(0x20, 1, 0xFF);
// Invert both ports so pins will show 1 when grounded
invert_port(0x20, 0, 0xFF);
invert_port(0x20, 1, 0xFF);
// Set the interrupt polarity to be active high and mirroring disabled, so
// pins 1 to 8 trigger INT A and pins 9 to 16 trigger INT B
set_interrupt_polarity(0x20, 1);
mirror_interrupts(0x20, 0);
// Set the interrupts default value to 0x00 so the interrupt will trigger when any pin registers as true
set_interrupt_defaults(0x20, 0, 0x00);
set_interrupt_defaults(0x20, 1, 0x00);
// Set the interrupt type to be 1 for ports A and B so an interrupt is
// fired when the pin does not match the default value
set_interrupt_type(0x20, 0, 0xFF);
set_interrupt_type(0x20, 1, 0xFF);
// Enable interrupts for all pins
set_interrupt_on_port(0x20, 0, 0xFF);
set_interrupt_on_port(0x20, 1, 0xFF);
while (1){
// read the interrupt status for each port.
// If the status is not 0 then an interrupt has occured on one of the pins
// so read the value from the interrupt capture.
if (read_interrupt_status(0x20, 0) != 0){
printf("Port 0: %x \n", read_interrupt_capture(0x20,0));
}
if (read_interrupt_status(0x20, 1) != 0){
printf("Port 1: %x \n", read_interrupt_capture(0x20,1));
}
usleep(200000); // sleep 0.2 seconds
}
return (0);
}
The difference between this and your code is I changed the interrupt type to be 1 on each pin so it will fire when the pin does not match the default value and I changed the while loop so on each loop the interrupt status for each port is checked and it only prints the result if the interrupt has fired.
I used the read_interrupt_capture() function to get the value of the interrupt when it fired and print that to the display.
When the code runs it will print the status repeatedly when a pin is connected to ground. If you only want it to print when the pin state changes change the set_interrupt_type(0x20, 0, 0xFF); to set_interrupt_type(0x20, 0, 0x00);
I have uploaded a copy of the c code to our GitHub repository at demo-iopiinterrupt.c
27/03/2020
Posted by:
Robspalu
Thanks for the new demo, just what I needed to help me understand my problem.
I have change the interrupt type so I detect each state change.
My intention now is to create a C library ABE_IoPi and a corresponding Lazarus wrapper so I can access the IoPi board from a Lazarus application I have already written, if successful I will need some more IoPi boards.
Thanks again for your help
Dave.
Note: documents in Portable Document Format (PDF) require Adobe Acrobat Reader 5.0 or higher to view.
Download Adobe Acrobat Reader or other PDF reading software for your computer or mobile device.