The Board keep restarting while comment out one of the task

eaoiyrioeaf wrote on Wednesday, February 22, 2017:

I have defined three tasks, below are the code of these tasks:

static void vThread1( void *pvParameters )
{
    //vTaskSetApplicationTaskTag( NULL, ( void * ) 1 );
    for(;;){
        vTaskDelay( 10000 );
        LED_1_LAT=0;
        while(U1STAbits.TRMT==0);
        UART1_sent((uchar*)"Thread1 Running\r\n\r\r\r",18);
    }
}

static void vThread2( void *pvParameters )
{
    //vTaskSetApplicationTaskTag( NULL, ( void * ) 2 );
    for(;;){
    vTaskDelay( 10000 );
    LED_1_LAT=1;
    while(U1STAbits.TRMT==0);
    UART1_sent((uchar*)"Thread2 Running\r\n\r\r\r",18);
    }
}

static void vIdle( void *pvParameters )
{
    //vTaskSetApplicationTaskTag( NULL, ( void * ) 1 );
    for(;;){
        Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();Nop();
    }
}

Then create above three tasks by below code:

xTaskCreate( vThread1, "Thread1", mainCHECK_TAKS_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );
    xTaskCreate( vThread2, "Thread2", mainCHECK_TAKS_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );
    xTaskCreate( vIdle, "IdleThread", mainCHECK_TAKS_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );

up to now, the program works well, the serial port keep out put “Thread1 Running” &“Thread2 Running” as I have expected.
When I read through the FreeRTOS manual “Mastering the FreeRTOS™Real Time Kernel”, I chapter 3.8, it’s mentioned the FreeRTOS itself will create a Idle task, so I comment out the Idle task create by me, below is the only part I have modified:
//xTaskCreate( vIdle, "IdleThread", mainCHECK_TAKS_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );
the program supposed to work well by then, but the truth is after comment out this statement, the board keeps restarting.
Really have no ideal why this happen, appreciate anyone can help me on this.

rtel wrote on Wednesday, February 22, 2017:

Your vIdle() task should have no real effect here.

How is UART1_sent() implemented? Does it include some mutual exclusion
to prevent a context switch to the other task half way through a string
being sent?

eaoiyrioeaf wrote on Wednesday, February 22, 2017:

Thank you for your reply Sir.
The UART1_sent do use UART interrupt for sending&receiving data, but I don’t believe it will affect context switching. because context switch are using Timer1 to trigger switch.
Below are my code, BTW my chip is dsPIC33EV256GM106 from Microchip.

volatile uchar *UART1_TX_DATA;
volatile uint UART1_TX_LEN;
uchar UART1_TX_BUFF[UART1_TX_BUFF_SIZE];

volatile uchar UART1_RX_BUFF[UART1_RX_BUFF_SIZE];
volatile uchar UART1_RX_MEM;
volatile bool UART1_RETURN;
void init_UART1(void)// initalize the UART1
{    
    U1MODEbits.STSEL = 0; // 1-Stop bit
    U1MODEbits.PDSEL = 0; // No Parity, 8-Data bits
    U1MODEbits.ABAUD = 0; // Auto-Baud disabled
    U1MODEbits.BRGH = 0; // Standard-Speed mode
    U1BRG = BRGVAL; // Baud Rate setting for 115200
    
    U1STAbits.UTXISEL0 = 0; // bit <15,13>=0b10 Interrupt when the last bit is shifted into TSR, and as a result, the TX FIFO is empty
    U1STAbits.UTXISEL1 = 1;
    IEC0bits.U1TXIE = 1; // Enable UART TX interrupt
    U1MODEbits.UARTEN = 1; // Enable UART
    U1STAbits.UTXEN = 1; // Enable UART TX
    
    U1STAbits.URXISEL=0b00; //Interrupt is set when any character is received
    IEC0bits.U1RXIE=1;  // Enable UART RX interrupt
    
    UART1_RX_MEM=0;
    UART1_RETURN=false;
}

void __attribute__((__interrupt__, auto_psv)) _U1TXInterrupt(void)
{
    IFS0bits.U1TXIF = 0; // Clear TX Interrupt flag
    while(U1STAbits.UTXBF==0 && UART1_TX_LEN>0)
    {
        U1TXREG = *UART1_TX_DATA++;
        UART1_TX_LEN--;
    }
}

void __attribute__((__interrupt__, auto_psv)) _U1RXInterrupt(void)
{
    IFS0bits.U1RXIF = 0; // Clear TX Interrupt flag
    UART1_RX_BUFF[UART1_RX_MEM]=U1RXREG;
    U1TXREG=UART1_RX_BUFF[UART1_RX_MEM];
    if(UART1_RX_BUFF[UART1_RX_MEM]=='\r')
    {
        UART1_RETURN=true;
        U1TXREG='\n';
    }
    UART1_RX_MEM++;
    if(UART1_RX_MEM>=UART1_RX_BUFF_SIZE)
        UART1_RX_MEM-=UART1_RX_BUFF_SIZE;
    
}

bool UART1_sent(uchar data[], uint length)
{
    if(U1STAbits.TRMT)
    {
        UART1_TX_DATA=data;
        U1TXREG = *UART1_TX_DATA++;
        UART1_TX_LEN=length-1;
        return true;
    }
    return false;    
}

eaoiyrioeaf wrote on Wednesday, February 22, 2017:

Sir The U1TXREG is a transmit register, once the data placed to this register, the UART moule will automatic shift the data out. and after the last bit of data shifted out, the UART module will trigger a interrupt to call the void attribute((interrupt, auto_psv)) _U1TXInterrupt(void);
So, basically, the UART1_sent(uchar data[], uint length), just triggle the first byte of data to sent, and the remaining data will be send out by the interrupt.

rtel wrote on Wednesday, February 22, 2017:

Consider what will happen one task starts to send a string, half the
string has been transmitted, then a context switch occurs to the other
task, and that task starts to send a string before the original string
has been transmitted completely. Take a look through the mutual
exclusion chapters in the book.
http://www.freertos.org/Documentation/RTOS_book.html

eaoiyrioeaf wrote on Thursday, February 23, 2017:

Actually the statement :while(U1STAbits.TRMT==0); is to prevent this from happen. if the “TRMT” bit is clear, that means the UART is occupied, task will wait it to set then start the string sending.
Anyway, I will read the book through to see whether I can find some clue.
Thanks again Sir!

rtel wrote on Thursday, February 23, 2017:

Actually the statement :while(U1STAbits.TRMT==0); is to prevent this
from happen. if the “TRMT” bit is clear, that means the UART is

Maybe that will work, but I suspect you have a race condition there.

eaoiyrioeaf wrote on Tuesday, March 07, 2017:

Hello Sir, This problem still un-resolved, but I have dig in the source code, and one thing I noticed is the vPortYield function in portasm_dsPIC.s file did not switching the value in Program Counter (PC) register while switch tasks.
Below is the code:

_vPortYield:

		PUSH	SR						/* Save the SR used by the task.... */
		PUSH	W0						/* ....then disable interrupts. */
		MOV		#32, W0
		MOV		W0, SR
		PUSH	W1						/* Save registers to the stack. */
		PUSH.D	W2
		PUSH.D	W4
		PUSH.D	W6
		PUSH.D 	W8
		PUSH.D 	W10
		PUSH.D	W12
		PUSH	W14
		PUSH	RCOUNT
		PUSH	TBLPAG
		PUSH	ACCAL
		PUSH	ACCAH
		PUSH	ACCAU
		PUSH	ACCBL
		PUSH	ACCBH
		PUSH	ACCBU
		PUSH	DCOUNT
		PUSH	DOSTARTL
		PUSH	DOSTARTH
		PUSH	DOENDL
		PUSH	DOENDH


		PUSH	CORCON
		#ifdef  __HAS_EDS__
			PUSH	DSRPAG
			PUSH	DSWPAG
		#else
			PUSH	PSVPAG
		#endif /* __HAS_EDS__ */
		MOV		_uxCriticalNesting, W0		/* Save the critical nesting counter for the task. */
		PUSH	W0
		MOV		_pxCurrentTCB, W0			/* Save the new top of stack into the TCB. */
		MOV		W15, [W0]

		call 	_vTaskSwitchContext

		MOV		_pxCurrentTCB, W0			/* Restore the stack pointer for the task. */
		MOV		[W0], W15
		POP		W0							/* Restore the critical nesting counter for the task. */
		MOV		W0, _uxCriticalNesting
		#ifdef __HAS_EDS__
			POP		DSWPAG
			POP		DSRPAG
		#else
			POP		PSVPAG
		#endif /* __HAS_EDS__ */
		POP		CORCON
		POP		DOENDH
		POP		DOENDL
		POP		DOSTARTH
		POP		DOSTARTL
		POP		DCOUNT
		POP		ACCBU
		POP		ACCBH
		POP		ACCBL
		POP		ACCAU
		POP		ACCAH
		POP		ACCAL
		POP		TBLPAG
		POP		RCOUNT						/* Restore the registers from the stack. */
		POP		W14
		POP.D	W12
		POP.D	W10
		POP.D	W8
		POP.D	W6
		POP.D	W4
		POP.D	W2
		POP.D	W0
		POP		SR

        return

        .end

