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.

RTOS/LAUNCHCC3220MODASF: interrupt latency periodically get longer

Part Number: LAUNCHCC3220MODASF

Tool/software: TI-RTOS

Hello,

On CC3220MODASF Launch Pad "LAUNCHCC3220MODASF",
interrupt latency looks like periodically get longer.
Usually, it's approx 3us, but periodically get 10us.
For more details, show the graph below.

This is the result of my sample program.

In my project, CPU must respond within several microseconds.
Therefore this latency is a issue to be solved.
How can I make the latency at around 3us constantly?

Sample program is attached.

#include <stddef.h>
#include <ti/drivers/GPIO.h>
#include <ti/drivers/Timer.h>
#include <ti/sysbios/BIOS.h>
#include "Board.h"

Timer_Handle timerHandle = 0;
Timer_Params timerParams;

unsigned long interruptLatency;

#define RECORD_LENGTH 32768
unsigned long interruptLatencyHistory[RECORD_LENGTH] = {};
unsigned long recordIndex = 0;


void timerCallback(Timer_Handle myHandle)
{
    if (timerHandle != 0) { // avoid exception
        interruptLatency = Timer_getCount(timerHandle);
        if (recordIndex >= RECORD_LENGTH) {
            GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
            while(1);   // fin.
        }
        interruptLatencyHistory[recordIndex++] = interruptLatency;
    }
}


void *mainThread(void *arg0)
{
    GPIO_init();

    GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);

    Timer_init();
    Timer_Params_init(&timerParams);
    timerParams.period = 100; // 100us
    timerParams.periodUnits = Timer_PERIOD_US;
    timerParams.timerMode = Timer_CONTINUOUS_CALLBACK;
    timerParams.timerCallback = timerCallback;
    timerHandle = Timer_open(Board_TIMER0, &timerParams);
    Timer_start(timerHandle);

    return (NULL);
}

Sample program usage
1) Import timerled_CC3220SF_LAUNCHXL_tirtos_ccs from SDK 2.10.
2) Replace serial_wifi.c in the project with attached file.
3) Build, load, and run.
4) Then Save Memory array interruptLatencyHistory in order to get latency data.

Tools
CCS8.0.0.00016_win32
simplelink_cc32xx_sdk_2_10_00_04
ti-cgt-arm_18.1.1.LTS (within SDK)
TI-RTOS 6.55.00.07 (within SDK)

I've tried below on the sample program,
- Change Board_TIMER0 to Board_TIMER1
- Change configuration Debug to Release
- Change base program timerled_CC3220SF_LAUNCHXL_tirtos_ccs to timerled_CC3220SF_LAUNCHXL_tirtos_gcc
- Change base program timerled_CC3220SF_LAUNCHXL_tirtos_ccs to serial_wifi_CC3220SF_LAUNCHXL_tirtos_ccs
- Change tools CCS8.0+SDK2.10+CGT18.1 to CCS7.4+SDK1.60+CGT16.9

The results did not change.
Unfortunately, I'm not familiar with FreeRTOS, so I've not tried yet...

Regards,

Nobuhiro

  • There was a mistake in sample program usage. Correct it as follows.
    2) Replace serial_wifi.c in the project with attached file.
    ->
    2) Replace timerled.c in the project with attached file.

    Nobuhiro
  • Hi Nobuhiro-san,

    First of all, thank you very much for providing very detailed steps on how to reproduce your issue. It really helps in letting me replicate what you're seeing and understanding the context of the problem.

    So I followed the steps that you wrote to reproduce the problem. Just like you, using tirtos I sometimes get latency spikes of up to ~750 ticks.

    I also tried the following steps to reduce latency:

    1. Use freertos instead of tirtos:

       Result: Base latency increased from ~300 ticks to ~500 ticks. Still get ~750 tick spikes.

    2. Increase timer interrupt priority in CC3220SF_LAUNCHXL.c (.intPriority in timerCC3220SFHWAttrs):

       Result: Base latency increased from ~300 ticks to ~400 ticks. Still get ~750 tick spikes.

    3. Manually setup GPT timer and interrupt without using TI Drivers:

       Result: Base latency dropped to ~100 ticks, no more latency spikes.

    To replicate, replace timerled code with the following:

    #include <stddef.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/Timer.h>
    #include <ti/sysbios/BIOS.h>
    #include "Board.h"
    #include <ti/devices/cc32xx/driverlib/timer.h>
    #include <ti/devices/cc32xx/driverlib/interrupt.h>
    #include <ti/devices/cc32xx/driverlib/prcm.h>
    #include <ti/devices/cc32xx/driverlib/rom_map.h>
    #include <ti/devices/cc32xx/inc/hw_memmap.h>
    #include <ti/devices/cc32xx/inc/hw_ints.h>
    #include <ti/devices/cc32xx/inc/hw_timer.h>
    #include <ti/devices/cc32xx/inc/hw_types.h>
    
    Timer_Handle timerHandle = 0;
    Timer_Params timerParams;
    
    unsigned long interruptLatency;
    
    #define RECORD_LENGTH 32768
    unsigned long interruptLatencyHistory[RECORD_LENGTH] = {};
    unsigned long recordIndex = 0;
    
    
    void timerCallback(void)
    {
        MAP_TimerIntClear(TIMERA2_BASE, 0x2FFF);
        interruptLatency = 8000 - MAP_TimerValueGet(TIMERA2_BASE, TIMER_A);
        if (recordIndex >= RECORD_LENGTH)
        {
            GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
            while (1)
                ;   // fin.
        }
        interruptLatencyHistory[recordIndex++] = interruptLatency;
    }
    
    
    void *mainThread(void *arg0)
    {
        GPIO_init();
    
        GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
    
        /* Initialize hardware timer */
        MAP_PRCMPeripheralClkEnable(PRCM_TIMERA2, PRCM_RUN_MODE_CLK);
        MAP_IntDisable(INT_TIMERA2A);
        MAP_IntDisable(INT_TIMERA2B);
        MAP_TimerIntDisable(TIMERA2_BASE,TIMER_CAPB_EVENT|TIMER_CAPB_MATCH|TIMER_TIMB_TIMEOUT|TIMER_CAPA_EVENT|TIMER_CAPA_MATCH|TIMER_TIMA_TIMEOUT);
        MAP_TimerDisable(TIMERA2_BASE,TIMER_BOTH);
        MAP_TimerIntClear(TIMERA2_BASE,TIMER_CAPB_EVENT|TIMER_CAPB_MATCH|TIMER_TIMB_TIMEOUT|TIMER_CAPA_EVENT|TIMER_CAPA_MATCH|TIMER_TIMA_TIMEOUT);
    
        /* set timer interrupt to 0, highest app priority */
        MAP_IntPrioritySet(INT_TIMERA2A,0<<5);
        MAP_IntPrioritySet(INT_TIMERA2B,0<<5);
    
        /* Configure timer as periodic count-down with period of 8000 ticks */
        MAP_TimerConfigure(TIMERA2_BASE,TIMER_CFG_PERIODIC);
        MAP_TimerLoadSet(TIMERA2_BASE,TIMER_A,8000);//8000 ticks at 80Mhz = 100us
        MAP_TimerIntRegister(TIMERA2_BASE,TIMER_A,timerCallback);
    
        /* Start the timer */
        MAP_IntEnable(INT_TIMERA2A);
        MAP_TimerIntEnable(TIMERA2_BASE,TIMER_TIMA_TIMEOUT);
        MAP_TimerEnable(TIMERA2_BASE,TIMER_A);
    
        return (NULL);
    }
    

    You will also have to add the following line into <ti/devices/cc32xx/driverlib/timer.h>, <ti/devices/cc32xx/driverlib/interrupt.h>, and <ti/devices/cc32xx/driverlib/prcm.h>:

    #include <ti/devices/cc32xx/inc/hw_types.h>

    So there probably is something within TI drivers and its interrupt handling that is causing the issue. I can point the TI drivers developers to this interrupt latency issue if you would like, but if you have critical timing requirements where need to consistently respond to interrupts as fast as possible I suggest you use driverlib to setup and handle those interrupts. 

    Regards,
    Michael

  • Hello Michael,

    Thanks for your quick response.
    I'm very glad to hear normal latency also shorten.

    When I posted, I was simplify the program to see the issue easily.
    Actually, this issue happened in my application without Timer.
    The interrupt source is not a Timer, but external device connected to GPIO.
    I'll try your suggestion (3) first.

    I hope the driver is fixed and this isuue is solved.

    Thanks,

    Nobuhiro

  • Hello, Michael,

    I've attempted modifying my application following your suggestion.
    In my application, I use the interrupt from GPIO28 and along with WLAN transmission.
    There are some spikes happened, especially right after WLAN transmission.

    I attach the sample program, that consist of two files.

    File 1)

    #include <stddef.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/PWM.h>
    #include <ti/drivers/SPI.h>
    #include <ti/drivers/net/wifi/slnetifwifi.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/devices/cc32xx/inc/hw_types.h>
    #include <ti/devices/cc32xx/inc/hw_memmap.h>
    #include <ti/devices/cc32xx/inc/hw_ints.h>
    #include <ti/devices/cc32xx/inc/hw_timer.h>
    #include <ti/devices/cc32xx/driverlib/timer.h>
    #include <ti/devices/cc32xx/driverlib/prcm.h>
    #include <ti/devices/cc32xx/driverlib/rom_map.h>
    #include <ti/devices/cc32xx/driverlib/gpio.h>
    #include <ti/devices/cc32xx/driverlib/pin.h>
    #include <ti/devices/cc32xx/driverlib/interrupt.h>
    #include "pthread.h"
    #include "Board.h"
    
    
    // ex4 gpio-tx
    #define USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
    #define RECORD_LENGTH 32768
    #define INTR_PERIOD_COUNTS_VALUE 4000 // 50us
    #define PWM_DUTY_COUNTS_VALUE    3500 // 43.75us
    #define GPIO28_INT_FROM_DEVICE 2
    #define AP_SSID "XXXXX"   // Access Point (Open security)
    #define PAYLOAD_SIZE 24576          // 24KB
    #define SEND_PERIOD_INT 2048        // WLAN sending occurs every 2048 interrupts (approx 102ms).
    
    PWM_Params pwmParams;
    PWM_Handle pwmHandle = 0;
    
    pthread_t gSpawnThread = (pthread_t)NULL;
    pthread_attr_t pAttrs_spawn;
    struct sched_param  priParam;
    
    Task_Params taskParams;
    Task_Struct taskStruct;
    Char taskStack[4096];
    
    Semaphore_Params semParams;
    Semaphore_Struct semStruct;
    Semaphore_Handle semHandle;
    
    int32_t sock;
    SlNetCfgIpV4Args_t ipV4;
    SlSockAddrIn_t sAddr;
    SlWlanSecParams_t secParams;
    
    unsigned long send_count = 0;
    unsigned char payload[PAYLOAD_SIZE] = {};
    unsigned long interruptCount = 0;
    unsigned long interruptLatency;
    unsigned long interruptLatencyHistory[RECORD_LENGTH] = {};
    unsigned long recordIndex = 0;
    
    // Callback Functions from SimpleLink Wifi Driver - must be defined
    void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent) {}
    void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent) {}
    void SimpleLinkHttpServerEventHandler(SlNetAppHttpServerEvent_t *pHttpEvent, SlNetAppHttpServerResponse_t *pHttpResponse) {}
    void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent) {}
    void SimpleLinkSockEventHandler(SlSockEvent_t *pSock) {}
    void SimpleLinkFatalErrorEventHandler(SlDeviceFatal_t *slFatalErrorEvent){}
    void SimpleLinkNetAppRequestEventHandler(SlNetAppRequest_t *pNetAppRequest, SlNetAppResponse_t *pNetAppResponse) {}
    void SimpleLinkNetAppRequestMemFreeEventHandler(uint8_t *buffer) {}
    
    
    // WLAN send
    // To evaluate the effect of wireless LAN transmission on latency of gpio28Callback.
    void sendTask(UArg arg0, UArg arg1)
    {
        for (;;) {
            Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
            *(uint32_t *)0x40005004 = 0x00000001;   // GPIO8(P3.7)=1
            send_count++;
            sl_SendTo(sock, payload, sizeof(payload), 0, (SlSockAddr_t*)&sAddr, sizeof(SlSockAddrIn_t));
            *(uint32_t *)0x40005004 = 0x00000000;   // GPIO8(P3.7)=0
        }
    }
    
    
    // This callback requires hard-realtime characteristic.
    void gpio28Callback(void)
    {
    #ifdef USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
        MAP_GPIOIntDisable(GPIOA3_BASE, GPIO_PIN_4);
        MAP_GPIOIntClear(GPIOA3_BASE, GPIO_PIN_4);
    #endif
        *(volatile uint32_t *)0x40005020 = 0x00000008;   // GPIO11(P1.10)=1
    
        interruptCount++;
        if (interruptCount > 10000) { // ignore init spike
            interruptLatency = (PWM_DUTY_COUNTS_VALUE) - *(volatile uint32_t *)(0x40033048);
            if (recordIndex >= RECORD_LENGTH) {
    //            GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
    //            while(1); // fin.
            } else {
                interruptLatencyHistory[recordIndex++] = interruptLatency;
            }
        }
    
        if (interruptCount % SEND_PERIOD_INT == 0) {
            *(uint32_t *)0x40005008 = 0x00000002;   // GPIO9(P3.9)=1
            Semaphore_post(semHandle);
            *(uint32_t *)0x40005008 = 0x00000000;   // GPIO9(P3.9)=0
        }
    
        *(volatile uint32_t *)0x40005020 = 0x00000000;   // GPIO11(P1.10)=0
    #ifdef USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
        MAP_GPIOIntEnable(GPIOA3_BASE, GPIO_PIN_4);
    #endif
    }
    
    
    void *mainThread(void *arg0)
    {
        GPIO_init();
        SPI_init();
    
        GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
    
        Semaphore_Params_init(&semParams);
        semParams.mode = Semaphore_Mode_BINARY;
        Semaphore_construct(&semStruct, 0, &semParams);
        semHandle = Semaphore_handle(&semStruct);
    
        // Create sl_Task
        pthread_attr_init(&pAttrs_spawn);
        priParam.sched_priority = 9;
        pthread_attr_setschedparam(&pAttrs_spawn, &priParam);
        pthread_attr_setstacksize(&pAttrs_spawn, 4096);
        pthread_create(&gSpawnThread, &pAttrs_spawn, sl_Task, NULL);
    
        // Create send task
        Task_Params_init(&taskParams);
        taskParams.stackSize = 4096;
        taskParams.stack = &taskStack;
        taskParams.priority = 10;
        Task_construct(&taskStruct, (Task_FuncPtr)sendTask, &taskParams, NULL);
    
        // Establish connection to AP
        sl_Stop(10000);
        sl_Start(0, 0, 0);
        ipV4.Ip =        (_u32)SL_IPV4_VAL(192, 168, 0, 6); // my(sender) ip
        ipV4.IpMask =    (_u32)SL_IPV4_VAL(255, 255, 255, 0);
        ipV4.IpGateway = (_u32)SL_IPV4_VAL(192, 168, 0, 1); // dummy
        ipV4.IpDnsServer=(_u32)SL_IPV4_VAL(192, 168, 0, 1); // dummy
        sl_NetCfgSet(SL_NETCFG_IPV4_STA_ADDR_MODE, SL_NETCFG_ADDR_STATIC, sizeof(SlNetCfgIpV4Args_t), (uint8_t *)&ipV4);
        secParams.Key = "";
        secParams.KeyLen = 0;
        secParams.Type = SL_WLAN_SEC_TYPE_OPEN;
        sl_WlanConnect(AP_SSID, strlen(AP_SSID),0,&secParams,0);
    
        Task_sleep(5000);   // wait 5s
    
        // Create socket
        sAddr.sin_family = SL_AF_INET;
        sAddr.sin_port = sl_Htons(5001);
        sAddr.sin_addr.s_addr = sl_Htonl(SL_IPV4_VAL(192, 168, 0, 108));    // receiver's ip
        sock = sl_Socket(SL_AF_INET, SL_SOCK_DGRAM, 0);
    
        // GPIO28(P2.2) is used as an interrupt source, connected to PWM06(P1.9).
    
    #ifdef USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
        MAP_PRCMPeripheralClkEnable(PRCM_GPIOA3, PRCM_RUN_MODE_CLK);
        MAP_UtilsDelay(10);
        PinTypeGPIO(PIN_18, PIN_MODE_0, false);
        GPIODirModeSet(GPIOA3_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN);
        IntPrioritySet(INT_GPIOA3, INT_PRIORITY_LVL_1);
        GPIOIntTypeSet(GPIOA3_BASE, GPIO_PIN_4, GPIO_RISING_EDGE);
    
        GPIOIntClear(GPIOA3_BASE, GPIO_PIN_4);
        GPIOIntRegister(GPIOA3_BASE, gpio28Callback);
        GPIOIntEnable(GPIOA3_BASE, GPIO_PIN_4);
    #else
        GPIO_setCallback(GPIO28_INT_FROM_DEVICE, gpio28Callback);
    #endif
    
        PWM_init();
        PWM_Params_init(&pwmParams);
        pwmParams.idleLevel = PWM_IDLE_LOW;
        pwmParams.periodUnits = PWM_PERIOD_COUNTS;
        pwmParams.periodValue = INTR_PERIOD_COUNTS_VALUE;
        pwmParams.dutyUnits = PWM_DUTY_COUNTS;
        pwmParams.dutyValue = PWM_DUTY_COUNTS_VALUE;
        pwmHandle = PWM_open(Board_PWM0, &pwmParams);  // PWM6(Timer3A)
        PWM_start(pwmHandle);
    
        GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
    
        return (NULL);
    }
    

    File2)

    *** CC3220SF_LAUNCHXL.c	2018-04-05 17:52:31.297000000 +0900
    --- file2_CC3220SF_LAUNCHXL.c	2018-04-05 18:06:14.422753100 +0900
    ***************
    *** 229,236 ****
          /* CC3220SF_LAUNCHXL_GPIO_SW3 */
          GPIOCC32XX_GPIO_22 | GPIO_CFG_INPUT | GPIO_CFG_IN_INT_RISING,
      
    !     /* CC3220SF_LAUNCHXL_SPI_MASTER_READY */
    !     GPIOCC32XX_GPIO_28 | GPIO_DO_NOT_CONFIG,
          /* CC3220SF_LAUNCHXL_SPI_SLAVE_READY */
          GPIOCC32XX_GPIO_12 | GPIO_DO_NOT_CONFIG,
      
    --- 229,236 ----
          /* CC3220SF_LAUNCHXL_GPIO_SW3 */
          GPIOCC32XX_GPIO_22 | GPIO_CFG_INPUT | GPIO_CFG_IN_INT_RISING,
      
    !     /* External Interrupt, connected to PWM06 GPIO10(P1.9) */
    !     GPIOCC32XX_GPIO_28 | GPIO_CFG_INPUT | GPIO_CFG_IN_INT_RISING,
          /* CC3220SF_LAUNCHXL_SPI_SLAVE_READY */
          GPIOCC32XX_GPIO_12 | GPIO_DO_NOT_CONFIG,
      
    ***************
    *** 246,252 ****
          /* CC3220SF_LAUNCHXL_GPIO_LED_D6 */
          /* GPIOCC32XX_GPIO_10 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW, */
          /* CC3220SF_LAUNCHXL_GPIO_LED_D5 */
    !     /* GPIOCC32XX_GPIO_11 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW, */
      
          /* Sharp Display - GPIO configurations will be done in the Display files */
          GPIOCC32XX_GPIO_12 | GPIO_DO_NOT_CONFIG, /* SPI chip select */
    --- 246,253 ----
          /* CC3220SF_LAUNCHXL_GPIO_LED_D6 */
          /* GPIOCC32XX_GPIO_10 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW, */
          /* CC3220SF_LAUNCHXL_GPIO_LED_D5 */
    !     GPIOCC32XX_GPIO_11 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW,
    !     GPIOCC32XX_GPIO_08 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_HIGH | GPIO_CFG_OUT_LOW,
      
          /* Sharp Display - GPIO configurations will be done in the Display files */
          GPIOCC32XX_GPIO_12 | GPIO_DO_NOT_CONFIG, /* SPI chip select */
    

    Sample program usage
    1) Import serial_wifi_CC3220SF_LAUNCHXL_tirtos_ccs from SDK 2.10.
    2) Replace serial_wifi.c in the project with attached file 1.
    3) Modify CC3220SF_LAUNCHXL.c in the project based on attached file2.diff.
    4) Connect GPIO10(P1.9) to GPIO28(P2.2) with jumper wire.
    5) Build, load, and run.
    6) Wait for a while, then Save Memory array interruptLatencyHistory in order to get latency data.
    (32-Bit Signed Int, 32768 words)

    The result of my sample program is shown below.
    Case 1) Use DriverLib ->Fig.1
    Case 2) Use TI Driver (Comment out the line 24 "#define USE_DRIVERLIB_INSTEAD_OF_TIDRIVER") ->Fig.2

    I have two question.

    1) How can I remove the spike latency?
    2) GPIO9 indicates execution time of Semaphore_post.
    It usually (case 2) takes 3us, but in case 1, it's about 100us.

    Tools
    LAUNCHCC3220MODASF
    CCS8.0.0.00016_win32
    simplelink_cc32xx_sdk_2_10_00_04
    ti-cgt-arm_18.1.1.LTS (within SDK)
    TI-RTOS 6.55.00.07 (within SDK)

    Regards,
    Nobuhiro

  • There are some additional information.

    The timing chart of case 1 is shown below.

    1) GPIO10: PWM06 -> GPIO28 as interrupt source
    2) GPIO11: gpio28Callback
    3) GPIO9: Semaphore_post
    4) GPIO8: sl_Send in sendTask (10ms+)

    In this case, Semaphore_post takes 109us, it's so long.

    The timing chart of case 2 is shown below.

    In this case, Semaphore_post takes 3us, it looks like no problem.

    Regards,
    Nobuhiro

  • Hi Nobuhiro-san,

    Following your instructions, I have reproduced the latency issue that you are seeing.

    For the small delay that you are seeing, it seems like you can eliminate it by not calling GPIO_init(), and only using driverlib calls to setup all of the GPIOs, including the debug GPIOs.

    With the following code:

    #include <stddef.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/PWM.h>
    #include <ti/drivers/SPI.h>
    #include <ti/drivers/net/wifi/slnetifwifi.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/devices/cc32xx/inc/hw_types.h>
    #include <ti/devices/cc32xx/inc/hw_memmap.h>
    #include <ti/devices/cc32xx/inc/hw_ints.h>
    #include <ti/devices/cc32xx/inc/hw_timer.h>
    #include <ti/devices/cc32xx/driverlib/timer.h>
    #include <ti/devices/cc32xx/driverlib/prcm.h>
    #include <ti/devices/cc32xx/driverlib/rom_map.h>
    #include <ti/devices/cc32xx/driverlib/gpio.h>
    #include <ti/devices/cc32xx/driverlib/pin.h>
    #include <ti/devices/cc32xx/driverlib/interrupt.h>
    #include "pthread.h"
    #include "Board.h"
    
    
    // ex4 gpio-tx
    #define USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
    #define RECORD_LENGTH 32768
    #define INTR_PERIOD_COUNTS_VALUE 4000 // 50us
    #define PWM_DUTY_COUNTS_VALUE    3500 // 43.75us
    #define GPIO28_INT_FROM_DEVICE 2
    #define AP_SSID "simplelinktest"   // Access Point (Open security)
    #define PAYLOAD_SIZE 24576          // 24KB
    #define SEND_PERIOD_INT 2048        // WLAN sending occurs every 2048 interrupts (approx 102ms).
    
    PWM_Params pwmParams;
    PWM_Handle pwmHandle = 0;
    
    pthread_t gSpawnThread = (pthread_t)NULL;
    pthread_attr_t pAttrs_spawn;
    struct sched_param  priParam;
    
    Task_Params taskParams;
    Task_Struct taskStruct;
    Char taskStack[4096];
    
    Semaphore_Params semParams;
    Semaphore_Struct semStruct;
    Semaphore_Handle semHandle;
    
    int32_t sock;
    SlNetCfgIpV4Args_t ipV4;
    SlSockAddrIn_t sAddr;
    SlWlanSecParams_t secParams;
    
    unsigned long send_count = 0;
    unsigned char payload[PAYLOAD_SIZE] = {};
    unsigned long interruptCount = 0;
    unsigned long interruptLatency;
    unsigned long interruptLatencyHistory[RECORD_LENGTH] = {};
    unsigned long recordIndex = 0;
    
    // Callback Functions from SimpleLink Wifi Driver - must be defined
    void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent) {}
    void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent) {}
    void SimpleLinkHttpServerEventHandler(SlNetAppHttpServerEvent_t *pHttpEvent, SlNetAppHttpServerResponse_t *pHttpResponse) {}
    void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent) {}
    void SimpleLinkSockEventHandler(SlSockEvent_t *pSock) {}
    void SimpleLinkFatalErrorEventHandler(SlDeviceFatal_t *slFatalErrorEvent){}
    void SimpleLinkNetAppRequestEventHandler(SlNetAppRequest_t *pNetAppRequest, SlNetAppResponse_t *pNetAppResponse) {}
    void SimpleLinkNetAppRequestMemFreeEventHandler(uint8_t *buffer) {}
    
    
    // WLAN send
    // To evaluate the effect of wireless LAN transmission on latency of gpio28Callback.
    void sendTask(UArg arg0, UArg arg1)
    {
        for (;;) {
            Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
            *(uint32_t *)0x40005004 = 0x00000001;   // GPIO8(P3.7)=1
            send_count++;
            sl_SendTo(sock, payload, sizeof(payload), 0, (SlSockAddr_t*)&sAddr, sizeof(SlSockAddrIn_t));
            *(uint32_t *)0x40005004 = 0x00000000;   // GPIO8(P3.7)=0
        }
    }
    
    
    // This callback requires hard-realtime characteristic.
    void gpio28Callback(void)
    {
    #ifdef USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
        MAP_GPIOIntDisable(GPIOA3_BASE, GPIO_PIN_4);
        MAP_GPIOIntClear(GPIOA3_BASE, GPIO_PIN_4);
    #endif
        *(volatile uint32_t *)0x40005020 = 0x00000008;   // GPIO11(P1.10)=1
    
        interruptCount++;
        if (interruptCount > 10000) { // ignore init spike
            interruptLatency = (PWM_DUTY_COUNTS_VALUE) - *(volatile uint32_t *)(0x40033048);
            if (recordIndex >= RECORD_LENGTH) {
    //            GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
                while(1); // fin.
            } else {
                interruptLatencyHistory[recordIndex++] = interruptLatency;
            }
        }
    
        if (interruptCount % SEND_PERIOD_INT == 0) {
            *(uint32_t *)0x40005008 = 0x00000002;   // GPIO9(P3.9)=1
            Semaphore_post(semHandle);
            *(uint32_t *)0x40005008 = 0x00000000;   // GPIO9(P3.9)=0
        }
    
        *(volatile uint32_t *)0x40005020 = 0x00000000;   // GPIO11(P1.10)=0
    #ifdef USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
        MAP_GPIOIntEnable(GPIOA3_BASE, GPIO_PIN_4);
    #endif
    }
    
    
    void *mainThread(void *arg0)
    {
        int lretVal;
        //GPIO_init();
        SPI_init();
    
    //    GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    //    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
    
        Semaphore_Params_init(&semParams);
        semParams.mode = Semaphore_Mode_BINARY;
        Semaphore_construct(&semStruct, 0, &semParams);
        semHandle = Semaphore_handle(&semStruct);
    
        // Create sl_Task
        pthread_attr_init(&pAttrs_spawn);
        priParam.sched_priority = 9;
        pthread_attr_setschedparam(&pAttrs_spawn, &priParam);
        pthread_attr_setstacksize(&pAttrs_spawn, 4096);
        pthread_create(&gSpawnThread, &pAttrs_spawn, sl_Task, NULL);
    
        // Create send task
        Task_Params_init(&taskParams);
        taskParams.stackSize = 4096;
        taskParams.stack = &taskStack;
        taskParams.priority = 10;
        Task_construct(&taskStruct, (Task_FuncPtr)sendTask, &taskParams, NULL);
    
        // Establish connection to AP
        sl_Stop(10000);
        lretVal = sl_Start(0, 0, 0);
        if(lretVal!=0){
            sl_WlanSetMode(ROLE_STA);
            sl_Stop(10000);
            lretVal = sl_Start(0,0,0);
        }
        ipV4.Ip =        (_u32)SL_IPV4_VAL(192, 168, 1, 2); // my(sender) ip
        ipV4.IpMask =    (_u32)SL_IPV4_VAL(255, 255, 255, 0);
        ipV4.IpGateway = (_u32)SL_IPV4_VAL(192, 168, 0, 1); // dummy
        ipV4.IpDnsServer=(_u32)SL_IPV4_VAL(192, 168, 0, 1); // dummy
        sl_NetCfgSet(SL_NETCFG_IPV4_STA_ADDR_MODE, SL_NETCFG_ADDR_STATIC, sizeof(SlNetCfgIpV4Args_t), (uint8_t *)&ipV4);
        secParams.Key = "wifitest";
        secParams.KeyLen = strlen(secParams.Key);
        secParams.Type = SL_WLAN_SEC_TYPE_WPA_WPA2;
        lretVal = sl_WlanConnect(AP_SSID, strlen(AP_SSID),0,&secParams,0);
    
        Task_sleep(5000);   // wait 5s
    
        // Create socket
        sAddr.sin_family = SL_AF_INET;
        sAddr.sin_port = sl_Htons(5001);
        sAddr.sin_addr.s_addr = sl_Htonl(SL_IPV4_VAL(192, 168, 1, 1));    // receiver's ip
        sock = sl_Socket(SL_AF_INET, SL_SOCK_DGRAM, 0);
    
        // GPIO28(P2.2) is used as an interrupt source, connected to PWM06(P1.9).
    
    #ifdef USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
        MAP_PRCMPeripheralClkEnable(PRCM_GPIOA3, PRCM_RUN_MODE_CLK);
        MAP_UtilsDelay(10);
        //Add the other debug GPIOS
        MAP_PRCMPeripheralClkEnable(PRCM_GPIOA1, PRCM_RUN_MODE_CLK);
        MAP_UtilsDelay(10);
    //    PinTypeGPIO(PIN_01, PIN_MODE_0, false); //GPIO10
    //    GPIODirModeSet(GPIOA1_BASE, GPIO_PIN_2, GPIO_DIR_MODE_OUT);
        PinTypeGPIO(PIN_02, PIN_MODE_0, false);//GPIO11
        GPIODirModeSet(GPIOA1_BASE, GPIO_PIN_3, GPIO_DIR_MODE_OUT);
        PinTypeGPIO(PIN_63, PIN_MODE_0, false); //GPIO08
        GPIODirModeSet(GPIOA1_BASE, GPIO_PIN_0, GPIO_DIR_MODE_OUT);
        PinTypeGPIO(PIN_64, PIN_MODE_0, false); //GPIO08
        GPIODirModeSet(GPIOA1_BASE, GPIO_PIN_1, GPIO_DIR_MODE_OUT);
    
        PinTypeGPIO(PIN_18, PIN_MODE_0, false);
        GPIODirModeSet(GPIOA3_BASE, GPIO_PIN_4, GPIO_DIR_MODE_IN);
        IntPrioritySet(INT_GPIOA3, INT_PRIORITY_LVL_0);
        GPIOIntTypeSet(GPIOA3_BASE, GPIO_PIN_4, GPIO_RISING_EDGE);
    
        GPIOIntClear(GPIOA3_BASE, GPIO_PIN_4);
        GPIOIntRegister(GPIOA3_BASE, gpio28Callback);
        GPIOIntEnable(GPIOA3_BASE, GPIO_PIN_4);
    #else
        GPIO_setCallback(GPIO28_INT_FROM_DEVICE, gpio28Callback);
    #endif
    
        PWM_init();
        PWM_Params_init(&pwmParams);
        pwmParams.idleLevel = PWM_IDLE_LOW;
        pwmParams.periodUnits = PWM_PERIOD_COUNTS;
        pwmParams.periodValue = INTR_PERIOD_COUNTS_VALUE;
        pwmParams.dutyUnits = PWM_DUTY_COUNTS;
        pwmParams.dutyValue = PWM_DUTY_COUNTS_VALUE;
        pwmHandle = PWM_open(Board_PWM0, &pwmParams);  // PWM6(Timer3A)
        PWM_start(pwmHandle);
    
        //GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
    
        return (NULL);
    }
    

    I get the result in figure 2:

    As for getting rid of the larger delay, I believe that this delay is due to the RTOS performing a context switch when the semaphore_post() unblocks your sendTask.

    Here is benchmark of the TIRTOS delays. Looking at the table, the delays for posting a semaphore are quite high but should not be >1000 cycles. I'm not sure how you would be able to optimize that semaphore delay. 

    One workaround to remove the delay would be to remove the semaphore and instead replace it with a global flag that your sendTask reads in a loop. Something like this eliminates the large delay:

    volatile bool sendWifiNow = false;
    void sendTask(UArg arg0, UArg arg1)
    {
        for (;;) {
            //Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
            if(sendWifiNow){
            *(uint32_t *)0x40005004 = 0x00000001;   // GPIO8(P3.7)=1
            send_count++;
            sl_SendTo(sock, payload, sizeof(payload), 0, (SlSockAddr_t*)&sAddr, sizeof(SlSockAddrIn_t));
            sendWifiNow = false;
            *(uint32_t *)0x40005004 = 0x00000000;   // GPIO8(P3.7)=0
            }
        }
    }
    
    
    // This callback requires hard-realtime characteristic.
    void gpio28Callback(void)
    {
    #ifdef USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
        MAP_GPIOIntDisable(GPIOA3_BASE, GPIO_PIN_4);
        MAP_GPIOIntClear(GPIOA3_BASE, GPIO_PIN_4);
    #endif
        *(volatile uint32_t *)0x40005020 = 0x00000008;   // GPIO11(P1.10)=1
    
        interruptCount++;
        if (interruptCount > 10000) { // ignore init spike
            interruptLatency = (PWM_DUTY_COUNTS_VALUE) - *(volatile uint32_t *)(0x40033048);
            if (recordIndex >= RECORD_LENGTH) {
    //            GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
                while(1); // fin.
            } else {
                interruptLatencyHistory[recordIndex++] = interruptLatency;
            }
        }
    
        if (interruptCount % SEND_PERIOD_INT == 0) {
            *(uint32_t *)0x40005008 = 0x00000002;   // GPIO9(P3.9)=1
            //Semaphore_post(semHandle);
            sendWifiNow = true;
            *(uint32_t *)0x40005008 = 0x00000000;   // GPIO9(P3.9)=0
        }
    
        *(volatile uint32_t *)0x40005020 = 0x00000000;   // GPIO11(P1.10)=0
    #ifdef USE_DRIVERLIB_INSTEAD_OF_TIDRIVER
        MAP_GPIOIntEnable(GPIOA3_BASE, GPIO_PIN_4);
    #endif
    }
    

    You will also need to change the priority level of sendTask to be the lowest priority in the system, otherwise it will prevent the other tasks from running. I understand that this workaround is very crude, but depending on your application it might be acceptable. If you like, I can get an engineer who works on TIRTOS to take a look and see if the semaphore delay can be reduced, but I suspect that even with optimization, you will not be able to reduce the delay much further.

    Regards,

    Michael

  • Thanks Michael,
    I attempted your suggestions, and got same results.
    The spikes are gone in the sample program.
    However, actual program might be too complex to apply this.
    Anyway, I try it.

    I hope this issue is fixed as soon as possible.
    Could you ask the TI Driver (RTOS?) team for fix this issue?
    If possible, I would like to know when it will be available.

    Regards,
    Nobuhiro
  • Hi Nobuhiro-san,

    According to my TIRTOS contact, there exists the option to use a zero latency interrupt in TIRTOS:
    processors.wiki.ti.com/.../BIOS_for_Stellaris_Devices
    However, in a zero latency interrupt you are not allowed to use Semaphore_post() or other similar functions.

    Thus, I recommend you rework your program to remove your dependency on the semaphore post in your ISR.

    Regards,
    Michael
  • Hello Michael,

    Using DriverLib instead of TI Driver, Polling instead of Semaphore, my application got fine.
    On the other hand, zero latency interrupt didn't work well, perhaps, because of my implementaion.
    However, I hope TI driver will work well.
    Thanks for your advice.

    Regards,
    Nobuhiro