Unknown function 0xA60: seems to happen while calling a particular application API only

OK I'm seeing this weird behavior that I'm trying to understand

I have a sensor task that reads sensor data continuously every 4 seconds. The value is then notified to the subscriber (NotificationManager) which then sends the data to UART, (and later to BLE custom service. 

Until I connect the BLE service from nRF Connect app, it all works ok (I see the UART print fine)

But when I attempt to connect to the BLE service via nRF Connect App, the program halts at 0xA60. (I have previously dealt with issues around logging and I wonder if it's related to it). Note that when I comment out the Notify call, the BLE connects OK. What does that tell us?

void MCP9808::Run()
{
    Write(Register::AMBIENT, 1);
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

    while(true)
    {
        Read();
        
        uint32_t taskNotify = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

        ParseTempInC();
        //Notify();  // uncommenting out results in A60 error upon BLE connection

        vTaskDelay(pdMS_TO_TICKS(DELAY_MS_PER_READ));
    }
}

void NotificationManager::Update(Publisher* publisher) 
{
    // retrieve the publisher's category
    auto category = publisher->GetCategory();

    switch (category)
    {
      case Publisher::Category::TEMPERATURE:
      {
	    MCP9808* mcp9808 = dynamic_cast<MCP9808*>(publisher);
	    if (!mcp9808) return;
	    
	    uint16_t value = mcp9808->GetTempInC();

	    char msg[100] = {0};
	    snprintf (msg, sizeof(msg) - 1, "Temp = %uC", value);
	    PushNotification(MakeNotification(msg), 
      }
    }
}  

Notification NotificationManager::MakeNotification(char* msg)
{
    Notification notification = {0};
    strncpy(notification.msg, msg, sizeof(notification.msg));
    notification.category = category;
    return notification; 
}

void NotificationManager::PushNotification(Notification notification)
{
    // write data to UART
    mUART.Write(notification.msg);
    
    // updating the custom value in the BLE characteristic table
    // mBLENotifierSrv.UpdateValue(reinterpret_cast<uint8_t*>(notification.msg));
}

  • 0XA60 is a halt instruction in the MBR hardfault handler, which means that your application somehow hardfaulted. 

    It could be many reasons but most likely are stack overflow or your tried to call an SVC (sd_xxx) call from a higher priority.

    Can I get your project to replicate the issue? Have your reviewed all the priorities of tasks from which you call softdevice API?

    Have you checked if your have any stack overflow?

  • The stack size is 2048 bytes, yes?

    I filled it in with 0xAA and I still see 0xAA during runtime (doesn't get overwritten) so probably no stack overflow.

    #define STACK_PATTERN 0xAA  // Use the byte pattern 0xAA for the stack initialization
    #define STACK_SIZE    2048  // Assuming a stack size of 2048 bytes for demonstration
    #define STACK_LIMIT   128   // The limit in bytes that we don't want the stack to approach
    
    uint8_t stack[STACK_SIZE];
    
    void initializeStackWithPattern() 
    {
        for (int i = 0; i < STACK_SIZE; i++) {
            stack[i] = STACK_PATTERN;
        }
    }
    
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        initializeStackWithPattern();
        // ...
    }

    I'm using the same priority for the two tasks I have i.e, 0.

    I can certainly attach a project once you make this thread private. Appreciate it a lot, Susheel

    Looking forward to solving this together

  • it is best to enable the native stack overflow detection in the RTOS and implement the hook function to know if there are any stack overflow in any of the tasks (not necessarily in the task that you created in the application.

    If we can rule out stack overflow and if you can review the interrupt priorities of the driver handlers of the peripheral you are using (priorities of ISR of peripheral from sdk_config.h file and not the priorities of the RTOS task). then we can rule out hardfault due to this aswell. 

    There are other ways to get the context of the hardfault by reading the registers or ARM. We can try that aswell to understand the nature of the hardfault.

  • OK I see the execution does indeed hit the following function in runtime. Hence stackoverflow is happening? What could be ways to avoid? I tried increasing the tasks' stack size but that resulted in NRF_ERROR_NO_MEM

    extern "C"
     {
        void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
        {
            ( void ) pcTaskName;
            ( void ) xTask;
      
        
            for( ;; ); 
        }
    }


    Currently, I only have 2 tasks each occupying 4 * 100 bytes in the stack

    xTaskCreate(SystemTask::Process, "Run", 100, this, 0, &mTaskHandle
    xTaskCreate(MCP9808::Process, "Process", 100, this, 0, &mTaskHandle
    What's the actual stack size of nRF52840? It's set to 2KB in Segger config


  • morpho said:
    OK I see the execution does indeed hit the following function in runtime. Hence stackoverflow is happening?

    Yes, this means that the RTOS has detected a stack overflow. Then we know that we are in the right direction of debugging.

    morpho said:
    I tried increasing the tasks' stack size but that resulted in NRF_ERROR_NO_MEM

    You have to first (temporarily) increase configTOTAL_HEAP_SIZE by a decent size because all tasks initial stack is allocated from heap. One you have enough heap size, try to increase stack size of one task, recompile, flash and see if you again hit the vApplicationStackOverflowHook. Repeat this process until you stop hitting the overflowHook function. When that happens you know which task size you increased which solved the stack overflow issue.

    Remember that there are many tasks apart from the tasks that you create in your applicaiton. For example, if your application using RTOS timers and doing a bit of processing in the timer callback, then the default value of configTIMER_TASK_STACK_DEPTH might be too less in your case. 

    You need to review all the default values in FreeRTOSConfig.h file to see if there is any calibration you need to do there.

Related