STM32F103 USB OTA升级BootLoader (一)

news2024/11/13 23:32:01

 1.配置外部高速晶振

 2.勾选USB功能

 3.将USB模式配置Virtual Port Com

 4.将系统主频配置为72M,USB频率配置为48M.

 5.配置好项目名称,开发环境,最后获取代码。

6.修改Flash大小和勾选Use Micro LIB

 

7.修改main.c代码

#include "main.h"
#include "usart.h"
#include "usb_device.h"
#include "gpio.h"
#include "Update.h"

void SystemClock_Config(void);

typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;

void Jump_To_App(uint32_t address)
{
    if (((*(__IO uint32_t*)address) & 0x2FFE0000) == 0x20000000)
    {
        JumpAddress = *(__IO uint32_t*) (address + 4);
        
		Jump_To_Application = (pFunction) JumpAddress;
			
        __set_MSP(*(__IO uint32_t*) address);
		
        Jump_To_Application();
    }
}

int main(void)
{
	uint8_t R_Buff[1] = {0};
	HAL_Init();
	SystemClock_Config();

	MX_GPIO_Init();
	MX_USART1_UART_Init();
	MX_USB_DEVICE_Init();

	printf("STM32F103 Boot Code Start\r\n");
	Read_Flash_Data(R_Buff, 1, FLASH_Updata_Flag_ADDR);
	printf("Bootloader R_Buff = 0x%x\r\n", R_Buff[0]);
	
	while (1)
	{
		
		if(R_Buff[0] == 0x55)
		{
			printf("Jump_To_App = %x\r\n", FLASH_APP_ADDR);
			Jump_To_App(FLASH_APP_ADDR);
		}
		else
		{
			Usart_Data_Handler();
		}
	}
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
  PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 Update.c代码

#include "Update.h"

uint32_t PageError = 0;

void Write_Flash(uint8_t *data, uint16_t DataLen, uint32_t Addr)
{
	uint16_t i = 0;
	uint64_t Data = 0;
    uint64_t temp = 0;
    
	HAL_FLASH_Unlock();
	for(i = 0; i < DataLen; i += 8)
	{
        Data = 0;        
        for(uint8_t j = 0; j < 8; j++)
        {
            temp = data[i + j];
            Data |= temp << 8 * j;
        }
        
		if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, FLASH_APP_ADDR + Addr + i, Data) == HAL_OK)
		{
             
		}
        
       /* printf("0x%16llx   |", Data);
        if(i % 16 == 0 && i != 0)
        printf("\r\n");*/
	}
	HAL_FLASH_Lock();
}


void Write_Updata_Flag_Flash(void)
{
    HAL_FLASH_Unlock();
    HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, FLASH_Updata_Flag_ADDR, 0x55555555);
    HAL_FLASH_Lock();
}

void Erase_Updata_Flag_Flash(void)
{
	FLASH_EraseInitTypeDef EraseInitStruct;
	HAL_FLASH_Unlock();
	EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
	EraseInitStruct.PageAddress        = FLASH_Updata_Flag_ADDR;
	EraseInitStruct.NbPages     = 1;
	if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
	{

    }
    HAL_FLASH_Lock();
}

void Erase_APP_Flash(void)
{
	FLASH_EraseInitTypeDef EraseInitStruct;
	HAL_FLASH_Unlock();
	EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
	EraseInitStruct.PageAddress        = FLASH_APP_ADDR;
	EraseInitStruct.NbPages     = 20;
	if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
	{

    }
    HAL_FLASH_Lock();
}


void Read_Flash_Data(uint8_t* pBuffer, uint32_t NumToRead, uint32_t ReadAddr)
{
    uint32_t i;
    for (i = 0; i < NumToRead; i++)
    {
        *((uint8_t*)pBuffer + i) = *((uint8_t*)ReadAddr + i);
    }
}


#define RX_QUEUE_LENGTH 	2048		
static uint8_t RxQueue[RX_QUEUE_LENGTH];
uint8_t Update_Data[1024 + 10];
static uint16_t RxQueueHead = 0;
static uint16_t RxQueueTail = 0;

