InterruptAttach() Am I using it right?

Hi,

I am trying to get interruptions to work on my beagleboard-xm and it doesn’t work. I don’t know if the problem is coming from the QNX part of the programmation or the DM3730 part.

[code]
volatile bool isLedOn = 1;
volatile bool ResetStatus = 0;
bool error = 0;
struct sigevent event;

int main(int argc, char *argv[]) {
std::cout << “Interrupt test program” << std::endl;
pthread_create(NULL,NULL,&intr_thread,NULL);
std::cout<<“Thread Creation successful” <<std::endl;
while(!error);
std::cout<<“END OF PROGRAM”<<std::endl;
return EXIT_SUCCESS;
}

const struct sigevent* isr_userbutton(void* arg, int id){
isLedOn = isLedOn ^ 1;
ResetStatus = 1;
return (&event);

}

void intr_thread(void){
uintptr_t mmap_addr;
if (ThreadCtl(_NTO_TCTL_IO,0)== - 1){
std::cout << “Thread control failed”<< std::endl;
error = 1;
}
else{
if(InterruptAttach(29,isr_userbutton,NULL,0,_NTO_INTR_FLAGS_TRK_MSK) == -1){
std::cout<<“InterruptAttach() failed”<<std::endl;
error = 1;
}
else{
ConfigLed();
ConfigInterrupt();
ConfigGPIOInterrupt();

		while (1){
			if (isLedOn){
				mmap_addr = MapUserspace(4,0x49056094);
				out32(mmap_addr,GPIO_22);
				munmap_device_io(mmap_addr,4);
			}
			else{
				mmap_addr = MapUserspace(4,0x49056090);
				out32(mmap_addr,GPIO_22);
				munmap_device_io(mmap_addr,4);
			}
			if (ResetStatus)
				ResetIRQStatus();
		}
	}
}
return EXIT_SUCCESS;

}[/code]

This is the essential part. Am I using AttachInterrupt() right? I am aware that I should release the Interrupt somewhere in code but it’s really just exploratory so I didn’t bother implementing it. So I just want to know if it’s my QNX implementation that’s at fault or the DM3730. Here is the other part of the code for the definitions of the functions.

uintptr_t MapUserspace (unsigned int len,unsigned long address){
	uintptr_t mmap_addr;
	mmap_addr = mmap_device_io(len,address);
	if (mmap_addr == MAP_DEVICE_FAILED){
		std::cout << " mmap_device_io failed" << std::endl;
		error = 1;
	}
	return mmap_addr;
}


void ConfigInterrupt(void){
	uintptr_t mmap_addr;
	uint32_t buffer;

	mmap_addr = MapUserspace(4,0x48200010); //Sysconfig
	out32(mmap_addr,0);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x48200050); //Idle
	out32(mmap_addr,0);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x48200174); //ILRm
	out32(mmap_addr,0);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x48200010); //MIRn
	buffer = in32(mmap_addr) | GPIO_29;
	out32(mmap_addr,buffer);
	munmap_device_io(mmap_addr,4);

	std::cout<<"ConfigInterrupt Done"<<std::endl;
}

void ConfigGPIOInterrupt (void){
	uintptr_t mmap_addr;
	uint32_t buffer;

	mmap_addr = MapUserspace(4,0x48310064); //Set IRQ Enable 1
	out32(mmap_addr,GPIO_4);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x48310074); //Set IRQ Enable 2
	out32(mmap_addr,GPIO_4);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x48310048); //Rising Edge
	buffer = in32(mmap_addr) | GPIO_4;
	out32(mmap_addr,buffer);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x48310018); //IRQ Status 1
	out32(mmap_addr,GPIO_4);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x48310028); //IRQ Status 2
	out32(mmap_addr,GPIO_4);
	munmap_device_io(mmap_addr,4);

	std::cout<<"ConfigGPIOInterrupt Done"<<std::endl;
}

void ResetIRQStatus (void){
	uintptr_t mmap_addr;
	mmap_addr = MapUserspace(4,0x48310018); //IRQ Status 1
	out32(mmap_addr,GPIO_4);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x483100); //IRQ Status 2
	out32(mmap_addr,GPIO_4);
	munmap_device_io(mmap_addr,4);
	ResetStatus = 1;

	std::cout<<"ResetIRQStatus Done"<<std::endl;

}

