你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

移植官方STM32F4XX IAP程序为HAL库的过程

[复制链接]
qq344269956 发布时间:2020-1-19 15:47
这段时间用到STM32F417XXX一芯片做项目需要用到IAP进行串口在线升级,官方例程是利用了一个IO进行控制升级,我的想法是,使用STM32的串口控制升级,大约的流程如下:
上电---->通过串口发送指定字符串------>自延时约200ms------>接收是否有上位机的指定字符串-------->如有进行升级,如无直接进行APP跳转。

首先我们下载了STM32F4xx_AN3965_V1.0.0作为初始例程,而且这个例程还有说明都一并放置到下载区了。

然后,我们首先生成了一个基于HAL的例程文件,只开启了UART1,其它的功能不用动


设置了时间为168MHz,然后生成了一个HAL库的代码。

将STM32F4xx_AN3965_V1.0.0里面的
common.c
flash_if.c
menu.c
ymodem.c
放置到Src文件夹中,头文件放置到inc文件夹中,在工程中将这几个文件添加到工程中(Application/usr文件夹上右键,add  existiong .....)

在头文件中添加上头文件
#include "menu.h"
#include "common.h"
#include "string.h"
#include "stdio.h"


添加下面的这些外部定义
extern pFunction Jump_To_Application;
extern uint32_t JumpAddress;
extern uint32_t FlashProtection;


编译后会出现一些错误,主要有:
FLASH_Sector_x的报错,找不到这些,打到这些地方全部改成FLASH_SECTOR_X

FLASH_Erase_SectorXX的报错,HAL中没有返回,相应更改一下:
uint32_t FLASH_If_Erase(uint32_t StartSector)
{
  uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;

  /* Get the sector where start the user flash area */
  UserStartSector = GetSector(APPLICATION_ADDRESS);

  for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)
  {
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */
    FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);
  }

  return (0);
}


其它的一些基本类似,解决办法都是是到:
stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c和中找到对应的函数进行替换
需要注意的是
有些函数:
FLASH_Erase_Sector等,会出现一个默认定义的情况,这时只需要将本来声明到在stm32F4xx_hal_flash.c、stm32F4xx_hal_flash_ex.c中
void               FLASH_MassErase(uint8_t VoltageRange, uint32_t Banks);
HAL_StatusTypeDef  FLASH_OB_EnableWRP(uint32_t WRPSector, uint32_t Banks);
HAL_StatusTypeDef  FLASH_OB_DisableWRP(uint32_t WRPSector, uint32_t Banks);
HAL_StatusTypeDef  FLASH_OB_RDP_LevelConfig(uint8_t Level);
HAL_StatusTypeDef  FLASH_OB_UserConfig(uint8_t Iwdg, uint8_t Stop, uint8_t Stdby);
HAL_StatusTypeDef  FLASH_OB_BOR_LevelConfig(uint8_t Level);
uint8_t            FLASH_OB_GetUser(void);
uint16_t           FLASH_OB_GetWRP(void);
uint8_t            FLASH_OB_GetRDP(void);
uint8_t            FLASH_OB_GetBOR(void);

将这些声明直接放置到对应的头文件中去,同时将头文件包含到需要用*.c中。
还需要修改这个函数
uint32_t FLASH_If_Erase(uint32_t StartSector)
{
  uint32_t UserStartSector = FLASH_SECTOR_1, i = 0;

  /* Get the sector where start the user flash area */
  UserStartSector = GetSector(APPLICATION_ADDRESS);

  for(i = UserStartSector; i <= FLASH_SECTOR_11; i += 1)//原来是i+=8,查一下定义这里应该是+1
  {
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */
    FLASH_Erase_Sector(i, FLASH_VOLTAGE_RANGE_3);
  }

  return (0);
}



