基于Ymodem协议的stm32f405rgt6+CubeMx+IAP在线升级
基于Ymodem协议的stm32f405rgt6+CubeMx+IAP在线升级
目录
一、CubeMX的配置
1.IAP
2.APP
二、移植Ymodem官方代码
1.文件移植
2.MDK文件、路径添加
3.修改代码
(1)删除不必要的代码
(2)修改IAP代码
(3)修改APP代码
三、烧录、测试
准备工作:
1.STM32F4开发板
2.USB转串口工具
3.MDK Keil5
4.CubeMX
5.secureCRT上位机软件
6.en.stsw-stm32067官方固件库
工程下载地址:
Ymodem_IAP_F405_CubeMx+secureCRT上位机软件
一、CubeMX的配置
需要配置IAP和APP两个工程,这两个工程的配置都比较简单
1.IAP
打开CubeMX软件,选好芯片型号,这里我的芯片型号是STM32F405RGT6
配置时钟
配置主时钟,我配置的是内部时钟,主频为168MHz
配置串口
我这里配置的是串口1,对应引脚为PA9和PA10,波特率为115200,串口采用轮询的方式通讯,不采用中断的方式,故不配置串口中断,其他默认。
生成代码
H和C文件分开,配置完成后,生成代码,为后续IAP移植修改作准备
2.APP
需要再配置一个APP工程,做一个简单的APP,就是让一个LED灯不断闪烁。
这里简单的配置了PB12口为输出,作为LED灯,其他配置过程这里就省略了。
二、移植Ymodem官方代码
1.文件移植
打开之前生成好的IAP工程目录,在该目录下新建一个Ymodem的文件夹
打开我们从官网下载好en.stsw-stm32067官方固件库,将en.stsw-stm32067->STM32F4xx_AN3965_V1.0.0->Project->STM32F4xx_IAP下的inc和src文件夹中的部分文件复制到新建的Ymodem的文件夹中
复制完的Ymodem的文件夹内容如下,一共8个文件
2.MDK文件、路径添加
打开IAP的MDK工程,添加一个Ymodem组,将Ymodem文件夹中的.c文件添加进去
添加Ymodem文件夹中的.H文件的路径
3.修改代码
完成1和2步后编译工程会报很多错误,需要修改代码
(1)删除不必要的代码
打开common.h文件,删除#include "stm324xg_eval.h" ,这个头文件是官方用在一个官方的开发板上的,我们用不到,故删之
(2)修改IAP代码
- common.c文件
打开common.c文件,在193行有报错,这里官方用的不是HAL库,而且官方用的开发板的接口有不同的定义,因此,我们根据自己的实际情况修改下面的代码
我们将这个函数修改如下,并且要添加一个头文件,从这个函数的内容可知,主要实现接收一个字节
/** @addtogroup STM32F4xx_IAP* @{*//* Includes ------------------------------------------------------------------*/
#include "common.h"
#include "usart.h" //添加的头文件
/* Private typedef -----------------------------------------------------------*/
/*** @brief Test to see if a key has been pressed on the HyperTerminal* @param key: The key pressed* @retval 1: Correct* 0: Error*/
uint32_t SerialKeyPressed(uint8_t *key)
{if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET){*key = (uint16_t)((&huart1)->Instance->DR & (uint16_t)0x01FF); return 1;}else{return 0;}
}
同样,修改下面的代码
修改成这样
/*** @brief Print a character on the HyperTerminal* @param c: The character to be printed* @retval None*/
void SerialPutChar(uint8_t c)
{USART_SendData(USART1, c);while (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) == RESET){}
}
在common.c末尾添加代码,添加void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)函数
//添加代码
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{/* Check the parameters */assert_param(IS_USART_ALL_PERIPH(USARTx));assert_param(IS_USART_DATA(Data)); /* Transmit Data */USARTx->DR = (Data & (uint16_t)0x01FF);
}
在common.h添加声明void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
/* Exported functions ------------------------------------------------------- */
void Int2Str(uint8_t* str,int32_t intnum);
uint32_t Str2Int(uint8_t *inputstr,int32_t *intnum);
uint32_t GetIntegerInput(int32_t * num);
uint32_t SerialKeyPressed(uint8_t *key);
uint8_t GetKey(void);
void SerialPutChar(uint8_t c);
void Serial_PutString(uint8_t *s);
void GetInputString(uint8_t * buffP);//添加声明
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
- flash_if.c文件
修改FLASH_If_Init(void)
修改如下
void FLASH_If_Init(void)
{ HAL_FLASH_Unlock();/* Clear pending flags (if any) */ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);}
修改FLASH_If_Erase(uint32_t StartSector)函数
修改成HAL库的方式,修改如下:
/*** @brief This function does an erase of all user flash area* @param StartSector: start of user flash area* @retval 0: user flash area successfully erased* 1: error occurred*/
uint32_t FLASH_If_Erase(uint32_t StartSector)
{uint32_t UserStartSector;uint32_t SectorError;FLASH_EraseInitTypeDef pEraseInit;/* Unlock the Flash to enable the flash control register access *************//* Get the sector where start the user flash area */UserStartSector = GetSector(APPLICATION_ADDRESS);pEraseInit.TypeErase = TYPEERASE_SECTORS;pEraseInit.Sector = UserStartSector;pEraseInit.NbSectors = GetSector(USER_FLASH_END_ADDRESS)-UserStartSector+1 ;pEraseInit.VoltageRange = VOLTAGE_RANGE_3;if (HAL_FLASHEx_Erase(&pEraseInit, &SectorError) != HAL_OK){/* Error occurred while page erase */return (1);}return (0);}
修改FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data ,uint32_t DataLength)函数
修改成如下:
/*** @brief This function writes a data buffer in flash (data are 32-bit aligned).* @note After writing data buffer, the flash content is checked.* @param FlashAddress: start address for writing data buffer* @param Data: pointer on data buffer* @param DataLength: length of data buffer (unit is 32-bit word) * @retval 0: Data successfully written to Flash memory* 1: Error occurred while writing data in Flash memory* 2: Written Data in flash memory is different from expected one*/
uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data ,uint32_t DataLength)
{uint32_t i = 0;for (i = 0; (i < DataLength) && (*FlashAddress <= (USER_FLASH_END_ADDRESS-4)); i++){/* Device voltage range supposed to be [2.7V to 3.6V], the operation willbe done by word */ FLASH_ProgramWord(*FlashAddress, *(uint32_t*)(Data+i)); /* Check the written value */if (*(uint32_t*)*FlashAddress != *(uint32_t*)(Data+i)){/* Flash content doesn't match SRAM content */return(2);}/* Increment FLASH destination address */*FlashAddress += 4;}return (0);
}
在flash_if.c末尾添加如下函数
void FLASH_ProgramWord(uint32_t Address, uint32_t Data)
{/* Check the parameters */assert_param(IS_FLASH_ADDRESS(Address));/* If the previous operation is completed, proceed to program the new data */CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);FLASH->CR |= FLASH_PSIZE_WORD;FLASH->CR |= FLASH_CR_PG;*(__IO uint32_t*)Address = Data;
}
在flash_if.h添加void FLASH_ProgramWord(uint32_t Address, uint32_t Data)声明
/* Exported functions ------------------------------------------------------- */
void FLASH_If_Init(void);
uint32_t FLASH_If_Erase(uint32_t StartSector);
uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data, uint32_t DataLength);
uint16_t FLASH_If_GetWriteProtectionStatus(void);
uint32_t FLASH_If_DisableWriteProtection(void);//添加声明
void FLASH_ProgramWord(uint32_t Address, uint32_t Data);
#endif /* __FLASH_IF_H */
修改 FLASH_If_GetWriteProtectionStatus(void)函数
修改如下
/*** @brief Returns the write protection status of user flash area.* @param None* @retval 0: No write protected sectors inside the user flash area* 1: Some sectors inside the user flash area are write protected*/
uint16_t FLASH_If_GetWriteProtectionStatus(void)
{uint32_t UserStartSector = FLASH_SECTOR_1;/* Get the sector where start the user flash area */UserStartSector = GetSector(APPLICATION_ADDRESS);/* Check if there are write protected sectors inside the user flash area */if ((*(__IO uint16_t *)(OPTCR_BYTE2_ADDRESS) >> (UserStartSector/8)) == (0xFFF >> (UserStartSector/8))){ /* No write protected sectors inside the user flash area */return 1;}else{ /* Some sectors inside the user flash area are write protected */return 0;}
}
修改FLASH_If_DisableWriteProtection(void)函数
修改如下
/*** @brief Disables the write protection of user flash area.* @param None* @retval 1: Write Protection successfully disabled* 2: Error: Flash write unprotection failed*/
uint32_t FLASH_If_DisableWriteProtection(void)
{__IO uint32_t UserStartSector = FLASH_SECTOR_1, UserWrpSectors = OB_WRP_SECTOR_1;/* Get the sector where start the user flash area */UserStartSector = GetSector(APPLICATION_ADDRESS);/* Mark all sectors inside the user flash area as non protected */ UserWrpSectors = 0xFFF-((1 << (UserStartSector/8))-1);/* Unlock the Option Bytes */HAL_FLASH_Unlock();/* Disable the write protection for all sectors inside the user flash area */FLASH_OB_DisableWRP(UserWrpSectors, FLASH_BANK_1);/* Start the Option Bytes programming process. */ if (HAL_FLASH_OB_Launch( ) != HAL_OK){/* Error: Flash write unprotection failed */return (2);}/* Write Protection successfully disabled */return (1);
}
需在末尾处添加 FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks)函数
HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks)
{HAL_StatusTypeDef status = HAL_OK;/* Check the parameters */assert_param(IS_OB_WRP_SECTOR(WRPSector));assert_param(IS_FLASH_BANK(Banks));/* Wait for last operation to be completed */status = FLASH_WaitForLastOperation(50000);if(status == HAL_OK){ *(__IO uint16_t*)OPTCR_BYTE2_ADDRESS |= (uint16_t)WRPSector; }return status;
}
并在flash_if.h添加函数声明HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);
/* Exported functions ------------------------------------------------------- */
void FLASH_If_Init(void);
uint32_t FLASH_If_Erase(uint32_t StartSector);
uint32_t FLASH_If_Write(__IO uint32_t* FlashAddress, uint32_t* Data, uint32_t DataLength);
uint16_t FLASH_If_GetWriteProtectionStatus(void);
uint32_t FLASH_If_DisableWriteProtection(void);//添加声明
void FLASH_ProgramWord(uint32_t Address, uint32_t Data);
HAL_StatusTypeDef FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);#endif /* __FLASH_IF_H */
修改GetSector(uint32_t Address)函数
修改如下:
/*** @brief Gets the sector of a given address* @param Address: Flash address* @retval The sector of a given address*/
static uint32_t GetSector(uint32_t Address)
{uint32_t sector = 0;if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0)){sector = FLASH_SECTOR_0; }else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1)){sector = FLASH_SECTOR_1; }else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2)){sector = FLASH_SECTOR_2; }else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3)){sector = FLASH_SECTOR_3; }else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4)){sector = FLASH_SECTOR_4; }else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5)){sector = FLASH_SECTOR_5; }else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6)){sector = FLASH_SECTOR_6; }else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7)){sector = FLASH_SECTOR_7; }else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8)){sector = FLASH_SECTOR_8; }else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9)){sector = FLASH_SECTOR_9; }else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10)){sector = FLASH_SECTOR_10; }else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/{sector = FLASH_SECTOR_11; }return sector;
}
- ymodem.h
在ymodem.h文件添加头文件#include "stdint.h"
#include "stdint.h"
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __YMODEM_H_
#define __YMODEM_H_
- main.c文件
在main.c文件添加头文件#include "menu.h"
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "menu.h"
main()函数添加 FLASH_If_Init()和 Main_Menu ()函数
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 */FLASH_If_Init();Main_Menu ();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
编译一下,已经没有错误了
(3)修改APP代码
打开APP工程,while(1)添加如下函数
int main(void)
{/* USER CODE BEGIN 1 */SCB->VTOR = FLASH_BASE | 0x4000; //中断向量表偏移/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12);HAL_Delay(1000);}/* USER CODE END 3 */
}
从IAP的flash_if.h的宏定义可以看出,这里的APP起始地址为0x08004000
生成bin文件,复制
fromelf.exe --bin -o "$L@L.bin" "#L
修改FLASH烧录地址
设置完成后编译一下,生成bin文件
三、烧录、测试
打开secureCRT上位机软件,选好端口,设置好波特率,去掉RTS/CTS的勾,点击连接,如下图
点击选项,选择会话选项,弹出如下窗口,按下图设置好,点击确定
将IAP代烧录到开发板,代码开始执行后,如下图
在下方窗口输入1,此时串口不断接受到'C',如下图所示
选择传输,点击发送Ymodem
选择添加好APP生成的bin文件,点击确定
等待一段时间,等待擦除flash,就会完成传输,此时,在下方窗口输入3,即可运行APP
至此,全部工作已结束
其他待更新。。。。。。
基于Ymodem协议的stm32f405rgt6+CubeMx+IAP在线升级相关推荐
- STM32F103代码远程升级(三)基于YModem协议串口升级程序的实现
文章目录 一.YModem协议简介 二.YModem的数据格式 1.起始帧的数据格式 2.数据帧的数据格式 3.结束帧的数据格式 4.文件传输过程 三.基于Ymodem协议串口升级程序的实现过程 1. ...
- ymodem android,【安卓相关】蓝牙基于Ymodem协议发送bin文件,对硬件设备进行升级。...
最近做的一个安卓项目是使用蓝牙基于Ymodem协议传输bin文件,实现对硬件设备进行升级. 做的过程中遇到了不少困难,用我这半吊子的语文水平,记录一下吧 怎么办,平时对各种文件传输协议真的是知之甚少啊 ...
- STM32 IAP 在线升级原理全解析
点击左上角的"关注",定期更新 STM32 最新资讯,总有你想要的信息! STM32 IAP 在线升级原理全解析 1. 什么是 IAP? IAP(In-Application ...
- 51单片机IAP在线升级
51单片机IAP在线升级 爱矽半导体E85F3325单片机IAP在线升级教程,此处可查看更新及demo下载 文章目录 前言 一.ROM资源 二.KEIL有关知识 1.BL51连接器: 2.LX51连接 ...
- CRC校验原理及STM32 IAP在线升级程序
CRC校验原理: 什么是CRC校验? CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定.循环冗余检查(CRC)是一种数据传输检错功能,对数据 ...
- STM32F429实现USB通过IAP在线升级
1.目标 1.实现STM32对U盘文件的读取. 2.实现STM32拓展外部SDRAM. 3.实现STM32拓展外部Flash. 4.实现内存管理. 5.实现Fatfs文件系统,读写U盘和外部Flash ...
- 基于串口通信的DSP应用程序在线升级方法
摘 要:为解决特殊场合DSP程序升级困难的问题,以TMS320F28035为例,介绍了一种基于串口通信的适合于TMS320C2000系列DSP实现程序更新的在线升级方法.描述了该在线升级方法的基本思 ...
- LPC2478(22)IAP在线升级
目录 1.开发环境 2.特性 3.IAR编译器的相关文件 3.1.icf文件 3.2.IcfEditorFile文件内容 3.3.ddf文件 3.4.board文件 4.IAP相关 4.1.软件复位 ...
- Cortex-M3单片机的IAP在线升级上位机和下位机
最近有个项目要做在线升级功能,我也是第一次做,把学习的过程总结下,希望能够帮助到 其他人吧.本篇博客主要介绍两个部分,下位机和上位机. 首先说下要实现功能: 1.上位机能够把APP的bin文件烧写进下 ...
最新文章
- layer的一种用法,自己画出弹出框样式
- 第41周星期四及Spring学习小结
- mysql测试spring事务是否生效
- math.js:灵活强大的JavaScript数学库
- 基于SQLite+EF6实现一套自己的Key-Value存储管理工具包(3)
- javascript弹出窗口总结
- Selenium Grid
- iOS开发-集成一网通支付
- php如何锁定表,PHPExcel冻结(锁定)表头的简单实现方法
- Ubuntu 下挂ISO到虚拟光驱的方法
- sklearn实战之逻辑回归与制作评分卡
- 图书馆管理系统 13-架构设计
- Linux vi精确匹配
- Mac m1 配置OpenCV (C++)
- ue4超级跳、do once、技能冷却时间
- 软件外包公司工作好不好,以下情况可考虑
- 原生Android 极光推送收到通知后自动点亮屏幕
- PMP考试 项目启动会和项目开工会议的区别(转载)
- 计算机中英语单词翻译,计算机有关的英语单词及翻译
- 2021-09-10 LeetCode_Java:1-5
热门文章
- linux服务器 自动重启 问题排查
- 富士最快计算机,高速处理 富士推出X RAW STUDIO转换软件
- H5实现可拖动的360度环拍物品展示(1)
- 如何将div上下居中,左右居中 有五种(width height定,width height不定 尺寸不固定)
- 杜邦分析模型 java_1.杜邦分析法的核心指标是( )。
- Android res\values-v26\values-v26.xml:9:5-12:13: AAPT: error: resource android:attr/colorError not f
- 攻防世界_MISC_练习区_刷题记录
- 深入浅出:FFmpeg 音频解码与处理AVFrame全解析
- 用Word2003也能给文档加上稿纸(转)
- 2021-06-27 记录最近刷过的数论题(整除分块,MillerRabin素性检测,积性函数,重数)