Interrupts with FreeRTOS task causing task overflow

npatel wrote on Saturday, December 17, 2016:

I am getting quite confused with this problem and not too sure why I am running into it. I am getting an error from FreeRTOS that states:

HALT: Task overflowed its stack.

Note that there is no task name being printed out here. If I dont fire the uart interrupts everything in the task works fine. When I begin entering in characters on the uart, eventually after a random time of entering in commands I get this message coming up.

I have increased the stack and heap sizes to be more than 16K and still encounter this problem in pretty much random times. (Its not taking longer to show the problem)

I am using fast_interrupts for the uart for the microblaze port. But I dont believe that the interrupts are the issue as I am able to fire them and print to hyperterminal just fine, without the task being executed. When I disable the main_task which is simply toggling a LED with characters being entered I get a stack overflow.

I have attached what the task is doing below:

void
main_task()
{
   int counter = 0;
   while( 1 )
   {
      if ( (counter++%2) == 0 )
      {
         *(volatile unsigned int*)0x40000000 &= ~0x1;
      }
      else
      {
         *(volatile unsigned int*)0x40000000 |= 0x1;
      }
      vTaskDelay(200);
   }
}

int main()
{
   xTaskCreate( (void(*)(void*)) main_task, "main_task", 4096, NULL, 3, &xCreatedTask );
   vTaskStartScheduler();
}

The linker script is below:

STARTUP(crt0.o)
ENTRY(_start)

_STACK_SIZE = 0x4000;
_HEAP_SIZE = 0x4000;

MEMORY
{
   mig_7series_0 : ORIGIN = 0x80000000, LENGTH = 0x10000000
}

SECTIONS
{
.vectors.reset 0x0 : {
   KEEP (*(.vectors.reset))
} 

.vectors.sw_exception 0x8 : {
   KEEP (*(.vectors.sw_exception))
} 

.vectors.interrupt 0x10 : {
   KEEP (*(.vectors.interrupt))
} 

.vectors.hw_exception 0x20 : {
   KEEP (*(.vectors.hw_exception))
} 

.text : {
   *(.text)
   *(.text.*)
   *(.gnu.linkonce.t.*)
} > mig_7series_0

.rodata : {
   __rodata_start = .;
   *(.rodata)
   *(.rodata.*)
   *(.gnu.linkonce.r.*)
   __rodata_end = .;
} > mig_7series_0

.sdata2 : {
   . = ALIGN(8);
   __sdata2_start = .;
   *(.sdata2)
   *(.sdata2.*)
   *(.gnu.linkonce.s2.*)
   . = ALIGN(8);
   __sdata2_end = .;
} > mig_7series_0

.sbss2 : {
   __sbss2_start = .;
   *(.sbss2)
   *(.sbss2.*)
   *(.gnu.linkonce.sb2.*)
   __sbss2_end = .;
} > mig_7series_0

.data : {
   . = ALIGN(4);
   __data_start = .;
   *(.data)
   *(.data.*)
   *(.gnu.linkonce.d.*)
   __data_end = .;
} > mig_7series_0

.sdata : {
   . = ALIGN(8);
   __sdata_start = .;
   *(.sdata)
   *(.sdata.*)
   *(.gnu.linkonce.s.*)
   __sdata_end = .;
} > mig_7series_0

.sbss (NOLOAD) : {
   . = ALIGN(4);
   __sbss_start = .;
   *(.sbss)
   *(.sbss.*)
   *(.gnu.linkonce.sb.*)
   . = ALIGN(8);
   __sbss_end = .;
} > mig_7series_0

.tdata : {
   __tdata_start = .;
   *(.tdata)
   *(.tdata.*)
   *(.gnu.linkonce.td.*)
   __tdata_end = .;
} > mig_7series_0

.tbss : {
   __tbss_start = .;
   *(.tbss)
   *(.tbss.*)
   *(.gnu.linkonce.tb.*)
   __tbss_end = .;
} > mig_7series_0

.bss (NOLOAD) : {
   . = ALIGN(4);
   __bss_start = .;
   *(.bss)
   *(.bss.*)
   *(.gnu.linkonce.b.*)
   *(COMMON)
   . = ALIGN(4);
   __bss_end = .;
} > mig_7series_0

_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 );

_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 );

/* Generate Stack and Heap definitions */

.heap (NOLOAD) : {
   . = ALIGN(8);
   _heap = .;
   _heap_start = .;
   . += _HEAP_SIZE;
   _heap_end = .;
} > mig_7series_0

.stack (NOLOAD) : {
   _stack_end = .;
   . += _STACK_SIZE;
   . = ALIGN(8);
   _stack = .;
   __stack = _stack;
} > mig_7series_0

_end = .;
}

rtel wrote on Saturday, December 17, 2016:

It sounds like there could be something in the ISR that is stomping over
the task’s stack. Assuming you have configCHECK_FOR_STACK_OVERFLOW set
to 2 then the stack overflow will be noted if anything writes over the
end of the task stack. Normally that memory will get written too
because the task stack has grown too large, but it could be anything
that writes to that memory.

npatel wrote on Saturday, December 17, 2016:

I do have the configCHECK_FOR_STACK_OVERFLOW set to 2.

I removed all code in the UART ISR, which I defined as a fast_interrupt. But still getting this. I then moved stack to the blockram, completely away from all other code and still getting the same error…

Not sure why this is happening. Will continue debugging, if there is any other suggestions they would be most welcome!

rs9562 wrote on Friday, December 30, 2016:

