532 lines
12 KiB
C
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;
|
|
}
|
|
}
|
|
|