STM32 讀取 BQ27541 電量
STM32 讀取 BQ27541 這是個人最近所接到的案子,要讀取電池包中的SOC,花了幾天終於完成了經驗總結如下:
TI bq27541 datasheet 對I2C介面的讀取如下圖,
圖1
我要採用的是(c) 1 byte-read,
用的是ST 範例程式 M24C08 EEPROM讀取的範例來寫:
用的是 MultiByteRead中這函式來讀取。
main 中用的是
I2C_EE_MultiByteRead(Rx1 ,0x2c, u16 NumByteToRead) 註 0x2c 是BQ27541讀取 SOC
而圖1 的時序我把它拆成下面七個步驟
Host Generated
|
指令
|
Fuel Gauge Generated
|
||
1
|
Start,
|
I2C_GenerateSTART(I2C1, ENABLE);
|
||
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
|
||||
2
|
ADDR[6:0] 0
|
I2C_Send7bitAddress(I2C1, 0xaa,
I2C_Direction_Transmitter);
|
Acknowledge
|
|
while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
|
||||
3
|
CMD[7:0]
|
I2C_SendData(I2C1, (u8)ReadAddr);
|
Acknowledge
|
|
while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_BYTE_TRANSMITTED));
|
||||
4
|
Start,
|
I2C_GenerateSTART(I2C1, ENABLE);
|
||
while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_MODE_SELECT));
|
||||
5
|
ADDR[6:0] 1
|
I2C_Send7bitAddress(I2C1, 0xab,
I2C_Direction_Receiver);
|
Acknowledge
|
|
while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
|
||||
for (i = NumByteToRead; i > 0;
i--,pBuffer++)
{
………………………………..
}
|
DATA[7:0]
|
|||
6
|
No Acknowledge
|
I2C_AcknowledgeConfig(I2C1, DISABLE);
|
||
while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_BYTE_RECEIVED));
|
||||
7
|
Stop
|
I2C_GenerateSTOP(I2C1, ENABLE);
|
而在 i2c_ee.c 中的 void I2C_EE_MultiByteRead 的程式則被我改成如下:
void I2C_EE_MultiByteRead(u8* pBuffer, u16
ReadAddr, u16 NumByteToRead)
{
u8
i = 0;
/*
Send STRAT condition */
I2C_GenerateSTART(I2C1, ENABLE);
/*
Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/*
Send EEPROM address for write */
I2C_Send7bitAddress(I2C1, 0xaa,
I2C_Direction_Transmitter);
/*
Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/*
Send the EEPROM's internal address to read from */
I2C_SendData(I2C1, (u8)ReadAddr);
/*
Test on EV8 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/*
Send STRAT condition */
I2C_GenerateSTART(I2C1, ENABLE);
/*
Test on EV5 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
/*
Send EEPROM address for read */
I2C_Send7bitAddress(I2C1, 0xab,
I2C_Direction_Receiver);
/*
Test on EV6 and clear it */
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
for (i = NumByteToRead; i > 0; i--,pBuffer++)
{
if (i == 1)
{
I2C_AcknowledgeConfig(I2C1,
DISABLE);
while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_BYTE_RECEIVED));
*pBuffer
= I2C_ReceiveData(I2C1);
I2C_AcknowledgeConfig(I2C1,
ENABLE);
}
else
{
I2C_AcknowledgeConfig(I2C1,
ENABLE);
while(!I2C_CheckEvent(I2C1,
I2C_EVENT_MASTER_BYTE_RECEIVED));
*pBuffer
= I2C_ReceiveData(I2C1);
i=i;
}
}
/*
Send STOP condition */
I2C_GenerateSTOP(I2C1, ENABLE);
}
下面是我用網路上找的一個 GPIO 模擬 I2C 的讀取EEPRO 範例來修改 上面的字義更足以描述整個流程
main 中用的是
{
if(!I2C_Start())return FALSE;
I2C_SendByte(0xAA& 0xFFFF); //這是重點
if(!I2C_WaitAck())
{I2C_Stop();
return FALSE;}
I2C_SendByte(0x2c& 0x00FF));
I2C_WaitAck();
I2C_Start();
I2C_SendByte(0xAB & 0xFFFF); //這是重點
I2C_WaitAck();
while(length)
{
*pBuffer = I2C_ReceiveByte();
if(length == 1)I2C_NoAck();
else I2C_Ack();
pBuffer++;
length--;
}
I2C_Stop();
return TRUE;
}
下面是我用網路上找的一個 GPIO 模擬 I2C 的讀取EEPRO 範例來修改 上面的字義更足以描述整個流程
main 中用的是
I2C_ReadByte(Tx1_Buffer, 0x01, 0x2c, 0xAB);
--------------------------------------------------------------------------------------------
bool I2C_ReadByte(u8* pBuffer, u8 length, u16 ReadAddress, u8 DeviceAddress)--------------------------------------------------------------------------------------------
{
if(!I2C_Start())return FALSE;
I2C_SendByte(0xAA& 0xFFFF); //這是重點
if(!I2C_WaitAck())
{I2C_Stop();
return FALSE;}
I2C_SendByte(0x2c& 0x00FF));
I2C_WaitAck();
I2C_Start();
I2C_SendByte(0xAB & 0xFFFF); //這是重點
I2C_WaitAck();
while(length)
{
*pBuffer = I2C_ReceiveByte();
if(length == 1)I2C_NoAck();
else I2C_Ack();
pBuffer++;
length--;
}
I2C_Stop();
return TRUE;
}
留言
張貼留言