硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1177|回复: 7
收起左侧

[Flash] 求助 : stm32H743 读内部Flash进入硬件错误

[复制链接]

9

主题

81

回帖

108

积分

初级会员

积分
108
发表于 2024-11-22 09:26:42 | 显示全部楼层 |阅读模式
本帖最后由 让我看看各位 于 2024-11-22 10:54 编辑

读大文件(400K)90%会进硬件错误 , 小文件1K,基本不会死机  ,用H7Tool查进入硬件错误的原因是总线错误 ,一顿瞎折腾也不知道啥原因,大佬们求助

这是读函数:

/*
*********************************************************************************************************
*   函 数 名: STMFLASH_Write
*   功能说明: 从指定地址开始写入指定长度的数据
*   形    参:
*       waddr  - 起始地址(此地址必须为4的倍数)
*       pbuf   - 数据指针
*       length - 字(32位)数(就是要写入的32位数据的个数)
*   输    出: 无
*   返 回 值: 无
*   特    别:
*       - 因为STM32H7的扇区较大,如果写地址非0xFF,会先擦除整个扇区且不保存扇区数据,导致整个扇区数据丢失。
*       - 写非0xFF的地址前,确保扇区中没有重要数据,最好先擦除整个扇区再写入。
*       - 该函数对OTP区域也有效,可以用来写OTP区。
*       - OTP区域地址范围:0X1FFF7800 ~ 0X1FFF7A0F(注意:最后16字节用于OTP数据块锁定,不要随意写入)
*********************************************************************************************************
*/
void STMFLASH_Write(uint32_t waddr, uint32_t *pbuf, uint32_t length)
{
    FLASH_EraseInitTypeDef FlashEraseInit;
    HAL_StatusTypeDef FlashStatus = HAL_OK;
    uint32_t SectorError = 0;
    uint32_t addrx = 0;
    uint32_t endaddr = 0;

    if (waddr < STM32_FLASH_BASE || waddr % 32 ||      /* 写入地址小于 STM32_FLASH_BASE, 或不是32的整数倍, 非法. */
        waddr > (STM32_FLASH_BASE + STM32_FLASH_SIZE)) /* 写入地址大于 STM32_FLASH_BASE + STM32_FLASH_SIZE, 非法. */
    {
        return;
    }

    HAL_FLASH_Unlock();           /* 解锁 */
    addrx = waddr;                /* 写入的起始地址 */
    endaddr = waddr + length * 4; /* 写入的结束地址 */

    if (addrx < 0X1FF00000)
    {
        while (addrx < endaddr) /* 扫清一切障碍.(对非FFFFFFFF的地方,先擦除) */
        {
            if (STMFLASH_ReadWord(addrx) != 0XFFFFFFFF) /* 有非0XFFFFFFFF的地方,要擦除这个扇区 */
            {
                FlashEraseInit.Banks = FLASH_BANK_1;
                FlashEraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;     /* 擦除类型,扇区擦除 */
                FlashEraseInit.Sector = STMFLASH_GetFlashSector(addrx); /* 要擦除的扇区 */
                FlashEraseInit.NbSectors = 1;                           /* 一次只擦除一个扇区 */
                FlashEraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3;    /* 电压范围,VCC=2.7~3.6V之间!! */
                if (HAL_FLASHEx_Erase(&FlashEraseInit, &SectorError) != HAL_OK)
                {
                    break; /* 发生错误了 */
                }

                SCB_CleanInvalidateDCache(); /* 清除无效的D-Cache */
            }
            else
            {
                addrx += 128 * 1024;
            }
            FLASH_WaitForLastOperation(FLASH_WAITETIME, FLASH_BANK_1); /* 等待上次操作完成 */
        }
    }

    FlashStatus = FLASH_WaitForLastOperation(FLASH_WAITETIME, FLASH_BANK_1); /* 等待上次操作完成 */
    if (FlashStatus == HAL_OK)
    {
        while (waddr < endaddr) /* 写数据 */
        {
            if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, waddr, (uint64_t)pbuf) != HAL_OK) /* 写入数据 */
            {
                break; /* 写入异常 */
            }
            waddr += 32;
            pbuf += 8;
        }
    }
    HAL_FLASH_Lock(); /* 上锁 */
}

