Tc397 + hightec 编译器 移植 freertos


前言:autosar os 确实很强,但是我们在学习一些汽车软件的协议栈的时候,比如学习以太网协议栈,CAN 协议栈, 诊断等 相关知识的时候,需要os, 但是也不至于把os 搞一遍,这时候我们的开发环境就需要一个简单好用的操作系统。

于是我网上找了各种资源,也没找到找到tc397 + hightec 编译器的 freertos 说明。于是 自己做一个吧。

目录

Tc397 + hightec 编译器 移植 freertos


需要完整环境,可以在最下方打赏领取。谢谢,制作不易


背景

硬件编译环境

芯片:Aurix Tc39x

编译器:Hightec

移植 freertos 操作系统。

freertos git 地址

JSON                  
https://github.com/FreeRTOS/FreeRTOS-Kernel.git

Rtos 源码地址

也可以访问官网去下载,学习。

JSON                  
https://www.FreeRTOS.org                  
https://github.com/FreeRTOS

Tc397 + hightec 编译器 移植 freertos    

本文介绍 基于 硬件 aurix tc397 编译器 hightec 的环境 去移植 freertos.  内核版本

JSON                  
FreeRTOS Kernel V10.5.1

移植freertos项目

工程 代码目录结构

JSON                  
├─asw                  
├─Configurations                  
  └─Debug                  
├─Libraries                  
  ├─iLLD                  
    └─TC39B                  
        └─Tricore                  
            ├─Asclin                  
              ├─Asc                  
              ├─Lin                  
              ├─Spi                  
              └─Std                  
            ├─Can                  
              ├─Can                  
              └─Std                  
            ├─Ccu6                  
              ├─Icu                  
              ├─PwmBc                  
              ├─PwmHl                  
              ├─Std                  
              ├─Timer                  
              ├─TimerWithTrigger                  
              └─TPwm                  
            ├─Convctrl                  
              └─Std                  
            ├─Cpu                  
              ├─Irq                  
              ├─Std                  
              └─Trap                  
            ├─Dma                  
              ├─Dma                  
              └─Std                  
            ├─Dts                  
              ├─Dts                  
              └─Std                  
            ├─Ebu                  
              ├─BFlashSpansion                  
              ├─BFlashSt                  
              ├─Dram                  
              ├─Sram                  
              └─Std                  
            ├─Edsadc                  
              ├─Edsadc                  
              └─Std                  
            ├─Emem                  
              └─Std                  
            ├─Eray                  
              ├─Eray                  
              └─Std                  
            ├─Evadc                  
              ├─Adc                  
              └─Std                  
            ├─Fce                  
              ├─Crc                  
              └─Std                  
            ├─Flash                  
              └─Std                  
            ├─Geth                  
              ├─Eth                  
              └─Std                  
            ├─Gpt12                  
              ├─IncrEnc                  
              └─Std                  
            ├─Gtm                  
              ├─Atom                  
                ├─Dtm_PwmHl                  
                ├─Pwm                  
                ├─PwmHl                  
                └─Timer                  
              ├─Std                  
              ├─Tim                  
                ├─In                  
                └─Timer                  
              ├─Tom                  
                ├─Dtm_PwmHl                  
                ├─Pwm                  
                ├─PwmHl                  
                └─Timer                  
              └─Trig                  
            ├─Hspdm                  
              └─Std                  
            ├─Hssl                  
              ├─Hssl                  
              └─Std                  
            ├─I2c                  
              ├─I2c                  
              └─Std                  
            ├─Iom                  
              ├─Driver                  
              ├─Iom                  
              └─Std                  
            ├─Msc                  
              ├─Msc                  
              └─Std                  
            ├─Mtu                  
              └─Std                  
            ├─Pms                  
              └─Std                  
            ├─Port                  
              ├─Io                  
              └─Std                  
            ├─Psi5                  
              ├─Psi5                  
              └─Std                  
            ├─Psi5s                  
              ├─Psi5s                  
              └─Std                  
            ├─Qspi                  
              ├─SpiMaster                  
              ├─SpiSlave                  
              └─Std                  
            ├─Rif                  
              ├─Rif                  
              └─Std                  
            ├─Scu                  
              └─Std                  
            ├─Sdmmc                  
              ├─Emmc                  
              ├─Sd                  
              └─Std                  
            ├─Sent                  
              ├─Sent                  
              └─Std                  
            ├─Smu                  
              ├─Smu                  
              └─Std                  
            ├─Spu                  
              └─Std                  
            ├─Src                  
              └─Std                  
            ├─Stm                  
              ├─Std                  
              └─Timer                  
            ├─_Build                  
            ├─_Impl                  
            ├─_Lib                  
              ├─DataHandling                  
              └─InternalMux                  
            └─_PinMap                  
  ├─Infra                  
    ├─Platform                  
      └─Tricore                  
          └─Compilers                  
    ├─Sfr                  
      └─TC39B                  
          └─_Reg                  
    └─Ssw                  
        └─TC39B                  
            └─Tricore                  
  └─Service                  
      └─CpuGeneric                  
          ├─If                  
            └─Ccu6If                  
          ├─StdIf                  
          ├─SysSe                  
            ├─Bsp                  
            ├─Comm                  
            ├─General                  
            ├─Math                  
            └─Time                  
          └─_Utilities                  
└─os                  
    └─FreeRTOS                  
        ├─include                  
        └─portable                  
            ├─GCC                  
              └─TC3                  
            ├─MemMang                  
              └─reserve                  
            └─Tasking                  
                └─TC3
       

初始环境

通过上面的文件夹结构,大家也能发现,base 实际上是aurix 的 iLLD环境。没错,我们一开始需要一个能跑到 main 的 无操作系统环境。

初始项目环境

这个环境怎么获取呢。可以通过aurix 的IDE 新建一个项目即可。

Tc397 + hightec 编译器 移植 freertos

确保 main 可以跑到。这个怎么验证呢。

