打印
[电池电源管理]

sh79f329a SMBus

[复制链接]
2322|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
badbud|  楼主 | 2015-9-9 16:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
太冷清了,移植自MEGA406 提供给大家交流 主机模式还没有测试注释掉了
//;*****************************************************
//;Company :   
//;File Name : smbus.h
//;Author :   
//;Create Data : 2015-08-04
//;Last Modified :
//;Description :
//;Version : 0.0
//;*****************************************************
#ifndef __smbus_H__
#define __smbus_H__

void InitSMBus(void);
void SMB_Master(void);
void MasterInsertMsg(unsigned char addr, unsigned char cmd, unsigned int Information);
void SMB_RestoreBus(void);        //this is used by generic timer to recover BusFault
void InitSMBvariables(void);
void SMB_CmdInterpreter(void);
void Check50uS(void);

void FillResponseInt(unsigned int info);
void FillResponseStr(void /*unsigned char __flash * source*/);
void FillWriteStr(unsigned char  * source);
unsigned char SMBW_Opt6(void );
unsigned char SMBW_BattMode(void );
unsigned char SMBW_CalibV(void );       
unsigned char SMBW_CalibC(void );                
unsigned char SMBW_Opt5(void );       
                       

//////////////////////////////////////////////////////////////////
#define  MfrName        0
#define  MfrName1          0
#define  MfrName2          1
#define  DeviceName  1
#define  DeviceName1    2
#define  DeviceName2    3
#define  DeviceR30      2
#define  DeviceR301       4
#define  DeviceR302       5

#define  MfrData          3

#define SMBvariables SV.SMBvar
#define SMBvar_int   SV.SMBint

#ifdef MODULE_SMBUS
  union { volatile unsigned char SMBvar[0x20][2]; volatile unsigned int SMBint[0x20]; } xdata SV;

  //Note: all of these strings must fit inside TW_TxBuf with room for Addr+Cmd+PEC
  //Also, at the front of each string is a "string constant" that indicates the
  //length of the rest of the string; this constant is in OCTAL!!
char code str_MfrName[32] _at_ 0x6100;
char code str_DeviceName[32] _at_ 0x6160;
char code str_DeviceChem[16] _at_ 0x61C0;
char code str_MfrData[32] _at_ 0x61D0;
char code str_DeviceR30[32] _at_ 0x6200;

#else

  extern union { volatile unsigned char SMBvar[0x20][2]; volatile unsigned int SMBint[0x20]; } xdata SV;

#endif

#define HOST_ADDR    0x10  // According to smbus specification Appendix C
#define CHARGER_ADDR 0x12
#define BATTERY_ADDR 0x16


// Note that the following cmds are both Master Write to Charger, and Slave Read.
#define SMB_M_CMD_CHARGINGCURRENT 0x14
#define SMB_M_CMD_CHARGINGVOLTAGE 0x15

//This command is Master Write only, to both the Charger & Host addresses
#define SMB_M_CMD_ALARMWARNING 0x16


//SMBus Variable + Command Name offset list
#define SMBV_MfrAccess  0
#define SMBV_RemCapAlm  1
#define SMBV_RemTimeAlm 2
#define SMBV_BattMode   3
#define SMBV_AtRate     4
#define SMBV_AtRateTTF  5
#define SMBV_AtRateTTE  6
#define SMBV_AtRateOK   7

#define SMBV_Temperature 8
#define SMBV_Voltage     9
#define SMBV_Current    10
#define SMBV_AvgCurrent 11
#define SMBV_MaxError   12
#define SMBV_RelSOC     13
#define SMBV_AbsSOC     14
#define SMBV_RemCap     15

#define SMBV_FullChgCap 16
#define SMBV_RunTTE     17
#define SMBV_AvgTTE     18
#define SMBV_AvgTTF     19
#define SMBV_ChgCurrent 20
#define SMBV_ChgVoltage 21
#define SMBV_BattStatus 22
#define SMBV_CycleCount 23

#define SMBV_DesignCap  24
#define SMBV_DesignVolt 25
#define SMBV_SpecInfo   26
#define SMBV_MfrDate    27
#define SMBV_SerialNo   28
#define SMBV_PackStackWidth   29   //0x0302
//#define SMBV_PackCTemrC    30       //200
#define SMBV_PackVoltage    31

#define SMBV_MfrName    32
#define SMBV_DeviceName 33
#define SMBV_DeviceChem 34
#define SMBV_MfrData    35
#define SMBV_Opt5     0x2F
#define SMBV_Opt4     0x3C
#define SMBV_Opt3     0x3D
#define SMBV_Opt2     0x3E
#define SMBV_Opt1     0x3F

#define SMBW_RAM     0x25

//Offsets within each of the 29 SMBvariables elements
#define lobyte 1 //0
#define hibyte 0 // 1 for avr

#define  SMB_DataFlashAddr    0x6000            // 14   0x7000 - 0x77ff
//#define  SMB_StringFlashAddr  0x6800            // 13   0x6800 - 0x6fff
//#define  SMB_StringCopyFlashAddr  0x6000    // 12   0x6000 - 0x67ff
#define  FlashStrAddr_MfrName            0x6100
#define  FlashStrAddr_MfrName1          0x6120
#define  FlashStrAddr_MfrName2          0x6140
#define  FlashStrAddr_DeviceName      0x6160
#define  FlashStrAddr_DeviceName1    0x6180
#define  FlashStrAddr_DeviceName2    0x61A0
#define  FlashStrAddr_DeviceChem      0x61C0

#define  FlashStrAddr_DeviceR30          0x6200
#define  FlashStrAddr_DeviceR301        0x6220
#define  FlashStrAddr_DeviceR302        0x6240
//SMBV_BatteryMode bit definitions

//  HiByte
#define CHARGE_CONTROLLER_ENABLED        0x01
#define PRIMARY_BATTERY                        0x02
#define ALARM_MODE                        0x20
#define CHARGER_MODE                        0x40
#define CAPACITY_MODE                        0x80

//  LoByte
#define INTERNAL_CHARGE_CONTROLLER        0x01
#define PRIMARY_BATTERY_SUPPORT                0x02
#define CONDITION_FLAG                        0x80



//SMBV_BatteryStatus bit definitions.

// HiByte
/* * * * * * Alarm Bits * * * * */
#define OVER_CHARGED_ALARM                0x80
#define TERMINATE_CHARGE_ALARM                0x40
#define OVER_TEMP_ALARM                        0x10
#define TERMINATE_DISCHARGE_ALARM        0x08
#define REMAINING_CAPACITY_ALARM        0x02
#define REMAINING_TIME_ALARM                0x01

// LoByte
/* * * * * * Status Bits * * * * */
#define INITIALIZED                0x80
#define DISCHARGING                0x40
#define FULLY_CHARGED                0x20
#define FULLY_DISCHARGED        0x10

/* * * * * * Error Codes * * * * */
#define SMBerr_OK               0x00        // r/w The Smart Battery processed the function code without detecting any errors.
#define SMBerr_Busy             0x01        // r/w The Smart Battery is unable to process the function code at this time.
#define SMBerr_ReservedCommand  0x02        // r/w The Smart Battery detected an attempt to read or write to a function code
                                        //     reserved by this version of the specification. The Smart Battery detected
                                        //     an attempt to access an unsupported optional manufacturer function code.
#define SMBerr_UnsuptdCommand   0x03        // r/w The Smart Battery does not support this function code which is
                                        //     defined in this version of the specification.
#define SMBerr_AccessDenied     0x04        //  w  The Smart Battery detected an attempt to write to a read-only function code.
#define SMBerr_OverUnderflow    0x05        // r/w The Smart Battery detected a data overflow or under flow.
#define SMBerr_BadSize          0x06         //  w  The Smart Battery detected an attempt to write to a function code with
                                        //     an incorrect size data block.
#define SMBerr_UnknownError     0x07         // r/w The Smart Battery detected an unidentifiable error.

#endif



沙发
badbud|  楼主 | 2015-9-9 16:05 | 只看该作者
//;*****************************************************
//;Company :   
//;File Name : smbus.c
//;Author :   scallyt
//;Create Data : 2015-09-09
//;Last Modified :
//;Description : smbus  interrupt  program
//;Version : 0.0
//;*****************************************************

#define MODULE_SMBUS
#include "SH79f329.h"
#include "main.h"
#include "smbus.h"
#include "timer.h"                //required for BusFault timer activation
#include "analog.h"
#include <intrins.h>
#include "flash.h"
#include "pack.h"
#include "interpret.h"          // ONLY include this file in THIS module!


