4700 interrupts

From Technologic Systems Manuals

We include a userspace IRQ patch in our kernels. This allows you to receive interrupts from your applications where you would normally have to write a kernel driver. This works by creating a file for each interrupt in '/proc/irq/<irqnum>/irq'. The new irq file allows you to block on a read on the file until an interrupt fires.

The original patch is documented here.

The Linux kernel supports up to 16 IRQs from the FPGA. When the CPU receives an IRQ from the FPGA, it uses the IRQ register in the #Syscon to find out which IRQ on the MUX is triggering. Currently only three IRQs are used. Off-board IRQs 5, 6, and 7 correspond to FPGA IRQs 0, 1, and 2, respectively. FPGA IRQs 3 to 15 are reserved for future uses. If the DIO pins are not being used as IRQs, they can be masked out by writing 0 to the corresponding bit in the IRQ mask register.

IRQ # Name Socket Location
49 Combined GPIO Interrupt Any MFP pin
64 XUART IRQ N/A
65 CAN1 IRQ N/A
66 CAN 2 IRQ N/A
67 IRQ5/DIO_00[1] CN1-93
68 IRQ6/DIO_01[1] CN1-91
69 IRQ7/DIO_02[1] CN1-89
70 EVGPIO N/A
  1. 1.0 1.1 1.2 The PC/104 IRQs need to have the MUXBUS bus enabled in order to function as IRQs

This example below will work with any of our products that support userspace IRQs. It opens the IRQ number specified in the first argument, and prints when it detects an IRQ.

#include <stdio.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char **argv)
{
	char proc_irq[32];
	int ret, irqfd = 0;
	int buf; // Holds irq junk data
	fd_set fds;

	if(argc < 2) {
		printf("Usage: %s <irq number>\n", argv[0]);
		return 1;
	}

	snprintf(proc_irq, sizeof(proc_irq), "/proc/irq/%d/irq", atoi(argv[1]));
	irqfd = open(proc_irq, O_RDONLY| O_NONBLOCK, S_IREAD);

	if(irqfd == -1) {
		printf("Could not open IRQ %s\n", argv[1]);
		return 1;
	}
	
	while(1) {
		FD_SET(irqfd, &fds); //add the fd to the set
		// See if the IRQ has any data available to read
		ret = select(irqfd + 1, &fds, NULL, NULL, NULL);
		
		if(FD_ISSET(irqfd, &fds))
		{
			FD_CLR(irqfd, &fds);  //Remove the filedes from set
			printf("IRQ detected\n");
			
			// Clear the junk data in the IRQ file
			read(irqfd, &buf, sizeof(buf));
		}
		
		//Sleep, or do any other processing here
		usleep(10000);
	}
	
	return 0;
}

Any of the MFP pins can be repurposed to trigger IRQ 49. For example, to make MFP_46 (CN2_72) trigger on a rising edge:

# Enable rising edge detection on MFP_46
peekpoke 32 0xD4019034 0x4000

# Unmask MFP_46
peekpoke 32 0xD40190A0 0x4000

# to clear the interrupt after it has been triggered
peekpoke 32 0xD401904c 0x4000

See page 169 of the CPU manual for more information on the interrupt controller.