CAN收发器TJA1145A休眠唤醒应用

目录

1.  TJA1145 工作原理简介

2.  SPI通讯

3.  唤醒源配置

4.  休眠配置

      


1.  TJA1145 工作原理简介

       TJA1145的唤醒工作原理主要依赖于其内部的唤醒机制和外部硬件的配合,主要涉及低功耗状态、选择性唤醒功能。TJA1145是一款CAN收发器,它支持多种工作模式,包括NormalStandbySleep等。在这些模式中,Sleep模式是最低功耗状态,而Normal模式则是最活跃的状态,其中Standby模式处于两者之间,允许一定的功能操作但功耗较低。TJA1145可以通过接收特定的唤醒源从Sleep或Standby模式唤醒到Standby或Normal模式。

  • 唤醒源的检测与处理: TJA1145内部有一个唤醒逻辑,当CAN总线上有特定的唤醒帧或者满足特定条件时,TJA1145会检测到这些唤醒源。例如,当报文过滤器的报文与唤醒帧寄存器相匹配时,TJA1145会认为检测到唤醒帧,然后通过内部逻辑使INH引脚置位变成高电平,以此来使能外部的电源芯片。INH引脚的高电平输出可以间接地使能电源芯片,从而唤醒ECU。

  • 硬件拓扑与电源管理: TJA1145的唤醒过程还需要外部硬件的支持。带唤醒功能的CAN收发器需要12V常电供电,并且INH脚需要连接到电源芯片的使能脚。这样,当CAN总线上有网络管理帧时,INH引脚变成高电平,去唤醒电源芯片,完成了一次完整的网络管理唤醒过程。

  • 状态切换与控制: TJA1145的状态切换可以通过SPI指令进行控制。例如,通过发送特定的SPI指令,可以将TJA1145从Normal或Sleep状态切换到Standby状态,或者从Standby状态切换到Sleep状态。在Sleep状态下,如果检测到有效的唤醒源,TJA1145会自动切换到Standby状态,从而通过INH引脚的高电平唤醒MCU和其他相关模块。

综上所述,TJA1145的唤醒工作原理涉及内部唤醒逻辑的检测与处理、外部硬件的支持以及通过SPI指令进行的状态切换控制。这些机制共同作用,使得TJA1145能够在需要时被唤醒,以支持汽车的网络通信和系统管理。

2.  SPI通讯

      TJA1145是通过SPI通信来配置相关寄存器的,SPI配置为全双工数据传输。开发过程中首先要保证MCU和TJA1145之间的通信正常,这个可以通过读取设备ID来验证,寄存器 0x7E 存储的为TJA1145的 ID code,如下图所示,时钟线空闲时为低电平(CPOL = 0),且在第二个跳变沿采样(CPHA = 1)。SPI使用四个接口信号进行同步和数据传输,在此不做赘述。

(1) 硬件SPI读写函数: 

