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.

CC1352R: simplelink_cc13x2_26x2_sdk_4_10_00_78 gpio.h

Part Number: CC1352R

Hi, 

I use CC1352R with SDK simplelink_cc13x2_26x2_sdk_4_10_00_78.

The question is:

Is it possible to use function for dynamically enable/disable interrupt on single GPIO pin, from device specific gpio driver (simplelink_cc13x2_26x2_sdk_4_10_00_78\source\ti\devices\cc13x2_cc26x2\driverlib) or for this purpose 

function from (C:\ti\simplelink_cc13x2_26x2_sdk_4_10_00_78\source\ti\drivers\GPIO.h) should be used.

For example: PIN_setInterrupt(....)

What is the correct way for dynamically enable/disable interrupt on pin, when the time is critical?

Best regrads,

Ilian

  • Hi Ilian,

    The correct way depend on the driver you use, if you use the GPIO driver (the ti/drivers one), you should use the enable/disable APIs that is provided. If using the PIN driver, you should use the PIN_setInterrupt() as proposed above. 

    Now you could potentially get away with using the driverlib version as well but this could end up conflicting with the internal state that the high-level drivers keep so you would need to be careful if going down that road.

  • Hi M-W,

    Thank you for your answer!

    Best regards,

    Ilian

  • Hi M-W,

    one question about interrupt event DIO register.

    Actually this is the interrupt Flags, I am right?

    I am trying to read this register.

    I am trying to identify only whether there were a front on a single pin (for this reason I don use call back function for interrupt).

    I see that the bit for event on a desired pin is set. (the pin is open and the interrupt is enabled)

    I use the function:

    GPIO_getEventDio()

    The flag in event register is set, but function return 0?

    The interrupt on this pin still enabled, because if I use : PIN_setInterrupt(LF_PinHandle,  PIN_ID(4) | PIN_IRQ_DIS); to disable the interrupt the function clear event flags.

    What is the way to read the event register?

    Best regards,

    Ilian

  • Hi Ilian,

    Assuming the bit is set in GPIO:EVFLAGS31_0, then you should be able to read it out, could you provide a dump of the register as well as thec ode where you try to read it out?

    Note that this event will only be set if both interrupt and edge detect is enabled. If this is true then you will likely have the PIN driver clear the event prior to you reading it out. Even if you do not register a callback the driver has the internal proxy callback used to filter IO interrupts to the correct callback. 

  • Hi M-W,

    Thank you for your fast response!

    The event is set.

    Attached here is the code snippet and debug view of  GPIO:EVFLAGS31_0.

    May be the reason is the internal callback, because when I use Step info I see that the register is read correct, when the code is running not.

    // Alocate pin DIO4 (LF DAT), for reception of a demodulated bits from LF receiver.
        LF_PinHandle = PIN_open(&LF_PinState,  LF_PinTable);
    
        // Test code.
        //PIN_registerIntCb(LF_PinHandle, &LF_DatCallBack);
    
        // Enable interrupt on DIO4.
        //lf_pin_status = PIN_setInterrupt(LF_PinHandle, PIN_ID(4) | PIN_IRQ_POSEDGE);
        lf_pin_status = PIN_setInterrupt(LF_PinHandle, PIN_ID(4) | PIN_IRQ_BOTHEDGES);
        if (lf_pin_status != 0)
        {
            // Error during setting.
            return lf_id; // TBD.
        }
    
        i = 2;
    
        do
        {
            ClockP_usleep(13); // Wait up to 13ms.
    
            // Disable interrupt on DIO4. Clear Event Flag!!!
            /*lf_pin_status = PIN_setInterrupt(LF_PinHandle,  PIN_ID(4) | PIN_IRQ_DIS);
            if (lf_pin_status != 0)
            {
                // Error during setting.
                return lf_id; // TBD.
            }
            */
            // Read Interrupt flag.
            // It is not good practice to mix high level driver function with driverlib function. Here it is used due to, read only flags, without changing the GPIO driver.
            if (GPIO_getEventDio(IOID_4))
            {
                i--;
            }
            else
            {
                if (PIN_getInputValue(LF_DAT))
                {
                    LF_Flags.LF_Flags1_bit.LF_RepeatReception = 1;
                }
    
                lf_pin_status = PIN_setInterrupt(LF_PinHandle, LF_DAT | PIN_IRQ_DIS);
                if (lf_pin_status != 0)
                {
                    // Error during setting.
                    return lf_id; // TBD.
                }
    
                PIN_close(LF_PinHandle);
    
                return lf_id;
            }
        }
        while(i);

    Best regards,

    Ilian

  • Hi Ilian,

    You are likely seeing the PIN HWI "stealing" your event. Try search for "PIN_hwi" in the disassembly view and put a breakpoint in this function.

  • Hi,

    this is possible reason, but I can not set break point "No code associated with"

    The possible solution is to set my own software flag in callback function, but it take time. This is a bit time and current consumption critical code

    Best regards,

    Ilian

  • Hi lilian,

    I tend to put the breakpoints in the "Disassembly view", it works as well and it is easier when debugging library code.

    As for the interrupt as such, I do not think you have a good way around it. More or less all drivers with IO depends on the PIN driver which means that it will register the internal callback and respond to and clear GPIO events that trigger. You will likely find it being quicker and smaller to just use the callback and flip software flags compared to working around it. I can't imagine it impacting the current significantly as it is already running the handler in the background. 

    A note from the code snippet you provided above, the following is not 13 ms as the comment suggest, it is 13 us (and really closer to 120us more likely due to the RTC dependency):

    ClockP_usleep(13); // Wait up to 13ms.

    May I ask what you are trying to implement here, it seems like some kind of serial protocol? 

  • Hi M-W,

    you are right about Clock_usleep(13), should be Clock_usleep(13000),  my mistake, thanks.

    I am trying to detect whether, there is an edge(s) on DIO4 during 13ms sleep time.

    If there is an edge I would like to exit from sleep.

    I try to use IOCIntDisable(IOID_4);, before reading the event flags, but did not help in running mode.

    According to you, implementing the callback with software flags is a good decision in this case?

    About breakpoints in "Disassembly view", for some reason I can't do that :)

    Best regards,

    Ilian

  • Hi ilian,

    Is the 13 ms sleep duration important or are you OK waking up earlier if the event fires? No matter the answer to that question, I would recommend the callback solution, potentially with a semaphore sync in case you do not need to sleep for the full 13ms duration.

    As for the breakpoints, strange. Hard to say why this is without seeing what you do but it should be possible, you could try set a breakdown down in the D. view somewhere inside your actual code (like in main()) and see if that works?

  • Hi M-W,

    Thank you for your responsiveness!

    Yes the 13ms is important, I need to wait up to 13ms or to event from the pin. If there is an even I should exit from 13ms sleep. I use nortos driver

    I already implement the callback solution (with software IFG) and it works.

    I found the next phenomena:

    Waiting in active mode (not using usleep()) and waiting for an event I use symple for(; ; ; ) 

    The code for measuring the necessary timeout is the next:

    while(1)
    {
       
      GPIO_toggleDio(IOID_24);
      for (k = 0; k < 15000; k++);
      {
        if (LF_IfgFlags)
          break;
      }
    }

    When k = 1; measured delay (with scope on pin 24) is 400ns.

    When k = 2; measured delay is 620ns ?

    For k = 15000 , dekay shoud b e 400ns * 15000 = 6ms. Measured delay is 1.88ms.

    Adding count event the count is 91145, which  is the some result. Clock speed is 48MHz. 

    Measuring count , when k = 1, count = 1107, which is 23us not 400ns?

    The optimization level is 0.

    Best regards,

    Ilian

  • Hi Ilian, 

    Have you considered the numbers of instructions required in the delay loop you use? Could you elaborate a bit on how this is supposed to work in practice?

    I would suggest you use the SemaphoreP DPL for delays like this where you can basically just do:

    SemaphoreP_pend(ifgFlagSemaphore, TIMEOUT_MS_TO_TICKS(6));

    This would means it waits up to 6ms or until the semaphore is posted from your callback. This solution also allows for standby while waiting which could be nice as you mentioned you were on a  power budget. 

  • Hi,

    I use NORTOS driver.

    Best regards,

    Ilian

  • Hi iLian,

    The Semaphore DPL is available even for the NoRTOS layer :)

  • Hi,

    using SemaphoreP_pend(...,....) is the MCU will enter in standby mode or sleep?

    When the semaphore is posted in callback is there a delay for wake up of the MCU?

    Because I am trying also a solution to wait in active mode and exit fast when event happen.

    Best regards,

    Ilian

  • Hi ilian,

    The device would enter standby, I guess this is what you refer to as sleep? The valid device states is Active, Idle, Standby, Shutdown (if you look at how we define them).

    When you are in the callback, the device is already active, this means that there is no additional wake up delay associated with the semaphore post. In short, the standby -> active responds time applies to your callback as well so if you want to have a quick callback reaction, you would need to keep the device out of standby. You can do this by setting a power constraint using the Power driver: Power_setConstraint().

  • Hi, Thank you!

    To prevent entering in Idle,Standby, Shutdown I use delay implemented with simple for(; ; ) and waiting flag from the callback.

    Due to needed from accurate timeout in active mode (for cycle settings) I use #pragma FUNCTION_OPTIONS(my_func(),"--opt_level=off") for this part of the program.

    Is it correct implementation?

    Best regards,

    Ilian

  • Hi ilian,

    I would really suggest you use the Power API to prevent the different power modes and instead depend on the DPL features available to you. You could of course do busy spins if you prefer but they will require you to perform tests to verify your loop counts vs time etc. Disabling optimization or not I would assume does not really matter as long as you do not change optimization from development -> release. As long as the optimization level remained constant I would assume the code generated would remain similar. 

  • Hi M-W,

    Thank you for the suggestions!

    I will use the Power_API to prevent entering in power modes, because for example for delays like 50us  using usleep(50); I saw that, the counts are more than 2400 for 50us delay without using the Power_setConstraint();

    Best regrads,

    Ilian

  • Hi M-W,

    I implement the solution and it works when the debugger is attached, when is disconnected there is added ~170us.

    I expect this but according to me the debugger add additional code and the behaviour should be the opposite?

    May be status = Power_setConstraint(PowerCC26XX_DISALLOW_IDLE); has different behaviour with and with out debugger?

    May be the debugger supports the correct active mode waiting in lf_sem_status = SemaphoreP_pend(LF_SemaphoreHdl, 1300); ?

    Whith out the debugger there is additon time ~170us , may be there is oscillator switching?

    What could be the reason for this debugger effect?

    Best regards,

    Ilian

  • Hi,

    I found the reason :)

    Use a Power_disablePolicy(); instead of Power_setConstraint(PowerCC26XX_DISALLOW_IDLE)

    Best regards,

    Ilian

  • Hi M-W,

    I have some question about creating semaphore, interrupt callback function, open a pin - how they are related to the current consumption.

    For example I have a function, which is invoked every 250ms.

    When function start:

     LF_SemaphoreHdl = SemaphoreP_createBinary(0); 

    LF_PinHandle = PIN_open(&LF_PinState,  LF_PinTable);

    PIN_registerIntCb(LF_PinHandle, &LF_DatCallBack);

    In the end of function:

    PIN_close(LF_PinHandle);
    SemaphoreP_delete(LF_SemaphoreHdl);

    The question are:

    Is it necessary to create a semaphore every time and delete it or not. If the semaphore exist all the  time this will increase current consumption?

    Ii register a interrupt callback, but can not un-register it. Is the callback have relation (vie interrupt driver) for increasing current consumption?

    Best regards,

    Ilian

  • Hi Ilian,

    You do not need to delete the semaphore, it does not impact current at all. Same goes for the PIN interrupt, onec you do close you will un-register etc. but it should not be needed. As long as the PIN is in the correct state then you should see no current increase at all leaving it enabled (or the driver open).

  • Hi Thanks,

    this mean that, I can :

    LF_SemaphoreHdl = SemaphoreP_createBinary(0); 

    LF_PinHandle = PIN_open(&LF_PinState,  LF_PinTable);

    PIN_registerIntCb(LF_PinHandle, &LF_DatCallBack);

    One time, after that invoke function which use them (every 250ms) and this will not impact the current consumtion?

    Bet regards,

    Ilian

  • Hi,

    Yes, that is correct, non of these would prevent standby mode. 

  • Hi M-W,

    Thanks! Sorry that I use that tread.

    I found strange behaviour of the project. I will try to explain.

    The idea is to have main cycle every 250ms. The MCU sleep 250ms wake up and verify some things and go to sleep again.

    Additionally the Sensor Controller work in background again on 250ms.

    How this is implemented:

    main_nortos.c

    /*
     *  ======== main ========
     */
    int main(void)
    {
        //NoRTOS_Config cfg;
    
    
        /* Call driver init functions */
        //Board_init();
        Board_Initialization();
    
        // Set config. parameters for NoRTOS.
    
        /* Start NoRTOS */
        NoRTOS_start();
    
        ClockP_Params clkParams;
        ClockP_Params_init(&clkParams);
    
        uint32_t period = 250000/Clock_tickPeriod;
        //uint32_t period = 0;
        clkParams.period = period;
        //clkParams.period = 0;
        clkParams.startFlag = true;
    
        /* Construct a periodic Clock Instance */
        ClockP_construct(&clk0Struct, (ClockP_Fxn)SWTick, period, &clkParams);
    
        //clk2Handle = ClockP_handle(&clk0Struct);
        ClockP_start(clk2Handle);
    
        /* Call mainThread function */
        mainThread(NULL);
    
        while (1) {}
    
    }

    In the main loop:

    /* Loop forever */
         while(1) {
    
             /* The SimpleLink host driver architecture mandate calling 'sl_task' in a NO-RTOS application's main loop.       */
             /* The purpose of this call, is to handle asynchronous events and get flow control information sent from the NWP.*/
             /* Every event is classified and later handled by the host driver event handlers. */
             sl_Task(NULL);
    
             Power_setPolicy(PowerCC26XX_standbyPolicy);
             Power_enablePolicy();
    
             Power_idleFunc();
             //usleep(250000); // Wait in LPM 250ms.
             //usleep(500000); // Wait in LPM 500ms.
             //usleep(1000000);// Wait in LPM 1s.
    
             // Clear External WDT.
             extWDTClear();
    
             if (scButtonsChanges) {
                 buttonsChanges |= scButtonsChanges;
                 scButtonsChanges = 0x0000;
             }
    
             if (scAccChanges) {
                 accChanges |= scAccChanges;
                 scAccChanges = 0x0000;
             }
    
             if (LF_Flags.LF_Flags1_bit.LF_Reception) {
    
                 LF_ReceptionTask();
    
                 LF_Flags.LF_Flags1_bit.LF_Reception = 0;
             }
    
    // Do some tasks..
    // ...
    
    } // End main loop
    
    /*
     *  ======== Main Time Base ISR ===============
     *            Resolution 250ms
     */
    
    void SWTick(uintptr_t arg0){
    
        // Test code.
        //GPIO_toggleDio(IOID_6);
    
        // Time base 250ms.
    
        if (!tFlags.tagStateBit.underLF) {
    
            // Enable the LF reception when the tag is outside the LF field every 250ms.
            LF_Flags.LF_Flags1_bit.LF_Reception = 1;
        }
        else {
    
            // The tag is under LF field.
            lfUnderFieldTimeCounter++;
    
            if (lfUnderFieldTimeCounter >= TIME_BASE_1S) {
    
                lfUnderFieldTimeCounter = 0x0000;
    
                // Enable the LF reception when the tag is inside the LF field every 1s.
                LF_Flags.LF_Flags1_bit.LF_Reception = 1;
            }
    // Do something
    // ....
    } // End
    

    1. Is that implementation is correct?

    Testing with Set/Reset pin (measuring with scope) everything work correct.

    The MCU wake up every 250ms do some fast verifications and goes to sleep again for 250ms.

     LF_ReceptionTask();  in general wait 13ms (using "lf_sem_status = SemaphoreP_pend(LF_SemaphoreHdl, 1300);") us we discuss before.

    The code work, but when I see the current consumption graph, there is a strange thing.

    It seems like the LF_ReceptionTask(); is invoke again, 1-2 ms after first call.

    May be this is a small out of sync from main MCU and SC? (The SC wake up the main MCU)

    Attached here is the current graph.

    Best regards,

    Ilian

     

  • Hi,

    From what I can tell your code looks OK. That said, I can't give you any good pointers on what the peak might be in terms of SW. There could be multiple reasons such as the SC waking up the MCU or the MCU being in a "pend" but got waked by something else just to go back to sleep again.

    It seems to be quite deterministic so I would recommend you throw down a few GPIO toggles (if possible) to check where in your SW you are currently located (not minding the extra current for the purpose of measuring). 

  • Hi M-W,

    Thanks again for your professional support!

    It is important to here that the code looks OK!

    I found reason.

    Best regards,

    Ilian