Project Home
Project Home
Documents
Documents
Wiki
Wiki
Discussion Forums
Discussions
Project Information
Project Info
Forum Topic - how to enable gpio interrupt on beaglebone black ?: (8 Items)
   
how to enable gpio interrupt on beaglebone black ?  
Hi QNX,

QNX Momentics IDE 6.5 SP1
beaglebone black BSP: bsp-nto650-ti-beaglebone-sp1-trunk-201209071340.zip

I have trouble to enable gpio interrupt on BBB. reference to the previous post in this forum, which claimed working with
 other board MX6X.
http://community.qnx.com/sf/discussion/do/listPosts/projects.core_os/discussion.newcode.topc24286

I connected BBB gpio1_28 to a push button, and in32(gpio_base + GPIO_DATAIN) shows gpio1_28 bears correct value when 
button pushed, however, the program never enters interrupt handler.

Below is my code, please help. Thanks in advance

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/neutrino.h>
#include <unistd.h>
#include <sys/mman.h>
#include <arm/inout.h>
#include <errno.h>
#include <arm/am335x.h>
#include <sys/iofunc.h>
#include <sys/dispatch.h>

#define MY_PIN			(1<<28)
int irq  = 98;
static uint32_t irqcount = 0;

static void Delay1(volatile unsigned int count)
{
    while(count--);
}

static const struct sigevent *handler(void *area, int id)
{
	irqcount++;
	printf("enter interrupt\n");
	return NULL;
}


int main(int argc, char *argv[])
{
	printf("0\n");

	if (ThreadCtl(_NTO_TCTL_IO, 0) == -1) {
		printf("ThreadCtl\r\n");
		return (!EOK);
	}

	uintptr_t gpio_base;

	int result = InterruptAttach( irq, handler, &gpio_base, sizeof(&gpio_base), _NTO_INTR_FLAGS_PROCESS);
    if(result == -1)
    {
    	printf("InterruptAttach error\r\n");
    }

   	// pin configuration ...
    gpio_base = mmap_device_io(AM335X_GPIO_SIZE, AM335X_GPIO1_BASE);
    if(gpio_base == MAP_DEVICE_FAILED)
    {
        perror("Can't map device I/O");
        return 0;
    }

	// set INPUT direction for MY_PIN	// 1 input
	out32( gpio_base + GPIO_OE, in32(gpio_base + GPIO_OE) | MY_PIN );

    if(in32(gpio_base + GPIO_DATAIN) & MY_PIN)
    	printf("connected 0 \n");
    else
    	printf("Disconnected 0\n");

	// set Interrupt CONFIGURATION "Rising Enge" for MY_PIN
	out32( gpio_base + GPIO_RISINGDETECT,  in32(gpio_base + GPIO_RISINGDETECT)  | MY_PIN );
	out32( gpio_base + GPIO_FALLINGDETECT, in32(gpio_base + GPIO_FALLINGDETECT) | MY_PIN );
	out32( gpio_base + GPIO_LEVELDETECT0,  in32(gpio_base + GPIO_LEVELDETECT0)  & ~MY_PIN );
	out32( gpio_base + GPIO_LEVELDETECT1,  in32(gpio_base + GPIO_LEVELDETECT1)  & ~MY_PIN );

	// set Interrupt ENABLED for MY_PIN
	out32( gpio_base + GPIO_IRQSTATUS_SET_0, in32(gpio_base + GPIO_IRQSTATUS_SET_0) | MY_PIN );//0x34
	out32( gpio_base + GPIO_IRQSTATUS_SET_1, in32(gpio_base + GPIO_IRQSTATUS_SET_1) | MY_PIN );//0x3c

	// GPIO_IRQWAKEN
	out32( gpio_base + 0x44, in32(gpio_base + 0x44) | MY_PIN );
	out32( gpio_base + 0x48, in32(gpio_base + 0x48) | MY_PIN );

	InterruptEnable();


	while(1)
	{
        Delay1(0xFFFFFF);
        Delay1(0xFFFFFF);
        Delay1(0xFFFFFF);
        Delay1(0xFFFFFF);

        if(in32(gpio_base + GPIO_DATAIN) & MY_PIN)
        	printf("connected %u\n", irqcount);
        else
        	printf("Disconnected %u\n", irqcount);

	}

	return EXIT_SUCCESS;
}
Re: how to enable gpio interrupt on beaglebone black ?  
Hi Mike,
you cannot use the general cascade vector 98. Instead, QNX provides individual logical GPIO IRQ vectors.