JSON                  
    /*Call main function of Cpu0 */                  
    Ifx_Ssw_jumpToFunction(core0_main);

在main 里面写好标识,调试一下即可。默认的环境应该都是可以的。

链接文件

注意 IDE 使用的默认编译器是tasking. 如果我们想换成 hightec 的编译器,需要修改 连接文件。

这里我们使用默认的地址分配。

JSON                  
MEMORY                  
{                  
    dsram5_local (w!xp): org = 0xd0000000, len = 96K                  
    dsram5 (w!xp): org = 0x10000000, len = 96K                  
    psram5 (w!xp): org = 0x10100000, len = 64K                  
                     
    dsram4_local (w!xp): org = 0xd0000000, len = 96K                  
    dsram4 (w!xp): org = 0x30000000, len = 96K                  
    psram4 (w!xp): org = 0x30100000, len = 64K                  
                     
    dsram3_local (w!xp): org = 0xd0000000, len = 96K                  
    dsram3 (w!xp): org = 0x40000000, len = 96K                  
    psram3 (w!xp): org = 0x40100000, len = 64K                  
                     
    dsram2_local (w!xp): org = 0xd0000000, len = 96K                  
    dsram2 (w!xp): org = 0x50000000, len = 96K                  
    psram2 (w!xp): org = 0x50100000, len = 64K                  
                     
    dsram1_local (w!xp): org = 0xd0000000, len = 240K                  
    dsram1 (w!xp): org = 0x60000000, len = 240K                  
    psram1 (w!xp): org = 0x60100000, len = 64K                  
                     
    dsram0_local (w!xp): org = 0xd0000000, len = 240K                  
    dsram0 (w!xp): org = 0x70000000, len = 240K                  
    psram0 (w!xp): org = 0x70100000, len = 64K                  
                     
    psram_local (w!xp): org = 0xc0000000, len = 64K                  
                     
    pfls0 (rx!p): org = 0x80000000, len = 3M                  
    pfls0_nc (rx!p): org = 0xa0000000, len = 3M                  
                     
    pfls1 (rx!p): org = 0x80300000, len = 3M                  
    pfls1_nc (rx!p): org = 0xa0300000, len = 3M                  
                     
    pfls2 (rx!p): org = 0x80600000, len = 3M                  
    pfls2_nc (rx!p): org = 0xa0600000, len = 3M                  
                     
    pfls3 (rx!p): org = 0x80900000, len = 3M                  
    pfls3_nc (rx!p): org = 0xa0900000, len = 3M                  
                     
    pfls4 (rx!p): org = 0x80c00000, len = 3M                  
    pfls4_nc (rx!p): org = 0xa0c00000, len = 3M                  
                     
    pfls5 (rx!p): org = 0x80f00000, len = 1M                  
    pfls5_nc (rx!p): org = 0xa0f00000, len = 1M                  
                     
    dfls0 (rx!p): org = 0xaf000000, len = 1M                  
                     
    ucb (rx!p): org = 0xaf400000, len = 24K                  
                     
    cpu0_dlmu (w!xp): org = 0x90000000, len = 64K                  
    cpu0_dlmu_nc (w!xp): org = 0xb0000000, len = 64K                  
                     
    cpu1_dlmu (w!xp): org = 0x90010000, len = 64K                  
    cpu1_dlmu_nc (w!xp): org = 0xb0010000, len = 64K                  
                     
    cpu2_dlmu (w!xp): org = 0x90020000, len = 64K                  
    cpu2_dlmu_nc (w!xp): org = 0xb0020000, len = 64K                  
                     
    cpu3_dlmu (w!xp): org = 0x90030000, len = 64K                  
    cpu3_dlmu_nc (w!xp): org = 0xb0030000, len = 64K                  
                     
    lmuram (w!xp): org = 0x90040000, len = 768K                  
    lmuram_nc (w!xp): org = 0xb0040000, len = 768K                  
                     
    cpu4_dlmu (w!xp): org = 0x90100000, len = 64K                  
    cpu4_dlmu_nc (w!xp): org = 0xb0100000, len = 64K                  
                     
    cpu5_dlmu (w!xp): org = 0x90110000, len = 64K                  
    cpu5_dlmu_nc (w!xp): org = 0xb0110000, len = 64K                  
                     
    edmem (w!xp): org = 0x99000000, len = 4M                  
    edmem_nc (w!xp): org = 0xb9000000, len = 4M                  
}

起始地址函数

JSON                  
void cstart(void)                  
{                  
    Ifx_Ssw_jumpToFunction(__StartUpSoftware);                  
}

需要根据实际的编译选项来修改。

到这里初始项目环境已经完毕。

添加os源码到工程

在这个基础上我们添加了 os的源码

JSON                  
└─os                  
    └─FreeRTOS                  
        ├─include                  
        └─portable                  
            ├─GCC                  
              └─TC3                  
            ├─MemMang                  
              └─reserve                  
            └─Tasking                  
                └─TC3

移植

堆使用

Rtos  对象是动态创建的所以需要用到 C 库 malloc() 和 free() 函数。但是这里不是直接使用 标准C 接口,而是进行了 丰富,优化,约束。

当 RTOS 内核需要 RAM 时,它不调用 malloc(),而是调用 pvPortMalloc()。释放 RAM 时, RTOS 内核调用 vPortFree(),而不是 free()。

在 rtos 源码中提供了下面五种 堆内存使用方式。在我们移植的时候,只需要选择其中一种。

1heap_1 —— 最简单,不允许释放内存。

1heap_2—— 允许释放内存,但不会合并相邻的空闲块。

1heap_3 —— 简单包装了标准 malloc() 和 free(),以保证线程安全。

1heap_4 —— 合并相邻的空闲块以避免碎片化。包含绝对地址放置选项。

1heap_5 —— 如同 heap_4,能够跨越多个不相邻内存区域的堆。

为了简单。本文使用了heap_1.c  ( heap_1 不太有用,因为 FreeRTOS 添加了静态分配支持)

所以在移植过程 文件夹MemMang 文件夹下面的五个文件

JSON                  
    heap_1.c                  
    heap_2.c                  
    heap_3.c                  
    heap_4.c                  
    heap_5.c

只需要保留 heap_1.c

FreeRTOSConfig.h

这里需要根据tc397的芯片手册进行修改。

比如 300M的主频

JSON                  
#define configCPU_CLOCK_HZ                         ( ( unsigned long ) 300000000UL )

下面这些定时器,中断相关的参数

比如下面的STM 的clc 控制寄存器,寄存器地址就需要去芯片手册里找。我这里找一个

JSON                  
/** brief 0, Clock Control Register */                  
#define STM0_CLC /*lint –e(923, 9078)*/ (*(volatile Ifx_STM_CLC*)0xF0001000u)                  
/** brief Clock Control Register */                  
typedef struct _Ifx_STM_CLC_Bits                  
{                  
    Ifx_UReg_32Bit DISR:1;            /**< brief [0:0] Module Disable Request Bit – DISR (rw) */                  
    Ifx_UReg_32Bit DISS:1;            /**< brief [1:1] Module Disable Status Bit – DISS (r) */                  
    Ifx_UReg_32Bit reserved_2:1;      /**< brief [2:2] internal Reserved */                  
    Ifx_UReg_32Bit EDIS:1;            /**< brief [3:3] Sleep Mode Enable Control – EDIS (rw) */                  
    Ifx_UReg_32Bit reserved_4:28;     /**< brief [31:4] internal Reserved */                  
} Ifx_STM_CLC_Bits;

下面给出全部的 该文件对应 tc397  配置。

JSON                  
#ifndef FREERTOS_CONFIG_H                  
#define FREERTOS_CONFIG_H                  
                 
#define configUSE_PREEMPTION                       1                  
#define configUSE_IDLE_HOOK                        0                  
                 
#define configCPU_CLOCK_HZ                         ( ( unsigned long ) 300000000UL )                  
#define configTICK_RATE_HZ                         ( ( TickType_t ) 1000UL )                  
                 
#define configMAX_PRIORITIES                       ( 10 )                  
#define configMINIMAL_STACK_SIZE                   ( ( unsigned short ) 256 )                  
#define configTOTAL_HEAP_SIZE                      ( ( size_t ) ( 48U * 1024U ) )                  
#define configMAX_TASK_NAME_LEN                    ( 16 )                  
                 
#define configENABLE_BACKWARD_COMPATIBILITY        0                  
#define configUSE_TRACE_FACILITY                   0                  
#define configUSE_16_BIT_TICKS                     0                  
#define configIDLE_SHOULD_YIELD                    0                  
#define configUSE_MALLOC_FAILED_HOOK               0                  
#define configCHECK_FOR_STACK_OVERFLOW             1                  
#define configUSE_TICK_HOOK                        0                  
#define configUSE_COUNTING_SEMAPHORES              1                  
#define configUSE_RECURSIVE_MUTEXES                1                  
#define configUSE_MUTEXES                          1                  
#define configRECORD_STACK_HIGH_ADDRESS            1                  
                 
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS    5                  
                 
/* Software timer configuration. */                  
#define configUSE_TIMERS                           ( 1 )                  
#define configTIMER_TASK_PRIORITY                  ( 9 )                  
#define configTIMER_QUEUE_LENGTH                   ( 5 )                  
#define configTIMER_TASK_STACK_DEPTH               configMINIMAL_STACK_SIZE                  
                 
/* Set the following definitions to 1 to include the API function, or zero                  
* to exclude the API function. */                  
#define INCLUDE_vTaskPrioritySet                   1                  
#define INCLUDE_uxTaskPriorityGet                  1                  
#define INCLUDE_vTaskDelete                        1                  
#define INCLUDE_vTaskCleanUpResources              1                  
#define INCLUDE_vTaskSuspend                       1                  
#define INCLUDE_vTaskDelayUntil                    1                  
#define INCLUDE_vTaskDelay                         1                  
                 
/* Interrupt above priority 31 are not effected by critical sections, but cannot call interrupt safe FreeRTOS functions. */                  
#define configMAX_API_CALL_INTERRUPT_PRIORITY      31                  
                 
/* Default definition of configASSERT(). */                  
#ifdef DEBUG                  
#ifdef __TASKING__                  
#define configASSERT( x )    if( ( x ) == 0 ) { __disable(); __debug(); }                  
#endif                  
#ifdef __clang__                  
#define configASSERT( x )    if( ( x ) == 0 ) { __builtin_tricore_disable(); __builtin_tricore_debug(); }                  
#endif                  
#else                  
#define configASSERT( x ) ((void)(x)) /* Empty macro to remove compiler warning(s) about unused variables */                  
#endif                  
                 
/* AURIX TCxxx definitions */                  
#define configCONTEXT_INTERRUPT_PRIORITY    1                  
#define configTIMER_INTERRUPT_PRIORITY      200 /* This value must not be bigger then context priority */                  
#define configCPU_NR                        0                  
#define configPROVIDE_SYSCALL_TRAP          0                  
#define configSYSCALL_CALL_DEPTH            2                  
#define configSTM                           ( ( uint32_t * ) (0xF0001000 + configCPU_NR*0x100 ) )                  
#define configSTM_SRC                       ( ( uint32_t * ) (0xF0038300 + configCPU_NR*0x8) )                  
#define configSTM_CLOCK_HZ                  ( 100000000 )                  
#define configSTM_DEBUG                     ( 1 )                  
#define configCONTEXT_SRC                   ( ( uint32_t * ) 0xF0038990 )                  
                 
#endif /* FREERTOS_CONFIG_H */                  

port.c 与 portmacro.h

这两个文件是需要开发者主要关注的文件。里面包含了大量的针对板子的移植工作。

比如根据芯片手册查到的 寄存器地址

寄存器地址

Tc397 + hightec 编译器 移植 freertos

截图出自 TC3xx Architecture vol1 V1.2.2.pdf          

对应的移植就是

