首页 > 其他分享 >FreeRtos的移植

FreeRtos的移植

时间:2024-10-26 17:58:26浏览次数:1  
标签:r0 FreeRtos pxCurrentTCB r3 中断 ldr 任务 移植

一.前言

之前移植过freertos操作系统,涉及到计算机和操作系统的底层,特此详细记录下这些知识点。至于具体的详细步骤,就不给出了,网上有很多参考,这里只分析“重点”。笔者的cpu内核是cotex-M3.

二.3个重点函数

  • vPortSVCHandler():加载第一个任务的中断处理函数。
  • xPortPendSVHandler():实现任务切换的中断处理函数(保存和恢复任务的上下文)。
  • xPortSysTickHandler():给操作系统提供滴答时钟。

三.vPortSVCHandler

FreeRTOS启动调度器时,调用prvStartFirstTask,再调用SVC中断来启动第一个任务

点击查看代码
__asm void prvStartFirstTask( void )
{
	PRESERVE8

	/* Use the NVIC offset register to locate the stack. */
	ldr r0, =0xE000ED08 /* 在Cortex-M中,0xE000ED08是SCB_VTOR这个寄存器的地址,里面存放的是向量表的起始地址,即MSP的地址 */
	ldr r0, [r0]
	ldr r0, [r0]

	/* Set the msp back to the start of the stack. */
	msr msp, r0  /* 设置主堆栈指针msp的值 *
	/* Globally enable interrupts. *//* 使能全局中断 */
	cpsie i
	cpsie f
	dsb
	isb
	/* Call SVC to start the first task. *//* 调用SVC去启动第一个任务 */
	svc 0/*产生系统调用,服务号 0表示 SVC 中断,接下来将会执行 SVC 中断服务函数*/
	nop
	nop
}

SVC中断被触发,PortSVCHandler加载第一个任务

点击查看代码
PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;/* 当前正在运行的任务的任务控制块指针,默认初始化为NULL,defined in task.c*/

__asm void vPortSVCHandler( void )
{
	PRESERVE8

	ldr	r3, =pxCurrentTCB	//r3=&pxCurrentTCB,即r3指向当前执行任务的TCB指针所在地址
	ldr r1, [r3]			//r1=*r3=pxCurrentTCB,既让r1指向当前任务的TCB
	ldr r0, [r1]			//r0=*r1=pxTopOfStack,即让r0执行当前任务栈顶
	/* Pop the core registers. */ //将当前任务栈内容pop,保存入cpu寄存器,注意序号小的寄存器会先被pop,所以pop顺序:r4...r10,r11
	ldmia r0!, {r4-r11}		/* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */
	msr psp, r0				/* Restore the task stack pointer. *// / 将当前任务栈顶赋给psp, 即psp = pxTopOfStack,执行后效果如图1所示	
	isb                     // 指令同步隔离,确保之前的指令都已执行完毕
	mov r0, #0              // r0清0,用于关中断
	msr	basepri, r0         //设置 basepri 寄存器的值为 0,即关闭所有中断。basepri 是一个中断屏蔽寄存器,大于等于此寄存器值的中断都将被屏蔽,但如果设置成0,则不关闭任何中断
	orr r14, #0xd
	bx r14                  ///任务上下文加载完毕,中断执行结束,返回用户线程,在ARM中,使用r14(LR寄存器)来保存子程序的返回地址(即上一个程序的地址)
}

四.xPortPendSVHandler

任务调度中断,被切换出去的任务,一部分参数由硬件自动保存,一部分手动保存

点击查看代码
__asm void xPortPendSVHandler( void )
{
	extern uxCriticalNesting;
	extern pxCurrentTCB;
	extern vTaskSwitchContext;

	PRESERVE8
        
	/*r0=psp, 进入PendSV中断时,上个任务环境即		     
	xPSR,PC,R14,R12,R3,R2,R1,R0这些将自动保存入任务栈,
	剩下R4-R11需要手动保存,同时PSP将自动更新(在更新之前 PSP 指向任务栈的栈顶),
	此时 PSP是"上文"任务的堆栈指针,具体指向见图3*/
	mrs r0, psp 
	isb			//确保之前指令已执行(为什么mrs或者msr执行完之后就要接一个isb或者dsb?不知道)
	/* Get the location of the current TCB. */
	ldr	r3, =pxCurrentTCB	//r3=&pxCurrentTCB
	ldr	r2, [r3]			//r2=*r3=pxCurrentTCB

	/* Save the core registers. */
	stmdb r0!, {r4-r11}	//将cpu寄存器保存入"上文"任务栈,注意push总是先push序号大的,因此push顺序:r11,r10....r4

	/* Save the new top of stack into the first member of the TCB. */
	str r0, [r2]	//*r2=r0 => pxTopOfStack=p0, 更新"上文"任务的栈顶

	stmdb sp!, {r0, r3}	//入栈栈顶指针和pxCurrentTCB,这个栈的指针是MSP,注意顺序:r3,r0
    /* 至此,上下文切换的"上文"环境保存完成 */
    
    //关中断,高于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断都将被屏蔽,configMAX_SYSCALL_INTERRUPT_PRIORITY的值在FreeRTOSConfig.h定义
	mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
	msr basepri, r0
        
	dsb	//数据隔离,同步之前对msr的操作
	isb	//指令隔离,确保之前所有指令已执行完毕,之后的指令使用的是正确的basepri配置
        
	bl vTaskSwitchContext	//跳转到vTaskSwitchContext函数去执行,pxCurrentTCB将被更改指向下一个任务
    //开中断
	mov r0, #0
	msr basepri, r0
   
	ldmia sp!, {r0, r3}	//从MSP栈加载r0和r3,此时r3已经指向新任务pxCurrentTCB的地址值,注意pop顺序:r0,r3
	
    /* 以下为上下文切换的"下文"环境切换 */
	/* The first item in pxCurrentTCB is the task top of stack. */
	ldr r1, [r3]	//r1=*r3=pxCurrentTCB,即新任务的TCB
	ldr r0, [r1]	//r0=*r1=pxTopOfStack,即新任务的栈顶指针

	/* Pop the core registers. */
	ldmia r0!, {r4-r11}	//将新任务的任务栈数据加载入cpu寄存器r4-r11
    
    /* 更新psp的值,等PendSV退出时,会以psp作为基地址,将任务栈中剩下的内容自动加载到CPU寄存器 */
    /* 剩下的内容包括: xPSR、PC、LR、r12、r3、r2、r1、r0 */
	msr psp, r0
	isb
	bx r14	//中断结束返回
}

五.xPortSysTickHandler

xPortSysTickHandler是一个定时中断服务函数,默认为1ms触发一次。在FreeRTOS中,它被用作触发PendSV中断,实际的任务切换在PendSV_Handler函数中执行。
移植参考如下:

点击查看代码
void SysTick_Handler(void)
{
	lv_tick_inc(1);
	swm_inctick();
	if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
	{
		xPortSysTickHandler();
	}
	
}

标签:r0,FreeRtos,pxCurrentTCB,r3,中断,ldr,任务,移植
From: https://www.cnblogs.com/Charles-Hui/p/18504215

相关文章

  • FreeRTOS学习——临界段代码保护及调度器挂起与恢复及其API函数内部实现详解
    FreeRTOS临界段代码保护及调度器挂起与恢复FreeRTOS临界段代码保护及调度器挂起与恢复临界保护区任务调度器挂起与恢复使用格式特点函数内部实现**vTaskSuspendAll();****==总结==**:xTaskResumeAll();FreeRTOS临界段代码保护及调度器挂起与恢复临界保护区什么......
  • 【北京迅为】i.mx8mm嵌入式linux开发指南第四篇 嵌入式Linux系统移植篇第六十九章uboo
      迅为i.mx8mm开发板特点: 性能强:i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核,主频高达1.8GHz,2GDDR4内存、8GEMMC存储。 PMIC:采用PCA9450A电源管理,是NXP全新研制配套iMX.8M的电源管理芯片,有六个......
  • FreeRTOS:任务
    目录一、简介二、任务栈三、任务控制块四、任务状态五、任务调度 五、任务间的通信六、相关API 一、简介    在裸机系统中,系统的主体就是main函数里面顺序执行的无限循环,这个无限循环里面,CPU按照顺序执行代码。在多任务系统中,我们根据功能的不同,把整......
  • 移植 CPAN 包
    安装Perl前往CPAN.org下载Perl源码包。安装:wgethttps://www.cpan.org/src/5.0/perl-5.40.0.tar.gztar-xzfperl-5*.tar.gzcdperl-5*./Configure-des-Dprefix=$HOME/.localmake-j$(nproc)makeinstall设置环境变量:exportPATH="$HOME/.local/bin:$PATH"expo......
  • 【TFT彩屏移植】STM32F4移植1.8寸TFT彩屏简明教程
    目录一.移植说明二.移植1.例程    物理接口:    延时函数:     底层驱动文件:    GUI界面文件:    测试demo:2.移植至F4创建工程:        调试接口选择SW:        RCC中HSE选择外部晶振:        GPIO配......
  • FreeRTOS - 任务调度
    在学习FreeRTOS过程中,结合韦东山-FreeRTOS手册和视频、野火-FreeRTOS内核实现与应用开发、及网上查找的其他资源,整理了该篇文章。如有内容理解不正确之处,欢迎大家指出,共同进步。1.任务的调度机制(核心是链表)使用链表来管理任务谁进行调度?TICK中断!每隔固定时间,会产生......
  • FreeRTOS - 任务管理
    在学习FreeRTOS过程中,结合韦东山-FreeRTOS手册和视频、野火-FreeRTOS内核实现与应用开发、及网上查找的其他资源,整理了该篇文章。如有内容理解不正确之处,欢迎大家指出,共同进步。参考:https://rtos.100ask.net/zh/FreeRTOS/DShanMCU-F103/chapter9.html#_9-5-%E7%A4%BA%E4%......
  • FreeRTOS - 队列
    在学习FreeRTOS过程中,结合韦东山-FreeRTOS手册和视频、野火-FreeRTOS内核实现与应用开发、及网上查找的其他资源,整理了该篇文章。如有内容理解不正确之处,欢迎大家指出,共同进步。1.队列1.1队列基本概念队列(queue)可以用于"任务到任务"、“任务到中断”、"中断到任务"......
  • docker以及nvidia-docker的安装、移植以及使用案例
    详细描述docker、nvidia-docker的安装步骤,通过案例描述docker的基本使用命令,包含docker创建、移植、加载等。文档真实案例编写,亲测可用,傻瓜式教程,直接复制即可成功安装。默认已经安装显卡驱动。一、docker的安装#由于apt官方库里的docker版本可能比较旧,所以先卸载可能......
  • FreeRTOS:消息队列
    目录一、简介二、特点三、消息队列控制块四、相关API五、使用场景 一、简介        FreeRTOS的消息队列(MessageQueue)是任务之间通信的一种常用机制,允许任务或中断将数据发送到队列中,其他任务从队列中读取数据。        消息队列在嵌入式实时操作......