typedef enum
{
	RECEIVER_IDLE	= 0,
    RECEIVER_HEAD_H,
    RECEIVER_HEAD_L,
    RECEIVER_CMD,
    RECEIVER_LEN_H,
    RECEIVER_LEN_L,
    RECEIVER_DATA,
    RECEIVER_CHECK,
}RECEIVER_STATE;

typedef enum
{
    UPDATE_IDLE = 0,
	UPDATE_START,	
    UPDATE_STARTING,
    UPDATE_END,
}UPDATE_STATE;

RECEIVER_STATE Receiver_State = RECEIVER_HEAD_H;
UPDATE_STATE Update_State = UPDATE_IDLE;

void OnDataReceived(uint8_t val)
{
	if(((RxQueueTail + 1) % RX_QUEUE_LENGTH) != RxQueueHead)		//queue is not full
	{		
		RxQueue[RxQueueTail++] = val;			                        //save data into queue
		RxQueueTail %= RX_QUEUE_LENGTH;		                    //queue tail++
	}
}

void ClearRxQueue(void)
{
	RxQueueHead = 0;
	RxQueueTail = 0;
	memset(RxQueue, 0, sizeof(RxQueue));
}

static uint16_t GetRxQueueLen(void)
{
	return ((RxQueueTail + RX_QUEUE_LENGTH - RxQueueHead) % RX_QUEUE_LENGTH);
}

uint8_t GetRxQueueData(void)
{
	uint8_t val;
	val = RxQueue[RxQueueHead];
	RxQueueHead = ((RxQueueHead + 1) % RX_QUEUE_LENGTH);
	return val;
}

uint8_t Check_Sum(uint8_t *str, uint16_t len)
{
    uint8_t sum = 0;
    for(;len > 0; len--)
    {
        sum += *str++;
    }
    return sum;
}

