8.2.0: Abort in ulTaskNotifyTake when executing portYIELD_WITHIN_API (TI RM48 port)

detoxie wrote on Friday, January 30, 2015:

Hi,
I get an abort exception when using the ulTaskNotifyTake function and executing the portYIELD_WITHIN_API macro (row 3874 in tasks.c). I don’t get it in other functions, e.g. xQueueGenericReceive.

The portYIELD_WITHIN_API() macro expands to:
{ portSYS_SSIR1_REG = portSYS_SSIR1_SSKEY; asm( " DSB " ); asm( " ISB " ); }

I have copied a 8.1.2 project in CCS and replaced the old OS files with the new 8.2.0 version.

The FreeRTOSConfig.h files are identical except for the #define configUSE_TASK_NOTIFICATIONS 1

I’m using the new portmacro.h file.

Kind regards,
Lars

rtel wrote on Friday, January 30, 2015:

Does this happen the first time you call ulTaskNotifyTake(), or are you
able to call it a few times successfully before it happens?

Does the abort happen on one of the lines in the macro, or can you step
the code a little further through the function before it happens.

In your case calling portYIELD_WITHIN_API() should pend a software
interrupt, but because the call is inside a critical section the
interrupt should remain pending until you exit the critical section on
line 3886. So you should be able to step through the
portYEIDL_WITHIN_API() macro, then onto the taskEXIT_CRITICAL(), without
the yield being attempted. If you can step through this code and let us
know exactly on which instruction the abort occurs that will be very
helpful in diagnosing its cause.

Regards.

detoxie wrote on Sunday, February 01, 2015:

Does this happen the first time you call ulTaskNotifyTake()…
No, it happens the second time because the first time I got the semaphore and the macro isn’t executed. So, the abort happens the FIRST time the MACRO is executed.

Does the abort happen on one of the lines in the macro…
I will test this on tuesday when I come to the office.

Meanwhile, here is the code:

ISR

#!cpp

#define USE_NOTIFICATION 0

#if ( USE_NOTIFICATION == 1 )
extern TaskHandle_t xSPIUARTTask;
#endif

void gioHighLevelInterrupt(void)
{
#if ( USE_NOTIFICATION == 0 )
static ISR_INT6_SPI_UART_GotInt_Queue gotintqueue6;
#endif
static BaseType_t xHigherPriorityTaskWoken;

    /* Loop until all interrupts are processed */
    do
    {
        offset = gioREG->OFF1;
        switch (offset - 1U)
        {
            /*
             * SPI-UART interrupt input (GPIOA(6))
             */
            case 6U:

            #if ( USE_NOTIFICATION == 0 )
                gotintqueue6.gotInt = true;
                (void) xQueueOverwriteFromISR( xISR_INT6_SPI_UART_GotInt_Queue, &gotintqueue6, &xHigherPriorityTaskWoken );
            #else
                vTaskNotifyGiveFromISR( xSPIUARTTask, &xHigherPriorityTaskWoken );
            #endif
                portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

            break;

            default:
            break;
        }
    } while (offset != 0U);
}

Task

#!cpp

#define USE_NOTIFICATION 0

void vSPIUARTTask( void *pvParameters )
{
    for( ;; )
    {
#if ( USE_NOTIFICATION == 0 )
        if ((xQueueReceive( xISR_INT6_SPI_UART_GotInt_Queue, &spiuartQueue, portMAX_DELAY)
            == pdTRUE) && (spiuartQueue.gotInt == true))
#else
        if (ulTaskNotifyTake( pdTRUE, portMAX_DELAY ) == pdTRUE)
#endif
        {
            code...
        }

        code...
    }
}

The xQueueReceive works but not ulTaskNotifyTake. When I get the first interrupt, ulTaskNotifyTake returns pdTRUE but when ulTaskNotifyTake is called again (and the macro executes), I get the abort exception.

I might very well have messed up it in some other area of the code (which I may have missed when did the copy [and also did comparisons afterwards]) but it’s a bit strange that xQueueReceive works but not ulTaskNotifyTake. :confused:

I get back to you when I have stepped through the macro.

Kind regards,
Lars

detoxie wrote on Tuesday, February 03, 2015:

Hi again,
I’ve debugged now and this is the result. The abort occurs at this line:
portSYS_SSIR1_REG = portSYS_SSIR1_SSKEY (in ulTaskNotifyTake)

portmacro.h

#!c

#define portSYS_SSIR1_REG ( * ( ( volatile uint32_t * ) 0xFFFFFFB0 ) )
#define portSYS_SSIR1_SSKEY ( 0x7500UL )

tasks.c - ulTaskNotifyTake

#!c

