Assigned IRQ interrupt to digital pin

Status
Not open for further replies.
Each time I read this thread, I am still wondering what exactly are you trying to accomplish?

Are you trying to completely emulate the current code? If so you should probably just use the current code...

Or are you finding that the current code has more overhead than you want or???

If you are wanting the fastest possible and you can arrange your setup such that you know only your pin will be the only pin on that port that will have in interrupt vector assigned to it,
Then you can simply use the attachInterruptVector call, like:

Code:
attachInterruptVector(IRQ_PORTC, &My_ISR);

Then your function is called for any interrupt that happens on PORTC.

Warning your function needs to clear that status, or it will be called again and again...
This is why in the old version of the functions that Paul linked to:
Code:
void portc_isr(void)
{
	// TODO: these are inefficent.  Use CLZ somehow....
	[COLOR="#FF0000"]uint32_t isfr = PORTC_ISFR;
	PORTC_ISFR = isfr;[/COLOR]
	if ((isfr & CORE_PIN9_BITMASK) && intFunc[9]) intFunc[9]();
	if ((isfr & CORE_PIN10_BITMASK) && intFunc[10]) intFunc[10]();
	if ((isfr & CORE_PIN11_BITMASK) && intFunc[11]) intFunc[11]();
	if ((isfr & CORE_PIN12_BITMASK) && intFunc[12]) intFunc[12]();
	if ((isfr & CORE_PIN13_BITMASK) && intFunc[13]) intFunc[13]();
	if ((isfr & CORE_PIN15_BITMASK) && intFunc[15]) intFunc[15]();
	if ((isfr & CORE_PIN22_BITMASK) && intFunc[22]) intFunc[22]();
	if ((isfr & CORE_PIN23_BITMASK) && intFunc[23]) intFunc[23]();
	if ((isfr & CORE_PIN27_BITMASK) && intFunc[27]) intFunc[27]();
	if ((isfr & CORE_PIN28_BITMASK) && intFunc[28]) intFunc[28]();
	if ((isfr & CORE_PIN29_BITMASK) && intFunc[29]) intFunc[29]();
	if ((isfr & CORE_PIN30_BITMASK) && intFunc[30]) intFunc[30]();
}
The two lines marked in RED are important. The first line retrieves the bit mask of which interrupt pin actually happened, which is used with the testing of bits to call off to the other functions.
But the 2nd line of function is also important. By writing those bits back to the register clear out that interrupt status.

But again nut sure exactly where you are going with this.

As for CORE_NUM_DIGITAL - Yes this is the total number of digital pins as per model type.

Yes that is the standard definition of a function pointer that the function takes no parameters and returns no value...
 
I am sorry if seen my questions are ripetitive or stupid .Or maybe I didn’t write so well English .
Thanks for your explanation. Indeed the Void function portc_Isr it is a function for retrieves, so it come after .
Before of it, attached_interruptVector , and of it I must understand how to attach the memory address of Vector 105 or IRQ89 that it is 0x000001A4 to my entry point of my Function .
As I understand ( maybe I wrong) the CPU stop base on that event and call the entry point .
How ? Where ?
I didn’t see that address ....
This is only for understand .
And since I still not well prepared maybe I confuse you and other .
 
In PJRC code the interrupt points to the portc_isr() code above - any pin interrupt causes that function to be called. That function can be replaced in the primary interrupt address table.

That portc_isr() code then pulls from a table of addresses per pin to call the _isr as recorded here in the AttachInterrupt call.

But interrupt per pin is not a hardware function - it is done in code as shown in post #26 ... again these references are to PRIOR PJRC code.
 
Interrupt pin are not , but the portC it is or I am wrong ?
That address I post before it is of hardware because it start with 0x0000....
So , ( I am trying to understand ) what the compiler understand , because 105 or 89 are reference for us , but the memory location where is wrote ?
 
I must understand how to attach the memory address of Vector 105 or IRQ89 that it is 0x000001A4 to my entry point of my Function .

Much of the info about how ARM Cortex-M4 interrupt vectors really work is not written in the datasheets. It's published in this book.

https://www.amazon.com/dp/0124080820

The info is also published in ARM's architecture reference manual. But ARM's reference is very difficult to read. Yiu's book is much easier, though it does cost real money. To get the hard to read but free reference, google for "DDI0403E".

If you really need to learn this low-level ARM stuff, I highly recommend buying Yiu's book.
 
Which Teensy is being used - the code accounts for the changing layout of the interrupt vectors for each processor used.

This table in ...\hardware\teensy\avr\cores\teensy3\mk20dx128.c sets up the address to call portc_isr()::
Code:
void (* const _VectorsFlash[NVIC_NUM_INTERRUPTS+16])(void) =
{
// ...
 
Is this a student project?

Perfectly ok if it is... we can help you better if we actually understand what you're trying to accomplish.
 
No , at 45 years old what student I can be !
It is only for the pleasure to understand Learning do not have age .
It is not easy , I know it , but only because I didn’t get the gear jet .... but will become easy with the time .
By the way , thanks you all for your support .
 
No , at 45 years old what student I can be !
It is only for the pleasure to understand Learning do not have age .
That is Young... Some of us are considerably older... Learning is great at any age! ;)

