bootloader_smbus.c

Go to the documentation of this file.
00001 /* This file has been prepared for Doxygen automatic documentation generation.*/
00040 //#define ENABLE_TESTCODE
00041 
00042 
00043 //#include <pgmspace.h>
00044 #include <inavr.h>
00045 
00046 #define MODULE_BOOTLDR          /* ensure that we instantiate our variables in bootldr.h */
00047 #include "bootldr.h"
00048 //#include "iom406_320.h"
00049 #include "iom406.h"     // IAR headerfile for Mega406 (EW 410)
00050 #include "flash.h"
00051 
00052 
00053 void TWI_handler(void);
00054 void SMB_RestoreBus(void);
00055 unsigned char FastCRC(unsigned char LastCRC, unsigned char newbyte);
00056 void SMB_BusTimeout(void);
00057 void SMB_Reply(void);
00058 void SMB_CmdInterpreter(void);
00059 void LoopMemory(void);
00060 
00061 
00062 //=======================================================================
00063 
00064 //This is used to check for an out-of-bounds SMBus command.
00065 #define HIGHEST_SMB_CMD 0x3F
00066 
00067 
00068 //Two-Wire-Interface TWSR (STATUS) values
00069 //Note that since our Prescale value is 0, we don't need to MASK the Status byte.
00070 
00071 //  Globally applicable TWI status codes:
00072 #define TWS_MASK  0xF8          /* Two-Wire Status Mask */
00073 #define TWS_NSTAT 0xF8          /* No Status Available now */
00074 
00075 //  MASTER-related Status codes:
00076 #define TWS_START 0x08
00077 #define TWS_RESTART 0x10
00078 #define TWS_WRITE_ACK 0x18      /* sent a SLA+W, got ACK */
00079 #define TWS_WRITE_NAK 0x20      /* sent SLA+W, got NAK */
00080 #define TWS_TXDATA_ACK 0x28     /* Data tx'd & was ACK'd */
00081 #define TWS_TXDATA_NAK 0x30     /* Data tx'd & was NAK'd */
00082 #define TWS_LOST_ARB 0x38       /* lost bus arbitration */
00083 
00084 #define TWS_READ_ACK 0x40       /* got ACK from a SLA+R request */
00085 #define TWS_READ_NAK 0x48       /* got NAK from a SLA+R request */
00086 #define TWS_RXDATA_ACK 0x50     /* We rcvd data and ACKd back */
00087 #define TWS_RXDATA_NACK 0x58    /* We rcvd data and we NACKd back */
00088 
00089 
00090 //  SLAVE-related Status codes:
00091 #define TWS_SLA_W 0x60          /* Got SLA + Write */
00092 #define TWS_SLA_R 0xA8          /* Got SLA + Read  */
00093 #define TWS_RDATA 0x80          /* Got a data byte */
00094 #define TWS_RCMD  0x80          /* Got a command byte */
00095 #define TWS_RSTOP 0xA0          /* Got a Stop */
00096 #define TWS_REPEAT 0xA0         /* Got a Repeated-Start */
00097 #define TWS_RACK  0xB8          /* Send a data byte and got an ACK back */
00098 #define TWS_RNAK  0xC0          /* Sent a data byte and got a NAK back */
00099 #define TWS_FINAL 0xC8          /* Sent the final byte, got ACK back */
00100 #define TWS_BERR  0x00          /* Saw a Bus Error */
00101 
00102 
00103 // Two-Wire CONTROL values
00104 
00105 #define TWC_GO 0x85         /* clr TWINT; assert ENA & IntEna */
00106 #define TWC_READ_NoACK 0x85 /* read a byte, but don't ACK when done */
00107 #define TWC_START 0xA5      /* send START bit, assert ENA & IntEna */
00108 #define TWC_STOP 0x94       /* leave INT *DISabled* when done */
00109 #define TWC_RESTART 0xB5    /* send STOP, then START again; INT ena */
00110 
00111 
00112 //=======================================================================
00113 
00114 
00115 unsigned char TW_TxBuf[36];     //must be long enough for any outbound strings
00116 unsigned char TW_TxBufCnt;      //how many valid bytes are in the buffer
00117 unsigned char TW_TxBufIndex;
00118 
00119 unsigned char TW_RxBuf[36];     //must be big enough for inbound programming data
00120 unsigned char TW_RxBufCnt;      // SLA + Cmd + Count + 32bytes + PEC = 36
00121 unsigned char TW_RxBufIndex;
00122 
00123 unsigned char TW_state;         //state variable
00124 unsigned char UsePEC;           //PEC usage is disabled by default.
00125 
00126 unsigned char LoopFlag;         //if we're looping on a slow memory operation
00127 unsigned char BigData;          //flag, if doing multi=packet 'I' command
00128 unsigned char src_i;
00129 unsigned char dest_i;
00130 unsigned char ctr;
00131 unsigned char lomemptr;
00132 unsigned char himemptr;
00133 unsigned char __flash *fptr;
00134 unsigned int eptr;
00135 
00136 unsigned char SRAMbuffer[128];          //this is the size of a Flash page (64 *WORDS*)
00137 
00138 //This byte contains flags from the TWI handler to tell the Foreground code what to do.
00139 //If this byte is ever non-zero, the foreground code will act on its contents.
00140 //Although it is written by both the Handler and the Foreground code, it does not
00141 //  need to be declared VOLATILE because the SMBus is halted until the foreground
00142 //  code finishes processing the associated command and has cleared this flag byte.
00143 unsigned char TWI_CmdFlags;
00144   #define SMB_GenBusTimeout 1   /* Tell Foreground to generate a bus timeout, as we saw an error! */
00145   #define SMB_SetUpReply 2      /* Have Foreground set up TW_TxBuf[]. */
00146   #define SMB_GotCmdData 4      /* Have Foreground interpret the complete received command. */
00147 
00148 
00149 unsigned char Status;           //this is a global variable and is the sole response to a READ using cmd 0x2F.
00150   #define SUCCESS 0
00151   #define BUSY    1
00152   #define BADPARAM 2
00153   #define CRCERROR 3
00154   #define FAILURE  0xFF
00155 
00156 
00157 //=======================================================================
00158 
00159 // Reset Management theory:
00160 //
00161 // To make it easier to enter the bootloader when the OptionalMfgCmd5 command is received
00162 // while running the SMBus interpreter in the application code, we monitor the Reset
00163 // Source flags.  If we arrive here without any flags being asserted, then we can assume
00164 // that we have jumped here from the application, and we can therefore assume that it is
00165 // intended that the bootloader code be run.
00166 // Otherwise, if any reset flag IS asserted when we enter, we check if there is a valid
00167 // vector present at 0x0000; if not, we run the bootloader in order to retrieve a valid
00168 // image, otherwise, we jump down to the application program and run it.
00169 //
00173 
00174 void __low_level_init(void)
00175 {
00176   unsigned char __flash * ptr = 0;
00177 
00178   if(!(MCUSR))    //If no reset source is asserted, we probably came here from the App code deliberately.
00179     return;       //Assume we need to run the BootLoader.
00180 
00181   // Some reset source was asserted. If it was Wdog, there may be a code problem and we
00182   // may need to handle it differently from other reset sources.  If so, add that code here.
00183   if(MCUSR & (1<<WDRF))
00184   {
00186   }
00187 
00188   //Some reset source was asserted, so if Reset vector is FFFF, assume we need to run the bootloader,
00189   // otherwise jump to the application code reset vector at 0x0000 and assume the App code is OK.
00190   if((*ptr++ != 0xFF) || (*ptr != 0xFF))
00191   {
00192     MCUCR &= (1<<IVSEL);
00193     asm("jmp 0");
00194   }
00195 
00196   //At this point, we apparently need to run the Bootloader code, as App section image appears invalid.
00197 }
00198 
00199 
00200 
00201 
00202 void init_boot(void)
00203 {
00204   __disable_interrupt();
00205   TW_TxBufCnt = 0;      //how many valid bytes are in the buffer
00206   TW_TxBufIndex = 0;
00207   TW_RxBufCnt = 0;
00208   TW_RxBufIndex = 0;
00209   TW_state = 0;
00210   UsePEC = 0;
00211   Status = SUCCESS;
00212   LoopFlag = 0;
00213   BigData = 0;
00214 
00215   SMB_RestoreBus();
00216   TWBCSR = (1<<TWBCIF) | (1<<TWBDT1) | (1<<TWBDT0) | (0<<TWBCIP);
00217 }
00218 
00219 
00220 /* ************************************************************* */
00221 /* ************************************************************* */
00222 /* ************************************************************* */
00223 
00224 //The following functions are included to demonstrate how the incoming
00225 // data should be set up for SMBus-based ISP commands.
00226 
00227 #ifdef ENABLE_TESTCODE
00228 
00229 void BOOT_TEST_EF(void)
00230 {
00231   //Test the Flash Page Erase functionality (put junk at 0x0000-0x007F first)
00232   TWI_CmdFlags = SMB_GotCmdData;
00233   TW_RxBuf[TWRX_CMD] = 'E';     //Erase
00234   TW_RxBuf[TWRX_MEM] = 'F';     //flash
00235   TW_RxBuf[TWRX_LOADDR] = 0x80;
00236   TW_RxBuf[TWRX_HIADDR] = 0;
00237   UsePEC = 0;
00238 }
00239 
00240 void BOOT_TEST_EE(void)
00241 {
00242   //Test the EEPROM Erase functionality (put junk at 0x1F0-0x1FF first; should only erase through 0x1F9)
00243   TWI_CmdFlags = SMB_GotCmdData;
00244   TW_RxBuf[TWRX_CMD] = 'E';     //Erase
00245   TW_RxBuf[TWRX_MEM] = 'E';     //EEPROM
00246   TW_RxBuf[TWRX_LOADDR] = 0xF0;
00247   TW_RxBuf[TWRX_HIADDR] = 0x01;
00248   TW_RxBuf[TWRX_SIZE] = 0x0a;   //only do 10 bytes (test non-power-of-2 case)
00249   UsePEC = 0;
00250 }
00251 
00252 void BOOT_TEST_I(void)
00253 {
00254   unsigned char i;
00255   TWI_CmdFlags = SMB_GotCmdData;
00256   TW_RxBuf[TWRX_CMD] = 'I';     //Insert
00257   TW_RxBuf[TWRX_LOADDR] = 0;
00258   TW_RxBuf[TWRX_HIADDR] = 0;
00259   for(i=0; i<16; i++)
00260     TW_RxBuf[TWRX_DATA+i]=i+33; //arbitrary data
00261   TW_RxBuf[TWRX_OFFSET] = 0x33; //insert data into SRAM buffer starting at arbitrary offset 0x33
00262   TW_RxBuf[TWRX_SIZE] = 16;
00263   UsePEC = 0;
00264 }
00265 
00266 void BOOT_TEST_WF(void)
00267 {
00268   unsigned char i;
00269   //Test the Flash Page WRITE functionality (store SRAMbuffer to flash 0x0000-0x007F)
00270   //Fill the buffer before doing WRITE tests.
00271   for(i=0; i<128; i++)
00272     SRAMbuffer[i]=i+33;
00273   TWI_CmdFlags = SMB_GotCmdData;
00274   TW_RxBuf[TWRX_CMD] = 'W';     //Write
00275   TW_RxBuf[TWRX_MEM] = 'F';     //flash
00276   TW_RxBuf[TWRX_LOADDR] = 0x80;
00277   TW_RxBuf[TWRX_HIADDR] = 0;
00278   UsePEC = 0;
00279 }
00280 
00281 void BOOT_TEST_WE(void)
00282 {  //Test the EEPROM WRITE functionality (store small piece of SRAMbuffer to eeprom 0x1F0-0x1FB)
00283   unsigned char i;
00284   //Fill the buffer before doing WRITE tests.
00285   for(i=0; i<128; i++)
00286     SRAMbuffer[i]=i+33;
00287   TWI_CmdFlags = SMB_GotCmdData;
00288   TW_RxBuf[TWRX_CMD] = 'W';     //Write
00289   TW_RxBuf[TWRX_MEM] = 'E';     //EEPROM
00290   TW_RxBuf[TWRX_LOADDR] = 0xF0; //any address is fine...
00291   TW_RxBuf[TWRX_HIADDR] = 0x01;
00292   TW_RxBuf[TWRX_OFFSET] = 0x33; //use an arbitrary block from inside the buffer area
00293   TW_RxBuf[TWRX_SIZE] = 0x0c;
00294   UsePEC = 0;
00295 }
00296 
00297 void BOOT_TEST_PF(void)
00298 {
00299   unsigned char i;
00300   //Verify that we can read back FLASH contents via the PATCH command.
00301   //First, clear SRAMbuffer.
00302   for(i=0; i<128; i++)
00303     SRAMbuffer[i] = 0;
00304   //Next, set up the PATCH command
00305   TWI_CmdFlags = SMB_GotCmdData;
00306   TW_RxBuf[TWRX_CMD] = 'P';     //Patch
00307   TW_RxBuf[TWRX_MEM] = 'F';     //flash
00308   TW_RxBuf[TWRX_LOADDR] = 0x80; //any address is fine...
00309   TW_RxBuf[TWRX_HIADDR] = 0x00;
00310   UsePEC = 0;
00311 }
00312 
00313 void BOOT_TEST_PE(void)
00314 {
00315   unsigned char i;
00316   //Verify that we can read back EEPROM contents via the PATCH command.
00317   //First, clear SRAMbuffer.
00318   for(i=0; i<128; i++)
00319     SRAMbuffer[i] = 0;
00320   //Next, set up the PATCH command
00321   TWI_CmdFlags = SMB_GotCmdData;
00322   TW_RxBuf[TWRX_CMD] = 'P';     //Patch
00323   TW_RxBuf[TWRX_MEM] = 'E';     //EEPROM
00324   TW_RxBuf[TWRX_LOADDR] = 0xE0; //address+size must be less than 0x200...
00325   TW_RxBuf[TWRX_HIADDR] = 0x01;
00326   TW_RxBuf[TWRX_OFFSET] = 0x00; //read it into the bottom of SRAMbuffer (arbitrary)
00327   TW_RxBuf[TWRX_SIZE] = 0x20;   //grab any size we want, up to 128 bytes
00328   UsePEC = 0;
00329 }
00330 
00331 unsigned char bigI;
00332 
00333 void BOOT_TEST_bigI(void)
00334 {
00335   unsigned char i;
00336   TW_RxBuf[TWRX_BLKCNT] = 32;
00337   TWI_CmdFlags = SMB_GotCmdData;
00338   TW_RxBuf[TWRX_CMD] = 'I';     //Insert
00339   for(i=0; i<26; i++)
00340     TW_RxBuf[TWRX_DATA+i]=i+1;  //arbitrary data
00341   bigI = i+1;                   //save for later
00342   TW_RxBuf[TWRX_OFFSET] = 0;    //insert data into SRAM buffer starting at arbitrary offset 0x33
00343   TW_RxBuf[TWRX_SIZE] = 128;
00344   UsePEC = 0;
00345 }
00346 
00347 void BOOT_TEST_bigI32(void)
00348 {
00349   unsigned char i;
00350   TW_RxBuf[TWRX_BLKCNT] = 32;
00351   TWI_CmdFlags = SMB_GotCmdData;
00352   for(i=0; i<32; i++)
00353     TW_RxBuf[3+i]=i+bigI;       //arbitrary data
00354   bigI += i;                    //save for later
00355 }
00356 
00357 void BOOT_TEST_bigI8(void)
00358 {
00359   unsigned char i;
00360   TW_RxBuf[TWRX_BLKCNT] = 6;
00361   TWI_CmdFlags = SMB_GotCmdData;
00362   for(i=0; i<6; i++)
00363     TW_RxBuf[3+i]=i+bigI;
00364 }
00365 
00366 
00367 
00368 
00369 
00370 void TestManager(void)
00371 {
00372   static unsigned char testctr = 0;
00373 
00374   switch(testctr)
00375   {
00376     case 0:
00377       BOOT_TEST_I();
00378       testctr++;
00379       break;
00380 
00381     case 1:
00382       BOOT_TEST_WF();
00383       testctr++;
00384       break;
00385 
00386     case 2:
00387       BOOT_TEST_PF();
00388       testctr++;
00389       break;
00390 
00391     case 3:
00392       BOOT_TEST_EF();
00393       testctr++;
00394       break;
00395 
00396     case 4:
00397       if(!LoopFlag)
00398       {
00399         BOOT_TEST_WE();
00400         testctr++;
00401       }
00402       break;
00403 
00404     case 5:
00405       if(!LoopFlag)
00406       {
00407         BOOT_TEST_EE();
00408         testctr++;
00409       }
00410       break;
00411 
00412     case 6:
00413       if(!LoopFlag)
00414       {
00415         BOOT_TEST_PE();
00416         testctr++;
00417       }
00418       break;
00419 
00420     case 7: //test the chained Initialize command
00421       BOOT_TEST_bigI();
00422       testctr++;
00423       break;
00424 
00425     case 8:
00426       BOOT_TEST_bigI32();
00427       testctr++;
00428       break;
00429 
00430     case 9:
00431       BOOT_TEST_bigI32();
00432       testctr++;
00433       break;
00434 
00435     case 10:
00436       BOOT_TEST_bigI32();
00437       testctr++;
00438       break;
00439 
00440     case 11:
00441       BOOT_TEST_bigI8();
00442       testctr++;
00443       break;
00444 
00445     case 12:
00446       break;
00447 
00448   }
00449 }
00450 
00451 #endif
00452 
00453 /* ************************************************************* */
00454 /* ************************************************************* */
00455 /* ************************************************************* */
00456 
00457 
00458 void main(void)
00459 {
00460   init_boot();
00461 
00462   for(;;)
00463   {
00464 
00465 #ifdef ENABLE_TESTCODE
00466     TestManager();
00467 #endif
00468 
00469     if(TWCR & (1<<TWINT))                       //Note that the TWI handler is POLLED in the BootLoader.
00470       TWI_handler();
00471 
00472     if(TWI_CmdFlags)
00473     {
00474       if(TWI_CmdFlags == SMB_SetUpReply)        /* Have Foreground set up TW_TxBuf[]. */
00475       {
00476         TWI_CmdFlags = 0;
00477         SMB_Reply();
00478       }
00479       else
00480       if(TWI_CmdFlags == SMB_GotCmdData)
00481       {
00482         TWI_CmdFlags = 0;
00483         SMB_CmdInterpreter();
00484       }
00485       else
00486       if(TWI_CmdFlags == SMB_GenBusTimeout)     /* Tell Foreground to generate a bus timeout, as we saw an error! */
00487       {
00488         TWI_CmdFlags = 0;
00489         SMB_BusTimeout();
00490       }
00491     }
00492 
00493     if(LoopFlag)                                /* handle a repeated SLOW memory operation off-line */
00494       LoopMemory();
00495   }
00496 }
00497 
00498 
00499 
00500 
00501 
00502 
00503 
00504 
00505 
00506 
00507 /* *************************************************************************
00508  *
00509  *   Low-Level SMBus Communications State Machine
00510  *
00511  ************************************************************************* */
00512 
00513 //unsigned char TW_state = TW_IDLE;     //state variable
00514 
00515 //State Machine states
00516 enum /*TW_State*/ {TW_IDLE=0, TW_Wait4Cmd, TW_Wait4RW, TW_Wait4Data, TW_ReplyData, TW_MSLA_W, TW_MCMD_W, TW_MDATA_W };
00517 
00518 void TWI_handler(void)
00519 {
00520   unsigned char Status;
00521 
00522   Status = TWSR & 0xF8;         //This identifies what caused the interrupt to fire.
00523 
00524   switch(TW_state)
00525   {
00526     default:
00527     case TW_IDLE:       //If not SLA_W or RSTOP, is an error!
00528       if(TWS_SLA_W == Status)   // saw Slave address match with a Write bit
00529       {
00530         TW_state = TW_Wait4Cmd;
00531       }
00532       else
00533       if(TWS_RSTOP == Status)   //Saw a Stop, possibly left over from previous cmd.
00534       {
00535          ;                      //Everything is probably OK.  Take no action.
00536       }
00537       else //had some type of error!
00538       {
00539         TWI_CmdFlags = SMB_GenBusTimeout;       //Flag the error & stay in this state.
00540         TWCR = (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
00541         return;
00542       }
00543       TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);        //must re-enable ACKing
00544       break;
00545 
00546 
00547     //SLAVE-mode states follow.
00548 
00549     case TW_Wait4Cmd:   //upon entry, we've expect to have received a Cmd byte.
00550       if(TWS_RCMD == Status)            //It appears that we have received a Command byte now.
00551       {
00552         if(SMBV_Opt5 == TWDR)
00553         {
00554           TW_state = TW_Wait4RW;        //set up next state
00555           TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);    //enable ACKing
00556           return;
00557         }
00558       }
00559       //In all cases except those that 'return' (above), it's an error.
00560       TWI_CmdFlags = SMB_GenBusTimeout; //Generate a bus timeout.
00561       TWCR = (1<<TWEA) | (1<<TWEN);     //disable int, and DON'T clear the TWINT flag!
00562       TW_state = TW_IDLE;               //Reset the state machine.
00563       break;
00564 
00565 
00566     case TW_Wait4RW:    //We will now find out if we will RX more, or we need to TX a reply instead.
00567       if(TWS_RDATA == Status)           //It is a WRITE-type command. Prep the RX buffer to accept more data.
00568       { //NOTE: OptionalMfgFunction5 is a BLOCK command in both directions.
00569         //Place all bytes of the transaction into the buffer so we can do a PEC on it if needed.
00570         TW_RxBuf[0] = TWAR & 0xFE;      //PEC requires the slave address to be included.
00571         TW_RxBuf[1] = SMBV_Opt5;        //store the previously-send Command.
00572         TW_RxBuf[2] = TWDR;             //THIS byte is the block byte count.
00573         TW_RxBufCnt = TWDR;
00574         TW_RxBufIndex = 3;              //the index to store data in the buffer
00575         TW_state = TW_Wait4Data;
00576         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);      //enable ACKing
00577       }
00578       else
00579       if(TWS_REPEAT == Status)  //We saw a re-Start, so must be getting ready for a Read cmd.
00580       { //Must now interpret previously-sent CurrentCmd & set up Reply data.
00581         TWI_CmdFlags = SMB_SetUpReply;          //Foreground routine will set up TWCR.
00582         TW_state = TW_ReplyData;                //Move to next state.
00583         TWCR = (1<<TWEA) | (1<<TWEN);           //disable int, and DON'T clear the TWINT flag!
00584         return;                                 
00585       }
00586       else  //some type of error!
00587       {
00588         TWI_CmdFlags = SMB_GenBusTimeout;       //Generate a bus timeout.
00589         TWCR = (1<<TWEA) | (1<<TWEN);           //disable int, and DON'T clear the TWINT flag!
00590         TW_state = TW_IDLE;                     //Reset the state machine.
00591       }
00592       break;
00593 
00594 
00595     case TW_Wait4Data:  //We are in Slave Receive operating mode.
00596       if(TWS_RDATA == Status)                   //received a data byte
00597       {
00598         TW_RxBuf[TW_RxBufIndex++] = TWDR;       //store the byte
00599         if(0 == --TW_RxBufCnt)                  //Have we received ALL expected data now?
00600         {
00601           TW_RxBufCnt = TW_RxBufIndex;          //re-use the Write Index's value as the Valid Byte Count.
00602           TW_RxBufIndex = 0;                    //clear the index in preparation for interpreting it.
00603           TWI_CmdFlags = SMB_GotCmdData;        //tell Foreground to process this now.
00604           //The foreground code is now responsible for either flagging an error and resetting
00605           // the state to IDLE, or clearing TWINT to allow the transaction to finish with a STOP.
00606           //If the cmd is OK, the Foregound must also clear TW_RxBufCnt when done so that STOP works right.
00607           //The foreground code must reference the UsePEC flag to determine if PEC is included & is valid.
00608           TWCR = (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
00609           TW_state = TW_IDLE;           //Expecting a STOP next; just 'eat' it at TW_Idle.
00610           return;
00611         }
00612       }
00613       else
00614       if(TWS_RSTOP == Status)           //got a STOP; all done RXing data now.
00615       { //Note: if we get a STOP prematurely, then we simply ignore the command,
00616         //  since it is too late to inform the Master of the error.
00617         TW_state = TW_IDLE;             //Reset the state machine in all cases.
00618       }
00619       else  //some type of error!
00620       {
00621         TWI_CmdFlags = SMB_GenBusTimeout;       //Generate a bus timeout.
00622         TWCR = (1<<TWEA) | (1<<TWEN);         //disable int, and DON'T clear the TWINT flag!
00623         TW_state = TW_IDLE;             //Reset the state machine.
00624         return;
00625       }
00626       TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);        //enable ACKing
00627       break;
00628 
00629 
00630     case TW_ReplyData:  //We are now in Slave Transmit operating mode.
00631       //Note: TW_TxBufCnt *always* includes the PEC byte! Since we don't
00632       // know whether the Master actually WANTS the PEC byte or not, we will
00633       // always TRY to send it, regardless of the state of the UsePEC flag.
00634       // If the Master does NOT want it, we will get a NAK while the PEC
00635       // byte is still in the buffer.  In the rare case where we send it all,
00636       // including the PEC byte, but we still get an ACK back, the TWI module
00637       // will be off-line anyway due to not setting the TWEA bit after sending PEC,
00638       // and we will therefore be unable to flag that an error has occurred.
00639       if((TWS_SLA_R == Status) || (TWS_RACK == Status)) //send out Reply data
00640       {
00641         TWDR = TW_TxBuf[TW_TxBufIndex++];       //send data out
00642         if(--TW_TxBufCnt == 0)                  //Have we emptied the buffer, incl. PEC?
00643           TWCR = (1<<TWINT) | (1<<TWEN);                // Yes, so don't set TWEA.
00644         else
00645           TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);    // No, so assert TWEA.
00646       }
00647       else
00648       if(TWS_RNAK == Status)    //We may have gotten this validly or as an Error.
00649       {
00650         if(TW_TxBufCnt == 1)    //Not an error. Master didn't want PEC; clear UsePEC flag!
00651         {
00652           TW_TxBufCnt = 0;      //clear the buffer too.
00653           UsePEC = 0;
00654         }
00655         else
00656         if(TW_TxBufCnt == 0)    //Not an error. Master wanted PEC (and got it); assert UsePEC.
00657           UsePEC = 1;
00658         else                    //some kind of error occurred; we got NAK too early!
00659         { //Note: the TWI module is now OFF-LINE, so we can't inform Host of this error!!
00660           ;
00661         }
00662         TW_state = TW_IDLE;                     //In all cases, go back to IDLE.
00663         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
00664       }
00665       else
00666 //    if(TWS_FINAL == Status)   //ERROR: we got an ACK but we have no more data!
00667       { //Since the TWI module is now in "Not Addressed Slave" mode, we can't flag the error.
00668         TW_state = TW_IDLE;     //Reset the state machine.
00669         TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
00670       }
00671       break;
00672 
00673   } // end of switch(TW_state)
00674 }
00675 
00676 
00677 
00678 
00679 
00680 
00681 
00682 
00683 
00684 
00685 /* *************************************************************************
00686  *
00687  *   ISP-over-SMBus Command Interpreter
00688  *
00689  ************************************************************************* */
00690 
00691 
00692 void SMB_BusTimeout(void)
00693 {
00694   int i;
00695 
00696   for(i=7000; i!=0; i--);   //4 cycles per interation, 28,000 cycles
00697 
00698   SMB_RestoreBus();
00699 }
00700 
00701 
00702 
00703 void SMB_Reply(void)
00704 {
00705   unsigned char temp;
00706 
00707   TWI_CmdFlags = 0;                     //clear the flag that brought us here.
00708   TW_TxBufIndex = 0;                    //initialize
00709   TW_TxBufCnt = 0;                      //initialize
00710 
00711   //At this time, the only valid response is to send back 'Status'.
00712   TW_TxBuf[0] = 1;                      //SMBus 'block' byte count
00713   TW_TxBuf[1] = Status;                 //Status value
00714   TW_TxBufIndex = 0;                    //point back to the start
00715   TW_TxBufCnt = 2;                      // # of valid bytes in this buffer
00716 
00717   //Generate PEC now for the *entire* transaction, including the original request!
00718   temp = FastCRC(0, (TWAR & 0xFE));     //use the SLA+W address
00719   temp = FastCRC(temp, SMBV_Opt5);
00720   temp = FastCRC(temp, (TWAR | 1));     //use the SLA+R address
00721 
00722   do {temp = FastCRC(temp, TW_TxBuf[TW_TxBufIndex++]);}
00723     while(TW_TxBufIndex != TW_TxBufCnt);
00724 
00725   TW_TxBuf[TW_TxBufIndex] = temp;       //append the CRC value on the end.
00726   TW_TxBufCnt++;                        //increase the byte count for the PEC.
00727   TW_TxBufIndex = 0;                    //Reset the buffer pointer.
00728   TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);    //have TWI continue from where it stalled.
00729 }
00730 
00731 
00732 
00733 
00734 
00735 unsigned char EEbusy(void)
00736 {
00737   return (EECR & (1<<EEPE));
00738 }
00739 
00740 
00741 
00742 unsigned char EEget(unsigned int address)
00743 {
00744   while(EECR & (1<<EEPE));
00745   EEAR = address;
00746   EECR |= (1<<EERE);
00747   return EEDR;
00748 }
00749 
00750 void EEerase(unsigned int address)
00751 {
00752   while(EECR & (1<<EEPE));
00753   EEAR = address;
00754   EECR = (1<<EEPM0) | (1<<EEMPE);
00755   EECR = (1<<EEPM0) | (1<<EEMPE) | (1<<EEPE);
00756 }
00757 
00758 void EEwrite(unsigned int address, unsigned char data)
00759 {
00760   while(EECR & (1<<EEPE));
00761   EEAR = address;
00762   EEDR = data;
00763   EECR = (1<<EEMPE);                    //do an Erase and a Write
00764   EECR = (1<<EEMPE) | (1<<EEPE);
00765 }
00766 
00767 
00768 
00769 
00770 
00771 
00772 void LoopMemory(void)
00773 {
00774   if(LoopFlag == 'E')           //this indicates "Write to EEPROM"
00775   {
00776     if(EEbusy())
00777       return;
00778     EEwrite(eptr++, SRAMbuffer[dest_i++]);
00779     if(--ctr)
00780       return;
00781     Status = SUCCESS;
00782     LoopFlag = 0;
00783     return;
00784   }
00785   else
00786   if(LoopFlag == 'e')           //this indicates "Erase EEPROM"
00787   {
00788     if(EEbusy())
00789       return;
00790     EEerase(eptr++);
00791     if(--ctr)
00792       return;
00793     Status = SUCCESS;
00794     LoopFlag = 0;
00795     return;
00796   }
00797 }
00798 
00799 
00800 
00801 
00802 
00803 //This function interprets received commands.
00804 void SMB_CmdInterpreter(void)
00805 {
00806   unsigned char temp;
00807 
00808   if(UsePEC)                            //check the CRC of the received packet.
00809   {
00810     temp = 0;                           //use this as our CRC value.
00811 
00812     do { temp = FastCRC(temp, TW_RxBuf[TW_RxBufIndex++]); }
00813     while(TW_RxBufCnt != TW_RxBufIndex);
00814 
00815     if(temp)    //The result of a CRC check SHOULD be =0 if all was ok.
00816     {
00817       Status = CRCERROR;
00818       TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);        //have TWI continue from where it stalled.
00819       return;
00820     }
00821   }
00822   // Message is valid enough to warrant calling each command's handler now.
00823   Status = BUSY;                        //in case it's a "looped" operation...
00824 
00825 
00826   if(!BigData)
00827   {
00828   //  TW_RxBufIndex = 3;                        //point to the first byte of Received Data.
00829     lomemptr = TW_RxBuf[TWRX_LOADDR];
00830     himemptr = TW_RxBuf[TWRX_HIADDR];
00831     src_i = TWRX_DATA;
00832     dest_i = TW_RxBuf[TWRX_OFFSET];
00833     ctr = TW_RxBuf[TWRX_SIZE];
00834 
00835     temp = TW_RxBuf[TWRX_CMD];          //What is the command?
00836   }
00837   else
00838   {
00839     temp = 'I';
00840     src_i = 3;                          //for all follow-on blocks, data MUST start at 3!
00841     //Note that ctr and dest_i are still valid from the previous block.
00842   }
00843 
00844 
00845   if(temp == 'W')                     //Write SRAMbuffer data into memory
00846   {
00847     if(TW_RxBuf[TWRX_MEM] == 'F')     //flash?
00848     {
00849       src_i = 0;                      //index into SRAMbuffer
00850       lomemptr &= 0x80;               //make sure the page boundary is clean
00851       dest_i = lomemptr;
00852       do
00853       {
00854         #pragma diag_suppress=Pe1053  // Suppress warning for conversion from long-type address to flash ptr.
00855         _FILL_TEMP_WORD(((himemptr<<8)|dest_i), (SRAMbuffer[src_i]|(SRAMbuffer[src_i+1]<<8)));
00856         #pragma diag_default=Pe1053   // Back to default.
00857         src_i += 2;                   // Select next word from SRAMbuffer.
00858         dest_i += 2;                  // Update flash page pointer.
00859       }
00860       while(src_i < 0x80);          // Loop until all bytes written.
00861 
00862       _PAGE_WRITE((himemptr<<8)|lomemptr);
00863       _WAIT_FOR_SPM();
00864       _ENABLE_RWW_SECTION();
00865 
00866       Status = SUCCESS;
00867     }
00868     else
00869     if(TW_RxBuf[TWRX_MEM] == 'E')  //eeprom?
00870     {
00871       eptr = (himemptr<<8) | lomemptr;
00872       if((eptr + ctr) > 512)
00873         Status = BADPARAM;
00874       else
00875       {
00876         LoopFlag = 'E';         //this indicates "Write to EEPROM"
00877       }
00878     }
00879     else
00880       Status = BADPARAM;
00881   }
00882 
00883   else
00884   if(temp == 'V')       //Verify info in SRAMbuffer against memory
00885   {
00886     if(TW_RxBuf[TWRX_MEM] == 'F')  //flash?
00887     {
00888       src_i = SUCCESS;              //use this variable to hold status
00889       dest_i = 0;
00890       fptr = (unsigned char __flash *)(lomemptr | (himemptr<<8));
00891       do { if(SRAMbuffer[dest_i++] != *fptr++) src_i=FAILURE; }
00892       while (dest_i < 128);
00893       Status = src_i;
00894     }
00895     else
00896     if(TW_RxBuf[TWRX_MEM] == 'E')  //eeprom?
00897     {
00898       eptr = (himemptr<<8) | lomemptr;
00899       if((eptr + ctr) > 512)
00900         Status = BADPARAM;
00901       else
00902       {
00903         src_i = SUCCESS;            //use this variable to hold status
00904         do { if(SRAMbuffer[dest_i++] != EEget(eptr++)) src_i=FAILURE; }
00905         while (--ctr);
00906         Status = src_i;
00907       }
00908     }
00909     else
00910       Status = BADPARAM;
00911   }
00912 
00913   else
00914   if(temp == 'E')       //Erase memory, starting at the specified address
00915   {
00916     if(TW_RxBuf[TWRX_MEM] == 'F')  //flash?
00917     {
00918       _WAIT_FOR_SPM();
00919       #pragma diag_suppress=Pe1053 // Suppress warning for conversion from long-type address to flash ptr.
00920       _PAGE_ERASE( (himemptr<<8) | (lomemptr & 0x80) );
00921       #pragma diag_default=Pe1053 // Back to default.
00922 
00923       Status = SUCCESS;
00924     }
00925     else
00926     if(TW_RxBuf[TWRX_MEM] == 'E')  //eeprom?
00927     {
00928       eptr = (himemptr<<8) | lomemptr;
00929       if((eptr + ctr) > 512)
00930         Status = BADPARAM;
00931       else
00932       {
00933         LoopFlag = 'e';         //this indicates "erase EEPROM"
00934       }
00935     }
00936     else
00937       Status = BADPARAM;
00938   }
00939 
00940   else
00941   if(temp == 'P')       //prepare to Patch a block of memory by reading it into SRAMbuffer
00942   {
00943     if(TW_RxBuf[TWRX_MEM] == 'F')  //flash?
00944     {
00945       if(lomemptr & 0x7F)          //it must be on a page boundary!!
00946         Status = BADPARAM;
00947       else
00948       {
00949         dest_i = 0;
00950         fptr = (unsigned char __flash *)(lomemptr | (himemptr<<8));
00951         do {SRAMbuffer[dest_i++] = *fptr++; }
00952         while (dest_i < 128);
00953         Status = SUCCESS;
00954       }
00955     }
00956     else
00957     if(TW_RxBuf[TWRX_MEM] == 'E')  //eeprom?
00958     {
00959       eptr = (himemptr<<8) | lomemptr;
00960       if((eptr + ctr) > 512)
00961         Status = BADPARAM;
00962       else
00963       {
00964         do { SRAMbuffer[dest_i++] = EEget(eptr++); }
00965         while (--ctr);
00966         Status = SUCCESS;
00967       }
00968     }
00969     else
00970       Status = BADPARAM;
00971   }
00972 
00973   else
00974   if(temp == 'A')       //Activate BootLoader ISP code (ignored in this code)
00975   {
00976     Status = SUCCESS;   //no action required, just ignore
00977   }
00978 
00979   else
00980   if(temp == 'I')       //Insert data from this packet into SRAMbuffer at the offset specified
00981   {
00982     if((ctr+dest_i) > 128)
00983       Status = BADPARAM;
00984     else
00985     {
00986       if(!BigData)
00987       {
00988         if(ctr > 26)    //26 is the most that can fit in an initial packet
00989         {
00990           BigData = 1;
00991           temp = TW_RxBuf[TWRX_BLKCNT] - 6;
00992         }
00993         else
00994           temp = ctr;
00995       }
00996       else              //this is a chained packet and MAY contain up to 32 bytes of data.
00997       {
00998         if(ctr <= TW_RxBuf[TWRX_BLKCNT])
00999           BigData = 0;
01000         temp = TW_RxBuf[TWRX_BLKCNT];
01001       }
01002 
01003 
01004       do
01005       {
01006         SRAMbuffer[dest_i++] = TW_RxBuf[src_i++];
01007         ctr--;
01008       }
01009       while (--temp);
01010       Status = SUCCESS;
01011     }
01012   }
01013 
01014   else
01015   if(temp == 'w')       //first decrypt the entire SRAM block, THEN write.
01016   {
01017     ;   
01018   }
01019 
01020   else
01021   if(temp == 'v')       //first decrypt the entire SRAM block, THEN verify.
01022   {
01023     ;   
01024   }
01025 
01026   else
01027   if(temp == 'X')       //Exit the BootLoader
01028   {
01029     asm("jmp 0");
01030   }
01031 
01032   else  //Not a valid command from our list
01033   {
01034     SMB_BusTimeout();   //Generate a bus timeout.
01035     TW_RxBufIndex = 0;  //Wipe out anything in the buffer, just in case.
01036     TW_RxBufCnt = 0;                    
01037     return;
01038   }
01039   //At this point it looks like everything went OK.
01040   TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);    //have TWI continue from where it stalled.
01041   return;
01042 }
01043 
01044 
01045 
01046 
01047 
01048 //This function restores the SMBus & the TWI_ISR state machine to normal after
01049 //  we have deliberately generated a bus timeout error (in order to tell the
01050 //  Master that something was wrong with his last command).
01051 void SMB_RestoreBus(void)
01052 {
01053   TWCR = 0;                     //shut down the peripheral
01054   TW_state = TW_IDLE;   //force an init of the state machine
01055   TWAR = 0x16;
01056   TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);    // | (1<<TWSTO)  re-enable
01057 
01058   //Note that we must be careful not to generate some kind of bus error
01059   // as a result of waking back up, or we will get into an endless loop
01060   // by generating another bus timeout if the IDLE state doesn't like
01061   // something it sees when it comes back to life.
01062 }
01063 
01064 
01065 
01066 
01067 
01068 
01069 
01070 /* *************************************************************************
01071  *
01072  *   Utilities for SMBus commmunications
01073  *
01074  ************************************************************************* */
01075 
01076 
01077 
01078 __flash unsigned char crctable[16] =  {0,0x07,0x0E,0x90, 0x1c,0x1b,0x12,0x15, 0x38,0x3F,0x36,0x31, 0x24,0x23,0x2A,0x2D};
01079 __flash unsigned char crctable2[16] = {0,0x70,0xE0,0x90, 0xC1,0xB1,0x21,0x51, 0x83,0xF3,0x63,0x13, 0x42,0x32,0xA2,0xD2};
01080 
01081 unsigned char FastCRC(unsigned char LastCRC, unsigned char newbyte)
01082 {
01083   unsigned char index;
01084 
01085   index = newbyte;
01086   index ^= LastCRC;
01087   index >>= 4;
01088   LastCRC &= 0x0F;
01089   LastCRC ^= crctable2[index];
01090 
01091   index = LastCRC;
01092   index ^= newbyte;
01093   index &= 0x0F;
01094   LastCRC &= 0xF0;
01095   LastCRC ^= crctable[index];
01096 
01097   return(LastCRC);
01098 }
01099 
01100 /*  This version doesn't require crctable2[], but requires more shifts.
01101 unsigned char SlowerCRC(unsigned char LastCRC, unsigned char newbyte)
01102 {
01103   unsigned char index;
01104 
01105   index = newbyte;
01106   index ^= LastCRC;
01107   index >>= 4;
01108   LastCRC <<= 4;
01109   LastCRC ^= crctable[index];
01110 
01111   index = LastCRC >> 4;
01112   index ^= newbyte;
01113   index &= 0x0F;
01114   LastCRC <<= 4;
01115   LastCRC ^= crctable[index];
01116 
01117   return(LastCRC);
01118 } */
01119 
01120 
01121 
01122 
01123 
01124 
01125 
01126 
01127 
01128 
01129 
01130 
01131 
01132 

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