View previous topic :: View next topic |
Author |
Message |
NWilson
Joined: 30 Jun 2011 Posts: 21 Location: King's Lynn. England
|
PIC24 'Interrupt-on-change Notification' problem |
Posted: Sat Jul 06, 2013 7:57 am |
|
|
Compiler : V5.008
PIC24FJ256GA106
Hi everyone, I am trying to use the 'Interrupt-on-change Notification' to wake up an instrument using two port pins.
The problem is, that I can wake the instrument up from either port pin , but when I combine them the compiler doesn't like it. Can anyone please tell me what I'm doing wrong, as I'm having a hard time figuring this one!
example code
Code: | #define ON_OFF PIN_D9
#define POWERGOOD PIN_F3
enable_interrupts(INTR_CN_PIN|ON_OFF); // This works OK
enable_interrupts(INTR_CN_PIN| POWERGOOD); // So does this
enable_interrupts(INTR_CN_PIN|ON_OFF|POWERGOOD); // Error
#INT_CNI
void cni_isr(void)
{
if(!input(ON_OFF))
{
// Do something
}
if (input(POWERGOOD))
{
// Do something
}
}
|
Thanks in advance |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Sat Jul 06, 2013 8:21 am |
|
|
I've always done them individually. I don't think you can combine them into one statement. Doing them individually will still turn them all on. On change interrupts change an additional register which you can verify in the LST file. For example, I am using 4 on change interrupts on a current project and individually setting them works such that all 4 trigger the interrupt. |
|
![](templates/subSilver/images/spacer.gif) |
NWilson
Joined: 30 Jun 2011 Posts: 21 Location: King's Lynn. England
|
|
Posted: Sat Jul 06, 2013 8:46 am |
|
|
Hi jeremiah,
Thanks for the quick reply,
Still a little confused! do you mean that I've nearly got it right, I just enable the interrupts separately and have one interrupt handler or do I have to have separate interrupt handlers for each pin?
I.E.
Code: | #define ON_OFF PIN_D9
#define POWERGOOD PIN_F3
enable_interrupts(INTR_CN_PIN|ON_OFF); // Enable each pin separately
enable_interrupts(INTR_CN_PIN| POWERGOOD);
enable_interrupts(INTR_GLOBAL);
#INT_CNI
void cni_isr(void)
{
if(!input(ON_OFF))
{
// Do something
}
if (input(POWERGOOD))
{
// Do something
}
} |
If you've got an example that would be great.
Regards
Neil |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Sat Jul 06, 2013 9:09 am |
|
|
What you have there will work.
Just be careful how you handle the ISR as all rising and falling edge transitions on each of your inputs will cause the whole ISR to trigger. It's a little extra processing, but I like to check and see what the previous I/O state was in addition to the current state to ensure it was an edge transition for that particular I/O. Also, if any of your inputs for the interrupt are from a button or switch type input, you may have to also consider debouncing, depending on the application. |
|
![](templates/subSilver/images/spacer.gif) |
NWilson
Joined: 30 Jun 2011 Posts: 21 Location: King's Lynn. England
|
|
Posted: Sat Jul 06, 2013 9:18 am |
|
|
Cheers Jeremiah
The code in the ISR de-bounces a switch and checks when the battery is charging, so is a little bit more complicated than that shown.
I didn't think to enable them separately, but will give it a go when I get back to work on Monday.
Regards
Neil |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Sat Jul 06, 2013 11:48 am |
|
|
It is somewhat confusing.
The Interrupt on Change, is the one form of interrupt where you 'OR' things in. There is a 'remark' in the include file which says something like 'OR with a define' (note the 'a'). What seems to happen is that it calculates back from the pin number, to generate the bit in the mask register, but doesn't handle multiple bits in one instruction. It would be impossible to do from multiple 'ored' values, since if you 'or two pin defines, you get another pin. However if you do it twice, and check what is generated, it merrily sets multiple bits.
It's a non documented limitation of the way the compiler does things.
Yes there is only one actual 'CNI' interrupt.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Jul 07, 2013 2:08 am |
|
|
I must confess that I never became aware of the problem because I enabled change notification of individual
bits by writing to the CNENx registers. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19366
|
|
Posted: Sun Jul 07, 2013 3:34 am |
|
|
Agreed
What goes wrong, is inherent in the way that CCS defines pin names. So (for instance), PIN_B0 is 5696, B1 5697, B2 5698 etc.. If you 'or' B0, with B1, you get the number for B1, while if you or B1, with D0 (5697, with 5792), you get 5857, which is not a legitimate pin number, and hence the 'error'.
What is 'silly' is that they should have either defined masks for this function (called something like CNEN_B0 for example), which could then directly be masks, and therefore could be ore'd together, or have thoroughly documented the limitation of the current approach.....
They are trying to be a little too 'smart', by using the existing pin names.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
NWilson
Joined: 30 Jun 2011 Posts: 21 Location: King's Lynn. England
|
|
Posted: Sun Jul 07, 2013 4:07 am |
|
|
Hi Ttelmah / FvM,
Many thanks for clearing that up for me. I must admit that after your reply yesterday I did some 'Or' ing and couldn't possibly see how Code: | enable_interrupts(INTR_CN_PIN|ON_OFF|POWERGOOD); |
could work.
As for writing directly to the CNENx registers, as FvM does, I'd rather let the compiler deal with things like that as I'm a relatively inexperienced programmer.
Hopefully I will get it going tomorrow.
Regards
Neil |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Sun Jul 07, 2013 7:35 am |
|
|
One thing to watch out for is you are using the new compiler which is still very new. I have something similar to what you posted in your last example working in 3 different projects, but on the 4.xxx compiler version. If it doesn't work, check the LST output of the 5.xxx compiler and make sure the calls to enable_interrupts are doing 2 things: 1.) Turning on the CNI interrupt and 2.) changing the CNENx registers (if I remember correctly, it is a bit set instruction).
You are right in that you shouldn't need to directly address the CNENx register at all. |
|
![](templates/subSilver/images/spacer.gif) |
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Jul 07, 2013 8:21 am |
|
|
I'm not against CCS built-in functions, they are convenient and mostly do what they claim to do. But sometimes
you need to go down to the SFR level to achieve a specific function, either because the built-in function has
errors or cant' do something by design. With CNI enable it's the latter case, unfortunately the manual doesn't mention
the restriction of only enabling a single pin per function call.
To use CNENx SFR, you must know the CNx bit number associated to a pin, then set the respective bit in CNENx register. Consequently, CNIE0 to CNIE15 are in CNEN1, CNIE16 to CNIE31 in CNEN2 etc.
You can use #bit to define individual CNIEx bits and #word to define the CNENx registers. |
|
![](templates/subSilver/images/spacer.gif) |
|