/*******************************************************************************
 * 函数名  : tja1145_write_regster
 * 描  述  : write寄存器
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
uint8_t tja1145_write_regster(uint8_t reg_addr, uint8_t value)
{
    status_t ret = STATUS_SUCCESS;
    uint8_t txdata[2] = {0};
    uint8_t rxData[2] = {0};

    reg_addr = reg_addr << 1;
    txdata[0] = reg_addr;
    txdata[1] = value;

    ret = LPSPI_DRV_MasterTransferBlocking(2, txdata, rxData, 2, 1000);
    if (ret != STATUS_SUCCESS)
    {
        log("tja1145_write_regster spi write fail!\r\n");
    }
    return;
}
/*******************************************************************************
 * 函数名  : tja1145_read_regster
 * 描  述  : read寄存器
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
uint8_t tja1145_read_regster(uint8_t reg_addr)
{
    uint8_t txdata[2] = {0};
    uint8_t rxData[2] = {0};
    reg_addr = (reg_addr << 1) | 0x01;
    txdata[0] = reg_addr;
    txdata[1] = 0xFF;
    LPSPI_DRV_MasterTransferBlocking(2, txdata, rxData, 2, 1000);

    return rxData[1];
}

(2) 软件(GPIO)模拟SPI读写函数: 

/*******************************************************************************
 * 函数名  : soft_spi_send16bit
 * 描  述  : SPI读写16bit(未使用)
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
uint8_t soft_spi_send16bit(uint16_t *txData, uint16_t *rxData, uint8_t bytes)
{
    uint8_t i, j;
    E521_CS_LOW;  // CS  =0;// DHGPIOWrite(PTB, 17, 0);
    E521_CLK_LOW; // CLK =0; // DHGPIOWrite(PTB, 14, 0);
    Delay_us(e521_DelayCnt);

    for (i = 0; i < bytes; i++)
    {
        for (j = 0; j < 16; j++)
        {
            E521_CLK_HIGH; // CLK_Write(1);

            DHGPIOWrite(PTB, 16, (txData[i] >> (15 - j) & 0x01)); // MOSI_Write( (txData[i]>>(7-j) & 0x01) );
            Delay_us(e521_DelayCnt);

            E521_CLK_LOW;

            rxData[i] |= (DHGPIORead(PTB, 15) << (15 - j)); // rxData[i] |= ( MISO_Read() << (7-j) );
            //log("[%d] = %x\r\n",j,DHGPIORead(PTB, 15) << (15 - j));
            Delay_us(e521_DelayCnt);
        }
    }

    E521_CS_HIGH; // CS_Write(1);
    Delay_us(e521_DelayCnt);
    return 0;
}

/*******************************************************************************
 * 函数名  : soft_spi_ReadWrite_byte
 * 描  述  : SPI读写一个字节
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
uint8_t soft_spi_send(uint8_t *txData, uint8_t *rxData, uint8_t bytes)
{
    uint8_t i, j;
    // CS_Write(0);	
    DHGPIOWrite(PTA, 9, 0);

    // CLK_Write(0);	
    DHGPIOWrite(PTE, 15, 0);

    Delay_us(DelayCnt);

    for (i = 0; i < bytes; i++)
    {
        for (j = 0; j < 8; j++)
        {
            // CLK_Write(1);
            DHGPIOWrite(PTE, 15, 1);

            // MOSI_Write( (txData[i]>>(7-j) & 0x01) );
            DHGPIOWrite(PTA, 8, (txData[i] >> (7 - j) & 0x01));

            Delay_us(DelayCnt);

            // CLK_Write(0);
            DHGPIOWrite(PTE, 15, 0);

            // rxData[i] |= ( MISO_Read() << (7-j) );
            rxData[i] |= (DHGPIORead(PTE, 16) << (7 - j));

            Delay_us(DelayCnt);
        }
    }
    // CS_Write(1);
    DHGPIOWrite(PTA, 9, 1);
    Delay_us(DelayCnt);
    return 0;
}

/*******************************************************************************
 * 函数名  : soft_spi_ReadWrite_byte
 * 描  述  : SPI写一个字节到寄存器
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
uint8_t soft_spi_ReadWrite_byte(uint8_t txData)
{
    uint8_t rxData = 0;
    soft_spi_send(&txData, &rxData, 1);
    return rxData;
}
/*******************************************************************************
 * 函数名  : soft_Spi_write_reg
 * 描  述  : SPI写一个字节到寄存器
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
void soft_Spi_write_reg(uint8_t addr, uint8_t Tx_buf)
{
    uint8_t txdata[2] = {0};
    uint8_t rxData[2] = {0};
    addr = addr << 1;
    txdata[0] = addr;
    txdata[1] = Tx_buf;
    soft_spi_send(txdata, rxData, 2);
    return;
}
/*******************************************************************************
 * 函数名  : soft_Spi_read_reg
 * 描  述  : SPI从寄存器读一个字节
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
uint8_t soft_Spi_read_reg(uint8_t addr)
{
    uint8_t rxData[2] = {0};
    uint8_t txdata[2] = {0};
    addr = (addr << 1) | 0x01;
    txdata[0] = addr;
    txdata[1] = 0xFF;
    soft_spi_send(txdata, rxData, 2);
    return rxData[1];
}
/*******************************************************************************
 * 函数名  : soft_Spi_Write_buffer
 * 描  述  : SPI写多个字节到地址
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
void soft_Spi_Write_buffer(uint8_t addr, uint8_t *Tx_buf, uint8_t lens)
{
    uint8_t txdata[] = {0};
    uint8_t rxData[] = {0};

    txdata[0] = (addr << 1);
    for (int i = 0; i < lens; i++)
    {
        txdata[i + 1] = Tx_buf[i];
    }
    soft_spi_send(txdata, rxData, lens + 1);

    return;
}
/*******************************************************************************
 * 函数名  : soft_Spi_read_buffer
 * 描  述  : SPI写多个字节到地址
 * 输  入  : -
 * 输  出  : -
 * 返回值  : 无
 *******************************************************************************/
