Need some advise on RTOS scheduler problems

bones23 wrote on Tuesday, January 08, 2008:

I am working with freeRTOS on an str912 and using the IAR debugger. I have gotten uart communication working on the eval board but every time I send a string of over four characters with my vSerialPutString function it causes all of the threads to halt. The timer and enet interrupts handlers still run but not the threads. I was able to fix this problem by putting a long delay in the vSerialPutString function but this does not seem like a good solution. Since all of the threads crash at the same time I figure it is a scheduler problem. Does anybody know of a good way of debugging scheduler problems?

davedoors wrote on Tuesday, January 08, 2008:

Are you able to post your code?

bones23 wrote on Tuesday, January 08, 2008:

sure, below is my serial code. The scheduler code is from the freeRTOS v4.6.

//uart configuration

xComPortHandle xSerialPortInitMedium( unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength, int comNum )
{
xComPortHandle xReturn;
UART_InitTypeDef xUARTx_Init;
GPIO_InitTypeDef GPIO_InitStructure;
xSemaphoreHandle semiphorTest;
xQueueHandle xRxedChartest;
UART_TypeDef* UARTx;
   
        switch(comNum){
        case 0:
          UARTx = UART0;
        break;
        case 1:
          UARTx = UART1;
        break;
        case 2:
          UARTx = UART2;
        break;
        }
       
        switch(comNum){
        case 0:
          xReturn = &COM0;
        break;
        case 1:
          xReturn = &COM1;
        break;
        case 2:
          xReturn = &COM2;
        break;
        }
       
        switch(comNum){
        case 0:
          xRxedChars0 = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
          xRxedChartest = xRxedChars0;
          vSemaphoreCreateBinary( xTxFIFOSemaphore0 );
          semiphorTest = xTxFIFOSemaphore0;
          break;
        case 1:
          xRxedChars = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
          xRxedChartest = xRxedChars;
          vSemaphoreCreateBinary( xTxFIFOSemaphore );
          semiphorTest = xTxFIFOSemaphore;
          break;
        case 2:
          xRxedChars2 = xQueueCreate( uxQueueLength, ( unsigned portBASE_TYPE ) sizeof( signed portCHAR ) );
          xRxedChartest = xRxedChars2;
          vSemaphoreCreateBinary( xTxFIFOSemaphore2 );
          semiphorTest = xTxFIFOSemaphore2;
          break;
        }

    /* If the queue/semaphore was created correctly then setup the serial port
    hardware. */
    if( ( xRxedChartest != serINVALID_QUEUE ) && ( semiphorTest != serINVALID_QUEUE ) )
    {
        /* Pre take the semaphore so a task will block if it tries to access
        it. */
                 switch(comNum){
                  case 0:
                    xSemaphoreTake( xTxFIFOSemaphore0, 0 );
                    break;
                  case 1:
                    xSemaphoreTake( xTxFIFOSemaphore, 0 );
                    break;
                  case 2:
                    xSemaphoreTake( xTxFIFOSemaphore2, 0 );
                    break;
                  }
       
        /* Configure the UART. */
        xUARTx_Init.UART_WordLength = UART_WordLength_8D;
        xUARTx_Init.UART_StopBits = UART_StopBits_1;
        xUARTx_Init.UART_Parity = UART_Parity_No;
        xUARTx_Init.UART_BaudRate = ulWantedBaud;
        xUARTx_Init.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
        xUARTx_Init.UART_Mode = UART_Mode_Tx_Rx;
        xUARTx_Init.UART_FIFO = UART_FIFO_Enable;

        /* Enable the UARTx Clock */
                 switch(comNum){
                  case 0:
                    SCU_APBPeriphClockConfig( __UART0, ENABLE );
                    break;
                  case 1:
                    SCU_APBPeriphClockConfig( __UART1, ENABLE );
                    break;
                  case 2:
                    SCU_APBPeriphClockConfig( __UART2, ENABLE );
                    break;
                  }

        portENTER_CRITICAL();
        {
            /* Configure the UART itself. */
            UART_DeInit( UARTx );       
            UART_Init( UARTx, &xUARTx_Init );
            UART_ITConfig( UARTx, UART_IT_Receive | UART_IT_Transmit, ENABLE );
            UARTx->ICR = serCLEAR_ALL_INTERRUPTS;
            UART_LoopBackConfig( UARTx, DISABLE );
                       switch(comNum){
                        case 0:
                          UART_IrDACmd( IrDA0, DISABLE );
                          VIC_Config( UART0_ITLine, VIC_IRQ, 9 );
              VIC_ITCmd( UART0_ITLine, ENABLE );
                          break;
                        case 1:
                          UART_IrDACmd( IrDA1, DISABLE );
                          VIC_Config( UART1_ITLine, VIC_IRQ, 9 );
              VIC_ITCmd( UART1_ITLine, ENABLE );
                          break;
                        case 2:
                          UART_IrDACmd( IrDA2, DISABLE );
                          VIC_Config( UART2_ITLine, VIC_IRQ, 9 );
              VIC_ITCmd( UART2_ITLine, ENABLE );
                          break;
                        }

            UART_Cmd( UARTx, ENABLE );           
            lTaskWaiting = pdFALSE;
        }
        portEXIT_CRITICAL();
    }
    else
    {
        xReturn = ( xComPortHandle ) 0;
    }

    /* This demo file only supports a single port but we have to return
    something to comply with the standard demo header file. */
    return xReturn;
}

