首页 > 其他分享 >STM32G030F6P6TR_IAP

STM32G030F6P6TR_IAP

时间:2024-08-01 16:28:04浏览次数:16  
标签:void FLASH uint8 uint32 IGK IAP STM32G030F6P6TR

 

 


 bootloader程序 

STM32FLASH读写

  1 /**
  2   ******************************************************************************
  3   * @file    stmflash.c
  4   * @brief   读写STM32内部flash(STM32G030F6P6TR)
  5   ******************************************************************************
  6   */
  7 
  8 #include "stmflash.h"
  9 
 10 uint8_t STMFLASH_BUF[FLASH_PAGE_SIZE]; //数据缓存 最多是2KB
 11 
 12 /**
 13 * @brief 读取STM内部FLASH数据
 14 * @param faddr:FLASH地址 (此地址必须为4的倍数!!)
 15 * @param *buffer:数据存放地址
 16 * @param length:读取的数据长度(32位数据)
 17 * @retval 无
 18 */
 19 void STMFLASH_ReadData(uint32_t faddr, uint8_t *buffer, uint32_t length)
 20 {
 21     for(uint16_t i=0; i < length/4 ; i++ ){
 22         memcpy(buffer+i*4, (uint32_t*)(faddr+i*4), 4);    //使用memcpy将32位数据存储到uint8_t数组中
 23     }
 24 }
 25 
 26 
 27 /**
 28 * @brief 数据无校验写入STM内部FLASH
 29 * @param faddr:FLASH起始地址 (此地址必须为4的倍数!!)
 30 * @param *buffer:要写入的数据地址
 31 * @param length:写入的数据字节数
 32 * @retval 无
 33 */
 34 #if STM32_FLASH_WREN    //如果使能了写   
 35 void STMFLASH_Write_NoCheck(uint32_t faddr,uint8_t *pBuffer,uint16_t length)   
 36 {         
 37     uint64_t temp;
 38     for(uint16_t i=0;i <= length/8;i++)
 39     {
 40         memcpy(&temp, pBuffer + i * 8, sizeof(temp));
 41         HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,faddr,temp);   //一次写8字节数据
 42       faddr += 8;//地址增加8.
 43     }  
 44 } 
 45 
 46 
 47 static uint32_t GetPage(uint32_t Addr)
 48 {
 49   return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;;
 50 }
 51 
 52 /**
 53 * @brief 擦除一页
 54 * @param Addr:页地址
 55 * @retval 1:擦除成功  0:擦除失败
 56 */
 57 uint8_t STMFLASH_ErasePage(uint32_t Addr)    
 58 {
 59     HAL_FLASH_Unlock();        //FLASH解锁
 60     
 61     FLASH_EraseInitTypeDef EraseInitStruct = {0}; //声明 FLASH_EraseInitTypeDef 结构体
 62     uint32_t  PageError = 0;
 63     EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;      //按页擦除
 64   EraseInitStruct.Page        = GetPage(Addr);                        //指定初始擦除的 Flash 页
 65   EraseInitStruct.NbPages     = 1 ;                                           //要擦除的页数
 66     
 67     HAL_StatusTypeDef EraseStatus = HAL_FLASHEx_Erase(&EraseInitStruct, &PageError);
 68     if ( EraseStatus != HAL_OK){        //调用擦除函数擦除    
 69             return 0;//擦擦失败
 70     }else
 71           return 1;//擦除成功
 72     
 73     HAL_FLASH_Lock();        //上锁
 74         
 75 }
 76 
 77 /**
 78 * @brief 从指定地址开始写入指定长度的数据
 79 * @param WriteAddr:起始地址(此地址必须为4的倍数!!)
 80 * @param *pBuffer:要写入的数据地址
 81 * @param length:写入的数据字节数
 82 * @retval 1:写入成功  0:写入失败
 83 */
 84 
 85 #include "stdio.h"
 86 extern void printfdata(uint8_t *data,uint16_t len);
 87 void STMFLASH_Write(uint32_t WriteAddr,uint8_t *pBuffer,uint16_t length)    
 88 {
 89     if(WriteAddr < FLASH_BASE||(WriteAddr>=(FLASH_BASE + FLASH_PAGE_SIZE * STM32_FLASH_SIZE/2))){
 90         return;//非法地址
 91     }
 92         
 93     uint32_t sector;           //扇区
 94     uint16_t secoff;           //扇区内偏移地址(按字节计算)
 95     uint16_t secremain;      //扇区内剩余地址(按字节计算)
 96     uint32_t offaddr;           //去掉0X08000000后的地址
 97     uint16_t i;    
 98     
 99     offaddr = WriteAddr - FLASH_BASE;                        //实际偏移地址
100     sector  = offaddr / FLASH_PAGE_SIZE;                  //地址所在扇区
101     secoff  = offaddr % FLASH_PAGE_SIZE;              //在扇区内的偏移(字节为基本单位.)
102     secremain = FLASH_PAGE_SIZE - secoff;              //扇区剩余空间大小   
103             
104     HAL_FLASH_Unlock();        //FLASH解锁    
105     if( length <= secremain ){
106         secremain = length;                                                  //如果写入数据长度不大于一个扇区
107     }
108     while(1)                                      //循环写入数据
109     {    
110         STMFLASH_ReadData((sector*FLASH_PAGE_SIZE + FLASH_BASE),(uint8_t*)STMFLASH_BUF,FLASH_PAGE_SIZE/4);//读出整个扇区的内容
111 
112         for( i=0; i < secremain;i++)    //校验数据
113         {
114             if(STMFLASH_BUF[secoff+i]!=0XFF)
115                 break;                                //需要擦除          
116         }
117         if( i < secremain )                //需要擦除
118         {        
119             STMFLASH_ErasePage(sector * FLASH_PAGE_SIZE + FLASH_BASE); /* 擦除这个扇区 */
120             FLASH_WaitForLastOperation(FLASH_WAITETIME);           //等待上次操作完成
121 
122             for(i=0;i < secremain;i++)//复制
123             {
124                 STMFLASH_BUF[i+secoff] = pBuffer[i];      
125             }
126             STMFLASH_Write_NoCheck(sector*FLASH_PAGE_SIZE+FLASH_BASE,STMFLASH_BUF,secremain+i);//写入整个扇区 
127             FLASH_WaitForLastOperation(FLASH_WAITETIME);           //等待上次操作完成
128             
129         }else                                         //不需要擦除直接写入
130             {
131                 STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间. 
132                 FLASH_WaitForLastOperation(FLASH_WAITETIME);           //等待上次操作完成
133             }
134             
135         if(length == secremain){
136             break;//写入结束了
137         }else//写入未结束
138             {
139                 sector++;                //扇区增1
140                 secoff = 0;                //偏移位置为0      
141                 pBuffer += secremain;      //指针偏移
142                 WriteAddr += secremain*8;    //写地址偏移  
143                 length -= secremain;    //字节数递减
144                 if(length > (FLASH_PAGE_SIZE/8)){
145                     secremain = FLASH_PAGE_SIZE/8;//下一个扇区还是写不完
146                 }else
147                     secremain = length;//下一个扇区可以写完了
148             }     
149     };    
150     
151     HAL_FLASH_Lock();        //上锁
152 }
153 
154 #endif
 1 /**
 2   ******************************************************************************
 3   * @file    stmflash.h
 4   * @brief   读写STM32内部flash(STM32G030F6P6TR)
 5   ******************************************************************************
 6   */
 7 
 8 
 9 #ifndef __STMFLASH_H__
