📄 bootloader_smbus.c
字号:
break;
case 1:
BOOT_TEST_WF();
testctr++;
break;
case 2:
BOOT_TEST_PF();
testctr++;
break;
case 3:
BOOT_TEST_EF();
testctr++;
break;
case 4:
if(!LoopFlag)
{
BOOT_TEST_WE();
testctr++;
}
break;
case 5:
if(!LoopFlag)
{
BOOT_TEST_EE();
testctr++;
}
break;
case 6:
if(!LoopFlag)
{
BOOT_TEST_PE();
testctr++;
}
break;
case 7: //test the chained Initialize command
BOOT_TEST_bigI();
testctr++;
break;
case 8:
BOOT_TEST_bigI32();
testctr++;
break;
case 9:
BOOT_TEST_bigI32();
testctr++;
break;
case 10:
BOOT_TEST_bigI32();
testctr++;
break;
case 11:
BOOT_TEST_bigI8();
testctr++;
break;
case 12:
break;
}
}
#endif;承上#ifdef ENABLE_TESTCODE启此(#if&#else---#endif如同选择if和else)
/* ************************************************************* */
/* ************************************************************* */
/* ************************************************************* */
void main(void)
{
init_boot();
for(;;)
{
#ifdef ENABLE_TESTCODE
TestManager();
#endif
if(TWCR & (1<<TWINT)) //TWI的控制寄存器Note that the TWI handler is POLLED in the BootLoader.中断启动
TWI_handler();
if(TWI_CmdFlags)
{
if(TWI_CmdFlags == SMB_SetUpReply) /* Have Foreground set up TW_TxBuf[]. 显著TW_TXBUF位置已经设置*/
{
TWI_CmdFlags = 0;
SMB_Reply();
}
else
if(TWI_CmdFlags == SMB_GotCmdData)
{
TWI_CmdFlags = 0;
SMB_CmdInterpreter();
}
else
if(TWI_CmdFlags == SMB_GenBusTimeout) /* Tell Foreground to generate a bus timeout, as we saw an error! */
{
TWI_CmdFlags = 0;
SMB_BusTimeout();
}
}
if(LoopFlag) /* handle a repeated SLOW memory operation off-line */
LoopMemory();
}
}
/* *************************************************************************
*
* Low-Level SMBus Communications State Machine状态
*
************************************************************************* */
//unsigned char TW_state = TW_IDLE; //state variable
//State Machine states
enum /*TW_State*/ {TW_IDLE=0, TW_Wait4Cmd, TW_Wait4RW, TW_Wait4Data, TW_ReplyData, TW_MSLA_W, TW_MCMD_W, TW_MDATA_W };
void TWI_handler(void)
{
unsigned char Status;
Status = TWSR & 0xF8; //This identifies what caused the interrupt to fire.
switch(TW_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
{
TW_state = TW_Wait4Cmd;
}
else
if(TWS_RSTOP == Status) //Saw a Stop, possibly left over from previous cmd.
{
; //Everything is probably OK. Take no action.
}
else //had some type of error!
{
TWI_CmdFlags = SMB_GenBusTimeout; //Flag the error & stay in this state.
TWCR = (1<<TWEA) | (1<<TWEN); //disable int, and DON'T clear the TWINT flag!
return;
}
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN); //must re-enable ACKing
break;
//SLAVE-mode states follow.
case TW_Wait4Cmd: //upon entry, we've expect to have received a Cmd byte.
if(TWS_RCMD == Status) //It appears that we have received a Command byte now.
{
if(SMBV_Opt5 == TWDR)
{
TW_state = TW_Wait4RW; //set up next state
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN); //enable ACKing
return;
}
}
//In all cases except those that 'return' (above), it's an error.
TWI_CmdFlags = SMB_GenBusTimeout; //Generate a bus timeout.
TWCR = (1<<TWEA) | (1<<TWEN); //disable int, and DON'T clear the TWINT flag!
TW_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: OptionalMfgFunction5 is a BLOCK command in both directions.
//Place all bytes of the transaction into the buffer so we can do a PEC on it if needed.
TW_RxBuf[0] = TWAR & 0xFE; //PEC requires the slave address to be included.
TW_RxBuf[1] = SMBV_Opt5; //store the previously-send Command.
TW_RxBuf[2] = TWDR; //THIS byte is the block byte count.
TW_RxBufCnt = TWDR;
TW_RxBufIndex = 3; //the index to store data in the buffer
TW_state = TW_Wait4Data;
TWCR = (1<<TWINT) | (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.
TWI_CmdFlags = SMB_SetUpReply; //Foreground routine will set up TWCR.
TW_state = TW_ReplyData; //Move to next state.
TWCR = (1<<TWEA) | (1<<TWEN); //disable int, and DON'T clear the TWINT flag!
return;
}
else //some type of error!
{
TWI_CmdFlags = SMB_GenBusTimeout; //Generate a bus timeout.
TWCR = (1<<TWEA) | (1<<TWEN); //disable int, and DON'T clear the TWINT flag!
TW_state = TW_IDLE; //Reset the state machine.
}
break;
case TW_Wait4Data: //We are in Slave Receive operating mode.
if(TWS_RDATA == Status) //received a data byte
{
TW_RxBuf[TW_RxBufIndex++] = TWDR; //store the byte
if(0 == --TW_RxBufCnt) //Have we received ALL expected data now?
{
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.
//The foreground code is now responsible for either flagging an error and resetting
// the state to IDLE, or clearing TWINT to allow the transaction to finish with a STOP.
//If the cmd is OK, the Foregound must also clear TW_RxBufCnt when done so that STOP works right.
//The foreground code must reference the UsePEC flag to determine if PEC is included & is valid.
TWCR = (1<<TWEA) | (1<<TWEN); //disable int, and DON'T clear the TWINT flag!
TW_state = TW_IDLE; //Expecting a STOP next; just 'eat' it at TW_Idle.
return;
}
}
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.
TW_state = TW_IDLE; //Reset the state machine in all cases.
}
else //some type of error!
{
TWI_CmdFlags = SMB_GenBusTimeout; //Generate a bus timeout.
TWCR = (1<<TWEA) | (1<<TWEN); //disable int, and DON'T clear the TWINT flag!
TW_state = TW_IDLE; //Reset the state machine.
return;
}
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN); //enable ACKing
break;
case TW_ReplyData: //We are now in Slave Transmit operating mode.
//Note: TW_TxBufCnt *always* includes the PEC byte! Since we don't
// know whether the Master actually WANTS the PEC byte or not, we will
// always TRY to send it, regardless of the state of the UsePEC flag.
// If the Master does NOT want it, we will get a NAK while the PEC
// byte is still in the buffer. In the rare case where we send it all,
// including the PEC byte, but we still get an ACK back, the TWI module
// will be off-line anyway due to not setting the TWEA bit after sending PEC,
// and we will therefore be unable to flag that an error has occurred.
if((TWS_SLA_R == Status) || (TWS_RACK == Status)) //send out Reply data
{
TWDR = TW_TxBuf[TW_TxBufIndex++]; //send data out
if(--TW_TxBufCnt == 0) //Have we emptied the buffer, incl. PEC?
TWCR = (1<<TWINT) | (1<<TWEN); // Yes, so don't set TWEA.
else
TWCR = (1<<TWINT) | (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!!
;
}
TW_state = TW_IDLE; //In all cases, go back to IDLE.
TWCR = (1<<TWINT) | (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.
TW_state = TW_IDLE; //Reset the state machine.
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
}
break;
} // end of switch(TW_state)
}
/* *************************************************************************
*
* ISP-over-SMBus Command Interpreter
*
************************************************************************* */
void SMB_BusTimeout(void)
{
int i;
for(i=7000; i!=0; i--); //4 cycles per interation, 28,000 cycles
SMB_RestoreBus();
}
void SMB_Reply(void)
{
unsigned char temp;
TWI_CmdFlags = 0; //clear the flag that brought us here.
TW_TxBufIndex = 0; //initialize
TW_TxBufCnt = 0; //initialize
//At this time, the only valid response is to send back 'Status'.
TW_TxBuf[0] = 1; //SMBus 'block' byte count
TW_TxBuf[1] = Status; //Status value
TW_TxBufIndex = 0; //point back to the start
TW_TxBufCnt = 2; // # of valid bytes in this buffer
//Generate PEC now for the *entire* transaction, including the original request!
temp = FastCRC(0, (TWAR & 0xFE)); //use the SLA+W address
temp = FastCRC(temp, SMBV_Opt5);
temp = FastCRC(temp, (TWAR | 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.
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN); //have TWI continue from where it stalled.
}
unsigned char EEbusy(void)
{
return (EECR & (1<<EEPE));
}
unsigned char EEget(unsigned int address)
{
while(EECR & (1<<EEPE));
EEAR = address;
EECR |= (1<<EERE);
return EEDR;
}
void EEerase(unsigned int address)
{
while(EECR & (1<<EEPE));
EEAR = address;
EECR = (1<<EEPM0) | (1<<EEMPE);
EECR = (1<<EEPM0) | (1<<EEMPE) | (1<<EEPE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -