• 【ADS-01】TC264实现LED灯闪烁


    编辑:CrazyRabbit
    日期:2022年7月31日

    本文介绍如何应用Infineon官方提供的免费IDE开发环境AURIX Development Studio和TC264开发板(龙邱科技提供)实现LED等闪烁。

    1. AURIX Development Studio

    AURIX Development Studio(下简称ADS), 是英飞凌推出在针对自家AURIX芯片的免费编译环境,软件使用无需license,长期免费。该开发环境基于业内流行的Eclipse打造而成,界面非常友好,对于刚刚接触英飞凌的朋友们而言更是易于上手。ADS集成了编译器、调试器、iLLD底层开发库等必备组件,无需开发者四处寻找调试器和底层库代码。ADS的编译器和调试器是基于TASKING编译器、调试器打造而成,稳定性上无需额外担心,调试器比较难用,全当是一个高阶版的下载器吧。

    2. 硬件环境

    本次实现的硬件环境是用龙邱科技提供的TC264核心板+母版+下载器:
    image.png
    这套硬件环境本来是给大学生智能车比赛用的,很适合不愿意花大价钱购买官方工具链的业余玩家或者英飞凌AURIX的自学用户(比如我)。

    3. 代码

    3.1 新建工程

    打开ADAS,选择工作区(略)之后,在File→New,新建AURIX工程
    image.png
    填写工程名称,选择Next下一步:
    image.png
    选择对应的芯片(TC26x B-Step),点击Finish:
    image.png
    在产生的结构树中新建一个“src”文件夹,用于存放自己写的代码:
    image.png
    建立以下代码文件:
    image.png

    3.2 关键代码

    先说明下,以下为该开发板默认的LED接口:
    LED0p P10_6 龙邱TC母板核心板上LED0 翠绿
    LED1p P10_5 龙邱TC母板核心板上LED1 蓝灯
    LED2p P20_6 龙邱TC母板上LED0
    LED3p P20_7 龙邱TC母板上LED1


    3.2.1 LQ_GPIO

    为了实现对GPIO引脚的基本操作,先建立LQ_GPIO的头文件,LQ_GPIO主要目的是:

    • 定义相关针脚枚举类GPIO_NAME,如P10_5 = 0xB005(B005的前两位B0实际是Module编号,05实际是PIN的编号)

    该地址可参考英飞凌TC264用户手册第十四章《General Purpose I/O Ports and Peripheral I/O Lines (Ports)
    》:
    image.png
    image.png
    如上表,给每个Module的所有寄存器加起来需要的内存大小有256个字节(00~FF),以下为iLLD中IfxPort_regdef.h中对Port结构体的定义,可以看出共有256字节和相关的寄存器:

    Port结构体:

    /** \brief  Port object */
    typedef volatile struct _Ifx_P
    {
        Ifx_P_OUT OUT;                          /**< \brief 0, Port Output Register */
        Ifx_P_OMR OMR;                          /**< \brief 4, Port Output Modification Register */
        Ifx_P_ID ID;                            /**< \brief 8, Identification Register */
        unsigned char reserved_C[4];            /**< \brief C, \internal Reserved */
        Ifx_P_IOCR0 IOCR0;                      /**< \brief 10, Port Input/Output Control Register 0 */
        Ifx_P_IOCR4 IOCR4;                      /**< \brief 14, Port Input/Output Control Register 4 */
        Ifx_P_IOCR8 IOCR8;                      /**< \brief 18, Port Input/Output Control Register 8 */
        Ifx_P_IOCR12 IOCR12;                    /**< \brief 1C, Port Input/Output Control Register 12 */
        unsigned char reserved_20[4];           /**< \brief 20, \internal Reserved */
        Ifx_P_IN IN;                            /**< \brief 24, Port Input Register */
        unsigned char reserved_28[24];          /**< \brief 28, \internal Reserved */
        Ifx_P_PDR0 PDR0;                        /**< \brief 40, Port Pad Driver Mode 0 Register */
        Ifx_P_PDR1 PDR1;                        /**< \brief 44, Port Pad Driver Mode 1 Register */
        unsigned char reserved_48[8];           /**< \brief 48, \internal Reserved */
        Ifx_P_ESR ESR;                          /**< \brief 50, Port Emergency Stop Register */
        unsigned char reserved_54[12];          /**< \brief 54, \internal Reserved */
        Ifx_P_PDISC PDISC;                      /**< \brief 60, Port Pin Function Decision Control Register */
        Ifx_P_PCSR PCSR;                        /**< \brief 64, Port Pin Controller Select Register */
        unsigned char reserved_68[8];           /**< \brief 68, \internal Reserved */
        Ifx_P_OMSR0 OMSR0;                      /**< \brief 70, Port Output Modification Set Register 0 */
        Ifx_P_OMSR4 OMSR4;                      /**< \brief 74, Port Output Modification Set Register 4 */
        Ifx_P_OMSR8 OMSR8;                      /**< \brief 78, Port Output Modification Set Register 8 */
        Ifx_P_OMSR12 OMSR12;                    /**< \brief 7C, Port Output Modification Set Register 12 */
        Ifx_P_OMCR0 OMCR0;                      /**< \brief 80, Port Output Modification Clear Register 0 */
        Ifx_P_OMCR4 OMCR4;                      /**< \brief 84, Port Output Modification Clear Register 4 */
        Ifx_P_OMCR8 OMCR8;                      /**< \brief 88, Port Output Modification Clear Register 8 */
        Ifx_P_OMCR12 OMCR12;                    /**< \brief 8C, Port Output Modification Clear Register 12 */
        Ifx_P_OMSR OMSR;                        /**< \brief 90, Port Output Modification Set Register */
        Ifx_P_OMCR OMCR;                        /**< \brief 94, Port Output Modification Clear Register */
        unsigned char reserved_98[8];           /**< \brief 98, \internal Reserved */
        Ifx_P_LPCR0 LPCR0;                      /**< \brief A0, Port LVDS Pad Control Register 0 */
        Ifx_P_LPCR1 LPCR1;                      /**< \brief A4, Port LVDS Pad Control Register 1 */
        Ifx_P_LPCR2 LPCR2;                      /**< \brief A8, Port LVDS Pad Control Register 2 */
        unsigned char reserved_A4[76];          /**< \brief AC, \internal Reserved */
        Ifx_P_ACCEN1 ACCEN1;                    /**< \brief F8, Port Access Enable Register 1 */
        Ifx_P_ACCEN0 ACCEN0;                    /**< \brief FC, Port Access Enable Register 0 */
    } Ifx_P;
    
    • 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
    • 定义GPIO的模式,本例最终用的是推挽输出模式
    • 定义宏:根据GPIO_NAME获取Port的Module首地址
    • 定义宏:根据GPIO_NAME获取PIN的编号
    • 声明GPIO的PIN初始化函数_void PIN_InitConfig(GPIO_Name_t pin,IfxPort_Mode mode, uint8 output);_
    • 声明GPIO的PIN的写入函数_void PIN_Write(GPIO_Name_t pin,uint8 output);_通过该函数来更新电平状态,(output为0则高电平,为1则低电平)
    • 声明GPIO的PIN电平翻转函数void PIN_Reverse(GPIO_Name_t pin);

    LQ_GPIO的头文件如下:

    #ifndef SRC_LQ_GPIO_H_
    #define SRC_LQ_GPIO_H_
    
    #include "Platform_Types.h"
    #include "IfxPort_regdef.h"
    #include "IfxPort.h"
    
    // GPIO Port No.
    typedef enum //
    {
        P10_5 = 0xB005,
        P10_6 = 0xB006,
        P20_6 = 0xC006,
        P20_7 = 0xC007,
    }GPIO_Name_t;
    
    //GPIO Mode
    #define PIN_MODE_OUTPUT          IfxPort_Mode_outputPushPullGeneral    /*!< 推挽输出  */
    #define PIN_MODE_OUTPUT_OD       IfxPort_Mode_outputOpenDrainGeneral   /*!< 开漏输出  */
    #define PIN_MODE_INPUT           IfxPort_Mode_inputNoPullDevice        /*!< 浮空输入  */
    #define PIN_MODE_INPUT_PULLUP    IfxPort_Mode_inputPullUp              /*!< 上拉输入  */
    #define PIN_MODE_INPUT_PULLDOWN  IfxPort_Mode_inputPullDown            /*!< 下拉输入  */
    
    // Get the GPIO Port Module Base Address
    #define PIN_GetModule(GPIO_NAME)    (Ifx_P*)(0xF0030000u | (GPIO_NAME & 0xFF00))
    // Get the GPIO Port Pin Index
    #define PIN_GetIndex(GPIO_NAME)    (uint8)(GPIO_NAME & 0x000F)
    
    void PIN_InitConfig(GPIO_Name_t pin,IfxPort_Mode mode, uint8 output);
    void PIN_Write(GPIO_Name_t pin,uint8 output);
    void PIN_Reverse(GPIO_Name_t pin);
    
    #endif /* SRC_LQ_GPIO_H_ */
    
    • 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

    对应的实现源文件是:

    #include "LQ_GPIO.h"
    
    void PIN_InitConfig(GPIO_Name_t pin,IfxPort_Mode mode,uint8 output)
    {
        Ifx_P *port = PIN_GetModule(pin);
        unsigned char pinIndex = PIN_GetIndex(pin);
    
        // 配置GPIO模式
        IfxPort_setPinMode(port, pinIndex, mode);
        IfxPort_setPinPadDriver(port, pinIndex, IfxPort_PadDriver_cmosAutomotiveSpeed2);
    
        /* GPIO输出模式时 输出状态 */
        if (0 == output)
        {
            IfxPort_setPinState(port, pinIndex, IfxPort_State_low);
        }
        else
        {
            IfxPort_setPinState(port, pinIndex, IfxPort_State_high);
        }
    }
    
    
    void PIN_Write(GPIO_Name_t pin,unsigned char output)
    {
        Ifx_P *port = PIN_GetModule(pin);
        unsigned char pinIndex = PIN_GetIndex(pin);
    
        // GPIO output Mode
        if (output == 0)
        {
            IfxPort_setPinState(port, pinIndex, IfxPort_State_low);
        }
        else
        {
            IfxPort_setPinState(port, pinIndex, IfxPort_State_high);
        }
    }
    
    void PIN_Reverse(GPIO_Name_t pin)
    {
        Ifx_P *port = PIN_GetModule(pin);
        unsigned char pinIndex = PIN_GetIndex(pin);
    
        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
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    3.2.2 LQ_GPIO_LED

    建立LED与GPIO引脚的关系并定义相关操作,编写LQ_GPIO_LED头文件,该头文件主要目的是:

    • 定义LED灯的编号枚举类LEDn_e
    • 定义LED灯的状态枚举类LEDs_e
    • 定义LED灯编号与PIN NAME的对应关系
    • 声明LED初始化函数_void GPIO_LED_Init(void);_
    • 声明LED控制函数_void LED_Ctrl(LEDn_e LEDn,LEDs_e LEDs);_
    • 声明LED测试函数void Test_GPIO_LED(void);

    相关头文件:

    #ifndef SRC_LQ_GPIO_LED_H_
    #define SRC_LQ_GPIO_LED_H_
    
    #include "LQ_GPIO.h"
    
    // define enum for LED number
    typedef enum
    {
        LED0 = 0,
        LED1 = 1,
        LED2 = 2,
        LED3 = 3,
        LED_ALL = 4
    } LEDn_e;
    
    // define enum for LED state
    typedef enum
    {
        ON = 0,
        OFF = 1,
        RVS = 2 
    }LEDs_e;
    
    // LED and Pin
    #define LED0p   P10_6
    #define LED1p   P10_5
    #define LED2p   P20_6
    #define LED3p   P20_7
    
    void GPIO_LED_Init(void);
    void LED_Ctrl(LEDn_e LEDn,LEDs_e LEDs);
    void Test_GPIO_LED(void);
    
    #endif /* SRC_LQ_GPIO_LED_H_ */
    
    • 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

    对应的源文件:

    #include "LQ_GPIO_LED.h"
    #include "LQ_STM.h"
    
    
    void GPIO_LED_Init(void)
    {
        // 初始化,输入口,高电平
        PIN_InitConfig(LED0p, PIN_MODE_OUTPUT, 0);
        PIN_InitConfig(LED1p, PIN_MODE_OUTPUT, 0);
        PIN_InitConfig(LED2p, PIN_MODE_OUTPUT, 0);
        PIN_InitConfig(LED3p, PIN_MODE_OUTPUT, 0);
    }
    
    
    void LED_Ctrl(LEDn_e LEDno,LEDs_e sta)
    {
        switch(LEDno)
        {
            case LED0:
                if(sta==ON)    PIN_Write(LED0p, 0);
                else if(sta==OFF)    PIN_Write(LED0p, 1);
                else if(sta==RVS)   PIN_Reverse(LED0p);
            break;
    
            case LED1:
              if(sta==ON)        PIN_Write(LED1p,0);
              else if(sta==OFF) PIN_Write(LED1p,1);
              else if(sta==RVS) PIN_Reverse(LED1p);
            break;
    
            case LED2:
              if(sta==ON)        PIN_Write(LED2p,0);
              else if(sta==OFF) PIN_Write(LED2p,1);
              else if(sta==RVS) PIN_Reverse(LED2p);
            break;
    
            case LED3:
              if(sta==ON)        PIN_Write(LED3p,0);
              else if(sta==OFF) PIN_Write(LED3p,1);
              else if(sta==RVS) PIN_Reverse(LED3p);
            break;
    
            case LED_ALL:
              if(sta==ON)
              {
                  PIN_Write(LED0p,0);
                  PIN_Write(LED1p,0);
                  PIN_Write(LED2p,0);
                  PIN_Write(LED3p,0);
              }
              else if(sta==OFF)
              {
                  PIN_Write(LED0p,1);
                  PIN_Write(LED1p,1);
                  PIN_Write(LED2p,1);
                  PIN_Write(LED3p,1);
              }
              else if(sta==RVS)
              {
                  PIN_Reverse(LED0p);
                  PIN_Reverse(LED1p);
                  PIN_Reverse(LED2p);
                  PIN_Reverse(LED3p);
              }
            break;
            default:
            break;
        }
    }
    
    void Test_GPIO_LED(void)
    {
        GPIO_LED_Init();
        while(1)
        {
            LED_Ctrl(LED_ALL, RVS);
            delayms(100);
        }
    }
    
    • 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

    3.2.3 LQ_STM

    由于实现对LED的翻转闪烁控制,需要实现计时功能,即要借助于TC264的系统定时器(STM),并实现自己的定时功能,LQ_STM实现以下功能:

    • 定义STM枚举类STM_t,包含STM0和STM1,其实这个对应于TC264两个CPU的时钟源,我们这里当然选STM0
    • 声明微妙级的延时函数_void STM_DelayUs(STM_t stm, unsigned long us);_
    • 声明毫秒级的延时函数_void delayms(unsigned short stmms);_

    声明两个延时函数:第一个是通过调用iLLD中的IfxStm_getTicksFromMicroseconds函数实现精确的微妙级计时;第二个是调用汇编指令NOP(无操作)实现不怎么精确的计时。
    本例中用#if条件汇编指令默认选用第一种方法

    头文件:

    #ifndef LQ_STM_H_
    #define LQ_STM_H_
    
    #include "Platform_Types.h"
    #include "IfxStm_regdef.h"
    #include "IfxStm.h"
    #include "IfxStm_cfg.h"
    
    // STM Module enumerate
    typedef enum{
        STM0 = 0,
        STM1 = 1
    }STM_t;
    
    void STM_DelayUs(STM_t stm, unsigned long us);
    void delayms(unsigned short stmms);
    
    # endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    对应的实现源文件:

    #include "LQ_STM.h"
    
    // STM Delay
     void STM_DelayUs(STM_t stm, uint32 us)
     {
        Ifx_STM * STM = IfxStm_getAddress((IfxStm_Index)stm);
        uint32 tick = IfxStm_getTicksFromMicroseconds(STM, us);
    
        IfxStm_waitTicks(STM, tick);
     }
    
    
    // delay function
    void delayms(unsigned short stmms)
    {
        #if 1
        // Accurate Delay
        while(stmms--){
            STM_DelayUs(STM0,1000);
        }
        #else 
        // Not accurate delay
        volatile unsigned long i = 0;
        while(stmms--)
        {
            for(i=0;i<16580;++i){
                __asm("NOP");
            }
        }
        #endif
    }
    
    • 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

    3.2.4 Cpu0_Main.c

    我们只利用Cpu0进行LED的控制,以下为源文件:

    #include "LQ_GPIO_LED.h"
    #include "IfxCpu.h"
    #include "IfxScuWdt.h"
    #include "IfxScuCcu.h"
    #include "LQ_STM.h"
    
    
    IfxCpu_mutexLock mutexCpu0InitIsOk = 1; // Flag of Cpu0 initialization
    
    int core0_main(void)
    {
        // Close the CPU Interrupt
        IfxCpu_disableInterrupts();
        // Close the Watch Dog
        IfxScuWdt_disableCpuWatchdog(IfxScuWdt_getCpuWatchdogPassword());
        IfxScuWdt_disableSafetyWatchdog(IfxScuWdt_getSafetyWatchdogPassword());
        // Initial LED
        GPIO_LED_Init();
        // Open CPU Interrupt
        IfxCpu_enableInterrupts();
        // Tell Cpu1, the Cpu0 finished initialization
        IfxCpu_releaseMutex(&mutexCpu0InitIsOk);
    
        while(1)
        {
            LED_Ctrl(LED_ALL,RVS);
            delayms(100);
        }
        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

    mutexCpu0InitIsOk变量是用来定义互斥锁的,其实在本例中没有什么用处。

    3.2.5 Cpu1_Main.c

    对应的Cpu1的源文件:

    #include "Ifx_Types.h"
    #include "IfxCpu.h"
    #include "IfxScuWdt.h"
    
    extern IfxCpu_mutexLock mutexCpu0InitIsOk;
    
    int core1_main(void)
    {
        // 开启CPU总中断
        IfxCpu_enableInterrupts();
        // 关闭看门狗
        IfxScuWdt_disableCpuWatchdog (IfxScuWdt_getCpuWatchdogPassword ());
        // 等待CPU0 初始化完成
        while(!IfxCpu_acquireMutex(&mutexCpu0InitIsOk));
        while(1)//主循环
        {
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4. Build & Debug

    4.1 编译

    点击Build按钮,对代码进行编译:
    image.png
    编译结束后,务必保证无Error:
    image.png
    同时,在Debug文件夹下会产生.elf文件,用于debug和下载
    image.png

    4.2 Debug

    Debug前,请务必用英飞凌的DAS工具确保硬件与PC通讯连接,连接方法本文不赘述。

    点击debug按钮旁边的小三角,选择Debug Configurations
    image.png
    双击TASKING C/C++ Debugger:
    image.png
    ① 选择出现的"LQ_GPIO_LED",② 选择默认出现的File,③ 将其删除 ④ 选择Add,在弹出的对话框中添加刚才的.elf文件 ⑤ 点击Debug
    image.png
    弹出对话框,选择“Switch”:
    image.png
    出现Debug界面,可以进行Debug:
    image.png

  • 相关阅读:
    STC8H开发(十五): GPIO驱动Ci24R1无线模块
    chatglm3-6b部署及微调
    boomYouth
    【python学习】Day-023 正则表达式
    C++算法前缀和的应用:分割数组的最大值的原理、源码及测试用例
    毛里智慧小学宿舍楼工程量清单编制
    [附源码]Python计算机毕业设计SSM教学团队管理系统(程序+LW)
    从零开始搭建搜索推荐系统(五十二)ElasticSearch搜索利器
    一本了解生成式人工智能
    龙迅LT89101L 是一款高性能 MIPI 至 LVDS 电平转换器
  • 原文地址:https://blog.csdn.net/CrazyRabbit1989/article/details/126090460