JSON                  
#define portCPU_PSW              0xFE04                  
#define portCPU_PSW_IS_OFF       ( 9 )                  
#define portCPU_PSW_CSC_MSK      ( 0x7F )                  
#define portCPU_ICR              0xFE2C                  
#define portCPU_ICR_CCPN_OFF     ( 0 )                  
#define portCPU_ICR_CCPN_MSK     ( 0x000000FFUL )                  
#define portCPU_FCX              0xFE38                  
#define portCPU_PCXI             0xFE00                  
#define portCPU_CORE_ID          0xFE1C

数据类型定义

JSON                  
/* Type definitions. */                  
#define portCHAR                 char                  
#define portSHORT                short                  
#define portLONG                 long                  
#define portFLOAT                float                  
#define portDOUBLE               double                  
#define portSTACK_TYPE           unsigned int                  
#define portBASE_TYPE            long                  
#define portPOINTER_SIZE_TYPE    uintptr_t

编译器指令

JSON                  
/* Instructions */                  
#define portNOP()               _nop()                  
#define portMEMORY_BARRIER()    _dsync()

话不多说,直接给出 portmacro.h

JSON                  
                 
#ifndef PORTMACRO_H                  
#define PORTMACRO_H                  
                 
#ifdef __cplusplus                  
    extern “C”                  
#endif                  
                 
#include “FreeRTOSConfig.h”                  
#include
         
#define portCPU_PSW              0xFE04          
#define portCPU_PSW_IS_OFF       ( 9 )          
#define portCPU_PSW_CSC_MSK      ( 0x7F )          
#define portCPU_ICR              0xFE2C          
#define portCPU_ICR_CCPN_OFF     ( 0 )          
#define portCPU_ICR_CCPN_MSK     ( 0x000000FFUL )          
#define portCPU_FCX              0xFE38          
#define portCPU_PCXI             0xFE00          
#define portCPU_CORE_ID          0xFE1C          
         
/* Register defintions */          
#define portSRC_SRCR_SRPN_OFF    0          
#define portSRC_SRCR_SRE_OFF     10          
#define portSRC_SRCR_TOS_OFF     11          
#define portSRC_SRCR_SRR_OFF     24          
#define portSRC_SRCR_SETR_OFF    26          
         
/* Type definitions. */          
#define portCHAR                 char          
#define portSHORT                short          
#define portLONG                 long          
#define portFLOAT                float          
#define portDOUBLE               double          
#define portSTACK_TYPE           unsigned int          
#define portBASE_TYPE            long          
#define portPOINTER_SIZE_TYPE    uintptr_t          
         
typedef portSTACK_TYPE       StackType_t;          
typedef long                 BaseType_t;          
typedef unsigned long        UBaseType_t;          
         
#if ( configUSE_16_BIT_TICKS == 1 )          
    typedef unsigned short   TickType_t;          
    #define portMAX_DELAY    ( TickType_t ) 0xffff          
#else          
    typedef unsigned int     TickType_t __attribute__( ( aligned( 4 ) ) );          
    #define portMAX_DELAY    ( TickType_t ) 0xffffffffUL          
#endif          
         
/* FreeRTOS parameters */          
#define portTICK_TYPE_IS_ATOMIC        1          
#define portSTACK_GROWTH               ( -1 )          
#define portTICK_PERIOD_MS             ( ( TickType_t ) 1000 / configTICK_RATE_HZ )          
#define portBYTE_ALIGNMENT             8          
#define portCRITICAL_NESTING_IN_TCB    0          
         
/* Attributes */          
#define portDONT_DISCARD               __attribute__( ( used ) )          
#define portNORETURN                   __attribute__( ( noreturn ) )          
         
/* Instructions */          
#define portNOP()               _nop()          
#define portMEMORY_BARRIER()    _dsync()          
         
/* Critical section management */          
extern void vPortEnterCritical( void );          
extern void vPortExitCritical( void );          
#define portENTER_CRITICAL()                                     vPortEnterCritical()          
#define portEXIT_CRITICAL()                                      vPortExitCritical()          
#define portENABLE_INTERRUPTS()                                  vPortSetCCPN( 0 );          
#define portDISABLE_INTERRUPTS()                                 vPortSetCCPN( configMAX_API_CALL_INTERRUPT_PRIORITY )          
#define portASSERT_IF_IN_ISR()                                   configASSERT( ( _mfcr( portCPU_PSW ) & ( 1 << portCPU_PSW_IS_OFF ) ) == 0 )          
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( ulSavedMaskValue )    vPortSetICR( ulSavedMaskValue )          
#define portSET_INTERRUPT_MASK_FROM_ISR()                        xPortSetCCPN( configMAX_API_CALL_INTERRUPT_PRIORITY )          
         
#ifndef configYIELD_SYSCALL_ID          
    #define configYIELD_SYSCALL_ID    0          
#endif          
         
#define portYIELD()    _syscall( configYIELD_SYSCALL_ID )          
#define portYIELD_FROM_ISR( xHigherPriorityTaskWoken )                                                                                         
    {                                                                                                                                          
        const uint32_t xTrigger = ( ( *configCONTEXT_SRC >> portSRC_SRCR_SRR_OFF ) & 0x1 ) != 1 && ( xHigherPriorityTaskWoken != 0 );          
        *configCONTEXT_SRC |= ( xTrigger << portSRC_SRCR_SETR_OFF );                                                                           
                                                                                                                                               
        /* Wait until write request completes to trigger IRQ */                                                                                
        _dsync();                                                                                                                              
        _isync();                                                                                                                              
    }          
         
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION          
    #define configUSE_PORT_OPTIMISED_TASK_SELECTION    1          
#endif          
         
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )          
         
/* Check the configuration. */          
    #if ( configMAX_PRIORITIES > 32 )          
        #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32.  It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.          
    #endif          
         
/* Store/clear the ready priorities in a bit map. */          
    #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities )      ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )          
    #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities )       ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )          
         
    #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )    uxTopPriority = ( 31UL – ( ( uint32_t ) __builtin_clz( ( uxReadyPriorities ) ) ) )          
         
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */          
         