//extern __flash unsigned char SM_Cmd_Table[0x40][2]; //in interpret.c
typedef unsigned char (*ptr2funcUC_V)(void);
extern ptr2funcUC_V SMB_ReadCmd[];
extern ptr2funcUC_V SMB_WriteCmd[];

//Internally-needed prototypes
unsigned char FastCRC(unsigned char LastCRC, unsigned char newbyte);
//extern unsigned char SMLOCK;


//This is used to check for an out-of-bounds SMBus command.
#define HIGHEST_SMB_CMD 0x3F


//Two-Wire-Interface TWSR (STATUS) values
//Note that since our Prescale value is 0, we don't need to MASK the Status byte.

//  Globally applicable TWI status codes:
#define TWS_MASK  0xF8                /* Two-Wire Status Mask */
#define TWS_NSTAT 0xF8                /* No Status Available now */

//  MASTER-related Status codes:
#define TWS_START 0x08
#define TWS_RESTART 0x10
#define TWS_WRITE_ACK 0x18        /* sent a SLA+W, got ACK */
#define TWS_WRITE_NAK 0x20        /* sent SLA+W, got NAK */
#define TWS_TXDATA_ACK 0x28        /* Data tx'd & was ACK'd */
#define TWS_TXDATA_NAK 0x30        /* Data tx'd & was NAK'd */
#define TWS_LOST_ARB 0x38        /* lost bus arbitration */

#define TWS_READ_ACK 0x40        /* got ACK from a SLA+R request */
#define TWS_READ_NAK 0x48        /* got NAK from a SLA+R request */
#define TWS_RXDATA_ACK 0x50        /* We rcvd data and ACKd back */
#define TWS_RXDATA_NACK 0x58        /* We rcvd data and we NACKd back */


//  SLAVE-related Status codes:
#define TWS_SLA_W 0x60                /* Got SLA + Write */
#define TWS_SLA_R 0xA8                /* Got SLA + Read  */
#define TWS_RDATA 0x80                /* Got a data byte */
#define TWS_RCMD  0x80                /* Got a command byte */
#define TWS_RSTOP 0xA0                /* Got a Stop */
#define TWS_REPEAT 0xA0                /* Got a Repeated-Start */
#define TWS_RACK  0xB8                /* Send a data byte and got an ACK back */
#define TWS_RNAK  0xC0                /* Sent a data byte and got a NAK back */
#define TWS_FINAL 0xC8                /* Sent the final byte, got ACK back */
#define TWS_BERR  0x00                /* Saw a Bus Error */


#define TWS_RADDACK  0xB0                /* Got SLA + Read and  ACKd back */
// Two-Wire CONTROL values

#define TWC_GO 0x85            /* clr TWINT; assert ENA & IntEna */
#define TWC_READ_NoACK 0x85 /* read a byte, but don't ACK when done */
#define TWC_START 0xA5            /* send START bit, assert ENA & IntEna */
#define TWC_STOP 0x94            /* leave INT *DISabled* when done */
#define TWC_RESTART 0xB5    /* send STOP, then START again; INT ena */


/* ************************************************************************* */

unsigned char idata TEST50US = 0;
unsigned char idata SMLOCK = 0;        //prevents Master bus grab attempts WHILE BUS IS IN MASTER MODE.

unsigned char idata TW_MTxBuf[8];        //Master-mode TX buffer
unsigned char idata TW_MTxBufCnt = 0;        //how many valid bytes are in the buffer
unsigned char idata TW_MTxBufIndex = 0;

// Note for the buffers below, these must be able to contain:
// Slave Address, SMBus Command, Byte Count (if Block-mode), up to 32 bytes, plus PEC.
unsigned char idata TW_TxBuf[36];        //must be long enough for any outbound strings
unsigned char idata TW_TxBufCnt = 0;        //how many valid bytes are in the buffer
unsigned char idata TW_TxBufIndex = 0;

unsigned char idata TW_RxBuf[36];        //In Application mode (non-ISP mode), only receive WORD commands.
signed char idata TW_RxBufCnt = 0;
unsigned char idata TW_RxBufIndex = 0;


unsigned char xdata TWI_CmdFlags;
  #define SMB_GenBusTimeout 1        /* Tell Foreground to generate a bus timeout, as we saw an error! */
  #define SMB_SetUpReply 2        /* Have Foreground set up TW_TxBuf[]. */
  #define SMB_GotCmdData 4        /* Have Foreground interpret the complete received command. */

unsigned char idata CurrentCmd = 0xFF;
unsigned char idata UsePEC = 0;        //PEC usage is disabled by default.


unsigned int xdata Flash_Addr = SMB_DataFlashAddr;
unsigned char xdata Flash_Cnt = 2;
unsigned char  * RStrptr;
//;***************************************************************
//;Description: smbu_init()
//;input          :
//;Returns    :
//;Notes      : set the special registers about smbus
//;***************************************************************
void InitSMBus()
{
  SMB_RestoreBus();
}


/* *************************************************************************
*
*   SMBus P1_6 Pin Change Interrupt (needed for Master Mode)
*
************************************************************************* */
void P1INT1_ISR(void)        interrupt  2  /// using        2
{
    TEST50US = 0;     //flag to SMBUS.C that bus activity happened
}



/* *************************************************************************
*
*   Low-Level SMBus Communications State Machine
*
************************************************************************* */

/*
unsigned char xdata TXmsg[4][4];    //leave room for PEC
volatile unsigned char xdata TXmsgHead = 0;
volatile unsigned char xdata TXmsgTail = 0;
volatile unsigned char xdata TXmsgQty = 0;

#define TXmsgEmpty (TXmsgQty == 0)
#define TXmsgFull (TXmsgQty == 4)
#define TXmsgDelete {++TXmsgTail; TXmsgTail &= (4-1);  TXmsgQty--;}

//We will compute the PEC for the message as well.
void MasterInsertMsg(unsigned char addr, unsigned char cmd, unsigned int Information)
{ //Note that the Charger address is ALWAYS 0x12! (sbsm100.pdf, 5.2)
  //The Host address is always 0x16.
  //The addr always assumes WRITE.
  //We only do a WORD WRITE.

  unsigned char * ptr = TXmsg[TXmsgHead];

  *ptr++ = addr;
  *ptr++ = cmd;
  *ptr++ = (unsigned char) Information;
  *ptr = (unsigned char)(Information>>8);

  if(TXmsgFull)
    return;


  ++TXmsgHead;
  TXmsgHead &= (4-1);
  TXmsgQty++;
}
*/


//#define TWCR   SMBCON
#define TWEA   2                //AA        ACK
#define TWINT  3                //SI                TWI interrupt flag
#define TWSTO  4        //STO
#define TWSTA  5        //STA         
#define TWEN   6                //ENSMB                TWI enable bit

//#define TWIE   ESMB                //TWI interrupt enable.  IEN0 4 bit

//#define TWAR   SMBADR   //
//#define TWDR   SMBDAT   //TWI data register

//State Machine states
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 };

unsigned char TWISR_state = TW_IDLE;        //state variable

