• 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 

Generated on Fri Dec 17 2010 12:09:22 for Multi-cell Lithium-Ion Battery Manager System using MSP430 and BQ76PL536 by  doxygen 1.7.1