I used cscope on the entire v9.0.0 source and demo examples and could not find your message:
“HALT: Task overflowed its stack”

I had a problem with my tasks being setup with a diiferent stack size than the define for configMINIMAL_STACK_SIZE variable. The code below helped me find it:

void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed portCHAR *pcTaskName)
{
    LCD_Write_Cmd(LCD_DISPLAY_CLEAR_CMD);
    LCD_Write_String_Addr((int8_t *)"Stack overflow", LCD_ROW0);
        sprintf((char *)buf1, "Time: %02u:%02u:%02u", (unsigned int)hours, (unsigned int)minutes, (unsigned int)seconds);
    LCD_Write_String_Addr(buf1, LCD_ROW1);
    sprintf((char *)buf2, "TaskHandle:%08x", (int)pxTask);
    LCD_Write_String_Addr(buf2, LCD_ROW2);
    sprintf((char *)buf3, "Task:%s", pcTaskName);
    LCD_Write_String_Addr(buf3, LCD_ROW3);
    while(1);
}

I wrote this to display the registers on unexpected exceptions. I do not use the standard library sprintf. The LCD is a small 4 line (20 character/per line).

int8_t buf0[LCD_CHAR_PER_LINE + 1];
int8_t buf1[LCD_CHAR_PER_LINE + 1];
int8_t buf2[LCD_CHAR_PER_LINE + 1];
int8_t buf3[LCD_CHAR_PER_LINE + 1];

#define R0   0
#define R1   1
#define R2   2
#define R3   3
#define R4   4
#define R5   5
#define R6   6
#define R7   7
#define R8   8
#define R9   9
#define R10 10 
#define R11 11 
#define R12 12 
#define R13 13 
#define R14 14 

int reg[60];
int exception_spsr;

/* 
 * Note:
 * Peripheral interrupt service routines should first clear the peripheral
 * interrupt flag followed by the VIC interrupt flag.
 */

void irq_display(uint8_t irq_code, uint8_t *irq_title_msg)
{
while (1)
{
    /* Display Exception Message */
    LCD_Write_Cmd(LCD_DISPLAY_CLEAR_CMD);
    LCD_Write_String_Addr((int8_t *)irq_title_msg, LCD_ROW0);
    sprintf((char *)buf1, "Time: %02u:%02u:%02u", (unsigned int)hours,
                                                   (unsigned int)minutes,
                                                   (unsigned int)seconds);
    LCD_Write_String_Addr(buf1, LCD_ROW1);
    delay_msec(2000);    
    LCD_Write_Cmd(LCD_DISPLAY_CLEAR_CMD);

    /* Display Registers R0 - R3 */
    sprintf((char *)buf0, "R0 :%08x  ", reg[R0]);
    LCD_Write_String_Addr(buf0, LCD_ROW0);

    sprintf((char *)buf1, "R1 :%08x  ", reg[R1]);
    LCD_Write_String_Addr(buf1, LCD_ROW1);

    sprintf((char *)buf2, "R2 :%08x  ", reg[R2]);
    LCD_Write_String_Addr(buf2, LCD_ROW2);

    sprintf((char *)buf3, "R3 :%08x  ", reg[R3]);
    LCD_Write_String_Addr(buf3, LCD_ROW3);

    LED_Blink_Delay(irq_code, 2500);

    /* Display Registers R4 - R7 */
   LCD_Write_String_Addr(buf3, LCD_ROW3);

    LED_Blink_Delay(irq_code, 2500);

    /* Display Registers R8 - R11 */
    sprintf((char *)buf0, "R8 :%08x  ", reg[R8]);
    LCD_Write_String_Addr(buf0, LCD_ROW0);

    sprintf((char *)buf1, "R9 :%08x  ", reg[R9]);
    LCD_Write_String_Addr(buf1, LCD_ROW1);

    sprintf((char *)buf2, "R10:%08x  ", reg[R10]);
    LCD_Write_String_Addr(buf2, LCD_ROW2);

    sprintf((char *)buf3, "R11:%08x  ", reg[R11]);
    LCD_Write_String_Addr(buf3, LCD_ROW3);

    LED_Blink_Delay(irq_code, 2500);

    /* Display Registers R12 - R14, SPSR */
    sprintf((char *)buf0, "R12:%08x  ", reg[R12]);
    LCD_Write_String_Addr(buf0, LCD_ROW0);

    sprintf((char *)buf1, "R13:%08x  ", reg[R13]);
    LCD_Write_String_Addr(buf1, LCD_ROW1);

    sprintf((char *)buf2, "R14:%08x  ", reg[R14]);
    LCD_Write_String_Addr(buf2, LCD_ROW2);

    sprintf((char *)buf3, "SPSR:%08x  ", exception_spsr);
    LCD_Write_String_Addr(buf3, LCD_ROW3);

    LED_Blink_Delay(irq_code, 2500);
}

}

void data_abort_handler(void)
{
    /* Save registers r0-r14 */
    __asm volatile ( "push {r0}"          );
    __asm volatile ( "ldr   r0, =reg"     );
    __asm volatile ( "stmia r0, {r0-r14}" );
    __asm volatile ( "pop  {r1}"          );
    __asm volatile ( "str   r1, [r0]"     );

    /* Save spsr */
    __asm volatile ( "ldr   r1, =exception_spsr" );
    __asm volatile ( "mrs   r0, spsr"     );
    __asm volatile ( "str   r0, [r1]"     );

    irq_display(LED_DATA_ABORT_IRQ, (uint8_t *)"Data Abort          ");
}