For me, learning here, is I learn by example... For example I mentioned try using attachInterruptVector.

If you then look through the code you will find:
Code:
void attachInterruptVector(enum IRQ_NUMBER_t irq, void (*function)(void))
{
	_VectorsRam[irq + 16] = function;
}
So you see that this just stuffs your function into the array: _VectorsRam and it offsets it by 16 units...
As @defragster mentioned this table is defined in mk20dx128.c

Now if you look at the datasheet for the processor you are using, which you can download from pjrc website: https://www.pjrc.com/teensy/datasheets.html
Example Teensy 3.6, and look at interrupt channel assignments, in this case it is section 3.4, you will find there are 16 ARM core system handler vectors, followed by the Non-Core vectors...
It starts out with a bunch of DMA interrupts. You will then find that Pin Detect (PORT C) is IRQ=61 Vector 77...

However one more set of complications. When your program is built, the actual interrupt vector table you see in the mk... file is actually:
Code:
__attribute__ ((section(".vectors"), used))
void (* const _VectorsFlash[NVIC_NUM_INTERRUPTS+16])(void) =
{

And then as part of the system reset handler: void ResetHandler(void)
Which is called as part of the chip Reset code,

At about line 772, you will see a couple lines of code:
Code:
	// default all interrupts to medium priority level
	for (i=0; i < NVIC_NUM_INTERRUPTS + 16; i++) _VectorsRam[i] = _VectorsFlash[i];
	for (i=0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_PRIORITY(i, 128);
	SCB_VTOR = (uint32_t)_VectorsRam;	// use vector table in RAM
This copies the interrupt vector out of flash memory into RAM, sets the priority of all of the interrupts to 128 (mid point), and then tells the system to use the interrupt vector which is now part of RAM.

So when you have setup to have an interrupt on PORTC on some pin and the pin changes, the system will call what ever is stored in _VectorsRam[77].

When depends on what the processor is doing at that time. That is if it is running normal user code or a lower priority (higher number) interrupt it will call immediately. If it is in a higher priority interrupt it will wait until that interrupt returns (and there are not any other higher priority interrupts pending).

And as I mentioned in previous post, if you do not clear the interrupt condition, it will continue to call your function again and again...

Hope that helps some.
 
I like your explanation , and it is work as you say , indeed it was already clear , that why I am looking for a direct call without using any pointers array table with enum or combined macro .
Since I enable ISR(89) ( for the T3.2) directly setting the memory register , since is enable , my ISR(89) have his unique static address location 0x000001A4 , this ( I believe if I am not wrong ) that when event happen , the CPU will point to that location first , then from there to my_function entry point ... e she/he will do his/her job .
Now I try to understand and find out how I can do it .... Placing inside that memory a ponter that point to the & of my function ?
Since I do not see any reference of that address in any c o h file inside ( IDE of Teensy ) I am getting crazy .... because it must have a fix WORD to let the compiler know that (89) in the vector table means that memory location .
Or I am crazy
 
Maybe it is _VectorsRAM , if so , this word do this job ( if I am not wrong ).
That why Paul clearly suggest me to study the architecture and language .
 
And only then , when I will understand , I will use the comfortable smart way of the final function attachedinterrupt .
Because otherwise I will create even more empty holes in my brain...hahahah
 
Not sure what you are asking?

Again if you look at mk20dx128.c You will see that the table is setup depending on board:
As for T3.2, the Interrupt number for PORTC isr is different than for T3.6... So you need to look at what is defined for MK20DX256...

I believe the interrupt is actually something like 105.. But again best to use the the #defines for IRQ_PORTC than if you change to different processor it will know the right one...

Now if you are looking for the default implementation for portc_isr? There is none...

That is in the mk20... file you will see:
Code:
void portc_isr(void)		__attribute__ ((weak, alias("unused_isr")));
So by default this interrupt vector has a default value in it to call unused_isr
Which simply does:
Code:
void unused_isr(void)
{
	fault_isr();
}
So it will do a hard fault (reset your board)

There are lots of these unused ISRs in the default table, again which will fault the board if nothing else is defined.

But since the attribute is set as weak, this gives you a couple of options.

1) Do what I mentioned above and call the attachInterruptVector.


OR

2) Simply define your own function portc_isr

That is your Arduino sketch could have in it:
Code:
void portc_isr() {
    // Do my ISR stuff
}
Note: This needs to have "C" linkage, but since arduino will include kinetis.h all of these ISR functions are defined inside of a
Code:
extern "C" {
...
extern void portc_isr(void);
...
}
 
