📄 bootloader_smbus.c
字号:
/* This file has been prepared for Doxygen automatic documentation generation.*/
/*! \file *********************************************************************
*
* \brief
* SMBus Bootloader for ATmega406
*
* \par Application note:
* AVR453: Smart Battery Reference Design
*
* \par Documentation:
* For comprehensive code documentation, supported compilers, compiler
* settings and supported devices see readme.html
*
* \author
* Atmel Corporation: http://www.atmel.com \n
* Support email: avr@atmel.com \n
* Original author: Rob G. Fries - Apt Inc.\n
*
* $Name$
* $Revision: 2687 $
* $RCSfile$
* $Date: 2007-11-12 10:39:44 +0100 (ma, 12 nov 2007) $ \n
******************************************************************************/
/*! \page doc_page1 Compilation Info
* \section Bootloader
* This software was written for the IAR Embedded Workbench, 4.11A/4.10B, but can also be
* built using 3.20C \n
* To make project:
* Add this file, bootloader_smbus.c to project, use用于 device -v3, enhanced core增强核,
* no RAMPZ register, enable bit definitions in I/O include files, optimization was set
* to medium, override default linker command file with: $PROJ_DIR$\\m406s_2kwBootLdr.xcl
* (included with the source), output format: ubrof8 for Debug and intel_extended for Release.\n
* To program the device with bootloader, one first has to erase the device and program the
* bootloader, then program the main section without erasing the device first.
*/
//#define ENABLE_TESTCODE;测试使能代码
//#include <pgmspace.h>
#include <inavr.h>
#define MODULE_BOOTLDR /* ensure that we instantiate our variables in bootldr.h */
#include "bootldr.h"
//#include "iom406_320.h"
#include "iom406.h" // IAR headerfile for Mega406 (EW 410)
#include "flash.h"
void TWI_handler(void);
void SMB_RestoreBus(void);
unsigned char FastCRC(unsigned char LastCRC, unsigned char newbyte);
void SMB_BusTimeout(void);
void SMB_Reply(void);
void SMB_CmdInterpreter(void);
void LoopMemory(void);
//=======================================================================
//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 */
// 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 TW_TxBuf[36]; //must be long enough for any outbound strings
unsigned char TW_TxBufCnt; //how many valid bytes are in the buffer
unsigned char TW_TxBufIndex;
unsigned char TW_RxBuf[36]; //must be big enough for inbound programming data
unsigned char TW_RxBufCnt; // SLA + Cmd + Count + 32bytes + PEC = 36
unsigned char TW_RxBufIndex;
unsigned char TW_state; //state variable
unsigned char UsePEC; //PEC usage is disabled by default.
unsigned char LoopFlag; //if we're looping on a slow memory operation
unsigned char BigData; //flag, if doing multi=packet 'I' command
unsigned char src_i;
unsigned char dest_i;
unsigned char ctr;
unsigned char lomemptr;
unsigned char himemptr;
unsigned char __flash *fptr;
unsigned int eptr;
unsigned char SRAMbuffer[128]; //this is the size of a Flash page (64 *WORDS*)
//This byte contains flags from the TWI handler to tell the Foreground code what to do.
//If this byte is ever non-zero, the foreground code will act on its contents.
//Although it is written by both the Handler and the Foreground code, it does not
// need to be declared VOLATILE because the SMBus is halted until the foreground
// code finishes processing the associated command and has cleared this flag byte.
unsigned char 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 Status; //this is a global variable and is the sole response to a READ using cmd 0x2F.
#define SUCCESS 0
#define BUSY 1
#define BADPARAM 2
#define CRCERROR 3
#define FAILURE 0xFF
//=======================================================================
// Reset Management theory:
//
// To make it easier to enter the bootloader when the OptionalMfgCmd5 command is received
// while running the SMBus interpreter in the application code, we monitor the Reset
// Source flags. If we arrive here without any flags being asserted, then we can assume
// that we have jumped here from the application, and we can therefore assume that it is
// intended that the bootloader code be run.
// Otherwise, if any reset flag IS asserted when we enter, we check if there is a valid
// vector present at 0x0000; if not, we run the bootloader in order to retrieve a valid
// image, otherwise, we jump down to the application program and run it.
//
//! \todo EXCEPTION: if the Watchdog flag is asserted, there is a POSSIBILITY that there's
//! a problem with the App code image. It is left to the user to determine if this is the
//! case and to take remedial action.
void __low_level_init(void)
{
unsigned char __flash * ptr = 0;
if(!(MCUSR)) //If no reset source is asserted, we probably came here from the App code deliberately.
return; //Assume we need to run the BootLoader.
// Some reset source was asserted. If it was Wdog, there may be a code problem and we
// may need to handle it differently from other reset sources. If so, add that code here.
if(MCUSR & (1<<WDRF))
{
//! \todo Add code here to handle Wdog reset.
}
//Some reset source was asserted, so if Reset vector is FFFF, assume we need to run the bootloader,
// otherwise jump to the application code reset vector at 0x0000 and assume the App code is OK.
if((*ptr++ != 0xFF) || (*ptr != 0xFF))
{
MCUCR &= (1<<IVSEL);
asm("jmp 0");
}
//At this point, we apparently need to run the Bootloader code, as App section image appears invalid.
}
void init_boot(void);主引导初始化程序
{
__disable_interrupt();
TW_TxBufCnt = 0; //how many valid bytes are in the buffer
TW_TxBufIndex = 0;
TW_RxBufCnt = 0;
TW_RxBufIndex = 0;
TW_state = 0;
UsePEC = 0;
Status = SUCCESS;
LoopFlag = 0;
BigData = 0;
SMB_RestoreBus();
TWBCSR = (1<<TWBCIF) | (1<<TWBDT1) | (1<<TWBDT0) | (0<<TWBCIP);
}
/* ************************************************************* */
/* ************************************************************* */
/* ************************************************************* */
//The following functions are included to demonstrate how the incoming
// data should be set up for SMBus-based ISP commands.接下来的功能包括证明如何增加设置命令。
#ifdef ENABLE_TESTCODE;如果该宏名在前面#define已经定义过,则语句后的代码将被编译。承上启下
void BOOT_TEST_EF(void);测试flash页写入功能性
{
//Test the Flash Page Erase functionality 功能性(put junk at 0x0000-0x007F first)
TWI_CmdFlags = SMB_GotCmdData;
TW_RxBuf[TWRX_CMD] = 'E'; //Erase
TW_RxBuf[TWRX_MEM] = 'F'; //flash
TW_RxBuf[TWRX_LOADDR] = 0x80;
TW_RxBuf[TWRX_HIADDR] = 0;
UsePEC = 0;
}
void BOOT_TEST_EE(void);EEPROM功能性写入测试。
{
//Test the EEPROM Erase functionality (put junk at 0x1F0-0x1FF first; should only erase through 0x1F9)
TWI_CmdFlags = SMB_GotCmdData;
TW_RxBuf[TWRX_CMD] = 'E'; //Erase
TW_RxBuf[TWRX_MEM] = 'E'; //EEPROM
TW_RxBuf[TWRX_LOADDR] = 0xF0;
TW_RxBuf[TWRX_HIADDR] = 0x01;
TW_RxBuf[TWRX_SIZE] = 0x0a; //only do 10 bytes (test non-power-of-2 case)
UsePEC = 0;
}
void BOOT_TEST_I(void)
{
unsigned char i;
TWI_CmdFlags = SMB_GotCmdData;
TW_RxBuf[TWRX_CMD] = 'I'; //Insert插入
TW_RxBuf[TWRX_LOADDR] = 0;
TW_RxBuf[TWRX_HIADDR] = 0;
for(i=0; i<16; i++)
TW_RxBuf[TWRX_DATA+i]=i+33; //arbitrary data任意数据
TW_RxBuf[TWRX_OFFSET] = 0x33; //insert data into SRAM buffer starting at arbitrary offset偏移量 0x33,33的偏移量留给其他初始化程序使用勿随意占用。
TW_RxBuf[TWRX_SIZE] = 16;
UsePEC = 0;
}
void BOOT_TEST_WF(void)
{
unsigned char i;
//Test the Flash Page WRITE functionality (store SRAMbuffer to flash 0x0000-0x007F)往FLASH内存储SRAMBUFFER中的资料。
//Fill the buffer before doing WRITE tests.在写测试之前写满。
for(i=0; i<128; i++)
SRAMbuffer[i]=i+33;
TWI_CmdFlags = SMB_GotCmdData;
TW_RxBuf[TWRX_CMD] = 'W'; //Write
TW_RxBuf[TWRX_MEM] = 'F'; //flash
TW_RxBuf[TWRX_LOADDR] = 0x80;
TW_RxBuf[TWRX_HIADDR] = 0;
UsePEC = 0;
}
void BOOT_TEST_WE(void)
{ //Test the EEPROM WRITE functionality (store small piece of SRAMbuffer to eeprom 0x1F0-0x1FB);从BUFFER中存少部分给EEPROM
unsigned char i;
//Fill the buffer before doing WRITE tests.
for(i=0; i<128; i++)
SRAMbuffer[i]=i+33;
TWI_CmdFlags = SMB_GotCmdData;
TW_RxBuf[TWRX_CMD] = 'W'; //Write
TW_RxBuf[TWRX_MEM] = 'E'; //EEPROM
TW_RxBuf[TWRX_LOADDR] = 0xF0; //any address is fine...
TW_RxBuf[TWRX_HIADDR] = 0x01;
TW_RxBuf[TWRX_OFFSET] = 0x33; //use an arbitrary block from inside the buffer area
TW_RxBuf[TWRX_SIZE] = 0x0c;
UsePEC = 0;
}
void BOOT_TEST_PF(void)
{
unsigned char i;
//Verify that we can read back FLASH contents via the PATCH command.通过扩展命令读取FLASH中的内容即检查。
//First, clear SRAMbuffer.
for(i=0; i<128; i++)
SRAMbuffer[i] = 0;
//Next, set up the PATCH command
TWI_CmdFlags = SMB_GotCmdData;
TW_RxBuf[TWRX_CMD] = 'P'; //Patch
TW_RxBuf[TWRX_MEM] = 'F'; //flash
TW_RxBuf[TWRX_LOADDR] = 0x80; //any address is fine...
TW_RxBuf[TWRX_HIADDR] = 0x00;
UsePEC = 0;
}
void BOOT_TEST_PE(void)
{
unsigned char i;
//Verify that we can read back EEPROM contents via the PATCH command.
//First, clear SRAMbuffer.
for(i=0; i<128; i++)
SRAMbuffer[i] = 0;
//Next, set up the PATCH command
TWI_CmdFlags = SMB_GotCmdData;
TW_RxBuf[TWRX_CMD] = 'P'; //Patch
TW_RxBuf[TWRX_MEM] = 'E'; //EEPROM
TW_RxBuf[TWRX_LOADDR] = 0xE0; //address+size must be less than 0x200...
TW_RxBuf[TWRX_HIADDR] = 0x01;
TW_RxBuf[TWRX_OFFSET] = 0x00; //read it into the bottom of SRAMbuffer (arbitrary)
TW_RxBuf[TWRX_SIZE] = 0x20; //grab any size we want, up to 128 bytes
UsePEC = 0;
}
unsigned char bigI;
void BOOT_TEST_bigI(void)
{
unsigned char i;
TW_RxBuf[TWRX_BLKCNT] = 32;
TWI_CmdFlags = SMB_GotCmdData;
TW_RxBuf[TWRX_CMD] = 'I'; //Insert
for(i=0; i<26; i++)
TW_RxBuf[TWRX_DATA+i]=i+1; //arbitrary data
bigI = i+1; //save for later
TW_RxBuf[TWRX_OFFSET] = 0; //insert data into SRAM buffer starting at arbitrary offset 0x33
TW_RxBuf[TWRX_SIZE] = 128;
UsePEC = 0;
}
void BOOT_TEST_bigI32(void)
{
unsigned char i;
TW_RxBuf[TWRX_BLKCNT] = 32;
TWI_CmdFlags = SMB_GotCmdData;
for(i=0; i<32; i++)
TW_RxBuf[3+i]=i+bigI; //arbitrary data
bigI += i; //save for later
}
void BOOT_TEST_bigI8(void)
{
unsigned char i;
TW_RxBuf[TWRX_BLKCNT] = 6;
TWI_CmdFlags = SMB_GotCmdData;
for(i=0; i<6; i++)
TW_RxBuf[3+i]=i+bigI;
}
void TestManager(void)
{
static unsigned char testctr = 0;
switch(testctr)
{
case 0:
BOOT_TEST_I();
testctr++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -