Page 1 of 1

Context Switch Arm Cortex M3

Posted: Wed Dec 10, 2014 8:01 pm
by gardinirafael
Good Night,
I have a problem with my context switch routine in Arm Cortex m3.
I have been trying to make a Delay function, but doesn't work.
When I put a Delay function inside of Task or internal variables, the context switch doesn't work and my task either.
Without Delay function and internal variables, the context works fine.
I think the problem is related with stack save but I don't know how solve.
Anybody have any idea how solve this question?
Below I put the main functions in process.

Thank you in advance.

Code: Select all

int main (void) 
{
	NVIC_SetPriority(SysTick_IRQn, 0xff);
	NVIC_SetPriority(PendSV_IRQn, 0xff);

    SystemCoreClockUpdate();
    if (SysTick_Config(SystemCoreClock / 100)) { 
        while (1);
    }

	tss = (TSS *) (heap + (4096 - sizeof(TSS)));
	tss2 = (TSS *) (heap2 + (4096 - sizeof(TSS)));

	create_task(tss, vTask);
	create_task(tss2, vTask2);

    asm volatile ("MOV R2, R0");
    asm volatile ("MOVS R0, #0");
    asm volatile ("MSR PSP, R0");

	*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;

	while(1);

	return 0;
}

Code: Select all

void create_task(TSS * tssr, void (*eip)(void))
{
	tssr->psr = 0x21000000;
	tssr->pc = (unsigned int) eip;
	tssr->lr = 0;
	tssr->r12 = 0;
}

Code: Select all

void Delay(unsigned int dlyTicks) 
{
    unsigned int curTicks = msTicks;

    while ((msTicks - curTicks) < dlyTicks);
}

Code: Select all

void PendSV_Handler(void)
{
    asm volatile ("CPSID I");
    asm volatile ("MRS R0, PSP");
    asm volatile ("STMDB R0!, {R4-R11}"); 

    asm volatile ("PUSH {R14}");              
    asm volatile ("BL OS_ContextSwitchHook");
    asm volatile ("POP {R14}");

    asm volatile ("LDMIA R0!, {R4-R11}");
    asm volatile ("MSR PSP, R0");
    asm volatile ("ORR LR, LR, #0x04");
    asm volatile ("CPSIE I");
    asm volatile ("BX R14");
}

Code: Select all

void SysTick_Handler(void) 
{	
    asm volatile ("CPSID I");

	msTicks++;

	if ( SysTick->CTRL & (1<16) )
	{
		*(portNVIC_INT_CTRL) = portNVIC_PENDSVSET;
	}

    asm volatile ("CPSIE I");
}

Code: Select all

void vTask(void)
{
	LPC_GPIO1->FIODIR |= (1 << 18);

	for (a = 0; a < MAX_T; a++)
	{	
		LPC_GPIO1->FIOCLR = (1 << 18);

//		for(c = 0; c < MAX_R; c++);
		Delay(100);

		LPC_GPIO1->FIOSET = (1 << 18);

//		for(c = 0; c < MAX_R; c++);
		Delay(100);
    }	

	while(1);
}

Re: Context Switch Arm Cortex M3

Posted: Wed Dec 10, 2014 10:54 pm
by thepowersgang
First off - Don't use multiple "asm volatile" statements for instructions that should never be split, the compiler is free to stick stuff between them.

I don't see anything that switches tasks here, just several disjoint functions (which imply that you're binding task switches directly to interrupts - don't do that).

Re: Context Switch Arm Cortex M3

Posted: Thu Dec 11, 2014 6:51 am
by gardinirafael
thepowersgang wrote:First off - Don't use multiple "asm volatile" statements for instructions that should never be split, the compiler is free to stick stuff between them.

I don't see anything that switches tasks here, just several disjoint functions (which imply that you're binding task switches directly to interrupts - don't do that).
I'll change commands "asm volatile" and return with results.

Sorry by my mistake, the switch task is inside of function OS_ContextSwitchHook.

This function is called by interrupt handler PendSV_Handler in first post.

Is wrong way to do that?

thanks.

Re: Context Switch Arm Cortex M3

Posted: Thu Dec 11, 2014 8:05 am
by Schol-R-LEA
I'm not an expert on ARM programming by any means, but I've done some checking, and I think you'll find the approach you are using for the interrupt handler itself won't work. You cannot write the interrupt handler itself in a C function, even if the code is all assembly; the C function entry and return mechanism will get in the way.

Essentially, it's the same basic problem you have when trying to writing for x86, which is that the interrupt return is handled differently from a C function return. While there is no special instruction for the return equivalent the x86's IRET, it does have to be performed differently, which means you have to write it as actual assembly code - not inside as inline assembly in a C function. At least, that is the impression I get from this article and others I have read.

Re: Context Switch Arm Cortex M3

Posted: Thu Dec 11, 2014 6:09 pm
by gardinirafael
Schol-R-LEA wrote:I'm not an expert on ARM programming by any means, but I've done some checking, and I think you'll find the approach you are using for the interrupt handler itself won't work. You cannot write the interrupt handler itself in a C function, even if the code is all assembly; the C function entry and return mechanism will get in the way.

Essentially, it's the same basic problem you have when trying to writing for x86, which is that the interrupt return is handled differently from a C function return. While there is no special instruction for the return equivalent the x86's IRET, it does have to be performed differently, which means you have to write it as actual assembly code - not inside as inline assembly in a C function. At least, that is the impression I get from this article and others I have read.
Schol , you are right .

I put PendSV_handler in separate assembly file and all process works perfectly .


Thanks thepowersgang and Schol.

Below you can find the end code .

Code: Select all

.text
.thumb
.syntax unified

.global PendSV_Handler
.align 2
.type PendSV_Handler, %function
PendSV_Handler:
	CPSID   I
	MRS     R0, PSP
	CBZ     R0, save

	STMDB R0!, {R4-R11}

	PUSH    {R14}
	LDR     R1, =switch
	BLX     R1
	POP     {R14}
restore:
	LDMIA R0!, {R4-R11}
	MSR     PSP, R0
	ORR     LR, LR, #0x04
	CPSIE   I
	BX      LR
save:
	MOV R0, R2
	LDR     R1, =0xE000E010
	LDR     R2, =(0x00000004 || 0x00000002 || 0x00000001)
	STR     R2, [R1]

	B   restore