STM8L052R8在线升级例程及步骤说明

更新时间:2024-04-10 09:27:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

一、程序代码

1、Bootloader程序 (1)主函数

#include \

//中断向量重映射

__root const long reintvec[]@\{

0x82008080,0x8200B804,0x8200B808,0x8200B80c,

0x8200B810,0x8200B814,0x8200B818,0x8200B81c,

0x8200B820,0x8200B824,0x8200B828,0x8200B82c,

0x8200B830,0x8200B834,0x8200B838,0x8200B83c,

0x8200B840,0x8200B844,0x8200B848,0x8200B84c,

0x8200B850,0x8200B854,0x8200B858,0x8200B85c,

0x8200B860,0x8200B864,0x8200B868,0x8200B86c,

0x8200B870,0x8200B874,0x8200B878,0x8200B87c, };

#ifdef TEST

u32 addresss=0xa090;

u8 temp[8]={1,2,3,4,5,6,7,8};

u8 temp_Valid_flag[4]={0}; #endif

void Clk_Init(void) {

CLK_SWR = 0x01; //HSI selected as system clock source CLK_CKDIVR = 0x00; //System clock source/1 }

void Delayus(u16 n_us) {

uint16_t i,j;

for(i=0;i

for(j=0;j<1;j++)

{IWDG_KR = 0xaa;} } }

void Delayms(u16 n_ms) { u8 k = 20; while(n_ms--) { while(k--) nop(); } }

void main(void) {

Clk_Init();

//中断内us级延时 uart_init(); rim();

DataFlashRead(APP_Valid_address,temp_Valid_flag,4);

if((temp_Valid_flag[0]==0x11) && (temp_Valid_flag[1]==0x22) (temp_Valid_flag[3]==0x44)) {

Jump_To_App(); }

#ifdef TEST

PC_DDR |= 0x80; //PC7输出口 PC_CR1 |= 0x80; //PC7推挽输出 PC_CR2 |= 0x80; //PC7输出速度最大为10MHZ PC_ODR &= ~0x80;//PC7输出低

Buzzer(3); #endif

while(1) {

uart_receive(); } }

(2)Flash函数

/*********************************************** * 函数名 :unlock_PROG

* 描述 :不使能FLASH保护 * 创建时间 :2017-05-17

************************************************/ void unlock_PROG(void) {

do{

FLASH_PUKR = 0x56; FLASH_PUKR = 0xAE;

}while((FLASH_IAPSR & 0x02)==0); }

/*********************************************** * 函数名 :unlock_DATA

* 描述 :不使能EEPROM保护 * 创建时间 :2017-05-17

************************************************/ void unlock_DATA(void) {

do{

FLASH_DUKR = 0xAE; memory !!! */

FLASH_DUKR = 0x56;

}while((FLASH_IAPSR & 0x08)==0); }

/*********************************************** * 函数名 :lock_PROG

* 描述 :使能FLASH保护 * 创建时间 :2017-05-17

************************************************/ void lock_PROG(void) {

FLASH_IAPSR &= (~0x02); }

/*********************************************** * 函数名 :lock_DATA

&& (temp_Valid_flag[2]==0x33) &&

/* Warning: keys are reversed on data * 描述 :使能EEPROM保护 * 创建时间 :2017-05-17

************************************************/ void lock_DATA(void) {

FLASH_IAPSR &= (~0x08); }

/*********************************************** * 函数名 :WriteFlashword

* 描述 :按字写FLASH/EEPROM * 创建时间 :2017-05-17

************************************************/ u8 WriteFlashword(u32 DataAddress, u16 DataBuffer) {

u32 Address = DataAddress; u16 DataPointer = DataBuffer; unlock_PROG(); unlock_DATA();

*((__far u8*) Address) = *((u8 *)(&DataPointer)); /* Write one byte - from lowest address*/ *((__far u8*)(Address + 1)) = *((u8 *)(&DataPointer) + 1); /* Write one byte*/

while(FLASH_IAPSR & 0x04 == 0); lock_PROG(); lock_DATA(); return 1; }

/*********************************************** * 函数名 :WriteBufferFlash

* 描述 :写4字节FLASH/EEPROM * 创建时间 :2017-05-17

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

u8 WriteBufferFlash(u32 DataAddress, u8 *DataBuffer, u16 DataCount) {

u32 Address = (u32)DataAddress; u8 *DataPointer = DataBuffer; unlock_PROG(); unlock_DATA();

while(DataCount >= 4) {

FLASH_CR2 |= (uint8_t)0x40;

*((__far u8*) Address) = (u8)*DataPointer ; /* Write one byte - from lowest address*/ *((__far u8*)(Address + 1)) = *(DataPointer + 1); /* Write one byte*/ *((__far u8*)(Address + 2)) = *(DataPointer + 2); /* Write one byte*/

*((__far u8*)(Address + 3)) = *(DataPointer + 3); /* Write one byte - from higher address*/

while((FLASH_IAPSR & (0x04 | 0x01)) == 0); Address += 4; DataPointer+= 4; DataCount -= 4; }