void SMB_ISR(void)         interrupt  4  /// using        2
{
  static unsigned char  TWISR_CmdFeatures = 0;        //Command-related feature flags
  unsigned char  Status;
  static unsigned char crc;
  unsigned char  tmp;

  EA = 0;
  //SMBSTA=SMBSTA|0x01;
  SetGenericTimer(SMBfaultTimer, 12);  //48mS

  Status = SMBSTA&0xF8;                                                //read the status of smbus        //This identifies what caused the interrupt to fire.

  switch(TWISR_state)
  {
    default:
    case TW_IDLE:        //If not SLA_W or RSTOP, is an error!
      if(TWS_SLA_W == Status)        // saw Slave address match with a Write bit
      {
              if(TWI_CmdFlags == SMB_GotCmdData)
              {
                //Assert that we're 'busy' to SMBus Master by leaving TWEA *off* until we get a STOP.
                //Note that this is 'legal' because we have ALREADY sent an ACK to our Slave Address,
                // as is required by the SMBus specification.
                TWISR_state = TW_Wait4Stop;
          SMBCON = (1<<TWEN);        //must NOT re-enable ACKing!
           ESMB = 1;
                break;//return;
              }
              else
              {
          TWISR_state = TW_Wait4Cmd;
            crc = FastCRC(0, (SMBADR & 0xFE));        //use the SLA+W address
              }
      }
      else
      if(TWS_RSTOP == Status)        //Saw a Stop, possibly left over from previous cmd.
      {
         ;                        //Everything is probably OK.  Take no action.
      }
      //else
     //if(TWS_START == Status)        //we have successfully sent a START bit. Handle MASTER mode.
      //{
     //   TWDR = TW_MTxBuf[TW_MTxBufIndex++];
     //   TWISR_state = TW_MSLA_W;
     // }
      else //had some type of error!
      {
        SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
        TWI_CmdFlags = SMB_GenBusTimeout;        //generate a bus timeout.
        SMBCON = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);                //disable int, and DON'T clear the TWINT flag!
        TWISR_state = TW_IDLE;                        //Reset the state machine.
        break;//return;
      }
      SMBCON = (1<<TWEA) | (1<<TWEN);        //must re-enable ACKing
      break;
/*
    case TW_Wait4Stop:
      if(TWS_RSTOP == Status)        //Saw a Stop, possibly left over from previous cmd.
      {
        SMBCON = (1<<TWEA) | (1<<TWEN);        //must re-enable ACKing
                //ESMB = 1;
        TWISR_state = TW_IDLE;                        //Reset the state machine.
      }
      else                                                                //or return        crc   not reset
        SMBCON =  (1<<TWEN);        //must NOT re-enable ACKing yet!
          ESMB = 1;
      break;
*/

    //SLAVE-mode states follow.

    case TW_Wait4Cmd:        //upon entry, we expect to have received a Cmd byte.
      if(TWS_RCMD == Status)                //It appears that we have received a Command byte now.
      {
         tmp = SMBDAT;                      //Save a copy.        
         CurrentCmd = tmp;                //Save a copy.               
         crc = FastCRC(crc, CurrentCmd);
        if(CurrentCmd <= HIGHEST_SMB_CMD)        //Is the Cmd within valid range?
        {
          //CurrentCmd = tmp;                //Save a copy.
          tmp = SM_Cmd_Table[tmp][0];        //Grab the Command Characteristics/Features flags.
        }
        else        //Not reset SMB, compatible with other programs, it is not my intention
        {
          tmp = SM_Cmd_Table[0][0];         //err cmd
        }       
               
        //if(tmp & SMBslave)                //Is the Command valid for Slaves?
        //{                                //The command appears to be valid.
          TWISR_CmdFeatures = tmp;        //Save the Feature flags for use in Wait4RW state.
          TWISR_state = TW_Wait4RW;        //set up next state
          SMBCON = (1<<TWEA) | (1<<TWEN);        //enable ACKing
          break;//return;
        //}
      }
      //In all cases except those that 'return' (above), it's an error.
      SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
      TWI_CmdFlags = SMB_GenBusTimeout;        //generate a bus timeout.
      SMBCON = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);     //disable int, and DON'T clear the TWINT flag!
      TWISR_state = TW_IDLE;                //Reset the state machine.
      break;

    case TW_Wait4RW:        //We will now find out if we will RX more, or we need to TX a reply instead.
      if(TWS_RDATA == Status)                //It is a WRITE-type command. Prep the RX buffer to accept more data.
      {        //NOTE: except for OptionalMfgFunction5, all WRITE cmds are 2-byte, plus optional PEC.
              //Place all bytes of the transaction into the buffer so we can do a PEC on it if needed.
              TW_RxBuf[0] = SMBADR & 0xFE;        //store everything incl. the slave address for computing PEC.
              TW_RxBuf[1] = CurrentCmd;        //store the previously-send Command.
        TW_RxBuf[2] = SMBDAT;                //store this first DATA byte
        TW_RxBufIndex = 3;                //use RxBufIndex as the index to store data in the buffer.
        if(TWISR_CmdFeatures & SCWW)        //is it a Write-WORD command type?
        {
            TW_RxBufCnt = 1;                //We expect 1 more data byte, and possibly PEC after that.
        }
        else
        if(TWISR_CmdFeatures & SCWG)        //is it a write-BLOCK command (must be OptionalMfgFunction5 then)
        {
          tmp = SMBDAT;
          if((tmp >= 1) && (tmp <= 32))
            TW_RxBufCnt = SMBDAT;
          else
             TW_RxBufCnt = Flash_Cnt;        
           //if(CurrentCmd == SMBV_Opt5)        //Is the Cmd within valid range?
           //  TW_RxBufCnt = Flash_Cnt;        
          //{
          //  SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_BadSize;
          //  TWI_CmdFlags = SMB_GenBusTimeout;        //generate a bus timeout.
          //  SMBCON = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);       //disable int, and DON'T clear the TWINT flag!
                //    ESMB = 0;
           // TWISR_state = TW_IDLE;                //Reset the state machine.
           // break;//return;
          //}
        }
        //else        //this Command doesn't allow EITHER word OR group/block Writes! It's Read-only!
        //{
         // SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_AccessDenied;
         // TWI_CmdFlags = SMB_GenBusTimeout;        //Not a WRITE-type cmd, so generate a bus timeout.
         //SMBCON = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
        //          ESMB = 0;
          //TWISR_state = TW_IDLE;                //Reset the state machine.
          //break;//return;
        //}
        TWISR_state = TW_Wait4Data;
        SMBCON = (1<<TWEA) | (1<<TWEN);        //enable ACKing
      }
      else
      if(TWS_REPEAT == Status)        //We saw a re-Start, so must be getting ready for a Read cmd.
      {        //Must now interpret previously-sent CurrentCmd & set up Reply data.
        //if(TWISR_CmdFeatures & (SCRW | SCRG))        //Is it a 'ReadWord' or 'ReadGroup' command type?
        {
          //TWI_CmdFlags = SMB_SetUpReply;        //Foreground decoder will set up SMBCON.
          TWISR_state = TW_ReplyData;                //Move to next state.
//.......
          TWI_CmdFlags = 0;                        //clear the flag that brought us here.
          //TW_TxBufIndex = 0;                        //initialize
          //TW_TxBufCnt = 0;                        //initialize
          if(CurrentCmd <= HIGHEST_SMB_CMD)        //Is the Cmd within valid range?
            SMB_ReadCmd[CurrentCmd]();
           else
            FillResponseInt(0xffff);
          //else //generate PEC now for the *entire* transaction, including the original request!

          {
            //Assume (TW_TxBufIndex == 0) and (TW_TxBufCtr == # of bytes of data, not incl PEC).
            //crc = FastCRC(0, (SMBADR & 0xFE));        //use the SLA+W address
            //crc = FastCRC(crc, CurrentCmd);
            crc = FastCRC(crc, (SMBADR | 1));        //use the SLA+R address
            //do {crc = FastCRC(crc, TW_TxBuf[TW_TxBufIndex++]);}
            //while(TW_TxBufIndex != TW_TxBufCnt);

            //TW_TxBuf[TW_TxBufIndex] = crc;        //append the CRC value on the end.
            TW_TxBufCnt++;                        //increase the byte count for the PEC.
            //TW_TxBufIndex = 0;                //Reset the buffer pointer.
          }  
          //SV.SMBint[SMBV_BattStatus] &= 0xFFF0;
          //TW_TxBufCnt++;
        SMBCON = (1<<TWEA) | (1<<TWEN);        //enable ACKing
         break;
//...............          
        }
        /*else
        {
          SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
          TWI_CmdFlags = SMB_GenBusTimeout;        //Not a READ-type cmd, so generate a bus timeout.
          SMBCON = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);                //disable int, and DON'T clear the TWINT flag!
                  ESMB = 0;
          TWISR_state = TW_IDLE;                //Reset the state machine.
          break;//return;
        }
        SMBCON = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
                ESMB = 0;
        break;//return;       
        */
      }
      else  //some type of error!
      {
        SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
        TWI_CmdFlags = SMB_GenBusTimeout;        //Generate a bus timeout.
        SMBCON = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);                //disable int, and DON'T clear the TWINT flag!
        TWISR_state = TW_IDLE;                        //Reset the state machine.
        break;//return;
      }
      break;

使用特权

