Memory STM32闪存写入导致多个硬故障错误

Memory STM32闪存写入导致多个硬故障错误,memory,arm,embedded,stm32,microcontroller,Memory,Arm,Embedded,Stm32,Microcontroller,我试图将几个字节的数据写入STM32F410CBT3闪存扇区4(大小为64KB),我选择了这个扇区,并假设它可以安全使用,因为代码大约为30KB(可能位于扇区1和扇区2中)。微控制器的时钟速度为100MHz(通过PLL) 以下是我的Flash写入代码: /* Programming in 16-bit words, so offset address of 0x04 should be enough */ #define FLASH_SECTOR4_BASEADDRESS

我试图将几个字节的数据写入STM32F410CBT3闪存扇区4(大小为64KB),我选择了这个扇区,并假设它可以安全使用,因为代码大约为30KB(可能位于扇区1和扇区2中)。微控制器的时钟速度为100MHz(通过PLL)

以下是我的Flash写入代码:

/* Programming in 16-bit words, so offset address of 0x04 should be enough */
#define FLASH_SECTOR4_BASEADDRESS                       ((uint32_t)0x8011000)
#define OFFSET                                          ((uint8_t)0x04)

#define ADDR0               FLASH_SECTOR4_BASEADDRESS                                           
#define ADDR1               ((uint32_t)(ADDR0 + OFFSET))
#define ADDR2               ((uint32_t)(ADDR1 + OFFSET))
#define ADDR3               ((uint32_t)(ADDR2 + OFFSET))
/* and so on... */


void FLASH_Init(void)
{
    /* Only use FLASH Sector 4 for storing configuration/calibration data. s_EraseInit is stored as a static variable. This function called first because s_EraseInit needs to have values before any FLASH functions/routines are called. */
    s_EraseInit.TypeErase = TYPEERASE_SECTORS;
    s_EraseInit.Sector = FLASH_SECTOR_4;
    s_EraseInit.NbSectors = 1;
    s_EraseInit.VoltageRange = VOLTAGE_RANGE_4; /* Input voltage to mcu is around 3.3V */
}


void FLASH_Write(void)
{
    /* Stop LPTIM1 interrupts prior to modifying FLASH region */
    HAL_LPTIM_Counter_Stop_IT(&hlptim1);

    /* Assign temp_x values of struct members stored globally. temp_x will be the variable used for the FlashProgram function */
    uint16_t temp0 = GlobalStruct[0].Member1;
    uint16_t temp1 = GlobalStruct[0].Member2;
    uint16_t temp2 = GlobalStruct[0].Member3;
    uint16_t temp3 = GlobalStruct[1].Member1;
    uint16_t temp4 = GlobalStruct[1].Member2;
    uint16_t temp5 = GlobalStruct[1].Member3;
    uint16_t temp6 = GlobalStruct[2].Member1;
    uint16_t temp7 = GlobalStruct[2].Member2;
    uint16_t temp8 = GlobalStruct[2].Member3;
    uint16_t temp9 = GlobalStruct[3].Member1;
    uint16_t temp10 = GlobalStruct[3].Member2;
    uint16_t temp11 = GlobalStruct[3].Member3;

    /* Unlock FLASH peripheral and clear FLASH status register (error) flags */
    HAL_FLASH_Unlock();
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP|FLASH_FLAG_OPERR|FLASH_FLAG_WRPERR|FLASH_FLAG_PGAERR|FLASH_FLAG_PGSERR);
    
    /* Mass erase FLASH sector 4 */
    FlashStatus[12] = HAL_FLASHEx_Erase(&s_EraseInit, &s_SectorError);

    /* Write into FLASH sector 4 and lock the FLASH peripheral after using it */
    FlashStatus[0] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR0, temp0);
    FlashStatus[1] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR1, temp1);   
    FlashStatus[2] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR2, temp2);   
    FlashStatus[3] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR3, temp3);
    FlashStatus[4] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR4, temp4);
    FlashStatus[5] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR5, temp5);
    FlashStatus[6] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR6, temp6);
    FlashStatus[7] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR7, temp7);
    FlashStatus[8] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR8, temp8);
    FlashStatus[9] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR9, temp9);
    FlashStatus[10] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR10, temp10);
    FlashStatus[11] = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, ADDR11, temp11);

    HAL_FLASH_Lock();
    
    /* Resume LPTIM1 interrupts after modifying FLASH region */
    HAL_LPTIM_Counter_Start_IT(&hlptim1, LPTIM1_AUTORELOAD_NUMBER);     
}

/*********************** Relevant code from the HAL Library *******************************/