<snip>
/* All ports are written to allow a yield in a critical
section (some will yield immediately, others wait until the
critical section exits) - but it is not something that
application code should ever do. */
// portYIELD_WITHIN_API();
portSYS_SSIR1_REG = portSYS_SSIR1_SSKEY;  <-- abort
asm( " DSB " );
asm( " ISB " );
<snip>

queue.c - xQueueGenericReceive

#!c

<snip>
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
    // portYIELD_WITHIN_API();
    portSYS_SSIR1_REG = portSYS_SSIR1_SSKEY;  <-- Does not abort
    asm( " DSB " );
    asm( " ISB " );
}
<snip>

It seems it’s not allowed to write to the address 0xFFFFFFB0 in ulTaskNotifyTake.

I have also posted a topic to the TI HALCoGen guys about this and asked when they will have a HALCoGen version for 8.2.0. As I said, I could very well have messed up something which I’ve missed. We could wait for the answer from Texas. One thing is that I’ve used HALCoGen’s sys_link.cmd file and not the file from your demo project. But I use the same sys_link.cmd file for the 8.1.2 project.

Kind regards,
Lars

detoxie wrote on Tuesday, February 03, 2015:

Noticed that the comment got lost. But I think you understood that the abort does not happen in queue.c - xQueueGenericReceive.

Regards

rtel wrote on Tuesday, February 03, 2015:

In the xQueueGenericReeive() case the portYIELD_WITHIN_API() call is not inside a critical section. In the ulTaskNotifyTake() case it is. I wonder if that has anything to do with it - although it would seem odd if it were the case as the yield in the TMS570 case is performed by pending a software interrupt - if the software interrupt is masked by the critical section that I would have thought it would just remain pending until the critical section was exited (which is how ports such as the Cortex-M3 and RX work, which use a similar pended software interrupt scheme for yielding).

There was a time when yielding from a critical section was done all over the place, whereas having just had a quick scan of the code that does not seem to be the case any more.

We can check this theory quickly by exiting then entering the critical section around the call to taskYIELD():

taskEXIT_CRITICAL();
portYIELD_WITHIN_API();
taskENTER_CRITICAL();

Only do that for this quick test though - don’t leave it in the code as there is the potential for a race condition with an interrupt.

If that is proven to fix the issue then I will have to get the TMS570 manual out, it might be something to do with the priority of the software interrupt, if it is configurable, I can’t remember. Although perhaps if this is an issue just restructuring the function to use a scheduler lock could also be an option.

Please let me know the result.

Regards.

detoxie wrote on Tuesday, February 03, 2015:

Hi,
I will come back to you in about 20 minutes. The hardware engineers are updating my mock-up board. :slight_smile:

And it’s not the TMS570. We’re using the RM48L952 MCU.

Regards.

detoxie wrote on Tuesday, February 03, 2015:

No, it still crashes on that line.

#!c
/* All ports are written to allow a yield in a critical
section (some will yield immediately, others wait until the
critical section exits) - but it is not something that
application code should ever do. */
//    portYIELD_WITHIN_API();
taskEXIT_CRITICAL();
portSYS_SSIR1_REG = portSYS_SSIR1_SSKEY;
asm( " DSB " );
asm( " ISB " );
taskENTER_CRITICAL();

The portSYS_SSIR1_REG expands to ( * ( ( volatile uint32_t * ) 0xFFFFFFB0 ) )
It seems that accessing this address is illegal at that moment?

Regards,
Lars

rtel wrote on Tuesday, February 03, 2015:

…and calling taskEXIT_CRITICAL() caused interrupts to be re-enabled?
The only reason they wouldn’t would be if critical sections were nested.

Just to check - you are calling the function from a task, not an interrupt?

I will have to dig out the manual to see what could be causing this. I
don’t have the compiler installed at the moment, and it will take a long
time to install (its of non-trivial size!).

Regards.

detoxie wrote on Tuesday, February 03, 2015:

I’ve debugged and at taskEXIT_CRITICAL() you land here (after the vPortSWI jumptable).

;-------------------------------------------------------------------------------
; swiPortExitCritical
.asmfunc
swiPortExitCritical
ldr r0, ulCriticalNestingConst
ldr r12, [r0]
cmp r12, #0
bxeq r14
subs r12, r12, #1
str r12, [r0]
bxne r14
mrs r0, SPSR
bic r0, r0, #0x80
msr SPSR_c, r0
bx r14
.endasmfunc

Yes, I am calling the ulTaskNotifyTake from vSPIUARTTask, se above.

You: I will have to dig out the manual…
It’s no hurry, take your time. I can go forward with 8.1.2.

Regards,
Lars

detoxie wrote on Friday, February 06, 2015:

Hi again,
I mentioned this above:
“One thing is that I’ve used HALCoGen’s sys_link.cmd file and not the file from your demo project. But I use the same sys_link.cmd file (HALCoGen produced) for the 8.1.2 project.”

