Assigned IRQ interrupt to digital pin

Status
Not open for further replies.

M.Melani

Active member
Hi guys,
( SORRY IF I DOUBLE POST , I AM NEW AND I MISTAKE FORUM )
I hope someone more capable of me can help me solve this dilemma.
I'm not a professional programmer so I apologize if my question could be trivial.

I am using Teensy 3.2 , great device by the way ....

I do not want to use function void attachInterrupt(uint8_t pin, void (*function)(void), int mode) because i must understand how it work to first , because i would like to manipulate Register directly .

In my example I want to enable one pins on the PORT C for input ,
and the unique interrupt 89 is enable by NVIC_ENABLE_IRQ(IRQ_PORTC); ,
, and the pin is configured for INT enable .
When INTERRUPT event happen ---> from kinesis.h this function will be called extern void portc_isr(void);

///////////////////////////////////////////////

uint32_t x=0;

void MY_FUNC(){

x++;

}

SIM_SCGC5 = ( 1 << 11 ) ; // EnablePortC Clock Gating Control Register 5 (SIM_SCGC5)
PORTC_PCR6 = ( 1 << 19 ) | ( 1 << 17 ) | ( 1 << 8 ) | ( 1 << 1 ) | ( 1 << 0 );

// where PRC6 is pin 11 of the register PORTC_PCR6

NVIC_SET_PRIORITY(IRQ_PORTC, 64); // set the priority to value 64

NVIC_ENABLE_IRQ(IRQ_PORTC); // enable IRQ for PORT C


//////////////////////////////////////////////////////////////////////////////
Now my point is ..... With this configuration, the whole port C is enabled for the interrupt 89 , but how can I address that pin PRC6 only to my MY_FUNC function?
How can I record the call of my function ?
I imagine using function pointers.
But what is the particular Interrupt memory register for that pin ?

Trying to understand the functioning mechanics of the function void attachInterrup() :
These lines in particular are those that carry out the addressing operation.

voidFuncPtr* isr_table = getIsrTable(config); // ??? i don't know , but i believe interr IRQ_PORTC
if(!isr_table) return;
uint32_t pin_index = getPinIndex(config); // i get the pin number
__disable_irq();
cfg = *config;
cfg &= ~0x000F0000; // disable any previous interrupt
*config = cfg;
isr_table[pin_index] = function; // set the function pointer !!!!!! THIS IS THE MOST !!!!


PLEASE can I have an example using the registers in a direct way ??
IM becoming crazy
NEED HELP

Thanks
Massi
 
the GPIO interrupts are managed with attachInterrupt() as you note. The work is done in hardware/teensy/avr/cores/teensy3/pins_teensy.c
You can configure individual pins for interrupt, but there is only one interrupt per PORTx. When you issue attachInterrupt(), pins_teensy.c stores the function pointer in a isr_table[] for each PORTx. When the pin interrupts, the PORTx interrupt routine is called,e.g. port_C_isr(). That function is defined by a macro in pins_teensy.c
https://github.com/PaulStoffregen/cores/blob/master/teensy3/pins_teensy.c#L272
Code:
#define PORT_ISR_FUNCTION_CLZ(port_name) \
    static void port_ ## port_name ## _isr(void) {            \
        uint32_t isfr = PORT ## port_name ##_ISFR;            \
        PORT ## port_name ##_ISFR = isfr;                     \
        voidFuncPtr* isr_table = isr_table_port ## port_name; \
        uint32_t bit_nr;                                      \
        while(isfr) {                                         \
            bit_nr = __builtin_ctz(isfr);                     \
            isr_table[bit_nr]();                              \
            isfr = isfr & (isfr-1);                           \
            if(!isfr) return;                                 \
        }                                                     \
    }
the port_C_isr() has to see which pin interrupted by checking each bit in the PORTx_ISFR. If a bit is set, the user isr function handler is called from the isr_table[] and the ISFT bit for the pin is cleared.
 
Last edited:
Very old versions had much simpler (but lower performance) attachInterrupt code.

Here is a link to the oldest code on github:

