Context Switch Arm Cortex M3

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
gardinirafael
Posts: 21
Joined: Mon Feb 03, 2014 12:52 pm

Context Switch Arm Cortex M3

Post 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);
}
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: Context Switch Arm Cortex M3

Post 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).
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
gardinirafael
Posts: 21
Joined: Mon Feb 03, 2014 12:52 pm

Re: Context Switch Arm Cortex M3

Post 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.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Context Switch Arm Cortex M3

Post 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.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
gardinirafael
Posts: 21
Joined: Mon Feb 03, 2014 12:52 pm

Re: Context Switch Arm Cortex M3

Post 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
Post Reply