bool Usart_Data_Handler(void)
{
    static uint8_t Data;
    static uint8_t Cmd;
    static uint8_t Check;
    static uint8_t Send_Data[10];
    static uint16_t Update_Pack_Num;
    static uint16_t Update_Pack_Num_Temp;
    static uint32_t Update_Data_Len;
    static uint32_t Write_Date_Len;
        
    static uint16_t Receive_Data_Len;
    static uint16_t Receive_Data_Count;
     
    
    while(GetRxQueueLen() > 0)
    {	
        Data = GetRxQueueData();
        
        if(Receiver_State == RECEIVER_HEAD_H)
        {
            if(Data == 0x55)
            {
                Receiver_State++;
            }
        }
        else if(Receiver_State == RECEIVER_HEAD_L)
        {
            if(Data == 0x55)
            {
                Receiver_State++;
            }
        }
        else if(Receiver_State == RECEIVER_CMD)
        {
            Receiver_State++;
            Receive_Data_Len = 0;
            Receive_Data_Count = 0;
            Cmd = Data;
            if(Cmd == 0x00)
            {
                printf("Cmd == 0x00\r\n");
            }else if(Cmd == 0x01)
            {
                Update_State = UPDATE_START;
                Update_Pack_Num = 0;
                Write_Date_Len = 0;
                printf("Update_State UPDATE_START\r\n");
            }
            else if(Cmd == 0x02)
            {
                Update_State = UPDATE_STARTING;
                printf("Update_State UPDATE_STARTING\r\n");
            }
            else if(Cmd == 0x03)
            {
                Update_State = UPDATE_END;
                printf("Update_State UPDATE_END\r\n");
            }                
        }
        else if(Receiver_State == RECEIVER_LEN_H)
        {
            Receiver_State++;
            Receive_Data_Len |= Data << 8;
        }
        else if(Receiver_State == RECEIVER_LEN_L)
        {
            Receiver_State++;
            Receive_Data_Len |= Data;
            if(Receive_Data_Len == 0)
            {
                Receiver_State = RECEIVER_CHECK;
            }
        }
        else if(Receiver_State == RECEIVER_DATA)
        {
            Update_Data[Receive_Data_Count++] = Data;
            
            if(Cmd == 0x01)
            {
                if(Receive_Data_Count == 4)
                {
                    Update_Data_Len = 0;
                    Update_Data_Len |= Update_Data[0] << 24;
                    Update_Data_Len |= Update_Data[1] << 16;
                    Update_Data_Len |= Update_Data[2] << 8;
                    Update_Data_Len |= Update_Data[3];
                }
            }
            else if(Cmd == 0x02)
            {
                if(Receive_Data_Count == 2)
                {
                    Update_Pack_Num_Temp = 0;
                    Update_Pack_Num_Temp |= Update_Data[0] << 8;
                    Update_Pack_Num_Temp |= Update_Data[1];
                }
            }
            
            if(Receive_Data_Count == Receive_Data_Len)
            {
                Receiver_State++;
            }
        }
        else if(Receiver_State == RECEIVER_CHECK)
        {
            Receiver_State = RECEIVER_HEAD_H;
            Check = Data;
            
            Send_Data[0] = 0x55;
            Send_Data[1] = 0x55;
            Send_Data[2] = Cmd;
            Send_Data[3] = 0x00;
            if(Update_State == UPDATE_START)
            {
                Erase_APP_Flash();  
                printf("Erase_APP_Flash\r\n");
                printf("Update_Data_Len = %d\r\n", Update_Data_Len);                
                
                Send_Data[4] = 0x00;
                Send_Data[5] = 0x00;
                CDC_Transmit_FS(Send_Data, 6);
            }
            else if(Update_State == UPDATE_STARTING)
            {
                if(Update_Pack_Num_Temp == Update_Pack_Num)
                {
                    Check = Check_Sum(Update_Data, Receive_Data_Len);
                    if(Check == Data)
                    {
                        Update_Pack_Num++;
                        Write_Flash(&Update_Data[2], Receive_Data_Len - 2, Write_Date_Len);
                        Write_Date_Len += Receive_Data_Len - 2;
                        printf("Receive Update_Pack_Num = %d\r\n", Update_Pack_Num_Temp);
                        printf("Write_Date_Len = %d, Update_Data_Len = %d\r\n", Write_Date_Len, Update_Data_Len);
                    }
                    else
                    {
                        printf("Check Error Check = %d, ReceCheck = %d \r\n", Check, Data);
                    }
                }
                
                if(Write_Date_Len == Update_Data_Len)
                {
                    Send_Data[2] = 0x03;
                    Send_Data[3] = 0x00;
                    Send_Data[4] = 0x00;
                    Send_Data[5] = 0x00;
                    CDC_Transmit_FS(Send_Data, 6);
                    Erase_Updata_Flag_Flash();
                    Write_Updata_Flag_Flash();
                    printf("Upgrade successfully \r\n");
                    NVIC_SystemReset();
                }
                else
                {
                    Send_Data[4] = 0x02;
                    Send_Data[5] = Update_Pack_Num >> 8;
                    Send_Data[6] = Update_Pack_Num;
                    Send_Data[7] = Check_Sum(&Send_Data[5], 2);
                    CDC_Transmit_FS(Send_Data, 8);
                }
            }
            else if(Update_State == UPDATE_END)
            {
                Send_Data[4] = 0x00;
                Send_Data[5] = 0x00;
                CDC_Transmit_FS(Send_Data, 6);
            }
        }
    }
}

void Usart_Get_Data_Handler(void)
{
	if(!Usart_Data_Handler())
	{
		return;
	}
}

Update.h代码

#ifndef __UPDATE_H
#define __UPDATE_H

#include "main.h"
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "usbd_cdc_if.h"

#define FLASH_Page_Size		(2048)
#define FLASH_Updata_Flag_ADDR	(0x08000000 + 9 * FLASH_Page_Size)
#define FLASH_APP_ADDR	(0x08000000 + 10 * FLASH_Page_Size)


void Erase_APP_Flash(void);
void Erase_Updata_Flag_Flash(void);
void Write_Flash(uint8_t *data, uint16_t DataLen, uint32_t Addr);
void Read_Flash_Data(uint8_t* pBuffer, uint32_t NumToRead, uint32_t ReadAddr);


