RH850F1L 移植freeRTOS

学习基于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->pxTopOfStack
    ld.w 0[r2], r2
    ld.w 0[r2], sp

    popsp r20 - r29                     # Restore General Purpose Register (callee save register)

    popsp r6 - r7
    ldsr r7, EIPC                       # Restore EIPC
    ldsr r6, EIPSW                      # Restore EIPSW

    popsp r1 - r2                       # Restore General Purpose Register (caller save register)
    popsp r6 - r19

	dispose 0, {ep, lp}

    eiret

4、任务切换task yield

_vPortYieldHandler:

    prepare {ep, lp}, 0

    pushsp r6 - r19                     # Save General Purpose Register (caller save register)
    pushsp r1 - r2

    stsr EIPSW, r6                      # Save EIPSW
    stsr EIPC, r7                       # Save EIPC
    pushsp r6 - r7

    pushsp r20 - r29                    # Save General Purpose Register (callee save register)

    mov _pxCurrentTCB, r2               # pxCurrentTCB->pxTopOfStack = SP
    ld.w 0[r2], r2
    st.w sp, 0[r2]

    jarl _vTaskSwitchContext, lp

    mov _pxCurrentTCB, r2               # SP = pxCurrentTCB->pxTopOfStack
    ld.w 0[r2], r2
    ld.w 0[r2], sp

    popsp r20 - r29                     # Restore General Purpose Register (callee save register)

    popsp r6 - r7
    ldsr r7, EIPC                       # Restore EIPC
    ldsr r6, EIPSW                      # Restore EIPSW

    popsp r1 - r2                       # Restore General Purpose Register (caller save register)
    popsp r6 - r19

    dispose 0, {ep, lp}

    eiret

5 tick 任务调度

_vISRWrapper:
    prepare {ep, lp}, 0

    pushsp r6 - r19                     # Save General Purpose Register (caller save register)
    pushsp r1 - r2

    stsr EIPSW, r6                      # Save EIPSW
    stsr EIPC, r7                       # Save EIPC
    pushsp r6 - r7

	//pushsp r20 - r30					#		  Save General Purpose Register (callee save register)

    mov _xInterruptNesting, r6
    ld.w 0[r6], r7
    cmp 0x0, r7                         # if ( xInterruptNesting == 0 )
    bne aa                              # {
    mov _pxCurrentTCB, r2               #     pxCurrentTCB->pxTopOfStack = SP
    ld.w 0[r2], r2                      #     SP = MainStackTop
    st.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 Cause

    ei                                  # Enable interrupt (enable interrupt nesting)
    jarl _vISRHandler, lp               # Call the ISR Handler
    di                                  # Disable interrupt (disable interrupt nesting)


    mov _xInterruptNesting, r6
    ld.w 0[r6], r7
    cmp 0x0, r7                         # if ( xInterruptNesting > 0 )
    be bb                               # {
    add -1, r7                          #     xInterruptNesting--
    st.w r7, 0[r6]                      # }
bb:
    cmp 0x0, r7
    bne dd                              # if ( xInterruptNesting == 0 )
    mov _xPortSwitchRequired, r6        # {
    ld.w 0[r6], r7                      #     if ( xPortSwitchRequired )
    cmp 0x0, r7                         #     {
    be cc
    st.w r0, 0[r6]                      #         xPortSwitchRequired = pdFALSE

    mov _pxCurrentTCB, r2               #         SP = pxCurrentTCB->pxTopOfStack
    ld.w 0[r2], r2
    ld.w 0[r2], sp

    pushsp r20 - r29                    #         Save General Purpose Register (callee save register)
    st.w sp, 0[r2]                      #         pxCurrentTCB->pxTopOfStack = SP

    jarl _vTaskSwitchContext, lp        #         vTaskSwitchContext()

    mov _pxCurrentTCB, r2               #         SP = pxCurrentTCB->pxTopOfStack
    ld.w 0[r2], r2
    ld.w 0[r2], sp

    popsp r20 - r29                     #         Restore General Purpose Register (callee save register)

    jr dd                               #     }
cc:                                     #     else
    mov _pxCurrentTCB, r2               #     {
    ld.w 0[r2], r2                      #         SP = pxCurrentTCB->pxTopOfStack
    ld.w 0[r2], sp                      #     }
dd:                                     # }
	//popsp r20 - r30                     #         Restore General Purpose Register (callee save register)
    popsp r6 - r7
    ldsr r7, EIPC                       # Restore EIPC
    ldsr r6, EIPSW                      # Restore EIPSW

    popsp r1 - r2                       # Restore General Purpose Register (caller save register)
    popsp r6 - r19

    dispose 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

各路中断需要做相应的配置去使能哪一种。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值