This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Two simultaneous interrupts handling at msp430

Other Parts Discussed in Thread: MSP430FR5739, CC1200, MSP430F5529

Dear friends, I have a big trouble.

I have two interrupt signal at the same time without time difference (oscilloscope shows no time difference between this signals) And my msp430fr5739 should capture this interrupts. But it doesn't. MCU "see" only one signal. I've tried to change front for ISR (PxIES). I've tried to check events by PxIFG in the "if"-condition, I've tried to check by PxIV register but it doesn't work. 

How I can capture two interrupts at the same time?

P.S.:that's a project with two cc1200 modules. 

Code snippet:

/*******************************************************************************
*   @fn         ISR Port2 routine
*   @brief      ISR handle functionality
*/
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void) {  
  switch(__even_in_range(P2IV,16))
	{
	case   0:  break;  //  No  Interrupt
	case   2:  break;  //  P2.0
	case   4:  break;  //  P2.1
	case   6:  break;  //  P2.2
	case   8:          //  P2.3
          /***********************************************************************
          *   @fn         packetReceivedISR_GPIO2_A          
          *   @brief      Function running every time a packet has been received
          */
          LPM4_EXIT;          
          packetRecTrans_A = true; 
          whatHappened = ISM_INCOME_A;
          // Clear ISR flag
          P2IFG &= ~BIT3;       
          break;
          
	case   10:         //  P2.4
          /***********************************************************************
          *   @fn         packetReceivedISR_GPIO2_B          
          *   @brief      Function running every time a packet has been received
          */ 
          LPM4_EXIT;          
          packetRecTrans_B = true; 
          whatHappened = ISM_INCOME_B;
          // Clear ISR flag
          P2IFG &= ~BIT4;          
          break;       
	case   12: break;  //  P2.5
	case   14: break;  //  P2.6
        case   16: break;  //  P2.7
        }
}

  • Reading the P2IV register automatically clears the corresponding interupt flag. When using P2IV, DO NOT clear any bits in P2IFG manually!

    Also, don't use magic numbers; replace 8 with P2IV_P2IFG3.

    Anyway, if two interrupts happen simultaneously, they will be executed immediately one after the other. Your code will overwrite the value in the whatHappened variable. You need two such variables, or two different bits in this variable.

  • Clemens Ladisch said:
    When using P2IV, DO NOT clear any bits in P2IFG manually!

    Why that? The only reason I would not do it is because I could miss an interrupt that happened between reading the IV and clearing the flag manually. Any other reason?

    Dennis

  • Yes, but it also introduces the risk of clearing the wrong bit, and, worst of all, it shows that the author of the code does not understand how the hardware works.
  • Clemens Ladisch said:
    Yes, but it also introduces the risk of clearing the wrong bit, and, worst of all, it shows that the author of the code does not understand how the hardware works.

    After all User's Guide says it all (why you shall not reset bit yourself):

    Any access (read or write) of the lower byte of the PxIV register, either word or byte access, automatically
    resets the highest pending interrupt flag. If another interrupt flag is set, another interrupt is immediately
    generated after servicing the initial interrupt.

    It also have (assembler) example showing no forcible interrupt flag resets

  • Hi Clemens & Ilmars!

    Clemens Ladisch said:
    it shows that the author of the code does not understand how the hardware works

    True and agree.

    This is more a general question. Let's have a look at the following:

    ...
    
    P2IE = 0x08 | 0x10;
    
    ...
    
    
    #pragma vector = PORT2_VECTOR
    __interrupt void Port_2( void )
    {  
      switch( P2IV )
      {
        case 8: // P2.3
        {
          // Do something for P2.3 IFG
    
          P2IFG &= ~BIT3;       
          break;
        }
              
        case  10: // P2.4
        {
          // Do something for P2.4 IFG
    
          P2IFG &= ~BIT4;          
          break;
        }
    
        default: break;
      }
    }

    If both interrupt flags were set now and the ISR is entered, reading the IV clears the highest pending flag and the switch-case also enters the appropriate case for the highest pending flag, then clearing exactly this flag inside this case will not affect any other pending flags. Only if there was another interrupt for exactly that source between reading the IV and clearing the flag will lead to a lost interrupt.

    Clemens Ladisch said:
    it also introduces the risk of clearing the wrong bit

    Could you explain this?

    Ilmars said:

    After all User's Guide says it all (why you shall not reset bit yourself):

    Any access (read or write) of the lower byte of the PxIV register, either word or byte access, automatically
    resets the highest pending interrupt flag. If another interrupt flag is set, another interrupt is immediately
    generated after servicing the initial interrupt.

    Even from this text I don't see any problem with clearing this bit manually, but maybe I just don't get it. Indeed I don't see any need for clearing a flag when using the IV, but at least for my current understanding I also do not see the problem in doing so. But since I can learn new things every day, I would appreciate it if you could clear things up for me.

    Regards,

    Dennis

  • Thank you a lot! I deleted "clear" instructions and replace magic numbers. And it works! But I have one more question. Can I check the PxIFG in ISR? For example:
    case P2IV_P2IFG3: // P2.3
    /***********************************************************************
    * @fn packetReceivedISR_GPIO2_A
    * @brief Function running every time a packet has been received
    */
    LPM4_EXIT;
    packetRecTrans_A = true;
    if(P2IFG & BIT4) <<<===========================is it legit?
    packetRecTrans_B = true;
    whatHappened = ISM_INCOME_A;
    break;
    I think that's help me to capture the second interrupt in any case.
  • If you accidentally happen to write "P2IFG &= ~BIT4" instead of BIT3, you are extremely unlikely to find this problem through testing.

    This isn't very likely to happen either, but why risk it in the first place?
  • Yes OK, that's right, of course.
  • Checking P2IFG explicitly does not make much sense, because the bit could be set just after you've checked it.

    The only reliable way to react to the interrupt bits is to allow the interrupt handler to be called. When there are two bits set, the handler gets executed twice.

    You must handle this case correctly. And once you do handle it correctly, you do not need to add other checks for the bits.

  • Dear friend, I have an strange issue after your good advice. Sometimes I catch two interrupts and sometimes only one. Probability for good result is 50/50.

    When I return in main routine after RETI, I'm trying to check P2IV for increase chances like this:

    switch(whatHappened) {
        case ISM_INCOME_A:
          loger[0] = 1;      
          whatHappened = 0x00;
          packetRecTrans_A = false; 
          if(P2IV == P2IV_P2IFG4)      //that check. I think that's no sense
            packetRecTrans_B = true;
          SmartPreambleRec(module_A, module_B); break; //my user func
        case ISM_INCOME_B:
          loger[0] = 2;      
          whatHappened = 0x00;
          packetRecTrans_B = false;       
          if(P2IV == P2IV_P2IFG3)     // and that
            packetRecTrans_A = true;
          SmartPreambleRec(module_B, module_A); break;   //my user func

    Am I right in my thoughts?

    that's my ISR routine:

    #pragma vector=PORT2_VECTOR
    __interrupt void Port_2(void) {  
      switch(__even_in_range(P2IV,16))
    	{
    	case   0:  break;  //  No  Interrupt
    	case   P2IV_P2IFG0:  break;  //  P2.0
    	case   P2IV_P2IFG1:  break;  //  P2.1
    	case   P2IV_P2IFG2:  break;  //  P2.2
    	case   P2IV_P2IFG3:          //  P2.3
              /***********************************************************************
              *   @fn         packetReceivedISR_GPIO2_A          
              *   @brief      Function running every time a packet has been received
              */
              LPM4_EXIT;          
              packetRecTrans_A = true;          
              whatHappened = ISM_INCOME_A;               
              break;          
    	case   P2IV_P2IFG4:         //  P2.4
              /***********************************************************************
              *   @fn         packetReceivedISR_GPIO2_B          
              *   @brief      Function running every time a packet has been received
              */ 
              LPM4_EXIT;          
              packetRecTrans_B = true;           
              whatHappened = ISM_INCOME_B;                           
              break;
          break;  
    	case   P2IV_P2IFG5: break;  
    	case   P2IV_P2IFG6: break;     
    	case   P2IV_P2IFG7: break;  
    	}
    }

  • You never need to check P2IFG explicitly.

    The code still has the problem that it overwrites the whatHappened variable. At the moment, it can have three states (nothing/A/B), but you need a fourth state (both A and B).

    And you already have packetRecTrans_A and packetRecTrans_B. Why don't you use those instead of whatHappened?

  • You are right. I must change my algorithm. Thank you!
  • Kirill Germanov said:

    Dear friend, I have an strange issue after your good advice. Sometimes I catch two interrupts and sometimes only one. Probability for good result is 50/50.

    When I return in main routine after RETI, I'm trying to check P2IV for increase chances like this:

    switch(whatHappened) {
        case ISM_INCOME_A:
          loger[0] = 1;      
          whatHappened = 0x00;
          packetRecTrans_A = false; 
          if(P2IV == P2IV_P2IFG4)      //that check. I think that's no sense
            packetRecTrans_B = true;
          SmartPreambleRec(module_A, module_B); break; //my user func
        case ISM_INCOME_B:
          loger[0] = 2;      
          whatHappened = 0x00;
          packetRecTrans_B = false;       
          if(P2IV == P2IV_P2IFG3)     // and that
            packetRecTrans_A = true;
          SmartPreambleRec(module_B, module_A); break;   //my user func

    Am I right in my thoughts?

    If you insert an useless statement in your main routine after the RETI and before the "switch (whatHappened) ...", you will fined that 100% of the time both interrupts were handled by your ISR. By "useless statement", I mean things like "P1OUT |= 0x00; "

    This is because after RETI, the interrupt is not re-enabled until another instruction is executed. The useless instruction give your ISR a change to handle the second interrupt.

  • I've tried this. I used after RETI __no_operation(), used __delay_cycles() and P3OUT |= BIT4 (Debug LED ON), and anyway MCU behaves weird.
  • How about change your ISR into this:

    #pragma vector=PORT2_VECTOR
    __interrupt void Port_2(void) {
      int copy;
      while (copy=P2IV)
      {
        switch(__even_in_range(copy, P2IV_P2IFG7))
    	{
    	case   P2IV_P2IFG0:  ...
    	case   P2IV_P2IFG1:  ...
      	. . .
            case   P2IV_P2IFG7:  ...
            }
      }
    }

  • 
    

    I've tried this. And still doesn't work. After RETI in main routine variable "whatHappened" in watch shows only one ISR execution.

    while(true) {    
        LPM4; 
        __no_operation();
        P3OUT |= BIT4;                    //Debug LED ON
        switch(whatHappened) {
        case ISM_INCOME_AB_ATST: //signals from two RF - At The Same Time //const uint8 ISM_INCOME_AB_ATST = 0x03;
        loger[0] = 1;      
        whatHappened = 0x00;
        packetRecTrans_A = packetRecTrans_B = false; 
    //      if(P2IV == P2IV_P2IFG4)
    //        packetRecTrans_B = true;
        SmartPreambleRec(module_A, module_B); break;
        case ISM_INCOME_A:
          loger[0] = 2;      
          whatHappened = 0x00;
          packetRecTrans_A = false; 
    //      if(P2IV == P2IV_P2IFG4)
    //        packetRecTrans_B = true;
          SmartPreambleRec(module_A, module_B); break;
        case ISM_INCOME_B:
          loger[0] = 3;      
          whatHappened = 0x00;
          packetRecTrans_B = false;       
    //      if(P2IV == P2IV_P2IFG3)
    //        packetRecTrans_A = true;
          SmartPreambleRec(module_B, module_A); break;
        default:
          loger[0] = 4;
          GlobeError = 0x03;
          break;
        }   
    }

    That's how look my ISR routines now:
    #pragma vector=PORT2_VECTOR
    __interrupt void Port_2(void) {
      int copy;
      while (copy=P2IV)
      {
        switch(__even_in_range(copy, P2IV_P2IFG7))
        {
            case   P2IV_NONE:  break;  //  No  Interrupt
            case   P2IV_P2IFG0:  break;  //  P2.0
            case   P2IV_P2IFG1:  break;  //  P2.1
            case   P2IV_P2IFG2:  break;  //  P2.2
            case   P2IV_P2IFG3:          //  P2.3
                  /***********************************************************************
                  *   @fn         packetReceivedISR_GPIO2_A          
                  *   @brief      Function running every time a packet has been received
                  */
                  LPM4_EXIT;          
                  packetRecTrans_A = true;          
                  whatHappened |= ISM_INCOME_A; //const uint8 ISM_INCOME_A = 0x01;              
                  break;          
            case   P2IV_P2IFG4:         //  P2.4
                  /***********************************************************************
                  *   @fn         packetReceivedISR_GPIO2_B          
                  *   @brief      Function running every time a packet has been received
                  */ 
                  LPM4_EXIT;          
                  packetRecTrans_B = true;           
                  whatHappened |= ISM_INCOME_B;  //const uint8 ISM_INCOME_B = 0x02;                         
                  break;
              break;  
            case   P2IV_P2IFG5: break;  //  P2.5
            case   P2IV_P2IFG6: break; 
            case   P2IV_P2IFG7: break;
            }
      }
    }

    Please, help! My mind is over today.

  • Switch (P2IV.....

    it both reads and clears the bit as to the reason this ISR got serviced in the first place.
    So don't read the register again inside the ISR, my understanding next pending bit for P2IV get set on reti and not at the clearing of IV register but I'm not sure.

    So I think the problem is how your event machine in main.c handles the flags after it got woken up by lmp4

    You have not showed that part of the code,
    but creating a fool prof event machine in main.c you have to think of race conditions etc.
    I for example turn off GIE as a IRQ could happen after I checked if any event but before I go to sleep again.

     

    while(1){                // loop forever
        _BIC_SR(GIE);        // so no interrupt between next 2 lines
        if (!(event.all))    // go to sleep if no tasks
          _BIS_SR(LPM3_bits + GIE);   // Enter LPM3 Sleep w/ interrupt

  • Hi, Tony! Thank you for your advice. Refer to you note - I showed all my code in main.c. All I have it is a switch-machine in main.c and another c.file with interrupts. Other functions it is a library functions from include files and it is not important for topic.

    I think that's after wake up from LPM first of all executes some first ISR, than return to main to the next line after LPM instruction (__no_operation() for example), then executes second ISR, because appropriate PxIFG were set. And only after that routines MCU executes switch in main.c. Am I right?

    P.S.:For this moment I've changed port for second interrupt from P2 to P1. And still doesn't work.  

  • Kirill,

    I may have caused you a lot of confusion. I do not have the MSP chip, I do not use CCS, And I did not understand your code. Thus I was like a blind man giving you directions to get out of a maze I cannot see.

    Basically, I am very comfortable with the "magic numbers" (which I can look them up from the Data-Sheet of the MSP chip). But I got lost in the "magic words" (which I am not capable of dealing with). 

    I have since verified the suggestion I gave you with a MSP430F5529 on the LaunchPad. It is very simple and works fine.

    --OCY

    That LaunchPad has a green LED at P1.0 and a red LED at P4.7. And I hooked up P2.3 and P2.4 to an external single pulse generator. Here is the entire code.

    EDIT: This is a wrong version. The correct version is in the next post. 

    #include <msp430f5529.h>
    
    volatile char whatHappend = 0;
    
    void main( void )
    {
      P1OUT = 0;
      P1DIR = 1;                            //BIT0 is red LED1
      P4OUT = 0;
      P4DIR = 0x80;                         //BIT7 is green LED2
    
      P2OUT = 0xFF;                         //all bits
      P2REN = 0xFF;                         //are pulled up
      P2IES = 0x18;                         //BIT4|BIT3 input falling edge
      P2IE = 0x18;                          //BIT4|BIT3 interrpt enable
    
      while (1)
      {
        P2IFG = 0;                          //ifg of all bits cleared
        __bis_SR_register(0xF8);
        if (whatHappend == 0x18)            //BIT4|BIT3 both happend
        {
          __bic_SR_register(8);             //GIE cleared
          whatHappend = 0;
          P4OUT |= 0x80;                    //BIT7 is green LED2
          __delay_cycles(2000000L);
          P4OUT &= ~0x80;
        }
        else                                //not both happend
        {
          whatHappend = 0;
          P1OUT |= 1;                       //BIT0 is red LED1
          __delay_cycles(2000000L);
          P1OUT &= ~1;
        }
      }
    }
    
    #pragma vector= 0x54                    //PORT2_VECTOR
    __interrupt void Port_2(void) {
      int copy;
      while (copy=P2IV)
      {
        switch(__even_in_range(copy, 16))   //P2IV_P2IFG7
          {
    	case 2: break;                  //P2IV_P2IFG0
    	case 4: break;                  //P2IV_P2IFG1
    	case 6: break;                  //P2IV_P2IFG2
    	case 8:                         //P2IV_P2IFG3
                    __bic_SR_register_on_exit(0xF8);
                    whatHappend |= 8;       //BIT3
                    break;
    	case 10:                        //P2IV_P2IFG4
                     __bic_SR_register_on_exit(0xF8);
                     whatHappend |= 0x10;   //BIT4
                     break;
    	case 12: break;                 //P2IV_P2IFG5
    	case 14: break;                 //P2IV_P2IFG6
    	case 16: break;                 //P2IV_P2IFG7
          }
      }
    }

  • Sorry, I posted the wrong version. Correct one is as follows.

    #include <msp430f5529.h>
    volatile char whatHappened = 0;
    void main( void )
    {
      WDTCTL = 0x5A80;                      //WDTPW|WDTHOLD;
      P1OUT = 0;
      P1DIR = 1;                            //BIT0 is red LED1
      P4OUT = 0;
      P4DIR = 0x80;                         //BIT7 is green LED2
      P2OUT = 0xFF;                         //all bits
      P2REN = 0xFF;                         //are pulled up
      P2IES = 0x18;                         //BIT4|BIT3 input falling edge
      P2IE = 0x18;                          //BIT4|BIT3 interrupt enable
      while (1)
      {
        P2IFG = 0;                          //ifg of all bits cleared
        __bis_SR_register(0xF8);
        if (whatHappened == 0x18)           //BIT4|BIT3 both happened
        {
          whatHappened = 0;
          P4OUT |= 0x80;                    //BIT7 is green LED2
          __delay_cycles(500000L);          //~0.5 sec
          P4OUT &= ~0x80;
        }
        else                                //not both happened
        {
          whatHappened = 0;
          P1OUT |= 1;                       //BIT0 is red LED1
          __delay_cycles(500000L);          //~0.5 sec
          P1OUT &= ~1;
        }
      }
    }
    #pragma vector= 0x54                    //PORT2_VECTOR
    __interrupt void Port_2(void) {
      int copy;
      while (copy=P2IV)
      {
        switch(__even_in_range(copy, 16))   //P2IV_P2IFG7
          {
    	case 2: break;                  //P2IV_P2IFG0
    	case 4: break;                  //P2IV_P2IFG1
    	case 6: break;                  //P2IV_P2IFG2
    	case 8:                         //P2IV_P2IFG3
                    __bic_SR_register_on_exit(0xF8);
                    whatHappened |= 8;      //BIT3
                    break;
    	case 10:                        //P2IV_P2IFG4
                     __bic_SR_register_on_exit(0xF8);
                     whatHappened |= 0x10;  //BIT4
                     break;
    	case 12: break;                 //P2IV_P2IFG5
    	case 14: break;                 //P2IV_P2IFG6
    	case 16: break;                 //P2IV_P2IFG7
          }
      }
    }
    

  • Thank you old_cow_yellow! Everything is right. I have the same code, but it doesn't works. I checked all my code for "dummy" mistakes or some differences.

    Now I solved problem with GPIO polling in ISR. It is not so good, but it works.

    And can you tell me

    old_cow_yellow said:
    I do not have the MSP chip, I do not use CCS, And I did not understand your code.



    I'm using IAR.
    And what did you mean refer to code? I mean, it is importanat for me. What's wrong with it? Too few comments? Or maybe my bad english? Sorry for offtop. But I'll appreciate any critique for my work.
  •  You can not use Switch(whatHappened) on bitfield vars, unless you create a case for every possible combination.
    You have to test each bit !!!!!!

    eventunion event;  

    while(1){                     // loop forever
        _BIC_SR(GIE);             // so no interupt between next 2 lines
        if (!(event.all))         // go to sleep if no tasks
          _BIS_SR(LPM3_bits + GIE);   // Enter LPM3 Sleep w/ interrupt
        
        if (event.door)  { event.door  = 0;    doorF();   }
        if (event.rtc)   { event.rtc   = 0;    rtcF();    }
        if (event.alarm) { event.alarm = 0;    alarmF();  }

    This is how you create a var that is both a single unsigned int and 16 individual bits that C compiler understands.

    typedef union eventTag  // place this in common.h so all modules have access to the event flags
    {
      unsigned int all;              /* the union of 16 below bits */
      struct {
      unsigned char door        : 1;
      unsigned char alarm      : 1;
      unsigned char rtc           : 1;
      };
    }eventunion;
    extern eventunion event;

  • Why not? I have defined values for every possible case. And if my var got wrong value switch-operator turns to default-case.

    const uint8 ISM_INCOME_A = 0x01;
    const uint8 ISM_INCOME_B = 0x02;
    const uint8 ISM_INCOME_AB_ATST = 0x03;
    
    switch(whatHappened) {
        case ISM_INCOME_AB_ATST:
          ...
         break;
        case ISM_INCOME_A:
          ...
         break;
        case ISM_INCOME_B:
          ...
         break;
        default:      
          GlobeError = 0x01;
          break;
        }  

  • Dear friend! Thank you for you instructions. I founded that my port init with pulldown input, but yours with pullup. And with pullup it works perfect! But I need pulldown. And that's confusing me a lot. 

    Now my code looks like:

      
    typedef union {
      uint8 events;              /* the union of 8 below bits */
      struct {
      uint8 ism_trx_A:    1; 
      uint8 ism_trx_B:    1;
      };
    }eventunion; 
    
      P2DIR = 0x00;
      P2OUT = 0x00;                         //all bits
      P2REN = 0x00;                         //are pulled up
      P2IES = 0x00;                         //BIT4|BIT3 input rising edge
      P2IE = 0x18;                          //BIT4|BIT3 interrupt enable
    
    while(true) {    
        LPM4;     
        __no_operation();    
        switch(whatHappened.events) {
        case ISM_INCOME_AB_ATST:
          ...
          break;
        case ISM_INCOME_A:   
          ...   
          break;
        case ISM_INCOME_B:
          ...
         break;
        default:      
          GlobeError = 0x03;
          break;
        }  
    }
    
    #pragma vector=PORT2_VECTOR
    __interrupt void Port_2(void) { 
        switch(__even_in_range(P2IV, P2IV_P2IFG7))
        {
            case   P2IV_NONE:  break;  //  No  Interrupt
            case   P2IV_P2IFG0:  break;  //  P2.0
            case   P2IV_P2IFG1:  break;  //  P2.1
            case   P2IV_P2IFG2:  break;  //  P2.2
            case   P2IV_P2IFG3:          //  P2.3
                  /***********************************************************************
                  *   @fn         packetReceivedISR_GPIO2_A          
                  *   @brief      Function running every time a packet has been received
                  */
                  LPM4_EXIT;
                  packetRecTrans_A = true;          
                  whatHappened.ism_trx_A = 1;                       
                  break;          
            case   P2IV_P2IFG4: 
                  LPM4_EXIT;              
                  packetRecTrans_B = true; 
                  whatHappened.ism_trx_B = 1;  
                  
                  break;  //  P2.4            
            case   P2IV_P2IFG5: break;  //  P2.5
            case   P2IV_P2IFG6:        //  P2.6               
                  break; 
            case   P2IV_P2IFG7:         //  P2.7              
                  break;
            } 
    }

  • The code your posted this time only says::

    typedef union {
      uint8 events;              /* the union of 8 below bits */
      struct {
      uint8 ism_trx_A:    1; 
      uint8 ism_trx_B:    1;
      };
    }eventunion; 
    
      P2DIR = 0x00;
      P2OUT = 0x00;                         //all bits
      P2REN = 0x00;                         //are pulled up
      P2IES = 0x00;                         //BIT4|BIT3 input rising edge
      P2IE = 0x18;                          //BIT4|BIT3 interrupt enable
    
    while(true) {    
        LPM4;     
        __no_operation();    
        switch(whatHappened.events) {
        case ISM_INCOME_AB_ATST:
          ...
          break;
        case ISM_INCOME_A:   
          ...   
          break;
        case ISM_INCOME_B:
          ...
         break;
        default:      
          GlobeError = 0x03;
          break;
        }  
    }
    
    #pragma vector=PORT2_VECTOR
    __interrupt void Port_2(void) { 
        switch(__even_in_range(P2IV, P2IV_P2IFG7))
        {
            case   P2IV_NONE:  break;  //  No  Interrupt
            case   P2IV_P2IFG0:  break;  //  P2.0
            case   P2IV_P2IFG1:  break;  //  P2.1
            case   P2IV_P2IFG2:  break;  //  P2.2
            case   P2IV_P2IFG3:          //  P2.3
                  /***********************************************************************
                  *   @fn         packetReceivedISR_GPIO2_A          
                  *   @brief      Function running every time a packet has been received
                  */
                  LPM4_EXIT;
                  packetRecTrans_A = true;          
                  whatHappened.ism_trx_A = 1;                       
                  break;          
            case   P2IV_P2IFG4: 
                  LPM4_EXIT;              
                  packetRecTrans_B = true; 
                  whatHappened.ism_trx_B = 1;  
                  
                  break;  //  P2.4            
            case   P2IV_P2IFG5: break;  //  P2.5
            case   P2IV_P2IFG6:        //  P2.6               
                  break; 
            case   P2IV_P2IFG7:         //  P2.7              
                  break;
            } 
    }

    Is there a main() {...} that holda the WDT? DId it set GIE  and goes to while (true) {...}? 

    Where are ISM_INCOME_AB_ATST etc. defined?

    You posted a lot of various fragments of code on different days. Are they all used at the same time when you say "it does not work". I have no way of knowing what combination does not work.

  • Sorry, I've got a problem with forum form filling and my stupidity. Can you look my whole project?two_cc1200_proj.7z

    Thank you!

  • Kirill,

    could you please upload something different than a .7z file? On the one hand not everyone can open it and on the other someone might even refuse to open a container with unknown content.

    Dennis
  • It appears that you have changed your code from what you have been posting before. I cannot chase this moving target.

    I have a hunch that if you edit your switch statement in you main() as follows:

        switch(whatHappened.events) {
        case 3: case 7: case 11: case 15:
          loger[0] = 1;
          P3OUT |= BIT4;      
          whatHappened.events = 0x00;
          packetRecTrans_A = packetRecTrans_B = false; 
          SmartPreambleRec(module_A, module_B); 
            break;
        case 1: case 5: case 9: case 13:      
          loger[0] = 2;
          P3OUT |= BIT5;
          whatHappened.events = 0x00;
          packetRecTrans_A = false; 
          SmartPreambleRec(module_A, module_B); 
            break;
        case 2: case 6: case 10: case 14:
          loger[0] = 3;
          P3OUT |= BIT6; 
          whatHappened.events = 0x00;
          packetRecTrans_B = false; 
          SmartPreambleRec(module_B, module_A); 
            break;
        default:
          loger[0] = 4;
          GlobeError = 0x03;
          break;
        }  

    And do NOT change anything else at this time, it might work better.

     

  •     switch(whatHappened.events) {
          case 3: case 7: case 11: case 15:
          loger[0] = 1;
          P3OUT |= BIT4;      
          whatHappened.events = 0x00;

    If a IRQ happened while at line 2-4 and sets a bit in whatHappened.bit field, it will be lost and your code would never know.

    temp = whatHappened.events;  // a IRQ could happen just after this so just don't clear but xor 
    whatHappened.events ^= temp; // copy and clear in a safe way,Warning compiler may optimize this gets lost
    switch(temp){


    Due to the no C guarantee on the xor, I ended up using if (event.bit0) {event.bit0=0;.....

  • While I'm not regularly reading the forum anymore, I have been notified of this thread and have to come out of lurking mode.

    OCY: "This is because after RETI, the interrupt is not re-enabled until another instruction is executed. The useless instruction give your ISR a change to handle the second interrupt."

    Sorry, that's wrong. If an ISR exits and another interrupt is pending, it is immediately executed. No 'main' instruction is executed in-between. If it were, the LPM mechanism wouldn't work, since MCLK is stopped with the RETI instruction until next interrupt unless LPM is exited, and main doesn't advance while LPM is active. This is not to be confused with the fact that a breakpoint set to the instruction right after entering LPM will trigger before LPM is entered at all (due to instruction prefetch that triggers the breakpont)
    If an interrupt 'hangs' on an MSP (that is, the IFG bit is not reset inside the ISR), the MSP will execute thsi ISR over and over again and NOT advance in main at all.

    Other MCUs, like the ATMega, do it differently (I had a 'hanging' interrupt on the ATMega128 using NutOS, and it slowly advanced main to the point where another OS call stopped the interrutp firing)

    About the original topic:
    Reading P2IFG might cause a problem if th einterrupt source for P2 is asynchronous to MCLK. In this case, it might be that you're reading the P2IFG register right at the moment the hardware wants to set an IFG flag due to an interrupt. In this case, the register is locked and the interrutp is not flagged.
    Writing P2IFG (clearing an IFG bit) is even worse: Writing 0x00 to it may overwrite all flags that have been set since last testing the register. And making an AND operation to clear a single bit will first read the register, then perform the BIC operation then write the result back. That means, any flags set in-between are overwritten when writing back, which spans multiple MCLK cycles.

    This is the main (if not only) reason why the IV registers were introduced for the ports.

    However, there is no need to leave the ISR to handle multiple penfing interrupts.

    Structure the ISR like this:

    while(1)
      switch(_even_in_range(xxxIV,y){
        case 0: return; // exit ISR when no more interrupts ar epending
        case 2: ...
          break;
        case 4: ...
          break;
        ....
        case y: ...
          break;
        default: // only needed if not all possible (even) cases 0..Y handled above
          ;
      }
    }

    This saves you the time overhead for exiting and re-entering the ISR while multiple interrupts are pending.

    If you want to combine cases (manly identical code for both) and need the value of the IV regiater, read it into a local variable before the swticht and use the variable inside the switch statement.

    Another approach for hadnling multiple itnerrupts, especially if the exact moment of the interrupt (order) is important and the interrupt latency is too much to detect it, would be to use a timer capture interrupt instead. then the moment of the capture is also available along wiht the fact that an interrupt happened. If oyu alread have a tiemr running with a high-enough frequency, then you can use all unused CCR units of this timer for capturing port interrupts.

**Attention** This is a public forum