/* Function prototypes */          
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters )    void vFunction( void * pvParameters )          
#define portTASK_FUNCTION( vFunction, pvParameters )          void vFunction( void * pvParameters )          
         
/* TCB handling */          
extern void vPortReclaimCSA( unsigned long ** pxTCB );          
#define portCLEAN_UP_TCB( pxTCB )    vPortReclaimCSA( ( unsigned long ** ) ( pxTCB ) )          
         
/* ICR & CCPN modifying functions to enable and disable interrupts.          
* Only interrupts with a priority lower than          
*/          
static void __attribute__( ( used, always_inline ) ) vPortSetCCPN( unsigned char ucCCPN )          
{          
    _disable();          
    _mtcr( portCPU_ICR, ( _mfcr( portCPU_ICR ) & ~portCPU_ICR_CCPN_MSK ) | ( ucCCPN & portCPU_ICR_CCPN_MSK ) );          
    _isync();          
    _enable();          
}          
         
static void __attribute__( ( used, always_inline ) ) vPortSetICR( portBASE_TYPE ulICR )          
{          
    _disable();          
    _mtcr( portCPU_ICR, ( unsigned int ) ulICR );          
    _isync();          
    _enable();          
}          
         
static portBASE_TYPE __attribute__( ( used, always_inline ) ) xPortSetCCPN( unsigned char ucCCPN )          
{          
    unsigned int xICR;          
         
    _disable();          
    xICR = _mfcr( portCPU_ICR );          
    _mtcr( portCPU_ICR, ( xICR & ~portCPU_ICR_CCPN_MSK ) | ( ucCCPN & portCPU_ICR_CCPN_MSK ) );          
    _isync();          
    _enable();          
    return ( portBASE_TYPE ) xICR;          
}          
         
#ifdef __cplusplus          
}          
#endif          
         
#endif /* PORTMACRO_H */          
       

话不多说,直接给出 port.c

JSON                  
                 
#include
#include
#include
           
#include “FreeRTOS.h”            
#include “task.h”            
           
/* Prgoram status word macros */            
#define portINITIAL_SYSTEM_PSW            
    ( 0x000008FFUL ) /* Supervisor Mode, MPU Register Set 0 and Call Depth Counting disabled. */            
           
/* Context save area macros */            
#define portCSA_FCX_MASK          ( 0x000FFFFFUL )            
#define portINITIAL_LOWER_PCXI    ( 0x00300000UL ) /* Set UL to upper and PIE to 1 */            
#define portINITIAL_UPPER_PCXI    ( 0x00200000UL ) /* Set UL to lower and PIE to 1 */            
#define portNUM_WORDS_IN_CSA      ( 16 )            
           
extern volatile unsigned long * pxCurrentTCB;            
           
/* Tick and context switch config */            
#define portTICK_COUNT    ( configSTM_CLOCK_HZ / configTICK_RATE_HZ )            
           
/* Register defines */            
static volatile uint32_t *const pxStm = configSTM;            
static volatile uint32_t *const pxStmSrc = configSTM_SRC;            
static volatile uint32_t *const pxContextSrc = configCONTEXT_SRC;            
#define portSTM_TIM0                 0x10            
#define portSTM_CMP0                 0x30            
#define portSTM_COMCON               0x38            
#define portSTM_ICR                  0x3C            
#define portSTM_ISCR                 0x40            
#define portSTM_OCS                  0xE8            
           
#define portSTM_CMCON_MSTART0_OFF    8            
#define portSTM_CMCON_MSIZE0_OFF     0            
#define portSTM_ICR_CMP0EN_OFF       0            
#define portSTM_ICR_CMP0OS_OFF       2            
#define portSTM_ISCR_CMP0IRR_OFF     0            
           
static inline void vPortStartFirstTask( void );            
static inline void vPortInitContextSrc( void );            
static inline void vPortInitTickTimer( void );            
           
static inline void __attribute__( ( always_inline ) ) vPortLoadContext( unsigned char ucCallDepth );            
static inline void __attribute__( ( always_inline ) ) vPortSaveContext( unsigned char ucCallDepth );            
           
static inline uint32_t * __attribute__( ( always_inline ) ) pxPortCsaToAddress( uint32_t xCsa );            
           
static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;            
           
/* FreeRTOS required functions */            
BaseType_t xPortStartScheduler( void )            
{            
    vPortInitTickTimer();            
    vPortInitContextSrc();            
    vPortStartFirstTask();            
           
    return 0;            
}            
           
void vPortEndScheduler()            
{            
    pxStmSrc[ 0 ] &= ~( 1 << portSRC_SRCR_SRE_OFF );            
    pxContextSrc[ 0 ] &= ~( 1 << portSRC_SRCR_SRE_OFF );            
}            
           
