FreeRTOS 移植要点(2)
port.c port.c 中主要实现了几个函数: pxPortInitialiseStack() xPortStartScheduler() vPortEndScheduler() vPortYield() vPortTickInterrupt() 还定义了个全局变量:uxCriticalNesting uxCriticalNesting 定义全局变量uxCriticalNesting 的代码如下。 /*
port.c
port.c 中主要实现了几个函数:
pxPortInitialiseStack()
xPortStartScheduler()
vPortEndScheduler()
vPortYield()
vPortTickInterrupt()
还定义了个全局变量:uxCriticalNesting
uxCriticalNesting
定义全局变量uxCriticalNesting 的代码如下。
/* Calls to portENTER_CRITICAL() can be nested. When they are nested the critical div should not be left (i.e. interrupts should not be re-enabled) until the nesting depth reaches 0. This variable simply tracks the nesting depth. Each task maintains it's own critical nesting depth variable so uxCriticalNesting is saved and restored from the task stack during a context switch. */ volatile unsigned portBASE_TYPE uxCriticalNesting = 0xff;
uxCriticalNesting 的初始值并不重要,因为每个任务的堆栈中存了uxCriticalNesting 各自的初始值0。
pxPortInitialiseStack
第一个介绍的是pxPortInitialiseStack()。这个函数的作用与uC/OS-II 中 OS_STK*OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt) 函数的作用是相同的,实现代码也大同小异。
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) { /* Place a few bytes of known values on the bottom of the stack. This can be uncommented to provide useful stack markers when debugging. *pxTopOfStack = ( portSTACK_TYPE ) 0x11; pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) 0x22; pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) 0x33; pxTopOfStack--; */ /* Setup the initial stack of the task. The stack is set exactly as expected by the portRESTORE_CONTEXT() macro. In this case the stack as expected by the HCS12 RTI instruction. */ /* The address of the task function is placed in the stack byte at a time. */ *pxTopOfStack = ( portSTACK_TYPE ) *( ((portSTACK_TYPE *) (&pxCode) ) + 1 ); pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) *( ((portSTACK_TYPE *) (&pxCode) ) + 0 ); pxTopOfStack--; /* Next are all the registers that form part of the task context. */ /* Y register */ *pxTopOfStack = ( portSTACK_TYPE ) 0xff; pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) 0xee; pxTopOfStack--; /* X register */ *pxTopOfStack = ( portSTACK_TYPE ) 0xdd; pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) 0xcc; pxTopOfStack--; /* A register contains parameter high byte. */ *pxTopOfStack = ( portSTACK_TYPE ) *( ((portSTACK_TYPE *) (&pvParameters) ) + 0 ); pxTopOfStack--; /* B register contains parameter low byte. */ *pxTopOfStack = ( portSTACK_TYPE ) *( ((portSTACK_TYPE *) (&pvParameters) ) + 1 ); pxTopOfStack--; /* CCR: Note that when the task starts interrupts will be enabled since "I" bit of CCR is cleared */ *pxTopOfStack = ( portSTACK_TYPE ) 0x00; pxTopOfStack--; #ifdef BANKED_MODEL /* The page of the task. */ *pxTopOfStack = ( portSTACK_TYPE ) ( ( int ) pxCode ); pxTopOfStack--; #endif /* Finally the critical nesting depth is initialised with 0 (not within a critical div). */ *pxTopOfStack = ( portSTACK_TYPE ) 0x00; return pxTopOfStack; }
xPortStartScheduler
xPortStartScheduler()函数对应于uC/OS-II 中的OSStartHighRdy() 函数。FreeRTOS的移植代码中并没有直接在xPortStartScheduler() 函数中实现具体功能,而是将真正的工作放到了xBankedStartScheduler()函数中,xPortStartScheduler()函数只是简单的调用xBankedStartScheduler()函数。之所以这样处理是因为相应的代码需放到64K以内的地址空间中。具体可以参看下面代码中的注释部分。
#pragma CODE_SEG __NEAR_SEG NON_BANKED /* Simply called by xPortStartScheduler(). xPortStartScheduler() does not start the scheduler directly because the header file containing the xPortStartScheduler() prototype is part of the common kernel code, and therefore cannot use the CODE_SEG pragma. */ static portBASE_TYPE xBankedStartScheduler( void ); #pragma CODE_SEG DEFAULT portBASE_TYPE xPortStartScheduler( void ) { /* xPortStartScheduler() does not start the scheduler directly because the header file containing the xPortStartScheduler() prototype is part of the common kernel code, and therefore cannot use the CODE_SEG pragma. Instead it simply calls the locally defined xBankedStartScheduler() - which does use the CODE_SEG pragma. */ return xBankedStartScheduler(); } /*-----------------------------------------------------------*/ #pragma CODE_SEG __NEAR_SEG NON_BANKED static portBASE_TYPE xBankedStartScheduler( void ) { /* Configure the timer that will generate the RTOS tick. Interrupts are disabled when this function is called. */ prvSetupTimerInterrupt(); /* Restore the context of the first task. */ portRESTORE_CONTEXT(); /* Simulate the end of an interrupt to start the scheduler off. */ __asm( "rti" ); /* Should not get here! */ return pdFALSE; }
上面代码中调用了prvSetupTimerInterrupt() 函数,这在 uC/OS-II中是没有对应代码的。prvSetupTimerInterrupt()函数的功能是设置定时中断的频率。在这里放这个函数从程序逻辑上来看并不是太好。我本人还是倾向于uC/OS-II 作者的做法,应该将prvSetupTimerInterrupt() 函数放到第一个运行的任务的代码中,虽然这里的做法也没错误。
vPortEndScheduler
这个函数在uC/OS-II 没有对应的函数,因为uC/OS-II 不允许退出。这个移植代码中也没有实现什么具体的功能,就是个空函数。
void vPortEndScheduler( void ) { /* It is unlikely that the HCS12 port will get stopped. */ }
vPortYield
vPortYield()函数等价于uC/OS-II 中的OSCtxSw()函数。具体代码如下:
/* * Manual context switch forced by calling portYIELD(). This is the SWI * handler. */ void interrupt vPortYield( void ) { portSAVE_CONTEXT(); vTaskSwitchContext(); portRESTORE_CONTEXT(); }
FreeRTOS中少了与 uC/OS-II 中 OSIntCtxSw()函数对应的函数,这时因为FreeRTOS 中相应的功能用一个宏定义来实现了:portRESTORE_CONTEXT() ,因此就不需要这个函数了。
vPortTickInterrupt()
最后一个函数是vPortTickInterrupt() 这个函数是定时中断处理函数,等价于uC/OS-II 移植代码中的:interrupt VectorNumber_Vrti void OSTickISR (void)
由于 FreeRTOS既支持抢占式多任务,也支持协作式多任务,所以vPortTickInterrupt()函数相对uC/OS-II 移植代码中的OSTickISR()来说要复杂些。
/* * RTOS tick interrupt service routine. If the cooperative scheduler is * being used then this simply increments the tick count. If the * preemptive scheduler is being used a context switch can occur. */ void interrupt vPortTickInterrupt( void ) { #if configUSE_PREEMPTION == 1 { /* A context switch might happen so save the context. */ portSAVE_CONTEXT(); /* Increment the tick ... */ vTaskIncrementTick(); /* ... then see if the new tick value has necessitated a context switch. */ vTaskSwitchContext(); TFLG1 = 1; /* Restore the context of a task - which may be a different task to that interrupted. */ portRESTORE_CONTEXT(); } #else { vTaskIncrementTick(); TFLG1 = 1; } #endif }
至此,所有移植代码就都分析完了。
实时操作系统内核其实都大同小异,掌握了一种再学习其余的很容易就能入门。从入门难度来说,uC/OS-II无疑是入门学习的首选。之所以这么说并不是因为uC/OS-II本身很简单,而是国内介绍uC/OS-II的资料非常多。相比起来,介绍FreeRTOS的资料就少的可怜了。我建议想要学习FreeRTOS的人还是应该先学习uC/OS-II,学懂了uC/OS-II,然后对比着学习FreeRTOS,这样会事半功倍。这也是我学习FreeRTOS的路径。

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



How to implement dual WeChat login on Huawei mobile phones? With the rise of social media, WeChat has become one of the indispensable communication tools in people's daily lives. However, many people may encounter a problem: logging into multiple WeChat accounts at the same time on the same mobile phone. For Huawei mobile phone users, it is not difficult to achieve dual WeChat login. This article will introduce how to achieve dual WeChat login on Huawei mobile phones. First of all, the EMUI system that comes with Huawei mobile phones provides a very convenient function - dual application opening. Through the application dual opening function, users can simultaneously

The programming language PHP is a powerful tool for web development, capable of supporting a variety of different programming logics and algorithms. Among them, implementing the Fibonacci sequence is a common and classic programming problem. In this article, we will introduce how to use the PHP programming language to implement the Fibonacci sequence, and attach specific code examples. The Fibonacci sequence is a mathematical sequence defined as follows: the first and second elements of the sequence are 1, and starting from the third element, the value of each element is equal to the sum of the previous two elements. The first few elements of the sequence

How to implement the WeChat clone function on Huawei mobile phones With the popularity of social software and people's increasing emphasis on privacy and security, the WeChat clone function has gradually become the focus of people's attention. The WeChat clone function can help users log in to multiple WeChat accounts on the same mobile phone at the same time, making it easier to manage and use. It is not difficult to implement the WeChat clone function on Huawei mobile phones. You only need to follow the following steps. Step 1: Make sure that the mobile phone system version and WeChat version meet the requirements. First, make sure that your Huawei mobile phone system version has been updated to the latest version, as well as the WeChat App.

In today's software development field, Golang (Go language), as an efficient, concise and highly concurrency programming language, is increasingly favored by developers. Its rich standard library and efficient concurrency features make it a high-profile choice in the field of game development. This article will explore how to use Golang for game development and demonstrate its powerful possibilities through specific code examples. 1. Golang’s advantages in game development. As a statically typed language, Golang is used in building large-scale game systems.

Implementing exact division operations in Golang is a common need, especially in scenarios involving financial calculations or other scenarios that require high-precision calculations. Golang's built-in division operator "/" is calculated for floating point numbers, and sometimes there is a problem of precision loss. In order to solve this problem, we can use third-party libraries or custom functions to implement exact division operations. A common approach is to use the Rat type from the math/big package, which provides a representation of fractions and can be used to implement exact division operations.

PHP Game Requirements Implementation Guide With the popularity and development of the Internet, the web game market is becoming more and more popular. Many developers hope to use the PHP language to develop their own web games, and implementing game requirements is a key step. This article will introduce how to use PHP language to implement common game requirements and provide specific code examples. 1. Create game characters In web games, game characters are a very important element. We need to define the attributes of the game character, such as name, level, experience value, etc., and provide methods to operate these

I'm really sorry that I can't provide real-time programming guidance, but I can provide you with a code example to give you a better understanding of how to use PHP to implement SaaS. The following is an article within 1,500 words, titled "Using PHP to implement SaaS: A comprehensive analysis." In today's information age, SaaS (Software as a Service) has become the mainstream way for enterprises and individuals to use software. It provides a more flexible and convenient way to access software. With SaaS, users don’t need to be on-premises

Title: Detailed explanation of data export function using Golang. With the improvement of informatization, many enterprises and organizations need to export data stored in databases into different formats for data analysis, report generation and other purposes. This article will introduce how to use the Golang programming language to implement the data export function, including detailed steps to connect to the database, query data, and export data to files, and provide specific code examples. To connect to the database first, we need to use the database driver provided in Golang, such as da