void ConfigLed (void){
	uintptr_t mmap_addr;
	uint32_t buffer;

	mmap_addr = MapUserspace(4,0x48002A0C);//PADCONF user button
	buffer = (in32(mmap_addr) & 0x0000FFFF) | 0x050C0000;
	out32(mmap_addr,buffer);
	munmap_device_io(mmap_addr,4);

	mmap_addr = MapUserspace(4,0x48310034);//GPIO OE
	buffer = in32(mmap_addr) | GPIO_4;
	out32(mmap_addr,buffer);
	munmap_device_io(mmap_addr,4);
	std::cout<<"ConfigLed Done"<<std::endl;
}

I don’t have any compilation and kernel errors and I am lost…
Thank you ,
Jean-Francois

JeanFrancois,

I am not sure what your final program will be/look like. However if at all possible I would suggest you use InterruptAttachEvent instead. It’s a tiny bit slower but has the huge advantage that the InterruptHandler (your code) can be debugged since it runs in User Space instead of Kernel Space. Using InterruptAttachEvent also means that you can’t accidentally hang the operating system which is nice :slight_smile:

Since you are returning an Event in your ISR, you need an InterruptWait call in your code (usually a separate thread) that waits for that event to get returned telling you that the ISR was triggered. I highly suggest you read the ‘Writing an Interrupt Handler’ section in the Help Doc’s as it has some sample code there.

qnx.com/developers/docs/6.3. … ndler.html

Tim

Hi Tim,

for now this program will only change a LED state (ON/OFF) when I will press the userbutton on the Beagleboard-XM. It’s really just an exploratory program for interruption.

I did read the link you’ve sent me but I am new to OS programmation in general and the informations is scattered (I feel so). I’ll re-read again and try to understand it more.

I will try the InterruptAttachEvent() and see what I can do. When you say slower , how much slower are we talking about?

So one way to see it is if I use InterruptAttachEvent() instead of InterruptAttach(), I’m trading speed for stability?

Thank you for you informations Tim,

Jean-Francois

I’m reading this post and the code and it looks very confused. It also seems to be incomplete so I can’t really address the question directly, but here are some observations.

  1. I don’t see an interrupt handler anywhere in the code. As is suggested, you don’t need one if you just want to be informed in user space when an interrupt occurs, but then you would want to do an InterruptAttachEvent().

  2. In the main you do a hard, almost infinite loop. This is generally a bad idea. Unless you have more than one processor, or you run at a low priority, this will typically lock up your system. At least until the “error” variable is modified. I notice that you did not make “error” volatile, which itself might be a problem.

  3. In the hardware access code, you seem to be bracketing your I/O access with mmap_device_io()
    and munmap_device_io(). While this code should work, it’s not how it’s done. You should use mmap_device_io() once during initialization and then just access the I/O port. There’s not reason to keep un-mapping it and re-mapping it.

  4. You start a thread called intr_thread, but I don’t see that code anywhere.

Hi maschoen,

for the interrupt handler and intr_thread, they are both in the first section of the code. the isr is

const struct sigevent* isr_userbutton(void* arg, int id){
   isLedOn = isLedOn ^ 1;
   ResetStatus = 1;
   return (&event);

}

and the thread is

void *intr_thread(void*){
   uintptr_t  mmap_addr;
   if (ThreadCtl(_NTO_TCTL_IO,0)== - 1){
      std::cout << "Thread control failed"<< std::endl;
      error = 1;
   }
   else{
      if(InterruptAttach(29,isr_userbutton,NULL,0,_NTO_INTR_FLAGS_TRK_MSK) == -1){
         std::cout<<"InterruptAttach() failed"<<std::endl;
         error = 1;
      }
      else{
         ConfigLed();
         ConfigInterrupt();
         ConfigGPIOInterrupt();

         while (1){
            if (isLedOn){
               mmap_addr = MapUserspace(4,0x49056094);
               out32(mmap_addr,GPIO_22);
               munmap_device_io(mmap_addr,4);
            }
            else{
               mmap_addr = MapUserspace(4,0x49056090);
               out32(mmap_addr,GPIO_22);
               munmap_device_io(mmap_addr,4);
            }
            if (ResetStatus)
               ResetIRQStatus();
         }
      }
   }
   return EXIT_SUCCESS;
}