StackType_t *pxPortInitialiseStack( StackType_t * pxTopOfStack,            
                                    TaskFunction_t pxCode,            
                                    void * pvParameters )            
{            
    uint32_t xLowerCsa = 0, xUpperCsa = 0;            
    uint32_t * pxUpperCSA = NULL;            
    uint32_t * pxLowerCSA = NULL;            
           
    /* Have to disable interrupts here because the CSAs are going to be            
     * manipulated. */            
    _disable();            
    {            
        /* DSync to ensure that buffering is not a problem. */            
        _dsync();            
           
        /* Consume two free CSAs. */            
        xLowerCsa = _mfcr( portCPU_FCX );            
        pxLowerCSA = pxPortCsaToAddress( xLowerCsa );            
           
        if( pxLowerCSA != NULL )            
        {            
            /* The Lower Links to the Upper. */            
            xUpperCsa = pxLowerCSA[ 0 ];            
            pxUpperCSA = pxPortCsaToAddress( pxLowerCSA[ 0 ] );            
        }            
           
        /* Check that we have successfully reserved two CSAs. */            
        if( ( pxLowerCSA != NULL ) && ( pxUpperCSA != NULL ) )            
        {            
            /* Remove the two consumed CSAs from the free CSA list. */            
            _mtcr( portCPU_FCX, pxUpperCSA[ 0 ] );            
            _isync();            
        }            
        else            
        {            
            /* Simply trigger a context list depletion trap. */            
            __asm( “tsvlcx” );            
        }            
    }            
    _enable();            
           
    /* Upper Context. */            
    memset( pxUpperCSA, 0, portNUM_WORDS_IN_CSA * sizeof( uint32_t ) );            
    pxUpperCSA[ 2 ] = ( uint32_t ) pxTopOfStack; /* A10;    Stack Return aka Stack Pointer */            
    pxUpperCSA[ 1 ] = portINITIAL_SYSTEM_PSW;    /* PSW    */            
    pxUpperCSA[ 0 ] = portINITIAL_UPPER_PCXI;            
           
    /* Lower Context. */            
    memset( pxLowerCSA, 0, portNUM_WORDS_IN_CSA * sizeof( uint32_t ) );            
    pxLowerCSA[ 8 ] = ( uint32_t ) pvParameters;          /* A4;    Address Type Parameter Register    */            
    pxLowerCSA[ 1 ] = ( uint32_t ) pxCode;                /* A11;    Return Address aka RA */            
    pxLowerCSA[ 0 ] = portINITIAL_LOWER_PCXI | xUpperCsa; /* PCXI pointing to the Upper context. */            
           
    /* Initialize the uxCriticalNesting. */            
    pxTopOfStack–;            
    *pxTopOfStack = 0;            
    /* Save the link to the CSA to the top of stack. */            
    pxTopOfStack–;            
    *pxTopOfStack = xLowerCsa;            
           
    return pxTopOfStack;            
}            
           
void __attribute__( ( interrupt_handler ) ) vPortSystemContextHandler()            
{            
    /* Disable interrupts to protect section*/            
    _disable();            
           
    /* Do a save, switch, execute */            
    vPortSaveContext( 0 );            
    vTaskSwitchContext();            
    vPortLoadContext( 0 );            
           
    _enable();            
}            
           
#define STR( x )     # x            
#define XSTR( s )    STR( s )            
__asm__ (            
    ” .pushsection .intvec_tc” XSTR( configCPU_NR ) “_” XSTR( configCONTEXT_INTERRUPT_PRIORITY ) “,”ax”,@progbitsn”            
                                                                                                 ” .align 5n”            
                                                                                                 ” __intvec_entry_” XSTR( configCONTEXT_INTERRUPT_PRIORITY ) “:n”            
                                                                                                                                                             ” svlcxn”            
                                                                                                                                                             ” movh.a %a14, hi:vPortSystemContextHandlern”            
                                                                                                                                                             ” lea %a14, [%a14]lo:vPortSystemContextHandlern”            
                                                                                                                                                             ” ji %a14n”            
                                                                                                                                                             ” .org 32n”            
                                                                                                                                                             ” .popsectionn” );            
void __attribute__( ( interrupt_handler ) ) vPortSystemTickHandler()            
{            
    unsigned long ulSavedInterruptMask;            
    BaseType_t xYieldRequired;            
           
    /* Increment compare value by tick count */            
    pxStm[ portSTM_CMP0 >> 2 ] = pxStm[ portSTM_CMP0 >> 2 ] + portTICK_COUNT;            
    pxStm[ portSTM_ISCR >> 2 ] |= ( 1 << portSTM_ISCR_CMP0IRR_OFF );            
           
    /* Check for possible tick drop.            
     * If the time is beyond the compare value, the next tick will need a complete            
     * wrap around. The tick count isn’t accruate any more. Increase the tick count            
     * or adapt to execute xTaskIncrementTick multiple times depending on the            
     * counts missed.   */            
    #if configCPU_STM_DEBUG != 0            
        configASSERT( ( pxStm[ portSTM_CMP0 >> 2 ] – pxStm[ portSTM_TIM0 >> 2 ] ) <= portTICK_COUNT );            
    #endif            
           
    /* Kernel API calls require Critical Sections. */            
    ulSavedInterruptMask = portSET_INTERRUPT_MASK_FROM_ISR();            
    {            
        /* Increment the Tick. */            
        xYieldRequired = xTaskIncrementTick();            
    }            
    portCLEAR_INTERRUPT_MASK_FROM_ISR( ulSavedInterruptMask );            
           
    portYIELD_FROM_ISR( xYieldRequired );            
}            
           
__asm__ (            
    ” .pushsection .intvec_tc” XSTR( configCPU_NR ) “_” XSTR( configTIMER_INTERRUPT_PRIORITY ) “,”ax”,@progbitsn”            
                                                                                               ” .align 5n”            
                                                                                               ” __intvec_entry_” XSTR( configTIMER_INTERRUPT_PRIORITY ) “:n”            
                                                                                                                                                         ” svlcxn”            
                                                                                                                                                         ” movh.a %a14, hi:vPortSystemTickHandlern”            
                                                                                                                                                         ” lea %a14, [%a14]lo:vPortSystemTickHandlern”            
                                                                                                                                                         ” ji %a14n”            
                                                                                                                                                         ” .org 32n”            
                                                                                                                                                         ” .popsectionn” );            
           
void __attribute__( ( noinline ) ) vPortSyscallYield( void );            
           
int vPortSyscallHandler( unsigned char id )            
{            
    switch( id )            
    {            
        case 0:            
            vPortSyscallYield();            
            break;            
           
        default:            
            break;            
    }            
           
    return 0;            
}            
           