https://github.com/PaulStoffregen/c...b545f3697d0552428f/teensy3/pins_teensy.c#L103

Inside each of the 5 interrupt functions, group of "if" statements in the old code is much simpler, but slower than using the CLZ optimization the new version uses. The old way code had a very simple structure using ordinary functions, rather than the new way with complicated C preprocessor macros.

Hopefully the old, simpler code will be easier to understand?
 
Beautiful this forum, thanks for your clear answers ....
Actually, a few months ago I was delighted on a Texas TM4C123GH6PM Cortex-M4 processor, which actually has the register for each pin.
The speed of the Teensy 3.2, and its small size stimulated me to start getting to know it. (Since a week)
Stupidly I believed (while reading the manual) and not find the respective interrupts for each pin, considering that the architecture of the M4 was identical for everyone, but even if it is, not for this functionality.
The macro code of the attachInterrupt function is very well written, and I'm still a bit blind in deciphering function pointers and various structures.
Eg : volatile static voidFuncPtr intFunc[CORE_NUM_DIGITAL] = { [0 ... CORE_NUM_DIGITAL-1] = dummy_isr };

{ [0 ... CORE_ What is the meaning of those points after 0 ???

or

static void port_ ## port_name ## _isr(void) { What is the meaning of ## , does the compiler see them as non-existent ? Or are they replace d?

Of course I'm still very blind but i keep studying .

Regarding the isr_table[] , ....Is an ISR_TABLE created or does it refer to the interrupt list of H files?

Sorry .... I have a thousand questions, I really like this and I can not stop
 
In the new code, there are 5 "isr_table" arrays, at lines 154-159. They're static arrays, basically the same as if you create an array of integers.

Code:
int myarray[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

But instead of a simple type like "int", they are function pointers, and the size of the array is a constant defined elsewhere, and they use a fancy syntax to initialize the array.
 
Thank you Paul , you great !
I must study Concatenation , never use it before .
What about voidFuncPtr intFunc[CORE_NUM_DIGITAL] = { [0 ... CORE_NUM_DIGITAL-1] = dummy_isr };
What is the meaning of those points after 0 ??? Why 3 ?
 
Hi everyone ,

Base on what i read over your examples and complex function pointers , i replicate some functions , but for simple int array i got error on Arduino(Teensy) IDE as :
"expected identifier before numeric constant " .... why ??

example , before setup i declare a int array :

int C[10]= {[0 ... 9] = 5 };

Where i am wrong ?
 
try this:

int C[10]= { 5 };
As I understand the OP's question, he/she wanted all 10 members of C to be set to 5. Your code would set C[0] to 5, and 0 to everything else.

I don't think C++ supports a way to do that initialization (GNU C has some support for non-linear initializations, but GNU C++ never adapted it, and Arduino/Teensy uses C++ underneath it).

So the simplest way is:
Code:
  int C[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

Or do it at run time in your setup function:
Code:
  for (size_t i = 0; i < 10; i++)
    C[i] = 5;
 
As Paul post , previously ,

https://stackoverflow.com/questions...ize-all-members-of-an-array-to-the-same-value

f your compiler is GCC you can use following syntax:

int array[1024] = {[0 ... 1023] = 5};

And this way it is used to create the attachedinterrupt() function for Teensy , indeed it is compiled by the IDE of Teensy ... so it is correct .

I tried on other IDE , and it is compiled without any problem .

I believe i make mistake in some way .

It should be compiled .

That way it is very smart , because with 3 dot you can easily initialize array to functions , to address of function ,assuring that all the memory for the array is well allocated ,

So i believe should have some reason during the declaration .
 
As Paul post , previously ,

https://stackoverflow.com/questions...ize-all-members-of-an-array-to-the-same-value

f your compiler is GCC you can use following syntax:

int array[1024] = {[0 ... 1023] = 5};.
As I said earlier, that is a GNU C extension. The GNU C++ compiler does not support it. When you use an .ino or .pde file, it is converted into C++ code. While much of C is a subset of C++, there are differences, and there are some things that are C only and not part of C++. Likewise with GNU C extensions, are not necessarily also available as GNU C++ extensions.
 
As I understand the OP's question, he/she wanted all 10 members of C to be set to 5. Your code would set C[0] to 5, and 0 to everything else.

I don't think C++ supports a way to do that initialization (GNU C has some support for non-linear initializations, but GNU C++ never adapted it, and Arduino/Teensy uses C++ underneath it).

So the simplest way is:
Code:
  int C[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

Or do it at run time in your setup function:
Code:
  for (size_t i = 0; i < 10; i++)
    C[i] = 5;

I 'm silly, you are right.
 
Hi guys !! I really need help .....

While accelerating the study on function pointers, structures, Typedefinition, enumerators, I really have difficulty reconstructing the minimum system of use of memory addresses to directly access the ISR of port C, and assign my function.
Unfortunately, I have hard head and I'm not prepared on the subject.
From what I understand (shortly summarizing an iterrupt on a pin), when an event happens, because we have set for that type of event for that port, after setting the pin and port feature, the microprocessor interrupts its main routines and accesses the address of MY_FUNCTION (which I have clearly defined before and assigned the entry point),….. and from there I will look for the interested pin , clear the event (flag) and let's example increment a global variable X .
In the two files ( pins_teensy.c and kinetis.h ) there are all the declarations, and in particular in the kinetis.h file, where all the memory addresses have been named (Very nice work ) .
I would like to use only the kinetis.h , I do not want to use READY functions, until I understand the minimum structure. Then I'm sure everything will have a similar gear for all the other features of the micro.

My simple program :

#define ppul6 6 // pin Button of PortC is PTC6
unsigned long x=0; // My variable

void My_Func(){ // My Function
x++; // increment my variable
PORTC_PCR6 &= ~(1 << ppul6); // I clear the Flag of the interrupt ( I do not have to read the result = PORTC_ISFR & (1<<ppul6); because It is only one pin)
} // Exit …


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 .

!!!!! and now I do not know how to assign my function to the enabled interrupt !!!!
What is the way to link the memory location of the interrupt with the entry point of my function? So how do I assign this pointer ?

} end of the Setup

void loop() {
delay(1000); // wait for a second
Serial.println(x); // My variable increases every time I press the button referred to ground on pin // 11 of Teensy
}



///// Thanks
 
PJRC has an efficient solution to catch the PORT int and direct it to a given pin's _isr(). Finding and reading that code is the best answer and doc for the issue starting with attachInterrupt()
 
It is true, very efficient , but it not easy to read . I believe all start from the enumerated Isr table vector , so each functions is related to the table ( number in sequence ) .
But it should have direct way to assign a function to the Vector memory address of ISR PortC .
Is you read my simple program , I missed that part .
 
Indeed - not trivial to read - I was stymied getting to the last step before posting. But I know it is there without reading the manual. Which would also be required to begin to understand the registers in the simple program.

The func() ptr saved in attachInterrupt() with isr_table[pin_index] = function; // set the function pointer

The _isr call to that seems to be obscured under this macro that concatenates the function code for all 5 ports then redirects to the table:: PORT_ISR_FUNCTION_CLZ(C)

That jumps based on bit it looks like :: isr_table[bit_nr]();
 
The ISR_Table was create to make our future work easy ,programming easy , as for the macros well structured .
But if i want to set only one interrupt , the manual tell me the memory location of that ISR , and I believe I do not need to create any table .
For sure I will need pointers .
But how ???
 
Not sure if this part was missed?
>> All Pins on a port trigger a single PORT interrupt for that port. The linked code then has to find the pin and jump to the function that was attached for that pin as recorded with attachInterrupt().
 
See the link to the older less compact code in post #3 - it shows a functional and more readable evaluation
 
This are the definition and the Pointer to the function , right ?
typedef void (*voidFuncPtr)(void);
volatile static voidFuncPtr intFunc[CORE_NUM_DIGITAL];

That accept the max PIN number base on Device model ., right ?
 
Status
Not open for further replies.
Back
Top