本文介绍如何应用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按钮旁边的小三角,选择debug configurations
双击tasking c/c++ debugger:
① 选择出现的"lq_gpio_led",② 选择默认出现的file,③ 将其删除 ④ 选择add,在弹出的对话框中添加刚才的.elf文件 ⑤ 点击debug 弹出对话框,选择“switch”:
出现debug界面,可以进行debug:
4.3 烧录
点击这个就能烧录了。
发表评论