If you look into init_intrinfo.c, you can see that GPIO1 common interrupt 98 is the cascade vector for 32 logical levels
 starting at 0x320 (=800 dez.). So ino rder to attach to pin 28 inside GPIO bank 1, you would need to attach to vector 
828 (800 + 28).

Regards,
Albrecht
Re: how to enable gpio interrupt on beaglebone black ?  
One more hint, regarding this:

int result = InterruptAttach( i..., &gpio_base, sizeof(&gpio_base) ...

I believe your goal is to have access to the mapped GPIO registers inside IRQ handler. However, you should
- first map the GPIO base into virtual memory
- then configure the GPIO
- then attach the IRQ handler, passing the *value* of gpio_base (e.g. the virtual adress) and the real size of the 
mapped object, in your case AM335X_GPIO_SIZE

Regards,
Albrecht
Re: how to enable gpio interrupt on beaglebone black ?  
Dear Albrecht,

Thank you for this quick answers. I modified my C program as suggested, HOWEVER, QNX is crashing and then restart when I
 push the button to invoke interrupt during my program running. Crashing message as below and follows my modified C 
codes. Please help to take a look. Thanks in advance.

# 
Shutdown[0,0] S/C/F=0/0/0 C/D=fe01f694/fe09d02c state(1)= 1
QNX Version 6.5.0 Release 2012/06/20-13:48:57EDT
[0]PID-TID=77846-1? P/T FL=00001800/81000000 "tmp/zzzblogspot_gmichael151920897210236"
armle context[effe8ee4]:
0000: 00000001 effe8f38 00000002 00000000 00000000 effe8f48 fe09b8a8 00002000
0020: effeaff0 effeaff0 fe09d054 effe8fc4 0000000b 000ffec8 00100c58 01037d28
0040: 80000113
instruction[01037d28]:
10 80 bd e8 10 40 bd e8 85 70 ff ea 10 40 2d e9 08 40 9d e5 0b c0 a0 e3 00 00 
stack[000ffec8]:
0000: 00100d64 00689af0 00000000 000ffefc 00000004 00100664 000fff04 00000001
0020: 28000000 0000000b 00000001 00000001 000fff65 00100778 00000001 000fff65
0040: 00000000 000fff89 00000000 00000003 00100034 00000004 00000020 00000005
0060: 00000006 00000009 001006b8 00000006 00001000 00000007 01000000 0000002d
U-Boot SPL 2013.04-rc1-14237-g90639fe-dirty (Apr 13 2013 - 13:57:11)
musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, HB-ISO Rx, HB-ISO Tx, SoftConn)
musb-hdrc: MHDRC RTL version 2.0 
musb-hdrc: setup fifo_mode 4
musb-hdrc: 28/31 max ep, 16384/16384 memory
..........
.......... 

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/neutrino.h>
#include <unistd.h>
#include <sys/mman.h>
#include <arm/inout.h>
#include <errno.h>
#include <arm/am335x.h>
#include <sys/iofunc.h>
#include <sys/dispatch.h>

#define MY_PIN			(1<<28)
int irq  = 828;
static uint32_t irqcount = 0;


static void Delay1(volatile unsigned int count)
{
    while(count--);
}

static const struct sigevent *handler(void *area, int id)
{
	irqcount++;
	printf("enter interrupt\n");
	return NULL;
}