void vPortInitTickTimer()            
{            
    pxStm[ portSTM_COMCON >> 2 ] =            
        ( 0 << portSTM_CMCON_MSTART0_OFF ) | ( 31 << portSTM_CMCON_MSIZE0_OFF );            
    pxStm[ portSTM_ICR >> 2 ] &= ~( 1 << portSTM_ICR_CMP0OS_OFF );            
    pxStmSrc[ 0 ] = ( ( configCPU_NR > 0 ?            
                        configCPU_NR + 1 : configCPU_NR ) << portSRC_SRCR_TOS_OFF ) |            
                    ( ( configTIMER_INTERRUPT_PRIORITY ) << portSRC_SRCR_SRPN_OFF );            
    pxStmSrc[ 0 ] |= ( 1 << portSRC_SRCR_SRE_OFF );            
    pxStm[ portSTM_CMP0 >> 2 ] = pxStm[ portSTM_TIM0 >> 2 ];            
    pxStm[ portSTM_ISCR >> 2 ] |= ( 1 << portSTM_ISCR_CMP0IRR_OFF );            
    pxStm[ portSTM_ICR >> 2 ] |= ( 1 << portSTM_ICR_CMP0EN_OFF );            
    pxStm[ portSTM_CMP0 >> 2 ] = pxStm[ portSTM_TIM0 >> 2 ] + portTICK_COUNT;            
    #if configTICK_STM_DEBUG != 0            
        pxStm[ portSTM_OCS >> 2 ] = 0x12000000;            
    #endif            
}            
           
void vPortInitContextSrc()            
{            
    pxContextSrc[ 0 ] =            
        ( ( configCPU_NR > 0 ?            
            configCPU_NR + 1 : configCPU_NR ) << portSRC_SRCR_TOS_OFF ) |            
        ( ( configCONTEXT_INTERRUPT_PRIORITY ) << portSRC_SRCR_SRPN_OFF );            
    pxContextSrc[ 0 ] |= ( 1 << portSRC_SRCR_SRE_OFF );            
}            
           
void vPortStartFirstTask()            
{            
    /* Disable interrupts  */            
    _disable();            
           
    vPortLoadContext( 0 );            
           
    /* Reset the call stack counting, to avoid trap on rfe */            
    unsigned long ulPsw = _mfcr( portCPU_PSW );            
           
    ulPsw &= ~( portCPU_PSW_CSC_MSK );            
    _mtcr( portCPU_PSW, ulPsw );            
    _isync();            
           
    /* Load the lower context and upper context through rfe to enable irqs */            
    __asm( “trslcx” );            
    __asm( “trfe” );            
    _nop();            
    _nop();            
    _nop();            
}            
           
void vPortLoadContext( unsigned char ucCallDepth )            
{            
    uint32_t ** ppxTopOfStack;            
    uint32_t uxLowerCSA;            
           
    /* Dsync is required for save CSA access */            
    _dsync();            
           
    /* Load the new CSA id from the stack and update the stack pointer */            
    ppxTopOfStack = ( uint32_t ** ) pxCurrentTCB;            
    uxLowerCSA = **ppxTopOfStack;            
    ( *ppxTopOfStack )++;            
    uxCriticalNesting = **ppxTopOfStack;            
    ( *ppxTopOfStack )++;            
           
    /* Store the lower context directly if inside the syscall or interrupt,            
     * else replace the lower context in the call stack. */            
    if( !ucCallDepth )            
    {            
        /* Update the link register */            
        _mtcr( portCPU_PCXI, uxLowerCSA );            
        _isync();            
    }            
    else            
    {            
        /* Update previous lower context */            
        uint32_t * pxCSA = pxPortCsaToAddress( _mfcr( portCPU_PCXI ) );            
        int i;            
           
        for(i = 0; i < ucCallDepth – 1; i++)            
        {            
            pxCSA = pxPortCsaToAddress( pxCSA[ 0 ] );            
        }            
           
        pxCSA[ 0 ] = uxLowerCSA;            
    }            
}            
           
void vPortSaveContext( unsigned char ucCallDepth )            
{            
    uint32_t ** ppxTopOfStack;            
    uint32_t * pxLowerCSA, * pxUpperCSA;            
    uint32_t uxLowerCSA;            
           
    /* Dsync is required for save CSA access */            
    _dsync();            
           
    /* Get the current context information. */            
    uxLowerCSA = _mfcr( portCPU_PCXI );            
           
    /* If this function is used inside a function from the syscall or interrupt,            
     * load the correct context from the call stack */            
    if( ucCallDepth )            
    {            
        uint32_t * pxCSA = pxPortCsaToAddress( uxLowerCSA );            
        int i;            
           
        for(i = 0; i < ucCallDepth – 1; i++)            
        {            
            pxCSA = pxPortCsaToAddress( pxCSA[ 0 ] );            
        }            
           
        uxLowerCSA = pxCSA[ 0 ];            
    }            
           
    pxLowerCSA = pxPortCsaToAddress( uxLowerCSA );            
    pxUpperCSA = pxPortCsaToAddress( pxLowerCSA[ 0 ] );            
           
    /* Load the stack pointer */            
    ppxTopOfStack = ( uint32_t ** ) pxCurrentTCB;            
    /* Update the stack info in the TCB */            
    *ppxTopOfStack = ( uint32_t * ) pxUpperCSA[ 2 ];            
    /* Place ucNestedContext */            
    ( *ppxTopOfStack )–;            
    **ppxTopOfStack = uxCriticalNesting;            
    /* Place the lower CSA id on the stack */            
    ( *ppxTopOfStack )–;            
    **ppxTopOfStack = uxLowerCSA;            
}            
           
void vPortSyscallYield()            
{            
    /* Do a save, switch, execute */            
    vPortSaveContext( configSYSCALL_CALL_DEPTH );            
    vTaskSwitchContext();            
    vPortLoadContext( configSYSCALL_CALL_DEPTH );            
}            
           
uint32_t * pxPortCsaToAddress( uint32_t xCsa )            
{            
    uint32_t pxCsa;            
           
    __asm ( “extr.u %0, %1, 16, 4n”            
          “sh     %0, %0, 28n”            
          “insert %0, %0, %1 6, 16n” : “+d” ( pxCsa ) : “d” ( xCsa ) );            
    /*pxCsa = (_extr_u(xCsa, 16, 4) << 28); */            
    /*pxCsa = _insert(pxCsa, xCsa, 6, 16); */            
    return ( uint32_t * ) pxCsa;            
}            
           
