项目健康管理模块IPMB,针对协议要求对I2C总结上的节点设备,每一个可以作为主设备去访问从设备的信息。
作为发起者,上电启动后主节点为主模式,发起请求消息;从节点在接收到主节点发送的请求消息后,主节点转换为从模式,从节点转换为主模式。从节点发送消息到目的节点,完成通信过程。
此协议遵循SMBUS协议。
项目基于stm32 设计完成IPMB健康管理,关键点在于主从模式的切换,首先要挂接中断,当为主模式时,关接收中断;当为从模式时打开中断。代码实现如下所示:
I2C配置实现:
void I2C1_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C1_Slave_Address; //�ӻ���ַ
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //�����ȼ�
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE); //ʹ���ж�
I2C_Cmd(I2C1, ENABLE); //ʹ��I2C
}
中断函数实现:
void I2C1_EV_IRQHandler(void)
{
__IO uint32_t SR1Register =0;
__IO uint32_t SR2Register =0;
Recvmark = 1;
SR1Register = I2C1->SR1;
SR2Register = I2C1->SR2;
/* I2C1�Ǵӻ�(MSL = 0) */
if((SR2Register &0x0001) != 0x0001)
{
/* �����ѷ�����ַ(ADDR = 1: EV1) */
if((SR1Register & 0x0002) == 0x0002)
{
/* �����־������������ */
SR1Register = 0;
SR2Register = 0;
Rx_Idx_IIC1=0;
Tx_Idx_IIC1=0;
}
/* ��������(RXNE = 1: EV2) */
if((SR1Register & 0x0040) == 0x0040)
{
Buffer_Rx_IIC1[Rx_Idx_IIC1++] = I2C1->DR;
SR1Register = 0;
SR2Register = 0;
}
/* ��ֹͣ����(STOPF =1: EV4) */
if(( SR1Register & 0x0010) == 0x0010)
{
I2C1->CR1 |= 0x0001;
SR1Register = 0;
SR2Register = 0;
Flag_RcvOK_IIC1 = 1;
}
/* ��������(TxE = 1: EV3) */
if((SR1Register & 0x0080) == 0x0080)
{
I2C1->DR = Response_Message[Tx_Idx_IIC1++];
SR1Register = 0;
SR2Register = 0;
}
/* ����Ӧ��(AF =1: EV3-2) */
if(( SR1Register & 0x0400) == 0x0400)
{
I2C1->SR1 &= 0xFDFF;
SR1Register = 0;
SR2Register = 0;
}
}
}
开关中断操作:主发送之前关闭中断,从接收时打开中断。
I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE); //使能中断
I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, DISABLE); //关闭中断
一般设计中,对于总线主模式,数据发送为抢占总线的操作,主模式在执行完总线发送需求后自动切换为从模式。
I2C允许多主站模式,数据发送采用总线竞争发送。