评论回复
板凳
badbud|  楼主 | 2015-9-9 16:06 | 只看该作者
   case TW_Wait4Data:        //We are in Slave Receive operating mode.
      if(TWS_RDATA == Status)                        //received a data byte
      {
        if(--TW_RxBufCnt < -1)                        //Are we past the PEC byte and still getting more data?
        {
          SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_BadSize;        //throw away the data & flag error
          TWI_CmdFlags = SMB_GenBusTimeout;        //Generate a bus timeout.
          SMBCON =  (1<<TWINT) | (1<<TWEA) | (1<<TWEN);                //disable int, and DON'T clear the TWINT flag!
          TWISR_state = TW_IDLE;                        //Reset the state machine.
          break;//return;
        }
        TW_RxBuf[TW_RxBufIndex++] = SMBDAT;        //store the byte
      }

      else
      if(TWS_RSTOP == Status)                        //got a STOP; all done RXing data now.
      { //Note: if we get a STOP prematurely, then we simply ignore the command,
              //  since it is too late to inform the Master of the error.
              if((TW_RxBufCnt > 0) || (TW_RxBufCnt < -1))        //We got a premature STOP or too much data; ERROR!
              {
          SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_BadSize;        //throw away the data.
        }
        else
        {
          if(0 == TW_RxBufCnt)
            UsePEC = 0;                                //there is no PEC coming for this packet.
          else
          if(-1 == TW_RxBufCnt)
            UsePEC = 1;                                //PEC was included.

          TW_RxBufCnt = TW_RxBufIndex;                //re-use the Write Index's value as the Valid Byte Count.
          TW_RxBufIndex = 0;                        //clear the index in preparation for interpreting it.
          TWI_CmdFlags = SMB_GotCmdData;        //tell Foreground to process this now.
          //Note that when (TWI_CmdFlags == SMB_GotCmdData), TWI ISR will respond with BUSY condition.

        }
        TWISR_state = TW_IDLE;                //Reset the state machine in all cases.
      }

      else  //some type of error during transmission!
      {
        SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;
        TWI_CmdFlags = SMB_GenBusTimeout;        //Not a WRITE-type cmd, so generate a bus timeout.
        SMBCON = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);                //disable int, and DON'T clear the TWINT flag!
        TWISR_state = TW_IDLE;                        //Reset the state machine.
        break;//return;
      }
      SMBCON = (1<<TWEA) | (1<<TWEN);        //enable ACKing
      break;


    case TW_ReplyData:
      if((TWS_SLA_R == Status) || (TWS_RACK == Status))        //send out Reply data
      {       
      /*
        SMBDAT = TW_TxBuf[TW_TxBufIndex++];        //send data out
        if(--TW_TxBufCnt == 0)                        //Have we emptied the buffer, incl. PEC?
          SMBCON = (1<<TWEN);                // Yes, so don't set TWEA.
        else
          SMBCON = (1<<TWEA) | (1<<TWEN);        // No, so assert TWEA.
                ESMB = 1;
        */
        if(TW_TxBufCnt == 1)
        {
             SMBDAT = crc;
         }else{
            if(((CurrentCmd>=0x20)&&(CurrentCmd<=0x23))||(CurrentCmd==0x30))
                        FillResponseStr();
           crc = FastCRC(crc, TW_TxBuf[TW_TxBufIndex]);
           SMBDAT = TW_TxBuf[TW_TxBufIndex++];        //send data out
           TW_TxBufCnt--;
         }
          SMBCON = (1<<TWEA) | (1<<TWEN);        // No, so assert TWEA.
      }
      else
      if(TWS_RNAK == Status)        //We may have gotten this validly or as an Error.
      {
        //if(TW_TxBufCnt == 1)        //Not an error. Master didn't want PEC; clear UsePEC flag!
        //{
          TW_TxBufCnt = 0;        //clear the buffer too.
          UsePEC = 0;
        //}
        //else
        //if(TW_TxBufCnt == 0)        //Not an error. Master wanted PEC (and got it); assert UsePEC.
         // UsePEC = 1;
        //else                        //some kind of error occurred; we got NAK too early!
       // { //Note: the TWI module is now OFF-LINE, so we can't inform Host of this error!!
       //   SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;        //flag it later
        //}
        SMBCON = (1<<TWEA) | (1<<TWEN);
      }
      else
//    if(TWS_FINAL == Status)        //ERROR: we got an ACK but we have no more data!
      { //Since the TWI module is now in "Not Addressed Slave" mode, we can't flag the error
              // back to the Master DURING this transaction; we WILL assert an error status though.
        //SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_BadSize;
        TWISR_state = TW_IDLE;        //Reset the state machine.
        SMBCON = (1<<TWEA) | (1<<TWEN);
      }
      break;



    //MASTER-mode states follow.
   /*
    case TW_MSLA_W:        //we just tried to send the SLAVE ADDRESS in Master Mode.
      if(TWS_WRITE_ACK == Status)         // we got an ACK back from the desired SLA+W transmission
      {
        SMBDAT = TW_MTxBuf[TW_MTxBufIndex++];        //send out Cmd
        TWISR_state = TW_MCMD_W;
        SMBCON = TWCR&0x75;                                      //clear TOUT,SI,TFREE flag
        SMBCON = (1<<TWEA) | (1<<TWEN);
                ESMB = 1;
      }
      else  //anything else is Unexpected or an Error result.
      { //We simply delete msgs that couldn't be sent as they will be resent in 10secs anyway.
        SMBCON = (1<<TWEA) | (1<<TWSTO) | (1<<TWEN);
                ESMB = 1;
        TWISR_state = TW_IDLE;        //Reset the state machine.
        TW_MTxBufCnt = 0;
        TW_MTxBufIndex = 0;
        TXmsgDelete;                  //Delete this just-sent msg from the TX buffer.
        SMLOCK = 0;
      }
      break;

    case TW_MCMD_W:        //we just sent a Master COMMAND byte or a Data byte
      if(TWS_TXDATA_ACK == Status)         // we got an ACK from data we sent.
      {
        if(TW_MTxBufCnt > TW_MTxBufIndex)
        {
          SMBDAT = TW_MTxBuf[TW_MTxBufIndex++];        //send out Data byte
          TWISR_state = TW_MCMD_W;
          SMBCON =  (1<<TWEA) | (1<<TWEN);
                  ESMB = 1;
        }
        else  //we've sent everything in the buffer, so send STOP now.
        {
          SMBCON = (1<<TWEA) | (1<<TWSTO) | (1<<TWEN);
                  ESMB = 1;
          TWISR_state = TW_IDLE;
          TW_MTxBufCnt = 0;
          TW_MTxBufIndex = 0;
          TXmsgDelete;                  //Delete this just-sent msg from the TX buffer.
          SMLOCK = 0;
        }
      }
      else  //Unexpected or Error response.
      {
          SMBCON =  (1<<TWEA) | (1<<TWSTO) | (1<<TWEN);
                  ESMB = 1;
          TWISR_state = TW_IDLE;
          TW_MTxBufCnt = 0;
          TW_MTxBufIndex = 0;
          TXmsgDelete;                  //Delete this just-sent msg from the TX buffer.
          SMLOCK = 0;
      }
      break;
      */
  } // end of switch(TWISR_state)
  EA = 1;
}

使用特权