I have now tested the demo project with 8.2.0. Added some of my code with the GIO ISR and the notification stuff, and it works!! :slight_smile:

So maybe the Texas (HALCoGen) memory mapping and the section configuration is causing this abort. I don’t know but maybe it’s a hint.

But as I said, I can continue with 8.1.2. I will share this information to the HALCoGen team too. But if you have an idea to what to do/change to make it work I will of course be grateful. Regards, Lars

Demo sys_link.cmd file
= = = = = = = = = = = =

#!c

/* Memory Map                                                                 */

MEMORY
{
    VECTORS (X)  : origin=0x00000000 length=0x00000020
    FLASH0  (RX) : origin=0x00000020 length=0x0017FFE0
    FLASH1  (RX) : origin=0x00180000 length=0x00180000
    STACKS  (RW) : origin=0x08000000 length=0x00000200
    RAM     (RW) : origin=0x08000200 length=0x0003FE00
 }

/*----------------------------------------------------------------------------*/
/* Section Configuration                                                      */

SECTIONS
{
    .intvecs : {} > VECTORS
    .text    : {} > FLASH0 | FLASH1
    .const   : {} > FLASH0 | FLASH1
    .cinit   : {} > FLASH0 | FLASH1
    .pinit   : {} > FLASH0 | FLASH1
    .heap    : {} > RAM
    .bss     : {} > RAM
    .data    : {} > RAM
/*  .sysmem  : {} > RAM */
}

/*----------------------------------------------------------------------------*/

HALCoGen sys_link.cmd file
= = = = = = = = = = = = =

#!c

/*----------------------------------------------------------------------------*/
/* Linker Settings                                                            */

--retain="*(.intvecs)"

/*----------------------------------------------------------------------------*/
/* Memory Map                                                                 */

MEMORY
{
    VECTORS (X)  : origin=0x00000000 length=0x00000020
    KERNEL  (RX) : origin=0x00000020 length=0x00008000 
    FLASH0  (RX) : origin=0x00008020 length=0x00177FE0
    FLASH1  (RX) : origin=0x00180000 length=0x00180000
    STACKS  (RW) : origin=0x08000000 length=0x00001500
    KRAM    (RW) : origin=0x08001500 length=0x00000800
    RAM     (RW) : origin=(0x08001500+0x00000800) length=(0x0003eb00 - 0x00000800)
}

/*----------------------------------------------------------------------------*/
/* Section Configuration                                                      */

SECTIONS
{
    .intvecs : {} > VECTORS
    /* FreeRTOS Kernel in protected region of Flash */
    .kernelTEXT   : { sys_startup.obj(.const)
                      tasks.obj (.const:.string)
                      -l=rtsv7R4_T_le_v3D16_eabi.lib<auto_init.obj> (.text)
                      -l=rtsv7R4_T_le_v3D16_eabi.lib<copy_decompress_rle.obj> (*)
                      -l=rtsv7R4_T_le_v3D16_eabi.lib<cpy_tbl.obj> (*)
                      -l=rtsv7R4_T_le_v3D16_eabi.lib<copy_zero_init.obj> (*)
                      -l=rtsv7R4_T_le_v3D16_eabi.lib<copy_decompress_none.obj> (*)
                      -l=rtsv7R4_T_le_v3D16_eabi.lib<icall32.obj> (.text)
                      -l=rtsv7R4_T_le_v3D16_eabi.lib<memset32.obj> (.text)
                      -l=rtsv7R4_T_le_v3D16_eabi.lib<memcpy32.obj> (.text)
                    } > KERNEL
    .cinit        : {} > KERNEL
    .pinit        : {} > KERNEL
    /* Rest of code to user mode flash region */
    .text         : {} > FLASH0 | FLASH1
    .const        : {} > FLASH0 | FLASH1
    /* FreeRTOS Kernel data in protected region of RAM */
    .kernelBSS    : {} > KRAM
    .kernelHEAP   : {} > RAM
    .bss          : {} > RAM
    .data         : {} > RAM    
    .sysmem       : {} > RAM
    FEE_TEXT_SECTION : {} > FLASH0 | FLASH1
    FEE_CONST_SECTION : {} > FLASH0 | FLASH1
    FEE_DATA_SECTION : {} > RAM
}

ssharonov wrote on Friday, September 11, 2015:

I encountered the same problem. FreeRTOS is 8.2.0, hardware is Freescale Kinetis Cortex M4F. So this is not TI CPU related. Any updates on this issue? Anybody else sees the same error?
Thanks,
Sergei

rtel wrote on Friday, September 11, 2015:

Could you please start a new thread so we can help you with this - the
existing thread is a bit long to see the conclusions easily.

Regards.

ssharonov wrote on Tuesday, September 15, 2015:

Appologies, false alarm. Wild function pointer landed (of all places!) in vPortSVCHandler and corrupted stack trace.
Regards,
Sergei