/** ****************************************************************************** * @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>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; } }