评论回复
地板
badbud|  楼主 | 2015-9-9 16:10 | 只看该作者
void SMB_CmdInterpreter(void)
{
  unsigned char xdata temp;

  if(SMB_GenBusTimeout == TWI_CmdFlags)        //The ISR detected an error condition.
  {
    TWI_CmdFlags = 0;                        //clear the flag that brought us here.
    //start the 26mS timer.  When it is done, the Timer handler will re-init the TWI peripheral.
    //SetGenericTimer(SMBfaultTimer, 26);
    SMB_RestoreBus();
    return;
  }/*
  else
  if(SMB_SetUpReply == TWI_CmdFlags)        //interpret a 'Read' Command.
  {
    TWI_CmdFlags = 0;                        //clear the flag that brought us here.
    TW_TxBufIndex = 0;                        //initialize
    TW_TxBufCnt = 0;                        //initialize
    if(0 != SMB_ReadCmd[CurrentCmd]())        //After interpreting, was there an error??
    {
      SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnsuptdCommand;
      SetGenericTimer(SMBfaultTimer, 26); //generate a bus timeout error.
      TW_TxBufIndex = 0;                  //Wipe out anything in the buffer, just in case.
      TW_TxBufCnt = 0;                       
      return;
    }
    else //generate PEC now for the *entire* transaction, including the original request!
    {
      //Assume (TW_TxBufIndex == 0) and (TW_TxBufCtr == # of bytes of data, not incl PEC).
      temp = FastCRC(0, (SMBADR & 0xFE));        //use the SLA+W address
      temp = FastCRC(temp, CurrentCmd);
      temp = FastCRC(temp, (SMBADR | 1));        //use the SLA+R address

      do {temp = FastCRC(temp, TW_TxBuf[TW_TxBufIndex++]);}
      while(TW_TxBufIndex != TW_TxBufCnt);

      TW_TxBuf[TW_TxBufIndex] = temp;        //append the CRC value on the end.
      TW_TxBufCnt++;                        //increase the byte count for the PEC.
      TW_TxBufIndex = 0;                //Reset the buffer pointer.
      SMBCON = TWCR&0x75;                                      //clear TOUT,SI,TFREE flag
      SMBCON = (1<<TWEA) | (1<<TWEN);        //have TWI continue from where it stalled.
          ESMB = 1;
    }
    return;
  }*/
  else
  if(SMB_GotCmdData == TWI_CmdFlags)        //process some received command+data.
  {
    //NOTE: as of 6/17/2005, TWI_CmdFlags should NOT be cleared until we are
    // completely done processing this message, else the TWI ISR will overwrite
    // the RX buffer and won't respond with BUSY as it should.  Note also that
    // the TWI is fully re-enabled when entering here, so we MUST NOT write
    // to any of the TWI h/w registers or we could create havoc.  -rgf

    if(UsePEC)                                //check the CRC of the received packet.
    {
      temp = 0;                                //use this as our CRC value.

      do { temp = FastCRC(temp, TW_RxBuf[TW_RxBufIndex++]); }
      while(TW_RxBufCnt != TW_RxBufIndex);

      if(temp)        //The result of a CRC check SHOULD be =0 if all was ok.
      {
              SMBvariables[SMBV_BattStatus][lobyte] |= SMBerr_UnknownError;

              //start the 26mS timer to generate a bus timeout error.
              SetGenericTimer(SMBfaultTimer, 26);
        TWI_CmdFlags = 0;                //clear the flag that brought us here.
        return;
      }

    }

    //The rcvd message is valid enough to warrant calling the command's handler now.


    //Note that none of the regular SMBus commands use Block Mode to send info
    // *TO* the Smart Battery, so TW_RxBuf[2] will NEVER be a byte count, but
    // will always be DATA.  For OptionalMfgFunction(5), the associated command
    // function itself is aware that [2] is the byte count and that the actual
    // data starts at offset=[3].
    TW_RxBufIndex = 2;                        //point to the first byte of Received Data.


    if(0 != SMB_WriteCmd[CurrentCmd]())        //After interpreting, was there an error??
    {
      TW_RxBufIndex = 0;                //Wipe out anything in the buffer, just in case.
      TW_RxBufCnt = 0;                       

      //start the 26mS timer to generate a bus timeout error.
      SetGenericTimer(SMBfaultTimer, 26);
      TWI_CmdFlags = 0;                        //clear the flag that brought us here.
      return;
    }
    //At this point it looks like everything went OK.
    TWI_CmdFlags = 0;                        //clear the flag that brought us here.
    //return;
    TWISR_state = TW_IDLE;        //Reset the state machine.
    SMBCON = SMBCON&0x75;   //clear TOUT,SI,TFREE flag
    SMBCON |= (1<<TWEA) | (1<<TWEN);
    ESMB = 1;
  }
}


//This function restores the SMBus & the TWI_ISR state machine to normal after
//  we have deliberately generated a bus timeout error (in order to tell the
//  Master that something was wrong with his last command).
void SMB_RestoreBus(void)
{
  SMBCON = 0;                        //shut down the peripheral
  SMBSTA = 0x04;                        //  65k  tout on  low level  detect//
  SMBADR = BATTERY_ADDR;                        //  disenable general call , address 0001011 //
  TWISR_state = TW_IDLE;        //force an init of the state machine                       
  SMBCON =  (1<<TWEA) | (1<<TWEN);        // | (1<<TWSTO)  re-enable
  ESMB = 1;

  //Note that we must be careful not to generate some kind of bus error
  // as a result of waking back up, or we will get into an endless loop
  // by generating another bus timeout if the IDLE state doesn't like
  // something it sees when it comes back to life.
}





/* *************************************************************************
*
*   Individual handlers for SMBus READ-type commands.
*
*   When any of these functions is called, the SMBus is in a halted state,
*   pending the completion of the called function.  If an error is detected
*   while processing any of these, a bus timeout error will have to be
*   generated to inform the Master that there was a problem.  Otherwise,
*   if everything is OK, the data that is being requested by the Master
*   must be set up in the TW_TxBuf buffer for transmission to the Master.
*   The functions below do not need to calculate the PEC value, as this
*   will be handled in the function SMB_CmdInterpreter() automatically.
*
*   The valid return values for all functions below are:
*      0: error detected; must generate a bus timeout error.
*      1: requested data is present in the TW_TxBuf buffer.
*
************************************************************************* */




void FillResponseInt(unsigned int info)
{
  TW_TxBuf[0] = (unsigned char) info;
  TW_TxBuf[1] = (unsigned char) (info >> 8);
  TW_TxBufIndex = 0;
  TW_TxBufCnt = 2;
}

/*
//void FillResponseStr(char  __flash * source)
{
  unsigned char xdata * dest = TW_TxBuf;
  unsigned char xdata ctr = 0;

  for(;;)
  {
    if(*dest++ = *source++)
      ctr++;
    else
      break;
  }

  TW_TxBufIndex = 0;
  TW_TxBufCnt = ctr;
}
*/
void FillResponseStrLen(unsigned char  * source)
{
  unsigned char * dest = TW_TxBuf;
  RStrptr = source;
  TW_TxBufCnt = (*source)+1;
   *dest = *source;
  TW_TxBufIndex = 0;

}
void FillResponseStr(void)
{
  unsigned char * dest = TW_TxBuf;

  *(dest+TW_TxBufIndex) = *(RStrptr+TW_TxBufIndex) ;
}
/*
void FillWriteStr(unsigned char  * source)
{
  unsigned char * dest = &TW_RxBuf[2];
  unsigned char ctr = 0;
  unsigned char size =32;
  unsigned char j=0;
  ///  *(dest++);
  ///  *(dest++);

  for(j=0;j<size+1;j++)
  {
         if(j==0)
         {
                  ctr = *dest;
                  size = ctr;
         }
         *(source+j) = *(dest+j) ;
  }
}
*/

/* ************************************************** */

unsigned char SMBR_MfrAccess(void)  // Cmd # 0x00
{
  FillResponseInt(SMBvar_int[SMBV_MfrAccess]);
  return 0;
}



unsigned char SMBR_RemCapAlm(void)  // 0x01
{
  FillResponseInt(SMBvar_int[SMBV_RemCapAlm]);
  return 0;
}


unsigned char SMBR_RemTimeAlm(void)  // 0x02
{
  FillResponseInt(SMBvar_int[SMBV_RemTimeAlm]);
  return 0;
}


unsigned char SMBR_BattMode(void)  // 0x03
{
  FillResponseInt(SMBvar_int[SMBV_BattMode]);
  return 0;
}


unsigned char SMBR_AtRate(void)  // 0x04
{
  FillResponseInt(SMBvar_int[SMBV_AtRate]);
  return 0;
}


unsigned char SMBR_AtRateTTF(void)  // 0x05
{
  unsigned int temp = AtRateTTF();
  SMBvar_int[SMBV_AtRateTTF] = temp;        //save local copy of result for DEBUG PURPOSES ONLY
  FillResponseInt(temp);
  return 0;
}


unsigned char SMBR_AtRateTTE(void)  // 0x06
{
  unsigned int temp = AtRateTTE();
  SMBvar_int[SMBV_AtRateTTE] = temp;
  FillResponseInt(temp);
  return 0;
}


unsigned char SMBR_AtRateOK(void)  // 0x07
{
  unsigned int temp = AtRateOK();
  SMBvar_int[SMBV_AtRateOK] = temp;
  FillResponseInt(temp);
  return 0;
}


unsigned char SMBR_Temperature(void)          // 0x08
{
  unsigned int temp = GetTemperature();
  SMBvar_int[SMBV_Temperature] = temp;
  FillResponseInt(SMBvar_int[SMBV_Temperature]);
  return 0;
}


unsigned char SMBR_Voltage(void)  // 0x09
{
  unsigned int volt = GetVoltage();
  SMBvar_int[SMBV_Voltage] = volt;
  FillResponseInt(SMBvar_int[SMBV_Voltage]);
  return 0;
}


unsigned char SMBR_Current(void)  // 0x0a
{
  signed int current = Current1Sec();

  SMBvar_int[SMBV_Current] = (unsigned int) current;
  FillResponseInt((unsigned int) current);
  return 0;
}