void vPortEnterCritical( void )            
{            
    portDISABLE_INTERRUPTS();            
    uxCriticalNesting++;            
           
    /* This is not the interrupt safe version of the enter critical function so            
     * assert() if it is being called from an interrupt context.  Only API            
     * functions that end in “FromISR” can be used in an interrupt.  Only assert if            
     * the critical nesting count is 1 to protect against recursive calls if the            
     * assert function also uses a critical section. */            
    if( uxCriticalNesting == 1 )            
    {            
        portASSERT_IF_IN_ISR();            
    }            
}            
           
void vPortExitCritical( void )            
{            
    configASSERT( uxCriticalNesting );            
    uxCriticalNesting–;            
           
    if( uxCriticalNesting == 0 )            
    {            
        portENABLE_INTERRUPTS();            
    }            
}            
           
void vPortReclaimCSA( unsigned long ** pxTCB )            
{            
    uint32_t ulHeadCSA, ulFreeCSA;            
    uint32_t * pulNextCSA;            
           
    /* The lower context (PCXI value) to return to the task is stored as the            
     * current element on the stack. Mask off everything in the PCXI register            
     * other than the address. */            
    ulHeadCSA = ( **pxTCB ) & portCSA_FCX_MASK;            
           
    /* Iterate over the CSAs that were consumed as part of the task. */            
    for(pulNextCSA = pxPortCsaToAddress( ulHeadCSA );            
        ( pulNextCSA[ 0 ] & portCSA_FCX_MASK ) != 0;            
        pulNextCSA = pxPortCsaToAddress( pulNextCSA[ 0 ] ) )            
    {            
        /* Mask off everything in the PCXI value other than the address. */            
        pulNextCSA[ 0 ] &= portCSA_FCX_MASK;            
    }            
           
    _disable();            
    {            
        /* Look up the current free CSA head. */            
        _dsync();            
        ulFreeCSA = _mfcr( portCPU_FCX );            
           
        /* Join the current free onto the tail of what is being reclaimed. */            
        pulNextCSA[ 0 ] = ulFreeCSA;            
           
        /* Move the head of the reclaimed into the Free. */            
        _mtcr( portCPU_FCX, ulHeadCSA );            
        _isync();            
    }            
    _enable();            
}            
           
void __attribute__( ( noreturn ) ) vPortLoopForever( void )            
{            
    while( 1 )            
    {            
    }            
}            
         

测试代码

我们在main 函数里面创建了两个任务。

创建任务

1task_app1

1task_app2

JSON                  
void core0_main(void)                  
{                  
    IfxCpu_enableInterrupts();                  
                     
    /* !!WATCHDOG0 AND SAFETY WATCHDOG ARE DISABLED HERE!!                  
     * Enable the watchdogs and service them periodically if it is required                  
     */                  
    IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());                  
    IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());                  
                     
    /* Wait for CPU sync event */                  
    IfxCpu_emitEvent(&g_cpuSyncEvent);                  
    IfxCpu_waitEvent(&g_cpuSyncEvent, 1);                  
                     
    /* Initialize a time variable */                  
    // Ifx_TickTime ticksFor1s = IfxStm_getTicksFromMilliseconds(BSP_DEFAULT_TIMER, WAIT_TIME);                  
                 
    /* Create LED1 app task */                  
    app1_status = xTaskCreate(task_app1, “APP1”, configMINIMAL_STACK_SIZE, NULL, 3, NULL);                  
                 
    /* Create LED2 app task */                  
    app2_status = xTaskCreate(task_app2, “APP2”, configMINIMAL_STACK_SIZE, NULL, 5, NULL);                  
                 
    /* Start the scheduler */                  
    vTaskStartScheduler();                  
                 
    while(1)                  
    {                  
    }                  
}

任务的内容很简单,就是周期任务,里面有counter 在自增。

任务实现

JSON                  
void task_app1(void)                  
{                  
    app1_cnt++;                  
    TickType_t xLastWakeTime;                  
    xLastWakeTime = xTaskGetTickCount();                  
    while(1)                  
    {                  
        app1_cnt++;                  
        vTaskDelayUntil(&xLastWakeTime, 1000);                  
    }                  
                 
}                  
void task_app2(void)                  
{                  
    app2_cnt++;                  
    while(1)                  
    {                  
        app2_cnt++;                  
        /* Delay 250ms */                  
        vTaskDelay(pdMS_TO_TICKS(250));                  
    }                  
}

编译测试

编译生成 elf, 和 map 文件。

检查map文件

我们来读取一下map 文件中的两个任务。实际上就是两个函数。和我们预期的一样。

JSON                  
0x800394cc 0x8003950d    66 g task_app1                                         pfls0     .CPU0.text      .text.task_app1                                         outputobjssrcCpu0_Main.o                  
0x8003950e 0x8003953f    50 g task_app2                                         pfls0     .CPU0.text      .text.task_app2     

我们也通过hightec 编译器提供的工具来读一下elf文件,看一下两个 任务的 符号

检查elf文件

JSON                  
tricore-readelf.exe .tc397_rtos.elf -s | grep task_*                  
   369: 00000000     0 FILE    LOCAL  DEFAULT   ABS tasks.c                  
   794: 800394cc    66 FUNC    GLOBAL DEFAULT    45 task_app1                  
  5511: 8003950e    50 FUNC    GLOBAL DEFAULT    45 task_app2

测试

直接调试器看一下 任务里面的全局变量是不是预想的自增。并且有大概四倍的关系。

测试通过。

Tc397 + hightec 编译器 移植 freertos

          

原文始发于微信公众号(汽车与基础软件):Tc397 + hightec 编译器 移植 freertos

版权声明:admin 发表于 2024年3月16日 上午12:22。
转载请注明:Tc397 + hightec 编译器 移植 freertos | CTF导航

相关文章