Yes , you right it is how it work .
But I think I must study more , because words as _attribute , week , alias , i must clear first in my head.
Hard fault happen if the IRQ it is abilitate but no function are assigned .... indeed you set up a pin for input , setting characteristics of the interrupt .... let this happen and all stuck !!!
Why should reset a not abilitate IRQ otherwise ??
Anyway , I will try to clear more words .
I am lost in so many questions .
 
Considering that I received the book in Thailand not before August 22nd, I'm trying to do MY point.
There are three things we need to do in writing an ISR. These things are:

initialize the interrupt handler // ( My_F)
declare the ISR function // ( My_F)
define the ISR's interrupt vector // and since i know the Memory location 0x000001A4 , inside this memory should stay the address of My_F Handler !!


Code:
// #define IRQ89      (*( uint32_t *)0x000001A4)  // or Vector 105
#define ppul6     6                          // pin Button of PortC is PTC6
unsigned long x=0; // My variable 

//void (*M)();

void My_F();
void My_F(){ // My Function 
PORTC_PCR6 &= ~(1 << ppul6); // clear the flag 
x +=1;  // increment my variable

} // end of My_F 

extern void My_F();
#pragma abs_address:0x000001A4;   // it should force the compiler to assign to that memory location , the entry point ( &My_F) 
void (* My_F_irq[])()={My_F}; // i am passing the & of My_F
#pragma end_abs_address 


void setup() {
Serial.begin(9600); // enable to monitor the event 
SIM_SCGC5 = ( 1 << 11 ) ; // set for PORT C e /m Clock Gating Control Register 5 (SIM_SCGC5)
PORTC_PCR6 = ( 1 << 19 ) | ( 1 << 17 ) | ( 1 << 8 ) | ( 1 << 1 ) | ( 1 << 0 );// Type of interrupt and INPUT and Pull Up

NVIC_ENABLE_IRQ(IRQ_PORTC); // Enable Interrupt for PORT_C setting the register 
NVIC_SET_PRIORITY(IRQ_PORTC, 64); // I SET ALSO THE PRIORITY , because function Serial it is active .



}// end of the Setup 

void loop() { 
delay(1000); // wait for a second
Serial.println(x);

}


When I press the button, everything stops, so I make a mistake or more errors.

Then I also tried another system to understand if the address of IRQ89 acquires address of My_F using attachInterruptVector (IRQ_PORTC, My_F);
Using this function all run perfect , so i believe that reading with function pointer the memory address of My_F , should be equal to the value wrote in the memory location 0x000001A4 // or Vector 105 or IRQ89 .... but is not .

And look like that Teensy IDE give this warning .
Studio_IRQ:16: warning: ignoring #pragma abs_address
#pragma abs_address:0x000001A4;

Studio_IRQ:18: warning: ignoring #pragma end_abs_address
#pragma end_abs_address

Where i am wrong ??
 
You might make use of the library I just posted - :: LTO-Compile-Error

Ignore the error and don't compile optimize with LTO.

Hopefully the examples will show you logging the line number of the FAULT so you can see what line precedes the fault.

Common faults go to one of five I pulled out as they were 'weak' - I keep the MCU alive and process output and make note of which fault _isr was triggered.

You get this feature just by putting it in your libraries folder and then adding the include, but adding a couple of other things can get the LED to blink and show and record line numbers near the fault it if traps safely.

Also - the PORTC interrupt vector is called on any pin on that port - noted in prior posts. It seems different pins can have different settings at the same time - so somewhere in there must be a reference to what pin those apply to? Also when the interrupt comes back it could be - as noted before - any pin on that port so the parsing code demonstrated by Paul on github to determine that.
 
Wait a minute .... interrupt vector are not called from the other pins of port C if you not set the other pins to make it happen .
In my example , Is fix to be for only one pin , so all the other pins are free and not related to interrupt vector 85.
I will try to modify the compiler option as you suggest by the way. But I believe are other mistake .
 
But I believe are other mistake .

Pre-defined weak linked names are assigned in kinetis.h and they are used in mk20dx128.c. The intended method is to simply create a function with the same name as used in kinetis.h, because the flash-based table is already populated with these names. Pragma is not the way. You can see the pre-defined name method used in the older attachInterrupt code which I have repeatedly urged you to read. The pre-defined name is used at line 182 in that code.

Why do you not read & follow the example code?
 
Paul , think easy , of course I read it , simply I am trying to learn how to attach my Named function to an Interrupt directly in the memory of the array .Without using your work, but not because I am not appreciate but because I must learn the way . Using a ready function do not mean knowing about programming. That why I run crazy ! Because I am not able to programming !
I tried to over write my function with Pragma , forcing the address of my function to that address.
IRQ89 must store only one function address for the Hanler_Function , or I am wrong ?
From that function then you can pickup the pin that cause the interrupt , and base of the result you can run other functions.
If I wrong , sorry guys ....
 
Status
Not open for further replies.
Back
Top