• 基于英飞凌AURIX TC275 Lite的三核轮休工程


    项目介绍

    本项目基于AURIX TC275 Lite开发板套件,使用AURIX Development Studio开发,实现了简单的三核轮休:CPU0检测按键按下,之后唤醒CPU1并翻转LED1,1秒后唤醒CPU2并翻转LED2,之后进入系统休眠状态。

    硬件介绍

    AURIX TM TC275 lite套件配备了基于32位单芯片AURIX TM TriCore的微控制器Aurix TM TC275。它可以与一系列开发工具一起使用,包括AURIX Development Studio、英飞凌免费的基于Eclipse的IDE,或来自Hightec/PLS/Infineon的基于Eclipse的FreeEntryToolchain。

    特性:

    • Arduino 连接器
    • Arduino ICSP 连接器
    • 稳压器 5V 至 3.3V
    • 可选 0 欧姆电阻器(1210英制中的R39_opt/R40_opt)
    • Arduino 连接器(数字)
    • 用于 AURIX™的20 MHz晶振和用于OCDS的12MHz晶振
    • 用于 WIFI/BLE 的 Mikrobus 连接器
    • 英飞凌 CAN 收发器 TLE9251VSJ 和 CAN 连接器
    • 针连接器 X2
    • 电源指示灯 (D5)
    • LED D1/D2用于ADBUS7/4和LED3用于ESR0信号(低电平有效)
    • Arduino 针连接器(电源和模拟输入)
    • 电位器 (10 kOhm) 和可焊接的0Ohm电阻器(0805 英制中的R33)
    • 微型 USB(推荐USB3.0)
    • 10 针 DAP 连接器
    • 复位按钮
    • 2 x Shield2GO 连接器,用于Infineon Maker Shields
    • EEPROM 1Kbit

    开发板电路结构框图
    👉 更多介绍:Funpack第二季第二期:KIT_AURIX_TC275_LITE

    电源管理

    该章节主要是参考芯片手册7.3.2节。

    电源管理方案允许激活电源关闭模式,从而使系统以对应应用状态所需的最小电源运行。通过分别调用Idle、Sleep或Standby模式,可以逐步降低功耗。Idle模式是特定于每个CPU的,而Sleep和Standby模式会影响整个系统。

    对于单个CPU,有两种工作状态:Run/Idle。运行状态下,CPU时钟启动且代码会不断运行,而idle下CPU时钟失能且代码不继续运行,外设时钟保持开启。

    对于整个系统,有三种电源模式: Run/Sleep/Standby:

    • Run:至少有一个主CPU没有请求休眠模式或备用模式,并且处于运行模式。所有外设都已激活。
    • Sleep:CPU代码暂停执行,进入Idle状态。如果外设置位各自的CLCx.EDIS位,则进入休眠状态。端口保留其早期的程序状态。
    • Standby:构成备用RAM和唤醒单元的备用域仍然供应。芯片其他部分的电源完全关闭。

    本工程比较关心的是系统如何进入系统休眠(system sleep)及如何从休眠中唤醒CPU。

    系统不同工作模式的切换
    从system run进入system sleep有两种方式:

    1. CPUSEL = 111b且PMCSRy.REQSLP = 10b (y = all CPUs);
    2. 通过CPUSEL,设置CPUy为主CPU,且其PMCSRy.REQSLPb = 10b;

    从system sleep唤醒的方法在手册中写的很全面,但是本工程主要利用定时器(STM)中断唤醒不同的CPU。当然,手册里所说的基本都需要操作CPU的寄存器,看也看不懂,但可以参考英飞凌提供的示例SCU_Power_Down_Sleep。

    代码结构及说明

    三核主程序

    CPU0负责GPIO初始化,包括板上两个LED与按键,并置LED初态为熄灭、初始化并启动STM0(后续会讲到),最后Cpu0_req_sleep(),以CPU0请求系统进入系统休眠状态。当其进入工作模式后,判断_flag2标志位,请求系统休眠。Cpu0_Main.c代码如下:

    #include 
    #include 
    #include 
    #include "Ifx_Types.h"
    #include "IfxCpu.h"
    #include "IfxScuWdt.h"
    
    IfxCpu_syncEvent g_cpuSyncEvent = 0;
    
    int core0_main(void)
    {
        IfxCpu_enableInterrupts();
        IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
        IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
        
        /* Wait for CPU sync event */
        IfxCpu_emitEvent(&g_cpuSyncEvent);
        IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
        
        init_GPIOs();
        initStm0();
        Cpu0_req_sleep();
    
        while(1)
        {
            if (_flag2 == TRUE) {
                _flag2 = FALSE;
                Cpu0_req_sleep();
            }
        }
        return (1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    CPU1先直接进入idle状态,并等待唤醒后判断标志位_flag1,负责翻转LED1并打开定时器STM1,最后再进入idle。Cpu1_Main.c代码如下:

    #include "Ifx_Types.h"
    #include "IfxCpu.h"
    #include "IfxScuWdt.h"
    #include 
    #include 
    #include 
    
    extern IfxCpu_syncEvent g_cpuSyncEvent;
    
    int core1_main(void)
    {
        IfxCpu_enableInterrupts();
        IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
        
        /* Wait for CPU sync event */
        IfxCpu_emitEvent(&g_cpuSyncEvent);
        IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    
        IfxCpu_setCoreMode(&MODULE_CPU1, IfxCpu_CoreMode_idle);
    
        while(1)
        {
            if (_flag1 == TRUE)
            {
                _flag1 = FALSE;
                led_toggle(LED1);
                runStm1();
                IfxCpu_setCoreMode(&MODULE_CPU1, IfxCpu_CoreMode_idle);
            }
        }
        return (1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    CPU2首先初始化但不启动STM1(后续会讲到),而后进入idle等待唤醒。Cpu2_Main.c代码如下:

    #include "Ifx_Types.h"
    #include "IfxCpu.h"
    #include "IfxScuWdt.h"
    #include 
    #include 
    #include 
    
    extern IfxCpu_syncEvent g_cpuSyncEvent;
    
    int core2_main(void)
    {
        IfxCpu_enableInterrupts();
        IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
        
        /* Wait for CPU sync event */
        IfxCpu_emitEvent(&g_cpuSyncEvent);
        IfxCpu_waitEvent(&g_cpuSyncEvent, 1);
    
        initStm1();
        IfxCpu_setCoreMode(&MODULE_CPU2, IfxCpu_CoreMode_idle);
    
        while(1)
        {
        }
        return (1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    GPIO

    所用到的GPIO仅两个LED与按键BUTTON,较为简单:

    #ifndef BSP_LED_BUTTON_H_
    #define BSP_LED_BUTTON_H_
    
    #include "IfxPort.h"
    #include "Ifx_Types.h"
    
    #define LED1         &MODULE_P00,5
    #define LED2         &MODULE_P00,6
    #define BUTTON       &MODULE_P00,7
    
    void init_GPIOs(void);
    void led_toggle(Ifx_P *port, uint8 pinIndex);
    
    #endif /* BSP_LED_BUTTON_H_ */
    //--------------------
    #include 
    #include "Bsp.h"
    #include 
    
    /* This function initializes the port pin which drives the LED */
    void init_GPIOs(void)
    {
        IfxPort_setPinMode(LED1, IfxPort_Mode_outputPushPullGeneral);
        IfxPort_setPinMode(LED2, IfxPort_Mode_outputPushPullGeneral);
        IfxPort_setPinMode(BUTTON, IfxPort_Mode_inputPullUp);
    
        /* Switch OFF the LED (low-level active) */
        IfxPort_setPinState(LED1, IfxPort_State_high);
        IfxPort_setPinState(LED2, IfxPort_State_high);
    }
    
    /* This function toggles the port pin and wait 1000 milliseconds */
    void led_toggle(Ifx_P *port, uint8 pinIndex)
    {
        IfxPort_togglePin(port, pinIndex);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    CPU0请求系统休眠

    该部分主要参考英飞凌提供的示例。

    #include 
    #include "IfxCpu.h"
    #include "IfxScuWdt.h"
    
    #define BLOCK_SLEEP_MODE    0x1                 /* Block sleep mode for STM                                         */
    #define PMSWCR1_CPUSEL      0x1                 /* Set the CPU0 as CPU master                                       */
    #define PMSWCR2_CPUSEL      0x2                 /* Set the CPU1 as CPU master                                       */
    #define PMSWCR3_CPUSEL      0x4                 /* Set the CPU2 as CPU master                                       */
    #define PMCSR0_REQSLP       0x2                 /* Request sleep mode                                               */
    
    void Cpu0_req_sleep(void)
    {
        /* Clear safety EndInit protection */
        IfxScuWdt_clearSafetyEndinitInline(IfxScuWdt_getSafetyWatchdogPasswordInline());
        /* Clear EndInit protection */
        IfxScuWdt_clearCpuEndinit(IfxScuWdt_getCpuWatchdogPassword());
    
        STM0_CLC.B.EDIS = BLOCK_SLEEP_MODE;
    
        SCU_PMSWCR1.B.CPUSEL = PMSWCR1_CPUSEL;      /* Set the CPU0 as CPU master to trigger a power down mode      */
        SCU_PMCSR0.B.REQSLP = PMCSR0_REQSLP;        /* Request System Sleep Mode CPU0                               */
    
        /* Set safety EndInit protection */
        IfxScuWdt_setSafetyEndinitInline(IfxScuWdt_getSafetyWatchdogPasswordInline());
        /* Set EndInit protection */
        IfxScuWdt_setCpuEndinit(IfxScuWdt_getCpuWatchdogPassword());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    两个系统定时器中断

    参考系统定时器(GTM)相关示例,可以写出定时器中断极其中断服务函数。

    STM0中断由CPU0申请,使用MODULE_STM0,频率20Hz,在其中断服务函数stmIsr0中,对按键进行扫描(即扫描按键频率为20Hz),判断其是否按下,若按下,则停止本计时器(为一个自动重载定时器),并唤醒CPU1,置标志位_flag1,从而使得CPU1继续运行其主程序中的代码。

    #ifndef BSP_STM_H_
    #define BSP_STM_H_
    
    void initStm0(void);
    void initStm1(void);
    void runStm0(void);
    void runStm1(void);
    
    extern uint16 _flag0;
    extern uint16 _flag1;
    extern uint16 _flag2;
    
    #endif /* BSP_STM_H_ */
    //--------------------
    #include 
    #include 
    #include "IfxStm_Timer.h"
    #include 
    
    #define ISR_PRIORITY_STM    20                  /* STM Interrupt priority for interrupt ISR                         */
    
    uint16 _flag0 = FALSE;
    uint16 _flag1 = FALSE;
    uint16 _flag2 = FALSE;
    
    IfxStm_Timer g_stmTimer0;
    IfxStm_Timer g_stmTimer1;
    IFX_INTERRUPT(stmIsr0, 0, ISR_PRIORITY_STM);
    IFX_INTERRUPT(stmIsr1, 2, ISR_PRIORITY_STM);
    
    void initStm0(void)
    {
        IfxStm_Timer_Config timerConfig;                                /* Timer configuration structure                */
    
        IfxStm_Timer_initConfig(&timerConfig, &MODULE_STM0);            /* Initialize it with default values            */
    
        timerConfig.base.frequency = 20;                                 /* Interrupt rate every STM_PERIOD seconds      */
        timerConfig.base.isrPriority = ISR_PRIORITY_STM;                /* Interrupt priority                           */
        timerConfig.base.isrProvider = IfxSrc_Tos_cpu0;                 /* CPU0 to trigger the interrupt                */
        timerConfig.comparator = IfxStm_Comparator_0;                   /* Comparator 0 register is used                */
    
        IfxStm_Timer_init(&g_stmTimer0, &timerConfig);                   /* Use timerConfig to initialize the STM        */
        IfxStm_Timer_run(&g_stmTimer0);
    }
    
    void initStm1(void)
    {
        IfxStm_Timer_Config timerConfig;                                /* Timer configuration structure                */
    
        IfxStm_Timer_initConfig(&timerConfig, &MODULE_STM1);            /* Initialize it with default values            */
    
        timerConfig.base.frequency = 1;                                 /* Interrupt rate every STM_PERIOD seconds      */
        timerConfig.base.isrPriority = ISR_PRIORITY_STM;                /* Interrupt priority                           */
        timerConfig.base.isrProvider = IfxSrc_Tos_cpu2;                 /* CPU2 to trigger the interrupt                */
        timerConfig.comparator = IfxStm_Comparator_0;                   /* Comparator 0 register is used                */
    
        IfxStm_Timer_init(&g_stmTimer1, &timerConfig);                   /* Use timerConfig to initialize the STM        */
    }
    
    void runStm0(void)
    {
        IfxStm_Timer_run(&g_stmTimer0);                                  /* Run the STM and set the compare Value        */
    }
    
    void runStm1(void)
    {
        IfxStm_Timer_run(&g_stmTimer1);                                  /* Run the STM and set the compare Value        */
    }
    
    void stmIsr0(void)
    {
        /* Enabling interrupts as ISR disables it */
        IfxCpu_enableInterrupts();
    
        /* Clear the timer event */
        IfxStm_Timer_acknowledgeTimerIrq(&g_stmTimer0);
    
        if (IfxPort_getPinState(BUTTON) == 0)
        {
            IfxStm_Timer_stop(&g_stmTimer0);
            IfxCpu_setCoreMode(&MODULE_CPU1, IfxCpu_CoreMode_run);
            _flag1 = TRUE;
        }
    }
    
    void stmIsr1(void)
    {
        /* Enabling interrupts as ISR disables it */
        IfxCpu_enableInterrupts();
    
        /* Clear the timer event */
        IfxStm_Timer_acknowledgeTimerIrq(&g_stmTimer1);
    
        IfxStm_Timer_stop(&g_stmTimer1);
    
        led_toggle(LED2);
        runStm0();
        _flag2 = TRUE;
        IfxCpu_setCoreMode(&MODULE_CPU2, IfxCpu_CoreMode_idle);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100

    STM1的中断由CPU2请求,当CPU1被唤醒,其开启STM1运行。STM1中断频率为1Hz(定时1秒),且当中断触发时关闭定时器(单次定时器),翻转LED2,重新开启STM0(重新开启按键扫描),最后置_flag2标志位(之后CPU0请求进入系统休眠),CPU2自己进入idle。

    功能展示

    参见工程演示视频。

    👉 B站:基于AURIX TC275 Lite的三核轮休工程

    项目总结

    此次工程主要参考TC275芯片手册,略微了解了一下各CPU的工作模式,以及系统的几种工作模式的切换,实现了三核分工、三核轮休。与一般的单核MCU开发板不同,TC275是三核并行,其对于单个CPU的工作状态与整体系统的工作状态之间,切换条件更为复杂。

    即使笔者参考了英飞凌提供的示例程序,但它也仅是CPU0请求系统休眠的功能,对于以CPU1/CPU2作为Master CPU请求系统休眠,笔者做了尝试但不保证正确,因此该部分代码没有提供,且该工程也仅有CPU0作为Master CPU请求系统休眠。关于系统休眠与否,笔者也没有很好的调试方法(调试时,貌似休眠CPU线程会被挂起,导致调试挂起)。

  • 相关阅读:
    电力行业人员定位管理解决方案之智能巡检
    C++语言GDAL批量裁剪多波段栅格图像:基于像元个数裁剪
    五:ffmpe主要参数的使用
    C++PrimerPlus(第6版)中文版:Chapter13.3多态共有继承例子(重点讲虚函数):usebrass2.cpp
    如何安装sbt(sbt在ubuntu上的安装与配置)(有详细安装网站和图解)
    城市内涝积水预防,万宾科技内涝监测仪如何预警?
    【Netty】1-3. Netty急速入门 - 编码实现(java)
    管理员必须知道的RADIUS认证服务器的部署成本
    解决Maven依赖下载缓慢的问题(亲测管用)
    warning LNK4017: DESCRIPTION 语句不支持目标平台;已忽略
  • 原文地址:https://blog.csdn.net/weixin_46422143/article/details/126610506