嵌入式开发--STM32G030C8T6,写片上FLASH死机CFGBSY和写入出错

故障现象1

G0系列,写片上FLASH时,经常死机,而且按复位键都没用,属于不断电都救不回来的那种死法。这种情况一般是由硬件置位了某个标志导致,只有断电才能故障复原。

故障查找

检查FLASH的相关寄存器,发现死机后SR寄存器如下图:

正常情况下,SR的值应该是等于0,如果哪一位不为0,则是出现了相应的错误。

上面的截图不仅仅是在死机之后出现,即使按下复位键,仍然是这样,通过操作寄存器,可以消除PGAERR和PGSERR两个标志位,但不能消除CFGBSY。

查手册发现,CFGBSY位是硬件置位和清0的,所以无法手动消除。

看来按复位键后,仍然不能正常工作的原因找到了,只要想办法清除这个标志位即可。

故障解决

通过向Flash的任意一个地址,直接写一个数,当然是不按照FLASH的操作流程。

数值无所谓。反正也不会真正写入数据的。

这时硬件会对FLASH的CFGBSY位清0,并将PGAERR和PGSERR两个标志位置位。

再手动对PGAERR和PGSERR两个标志位清0即可。

代码如下:

c 复制代码
//向任意地址写一个数,数值任意,在Flash的SR寄存器中,硬件会自动清除CFGBSY标志,同时产生2个错误
//再手动清除这两个错误标志即可清除CFGBSY标志
void LL_flash_clear_cfgbsy(void)    //CFGBSY标志无法软件清除,只能通过制造错误,让硬件清除
{
	if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_CFGBSY) != 0x00U)
	{
			*(uint32_t *)(0x08001000) = 1;	//向FLASH任意位置写一个数
			__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR) ;//清除2个标志位
			__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR) ;
	}
}

故障现象2

G0系列的FLASH写入,是双字模式,也就是一次写入8字节,即64位。

STM32G030C8T6的一页是2K字节,也就是256个u64。

当我写入的数据比较多时,比如一次写整整一页,这时就必然会在接近完成的时候发生写入错误,代码如下:

c 复制代码
//直接写入FLASH,在写入前不检查FLASH内容是否为空
u8 LL_flash_write_without_check(u32 addr, u64* pdata64, u16 len)
{
  u16 i,j;
  u8 ret;
  u64 read;
  u64 write;
  u8 err=0;
  
  HAL_FLASH_Unlock();
  
  for(j=0; j<len; j++)
  {
    for(i=0; i<10; i++)    //不超过10次的重复操作,以保证写入成功
    {
      ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr+j*8, *(pdata64+j));
      if(ret == HAL_OK)
      {
        read = *(__IO uint64_t *)(addr+j*8);  //在MCU认为写入正确以后,再次读取数据,并进行比对,如果比对不成功,说明写入出错
        write = *(pdata64+j);
        if(read == write)
          break;
        else
        {
          ret = 255;
          return ret;
        }
      }
      else
        err = 1;
    }
  }
  
  HAL_FLASH_Lock();
  return 0;
}

每次都会在写入超过0xe0,也就是224个数据之后出现错误,也可能是225,或者226,227,不会再更大了。换了板子也是同样的故障。

具体情况就是HAL_FLASH_Program返回值为0,表示写入成功,但是再次读取数据时,读出的数据与写入的数据不相等。

故障解决

不得已对代码进行了修改,如下

c 复制代码
//直接写入FLASH,在写入前不检查FLASH内容是否为空
u8 LL_flash_write_without_check(u32 addr, u64* pdata64, u16 len)
{
  u16 i,j;
  u8 ret;
  u64 read;
  u64 write;
  u8 err=0;
  
  HAL_FLASH_Unlock();
  
  for(j=0; j<len; j++)
  {
    for(i=0; i<10; i++)    //不超过10次的重复操作,以保证写入成功
    {
      write = *(pdata64+j);
      ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr+j*8, write);
      if(ret == HAL_OK)
      {
        read = *(__IO uint64_t *)(addr+j*8);  //在MCU认为写入正确以后,再次读取数据,并进行比对,如果比对不成功,说明写入出错
        if(read == write)
          break;
        else
        {
          ret = 255;
          HAL_FLASH_Lock();
          return ret;
        }
      }
      else
      {
        err = 1;
      }
    }
  }
  
  HAL_FLASH_Lock();
  return 0;
}

其实修改的就是

c 复制代码
      ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr+j*8, *(pdata64+j));

改成了

c 复制代码
      write = *(pdata64+j);
      ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr+j*8, write);

故障排除。而这两种方式是完全等价的啊。难道是编译器出问题了?

唉,问题解决就行。

相关推荐
旧味清欢|9 分钟前
关注分离(Separation of Concerns)在前端开发中的实践演进:从 XMLHttpRequest 到 Fetch API
javascript·http·es6
-代号95271 小时前
【JavaScript】十四、轮播图
javascript·css·css3
可待电子单片机设计定制(论文)2 小时前
【STM32设计】数控直流稳压电源的设计与实现(实物+资料+论文)
stm32·嵌入式硬件·mongodb
QTX187302 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
march_birds2 小时前
FreeRTOS 与 RT-Thread 事件组对比分析
c语言·单片机·算法·系统架构
小麦嵌入式3 小时前
Linux驱动开发实战(十一):GPIO子系统深度解析与RGB LED驱动实践
linux·c语言·驱动开发·stm32·嵌入式硬件·物联网·ubuntu
猿榜3 小时前
js逆向-喜某拉雅Xm-Sign参数解密
javascript
转转技术团队3 小时前
代码变更暗藏危机?代码影响范围分析为你保驾护航
前端·javascript·node.js
Mintopia3 小时前
Node.js高级实战:自定义流与Pipeline的高效数据处理 ——从字母生成器到文件管道的深度解析
前端·javascript·node.js