My main is doing a hard infinite loop I am aware of that. I’m not used to OS programming. With no OS, you don’t want to program to run once so you put the setup at the beginning of the program and loop for the action you want to do. How would I go if I want to program to in a loop without creating a loop like I did? If I don’t put that loop, I’ll have to restart the program each time I want to change the LED state once…

As for the munmap_device_io ,I just close the userspace for each of the registers when I’m done to make sure I will not be conflicting with what is already running on the board. I don’t think that is my problem here though.

After Tim’s post, I went on to look for documentation for InterruptAttachEvent() and it’s not clear for me. Correct me if i’m wrong, but by using InterruptAttachEvent(), when an interrupt occur, a signal or pulse is send to notify of the interrupt. So with InterruptWait(), I just wait for an interrupt and when there is an Interrupt, I check whatever register I need to check to see if it’s the interrupt I am waiting for (in my case, Pin 4 on GPIO1) and do the action accordingly. So do I get that right?

while(1)
{
InterruptWait();
DoWhatYouWant();
}

mmap_device_io() does not reserve the I/O port, nor does it restrict another process from using it. It just give your process access. I agree, your code should be fine, it’s just unnecessary.

That’s right. InterruptWait() is waiting for the pulse to arrive. If you have nothing else to do, you can do this in your main thread. If you want to do something else while you wait for the interrupt, you can create a new thread to call InterruptWait().

If I do

while(1)
{
InterruptWait();
DoWhatYouWant();
}

or

while(!error) ;

and process the interrupt in another thread, I don’t see how that is any different. If my main just run through , I won’t be able to do anything in my threads. So if I put while(!error); as long as there isn’t an error popping, it will stay in the main thread. And if my understanding if right, the child threads (in my case intr_thread) are the same priority so they should share CPU time. I do my processing in my thread and the main is basically just an empty shell creating the pthread for the intr_thread. I might be wrong though.

As for mmap_device_io , if each time I re-call mmap_addr = mmap_device_io(len,address) for the same addresses , will that create a memory bloat or something like that ? Or it’s really just assigning a new virtual address to mmap_addr ?

JFGagnon,

What happens depends on what kind of scheduling you have. If it’s FIFO then your main() code will never give up the CPU to your child thread that runs the code that does the work. If it’s Round Robin, it will give up the CPU but only after it consumes it’s time slice (likely 10 ms which is a long time if the hardware you are going to read from could change state in that time). You will also starve any other process that is running that is of lower priority (unlike when you program directly without an O/S, like say on a PIC Micro Controller, there are always other processes running on QNX).

If you want to do nothing in your main thread, change it to:

while (!error)
{
delay (10); // sleep for 10 milliseconds
}

This way instead of hogging the CPU it will go to sleep letting other threads/processes run immediately. This is the polite thing to do :slight_smile:

Tim

Hence why
while(1)
{
InterruptWait();
DoWhatYouWant();
}
will be better. Thanks for the infos.

Jean-Francois

