久之前就想开始在博客上记录自己的嵌入式学习历程。虽然工作三四年了但感觉自己还是一个菜鸟。嵌入式上的操作系统虽然已经接触一年了但是却从来没有自己动手移植过,所以对于移植真的属于小白。看过别人的移植过程简述,感觉其实也就那么个事。但是真的到自己动手实践时却发现什么是理论与实践的差距。
通过两天的亲自动手操作,决定将自己的移植过程记录下来!
移植前的准备:1)硬件(MCU :NXP LPC1778)
2)UC/OS III源码 (来自野火ISO-系统进阶篇 )
3)NXP LCP1778库文件
开始:
其实系统移植主要的修改主要取决于:
1)编译环境(IAR与KEIL各不相同,尤其是在汇编指令的识别)
2)移植到的平台(ARM Cortex-M3 虽然LPC1778与STM32F107都属于M3 )
建立一个新的KEIL工程 ,工程框架如下图:
需修改的汇编文件 cpu_a.asm、os_cpu_a.asm、startup_LPC177x_8x.s
1) cpu_a.asm、os_cpu_a.asm
将public改为EXPORT
RSEG CODE:CODE:NOROOT(2)
THUMB
注释掉改为
PRESERVE8
AREA |.text|,CODE,READONLY
THUMB
```
将汇编文件中函数名称后的":"去掉
2) startup_LPC177x_8x.s文件中将PendSV_Handler改为 OS_CPU_PendSVHandler
修改配置文件 OS_cfg.h(此文件都是宏定义,主要是钩子函数、优先级及一些系统参数。裁剪内核可以通过此处修改)
ifndef OS_CFG_H
define OS_CFG_H
/* ---------------------------- MISCELLANEOUS -------------------------- */
define OS_CFG_APP_HOOKS_EN 0u /* Enable (1) or Disable (0) application specific hooks */
define OS_CFG_ARG_CHK_EN 1u /* Enable (1) or Disable (0) argument checking */
define OS_CFG_CALLED_FROM_ISR_CHK_EN 1u /* Enable (1) or Disable (0) check for called from ISR */
define OS_CFG_DBG_EN 1u /* Enable (1) debug code/variables */
define OS_CFG_ISR_POST_DEFERRED_EN 1u /* Enable (1) or Disable (0) Deferred ISR posts */
define OS_CFG_OBJ_TYPE_CHK_EN 0u /* Enable (1) or Disable (0) object type checking */
define OS_CFG_TS_EN 0u /* Enable (1) or Disable (0) time stamping */
define OS_CFG_PEND_MULTI_EN 1u /* Enable (1) or Disable (0) code generation for multi-pend feature */
define OS_CFG_PRIO_MAX 15u /* Defines the maximum number of task priorities (see OS_PRIO data type) */
define OS_CFG_SCHED_LOCK_TIME_MEAS_EN 0u /* Include code to measure scheduler lock time */
define OS_CFG_SCHED_ROUND_ROBIN_EN 1u /* Include code for Round-Robin scheduling */
define OS_CFG_STK_SIZE_MIN 64u /* Minimum allowable task stack size */
/* ----------------------------- EVENT FLAGS --------------------------- */
define OS_CFG_FLAG_EN 0u /* Enable (1) or Disable (0) code generation for EVENT FLAGS */
define OS_CFG_FLAG_DEL_EN 1u /* Include code for OSFlagDel() */
define OS_CFG_FLAG_MODE_CLR_EN 1u /* Include code for Wait on Clear EVENT FLAGS */
define OS_CFG_FLAG_PEND_ABORT_EN 1u /* Include code for OSFlagPendAbort() */
/* -------------------------- MEMORY MANAGEMENT ------------------------ */
define OS_CFG_MEM_EN 1u /* Enable (1) or Disable (0) code generation for MEMORY MANAGER */
/* --------------------- MUTUAL EXCLUSION SEMAPHORES ------------------- */
define OS_CFG_MUTEX_EN 0u /* Enable (1) or Disable (0) code generation for MUTEX */
define OS_CFG_MUTEX_DEL_EN 1u /* Include code for OSMutexDel() */
define OS_CFG_MUTEX_PEND_ABORT_EN 1u /* Include code for OSMutexPendAbort() */
/* --------------------------- MESSAGE QUEUES -------------------------- */
define OS_CFG_Q_EN 0u /* Enable (1) or Disable (0) code generation for QUEUES */
define OS_CFG_Q_DEL_EN 1u /* Include code for OSQDel() */
define OS_CFG_Q_FLUSH_EN 1u /* Include code for OSQFlush() */
define OS_CFG_Q_PEND_ABORT_EN 1u /* Include code for OSQPendAbort() */
/* ----------------------------- SEMAPHORES ---------------------------- */
define OS_CFG_SEM_EN 0u /* Enable (1) or Disable (0) code generation for SEMAPHORES */
define OS_CFG_SEM_DEL_EN 1u /* Include code for OSSemDel() */
define OS_CFG_SEM_PEND_ABORT_EN 1u /* Include code for OSSemPendAbort() */
define OS_CFG_SEM_SET_EN 1u /* Include code for OSSemSet() */
/* -------------------------- TASK MANAGEMENT -------------------------- */
define OS_CFG_STAT_TASK_EN 1u /* Enable (1) or Disable(0) the statistics task */
define OS_CFG_STAT_TASK_STK_CHK_EN 1u /* Check task stacks from statistic task */
define OS_CFG_TASK_CHANGE_PRIO_EN 0u /* Include code for OSTaskChangePrio() */
define OS_CFG_TASK_DEL_EN 1u /* Include code for OSTaskDel() */
define OS_CFG_TASK_Q_EN 0u /* Include code for OSTaskQXXXX() */
define OS_CFG_TASK_Q_PEND_ABORT_EN 1u /* Include code for OSTaskQPendAbort() */
define OS_CFG_TASK_PROFILE_EN 0u /* Include variables in OS_TCB for profiling */
define OS_CFG_TASK_REG_TBL_SIZE 1u /* Number of task specific registers */
define OS_CFG_TASK_SEM_PEND_ABORT_EN 0u /* Include code for OSTaskSemPendAbort() */
define OS_CFG_TASK_SUSPEND_EN 1u /* Include code for OSTaskSuspend() and OSTaskResume() */
/* -------------------------- TIME MANAGEMENT -------------------------- */
define OS_CFG_TIME_DLY_HMSM_EN 1u /* Include code for OSTimeDlyHMSM() */
define OS_CFG_TIME_DLY_RESUME_EN 1u /* Include code for OSTimeDlyResume() */
/* ------------------------- TIMER MANAGEMENT -------------------------- */
define OS_CFG_TMR_EN 0u /* Enable (1) or Disable (0) code generation for TIMERS */
define OS_CFG_TMR_DEL_EN 1u /* Enable (1) or Disable (0) code generation for OSTmrDel() */
endif
修改os_cpu.h 注释掉
OS_CPU_SysTickHandler(void);
OS_CPU_SysTickInit (CPU_INT32U cnts);
这两个函数是系统的滴答时间,但是M3中有滴答时间函数所以此处删掉即可,改用M3自带的系统滴答时间。虽然很简单,但是系统能否正常运行的滴答时间起到了主要的作用。
主函数`:
#include "LPC177x_8x.h"
#include "system_LPC177x_8x.h"
#include "lpc177x_8x_gpio.h"
#include "os_cfg_app.h"
#include "os.h"
#include "os_type.h"
// LPC1788¹¤×÷ÔÚ120MHZ£¬¾PLL·ÖƵºóµÄÍâÉèʱÖÓPeripheralClockΪ60MHZ
// 1msΪµ¥Î» 60000000/1000 = 60000
static OS_TCB LED_TCB;
static CPU_STK LED_Stk[128];
static void task1(void* p_arg);
void timer_init(void);
void BSP_Init(void);
void SysTick_init(void);
void BSP_Init(void)
{
GPIO_Init();
FIO_ByteSetDir(4,3,16,1);
SysTick_init();
}
void SysTick_init(void)
{
/* ³õʼ»¯²¢Ê¹ÄÜSysTick¶¨Ê±Æ÷ */
SysTick_Config(SystemCoreClock/OS_CFG_TICK_RATE_HZ);
/* ÅäÖÃ1ms ÖжÏÒ»´Î£¬¼´osµÄƵÂÊΪ1000hz */
if (SysTick_Config(SystemCoreClock/OS_CFG_TICK_RATE_HZ))
{
/* Capture error */
while (1);
}
}
void SysTick_Handler(void)
{
OSIntEnter(); //ÓÃÓÚͳ¼ÆÖжϵÄǶÌײãÊý£¬¶ÔǶÌײãÊý+1
OSTimeTick(); //ͳ¼ÆÊ±¼ä£¬±éÀúÈÎÎñ£¬¶ÔÑÓʱÈÎÎñ¼ÆÊ±¼õ1
OSIntExit(); //¶ÔǶÌײãÊý¼õ1£¬ÔÚÍ˳öÖжÏǰÆô¶¯ÈÎÎñµ÷¶È
}
void Task_LED(void *p_arg)
{
OS_ERR err;
(void)p_arg; // 'p_arg' ²¢Ã»ÓÐÓõ½£¬·ÀÖ¹±àÒëÆ÷Ìáʾ¾¯¸æ
while (1)
{
FIO_ByteClearValue(4, 3, 16);
OSTimeDly (200,OS_OPT_TIME_HMSM_STRICT,&err);
FIO_ByteSetValue(4, 3, 16);
OSTimeDly (200,OS_OPT_TIME_HMSM_STRICT,&err);
}
}
int main(void)
{
OS_ERR err;
SystemInit();
// SystemCoreClockUpdate();
/* ³õʼ»¯"uC/OS-III"ÄÚºË */
BSP_Init();
OSInit(&err);
/*´´½¨ÈÎÎñ*/
OSTaskCreate((OS_TCB *)&LED_TCB, // ÈÎÎñ¿ØÖÆ¿éÖ¸Õë
(CPU_CHAR *)"LED", // ÈÎÎñÃû³Æ
(OS_TASK_PTR )Task_LED, // ÈÎÎñ´úÂëÖ¸Õë
(void *)0, // ´«µÝ¸øÈÎÎñµÄ²ÎÊýparg
(OS_PRIO )2, // ÈÎÎñÓÅÏȼ¶
(CPU_STK *)&LED_Stk[0], // ÈÎÎñ¶ÑÕ»»ùµØÖ·
(CPU_STK_SIZE)12, // ¶ÑջʣÓྯ½äÏß
(CPU_STK_SIZE)128, // ¶ÑÕ»´óС
(OS_MSG_QTY )0, // ¿É½ÓÊÕµÄ×î´óÏûÏ¢¶ÓÁÐÊý
(OS_TICK )0, // ʱ¼äƬÂÖתʱ¼ä
(void *)0, // ÈÎÎñ¿ØÖÆ¿éÀ©Õ¹ÐÅÏ¢
(OS_OPT )(OS_OPT_TASK_STK_CHK |
OS_OPT_TASK_STK_CLR), // ÈÎÎñÑ¡Ïî
(OS_ERR *)&err); // ·µ»ØÖµ
/* Æô¶¯¶àÈÎÎñϵͳ£¬¿ØÖÆÈ¨½»¸øuC/OS-II */
OSStart(&err);
}
主函数中的6头文件是必须有的,函数里面运行的例程是将其他的例程直接复制过来改了改引脚定义而已。
上述工作做完基本上uC/OS 移植搞完了,但是在运行时发现进入OSTimeDly后任务一直处在空闲状态不能继续执行,看到网上说是由于系统的心跳时间有问题。但是不管怎么改还是不行。后来发现是因为
os_cfg_app.h中的
define OS_CFG_STAT_TASK_PRIO 11u /* Priority */
与os_cfg.h的
define OS_CFG_PRIO_MAX 15u /* Defines the maximum number of task priorities (see OS_PRIO data type) */
“`
有冲突。
OS_CFG_PRIO_MAX 定义了最大优先级数
所有任务的优先级数值不能比这个数值大。
虽然移植完成后uC/OS III 移植完成了,但是还是有很多搞不懂的地方。只能说照葫芦画瓢成功了。