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));
}

Parents
  • 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

  • maybe do a strncpy like below instead

    strncpy(buff, (const char *)pcTaskName, configMAX_TASK_NAME_LEN); 

    Or check in the memory if there is only Pro in the sequential address of the memory of if it has the whole "Process" name and it is just the matter of using the right size in the API.

  • Copying configMAX_TASK_NAME_LEN bytes still produces Pro.

    What memory view would you look into? 
    No way anyone can decode this

  • The problem was configMAX_TASK_NAME_LEN inFreeRTOSConfig.h was set to 4.

  • OK so as I continued to add more stuff (including a single virtual method as shown below), I now see the app crashing at the startup. When however I comment out the function body, it runs fine.

    void MCP9808::OnSubscribeChange(bool subscribeRequest) 
    {
        if (subscribeRequest)
        {
            vTaskResume(mTaskHandle);
        }
        else
        {
            vTaskSuspend(mTaskHandle);
        }
    }
    



    I tried increasing the heap size to 8192 and stack size to 300 to no avail

  • "Unknown function at 0x87201846" does not look like a valid code address. This is either that 

    • your applicaiton is dereference as corrupt function pointer or
    • still some stack overflow in some task somewhere.

    For the second point, you can enable some configs and run some tests as mentioned here to catch any stack overflows in your app.

    If you have tried increasing task stack size for every task that the application created, then try to see if you need to increase the stack size of the main or timer task. 

Reply
  • "Unknown function at 0x87201846" does not look like a valid code address. This is either that 

    • your applicaiton is dereference as corrupt function pointer or
    • still some stack overflow in some task somewhere.

    For the second point, you can enable some configs and run some tests as mentioned here to catch any stack overflows in your app.

    If you have tried increasing task stack size for every task that the application created, then try to see if you need to increase the stack size of the main or timer task. 

Children
  • For the second point, you can enable some configs and run some tests as mentioned here to catch any stack overflows in your app.

    I already have the configCHECK_FOR_STACK_OVERFLOW set to 1 in addition to the hook function.

    Note that the application 'crashes' before even executing the main.

    extern "C"
     {
        void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
        {
            ( void ) pcTaskName;
            ( void ) xTask;
    
            char buff[100] = {0};
            strncpy(buff, (const char *)pcTaskName, configMAX_TASK_NAME_LEN);
    
            UBaseType_t uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
        
            while(1);
        }
    }


    Commenting out the contents of OnSubscribeChange doesn't lead to any crash but curious as to why

  • morpho said:
    Commenting out the contents of OnSubscribeChange doesn't lead to any crash but curious as to why

    Is the scheduler started when you call vTaskREsume or vTaskSuspend? 
    I have seen that sometimes trying to do these things before the scheduler started causes hardfault.

    What is the context in which OnSubscribeChange is called? Is it running in ISR context or the RTOS thread context? Since you know exactly where it crashes, you can step into the code in the debugger mode and see if it is crashing everytime it runs OnSubscribeChange  or it happens once over many calls to OnSubscribeChange ?

  • That was it seemingly - the scheduler wasn't started while OnSubscribeChange was called.

    The caller is now calling it like

    	  if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
    	  {
    	      OnSubscribeChange(true);
    	  }


    Though how's it even failing before main starts? 

  • morpho said:
    Though how's it even failing before main starts? 

    You will be able to set a breakpoint at the  OnSubscribeChange(true); in the above code you showed and start the program in debugger. When the program runs and the breakpoint hits, you will be able to see the function call history on how you reached here before the scheduler has started. Seems like there is some logical error in the state machine of your application.

Related