- Main Page
- Data Structures
- Files

- File List
- Globals

# bq_pack.c

Go to the documentation of this file.

    00001 //******************************************************************************
    00002 //THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
    00003 //REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
    00004 //INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
    00005 //FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
    00006 //COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
    00007 //TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET
    00008 //POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY
    00009 //INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR
    00010 //YOUR USE OF THE PROGRAM.
    00011 //
    00012 //IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
    00013 //CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY
    00014 //THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED
    00015 //OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT
    00016 //OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.
    00017 //EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF
    00018 //REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS
    00019 //OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF
    00020 //USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S
    00021 //AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF
    00022 //YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS
    00023 //(U.S.$500).
    00024 //
    00025 //Unless otherwise stated, the Program written and copyrighted
    00026 //by Texas Instruments is distributed as "freeware".  You may,
    00027 //only under TI's copyright in the Program, use and modify the
    00028 //Program without any charge or restriction.  You may
    00029 //distribute to third parties, provided that you transfer a
    00030 //copy of this license to the third party and the third party
    00031 //agrees to these terms by its first use of the Program. You
    00032 //must reproduce the copyright notice and any other legend of
    00033 //ownership on each copy or partial copy, of the Program.
    00034 //
    00035 //You acknowledge and agree that the Program contains
    00036 //copyrighted material, trade secrets and other TI proprietary
    00037 //information and is protected by copyright laws,
    00038 //international copyright treaties, and trade secret laws, as
    00039 //well as other intellectual property laws.  To protect TI's
    00040 //rights in the Program, you agree not to decompile, reverse
    00041 //engineer, disassemble or otherwise translate any object code
    00042 //versions of the Program to a human-readable form.  You agree
    00043 //that in no event will you alter, remove or destroy any
    00044 //copyright notice included in the Program.  TI reserves all
    00045 //rights not specifically granted under this license. Except
    00046 //as specifically provided herein, nothing in this agreement
    00047 //shall be construed as conferring by implication, estoppel,
    00048 //or otherwise, upon you, any license or other right under any
    00049 //TI patents, copyrights or trade secrets.
    00050 //
    00051 //You may not use the Program in non-TI devices.
    00052 //
    00053 //This software has been submitted to export control regulations
    00054 //The ECCN is EAR99
    00055 //****************************************************************************
    00056
    00068 #include <intrinsics.h>
    00069 #include <string.h>
    00070 #include <stdio.h>
    00071
    00072 #include "MSP430.h"
    00073 #include "main.h"
    00074 #include "bq_pack.h"
    00075 #include "spi_if.h"
    00076 #include "data_flash.h"
    00077 #include "USBCDC_constructs.h"
    00078 #include "Common\types.h"
    00079 #include "Common\hal_macros.h"
    00080
    00081
    00082 /******************************************************************************/
    00083 /*                            Global variables                                */
    00084 /******************************************************************************/
    00085 //Global variable that contains the battery pack information
    00086 bq_pack_t bq_pack;
    00087 //SW flag that controls the Charge/Discharge mode
    00088 unsigned char HOST_CONTROL_IN = 0;
    00089
    00090 /******************************************************************************/
    00091 /*                            Local variables                                 */
    00092 /******************************************************************************/
    00093 //Array that stores a copy of the last known cell voltages
    00094 static unsigned short cell_values[NUMBER_OF_CELLS];
    00095
    00102 short bq_pack_address_discovery(void)
    00103 {
    00104   unsigned short i, n;
    00105   unsigned char reg_val[2];
    00106
    00107   i=NUMBER_OF_BQ_DEVICES; //controls iteration loop
    00108   while (i>0)
    00109   {
    00110     //*Send BROADCAST_RESET to address 0x00*/
    00111     bq_dev_write_reg(BROADCAST_ADDR, RESET_REG, BQ76PL536_RESET);
    00112
    00113     n=0;  //controls number of discovered devices
    00114     while (n<NUMBER_OF_BQ_DEVICES)
    00115     {
    00116     //*Read DEVICE_STATUS reg at address 0x00*/
    00117     bq_dev_read_reg(DISCOVERY_ADDR, DEVICE_STATUS_REG, 1, DISCARD_CRC, reg_val);
    00118
    00119       //*Verify if MSB is equal to 0*/
    00120       if (reg_val[0] & (1<<7))
    00121       {
    00122         n = NUMBER_OF_BQ_DEVICES; //break internal loop
    00123       }
    00124       else
    00125       {
    00126         //*Assign a new address*/
    00127
    00128         //Save assigned address
    00129         n++;
    00130         bq_pack.bq_devs[n-1].device_address = n;
    00131
    00132         //ADDR_CTRL = n;
    00133         bq_dev_write_reg(DISCOVERY_ADDR, ADDRESS_CONTROL_REG, n);
    00134
    00135         //read ADDR_CTRL
    00136         bq_dev_read_reg(n, ADDRESS_CONTROL_REG, 1, DISCARD_CRC, reg_val);
    00137         if ((reg_val[0]&0x3F) == n)
    00138         {
    00139           //address next device or finish device detection
    00140           if (n==NUMBER_OF_BQ_DEVICES)
    00141             return n;
    00142         }
    00143         else
    00144         {
    00145           //break internal loop
    00146           n = NUMBER_OF_BQ_DEVICES;
    00147         }
    00148       }
    00149     }
    00150
    00151     i--;
    00152   }
    00153
    00154   return 0;
    00155 }
    00156
    00164 short bq_pack_init(void)
    00165 {
    00166   unsigned char i;
    00167
    00168   for (i=0; i<NUMBER_OF_BQ_DEVICES; i++)
    00169   {
    00170     //*Init cell count for each BQ device*/
    00171     bq_pack.bq_devs[i].cell_count = MAX_CELLS_NUMBER_IN_BQ;
    00172
    00173     //*Configure each BQ device*/
    00174     conf_bq_dev(&bq_pack.bq_devs[i]);
    00175
    00176     //*Initilize data structures*/
    00177     init_bq_dev_data_structure(&bq_pack.bq_devs[i]);
    00178
    00179     //*Read cell voltage*/
    00180     bq_dev_read_cell_voltage(&bq_pack.bq_devs[i]);
    00181   }
    00182   //battery manager initial mode
    00183   bq_pack.op_mode = FAULT_MODE;
    00184   bq_pack.error_status = 0;
    00185   bq_pack.voltage = 0;
    00186   bq_pack.timer_status = 0;
    00187   bq_pack.eoc_eod_timer = 0;
    00188   bq_pack.charge_taper_timer = 0;
    00189   bq_pack.chg_dschg_op_timer = 0;
    00190   bq_pack.balancing_timer = 0;
    00191   bq_pack.max_balance_timer = 0;
    00192   bq_pack.last_imbalanced_cell_idx = 0;
    00193   bq_pack.cell_imbalance_fail_timer = 0;
    00194   // set the battery manager to initial mode
    00195   update_op_mode(INITIAL_MODE);
    00196   return 0;
    00197 }
    00198
    00199
    00207 void update_bq_pack_data(void)
    00208 {
    00209   unsigned char i, cell_cnt;
    00210   unsigned short stack_voltage = 0;
    00211   //read the pack data
    00212   for (i=0; i<NUMBER_OF_BQ_DEVICES; i++)
    00213   {
    00214     //*Read each device status*/
    00215     bq_dev_read_status(&bq_pack.bq_devs[i]);
    00216
    00217     //*Read each cell voltage and calculate BQ Pack voltage*/
    00218     bq_dev_read_cell_voltage(&bq_pack.bq_devs[i]);
    00219
    00220     //Identify the lowest and highest voltage in the pack
    00221     if (i == 0)
    00222     {
    00223       bq_pack.lowest_cell_volts = bq_pack.bq_devs[i].cell_voltage[0];
    00224       bq_pack.highest_cell_volts = bq_pack.bq_devs[i].cell_voltage[0];
    00225     }
    00226     //calculate the pack voltage
    00227     for (cell_cnt=0; cell_cnt<bq_pack.bq_devs[i].cell_count; cell_cnt++)
    00228     {
    00229       stack_voltage += bq_pack.bq_devs[i].cell_voltage[cell_cnt];
    00230
    00231       if (bq_pack.bq_devs[i].cell_voltage[cell_cnt]
    00232           < bq_pack.lowest_cell_volts)
    00233       {
    00234         bq_pack.lowest_cell_volts = bq_pack.bq_devs[i].cell_voltage[cell_cnt];
    00235       }
    00236       else if (bq_pack.bq_devs[i].cell_voltage[cell_cnt]
    00237                > bq_pack.highest_cell_volts)
    00238       {
    00239         bq_pack.highest_cell_volts = bq_pack.bq_devs[i].cell_voltage[cell_cnt];
    00240       }
    00241     }
    00242
    00243     //*Read each device errors*/
    00244     bq_dev_read_errors(&bq_pack.bq_devs[i]);
    00245
    00246     //*Read each device temperature*/
    00247     bq_dev_read_temps(&bq_pack.bq_devs[i]);
    00248   }
    00249
    00250   //*Save BQ Pack voltage*/
    00251   bq_pack.voltage = stack_voltage;
    00252
    00253   return;
    00254 }
    00255
    00262 void bq_pack_start_conv(void)
    00263 {
    00264   //Should address all devices in the stack
    00265   bq_dev_write_reg(BROADCAST_ADDR, ADC_CONVERT_REG, ADC_CONVERT_VAL);
    00266
    00267 }
    00268
    00275 void CheckFaultConditions(void)
    00276 {
    00277   //check for POT or COV conditions
    00278   if (check_for_pot() || check_for_cov())
    00279   {
    00280     bq_pack.error_status |= STATUS_ERROR_POT_COV;
    00281
    00282     //can only return to previous mode when error condition disapears
    00283     update_op_mode(FAULT_MODE);
    00284
    00285   }
    00286   //Check for CUV condition
    00287   if (check_for_cuv())
    00288   {
    00289     bq_pack.error_status |= STATUS_ERROR_CUV;
    00290
    00291     //can only return to previous mode when error condition disapears
    00292     update_op_mode(FAULT_MODE);
    00293   }
    00294 }
    00295
    00296
    00303 void CheckChargeDischargeModes(void)
    00304 {
    00305   //Charge/Discharge watchdog timer ON??
    00306   if (bq_pack.timer_status & START_CHG_DSCHG_OP_TIMER)
    00307   { //Charge/Discharge watchdog timer expired??
    00308     if (bq_pack.chg_dschg_op_timer >= (get_u32_value(CHARGE_DISCHARGE_TIME)))
    00309     { //Check if the cells increased their voltage
    00310       if (check_for_charge_op())
    00311       {
    00312         //Charge operation detected!
    00313         update_op_mode(CHARGE_OP);
    00314       }//Check if the cells decreased their voltage
    00315       else if (check_for_discharge_op())
    00316       {
    00317         //Discharge operation detected!
    00318         update_op_mode(DISCHARGE_OP);
    00319       }
    00320
    00321       //Clear timer count
    00322       bq_pack.chg_dschg_op_timer = 0;
    00323
    00324       //Save current cell voltages for next comparison
    00325       copy_cell_voltage_values();
    00326     }
    00327   }
    00328 }
    00329
    00337 #if CELL_BALANCING_EN
    00338 void CellBalancing(void)
    00339 {
    00340
    00341   unsigned short dev_id;
    00342
    00343
    00344   if (bq_pack.timer_status & START_CELL_BALANCE_TIMER)
    00345   {
    00346     //*Perform cell balancing only if CHARGE OPERATION is in effect*/
    00347     //if battery pack is charging
    00348     if (HOST_CONTROL_IN & IN_HOST_CHG_OP)
    00349     {
    00350       //balancing time has expired? Yes, then...
    00351       if (bq_pack.balancing_timer >= (get_u32_value(BALANCE_TIME)-2))
    00352       {
    00353         //cell balancing achieved?
    00354         if ((bq_pack.highest_cell_volts - bq_pack.lowest_cell_volts) >=
    00355           get_u32_value(BALANCE_VOLTS_THRESHOLD))
    00356         { //cell balancing achieved? ->No,
    00357           //then reset balancing timer & continue balancing
    00358           for (dev_id=0; dev_id<NUMBER_OF_BQ_DEVICES; dev_id++)
    00359           {
    00360             //*Enable bypass resistor for all balanced cells*/
    00361             enable_bypass_resistor(dev_id, (~find_imbalanced_cell(dev_id)));
    00362
    00363           }
    00364           //reset balancing virtual timer
    00365           bq_pack.balancing_timer = 0;
    00366
    00367         }
    00368         else
    00369         {
    00370           //cell balancing achieved? ->Yes,
    00371           //then Stop balancing timer
    00372           bq_pack.timer_status &= ~START_CELL_BALANCE_TIMER;
    00373
    00374           //Disable bypass resistors
    00375           disable_all_bypass_resistors();
    00376         }
    00377       }
    00378       //If max balancing time has expired, then...
    00379       if (bq_pack.max_balance_timer > get_u32_value(MAX_BALANCE_TIME))
    00380       {
    00381         //flag the error and set the pack in SOV mode..
    00382         bq_pack.error_status |= STATUS_ERROR_MAX_BALANCE_TIME;
    00383         update_op_mode(SOV_MODE);
    00384       }
    00385
    00386        //If cell Imbalance timer time has expired, then...
    00387       if(bq_pack.cell_imbalance_fail_timer
    00388          > get_u32_value(CELL_IMBALANCE_FAIL_TIME))
    00389       {
    00390         //flag the error and set the pack in SOV mode..
    00391         bq_pack.error_status |= STATUS_ERROR_IMBALANCE_FAIL;
    00392         update_op_mode(SOV_MODE);
    00393       }
    00394     }
    00395     else //If pack is not in charging mode then...
    00396     {
    00397       //Stop cell balancing timers
    00398       bq_pack.timer_status &= ~START_CELL_BALANCE_TIMER;
    00399       //reset all cell balancing timers
    00400       bq_pack.balancing_timer=0;
    00401       bq_pack.max_balance_timer=0;
    00402       bq_pack.cell_imbalance_fail_timer=0;
    00403
    00404       //*Disable all bypass resistors*/
    00405       disable_all_bypass_resistors();
    00406     }
    00407   }
    00408   else //if cell balancing is not active then start balancing
    00409   {
    00410     /*Perform cell balancing only if CHARGE OPERATION is in effect*/
    00411     if (HOST_CONTROL_IN & IN_HOST_CHG_OP)
    00412     {
    00413       //check if cell balancing is required...
    00414       if (((bq_pack.highest_cell_volts - bq_pack.lowest_cell_volts) >=
    00415           get_u32_value(BALANCE_VOLTS_THRESHOLD)))
    00416       {
    00417         //and allowed...
    00418         if(bq_pack.lowest_cell_volts > get_u32_value(MIN_BALANCE_VOLTS))
    00419         {
    00420           //Start cell balancing timer
    00421           bq_pack.timer_status |= START_CELL_BALANCE_TIMER;
    00422           //reset cell balancing timers
    00423           bq_pack.balancing_timer = 0;
    00424           bq_pack.max_balance_timer = 0;
    00425           bq_pack.cell_imbalance_fail_timer = 0;
    00426           //enable the bypass resistors
    00427
    00428           for (dev_id=0; dev_id<NUMBER_OF_BQ_DEVICES; dev_id++)
    00429           {
    00430             //*Enable bypass resistor for all balanced cells*/
    00431             enable_bypass_resistor(dev_id, (~find_imbalanced_cell(dev_id)));
    00432
    00433           }
    00434         }
    00435       }
    00436     }
    00437   }
    00438 }
    00439 #endif
    00440
    00448 void CheckEndOfChargeOrDischargeModes(void)
    00449 {
    00450    //*For Operation mode different than FAULT MODE*/
    00451   if (bq_pack.op_mode < FAULT_MODE)
    00452   {  //check if pack voltage is lower than the end of discharge voltage
    00453     if (bq_pack.voltage < get_u32_value(PACK_END_OF_DISCHARGE_VOLTAGE))
    00454     {
    00455       update_op_mode(END_OF_DISCHARGE);
    00456
    00457     }//check if the battery pack voltage is higher than the end of charge volt
    00458     else if (bq_pack.voltage > get_u32_value(PACK_END_OF_CHARGE_VOLTAGE))
    00459     {
    00460       update_op_mode(END_OF_CHARGE);
    00461
    00462     }
    00463   }
    00464 }
    00465
    00472 void BatteryPackManager(void)
    00473 {
    00474
    00475   CheckFaultConditions();
    00476   CheckChargeDischargeModes();
    00477   CheckEndOfChargeOrDischargeModes();
    00478 #if CELL_BALANCING_EN
    00479   CellBalancing();
    00480 #endif
    00481
    00482 }
    00483
    00490 unsigned short get_bq_pack_voltage(void)
    00491 {
    00492   return bq_pack.voltage;
    00493 }
    00494
    00502 unsigned short get_bq_pack_timer(void)
    00503 {
    00504   return bq_pack.eoc_eod_timer;
    00505 }
    00506
    00513 void update_bq_pack_timer(void)
    00514 {
    00515   if (bq_pack.timer_status & START_END_OF_CHG_DSCHG_TIMER)
    00516   {
    00517     bq_pack.eoc_eod_timer++;
    00518   }
    00519
    00520   if (bq_pack.timer_status & START_CHARGE_TAPER_TIMER)
    00521   {
    00522     bq_pack.charge_taper_timer++;
    00523   }
    00524
    00525
    00526   if (bq_pack.timer_status & START_CHG_DSCHG_OP_TIMER)
    00527   {
    00528     bq_pack.chg_dschg_op_timer++;
    00529   }
    00530
    00531
    00532 #if CELL_BALANCING_EN
    00533   if (bq_pack.timer_status & START_CELL_BALANCE_TIMER)
    00534   {
    00535     bq_pack.balancing_timer++;
    00536     bq_pack.max_balance_timer++;
    00537
    00538     //Update imbalance timer if voltage between any 2 cells
    00539     //> CELL_IMBALANCE_THRESHOLD
    00540     if (cell_imbalance_threshold_reached())
    00541     {
    00542       bq_pack.cell_imbalance_fail_timer++;
    00543     }
    00544     else
    00545     {
    00546       bq_pack.cell_imbalance_fail_timer = 0;
    00547     }
    00548   }
    00549 #endif
    00550
    00551   return;
    00552 }
    00553
    00554
    00561 op_modes_t get_bq_pack_mode(void)
    00562 {
    00563   return bq_pack.op_mode;
    00564 }
    00565
    00566 void set_bq_pack_mode(op_modes_t mode)
    00567 {
    00568   bq_pack.op_mode = mode;
    00569
    00570   return;
    00571 }
    00572
    00573
    00574 /******************************************************************************/
    00575 /*                            Local functions                                 */
    00576 /******************************************************************************/
    00583 void conf_bq_dev(bq_dev_t* this)
    00584 {
    00585   unsigned short temp;
    00586
    00587   bq_dev_write_reg(this->device_address, ADC_CONTROL_REG, ADC_CONTROL_VAL_6);
    00588
    00589   bq_dev_write_reg(this->device_address, IO_CONTROL_REG, IO_CONTROL_VAL);
    00590
    00591   bq_dev_write_reg(this->device_address, CB_CTRL_REG, CB_CTRL_VAL);
    00592   bq_dev_write_reg(this->device_address, CB_TIME_REG, CB_TIME_VAL);
    00593
    00594   bq_dev_write_reg(this->device_address, SHDW_CTRL_REG, SHDW_CTRL_ACCESS_EN_VAL);
    00595
    00596   bq_dev_write_reg(this->device_address, FUNCTION_CONFIG_REG, FUNC_CONFIG_VAL_6);
    00597
    00598   bq_dev_write_reg(this->device_address, SHDW_CTRL_REG, SHDW_CTRL_ACCESS_EN_VAL);
    00599   bq_dev_write_reg(this->device_address, IO_CONFIG_REG, IO_CONFIG_VAL);
    00600
    00601   temp = get_u32_value(COV_THRESHOLD);
    00602   if (temp > 2000)
    00603     temp = (temp - 2000)/50;
    00604   else
    00605     temp = 0;
    00606
    00607   bq_dev_write_reg(this->device_address, SHDW_CTRL_REG, SHDW_CTRL_ACCESS_EN_VAL);
    00608   bq_dev_write_reg(this->device_address, CONFIG_COV_REG, CONFIG_COV_VAL | temp);
    00609   bq_dev_write_reg(this->device_address, SHDW_CTRL_REG, SHDW_CTRL_ACCESS_EN_VAL);
    00610   bq_dev_write_reg(this->device_address, CONFIG_COVT_REG,
    00611                    CONFIG_COVT_VAL | COV_TIME);
    00612
    00613   temp = get_u32_value(CUV_THRESHOLD);
    00614   if (temp > 700)
    00615     temp = (temp - 700)/100;
    00616   else
    00617     temp = 13;  /*Def CUV Threshold value = 2000mV*/
    00618   bq_dev_write_reg(this->device_address, SHDW_CTRL_REG, SHDW_CTRL_ACCESS_EN_VAL);
    00619   /*Def CUV Threshold = 2V*/
    00620   bq_dev_write_reg(this->device_address, CONFIG_CUV_REG, CONFIG_CUV_VAL | temp);
    00621   bq_dev_write_reg(this->device_address, SHDW_CTRL_REG, SHDW_CTRL_ACCESS_EN_VAL);
    00622   bq_dev_write_reg(this->device_address, CONFIG_CUVT_REG, CONFIG_CUVT_VAL
    00623                    | CUV_TIME);
    00624
    00625   bq_dev_write_reg(this->device_address, SHDW_CTRL_REG, SHDW_CTRL_ACCESS_EN_VAL);
    00626   /*TS2=TS1=50stC*/
    00627   bq_dev_write_reg(this->device_address, CONFIG_OT_REG, CONFIG_OT_VAL);
    00628   bq_dev_write_reg(this->device_address, SHDW_CTRL_REG, SHDW_CTRL_ACCESS_EN_VAL);
    00629   /*Over Temp Time delay = 2000ms*/
    00630   bq_dev_write_reg(this->device_address, CONFIG_OTT_REG, CONFIG_OTT_VAL);
    00631
    00632   return;
    00633 }
    00634
    00642 void init_bq_dev_data_structure(bq_dev_t* this)
    00643 {
    00644   bq_dev_read_reg(this->device_address, DEVICE_STATUS_REG, 1, DISCARD_CRC,
    00645                  (unsigned char*) &this->device_status);
    00646
    00647   bq_dev_read_reg(this->device_address, TEMPERATURE1_L_REG, 2, DISCARD_CRC,
    00648                  (unsigned char*) &this->temperature1);
    00649   bq_dev_read_reg(this->device_address, TEMPERATURE2_L_REG, 2, DISCARD_CRC,
    00650                  (unsigned char*) &this->temperature2);
    00651
    00652   /*Errors handling*/
    00653   bq_dev_read_reg(this->device_address, ALERT_STATUS_REG, 1, DISCARD_CRC,
    00654                  (unsigned char*) &this->alert_status);
    00655   bq_dev_read_reg(this->device_address, FAULT_STATUS_REG, 1, DISCARD_CRC,
    00656                  (unsigned char*) &this->fault_status);
    00657   bq_dev_read_reg(this->device_address, COV_FAULT_REG, 1, DISCARD_CRC,
    00658                  (unsigned char*) &this->cov_fault);
    00659   bq_dev_read_reg(this->device_address, CUV_FAULT_REG, 1, DISCARD_CRC,
    00660                  (unsigned char*) &this->cuv_fault);
    00661
    00662   /*Clear alerts and faults (May not be so trivial...)*/
    00663   bq_dev_clear_alerts(this);
    00664   bq_dev_clear_faults(this);
    00665
    00666   return;
    00667 }
    00668
    00669
    00676 short bq_dev_read_cell_voltage(bq_dev_t* this)
    00677 {
    00678   unsigned char* pPtr;
    00679   unsigned char temp;
    00680   short i, ret_val;
    00681   unsigned long voltage_comput;
    00682
    00683   ret_val = bq_dev_read_reg(this->device_address, VCELL1_L_REG,
    00684             (MAX_CELLS_NUMBER_IN_BQ<<1) , DISCARD_CRC,
    00685             (unsigned char *) &this->cell_voltage[0]);
    00686
    00687   for (i=0; i<MAX_CELLS_NUMBER_IN_BQ; i++)
    00688   {
    00689     //Swap the data in the array as BQ dev returns data in Big Endian notation
    00690     pPtr = (unsigned char *)(&this->cell_voltage[i]);
    00691     temp = *pPtr;
    00692     *(pPtr) = *(pPtr+1);
    00693     *(pPtr+1) = temp;
    00694
    00695     //compute cell voltage -> cell_voltage=VCELL x 6250/16383
    00696     voltage_comput = this->cell_voltage[i] * (unsigned long)(adc_step_mul);
    00697     this->cell_voltage[i] = voltage_comput/((unsigned long)(adc_step_div));
    00698   }
    00699
    00700   return ret_val;
    00701 }
    00702
    00703
    00704
    00711 void bq_dev_clear_alerts(bq_dev_t* this)
    00712 {
    00713   unsigned char Value;
    00714
    00715   //clear alert bit in device status register
    00716   bq_dev_read_reg(this->device_address, DEVICE_STATUS_REG, 1, DISCARD_CRC,
    00717                  (unsigned char*) &Value);
    00718   Value |= BIT5;
    00719   //set alert bit as 1
    00720   bq_dev_write_reg(this->device_address, DEVICE_STATUS_REG, Value);
    00721   Value &= ~BIT5;
    00722   //clear alert bit
    00723   bq_dev_write_reg(this->device_address, DEVICE_STATUS_REG, Value);
    00724
    00725   //Read ALERT_STATUS_REG register
    00726   bq_dev_read_reg(this->device_address, ALERT_STATUS_REG, 1, DISCARD_CRC,
    00727                  (unsigned char*) &Value);
    00728   //Write 1's to ALERT_STATUS_REG register
    00729   bq_dev_write_reg(this->device_address, ALERT_STATUS_REG, Value);
    00730
    00731   Value = 0x00;
    00732   // Write 0's ALERT_STATUS_REG register
    00733   bq_dev_write_reg(this->device_address, ALERT_STATUS_REG, Value);
    00734
    00735 }
    00736
    00737
    00744 void bq_dev_clear_faults(bq_dev_t* this)
    00745 {
    00746   unsigned char Value;
    00747
    00748     //clear fault bit in device status register
    00749   bq_dev_read_reg(this->device_address, DEVICE_STATUS_REG, 1, DISCARD_CRC,
    00750                  (unsigned char*) &Value);
    00751   Value |= BIT6;
    00752   //set fault bit as 1
    00753   bq_dev_write_reg(this->device_address, DEVICE_STATUS_REG, Value);
    00754   Value &= ~BIT6;
    00755   //clear fault bit
    00756   bq_dev_write_reg(this->device_address, DEVICE_STATUS_REG, Value);
    00757
    00758   //Read FAULT_STATUS register
    00759   bq_dev_read_reg(this->device_address, FAULT_STATUS_REG, 1, DISCARD_CRC,
    00760                  (unsigned char*) &Value);
    00761   //Write 1's to FAULT_STATUS register
    00762   bq_dev_write_reg(this->device_address, FAULT_STATUS_REG, Value);
    00763
    00764   Value = 0x00;
    00765   // Write 0's FAULT_STATUS register
    00766   bq_dev_write_reg(this->device_address, FAULT_STATUS_REG, Value);
    00767
    00768
    00769 }
    00770
    00771
    00779 short bq_dev_read_errors(bq_dev_t* this)
    00780 {
    00781   bq_dev_read_reg(this->device_address, DEVICE_STATUS_REG, 1, DISCARD_CRC,
    00782                  (unsigned char*) &this->device_status);
    00783   bq_dev_read_reg(this->device_address, ALERT_STATUS_REG, 1, DISCARD_CRC,
    00784                  (unsigned char*) &this->alert_status);
    00785   bq_dev_read_reg(this->device_address, FAULT_STATUS_REG, 1, DISCARD_CRC,
    00786                  (unsigned char*) &this->fault_status);
    00787   bq_dev_read_reg(this->device_address, COV_FAULT_REG, 1, DISCARD_CRC,
    00788                  (unsigned char*) &this->cov_fault);
    00789   bq_dev_read_reg(this->device_address, CUV_FAULT_REG, 1, DISCARD_CRC,
    00790                  (unsigned char*) &this->cuv_fault);
    00791
    00792   return 0;
    00793 }
    00794
    00795
    00802 short bq_dev_read_temps(bq_dev_t* this)
    00803 {
    00804   unsigned char data[2];
    00805
    00806   //Bytes need to be swaped as BQ device supports Big Endian
    00807   bq_dev_read_reg(this->device_address, TEMPERATURE1_L_REG, 2, DISCARD_CRC,
    00808                  (unsigned char*) &data[0]);
    00809   this->temperature1 = ((data[0] << 8) | data[1]);
    00810   bq_dev_read_reg(this->device_address, TEMPERATURE2_L_REG, 2, DISCARD_CRC,
    00811                  (unsigned char*) &data[0]);
    00812   this->temperature2 = ((data[0] << 8) | data[1]);
    00813
    00814   return 0;
    00815 }
    00816
    00817
    00824 short bq_dev_read_status(bq_dev_t* this)
    00825 {
    00826   return bq_dev_read_reg(this->device_address, DEVICE_STATUS_REG, 1,
    00827          DISCARD_CRC, (unsigned char*) &this->device_status);
    00828 }
    00829
    00830
    00837 void update_op_mode(op_modes_t new_mode)
    00838 {
    00839
    00840   if (bq_pack.op_mode == new_mode)
    00841     return;
    00842
    00843   bq_pack.op_mode = new_mode;
    00844
    00845   switch (new_mode)
    00846   {
    00847     case CHARGE_OP:
    00848 // Prepare the outgoing string
    00849       strcpy(OutputString,"\r\nThe battery pack is in CHARGE_OP Mode\r\n");
    00850 #ifdef USB_COMM
    00851 // Send the response over USB
    00852       sendData_waitTilDone((BYTE*)OutputString,strlen(OutputString),1,10);
    00853 #endif
    00854 #ifdef UART_COMM
    00855 // Send the message to the host over UART
    00856       putsUART((BYTE*)OutputString,strlen(OutputString));
    00857 #endif
    00858
    00859       break;
    00860
    00861     case END_OF_CHARGE:
    00862 // Prepare the outgoing string
    00863       strcpy(OutputString,"\r\nThe battery pack is in END_OF_CHARGE Mode\r\n");
    00864 #ifdef USB_COMM
    00865 // Send the response over USB
    00866       sendData_waitTilDone((BYTE*)OutputString,strlen(OutputString),1,10);
    00867 #endif
    00868 #ifdef UART_COMM
    00869 // Send the message to the host over UART
    00870       putsUART((BYTE*)OutputString,strlen(OutputString));
    00871 #endif
    00872
    00873       break;
    00874
    00875     case DISCHARGE_OP:
    00876 // Prepare the outgoing string
    00877   strcpy(OutputString,"\r\nThe battery pack is in DISCHARGE_OP Mode\r\n");
    00878 #ifdef USB_COMM
    00879 // Send the response over USB
    00880       sendData_waitTilDone((BYTE*)OutputString,strlen(OutputString),1,10);
    00881 #endif
    00882 #ifdef UART_COMM
    00883 // Send the message to the host over UART
    00884       putsUART((BYTE*)OutputString,strlen(OutputString));
    00885 #endif
    00886
    00887       break;
    00888
    00889     case END_OF_DISCHARGE:
    00890 // Prepare the outgoing string
    00891   strcpy(OutputString,"\r\nThe battery pack is in END_OF_DISCHARGE Mode\r\n");
    00892 #ifdef USB_COMM
    00893 // Send the response over USB
    00894       sendData_waitTilDone((BYTE*)OutputString,strlen(OutputString),1,10);
    00895 #endif
    00896 #ifdef UART_COMM
    00897 // Send the message to the host over UART
    00898       putsUART((BYTE*)OutputString,strlen(OutputString));
    00899 #endif
    00900
    00901       break;
    00902
    00903     case FAULT_MODE:
    00904 // Prepare the outgoing string
    00905       strcpy(OutputString,"\r\nThe battery pack is in FAULT_MODE Mode\r\n");
    00906 #ifdef USB_COMM
    00907 // Send the response over USB
    00908       sendData_waitTilDone((BYTE*)OutputString,strlen(OutputString),1,10);
    00909 #endif
    00910 #ifdef UART_COMM
    00911 // Send the message to the host over UART
    00912       putsUART((BYTE*)OutputString,strlen(OutputString));
    00913 #endif
    00914
    00915       //Disable Balancing Virtual Timer
    00916       bq_pack.timer_status &= ~START_CELL_BALANCE_TIMER;
    00917       break;
    00918
    00919     case SOV_MODE:
    00920 // Prepare the outgoing string
    00921       strcpy(OutputString,"\r\nThe battery pack is in SOV_MODE Mode\r\n");
    00922 #ifdef USB_COMM
    00923 // Send the response over USB
    00924       sendData_waitTilDone((BYTE*)OutputString,strlen(OutputString),1,10);
    00925 #endif
    00926 #ifdef UART_COMM
    00927 // Send the message to the host over UART
    00928       putsUART((BYTE*)OutputString,strlen(OutputString));
    00929 #endif
    00930       //Disable Cell Balancing Timer
    00931       bq_pack.timer_status &= ~START_CELL_BALANCE_TIMER;
    00932       break;
    00933
    00934     case INITIAL_MODE:
    00935
    00936       //Clear error_status
    00937       bq_pack.error_status = 0;
    00938
    00939       //Clear charge/discharge timer
    00940       bq_pack.chg_dschg_op_timer = 0;
    00941
    00942       //Start Charge/Discharge operation timer
    00943       bq_pack.timer_status |= START_CHG_DSCHG_OP_TIMER;
    00944
    00945       //Disable DRDY pin interrupt
    00946       BQ76PL536_DRDY_PxIE  &= ~IN_BQ_DRDY;
    00947
    00948       //Trigger 'PL536 ADC conversion and then..
    00949       bq_pack_start_conv();
    00950
    00951       //Wait for data to be ready
    00952       while(!(BQ76PL536_DRDY_PxIN  & IN_BQ_DRDY))
    00953         ;
    00954
    00955       //Read data from BQ pack for overall system verification
    00956       update_bq_pack_data();
    00957       //Copy current cell values
    00958       copy_cell_voltage_values();
    00959
    00960       //Enable DRDY pin interrupt
    00961       BQ76PL536_DRDY_PxIFG  &= ~IN_BQ_DRDY;
    00962       BQ76PL536_DRDY_PxIE  |= IN_BQ_DRDY;
    00963
    00964 // Prepare the outgoing string
    00965       strcpy(OutputString,"\r\nThe battery pack is in INITIAL_MODE Mode\r\n");
    00966 #ifdef USB_COMM
    00967 // Send the response over USB
    00968       sendData_waitTilDone((BYTE*)OutputString,strlen(OutputString),1,10);
    00969 #endif
    00970 #ifdef UART_COMM
    00971 // Send the message to the host over UART
    00972       putsUART((BYTE*)OutputString,strlen(OutputString));
    00973 #endif
    00974
    00975       break;
    00976
    00977
    00978     default:
    00979       break;
    00980   }
    00981
    00982   return;
    00983 }
    00984
    00985
    00992 short check_for_cov(void)
    00993 {
    00994
    00995   unsigned short i, cell;
    00996
    00997   for (i=0; i<NUMBER_OF_BQ_DEVICES; i++)
    00998   {
    00999     if (bq_pack.bq_devs[i].fault_status & (1<<FAULT_COV_POS))
    01000     {
    01001       //Check if error condition is still in effect
    01002       for (cell=0; cell < bq_pack.bq_devs[i].cell_count; cell++)
    01003       {
    01004         if (bq_pack.bq_devs[i].cov_fault & (1<<cell))
    01005         {
    01006           if (bq_pack.bq_devs[i].cell_voltage[cell]
    01007               > get_u32_value(COV_RECOVERY_THRESHOLD))
    01008           {
    01009             //COV condition still present
    01010             return 1; //error
    01011           }
    01012           else
    01013           {
    01014             //COV condition cleared
    01015             //clear FAULT flag
    01016             bq_dev_write_reg(bq_pack.bq_devs[i].device_address,
    01017                              FAULT_STATUS_REG, (1<<FAULT_COV_POS));
    01018             bq_dev_write_reg(bq_pack.bq_devs[i].device_address,
    01019                              FAULT_STATUS_REG, (0<<FAULT_COV_POS));
    01020
    01021             //Assumption COV and CUV are mutually exclusive
    01022             update_op_mode(INITIAL_MODE);
    01023           }
    01024         }
    01025       }
    01026     }
    01027   }
    01028
    01029   return 0;
    01030 }
    01031
    01032
    01039 short check_for_cuv(void)
    01040 {
    01041   unsigned short i, cell;
    01042
    01043   for (i=0; i<NUMBER_OF_BQ_DEVICES; i++)
    01044   {
    01045     if (bq_pack.bq_devs[i].fault_status & (1<<FAULT_CUV_POS))
    01046     {
    01047       //Check if error condition is still in effect
    01048       for (cell=0; cell < bq_pack.bq_devs[i].cell_count; cell++)
    01049       {
    01050         if (bq_pack.bq_devs[i].cuv_fault & (1<<cell))
    01051         {
    01052           if (bq_pack.bq_devs[i].cell_voltage[cell]
    01053               < get_u32_value(CUV_RECOVERY_THRESHOLD))
    01054           {
    01055             //CUV condition still present
    01056             return 1; //error
    01057           }
    01058           else
    01059           {
    01060             //CUV condition cleared
    01061             //clear FAULT flag
    01062             bq_dev_write_reg(bq_pack.bq_devs[i].device_address,
    01063                             FAULT_STATUS_REG, (1<<FAULT_CUV_POS));
    01064             bq_dev_write_reg(bq_pack.bq_devs[i].device_address,
    01065                              FAULT_STATUS_REG, (0<<FAULT_CUV_POS));
    01066
    01067             //Assumption COV and CUV are mutually exclusive
    01068             update_op_mode(INITIAL_MODE);
    01069           }
    01070         }
    01071       }
    01072     }
    01073   }
    01074
    01075   return 0;
    01076 }
    01077
    01078
    01085 short check_for_pot(void)
    01086 {
    01087   /*Temp sensor connected to first BQ device only*/
    01088   if (bq_pack.bq_devs[0].alert_status & (0x3<<ALERT_OT1_POS))
    01089   {
    01090       return 1; //error
    01091   }
    01092
    01093   return 0;
    01094 }
    01095
    01096
    01104 unsigned short check_for_charge_op(void)
    01105 {
    01106   unsigned short i, j, cell_cnt;
    01107
    01108   j=0;
    01109   for (i=0; i<NUMBER_OF_BQ_DEVICES; i++)
    01110   {
    01111     /*Read each cell voltage and compare it vs initial cell voltage*/
    01112     for (cell_cnt=0; cell_cnt<bq_pack.bq_devs[i].cell_count; cell_cnt++)
    01113     {
    01114       if (bq_pack.bq_devs[i].cell_voltage[cell_cnt] > cell_values[j])
    01115       {
    01116         if ((bq_pack.bq_devs[i].cell_voltage[cell_cnt] - cell_values[j])
    01117              > get_u32_value(DELTA_CHARGE_V))
    01118         {
    01119           return 1;
    01120         }
    01121       }
    01122       j++;
    01123     }
    01124   }
    01125
    01126   return 0;
    01127 }
    01128
    01129
    01137 unsigned short check_for_discharge_op(void)
    01138 {
    01139   unsigned short i, j, cell_cnt;
    01140
    01141   j=0;
    01142   for (i=0; i<NUMBER_OF_BQ_DEVICES; i++)
    01143   {
    01144     /*Read each cell voltage and compare it vs initial cell voltage*/
    01145     for (cell_cnt=0; cell_cnt<bq_pack.bq_devs[i].cell_count; cell_cnt++)
    01146     {
    01147       if (cell_values[j] > bq_pack.bq_devs[i].cell_voltage[cell_cnt])
    01148       {
    01149         if ((cell_values[j] - bq_pack.bq_devs[i].cell_voltage[cell_cnt])
    01150               > get_u32_value(DELTA_DISCHARGE_V))
    01151         {
    01152           return 1;
    01153         }
    01154       }
    01155       j++;
    01156     }
    01157   }
    01158
    01159   return 0;
    01160 }
    01161
    01162
    01169 void copy_cell_voltage_values(void)
    01170 {
    01171   unsigned short i, j, cell_cnt;
    01172
    01173   j = 0;
    01174   for (i=0; i<NUMBER_OF_BQ_DEVICES; i++)
    01175   {
    01176     /*Read each cell voltage and compare it vs initial cell voltage*/
    01177     for (cell_cnt=0; cell_cnt<bq_pack.bq_devs[i].cell_count; cell_cnt++)
    01178     {
    01179       cell_values[j++] = bq_pack.bq_devs[i].cell_voltage[cell_cnt];
    01180     }
    01181   }
    01182
    01183   return;
    01184 }
    01185
    01186
    01193 unsigned short cell_imbalance_threshold_reached(void)
    01194 {
    01195   if ((bq_pack.highest_cell_volts - bq_pack.lowest_cell_volts)
    01196        > get_u32_value(CELL_IMBALANCE_FAIL_THRESHOLD))
    01197     return 1;
    01198   else
    01199     return 0;
    01200 }
    01201
    01209 unsigned short find_imbalanced_cell(unsigned short in_dev_id)
    01210 {
    01211   unsigned short cell_id, imb_cells_mask, cnt;
    01212
    01213   cnt = 0;
    01214   imb_cells_mask = 0xFFFF;
    01215
    01216   /*Read each cell voltage and compare it vs lowest cell voltage*/
    01217   for (cell_id=0; cell_id<bq_pack.bq_devs[in_dev_id].cell_count; cell_id++)
    01218   {
    01219     imb_cells_mask &= ~(1<<cnt);
    01220
    01221     if ((bq_pack.highest_cell_volts
    01222           - bq_pack.bq_devs[in_dev_id].cell_voltage[cell_id]) >=
    01223           get_u32_value(BALANCE_VOLTS_THRESHOLD))
    01224     {
    01225       imb_cells_mask |= (1<<cnt);
    01226     }
    01227     cnt++;
    01228   }
    01229
    01230   return imb_cells_mask;
    01231 }
    01232
    01239 void enable_bypass_resistor(unsigned short in_dev_id, unsigned short in_value)
    01240 {
    01241   bq_dev_write_reg(bq_pack.bq_devs[in_dev_id].device_address,
    01242                    CB_TIME_REG, get_u32_value(BALANCE_TIME));
    01243   bq_dev_write_reg(bq_pack.bq_devs[in_dev_id].device_address,
    01244                    CB_CTRL_REG, (0x003F & in_value));
    01245
    01246   return;
    01247 }
    01248
    01249
    01256 void disable_bypass_resistor(unsigned short in_dev_id, unsigned short in_value)
    01257 {
    01258   unsigned char reg_val;
    01259   //Read CB_CTRL_REG register
    01260   bq_dev_read_reg(bq_pack.bq_devs[in_dev_id].device_address, CB_CTRL_REG, 1,
    01261                   DISCARD_CRC, (unsigned char*) &reg_val);
    01262
    01263   //Write 0's to the bits in the CB_CTRL_REG register
    01264   reg_val &= ~(in_value);
    01265   bq_dev_write_reg(bq_pack.bq_devs[in_dev_id].device_address,
    01266                    CB_CTRL_REG, reg_val);
    01267
    01268   return;
    01269 }
    01270
    01271
    01279 void disable_all_bypass_resistors(void)
    01280 {
    01281   unsigned short bq_dev_id;
    01282
    01283   for (bq_dev_id=0; bq_dev_id<NUMBER_OF_BQ_DEVICES; bq_dev_id++)
    01284   {
    01285     bq_dev_write_reg(bq_pack.bq_devs[bq_dev_id].device_address, CB_CTRL_REG, 0);
    01286   }
    01287
    01288   return;
    01289 }
    01290
    01291
    01292 /*EOF*/
    01293