smbus.c

Go to the documentation of this file.
00001 /* This file has been prepared for Doxygen automatic documentation generation.*/
00027 // Revision List:
00028 //   June 13, 2005: fixed error in handling receive BLOCK (added use of byte count).
00029 //   June 6, 2005: added clearing of SMLOCK after data successfully sent.
00030 //   June 5, 2005: changed TWBR init value to be 12 instead of 11 to make 100KHz.
00031 //   May 10, 2005: added init of TWBR during Master Transmit mode.
00032 
00033 
00034 
00035 //#include <pgmspace.h>
00036 #include <inavr.h>
00037 
00038 
00039 #define MODULE_SMBUS            /* ensure that we instantiate our variables in smbus.h */
00040 #include "smbus.h"              //instantiates variables & flash strings
00041 
00042 #include "timer.h"              //required for BusFault timer activation
00043 #include "pack.h"               //required for a few calculations
00044 #include "analog.h"             //required for SMBus analog calculations
00045 #include "calibration.h"                //required for SMBus analog calculations
00046 //#include "iom406_320.h"
00047 #include <iom406.h>     // IAR headerfile for Mega406 (EW 410)
00048 #include "interpret.h"          // ONLY include this file in THIS module!
00049 #include "main.h"
00050 #include "pwrmgmt.h"
00051 
00052 
00053 //extern __flash unsigned char SM_Cmd_Table[0x40][2]; //in interpret.c
00054 typedef unsigned char (*ptr2funcUC_V)(void);
00055 extern ptr2funcUC_V SMB_ReadCmd[];
00056 extern ptr2funcUC_V SMB_WriteCmd[];
00057 
00058 //Internally-needed prototypes
00059 unsigned char FastCRC(unsigned char LastCRC, unsigned char newbyte);
00060 //extern unsigned char SMLOCK;
00061 
00062 
00063 //This is used to check for an out-of-bounds SMBus command.
00064 #define HIGHEST_SMB_CMD 0x3F
00065 
00066 
00067 //Two-Wire-Interface TWSR (STATUS) values
00068 //Note that since our Prescale value is 0, we don't need to MASK the Status byte.
00069 
00070 //  Globally applicable TWI status codes:
00071 #define TWS_MASK  0xF8          /* Two-Wire Status Mask */
00072 #define TWS_NSTAT 0xF8          /* No Status Available now */
00073 
00074 //  MASTER-related Status codes:
00075 #define TWS_START 0x08
00076 #define TWS_RESTART 0x10
00077 #define TWS_WRITE_ACK 0x18      /* sent a SLA+W, got ACK */
00078 #define TWS_WRITE_NAK 0x20      /* sent SLA+W, got NAK */
00079 #define TWS_TXDATA_ACK 0x28     /* Data tx'd & was ACK'd */
00080 #define TWS_TXDATA_NAK 0x30     /* Data tx'd & was NAK'd */
00081 #define TWS_LOST_ARB 0x38       /* lost bus arbitration */
00082 
00083 #define TWS_READ_ACK 0x40       /* got ACK from a SLA+R request */
00084 #define TWS_READ_NAK 0x48       /* got NAK from a SLA+R request */
00085 #define TWS_RXDATA_ACK 0x50     /* We rcvd data and ACKd back */
00086 #define TWS_RXDATA_NACK 0x58    /* We rcvd data and we NACKd back */
00087 
00088 
00089 //  SLAVE-related Status codes:
00090 #define TWS_SLA_W 0x60          /* Got SLA + Write */
00091 #define TWS_SLA_R 0xA8          /* Got SLA + Read  */
00092 #define TWS_RDATA 0x80          /* Got a data byte */
00093 #define TWS_RCMD  0x80          /* Got a command byte */
00094 #define TWS_RSTOP 0xA0          /* Got a Stop */
00095 #define TWS_REPEAT 0xA0         /* Got a Repeated-Start */
00096 #define TWS_RACK  0xB8          /* Send a data byte and got an ACK back */
00097 #define TWS_RNAK  0xC0          /* Sent a data byte and got a NAK back */
00098 #define TWS_FINAL 0xC8          /* Sent the final byte, got ACK back */
00099 #define TWS_BERR  0x00          /* Saw a Bus Error */
00100 
00101 
00102 // Two-Wire CONTROL values
00103 
00104 #define TWC_GO 0x85         /* clr TWINT; assert ENA & IntEna */
00105 #define TWC_READ_NoACK 0x85 /* read a byte, but don't ACK when done */
00106 #define TWC_START 0xA5      /* send START bit, assert ENA & IntEna */
00107 #define TWC_STOP 0x94       /* leave INT *DISabled* when done */
00108 #define TWC_RESTART 0xB5    /* send STOP, then START again; INT ena */
00109 
00110 
00111 /* ************************************************************************* */
00112 
00113 unsigned char TEST50US = 0;
00114 unsigned char SMLOCK = 0;       //prevents Master bus grab attempts WHILE BUS IS IN MASTER MODE.
00115 
00116 unsigned char TW_MTxBuf[8];     //Master-mode TX buffer
00117 unsigned char TW_MTxBufCnt = 0; //how many valid bytes are in the buffer
00118 unsigned char TW_MTxBufIndex = 0;
00119 
00120 // Note for the buffers below, these must be able to contain:
00121 // Slave Address, SMBus Command, Byte Count (if Block-mode), up to 32 bytes, plus PEC.
00122 unsigned char TW_TxBuf[36];     //must be long enough for any outbound strings
00123 unsigned char TW_TxBufCnt = 0;  //how many valid bytes are in the buffer
00124 unsigned char TW_TxBufIndex = 0;
00125 
00126 unsigned char TW_RxBuf[10];     //In Application mode (non-ISP mode), only receive WORD commands.
00127 signed char TW_RxBufCnt = 0;
00128 unsigned char TW_RxBufIndex = 0;
00129 
00130 
00131 //This byte contains flags from the TWI ISR to tell the Foreground code what to do.
00132 //If this byte is ever non-zero, the foreground code will act on its contents.
00133 //Although it is written by both the ISR and the Foreground code, it does not
00134 //  need to be declared VOLATILE because the SMBus is halted until the foreground
00135 //  code finishes processing the associated command and has cleared this flag byte.
00136 unsigned char TWI_CmdFlags;
00137   #define SMB_GenBusTimeout 1   /* Tell Foreground to generate a bus timeout, as we saw an error! */
00138   #define SMB_SetUpReply 2      /* Have Foreground set up TW_TxBuf[]. */
00139   #define SMB_GotCmdData 4      /* Have Foreground interpret the complete received command. */
00140 
00141 unsigned char CurrentCmd = 0xFF;
00142 unsigned char UsePEC = 0;       //PEC usage is disabled by default.
00143 
00144 
00145 
00146 
00147 /* *************************************************************************
00148  *
00149  *   SMBus Initialization routine
00150  *
00151  ************************************************************************* */
00152 
00153 void InitSMBus(void)
00154 {
00155   SMB_RestoreBus();
00156   TWBCSR = (1<<TWBCIF) | (1<<TWBCIE) | (1<<TWBDT1) | (1<<TWBDT0) | (0<<TWBCIP);
00157 }
00158 
00159 
00160 
00161 
00162 /* *************************************************************************
00163  *
00164  *   SMBus Wakeup Interrupt
00165  *
00166  ************************************************************************* */
00167 
00168 
00169 //This wakes up a battery from sleep mode into the "On" state, per sbdat110, 4.4.2
00170 
00171 #pragma vector = TWI_BUS_CD_vect
00172 __interrupt void TWICD_ISR(void)
00173 {
00174   //clear bits per sbdat110, 4.4.2
00175   SMBvariables[SMBV_BattMode][hibyte] &= ~(0xE3);       
00176 
00177   if(TWBCSR & (1<<TWBCIP))      //this int was caused by bus DISCONNECT event.
00178   {
00179     TWBCSR &= ~(1<<TWBCIP);
00180     ChangePowerMode(POWERMODE_IDLE,0);
00181   }
00182   else  //this int occurred due to a bus CONNECT event.
00183   {
00184     TWBCSR |= (1<<TWBCIP);
00185     ChangePowerMode(POWERMODE_ACTIVE,0);
00186   }
00187 }
00188 
00189 
00190 
00191 
00192 /* *************************************************************************
00193  *
00194  *   SMBus PA6 Pin Change Interrupt (needed for Master Mode)
00195  *
00196  ************************************************************************* */
00197 
00198 
00199 #pragma vector = PCINT0_vect
00200 __interrupt void PCINT0_ISR(void)
00201 {
00202     TEST50US = 0;     //flag to SMBUS.C that bus activity happened
00203 }
00204 
00205 
00206 
00207 
00208 #pragma vector = PCINT1_vect
00209 __interrupt void PCINT1_ISR(void)
00210 {
00211     ;   //unused
00212 }
00213 
00214 
00215 
00216 
00217 
00218 /* *************************************************************************
00219  *
00220  *   Low-Level SMBus Communications State Machine
00221  *
00222  ************************************************************************* */
00223 
00224 /*
00225 
00226 Slave Mode
00227 -------------
00228 
00229 
00230 
00231 Master Mode
00232 -------------
00233 
00234 Master mode is initiated by foreground code.  When a message is available for
00235 transmission via Master mode (typically due to a timer expiring), it
00236 is placed in the TWI Master TX buffer.  However, transmission cannot begin
00237 immediately due to the SMBus requirement that "A bus master is required to
00238 check for bus idle time of 50 us."
00239 
00240 To meet this requirement, the AVR's pin-change detection mechanism is used
00241 to monitor for bus idle conditions.  PA5 must be wired externally to the
00242 SMBCLK signal (pin 5 on CONN1) to allow this functionality.  (Alternately,
00243 in the user's production system, any I/O signal with pin-change capability
00244 can be used instead of PA5 if desired.)  PA5 is also used to check for the
00245 SMCLK pin being held low for extended periods by other devices on the bus
00246 as well as checking if the AVR itself doing so locally.
00247 
00248 A 3-level system is employed to ensure bus availability.  First, the presence
00249 of a message in the transmit buffer results in execution of the foreground code
00250 that manages Master mode.  Next, if the Slave state machine is not in the
00251 IDLE state, no attempt is made to take control of the bus.  Lastly, PA5 is
00252 checked to be sure it is not currently at a logical zero condition.  At this
00253 point the bus appears to be free, so a flag (called TEST50US) is asserted to
00254 indicate that the 50uS test has now begun; the Pin-Change Interrupt for PA5 is
00255 also enabled.  The foreground SMBus Master mode management code is then exited.
00256 With a clock speed of only 1MHz, 50 uS corresponds to only 50 instructions at
00257 most.  Therefore, when the code is re-entered it is guaranteed that at least
00258 50uS has passed.
00259 
00260 When the pin-change interrupt is active, bus activity will
00261 trigger the pin-change interrupt.  The corresponding ISR will clear the TEST50US
00262 flag, indicating that the bus is not free.  Thus, when the foreground code is
00263 re-entered, if the flag is not asserted but there is a message in the buffer,
00264 it is understood that the test has failed and must be started again; thus the
00265 flag will again be asserted and the routine will be exited.
00266 
00267 When the foreground code is eventually re-entered with the flag still asserted,
00268 and if the PA5 pin is not low, and the TWI ISR Slave State Machine is in IDLE,
00269 action is immediately taken to begin transmission while the bus is free.  An
00270 additional interlock flag (SMLOCK) is asserted to indicate that Master mode has
00271 been entered by the TWI Hardware, so that the foreground code will not attempt to
00272 repeatedly initiate a transmission for the same message.  (Note that checking
00273 for the IDLE state is required due to the possibility that the ISR could have
00274 been activated just after the flag was last asserted.  Additionally it is possible
00275 that another slave device is halting the bus by keeping SMCLK low for an extended
00276 period, so this needs to also be checked before attempting to take over the bus.)
00277 
00278 If the AVR is successful in taking ownership of the bus, at the completion of the
00279 transmission of the desired Slave address the ISR will be activated with a Status
00280 code of 0x??.  As a result, the state machine will now vector into the states
00281 related to Master Mode transmission, and the ISR will handle all further aspects
00282 of the transmission.  Alternately, if the TWI module is unsuccessful in taking over
00283 the bus, the TWI ISR will still be entered but with Status codes that are indicative
00284 of an error having occurred.  In this latter case, the SMLOCK and TEST50US flags will
00285 be cleared to force another bus takeover attempt in the future.
00286 
00287 */
00288 
00289 
00290 
00291 unsigned char TXmsg[4][4];    //leave room for PEC
00292 volatile unsigned char TXmsgHead = 0;
00293 volatile unsigned char TXmsgTail = 0;
00294 volatile unsigned char TXmsgQty = 0;
00295 
00296 #define TXmsgEmpty (TXmsgQty == 0)
00297 #define TXmsgFull (TXmsgQty == 4)
00298 #define TXmsgDelete {++TXmsgTail; TXmsgTail &= (4-1);  TXmsgQty--;}
00299 
00300 //We will compute the PEC for the message as well.
00301 void MasterInsertMsg(unsigned char addr, unsigned char cmd, unsigned int data)
00302 { //Note that the Charger address is ALWAYS 0x12! (sbsm100.pdf, 5.2)
00303   //The Host address is always 0x16.
00304   //The addr always assumes WRITE.
00305   //We only do a WORD WRITE.
00306 
00307   unsigned char * ptr = TXmsg[TXmsgHead];
00308 
00309   *ptr++ = addr;
00310   *ptr++ = cmd;
00311   *ptr++ = (unsigned char) data;
00312   *ptr = (unsigned char)(data>>8);
00313 
00314   if(TXmsgFull)
00315     return;
00316 
00317 
00318   ++TXmsgHead;
00319   TXmsgHead &= (4-1);
00320   TXmsgQty++;
00321 }
00322 
00323 
00324 
00325 
00326 
00327 //TWI Interrupt Service Routine
00328 //  This ISR contains a state machine for handling the low-level bus communications.
00329 //  It uses the variable TWI_CmdFlags to communicate the need for message processing
00330 //    to the foreground-based command interpreter.  Whenever it passes control off
00331 //    to the foreground routine, the SMBus is halted.
00332 
00333 /* Changes to the operation of the SMBus State Machine as of 6/17/2005 (rgf):
00334 
00335    Since there can be multiple Masters on the bus addressing a Smart Battery,
00336    namely either a Host or a Charger, it is entirely possible that one Master
00337    may support PEC while the other does not.  For maximum reliability, we must
00338    be able to support the reception of PEC on-the-fly regardless of whether it
00339    was used in the past or not.
00340 
00341    To do so, we determine an expected byte count WITHOUT PEC.  While receiving,
00342    we decrement this counter and store received bytes until either (a) the counter
00343    drops below a value of (-1), or (b) we receive a STOP.  If we receive a STOP
00344    and the counter is not either 0 or -1, this is an error and is flagged as such.
00345    (Note that AFTER receiving a STOP, it is not possible to flag an error to the
00346    Host or Charger except through the Battery Status flags.)  If the counter is
00347    zero, this indicates that PEC is disabled.  If the counter is -1, this indicates
00348    that PEC is enabled.  The message will be processed with this knowledge.
00349 
00350    However, since the SCL line is not being held low due to TWINT being left asserted,
00351    a different mechanism is needed to hold off incoming messages to the battery
00352    until the previous message has been processed.  This is done by turning off
00353    the generation of ACK on any subsequent bytes and/or messages until the foreground
00354    code has finished processing the prior message.
00355 
00356    It is crucial therefore that the foreground code does not change the
00357    value of the TWI_CmdFlags variable from being equal to 'SMB_GotCmdData'
00358    until after it is completely done with processing of the prior message.
00359 
00360    This mechanism also is valid if a Master attempts to perform a Master Read
00361    while the battery is busy.  In this case, the second byte from the Master,
00362    specifically the SMBus Command byte, will not be acknowledged.  The Master
00363    is thereby required to generate a STOP condition.
00364 
00365 */
00366 
00367 //State Machine states
00368 enum /*TWISR_State*/ {TW_IDLE=0, TW_Wait4Stop, TW_Wait4Cmd, TW_Wait4RW, TW_Wait4Data, TW_ReplyData, TW_MSLA_W, TW_MCMD_W, TW_MDATA_W };
00369 
00370 unsigned char TWISR_state = TW_IDLE;    //state variable
00371 
00372 
00373 #pragma vector = TWI_vect
00374 __interrupt void TWI_ISR(void)
00375 {
00376   static unsigned char TWISR_CmdFeatures = 0;   //Command-related feature flags
00377   unsigned char Status;
00378   unsigned char tmp;
00379 
00380   Status = TWSR & 0xF8;         //This identifies what caused the interrupt to fire.
00381 
00382   switch(TWISR_state)
00383   {
00384     default:
00385     case TW_IDLE:       //If not SLA_W or RSTOP, is an error!
00386       if(TWS_SLA_W == Status)   // saw Slave address match with a Write bit
00387       {
00388         if(TWI_CmdFlags == SMB_GotCmdData)
00389         {
00390           //Assert that we're 'busy' to SMBus Master by leaving TWEA *off* until we get a STOP.
00391           //Note that this is 'legal' because we have ALREADY sent an ACK to our Slave Address,
00392           // as is required by the SMBus specification.
00393           TWISR_state = TW_Wait4Stop;
00394           TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE);    //must NOT re-enable ACKing!
00395           return;
00396         }
00397         else
00398           TWISR_state = TW_Wait4Cmd;
00399       }
00400       else
00401       if(TWS_RSTOP == Status)   //Saw a Stop, possibly left over from previous cmd.
00402       {
00403          ;                      //Everything is probably OK.  Take no action.
00404       }
00405       else
00406       if(TWS_START == Status)   //we have successfully sent a START bit. Handle MASTER mode.
00407       {
00408         TWDR = TW_MTxBuf[TW_MTxBufIndex++];
00409         TWISR_state = TW_MSLA_W;
00410       }
00411       else //had some type of error!
00412       {
00413         SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
00414         TWI_CmdFlags = SMB_GenBusTimeout;       //generate a bus timeout.
00415         TWCR = (1<<TWEA) | (1<<TWEN);           //disable int, and DON'T clear the TWINT flag!
00416         TWISR_state = TW_IDLE;                  //Reset the state machine.
00417         return;
00418       }
00419       TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);    //must re-enable ACKing
00420       break;
00421 
00422     case TW_Wait4Stop:
00423       if(TWS_RSTOP == Status)   //Saw a Stop, possibly left over from previous cmd.
00424       {
00425         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);  //must re-enable ACKing
00426         TWISR_state = TW_IDLE;                  //Reset the state machine.
00427       }
00428       else
00429         TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE);      //must NOT re-enable ACKing yet!
00430       break;
00431 
00432 
00433     //SLAVE-mode states follow.
00434 
00435     case TW_Wait4Cmd:   //upon entry, we expect to have received a Cmd byte.
00436       if(TWS_RCMD == Status)            //It appears that we have received a Command byte now.
00437       {
00438         tmp = TWDR;
00439         if(tmp <= HIGHEST_SMB_CMD)      //Is the Cmd within valid range?
00440         {
00441           CurrentCmd = tmp;             //Save a copy.
00442           tmp = SM_Cmd_Table[tmp][0];   //Grab the Command Characteristics/Features flags.
00443           if(tmp & SMBslave)            //Is the Command valid for Slaves?
00444           {                             //The command appears to be valid.
00445             TWISR_CmdFeatures = tmp;    //Save the Feature flags for use in Wait4RW state.
00446             TWISR_state = TW_Wait4RW;   //set up next state
00447             TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);      //enable ACKing
00448             return;
00449           }
00450         }
00451       }
00452       //In all cases except those that 'return' (above), it's an error.
00453       SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
00454       TWI_CmdFlags = SMB_GenBusTimeout; //generate a bus timeout.
00455       TWCR = (1<<TWEA) | (1<<TWEN);     //disable int, and DON'T clear the TWINT flag!
00456       TWISR_state = TW_IDLE;            //Reset the state machine.
00457       return;
00458 //    break;
00459 
00460 
00461     case TW_Wait4RW:    //We will now find out if we will RX more, or we need to TX a reply instead.
00462       if(TWS_RDATA == Status)           //It is a WRITE-type command. Prep the RX buffer to accept more data.
00463       { //NOTE: except for OptionalMfgFunction5, all WRITE cmds are 2-byte, plus optional PEC.
00464         //Place all bytes of the transaction into the buffer so we can do a PEC on it if needed.
00465         TW_RxBuf[0] = TWAR & 0xFE;      //store everything incl. the slave address for computing PEC.
00466         TW_RxBuf[1] = CurrentCmd;       //store the previously-send Command.
00467         TW_RxBuf[2] = TWDR;             //store this first DATA byte
00468         TW_RxBufIndex = 3;              //use RxBufIndex as the index to store data in the buffer.
00469         if(TWISR_CmdFeatures & SCWW)    //is it a Write-WORD command type?
00470         {
00471             TW_RxBufCnt = 1;            //We expect 1 more data byte, and possibly PEC after that.
00472         }
00473         else
00474         if(TWISR_CmdFeatures & SCWG)    //is it a write-BLOCK command (must be OptionalMfgFunction5 then)
00475         {
00476           tmp = TWDR;
00477           if((tmp >= 1) && (tmp <= 32))
00478             TW_RxBufCnt = TWDR;
00479           else
00480           {
00481             SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_BadSize;
00482             TWI_CmdFlags = SMB_GenBusTimeout;   //generate a bus timeout.
00483             TWCR = (1<<TWEA) | (1<<TWEN);       //disable int, and DON'T clear the TWINT flag!
00484             TWISR_state = TW_IDLE;              //Reset the state machine.
00485             return;
00486           }
00487         }
00488         else    //this Command doesn't allow EITHER word OR group/block Writes! It's Read-only!
00489         {
00490           SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_AccessDenied;
00491           TWI_CmdFlags = SMB_GenBusTimeout;     //Not a WRITE-type cmd, so generate a bus timeout.
00492           TWCR = (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
00493           TWISR_state = TW_IDLE;                //Reset the state machine.
00494           return;
00495         }
00496         TWISR_state = TW_Wait4Data;
00497         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);  //enable ACKing
00498       }
00499       else
00500       if(TWS_REPEAT == Status)  //We saw a re-Start, so must be getting ready for a Read cmd.
00501       { //Must now interpret previously-sent CurrentCmd & set up Reply data.
00502         if(TWISR_CmdFeatures & (SCRW | SCRG))   //Is it a 'ReadWord' or 'ReadGroup' command type?
00503         {
00504           TWI_CmdFlags = SMB_SetUpReply;        //Foreground decoder will set up TWCR.
00505           TWISR_state = TW_ReplyData;           //Move to next state.
00506         }
00507         else
00508         {
00509           SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
00510           TWI_CmdFlags = SMB_GenBusTimeout;     //Not a READ-type cmd, so generate a bus timeout.
00511           TWCR = (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
00512           TWISR_state = TW_IDLE;                //Reset the state machine.
00513           return;
00514         }
00515         TWCR = (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
00516         return;                                 
00517       }
00518       else  //some type of error!
00519       {
00520         SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
00521         TWI_CmdFlags = SMB_GenBusTimeout;       //Generate a bus timeout.
00522         TWCR = (1<<TWEA) | (1<<TWEN);           //disable int, and DON'T clear the TWINT flag!
00523         TWISR_state = TW_IDLE;                  //Reset the state machine.
00524         return;
00525       }
00526       break;
00527 
00528 
00529     case TW_Wait4Data:  //We are in Slave Receive operating mode.
00530       if(TWS_RDATA == Status)                   //received a data byte
00531       {
00532         tmp = TWDR;
00533         if(--TW_RxBufCnt < -1)                  //Are we past the PEC byte and still getting more data?
00534         {
00535           SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_BadSize;      //throw away the data & flag error
00536           TWI_CmdFlags = SMB_GenBusTimeout;     //Generate a bus timeout.
00537           TWCR = (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
00538           TWISR_state = TW_IDLE;                        //Reset the state machine.
00539           return;
00540         }
00541         TW_RxBuf[TW_RxBufIndex++] = TWDR;       //store the byte
00542       }
00543 
00544       else
00545       if(TWS_RSTOP == Status)                   //got a STOP; all done RXing data now.
00546       { //Note: if we get a STOP prematurely, then we simply ignore the command,
00547         //  since it is too late to inform the Master of the error.
00548         if((TW_RxBufCnt > 0) || (TW_RxBufCnt < -1))     //We got a premature STOP or too much data; ERROR!
00549         {
00550           SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_BadSize;      //throw away the data.
00551         }
00552         else
00553         {
00554           if(0 == TW_RxBufCnt)
00555             UsePEC = 0;                         //there is no PEC coming for this packet.
00556           else
00557           if(-1 == TW_RxBufCnt)
00558             UsePEC = 1;                         //PEC was included.
00559 
00560           TW_RxBufCnt = TW_RxBufIndex;          //re-use the Write Index's value as the Valid Byte Count.
00561           TW_RxBufIndex = 0;                    //clear the index in preparation for interpreting it.
00562           TWI_CmdFlags = SMB_GotCmdData;        //tell Foreground to process this now.
00563           //Note that when (TWI_CmdFlags == SMB_GotCmdData), TWI ISR will respond with BUSY condition.
00564         }
00565         TWISR_state = TW_IDLE;          //Reset the state machine in all cases.
00566       }
00567 
00568       else  //some type of error during transmission!
00569       {
00570         SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
00571         TWI_CmdFlags = SMB_GenBusTimeout;       //Not a WRITE-type cmd, so generate a bus timeout.
00572         TWCR = (1<<TWEA) | (1<<TWEN);           //disable int, and DON'T clear the TWINT flag!
00573         TWISR_state = TW_IDLE;                  //Reset the state machine.
00574         return;
00575       }
00576 
00577       TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);    //enable ACKing
00578       break;
00579 
00580 
00581     case TW_ReplyData:  //We are now in Slave Transmit operating mode.
00582       //The foreground code has set up the response that we are now sending.
00583       //Note: TW_TxBufCnt *always* includes the PEC byte! Since we don't
00584       // know whether the Master actually WANTS the PEC byte or not, we will
00585       // always TRY to send it, regardless of the state of the UsePEC flag.
00586       // If the Master does NOT want it, we will get a NAK while the PEC
00587       // byte is still in the buffer.  In the rare case where we send it all,
00588       // including the PEC byte, but we still get an ACK back, the TWI module
00589       // will be off-line anyway due to not setting the TWEA bit after sending PEC,
00590       // and we will therefore be unable to flag that an error has occurred.
00591       if((TWS_SLA_R == Status) || (TWS_RACK == Status)) //send out Reply data
00592       {
00593         TWDR = TW_TxBuf[TW_TxBufIndex++];       //send data out
00594         if(--TW_TxBufCnt == 0)                  //Have we emptied the buffer, incl. PEC?
00595           TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE);            // Yes, so don't set TWEA.
00596         else
00597           TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);        // No, so assert TWEA.
00598       }
00599       else
00600       if(TWS_RNAK == Status)    //We may have gotten this validly or as an Error.
00601       {
00602         if(TW_TxBufCnt == 1)    //Not an error. Master didn't want PEC; clear UsePEC flag!
00603         {
00604           TW_TxBufCnt = 0;      //clear the buffer too.
00605           UsePEC = 0;
00606         }
00607         else
00608         if(TW_TxBufCnt == 0)    //Not an error. Master wanted PEC (and got it); assert UsePEC.
00609           UsePEC = 1;
00610         else                    //some kind of error occurred; we got NAK too early!
00611         { //Note: the TWI module is now OFF-LINE, so we can't inform Host of this error!!
00612           SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError; //flag it later
00613         }
00614         TWISR_state = TW_IDLE;                  //In all cases, go back to IDLE.
00615         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
00616       }
00617       else
00618 //    if(TWS_FINAL == Status)   //ERROR: we got an ACK but we have no more data!
00619       { //Since the TWI module is now in "Not Addressed Slave" mode, we can't flag the error
00620         // back to the Master DURING this transaction; we WILL assert an error status though.
00621         SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_BadSize;
00622         TWISR_state = TW_IDLE;  //Reset the state machine.
00623         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
00624       }
00625       break;
00626 
00627 
00628 
00629     //MASTER-mode states follow.
00630 
00631     case TW_MSLA_W:     //we just tried to send the SLAVE ADDRESS in Master Mode.
00632       if(TWS_WRITE_ACK == Status)       // we got an ACK back from the desired SLA+W transmission
00633       {
00634         TWDR = TW_MTxBuf[TW_MTxBufIndex++];     //send out Cmd
00635         TWISR_state = TW_MCMD_W;
00636         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
00637       }
00638       else  //anything else is Unexpected or an Error result.
00639       { //We simply delete msgs that couldn't be sent as they will be resent in 10secs anyway.
00640         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWSTO) | (1<<TWEN) | (1<<TWIE);
00641         TWISR_state = TW_IDLE;  //Reset the state machine.
00642         TW_MTxBufCnt = 0;
00643         TW_MTxBufIndex = 0;
00644         TXmsgDelete;                  //Delete this just-sent msg from the TX buffer.
00645         SMLOCK = 0;
00646       }
00647       break;
00648 
00649     case TW_MCMD_W:     //we just sent a Master COMMAND byte or a Data byte
00650       if(TWS_TXDATA_ACK == Status)      // we got an ACK from data we sent.
00651       {
00652         if(TW_MTxBufCnt > TW_MTxBufIndex)
00653         {
00654           TWDR = TW_MTxBuf[TW_MTxBufIndex++];   //send out Data byte
00655           TWISR_state = TW_MCMD_W;
00656           TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
00657         }
00658         else  //we've sent everything in the buffer, so send STOP now.
00659         {
00660           TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWSTO) | (1<<TWEN) | (1<<TWIE);
00661           TWISR_state = TW_IDLE;
00662           TW_MTxBufCnt = 0;
00663           TW_MTxBufIndex = 0;
00664           TXmsgDelete;                  //Delete this just-sent msg from the TX buffer.
00665           SMLOCK = 0;
00666         }
00667       }
00668       else  //Unexpected or Error response.
00669       {
00670           TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWSTO) | (1<<TWEN) | (1<<TWIE);
00671           TWISR_state = TW_IDLE;
00672           TW_MTxBufCnt = 0;
00673           TW_MTxBufIndex = 0;
00674           TXmsgDelete;                  //Delete this just-sent msg from the TX buffer.
00675           SMLOCK = 0;
00676       }
00677       break;
00678 
00679   } // end of switch(TWISR_state)
00680 }
00681 
00682 
00683 
00684 /* *************************************************************************
00685  *
00686  *   Foreground SMBus Command Interpreter
00687  *
00688  ************************************************************************* */
00689 
00690 
00691 
00692 
00693 //This attempts to initiate Master Mode if a message is in the buffer.
00694 void SMB_Master(void)
00695 {
00696   unsigned char * ptr;
00697   unsigned char PEC;
00698 
00699   if(!(TW_MTxBufCnt))   //is there an active message
00700   {
00701     if(TXmsgEmpty)
00702       return;
00703 
00704     ptr = TXmsg[TXmsgTail];
00705     if(UsePEC)
00706     {
00707       PEC = FastCRC( 0,  TW_MTxBuf[0] = *ptr++);
00708       PEC = FastCRC(PEC, TW_MTxBuf[1] = *ptr++);
00709       PEC = FastCRC(PEC, TW_MTxBuf[2] = *ptr++);
00710       PEC = FastCRC(PEC, TW_MTxBuf[3] = *ptr);
00711       TW_MTxBuf[4] = PEC;
00712       TW_MTxBufCnt = 5;
00713     }
00714     else
00715     {
00716       TW_MTxBuf[0] = *ptr++;
00717       TW_MTxBuf[1] = *ptr++;
00718       TW_MTxBuf[2] = *ptr++;
00719       TW_MTxBuf[3] = *ptr;
00720       TW_MTxBufCnt = 4;
00721     }
00722 
00723     TW_MTxBufIndex = 0;
00724     SMLOCK = 0;
00725     TEST50US = 0;
00726   }
00727 
00728   if(SMLOCK)  //if asserted, we already started a TX action.
00729     return;
00730 
00731   if(TEST50US)  //if asserted when get here, we've waited at least 50uS & saw no bus activity.
00732   {
00733     __disable_interrupt();
00734     if((PINA & (1<<6)) && (TWISR_state == TW_IDLE))
00735     {
00736       SMLOCK = 1;
00737       TWBR = 12;   //12 yields 100KHz
00738       TWCR = ((1<<TWINT) | (1<<TWSTA) | (1<<TWEN) | (1<<TWIE)); //send a START
00739       PCICR = 0;   //disable PCINT0 / PA6
00740       TEST50US = 0;   //clear this flag, so that PCINT6 gets re-enabled if must re-try.
00741     }
00742     __enable_interrupt();
00743     return;
00744   }
00745 
00746   if((PINA & (1<<6)) && (TWISR_state == TW_IDLE))
00747   {
00748     TEST50US = 1;
00749     //enable PinChange Interrupt for PA6 here.  PA6 is PCINT6.
00750     PCIFR = (1<<PCIF1) | (1<<PCIF0); //clear any flags present
00751     PCMSK0 = (1<<6);   //enable PA6 pin-change
00752     PCICR = (1<<PCIE0);   //enable PCINT0
00753   }
00754 }
00755 
00756 
00757 
00758 
00759 
00760 void Check50uS(void)
00761 {
00762   if(TEST50US)
00763     SMB_Master();
00764 }
00765 
00766 
00767 
00768 
00769 
00770 
00771 void SMB_CmdInterpreter(void)
00772 {
00773   unsigned char temp;
00774 
00775   if(SMB_GenBusTimeout == TWI_CmdFlags) //The ISR detected an error condition.
00776   {
00777     TWI_CmdFlags = 0;                   //clear the flag that brought us here.
00778     //start the 26mS timer.  When it is done, the Timer handler will re-init the TWI peripheral.
00779     SetGenericTimer(SMBfaultTimer, 26);
00780     return;
00781   }
00782   else
00783   if(SMB_SetUpReply == TWI_CmdFlags)    //interpret a 'Read' Command.
00784   {
00785     TWI_CmdFlags = 0;                   //clear the flag that brought us here.
00786     TW_TxBufIndex = 0;                  //initialize
00787     TW_TxBufCnt = 0;                    //initialize
00788     if(0 != SMB_ReadCmd[CurrentCmd]())  //After interpreting, was there an error??
00789     {
00790       SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnsuptdCommand;
00791       SetGenericTimer(SMBfaultTimer, 26); //generate a bus timeout error.
00792       TW_TxBufIndex = 0;                  //Wipe out anything in the buffer, just in case.
00793       TW_TxBufCnt = 0;                  
00794       return;
00795     }
00796     else //generate PEC now for the *entire* transaction, including the original request!
00797     {
00798       //Assume (TW_TxBufIndex == 0) and (TW_TxBufCtr == # of bytes of data, not incl PEC).
00799       temp = FastCRC(0, (TWAR & 0xFE)); //use the SLA+W address
00800       temp = FastCRC(temp, CurrentCmd);
00801       temp = FastCRC(temp, (TWAR | 1)); //use the SLA+R address
00802 
00803       do {temp = FastCRC(temp, TW_TxBuf[TW_TxBufIndex++]);}
00804       while(TW_TxBufIndex != TW_TxBufCnt);
00805 
00806       TW_TxBuf[TW_TxBufIndex] = temp;   //append the CRC value on the end.
00807       TW_TxBufCnt++;                    //increase the byte count for the PEC.
00808       TW_TxBufIndex = 0;                //Reset the buffer pointer.
00809       TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);    //have TWI continue from where it stalled.
00810     }
00811     return;
00812   }
00813   else
00814   if(SMB_GotCmdData == TWI_CmdFlags)    //process some received command+data.
00815   {
00816     //NOTE: as of 6/17/2005, TWI_CmdFlags should NOT be cleared until we are
00817     // completely done processing this message, else the TWI ISR will overwrite
00818     // the RX buffer and won't respond with BUSY as it should.  Note also that
00819     // the TWI is fully re-enabled when entering here, so we MUST NOT write
00820     // to any of the TWI h/w registers or we could create havoc.  -rgf
00821 
00822     if(UsePEC)                          //check the CRC of the received packet.
00823     {
00824       temp = 0;                         //use this as our CRC value.
00825 
00826       do { temp = FastCRC(temp, TW_RxBuf[TW_RxBufIndex++]); }
00827       while(TW_RxBufCnt != TW_RxBufIndex);
00828 
00829       if(temp)  //The result of a CRC check SHOULD be =0 if all was ok.
00830       {
00831         SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
00832 
00833         //start the 26mS timer to generate a bus timeout error.
00834         SetGenericTimer(SMBfaultTimer, 26);
00835         TWI_CmdFlags = 0;               //clear the flag that brought us here.
00836         return;
00837       }
00838     }
00839 
00840     //The rcvd message is valid enough to warrant calling the command's handler now.
00841 
00842 
00843     //Note that none of the regular SMBus commands use Block Mode to send info
00844     // *TO* the Smart Battery, so TW_RxBuf[2] will NEVER be a byte count, but
00845     // will always be DATA.  For OptionalMfgFunction(5), the associated command
00846     // function itself is aware that [2] is the byte count and that the actual
00847     // data starts at offset=[3].
00848     TW_RxBufIndex = 2;                  //point to the first byte of Received Data.
00849 
00850 
00851     if(0 != SMB_WriteCmd[CurrentCmd]()) //After interpreting, was there an error??
00852     {
00853       TW_RxBufIndex = 0;                //Wipe out anything in the buffer, just in case.
00854       TW_RxBufCnt = 0;                  
00855 
00856       //start the 26mS timer to generate a bus timeout error.
00857       SetGenericTimer(SMBfaultTimer, 26);
00858       TWI_CmdFlags = 0;                 //clear the flag that brought us here.
00859       return;
00860     }
00861     //At this point it looks like everything went OK.
00862     TWI_CmdFlags = 0;                   //clear the flag that brought us here.
00863     return;
00864   }
00865 }
00866 
00867 
00868 
00869 
00870 
00871 //This function restores the SMBus & the TWI_ISR state machine to normal after
00872 //  we have deliberately generated a bus timeout error (in order to tell the
00873 //  Master that something was wrong with his last command).
00874 void SMB_RestoreBus(void)
00875 {
00876   TWCR = 0;                     //shut down the peripheral
00877   TWISR_state = TW_IDLE;        //force an init of the state machine
00878   TWAR = BATTERY_ADDR;                  
00879   TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN) | (1<<TWIE);        // | (1<<TWSTO)  re-enable
00880 
00881   //Note that we must be careful not to generate some kind of bus error
00882   // as a result of waking back up, or we will get into an endless loop
00883   // by generating another bus timeout if the IDLE state doesn't like
00884   // something it sees when it comes back to life.
00885 }
00886 
00887 
00888 
00889 
00890 
00891 
00892 
00893 
00894 
00895 
00896 
00897 
00898 /* *************************************************************************
00899  *
00900  *   Individual handlers for SMBus READ-type commands.
00901  *
00902  *   When any of these functions is called, the SMBus is in a halted state,
00903  *   pending the completion of the called function.  If an error is detected
00904  *   while processing any of these, a bus timeout error will have to be
00905  *   generated to inform the Master that there was a problem.  Otherwise,
00906  *   if everything is OK, the data that is being requested by the Master
00907  *   must be set up in the TW_TxBuf buffer for transmission to the Master.
00908  *   The functions below do not need to calculate the PEC value, as this
00909  *   will be handled in the function SMB_CmdInterpreter() automatically.
00910  *
00911  *   The valid return values for all functions below are:
00912  *      0: error detected; must generate a bus timeout error.
00913  *      1: requested data is present in the TW_TxBuf buffer.
00914  *
00915  ************************************************************************* */
00916 
00917 
00918 
00919 
00920 void FillResponseInt(unsigned int info)
00921 {
00922   TW_TxBuf[0] = (unsigned char) info;
00923   TW_TxBuf[1] = (unsigned char) (info >> 8);
00924 
00925   TW_TxBufIndex = 0;
00926   TW_TxBufCnt = 2;
00927 }
00928 
00929 
00930 void FillResponseStr(char __flash * source)
00931 {
00932   unsigned char * dest = TW_TxBuf;
00933   unsigned char ctr = 0;
00934 
00935   for(;;)
00936   {
00937     if(*dest++ = *source++)
00938       ctr++;
00939     else
00940       break;
00941   }
00942 
00943   TW_TxBufIndex = 0;
00944   TW_TxBufCnt = ctr;
00945 }
00946 
00947 
00948 
00949 
00950 /* ************************************************** */
00951 
00952 unsigned char SMBR_MfrAccess(void)      // Cmd # 0
00953 {
00954   FillResponseInt(SMBvar_int[SMBV_MfrAccess]);
00955   return 0;
00956 }
00957 
00958 
00959 
00960 unsigned char SMBR_RemCapAlm(void)      // 1
00961 {
00962   FillResponseInt(SMBvar_int[SMBV_RemCapAlm]);
00963   return 0;
00964 }
00965 
00966 
00967 unsigned char SMBR_RemTimeAlm(void)     // 2
00968 {
00969   FillResponseInt(SMBvar_int[SMBV_RemTimeAlm]);
00970   return 0;
00971 }
00972 
00973 
00974 unsigned char SMBR_BattMode(void)       // 3
00975 {
00976   FillResponseInt(SMBvar_int[SMBV_BattMode]);
00977   return 0;
00978 }
00979 
00980 
00981 unsigned char SMBR_AtRate(void)         // 4
00982 {
00983   FillResponseInt(SMBvar_int[SMBV_AtRate]);
00984   return 0;
00985 }
00986 
00987 
00988 unsigned char SMBR_AtRateTTF(void)      // 5
00989 {
00990   unsigned int temp = AtRateTTF();
00991   SMBvar_int[SMBV_AtRateTTF] = temp;    //save local copy of result for DEBUG PURPOSES ONLY
00992   FillResponseInt(temp);
00993   return 0;
00994 }
00995 
00996 
00997 unsigned char SMBR_AtRateTTE(void)      // 6
00998 {
00999   unsigned int temp = AtRateTTE();
01000   SMBvar_int[SMBV_AtRateTTE] = temp;
01001   FillResponseInt(temp);
01002   return 0;
01003 }
01004 
01005 
01006 unsigned char SMBR_AtRateOK(void)       // 7
01007 {
01008   unsigned int temp = AtRateOK();
01009   SMBvar_int[SMBV_AtRateOK] = temp;
01010   FillResponseInt(temp);
01011   return 0;
01012 }
01013 
01014 
01015 unsigned char SMBR_Temperature(void)    //  8
01016 {
01017   unsigned int temp = GetTemperature();
01018   SMBvar_int[SMBV_Temperature] = temp;
01019   FillResponseInt(temp);
01020   return 0;
01021 }
01022 
01023 
01024 unsigned char SMBR_Voltage(void)        //  9
01025 {
01026   unsigned int volt = GetVoltage();
01027   SMBvar_int[SMBV_Voltage] = volt;
01028   FillResponseInt(volt);
01029   return 0;
01030 }
01031 
01032 
01033 unsigned char SMBR_Current(void)        // 10
01034 {
01035   signed int current = Current1Sec();
01036 
01037   SMBvar_int[SMBV_Current] = (unsigned int) current;
01038   FillResponseInt((unsigned int) current);
01039   return 0;
01040 }
01041 
01042 
01043 unsigned char SMBR_AvgCurrent(void)     // 11
01044 {
01045   signed int current = CCarray_Average();
01046 
01047   SMBvar_int[SMBV_AvgCurrent] = (unsigned int) current;
01048   FillResponseInt((unsigned int) current);
01049   return 0;
01050 }
01051 
01052 
01053 unsigned char SMBR_MaxError(void)       // 12
01054 {
01055   FillResponseInt(SMBvar_int[SMBV_MaxError] = 0);
01056   return 0;
01057 }
01058 
01059 
01060 unsigned char SMBR_RelSOC(void)         // 13
01061 {
01062   unsigned int temp = RelativeSOC();
01063 
01064   SMBvar_int[SMBV_RelSOC] = temp;
01065   FillResponseInt(temp);
01066   return 0;
01067 }
01068 
01069 
01070 unsigned char SMBR_AbsSOC(void)         // 14
01071 {
01072   unsigned int temp = AbsoluteSOC();
01073   SMBvar_int[SMBV_AbsSOC] = temp;
01074   FillResponseInt(temp);
01075   return 0;
01076 }
01077 
01078 
01079 unsigned char SMBR_RemCap(void)         // 15
01080 {
01081   unsigned int cap = RemainingCap();
01082   FillResponseInt(cap);
01083   SMBvar_int[SMBV_RemCap] = cap;
01084   return 0;
01085 }
01086 
01087 
01088 unsigned char SMBR_FullChgCap(void)     // 16
01089 {
01090   unsigned int cap = FullChgCap();
01091   FillResponseInt(cap);
01092   SMBvar_int[SMBV_FullChgCap] = cap;
01093   return 0;
01094 }
01095 
01096 
01097 unsigned char SMBR_RunTTE(void)         // 17
01098 {
01099   unsigned int temp = TimeToEmpty(0);
01100   FillResponseInt(temp);
01101   SMBvar_int[SMBV_RunTTE] = temp;
01102   return 0;
01103 }
01104 
01105 
01106 unsigned char SMBR_AvgTTE(void)         // 18
01107 {
01108   unsigned int temp = TimeToEmpty(1);
01109   FillResponseInt(temp);
01110   SMBvar_int[SMBV_AvgTTE] = temp;
01111   return 0;
01112 }
01113 
01114 
01115 unsigned char SMBR_AvgTTF(void)         // 19
01116 {
01117   unsigned int temp = AvgTimeToFull();
01118   FillResponseInt(temp);
01119   SMBvar_int[SMBV_AvgTTF] = temp;
01120   return 0;
01121 }
01122 
01123 
01124 
01125 /* ********************************************** */
01126 
01127 // These two messages are sent from either a Charger or a Host
01128 unsigned char SMBR_ChgCurrent(void)     // 20
01129 {
01130   SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
01131   FillResponseInt(SMBvar_int[SMBV_ChgCurrent]);
01132   return 0;
01133 }
01134 
01135 
01136 unsigned char SMBR_ChgVoltage(void)     // 21
01137 {
01138   SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
01139   FillResponseInt(SMBvar_int[SMBV_ChgVoltage]);
01140   return 0;
01141 }
01142 
01143 
01144 /* ********************************************** */
01145 
01146 
01147 unsigned char SMBR_BattStatus(void)     // 22
01148 {
01149   FillResponseInt(SMBvar_int[SMBV_BattStatus]);
01150   SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;
01151   return 0;
01152 }
01153 
01154 
01155 unsigned char SMBR_CycleCount(void)     // 23
01156 {
01157   FillResponseInt(SMBvar_int[SMBV_CycleCount]);
01158   return 0;
01159 }
01160 
01161 
01162 unsigned char SMBR_DesignCap(void)      // 24
01163 {
01164   unsigned long temp;
01165 
01166   if(SMBvariables[SMBV_BattMode][hibyte] & CAPACITY_MODE)       //use mW in calculations
01167     temp = PACK_DESIGNCAPMW;
01168   else
01169     temp = PACK_DESIGNCAPC5;
01170 
01171   FillResponseInt(temp);
01172   SMBvar_int[SMBV_DesignCap] = (unsigned int)temp;
01173   return 0;
01174 }
01175 
01176 
01177 unsigned char SMBR_DesignVolt(void)     // 25
01178 {
01179   FillResponseInt(PACK_NOMINALV);
01180   SMBvar_int[SMBV_DesignVolt] = PACK_NOMINALV;
01181   return 0;
01182 }
01183 
01184 
01185 unsigned char SMBR_SpecInfo(void)       // 26
01186 {
01187   FillResponseInt(SMBvar_int[SMBV_SpecInfo]);   
01188   return 0;
01189 }
01190 
01191 
01192 unsigned char SMBR_MfrDate(void)        // 27
01193 {
01194   FillResponseInt(SMBvar_int[SMBV_MfrDate]);    
01195   return 0;
01196 }
01197 
01198 
01199 unsigned char SMBR_SerialNo(void)       // 28
01200 {
01201   FillResponseInt(SMBvar_int[SMBV_SerialNo]);   
01202   return 0;
01203 
01204 }
01205 
01206 
01207 unsigned char SMBR_MfrName(void)        // 32
01208 {
01209   FillResponseStr(str_MfrName);                 
01210   return 0;
01211 }
01212 
01213 
01214 
01215 unsigned char SMBR_DeviceName(void)     // 33
01216 {
01217   FillResponseStr(str_DeviceName);              
01218   return 0;
01219 }
01220 
01221 
01222 unsigned char SMBR_DeviceChem(void)     // 34
01223 {
01224   FillResponseStr(str_DeviceChem);              
01225   return 0;
01226 }
01227 
01228 
01229 unsigned char SMBR_MfrData(void)        // 35
01230 {
01231   FillResponseStr(str_MfrData);                 
01232   return 0;
01233 }
01234 
01235 
01236 unsigned char SMBR_Opt5(void)           // 0x2F
01237 {
01238   FillResponseInt(12345);                       
01239   return 0;
01240 //  return SMBerr_ReservedCommand;
01241 }
01242 
01243 
01244 unsigned char SMBR_Opt4(void)           // 0x3C (serves as Calibration control)
01245 {
01246   FillResponseInt( calibration_state ); // Prepare current state in TX buf.
01247   return 0; // Return "OK, there are data to transmitted".
01248 
01249 }
01250 
01251 
01252 unsigned char SMBR_Opt3(void)           // 0x3D
01253 {
01254 
01255   return SMBerr_ReservedCommand;        //unused
01256 }
01257 
01258 
01259 unsigned char SMBR_Opt2(void)           // 0x3E
01260 {
01261 
01262   return SMBerr_ReservedCommand;        //unused
01263 }
01264 
01265 
01266 unsigned char SMBR_Opt1(void)           // 0x3F
01267 {
01268 
01269   return SMBerr_ReservedCommand;        //unused
01270 }
01271 
01272 
01273 unsigned char SMBR_invalid(void)        //This should never execute, if error is caught early!
01274 {
01275   return SMBerr_UnsuptdCommand;
01276 }
01277 
01278 
01279 
01280 //typedef unsigned char (*ptr2funcUC_V)(void);
01281 
01282 //Table of pointers to functions, indexed from the received SMBus Command byte.
01283 ptr2funcUC_V SMB_ReadCmd[HIGHEST_SMB_CMD+1] =
01284 {
01285   SMBR_MfrAccess,       //  0
01286   SMBR_RemCapAlm,       //  1
01287   SMBR_RemTimeAlm,      //  2
01288   SMBR_BattMode,        //  3
01289   SMBR_AtRate,          //  4
01290   SMBR_AtRateTTF,       //  5
01291   SMBR_AtRateTTE,       //  6
01292   SMBR_AtRateOK,        //  7
01293   SMBR_Temperature,     //  8
01294   SMBR_Voltage,         //  9
01295   SMBR_Current,         // 10
01296   SMBR_AvgCurrent,      // 11
01297   SMBR_MaxError,        // 12
01298   SMBR_RelSOC,          // 13
01299   SMBR_AbsSOC,          // 14
01300   SMBR_RemCap,          // 15
01301   SMBR_FullChgCap,      // 16
01302   SMBR_RunTTE,          // 17
01303   SMBR_AvgTTE,          // 18
01304   SMBR_AvgTTF,          // 19
01305   SMBR_ChgCurrent,      // 20
01306   SMBR_ChgVoltage,      // 21
01307   SMBR_BattStatus,      // 22
01308   SMBR_CycleCount,      // 23
01309   SMBR_DesignCap,       // 24
01310   SMBR_DesignVolt,      // 25
01311   SMBR_SpecInfo,        // 26
01312   SMBR_MfrDate,         // 27
01313   SMBR_SerialNo,        // 28
01314   SMBR_invalid,
01315   SMBR_invalid,
01316   SMBR_invalid,
01317   SMBR_MfrName,         // 32
01318   SMBR_DeviceName,      // 33
01319   SMBR_DeviceChem,      // 34
01320   SMBR_MfrData,         // 35
01321   SMBR_invalid,
01322   SMBR_invalid,
01323   SMBR_invalid,
01324   SMBR_invalid,
01325   SMBR_invalid,
01326   SMBR_invalid,
01327   SMBR_invalid,
01328   SMBR_invalid,
01329   SMBR_invalid,
01330   SMBR_invalid,
01331   SMBR_invalid,
01332   SMBR_Opt5,            // 0x2F
01333   SMBR_invalid,
01334   SMBR_invalid,
01335   SMBR_invalid,
01336   SMBR_invalid,
01337   SMBR_invalid,
01338   SMBR_invalid,
01339   SMBR_invalid,
01340   SMBR_invalid,
01341   SMBR_invalid,
01342   SMBR_invalid,
01343   SMBR_invalid,
01344   SMBR_invalid,
01345   SMBR_Opt4,            // 0x3C
01346   SMBR_Opt3,            // 0x3D
01347   SMBR_Opt2,            // 0x3E
01348   SMBR_Opt1             // 0x3F
01349 };
01350 
01351 
01352 
01353 /* *************************************************************************
01354  *
01355  *   Individual handlers for SMBus WRITE-type commands
01356  *
01357  ************************************************************************* */
01358 
01359 
01360 unsigned char SMBW_MfrAccess(void)      //  0
01361 {
01362   unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
01363   SMBvar_int[SMBV_MfrAccess] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
01364   SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
01365   return 0;
01366 }
01367 
01368 
01369 unsigned char SMBW_RemCapAlm(void)      //  1
01370 {
01371   unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
01372   SMBvar_int[SMBV_RemCapAlm] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
01373   SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
01374   return 0;
01375 }
01376 
01377 
01378 unsigned char SMBW_RemTimeAlm(void)     //  2
01379 {
01380   unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
01381   SMBvar_int[SMBV_RemTimeAlm] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
01382   SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
01383   return 0;
01384 }
01385 
01386 
01387 unsigned char SMBW_BattMode(void)       //  3
01388 {
01389   unsigned char tempH = TW_RxBuf[TW_RxBufIndex+1];
01390   unsigned char tempL;
01391 
01392   tempL = SMBvariables[SMBV_BattMode][lobyte] & 0xF0;
01393 
01394   if(tempH & 0x1C)
01395     return SMBerr_AccessDenied;         //attempt to write to reserved bits!
01396 
01397 
01398   if(~(tempL & INTERNAL_CHARGE_CONTROLLER))
01399   {
01400     tempH &= ~CHARGE_CONTROLLER_ENABLED;  //feature not present, don't let it get turned on.
01401   }
01402 
01403 
01404   if(tempH & PRIMARY_BATTERY)
01405   {
01406     ;   //let the Host do what it wants with this flag; we ignore it.
01407   }
01408 
01409   if(tempH & ALARM_MODE)
01410     SetAlarmMode;       //this DISABLES sending alarm msgs for 60 secs
01411 
01412 
01413   if(tempH & CHARGER_MODE)
01414   {
01415     ;   //Allow Host to enable us to send Master-mode Charger-Voltage/Current msgs to the Charger
01416   }
01417 
01418 
01419   if(tempH & CAPACITY_MODE)
01420   {
01421     ;   //Host must be allowed to control this bit (report in mAH or 10mWH)
01422   }
01423 
01424 
01425   SMBvar_int[SMBV_BattMode] = tempL | (tempH<<8);       //write the modified bits.
01426 
01427   return 0;
01428 }
01429 
01430 
01431 
01432 unsigned char SMBW_AtRate(void)         //  4
01433 {
01434   unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
01435   SMBvar_int[SMBV_AtRate] = temp | (TW_RxBuf[TW_RxBufIndex++]<<8);
01436   SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
01437   return 0;
01438 }
01439 
01440 unsigned char SMBW_Opt5(void)           // 0x2F
01441 {
01442   __disable_interrupt();
01443   MCUSR = 0x1F;                         //clear all reset sources before jumping to bootloader code.
01444 //  __watchdog_reset;                                   //
01445 
01446   asm("jmp 0x9000");                                    // Byte adress
01447 
01448 //  __watchdog_reset;                                           // reset watchdog
01449   return(1);                                                    // to avoid compiler warning, should never be reached
01450 
01451 //  return SMBerr_ReservedCommand; // <-- Compiler generates warning if return statement is missing.
01452 }
01453 
01454 unsigned char SMBW_Opt4(void)           // 0x3C
01455 {
01456   calibration_state_req = TW_RxBuf[TW_RxBufIndex++];
01457   calibration_state_req |= (unsigned int)TW_RxBuf[TW_RxBufIndex++] << 8; // Store request details.
01458   SetCalibRequest; // Set action flag so that main loop starts calibrating.
01459   return 0; // Return OK.
01460 }
01461 
01462 unsigned char SMBW_Opt3(void)           // 0x3D
01463 {
01464   return SMBerr_ReservedCommand;
01465 }
01466 
01467 unsigned char SMBW_Opt2(void)           // 0x3E
01468 {
01469   return SMBerr_ReservedCommand;
01470 }
01471 
01472 unsigned char SMBW_Opt1(void)           // 0x3F
01473 {
01474   return SMBerr_ReservedCommand;
01475 }
01476 
01477 unsigned char SMBW_Invalid(void)        //This should never execute, if error is caught early!
01478 {
01479   return SMBerr_AccessDenied;
01480 }
01481 
01482 
01483 
01484 //Table of pointers to functions, indexed from the received SMBus Command byte.
01485 ptr2funcUC_V SMB_WriteCmd[HIGHEST_SMB_CMD+1] =
01486 {
01487   SMBW_MfrAccess,       //  0
01488   SMBW_RemCapAlm,       //  1
01489   SMBW_RemTimeAlm,      //  2
01490   SMBW_BattMode,        //  3
01491   SMBW_AtRate,          //  4
01492   SMBW_Invalid,
01493   SMBW_Invalid,
01494   SMBW_Invalid,
01495   SMBW_Invalid,
01496   SMBW_Invalid,
01497   SMBW_Invalid,
01498   SMBW_Invalid,
01499   SMBW_Invalid,
01500   SMBW_Invalid,
01501   SMBW_Invalid,
01502   SMBW_Invalid,         //0x0F
01503 
01504   SMBW_Invalid,
01505   SMBW_Invalid,
01506   SMBW_Invalid,
01507   SMBW_Invalid,
01508   SMBW_Invalid,
01509   SMBW_Invalid,
01510   SMBW_Invalid,
01511   SMBW_Invalid,
01512   SMBW_Invalid,
01513   SMBW_Invalid,
01514   SMBW_Invalid,
01515   SMBW_Invalid,
01516   SMBW_Invalid,
01517   SMBW_Invalid,
01518   SMBW_Invalid,
01519   SMBW_Invalid,         //0x1F
01520 
01521   SMBW_Invalid,
01522   SMBW_Invalid,
01523   SMBW_Invalid,
01524   SMBW_Invalid,
01525   SMBW_Invalid,
01526   SMBW_Invalid,
01527   SMBW_Invalid,
01528   SMBW_Invalid,
01529   SMBW_Invalid,
01530   SMBW_Invalid,
01531   SMBW_Invalid,
01532   SMBW_Invalid,
01533   SMBW_Invalid,
01534   SMBW_Invalid,
01535   SMBW_Invalid,
01536   SMBW_Opt5,            // 0x2F
01537 
01538   SMBW_Invalid,
01539   SMBW_Invalid,
01540   SMBW_Invalid,
01541   SMBW_Invalid,
01542   SMBW_Invalid,
01543   SMBW_Invalid,
01544   SMBW_Invalid,
01545   SMBW_Invalid,
01546   SMBW_Invalid,
01547   SMBW_Invalid,
01548   SMBW_Invalid,
01549   SMBW_Invalid,
01550   SMBW_Opt4,            // 0x3C
01551   SMBW_Opt3,            // 0x3D
01552   SMBW_Opt2,            // 0x3E
01553   SMBW_Opt1             // 0x3F
01554 };
01555 
01556 
01557 
01558 
01559 
01560 
01561 /* *************************************************************************
01562  *
01563  *   Utilities for SMBus commmunications
01564  *
01565  ************************************************************************* */
01566 
01567 
01568 
01569 __flash unsigned char crctable[16] =  {0,0x07,0x0E,0x90, 0x1c,0x1b,0x12,0x15, 0x38,0x3F,0x36,0x31, 0x24,0x23,0x2A,0x2D};
01570 __flash unsigned char crctable2[16] = {0,0x70,0xE0,0x90, 0xC1,0xB1,0x21,0x51, 0x83,0xF3,0x63,0x13, 0x42,0x32,0xA2,0xD2};
01571 
01572 unsigned char FastCRC(unsigned char LastCRC, unsigned char newbyte)
01573 {
01574   unsigned char index;
01575 
01576   index = newbyte;
01577   index ^= LastCRC;
01578   index >>= 4;
01579   LastCRC &= 0x0F;
01580   LastCRC ^= crctable2[index];
01581 
01582   index = LastCRC;
01583   index ^= newbyte;
01584   index &= 0x0F;
01585   LastCRC &= 0xF0;
01586   LastCRC ^= crctable[index];
01587 
01588   return(LastCRC);
01589 }
01590 
01591 /*  This version doesn't require crctable2[], but requires more shifts.
01592 unsigned char SlowerCRC(unsigned char LastCRC, unsigned char newbyte)
01593 {
01594   unsigned char index;
01595 
01596   index = newbyte;
01597   index ^= LastCRC;
01598   index >>= 4;
01599   LastCRC <<= 4;
01600   LastCRC ^= crctable[index];
01601 
01602   index = LastCRC >> 4;
01603   index ^= newbyte;
01604   index &= 0x0F;
01605   LastCRC <<= 4;
01606   LastCRC ^= crctable[index];
01607 
01608   return(LastCRC);
01609 } */
01610 
01611 
01612 
01613 
01614 
01615 
01617 // This sets power-up defaults.
01618 void InitSMBvariables(void)
01619 {
01620   SMBvar_int[SMBV_MfrAccess] = 0x4060;                          // Mega406 ap-note, revision 0 code
01621   SMBvar_int[SMBV_RemCapAlm] = (PACK_DESIGNCAPTYP / 10);        // per sbdat110, 4.4.1
01622   SMBvar_int[SMBV_RemTimeAlm] = 0x000A;                 // per sbdat110, 4.4.1
01623   SMBvar_int[SMBV_BattMode  ] = 0x0000; //
01624   SMBvar_int[SMBV_AtRate    ] = 0x0000; //
01625 
01626 /* For testing with no calcs
01627   SMBvar_int[SMBV_AtRateTTF ] = 0x0000; //
01628   SMBvar_int[SMBV_AtRateTTE ] = 0x0000; //
01629   SMBvar_int[SMBV_AtRateOK  ] = 0x0000; //
01630 
01631   SMBvar_int[SMBV_Temperature] = 0x0000;        //
01632   SMBvar_int[SMBV_Voltage    ] = 0x0000;        //
01633   SMBvar_int[SMBV_Current    ] = 0x0000;        //
01634   SMBvar_int[SMBV_AvgCurrent ] = 0x0000;        //
01635   SMBvar_int[SMBV_MaxError   ] = 0x0000;        //
01636   SMBvar_int[SMBV_RelSOC     ] = 0x0000;        //
01637   SMBvar_int[SMBV_AbsSOC     ] = 0x0000;        //
01638   SMBvar_int[SMBV_RemCap     ] = 0x0000;        //
01639 
01640   SMBvar_int[SMBV_FullChgCap] = 0x0000; //
01641   SMBvar_int[SMBV_RunTTE    ] = 0x0000; //
01642   SMBvar_int[SMBV_AvgTTE    ] = 0x0000; //
01643   SMBvar_int[SMBV_AvgTTF    ] = 0x0000; //
01644   SMBvar_int[SMBV_ChgCurrent] = 0x0000; //
01645   SMBvar_int[SMBV_ChgVoltage] = 0x0000; //
01646 */
01647   SMBvar_int[SMBV_BattStatus] = 0x0080; //per sbdat110, 4.4.1
01648   SMBvar_int[SMBV_CycleCount] = 0x0000; //per sbdat110, 4.4.1
01649 
01650 /* For testing with no calcs
01651   SMBvar_int[SMBV_DesignCap ] = 0x0000; //
01652   SMBvar_int[SMBV_DesignVolt] = 0x0000; //
01653 */
01654 
01655   SMBvar_int[SMBV_SpecInfo  ] = 0x0031; // no scaling of I or V; we support PEC, and we're V1.1
01656   SMBvar_int[SMBV_MfrDate   ] = ((2005-1980)<<9)+(8<<5)+(31);   
01657   SMBvar_int[SMBV_SerialNo  ] = 12345;  // arbitrary...
01658 
01659   //Note that for the Block-Read variables, we copy those into a RAM buffer only as needed.
01660   // These are MfrName, DeviceName, DeviceChem, and MfrData.
01661 
01662   SetMaxTopAcc((long)6600*10727);   
01663 //  RunningAcc = (long)1000*10727;    //for testing, to start at other point than 0, 1000 * 10727
01664 }
01665 
01666 
01667 
01668 
01669 /* Some important notes from the SMBus specs:
01670 
01671 Insertion or removal of a Smart Battery may be detected when the ‘Safety Signal’ transitions from or to an
01672 open-circuit value (>100k.)
01673 
01674 When an SMBus device acting as the bus master detects an error, it must attempt to return the bus to the idle
01675 state by generating a STOP condition.
01676 
01677 The Smart Battery must ALWAYS acknowledge its own address. Failure to do so might cause the SMBus
01678 Host or Smart Battery Charger to incorrectly assume the Smart Battery is NOT present in the system,
01679 although the ‘Safety Signal’ can be used to detect the presence of a Smart Battery in a system. Note
01680 however that the Smart Battery may choose not to acknowledge any byte following its address if it is
01681 busy or otherwise unable to respond. If this occurs, the requestor should re-try the data request.
01682 
01683 After each SMBus transaction directed to the Smart Battery device address, the Smart Battery must place
01684 the appropriate error code in the lower nibble of the BatteryStatus() register. If the transaction completed
01685 successfully, the error codes should be cleared to signify that no error was detected. Timeout and other
01686 errors not described by one of the error code types may be signaled with an Unknown Error.
01687 
01688 Another device may try to interrogate the battery immediately after a transaction from the Host.
01689 The safest method to insure that the read of BatteryStatus() corresponds to the most recently read data value
01690 is to perform this read of BatteryStatus() immediately after the read of the initial data value. This may be
01691 accomplished by issuing a SMBus START condition after the SMBus STOP condition from the previous
01692 transmission.
01693 
01694 A bus master is required to check for bus idle time of 50 us.
01695 
01696 The Smart Battery enters the “On State whenever it detects that the SMBus Clock and Data lines go high.
01697 The battery should be active and able to communicate via the SMBus within 1 ms of detecting these SMBus
01698 lines going high.
01699 
01700 The Smart Battery may not begin *broadcasting* ChargingVoltage(), ChargingCurrent() or AlarmWarning()
01701 messages to either the SMBus Host or Smart Battery Charger for at least 10 seconds after entering the “On
01702 State.”
01703 
01704 When the Smart Battery enters the “On State” the following values must be reinitialized:
01705 Function (Data Value)           Initial Value           
01706 ---------------------   ----------------------------    
01707 BatteryMode()           Bit 15: CAPACITY_MODE=0
01708                         Bit 14: CHARGER_MODE=0
01709                         Bit 13: ALARM MODE=0
01710                         Bit 9: PRIMARY_BATTERY=0
01711                         Bit 8: CHARGE_CONTROLLER_ENABLED=0
01712 
01713 
01714 The Smart Battery may enter the “Off State” whenever the SMBus Clock and Data lines both remain low
01715 for greater than 2.5 seconds.
01716 
01717 There is no limit to the speed (other than SMBus limits) or rate at which data may be requested from the
01718 Smart Battery. Continuous data polling at high rates is permitted and allowed, though not encouraged due
01719 to limitations on SMBus bandwidth and availability. The Smart Battery may delay any data request by
01720 holding the CLOCK line low for up to 25 ms. This may be done in order to re-calculate the requested data
01721 value or to retrieve data from a storage device.
01722 
01723 
01724 */

Generated on Mon Nov 12 15:59:58 2007 for AVR453 Smart Battery Reference Design by  doxygen 1.5.3