我的自定义上下文切换在ARM的内联汇编中无法正常工作

编程语言 2026-07-12

我已经为我的上下文切换项目工作了一段时间,但在ARM内联汇编方面遇到了麻烦。我不知道如何用调试器逐步跟踪每一个汇编上下文,也不确定自己是否看懂了内联汇编。就这方面来说,我基本上是新手。如果你们能帮帮我,我会非常感激。完整的代码在下面的部分。

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"


volatile int32_t TimeDelay = 0;
void Delay(uint32_t nTime);

uint32_t stack_Blink_1[9]= {0};
uint32_t *sp_Blink_1 = &stack_Blink_1[8];

uint32_t stack_Blink_2[9]= {0};
uint32_t *sp_Blink_2 = &stack_Blink_2[8];

uint32_t curr_Task = 0;
uint32_t next_Task = 0;
uint32_t *PSP_Array[2]={0};


void GPIO_SETUP(void);
void EXTI_SETUP(void);
void Blink_1(void);
void Blink_2(void);

int main(void){

    SysTick_Config(7200000);
    GPIO_SETUP();
    EXTI_SETUP();
    NVIC_EnableIRQ(EXTI2_IRQn);

    SCB->CCR |= SCB_CCR_STKALIGN_Msk;

    sp_Blink_1--;
    *(sp_Blink_1--) = (1U << 24); //xPSR
    sp_Blink_1--;
    sp_Blink_1--;
    *sp_Blink_1 = (uint32_t)&Blink_1; //PC
    sp_Blink_1-= 4;

    sp_Blink_2--;
    *(sp_Blink_2--) = (1U << 24); //xPSR
    sp_Blink_2--;
    sp_Blink_2--;
    *sp_Blink_2 = (uint32_t)&Blink_2; //PC
    sp_Blink_2-= 4;

    PSP_Array[0]=sp_Blink_1;
    PSP_Array[1]=sp_Blink_2;

    Blink_1();

    while(1){

    }
}

void PendSV_Handler(void){

    __ASM volatile(
                    //save current context
                    "MRS R0, PSP\n\t" // Get current process stack pointer value
                    "ISB\n\t"
                    "STMDB R0!, {R4-R11}\n\t" // Save R4 to R11 in task stack (8 regs)
                    "LDR R1, %[curr_Task]\n\t" 
                    "LDR R2, [R1]\n\t" // Get current task ID
                    "LDR R3, %[psp_array]\n\t"
                    "STR R0,[R3, R2, LSL #2]\n\t" // Save PSP value into PSP_array
                    //-----------------------------------------------------------------
                    //load next context
                    "LDR R4, %[next_task]\n\t"
                    "LDR R4, [R4]\n\t" // Get next task ID
                    "STR R4, [R1]\n\t" // Set curr_task = next_task
                    "LDR R0,[R3, R4, LSL #2]\n\t" // Load PSP value from PSP_array
                    "LDMIA R0!, {R4-R11}\n\t" // Load R4 to R11 from task
                    "MSR PSP, R0\n\t" // Set PSP to next task
                    "ISB\n\t"
                    "BX LR\n\t" // Return
                    //"ALIGN 4\n\t"
                    : // Output Operands
                    : [curr_Task] "m" (curr_Task),
                      [psp_array] "m" (PSP_Array),
                      [next_task] "m" (next_Task) // Input Operands
                );
}

void SysTick_Handler(void){
    if(TimeDelay > 0)
        TimeDelay--;
}

void EXTI2_IRQHandler(void){
    if(curr_Task == 0){
        EXTI_ClearITPendingBit(EXTI_Line2);
        curr_Task = 1;
    }else{
        EXTI_ClearITPendingBit(EXTI_Line2);
        curr_Task =0;
    }
    SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}

void Delay(uint32_t nTime){
    TimeDelay = nTime;
    while(TimeDelay != 0);
}

void Blink_1(void){
    while(1){
        GPIO_ResetBits(GPIOB,GPIO_Pin_1);
        Delay(10);
        GPIO_SetBits(GPIOB,GPIO_Pin_1);
        Delay(10);
    }
}

void Blink_2(void){
    while(1){
        GPIO_ResetBits(GPIOB,GPIO_Pin_0);
        Delay(10);
        GPIO_SetBits(GPIOB,GPIO_Pin_0);
        Delay(10);
    }
}

void GPIO_SETUP(void){

    GPIO_InitTypeDef GPIO_InitStruct_A2;
    GPIO_InitStruct_A2.GPIO_Pin  = GPIO_Pin_2;
    GPIO_InitStruct_A2.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct_A2.GPIO_Mode = GPIO_Mode_IPD;

    GPIO_InitTypeDef GPIO_InitStruct_B0;
    GPIO_InitStruct_B0.GPIO_Pin  = GPIO_Pin_0;
    GPIO_InitStruct_B0.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct_B0.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitTypeDef GPIO_InitStruct_B1;
    GPIO_InitStruct_B1.GPIO_Pin  = GPIO_Pin_1;
    GPIO_InitStruct_B1.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct_B1.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitTypeDef GPIO_InitStruct_C13;
    GPIO_InitStruct_C13.GPIO_Pin  = GPIO_Pin_13;
    GPIO_InitStruct_C13.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct_C13.GPIO_Mode = GPIO_Mode_Out_PP;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

    GPIO_Init(GPIOA,&GPIO_InitStruct_A2);
    GPIO_Init(GPIOB,&GPIO_InitStruct_B0);
    GPIO_Init(GPIOB,&GPIO_InitStruct_B1);
    GPIO_Init(GPIOC,&GPIO_InitStruct_C13);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, 2);

    GPIO_SetBits(GPIOB,GPIO_Pin_0);
    GPIO_SetBits(GPIOB,GPIO_Pin_1);
    GPIO_SetBits(GPIOC,GPIO_Pin_13);

}

void EXTI_SETUP(void){

    EXTI_InitTypeDef EXTI_InitStruct_2;
    EXTI_InitStruct_2.EXTI_Line = EXTI_Line2;
    EXTI_InitStruct_2.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStruct_2.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStruct_2.EXTI_LineCmd = ENABLE;

    EXTI_Init(&EXTI_InitStruct_2);

}

解决方案

问题之所以出现,是因为我让PSP寄存器指向了任务栈。这样会导致数据损坏,处理器也无法切换到这些任务。不是让PSP指向任务栈,而是在PendSV触发后,把任务栈中的数据取出,放到PSP指向的位置。

#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_exti.h"


volatile int32_t TimeDelay = 0;
void Delay(uint32_t nTime);

uint32_t stack_Blink_1[18]= {0};
uint32_t *sp_Blink_1 = &stack_Blink_1[17];

uint32_t stack_Blink_2[18]= {0};
uint32_t *sp_Blink_2 = &stack_Blink_2[17];

uint32_t curr_Task = 0;
uint32_t next_Task = 1;
uint32_t *pCurr_Task = 0;
uint32_t *pNext_Task = 0;
uint32_t *PSP_Array[2]={0};
uint32_t **pPSP_Array = 0;

uint32_t tmp = 0;


void GPIO_SETUP(void);
void EXTI_SETUP(void);
void Blink_1(void);
void Blink_2(void);

int main(void){

    SysTick_Config(7200000);
    GPIO_SETUP();
    EXTI_SETUP();
    NVIC_EnableIRQ(EXTI2_IRQn);
    NVIC_SetPriority(PendSV_IRQn, 0xEF);
    NVIC_SetPriority(EXTI2_IRQn, 0xFF);

    SCB->CCR |= SCB_CCR_STKALIGN_Msk;

    sp_Blink_1--;
    *(sp_Blink_1--) = (1U << 24); //xPSR
    *sp_Blink_1 = (uint32_t)&Blink_1; //PC

    sp_Blink_2--;
    *(sp_Blink_2--) = (1U << 24); //xPSR
    *sp_Blink_2 = (uint32_t)&Blink_2; //PC

    pCurr_Task = &curr_Task;
    pNext_Task = &next_Task;

    sp_Blink_1 = (uint32_t *)((((uint32_t)stack_Blink_1 / 8) * 8) + 8);
    sp_Blink_2 = (uint32_t *)((((uint32_t)stack_Blink_2 / 8) * 8) + 8);

    PSP_Array[0]=sp_Blink_1;
    PSP_Array[1]=sp_Blink_2;
    pPSP_Array = &PSP_Array[0];

    tmp = __get_MSP();
    __set_PSP(tmp);

    __set_CONTROL(0x3);
    __ISB();

    Blink_1();

    while(1){

    }
}

void PendSV_Handler(void){

    __ASM volatile(

                    //save current context
                    "CPSID I                   \n\t" //__disable_irq()
                    "MRS R0, PSP               \n\t"
                    "LDR R1, %[pPSP_Array]     \n\t" //loadin the address of PSP_Array
                    "LDR R3, %[curr_Task]      \n\t"
                    "LDR R1, [R1, R3, LSL #2]  \n\t" //getting the stack value from array (&stack_Blink_x)
                    "ADD R1, #32               \n\t" //stack_Blink_x[8](
                    "STMDB R1!, {R4-R11}       \n\t" // Save R4 to R11 in task stack (8 regs) after saving the r1 goes back to stack_Blink_1[0]
                    "LDR R1, %[curr_Task]      \n\t"
                    "LDR R2, %[pCurr_Task]     \n\t"

                    //load next context
                    "LDR R3, %[next_task]      \n\t"
                    "STR R3, [R2]              \n\t" // Set curr_task = next_task
                    "LDR R2, %[pNext_Task]     \n\t"
                    "STR R1, [R2]              \n\t" // set next_task = curr_task (we are toggling)
                    "LDR R1, %[pPSP_Array]     \n\t"
                    "LDR R1, [R1, R3, LSL #2]  \n\t" // Load PSP value from PSP_array (&stack_Blink_x)
                    "LDMIA R1!, {R4-R11}       \n\t" // Load R4 to R11 from stack
                    "MOV R2, R0                \n\t"
                    "ADD R2, #24               \n\t"
                    "ADD R1, #24               \n\t"
                    "LDR R3, [R1]              \n\t"
                    "STM R2, {R3}              \n\t"
                    "ADD R2, #4                \n\t"
                    "ADD R1, #4                \n\t"
                    "LDR R3, [R1]              \n\t"
                    "STM R2, {R3}              \n\t"
                    "CPSIE I      \n\t" //__enable_irq()
                    "BX R14         \n\t" // Return
                    : // Output Operands
                    : [curr_Task] "m" (curr_Task),
                      [pPSP_Array] "m" (pPSP_Array),
                      [next_task] "m" (next_Task),
                      [pCurr_Task] "m" (pCurr_Task),
                      [pNext_Task] "m" (pNext_Task) // Input Operands
                    :"memory","r0","r1","r2","r3"
    );
}

void SysTick_Handler(void){
    if(TimeDelay > 0)
        TimeDelay--;
}

void EXTI2_IRQHandler(void){
    EXTI_ClearITPendingBit(EXTI_Line2);
    SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
}

void Delay(uint32_t nTime){
    TimeDelay = nTime;
    while(TimeDelay != 0);
}

void Blink_1(void){   
    while(1){
        GPIO_ResetBits(GPIOB,GPIO_Pin_0);
        Delay(10);
        GPIO_SetBits(GPIOB,GPIO_Pin_0);
        Delay(10);
    }
}

void Blink_2(void){  
    while(1){
        GPIO_ResetBits(GPIOB,GPIO_Pin_1);
        Delay(10);
        GPIO_SetBits(GPIOB,GPIO_Pin_1);
        Delay(10);
    }
}

void GPIO_SETUP(void){

    GPIO_InitTypeDef GPIO_InitStruct_A2;
    GPIO_InitStruct_A2.GPIO_Pin  = GPIO_Pin_2;
    GPIO_InitStruct_A2.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct_A2.GPIO_Mode = GPIO_Mode_IPD;

    GPIO_InitTypeDef GPIO_InitStruct_B0;
    GPIO_InitStruct_B0.GPIO_Pin  = GPIO_Pin_0;
    GPIO_InitStruct_B0.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct_B0.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitTypeDef GPIO_InitStruct_B1;
    GPIO_InitStruct_B1.GPIO_Pin  = GPIO_Pin_1;
    GPIO_InitStruct_B1.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct_B1.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitTypeDef GPIO_InitStruct_C13;
    GPIO_InitStruct_C13.GPIO_Pin  = GPIO_Pin_13;
    GPIO_InitStruct_C13.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStruct_C13.GPIO_Mode = GPIO_Mode_Out_PP;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

    GPIO_Init(GPIOA,&GPIO_InitStruct_A2);
    GPIO_Init(GPIOB,&GPIO_InitStruct_B0);
    GPIO_Init(GPIOB,&GPIO_InitStruct_B1);
    GPIO_Init(GPIOC,&GPIO_InitStruct_C13);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, 2);

    GPIO_SetBits(GPIOB,GPIO_Pin_0);
    GPIO_SetBits(GPIOB,GPIO_Pin_1);
    GPIO_SetBits(GPIOC,GPIO_Pin_13);

}

void EXTI_SETUP(void){

    EXTI_InitTypeDef EXTI_InitStruct_2;
    EXTI_InitStruct_2.EXTI_Line = EXTI_Line2;
    EXTI_InitStruct_2.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStruct_2.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStruct_2.EXTI_LineCmd = ENABLE;

    EXTI_Init(&EXTI_InitStruct_2);

}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章