10 #define __STMFLASH_H__
11 #include "main.h" 
12 #include "string.h"
13 
14 //用户根据自己的需要设置
15 extern void FLASH_PageErase(uint32_t Banks, uint32_t Page);
16 
17 #define STM32_FLASH_SIZE     32                            //所选STM32的FLASH容量大小(单位为K)
18 #define STM32_FLASH_WREN     1                  //使能FLASH写入(0,不是能;1,使能)
19 #define FLASH_WAITETIME      10             //FLASH等待超时时间
20 
21 
22 void STMFLASH_Write(uint32_t WriteAddr,uint8_t *pBuffer,uint16_t length);        
23 void STMFLASH_Write_NoCheck(uint32_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite);
24 void STMFLASH_ReadData(uint32_t faddr, uint8_t *buffer, uint32_t length);
25 uint8_t STMFLASH_ErasePage(uint32_t Addr)    ;
26 #endif

IAP

  1 /**
  2   ******************************************************************************
  3   * @file    iap.c
  4   * @brief   在线升级APP
  5   ******************************************************************************
  6   */
  7 
  8 #include "iap.h"
  9 
 10 Stm32IapStruct IGK_IAP;
 11 //CRC校验表
 12 unsigned long CRC32Table[256];
 13 
 14 uint8_t  Uart2_Rx[UART2_RX_LEN]={0};
 15 uint8_t  Uart2_Tx[UART2_TX_LEN]={0};
 16 uint16_t Uart2_Rx_length = 0;
 17 uint16_t Uart2_Tx_length = 0;
 18 
 19 //定义一个函数指针变量
 20 typedef  void (*pFunction)(void);
 21 
 22 void App_Jump(uint32_t app_addr) {
 23     __disable_irq();    //关闭总中断
 24     HAL_DeInit();
 25     if (((*(__IO uint32_t*)app_addr) & 0x2FFE0000 ) == 0x20000000)
 26     { 
 27       /* Jump to user application */
 28       uint32_t JumpAddress = *(__IO uint32_t*) (app_addr + 4);
 29       pFunction Jump_To_Application = (pFunction) JumpAddress;
 30       /* Initialize user application's Stack Pointer */
 31       __set_MSP(*(__IO uint32_t*) app_addr);//设置栈指针
 32       Jump_To_Application();
 33     }
 34 }
 35 
 36 void Uart2_Tx_Start(uint16_t len){
 37     HAL_UART_Transmit_DMA(&huart2,(uint8_t *)&Uart2_Tx,len);
 38 }
 39 
 40 //IAP初始化
 41 void IAP_BootLoad_Init(void)    
 42 {
 43   //CRC校验的表
 44     CRC32TableCreate();    
 45     //初始化
 46     IGK_IAP.UpdataStart = 0;
 47     IGK_IAP.UpdataOk = 0;
 48     IGK_IAP.WateTime = 0;
 49     IGK_IAP.RxBuff = Uart2_Rx;//接收数据指针
 50     IGK_IAP.TxBuff = Uart2_Tx;//发送数据指针
 51     IGK_IAP.RxLength = &Uart2_Rx_length;//接收长度
 52     IGK_IAP.SendFunc = Uart2_Tx_Start;//发送函数
 53 }
 54 
 55 //CRC32校验,
 56 //pBuf:整包数据
 57 //pBufSize:实际长度
 58 uint8_t check_data(uint8_t *pBuf ,uint16_t pBufSize)    //1:成功 0:错误 
 59 {
 60     uint32_t get_PC_crcVel=0;
 61   uint32_t CRC_PC_vel = 0;
 62     uint8_t *pbuff;
 63     if(pBufSize<5)
 64     {
 65             return 0;
 66     }
 67     pbuff = pBuf+pBufSize-4;
 68     
 69     CRC_PC_vel = pbuff[0]<<24|pbuff[1]<<16|pbuff[2]<<8|pbuff[3];    //接收的CRC32
 70     
 71     get_PC_crcVel  = CRC32Calculate(pBuf,pBufSize-4);    //MCU端计算的CRC32
 72     
 73     if(get_PC_crcVel == CRC_PC_vel)
 74     {
 75         return 1;
 76     }
 77     else
 78     {
 79         return 0;
 80     }
 81 }
 82 
 83 
 84 //IAP数据解析,放到串口中断--------------------------------------------------------------------------
 85 void IAP_BootLoad_UpData(void)
 86 {
 87     unsigned int crc=0;
 88     //上位机请求刷固件
 89     if((IGK_IAP.RxBuff[0] == 0xF1) && (IGK_IAP.RxBuff[1] == 0x01))
 90     {
 91                 
 92         if(check_data(IGK_IAP.RxBuff,*IGK_IAP.RxLength))//crc校验成功
 93         {
 94             //开始刷固件标志位
 95             IGK_IAP.UpdataStart = 1;
 96             //获取固件大小
 97             IGK_IAP.FirmwareSize = IGK_IAP.RxBuff[2]<<24 | IGK_IAP.RxBuff[3]<<16 | IGK_IAP.RxBuff[4]<<8 | IGK_IAP.RxBuff[5];
 98             //获取总包数
 99             IGK_IAP.PackageNum = IGK_IAP.RxBuff[6]<<8 | IGK_IAP.RxBuff[7];
100             //响应
101             IGK_IAP.TxBuff[0] = 0xF1;        //帧头
102             IGK_IAP.TxBuff[1] = 0x81;        //功能码
103             
104             IGK_IAP.TxBuff[2] = IGK_IAP.RxBuff[2];
105             IGK_IAP.TxBuff[3] = IGK_IAP.RxBuff[3];
106             IGK_IAP.TxBuff[4] = IGK_IAP.RxBuff[4];
107             IGK_IAP.TxBuff[5] = IGK_IAP.RxBuff[5];
108             
109             IGK_IAP.TxBuff[6] = IGK_IAP.RxBuff[6];
110             IGK_IAP.TxBuff[7] = IGK_IAP.RxBuff[7];
111             
112             crc = CRC32Calculate(IGK_IAP.TxBuff,8);
113             
114             IGK_IAP.TxBuff[8] = crc>>24;
115             IGK_IAP.TxBuff[9] = crc>>16;
116             IGK_IAP.TxBuff[10] = crc>>8;
117             IGK_IAP.TxBuff[11] = crc&0xff;
118             
119             IGK_IAP.SendFunc(12);
120         }
121     }
122     else if((IGK_IAP.RxBuff[0] == 0xF1) && (IGK_IAP.RxBuff[1] == 0x02))
123     {
124         //crc校验成功,写入Flash
125         if(check_data(IGK_IAP.RxBuff,*IGK_IAP.RxLength))
126         {
127             //解析
128             //获取包索引
129             IGK_IAP.PackageIndex = IGK_IAP.RxBuff[2]<<8 | IGK_IAP.RxBuff[3];
130             //写入flash
131             STMFLASH_Write(STM32_FLASH_USER+IGK_IAP.PackageIndex*PackageSize,&IGK_IAP.RxBuff[4],*IGK_IAP.RxLength-8);
132             //响应
133             IGK_IAP.TxBuff[0] = 0xF1;
134             IGK_IAP.TxBuff[1] = 0x82;    
135             
136             IGK_IAP.TxBuff[2] = IGK_IAP.RxBuff[2];
137             IGK_IAP.TxBuff[3] = IGK_IAP.RxBuff[3];
138             //结果
139             IGK_IAP.TxBuff[4] = 0x01;
140             
141             crc = CRC32Calculate(IGK_IAP.TxBuff,5);
142             
143             IGK_IAP.TxBuff[5] = crc>>24;
144             IGK_IAP.TxBuff[6] = crc>>16;
145             IGK_IAP.TxBuff[7] = crc>>8;
146             IGK_IAP.TxBuff[8] = crc&0xff;
147             
148             IGK_IAP.SendFunc(9);
149             //判断是否接收完成
150             if(IGK_IAP.PackageIndex == (IGK_IAP.PackageNum-1))
151             {
152                 //更新完成标志位
153                 IGK_IAP.UpdataOk = 1;                           
154             }
155         }
156         else//crc校验失败,返回错误类型
157         {
158              //响应
159             IGK_IAP.TxBuff[0] = 0xF1;
160             IGK_IAP.TxBuff[1] = 0x82;    
161             
162             IGK_IAP.TxBuff[2] = IGK_IAP.RxBuff[2];
163             IGK_IAP.TxBuff[3] = IGK_IAP.RxBuff[3];
164             //结果
165             IGK_IAP.TxBuff[4] = 0x02;
166             crc = CRC32Calculate(IGK_IAP.TxBuff,5);
167             IGK_IAP.TxBuff[5] = crc>>24;
168             IGK_IAP.TxBuff[6] = crc>>16;
169             IGK_IAP.TxBuff[7] = crc>>8;
170             IGK_IAP.TxBuff[8] = crc&0xff;
171             IGK_IAP.SendFunc(9);           
172         }
173         
174     }         
175 }
176 
177 //生成CRC校验表
178 void CRC32TableCreate(void)
179 {
180     unsigned int c;
181     unsigned int i, j;
182 
183     for (i = 0; i < 256; i++) {
184         c = (unsigned int)i;
185         for (j = 0; j < 8; j++) {
186             if (c & 1)
187                 c = 0xedb88320L ^ (c >> 1);
188             else
189                 c = c >> 1;
190         }
191         CRC32Table[i] = c;
192     }
193 }
194 
195 //计算CRC校验
196 unsigned int CRC32Calculate(uint8_t *pBuf ,uint16_t pBufSize)
197 {
198     unsigned int retCRCValue=0xffffffff;
199     unsigned char *pData;
200     pData=(unsigned char *)pBuf;
201      while(pBufSize--)
202      {
203          retCRCValue=CRC32Table[(retCRCValue ^ *pData++) & 0xFF]^ (retCRCValue >> 8);
204      }
205      return retCRCValue^0xffffffff;
206 }
 1 /**
 2   ******************************************************************************
 3   * @file    iap.c
 4   * @brief   在线升级APP
 5   ******************************************************************************
 6   */
 7 
 8 #ifndef __IAP_H__
 9 #define __IAP_H__