unsigned char SMBR_AvgCurrent(void)  // 0x0b
{
  //signed int current = CCarray_Average();
  //SMBvar_int[SMBV_AvgCurrent] = (unsigned int) current;
  FillResponseInt(SMBvar_int[SMBV_AvgCurrent]);
  return 0;
}


unsigned char SMBR_MaxError(void)  // 0x0C
{
  FillResponseInt(SMBvar_int[SMBV_MaxError] = 0);
  return 0;
}


unsigned char SMBR_RelSOC(void)  // 0x0d
{
// unsigned int temp = RelativeSOC();

  //SMBvar_int[SMBV_RelSOC] = temp;
  FillResponseInt(SMBvar_int[SMBV_RelSOC]);
  return 0;
}


unsigned char SMBR_AbsSOC(void)  // 0x0e
{
  //unsigned int temp = AbsoluteSOC();
  //SMBvar_int[SMBV_AbsSOC] = temp;
  FillResponseInt(SMBvar_int[SMBV_AbsSOC]);
  return 0;
}


unsigned char SMBR_RemCap(void)  //0x0f
{
  //unsigned int cap = RemainingCap();
  FillResponseInt(SMBvar_int[SMBV_RemCap]);
  //SMBvar_int[SMBV_RemCap] = cap;
  return 0;
}


unsigned char SMBR_FullChgCap(void)        // 0x10
{
  //unsigned int cap = FullChgCap();
  FillResponseInt(SMBvar_int[SMBV_FullChgCap]);
  //SMBvar_int[SMBV_FullChgCap] = cap;
  return 0;
}


unsigned char SMBR_RunTTE(void)  // 0x11
{
  //unsigned int temp = TimeToEmpty(0);
  FillResponseInt(SMBvar_int[SMBV_RunTTE]);
  //SMBvar_int[SMBV_RunTTE] = temp;
  return 0;
}


unsigned char SMBR_AvgTTE(void)  // 0x12
{
  //unsigned int temp = TimeToEmpty(1);
  FillResponseInt(SMBvar_int[SMBV_AvgTTE]);
  //SMBvar_int[SMBV_AvgTTE] = temp;
  return 0;
}


unsigned char SMBR_AvgTTF(void)  // 0x13
{
  //unsigned int temp = AvgTimeToFull();
  FillResponseInt(SMBvar_int[SMBV_AvgTTF]);
  //SMBvar_int[SMBV_AvgTTF] = temp;
  return 0;
}



//////////////////////////////////////////////////////////

// These two messages are sent from either a Charger or a Host
unsigned char SMBR_ChgCurrent(void)        // 0x14
{
  unsigned int temp=0;
  SV.SMBint[SMBV_BattStatus] &= 0xFFF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
  if(!(SMBvariables[SMBV_PackStackWidth] [lobyte] & FULLY_CHARGED) &&
      !(SMBvariables[SMBV_PackStackWidth] [hibyte] & TERMINATE_CHARGE_ALARM) &&
      !(SMBvariables[SMBV_PackStackWidth] [hibyte] & OVER_CHARGED_ALARM)) { // it is OK to charge?
       temp = SMBvar_int[SMBV_ChgCurrent];
   }
  FillResponseInt(temp);//Pack_CCCV_CPack_CCCV_C
  return 0;
}


unsigned char SMBR_ChgVoltage(void)  // 0x15
{
  unsigned int temp=0;
  SV.SMBint[SMBV_BattStatus] &= 0xFFF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
  if(!(SMBvariables[SMBV_PackStackWidth] [lobyte]  & FULLY_CHARGED) &&
      !(SMBvariables[SMBV_PackStackWidth] [hibyte]& TERMINATE_CHARGE_ALARM) &&
      !(SMBvariables[SMBV_PackStackWidth] [hibyte] & OVER_CHARGED_ALARM)) { // it is OK to charge?

       temp = SMBvar_int[SMBV_ChgVoltage];
  }
  FillResponseInt(temp);
  return 0;
}


/////////////////////////////////////////////////////////


unsigned char SMBR_BattStatus(void)        // 0x16
{
  FillResponseInt(SMBvar_int[SMBV_BattStatus]);
  SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;
  return 0;
}


unsigned char SMBR_CycleCount(void)        // 0x17
{
  FillResponseInt(SMBvar_int[SMBV_CycleCount]);
  return 0;
}


unsigned char SMBR_DesignCap(void)        // 0x18
{
  unsigned long temp = SV.SMBint[SMBV_DesignCap];

  if(SV.SMBint[SMBV_BattMode] & CAPACITY_MODE)        //use mW in calculations
    temp = (temp*SV.SMBint[SMBV_DesignVolt])/10000;

  FillResponseInt(temp);
  //SMBvar_int[SMBV_DesignCap] = (unsigned int)temp;
  return 0;
}


unsigned char SMBR_DesignVolt(void)        // 0x19
{
  FillResponseInt(SMBvar_int[SMBV_DesignVolt] );
  return 0;
}


unsigned char SMBR_SpecInfo(void)        // 26
{
  FillResponseInt(SMBvar_int[SMBV_SpecInfo]);        //! \todo  this value is filled in as const by init.
  return 0;
}


unsigned char SMBR_MfrDate(void)        // 27
{
  FillResponseInt(SMBvar_int[SMBV_MfrDate]);        //! \todo  this value is filled in as const by init.
  return 0;
}


unsigned char SMBR_SerialNo(void)        // 28
{
  FillResponseInt(SMBvar_int[SMBV_SerialNo]);        //! \todo  this value is filled in as const by init.
  return 0;

}

unsigned char SMBR_PackStackWidth(void)        // 29
{
  FillResponseInt(SMBvar_int[SMBV_PackStackWidth]);        //! \todo  this value is filled in as const by init.
  return 0;
}


unsigned char SMBR_MfrName(void)        //   Cmd # 0x20
{
  FillResponseStrLen(str_MfrName);                        //! \todo  Modify as needed. __flash char defined in smbus.h
  return 0;
}



unsigned char SMBR_DeviceName(void)        //Cmd # 0x21
{
  FillResponseStrLen(str_DeviceName);                        //! \todo  Modify as needed. __flash char defined in smbus.h
  return 0;
}


unsigned char SMBR_DeviceChem(void)        //Cmd # 0x22
{          
  FillResponseStrLen(str_DeviceChem);                //! \todo  Modify as needed. __flash char defined in smbus.h
  return 0;
}


unsigned char SMBR_MfrData(void)        // Cmd # 0x23
{
  FillResponseStrLen(str_MfrData);                        //! \todo  Modify as needed. __flash char defined in smbus.h
  return 0;
}


unsigned char SMBR_0x2e(void)        //   Cmd # 0x26
{
  //! \todo  Modify as needed. __flash char defined in smbus.h str_MfrName
  TW_TxBuf[0] = 3;
  TW_TxBuf[1] = (unsigned char) (Flash_Addr >> 8);
  TW_TxBuf[2] = (unsigned char) Flash_Addr;
  TW_TxBuf[3] = (unsigned char) Flash_Cnt;
  TW_TxBufIndex = 0;
  TW_TxBufCnt = 4;
  return 0;
}


unsigned char SMBR_Opt5(void)                // 0x2F
{
  //FillResponseInt(12345);                        //! \todo  this value is defined as a constant here.

  unsigned char * dest = TW_TxBuf;
  unsigned char j=0;
  *dest = Flash_Cnt;
  for(j=0;j<Flash_Cnt;j++)
  {
         *(dest+j+1) = Flash_Read(Flash_Addr+j);
  }
  TW_TxBufIndex = 0;
  TW_TxBufCnt = Flash_Cnt+1;
  return 0;
//  return SMBerr_ReservedCommand;
}


unsigned char SMBR_0x30(void)                // Cmd # 0x30
{
  FillResponseStrLen(str_DeviceR30);                        //! \todo  Modify as needed. __flash char defined in smbus.h
  return 0;
}


unsigned char SMBR_Opt4(void)                // 0x3C (serves as Calibration control)
{
  //FillResponseInt( calibration_state ); // Prepare current state in TX buf.
  unsigned int volt = ReadCell(4);
  FillResponseInt(volt);
  return 0; // Return "OK, there are data to transmitted".

}


unsigned char SMBR_Opt3(void)                // 0x3D
{
  unsigned int volt = ReadCell(3);
  FillResponseInt(volt);
  return 0;
}


unsigned char SMBR_Opt2(void)                // 0x3E
{
  unsigned int volt = ReadCell(2);
  FillResponseInt(volt);
  return 0;
}


