打印
[STM32F0]

笔记---基于HAL库的M0在应用升级IAP

[复制链接]
2131|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Larm1|  楼主 | 2019-4-17 09:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
       虽然之前看过STM32的在应用升级IAP,但是一直没有亲自实验过,最近心血来潮准备体验一下。具体的实现原理这里就不再描述,网上的资料很多。因为M0的APP实现方式不同于M0+、M3、M4等内核的实现方式,所以在这里做个笔记。

       实验平台:
       硬件: STM32F072 Nucleo开发板
       软件: HAL库
       工具: IAR
       参考: STSW-STM32116————官方提供的F0例程(AN4065)

一、IAP工程功能
       上电后执行IAP,在跳转到APP之前,使用PC6控制LED翻转5次,再检测APP跳转条件,满足后跳转到APP。
       使用CubeMx生成工程之后。增加FLASH_If_Init函数,以初始化Flash,具体代码如下:
void FLASH_If_Init(void)
{
  /* Unlock the Program memory */
  HAL_FLASH_Unlock();

  /* Clear all FLASH flags */  
  __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP|FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR );
}
具体main函数如下:
int main(void)
{
  uint8_t  num = 0;
  uint32_t tmp=0;
  
  FLASH_If_Init();
  HAL_Init();

  SystemClock_Config();
  MX_GPIO_Init();
  
  for ( num=0; num<5; num ++)
  {
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
   
    for (tmp=0; tmp<300000; tmp ++);
   
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);
   
    for (tmp=0; tmp<300000; tmp ++);
  }
  
         //// 判断APP的地址处是否已经下载了APP程序
  if ( ((*(__IO uint32_t *)APP_ADDR)&0x2FFE0000)==0x20000000 )
  {
    JumpAddr = *(__IO uint32_t *)(APP_ADDR + 4); //// 设置APP复位中断入口地址
    JumpApp = (pFunction)JumpAddr;
    __set_MSP(*(__IO uint32_t *)APP_ADDR); //// 设置APP栈顶地址
    JumpApp(); //// 跳转到APP
  }
  
  while (1);
}
二、APP工程功能
       由于在网上看见之前有在验证APP时,有各种现象——外部中断、串口中断和定时器中断等不响应,所以设计的工具比较多一下,看看具体有没有问题。
       功能1、外部中断——PA0上升沿触发外部中断,在中断内翻转PC9;
       功能2、TIM3定时中断——在中断内翻转PC7;
       功能3、串口1空闲中断——接收到的数据正确后,翻转PC8;
       功能4、主函数循环执行以下功能——开启串口DMA接收数据、串口发送数据、PC6状态翻转、延时。
       PC6~PC9输出控制LED灯。

       F0属于M0内核,不同于M0+、M3和M4等内核,没有专门的中断向量控制寄存器,中断向量的设置只能采用拷贝到SRAM方式。具体实现方式——定义一个位于SRAM首地址全局数组变量,将M0的所有中断入口地址拷贝到该变量内,再将SRAM的地址映射到地址0x00000000,发生中断后,MCU自动从地址0x00000000对应的偏移处寻找中断入口,如下:
///// 定义全局数组以存储中断向量表,M0共48个
#if (defined (__CC_ARM) ) //// for keil MDK compiler
__IO uint32_t VectorTable[48] __attribute__((at(0x20000000)));
#elif (defined (__ICCARM__) ) //// for IAR compiler
#pragma location=0x20000000
__no_init __IO uint32_t VectorTable[48];
#elif (defined ( __GNUC__) ) //// for GNU compiler
__IO uint32_t VectorTable[48] attribute__((section(".RAMVectorTable")));
#elif (defined ( __TASKING__) ) //// for TASKING compiler
__IO uint32_t VectorTable[48] at(0x20000000);
#endif

//// interrupt vector remapping
void AppVectorTblRemap(void)
{
  uint8_t     tmp;
  uint32_t    tmpCfgr=0;
  
        //// copy interrupt vector
  for (tmp=0; 48>tmp; tmp++)
  {
                //// because size of interrupt vector's address is 4, so tmp+=4(be equal to
                //// tmp<<=2);
    VectorTable[tmp] = *( __IO uint32_t *)(APP_FLASH_ADDR + (tmp<<2));
  }
  
  __HAL_RCC_SYSCFG_CLK_ENABLE();
  tmpCfgr = SYSCFG->CFGR1;
  tmpCfgr &= (uint32_t)(~SYSCFG_CFGR1_MEM_MODE_Msk);
  tmpCfgr |= (uint32_t)0x03; //// embedded SRAM mapped at 0x0000 0000
  SYSCFG->CFGR1 = tmpCfgr;
}
      其余代码实现如下:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (TIM3==htim->Instance)
  {
    TimerBitSta ^= 1;
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, (GPIO_PinState)TimerBitSta);
  }
}