void ClearRxQueue(void);
void OnDataReceived(uint8_t val);
bool Usart_Data_Handler(void);

#endif

 源码链接:跳转链接

上位机升级工具:升级工具

STM32F103 USB OTA升级APP (二):跳转链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/931658.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

跨境新手看过来!各国营销禁忌盘点!别再盲目踩雷了!

本土化是跨境卖家出海制胜的关键因素之一&#xff0c;不管是卖家的产品&#xff0c;还是营销推广策略&#xff0c;都要符合目标市场的习惯&#xff0c;才会有较好的效果。而与此相反的&#xff0c;如果卖家在营销过程中&#xff0c;踩到了营销雷区&#xff0c;那结果也可想而知…

LeetCode 43题:字符串相乘

题目 给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 "2", num2 "3&…

核污水会造成什么影响

目录 1.什么是核污水 2.什么是氚元素 3.氚元素的半衰期 4.核污水对人类健康的影响 5.我们应该采取什么措施保护自己 1.什么是核污水 核污水是指核设施&#xff08;如核电站、核燃料回收厂等&#xff09;产生的含有放射性物质的废水。核污水中可能含有放射性同位素、放射性…

国产化-银河麒麟V10系统及docker的安装

一、最近在研究国产化操作系统&#xff0c;“银河麒麟V10”&#xff0c; 在我电脑本机vmware 15的虚拟机中进行安装测试&#xff1b; 1.点击这里提交产品试用申请&#xff0c;不过只需要随便输入&#xff0c;手机号验证码验证后方可跳转至下载地址产品试用申请国产操作系统、银…

机器学习实战之用 Scikit-Learn 正则化方法解决过拟合详解

你是不是在模型训练中遇到过这样的问题&#xff1a;在训练集上表现得极好&#xff0c;但在测试集上效果不佳&#xff1f;这就是过拟合的问题。 过拟合是模型在训练过程中学到了数据的“噪声”而非规律&#xff0c;导致在未知数据上表现不佳。那么怎么解决这个问题呢&#xff1…

vue3将通用组件注册成全局组件

一、问题重现 我们用过vue的人都知道会有一个components文件夹用来存放我们的通用组件&#xff1a; 这里我的通用组件就有四个&#xff0c;但是有一些是使用评率比较高的&#xff0c;如果很多地方要使用我还得导入相同的组件&#xff0c;写的都是一样的代码&#xff1a; impo…

动态表情包怎么制作?分享一个一键生成gif动图的方法

跟朋友聊天时&#xff0c;经常会用很多有趣的表情包给朋友回复&#xff0c;那么除了利用系统提供的gif动画包&#xff0c;怎么才能完成gif图片制作&#xff08;https://www.gif.cn&#xff09;呢&#xff1f;下面就为大家分享一个一键生成gif动图的方法&#xff0c;通过简单的操…

msvcp110.dll丢失的解决方法,大家最常用的三个解决方法【教程】

win10是一款非常优秀的电脑系统&#xff0c;但有时候也会出现文件错误&#xff0c;比如msvcp110.dll丢失。这个问题可能会导致一些应用程序无法正常运行&#xff0c;甚至可能影响到系统的稳定性。那么&#xff0c;面对这样一个问题&#xff0c;我们应该如何解决呢&#xff1f;今…

C语言_分支和循环语句(1)

文章目录 前言分支语句循环语句一、什么是语句1.C语句可分为以下五类&#xff1a;2. 控制语句3.以下三类&#xff1a; 二、分支语句&#xff08;选择结构&#xff09;2.1 .1 if语句语法结构2.1.2 if书写形式的对比2.1.3 练习2.2 switch 语句 2.2.1 在switch语句中的break2.2.2 …

美团2面:5个9高可用99.999%,如何实现?

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如网易、有赞、希音、百度、网易、滴滴的面试资格&#xff0c;遇到一几个很重要的面试题&#xff1a; 问题1&#xff1a;你们系统&#xff0c;高可用怎么实现&#xff1f; 问题2&am…

根据案例写PLC程序-红绿灯控制

