本文介绍如何应用Infineon官方提供的免费IDE开发环境AURIX Development Studio和TC264开发板(龙邱科技提供)实现LED的闪烁。
1. AURIX Development Studio
AURIX Development Studio(下简称ADS), 是英飞凌推出在针对自家AURIX芯片的免费编译环境,软件使用无需license,长期免费。该开发环境基于业内流行的Eclipse打造而成,界面非常友好,对于刚刚接触英飞凌的朋友们而言更是易于上手。ADS集成了编译器、调试器、iLLD底层开发库等必备组件,无需开发者四处寻找调试器和底层库代码。ADS的编译器和调试器是基于TASKING编译器、调试器打造而成,稳定性上无需额外担心,调试器比较难用,全当是一个高阶版的下载器吧。
2. 硬件环境
本次实现的硬件环境是用龙邱科技提供的TC264核心板+母版+下载器:
3.代码
3.1新建工程
打开ADAS,选择工作区(略)之后,在File→New,新建AURIX工程
填写工程名称,选择Next下一步:
选择对应的芯片(TC26x B-Step),点击Finish:
在产生的结构树中新建一个“src”文件夹,用于存放自己写的代码:
建立以下代码文件:
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)
如上表,每个Moudule的所有寄存器加起来需要的内存大小有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;
定义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的头文件(.h文件)如下:
#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 //
{
P21_4 = 0xC104,
P21_5 = 0xC105,
P20_8 = 0xC008,
P20_9 = 0xC009,
}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_ */
其中typedef enum中的地址为下图对应的地址
查看原理图,发现开发板的四个等分别是P21.4,P21.5,P20.8,P20.9所以0xC104,0xC105,0xC008,0xC009。这个根据自己开发板而定。
对应的实现源文件(.c文件)是:
#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);
}
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);
相关头文件(.h文件):
#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 P20_8
#define LED1p P20_9
#define LED2p P21_4
#define LED3p P21_5
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_ */
对应的源文件(.c文件):
#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);
}
}
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条件汇编指令默认选用第一种方法
头文件(.h文件):
#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
对应的源文件(.c文件):
#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
}
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);
}
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)//主循环
{
}
}
4. Build & Debug
注意:在这一步的编译和Debug中,如果提示“找不到FTD2××.dll”,都是因为开发板和电脑没有连接上,可以打开设备管理器,找到对应串口安装
4.1 编译
点击Build按钮,对代码进行编译:
编译结束后,务必保证无Error:
同时,在Debug文件夹下会产生.elf文件,用于debug和下载
4.2 Debug
Debug前,请务必用英飞凌的DAS工具确保硬件与PC通讯连接,连接方法本文不赘述。
点击debug按钮旁边的小三角,选择Debug Configurations
双击TASKING C/C++ Debugger:
① 选择出现的"LQ_GPIO_LED",② 选择默认出现的File,③ 将其删除 ④ 选择Add,在弹出的对话框中添加刚才的.elf文件 ⑤ 点击Debug
弹出对话框,选择“Switch”:
出现Debug界面,可以进行Debug:
4.3 烧录
点击这个就能烧录了。