发新帖我要提问
12
返回列表
打印

GD 32 Trochili RTOS 移植

[复制链接]
楼主: chenqiang10
手机看帖
扫描二维码
随时随地手机跟帖
21
chenqiang10|  楼主 | 2018-10-27 12:02 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
线程优先级计算函数
函数 uCpuCalcHiPRIO()通过 RBIT和 CLZ指令来加速计算线程队列中的最高线程优先级。
内核与处理器接口函数
函数 uCpuInit()完成处理器初始化,主要是设置主频和系统心跳时钟中断.该函数首先设
置 Systick 参数,使得处理器硬件时钟 Systick 按照指定频率发出中断,目前在 GD32F10x 处
理器上是按照 72M 处理器频率和每 10 毫秒一次定时器中断来设置的。

使用特权

评论回复
22
chenqiang10|  楼主 | 2018-10-27 12:04 | 只看该作者
内核启动流程
这里我们结合代码和注释来分析内核是如何启动的。内核启动函数在文件 kernel.c 中。

使用特权

评论回复
23
chenqiang10|  楼主 | 2018-10-27 12:05 | 只看该作者
该函数具体代码如下:
void xKernelStart(TUserEntry pUserEntry,
TCpuSetupEntry pCpuEntry,
TBoardSetupEntry pBoardEntry,
TTraceEntry pTraceEntry)
{
TReg32 imask;
CpuEnterCritical(&imask);
/* 初始化基本内核参数 */
memset(&uKernelVariable, 0, sizeof(uKernelVariable));
uKernelVariable.UserEntry = pUserEntry;
uKernelVariable.CpuSetupEntry = pCpuEntry;
uKernelVariable.BoardSetupEntry = pBoardEntry;
uKernelVariable.TraceEntry = pTraceEntry;
uKernelVariable.Schedulable = eTrue;
/* 初始化所有内核模块 */
uThreadModuleInit(); /* 初始化线程管理模块 */
#if (TCL_TIMER_ENABLE)
uTimerModuleInit(); /* 初始化定时器模块 */
#endif
#if (TCL_IRQ_ENABLE)
uIrqModuleInit(); /* 初始化中断管理模块 */
#endif
/* 初始化内核线程并且激活 */
InitIdleDaemon(); /* 初始化内核 IDLE 线程并且激活
*/#if ((TCL_TIMER_ENABLE) && (TCL_TIMER_DAEMON_ENABLE))
uTimerInitDaemon(); /* 初始化内核定时器线程并且激活
*/
#endif
#if ((TCL_IRQ_ENABLE) && (TCL_IRQ_DAEMON_ENABLE))
uIrqInitDaemon(); /* 初始化内核 IRQ 线程并且激活
*/
#endif
uKernelVariable.CpuSetupEntry(); /* 调用处理器和板级初始化函数
*/
uKernelVariable.BoardSetupEntry(); /* 调用处理器和板级初始化函数
*/
CpuLoadIdleThread(); /* 启动内核 IDLE 线程
*/
CpuLeaveCritical(imask);
while (eTrue)
{
uDebugPanic("", __FILE__, __FUNCTION__, __LINE__);
}
}


使用特权

评论回复
24
chenqiang10|  楼主 | 2018-10-27 12:05 | 只看该作者
在内核启动之前,必须注册用户应用程序入口函数。用户可以在这个函数里初始化应用线程,对 BSP 和设备进行初始化。

使用特权

评论回复
25
chenqiang10|  楼主 | 2018-10-27 12:06 | 只看该作者
Trochili 多线程编程
下面代码演示了如何注册一个恰当的用户应用函数。
#include "example.h"
#include "trochili.h"
#if (EVB_EXAMPLE == CH13_BOARD_TEST_EXAMPLE)
/* 用户线程参数 */
#define THREAD_LED_STACK_BYTES (512)
#define THREAD_LED_PRIORITY (5)
#define THREAD_LED_SLICE (20)




使用特权

评论回复
26
chenqiang10|  楼主 | 2018-10-27 12:07 | 只看该作者
用户线程定义
/* 用户线程栈定义 */
static TWord ThreadLedStack[THREAD_LED_STACK_BYTES/4];/* 用户线程定义 */
static TThread ThreadLed;


使用特权

评论回复
27
chenqiang10|  楼主 | 2018-10-27 12:07 | 只看该作者
用户定时器结构
/* 用户定时器结构 */
static TTimer LedTimer;




使用特权

评论回复
28
chenqiang10|  楼主 | 2018-10-27 12:15 | 只看该作者
线程做无用操作,起到空转效果

/* 线程做无用操作,起到空转效果 */
static delay(TWord count)
{
while(count --);
}


使用特权

评论回复
29
chenqiang10|  楼主 | 2018-10-27 12:16 | 只看该作者

用户定时器 1 的回调函数  