10 #include "main.h" 
11 #include "stmflash.h"
12 #include "usart.h"
13 #include "stdio.h"
14 
15 #define UART2_RX_LEN     1024 + 50
16 #define UART2_TX_LEN     256
17 
18 //一包数据的字节数
19 #define PackageSize                1024
20 
21 #define STM32_FLASH_USER     0x08004000         //存储数据的FLASH的起始地址
22 
23 //定义一个函数指针变量
24 typedef  void (*PFunc)(void);                            
25 typedef  void (*PFunc_U16)(uint16_t);    
26 
27 extern uint16_t Uart2_Rx_length;
28 
29 typedef struct
30 {
31     uint8_t UpdataStart;        //开始更新标志
32     uint8_t UpdataOk;                //更新完成标志
33     uint32_t FirmwareSize;    //固件大小
34         uint16_t PackageIndex;    //包索引
35     uint16_t PackageNum;        //分包数    
36     uint16_t WateTime;            //等待上位机请求刷固件超时时间
37     uint8_t* RxBuff;                //接收数据指针
38     uint8_t* TxBuff;                //发送数据指针
39     uint16_t* RxLength;            //接收长度
40     PFunc_U16 SendFunc;            //发送函数指针 
41 }Stm32IapStruct;
42 
43 extern Stm32IapStruct IGK_IAP;
44 
45 void App_Jump(uint32_t app_addr) ;
46 
47 //IAP初始化
48 void IAP_BootLoad_Init(void);
49 void IAP_BootLoad_UpData(void);
50 void iap_load_app(uint32_t appxaddr);
51 //计算CRC校验
52 unsigned int CRC32Calculate(uint8_t *pBuf ,uint16_t pBufSize);
53 //生成CRC校验表
54 void CRC32TableCreate(void);
55 #endif
56 
57 /*************************************************************************
58 
59     通信协议 
60     帧头:0xF1 
61         1.请求更新固件 
62             上位机发: 
63                 0x01:
64                 帧头【1】+ 功能码【1】+ 固件长度【4】+ 分包数【2】+ CRC32【4】
65                             F1          01      00 00 22 84        00 09    65 4F AC 44
66         单片机响应: 
67                 0x81: 
68                 帧头【1】+ 功能码【1】+ 固件长度【4】+ 分包数【2】+ CRC32【4】
69                             F1                     81             00 00 22 84                 00 09     ED 59 46 B6 
70         2.发送数据包 
71             上位机发: 
72                 0x02: 
73                 帧头【1】+ 功能码【1】+ 包索引【2】+数据【1024】+ CRC32【4】
74                           F1                         82             00 00         02 1A             28 91 6C F1             02 00 00 F8 04 ...
75                 单片机响应: 
76             单片机响应: 
77                 0x82: 
78                 帧头【1】+ 功能码【1】+ 包索引【2】+结果【1】+ CRC32【4】
79                          F1                         82                 00 08             01                 4B F8 4A DE 
80         结果说明:
81             0x01:正常;
82             0x02:CRC 校验错误;
83             0x03:长度不够,丢失数据;
84         
85 ************************************************************************/

 

