基于S32K148快速调试TJA1101

1.前言

汽车架构演变[图片来源:NXP]

如上图所示,为了适应车身越来越多的ECU节点,汽车电子架构正在从传统的分布式往集中式(Domain、Zonal)转变。在这转变的过程中,除了传统的CAN,LIN节点变多之外,汽车以太网也开始被广泛的使用。

以下图(传统的分布式架构)为例,汽车以太网主要用于大数据传输的场合,如摄像头,雷达,显示,网关等。

分布式架构中车载网络[图片来源:NXP]

在CAN、LIN收发器占据大部分市场份额的NXP也早在2017年推出了百兆车载以太网PHY芯片-TJA1100,随后又推出了TJA1101,TJA1102等产品,roadmap如下所示,下文将介绍如何快速调试TJA1101。

NXP PHY Roadmap[图片来源:NXP]

2.TJA1101简介

TJA1101为单端口IEEE 802.3bw(100BASE-T1) PHY,符合功能安全ASIL-A。可通过非屏蔽双绞线(UTP)电缆提供100Mbit/s的发送和接收能力,同时针对耦合到UTP线路的容性信号耦合进行了优化,支持至少15米的电流长度。TJA1101与介质访问控制单元(MAC)的通信接口为MII或者RMII。

TJA1101支持符合OPEN联盟TC10标准的睡眠和唤醒转发解决方案,具体如下,同时拥有和唤醒线路相关的本地唤醒引脚。

  • 全局系统唤醒
  • 通过总线进行可靠的远程唤醒检测
  • PHY层级唤醒转发
  • 进入睡眠时的握手确认
  • 节省一个额外的唤醒线路

3.TJA1101调试

目前TJA1101系列主推的是TJA1101BHN,但是笔者手上只有S32K148+TJA1101AHN的板子,TJA1101AHN和TJA1101BHN是软硬件兼容的,这里就以TJA1101AHN为例,介绍调试相关的内容。

3.1 硬件

测试环境主要由两块板子组成,一块S32K148评估板,用于驱动TJA1101,并发送数据;一块以太网转接板,将车载以太网信号转为工业以太网信号,方便在电脑上查看。

3.1.1 整体框图

整个测试环境的框图如下所示:

整体框图

3.1.2 评估板

对于TJA1101的调试工作在S32K148评估板完成,如下是S32K148评估板有关以太网部份的介绍。

3.1.2.1 参考原理图

TJA1101的推荐电路图如下所示,

TJA1101推荐电路图

其中使用本地25MHz晶振的MII和RMII连接方式如下图所示,

MII and RMII

3.1.2.2 引脚说明

TJA1101和S32K148的接口主要是®MII和SMI,S32K148用到的引脚以及功能定义如下:

MII接口和SMI接口

同时,TJA1101有一些引脚具有pin strapping的功能,如下所示:(红框中是S32K148板子的实际配置)

Pin strapping

3.1.3 转接板

以太网转接板主要元器件为一颗工业以太网PHY+以太网PHY,然后都配置成Reverse MII模式,用来实现车载以太网的信号转换成传统的工业以太网的信号

3.1.3.1 参考原理图

Reverse MII模式下的TJA1101推荐原理图如下:

Reverse MII

3.1.3.2 模式配置

参考上一章节有关pin strapping的描述,转接板上TJA1101的配置为:Master,自主模式,Reverse MII。

3.1.3.3 原理介绍

如果需要深入了解转接板的原理图,可以查看胡工的公众号文章,链接如下:

3.2 软件

接下来是软件的配置介绍,本次对于TJA1101的调试基于S32DS 2.2自带的如下例程进行修改。

phy_tja1101_s32k148

打开例程后,图形化界面相关的组件有三个,其中GPIO口的配置参考3.1.2.2章节进行设置,phy和mac的设置介绍如下。

3.2.1 物理层(TJA1101):

打开phy组件的图形化界面,如下所示:

PHY配置

其中,有四项配置说明下:

  • Address设置需要和pin strapping的设置匹配,或者使用广播地址0x00
  • PHY Role,设置为自动,跟随pin strapping,为从机模式
  • link Up Event Callback,填充link up事件发生时调用的回调函数名称
  • link Down Event Callback,填充link down事件发生时调用的回调函数名称
3.2.2 数据链路层(S32K148):

打开ethernet组件的图形化界面,如下所示:

MAC配置

其中,有两项配置说明下:

  • MAC Address,测试时随便填充即可,实际使用时车厂统一分配
  • MII configuration,选择模式,速度以及全双工/半双工
3.2.3 主要代码
#define GPIO_PORT   PTE
#define PCC_CLOCK   PCC_PORTE_CLOCK
#define LED1_RED    (1 << 21U)
#define LED2_YELLOW  (1 << 22U)
#define LED3_BLUE   (1 << 23U)
#define PTB_PHY_INT (1 << 20U)
#define PTC_BTN0    (1 << 12U)
#define PTC_BTN1    (1 << 13U)