这个函数需要修改一下,标红的两句是新加的:
void FLASH_Erase_Sector(uint32_t Sector, uint8_t VoltageRange)
{
  uint32_t tmp_psize = 0U;

  /* Check the parameters */
  assert_param(IS_FLASH_SECTOR(Sector));
  assert_param(IS_VOLTAGERANGE(VoltageRange));
  FLASH_WaitForLastOperation(0xFFF);
  if(VoltageRange == FLASH_VOLTAGE_RANGE_1)
  {
     tmp_psize = FLASH_PSIZE_BYTE;
  }
  else if(VoltageRange == FLASH_VOLTAGE_RANGE_2)
  {
    tmp_psize = FLASH_PSIZE_HALF_WORD;
  }
  else if(VoltageRange == FLASH_VOLTAGE_RANGE_3)
  {
    tmp_psize = FLASH_PSIZE_WORD;
  }
  else
  {
    tmp_psize = FLASH_PSIZE_DOUBLE_WORD;
  }
       
        FLASH_WaitForLastOperation(0xFFF);
  /* If the previous operation is completed, proceed to erase the sector */
  CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
  FLASH->CR |= tmp_psize;
  CLEAR_BIT(FLASH->CR, FLASH_CR_SNB);
  FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos);
  FLASH->CR |= FLASH_CR_STRT;
}



其它修改,串口修改:
void SerialPutChar(uint8_t c)
{
  HAL_UART_Transmit_IT(&huart1, &c,1);
        while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET);
}



uint32_t SerialKeyPressed(uint8_t *key)
{
       
        if(HAL_UART_Receive(&huart1,key,1,0xFF) == HAL_OK)
        {
                return 1;
        }
        else
        {
                return 0;
        }

}

在修改完成确认没有错误了,就需要如下操作:
修改main函数:
int CmpStr(const char *data,const char *data1,int index1,int index2,int length);

#ifdef  __GNUC__

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
       
#else

#define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)
       
#endif

PUTCHAR_PROTOTYPE
{
        HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
        return ch;
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
        //FLASH_If_Init();
  /* USER CODE END 1 */


  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */
  uint8_t mychar[30] = "*****************\n\r";//上下交互的语句,请自定义
  /* 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 */
       

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
               
                Serial_PutString(mychar);

                if(HAL_UART_Receive(&huart1,mychar,16,0xFF) == HAL_OK)
                {
                        if(CmpStr((char *)mychar,"**************",0,0,strlen("***********")) == 0)//标红的需要自已定义
                        {
                                printf("正在等待数据文件下发......\r\n");

                               
                                FLASH_If_Init();
                               
                                //Main_Menu();
                                //FlashProtection = !FLASH_If_GetWriteProtectionStatus();
                                SerialDownload();
                        }                       
                }

    /* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
    if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
    {
                        Serial_PutString((uint8_t *)"start user Program!\r\n\n");
                        //HAL_Delay(100);;
                        /* Jump to user application */
      JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
      Jump_To_Application = (pFunction) JumpAddress;
      /* Initialize user application's Stack Pointer */
      __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
                        Serial_PutString((uint8_t *)"Start program execution......\r\n\n");
                        //HAL_Delay(100);
      Jump_To_Application();
    }
                else
                {
                        Serial_PutString((uint8_t *)"no user Program\r\n\n");
                }
               
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}



int CmpStr(const char *data,const char *data1,int index1,int index2,int length)
{
         //int temp = 0;
         for(int i = 0; i< length;i++)
         {
                 if(*(data+index1+i)- *(data1+index2+i) >0)
                 {
                         return 1;  
                 }
                 if(*(data+index1+i)- *(data1+index2+i) <0)
                 {
                          return -1;
                 }
         }
         return 0;
}


好了,基本就这些,有问题留言,我有时间就回复。。。
如果有好的提议,可以一起探讨一下!

串口1设置

串口1设置

stm32f4_iap_using_usart.zip

下载

1.66 MB, 下载次数: 195

STM32 MCU IAP例程跳转到APP代码简要分析.pdf

下载

38.67 KB, 下载次数: 75

收藏 5 评论4 发布时间:2020-1-19 15:47

举报

4个回答
jeffhe1 回答时间:2020-1-20 09:12:11
謝謝分享
慎微 回答时间:2020-1-20 15:20:55
感恩分享
生命在于折腾! 回答时间:2020-1-31 09:56:06
谢谢 分享
LaLaLa321 回答时间:2020-8-27 16:01:51
我用的CUBEMX里的例程,自己用CUBEMX建立工程将文件添加进去后,通过Ymodem下载程序,可以正常跑但执行到HAL_Delay()就卡死了,版主有遇到同样的情况吗
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版