int main(int argc, char *argv[])
{
	if (ThreadCtl(_NTO_TCTL_IO, 0) == -1) {
		printf("ThreadCtl\r\n");
		return (!EOK);
	}

	// pin configuration ...
	uintptr_t gpio_base = mmap_device_io(AM335X_GPIO_SIZE, AM335X_GPIO1_BASE);
        if(gpio_base == MAP_DEVICE_FAILED)
        {
              perror("Can't map device I/O");
              return 0;
        }

	// set INPUT direction for MY_PIN	// 1 input
	out32( gpio_base + GPIO_OE, in32(gpio_base + GPIO_OE) | MY_PIN );

	// set Interrupt CONFIGURATION "Rising Edge/Falling Edge" for MY_PIN
	out32( gpio_base + GPIO_RISINGDETECT,  in32(gpio_base + GPIO_RISINGDETECT)  | MY_PIN );
	out32( gpio_base + GPIO_FALLINGDETECT, in32(gpio_base + GPIO_FALLINGDETECT) | MY_PIN );
	out32( gpio_base + GPIO_LEVELDETECT0,  in32(gpio_base + GPIO_LEVELDETECT0)  & ~MY_PIN );
	out32( gpio_base + GPIO_LEVELDETECT1,  in32(gpio_base + GPIO_LEVELDETECT1)  & ~MY_PIN );

	// set Interrupt ENABLED for MY_PIN
	out32( gpio_base + GPIO_IRQSTATUS_SET_0, in32(gpio_base + GPIO_IRQSTATUS_SET_0) | MY_PIN );//0x34
//	out32( gpio_base + GPIO_IRQSTATUS_SET_1, in32(gpio_base + GPIO_IRQSTATUS_SET_1) | MY_PIN );//0x3c

	// GPIO_IRQWAKEN
	out32( gpio_base + 0x44, in32(gpio_base + 0x44) | MY_PIN );
//	out32( gpio_base + 0x48, in32(gpio_base + 0x48) | MY_PIN );

	InterruptEnable();

	int result = InterruptAttach( irq, handler, &gpio_base, AM335X_GPIO_SIZE, _NTO_INTR_FLAGS_PROCESS);
	if(result == -1)
	{
		printf("InterruptAttach wrong\r\n");
	}
	else
	{
		printf("Attached IRQ ID = %d\r\n", result);
	}

	while(1)
	{
        Delay1(0xFFFFFF);
        Delay1(0xFFFFFF);
        Delay1(0xFFFFFF);
        Delay1(0xFFFFFF);

        if(in32(gpio_base + GPIO_DATAIN) & MY_PIN)
        	printf("connected %u\n", irqcount);
        else
        	printf("Disconnected %u\n", irqcount);
	}

	return EXIT_SUCCESS;
}
Re: how to enable gpio interrupt on beaglebone black ?  
You must not use printf() inside an interrupt handler.

http://www.qnx.com/developers/docs/6.5.0SP1.update/index.html#./com.qnx.doc.neutrino_prog/inthandler.html is a nice and 
concise description of how to implement IRQ handlers correctly. In particular, the "Safety Information" section.

Regards,
Albrecht
Re: how to enable gpio interrupt on beaglebone black ?  
Dear Albrecht,

Thank you for the great advices. Printf kills the system. After deleting printf(..), interrupt as designed.

Best

Mike
Re: how to enable gpio interrupt on beaglebone black ?  
The code in an ISR executes in kernel mode, which means that
1. It cannot make any kernel calls
2. Any fault in the code will bring down the system
3. Any delays in the code will adversely affect the responsiveness of
the system

For these reasons we strongly recommend that you do not use ISRs,
unless absolutely necessary (e.g., need to read/write registers only
accessible in the most privileged mode). Instead, use
InterruptAttachEvent() and handle the interrupt in a high-priority
thread.

--Elad

On Wed, 2018-02-21 at 07:05 -0500, Albrecht Uhlmann wrote:
> You must not use printf() inside an interrupt handler.
> 
> http://www.qnx.com/developers/docs/6.5.0SP1.update/index.html#./com.q
> nx.doc.neutrino_prog/inthandler.html is a nice and concise
> description of how to implement IRQ handlers correctly. In
> particular, the "Safety Information" section.
> 
> Regards,
> Albrecht
> 
> 
> 
> _______________________________________________
> 
> OSTech
> http://community.qnx.com/sf/go/post118607
> To cancel your subscription to this discussion, please e-mail ostech-
> core_os-unsubscribe@community.qnx.com
Re: how to enable gpio interrupt on beaglebone black ?  
thank you for the suggestions, lesson learned.

Best