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.

CC2541: CC2541 Interrupt issue with osal_run_system() function

Part Number: CC2541


Hello sir,,

I am using cc2541 BLE chipset.

The development circumstances =======================

Based code : "SimpleBLEPeripheral"

compiler : IAR

===============================================

Question

1. I turned off osal_run_system() function and  I tested external interrupt and gpio out.

   without osal_run_system() function, the interrupt is good.

  However, If I turn on the osal_run_system() function the external interrupt is missiong sometimes.

  Do you have any Idea for this issue?   

  • Can you elaborate how you tested external interrupt and gpio out?
  • Hello, sir.

    I used two pins as belows and used timer3.

    p0.7 : input pin

    p1.0 : output pin

    The code sequence is very easy.

    If the input pin has external interrupt, just p1.0 high and low.  

    But, with osal_run_system() function the interrupt is missing periodically.

    I checked the osal_run_system() function, I think whenever the device has adverting, the interrupt is delay

    I really need to solve this problem.  I need your help.

    Thank you.

    ===============================================================

    main.c

    #define P0_7_PIN BIT7  // input zero
    #define P1_0_PIN BIT0  // output pwm

    volatile uint16 delay_1ms=0;
    volatile uint16 dimmer_step =0;
    volatile bool zero_state = FALSE;

    #if 1
    #pragma vector = P0INT_VECTOR
    __interrupt void p0_ISR(void)
    {
     P0IFG = 0;
     zero_state = true;
     // Clear CPU interrupt status flag for P0.
     P0IF = 0;
    }
    #endif
    void GPIO_set(void)
    {
     P1SEL &= P1_0_PIN;    // GPIO.
     P1DIR |= P1_0_PIN;    // Output.
     P1_0 = 0;         // pwm  off.

     #if 1
     P0SEL &= ~P0_7_PIN;        // Select pin to function as General Purpose I/O.
     P0DIR &= ~P0_7_PIN;        // Select direction as input.
     P0INP &= ~P0_7_PIN;        // Pull up/pull down.

     
     //PICTL |= 1;       // Falling edge
     PICTL |= 0;       // Risinging edge
     P0IEN |= P0_7_PIN;   // Enable interrupt from pin.
     IEN1 |= IEN1_P0IE;   // Port 0 interrupt enable

     //P0IFG = ~P0_7_PIN;   // Clear status flag for pin.
     P0IFG = 0;
     P0IF = 0;      // Clear CPU interrupt status flag for P0.
     EA = 1;
     #endif
    }

    // 62.5ns
    #pragma vector = T3_VECTOR
    __interrupt void t3_isr(void)
    {
     // Clears the module interrupt flag.
     T3OVFIF = 0;
     
     if(delay_1ms>0)delay_1ms--;
     // Clears the CPU interrupt flag.
     T3IF = 0;
    }

    // normal overflow timer interrupt
    void Timer3_init(void)  // 8bit timer
    {
     #if 0  // 1ms
     CLKCONCMD = (CLKCONCMD & ~CLKCON_TICKSPD) | CLKCON_TICKSPD_32M;

     // Enable Timer 1 interrupts by setting [IEN1.T1IE=1]
     T3IE = 1;
     // 1ms =>
     T3CTL = T3CTL_DIV_128 | T3CTL_MODE_FREERUN | T3CTL_OVFIM | T3CTL_CLR | T3CTL_START;
     #else
     CLKCONCMD = (CLKCONCMD & ~CLKCON_TICKSPD) | CLKCON_TICKSPD_32M;
     
     // Enable Timer 1 interrupts by setting [IEN1.T1IE=1]
     T3IE = 1;
     // 64us
     T3CTL = T3CTL_DIV_16 | T3CTL_MODE_FREERUN | T3CTL_OVFIM | T3CTL_CLR | T3CTL_START;
     // 32000000/16 =2000000  ==> 0.5ns ==> 0.5ns * 125(8bit timer) = 62.5ns * 2 = 125ns
     #endif
    }
    void Delay_1ms(uint16 delay)
    {
     delay_1ms = delay;  
     while(delay_1ms);
    }
     // uart baudrate : 115200 bps
    int main(void)
    {
     /* Initialize hardware */

     HAL_BOARD_INIT();
     UART_INIT();
     GPIO_set();
     Timer3_init();

     // Initialize board I/O
     InitBoard( OB_COLD );

     /* Initialze the HAL driver */
     HalDriverInit();
     /* Initialize NV system */
     osal_snv_init();

     /* Initialize LL */
     /* Initialize the operating system */
     osal_init_system();
     /* Enable interrupts */
     HAL_ENABLE_INTERRUPTS();
     // Final board initialization
     InitBoard( OB_READY );

     /* Start OSAL */
     //uart0Send(uartTxBuffer, SIZE_OF_UART_TX_BUFFER);
     osal_start_system(); // No Return from here
     return 0;
    }

    ===============================================================

    osal.c

    void Dimmer_set(uint16 deadtime)
    {
     if(deadtime==Dimmer_off_min)
     {
      P1_0 =1;
      //for(int i =0;i++;i<100)halMcuWaitUs(50000);
     }
     else   // off time is long
     {
      P1_0 =0;
      Delay_1ms(deadtime); // 65us * step 
      //halMcuWaitUs(1000);
      P1_0 =1;   // triac on
     }
     //dimmer_step++;
     //if(deadtime==100)deadtime=0;
     zero_state =false;

    }
    void osal_start_system( void )
    {
      ////dimmer_step = Dimmer_off_min;  //default light on
       dimmer_step = 35;  //default light on
     for(;;)  // Forever Loop
     {
      //dimmer_step = (uint16)app_data;
      osal_run_system();
      //receive_data_app(); 
      if(zero_state)Dimmer_set(dimmer_step);
     }
    }

    ===============================================================================

  • Which example do you test this? By the way, does your p0_ISR get triggered when P0.7 (GPI) has a rising edge?

    In your code, what is BIT7 and I suppose you should use "PICTL =0;" instead of "PICTL |= 0;" to clear edge bit to make P0.7 use rising edge for triggering.
  • Hello sir,
    I changed PICTL = 0 as you recommended but the symptom is same.
    And I used the "SimpleBLEPeripheral" test code.

    I used extenal signal using AC has 8.35ms. So, the interrupt is happened every 8.35ms
    ===========================
    does your p0_ISR get triggered when P0.7 (GPI) has a rising edge?
    ==> yes
    ===========================
    Once again, with osal_run_system() function the interrupt has delay.
    without osal_run_system() function the interrupt does not have any problem.

    Thank you for your reply.
  • I think you shouldn't put "if(zero_state)Dimmer_set(dimmer_step);" inside Forever Loop of osal_start_system. You should send an application event from p0_ISR and do Dimmer_set inside application event handler. You can refer to how hal_key.c send key event to application to implement this accordingly.
  • OK, I will try it and I will tell you the result.
    Thank you.
  • I tested interrupt using hal_key.c. But the interrupt time is not good.
    The interrupt is happened very slow. I need to check the interrupt every 8.35ms.

    Below code, I just tested whenever the external interrupt is happened, P1_0 port has toggle mode.
    I reduced key debounce time as short as possible.
    And as you mentioned the Dimmer_set() function is removed.
    =============================================================================
    hal_key.c >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.
    // set p0.1 rising edge interrupt
    #define HAL_KEY_SW_6_PORT P0
    #define HAL_KEY_SW_6_BIT BV(7)
    #define HAL_KEY_SW_6_SEL P0SEL
    #define HAL_KEY_SW_6_DIR P0DIR

    /* edge interrupt */
    #define HAL_KEY_SW_6_EDGEBIT BV(0)
    #define HAL_KEY_SW_6_EDGE HAL_KEY_RISING_EDGE

    /* SW_6 interrupts */
    #define HAL_KEY_SW_6_IEN IEN1 /* CPU interrupt mask register */
    #define HAL_KEY_SW_6_IENBIT BV(5) /* Mask bit for all of Port_0 */
    #define HAL_KEY_SW_6_ICTL P0IEN /* Port Interrupt Control register */
    #define HAL_KEY_SW_6_ICTLBIT BV(7) /* P0IEN - P0.7 enable/disable bit */
    #define HAL_KEY_SW_6_PXIFG P0IFG /* Interrupt flag at source */

    void HalKeyConfig (bool interruptEnable, halKeyCBack_t cback)
    {
    /* Enable/Disable Interrupt or */
    Hal_KeyIntEnable = interruptEnable;
    /* Register the callback fucntion */
    pHalKeyProcessFunction = cback;
    /* Determine if interrupt is enable or not */
    if (Hal_KeyIntEnable)
    {
    /* Rising/Falling edge configuratinn */
    PICTL &= ~(HAL_KEY_SW_6_EDGEBIT); /* Clear the edge bit */
    /* For rising edge, the bit must be set. */
    #if (HAL_KEY_SW_6_EDGE == HAL_KEY_RISING_EDGE)
    PICTL = 0; // rising edge
    #endif

    HAL_KEY_SW_6_ICTL |= HAL_KEY_SW_6_ICTLBIT;
    HAL_KEY_SW_6_IEN |= HAL_KEY_SW_6_IENBIT;
    HAL_KEY_SW_6_PXIFG = 0;

    /* Do this only after the hal_key is configured - to work with sleep stuff */
    if (HalKeyConfigured == TRUE)
    {
    osal_stop_timerEx(Hal_TaskID, HAL_KEY_EVENT); /* Cancel polling if active */
    }
    }
    else /* Interrupts NOT enabled */
    {
    HAL_KEY_SW_6_ICTL &= ~(HAL_KEY_SW_6_ICTLBIT); /* don't generate interrupt */
    HAL_KEY_SW_6_IEN &= ~(HAL_KEY_SW_6_IENBIT); /* Clear interrupt enable bit */
    osal_set_event(Hal_TaskID, HAL_KEY_EVENT);
    }
    /* Key now is configured */
    HalKeyConfigured = TRUE;
    }

    void halProcessKeyInterrupt (void)
    {
    bool valid=FALSE;

    if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT) /* Interrupt Flag has been set */
    {
    HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT); /* Clear Interrupt Flag */
    valid = TRUE;
    }
    if (valid)
    {
    //osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
    osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, 5);
    }
    }

    HAL_ISR_FUNCTION( halKeyPort0Isr, P0INT_VECTOR )
    {
    HAL_ENTER_ISR();
    if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT)
    {
    halProcessKeyInterrupt();
    }

    /*
    Clear the CPU interrupt flag for Port_0
    PxIFG has to be cleared before PxIF
    */
    HAL_KEY_SW_6_PXIFG = 0;
    HAL_KEY_CPU_PORT_0_IF = 0;

    CLEAR_SLEEP_MODE();
    HAL_EXIT_ISR();
    return;
    }

    onboard.c >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    void OnBoard_KeyCallback ( uint8 keys, uint8 state )
    {
    uint8 shift;
    (void)state;

    // shift key (S1) is used to generate key interrupt
    // applications should not use S1 when key interrupt is enabled
    shift = (OnboardKeyIntEnable == HAL_KEY_INTERRUPT_ENABLE) ? false : ((keys & HAL_KEY_SW_6) ? true : false);

    if ( OnBoard_SendKeys( keys, shift ) != SUCCESS )
    {
    // Process SW6 here
    if ( keys & HAL_KEY_SW_6 ) // Switch 6
    {
    P1_0 =~P1_0;
    zero_state = true;
    }
    }

    /* If any key is currently pressed down and interrupt
    is still enabled, disable interrupt and switch to polling */
    if( keys != 0 )
    {
    if( OnboardKeyIntEnable == HAL_KEY_INTERRUPT_ENABLE )
    {
    OnboardKeyIntEnable = HAL_KEY_INTERRUPT_DISABLE;
    HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);
    }
    }
    /* If no key is currently pressed down and interrupt
    is disabled, enable interrupt and turn off polling */
    else
    {
    if( OnboardKeyIntEnable == HAL_KEY_INTERRUPT_DISABLE )
    {
    OnboardKeyIntEnable = HAL_KEY_INTERRUPT_ENABLE;
    HalKeyConfig( OnboardKeyIntEnable, OnBoard_KeyCallback);
    }
    }
    }
    =============================================================================
  • What do you mean "I need to check the interrupt every 8.35ms"? When you triggered P0.7 with your new revision of codes, is your halProcessKeyInterrupt triggered immediately?
  • What do you mean "I need to check the interrupt every 8.35ms"?
    ==> I put the signal into the P0.7 port every 8.35ms, so the interrupt has to happened every 8.35ms.

    When you triggered P0.7 with your new revision of codes, is your halProcessKeyInterrupt triggered immediately?
    ==> Yes
    whenever interrupt is happened, the port toggle (This is just checking interrupt)
    if ( OnBoard_SendKeys( keys, shift ) != SUCCESS )
    {
    // Process SW6 here
    if ( keys & HAL_KEY_SW_6 ) // Switch 6
    {
    P1_0 =~P1_0;
    zero_state = true;
    }
    }

    Do I used wrong?
  • You should check if your code goes to HAL_KEY_EVENT after halProcessKeyInterrupt is triggered.
  • I tested HAL_KEY_EVENT. it was working correctly.
    And I changed test function as below. However the interrupt is not good.
    Sometimes every 2seconds has interrupt,
    Sometimes every 5seconds has interrupt,
    Sometimes every 8seconds has interrupt,

    As you know, I put the interrupt signal every 8.35ms. So the interrupt should be happened every 8.35ms
    If I used external button, the interrupt is working correctly, I think timer or system routine problems.
    I need your help.

    static void simpleBLEPeripheral_HandleKeys( uint8 shift, uint8 keys )
    {
    if ( keys & HAL_KEY_SW_6 )
    {
    #if 1
    P1_0 = ~P1_0;
    #else
    P1_0 =0;
    Delay_1ms(35); // 65us * step
    //halMcuWaitUs(1000);
    P1_0 =1; // triac on
    #endif
    }
    }

    1. In normal interrupt without osal_run_system() function, interrupt has happened every 8.35ms.
    But why normal interrupt with osal_run_system() function has not good interrupt?
    2. As you recommended method, it is not good.
    Do you have another idea?
  • Why do you need to put the interrupt signal every 8.35ms? It very fast and I suppose if there is other system interrupt, this GPI interrupt might not be handled in time.
  • It is bad news for me.

    I want to make 220V ac dimmer controlled by BLE. So I have to control gpio every 8.63ms.
    I wonder cc2541 has 32MHz xtal. I think it it very fast so I choose cc2541 chipset.

    And in normal condtion it is working correctly. Only the problems is with osal_run_system() function.
    I checked the osal_run_system() function, whenever the advertising the interrupt off and on is continuously,
    If I removed the interrupt off on sequence, what happened?
    // HAL_ENTER_CRITICAL_SECTION(intState);
    // HAL_EXIT_CRITICAL_SECTION(intState);


    And I wonder how much times do you guarantee with osal_run_system() function?
  • If you only have to run "P1_0 = ~P1_0; " in your "if ( keys & HAL_KEY_SW_6 )..." of simpleBLEPeripheral_HandleKeys, I don't think it would cause any delay. I suppose you have other task in your SimpleBLEPeripheral that block CPU and causes such 2-8 seconds delay. If you use original SimpleBLEPeripheral example and only add P0.7 as interrupt to run "P1_0 = ~P1_0; " in your "if ( keys & HAL_KEY_SW_6 )..., do you still see such delay?
  • It has same symptom as below, when I put in the 8.35ms signal.
    Sometimes every 2seconds has interrupt,
    Sometimes every 5seconds has interrupt,
    Sometimes every 8seconds has interrupt,

    But If i used external button, it is working. The interrup work correctly.
  • If you use original SimpleBLEPeripheral example and only add P0.7 as interrupt to run "P1_0 = ~P1_0; " in your "if ( keys & HAL_KEY_SW_6 )..." and still see this issue, I would suggest you not to trigger ISR so fast. Maybe you can try to put "P1_0 = ~P1_0; " inside your ISR intead of do it in KEY event handler.

  • Not only the P1_0 = ~P1_0.
    When the interrupt is happened, I have to used the below flow
    P1_0 =0;
    Delay_1ms(3); // 1 ~ 8
    P1_0 =1;

    ====================================================================================
    void halProcessKeyInterrupt (void)
    {
    bool valid=FALSE;

    if (HAL_KEY_SW_6_PXIFG & HAL_KEY_SW_6_BIT) /* Interrupt Flag has been set */
    {
    P1_0 =0;
    Delay_1ms(3); // 65us * step
    P1_0 =1;
    HAL_KEY_SW_6_PXIFG = ~(HAL_KEY_SW_6_BIT); /* Clear Interrupt Flag */
    //valid = TRUE;
    }
    if (valid)
    {
    //osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, HAL_KEY_DEBOUNCE_VALUE);
    osal_start_timerEx (Hal_TaskID, HAL_KEY_EVENT, 1);
    }
    }
    ====================================================================================
    In the service routine the delay is not work,
    every interrupt is happened, I have to used some function.
    from now, it is not good news.
  • Yes, you shouldn’t do delay in ISR.
  • Just to provide some more information here, when you turn on the stack (i.e .use osal_run_system), there are going to be very many interrupts fired by the stack. So this will definitely delay your own interrupts. There is really nothing you can do about this. If you make your interrupts higher priority, you will then delay the stack which will cause problems.

    The way the system is architected, you can not expect to receive interrupts at the exact expected time if the stack is running.