lock_PROG(); lock_DATA(); return 1; }

/*********************************************** * 函数名 :WriteBuffer

* 描述 :写FLASH/EEPROM * 创建时间 :2017-05-17

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

u8 WriteBuffer(u32 DataAddress, u8 *DataBuffer, u8 DataCount,FLASH_TypeDef MemType)

{

if(MemType == FLASH_PROG) //for Flash {

if((DataAddress >= FLASH_START) && ((DataAddress + DataCount - 1) <= FLASH_END)) return WriteBufferFlash(DataAddress, DataBuffer, DataCount); }

else //for EEPROM {

if((DataAddress >= EEPROM_START) && ((DataAddress + DataCount - 1) <= EEPROM_END)) return WriteBufferFlash(DataAddress, DataBuffer, DataCount); }

return 0; }

/*********************************************** * 函数名 :DataFlashRead * 描述 :读FLASH/EEPROM * 创建时间 :2017-05-17

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

void DataFlashRead(u32 DataAddress,u8 *DataBuffer,u8 DataCount) {

for(u8 i = 0; i < DataCount; i++) {

DataBuffer[i] = (*(__far u8*)(DataAddress + i)); //__far 返回32bit } }

/*********************************************** * 函数名 :FLASH_EraseBlock * 描述 :读FLASH/EEPROM * 创建时间 :2017-05-17

************************************************/ __ramfunc void FLASH_EraseBlock(u32 Address) {

u8 __far *pwFlash = (__far u8 *)Address; /* Enable erase block mode */ FLASH_CR2 |= 0x20;

//*((__far u32*)Address) = (u32)0; *pwFlash = 0; *(pwFlash+1) = 0; *(pwFlash+2) = 0; *(pwFlash+3) = 0; }

/*********************************************** * 函数名 :Clean_savespace * 描述 :清除存储空间 * 创建时间 :2017-05-17

************************************************/ void Clean_savespace(u16 BlockNum, u8 Count) {

u32 address;u8 i;

unlock_PROG(); unlock_DATA();

for(i=0; i

address = (u32)(0x00008000 + (u32)(BlockNum+i) * 128);

FLASH_EraseBlock(address); //Delay_ms(6); }

lock_PROG();

远指针 指针指向的地址与数据段的段地址不同 lock_DATA(); }

void Jump_To_App(void) {

asm(\ SP \ asm(\ A, $FF\ asm(\ XL, A \ asm(\, X \

asm(\ //B800是要跳转到偏移地址 }

void Jump_To_RESET(void) {

asm(\ SP \ asm(\ A, $FF\ asm(\ XL, A \ asm(\, X \

asm(\ //8000是要跳转到偏移地址 }

(3)串口函数

#define Rev_counter 600

//7E CMD LenH LenL......CrcH CrcL E7

typedef struct ud {

u8 Receive_data[Rev_counter]; //数据接收 u16 Total_Bytes; //总字节数

u16 Single_Counter; //单包数据计数器

u16 Total_Bytes_Counter; //总接收数据个数计数器

}uart_D;

uart_D Uart_data; bool CMD_flag=FALSE; bool RECE_flag=FALSE;

u8 Valid_flag[4]={0x11,0x22,0x33,0x44};

//#include \

/*********************************************** * 函数名 :uart_init

* 描述 :串口初始化 * 创建时间 :2017-05-17

************************************************/ void uart_init(void) {

CLK_PCKENR1 |= 0x20; //使能串口时钟

//USART1_BRR2 = 0x03;

//USART1_BRR1 = 0x68; //波特率9600 USART1_BRR2 = 0x0b;

USART1_BRR1 = 0x08; //波特率115200

USART1_CR2 |= 0x0c;

USART1_CR2 &= ~0x20; //禁止接收中断 USART1_CR1 &= ~0x20;

PC_DDR |= 0x08; //PC3输出口 TXD管脚必须设置为输出推挽,否则不能发送数据 PC_CR1 |= 0x08; //PC3推挽输出 PC_CR2 |= 0x08; //PC3输出速度最大为10MHZ PC_ODR &= ~0x08; //PC3输出低 }

u8 uart_receive(void) //轮询接收串口数据 {

u8 sr;

u8 Receivedata;

sr = USART1_SR;

while(!(sr & 0x20)) //接收数据准备好读 sr = USART1_SR;

if(sr & 0x09) //有溢出和奇偶校验错误 {

Receivedata = USART1_DR;

return 0; }

if(Uart_data.Single_Counter < Rev_counter)

Uart_data.Receive_data[Uart_data.Single_Counter++] = USART1_DR;

if(CMD_flag == TRUE) //接收到升级总字节数后,开始接收升级数据 {

Uart_data.Total_Bytes_Counter++;

if(Uart_data.Total_Bytes == Uart_data.Total_Bytes_Counter) RECE_flag=TRUE; }

Uart_Deal(); return 1; }

/*********************************************** * 函数名 :uart_send

* 描述 :串口发送一个字节 * 创建时间 :2017-05-17

************************************************/ void uart_send(u8 sdata) {

while(!(USART1_SR & 0x80)); //没有数据移动

USART1_DR = sdata;

while(!(USART1_SR & 0x40)); //等待发送完成 }

void Uart_Deal(void) {

u8 LenL;

u16 LenH,LEN; u8 CrcL;

u16 CRC,CrcH,CRC_temp; u8 CMD;

u16 Total_Byte_H; u8 Total_Byte_L;

if(CMD_flag == FALSE) //先接收总字节数 {

if(Uart_data.Receive_data[0] == 0x7E) {

if(Uart_data.Single_Counter == 4) //接收到LEN {

LenH = Uart_data.Receive_data[2]; LenL = Uart_data.Receive_data[3];

LEN = (LenH<<8 | LenL); }

else if(Uart_data.Single_Counter == (LEN+7)) //接收完一帧数据 {

if(Uart_data.Receive_data[LEN+6] == 0xE7) //包尾 {

CrcH = Uart_data.Receive_data[LEN+4]; CrcL = Uart_data.Receive_data[LEN+5];

CRC = (CrcH<<8 | CrcL);

CRC_temp = GlobFun_CRC_Check(Uart_data.Receive_data,(LEN+4)); //校验包头

CMD = Uart_data.Receive_data[1];

if(CRC == CRC_temp) {

if(CMD == 0x01) //升级命令 {

Total_Byte_H = Uart_data.Receive_data[4]; Total_Byte_L = Uart_data.Receive_data[5];

Uart_data.Total_Bytes = (Total_Byte_H<<8 | Total_Byte_L); //接收总字节数

Uart_data.Total_Bytes_Counter = 0; //总字节数计数器

CMD_flag = TRUE; //开始接收升级数据标志

uart_send(0x55);

}

}

Uart_data.Single_Counter = 0; //不管校验是否通过都清零计数器 } } } else

Uart_data.Single_Counter = 0; //接收不到包头就清零计数器 }

else //接收升级数据 {

if(RECE_flag==TRUE) //接收到全部升级数据 {

WriteBufferFlash(APP_start_address,Uart_data.Receive_data,600); //向APP区写数据

WriteBufferFlash(APP_Valid_address,Valid_flag,4); //写APP存在标志

Jump_To_RESET(); //复位 } } }

(4)CRC校验函数

u8 auchCRCHi[] = { /* CRC 高位字节表 */ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 };

u8 auchCRCLo[] = { /* CRC 低位字节表*/ 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 };

u16 GlobFun_CRC_Check(u8 *L_CRC_Buffer,u8 L_CRC_Len) {

u16 CRC_Result=0; u16 L_CRC_Index = 0; u8 L_CRC_H = 0xff; u8 L_CRC_L = 0xff; u8 I_CRC_Msb=0; u8 I_CRC_Lsb=0;

//L_CRC_Buffer++; //不包括对包头0x7E的校验

while(L_CRC_Len--) {

L_CRC_Index = L_CRC_H ^ *L_CRC_Buffer++; L_CRC_H = L_CRC_L ^ auchCRCHi[L_CRC_Index]; L_CRC_L = auchCRCLo[L_CRC_Index]; }

I_CRC_Msb = L_CRC_L; I_CRC_Lsb = L_CRC_H;

CRC_Result=(I_CRC_Lsb<<8)|I_CRC_Msb;

return CRC_Result; }

(5)lnkstm8l052r8_boot.icf

///////////////////////////////////////////////////////////////// // Example ILINK command file for

// STM8 IAR C/C++ Compiler and Assembler. //

// Copyright 2014 IAR Systems AB. //

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

define memory with size = 16M;

define region TinyData = [from 0x00 to 0xFF];

define region NearData = [from 0x0000 to 0x0FFF];

define region Eeprom = [from 0x1000 to 0x10FF];

define region BootROM = [from 0x6000 to 0x67FF];

define region NearFuncCode = [from 0x8000 to 0xD7FF];

define region FarFuncCode = [from 0x8000 to 0xD7FF];

define region HugeFuncCode = [from 0x8000 to 0xD7FF]; /*

define region NearFuncCode = [from 0x8000 to 0xFFFF];

define region FarFuncCode = [from 0x8000 to 0xFFFF]

| [from 0x10000 to 0x17FFF];

define region HugeFuncCode = [from 0x8000 to 0x17FFF]; */

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

define block CSTACK with size = _CSTACK_SIZE {};

define block HEAP with size = _HEAP_SIZE {};

define block INTVEC with size = 0x80 { ro section .intvec };

// Initialization

initialize by copy { rw section .far.bss,

rw section .far.data,

rw section .far_func.textrw, rw section .huge.bss, rw section .huge.data,

rw section .huge_func.textrw, rw section .iar.dynexit, rw section .near.bss, rw section .near.data,

rw section .near_func.textrw, rw section .tiny.bss, rw section .tiny.data, ro section .tiny.rodata };

initialize by copy with packing = none {section __DLIB_PERTHREAD };

do not initialize { rw section .eeprom.noinit, rw section .far.noinit, rw section .huge.noinit, rw section .near.noinit, rw section .tiny.noinit, rw section .vregs };

// Placement

place at start of TinyData { rw section .vregs }; place in TinyData { rw section .tiny.bss,

rw section .tiny.data, rw section .tiny.noinit, rw section .tiny.rodata };

place at end of NearData { block CSTACK }; place in NearData { block HEAP,

rw section __DLIB_PERTHREAD, rw section .far.bss, rw section .far.data, rw section .far.noinit,

rw section .far_func.textrw, rw section .huge.bss, rw section .huge.data, rw section .huge.noinit,

rw section .huge_func.textrw, rw section .iar.dynexit, rw section .near.bss, rw section .near.data, rw section .near.noinit,

rw section .near_func.textrw };

place at start of NearFuncCode { block INTVEC };

place in NearFuncCode { ro section __DLIB_PERTHREAD_init, ro section .far.data_init,

ro section .far_func.textrw_init, ro section .huge.data_init,

ro section .huge_func.textrw_init, ro section .iar.init_table, ro section .init_array,

ro section .near.data_init, ro section .near.rodata, ro section .near_func.text, ro section .near_func.textrw_init,

ro section .tiny.data_init, ro section .tiny.rodata_init };

*/ 4、将lnkstm8l052r8_boot.icf和lnkstm8l052r8_App.icf,放置在安装目录下的config文件夹下面,(“C:\\Program Files\\IAR Systems\\Embedded Workbench 7.0\\stm8\\config”),否则有些功能可能不能实现。

5、需要在Opition中的LINK选项下链接“$TOOLKIT_DIR$\\config\\lnkstm8l052r8_boot.icf”“$TOOLKIT_DIR$\\config\\lnkstm8l052r8_App.icf”,否则不能实现在线升级。不能运行App程序。 6、bootloader工程接收并向Flash中写完App工程的数据后,会向APP_Valid_address地址写入temp_Valid_flag数组的数据,然后软件复位,重新开始运行bootloader程序,检测到APP_Valid_address地址的数据有效后,就跳向App起始地址开始运行App程序。

7、 用串口助手(sscom3)发送升级命令7E 01 00 02 02 56 17 5B E7,其中02 56是要升级的总字节数(要根据自己的文件大小更改),17 58是16位的CRC校验(命令不同校验码不同),7E、E7分别是包头和包尾,01是命令,发送完升级命令后,bootloader程序会发送0x55到串口助手,然后再发送你要升级的文件(升级文件用的.bin格式),发送完成后蜂鸣器每隔一秒响一次。

8、因为百度文库不能上传压缩包,只能上传文档,所以大部分的程序只能都贴到word里了,看着有些费劲,但是大部分的程序都贴出来了,想学习在线升级的朋友就不要嫌麻烦,自己建立工程整理代码吧!

本文来源:https://www.bwwdw.com/article/o53r.html

Top