/* 用户定时器 1 的回调函数,间隔 1 秒,点亮或熄灭 Led1 */
static void Blink(TArgument data)
{
static int index = 0;
if (index % 2)
{
EvbLedControl(LED1, LED_OFF);
EvbLedControl(LED2, LED_OFF);
}
else
{
EvbLedControl(LED1, LED_ON);
EvbLedControl(LED2, LED_ON);
}
index++;
}


使用特权

评论回复
30
chenqiang10|  楼主 | 2018-10-27 12:17 | 只看该作者
按键中断处理函数
/* 评估板按键中断处理函数 */
static TBitMask EvbKeyISR(TArgument data)
{
TState state;
TError error;
static TWord index = 1;
if (EvbKeyScan())
{
if (index % 2)
{
/* 启动用户定时器 */state = TclStartTimer(&LedTimer, 0U, &error);
TCL_ASSERT((state == eSuccess), "");
TCL_ASSERT((error == TCLE_TIMER_NONE), "");
}
else
{
/* 关闭用户定时器 */
state = TclStopTimer(&LedTimer, &error);
TCL_ASSERT((state == eSuccess), "");
TCL_ASSERT((error == TCLE_TIMER_NONE), "");
}
index++;
}
return TCLR_IRQ_DONE;
}




使用特权

评论回复
31
chenqiang10|  楼主 | 2018-10-27 12:18 | 只看该作者
Led 线程的主函数
/* Led 线程的主函数 */
static void ThreadLedEntry(TArgument data)
{
while (eTrue)
{
delay(0x4fffff);
EvbLedControl(LED3, LED_ON);
TclTrace("LED3 ON\r\n");
delay(0x4fffff);
EvbLedControl(LED3, LED_OFF);
TclTrace("LED3 OFF\r\n");
}
}




使用特权

评论回复
32
chenqiang10|  楼主 | 2018-10-27 12:18 | 只看该作者
用户应用程序入口函数
/* 用户应用程序入口函数 */
static void AppSetupEntry(void)
{
TState state;
TError error;
/* 设置和 KEY 相关的外部中断向量 */
state = TclSetIrqVector(KEY_IRQ_ID, &EvbKeyISR, (TArgument)0,
(TThread*)0, &error);
TCL_ASSERT((state == eSuccess), "");
TCL_ASSERT((error == TCLE_IRQ_NONE), "");/* 初始化用户定时器 */
state = TclInitTimer(&LedTimer, TCLP_TIMER_PERIODIC,
TCL_MLS2TICKS(1000), &Blink, (TArgument)0,
&error);
TCL_ASSERT((state == eSuccess), "");
TCL_ASSERT((error == TCLE_TIMER_NONE), "");
/* 初始化 Led 线程 */
state = TclInitThread(&ThreadLed,
&ThreadLedEntry, (TArgument)0,
ThreadLedStack, THREAD_LED_STACK_BYTES,
THREAD_LED_PRIORITY, THREAD_LED_SLICE,
&error);
TCL_ASSERT((state == eSuccess), "");
TCL_ASSERT((error == TCLE_THREAD_NONE), "");
/* 激活 Led 线程 */
state = TclActivateThread(&ThreadLed, &error);
TCL_ASSERT((state == eSuccess), "");
TCL_ASSERT((error == TCLE_THREAD_NONE), "");
}




使用特权

评论回复
33
chenqiang10|  楼主 | 2018-10-27 12:19 | 只看该作者
main 函数
/* 处理器 BOOT 之后会调用 main 函数,必须提供 */
int main(void)
{
/* 注册各个内核函数,启动内核 */
TclStartKernel(&AppSetupEntry,
&CpuSetupEntry,
&EvbSetupEntry,
&EvbTraceEntry);
return 1;
}




使用特权

评论回复
34
chenqiang10|  楼主 | 2018-10-27 12:19 | 只看该作者
函数 AppSetupEntry ()就是所说的用户应用程序入口函数,在该函数里,我们初始化了 LED 和 KEY 设备,通过内核接管了 KEY 的中断处理,然后初始化了一个定
时器,最后将 LED 线程激活

使用特权

评论回复
35
chenqiang10|  楼主 | 2018-10-27 12:20 | 只看该作者
这个函数注册到内核后,在内核启动过程中被调用,在这之后,内核将通过 IDLE 线程启动多任务。因为 IDLE 线程优先级最低,所以 LED 线程随即抢占 IDLE
线程,用户程序开始执行。

使用特权

评论回复
36
chenqiang10|  楼主 | 2018-10-27 12:21 | 只看该作者
这次在GD32上移植RTOS 就到这里。

使用特权

评论回复
37
caijie001| | 2018-10-27 22:28 | 只看该作者
rtos的源码呢

使用特权

评论回复
38
戏如人生8| | 2018-10-28 14:25 | 只看该作者
赞一个

使用特权

评论回复
39
stm32jy| | 2018-10-29 20:58 | 只看该作者
感谢分享,这个操作系统还没玩过

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则