案例&#xff1a; 1、南北方向红灯点亮30s后熄灭&#xff1b; 2、在点亮南北方向红灯的同时点亮东西方向绿灯&#xff0c;并在点亮25s后&#xff0c;以0.5s熄灭0.5s点亮的时间闪烁3次后熄灭&#xff1b; 3、在东西方向绿灯熄灭后&#xff0c;东西方向黄灯点亮2s后熄灭&#xff…

手把手教你训练自己的Lora

本文教你手把手训练自己的Lora模型&#xff0c; 炼制的是Stable Diffusion的Lora模型。 1 准备工作 1.1 训练工具 当然&#xff0c; 我们可以使用Stable Diffusion的源码进行修改&#xff0c; 然后训练Lora模型。 但对于非专业用户来说&#xff0c; 这个门槛太高了。 推荐使…

Cookie for Mac:隐私保护工具保护您的在线隐私

随着互联网的发展&#xff0c;我们每天都会浏览各种网站&#xff0c;享受在线购物、社交娱乐和学习资料等各种便利。然而&#xff0c;您是否曾经遇到过需要频繁输入用户名和密码的情况&#xff1f;或者不方便访问您常用的网站&#xff1f;如果是这样&#xff0c;那么Cookie for…

无涯教程-机器学习 - 数据可视化

在上一章中&#xff0c;无涯教程讨论了数据对于机器学习算法的重要性&#xff0c;以了解具有统计信息的数据&#xff0c;还有另一种称为可视化的方式来理解数据。 借助数据可视化&#xff0c;可以看到数据的属性保持什么样的关联&#xff0c;这是查看要素是否与输出相对应的最…

ELK高级搜索(二)

文章目录 7&#xff0e;Java api 文档管理7.1 es技术特点7.2 获取数据7.3 文档查询7.4 文档新增7.5 文档修改7.6 文档删除7.7 文档bulk 8&#xff0e;图解es内部机制8.1 es分布式基础8.2 分片shard、副本replica8.3 单node环境创建index8.4 多node环境replica shard8.5 横向扩容…

WPF基础入门-Class7-WPF-MVVN框架

WPF基础入门 Class7-MVVN框架 使用框架可以省掉如Class6中的ViewModelBase.cs的OnPropertyChanged&#xff0c;亦方便命令传参 1、NuGet安装CommunityToolkit.Mvvm&#xff08;原Mircrosoft.Toolkit.Mvvm&#xff09;也可以安装MVVMLight等其他集成库 2、显示页面&#xff1…

【LeetCode-中等题】240. 搜索二维矩阵 II

文章目录 题目方法一&#xff1a;暴力双for查找方法二&#xff1a;二分查找&#xff0c;对每二维数组进行拆分&#xff0c;一行一行的进行二分查找方法三&#xff1a;列倒序Z字形查找 题目 方法一&#xff1a;暴力双for查找 public boolean searchMatrix(int[][] matrix, int …

Ansible 修改文件内容

按照下方所述&#xff0c;创建一个名为 /home/greg/ansible/issue.yml 的 playbook &#xff1a; 该 playbook 将在所有清单主机上运行 该 playbook 会将 /etc/issue 的内容替换为下方所示的一行文本&#xff1a; 在 dev 主机组中的主机上&#xff0c;这行文本显示 为&#x…

计算机msvcp120.dll丢失的解决方法,非常靠谱的三个解决方法

今天&#xff0c;我将为大家分享一个关于电脑报错msvcp120.dll解决方法的话题。在日常生活中&#xff0c;我们可能会遇到这样的问题&#xff1a;电脑突然出现“程序无法正常运行”的提示&#xff0c;然后要求我们重新安装某个软件或者升级系统。这时候&#xff0c;我们很可能会…

docker 学习-- 04 实践搭建 1(宝塔)

docker 学习-- 04 实践 1&#xff08;宝塔&#xff09; docker 学习-- 01 基础知识 docker 学习-- 02 常用命令 docker 学习-- 03 环境安装 docker 学习-- 04 实践 1&#xff08;宝塔&#xff09; 通过上面的学习&#xff0c; 已经可以搭建简单的案例&#xff0c; 接着我会搭…