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.

CC2642R: UART_close() hwi exception on semaphore_post

Part Number: CC2642R
Other Parts Discussed in Thread: SYSBIOS

With help of Clement i was able to debug a hardware exception.

It seems like the system runs into
> Hard Fault: FORCED: BUSFAULT: PRECISERR.Data Access Error. Address = 0x1a19c

Reading out the lr register after adding an exeption handler hook and disabling buffered writing shows a return address in ti_sysbios_knl_Semaphore_post__E.

The fault seems to happen inside the UART logging functionality, more specifically UART_close(), see code below for UART setup and print functions.

#include <ti/drivers/UART.h>
#include <ti_drivers_config.h>
#include <lovelyLogging/src/lovelyLogging.h>

#define UART_BUFFER_SIZE 200
char uart_output_buffer[UART_BUFFER_SIZE] = {'-'};
static UART_Params params;

void cc26x2_logging_uart_init() {
    UART_init();
    UART_Params_init(&params);
    params.baudRate = 115200;
    params.readMode = UART_MODE_BLOCKING;
    params.writeMode = UART_MODE_BLOCKING;
    params.readTimeout = UART_WAIT_FOREVER;
    params.writeTimeout = UART_WAIT_FOREVER;
    params.readDataMode = UART_DATA_BINARY;
    params.writeDataMode = UART_DATA_BINARY;
}


volatile int uart_opened_count = 0;
volatile int uart_closed_count = 0;
volatile int uart_close_attempt_count = 0;

void cc26x2_logging_flush() {
    int string_length;

    UART_Handle uart = UART_open(CONFIG_UART_0, &params);
    if ( NULL == uart ) return;
    uart_opened_count++;

    while ( 0 == llog_is_empty() ) {
        string_length = llog_next_entry_as_string(
                            uart_output_buffer,
                            UART_BUFFER_SIZE
                        );
        UART_write(uart, uart_output_buffer, string_length);
    }
    uart_close_attempt_count++;
    UART_close(uart);
    uart_closed_count++;
}

Multiple log entries are created and flushed from inside simplePeripheral_init() and right after simplePeripheral_init() returns.

They are all printed to the console. Lets say we have printed n messages at this point.

Then, whatever the next message is after this point, causes a HWI exception as described above.
The system seems to never return from UART_close(), because the debug variables show the following values:

uart_opened_count == n + 1
uart_close_attempt_count == n + 1
uart_closed_count == n

