/** ****************************************************************************** * File Name : pl455_comm.c * Description : This file provides code for the configuration * of CAN communication. ****************************************************************************** * @attention * *

© Copyright (c) 2019 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include #include "pl455.h" #include "uart2.h" #include "pl455_comm.h" #include "asutil.h" #include "malloc.h" #include "delay.h" #include "device_param.h" #include "brtc.h" #include "console.h" /* Private define ------------------------------------------------------------*/ #define PL455_COMM_TASK_TIME 5 // 5ms TASK #define PL455_COMM_RX_TIMEOUT 500 // 500ms TimeOut #define PL455_COMM_RX_DELAY 5 #define PL455_COMM_TX_DELAY 50 #define PL455_COMM_MAX_TIMEOUT 10 #define PL455_COMM_MAX_BUFFER_SIZE 512 #define PACK_BUF_MAX 50 #define PL455_VREF 2.5 // VREF 2.5V /* Private typedef -----------------------------------------------------------*/ typedef struct { uint8_t *Buffer; u16 Tick; u16 Position; u8 BufferStart; u8 TxFlag; u8 TxDetail; u8 RxFlag; u8 MsgPrint; u8 DataPrint; u8 BakMsgPrint; u8 BakDataPrint; } TPl455CommConfig, *PPl455CommConfig; typedef struct { u32 Tick; u16 Timeout; u8 Commfail; u8 Init; } TPl455CommState, *PPl455CommState; typedef struct { s16 cvolt[16]; } TPackBuf, *PPackBuf; typedef struct { u16 cell_fail : 1; u16 ocv_alarm : 1; u16 ocv_shutdown : 1; u16 odv_alarm : 1; u16 odv_shutdown : 1; u16 cell_balance : 1; u16 reserved : 10; } TCellAlarm, *PCellAlarm; typedef struct _TCellData { u16 volt; TCellAlarm alarm; } TCellData, *PCellData; typedef struct _TPack { TCellData cell[16]; } TPack, *PPack; /* Private macro -------------------------------------------------------------*/ const uint16_t emptyNo = 7; /* Private variables ---------------------------------------------------------*/ TPl455CommConfig Pl455Config; TPl455CommState Pl455CommState; uint16_t PackBufCh = 0; TPackBuf PackBuf[PACK_BUF_MAX]; TPack PackData; u16 CellVoltSum, disCellVoltSum; u32 Balance_Avg, disBalance_Avg; u8 CellBalancingFlag = false, disCellBalancingFlag; u8 CellBalancingOff = false; u8 CB_Rest = false; u32 CB_Tick = 0; u32 disCB_Tick = 0; u16 ManualBalValue = 0; u8 ManualBalFlag = 0; /* Private function prototypes -----------------------------------------------*/ void Pl455CommProcess(void); void Pl455PacketInit(void); void Pl455UpdateData(void); void SendDataToPl455(uint8_t *data, u16 len); u8 GetPl455CommPacket(uint8_t *rdata, uint16_t len); void Pl455_commfail_clear(void); void Pl455_commfail_check(void); void CellVoltagePutBuf(uint8_t *pdata); void MakeCellAvgData(void); void PL455_Cell_AutoBalancing(uint32_t rBal); void PL455_Cell_ManualBalancing(uint32_t rBal); /* Private functions ---------------------------------------------------------*/ void Pl455CommInit(void) { pl455_gpio_Init(); pl455_wakeup(); CommClear(); CommReset(); setSendFunc(&SendDataToPl455); setRecvFunc(&GetPl455CommPacket); memset(&Pl455Config, 0x00, sizeof(TPl455CommConfig)); memset(&Pl455CommState, 0x00, sizeof(TPl455CommState)); Pl455Config.Buffer = mymalloc(sizeof(PL455_COMM_MAX_BUFFER_SIZE)); device_status.battery_status.bit.ACB = true; } void Pl455DeviceInit(void) { int nSent, nRead = 0; int nDev_ID; uint32_t wTemp = 0; nSent = nSent; nRead = nRead; nDev_ID = 0; // Wake all devices // The wake tone will awaken any device that is already in shutdown and the pwrdown will shutdown any device // that is already awake. The least number of times to sequence wake and pwrdown will be half the number of // boards to cover the worst case combination of boards already awake or shutdown. nSent = WriteReg(nDev_ID, 12, 0x40, 1, FRMWRT_ALL_NR); // send out broadcast pwrdown command delay_os_ms(5); //~5ms pl455_wakeup(); delay_os_ms(5); //~5ms // Mask Customer Checksum Fault bit - [15] USER_CKSUM_MSK nSent = WriteReg(0, 107, 0x8000, 2, FRMWRT_ALL_NR); // clear all fault summary flags // Clear all faults nSent = WriteReg(0, 82, 0xFFC0, 2, FRMWRT_ALL_NR); // clear all fault summary flags - 7.6.3.27 FAULT_SUM 0x52-53 (82-83) Fault Summary nSent = WriteReg(0, 81, 0x38, 1, FRMWRT_ALL_NR); // clear fault flags in the system status register // Auto-address all boards (section 1.2.2) nSent = WriteReg(0, 14, 0x19, 1, FRMWRT_ALL_NR); // set auto-address mode on all boards - 7.6.3.9 DEVCONFIG 0x0E (14) Device Configuration nSent = WriteReg(0, 12, 0x08, 1, FRMWRT_ALL_NR); // enter auto address mode on all boards, the next write to this ID will be its address // Set addresses for all boards in daisy-chain (section 1.2.3) nSent = WriteReg(nDev_ID, 10, nDev_ID, 1, FRMWRT_ALL_NR); // send address to each board // Enable all communication interfaces on all boards in the stack (section 1.2.1) // nSent = WriteReg(0, 16, 0x10F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces on all boards in stack nSent = WriteReg(0, 16, 0x1080, 2, FRMWRT_ALL_NR); // set communications baud rate and disable all interfaces on all boards in stack - only enable uart /* Change to final baud rate used in the application (set by BAUDRATE define in pl455.h). * Up to this point, all communication is at 250Kb, as the COMM_RESET done at the initial * startup resets the bq76PL455A-Q1 UART to 250Kb. */ switch(BAUDRATE) { case 125000: nSent = WriteReg(0, 16, 0x00F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces delay_os_ms(1); // sciSetBaudrate(scilinREG, BAUDRATE); break; case 250000: delay_os_ms(1); break; case 500000: nSent = WriteReg(0, 16, 0x20F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces delay_os_ms(1); // sciSetBaudrate(scilinREG, BAUDRATE); break; case 1000000: nSent = WriteReg(0, 16, 0x30F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces delay_os_ms(1); // sciSetBaudrate(scilinREG, BAUDRATE); break; } // Clear all faults (section 1.2.7) nSent = WriteReg(0, 82, 0xFFC0, 2, FRMWRT_ALL_NR); // clear all fault summary flags nSent = WriteReg(0, 81, 0x38, 1, FRMWRT_ALL_NR); // clear fault flags in the system status register delay_os_ms(10); // Configure AFE (section 2.2.1) nDev_ID = 0; // nSent = WriteReg(nDev_ID, 60, 0x00, 1, FRMWRT_SGL_NR); // set 0 mux delay nSent = WriteReg(nDev_ID, 61, 0x00, 1, FRMWRT_SGL_NR); // set 0 initial sampling delay // Configure voltage and internal sample period (section 2.2.2) nDev_ID = 0; nSent = WriteReg(nDev_ID, 62, 0xCC, 1, FRMWRT_SGL_NR); // set 99.92us ADC sampling period - Cell and die temperature measurement period // Configure the oversampling rate (section 2.2.3) nDev_ID = 0; nSent = WriteReg(nDev_ID, 7, 0x00, 1, FRMWRT_SGL_NR); // set no oversampling period // Clear and check faults (section 2.2.4) nDev_ID = 0; nSent = WriteReg(nDev_ID, 81, 0x38, 1, FRMWRT_SGL_NR); // clear fault flags in the system status register nSent = WriteReg(nDev_ID, 82, 0xFFC0, 2, FRMWRT_SGL_NR); // clear all fault summary flags nRead = ReadReg(nDev_ID, 81, &wTemp, 1, 0); // 0ms timeout nRead = ReadReg(nDev_ID, 82, &wTemp, 2, 0); // 0ms timeout // Select number of cells and channels to sample (section 2.2.5.1) nDev_ID = 0; nSent = WriteReg(nDev_ID, 13, 0x10, 1, FRMWRT_SGL_NR); // set number of cells to 16 // 1111 1111 0111 1111 nSent = WriteReg(nDev_ID, 3, 0xFF7F00C0, 4, FRMWRT_SGL_NR); // select all cell, AUX channels 0 and 1, and internal digital die and internal analog die temperatures // // Select identical number of cells and channels on all modules simultaneously (section 2.2.5.2) // nSent = WriteReg(0, 13, 0x10, 1, FRMWRT_ALL_NR); // set number of cells to 16 // nSent = WriteReg(0, 3, 0xFFFF03C0, 4, FRMWRT_ALL_NR); // select all cell, AUX channels 0 and 1, and internal digital die and internal analog die temperatures // nSent = WriteReg(0, 13, 0x08, 1, FRMWRT_ALL_NR); // set number of cells to 8 // nSent = WriteReg(0, 3, 0x00FF03C0, 4, FRMWRT_ALL_NR); // select all cell channels 1-8, AUX channels 0 and 1, and internal digital die and internal analog die temperatures // Set cell over-voltage and cell under-voltage thresholds on a single board (section 2.2.6.1) nDev_ID = 0; nSent = WriteReg(nDev_ID, 144, 0xD1EC, 2, FRMWRT_SGL_NR); // set OV threshold = 4.1000V nSent = WriteReg(nDev_ID, 142, 0x0000, 2, FRMWRT_SGL_NR); // set UV threshold = 1.9000V // Set CBCONFIG 0x13 (19) Balance Configuration nSent = WriteReg(nDev_ID, 19, 0x28, 1, FRMWRT_SGL_NR); // set BAL_TIME = 1 minute and set BAL_CONTINUE = 1 // Test CBENBL 0x14?15 (20?21) Balancing Enable for (int i = 0; i < 16; i++) { nSent = WriteReg(nDev_ID, 20, (1 << i), 2, FRMWRT_SGL_NR); // set BAL_TIME = 1 minute and set BAL_CONTINUE = 1 delay_os_ms(200); } nSent = WriteReg(nDev_ID, 20, 0x0000, 2, FRMWRT_SGL_NR); // set BAL_TIME = 1 minute and set BAL_CONTINUE = 1 // // Set cell over-voltage and cell under-voltage thresholds on all boards simultaneously (section 2.2.6.2) // nSent = WriteReg(0, 144, 0xD1EC, 2, FRMWRT_ALL_NR); // set OV threshold = 4.1000V // nSent = WriteReg(0, 142, 0x6148, 2, FRMWRT_ALL_NR); // set UV threshold = 1.9000V // Send broadcast request to all boards to sample and send results (section 3.2) // nSent = WriteReg(0, 2, 0x02, 1, FRMWRT_ALL_NR); // send sync sample command // nSent = WaitRespFrame(bFrame, 81, 0); // 24 bytes data (x3) + packet header (x3) + CRC (x3), 0ms timeout // Send broadcast request to all boards to sample and store results (section 3.3.1) // nSent = WriteReg(0, 2, 0x00, 1, FRMWRT_ALL_NR); // send sync sample command // Read sampled data from boards (section 3.3.2) // 24 bytes - still configured for 8 AFE channels plus 2 AUX channels plus internal digital and analog die // temperatures (see code for section 2.2.5.2) // nDev_ID = 2; // nSent = WriteReg(nDev_ID, 2, 0x20, 1, FRMWRT_SGL_R); // send read sampled values command // nSent = WaitRespFrame(bFrame, 27, 0); // 24 bytes data + packet header + CRC, 0ms timeout // nDev_ID = 1; // nSent = WriteReg(nDev_ID, 2, 0x20, 1, FRMWRT_SGL_R); // send read sampled values command // nSent = WaitRespFrame(bFrame, 27, 0); // 24 bytes data + packet header + CRC, 0ms timeout // nDev_ID = 0; // nSent = WriteReg(nDev_ID, 2, 0x20, 1, FRMWRT_SGL_R); // send read sampled values command // nSent = WaitRespFrame(bFrame, 27, 0); // 24 bytes data + packet header + CRC, 0ms timeout // // Send sample request to single board to sample and send results (section 4.2) // nDev_ID = 1; // nSent = WriteReg(nDev_ID, 2, 0x01, 1, FRMWRT_SGL_NR); // send sync sample command // nSent = WaitRespFrame(bFrame, 27, 0); // 24 bytes data + packet header + CRC, 0ms timeout // // Send sample request with embedded channel and oversample information (section 4.3.1) // nDev_ID = 3; // nSent = WriteReg(nDev_ID, 2, 0x0000FF03C000, 6, FRMWRT_SGL_NR); // send sync sample command with channel // // selection and oversample selection embedded // Read previously sampled data from single board (section 4.3.2) // nDev_ID = 0; // nSent = WriteReg(nDev_ID, 2, 0x20, 1, FRMWRT_SGL_R); // send read sampled values command // nSent = WaitRespFrame(bFrame, 27, 0); // 24 bytes data + packet header + CRC, 0ms timeout // Configure GPIO pin direction and set new pin values (section 5.2.1) // nDev_ID = 0; // nSent = WriteReg(nDev_ID, 123, 0x00, 1, FRMWRT_SGL_NR); // turn off all GPIO pull downs // nSent = WriteReg(nDev_ID, 122, 0x00, 1, FRMWRT_SGL_NR); // turn off all GPIO pull ups // nSent = WriteReg(nDev_ID, 120, 0x07, 1, FRMWRT_SGL_NR); // set GPIO[2:0] to output direction // nSent = WriteReg(nDev_ID, 122, 0x07, 1, FRMWRT_SGL_NR); // turn off GPIO[5:4] pull ups and turn on GPIO[2:0] pull ups // nSent = WriteReg(nDev_ID, 121, 0x01, 1, FRMWRT_SGL_NR); // set GPIO outputs (pattern b001) // nSent = WriteReg(nDev_ID, 121, 0x02, 1, FRMWRT_SGL_NR); // set GPIO outputs (pattern b010) // nSent = WriteReg(nDev_ID, 121, 0x04, 1, FRMWRT_SGL_NR); // set GPIO outputs (pattern b100) // nSent = WriteReg(nDev_ID, 121, 0x07, 1, FRMWRT_SGL_NR); // set GPIO outputs (pattern b111) // nSent = WriteReg(nDev_ID, 121, 0x00, 1, FRMWRT_SGL_NR); // set GPIO outputs (pattern b000) // Configure GPIO inputs with or without pull ups or pull downs (section 5.2.2) // nDev_ID = 0; // nSent = WriteReg(nDev_ID, 123, 0x04, 1, FRMWRT_SGL_NR); // enable pull down for GPIO2, turn off all other GPIO pull downs // nSent = WriteReg(nDev_ID, 122, 0x03, 1, FRMWRT_SGL_NR); // enable pull ups for GPIO[1:0], turn off all other GPIO pull ups // nSent = WriteReg(0, 122, 0x03, 1, FRMWRT_ALL_NR); // broadcast to all boards to enable pull ups for GPIO[1:0] and turn off all other GPIO pull ups // Setting a GPIO output value (section 5.2.3.1) // nDev_ID = 0; // nSent = WriteReg(nDev_ID, 120, 0x17, 1, FRMWRT_SGL_NR); // set GPIO direction for GPIO4 and GPIO[2:0] as outputs, GPIO3 and GPIO5 as inputs // nSent = WriteReg(nDev_ID, 121, 0x12, 1, FRMWRT_SGL_NR); // set GPIO4 and GPIO1, clear GPIO2 and GPIO0 // Reading a GPIO input value (section 5.2.3.2) // nDev_ID = 0; // nSent = WriteReg(nDev_ID, 120, 0x30, 1, FRMWRT_SGL_NR); // set GPIO direction for GPIO[5:4] as outputs, GPIO[3:0] as inputs // nRead = ReadReg(nDev_ID, 124, &wTemp, 1, 0); // read GPIO inputs, 0ms timeout // Steps for saving register configuration to EEPROM (sections 6.2.1 to 6.2.4) // ** the code is commented out below to avoid accidental use - uncomment to use // nDev_ID = 0; // //nSent = WriteReg(nDev_ID, 130, 0x8C2DB194, 4, FRMWRT_SGL_NR); // write Magic Number 1 // //nSent = WriteReg(nDev_ID, 252, 0xA375E60F, 4, FRMWRT_SGL_NR); // write Magic Number 2 // //nSent = WriteReg(nDev_ID, 12, 0x10, 1, FRMWRT_SGL_NR); // send Write RAM to EEPROM command // nRead = ReadReg(nDev_ID, 12, &wTemp, 1, 0); // read WRITE_EEPROM status bit, 0ms timeout //test WRITE_EEPROM bit to check for completion // Steps for saving register configuration to EEPROM in all devices in stack (sections 6.2.5) // ** the code is commented out below to avoid accidental use - uncomment to use //nSent = WriteReg(0, 130, 0x8C2DB194, 4, FRMWRT_ALL_NR); // write Magic Number 1 //nSent = WriteReg(0, 252, 0xA375E60F, 4, FRMWRT_ALL_NR); // write Magic Number 2 //nSent = WriteReg(0, 12, 0x10, 1, FRMWRT_ALL_NR); // send Write RAM to EEPROM command // nDev_ID = 0; // nRead = ReadReg(nDev_ID, 12, &wTemp, 1, 0); // read WRITE_EEPROM status bit, 0ms timeout // //test WRITE_EEPROM bit to check for completion // nDev_ID = 1; // nRead = ReadReg(nDev_ID, 12, &wTemp, 1, 0); // read WRITE_EEPROM status bit, 0ms timeout // //test WRITE_EEPROM bit to check for completion // nDev_ID = 2; // nRead = ReadReg(nDev_ID, 12, &wTemp, 1, 0); // read WRITE_EEPROM status bit, 0ms timeout //test WRITE_EEPROM bit to check for completion // Assign devices to specific group IDs (section 7) // nDev_ID = 1; // nSent = WriteReg(nDev_ID, 11, 0x01, 1, FRMWRT_SGL_NR); // assign Dev ID 1 to Group ID 1 // nDev_ID = 2; // nSent = WriteReg(nDev_ID, 11, 0x01, 1, FRMWRT_SGL_NR); // assign Dev ID 1 to Group ID 1 // delay_os_ms(1); // nRead = ReadReg(1, 11, &wTemp, 1, 0); // read group ID register, 0ms timeout // nRead = ReadReg(2, 11, &wTemp, 1, 0); // read group ID register, 0ms timeout // Send group sample request with embedded channel and oversample information (section 7.1) // send sync sample command (first data byte = command (b[7:5] = 0) | highest device to respond (0x01)) with // channel selection and oversample selection embedded // nGrp_ID = 1; // nSent = WriteReg(nGrp_ID, 2, 0x02FFFF550000, 6, FRMWRT_GRP_R); // nSent = WaitRespFrame(bFrame, 86, 0); // 40 bytes data (x2) + packet header (x2) + CRC (x2), 0ms timeout // Send group sample request - 1 byte method (section 7.2) // send sync sample command with channel (data byte = command (b[7:5] = 0) | highest device to respond (0x01)) // sampling parameters are taken from values already stored in Command Channel Select and Oversampling registers // nGrp_ID = 1; // nSent = WriteReg(nGrp_ID, 2, 0x02, 1, FRMWRT_GRP_R); // nSent = WaitRespFrame(bFrame, 86, 0); // 40 bytes data (x2) + packet header (x2) + CRC (x2), 0ms timeout // Send group register read - 2 byte method (section 7.3) // read Command Channel Select register (first data byte = highest device to respond (0x01), second data byte // = number of data bytes - 1 (4 bytes = 0x03)) // sampling parameters are taken from values already stored in Command Channel Select and Oversampling registers // nGrp_ID = 1; // nSent = WriteReg(nGrp_ID, 3, 0x0203, 2, FRMWRT_GRP_R); // nSent = WaitRespFrame(bFrame, 14, 0); // 4 bytes data (x2) + packet header (x2) + CRC (x2), 0ms timeout // Send group register read - 1 byte method (section 7.4) // read Command Channel Select register (data byte = number of data bytes - 1 (4 bytes = b011) | highest device // to respond (0x01)) // sampling parameters are taken from values already stored in Command Channel Select and Oversampling registers // nGrp_ID = 1; // nSent = WriteReg(nGrp_ID, 3, 0x62, 1, FRMWRT_GRP_R); // nSent = WaitRespFrame(bFrame, 14, 0); // 4 bytes data (x2) + packet header (x2) + CRC (x2), 0ms timeout // Send general broadcast register read - 2 byte method (section 8.1) // read Command Channel Select register (first data byte = highest device to respond (0x01), second data byte // = number of data bytes - 1 (0x03)) // nSent = WriteReg(0, 3, 0x0203, 2, FRMWRT_ALL_R); // nSent = WaitRespFrame(bFrame, 14, 0); // 4 bytes data (x2) + packet header (x2) + CRC (x2), 0ms timeout // Send general broadcast register read - 1 byte method (section 8.2) // read Command Channel Select register (data byte = number of data bytes - 1 (4 bytes = b011) | highest device // to respond (0x01)) // nSent = WriteReg(0, 3, 0x62, 1, FRMWRT_ALL_R); // nSent = WaitRespFrame(bFrame, 14, 0); // 4 bytes data (x2) + packet header (x2) + CRC (x2), 0ms timeout } void Pl455DeviceReInit(void) { int nSent, nRead = 0; int nDev_ID; uint32_t wTemp = 0; nSent = nSent; nRead = nRead; nDev_ID = 0; // Wake all devices // The wake tone will awaken any device that is already in shutdown and the pwrdown will shutdown any device // that is already awake. The least number of times to sequence wake and pwrdown will be half the number of // boards to cover the worst case combination of boards already awake or shutdown. nSent = WriteReg(nDev_ID, 12, 0x40, 1, FRMWRT_ALL_NR); // send out broadcast pwrdown command delay_os_ms(5); //~5ms pl455_wakeup(); delay_os_ms(5); //~5ms // Mask Customer Checksum Fault bit - [15] USER_CKSUM_MSK nSent = WriteReg(0, 107, 0x8000, 2, FRMWRT_ALL_NR); // clear all fault summary flags // Clear all faults nSent = WriteReg(0, 82, 0xFFC0, 2, FRMWRT_ALL_NR); // clear all fault summary flags - 7.6.3.27 FAULT_SUM 0x52-53 (82-83) Fault Summary nSent = WriteReg(0, 81, 0x38, 1, FRMWRT_ALL_NR); // clear fault flags in the system status register // Auto-address all boards (section 1.2.2) nSent = WriteReg(0, 14, 0x19, 1, FRMWRT_ALL_NR); // set auto-address mode on all boards - 7.6.3.9 DEVCONFIG 0x0E (14) Device Configuration nSent = WriteReg(0, 12, 0x08, 1, FRMWRT_ALL_NR); // enter auto address mode on all boards, the next write to this ID will be its address // Set addresses for all boards in daisy-chain (section 1.2.3) nSent = WriteReg(nDev_ID, 10, nDev_ID, 1, FRMWRT_ALL_NR); // send address to each board // Enable all communication interfaces on all boards in the stack (section 1.2.1) // nSent = WriteReg(0, 16, 0x10F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces on all boards in stack nSent = WriteReg(0, 16, 0x1080, 2, FRMWRT_ALL_NR); // set communications baud rate and disable all interfaces on all boards in stack - only enable uart /* Change to final baud rate used in the application (set by BAUDRATE define in pl455.h). * Up to this point, all communication is at 250Kb, as the COMM_RESET done at the initial * startup resets the bq76PL455A-Q1 UART to 250Kb. */ switch(BAUDRATE) { case 125000: nSent = WriteReg(0, 16, 0x00F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces delay_os_ms(1); // sciSetBaudrate(scilinREG, BAUDRATE); break; case 250000: delay_os_ms(1); break; case 500000: nSent = WriteReg(0, 16, 0x20F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces delay_os_ms(1); // sciSetBaudrate(scilinREG, BAUDRATE); break; case 1000000: nSent = WriteReg(0, 16, 0x30F8, 2, FRMWRT_ALL_NR); // set communications baud rate and enable all interfaces delay_os_ms(1); // sciSetBaudrate(scilinREG, BAUDRATE); break; } // Clear all faults (section 1.2.7) nSent = WriteReg(0, 82, 0xFFC0, 2, FRMWRT_ALL_NR); // clear all fault summary flags nSent = WriteReg(0, 81, 0x38, 1, FRMWRT_ALL_NR); // clear fault flags in the system status register delay_os_ms(10); // Configure AFE (section 2.2.1) nDev_ID = 0; // nSent = WriteReg(nDev_ID, 60, 0x00, 1, FRMWRT_SGL_NR); // set 0 mux delay nSent = WriteReg(nDev_ID, 61, 0x00, 1, FRMWRT_SGL_NR); // set 0 initial sampling delay // Configure voltage and internal sample period (section 2.2.2) nDev_ID = 0; nSent = WriteReg(nDev_ID, 62, 0xCC, 1, FRMWRT_SGL_NR); // set 99.92us ADC sampling period - Cell and die temperature measurement period // Configure the oversampling rate (section 2.2.3) nDev_ID = 0; nSent = WriteReg(nDev_ID, 7, 0x00, 1, FRMWRT_SGL_NR); // set no oversampling period // Clear and check faults (section 2.2.4) nDev_ID = 0; nSent = WriteReg(nDev_ID, 81, 0x38, 1, FRMWRT_SGL_NR); // clear fault flags in the system status register nSent = WriteReg(nDev_ID, 82, 0xFFC0, 2, FRMWRT_SGL_NR); // clear all fault summary flags nRead = ReadReg(nDev_ID, 81, &wTemp, 1, 0); // 0ms timeout nRead = ReadReg(nDev_ID, 82, &wTemp, 2, 0); // 0ms timeout // Select number of cells and channels to sample (section 2.2.5.1) nDev_ID = 0; nSent = WriteReg(nDev_ID, 13, 0x10, 1, FRMWRT_SGL_NR); // set number of cells to 16 // 1111 1111 0111 1111 nSent = WriteReg(nDev_ID, 3, 0xFF7F00C0, 4, FRMWRT_SGL_NR); // select all cell, AUX channels 0 and 1, and internal digital die and internal analog die temperatures // // Select identical number of cells and channels on all modules simultaneously (section 2.2.5.2) // nSent = WriteReg(0, 13, 0x10, 1, FRMWRT_ALL_NR); // set number of cells to 16 // nSent = WriteReg(0, 3, 0xFFFF03C0, 4, FRMWRT_ALL_NR); // select all cell, AUX channels 0 and 1, and internal digital die and internal analog die temperatures // nSent = WriteReg(0, 13, 0x08, 1, FRMWRT_ALL_NR); // set number of cells to 8 // nSent = WriteReg(0, 3, 0x00FF03C0, 4, FRMWRT_ALL_NR); // select all cell channels 1-8, AUX channels 0 and 1, and internal digital die and internal analog die temperatures // Set cell over-voltage and cell under-voltage thresholds on a single board (section 2.2.6.1) nDev_ID = 0; nSent = WriteReg(nDev_ID, 144, 0xD1EC, 2, FRMWRT_SGL_NR); // set OV threshold = 4.1000V nSent = WriteReg(nDev_ID, 142, 0x0000, 2, FRMWRT_SGL_NR); // set UV threshold = 1.9000V nSent = WriteReg(nDev_ID, 20, 0x0000, 2, FRMWRT_SGL_NR); // set BAL_TIME = 1 minute and set BAL_CONTINUE = 1 } /** * @brief Initialize the Ethernet Module communication application * @param None * @retval None */ void App_TaskPl455Comm(void) { Pl455CommInit(); Pl455DeviceInit(); while (DEF_TRUE) { Pl455CommProcess(); Pl455UpdateData(); delay_os_ms(PL455_COMM_TASK_TIME); } } void Pl455UpdateData(void) { device_value.Heartbeat = OptimeStamp; device_status.battery_status.bit.AFE = Pl455CommState.Commfail; } u8 Pl455BuffFlag = true; void Pl455CommProcess(void) { int nSent, nRead, nDev_ID = 0; uint32_t rTmp = 0; if (Pl455Config.Buffer != NULL) { nSent = WriteReg(nDev_ID, 81, 0x38, 1, FRMWRT_SGL_NR); // clear fault flags in the system status register nSent = WriteReg(nDev_ID, 82, 0xFFC0, 2, FRMWRT_SGL_NR); // clear all fault summary flags nRead = ReadReg(nDev_ID, 81, &rTmp, 1, 0); // 0ms timeout nRead = ReadReg(nDev_ID, 82, &rTmp, 2, 0); // 0ms timeout delay_os_ms(1); nSent = WriteReg(nDev_ID, 2, 0x00, 1, FRMWRT_SGL_R); // send read sampled values command nSent = nSent; delay_os_ms(1); nRead = WaitRespFrame(Pl455Config.Buffer, 27, 0); // 24 bytes data + packet header + CRC, 0ms timeout if (nRead > 0) { if ((Pl455Config.MsgPrint == true)&&(screenmode == DIAG_MODE)) UART_DATA_PRINT(1, Pl455Config.Buffer, Pl455Config.Position, RX_PRINT); Pl455_commfail_clear(); CellVoltagePutBuf(Pl455Config.Buffer); MakeCellAvgData(); } else { Pl455_commfail_check(); } delay_os_ms(1); nRead = ReadReg(nDev_ID, 20, &rTmp, 2, 0); // Cell balancing register if (nRead > 0) { if (device_status.battery_status.bit.ACB) PL455_Cell_AutoBalancing(rTmp); else PL455_Cell_ManualBalancing(rTmp); } } } // VCELL = [(2 * VREF) / 65535] * READ_ADC_VALUE u16 GetCellVoltageConvValue(uint8_t *data) { uint16_t adcValue = (uint16_t)((data[0] << 8) | data[1]); float ftmp; ftmp = ((2 * PL455_VREF) / 65535) * adcValue; return (uint16_t)(ftmp * 1000);; } void CellVoltagePutBuf(uint8_t *pdata) { s32 ch, j, cno, tmp; ch = PackBufCh; j = 1; cno = 14; // data buffering PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 15 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 14 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 13 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 12 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 11 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 10 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 9 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 8 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 7 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 6 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 5 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 4 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 3 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 2 PackBuf[ch].cvolt[cno--] = GetCellVoltageConvValue(&pdata[j]); j += 2; // Cell 1 if (Pl455BuffFlag == true) { Pl455BuffFlag = false; for (int i = 0; i < DEVICE_MAX_CELL; i++) { for (int j = 0; j < PACK_BUF_MAX; j++) { PackBuf[j].cvolt[i] = PackBuf[ch].cvolt[i]; } } } // Volt Avg for (int i = 0; i < DEVICE_MAX_CELL; i++) { tmp = 0; for (int j = 0; j < PACK_BUF_MAX; j++) { tmp += PackBuf[j].cvolt[i]; } device_value.Cell.voltage[i] = (uint16_t)(tmp / PACK_BUF_MAX); } PackBufCh++; PackBufCh %= PACK_BUF_MAX; } /* Internal Analog Die Temperature deg C = (VADC - 1.8078) * 147.514 where VADC=[(2 * VREF) / 65535] * READ_ADC_VALUE VVM = -2 * [(2 * VREF) / 65535] * READ_ADC_VALUE Internal Digital Die Temperature deg C = (VADC - 2.287) * 131.944 VMODULE = ([(2 * VREF) / 65535] * READ_ADC_VALUE) * 25 VAUX = [(2 * VREF) / 65535] * READ_ADC_VALUE */ void MakeCellAvgData(void) { u32 sum; TMinMax min, max; sum = 0; memset(&min, 0x00, sizeof(TMinMax)); memset(&max, 0x00, sizeof(TMinMax)); for (int i = 0; i < DEVICE_MAX_CELL; i++) { if (i == 0) { max.value = device_value.Cell.voltage[i]; max.num = i; min.value = device_value.Cell.voltage[i]; min.num = i; } if (max.value < device_value.Cell.voltage[i]) { max.value = device_value.Cell.voltage[i]; max.num = i; } if (min.value > device_value.Cell.voltage[i]) { min.value = device_value.Cell.voltage[i]; min.num = i; } sum += device_value.Cell.voltage[i]; } device_value.BatVoltage = sum / 10; device_value.Cell.avg.Max.value = max.value; device_value.Cell.avg.Max.num = max.num; device_value.Cell.avg.Min.value = min.value; device_value.Cell.avg.Min.num = min.num; device_value.Cell.avg.diff = max.value - min.value; device_value.Cell.avg.avg = (u16)(sum / DEVICE_MAX_CELL); } void dec_cb_tick(u16 tick) { if (CB_Tick > tick) CB_Tick -= tick; else CB_Tick = 0; } void PL455_Cell_AutoBalancing(uint32_t rBal) { u16 bal = 0; u8 setBal = false; PDEVICE_PARAM param = &device_param; for (int i = 0; i < 16; i++) { if ((rBal >> i) & 0x0001) { if (i < emptyNo) bal |= (uint16_t)(1 << i); else if (i == emptyNo) ; else if (i > emptyNo) bal |= (uint16_t)(1 << (i - 1)); } } device_status.cellbalance.value = bal; if (CB_Rest == true) { if (CB_Tick == 0) { CB_Rest = false; CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000; setBal = true; } } else { if (CB_Tick == 0) { CB_Rest = true; CB_Tick = param->chg_ctrl.cell_bal_cfg.Cell_Balance_Interval * 1000; setBal = true; } } if (CellBalancingFlag == true) { // Before cell balancing status is ON if (device_value.Cell.avg.Max.value < param->chg_ctrl.cell_bal_cfg.Cell_Balance_Threshold) CellBalancingFlag = false; else if (device_value.Cell.avg.diff < (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Min - 5)) { if (device_status.warning.bit.cell_over_voltage == 0) CellBalancingFlag = false; } } else { // Before cell balancing status is OFF if (device_value.Cell.avg.Max.value > (param->chg_ctrl.cell_bal_cfg.Cell_Balance_Threshold + param->chg_ctrl.cell_bal_cfg.Cell_Balance_Window)) { if (device_value.Cell.avg.diff > param->chg_ctrl.cell_bal_cfg.Cell_Balance_Min) CellBalancingFlag = true; else if (device_status.warning.bit.cell_over_voltage) CellBalancingFlag = true; } } device_status.battery_status.bit.CB = CellBalancingFlag; if (CellBalancingFlag == true) { if (setBal == true) { if (CB_Rest == false) { if (device_value.Cell.avg.Min.value > 3580) { if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > 20) { Balance_Avg = device_value.Cell.avg.avg + 10; } else { if ((device_value.Cell.avg.avg - device_value.Cell.avg.Min.value) > 20) Balance_Avg = device_value.Cell.avg.avg + 2; else Balance_Avg = device_value.Cell.avg.avg + 5; } } else { if (device_value.Cell.avg.diff > 100) { if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) Balance_Avg = device_value.Cell.avg.avg + 20; else Balance_Avg = device_value.Cell.avg.avg - 20; } else if (device_value.Cell.avg.diff > 80) { if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) Balance_Avg = device_value.Cell.avg.avg + 15; else Balance_Avg = device_value.Cell.avg.avg - 15; } else if (device_value.Cell.avg.diff > 60) { if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) Balance_Avg = device_value.Cell.avg.avg + 10; else Balance_Avg = device_value.Cell.avg.avg - 10; } else if (device_value.Cell.avg.diff > 40) { if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) Balance_Avg = device_value.Cell.avg.avg + 5; else Balance_Avg = device_value.Cell.avg.avg - 5; } else if (device_value.Cell.avg.diff > 30) { if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) Balance_Avg = device_value.Cell.avg.avg + 2; else Balance_Avg = device_value.Cell.avg.avg - 2; } else if (device_value.Cell.avg.diff > 20) { if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) Balance_Avg = device_value.Cell.avg.avg + 2; else Balance_Avg = device_value.Cell.avg.avg - 2; } else if (device_value.Cell.avg.diff > 10) { if ((device_value.Cell.avg.Max.value - device_value.Cell.avg.avg) > (device_value.Cell.avg.avg - device_value.Cell.avg.Min.value)) Balance_Avg = device_value.Cell.avg.avg + 1; else Balance_Avg = device_value.Cell.avg.avg - 1; } else { Balance_Avg = device_value.Cell.avg.avg; } } bal = 0; for (int i = 0; i < DEVICE_MAX_CELL; i++) { if ((device_value.Cell.voltage[i] > Balance_Avg) || ((device_status.cov_warning_cell.uValue >> i) == 1)) { if (i < emptyNo) bal = bal | (1 << i); else bal = bal | (1 << (i + 1)); } } WriteReg(0, 20, bal, 2, FRMWRT_SGL_NR); // Cell balancing all off } else { // CB Rest time bal = 0; for (int i = 0; i < DEVICE_MAX_CELL; i++) { if ((device_status.cov_warning_cell.uValue >> i) == 1) { if (i < emptyNo) bal = bal | (1 << i); else bal = bal | (1 << (i + 1)); } } WriteReg(0, 20, bal, 2, FRMWRT_SGL_NR); // Cell balancing all off } } } else { if (device_status.cellbalance.value != 0x0000) WriteReg(0, 20, 0x0000, 2, FRMWRT_SGL_NR); // Cell balancing all off } } void SetManualBalancing(u8 flag, u32 cNo) { ManualBalFlag = flag; if (ManualBalFlag == true) { if (cNo >= 1) ManualBalValue |= (1 << (cNo - 1)); } else { ManualBalValue = 0; } } void PL455_Cell_ManualBalancing(uint32_t rBal) { u16 bal = 0; for (int i = 0; i < 16; i++) { if ((rBal >> i) & 0x0001) { if (i < 8) bal |= (uint16_t)(1 << i); else if (i == 9) ; else if (i > 9) bal |= (uint16_t)(1 << (i - 1)); } } device_status.cellbalance.value = bal; if (ManualBalFlag == true) { if (ManualBalValue != bal) WriteReg(0, 20, ManualBalValue, 2, FRMWRT_SGL_NR); // Cell balancing all off } else { if (bal != 0) WriteReg(0, 20, 0x0000, 2, FRMWRT_SGL_NR); // Cell balancing all off } } void Pl455_commfail_clear(void) { Pl455CommState.Timeout = 0; Pl455CommState.Commfail = false; } void Pl455_commfail_check(void) { if (Pl455CommState.Commfail == false) { Pl455CommState.Timeout++; if (Pl455CommState.Timeout >= (PL455_COMM_MAX_TIMEOUT / 2)) { Pl455DeviceReInit(); delay_os_ms(1000); } if (Pl455CommState.Timeout >= PL455_COMM_MAX_TIMEOUT) { Pl455CommState.Commfail = true; } } if ((Pl455Config.DataPrint == true) && (screenmode == DIAG_MODE)) { printf("\r\nTimeout[%d] PL455 %03d(%d)" , Pl455CommState.Timeout , Pl455Config.Position , Pl455CommState.Commfail ); } } void SendDataToPl455(uint8_t *data, u16 len) { UART2_Flush(); UART2_PutStr(data, len); if ((Pl455Config.MsgPrint == true)&&(screenmode == DIAG_MODE)) UART_DATA_PRINT(2, data, len, TX_PRINT); } void Pl455PacketInit(void) { Pl455Config.BufferStart = false; Pl455Config.Position = 0; } u8 GetPl455CommPacket(uint8_t *rdata, uint16_t len) { u8 one; u16 count; Pl455PacketInit(); count = 0; while(1) { if (UART2_GetChar(&one) == SUCCESS) { count = 0; if ((Pl455Config.DataPrint == true)&&(screenmode == DIAG_MODE)) { if (Pl455Config.BufferStart == false) printf("\r\n[PL455 RECV] : "); printf("%02X ", one); } if (Pl455Config.Position >= PL455_COMM_MAX_BUFFER_SIZE) { Pl455PacketInit(); return false; } if (Pl455Config.BufferStart == false) { rdata[Pl455Config.Position] = one; Pl455Config.Position++; Pl455Config.BufferStart = true; } else { rdata[Pl455Config.Position++] = one; } } else { if ((Pl455Config.BufferStart == true)&&(count > 0)) return true; count++; if (count >= (PL455_COMM_RX_TIMEOUT / PL455_COMM_RX_DELAY)) return false; delay_os_ms(PL455_COMM_RX_DELAY); } } } /* Public Status Function ************************************************************/ u16 GetBalanceAvg(void) { return Balance_Avg; } u16 GetBalanceFlag(void) { return CellBalancingFlag; } /* Display Function ******************************************************************/ #ifdef CONSOLE_DEBUG void ODisplayBalancingValue(u8 p) { float aParam; if (p || (disBalance_Avg != Balance_Avg)) { aParam = (float)Balance_Avg / 1000; FloatNormalOutIntXY(71, 10 , aParam, 5, 3); disBalance_Avg = Balance_Avg; } if (p || (disCellBalancingFlag != CellBalancingFlag)) { if (CellBalancingFlag == true) YellowOutXY(68, 11, (u8 *)"O"); else GreenOutXY(68, 11, (u8 *)"X"); disCellBalancingFlag = CellBalancingFlag; } if (p || ((disCB_Tick / 1000) != (CB_Tick / 1000))) { aParam = (float)(disCB_Tick / 1000); FloatNormalOutIntXY(70, 11,aParam, 6, 0); disCB_Tick = CB_Tick; } } void DDisplay_Pl455Comm(u8 p) { if (p ||(Pl455Config.BakMsgPrint != Pl455Config.MsgPrint)) { if (Pl455Config.MsgPrint) GreenOutXY ( 27, 6, (u8 *)"ENABLE "); else NormalOutXY( 27, 6, (u8 *)"DISABLE"); Pl455Config.BakMsgPrint = Pl455Config.MsgPrint; } if (p ||(Pl455Config.BakDataPrint != Pl455Config.DataPrint)) { if (Pl455Config.DataPrint)GreenOutXY ( 71, 6, (u8 *)"ENABLE "); else NormalOutXY( 71, 6, (u8 *)"DISABLE"); Pl455Config.BakDataPrint = Pl455Config.DataPrint; } } u8 DPl455CommCommand(u8 cmd) { u8 result = false; switch (cmd) { case '0': // PL455 COMM MSG MONITOR if (Pl455Config.MsgPrint == true) { Pl455Config.MsgPrint = false; UserMessage("[MESSAGE]: PL455 MSG PRINT DISABLE"); } else { Pl455Config.MsgPrint = true; UserMessage("[MESSAGE]: PL455 MSG PRINT ENABLE"); } break; case '1': // PL455 COMM DATA MONITOR if (Pl455Config.DataPrint == true) { Pl455Config.DataPrint = false; UserMessage("[MESSAGE]: PL455 DATA PRINT DISABLE"); } else { Pl455Config.DataPrint = true; UserMessage("[MESSAGE]: PL455 DATA PRINT ENABLE"); } break; default: result = 1; break; } return result; } #endif // #ifdef CONSOLE_DEBUG /******************* (C) COPYRIGHT 2015 STMicroelectronics *****END OF FILE****/