硬件介绍:
KIT_AURIX_TC275_LITE开发板搭载了英飞凌单片三和微控制器TC275。专用于满足汽车行业的需求。
· 搭载了基于AURIX™ TriCore™ 单片三核微控制器TC275
· 板载Micro USB接口的miniWiggler调试器
· 两个Infineon Shield2Go扩展接口
· 兼容MikroBUS 和Arduino扩展连接
· 带有Infineon新一代CAN 收发器TLE9251VSJ ,可用于汽车和工业应用的HS CAN网络开发
· 已焊接可调旋转电位计,用于评估模拟电压的采集
· 一个用户输入按键
· 预留三个LED可作为工作指示灯
任务:
本期选择任务2:设计一个呼吸灯,通过旋转板卡上的电位计,改变呼吸灯闪烁速率,同时将ADC采集的数据通过串口/CAN,发送到另一台设备上显示。
实现过程:
准备工作。第一次接触英飞凌的板卡。首先是开发工具。官方提供了AURIX™ Development Studio。是一个基于Eslipse的免费IDE,使用C作为开发语言,参考着老师的直播课,拿到了官网提供的详细例程。这里使用了英飞凌底层驱动库(iLLD)做开发,大量参考了官网提供的例程。本来计划使用一下官方工具OneEye,但是太复杂了,没能搞明白,所以展示部分用pyqt写了个上位机进行显示。
动手制作。通过流程框图,可知需要实现几个功能,ADC功能,用来读取电位器的值。PWM功能,用来驱动LED灯,实现呼吸灯效果。串口功能,用来将电位器的AD值上送给电脑。通过电位器的AD值,需要控制呼吸灯的频率,所以还需要实现一个时钟,用来计时。
使用例程Blinky_LED_1_KIT_TC275_LK来作为基础框架,将项目改名。参考着例程搭建起开发板的基础框架。将LED灯控制部分删除。
串口部分参考例程“ASCLIN_UART_1_KIT_TC275_LK”。例程中是实现了串口的发和收,需要留意的是例程中使用的是P15.2/P15.3这两个管脚,想直接使用烧写器中的串口,这里需要修改到P14.0/P14.1。然后添加了一个自定义的发送字符串的函数。
#include "IfxAsclin_Asc.h"
#include "IfxCpu_Irq.h"
/*********************************************************************************************************************/
/*------------------------------------------------------Macros-------------------------------------------------------*/
/*********************************************************************************************************************/
#define UART_BAUDRATE 115200 /* UART baud rate in bit/s */
//#define UART_PIN_RX IfxAsclin0_RXB_P15_3_IN /* UART receive port pin */
//#define UART_PIN_TX IfxAsclin0_TX_P15_3_OUT /* UART transmit port pin */
//更换串口
#define UART_PIN_RX IfxAsclin0_RXA_P14_1_IN /* UART receive port pin */
#define UART_PIN_TX IfxAsclin0_TX_P14_0_OUT /* UART transmit port pin
/* Definition of the interrupt priorities */
#define INTPRIO_ASCLIN0_RX 18
#define INTPRIO_ASCLIN0_TX 19
#define UART_RX_BUFFER_SIZE 64 /* Definition of the receive buffer size */
#define UART_TX_BUFFER_SIZE 64 /* Definition of the transmit buffer size */
#define SIZE 13 /* Size of the string */
/*********************************************************************************************************************/
/*-------------------------------------------------Global variables--------------------------------------------------*/
/*********************************************************************************************************************/
/* Declaration of the ASC handle */
static IfxAsclin_Asc g_ascHandle;
/* Declaration of the FIFOs parameters */
static uint8 g_ascTxBuffer[UART_TX_BUFFER_SIZE + sizeof(Ifx_Fifo) + 8];
static uint8 g_ascRxBuffer[UART_RX_BUFFER_SIZE + sizeof(Ifx_Fifo) + 8];
/* Definition of txData and rxData */
uint8 g_txData[] = "Hello World!";
uint8 g_rxData[SIZE] = {''};
/* Size of the message */
Ifx_SizeT g_count = sizeof(g_txData);
/*********************************************************************************************************************/
/*---------------------------------------------Function Implementations----------------------------------------------*/
/*********************************************************************************************************************/
/* Adding of the interrupt service routines */
IFX_INTERRUPT(asclin0TxISR, 0, INTPRIO_ASCLIN0_TX);
void asclin0TxISR(void)
{
IfxAsclin_Asc_isrTransmit(&g_ascHandle);
}
IFX_INTERRUPT(asclin0RxISR, 0, INTPRIO_ASCLIN0_RX);
void asclin0RxISR(void)
{
IfxAsclin_Asc_isrReceive(&g_ascHandle);
}
/* This function initializes the ASCLIN UART module */
void init_ASCLIN_UART(void)
{
/* Initialize an instance of IfxAsclin_Asc_Config with default values */
IfxAsclin_Asc_Config ascConfig;
IfxAsclin_Asc_initModuleConfig(&ascConfig, &MODULE_ASCLIN0);
/* Set the desired baud rate */
ascConfig.baudrate.baudrate = UART_BAUDRATE;
/* ISR priorities and interrupt target */
ascConfig.interrupt.txPriority = INTPRIO_ASCLIN0_TX;
ascConfig.interrupt.rxPriority = INTPRIO_ASCLIN0_RX;
ascConfig.interrupt.typeOfService = IfxCpu_Irq_getTos(IfxCpu_getCoreIndex());
/* FIFO configuration */
ascConfig.txBuffer = &g_ascTxBuffer;
ascConfig.txBufferSize = UART_TX_BUFFER_SIZE;
ascConfig.rxBuffer = &g_ascRxBuffer;
ascConfig.rxBufferSize = UART_RX_BUFFER_SIZE;
/* Pin configuration */
const IfxAsclin_Asc_Pins pins =
{
NULL_PTR, IfxPort_InputMode_pullUp, /* CTS pin not used */
&UART_PIN_RX, IfxPort_InputMode_pullUp, /* RX pin */
NULL_PTR, IfxPort_OutputMode_pushPull, /* RTS pin not used */
&UART_PIN_TX, IfxPort_OutputMode_pushPull, /* TX pin */
IfxPort_PadDriver_cmosAutomotiveSpeed1
};
ascConfig.pins = &pins;
IfxAsclin_Asc_initModule(&g_ascHandle, &ascConfig); /* Initialize module with above parameters */
}
/* This function sends and receives the string "Hello World!" */
//void send_receive_ASCLIN_UART_message(void)
//{
// IfxAsclin_Asc_write(&g_ascHandle, g_txData, &g_count, TIME_INFINITE); /* Transmit data via TX */
// IfxAsclin_Asc_read(&g_ascHandle, g_rxData, &g_count, TIME_INFINITE); /* Receive data via RX */
//}
void Uart_SendStr(char* str) {
Ifx_SizeT len = (Ifx_SizeT)strlen(str);
IfxAsclin_Asc_write(&g_ascHandle, str, &len, TIME_INFINITE); /* Transmit data via TX */
}
参考例程"ADC_Single_Channel_1_KIT_TC275_LK"来读取电位器的值。电位器的值实测是从0~4095.
#include "IfxVadc_Adc.h"
#include "ADC_Single_Channel.h"
/*********************************************************************************************************************/
/*------------------------------------------------------Macros-------------------------------------------------------*/
/*********************************************************************************************************************/
#define VADC_GROUP IfxVadc_GroupId_0 /* Use the ADC group 0 */
#define CHANNEL_ID 0 /* Use the Channel 0 */
#define CHANNEL_RESULT_REGISTER 5
/*********************************************************************************************************************/
/*-------------------------------------------------Global variables--------------------------------------------------*/
/*********************************************************************************************************************/
ApplicationVadcBackgroundScan g_vadcBackgroundScan;
/*********************************************************************************************************************/
/*---------------------------------------------Function Implementations----------------------------------------------*/
/*********************************************************************************************************************/
/* The VADC module and group are initialized */
void vadcBackgroundScanInit(void)
{
/* VADC module configuration */
/* Create VADC configuration */
IfxVadc_Adc_Config adcConfig;
/* Initialize the VADC configuration with default values */
IfxVadc_Adc_initModuleConfig(&adcConfig, &MODULE_VADC);
/* Initialize the VADC module using the VADC configuration */
IfxVadc_Adc_initModule(&g_vadcBackgroundScan.vadc, &adcConfig);
/* VADC group configuration */
/* Create group configuration */
IfxVadc_Adc_GroupConfig adcGroupConfig;
/* Initialize the group configuration with default values */
IfxVadc_Adc_initGroupConfig(&adcGroupConfig, &g_vadcBackgroundScan.vadc);
/* Define which ADC group is going to be used */
adcGroupConfig.groupId = VADC_GROUP;
adcGroupConfig.master = VADC_GROUP;
/* Enable background scan source */
adcGroupConfig.arbiter.requestSlotBackgroundScanEnabled = TRUE;
/* Enable background auto scan mode */
adcGroupConfig.backgroundScanRequest.autoBackgroundScanEnabled = TRUE;
/* Enable the gate in "always" mode (no edge detection) */
adcGroupConfig.backgroundScanRequest.triggerConfig.gatingMode = IfxVadc_GatingMode_always;
/* Initialize the group using the group configuration */
IfxVadc_Adc_initGroup(&g_vadcBackgroundScan.adcGroup, &adcGroupConfig);
}
/* The input channels to be used are setup and the VADC is set into run mode */
void vadcBackgroundScanRun(void)
{
/* Initialize the channel configuration of application handle g_vadcBackgroundScan with default values */
IfxVadc_Adc_initChannelConfig(&g_vadcBackgroundScan.adcChannelConfig, &g_vadcBackgroundScan.adcGroup);
g_vadcBackgroundScan.adcChannelConfig.channelId = (IfxVadc_ChannelId)CHANNEL_ID;
g_vadcBackgroundScan.adcChannelConfig.resultRegister = (IfxVadc_ChannelResult)CHANNEL_RESULT_REGISTER;
g_vadcBackgroundScan.adcChannelConfig.backgroundChannel = TRUE;
/* Initialize the channel of application handle g_VadcBackgroundScan using the channel configuration */
IfxVadc_Adc_initChannel(&g_vadcBackgroundScan.adcChannel, &g_vadcBackgroundScan.adcChannelConfig);
/* Enable background scan for the channel */
IfxVadc_Adc_setBackgroundScan(&g_vadcBackgroundScan.vadc,
&g_vadcBackgroundScan.adcGroup,
(1 << (IfxVadc_ChannelId)CHANNEL_ID),
(1 << (IfxVadc_ChannelId)CHANNEL_ID));
/* Start background scan conversion */
IfxVadc_Adc_startBackgroundScan(&g_vadcBackgroundScan.vadc);
}
#define RETRY_MAX 0xf000
uint32_t Adc_GetValue(void) {
Ifx_VADC_RES conversionResult;
uint16_t retry = 0;
do {
conversionResult = IfxVadc_Adc_getResult(&g_vadcBackgroundScan.adcChannel);
if (retry++ > RETRY_MAX) {
return 0xffffffff;
}
} while (!conversionResult.B.VF);
return conversionResult.B.RESULT;
}
PWM输出部分参考了“GTM_TOM_PWM_1_KIT_TC275_LK”。这里使用50000作为周期,500作为步进值。每100次循环,完成LED从暗到亮或从亮到暗的变化。所以这里只需要控制每次循环间隔的时间,就能控制呼吸灯闪烁的频率了。
#include "GTM_TOM_PWM.h"
#include "Ifx_Types.h"
#include "IfxGtm_Tom_Pwm.h"
/*********************************************************************************************************************/
/*------------------------------------------------------Macros-------------------------------------------------------*/
/*********************************************************************************************************************/
#define ISR_PRIORITY_TOM 20 /* Interrupt priority number */
#define LED IfxGtm_TOM1_4_TOUT14_P00_5_OUT /* LED which will be driven by the PWM */
#define PWM_PERIOD 50000 /* PWM period for the TOM */
#define FADE_STEP PWM_PERIOD / 100 /* PWM duty cycle for the TOM */
/*********************************************************************************************************************/
/*-------------------------------------------------Global variables--------------------------------------------------*/
/*********************************************************************************************************************/
IfxGtm_Tom_Pwm_Config g_tomConfig; /* Timer configuration structure */
IfxGtm_Tom_Pwm_Driver g_tomDriver; /* Timer Driver structure */
uint32 g_fadeValue = 0; /* Fade value, starting from 0 */
sint8 g_fadeDir = 1; /* Fade direction variable */
/*********************************************************************************************************************/
/*-----------------------------------------------Function Prototypes-------------------------------------------------*/
/*********************************************************************************************************************/
void setDutyCycle(uint32 dutyCycle); /* Function to set the duty cycle of the PWM */
/*********************************************************************************************************************/
/*--------------------------------------------Function Implementations-----------------------------------------------*/
/*********************************************************************************************************************/
/* This function initializes the TOM */
void initGtmTomPwm(void)
{
IfxGtm_enable(&MODULE_GTM); /* Enable GTM */
IfxGtm_Cmu_enableClocks(&MODULE_GTM, IFXGTM_CMU_CLKEN_FXCLK); /* Enable the FXU clock */
/* Initialize the configuration structure with default parameters */
IfxGtm_Tom_Pwm_initConfig(&g_tomConfig, &MODULE_GTM);
g_tomConfig.tom = LED.tom; /* Select the TOM depending on the LED */
g_tomConfig.tomChannel = LED.channel; /* Select the channel depending on the LED */
g_tomConfig.period = PWM_PERIOD; /* Set the timer period */
g_tomConfig.pin.outputPin = &LED; /* Set the LED port pin as output */
g_tomConfig.synchronousUpdateEnabled = TRUE; /* Enable synchronous update */
IfxGtm_Tom_Pwm_init(&g_tomDriver, &g_tomConfig); /* Initialize the GTM TOM */
IfxGtm_Tom_Pwm_start(&g_tomDriver, TRUE); /* Start the PWM */
}
/* This function creates the fade effect for the LED */
void fadeLED(void)
{
if((g_fadeValue + FADE_STEP) >= PWM_PERIOD)
{
g_fadeDir = -1; /* Set the direction of the fade */
}
else if((g_fadeValue - FADE_STEP) <= 0)
{
g_fadeDir = 1; /* Set the direction of the fade */
}
g_fadeValue += g_fadeDir * FADE_STEP; /* Calculation of the new duty cycle */
setDutyCycle(g_fadeValue); /* Set the duty cycle of the PWM */
}
//
///* This function sets the duty cycle of the PWM */
void setDutyCycle(uint32 dutyCycle)
{
g_tomConfig.dutyCycle = dutyCycle; /* Change the value of the duty cycle */
IfxGtm_Tom_Pwm_init(&g_tomDriver, &g_tomConfig); /* Re-initialize the PWM */
}
时钟部分参考了“STM_Interrupt_1_KIT_TC275_LK”。电位器AD的值事【0,4095】,中位数是2048.呼吸灯是PWM循环100次的结果,直接将AD的值放大10倍,使用us做单位,用来延时,就可以把呼吸灯从暗到亮(从亮到暗)的时长控制在0~4秒之间了。所以这里自建了一个us延时的函数。
/*********************************************************************************************************************/
#include "STM_Interrupt.h"
#include "Bsp.h"
#include "IfxPort.h"
#include "IfxStm.h"
/*********************************************************************************************************************/
/*------------------------------------------------------Macros-------------------------------------------------------*/
/*********************************************************************************************************************/
#define ISR_PRIORITY_STM 40 /* Priority for interrupt ISR */
//#define TIMER_INT_TIME 500 /* Time between interrupts in ms */
/*********************************************************************************************************************/
/*-------------------------------------------------Global variables--------------------------------------------------*/
/*********************************************************************************************************************/
IfxStm_CompareConfig g_STMConf; /* STM configuration structure */
//Ifx_TickTime g_ticksFor500ms; /* Variable to store the number of ticks to wait */
/*********************************************************************************************************************/
/*---------------------------------------------Function Implementations----------------------------------------------*/
/*********************************************************************************************************************/
/* Macro to define Interrupt Service Routine.
* This macro makes following definitions:
* 1) Define linker section as .intvec_tc<vector number>_<interrupt priority>.
* 2) define compiler specific attribute for the interrupt functions.
* 3) define the Interrupt service routine as ISR function.
*
* IFX_INTERRUPT(isr, vectabNum, priority)
* - isr: Name of the ISR function.
* - vectabNum: Vector table number.
* - priority: Interrupt priority. Refer Usage of Interrupt Macro for more details.
*/
/* Function to initialize the STM */
void initSTM(void)
{
IfxStm_initCompareConfig(&g_STMConf); /* Initialize the configuration structure with default values */
// g_STMConf.triggerPriority = ISR_PRIORITY_STM; /* Set the priority of the interrupt */
// g_STMConf.typeOfService = IfxSrc_Tos_cpu0; /* Set the service provider for the interrupts */
// g_STMConf.ticks = g_ticksFor500ms; /* Set the number of ticks after which the timer triggers an
// * interrupt for the first time */
// IfxStm_initCompare(STM, &g_STMConf); /* Initialize the STM with the user configuration */
IfxStm_initCompare(&MODULE_STM0, &g_STMConf);
}
void Delay_us(uint32_t us) {
uint32 tick = IfxStm_getTicksFromMicroseconds(&MODULE_STM0, us);
IfxStm_waitTicks(&MODULE_STM0, tick);
}
void Delay_ms(uint32_t ms) {
uint32 tick = IfxStm_getTicksFromMilliseconds(&MODULE_STM0, ms);
IfxStm_waitTicks(&MODULE_STM0, tick);
}
上位机展示。OneEye界面是真漂亮。按着官方例程实现了一下OneEye的功能。感觉过于复杂。就收工写一个上位机界面。使用pyqt做界面,用一个旋转按钮来同步电位器的信息。上位机通过串口通讯获得开发板当前的信息。
心得体会:
感谢funpack带来的这期活动。第一次接触英飞凌的板子,板子的三核还没搞明白,现在是一核工作,两核旁观。官网提供的文档着实让人吃惊,文档之多之细,确实让人佩服。参加这样的活动,受益多多,而且欢乐无穷!