I wonder how I may debug this kind of behaviour to figure out where the exception occurs and why.
All feels like a dig in the dark to me to be honest :/

  • Hi Lars,
    Try to stop the execution with a break-point right before the error occurs. Then, using the ROV, verify the status of the different threads (including the stack size) and the different semaphores. The goal is to verify that you are not accessing a structure that has already been freed (or a structure that is not initialized).

    Last element, if the size of your project allows it, try to disable the code optimization. Then verify if the error still happens. If yes, then try to debug without the code optimization enabled, it's generally easier. (NOTE: If turning off the optimization hides the error, please do NOT consider this as a fix)

    Best regards,

  • Most views in the ROV dont display data but an error message:

    Received exception from ROV Server:
    Target memory read failed: 0xSOMEADDR, length: xx
    This read is at an invalid address accoding to the application's section map. The application is either uninitialized or corrupt.

    Happens on views for semaphore, task, GateMutexPri, GateHWi, Event and Clock.

    Optimisation has been turned off.

  • Hi Lars,

    Do you see these errors including if you stop the execution long time before the error occurs?

    Regards,

  • Hi again,

    Try to use the ROV Classic instead of the one you are using.

    Edit: I wrote it reversed: Try to use the Runtime Object View instead of the ROV Classic. With my apologizes. 

    Best regards,

  • Hello again,

    I am using the Object Viewer now.

    There is a list of semaphores, but I am not sure how they help me.
    Its a bunch of addresses, event 'none', eventId 'N/A', 'binary`, some have counts of 0, some of 1, pendedTasks 'none'.

    I am looking at the tasks, and after running into the fault, the ti.sysbios.knl.task.IdleTask says blockedOn: `Internal Error`. Stack Peak and sizes are okay.

    I dont really know what I am searching for, so I have attached a screenshot. This is the state after the exception occured.

    Resetting the device during debug will lead to semaphores that are uninitialized and ending up in `ti_sysbios_family_arm_m3_Hwi_interruptsAreDisabledButShouldNotBe`, what I do not really understand, cause I would assume a resets resets the system and then restarts from there?

    Before the error occurs, with a breakpoint before the call to UART_close, blockedOn: `Internal Error` is shown for the ti.sysbios.knl.Task,IdleTask.
    That might be a hint, but I dont see what to do with this information.

  • Hi,

    Try to find the address of the semaphore used by the UART, then you can verify if the semaphore is in the list (and if something happened to it).

    You can also change the view in the BIOS module in order to check the errors. Same in the HWI module to see the exceptions.

    Best regards,

  • the exact line where the exception occurs seems to be:

    # HwiP_tirtos.c
    
    uintptr_t HwiP_disable(void)
    {
        uintptr_t key;
        key = Hwi_disable();  // exception on running this line.
        return (key);
    }
    

  • Hi Lars,

    I wonder if the issue is really caused by the line you have identified (or if the line basically reveals the error).

    • Have you called the function BIOS_start() before UART_close()? (I think so, which is good)
    • In which context (task, Hwi, Swi) do you call the UART_close() function? (should be called in task context - not in Hwi/Swi context => this seems ok too)
    • Is there any corruption of the HWIs? Please verify this in the HWI module. You can also take a memory using the memory browser.

    Best regards,

  • I wonder if the issue is really caused by the line you have identified (or if the line basically reveals the error).

    Pretty sure its just a result of something that went bad earlier, but I am not sure how I would track that.

    I was expecting any semaphore to be taken on UART_open() and returned on UART_close(), but couldnt see any changes to semaphores on UART_open().

    Running into the execHandler Hook, the lr register points to the ...knl_Semaphore_post_E() function, but only if UART_write() is called between UART_open() and UART_close(). If I remove the `UART_write` function from `cc26x2_logging_flush()` (see opening post), no HWI exception occurs.

    • BIOS_start() is called at the end of main() after creating the tasks.
    • Context should be task, but I am not entirely sure. Printing inside of simplePeripheral_init() seems to work. Whatever should be printed after the function has returned seems to cause the error, but I do not know where that happens, its one of the things i was trying to find out (its a pretty big project that was not written by me and the original author is no longer available).
    • Where would I be able to see this? There is a UARTCC26XX_hwiIntFxn with irp of 0x0, not sure what means.

  • Hi,

    We need to be sure of the context. Can you try to make a call to the functions from a task context? I bet you have a function called SimplePeripheral_taskFxn in your project. Maybe you could make a call from there just to verify.

    Another element, do you know if the UART is used for something else? For example for a display or for DTM (Direct Test Mode)?

    Regards,

  • Yes this works.

    static void SimplePeripheral_taskFxn(UArg a0, UArg a1)
    {
      SimplePeripheral_init();
    
      DEBUG("SimplePeripheral_init successful.");

    // [...] }

    (DEBUG is a macro that adds the message along with some other info like file name and line to a print buffer, then flushes it using cc26x2_logging_flush() as posted in the opening post.)

    So I guess it is a context problem?
    Although I am not sure what that means.

    The UART is used for the log only.

  • Hi,

    It definitely looks like a context issue.

    It means that you are in a HWI (HardWare Interrupt) or in a SWI (SoftWare Interrupt) when you execute a blocking function - the RTOS disallows this (because it mess-up all). You absolutely to be in a task to execute the blocking functions.

    So what is the solution? Don't call the logging functions in a HWI or a SWI. Leverage RTOS functionalities (such as mailbox, events, semaphore) to, for example, post a message in a mailbox and then treat it in a task context (e.g. in SimplePeripheral_taskFxn).

    I hope this will help,

    Regards,

  • I understand what a hardware interrupt context is.

    But I don't know what a software interrupt context is as in: how I would know that I am currently running in this context. Where does the task context end?
    It is probably something RTOS specific? From the TI Stack, all the bluetooth related functions that handle messages, are these called in a SWI context?

  • I guess I was standing too close to the problem to actually see it.

    The simplest solution seems to be to not flush the log messages immediately on creation, but to flush them in a periodic task, what will take printing and therefore the blocking function out of any context but the task context.

    Before, I tried to enqueue a message whenever a new log entry was created, and then added the respective handler as a case in simplerPeripheral_processAppMsg(). I still think this should be a good way to do it, but this approach let to the debugger losing connection.
    Any idea what might have gone wrong there?

  • Hi,

    You may want to assess if having the UART in blocking mode is really the best idea. Maybe it would be best to change for callback mode.

    Other option is to created a task fully dedicated to UART handling. In that case, no problem with UART blocking mode. Having the UART in a separate task would require a bit of work (especially to implement a good way to pass messages to the task) but I think it is worth. The great part of this solution is the simplicity of removing it in your final code.

    Kind regards,