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

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

[复制链接]
lospring 发布时间:2021-5-21 15:18
虽然之前看过STM32的在应用升级IAP,但是一直没有亲自实验过,最近心血来潮准备体验一下。具体的实现原理这里就不再描述,网上的资料很多。因为M0的APP实现方式不同于M0+、M3、M4等内核的实现方式,所以在这里做个笔记。
% s8 X: f* z+ _% a$ h5 i& G9 ^! _' s) v1 X  w
       实验平台:
: {* m$ i" ~+ O4 Z% D8 O4 y       硬件: STM32F072 Nucleo开发板! v; x' u3 G  z2 ^
       软件: HAL库
' V4 T8 b4 @/ K       工具: IAR
# ?% Q# ~% X1 W       参考: STSW-STM32116————官方提供的F0例程(AN4065), o" T; {% `, @$ f+ s

, s* ~! i% `: [# x8 a一、IAP工程功能* E4 A4 o4 }0 l7 b, M
       上电后执行IAP,在跳转到APP之前,使用PC6控制LED翻转5次,再检测APP跳转条件,满足后跳转到APP。
  w3 b" D! ~# \3 S* n& g9 \       使用CubeMx生成工程之后。增加FLASH_If_Init函数,以初始化Flash,具体代码如下:
* [" Z1 {1 I4 R7 ~
  • 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 );
  • }) `  x9 R% D/ e3 k4 e

, a8 M" {* l' R/ }/ z[color=rgb(51, 102, 153) !important]复制代码
- s" i: O' N* a* }
具体main函数如下:
1 H2 p) E" X2 `$ P- @, {; k
  • 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);
  • }
    1 n& K7 W' R. ]& e* F$ ?$ ~/ u

, d8 F2 e* ]5 A[color=rgb(51, 102, 153) !important]复制代码

% z" `) N2 t# D! Z& t二、APP工程功能
7 Q  \, ~5 y0 s; J% B       由于在网上看见之前有在验证APP时,有各种现象——外部中断、串口中断和定时器中断等不响应,所以设计的工具比较多一下,看看具体有没有问题。
+ \( A- ?7 U7 x3 m. w& b/ G       功能1、外部中断——PA0上升沿触发外部中断,在中断内翻转PC9;3 y, X" F0 z" y* o- E
       功能2、TIM3定时中断——在中断内翻转PC7;, J9 J! `+ {. J: K3 U
       功能3、串口1空闲中断——接收到的数据正确后,翻转PC8;
. P$ E, ^9 t7 z/ \* M8 G       功能4、主函数循环执行以下功能——开启串口DMA接收数据、串口发送数据、PC6状态翻转、延时。
' N* n8 j4 u+ I3 u' ~% m' g! o       PC6~PC9输出控制LED灯。
' s5 K9 I& K) D  `; |
3 N) q7 [) e2 X+ y       F0属于M0内核,不同于M0+、M3和M4等内核,没有专门的中断向量控制寄存器,中断向量的设置只能采用拷贝到SRAM方式。具体实现方式——定义一个位于SRAM首地址全局数组变量,将M0的所有中断入口地址拷贝到该变量内,再将SRAM的地址映射到地址0x00000000,发生中断后,MCU自动从地址0x00000000对应的偏移处寻找中断入口,如下:0 F: H3 k: G0 r- M: r
  • ///// 定义全局数组以存储中断向量表,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;
  • }
    0 w: j$ J4 ?2 v& h9 N& Q

! [, S# o- c  ?$ p6 _6 Q& G7 N[color=rgb(51, 102, 153) !important]复制代码
. R% ^, |5 j4 r1 E' z
      其余代码实现如下:+ k4 g# t; ^) W
  • 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);
  • }- ^' a: ~  P8 p
& A( d  C. V8 b
[color=rgb(51, 102, 153) !important]复制代码
/ Z1 v  [  n4 w
     中断服务程序:' I. a' x- Q. W( `9 P# _
  • void EXTI0_1_IRQHandler(void)
  • {
  •   Exit0IrqCb();
  • }
  • /**
  •   * @brief 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 */
  • }
    1 i9 ^, x. d, O

( Z$ I7 Z2 }) i[color=rgb(51, 102, 153) !important]复制代码
- x% S# }6 g$ ~' H  `! V9 G; `: d' A
     主程序:5 _) L1 N! a2 b, [6 ^
  • 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 */
  • }/ O6 \: |' F: q% N( c# J, z
) g3 V( w* }  x; o: D9 \+ F7 v
[color=rgb(51, 102, 153) !important]复制代码
2 j2 w7 n7 y1 q  J# l
       两个工程编译通过后,使用仿真器将执行文件烧录到MCU,程序运行正常。TIM3定时中断你控制的灯一直亮,但是亮度没有其余的灯亮,因为占空比不是100%;测试串口时,使用镊子或者金属片将串口连个引脚短接起来后,在串口中断内控制翻转控制的LED均正常没有出现网上说的中断不响应等问题。' n1 R* q$ H4 u
       整个工程代码见附件。 F072TestApp.rar (1.05 MB, 下载次数: 10)
赞 收藏 评论1 发布时间:2021-5-21 15:18

举报

1个回答
jxchen 回答时间:2021-12-8 00:08:32

~~~
~~~~

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版