/**
  * @brief  Program byte, halfword, word or double word at a specified address
  * @param  TypeProgram  Indicate the way to program at a specified address.
  *                           This parameter can be a value of @ref FLASH_Type_Program
  * @param  Address  specifies the address to be programmed.
  * @param  Data specifies the data to be programmed
  * 
  * @retval HAL_StatusTypeDef HAL Status
  */
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
  HAL_StatusTypeDef status = HAL_ERROR;
  
  /* Process Locked */
  __HAL_LOCK(&pFlash);
  
  /* Check the parameters */
  assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
  
  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
  
  if(status == HAL_OK)
  {
    if(TypeProgram == FLASH_TYPEPROGRAM_BYTE)
    {
      /*Program byte (8-bit) at a specified address.*/
      FLASH_Program_Byte(Address, (uint8_t) Data);
    }
    else if(TypeProgram == FLASH_TYPEPROGRAM_HALFWORD)
    {
      /*Program halfword (16-bit) at a specified address.*/
      FLASH_Program_HalfWord(Address, (uint16_t) Data);
    }
    else if(TypeProgram == FLASH_TYPEPROGRAM_WORD)
    {
      /*Program word (32-bit) at a specified address.*/
      FLASH_Program_Word(Address, (uint32_t) Data);
    }
    else
    {
      /*Program double word (64-bit) at a specified address.*/
      FLASH_Program_DoubleWord(Address, Data);
    }
    
    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
    
    /* If the program operation is completed, disable the PG Bit */
    FLASH->CR &= (~FLASH_CR_PG);  
  }
  
  /* Process Unlocked */
  __HAL_UNLOCK(&pFlash);
  
  return status;
}
关于上面的代码,全局结构的成员是8位或16位。在进入闪存写入序列之前,我停止了LPTIM1中断,因为我认为如果LPTIM1中断恰好发生在微控制器覆盖其闪存时,则可能会导致问题

问题

尽管一个非常相似的代码(不同的是写入的数据)在不同的STM32F410CBT3微控制器上工作,但我在这段代码上一直存在硬故障错误。我还匹配了MDK-ARM
IROM1:Start 0x8000000,大小0x1C000
上的链接器设置,之前它位于
IROM1:Start 0x8000000,大小0x20000
。我观察到的常见模式是,基于MDK-ARM的内存查看器,当所有内存块上出现
时,闪存会被擦除。之后,它再次转到
0xFF
,表示没有写入任何块/节。此时,代码已经在其HardFault处理程序中。如果代码正常工作,扇区将从
变为写入闪存的任何值

关于硬故障错误,它有时显示为内存管理故障,其中引发了
IACCVIOL
(指令访问冲突标志),并且
SCB->MMFAR
不包含任何地址。在大多数情况下,它显示为总线故障,其中
SCB->BFAR=0xFFFFFFFF
,且
BFARVALID
标志处于高位,并且
preciser
标志也被提升。我查看了STM32F410内存映射,地址
0xFFFFFFFF
指向512Mbyte块7 Cortex-M4的内部外围设备。在极少数情况下,它显示为使用故障,其中
取消指示
位较高。有时,闪存写入序列确实有效,但仅在使用断点时有效

我尝试的

  • 最初,我立即将struct成员放在
    HAL\u FLASH\u程序
    api中。基于UsageFault错误,我认为结构成员访问太慢,所以我声明了那些无符号的16位
    tempX
    变量来保存结构成员的值。错误仍然存在,并且可能不是原因,因为编译器可能会以任何方式对其进行优化。我还尝试使用延迟,但错误仍然存在
  • 我将16位
    tempX
    变量声明更改为
    uint32\u t
    ,因为我在某个地方读到输入需要是32位或64位。我将其更改为
    uint32\t
    declarations,错误仍然存在
  • 我还尝试使用
    FLASH\u-TYPEPROGRAM\u-WORD
    而不是
    FLASH\u-TYPEPROGRAM\u-HALFWORD
    ,错误仍然存在。在不同的微控制器上,我注意到这不会有太大影响,因为如果我要在Flash部分本身中写入一个16位值(例如,
    0xAAAA
    ),如果使用
    Flash\u TYPEPROGRAM\u WORD
    ,它会显示为
    0x0000aaa
    ,或
    0xffffaaa
    如果使用了
    FLASH\u TYPEPROGRAM\u半字
    ,因为左16位被清除为
    0xFFFF
    ,但没有被重新写入
    0x0000
    ,因为只有至少16位被覆盖
  • 起初,我认为编写
    0xFFFF
    会引起问题,但在确保所有结构成员都是非零或非fff之后,错误仍然存在。在不同的微控制器上,我仍然可以将
    0xFFFF
    写入闪存,而不会导致任何错误
  • 我还尝试使用不同的位置(尽管仍然位于扇区4),但错误仍然存在
  • 我验证了每当发生硬故障错误时,
    FlashStatus[x],x=0…12
    仅包含
    HAL\u OK
    FLASH->SR
    寄存器通常也不显示任何内容(无错误状态)
  • 变量
    s_Sector error
    通常具有
    0xFFFFFFFF
    ,表示所有扇区(扇区4)都已成功擦除
问题
我错过了什么?任何帮助都将不胜感激。我也不知道如何更深入地调试这个问题,如果有任何关于调试这个问题的提示,我也将不胜感激,我将其用作识别硬故障错误的参考。谢谢大家!

我在查看HAL文件时犯了一个错误,使用了
电压范围范围范围范围范围范围4
闪光电压范围范围范围范围4
而不是
闪光电压范围范围范围范围范围3
。HAL文件显示,这两个选项都适用于由2.7V-3.6V供电的微控制器,但两个选项之间的差异是电压范围4的外部Vpp使用
FLASH\u VOLTAGE\u RANGE\u 3
实际上解决了我的问题
,这意味着我最初的问题是由于错误地擦除闪存而引起的,而不是因为我对闪存编程错误

我最初选择了
电压范围\u 4
,因为我在阅读参考手册中的这一页时误解了电压范围:

下面这一节实际上告诉我应该使用哪个电压范围,因为HAL库中引用的电压范围对应于
FLASH\u CR->PSIZE
位:

为什么每次尝试都会出现不同的硬故障错误,为什么需要以某种方式(64位擦除/32位擦除/16位擦除/8位擦除)擦除闪存,这对我来说仍然是个谜