chipKIT® Development Platform

Inspired by Arduino™

[Code Posted] Change Notification Interrupts

Created Fri, 01 Jun 2012 22:16:43 +0000 by Demolishun


Demolishun

Fri, 01 Jun 2012 22:16:43 +0000

Hello all. I am currently testing a change to the WInterrupts.c to include support for Change Notification interrupts. It is working fine, but I was hoping to conditionally compile the checks that determine if the interrupt has triggered. That way one could control if it checks for an interrupt using a #define. I tried putting the define at the top of the sketch, but it does not affect the statements in the WInterrupts as it gets parsed first. If I cannot get this to work it is not a big deal. I will just include a header file that allows people to tweak the operation of the ISR.

Also, I currently have 2 settings: CHANGE and CHANGE_PULLUP. These do exactly what you would expect. One is a change interrupt and the other enables pullups.

One question I have is when you enable interrupt on a pin that is an output, can you still read PORTx to get the pin output state, or do I need to read LATx? Right now I am assuming PORTx will work and I will be testing this. I also checked the datasheet and the logic diagram for the port seem to indicate that the port state gets fed back to the read block. At least that is the way it looks to me.


EmbeddedMan

Sat, 02 Jun 2012 01:03:56 +0000

If you want to read the pin, read PORTx. If you want to read the state of the output latch, read LATx. They are separate things.

Now a write to PORTx is the same as a write to LATx, in essence.

*Brian


Demolishun

Sat, 02 Jun 2012 07:36:13 +0000

@EmbeddedMan, Thanks for the information!

Here it is: [url]http://demolishun.net/chipkit/[/url] Click on the change_notification link.
There are 4 files: 3 are source, one is a test example. The 3 source files go in: "mpide-0023-windows-20120429-test\hardware\pic32\cores\pic32"

Of course the example goes in your mpide folder.

I found that the documentation lists chipKit Pin # 12 as "SDI2/PMA5/CN8/RG7". This is wrong it should be "SDI2/PMA4/CN9/RG7". For a while I thought there was no access to CN9 on the board.

To use:

void somefunc(){
}
...
attachInterrupt(<EXT_CN2 through EXT_CN18>, somefunc, <CHANGE or CHANGE_PULLUP>);
...
detachInterrupt(<EXT_CN2 through EXT_CN18>);

I tried to stay true to the current implementation of the code so it is styled very similarly. Another thing to point out is that you should not enable CHANGE_PULLUP on a pin set to output. I don't know why, but the docs specifically say NOT to do this. I will bet it draws more current than it should or maybe it messes up stuff.

Outputs don't work with CN interrupts.

Please test and report back.

Edit: I have been doing some testing. It turns out that the pins seem to default to being OPEN (TRIS) on device reset. Interrupts do not trigger in that state. This is a really cool feature. That way you can effectively enable and disable interrupts on a pin just by calling the pinMode function. This could be useful for doing a button debounce for instance, or to limit the number of events to a sane rate, etc.


lanmat

Thu, 21 Jun 2012 21:38:08 +0000

@Demolishun, Awesome work! This is just what I was looking for.

I'm trying to make a single max32 be a flow rate meter for up to 12 different sensors, which requires pulse counting over a defined interval. Problem is using more than the 4 external interrupts.

The question/problem I have is: the Max32 has CN0 & CN1 available, but I can't quite figure out how to take your modifications in WInterrupts.c and modify them to get everything to work correctly. For instance, I figured out this doesn't work:

		case EXT_CN0:	// not on Uno32
			CNENbits.CNEN0		=	1;
			CNPUEbits.CNPUE0	=	pullup;
			CN_BIT_SET(cn_last,PORTB,0,0x01);
			break;
			
		case EXT_CN1:	// not on Uno32
			CNENbits.CNEN1		=	1;
			CNPUEbits.CNPUE1	=	pullup;
			CN_BIT_SET(cn_last,PORTB,0,0x02);
			break;

...any advice on getting these core library modifications to allow pulse counting on any CN input on the max32?


Demolishun

Tue, 26 Jun 2012 21:20:44 +0000

@lanmat, nice to meet you.

I apologize for not getting back to you quicker. It needs more changes than that. It also needs to have a couple of changes in the interrupt handler. There is room there in the handler, but it needs to be adjusted to have it actually call the interrupt when it sees the pin change. I can't look at it right now, but if you look at it try and see if you can figure it out. I am guessing you are now getting the interrupt, but it is just not doing anything with it.

I toyed before with enabling those on the Uno as well, but I wanted to keep it from messing with the clock pins or whatever those are connected to. I will look at it later this week and see if I cannot do some conditional compiling. I just don't want to have someone crashing their processor because it is enabled on the Uno.

Thanks for testing this library on the Max.


lanmat

Tue, 26 Jun 2012 23:48:05 +0000

No Problem. My immediate testing needs can be easily covered by the standard interrupts. Whenever you can take a look, I'd really appreciate it. I'll try messing around in the meantime.


Demolishun

Wed, 27 Jun 2012 02:19:42 +0000

Try this for enabling the interrupts:

// change notification interrupts
			case EXT_CN0:	
				#ifdef _BOARD_MEGA_
					CNENbits.CNEN0		=	1;
					CNPUEbits.CNPUE0	=	pullup;
					CN_BIT_SET(cn_last,PORTB,2,0x01);
				#else
					// not on Uno32
					#warning "EXT_CN0 is not implemented"				
					good_vector = 0;
				#endif
				break;
				
			case EXT_CN1:	
				#ifdef _BOARD_MEGA_
					CNENbits.CNEN1		=	1;
					CNPUEbits.CNPUE1	=	pullup;
					CN_BIT_SET(cn_last,PORTB,2,0x02);
				#else
					// not on Uno32
					#warning "EXT_CN1 is not implemented"				
					good_vector = 0;
				#endif
				break;

