学习基于GHS将freeRTOS移植到RH850 F1L的过程
移植过程参考github的一个教程,其中有部分修改优化,但是不多。
GitHub - mikisama/FreeRTOS_RH850: FreeRTOS port for Renesas RH850
支持gcc、ghs、ccrh、IAR 4种编译器。
有问题一起讨论,也可以直接按照github上的参考一步步移植。
freeRTOS下载
直接到官网下载即可
FreeRTOS - Free RTOS Source Code Downloads, the official FreeRTOS zip file release download
下载完成后,目录如下:

- 图片中的点c是RTOS的源文件,这些不用动,直接拿来用。
- portable中是平台依赖相关的文件,也是我们需要动手移植修改的。
- include文件是API接口文件,代码中使用的时候直接include对应文件即可
移植前准备
RH850 F1L这款芯片比较特殊,用的不是标准的ARM核,而是瑞萨自己开发的,这样对移植工作比较麻烦,特别是关于freeRTOS任务栈初始化、任务启动和切换,这些和mcu底层相关性大的地方,大部分需要查阅瑞萨官方资料。
freeRTOS从启动到开始任务调度之前需要完成下面几件事?
- 任务栈初始化
- 执行first task
- 任务切换(task yield)
- sys tick 任务调度(涉及任务状态的保存)
- OS无限循环任务调度
相应的MCU相关的配置有:
- 中断向量表配置
- sys tick中断配置
- 系统堆栈配置
移植
后面就直接把对应的移植过程一一总结
1、freeRTOS portable目录

展开MemMang和GHS(本人用的编译器)文件夹:


