IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32升级程序问题及解决方法记录 -> 正文阅读

[嵌入式]STM32升级程序问题及解决方法记录

最近做STM32的升级程序,原来做过标准库的升级,这次用的是HAL库的升级。原本以为很简单,但缺困扰了我好几天。首先是FLASH的读写。

TestStatus FLASH_Write_NWord(uint32_t WriteAddr,uint32_t *pBuffer,uint32_t Num)
{
	uint32_t i;
	FLASH_Status FLASHStatus = FLASH_COMPLETE;	// 记录每次写入的结果
	TestStatus MemoryProgramStatus = PASSED;	// 记录整个测试结果
	
	HAL_FLASH_Unlock();               //解锁Flash
	__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGAERR | FLASH_FLAG_WRPERR | FLASH_FLAG_BSY);
	
	for(i = 0;i < Num;i += 4)					//向内部FLASH写入数据
	{
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr, *pBuffer) != HAL_OK)
		{
			if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr, *pBuffer) != HAL_OK)
			{
				MemoryProgramStatus = FAILED;	// 两次写入不成功编程失败
				break;
			}
		}
		WriteAddr += 4;	
		pBuffer ++;
	}
	HAL_FLASH_Lock();  								// 上锁
	return MemoryProgramStatus;
}
void FLASH_Read_NWord(uint32_t ReadAddr,uint32_t *pBuffer,uint32_t Num)
{
	uint32_t i;
	for(i = 0;i < Num;i++)
	{
		pBuffer[i]=*(__IO uint32_t*)ReadAddr; 		//读取4个字节.
		ReadAddr += 4;								//偏移4个字节
	}
}
void FLASH_Erase_NWord(long WriteAddr,long Num) 
{
	unsigned char PageNum,j;
	FLASH_Status FLASHStatus = FLASH_COMPLETE;	// 记录每次擦除的结果	
	PageNum = Num / FLASH_PAGE_SIZE;			// 计算要擦除多少页
	FLASH_EraseInitTypeDef My_Flash;
	uint32_t PageError = 0;                    //设置PageError,如果出现错误这个变量会被设置为出错的FLASH地址
	
	if(Num % FLASH_PAGE_SIZE != 0)				// 不足一页页数加1
		PageNum ++;
		
	My_Flash.TypeErase = FLASH_TYPEERASE_PAGES; //标明Flash执行页面只做擦除操作
  	My_Flash.PageAddress = WriteAddr;  			//声明要擦除的地址
  	My_Flash.NbPages = PageNum;                 //说明要擦除的页数,此参数必须是Min_Data = 1和Max_Data =(最大页数-初始页的值)之间的值

	
	__disable_irq(); 							// 关总中断,防止FLASH操作过程中中断影响
	HAL_FLASH_Unlock();								// 解锁
	__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PGAERR | FLASH_FLAG_WRPERR);
	HAL_FLASHEx_Erase(&My_Flash, &PageError);
	HAL_FLASH_Lock();								// 上锁
	__enable_irq(); 							// 开总中断
}

用这三句代替之前的标准库的:写 读 擦
在升级过程中遇到了4个问题,第一个问题是,收到分包内容之后,就被清理了,之后串口BUF里的数据变成了一个不对的数,这导致一个包需要重复传3次左右才成功,大大影响了升级效率。后来改了stm32l1xx_hal_uart.c才解决了这个问题。在HAL串口库里有这么一句:

  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if (errorflags == RESET)
  {
    /* UART in mode Receiver -------------------------------------------------*/
    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }

其实DEBUG一下,也知道是USART_SR_FE的问题,即:帧错误。 但是实在是找不到为什么帧错误。索性就把**if (errorflags == RESET)**屏蔽了。之后还屏蔽了一处:

#if 0
    if (--huart->RxXferCount == 0U)
    {
      /* Disable the UART Data Register not empty Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

      /* Disable the UART Parity Error Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
      __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

      /* Rx process is completed, restore huart->RxState to Ready */
      huart->RxState = HAL_UART_STATE_READY;

      /* Check current reception Mode :
         If Reception till IDLE event has been selected : */
      if (huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
      {
        /* Set reception type to Standard */
        huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;

        /* Disable IDLE interrupt */
        CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);

        /* Check if IDLE flag is set */
        if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE))
        {
          /* Clear IDLE flag in ISR */
          __HAL_UART_CLEAR_IDLEFLAG(huart);
        }

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
        /*Call registered Rx Event callback*/
        huart->RxEventCallback(huart, huart->RxXferSize);
#else
        /*Call legacy weak Rx Event callback*/
        HAL_UARTEx_RxEventCallback(huart, huart->RxXferSize);
#endif
      }
      else
      {
       /* Standard reception API called */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)		  
       /*Call registered Rx complete callback*/
       huart->RxCpltCallback(huart);
#else
       /*Call legacy weak Rx complete callback*/
       HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
      }

      return HAL_OK;
    }
	#endif

这个问题得以解决。至于原因,后续再探讨,实在是没有时间看着一块。

第二个问题是,升级过程中到了第16包溢出,但换个板子就没事了。或者在最后跳转的时候,进入到了HardFault_Handler中,原因不明。最后无解,换了个单片机之后,溢出和HardFault_Handler也都不见了。至于为什么用着用着单片机就不行了,可能是硬件设计有问题。

第三个问题,就是换了单片机之后,晶振不起振,卡死到HAL_RCC_OscConfig函数中。只能去重新修改时钟树,改为内部的晶振。这个不起振在L系列见的比较多,在F系列还没见到。看得文章也不少了,原因大概率和电源有关。可靠的解决办法2个,要么设计的时候设计成有源晶振,要么用单片机内部的晶振(总不能单片机自带的晶振也不行吧?)

第四个问题,跳转了之后程序不正常。可能是在跳转之前关闭了一些东西,但即便如此,挑转到了新程序的地方也有初始化啊,但就是不行。后来在写完程序之后,加了一个复位。即:程序写到制定位置之后,复位HAL_NVIC_SystemReset(); 之后再跳转。这样就没问题了。因为要复位,所以要借助于FLASH给标记。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-31 15:36:26  更:2021-08-31 15:38:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:45:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码