void soft_Spi_read_buffer(uint8_t addr, uint8_t *Rx_buf, uint8_t lens)
{
    uint8_t txdata[] = {0};
    uint8_t rxData[] = {0};

    txdata[0] = (addr << 1) | 0x01;
    for (int i = 0; i < lens; i++)
    {
        txdata[i + 1] = 0xFF;
    }
    soft_spi_send(txdata, rxData, lens + 1);
    Rx_buf = &rxData[1];

    return;
}

3.  唤醒源配置

       唤醒源配置需要将唤醒帧信息填入 TJA1145 芯片相应的寄存器中,有以下两种配置方式:配置一:只校验唤醒帧的 ID;配置二:校验唤醒帧 ID 且校验唤醒帧数据字段;

配置一:

       顾名思义,如果只校验唤醒帧的 ID,当 TJA1145 芯片收到唤醒帧的ID就会拉高INH脚,进入唤醒流程。该配置主要涉及0x29、0x2A、0x2D、0x2E 、0x2F、0x68~0x6F等寄存器。通过对这几个寄存器的配置可以实现特定帧唤醒和任意帧唤醒。0x29、0x2A寄存器配置唤醒帧ID验证码; 0x2D、0x2E寄存器配置唤醒ID掩码; 0x2F寄存器可配置唤醒条件是否需要校验数据位; 当采用方式一配置唤醒源时,0x68~0x6F寄存器需要全配置为0XFF。寄存器信息见附件TJA1145数据手册。

      本文示例为特定帧唤醒(标准帧),唤醒源为:0x400~0x47F 、0x285、0x286。具体配置如下:

    tja1145_write_regster(0X0A, 0x00);   /* < 写保护寄存器,解锁-0x00,上锁-0xFF */
    tja1145_write_regster(0X23, 0x03);   /* < 唤醒检测使能 */
    tja1145_write_regster(0X26, 0x05);   /* < 波特率寄存器 */
    tja1145_write_regster(0X2F, 0x00);   /* < 唤醒条件不需要判断数据位,长度设置为0,PNDM位 置0 */
    tja1145_write_regster(0X04, 0x06);
    
    /* 当唤醒条件设置为只判断帧ID时,需要通过该类寄存器设置唤醒帧ID验证码,见tja1145文档page19、20 */
    tja1145_write_regster(0X27, 0x00);   /* < 27寄存器,配置唤醒帧ID验证码(扩展帧) */     
    tja1145_write_regster(0X28, 0x00);   /* < 28寄存器,配置唤醒帧ID验证码(扩展帧) */
    tja1145_write_regster(0X29, 0x00);   /* < 29寄存器,配置唤醒帧ID验证码(标准帧/扩展帧)验证码:0x400 */
    tja1145_write_regster(0X2A, 0x10);   /* < 2A寄存器,配置唤醒帧ID验证码(标准帧/扩展帧)验证码:0x400 */

    /* 当支持多帧ID唤醒时,需要通过该类寄存器设置唤醒帧ID掩码,见tja1145文档page19、20 */
    tja1145_write_regster(0X2B, 0x00);   /* < 2B寄存器,配置唤醒ID掩码; */  
    tja1145_write_regster(0X2C, 0x00);   /* < 2C寄存器,配置唤醒ID掩码; */  
    /* 支持285,286,165,以及NM报文唤醒 */
    tja1145_write_regster(0X2D, 0xfc);   /* < 2D寄存器,配置唤醒ID掩码;掩码:0x37f */  
    tja1145_write_regster(0X2E, 0x0d);   /* < 2E寄存器,配置唤醒ID掩码;掩码:0x37f*/                                                             
    
    /* 当唤醒条件设置为要判断唤醒帧字段时,需要配置该类寄存器,当唤醒条件设置为只判断帧ID时,只需要需要配置该类寄存器为0XFF */
    tja1145_write_regster(0X68, 0xff);   /* < 68寄存器,配置唤醒帧数据位掩码 */
    tja1145_write_regster(0X69, 0xff);   /* < 69寄存器,配置唤醒帧数据位掩码,该寄存器第0位设置为1表示唤醒帧数据位第1个字节第0位置1才可以唤醒MCU  */
    tja1145_write_regster(0X6A, 0xff);   /* < 6A寄存器,配置唤醒帧数据位掩码 */
    tja1145_write_regster(0X6B, 0xff);   /* < 6B寄存器,配置唤醒帧数据位掩码 */
    tja1145_write_regster(0X6C, 0xff);   /* < 6C寄存器,配置唤醒帧数据位掩码,该寄存器第0位、第1位设置为1表示唤醒帧数据位第4个字节的第0位或者第1位置1才可以唤醒MCU  */
    tja1145_write_regster(0X6D, 0xff);   /* < 6D寄存器,配置唤醒帧数据位掩码 */
    tja1145_write_regster(0X6E, 0xff);   /* < 6E寄存器,配置唤醒帧数据位掩码 */
    tja1145_write_regster(0X6F, 0xff);   /* < 6F寄存器,配置唤醒帧数据位掩码 */

    tja1145_write_regster(0X20, 0x71);   /* 使能CAN指定ID唤醒 */
    tja1145_write_regster(0X01, 0x07);   /* < 模式选择寄存器, Sleep mode-0x01,Standby mode-0x04,Normal mode-0x07 */
    tja1145_write_regster(0X0A, 0xff);   /* < 写保护寄存器,解锁-0x00,上锁-0xFF */

配置二: 

       如果校验唤醒帧 ID 且校验唤醒帧数据字段,当 TJA1145 芯片收到唤醒帧的ID且收到特定的数据才会拉高INH脚,进入唤醒流程。该配置涉及寄存器与方法一相同。主要有0x29、0x2A、0x2D、0x2E 、0x2F、0x68~0x6F 等寄存器。通过对这几个寄存器的配置可以实现特定帧唤醒和任意帧唤醒。0x29、0x2A寄存器配置唤醒帧ID验证码; 0x2D、0x2E寄存器配置唤醒ID掩码; 0x2F寄存器可配置唤醒条件是否需要校验数据位; 当采用方式一配置唤醒源时,0x68~0x6F寄存器需要全配置为0XFF。寄存器信息见附件TJA1145数据手册。

      本文示例为特定帧唤醒(标准帧),唤醒源为:0x400~0x47F 、0x285、0x286且数据字段第4个字节必须为0x03.。具体配置如下:

    tja1145_write_regster(0X0A, 0x00);   /* < 写保护寄存器,解锁-0x00,上锁-0xFF */
    tja1145_write_regster(0X23, 0x03);   /* < 唤醒检测使能 */
    tja1145_write_regster(0X26, 0x05);   /* < 波特率寄存器 */
    tja1145_write_regster(0X2F, 0x48);   /* < 唤醒条件不需要判断数据位,长度设置为0,PNDM位 置0 */
    tja1145_write_regster(0X04, 0x06);

    /* 当唤醒条件设置为只判断帧ID时,需要通过该类寄存器设置唤醒帧ID验证码,见tja1145文档page19、20 */
    tja1145_write_regster(0X27, 0x00);   /* < 27寄存器,配置唤醒帧ID验证码(扩展帧) */     
    tja1145_write_regster(0X28, 0x00);   /* < 28寄存器,配置唤醒帧ID验证码(扩展帧) */
    tja1145_write_regster(0X29, 0x00);   /* < 29寄存器,配置唤醒帧ID验证码(标准帧/扩展帧)验证码:0x400 */
    tja1145_write_regster(0X2A, 0x10);   /* < 2A寄存器,配置唤醒帧ID验证码(标准帧/扩展帧)验证码:0x400 */

    /* 当支持多帧ID唤醒时,需要通过该类寄存器设置唤醒帧ID掩码,见tja1145文档page19、20 */
    tja1145_write_regster(0X2B, 0x00);   /* < 2B寄存器,配置唤醒ID掩码; */  
    tja1145_write_regster(0X2C, 0x00);   /* < 2C寄存器,配置唤醒ID掩码; */  
    /* 支持285,286,165,以及NM报文唤醒 */
    tja1145_write_regster(0X2D, 0xfc);   /* < 2D寄存器,配置唤醒ID掩码;掩码:0x37f */  
    tja1145_write_regster(0X2E, 0x0d);   /* < 2E寄存器,配置唤醒ID掩码;掩码:0x37f*/                                                             
    
    /* 当唤醒条件设置为要判断唤醒帧字段时,需要配置该类寄存器,当唤醒条件设置为只判断帧ID时,只需要需要配置该类寄存器为0XFF */
    tja1145_write_regster(0X68, 0x00);   /* < 68寄存器,配置唤醒帧数据位掩码,该寄存器第0位设置为1表示唤醒帧数据位第0个字节第0位置1才可以唤醒MCU */
    tja1145_write_regster(0X69, 0x00);   /* < 69寄存器,配置唤醒帧数据位掩码,该寄存器第0位设置为1表示唤醒帧数据位第1个字节第0位置1才可以唤醒MCU */
    tja1145_write_regster(0X6A, 0x00);   /* < 6A寄存器,配置唤醒帧数据位掩码,该寄存器第0位设置为1表示唤醒帧数据位第2个字节第0位置1才可以唤醒MCU */
    tja1145_write_regster(0X6B, 0x00);   /* < 6B寄存器,配置唤醒帧数据位掩码,该寄存器第0位设置为1表示唤醒帧数据位第3个字节第0位置1才可以唤醒MCU */
    tja1145_write_regster(0X6C, 0x03);   /* < 6C寄存器,配置唤醒帧数据位掩码,该寄存器第0位、第1位设置为1表示唤醒帧数据位第4个字节的第0位或者第1位置1才可以唤醒MCU  */
    tja1145_write_regster(0X6D, 0x00);   /* < 6D寄存器,配置唤醒帧数据位掩码,该寄存器第0位设置为1表示唤醒帧数据位第5个字节第0位置1才可以唤醒MCU */ 
    tja1145_write_regster(0X6E, 0x00);   /* < 6E寄存器,配置唤醒帧数据位掩码,该寄存器第0位设置为1表示唤醒帧数据位第6个字节第0位置1才可以唤醒MCU */ 
    tja1145_write_regster(0X6F, 0x00);   /* < 6F寄存器,配置唤醒帧数据位掩码,该寄存器第0位设置为1表示唤醒帧数据位第7个字节第0位置1才可以唤醒MCU */

    tja1145_write_regster(0X20, 0x71);   /* 使能CAN指定ID唤醒 */
    tja1145_write_regster(0X01, 0x07);   /* < 模式选择寄存器, Sleep mode-0x01,Standby mode-0x04,Normal mode-0x07 */
    tja1145_write_regster(0X0A, 0xff);   /* < 写保护寄存器,解锁-0x00,上锁-0xFF */

4.  休眠配置

     安装好唤醒源后就可以配置TJA1145进入低功耗模式,在进入休眠前要注意先清除所有事件状态位,涉及的寄存器地址有0x60、0x61、0x63、0x64,清除事件状态位的方法为:向0x60、0x61、0x63、0x64寄存器写0xFF。本文示例如下:

    tja1145_write_regster(0x0A, 0x00);   /*解锁*/
	tja1145_write_regster(0X60, 0X00);   /*清全局事件状态寄存器*/
	tja1145_write_regster(0X61, 0xff);   /*清系统事件状态寄存器*/
	tja1145_write_regster(0X63, 0xff);   /*清发送事件状态寄存器*/
	tja1145_write_regster(0X64, 0xff);   /*清唤醒事件状态寄存器*/
	tja1145_write_regster(0X01, 0X01);   /* tja1445进入sleep模式 */

      

  • 32
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值