unsigned char SMBR_Opt1(void)                // 0x3F
{
  unsigned int volt = ReadCell(1);
  FillResponseInt(volt);
  return 0;
}



unsigned char SMBR_invalid(void)        //This should never execute, if error is caught early!
{
  FillResponseInt(0xffff);
  return 0;
  //return SMBerr_UnsuptdCommand;
}



//typedef unsigned char (*ptr2funcUC_V)(void);

//Table of pointers to functions, indexed from the received SMBus Command byte.

ptr2funcUC_V SMB_ReadCmd[HIGHEST_SMB_CMD+1] =
{
  SMBR_MfrAccess,        //  0
  SMBR_RemCapAlm,        //  1
  SMBR_RemTimeAlm,        //  2
  SMBR_BattMode,          //  3
  SMBR_AtRate,             //  4
  SMBR_AtRateTTF,          //  5
  SMBR_AtRateTTE,          //  6
  SMBR_AtRateOK,           //  7
  SMBR_Temperature,        //  8
  SMBR_Voltage,            //  9
  SMBR_Current,            // 10
  SMBR_AvgCurrent,         // 11
  SMBR_MaxError,           // 12
  SMBR_RelSOC,             // 13
  SMBR_AbsSOC,             // 14
  SMBR_RemCap,             // 15
  SMBR_FullChgCap,         // 16
  SMBR_RunTTE,             // 17
  SMBR_AvgTTE,             // 18
  SMBR_AvgTTF,             // 19
  SMBR_ChgCurrent,         // 20
  SMBR_ChgVoltage,         // 21
  SMBR_BattStatus,         // 22
  SMBR_CycleCount,         // 23
  SMBR_DesignCap,          // 24
  SMBR_DesignVolt,         // 25
  SMBR_SpecInfo,           // 26
  SMBR_MfrDate,            // 27
  SMBR_SerialNo,           // 28
  SMBR_PackStackWidth,  //29
  SMBR_invalid,
  SMBR_invalid,
  SMBR_MfrName,            // 32
  SMBR_DeviceName,         // 33
  SMBR_DeviceChem,         // 34
  SMBR_MfrData,            // 35
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_0x2e,
  SMBR_Opt5,               // 0x2F
  SMBR_0x30,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_invalid,
  SMBR_Opt4,               // 0x3C
  SMBR_Opt3,               // 0x3D
  SMBR_Opt2,               // 0x3E
  SMBR_Opt1               // 0x3F
};




使用特权

评论回复
5
badbud|  楼主 | 2015-9-9 16:11 | 只看该作者
/* *************************************************************************
*
*   Individual handlers for SMBus WRITE-type commands
*
************************************************************************* */


unsigned char SMBW_MfrAccess(void)        //  0
{
  unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
  SMBvar_int[SMBV_MfrAccess] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
  SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
  return 0;
}


unsigned char SMBW_RemCapAlm(void)        //  1
{
  unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
  SMBvar_int[SMBV_RemCapAlm] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
  SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
  return 0;
}


unsigned char SMBW_RemTimeAlm(void)        //  2
{
  unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
  SMBvar_int[SMBV_RemTimeAlm] = temp | (TW_RxBuf[TW_RxBufIndex]<<8);
  SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
  return 0;
}


unsigned char SMBW_BattMode(void)          //  3
{
  unsigned char tempH = TW_RxBuf[TW_RxBufIndex+1];
  unsigned char tempL;

  tempL = SMBvariables[SMBV_BattMode][lobyte] & 0xF0;

  if(tempH & 0x1C)
    return SMBerr_AccessDenied;                //attempt to write to reserved bits!


  if(~(tempL & INTERNAL_CHARGE_CONTROLLER))
  {
    tempH &= ~CHARGE_CONTROLLER_ENABLED;  //feature not present, don't let it get turned on.
  }


  if(tempH & PRIMARY_BATTERY)
  {
    ;        //let the Host do what it wants with this flag; we ignore it.
  }

  //if(tempH & ALARM_MODE)
  //  SetAlarmMode;        //this DISABLES sending alarm msgs for 60 secs


  if(tempH & CHARGER_MODE)
  {
    ;        //Allow Host to enable us to send Master-mode Charger-Voltage/Current msgs to the Charger
  }


  if(tempH & CAPACITY_MODE)
  {
    ;        //Host must be allowed to control this bit (report in mAH or 10mWH)
  }


  SMBvar_int[SMBV_BattMode] = tempL | (tempH<<8);        //write the modified bits.

  return 0;
}



unsigned char SMBW_AtRate(void)             //  4
{
  unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
  SMBvar_int[SMBV_AtRate] = temp | (TW_RxBuf[TW_RxBufIndex++]<<8);
  SMBvariables[SMBV_BattStatus][lobyte] &= 0xF0;  //since this cmd is OK, clear Error bits per sbdat110, 4.3.2
  return 0;
}

unsigned char SMBW_CalibV(void)               // 0x1E
{

// unsigned char temp = TW_RxBuf[TW_RxBufIndex++];
  //unsigned int tempI = temp|(TW_RxBuf[TW_RxBufIndex] << 8);  

  return 0; // Return OK.
}

unsigned char SMBW_CalibC(void)               // 0x1F
{
  //unsigned int temp = TW_RxBuf[TW_RxBufIndex++];
  //temp = (signed int)(temp | (TW_RxBuf[TW_RxBufIndex]<<8));
  //__disable_interrupt();
  //CalibrateCCoffset_1A((signed int)temp);
  //__enable_interrupt();
  return 0;
}

unsigned char SMBW_Opt6(void)               // 0x2e  3 addrh addrl optlen
{  
  unsigned int temp = TW_RxBuf[3];
  if(UsePEC == 0)
          return(1);
   Flash_Addr = (temp<<8)|(unsigned int)TW_RxBuf[4];
  if(TW_RxBuf[2] == 3)
  {
     Flash_Cnt = TW_RxBuf[5];  
     if((TW_RxBuf[5] == 0xff)&&(Flash_Addr>0x5fff)) // 12 ~ 15 扇区
     {
        EA = 0;
         FlashErase(Flash_Addr);  //0x0000 ~ 0x7fff   
         EA = 1;
     }
  }
  //FillWriteStr(&SMBstring[0][0]);
  return 0;
}

unsigned char SMBW_Opt5(void)               // 0x2F
{
  unsigned char j=0;
  //__disable_interrupt();
  if(UsePEC == 0)
          return(1);
  EA = 0;
  //MCUSR = 0x1F;                         //clear all reset sources before jumping to bootloader code.
//  __watchdog_reset;                                        //

  //asm("jmp 0x9000");                                        // Byte adress

//  __watchdog_reset;                                                // reset watchdog


  for(j=0;j<TW_RxBuf[2];j++)
  {
        Flash_Write((Flash_Addr + j), TW_RxBuf[3+j]);
  }
  EA = 1;
  return(0);                                                        // to avoid compiler warning, should never be reached

//  return SMBerr_ReservedCommand; // <-- Compiler generates warning if return statement is missing.
}

unsigned char SMBW_Opt4(void)               // 0x3C
{
  //calibration_state_req = TW_RxBuf[TW_RxBufIndex++];
  //calibration_state_req |= (unsigned int)TW_RxBuf[TW_RxBufIndex++] << 8; // Store request details.
  SetCalibRequest; // Set action flag so that main loop starts calibrating.
  return 0; // Return OK.
}


unsigned char SMBW_Opt3(void)               // 0x3D
{
  return SMBerr_ReservedCommand;
}

unsigned char SMBW_Opt2(void)               // 0x3E
{
  return SMBerr_ReservedCommand;
}

unsigned char SMBW_Opt1(void)               // 0x3F
{
  return SMBerr_ReservedCommand;
}

unsigned char SMBW_Invalid(void)        //This should never execute, if error is caught early!
{
  return SMBerr_AccessDenied;
}


//Table of pointers to functions, indexed from the received SMBus Command byte.
ptr2funcUC_V SMB_WriteCmd[HIGHEST_SMB_CMD+1] =
{
  SMBW_MfrAccess,        //  0
  SMBW_RemCapAlm,        //  1
  SMBW_RemTimeAlm,        //  2
  SMBW_BattMode,          //  3
  SMBW_AtRate,             //  4
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,                //0x0F

  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,                //0x1F

  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Opt6,
  SMBW_Opt5,               // 0x2F

  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Invalid,
  SMBW_Opt4,               // 0x3C
  SMBW_Opt3,               // 0x3D
  SMBW_Opt2,               // 0x3E
  SMBW_Opt1               // 0x3F
};

