Files

1147 lines
38 KiB
C

/**
******************************************************************************
* File Name : pl455_comm.c
* Description : This file provides code for the configuration
* of CAN communication.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* 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 <includes.h>
#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****/