//the string print function
void vSerialPutString( xComPortHandle pxPort, const signed portCHAR * const pcString, unsigned portSHORT usStringLength )
{
signed portCHAR *pxNext;
int lengthCount = 0;
int j;

    /* A couple of parameters that this port does not use. */
    //( void ) usStringLength;
   
    /* NOTE: This implementation does not handle the queue being full as no
    block time is used! */

    /* Send each character in the string, one at a time. */
    pxNext = ( signed portCHAR * ) pcString;
    while( lengthCount < usStringLength )
    {
                for(j=10000; j>0; j–);
        xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );
        pxNext++;
                lengthCount += 1;
    }
}
//print char function
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed portCHAR cOutChar, portTickType xBlockTime )
{
portBASE_TYPE xReturn;
UART_TypeDef* UARTx;
xQueueHandle xTxFiFoSem;
int j;
        switch(pxPort->portNum)
                        {
                        case 0:
                          xTxFiFoSem = xTxFIFOSemaphore0;
                          UARTx = UART0;
                          break;
                        case 1:
                          xTxFiFoSem = xTxFIFOSemaphore;
                          UARTx = UART1;
                          break;
                        case 2:
                          xTxFiFoSem = xTxFIFOSemaphore2;
                          UARTx = UART2;
                          break;
                        }
       
        /* Can we write to the FIFO? */
        if( UARTx->FR & serTX_FIFO_FULL )
        {
                       
            /* Wait for the interrupt letting us know there is space on the
            FIFO.  It is ok to block in a critical section, interrupts will be
            enabled    for other tasks once we force a switch. */
            lTaskWaiting = pdTRUE;
           
                       
            /* Just to be a bit different this driver uses a semaphore to
            block the sending task when the FIFO is full.  The standard COMTest
            task assumes a queue of adequate length exists so does not use
            a block time.  For this demo the block time is therefore hard
            coded. */
                       
                          xReturn = xSemaphoreTake( xTxFiFoSem, serTX_BLOCK_TIME );
              if( xReturn )
              {
                  UARTx->DR = cOutChar;
              }
                       
        }
        else
        {
                          for(j=5000; j>0; j–);
                          portENTER_CRITICAL();
                          //printf("%d", UARTx->FR);
                          UARTx->DR = cOutChar;
                          //printf("%d ", UARTx->FR);
              xReturn = pdPASS;
                          portEXIT_CRITICAL();

        }
   
    return xReturn;
}

davedoors wrote on Wednesday, January 09, 2008:

                for(j=10000; j>0; j–);
        xSerialPutChar( pxPort, *pxNext, serNO_BLOCK );

this code writes 10000 bytes to a queue that is too short to receive them. If you use a block time then the task will block when the queue becomes full and then unblock when there is space to write again.

bones23 wrote on Wednesday, January 09, 2008:

Pasting into the message window got rid of all the indenting in my code. Sorry about that. The for(j=10000; j>0; j–); statement is just a do nothing loop. Its the quick and dirty delay I was talking about.

davedoors wrote on Thursday, January 10, 2008:

Ah, I see that now. It could still be a problem with the queue getting full though. Is it possible the queue is still getting full though if it was not already empty when you started to fill it again?

bones23 wrote on Friday, January 18, 2008:

I am pretty sure its not. I have put a block time of 100 in there with no change of behaviore.