开发中用到TJA1145模块的休眠唤醒功能,由于时间紧只关注了用到的部分,如有错误还请指正
一、基础知识:
1、CAN总线通常采用双绞线来传输差分信号
双绞线:是一种由两根导线以螺旋方式绞合在一起的电缆结构
差分信号:用两根信号线之间的电压差来表示信息
2、CAN收发器的作用:
将CAN总线上的差分信号转换为高电平(逻辑1)和低电平(逻辑0)的数字信号
3、为什么要用差分信号传输:
差分信号抗干扰能力强,其通过信号线之间的电压差表示信息,面对电磁干扰时两根信号线同时受影响,以信号线间的电压差为参考影响较小
二、相关说明
1、TJA1145引脚图
INH:JTA1145 唤醒输出引脚,用于控制开关电源芯片使能
SDO,SDI,SCK,SCSN:通过SPI读写TJA1145寄存器
WAKE:TJA1145唤醒输入引脚,可配置唤醒信号边沿(上升沿,下降沿)
2、SPI链路验证
TJA1145是通过SPI通信来配置相关寄存器的,所以首先要保证MCU和TJA1145之间的通信正常,这个可以通过读取设备ID来验证,时钟极性和时钟相位如下:
CPOL = 0 CPHA = 1
需要注意的是,读写数据时 地址字节的最低位:0为写 1为读
3、休眠唤醒说明
一般来说唤醒有KL15唤醒 和 CAN唤醒:
KL15唤醒:指钥匙点火(ACC)信号,输入高时给MCU供电
CAN唤醒:检测到唤醒报文时 INH引脚拉高,使能电源芯片给MCU供电
CAN唤醒即Normal模式和Sleep模式之间的切换,正常收发报文处于Normal模式,休眠时处于Sleep模式,由于INH引脚在Sleep模式时为低,所以在MCU属于休眠状态时TJA1145也需要在Sleep模式,以防止异常唤醒MCU
根据上图可以看出 Normal模式切换为Sleep模式需要满足三个条件:
1、MC = sleep
2、没有等待的唤醒事件
3、至少要有一个常规唤醒源
即 在切换到睡眠模式前,必须至少启用一个常规唤醒事件,并清除所有事件状态位
下面是一些相关的寄存器:
模式寄存器
使能CAN唤醒
设置唤醒边沿检测
事件状态及捕获寄存器
注意:
由于TJA1145设计为 只支持特定CAN报文唤醒而不支持CANFD唤醒,以防止仅在CAN通信时产生总线错误,即CANFD报文不会被识别为有效的唤醒帧
4、休眠唤醒配置
1)CAN唤醒需要启用 Partial Networking
2)使能CAN选择性唤醒 成功配置部分网络寄存器
3)设置数据速率为500k
4)配置帧控制寄存器:识别格式为标准帧,不关注数据字段长度和内容
5)使能CAN唤醒检测、使能唤醒pin脚上升沿检测
6)清除所有事件状态位
三、唤醒报文设置
1)唤醒ID设置
TJA1145只能标准帧唤醒,所以用到地址0x29、0x2A
2)示例:设置唤醒ID为0x7A4
根据文档,0x29的bit7~bit2用来表示标准帧的bit5~bit0,
即0x29的bit7~bit2为100100,向0x29写入 100100 00(0x90)
根据文档,0x2A的bit4~bit0用来表示标准帧的bit10~bit6,
即0x2A的bit4~bit0为11110,向0x29写入 00011110(0x1E)
最终表示结果0x7A4
四、实现代码
读函数
uint8_t CanTrcv_119_TJA1145_ReadOneReg(uint8_t addr) {
status_t stdRet;
uint8_t sendBuf[2] = {0};
uint8_t RxBuf[2] = {0};
sendBuf[0] = (addr << 1U) | 1U;
sendBuf[1] = 0x00;
while(LPSPI_DRV_MasterGetTransferStatus(LPSPICOM0, NULL) != STATUS_SUCCESS);
stdRet = LPSPI_DRV_MasterTransfer(LPSPICOM0, sendBuf, RxBuf, 2U);
return stdRet;
}
写函数
uint8_t CanTrcv_119_TJA1145_WriteOneReg(uint8_t addr, uint8_t data) {
status_t stdRet;
uint8_t sendBuf[2] = {0};
sendBuf[0] = (addr << 1U) | 0U;
sendBuf[1] = data;
while(LPSPI_DRV_MasterGetTransferStatus(LPSPICOM0, NULL) != STATUS_SUCCESS);
stdRet = LPSPI_DRV_MasterTransfer(LPSPICOM0, sendBuf, NULL, 2U);
return stdRet;
}
初始化函数
void CanTrcv_Init(void)
{
//baud rate 500k
CanTrcv_119_TJA1145_WriteOneReg( CANTRCV_119_TJA1145_REGADDR_DATA_RATE, CANTRCV_119_TJA1145_COMM_RATE);
//Filter standard frames
CanTrcv_119_TJA1145_WriteOneReg( CANTRCV_119_TJA1145_REGADDR_FRAME_CONTROL, CANTRCV_119_TJA1145_FILTER_STANDARD_FRAME);
//wakeup id 0x7A4
CanTrcv_119_TJA1145_WriteOneReg( 0x29, 0x90);
CanTrcv_119_TJA1145_WriteOneReg( 0x2A, 0x1E);
//set single filter id
CanTrcv_119_TJA1145_WriteOneReg( 0x2D, 0);
CanTrcv_119_TJA1145_WriteOneReg( 0x2E, 0);
//set mode control : normal
CanTrcv_119_TJA1145_WriteOneReg( CANTRCV_119_TJA1145_REGADDR_MODECTRL, CANTRCV_119_TJA1145_MC_NORMAL);
//set CAN control:为CFDC = 1, PNCOK = 1, CPNC = 1, CMC = 10
CanTrcv_119_TJA1145_WriteOneReg( CANTRCV_119_TJA1145_REGADDR_CANCTRL, CANTRCV_119_TJA1145_REGVALUE_CANCTRL);
}
休眠函数
void CanTrcv_Sleep(void)
{
uint8_t ret = -1;
tja1145_reg_config sleep_reg_config[] =
{
//clear all event status
{TJA1145_REG_Event_capture_status, 0xff},
{TJA1145_REG_System_event_status, 0xff},
{TJA1145_REG_Transceiver_event_status, 0xff},
{TJA1145_REG_WAKE_pin_event_status, 0xff},
//enable/disable wake-up event
{TJA1145_REG_System_event_enable, 0x00},
{TJA1145_REG_Transceiver_event_enable, 0x01}, //CAN wake-up enable
{TJA1145_REG_WAKE_pin_enable, 0x02},
};
uint8_t i = 0;
for(i = 0; i < sizeof(sleep_reg_config)/sizeof(sleep_reg_config[0]); i++){
ret = CanTrcv_119_TJA1145_WriteOneReg(sleep_reg_config[i].reg_addr, sleep_reg_config[i].reg_val);
if(ret != 0){
break;
}
}
//set mode control : sleep
CanTrcv_119_TJA1145_WriteOneReg(CANTRCV_119_TJA1145_REGADDR_MODECTRL,CANTRCV_119_TJA1145_MC_SLEEP);
}
头文件
/*
* tja1145.h
*
*/
#ifndef DRIVER_TJA1145_TJA1145_H_
#define DRIVER_TJA1145_TJA1145_H_
#define CANTRCV_119_TJA1145_REGADDR_MODECTRL (0x01U)
#define CANTRCV_119_TJA1145_REGADDR_CANCTRL (0x20U)
#define CANTRCV_119_TJA1145_REGADDR_WAKEUP_EN (0x23U)
#define CANTRCV_119_TJA1145_REGADDR_DATA_RATE (0x26U)
#define CANTRCV_119_TJA1145_REGADDR_FRAME_CONTROL (0x2fU)
#define CANTRCV_119_TJA1145_REGADDR_EVENTSTATUS (0x60U)
#define CANTRCV_119_TJA1145_REGADDR_WAKEUP_EDGE (0x4CU)
#define CANTRCV_119_TJA1145_COMM_RATE (0x05)
#define CANTRCV_119_TJA1145_FILTER_STANDARD_FRAME (0x00)
#define CANTRCV_119_TJA1145_STATUS_VAL_CLEAR (0x0U)
#define CANTRCV_119_TJA1145_CAN_WAKE_UP (0x01U)
#define CANTRCV_119_TJA1145_MC_NORMAL (0x7U)
#define CANTRCV_119_TJA1145_MC_SLEEP (0x1U)
#define CANTRCV_119_TJA1145_REGVALUE_CANCTRL (0x72U)//0x41U
#define CANTRCV_119_TJA1145_WAKEUP_RISE (0x2U)
typedef enum{
TJA1145_REG_Mode_control = 0x01,
TJA1145_REG_Main_status = 0x03,
TJA1145_REG_System_event_enable = 0x04,
TJA1145_REG_Memory_0 = 0x06,
TJA1145_REG_Memory_1 = 0x07,
TJA1145_REG_Memory_2 = 0x08,
TJA1145_REG_Memory_3 = 0x09,
TJA1145_REG_Lock_control = 0x0A,
TJA1145_REG_CAN_control = 0x20,
TJA1145_REG_Transceiver_status = 0x22,
TJA1145_REG_Transceiver_event_enable = 0x23,
TJA1145_REG_Data_rate = 0x26,
TJA1145_REG_Identifier_0 = 0x27,
TJA1145_REG_Identifier_1 = 0x28,
TJA1145_REG_Identifier_2 = 0x29,
TJA1145_REG_Identifier_3 = 0x2A,
TJA1145_REG_Mask_0 = 0x2B,
TJA1145_REG_Mask_1 = 0x2C,
TJA1145_REG_Mask_2 = 0x2D,
TJA1145_REG_Mask_3 = 0x2E,
TJA1145_REG_Frame_control = 0x2F,
TJA1145_REG_Data_mask_0 = 0x68,
TJA1145_REG_Data_mask_1 = 0x69,
TJA1145_REG_Data_mask_2 = 0x6A,
TJA1145_REG_Data_mask_3 = 0x6B,
TJA1145_REG_Data_mask_4 = 0x6C,
TJA1145_REG_Data_mask_5 = 0x6D,
TJA1145_REG_Data_mask_6 = 0x6E,
TJA1145_REG_Data_mask_7 = 0x6F,
TJA1145_REG_WAKE_pin_status = 0x4B,
TJA1145_REG_WAKE_pin_enable = 0x4C,
TJA1145_REG_Event_capture_status = 0x60,
TJA1145_REG_System_event_status = 0x61,
TJA1145_REG_Transceiver_event_status = 0x63,
TJA1145_REG_WAKE_pin_event_status = 0x64,
TJA1145_REG_Identification = 0x7E,
}tja1145_regs;
typedef struct{
tja1145_regs reg_addr;
unsigned char reg_val;
}tja1145_reg_config;
void CanTrcv_Init(void);
void CanTrcv_Sleep(void);
uint8_t CanTrcv_119_TJA1145_WriteOneReg(uint8_t addr, uint8_t data);
uint8_t CanTrcv_119_TJA1145_ReadOneReg(uint8_t addr);
#endif /* DRIVER_TJA1145_TJA1145_H_ */
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/floenrce/article/details/135084378