even there is a function vTaskSwitchContext(viod) , but this function didn’t switching the PC, what it did is to find the highest priority task, and return the point of task’s TCB.
Do you think this is the reason cause the error?
BTW, I have put and error trap in my code, and it proved the board restart is caused by Address Error, That is to say the error is caused by wrong PC.
Below is my error trap:

void __attribute__((__interrupt__, __no_auto_psv__)) _AddressError(void)
{
     __asm__ volatile("nop"); // use volatile keyword to avoid the instruction being optimized away
}

rtel wrote on Tuesday, March 07, 2017:

I’m not sure I understand. The vTaskSwitchContex() function will work
the same each time - why do you think its behaviour on just one call
would be the problem?

eaoiyrioeaf wrote on Wednesday, March 08, 2017:

Hello Sir, What I mean is in the overall switching procedure there is no place operated the PC, I’m not focus on the function vTaskSwitchContex() .

eaoiyrioeaf wrote on Wednesday, March 08, 2017:

I just finished another experiment. I have disable all the user defined interrupt, and comment out the UART1_sent function, just left a simple LED control instruction as shown below, the result still the same.

static void vThread1( void *pvParameters )
{
    //vTaskSetApplicationTaskTag( NULL, ( void * ) 1 );
    for(;;){ 
        vTaskDelay( 5000 );
        LED_1_LAT=0;
        //while(U1STAbits.TRMT==0);
        //UART1_sent((uchar*)"Thread1 Running\r\n\r\r\r",18);
    }
}

one of my finding is, once the FreeRTOS called the system default idle task prvIdleTask(), this error will happen.
If I create the user defined idle task, and use the idle task to occupy all the idle time, the error never appear.

rtel wrote on Wednesday, March 08, 2017:

What is configMINIMAL_STACK_SIZE set to? That sets the size of the
stack used by the idle task.

eaoiyrioeaf wrote on Wednesday, March 08, 2017:

The configMINIMAL_STACK_SIZE is 105, I believe it’s large enough to store all the registers.

eaoiyrioeaf wrote on Wednesday, March 08, 2017:

My Chip have 16kByte RAM, Below are the configuration:

#define configUSE_PREEMPTION			1
#define configUSE_IDLE_HOOK				1
#define configUSE_TICK_HOOK				0
#define configTICK_RATE_HZ				( ( TickType_t ) 1000 )
#define configCPU_CLOCK_HZ				( ( unsigned long ) 64000000 )  /* Fosc / 2 */
#define configMAX_PRIORITIES			( 4 )
#define configMINIMAL_STACK_SIZE		( 105 )
#define configTOTAL_HEAP_SIZE			( ( size_t ) 5120 )
#define configMAX_TASK_NAME_LEN			( 4 )
#define configUSE_TRACE_FACILITY		0
#define configUSE_16_BIT_TICKS			1
#define configIDLE_SHOULD_YIELD			1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 		1
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet		1
#define INCLUDE_uxTaskPriorityGet		0
#define INCLUDE_vTaskDelete				0
#define INCLUDE_vTaskCleanUpResources	0
#define INCLUDE_vTaskSuspend			1
#define INCLUDE_vTaskDelayUntil			1
#define INCLUDE_vTaskDelay				1


#define configKERNEL_INTERRUPT_PRIORITY	0x01

#endif /* FREERTOS_CONFIG_H */

rtel wrote on Wednesday, March 08, 2017:

The demo in the FreeRTOS download has this set to 115. Did you try
increasing it?

eaoiyrioeaf wrote on Thursday, March 09, 2017:

After set it to 205, still the same.

eaoiyrioeaf wrote on Thursday, March 09, 2017:

Hello Sir, When I comment out the vCoRoutineSchedule from the code, the program goes well, I believe what cause the error is the the Co-Routine, any comment on that?
void vApplicationIdleHook( void )
{
/* Schedule the co-routines from within the idle task hook. */
//vCoRoutineSchedule();
}

rtel wrote on Thursday, March 09, 2017:

Hmm. If only you had mentioned you were actually calling something from
the idle hook then that would have been found much earlier.

eaoiyrioeaf wrote on Thursday, March 09, 2017:

I’m sorry Sir, I have focus on the PC value for long time until reach this point.
But this calling is from the example port, I haven’t made any change. I’m curious what is the Co-Routine doing? If I remove it from the project, what will happen?

richarddamon wrote on Thursday, March 09, 2017:

Are you using the CoRoutines in FreeRTOS (I don’t as they have a somewhat clunky interface and seam intended for very resource limited processors)? One big requirement of the idle hook is that you can’t put anything that might block there, I am not sure that vCoRoutineSchedule meets that requirement, do the coroutines say to put it there?