Try this for disabling:

// change notification interrupts
			case EXT_CN0:	
				#ifdef _BOARD_MEGA_
					CNENbits.CNEN0		=	0;
				#else
					// not on Uno32
					#warning "EXT_CN0 is not implemented"
					good_vector = 0;
				#endif
				break;
				
			case EXT_CN1:	
				#ifdef _BOARD_MEGA_
					CNENbits.CNEN1		=	0;
				#else
					// not on Uno32
					#warning "EXT_CN1 is not implemented"
					good_vector = 0;
				#endif
				break;

Add this in the interrupt just before the other function calls:

#ifdef _BOARD_MEGA_
		#ifndef DISABLE_EXT_CN0
		CN_CALLFUNC(EXT_CN0,0x01)
		#endif
		#ifndef DISABLE_EXT_CN1
		CN_CALLFUNC(EXT_CN1,0x02)
		#endif
	#endif

I also noticed there are more CN pins after the 19th one on the UNO32. However, I have no idea if the bits will line up. I am pulling the state of the bits from the port registers and storing those sequentially in a 32 bit number. I have no idea is those will line up with the MAX32 port pins or not. Unfortunately I don't have a MAX32 to test. So if you run into a pin that does not work it may be because I am not pulling the data from the right port. Or do the ports line up on a UNO32 versus a MAX32? If they do I should be able to easily add the extra ones after the 19th one.


majenko

Sun, 15 Jul 2012 17:57:09 +0000

I think it's a bit silly modifying the core for this task.

I have just knocked up a library (it took me about 30 minutes at the outside) to do change notification.

Your system looks needlessly complex and obfuscated to me.

Here's my library: [url]http://sourceforge.net/projects/chipkitcn/[/url] (it's only Beta at the moment - needs more testing).

Just do:

#include <ChangeNotification.h>

and you can use change notifications CN_0 thru CN_21 as the interrupt number to attachInterrupt() and detachInterrupt().

It supports FALLING, RISING and CHANGE as the interrupt types.

There is never any need to modify the core for simple tasks like this.


Demolishun

Sun, 15 Jul 2012 20:56:31 +0000

Looks great. It is definitely an option for people who do not want to modify the core.

My code changes follow the pattern laid out by the original coders. I did not write the code for edge triggering that already existed. It also follows the interface standards set the Arduino coders.

I see that yours allows for edge triggering which my version does not support. Good job on that. I also like that you came up with a way to index rather than use case statements. One thing to watch out for is CN pins that should not be enabled on specific platforms like CN0 and CN1. They should not be enabled on the uno32. Those pins control clock lines or something. So are unusable on the uno32 and enabling those might have bad effects on the uno32. Also, for very fast signals edge triggering may fail. As it may never see the actual state of the edge.

I felt that the core was incomplete so I added the code necessary to complete the features.

Your system looks needlessly complex and obfuscated to me.

Yeah, the lining up of the bits in the 32 bit word is a bit ugly. Other than that it pretty much follows the original pattern of the existing code.

There is never any need to modify the core for simple tasks like this.

Considering that the existing code is unfinished I don't agree with that statement. I have had to fix a couple of libraries now to get them to work properly. So I am doing my best to help the developers by fixing what I believe is broken and giving it back to them. I would suggest you do the same so they can choose from a number of options and perhaps combine the best of each method.


majenko

Sun, 15 Jul 2012 23:01:23 +0000

I always try and release my libraries on sourceforge and invite anyone who wants to to contribute. If anyone wants to contribute to any of my libraries I will gladly add you as a committer to the project.


majenko

Tue, 17 Jul 2012 19:05:10 +0000

My library now supports multiple interrupts per pin - one per direction type.

detachInterrupt(CN_x) will remove ALL interrupts from a pin.

attachInterrupt(CN_x,function,direction) will add the interrupt to that specific direction. You can add a function to multiple directions:

attachInterrupt(CN_4,pressed,RISING);
attachInterrupt(CN_4,released,FALLING);

You can remove a single direction interrupt with:

detachInterrupt(CN_x,direction);

woerr

Fri, 13 Jan 2017 12:27:07 +0000

I get the following errors from changenotification.h

using uecide 0.8.8alpha22

First plib.h was missing, so I added it from mpide. Then adc10 was missing, So I added it from mpide.

Now I get the following when compiling.

Error at line 29 in file ChangeNotification.cpp: ‣ invalid conversion from 'volatile unsigned int*' to 'volatile uint32_t* {aka volatile long unsigned int*' [-fpermissive]}

I understand that maybe just copying files from mpide may not work. I am just looking for a workaround.


majenko

Fri, 13 Jan 2017 12:39:36 +0000

Where / how did you get changenotification.h et al? It could be you have the wrong version? plib.h should not be a requirement.


woerr

Fri, 13 Jan 2017 12:59:47 +0000

I got it from http://sourceforge.net/projects/chipkitcn/

Removed that and installed it via uecide plugin manager and it works fine.


majenko

Fri, 13 Jan 2017 14:58:20 +0000

I thought so. That one should not exist, but I cannot get rid of it. It should be telling you to go to github on the home page.