/* *************************************************************************
*
*   Utilities for SMBus commmunications
*
************************************************************************* */
code const unsigned char crctable[16] =  {0,0x07,0x0E,0x09, 0x1c,0x1b,0x12,0x15, 0x38,0x3F,0x36,0x31, 0x24,0x23,0x2A,0x2D};
code const unsigned char crctable2[16] =  {0,0x70,0xE0,0x90, 0xC1,0xB1,0x21,0x51, 0x83,0xF3,0x63,0x13, 0x42,0x32,0xA2,0xD2};
unsigned char FastCRC(unsigned char LastCRC, unsigned char newbyte)
{
  unsigned char idata index;

  index = newbyte;
  index ^= LastCRC;
  index >>= 4;
  LastCRC &= 0x0F;
  LastCRC ^= crctable2[index];

  index = LastCRC;
  index ^= newbyte;
  index &= 0x0F;
  LastCRC &= 0xF0;
  LastCRC ^= crctable[index];

  return(LastCRC);
}
void SMBvariablesFlash(void)
{
  unsigned char index;
  unsigned char wbuffer[2];
  unsigned char flag;

  flag =1;
  while(flag)
  {
    if(1 == flag)
    {
      FlashErase(0x7000);  //0x0000 ~ 0x7fff   
      flag = 2;
      //delay();
    }
    Flash_Write((SMB_DataFlashAddr + index*2), SMBvariables[index][hibyte]);
    Flash_Write((SMB_DataFlashAddr + 1 + index*2), SMBvariables[index][lobyte]);
    wbuffer[hibyte] = Flash_Read(SMB_DataFlashAddr + index*2); //扇区14
    wbuffer[lobyte] = Flash_Read(SMB_DataFlashAddr + 1 + index*2); //扇区14
    if((SMBvariables[index][hibyte] != wbuffer[hibyte])||(SMBvariables[index][lobyte] != wbuffer[lobyte]))
    {
      flag = 1;
      index = 0;
      continue;
    }
    if(index > SMBV_SerialNo)
      break;
    //if()


  }


}

//! \todo  This can be modified to load defaults from EEPROM rather than fixed values to the SMB variables.
// This sets power-up defaults.
void InitSMBvariables(void)
{
  unsigned char i;

  for(i=0; i<0x20; i++)
  {
    SMBvariables[i][hibyte] = Flash_Read(SMB_DataFlashAddr + i*2); //扇区14
    SMBvariables[i][lobyte] = Flash_Read(SMB_DataFlashAddr + 1 + i*2); //扇区14
  }

  if((SMBvariables[SMBV_PackStackWidth] [hibyte]> 4)||(SMBvariables[SMBV_PackStackWidth][hibyte] < 2))
     SMBvariables[SMBV_PackStackWidth ][hibyte] = 3;        //
  if((SMBvariables[SMBV_PackStackWidth][lobyte] > 5)||(SMBvariables[SMBV_PackStackWidth][lobyte] < 1))
     SMBvariables[SMBV_PackStackWidth ] [lobyte]= 2;        //
  if((SMBvar_int[SMBV_DesignCap] > 10000)||(SMBvar_int[SMBV_DesignCap] < 2000))
     SMBvar_int[SMBV_DesignCap ] = 4400;        //

         
  //SMBvar_int[SMBV_MfrAccess] = 0x4060;
  if((SMBvar_int[SMBV_RemCapAlm] > 1200)||(SMBvar_int[SMBV_RemCapAlm] < 200))
    SMBvar_int[SMBV_RemCapAlm] = (SMBvar_int[SMBV_DesignCap ] / 10);        // per sbdat110, 4.4.1
  if((SMBvar_int[SMBV_RemTimeAlm] > 20)||(SMBvar_int[SMBV_RemTimeAlm] < 3))
      SMBvar_int[SMBV_RemTimeAlm] = 10;
  SMBvar_int[SMBV_BattMode  ] = 0x0000;       
  SMBvar_int[SMBV_AtRate    ] = 0x0000;       
/* For testing with no calcs
  SMBvar_int[SMBV_AtRateTTF ] = 0x0000;        //
  SMBvar_int[SMBV_AtRateTTE ] = 0x0000;        //
  SMBvar_int[SMBV_AtRateOK  ] = 0x0000;        //

  SMBvar_int[SMBV_Temperature] = 0x0000;        //
  SMBvar_int[SMBV_Voltage    ] = 0x0000;        //
  SMBvar_int[SMBV_Current    ] = 0x0000;        //
  SMBvar_int[SMBV_AvgCurrent ] = 0x0000;        //
  SMBvar_int[SMBV_MaxError   ] = 0x0000;        //
  SMBvar_int[SMBV_RelSOC     ] = 0x0000;        //
  SMBvar_int[SMBV_AbsSOC     ] = 0x0000;        //
  SMBvar_int[SMBV_RemCap     ] = 0x0000;        //

  SMBvar_int[SMBV_FullChgCap] = 0x0000;        //
  SMBvar_int[SMBV_RunTTE    ] = 0x0000;        //
  SMBvar_int[SMBV_AvgTTE    ] = 0x0000;        //
  SMBvar_int[SMBV_AvgTTF    ] = 0x0000;        //
  SMBvar_int[SMBV_ChgCurrent] = 0x0000;        //
  SMBvar_int[SMBV_ChgVoltage] = 0x0000;        //
*/
  if((SMBvar_int[SMBV_ChgCurrent] > 6000)||(SMBvar_int[SMBV_ChgCurrent] < 800))
    SMBvar_int[SMBV_ChgCurrent] = CELL_CCCV_C*SMBvariables[SMBV_PackStackWidth][lobyte];       
  if((SMBvar_int[SMBV_ChgVoltage] > 17000)||(SMBvar_int[SMBV_ChgVoltage] < 8000))
    SMBvar_int[SMBV_ChgVoltage] = CELL_CCCV_V*SMBvariables[SMBV_PackStackWidth ][hibyte];       

  SMBvar_int[SMBV_BattStatus] = 0x0080;        //per sbdat110, 4.4.1
  if(SMBvar_int[SMBV_CycleCount] > 300)
    SMBvar_int[SMBV_CycleCount] = 0x0000;        //per sbdat110, 4.4.1

  if((SMBvar_int[SMBV_DesignVolt] > 16800)||(SMBvar_int[SMBV_DesignVolt] < 7000))
    SMBvar_int[SMBV_DesignVolt] = 11100;        //

  if((SMBvar_int[SMBV_SpecInfo] != 0x0021)||(SMBvar_int[SMBV_SpecInfo] != 0x0031))
    SMBvar_int[SMBV_SpecInfo  ] = 0x0031;        // no scaling of I or V; we support PEC, and we're V1.1
  if(SMBvar_int[SMBV_MfrDate] > ((2050-1980)<<9)+(12<<5)+(31))
    SMBvar_int[SMBV_MfrDate   ] = ((2015-1980)<<9)+(8<<5)+(31);        //! \todo Fill in current year, month, day. Values are octal
/* For testing with no calcs
  SMBvar_int[SMBV_SerialNo  ] = 12345;        // arbitrary...
*/

  SMBvar_int[SMBV_Current    ] = 0x0000;        //
  SMBvar_int[SMBV_AvgCurrent ] = 0x0000;        //
  SMBvar_int[SMBV_MaxError   ] = 0x0001;        //
  SMBvar_int[SMBV_RelSOC     ] = 0x0000;        //
  SMBvar_int[SMBV_AbsSOC     ] = 0x0000;        //
  SMBvar_int[SMBV_RemCap     ] = 1000;        //

  if((SMBvar_int[SMBV_FullChgCap] > SMBvar_int[SMBV_DesignCap ]*2)||(SMBvar_int[SMBV_FullChgCap] < SMBvar_int[SMBV_DesignCap ]/2))
    SMBvar_int[SMBV_FullChgCap] = SMBvar_int[SMBV_DesignCap ];


  //Note that for the Block-Read variables, we copy those into a RAM buffer only as needed.
  // These are MfrName, DeviceName, DeviceChem, and MfrData.

  SetMaxTopAcc((long)SMBvar_int[SMBV_DesignCap ]*3600);   //! \todo for testing, initialized value before reaching fully charged, 6600mAh * 10727
  RunningAcc = (long)1000*3600;    //for testing, to start at other point than 0, 1000 * 10727

}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

26

帖子

1

粉丝