Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 3 1 2 3 LastLast
Results 1 to 25 of 70

Thread: Assigned IRQ interrupt to digital pin

  1. #1
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31

    Assigned IRQ interrupt to digital pin

    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

  2. #2
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    2,200
    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/co..._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 by manitou; 08-02-2018 at 01:55 PM.

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,585
    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/co..._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?

  4. #4
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    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

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,585
    "##" is the concatenation operator. Details here.

    https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html

    Best to compare the new and old code side-by-side. It's creating the ISR function names by concatenating strings.

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,585
    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.

  7. #7
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    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 ?

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,585
    Quote Originally Posted by M.Melani View Post
    What is the meaning of those points after 0 ??? Why 3 ?
    https://stackoverflow.com/questions/...the-same-value

    https://gcc.gnu.org/onlinedocs/gcc-4...ted-Inits.html

  9. #9
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    THANK YOU PAUL ! Appreciate !

  10. #10
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,265
    Quote Originally Posted by PaulStoffregen View Post
    "##" is the concatenation operator. Details here.

    https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html

    Best to compare the new and old code side-by-side. It's creating the ISR function names by concatenating strings.
    Just to clarify, the '##' concatenation operator (and the '#' stringize operator BTW) only work within #define expansions.

  11. #11
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    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 ?

  12. #12
    try this:

    int C[10]= { 5 };

  13. #13
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,265
    Quote Originally Posted by larry_berlin View Post
    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;

  14. #14
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    As Paul post , previously ,

    https://stackoverflow.com/questions/...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 .

  15. #15
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,265
    Quote Originally Posted by M.Melani View Post
    As Paul post , previously ,

    https://stackoverflow.com/questions/...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.

  16. #16
    Quote Originally Posted by MichaelMeissner View Post
    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.

  17. #17
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    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

  18. #18
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,752
    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()

  19. #19
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    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 .

  20. #20
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,752
    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]();

  21. #21
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    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 ???

  22. #22
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,752
    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().

  23. #23
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,752
    See the link to the older less compact code in post #3 - it shows a functional and more readable evaluation

  24. #24
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,585
    Here's that link again.

    https://github.com/PaulStoffregen/co..._teensy.c#L103

    Use this much simpler code!

  25. #25
    Member
    Join Date
    Aug 2018
    Location
    Italy and Thailand
    Posts
    31
    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 ?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •