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.

CC1352P: mixing one shot + continuous timers

Part Number: CC1352P
Other Parts Discussed in Thread: SYSCONFIG

Hi. I'm using CCS Version: 12.3.0.00005, SimpleLink v6.41.0.17

I have an architecture where I'm waiting for a packet, then using a one shot timer to wait an offset in microseconds, followed by a continuous timer for a few cycles of fixed interval. 

For example, I get a packet at t=1000us, I wait an offset of 2000us, then fire a continuous timer every 3000 us for 10 cycles. 
I am using a GPIO on a scope to verify the timing, it looks great running concurrently with my radio thread and UART threads. 

The ultimate purpose for this is to schedule system events such as GPIO toggles or ADC reads exactly when I want them to occur, outside of a chained set of radio commands. 
It seems these need to be decoupled when using the chained API. 

After a random interval of time, functioning perfectly for minutes and even hours, I get a hardfault, jump to invalid PC @ 0x00. 
This was not happening until I started using the continous timer. I was using lots of one shot timers before, now I'm using the combination of one shot + continuous when I noticed this failure mode.

The timer callbacks are set at boot, and those values never change. 
My tasks have plenty of stack space, which was my next guess that the environment is trashed. 

Here's the code - not optimized for production, just trying things.

A few questions 

  • Are there better ways to schedule system events when using radio command chains?
  • Do I need to re-register the callback for a timer after so many cycles?
  • Is there a better tool to investigate hard faults?
    • I need to use ROV to get PC,LR,SP, then over write them in the register view to see the call stack of the hard fault
    • Not quite giving me the smoking gun I'm looking for



void gpTimerWithCBOneShot(int timer_num, int timeout_us, void(cb)(Timer_Handle myHandle, int_fast16_t status)) {
    Timer_Params params;
    Timer_Params_init(&params);
    params.period        = timeout_us;
    params.periodUnits   = Timer_PERIOD_US;
    params.timerMode     = Timer_ONESHOT_CALLBACK;
    params.timerCallback = cb;

    timer[timer_num] = Timer_open(timer_num, &params);

    if (timer[timer_num] == NULL)
    {
        while (1) {} // should only happen when adding new timers and not closing them
    }
}

void gpTimerWithCBContinuous(int timer_num, int timeout_us, void(cb)(Timer_Handle myHandle, int_fast16_t status)) {
    Timer_Params params;
    Timer_Params_init(&params);
    params.period        = timeout_us;
    params.periodUnits   = Timer_PERIOD_US;
    params.timerMode     = Timer_CONTINUOUS_CALLBACK;
    params.timerCallback = cb;

    timer[timer_num] = Timer_open(timer_num, &params);

    if (timer[timer_num] == NULL)
    {
        while (1) {} // should only happen when adding new timers and not closing them
    }
}

...
    // init timers w/ callbacks but do not start
    gpTimerWithCBOneShot(CONFIG_TIMER_5,1, &offsetCb);
    gpTimerWithCBContinuous(CONFIG_TIMER_7,1, &slotTimerCb);
...
    // radio RX callback, time to start offset timer
    gpStopTimer(CONFIG_TIMER_5);
    gpStartTimer(CONFIG_TIMER_5, offsetInterval);
...
    // offsetCb
    void offsetCb(Timer_Handle myHandle, int_fast16_t status) {
        gpStopTimer(CONFIG_TIMER_5); // turn off offset timer
        gpStopTimer(CONFIG_TIMER_7);
        gpStartTimer(CONFIG_TIMER_7, peroidicInterval);
    }
... 
    // after a number of periodic interrupts, we shut off the peroidic timer
    gpStopTimer(CONFIG_TIMER_7);

 

  • Thanks Marie. 

    I've never had a call stack show up properly in ROV. See the image below. 
    I've been manually copying the SP/LR/PC registers into the debugger.

  • Hi Mike,

    Do you just have this issue with the Exception Call Stack or every view in ROV? Are you using a CC1352P LaunchPad or a custom board?

    Did you set the Enable Exception Decoding at runtime option in SysConfig?

    Cheers,

    Marie H

  • Thanks Marie!

    This is a custom PCB. 
    I do have another project with the same source for a launch pad but I have not used it in quite a while. 

    The Exception call stack is the only thing that fails to load. 
    If I look at the Exception details under HWI, I can see the SP/LR/PC registers of the fault, where I can overwrite the system registers with the debugger and get the call stack. I can see tasks/semaphores/mailboxes otherwise. 

    The issue in this case is that the PC jumped to 0, so I cannot use that method. 

    I do have Enable Exception Decoding at runtime enabled, however I noticed the results were the same either way. 

  • Hi Mike,

    I see.

    And what do you see when you copy the SP/LR/PC addresses into Memory browser?

    I have never heard about this issue before. But if one-shot timers are what works in your case, is there anything stopping you from using them?

    Cheers,

    Marie H

  • Mike,

    if the jump to 0 is a result of a function call to a null-pointer, you may still find the source address in the link register (LR). The fault handler should normally not modify the link register.

    You are using multiple hardware timers and you start and stop them in various ways in your callbacks. The code you show is not complete. It's impossible to guess what could be wrong. The general way to debug such issues is, to clone your project and to reduce it as much as possible with the error still occuring. Quite often it turns out that the problem is somewhere else.

    Since you are stopping some timers inside the callbacks, I wonder if that could be the issue. The Timer driver unregisters a callback function in that case and the underlying GPTimer driver replaces that by a nullpointer. You could try:

    1. Place GPTimerCC26XX.c inside your project
    2. Add a dummy handler function as below.

    static void nullhandler(GPTimerCC26XX_Handle gptHandle, GPTimerCC26XX_IntMask intMask)
    {
        for (;;);
    }
    
    /*!
     *  @brief  Destruct interrupt for timer handle.
     *          This function must only be called once after opening a timer and
     *          should not be called before calling GPTimerCC26XX_registerInterrupt
     */
    void GPTimerCC26XX_unregisterInterrupt(GPTimerCC26XX_Handle handle)
    {
        GPTimerCC26XX_HWAttrs const *hwAttrs = handle->hwAttrs;
        GPTimerCC26XX_Object *object         = handle->object;
    
        uint32_t ui32Base = hwAttrs->baseAddr;
        uint32_t timer    = GPT_LUT[handle->timerPart].map;
    
        /* Disable all timer unit interrupts, use "timer" variable as mask */
        TimerIntDisable(ui32Base, timer);
    
        /* Destroy callback function */
        object->hwiCallbackFxn[handle->timerPart] = nullhandler;
        /* Destruct HWI */
        HwiP_Struct *pHwi                         = &object->hwi[handle->timerPart];
        HwiP_destruct(pHwi);
    }

  • Thanks Rick! 

    Good timing b/c I'm staring at them right now. 
    The ROV Exception info is showing PC = 0 and LR = 2. 
    The debug registers view is showing PC inside customFaultISR, and the LR is 1 byte behind that. 

    One thing I've learned by toggling a few spare GPIOs, is that I'm seeing a timer ISR fire, UART ISR and the radio ISR are all firing around the same time. 
    One other thing I'm seeing is that It can take > 1 ms to post a semaphore from my timer ISR. 
    The Blue trace is the toggle from the uartIsr below. The purple trace is the radio ISR firing. 
    I would expect the blue pulses to last 4-5 microseconds like the ones to the right of the long one. 



    I am trying to see why my system is spending so much time in the ISR. 
    Almost as if it's being interrupted while posting the semaphore. 
    I know in other RTOS's there is a separate API to post a semaphore from an ISR. 

    The blue trace below is the uart ISR, and the purple is the timer ISR. 
    I can see the timer fire while posting the semaphore from the uart ISR.
    This happens most cycles and doesn't seem to bother things. 



    void UartIsrHandler(void)
    {
        uint32_t IntStatusBitField = UARTIntStatus(UART0_BASE, 1);              // Get status of enabled interrupts
        UARTIntClear(UART0_BASE, (IntStatusBitField & 0xF0));                   // Clear flags handled by this handler
    
        if(IntStatusBitField & (UART_INT_RX | UART_INT_RT))                     // RX or RX timeout
        {
            GPIO_write(CONFIG_GPIO_0,1);
            Semaphore_post(uartIsrSem);
            GPIO_write(CONFIG_GPIO_0,0);
        }
        else    // Interrupt due to a non-RX event
        {
    
        }
    }


    While taking that 2nd screen shot, I had more meaningful output in the ROV viewer.

    PC = 0 
    LR = 0x20006b63

    Looking in the memory map 

                      20006b63    00000001     scheduleThread.o (.data.schIndex)

    It looks like its jumping the PC to the .data section. 
    schIndex is for my RAM log of schedule history. 

                schLog[schIndex++ & 0x3F] = event; 

    After disabling my RAM log, replicating the failure, the ROV shows PC/LR = 0.
    The ROV is showing an exception happening between interrupt 3 and 21, which I need to look up. 



    I changed from the Timer driver to driverlib and I'm seeing less failures, but still having reliability issues. 

    Here is my complete timer code. The offset timer is fired from a radio callback, the slot timer is called from the offset timer callback.  
    The DeInit calls are called before restarting the timer every time. 
    We never de register the interrupt handler for either of the timers. 

    /*
     *      GPT1 is the offset timer
     *          * scheduled in  RX callback for slot-rxtime interval
     *      GPT0 is the slot timer
     *          * scheduled in offset timer callback
     *          * fires every slot 
     */
    
    #include "app.h"
    
    #include DeviceFamily_constructPath(driverlib/timer.h)
    
    void Slot_IntHandler(void) {
        Semaphore_post(sem2);
        TimerIntClear(GPT0_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any timer interrupt flags
    }
    
    void Board_Init_Slot_Timer_GPT0A(void)
    {
        PRCMPowerDomainOn(PRCM_DOMAIN_TIMER);                                               // Turn on power to timer domain
        while (PRCMPowerDomainsAllOn(PRCM_DOMAIN_TIMER) != PRCM_DOMAIN_POWER_ON) {}         // Wait for timer power domain to start
    
        PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER0);                                        // Enable timer clock gating in run mode
        PRCMLoadSet();
        while (!PRCMLoadGet()) {}                                                           // Wait for timer clock gate to open
    
        TimerDisable(GPT0_BASE, TIMER_A);                                                   // Ensure timer is disabled
    
        TimerConfigure(GPT0_BASE, TIMER_CFG_PERIODIC);                                      // Configure GPT0 as Full-width (32bit) periodic down-count timer
        TimerStallControl(GPT0_BASE, TIMER_A, true);                                        // Stall timer on debug mode
    
        IntPrioritySet(INT_GPT0A, INT_PRI_LEVEL0);                                          // Set the priority of the GPT0A ISR to 0 (highest priority)
        TimerIntRegister(GPT0_BASE, TIMER_A, Slot_IntHandler);
    }
    
    
    void Board_Restart_Slot_Timer_GPT0A(uint32_t t)
    {
        TimerDisable(GPT0_BASE, TIMER_A);                                                   // Ensure timer is disabled
        TimerIntDisable(GPT0_BASE, TIMER_TIMA_TIMEOUT);
        HWREG(GPT0_BASE + GPT_O_CFG) = 0x00000000;
    
        TimerConfigure(GPT0_BASE, TIMER_CFG_PERIODIC);                                      // Configure GPT0 as Full-width (32bit) periodic down-count timer
                                                                                            // Note: must use down counter, there is an issue on the CC2651 with clearing an periodic up counter !
    
        TimerLoadSet(GPT0_BASE, TIMER_A, t);                                                // Load timeout count value
        TimerIntClear(GPT0_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any timer interrupt flags
        TimerIntEnable(GPT0_BASE, TIMER_TIMA_TIMEOUT);                                      // Configure timer interrupt source mask that will be referred to the ISR
        IntEnable(INT_GPT0A);
    
        TimerEnable(GPT0_BASE, TIMER_A);                                                    // Start timer
    }
    
    
    void Board_DeInit_Slot_Timer_GPT0A(void)
    {
        TimerDisable(GPT0_BASE, TIMER_A);
        IntDisable(INT_GPT0A);
        TimerIntDisable(GPT0_BASE, TIMER_TIMA_TIMEOUT);
        TimerIntClear(GPT0_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any pending interrupt flag.
    }
    
    void Offset_IntHandler(void) {
        Semaphore_post(sem1);
    
        Board_DeInit_Offset_Timer_GPT1A();                                                  // Shut off Offset timer
        Board_DeInit_Slot_Timer_GPT0A();
        Board_Restart_Slot_Timer_GPT0A(PACKET_INTERVAL_US*48);
        TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any timer interrupt flags
    }
    
    void Board_Init_Offset_Timer_GPT1A(void)
    {
        PRCMPowerDomainOn(PRCM_DOMAIN_TIMER);                                               // Turn on power to timer domain
        while (PRCMPowerDomainsAllOn(PRCM_DOMAIN_TIMER) != PRCM_DOMAIN_POWER_ON) {}         // Wait for timer power domain to start
    
        PRCMPeripheralRunEnable(PRCM_PERIPH_TIMER1);                                        // Enable timer clock gating in run mode
        PRCMLoadSet();
        while (!PRCMLoadGet()) {}                                                           // Wait for timer clock gate to open
    
        TimerDisable(GPT1_BASE, TIMER_A);                                                   // Ensure timer is disabled
    
        TimerConfigure(GPT1_BASE, TIMER_CFG_ONE_SHOT);                                      // Configure GPT0 as Full-width (32bit) one shot down-count timer
        TimerStallControl(GPT1_BASE, TIMER_A, true);                                        // Stall timer on debug mode
    
        IntPrioritySet(INT_GPT1A, INT_PRI_LEVEL0);                                          // Set the priority of the GPT0A ISR to 0 (highest priority)
        TimerIntRegister(GPT1_BASE, TIMER_A, Offset_IntHandler);
    }
    
    
    void Board_Restart_Offset_Timer_GPT1A(uint32_t t)
    {
        TimerDisable(GPT1_BASE, TIMER_A);                                                   // Ensure timer is disabled
        TimerIntDisable(GPT1_BASE, TIMER_TIMA_TIMEOUT);
        HWREG(GPT1_BASE + GPT_O_CFG) = 0x00000000;
    
        TimerConfigure(GPT1_BASE, TIMER_CFG_ONE_SHOT);                                      // Configure GPT0 as Full-width (32bit) one shot down-count timer
                                                                                            // Note: must use down counter, there is an issue on the CC2651 with clearing an periodic up counter !
    
        TimerLoadSet(GPT1_BASE, TIMER_A, t);                                                // Load timeout count value
        TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any timer interrupt flags
        TimerIntEnable(GPT1_BASE, TIMER_TIMA_TIMEOUT);                                      // Configure timer interrupt source mask that will be referred to the ISR
        IntEnable(INT_GPT1A);
    
        TimerEnable(GPT1_BASE, TIMER_A);                                                    // Start timer
    }
    
    
    void Board_DeInit_Offset_Timer_GPT1A(void)
    {
        TimerDisable(GPT1_BASE, TIMER_A);
        IntDisable(INT_GPT1A);
        TimerIntDisable(GPT1_BASE, TIMER_TIMA_TIMEOUT);
        TimerIntClear(GPT1_BASE, TIMER_TIMA_TIMEOUT);                                       // Clear any pending interrupt flag.
    }


    void radioCb(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) {
        ...
    
        Board_DeInit_Slot_Timer_GPT0A();
        Board_DeInit_Offset_Timer_GPT1A();
        Board_Restart_Offset_Timer_GPT1A(48*offsetTimeUs);
        
        ...
    }
    It seems like a race condition because sometimes it'll run for an hour without issues, other times it fails in 5 minutes. 
    The callbacks are registered at boot and don't change at runtime, so this has been tough to track down. 
  • More data : 

    Posting the semaphores from the timer ISR's always take 4-5 microseconds. 
    this seems specific to the UART semaphore 

    The UART task looks for the uartIsrSem, buffers bytes from the FIFO, looks for a packet and posts to a mailbox if found, then services the TX buffers.
    Would it be better to have the RX task split from the TX task? Could that Task_yield() be subjecting me to a full RTOS clock tick? 
    I'm also using Task_yield() on my scheduler, which is using the timer ISR that only takes 4-5 microseconds. 

        while(1) {
            // prefer a while below to empty the FIFO in one shot
            // if vs while did not make much of a difference in terms of semaphore post taking 1 ms
            if (Semaphore_pend(uartIsrSem, BIOS_NO_WAIT)) {
                if (UARTCharsAvail(UART0_BASE)) {
                    g_SerialInBuffer[g_SerialInBufferWriteIndex] = UARTCharGetNonBlocking(UART0_BASE);
                    g_SerialInBufferWriteIndex++;
                    g_SerialInBufferWriteIndex &= (uint8_t)(SERIAL_BUFFER_NUM_BYTES - 1);
                }
            }
    
            ... // examine new bytes and look for packets
            // if a packet was found 
            Mailbox_post(uartRxMbox, &uartMsg, BIOS_NO_WAIT);
    
            if (g_SerialOutBufferReadIndex != g_SerialOutBufferWriteIndex) { // if bytes to send
                if (!UARTBusy(UART0_BASE)) {
                    UARTCharPutNonBlocking(UART0_BASE, g_SerialOutBuffer[g_SerialOutBufferReadIndex++]);
                }
            }
            Task_yield();
        }

  • More data:

    It's not the semaphore post holding up the MCU. 
    I took the semaphore out and allowed the ISR to buffer one byte at a time (and the whole chunk, same results)
    It really seems like this interrupt is being pre-empted 

    void UartIsrHandler(void)
    {
        uint32_t IntStatusBitField = UARTIntStatus(UART0_BASE, 1);              // Get status of enabled interrupts
    
        if(IntStatusBitField & (UART_INT_RX | UART_INT_RT))                     // RX or RX timeout
        {
            GPIO_write(CONFIG_GPIO_0,1);
            if (UARTCharsAvail(UART0_BASE)) {
                g_SerialInBuffer[g_SerialInBufferWriteIndex] = UARTCharGetNonBlocking(UART0_BASE);
                g_SerialInBufferWriteIndex++;
                g_SerialInBufferWriteIndex &= (uint8_t)(SERIAL_BUFFER_NUM_BYTES - 1);
            }
    
            GPIO_write(CONFIG_GPIO_0,0);
        }
        else    // Interrupt due to a non-RX event
        {
    
        }
        UARTIntClear(UART0_BASE, (IntStatusBitField & 0xF0));                   // Clear flags handled by this handler
    }

  • More data: 

    just clearing the interrupt and exiting is taking > 1 ms

    void UartIsrHandler(void)
    {
        GPIO_write(CONFIG_GPIO_0,1);
        uint32_t IntStatusBitField = UARTIntStatus(UART0_BASE, 1);              // Get status of enabled interrupts
        UARTIntClear(UART0_BASE, (IntStatusBitField & 0xF0));                   // Clear flags handled by this handler
        GPIO_write(CONFIG_GPIO_0,0);
    }

    This is my uart init

        // Turn on power to UART and enable clock gating.
        // Note: Failure to turn on the UART before accessing UART0_BASE reg will result in a memory bus fault !!!
        PRCMPowerDomainOn(PRCM_DOMAIN_SERIAL);                                              // Turn on power to serial domain (UART, etc).
        while (PRCMPowerDomainsAllOn(PRCM_DOMAIN_SERIAL) != PRCM_DOMAIN_POWER_ON) {}        // Wait for serial power domain to start
    
        PRCMPeripheralRunEnable(PRCM_PERIPH_UART0);                                         // Enable UART clock gating in run mode
        PRCMLoadSet();
        while (!PRCMLoadGet()) {}                                                           // Wait for UART clock gate to open
    
        // Now that the UART has power and clock, proceed with configuring its registers:
        UARTDisable(UART0_BASE);                                                            // Disable UART function
        UARTIntDisable(UART0_BASE, 0xFF1);                                                  // Disable all UART module interrupts (see UART IMSC)
    
        IOCPortConfigureSet(CONFIG_GPIO_UART2_0_RX, IOC_PORT_MCU_UART0_RX, IOC_STD_INPUT);  // IOC_STD_INPUT may not be exactly what you want...
        IOCPortConfigureSet(CONFIG_GPIO_UART2_0_TX, IOC_PORT_MCU_UART0_TX, IOC_STD_INPUT);  // IOC_STD_INPUT may not be exactly what you want...
    
        UARTConfigSetExpClk(UART0_BASE, UART0_CLOCK, UART0_BAUD, (UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_NONE | UART_CONFIG_STOP_ONE)); // Sets the configuration of the UART
        UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);                     // Set number of chars in fifo's that will generate int's when enabled.
                                                                                            // Generate RX int on reception of 1 char.  Generate TX int when fifo has one char left
        UARTIntRegister(UART0_BASE, &UartIsrHandler);                                        // Register combined UART ISR function for the UART0_COMB (combined uart int handler, ie RX, TX, etc.)
    
        // *Clear all UART module interrupt flags
        UARTIntClear(UART0_BASE, (UART_INT_TX | UART_INT_RX |
                UART_INT_RT | UART_INT_OE | UART_INT_BE | UART_INT_PE |
                UART_INT_FE | UART_INT_CTS | UART_INT_EOT));
    
        UARTIntEnable(UART0_BASE, (UART_INT_RX | UART_INT_RT));
        UARTEnable(UART0_BASE);
    

  • Does your "real" application use the UART through DriverLib or are you using the "official" UART driver in ti/drivers (either UART or UART2)? I strongly recommend using the official drivers. They are usually clunky and overengineered, but they often contain workarounds for certain hardware quirks and contain useful comments. At least you should study them carefully before implementing your own driver.

    If you really want to implement your own peripheral drivers and install your own ISRs:

    • don't use PCRM calls directly, but use the Power driver just like the ti/drivers do it (Power_setDependency(PowerCC26XX_PERIPH_UART0), Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY), ...
      The Power driver must keep track of which peripheral is enabled and whether it is allowed to enter standby. Otherwise a call to Task_yield() can easily switch off your UART and go to standby without you noticing it.
    • don't install ISRs through DriverLib calls, but use the Hwi module in the TIRTOS kernel. This is necessary to make the kernel aware that you are in an ISR when calling Semaphore_post().

    You may have a look at this thread how to implement own peripheral drivers when using TIRTOS.

    If this does still not solve your issues, can you reduce your application even further? Can you remove the radio? Could it be a stack overflow?

  • Thanks again Rick. 

    I had the constraints as follows: 

        Power_setConstraint(PowerCC26XX_DISALLOW_IDLE);
        Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY);
        Power_setConstraint(PowerCC26XX_DISALLOW_SHUTDOWN);

    But I did NOT have the dependencies, so I added 

        Power_setDependency(PowerCC26XX_PERIPH_UART0);
        Power_setDependency(PowerCC26XX_PERIPH_RFCORE);
        Power_setDependency(PowerCC26XX_PERIPH_GPT0);
        Power_setDependency(PowerCC26XX_PERIPH_GPT1);

    I'm still seeing the UART ISR take about 1 ms. and the same hardfault hit. 
    The UART ISR taking so long seems like a huge red flag. Especially occurring so close to the failure. 

    Next, I'm going to try to use the HWI API and review the UART driver as you suggested. 
    My real application has been using the official UART2 driver and Timer driver, However after seeing some hardfaults related to those drivers I decided to try my own based on a colleague's input who is using driverlib which is actually in production. Performance has improved (less hard faults) but when I enable the full application, I always run into this PC=0 issue, even after the refactor with driverlib.

  • You only need to set the dependencies on peripherals that you are directly accessing through driverlib. The RFCore is handled by the hig-hlevel RF driver. You don't want to disallow idle, but only standby when the UART or the GP timer is active. Shutdown is also not relevant here.

    I'm very sure that the high-level ti drivers are not the root cause of the hardfaults you are observing, but it's something else in your application. Maybe an unintended memory overwrite or a jump to a function pointer that is null. Have you checked the stack utilization in ROV and tried to increase stack sizes?

  • Thanks again Rick. 

    ROV says plenty of stack. Each task stack has about 512 bytes left. 

    I thought the same thing because, why would a pointer that was set and used thousands of times be null? 
    A trashed environment of course.

    I can increase all the task stacks as well as the stack size in the linker file and see if things get better, but I've definitely tried this before. 

  • It doesn't seem like stack size is the issue. Just doubled them all, and HWI stack has 3.5k free, same failure mode. 

  • More data - should additionally prove its not a stack overflow.

    I know this is not the intended usage or interface but I had some ideas because I was hung up on the long interrupt time. 

    Still using UART via driverlib, I simplified the UART ISR to just clearing its own flags and NOT posting a semaphore and ...... the system ran stable for hours. 
    I'm just reading from the FIFO in my uart thread when UARTCharsAvail() tells me to. 

    So then I thought, if I originally intended to poll a semaphore, and now I'm polling the FIFO, do I need the interrupt? 
    So I disabled it, and the system appears to be stable as well. 

    I would prefer to use the recommended APIs, especially because manual DMA config will take some time. 
    Is there a reference somewhere that compares UART vs UART2 drivers? It seems like syscfg points you to UART2 but there's also just a plain UART driver available as well. 

  • Are you using the TIRTOS kernel Hwi module now or are you still instlling your ISRs via DriverLib? Most of the kernel APIs are forbidden in the latter case. You MUST use the Hwi module although I can't tell you whether it would cause the behavior you observe.

    So then I thought, if I originally intended to poll a semaphore, and now I'm polling the FIFO, do I need the interrupt

    If poll the FIFO, then no, but it keeps the CPU busy which you probably don't want.