How to identify the input pin which have triggered the interrupt (using ASF library)?

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am trying to detect the input pin which have triggered the interrupt. But it appears that the library is already reading the interrupt status register. And that's why status register is cleared and I can not read it again inside my interrupt function.

 

void PIOA_Handler(void)
{
	pio_handler_process(PIOA, ID_PIOA);
}

Above is the Library side Interrupt handler, which calls the function below.

void pio_handler_process(Pio *p_pio, uint32_t ul_id)
{
	uint32_t status;
	uint32_t i;

	/* Read PIO controller status */
	status = pio_get_interrupt_status(p_pio);
	status &= pio_get_interrupt_mask(p_pio);

	/* Check pending events */
	if (status != 0) {
		/* Find triggering source */
		i = 0;
		while (status != 0) {
			/* Source is configured on the same controller */
			if (gs_interrupt_sources[i].id == ul_id) {
				/* Source has PIOs whose statuses have changed */
				if ((status & gs_interrupt_sources[i].mask) != 0) {
					gs_interrupt_sources[i].handler(gs_interrupt_sources[i].id,
							gs_interrupt_sources[i].mask);
					status &= ~(gs_interrupt_sources[i].mask);
				}
			}
			i++;
			if (i >= MAX_INTERRUPT_SOURCES) {
				break;
			}
		}
	}

	/* Check capture events */
#if (SAM3S || SAM4S || SAM4E)
	if (pio_capture_enable_flag) {
		if (pio_capture_handler) {
			pio_capture_handler(p_pio);
		}
	}
#endif
}

And the bolded "handler" is my interrupt function pointer who is supposed to know which pin have called the interrupt. I am trying to not edit the library files, I do not want to pass the status to my Interrupt function.

This topic has a solution.
Last Edited: Wed. Feb 9, 2022 - 01:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like you can have more than one handler (up to MAX_INTERRUPT_SOURCES) each having a mask (handling a subset of the pins), is this not enough?
/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The above code is from library itself (pio_handler.c) I have only one handler for PIOA and I am using 4 pins (PIOA15, PIOA16, PIOA17, PIOA18) I want my interrupt handler pointer (named "handler") to know the content of variable "status" but I cant think of a way without disturbing the library code.

 

The "mask" is actually the enabled interrupt pins I have used 4 pins so the mask always have 4 bits set (respect to the pins I've used).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why only one handler is what I'm asking. You have this function to add more I guess (just from google search, I did not try it):
 

/**
 * \brief Set an interrupt handler for the provided pins.
 * The provided handler will be called with the triggering pin as its parameter
 * as soon as an interrupt is detected.
 *
 * \param p_pio PIO controller base address.
 * \param ul_id PIO ID.
 * \param ul_mask Pins (bit mask) to configure.
 * \param ul_attr Pins attribute to configure.
 * \param p_handler Interrupt handler function pointer.
 *
 * \return 0 if successful, 1 if the maximum number of sources has been defined.
 */
uint32_t pio_handler_set(Pio *p_pio, uint32_t ul_id, uint32_t ul_mask,
		uint32_t ul_attr, void (*p_handler) (uint32_t, uint32_t))

/Lars

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since you get the mask as the handlers second parameter you can actually just set the same handler function 4 times (different masks).

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

it appears that the library is already reading the interrupt status register. And that's why status register is cleared

Does reading the ISR clear the bits?  I thought most of the SAM GPIO peripherals needed explicit clearing...

 

I'm not sure that the code you're looking at goes with the SAML10 chips.  From the datasheet, it looks like pin interrupts go through the EIC peripheral rather than the PORT peripheral.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
I'm not sure that the code you're looking at goes with the SAML10 chips.

I'm sure it's not for SAML10, Tag says SAM4S.

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'll assume that this is an ASF4 ("Start") based project?  (ASF3 doesn't seem to have support for SAML.)

I created a sample Start Project for SAML10 and found the actual ISR code used:

/**
 * \brief Inter EIC interrupt handler
 */
static void _ext_irq_handler(void)
{
	volatile uint32_t flags = hri_eic_read_INTFLAG_reg(EIC);
	int8_t            pos;
	uint32_t          pin = INVALID_PIN_NUMBER;

	hri_eic_clear_INTFLAG_reg(EIC, flags);

	ASSERT(callback);

	while (flags) {
		pos = ffs(flags) - 1;
		while (-1 != pos) {
			uint8_t lower = 0, middle, upper = EXT_IRQ_AMOUNT;

			while (upper >= lower) {
				middle = (upper + lower) >> 1;
				if (_map[middle].extint == pos) {
					pin = _map[middle].pin;
					break;
				}
				if (_map[middle].extint < pos) {
					lower = middle + 1;
				} else {
					upper = middle - 1;
				}
			}

			if (INVALID_PIN_NUMBER != pin) {
				callback(pin);
			}
			flags &= ~(1ul << pos);
			pos = ffs(flags) - 1;
		}
		flags = hri_eic_read_INTFLAG_reg(EIC);
		hri_eic_clear_INTFLAG_reg(EIC, flags);
	}
}

There are a couple of interesting things I noticed there:

  1. Definitely not the same as the SAM4/3 code.
  2. The interrupts are handled in hpl/hpl_eic.c - the "external interrupt handler driver", rather than in the Port driver.
  3. The handler DOES clear the INTFLAGS.  Repeatedly.
  4. The pin number IS passed to the callback function as an argument (the only argument), so you don't need to re-examine INTFLAGS.
  5. I'm not sure what those nested while loops are doing.  Maybe checking all the pins that a particular interrupt might occur on?  (I was pretty sure than one SAMD, only one pin can have the interrupt enabled at a time.)
  6. (Seems potentially slow :-( )

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
  • I'm not sure what those nested while loops are doing.
  • (Seems potentially slow :-( )

Hmm.  "Start" builds a "#defined" table of just the pins that you've configured to generate interrupts, so potentially the loops optimize away if you only have one (or a couple?) of pins thus configured...