#define PHY_CONFIG1                  18U
#define PHY_CONFIG1_FWDREM           0x0004U
#define PHY_EXTENDED_CTRL_ADDR       17U
#define PHY_EXTENDED_CTRL_CONFIG_EN  0x0004U
#define PHY_COM_CONFIG               27U
#define PHY_COM_CONFIG_WAKE          0x0040U

static uint8_t srcMacaddress[]={0x11,0x22,0x33,0x44,0x55,0x99};

typedef struct {
	uint8_t destAddr[6];
	uint8_t srcAddr[6];
	uint16_t length;
	uint8_t payload[1500];
} mac_frame_t;

void copyBuff(uint8_t *dest, uint8_t *src, uint32_t len)
{
	uint32_t i;

	for (i = 0; i < len; i++)
	{
		dest[i] = src[i];
	}
}

void rx_callback(uint8_t instance, enet_event_t event, uint8_t ring)
{
	(void)instance;

	if (event == ENET_RX_EVENT)
	{
		enet_buffer_t buff;
		status_t status;

		status = ENET_DRV_ReadFrame(INST_ETHERNET1, ring, &buff, NULL);
		if (status == STATUS_SUCCESS)
		{
			mac_frame_t *frame;

			frame = (mac_frame_t *) buff.data;

			/* You can process the payload here */
			(void)frame->payload;

//	        /*turn off Blue led*/
//	        PINS_DRV_SetPins(GPIO_PORT, LED3_BLUE);

			ENET_DRV_ProvideRxBuff(INST_ETHERNET1, ring, &buff);
		}
	}
}

/* Port C IRQ handler */
void portc_Handler(void)
{
	uint32_t flags;
	static bool loopback;
	static phy_role_t phyRole = PHY_ROLE_MASTER;
	uint32_t delay = 1000000U;

	do
	{
		/* wait some time to allow capturing pushing multiple buttons at once */
		delay--;
	}
	while(delay != 0);

	flags = PINS_DRV_GetPortIntFlag(PORTC);
	if ((flags & (PTC_BTN1 | PTC_BTN0)) == (PTC_BTN1 | PTC_BTN0))
	{
		/* both buttons pressed - change master/slave settings */
		PHY_SetRole(0, phyRole);
		phyRole = (phyRole == PHY_ROLE_MASTER) ? (PHY_ROLE_SLAVE) : (PHY_ROLE_MASTER);
	}
	else
	{
		if ((flags & PTC_BTN1) != 0U)
		{
			PHY_Sleep(0);
		}
		if ((flags & PTC_BTN0) != 0U)
		{
			if (loopback)
			{
				PHY_SetLoopback(0, PHY_LOOPBACK_NONE);
			}
			else
			{
				PHY_SetLoopback(0, PHY_LOOPBACK_INTERNAL);
			}
			loopback = !loopback;
		}
	}
    /* Clear interrupt flag */
	PINS_DRV_ClearPortIntFlagCmd(PORTC);
}

/* Link up callback */
void link_up(uint8_t phy)
{
	if (phy == 0U)
	{
		/* if link up,turn off red led and turn on yellow led*/
		PINS_DRV_ClearPins(GPIO_PORT, LED2_YELLOW);
		PINS_DRV_SetPins(GPIO_PORT, LED1_RED);
		PINS_DRV_SetPins(GPIO_PORT, LED3_BLUE);
	}
}

/* Link down callback  */
void link_down(uint8_t phy)
{
	if (phy == 0U)
	{
		/* set PTE21 to low for turning on Red led*/
		PINS_DRV_ClearPins(GPIO_PORT, LED1_RED);
		PINS_DRV_SetPins(GPIO_PORT, LED2_YELLOW);
		PINS_DRV_SetPins(GPIO_PORT, LED3_BLUE);
	}
}

/*!
 \brief The main function for the project.
 \details The startup initialization sequence is the following:
 * - startup asm routine
 * - main()
 */