void Exit0IrqCb(void)
{
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0))
  {
    ExitBitSta ^= 1;
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, (GPIO_PinState)ExitBitSta);
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
  }
}

void Usart1IrqCb(void)
{
  if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
  {
    USART1->ISR;
    USART1->RDR;
      
    if ( (1==TestUartRcvBuf[0]) && (5==TestUartRcvBuf[4]) )
    {
      UsartBitSta ^= 1;
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, (GPIO_PinState)UsartBitSta);
      TestUartRcvBuf[0] = 0;
      TestUartRcvBuf[4] = 0;
    }
   
  }
  HAL_UART_AbortReceive_IT(&huart1);
  HAL_UART_DMAStop(&huart1);
  __HAL_UART_CLEAR_IT(&huart1, UART_FLAG_IDLE);
}
     中断服务程序:
void EXTI0_1_IRQHandler(void)
{
  
  Exit0IrqCb();
}



/**
  * [url=home.php?mod=space&uid=247401]@brief[/url] This function handles TIM3 global interrupt.
  */
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  /* USER CODE END TIM3_IRQn 0 */
  HAL_TIM_IRQHandler(&htim3);
  /* USER CODE BEGIN TIM3_IRQn 1 */

  /* USER CODE END TIM3_IRQn 1 */
}


void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  Usart1IrqCb();
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}
     主程序:
int main(void)
{
  /* USER CODE BEGIN 1 */
  uint32_t tmp;
  
  AppVectorTblRemap();
  /* 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_DMA_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
  
  /* USER CODE BEGIN 2 */
  HAL_TIM_Base_Start_IT(&htim3);
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
  __set_PRIMASK(0); //// close interrupt in IAP, so open
  
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    HAL_UART_Receive_DMA(&huart1, TestUartRcvBuf ,UART_BUF_LEN);
    HAL_UART_Transmit(&huart1, TestUartSndBuf ,UART_BUF_LEN, UART_BUF_LEN);
   
////          HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
////    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);
   
////    for (tmp=0; tmp<600000; tmp ++);
   
   
    WhileBitSta ^= 1;
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, (GPIO_PinState)WhileBitSta);
    for (tmp=0; tmp<600000; tmp ++);
   
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
       两个工程编译通过后,使用仿真器将执行文件烧录到MCU,程序运行正常。TIM3定时中断你控制的灯一直亮,但是亮度没有其余的灯亮,因为占空比不是100%;测试串口时,使用镊子或者金属片将串口连个引脚短接起来后,在串口中断内控制翻转控制的LED均正常没有出现网上说的中断不响应等问题。
       整个工程代码见附件。
       F072TestApp.rar (1.05 MB)
       F072TestIap.rar (487.8 KB)

使用特权

评论回复
沙发
mmuuss586| | 2019-4-18 09:44 | 只看该作者
感谢分享

使用特权

评论回复
板凳
晓伍| | 2019-5-8 08:34 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
地板
观海| | 2019-5-8 08:41 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
5
guanjiaer| | 2019-5-8 08:50 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
6
heimaojingzhang| | 2019-5-8 08:57 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
7
keaibukelian| | 2019-5-8 08:59 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
8
labasi| | 2019-5-8 09:04 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
9
paotangsan| | 2019-5-8 09:47 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
10
renzheshengui| | 2019-5-8 09:55 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
11
wakayi| | 2019-5-8 10:10 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
12
wowu| | 2019-5-8 10:16 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
13
木木guainv| | 2019-5-8 10:38 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
14
wangjiahao88| | 2019-5-8 11:04 | 只看该作者
这个 之前使用过,STM32F046的,没有成功……不知道为什么,,,,,,

使用特权

评论回复
15
djz1992| | 2019-5-13 20:42 | 只看该作者
感谢分享,后面深入研究一下,主要想做GPRS的远程升级

使用特权

评论回复
16
letflying| | 2020-11-5 11:11 | 只看该作者
楼主只是实现了IAP到APP的跳转,并没有实现falsh_if的HAL库函数的读写操作,以及Ymodem的协议啊

使用特权

评论回复
17
Larm1|  楼主 | 2021-5-17 11:59 | 只看该作者
letflying 发表于 2020-11-5 11:11
楼主只是实现了IAP到APP的跳转,并没有实现falsh_if的HAL库函数的读写操作,以及Ymodem的协议啊 ...

真正做产品的话我觉得不会使用Ymodem协议,而是使用自定义的代码,使用该协议的都是用现成的上下位机代码做研究,这种升级协议使用通用协议不完全...

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:大爱无疆

53

主题

389

帖子

0

粉丝