Files
jiacun-20s-200A/BSP/i2c.c
T
2026-08-25 17:30:40 +08:00

532 lines
12 KiB
C

/**
******************************************************************************
* @file tim.c
* @author Jerry
* @version V2.1
* @date 22-April-2022
* @brief tim program body.
******************************************************************************
* @attention
*
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "global.h"
#include "string.h"
#include "sys.h"
#include "soe.h"
//64-byte page write buffer
//1,000,000 program/erase cycles
//100 year data retention
//AT24C256 32K Bytes = 128 * 256 bytes
//0x0000 不可初始化数据
//0x0200 厂内可初始化数据
//0x0400 升级初始化数据
//0x0800 报警记录数据
#define I2C_EEPROM I2C1
#define I2C_AFE I2C1
#define DEVICE_ID_EEPROM 0xA0
#define DEVICE_ID_AFE 0x34
#define I2C_TIMEOUT_COUNT 10000
#define FLASH_PAGE_ADDR 0x0800FC00 //要擦除的FLASH页地址
#define JUMP_TO_USER 0X20230612 //用户固件更新标记
#define JUMP_BUTNULL 0XFFFFFFFF //无更新标记
uint8_t IAP_Run; //执行程序时是否正常的标志
uint8_t DL_Index; //跳转位置的标识
uint32_t DL_Addr; //根据标识计算出的位置
uint32_t DL_Jump;
void uf_I2C1_Init(void)
{
uint8_t tmp[8];
uint32_t ee_index;
uint16_t ee_pc;
uint16_t ee_num;
/*初始化IIC*/
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
/* Configure I2C1 pins: PB6->SCL and PB7->SDA */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 80000;
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
I2C_AcknowledgeConfig(I2C1, ENABLE);
/*IAP标志*/
IAP_Run = 0x55;
EEPROM_WrMulByte(EE_IAP_NEW1,&IAP_Run);
delay_ms(10);
EEPROM_WrMulByte(EE_IAP_NEW2,&IAP_Run);
delay_ms(10);
/*为兼容此前底层,写入标识*/
EEPROM_RdMulByte(0,1,1,&DL_Index);
if((DL_Index != 0) && (DL_Index != 1)) //之前未刷过程序
{
DL_Index = 1; //现在一般是1
}
//读出检查,确认是这个位置并且无用户数据/跳转标志,才进行写入
DL_Addr = FLASH_PAGE_ADDR + 0x10000 * DL_Index;
FLASH_RdWord(DL_Addr, &DL_Jump, 1);
if(DL_Jump == JUMP_BUTNULL)
{
DL_Jump = JUMP_TO_USER;
FLASH_WrData(DL_Addr,(uint16_t *)&DL_Jump,8);
}
//若该位置有值,且不是跳转标志,跳转到另一个位置检查并写入
else if(DL_Jump != JUMP_TO_USER)
{
DL_Index = (DL_Index==0) ? 1:0; //取另一个地址查询,若仍然不对,那该用户程序不依靠IAP底层
DL_Addr = FLASH_PAGE_ADDR + 0x10000 * DL_Index;
FLASH_RdWord(DL_Addr, &DL_Jump, 1);
if(DL_Jump == JUMP_BUTNULL)
{
DL_Jump = JUMP_TO_USER;
FLASH_WrData(DL_Addr,(uint16_t *)&DL_Jump,8);
}
}
#if LTE_Conn
//上电读OTA升级回复标志
EEPROM_RdMulByte(EE_OTA_FINE,&tmp[0]);
if((tmp[0] == 0xAA) || (tmp[0] == 0xBB))
{
LTE_OTA_fineFlag = tmp[0];
}
else
{
LTE_OTA_fineFlag = 0;
}
#endif
/*EEPROM无值,赋默认值,但不主动写入EEPROM*/
//上电读485地址(先暂时获得一个值,之后根据paraMem参数来决定是否改变)
EEPROM_RdMulByte(EE_ADDR,&tmp[0]);
if((tmp[0]>=1) && (tmp[0]<=AddrMax))
{
bmsMem.E2_485Addr = tmp[0];
}
else
{
bmsMem.E2_485Addr = 2;
}
// //上电读屏幕语言
// EEPROM_RdMulByte(EE_LANG,&tmp[0]);
// if((tmp[0]==0) || (tmp[0]==1)) //0对应英文,1对应中文
// {
// language = tmp[0];
// }
// else
// {
// language = 0; //默认英文
// }
#if Addr_SetAuto
uint16_t random;
//上电读自动分配地址的随机队列标志
EEPROM_RdMulByte(EE_ASSIGN,&tmp[0]);
random = tmp[0]<<8 | tmp[1];
if((random>AddrMax) && (random<0xffff)) //AddrMax+1~65534
{
bmsMem.can_ArrayIndex = random;
}
else
{
bmsMem.can_ArrayIndex = 0;
}
#endif
//上电读是否需要充电校准总容量
EEPROM_RdMulByte(EE_FCC_TIME,&tmp[0]);
fcc_Calitimecount = tmp[0]<<24 | tmp[1]<<16 | tmp[2]<<8 | tmp[3];
if(fcc_Calitimecount <= timecount) //存的数据不算异常
{
fcc_CaliStartFlag = 1; //记录了起始时间,说明正在计时等满充
}
#if LTE_Conn
//上电读取消绑定标志
EEPROM_RdMulByte(EE_UNSUB,&tmp[0]);
if(tmp[0] <= 1)
{
LTE_UNSUB_Flag = tmp[0];
}
else
{
LTE_UNSUB_Flag = 0;
}
#endif
/*上电读取记录相关信息*/
EEPROM_RdMulByte(EE_SOE_INF,tmp);
ee_index = tmp[0]<<24 | tmp[1]<<16 | tmp[2]<<8 | tmp[3];
ee_pc = tmp[4]<<8 | tmp[5];
ee_num = tmp[6]<<8 | tmp[7];
//当前地址=0或0XFFFF或不为64倍数,初始化地址和记录序号
if((ee_pc < 0x1000) || (ee_pc > 0x2940) || (ee_pc == 0xffff) || (ee_pc%64 !=0))
{
soe.pc = RECORD_START_ADDR;
soe.index = 0;
soe.num = 0;
}
else
{
soe.index = ee_index;
soe.pc = ee_pc;
soe.num = ee_num;
}
}
//EEPROM写多字节,注意写入时不要跨page
uint8_t EEPROM_WrMulByte(uint8_t addrH, uint8_t addrL, uint8_t lenth, uint8_t *data)
{
uint8_t i;
uint16_t i2c_timeout;
//I2C总线BUSY
i2c_timeout = I2C_TIMEOUT_COUNT;
while(I2C_GetFlagStatus(I2C_EEPROM,I2C_FLAG_BUSY) == SET)
{
if((i2c_timeout--) == 0) return 9;
}
/*起始位*/
I2C_GenerateSTART(I2C_EEPROM, ENABLE);
i2c_timeout = I2C_TIMEOUT_COUNT;
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS) //EV5
{
if((i2c_timeout--) == 0) return 1;
}
/*EV5事件检测到,发送Device ID(写)*/
I2C_Send7bitAddress(I2C_EEPROM, DEVICE_ID_EEPROM, I2C_Direction_Transmitter);
i2c_timeout = I2C_TIMEOUT_COUNT;
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS) //EV6
{
if((i2c_timeout--) == 0) return 2;
}
/*EV6事件检测到,发送EEPROM 存储单元地址*/
//检测EV8,表示发送寄存器空了就可以继续填数据了,无需等待移位寄存器空
I2C_SendData(I2C_EEPROM, addrH);
i2c_timeout = I2C_TIMEOUT_COUNT;
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS)
{
if((i2c_timeout--) == 0) return 3;
}
/*发送EEPROM 存储单元地址*/
I2C_SendData(I2C_EEPROM, addrL);
i2c_timeout = I2C_TIMEOUT_COUNT;
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS)
{
if((i2c_timeout--) == 0) return 4;
}
/*发送写入EERPOM数据*/
for(i=0;i<lenth-1;i++)
{
i2c_timeout = I2C_TIMEOUT_COUNT;
I2C_SendData(I2C_EEPROM, *data++);
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS)
{
if((i2c_timeout--) == 0) return 5;
}
}
//最后一个数据EV8_2
i2c_timeout = I2C_TIMEOUT_COUNT;
I2C_SendData(I2C_EEPROM, *data++);
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
if((i2c_timeout--) == 0) return 5;
}
/*停止位*/
I2C_GenerateSTOP(I2C_EEPROM, ENABLE);
return 0;
}
//EEPROM随机读多字节
uint8_t EEPROM_RdMulByte(uint8_t addrH, uint8_t addrL, uint8_t lenth, uint8_t *data)
{
uint8_t i;
uint16_t i2c_timeout;
//I2C总线BUSY
i2c_timeout = I2C_TIMEOUT_COUNT;
while(I2C_GetFlagStatus(I2C_EEPROM,I2C_FLAG_BUSY) == SET)
{
if((i2c_timeout--) == 0) return 9;
}
//ACK
I2C_AcknowledgeConfig(I2C_EEPROM, ENABLE);
/*起始位*/
i2c_timeout = I2C_TIMEOUT_COUNT;
I2C_GenerateSTART(I2C_EEPROM, ENABLE);
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS) //EV5
{
if((i2c_timeout--) == 0) return 1;
}
/*发送Device ID(写)*/
i2c_timeout = I2C_TIMEOUT_COUNT;
I2C_Send7bitAddress(I2C_EEPROM, DEVICE_ID_EEPROM, I2C_Direction_Transmitter);
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS)
{
if((i2c_timeout--) == 0) return 2;
}
/*发送EEPROM 存储单元地址*/
i2c_timeout = I2C_TIMEOUT_COUNT;
I2C_SendData(I2C_EEPROM, addrH);
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
if((i2c_timeout--) == 0) return 3;
}
/*发送EEPROM 存储单元地址*/
i2c_timeout = I2C_TIMEOUT_COUNT;
I2C_SendData(I2C_EEPROM, addrL);
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS)
{
if((i2c_timeout--) == 0) return 4;
}
/*起始位*/
i2c_timeout = I2C_TIMEOUT_COUNT;
I2C_GenerateSTART(I2C_EEPROM, ENABLE);
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_MODE_SELECT)!= SUCCESS)
{
if((i2c_timeout--) == 0) return 5;
}
/*发送DEVICE(读)*/
i2c_timeout = I2C_TIMEOUT_COUNT;
I2C_Send7bitAddress(I2C_EEPROM, DEVICE_ID_EEPROM, I2C_Direction_Receiver);
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS)
{
if((i2c_timeout--) == 0) return 6;
}
/*读lenth长度数据*/
for(i=0;i<lenth-1;i++)
{
i2c_timeout = I2C_TIMEOUT_COUNT;
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
{
if((i2c_timeout--) == 0) return 7;
}
*data++ = I2C_ReceiveData(I2C_EEPROM);
}
//NACK
I2C_AcknowledgeConfig(I2C_EEPROM, DISABLE);
//我认为ACK disable因该放在接收数据之前,这样接到数据后可以马上发NACK信号
i2c_timeout = I2C_TIMEOUT_COUNT;
while(I2C_CheckEvent(I2C_EEPROM, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS)
{
if((i2c_timeout--) == 0) return 8;
}
*data++ = I2C_ReceiveData(I2C_EEPROM);
/*停止位*/
I2C_GenerateSTOP(I2C_EEPROM, ENABLE);
return 0;
}
//AFE通信函数(AFE_WriteOneByte/AFE_ReadMulByte)已移至BSP/spi.c,使用SPI2与SH3673520通信
//write zero cali data to eeprom
//read from eeprom and check
uint8_t EEPROM_CALI_WrZero(int16_t data)
{
uint8_t tempW[4];
uint8_t tempR[4];
uint8_t i;
tempW[0] = (data >>8) & 0xff;
tempW[1] = data & 0xff;
tempW[2] = tempW[0] ^ 0xff;
tempW[3] = tempW[1] ^ 0xff;
if(EEPROM_WrMulByte(EE_CALI_ZERO,tempW) !=0)
{
return 1; //iic write error
}
delay_ms(20); //are there?
if(EEPROM_RdMulByte(EE_CALI_ZERO,tempR) !=0)
{
return 2; //iic read error
}
for(i=0;i<4;i++)
{
if(tempR[i] != tempW[i])
{
return 3; //check error
}
}
return 0;
}
//write gain cali data to eeprom
uint8_t EEPROM_CALI_WrGain(int16_t data)
{
uint8_t tempW[4];
uint8_t tempR[4];
uint8_t i;
tempW[0] = (data >>8) & 0xff;
tempW[1] = data & 0xff;
tempW[2] = tempW[0] ^ 0xff;
tempW[3] = tempW[1] ^ 0xff;
if(EEPROM_WrMulByte(EE_CALI_GAIN,tempW) !=0)
{
return 1;
}
delay_ms(20);
if(EEPROM_RdMulByte(EE_CALI_GAIN,tempR) !=0)
{
return 2; //iic read error
}
for(i=0;i<4;i++)
{
if(tempR[i] != tempW[i])
{
return 3; //check error
}
}
return 0;
}
int16_t EEPROM_CALI_RdZero(void)
{
uint8_t i;
uint8_t tempR[4];
int16_t result;
EEPROM_RdMulByte(EE_CALI_ZERO,tempR);
if(((tempR[0] ^ 0xff) == tempR[2]) && ((tempR[1] ^ 0xff) == tempR[3]))
{
result = tempR[0] << 8 | tempR[1];
return result;
}
else
{
EEPROM_RdMulByte(2,0,4,tempR); //读取旧地址的数据
if(((tempR[0] ^ 0xff) == tempR[2]) && ((tempR[1] ^ 0xff) == tempR[3]))
{
//符合存储格式,说明之前校准值保存在旧地址,赋值到新地址,并清除
EEPROM_WrMulByte(EE_CALI_ZERO,tempR);
delay_ms(5);
result = tempR[0] << 8 | tempR[1];
//为了不影响现在在旧地址的数据,将这部分清空
for(i=0;i<4;i++)
{
tempR[i] = 0xff;
}
EEPROM_WrMulByte(2,0,4,tempR);
delay_ms(5);
EEPROM_WrMulByte(2,4,4,tempR);
delay_ms(5);
}
else
{
result = 0;
}
return result;
}
}
int16_t EEPROM_CALI_RdGain(void)
{
uint8_t i;
uint8_t tempR[4];
int16_t result;
EEPROM_RdMulByte(EE_CALI_GAIN,tempR);
if(((tempR[0] ^ 0xff) == tempR[2]) && ((tempR[1] ^ 0xff) == tempR[3]))
{
result = tempR[0] << 8 | tempR[1];
return result;
}
else
{
EEPROM_RdMulByte(3,0,4,tempR); //读取旧地址的数据
if(((tempR[0] ^ 0xff) == tempR[2]) && ((tempR[1] ^ 0xff) == tempR[3]))
{
//符合存储格式,说明之前校准值保存在旧地址,赋值到新地址,并清除
EEPROM_WrMulByte(EE_CALI_GAIN,tempR);
delay_ms(5);
result = tempR[0] << 8 | tempR[1];
//为了不影响现在在旧地址的数据,将这部分清空
for(i=0;i<4;i++)
{
tempR[i] = 0xff;
}
EEPROM_WrMulByte(3,0,4,tempR);
delay_ms(5);
EEPROM_WrMulByte(3,4,4,tempR);
delay_ms(5);
}
else
{
result = 10000;
}
return result;
}
}