EIC INTFLAG bits

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

Hello everyone.

 

I am writing an interrupt handler for a external interrupt (EXTINT2) on an ATSAMC21N18A. I get by with a qualifier like this:

if (EIC->INTFLAG.reg & (1ul << 2))

but I'd much rather do something like:

if (EIC->INTFLAG.bit.EXTINT2)

I cannot access the INTFLAG register as bits, I get an error "has no member named 'EXTINT2.' When I look at the implementation in eic.h I see

typedef union { // __I to avoid read-modify-write on write-to-clear register
  struct {
    __I uint32_t EXTINT:16;        /*!< bit:  0..15  External Interrupt                 */
    __I uint32_t :16;              /*!< bit: 16..31  Reserved                           */
  } bit;                       /*!< Structure used for bit  access                  */
  uint32_t reg;                /*!< Type      used for register access              */
} EIC_INTFLAG_Type;

How do I access an individual bit in this register?

 

Last Edited: Tue. Apr 26, 2022 - 05:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can't use exactly the syntax you're after, this is just how C's bitfields work.

 

The EXTINT member of the bitfield has been setup 16 bits wide. If you're really tied to using the syntax you want, you could roll your own device header and define the bitfield with individual bits for each interrupt.

 

 

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

The other thing to consider, is why do you want to access like this?

 

Given the NVIC get's only 1 interrupt line for the entire EIC (unlike AVR INT pins which have an interrupt vector per pin) - unless you are using only 1 or 2 interrupt pins, and don't have extreme interrupt latency requirements - the more typical thing to do would be to find the interrupt source in the handler, and dispatch the required behaviour via a jump table (read: an array of function pointers), something like:

 

void EIC_Handler(void)
{
	for (uint8_t n = 0; n < 16; n++){			// Check which interrupt(s) caused the interrupt
		if (EIC->INTFLAG.reg & (1 << n)){
			EIC->INTFLAG.reg = (1 << n);            // Clear the interrupt flag
			if (jump_table[n] != NULL){
				jump_table[n]();		// Call the appropriate function
			}
		}
	}
}

 

static void (*const jump_table[16])(void) = {
	[0] =						NULL,
	[1] =	   					NULL,
	[2] =	                                        NULL,
    [DEFINE_SOMETHING_READABLE_FOR_THESE] =		NULL,
	[4] =                                           NULL,
	[5] =						NULL,
	[6] =						NULL,
	[7] =						NULL,
	[8] =		                                NULL,
	[9] =						NULL,
	[10] =		                                NULL,
	[11] =	                                        NULL,
	[12] =	                                        NULL,
	[13] =	                                        NULL,
	[14] =						NULL,
	[15] =						NULL,
};

 

Last Edited: Sun. May 8, 2022 - 07:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since the .bit unions have gone away in the Microchip more-recent versions of the include files, I think the official theory is that you should use:

 

if (EIC->INTFLAG.reg & EIC_INTFLAG_EXTINT1)

There is not, after all, bitwise access to those registers, and hinding that fact has caused problems (xxx.bit.foo = 1 to a register that clears bits when you write 1, does all sorts of wrong things.)

 

(which with the new .h files changes to)

  if (EIC_REGS->EIC_INTFLAG & EIC_INTFLAG_EXTINT1_Msk)

(such redundancy!  Alas, it almost makes sense; especially the use of _Msk and _Pos to keep those symbols apart.  Sigh.)

 

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

 Since the .bit unions have gone away in the Microchip more-recent versions of the include files

I see that.

 

At the end of the day no biggie, I just thought a bitwise access looks immediately more elegant.

 

But I notice there are no bitwise instructions in the Thumb instruction set - I'm coming from PICs with their rich bitwise access and maybe I have to get rid of that hangup.

 

Thanks all.

Last Edited: Tue. May 10, 2022 - 12:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lisican wrote:

 

But I notice there are no bitwise instructions in the Thumb instruction set - I'm coming from PICs with their rich bitwise access and maybe I have to get rid of that hangup.

 

 

True, but in the spirit of seeing the good in things - the ATSAM devices for many of the peripheral registers include xSET and xCLR registers, that allow you to set and clear individual bits, in a single cycle (i.e. without the compiler having to generate R/M/W routines). Whilst this doesn't exist for INTFLAG, keeping it contextual for the EIC, INTENSET and INTENCLR exist... from the datasheet:

26.8.7 Interrupt Enable Set
     Name: INTENSET
     Offset: 0x10
     Reset: 0x00000000
     Property: PAC Write-Protection
     This register allows the user to enable an interrupt without doing a read-modify-write operation. Changes in this
     register will also be reflected in the Interrupt Enable Clear (INTENCLR) register.

 

Unless of course you misread what these registers do, and them perform an |= on them. There's been several threads about this; I caught myself out too when I first started using ATSAM.

 

Edit: or - using bit access in the SET/CLR registers can itself cause all manner of pain. See this thread... use reg access, with the appropriate macro masks, and you can still set/clear individual bits, in a single cycle, where these registers exist.

Last Edited: Tue. May 10, 2022 - 12:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes these are most handy.

 

Though I must say though that for that particular example - " Changes in this register will also be reflected in the Interrupt Enable Clear (INTENCLR) register." - is quite counterintuitive to me.

 

Something like DIRSET does not affect DIRCLR, just the actual DIR register, as I would expect.

 

I am not a fan of how INTENSET and INTENCLR are coupled that way without an INT register in between, like in DIR. I find it counterintuitive that setting a bit in INTENCLR disables the interrupt but that is read back as a zero.

Last Edited: Tue. May 10, 2022 - 12:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lisican wrote:

is quite counterintuitive to me.

 

You and me both, I've only been working with ATSAM devices for ~9 months now, and I must admit I found the learning curve around the documentation/DFP headers/datasheets steep - but like anything, once you get your head into and accept the quirks it all falls into place easily enough.

 

I guess you've noticed the various OUTSET/OUTCLR registers now then, to help with your other thead? https://community.atmel.com/foru...

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

Yes, I did notice OUTSET/OUTCLR  early in the piece, quite liked that.  In that post I was looking for a quick way to shift bits (eg: incorporating byte swaps, etc.) but did not know that ARM bit shifts were single cycle for any number of places. (Coming from PICs all shifts were single bit at a time but nibble swaps could help there).