liyue12 发表于 2020-6-4 17:19:48

stm32l431 flash无法写入的问题

芯片型号是STM32L431RC,用HAL库往flash里写入一个双字无法成功。stm32l4 系列只能双字写,或者fast写(写一个ROW,另外我试了这种方式也没成功)。

代码如下:
      __disable_irq();
      HAL_FLASH_Unlock();

      __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGAERR | FLASH_FLAG_WRPERR);

      FLASH_PageErase(100, FLASH_BANK_1);         //stm32l431一页2048字节,100页对应0x8032000,FLASH容量256kb,也没有超                                                                            //只有bank1
      ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, 0x8032000, 0x0102030405060708);
      printf("errcode = %x\n", pFlash.ErrorCode);

      HAL_FLASH_Lock();
      __enable_irq();


实验现象是:返回错误代码0xA0,查数据手册是 PGAERR 和 PGSERR。数据手册说PGSERR是在PGAERR置位的情况下置位的,所以错误原因应该是PGAERR. 可是写入数据的地址是0x803200,是8的倍数。

有没有人知道要怎么样才能写成功?



liyue12 发表于 2020-6-5 13:40:57

谢谢各位的回复,我发现我的程序问题出在哪里了,是我用的HAL库函数不对。擦除应该用HAL_FLASHEx_Erase这个函数。
如果用FLASH_PageErase 这个函数,那在后面加一句
CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB))关CR寄存器的PER位也行

是4楼给我的思路,我发现他提供的HAL包中的代码,用的擦除函数是HAL_FLASHEx_Erase,去看函数源码,
发现里面调用了FLASH_PageErase和FLASH_MassErase这两个函数(针对不同擦除方式)
在FLASH_PageErase这个函数后有CLEAR_BIT(FLASH->CR, (FLASH_CR_PER | FLASH_CR_PNB))
在FLASH_MassErase这个函数后有CLEAR_BIT(FLASH->CR, (FLASH_CR_MER1))
所以问题是函数用错了,导致该清零的位没有清零。

另外3楼说的,可能是您理解错了,stm32的内存控制寄存器平时是锁着的,操作内存时是要先解锁,操作完了再上锁,所以顺序是对的。

MrJiu 发表于 2020-6-5 00:21:56

没用过用HAL写flash,自己直接用的寄存器实现的...好像问题不大!!!;P;P;P

mikecai 发表于 2020-6-5 10:03:52

初看一下,您的HAL_FLASH_Unlock()和HAL_FLASH_Loock() 位置应互换一下;锁定 flash,是不许别的进程来处理 flash 资源。当前 flash 处理后,unlock 它,许可别的task,别的进程,处理 flash

watershade 发表于 2020-6-5 12:14:54

这是HAL包中的代码,多了一个__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR)和__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PEMPTY)。还有一个选择Bank的过程:


int main(void)
{
uint8_t data_index = 0;

/* STM32L4xx HAL library initialization:
       - Configure the Flash prefetch, Instruction cache, Data cache
       - Systick timer is configured by default as source of time base, but user
         can eventually implement his proper time base source (a general purpose
         timer for example or other time source), keeping in mind that Time base
         duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
         handled in milliseconds basis.
       - Set NVIC Group Priority to 4
       - Low Level Initialization
   */
HAL_Init();

/* Configure the system clock to 120 MHz */
SystemClock_Config();

/* Initialize LED1, LED2 and LED3 */
BSP_LED_Init(LED1);
BSP_LED_Init(LED2);
BSP_LED_Init(LED3);

/* Unlock the Flash to enable the flash control register access *************/
HAL_FLASH_Unlock();

/* Erase the user Flash area
    (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/

/* Clear OPTVERR bit set on virgin samples */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);

/* Clear PEMPTY bit set (as the code is executed from Flash which is not empty) */
if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_PEMPTY) != 0)
{
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PEMPTY);
}

/* Get the bank */
BankNumber = GetBank(FLASH_USER_START_ADDR);

/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_MASSERASE;
EraseInitStruct.Banks   = BankNumber;

if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
{
    /*
      Error occurred while mass erase.
      User can add here some code to deal with this error.
      To know the code error, user can call function 'HAL_FLASH_GetError()'
    */
    /* Infinite loop */
    while (1)
    {
      BSP_LED_On(LED3);
    }
}

/* Program the user Flash area word by word
    (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/

Address = FLASH_USER_START_ADDR;

while (Address < (FLASH_USER_END_ADDR - (FLASH_ROW_SIZE*sizeof(uint64_t))))
{
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST, Address, (uint64_t)Data64_To_Prog) == HAL_OK)
    {
      Address = Address + (FLASH_ROW_SIZE*sizeof(uint64_t));
    }
   else
    {
      /* Error occurred while writing data in Flash memory.
         User can add here some code to deal with this error */
      while (1)
      {
      BSP_LED_On(LED3);
      }
    }
}

if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FAST_AND_LAST, Address, (uint64_t)Data64_To_Prog) != HAL_OK)
{
    /* Error occurred while writing data in Flash memory.
       User can add here some code to deal with this error */
    while (1)
    {
      BSP_LED_On(LED3);
    }
}

/* Lock the Flash to disable the flash control register access (recommended
   to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();

/* Check if the programmed data is OK
      MemoryProgramStatus = 0: data programmed correctly
      MemoryProgramStatus != 0: number of words not programmed correctly ******/
Address = FLASH_USER_START_ADDR;
MemoryProgramStatus = 0x0;

while (Address < FLASH_USER_END_ADDR)
{
    for (data_index = 0; data_index < FLASH_ROW_SIZE; data_index++)
    {
      data64 = *(__IO uint64_t *)Address;
   
      if(data64 != Data64_To_Prog)
      {
      MemoryProgramStatus++;
      }
      Address = Address + sizeof(uint64_t);
    }
}

/*Check if there is an issue to program data*/
if (MemoryProgramStatus == 0)
{
    /* No error detected. Switch on LED1*/
    BSP_LED_On(LED1);
}
else
{
    /* Error detected. Switch on LED2*/
    BSP_LED_On(LED2);
}

/* Infinite loop */
while (1)
{
}
}

sxying 发表于 2020-6-5 16:55:40

在擦除那句后面加两句。
                        FLASH_WaitForLastOperation(FLASH_WAITETIME);                  //等待上次操作完成
                        CLEAR_BIT(FLASH->CR, FLASH_CR_PER);               

stm32l433 亲测可行。

liyue12 发表于 2020-6-5 19:00:27

是的,还要加上 FLASH_WaitForLastOperation(FLASH_WAITETIME) 这句话,等擦除完成

butterflyspring 发表于 2020-6-12 12:15:34

建议用 HAL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError) 这个函数擦除。这个函数里包含了对CACHE的禁止,逻辑更完整。具体可以参考官方例程:lol
页: [1]
查看完整版本: stm32l431 flash无法写入的问题