heap_4.c这个不用修改,GHS下面的三个文件需要移植
2、任务栈初始化
port.c中:
StackType_t *pxPortInitialiseStack( StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters )
{/* Simulate the stack frame as it would be created by a context switch* interrupt. */*( pxTopOfStack ) = ( StackType_t ) 0x30303030; /* R30 (EP) */*( --pxTopOfStack ) = ( StackType_t ) prvTaskExitError; /* R31 (LP) */*( --pxTopOfStack ) = ( StackType_t ) pvParameters; /* R6 */*( --pxTopOfStack ) = ( StackType_t ) 0x07070707; /* R7 */*( --pxTopOfStack ) = ( StackType_t ) 0x08080808; /* R8 */*( --pxTopOfStack ) = ( StackType_t ) 0x09090909; /* R9 */*( --pxTopOfStack ) = ( StackType_t ) 0x10101010; /* R10 */*( --pxTopOfStack ) = ( StackType_t ) 0x11111111; /* R11 */*( --pxTopOfStack ) = ( StackType_t ) 0x12121212; /* R12 */*( --pxTopOfStack ) = ( StackType_t ) 0x13131313; /* R13 */*( --pxTopOfStack ) = ( StackType_t ) 0x14141414; /* R14 */*( --pxTopOfStack ) = ( StackType_t ) 0x15151515; /* R15 */*( --pxTopOfStack ) = ( StackType_t ) 0x16161616; /* R16 */*( --pxTopOfStack ) = ( StackType_t ) 0x17171717; /* R17 */*( --pxTopOfStack ) = ( StackType_t ) 0x18181818; /* R18 */*( --pxTopOfStack ) = ( StackType_t ) 0x19191919; /* R19 */*( --pxTopOfStack ) = ( StackType_t ) 0x01010101; /* R1 */*( --pxTopOfStack ) = ( StackType_t ) 0x02020202; /* R2 */*( --pxTopOfStack ) = ( StackType_t ) portINITIAL_PSW; /* EIPSW */*( --pxTopOfStack ) = ( StackType_t ) pxCode; /* EIPC */*( --pxTopOfStack ) = ( StackType_t ) 0x20202020; /* R20 */*( --pxTopOfStack ) = ( StackType_t ) 0x21212121; /* R21 */*( --pxTopOfStack ) = ( StackType_t ) 0x22222222; /* R22 */*( --pxTopOfStack ) = ( StackType_t ) 0x23232323; /* R23 */*( --pxTopOfStack ) = ( StackType_t ) 0x24242424; /* R24 */*( --pxTopOfStack ) = ( StackType_t ) 0x25252525; /* R25 */*( --pxTopOfStack ) = ( StackType_t ) 0x26262626; /* R26 */*( --pxTopOfStack ) = ( StackType_t ) 0x27272727; /* R27 */*( --pxTopOfStack ) = ( StackType_t ) 0x28282828; /* R28 */*( --pxTopOfStack ) = ( StackType_t ) 0x29292929; /* R29 */return pxTopOfStack;
}
3、first task接口实现
_vPortStartFirstTask:mov _pxCurrentTCB, r2 # SP = pxCurrentTCB->pxTopOfStackld.w 0[r2], r2ld.w 0[r2], sppopsp r20 - r29 # Restore General Purpose Register (callee save register)popsp r6 - r7ldsr r7, EIPC # Restore EIPCldsr r6, EIPSW # Restore EIPSWpopsp r1 - r2 # Restore General Purpose Register (caller save register)popsp r6 - r19dispose 0, {ep, lp}eiret
4、任务切换task yield
_vPortYieldHandler:prepare {ep, lp}, 0pushsp r6 - r19 # Save General Purpose Register (caller save register)pushsp r1 - r2stsr EIPSW, r6 # Save EIPSWstsr EIPC, r7 # Save EIPCpushsp r6 - r7pushsp r20 - r29 # Save General Purpose Register (callee save register)mov _pxCurrentTCB, r2 # pxCurrentTCB->pxTopOfStack = SPld.w 0[r2], r2st.w sp, 0[r2]jarl _vTaskSwitchContext, lpmov _pxCurrentTCB, r2 # SP = pxCurrentTCB->pxTopOfStackld.w 0[r2], r2ld.w 0[r2], sppopsp r20 - r29 # Restore General Purpose Register (callee save register)popsp r6 - r7ldsr r7, EIPC # Restore EIPCldsr r6, EIPSW # Restore EIPSWpopsp r1 - r2 # Restore General Purpose Register (caller save register)popsp r6 - r19dispose 0, {ep, lp}eiret
5 tick 任务调度
_vISRWrapper:prepare {ep, lp}, 0pushsp r6 - r19 # Save General Purpose Register (caller save register)pushsp r1 - r2stsr EIPSW, r6 # Save EIPSWstsr EIPC, r7 # Save EIPCpushsp r6 - r7//pushsp r20 - r30 # Save General Purpose Register (callee save register)mov _xInterruptNesting, r6ld.w 0[r6], r7cmp 0x0, r7 # if ( xInterruptNesting == 0 )bne aa # {mov _pxCurrentTCB, r2 # pxCurrentTCB->pxTopOfStack = SPld.w 0[r2], r2 # SP = MainStackTopst.w sp, 0[r2] # }mov ___ghsend_stack, sp
aa:add 0x1, r7 # xInterruptNesting++st.w r7, 0[r6]stsr EIIC, r6 # Save EI level Interrupt Causeei # Enable interrupt (enable interrupt nesting)jarl _vISRHandler, lp # Call the ISR Handlerdi # Disable interrupt (disable interrupt nesting)mov _xInterruptNesting, r6ld.w 0[r6], r7cmp 0x0, r7 # if ( xInterruptNesting > 0 )be bb # {add -1, r7 # xInterruptNesting--st.w r7, 0[r6] # }
bb:cmp 0x0, r7bne dd # if ( xInterruptNesting == 0 )mov _xPortSwitchRequired, r6 # {ld.w 0[r6], r7 # if ( xPortSwitchRequired )cmp 0x0, r7 # {be ccst.w r0, 0[r6] # xPortSwitchRequired = pdFALSEmov _pxCurrentTCB, r2 # SP = pxCurrentTCB->pxTopOfStackld.w 0[r2], r2ld.w 0[r2], sppushsp r20 - r29 # Save General Purpose Register (callee save register)st.w sp, 0[r2] # pxCurrentTCB->pxTopOfStack = SPjarl _vTaskSwitchContext, lp # vTaskSwitchContext()mov _pxCurrentTCB, r2 # SP = pxCurrentTCB->pxTopOfStackld.w 0[r2], r2ld.w 0[r2], sppopsp r20 - r29 # Restore General Purpose Register (callee save register)jr dd # }
cc: # elsemov _pxCurrentTCB, r2 # {ld.w 0[r2], r2 # SP = pxCurrentTCB->pxTopOfStackld.w 0[r2], sp # }
dd: # }//popsp r20 - r30 # Restore General Purpose Register (callee save register)popsp r6 - r7ldsr r7, EIPC # Restore EIPCldsr r6, EIPSW # Restore EIPSWpopsp r1 - r2 # Restore General Purpose Register (caller save register)popsp r6 - r19dispose 0, {ep, lp}eiret
6 OS系统定时器配置
为OS提供心跳。
void ApiSysClkOstm0Init(uint32_t os_ticks)
{Os_Enable_OS_CPU_Ticks();ICOSTM0 = (0 << 12) | /* clear interrupt flag */(0 << 7) | /* unmask interrupt */#ifdef INT_VECT_EBASE_DIRECT//(0 << 6) | /* direct method */#else(1 << 6) | /* table reference method */#endif(0x7 << 0); /* interrupt priority lowest */OSTM0.CMP = (OSTM_PCLK / os_ticks) - 1;OSTM0.CTL = 0X01U;OSTM0.EMU = 0X00U;
}
7 中断配置
中断向量表地址索引有2种方法
Direct Vector Method和Table Reference Method
各路中断需要做相应的配置去使能哪一种。
