int main(void)
{
  /* Write your local variable definition here */
  enet_buffer_t buff;
  mac_frame_t frame;
  uint8_t i;
  status_t ENET_status;
  static uint16_t extCtrl = 0;

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
#ifdef PEX_RTOS_INIT
  PEX_RTOS_INIT(); /* Initialization of the selected RTOS. Macro is defined by the RTOS component. */
#endif
  /*** End of Processor Expert internal initialization.                    ***/

  /* Initialize and configure clocks
   * 	-	see clock manager component for details
   */
  CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT,
                 g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
  CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_AGREEMENT);

  /* Initialize pins
   *	-	See PinSettings component for more info
   */
  PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);

  /* Initialize ENET instance */
  ENET_DRV_Init(INST_ETHERNET1, &ethernet1_State, &ethernet1_InitConfig0, ethernet1_buffConfigArr0, ethernet1_MacAddr);
  ENET_DRV_EnableMDIO(INST_ETHERNET1, false);

  /* turn on Red led for init */
  PINS_DRV_ClearPins(GPIO_PORT, LED1_RED);

  PHY_FrameworkInit(phyConfig, phyDrivers);
  PHY_Init(0);

  /* make custom settings */
  PHY_RMR(0, PHY_EXTENDED_CTRL_ADDR, PHY_EXTENDED_CTRL_CONFIG_EN, PHY_EXTENDED_CTRL_CONFIG_EN);
  PHY_RMR(0, PHY_CONFIG1, PHY_CONFIG1_FWDREM, PHY_CONFIG1_FWDREM);
  PHY_RMR(0, PHY_COM_CONFIG, PHY_COM_CONFIG_WAKE, PHY_COM_CONFIG_WAKE);  /* ratio metric threshold on wake pin */
  PHY_RMR(0, PHY_EXTENDED_CTRL_ADDR, 0, PHY_EXTENDED_CTRL_CONFIG_EN);

  INT_SYS_InstallHandler(PORTC_IRQn, portc_Handler, (isr_t *)0);
  INT_SYS_EnableIRQ(PORTC_IRQn);

//  /* set tja1101 into internal loopback mode */
//  PHY_SetLoopback(0, PHY_LOOPBACK_INTERNAL);


  /* prepare for sending data */
  for (i = 0; i < 50U; i++)
  {
	  frame.payload[i] = i;
  }
  copyBuff(frame.destAddr, ethernet1_MacAddr, 6U);
  copyBuff(frame.srcAddr, srcMacaddress, 6U);
  frame.length = 50U;
  buff.data = (uint8_t *)&frame;
  /* Length == 12 bytes MAC addresses + 2 bytes length + 50 bytes payload */
  buff.length = 64U;

  ENET_DRV_SendFrame(INST_ETHERNET1, 0U, &buff, NULL);
  OSIF_TimeDelay(500);
  while (1)
  {
	  /* Provides polling support, by handling specific events */
	  PHY_MainFunction(0);

	  ENET_status = ENET_DRV_GetTransmitStatus(INST_ETHERNET1,0,&buff, NULL);
	  if (ENET_status == STATUS_SUCCESS)
	  {
		  ENET_DRV_SendFrame(INST_ETHERNET1, 0U, &buff, NULL);
		  /* if send ok, toggle yellow led*/
		  PINS_DRV_TogglePins(GPIO_PORT, LED2_YELLOW);
	  }

      PHY_Read(0, PHY_EXTENDED_CTRL_ADDR, &extCtrl);
      if (extCtrl == 0xD000U)
      {
          /* when tja1101 go to sleep mode, toggle on blue led*/
    	  PINS_DRV_TogglePins(GPIO_PORT, LED3_BLUE);
  		  PINS_DRV_SetPins(GPIO_PORT, LED1_RED);
  		  PINS_DRV_SetPins(GPIO_PORT, LED2_YELLOW);
      }

	  OSIF_TimeDelay(500);
  }

3.3 测试

3.3.1 测试normal mode

连上S32K148开发板、以太网转接板以及电脑,然后上电,红色LED短暂亮一下,然后黄色LED闪烁,在电脑的抓包软件wireshark上能看到S32K148循环发送的以太网数据。

wireshark抓取的部分数据如下图:

wireshark抓取的数据

3.3.2 测试link up 和 link down

两种中断状态进入的条件如下:

link up and down

测试情况为:

  • 上电之后,先打开红色LED,然后进入link_up回调函数,关闭红色LED,打开黄色LED。wireshark显示数据正常发送的同时,黄色LED闪烁。

  • 接着断开双绞线(TRX_P和TRX_N),进入link_down回调函数,关闭黄色LED,打开红色LED。wireshark面板上没有数据显示。

  • 最后接上双绞线(TRX_P和TRX_N),进入link_up回调函数,关闭红色LED,打开黄色LED。wireshark显示数据正常发送的同时,黄色LED闪烁。

3.3.3 测试wake up

通过在WAKE_IN_OUT引脚产生上升沿去产生唤醒事件,从而唤醒TJA1101。
测试情况为:

  • 上电之后红色LED短暂亮一下,然后黄色LED闪烁。按下开发板的按钮,配置TJA1101进入sleep模式,黄色LED熄灭,蓝色LED点亮,wireshark面板上没有数据显示。

  • 在WAKE_IN_OUT引脚短接一下VDD,产生一个上升沿,唤醒TJA1101,进入normal模式,关闭蓝色LED,黄色LED闪烁,wireshark显示数据正常发送。

4.参考资料

本文主要介绍了如何快速调试TJA1101,对于很多细节的东西没有展开。后面有时间会专门写几篇文章分别介绍TJA1101的硬件设计,软件驱动以及测试注意事项。


如果觉得本文对你有用,不妨给个一键三连!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Auto FAE进阶之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值