本帖最后由 电脑小白 于 2018-7-18 15:56 编辑
重磅出击,全球独此一份代码。原子大大,求票票,求酷贴,求置顶。
PS: 此IAP是用超级终端工具通过串口发送bin文件进行升级操作的!
附件中有app的demo工程和bootloader工程源码。
新添加了:工程地址设置说明(设置地址很重要,要不然没法从bootloader跳到app里去运行)。见新的附件。
Copyright 2016-2020 Alex.Fang All rights reserved.
Header: stm8s105c6t6 IAP code
File Name: main.c
Author: Alex.Fang (www.openedv.com username=电脑小白)
Date: 2016-07-22
免责声明:
此代码你可以用来学习和交流。不得商用!应用此程序酿成事故由你自己承担!
本人不负责维护和支持此代码!如有疑问和看不懂别来烦我! ^_^
openedv论坛好友可以随便下载和转给他人参阅学习。
版权遵循 = GPL
开发环境为IAR的代码和范例:见39楼另一大神贡献的补充帖子。
main.c 代码内容:
[mw_shl_code=c,true]
/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include <stdio.h>
#include "stm8s.h"
#include "stm8s_clk.h"
#include "main.h"
//#include "stm8s_wwdg.h"
#include "delay.h"
#include "flash.h"
#include "stm8s_flash.h"
#include "config.h"
#include "IO_config.h"
#include "crc16.h"
#include "xmodem.h"
#include "stm8s_uart2.h"
#include "uart2.h"
//#include "stm8s_tim2.h"
//#include "wwdg.h"
//#define NGI() _asm("sim"); /* 禁止全局中断 */
//#define EGI() _asm("rim"); /* 使能全局中断 */
//#define WFI() _asm("halt"); /*进入到低功耗模 WFI */
/* Private defines -----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
//address for GO command
//TFunction GoAddress;
void STM8_CLK_Init(void)
{
CLK_DeInit();//复位时钟寄存器
CLK_HSICmd(ENABLE);//HSI = 16MHz
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); //f_psc = 16MHz/1
//CLK_ClockSecuritySystemEnable();//开启时钟安全系统
//enableInterrupts();
}
void system_init(void)
{
STM8_CLK_Init();
FLASH_DeInit();
Init_GPIO();
Init_UART2();
}
void main(void)
{
//_asm("sim");//关全部中断
disableInterrupts();
system_init();
//_asm("rim");//开全部中断
enableInterrupts();
uart2_data("\r\n\r\n",4);
uart2_data("Bootloader Start...\r\n",21);
uart2_data("Ver=20160722_1.0\r\n",18);
disableInterrupts();
//unlock_PROG();
//unlock_DATA();
//Print("goto app...\r\n");
//goto_app();
//Print("Failed!\r\n");
//waiting_time_count=200;
Xmoden_STate = IDLE;
//RS232_Tran_Chr(NAK);
disp_menu();
while (1)
{
RS232_ISR();
RS232_Rec_Xmodem();
}//end while
}
[/mw_shl_code]
xmode.c 代码如下:
[mw_shl_code=c,true]
uchar RS232_Rec;
uchar RS232_Rec_old;
uchar RS232_Rec_flag=0;
//uchar RS232_Trn_flag=1;
enum TXmoden_STate Xmoden_STate = IDLE;
uchar Xmodem_Buffer[135]; /* 128 for XModem + 3 head chars + 2 crc + nul */
//uchar Xmodem_Buffer_Ptr=0;
//uchar ChkSum=0;
//uchar PSer=1,PT=0;
//uchar xerror;
uint16_t waiting_time_count=HOLDTIME;
uint32_t App_address=0;
/*******************************************************************************
** 函数名称 : check
** 功能描述 : 校验,CRC为真则为CRC校验,否则为校验和
** 入口参数 : <crc>[in] 选择是CRC校验还是SUM校验
** <buf>[in] 校验的原始数据
** <sz>[in] 校验的数据长度
** 出口参数 : 无
** 返 回 值 : 校验无误返回TURE,反之返回FALSE
** 其他说明 : 无
*******************************************************************************/
static int check(int crc, const unsigned char *buf, int sz)
{
if (crc){
unsigned short crc = crc16_ccitt(buf, sz);
unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
if (crc == tcrc)
return TRUE;
}
else{
int i;
unsigned char cks = 0;
for (i = sz; i != 0; i--){
cks += *(buf++);
}
if (cks == *buf)
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------
void RS232_ISR(void)
{
Receive(&RS232_Rec,100);
//Transmit(RS232_Rec);
RS232_Rec_flag = 1;
}
//----------------------------------------------------------
void RS232_Tran_Chr(uchar chr)
{
Transmit(chr);
}
void disp_menu(void)
{
Print("\r\n----------bootloader----------\r\n");
Print("1.download\r\n");
Print("2.goto app\r\n");
Print("------------------------------\r\n");
Print("Please choose (1 or 2):\r\n");
Print("Timeout = [ ");
}
void disp_1(void)
{
Print("\r\nPress = 1\r\n");
Print("Choose file...\r\n ");
}
void disp_2(void)
{
Print("\r\nPress = 2\r\n");
Print("Goto app...");
delay_ms(20);
goto_app();
Print("\r\nFailed!\r\n\r\n");
waiting_time_count=HOLDTIME;
Xmoden_STate = IDLE;
disp_menu();
}
void RS232_Rec_Xmodem(void)
{
uint8_t packetno = 1;
uint8_t bufsz;
uint8_t crc = 1;//启用CRC校验
uint16_t i=0;
//uint16_t j=0;
if(Xmoden_STate == IDLE){
if(waiting_time_count!=0){
waiting_time_count--;
RS232_Tran_Chr(8);
RS232_Tran_Chr(8);
RS232_Tran_Chr(8);
RS232_Tran_Chr(8);
RS232_Tran_Chr(8);
//RS232_Tran_Chr('[');
RS232_Tran_Chr(waiting_time_count/100%10+'0');
RS232_Tran_Chr(waiting_time_count/10%10+'0');
RS232_Tran_Chr(waiting_time_count%10+'0');
RS232_Tran_Chr(']');
RS232_Tran_Chr(' ');
delay_ms(100);
}
else {
Print("\r\nTimeout,goto_app!\r\n");
delay_ms(20);
goto_app();
Print("\r\nFailed!");
waiting_time_count=HOLDTIME;
disp_menu();
}
if(RS232_Rec_flag)
{
if(RS232_Rec_old!=RS232_Rec){
RS232_Rec_old=RS232_Rec;
waiting_time_count=HOLDTIME;
if(RS232_Rec == 13){//回车
disp_menu();
}
else if(RS232_Rec == '1'){
disp_1();
waiting_time_count=50;
Xmoden_STate = WSTART;
//RS232_Tran_Chr(NAK);
}
else if(RS232_Rec == '2'){
disp_2();
}
}
RS232_Rec_flag=0;
}
return;
}
if(RS232_Rec_flag)
{
RS232_Rec_flag=0;
if((RS232_Rec == 'B')||(RS232_Rec == 'b')) {
RS232_Rec=0;
waiting_time_count=HOLDTIME;
Xmoden_STate = IDLE; //进入"空闲"状态
disp_menu();
}
else if(RS232_Rec==SOH){ //开始传输文件
bufsz=128;
App_address=MAIN_USER_RESET_ADDR;
while(RS232_Rec==SOH){//接收到有效数据帧头
Xmodem_Buffer[0]=RS232_Rec;
for(i=0;i<132;i++){//接收一帧数据
Receive(&Xmodem_Buffer[i+1],10000UL);
//Receive_while(&Xmodem_Buffer[i+1]);
}
if((Xmodem_Buffer[1]==(uint8_t)~Xmodem_Buffer[2])&&(packetno==Xmodem_Buffer[1])//包序号无误
&&(check(crc, &Xmodem_Buffer[3], bufsz))){//CRC校验无误
packetno++;
//
firmware_option();
App_address+=128;
//delay_ms(1);
Transmit(ACK);
}
else {//要求重发
Transmit(NAK);
}
//delay_ms(10);
//Transmit(ACK);
waiting_time_count=1000;
do {
Receive(&RS232_Rec,1000);//读取下一帧数据的帧头
}while((RS232_Rec!=SOH)&&(waiting_time_count--));
if(waiting_time_count==0)break;
}
Transmit(ACK);
Receive(&RS232_Rec,10000);
if(RS232_Rec==EOT){//文件发送结束标志
Transmit(ACK);
}
eraser_option();
waiting_time_count=HOLDTIME;
Xmoden_STate = IDLE; //进入"空闲"状态
disp_menu();
}
else {
if(waiting_time_count!=0){
waiting_time_count--;
delay_ms(100);
}
else {
waiting_time_count=20;
Transmit('C');//crc
//Transmit(NAK);//sum
}
}
}
}
//本函数的调用方式如下:
// Xmoden_STate = WSTART;
// RS232_Tran_Chr(NAK);
// while(Xmoden_STate != IDLE) RS232_Rec_Xmodem();
/*
void firmware_option(void)
{
uint16_t i=0;
uint16_t j=0;
uint8_t FULL_status=0;
//uint8_t * p_str=pstr;
FLASH_Unlock(FLASH_MEMTYPE_PROG);
for(i=0;i<125;i++){
if((Xmodem_Buffer[i+3]==CTRLZ)&&(Xmodem_Buffer[i+4]==CTRLZ)&&(Xmodem_Buffer[i+5]==CTRLZ))
{
FULL_status=1;
j=i;
break;
}
}
if(FULL_status==0){
//App_address
for(i=0;i<128;i++){
FLASH_EraseByte(App_address+i);
//delay_ms(1);
FLASH_ProgramByte(App_address+i,Xmodem_Buffer[3+i]);
}
}
else {
//App_address
for(i=0;i<j;i++){
FLASH_EraseByte(App_address+i);
//delay_ms(1);
FLASH_ProgramByte(App_address+i,Xmodem_Buffer[3+i]);
}
}
FLASH_Lock(FLASH_MEMTYPE_PROG);
}
*/
void firmware_option(void)
{
uint16_t i=0;
//uint8_t * p_str=pstr;
FLASH_Unlock(FLASH_MEMTYPE_PROG);
//App_address
for(i=0;i<128;i++){
FLASH_EraseByte(App_address+i);
//delay_ms(1);
FLASH_ProgramByte(App_address+i,Xmodem_Buffer[3+i]);
}
FLASH_Lock(FLASH_MEMTYPE_PROG);
}
void eraser_option(void)
{
uint16_t i=0;
//uint8_t * p_str=pstr;
FLASH_Unlock(FLASH_MEMTYPE_PROG);
//App_address
while(FLASH_ReadByte(App_address-1)==CTRLZ){
FLASH_EraseByte(App_address-1);
App_address--;
}
FLASH_Lock(FLASH_MEMTYPE_PROG);
}
[/mw_shl_code]
串口IAP升级操作步骤说明 1、准备工作 先拷贝升级所需要的文件到桌面。 (Win xp有自带的超级终端,怎么打开xp自带的超级终端这里不做介绍) Win7和win10需要自行下载超级终端软件。 2、打开超级终端,如下图
1
3、打开后弹出新建连接对话框,点击cancel(不新建,若没有提前配置好的需要新建)。 如果从没有打开过超级终端,那么将会提示输入国家代号和拨号,如下: 国家代号输入:020 拨号:123(随便填) 分号:456(随便填) 拨号模式选择:脉冲拨号。
2
4、打开配置好的配置文件:File->open
3
5、找到driver文件夹下ttys9600.ht文件 (有时候需要自己去建立超级终端配置,,如何配置这里不做介绍)
4
6、进入升级模式 输入enter回车键,会自动返回当前mcu的版本号入下图。(查询当前mcu版本) 连续输入5次空格键将进入升级模式。(注意要30秒内要按下数字键1) 升级模式返回如下显示: Bootloader start... 1---下载bin文件 2---运行下载好的bin固件
5
7、键盘在timeout不等于0的时间内输入“1”。Timeout=0时会自动退出升级模式的。 输入1以后会进入发送固件模式。如下图: 选择要发送的bin文件。Transfer-->Send file...
6
8、发送升级bin固件 Protocol要选择为xmode.注意不是1k-xmode。Browse找到driver下的bin固件。 点击send开始传输。
7
9、找到文件如下:
8
10、加载文件后,并选择好xmode协议传输。 点击send后将开始传输固件到mcu。
9
11、传输文件过程。
10
11
12
12、文件传输完毕。 自动进行30秒倒计时。 30内没有按键按下将自动退出升级模式,执行刚更新的固件。 此时间段内如果按下数字键2,将立即退出升级模式并执行刚更新的固件。
13
13、按下了数字键2后,退出升级模式如下图: 按下1会提示:press=1 按下2会提示:press=2 出现“start...”提示,就是升级完成已经在运行新的固件了。
14
14、至此升级操作已经完成。
|