持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
简介
EC里的SMbus主要有下面两个作用,一是进行CPU、GPU等的温度读取与控制,二是对智能电池的相关信息进行读取。另外SMBus也会把相关信息上报给操作系统,所以SMBus的作用非常重要,本文主要介绍下SMBus的基本概念以及移植方法。
一、SMBus介绍
SMBus分为主机和从机。
SMBus主机接口
当检测到INTC中断(设计A、B、C、D、E、F分别为INT9、INT10、INT16、INT4、INT160、INT161)时,软件可以通过读取Host Status Register来了解中断源。有5种中断条件:字节完成、失败、总线错误、设备错误和完成。
SMBus从机接口
slave支持以下三种消息类型:Byte Write、Byte Read和Host Notify。当检测到INTC中断(设计A、B、C分别为INT9、INT10、INT16)时,软件可以读取Slave Status Register来了解中断源。有4种中断条件:STOP Condition Detect Status、Slave Timeout Status、Slave Data Status和Host Notify Status。在“Byte Write/Byte Read”命令中,软件必须在从数据寄存器中写/读两次数据,才能释放SMCLK行。第一次,软件在从机数据寄存器中设置/获取数据,但SMCLK线不会被释放。SMCLK线将被保持在低位,直到软件第二次在从数据寄存器中读写数据,之后SMCLK线将被释放。
二、移植指南
编写步骤
下面是软件为各种命令编写寄存器的步骤。
- 快捷命令
- 使能SMBus主机控制器(主机控制寄存器2中的SMBus Host Enable位设置为1)。该命令中I2C_EN位必须为0。
- 在快速命令中,发送发送从地址寄存器(软件需要将数据写入发送从地址寄存器)。
- 启动事务(向主机控制寄存器写入41h,选择“Quick Command”,启用中断,启动事务)。
- 当数据传输完成时,会产生一个中断。软件可以读取主机状态寄存器来知道中断的来源。 注意:读取状态寄存器后,软件必须写入1以清除状态寄存器。
- 发送字节命令
- 使能SMBus主机控制器(主机控制寄存器2中的SMBus Host Enable位设置为1)。该命令中I2C_EN位必须为0。
- 在发送字节命令中,发送发送从地址寄存器和主机命令寄存器(软件将数据写入发送从地址寄存器和主机命令寄存器)(主机命令寄存器用于发送数据)。发送从地址寄存器的第0位必须是0。
- 启动事务(向主机控制寄存器写入45h,它将选择“发送字节/接收字节命令”,启用中断,并启动事务)。
- 当数据传输完成时,会产生一个中断。软件可以读取主机状态寄存器来知道中断的来源。
流程示例
下面是主机接口发送Byte的流程
BYTE bSMBusSendByte(BYTE Channel,BYTE Addr,BYTE SData,BYTE PECSupport)
{
BYTE error;
BYTE result;
BYTE status;
if(1)
{
error = 0xEE; // Pre-set error
result = FALSE; // Pre-set result is fail
SMBCRC8_A=0x00; // Clear CRC variable
*asSMBus[Channel].SMBusADR = Addr; // set address with writing bit
*asSMBus[Channel].SMBusCMD = SData; // Set command
if(PECSupport)
{
CalcCRC8(Addr); // To calculate crc8
CalcCRC8(SData); // To calculate crc8
}
*asSMBus[Channel].SMBusSTA = 0xFE; // clear bits
if(PECSupport)
{
*asSMBus[Channel].SMBusPEC = SMBCRC8_A;
*asSMBus[Channel].SMBusCTL = (0x04|HOCTL_SRT|HOCTL_PEC_EN); // Start transaction
}
else
{
*asSMBus[Channel].SMBusCTL = (0x04|HOCTL_SRT); // Start transaction
}
TR1 = 0; // Disable timer1
ET1 = 0; // Disable timer1 interrupt
_nop_();
TH1 = Timer_26ms>>8; // Set timer1 counter 26ms
TL1 = Timer_26ms; // Set timer1 counter 26ms
TF1 = 0; // Clear overflow flag
TR1 = 1; // Enable timer1
while (!TF1)
{
status = *asSMBus[Channel].SMBusSTA; // Read SMBus Host Status
if(IS_MASK_SET(status, (HOSTA_FINTR+HOSTA_DVER+HOSTA_BSER+HOSTA_FAIL+HOSTA_NACK+HOSTA_TMOE )))
{
TR1=0; // Disable timer1
TF1=0; // Clear overflow flag
ET1=1; // Enable timer1 interrupt
break;
}
}
if(TF1) // 26ms time-out and no any status bit is set.
{
TR1=0;
TF1=0;
ET1=1; // Enable timer1 interrupt
ResetSMBus(Channel);
error = 0xEE;
}
else
{
if(IS_MASK_SET(status, (HOSTA_DVER+HOSTA_BSER+HOSTA_FAIL+HOSTA_NACK+HOSTA_TMOE)))
{
if(IS_MASK_SET(status, (HOSTA_BSER+HOSTA_FAIL)))
{
ResetSMBus(Channel);
}
error = 0xEE;
}
else // Only Finish Interrupt bit is set.
{
error = 0x00;
}
}
if(error == 0xEE)
{
result = FALSE;
}
else
{
result = TRUE;
}
*asSMBus[Channel].SMBusSTA=0xFE; // clear bits
}
return(result);
}
三、完结
本文结束。