串口配置

 

初始化IAP 开启串口DMA 

1   /* USER CODE BEGIN 2 */
2     IAP_BootLoad_Init();
3     HAL_UARTEx_ReceiveToIdle_DMA(&huart2,(uint8_t *)&Uart2_Rx,UART2_RX_LEN);
4   /* USER CODE END 2 */

 STM32串口DMA空闲回调

1 void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
2     if (huart->Instance == USART2){
3         Uart2_Rx_length = Size ;
4         IAP_BootLoad_UpData();
5         HAL_UARTEx_ReceiveToIdle_DMA(&huart2,(uint8_t *)&Uart2_Rx,UART2_RX_LEN);
6     }
7 }

配置bootloader程序空间大小

 定义APP地址

1 /* USER CODE BEGIN PD */
2 #define STM32_FLASH_USER     0x08004000         //存储数据的FLASH的起始地址
3  
4 /* USER CODE END PD */

跳转到APP

1   while (1)
2   {
3         //如果更新完成或者等待上位机请求超时,则跳转到主程序
4         if(IGK_IAP.UpdataOk)
5         {
6             App_Jump(APP_ADDR);
7         }
8 }

 


 

 APP程序 

 配置flash

配置向量偏移地址开启系统总中断

 1 int main(void)
 2 {
 3   /* USER CODE BEGIN 1 */
 4     SCB->VTOR = FLASH_BASE | 0x4000; //
 5   /* USER CODE END 1 */
 6 
 7   /* MCU Configuration--------------------------------------------------------*/
 8 
 9   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
10   HAL_Init();
11 
12   /* USER CODE BEGIN Init */
13     __enable_irq();    //开启总中断
14   /* USER CODE END Init */

 

参考: 【STM32 IAP技术实现】适合小白“食用”(以STM32F103C8T6为例)_stm32f103c8t6 串口iap bootloader-CSDN博客

 

通过百度网盘分享的文件:STM32G030F6P6TR_IAP.zip
链接:https://pan.baidu.com/s/1pncer6ge9Bn56FnWb36YgA?pwd=IAP1
提取码:IAP1

STM32串口DMA空闲回调

标签:void,FLASH,uint8,uint32,IGK,IAP,STM32G030F6P6TR
From: https://www.cnblogs.com/observer01/p/18336876

相关文章