/*
*********************************************************************************************************
*   函 数 名: STMFLASH_ReadWord
*   功能说明: 从指定地址读取一个字 (32位数据)
*   形    参:
*       faddr - 读取地址 (此地址必须为4的倍数)
*   输    出: 无
*   返 回 值:
*       读取到的数据 (32位)
*********************************************************************************************************
*/
uint32_t STMFLASH_ReadWord(uint32_t faddr)
{
    return *(volatile uint32_t *)faddr;
}

/*
*********************************************************************************************************
*   函 数 名: STMFLASH_Read
*   功能说明: 从指定地址开始读出指定长度的数据
*   形    参:
*       raddr - 起始地址
*       pbuf  - 存储读取数据的缓冲区指针
*       length- 要读取的字(32位)数,即4个字节的整数倍
*   输    出: 无
*   返 回 值: 无
*********************************************************************************************************
*/
void STMFLASH_Read(uint32_t raddr, uint32_t *pbuf, uint32_t length)
{
    uint32_t i;
    for (i = 0; i < length; i++)
    {
        pbuf[i = STMFLASH_ReadWord(raddr); /* 读取4个字节 */
        raddr += 4;                         /* 偏移4个字节 */
    }
}

/*
*********************************************************************************************************
*   函 数 名: STMFLASH_GetFlashSector
*   功能说明: 获取某个地址所在的flash扇区
*   形    参:
*       faddr - flash地址
*   输    出: 无
*   返 回 值:
*       0~7 - addr所在的Bank1扇区编号
*       8~15 - addr所在的Bank2扇区编号(需要减去8,才得到Bank2的实际扇区编号)
*********************************************************************************************************
*/
uint8_t STMFLASH_GetFlashSector(uint32_t addr)
{
    if (addr < BANK1_FLASH_SECTOR_1)
        return 0;
    else if (addr < BANK1_FLASH_SECTOR_2)
        return 1;
    else if (addr < BANK1_FLASH_SECTOR_3)
        return 2;
    else if (addr < BANK1_FLASH_SECTOR_4)
        return 3;
    else if (addr < BANK1_FLASH_SECTOR_5)
        return 4;
    else if (addr < BANK1_FLASH_SECTOR_6)
        return 5;
    else if (addr < BANK1_FLASH_SECTOR_7)
        return 6;
    else if (addr < BANK2_FLASH_SECTOR_0)
        return 7;
    else if (addr < BANK2_FLASH_SECTOR_1)
        return 8;
    else if (addr < BANK2_FLASH_SECTOR_2)
        return 9;
    else if (addr < BANK2_FLASH_SECTOR_3)
        return 10;
    else if (addr < BANK2_FLASH_SECTOR_4)
        return 11;
    else if (addr < BANK2_FLASH_SECTOR_5)
        return 12;
    else if (addr < BANK2_FLASH_SECTOR_6)
        return 13;
    else if (addr < BANK2_FLASH_SECTOR_7)
        return 14;

    return 15;
}



下面是.H文件内容
#ifndef __STMFLASH_H
#define __STMFLASH_H

#include <stdint.h>

/* FLASH起始地址 */
#define STM32_FLASH_SIZE 0X200000   /* STM32 FLASH 总大小 */
#define STM32_FLASH_BASE 0x08000000 /* STM32 FLASH 起始地址 */

#define FLASH_WAITETIME 50000 /* FLASH等待超时时间 */

/* FLASH 扇区的起始地址,分2个bank,每个bank 1MB */
/* BANK1 */
#define BANK1_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Bank1扇区0起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_1 ((uint32_t)0x08020000) /* Bank1扇区1起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_2 ((uint32_t)0x08040000) /* Bank1扇区2起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_3 ((uint32_t)0x08060000) /* Bank1扇区3起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_4 ((uint32_t)0x08080000) /* Bank1扇区4起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_5 ((uint32_t)0x080A0000) /* Bank1扇区5起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_6 ((uint32_t)0x080C0000) /* Bank1扇区6起始地址, 128 Kbytes */
#define BANK1_FLASH_SECTOR_7 ((uint32_t)0x080E0000) /* Bank1扇区7起始地址, 128 Kbytes */

/* BNAK2 */
#define BANK2_FLASH_SECTOR_0 ((uint32_t)0x08100000) /* Bank2扇区0起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_1 ((uint32_t)0x08120000) /* Bank2扇区1起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_2 ((uint32_t)0x08140000) /* Bank2扇区2起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_3 ((uint32_t)0x08160000) /* Bank2扇区3起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_4 ((uint32_t)0x08180000) /* Bank2扇区4起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_5 ((uint32_t)0x081A0000) /* Bank2扇区5起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_6 ((uint32_t)0x081C0000) /* Bank2扇区6起始地址, 128 Kbytes */
#define BANK2_FLASH_SECTOR_7 ((uint32_t)0x081E0000) /* Bank2扇区7起始地址, 128 Kbytes */

不知道和内部的时钟主频配置有关系没
这是时钟树配置










时钟配置

时钟配置
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2024-11-23 09:36:55 | 显示全部楼层
楼主说的读大文件,是读取的内部Flash吗,使用函数STMFLASH_Read,这个函数看着没什么问题

方便的话,贴下你的测试代码看下。
回复

使用道具 举报

9

主题

81

回帖

108

积分

初级会员

积分
108
 楼主| 发表于 2024-11-29 10:11:41 | 显示全部楼层
本帖最后由 让我看看各位 于 2024-11-29 10:24 编辑

问题解决了 , 回来填个坑 , 同事找到的问题 ,我也跟着学习了; 正好发上来让大伙瞅瞅是不是这个思路
问题出在一下代码上 :

char *tempp;
        tempp = "mainSysCfg:0x";
        strcat((INT8 *)tempp, (char *)itoa_1(gMainBoardCfg, temps, 16));

先申请了一个char型的指针 tempp
然后tempp 重新指向了一个常量字符串 "mainSysCfg:0x",这里的"mainSysCfg:0x"是字符串 , 被编译再flash中 ,
然后使用 strcat 函数将 gMainBoardCfg 转换为十六进制字符串并拼接到 tempp 指向的字符串后面。

问题就出在使用 tempp直接修改了内部flash, 运行到这里后flash的寄存器就会报 (PGSERR1:存储区 1 编程顺序错误标志) , 内部flash中gMainBoardCfg后面本来编译好的被新增加的覆盖掉 , 然后运行到被覆盖掉的位置 , 就触发硬件错误死机 ;

然后现在修改成:
char *tempp;
strcpy((char *)tempp,"mainSysCfg:0x");
strcat((INT8 *)tempp, (char *)itoa_1(gMainBoardCfg, temps, 16));

不直接修改flash中内容了, 复制到ram中编辑 , 也不死机了 ,falsh寄存器也不报错了
回复

使用道具 举报

9

主题

81

回帖

108

积分

初级会员

积分
108
 楼主| 发表于 2024-11-29 10:40:16 | 显示全部楼层
其实还是有一个疑惑点 , 内部flash不是有锁么 , 这个指针是怎么绕过锁去修改的flash内容的呢
回复

使用道具 举报

356

主题

2180

回帖

3253

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3253
发表于 2024-11-29 11:07:55 | 显示全部楼层
让我看看各位 发表于 2024-11-29 10:40
其实还是有一个疑惑点 , 内部flash不是有锁么 , 这个指针是怎么绕过锁去修改的flash内容的呢

编译器不知道flash的锁,也不知道flash的擦写步骤,它只会按照普通读写存储器的模式去操作。
你这个操作属于代码错误,flash肯定没写上什么内容,但是内核会识别到,置标志位。

flash上防着的char,严谨的应该加入const这个关键字。指向flash的指针,也应该加入const关键字。编译器才有可能识别到错误。
回复

使用道具 举报

10

主题

112

回帖

142

积分

初级会员

积分
142
发表于 2024-11-29 11:14:28 | 显示全部楼层
本帖最后由 xy201207 于 2024-11-29 11:26 编辑
让我看看各位 发表于 2024-11-29 10:11
问题解决了 , 回来填个坑 , 同事找到的问题 ,我也跟着学习了; 正好发上来让大伙瞅瞅是不是这个思路
问题出 ...

你竟然往一个野指针复制数据?
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117546
QQ
发表于 2024-11-30 06:50:47 | 显示全部楼层
让我看看各位 发表于 2024-11-29 10:11
问题解决了 , 回来填个坑 , 同事找到的问题 ,我也跟着学习了; 正好发上来让大伙瞅瞅是不是这个思路
问题出 ...

谢谢告知最终原因。
回复

使用道具 举报

9

主题

81

回帖

108

积分

初级会员

积分
108
 楼主| 发表于 2024-12-2 08:44:32 | 显示全部楼层
caicaptain2 发表于 2024-11-29 11:07
编译器不知道flash的锁,也不知道flash的擦写步骤,它只会按照普通读写存储器的模式去操作。
你这个操作 ...

谢谢大佬
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-14 02:35 , Processed in 0.046197 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表