I was able to make an interruption work with InterruptAttachEvent() . For anyone who might be struggling, I am posting my code error for reference. It`s not the best commented code but that should get you started. I am using the beagle board Xm. Basically , what the program does is switch the led D6 when you press the userbutton on the beagleboard. Thanks for the help Tim and maschoen.

#include <cstdlib>
#include <iostream>
#include <sys/mman.h>
#include <pthread.h>
#include <sys/neutrino.h>
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <hw/inout.h>

#define GPIO_4 	0x00000010
#define GPIO_29 0x20000000

void ConfigInterrupt(void);
void ConfigGPIOInterrupt (void);
void ResetIRQStatus (void);
void ConfigLed (void);
uintptr_t MapUserspace (unsigned int len,unsigned long address);
void *intr_thread(void*);
void *wait_thread(void*);

volatile bool isLedOn = 1;
volatile bool ResetStatus = 0;
volatile bool isIntrOn = 0;
volatile bool error = 0;
struct sigevent event;


int main(int argc, char *argv[]) {
	uintptr_t mmap_addr;
	uint32_t mem;
	event.sigev_notify = SIGEV_INTR;
	std::cout << "Interrupt test program 1:48" << std::endl;
	if (ThreadCtl(_NTO_TCTL_IO,0)== - 1){
			std::cout << "Thread control failed"<< std::endl;
			error = 1;
		}
	else{
			if (InterruptAttachEvent(29,&event,_NTO_INTR_FLAGS_TRK_MSK) == -1)
				std::cout << "Attach Interrupt failed"<<std::endl;
			else{
				ConfigLed();
				ConfigInterrupt();
				ConfigGPIOInterrupt();
				while(1){
					std::cout<<"Before Interrupt Wait"<<std::endl;
					mmap_addr = MapUserspace(4,0x48310018);
					std::cout<<"IRQ Status : "<<std::hex<<in32(mmap_addr)<<std::endl;

					mmap_addr = MapUserspace(4,0x48200090);
					std::cout<<"INTCPS_ISR_SET : "<<std::hex<<in32(mmap_addr)<<std::endl;

					InterruptWait(0,0);
					mmap_addr = MapUserspace(4,0x48310018);
					std::cout<<"Interrupt Wait"<<std::endl;
					mmap_addr = MapUserspace(4,0x48310018);
						isLedOn = isLedOn ^1;
						if (isLedOn){
							mmap_addr = MapUserspace(4,0x49056094);
							out32(mmap_addr,GPIO_22);
						}
						else{
							mmap_addr = MapUserspace(4,0x49056090);
							out32(mmap_addr,GPIO_22);
						}
						mmap_addr = MapUserspace(4,0x48310018);
						std::cout<<"IRQ Status : "<<std::hex<<in32(mmap_addr)<<std::endl;

						ResetIRQStatus();
				}
			}
		std::cout<<"END OF PROGRAM"<<std::endl;
		return EXIT_SUCCESS;
	}

}

uintptr_t MapUserspace (unsigned int len,unsigned long address){
	uintptr_t mmap_addr;
	mmap_addr = mmap_device_io(len,address);
	if (mmap_addr == MAP_DEVICE_FAILED){
		std::cout << " mmap_device_io failed" << std::endl;
		error = 1;
	}
	return mmap_addr;
}


void ConfigInterrupt(void){
	uintptr_t mmap_addr;

	mmap_addr = MapUserspace(4,0x48200010); //Sysconfig
	out32(mmap_addr,0);

	mmap_addr = MapUserspace(4,0x48200050); //Idle
	out32(mmap_addr,1);

	mmap_addr = MapUserspace(4,0x48200174); //ILRm
	out32(mmap_addr,0);

	mmap_addr = MapUserspace(4,0x48200088); // Clear MIRn
	out32(mmap_addr,GPIO_29);

	std::cout<<"ConfigInterrupt Done"<<std::endl;
}

void ConfigGPIOInterrupt (void){
	uintptr_t mmap_addr;
	uint32_t buffer;

	mmap_addr = MapUserspace(4,0x48310064); //Set IRQ Enable 1
	out32(mmap_addr,GPIO_4);

	mmap_addr = MapUserspace(4,0x48310048); //Edge (rising = 0x48, falling = 0x4C)
	buffer = in32(mmap_addr) | GPIO_4;
	out32(mmap_addr,buffer);

	mmap_addr = MapUserspace(4,0x48310018); //IRQ Status 1
	out32(mmap_addr,GPIO_4);


	std::cout<<"ConfigGPIOInterrupt Done"<<std::endl;
}

void ResetIRQStatus (void){
	uintptr_t mmap_addr;
	mmap_addr = MapUserspace(4,0x48310018); //IRQ Status 1
	out32(mmap_addr,GPIO_4);

	mmap_addr = MapUserspace(4,0x48200088); //Clear MIR
	out32(mmap_addr,GPIO_29);

	std::cout<<"ResetIRQStatus Done"<<std::endl;

}

void ConfigLed (void){
	uintptr_t mmap_addr;
	uint32_t buffer;

	mmap_addr = MapUserspace(4,0x48002A0C);//PADCONF user button
	buffer = (in32(mmap_addr) & 0x0000FFFF) | 0x050C0000;
	out32(mmap_addr,buffer);
}

***EDIT : It also works with InterruptAttach() function. You just have to create the ISR and replace InterruptAttachEvent(29,&event,_NTO_INTR_FLAGS_TRK_MSK) by InterruptAttach(29,&isr_userbutton,0,0,_NTO_INTR_FLAGS_TRK_MSK)

And create an ISR

const struct sigevent* isr_userbutton(void* arg, int id){
isLedOn = isLedOn ^ 1;
return (&event);

}[/code]

and remove the line [code]
isLedOn = isLedOn ^1;

in the original code.