你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32H743 flash read 进入hardfault

[复制链接]
澜月亮 提问时间:2019-8-15 11:06 /
使用STM32H743VIT6芯片时,系统时钟为400MHz,从片上Flash读取数据时,有时会进入hardfault。对flash全部擦除后再次下载后,从片上Flash读取数据恢复正常。有没有大牛知道该如何解决这个问题?这是芯片本身的bug吗?

系统时钟配置如下:
//时钟设置函数
//Fvco=Fs*(plln/pllm);
//Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));
//Fq=Fvco/pllq=Fs*(plln/(pllm*pllq));

//Fvco:VCO频率
//Fsys:系统时钟频率,也是PLL1的p分频输出时钟频率
//Fq:PLL1的q分频输出时钟频率
//Fs:PLL输入时钟频率,可以是HSI,CSI,HSE等.

//plln:PLL1倍频系数(PLL倍频),取值范围:4~512.
//pllm:PLL1预分频系数(进PLL之前的分频),取值范围:2~63.
//pllp:PLL1的p分频系数(PLL之后的分频),分频后作为系统时钟,取值范围:2~128.(且必须是2的倍数)
//pllq:PLL1的q分频系数(PLL之后的分频),取值范围:1~128.

//CPU频率(rcc_c_ck)=sys_d1cpre_ck=400Mhz
//rcc_aclk=rcc_hclk3=200Mhz
//AHB1/2/3/4(rcc_hclk1/2/3/4)=200Mhz  
//APB1/2/3/4(rcc_pclk1/2/3/4)=100Mhz  
//FMC时钟频率=pll2_r_ck=((25/25)*512/2)=256Mhz

//外部晶振为25M的时候,推荐值:plln=160,pllm=5,pllp=2,pllq=2.
//得到:Fvco=25*(160/5)=800Mhz
//     Fsys=800/2=400Mhz
//     Fq=800/2=400Mhz
//外部晶振为16M的时候,推荐值:plln=250,pllm=5,pllp=2,pllq=2.
//得到:Fvco=16*(250/5)=800Mhz
//     Fsys=800/2=400Mhz
//     Fq=800/2=400Mhz
//返回值:0,成功;1,失败。
void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)
{
        HAL_StatusTypeDef ret=HAL_OK;
        RCC_ClkInitTypeDef RCC_ClkInitStruct;
        RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_PeriphCLKInitTypeDef periphClkInitStruct;
        
        MODIFY_REG(PWR->CR3,PWR_CR3_SCUEN, 0);
        __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

        while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {}

        RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_HSE;
        RCC_OscInitStruct.HSEState=RCC_HSE_ON;
        RCC_OscInitStruct.HSIState=RCC_HSI_OFF;
        RCC_OscInitStruct.CSIState=RCC_CSI_OFF;
        RCC_OscInitStruct.PLL.PLLState=RCC_PLL_ON;
        RCC_OscInitStruct.PLL.PLLSource=RCC_PLLSOURCE_HSE;

        RCC_OscInitStruct.PLL.PLLN=plln;
        RCC_OscInitStruct.PLL.PLLM=pllm;
        RCC_OscInitStruct.PLL.PLLP=pllp;
        RCC_OscInitStruct.PLL.PLLQ=pllq;

        RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
        RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
        ret=HAL_RCC_OscConfig(&RCC_OscInitStruct);
        if(ret!=HAL_OK) while(1);
//选中 PLL 作为系统时钟源并且配置 HCLK,PCLK1、 PCLK2、 PCLK3 和 PCLK4  
        RCC_ClkInitStruct.ClockType=(RCC_CLOCKTYPE_SYSCLK|\
                                RCC_CLOCKTYPE_HCLK |\
                                RCC_CLOCKTYPE_D1PCLK1 |\
                                RCC_CLOCKTYPE_PCLK1 |\
                                RCC_CLOCKTYPE_PCLK2 |\
                                RCC_CLOCKTYPE_D3PCLK1);

        RCC_ClkInitStruct.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;//系统时钟源 PLL
        RCC_ClkInitStruct.SYSCLKDivider=RCC_SYSCLK_DIV1;//SYSCLK 分频系数 1
        RCC_ClkInitStruct.AHBCLKDivider=RCC_HCLK_DIV2;//AHB 分频系数 2
        RCC_ClkInitStruct.APB1CLKDivider=RCC_APB1_DIV2;//APB1 分频系数 2
        RCC_ClkInitStruct.APB2CLKDivider=RCC_APB2_DIV2;//APB2 分频系数 2
        RCC_ClkInitStruct.APB3CLKDivider=RCC_APB3_DIV2;//APB3 分频系数 2  
        RCC_ClkInitStruct.APB4CLKDivider=RCC_APB4_DIV2;//APB4 分频系数 2
/*ST 官方例程使用的就是 4 个 WS, 其实大于 2 个 WS 都可以(最大不
        能超过 7 个 WS),延时越久越稳定,但是肯定影响性能        */
        FLASH->ACR &= ~FLASH_ACR_WRHIGHFREQ_Msk;
        FLASH->ACR |= FLASH_ACR_WRHIGHFREQ_2;//rcc_aclk 设置的是 200Mhz,设置 WRHIGHFREQ[1:0]=10 即可
        ret=HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);

        if(ret!=HAL_OK) while(1);
        
//设置SPI1的时钟源
        periphClkInitStruct.PeriphClockSelection=RCC_PERIPHCLK_SPI1 | RCC_PERIPHCLK_SPI3 | RCC_PERIPHCLK_SPI6;            //设置SPI1 、 SPI3、SPI6时钟源
        periphClkInitStruct.Spi123ClockSelection=RCC_SPI123CLKSOURCE_PLL;        //SPI1时钟源使用PLL1Q
        periphClkInitStruct.Spi6ClockSelection =RCC_SPI6CLKSOURCE_D3PCLK1;        //SPI6时钟源使用PCLK4 100MHz
       ret=HAL_RCCEx_PeriphCLKConfig(&periphClkInitStruct);
        if(ret!=HAL_OK) while(1);

        __HAL_RCC_CSI_ENABLE() ;
        __HAL_RCC_SYSCFG_CLK_ENABLE() ;  
        HAL_EnableCompensationCell();
}


flash 读写函数具体如下:
#include "hal_flash.h"
//读取指定地址的字(32 位数据)
//addr:读地址
//返回值:对应数据
uint32_t HAL_FLASH_ReadWord(uint32_t addr)
{
        uint32_t value = 0;
        value = *(__IO uint32_t*)addr;//此处进入hardfault,传入的地址为0x08060000
        return value;
}

uint16_t HAL_FLASH_GetFlashSector(uint32_t addr)
{
        if(addr<ADDR_FLASH_SECTOR_1_BANK1)return FLASH_SECTOR_0;
        else if(addr<ADDR_FLASH_SECTOR_2_BANK1)return FLASH_SECTOR_1;
        else if(addr<ADDR_FLASH_SECTOR_3_BANK1)return FLASH_SECTOR_2;
        else if(addr<ADDR_FLASH_SECTOR_4_BANK1)return FLASH_SECTOR_3;
        else if(addr<ADDR_FLASH_SECTOR_5_BANK1)return FLASH_SECTOR_4;
        else if(addr<ADDR_FLASH_SECTOR_6_BANK1)return FLASH_SECTOR_5;
        else if(addr<ADDR_FLASH_SECTOR_7_BANK1)return FLASH_SECTOR_6;
        else if(addr<ADDR_FLASH_SECTOR_0_BANK2)return FLASH_SECTOR_7;
        else if(addr<ADDR_FLASH_SECTOR_1_BANK2)return FLASH_SECTOR_0;
        else if(addr<ADDR_FLASH_SECTOR_2_BANK2)return FLASH_SECTOR_1;
        else if(addr<ADDR_FLASH_SECTOR_3_BANK2)return FLASH_SECTOR_2;
        else if(addr<ADDR_FLASH_SECTOR_4_BANK2)return FLASH_SECTOR_3;
        else if(addr<ADDR_FLASH_SECTOR_5_BANK2)return FLASH_SECTOR_4;
        else if(addr<ADDR_FLASH_SECTOR_6_BANK2)return FLASH_SECTOR_5;
        else if(addr<ADDR_FLASH_SECTOR_7_BANK2)return FLASH_SECTOR_6;
        return FLASH_SECTOR_7;
}
uint8_t HAL_FLASH_GetFlashBank(uint32_t addr)
{
        if(addr >= ADDR_FLASH_BANK1_START && addr <= ADDR_FLASH_BANK1_END)
                return FLASH_BANK_1;
        else if(addr >= ADDR_FLASH_BANK2_START && addr <= ADDR_FLASH_BANK2_END)
                return FLASH_BANK_2;
        else
                return 0;
}

uint32_t HAL_FLASH_EraseSector(uint32_t addr)//擦除片区
{
        FLASH_EraseInitTypeDef FlashEraseInit;
        uint32_t SectorError=0;
        uint8_t FLASH_BANK = 0;
        FLASH_BANK = HAL_FLASH_GetFlashBank(addr); //操作 BANK
        FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS; //擦除类型
        FlashEraseInit.Sector=HAL_FLASH_GetFlashSector(addr);//要擦除的扇区
        FlashEraseInit.Banks= FLASH_BANK;
        FlashEraseInit.NbSectors=1; //一次只擦除一个扇区
        FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3; //电压范围
        if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK)
        {
                return 1; //发生错误了
        }
        SCB_CleanInvalidateDCache(); //清除无效的 D-C
        return 0;
}

//从指定地址开始写入指定长度的数据
//特别注意:因为 STM32H7 的扇区实在太大,没办法本地保存扇区数据,所以本函数
// 写地址如果非 0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
// 写非 0XFF 的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
// 没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写.
//该函数对 OTP 区域也有效!可以用来写 OTP 区!
//OTP 区域地址范围:0X1FF0F000~0X1FF0F41F
//WriteAddr:起始地址(此地址必须为 4 的倍数!!)
//pBuffer:数据指针
//NumToWrite:字(32 位)数(就是要写入的 32 位数据的个数.)
void HAL_FLASH_Write(uint32_t WriteAddr,uint32_t *pBuffer,uint32_t NumToWrite)
{
        FLASH_EraseInitTypeDef FlashEraseInit;
        HAL_StatusTypeDef FlashStatus=HAL_OK;
        uint32_t SectorError=0;
        uint32_t addrx=0;
        uint32_t endaddr=0;
        uint8_t FLASH_BANK = 0;
        if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)
                return; //非法地址
        HAL_FLASH_Unlock(); //解锁
        addrx=WriteAddr; //写入的起始地址
        endaddr=WriteAddr+NumToWrite*4; //写入的结束地址
        
        if(addrx<0X1FF00000)
        {
                while(addrx<endaddr) //扫清一切障碍.(对非 FFFFFFFF 的地方,先擦除)
                {
                        if(HAL_FLASH_ReadWord(addrx)!=0XFFFFFFFF) //要擦除这个扇区
                        {
                                FLASH_BANK = HAL_FLASH_GetFlashBank(addrx); //操作 BANK
                                FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS; //擦除类型
                                FlashEraseInit.Sector=HAL_FLASH_GetFlashSector(addrx);//要擦除的扇区
                                FlashEraseInit.Banks= FLASH_BANK;
                                FlashEraseInit.NbSectors=1; //一次只擦除一个扇区
                                FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3; //电压范围
                                if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK)
                                {
                                        break; //发生错误了
                                }
                                SCB_CleanInvalidateDCache(); //清除无效的 D-Cache
                        }else
                                addrx+=4;
                        FLASH_WaitForLastOperation(FLASH_WAITETIME,FLASH_BANK);
                }
        }
        FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME,FLASH_BANK);
        if(FlashStatus==HAL_OK)
        {
                while(WriteAddr<endaddr)//写数据
                {
                        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD,WriteAddr,
                        (uint64_t)pBuffer)!=HAL_OK)//写入数据
                        {
                                break; //写入异常
                        }
                        WriteAddr+=32;
                        pBuffer+=8;
                }
        }
        HAL_FLASH_Lock(); //上锁
}

//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToRead:字(32 位)数
void HAL_FLASH_Read(uint32_t ReadAddr,uint32_t *pBuffer,uint32_t NumToRead)
{
        uint32_t i;
        for(i=0;i<NumToRead;i++)
        {
                pBuffer=HAL_FLASH_ReadWord(ReadAddr);//读取 4 个字节.
                ReadAddr+=4;//偏移 4 个字节.
        }
}

主函数如下:
int main(void)
{
__IO uint32_t data[API_FLASH_UPDATELEN] = {0};//API_FLASH_UPDATELEN为宏定义即32
Cache_Enable();                             //打开L1-Cache
        HAL_Init();                                                    //初始化HAL库
        Stm32_Clock_Init(250,5,2,4);                //设置时钟,400Mhz

        HAL_FLASH_Read(API_FLASH_UPDATE_ADDR, (uint32_t*)data, API_FLASH_UPDATELEN/4);//
API_FLASH_UPDATE_ADDR宏定义为0x08060000
#if 1
        while(1){
               
        }
#endif

}
报错时,相关寄存器的值如下图所示:

图片1.png


bus fault1.png













收藏 评论7 发布时间:2019-8-15 11:06

举报

7个回答
s7631001 回答时间:2019-8-15 12:21:19
抢个沙发吧
tanic 回答时间:2019-8-15 14:03:10
不是,一般是你指针操作有问题,
奏奏奏 回答时间:2019-8-15 17:18:36
#define        Reload_value_IWDG_ADDR 0x0800C000
volatile uint8_t Start_DATA[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};               

Start_DATA[0]=*(unsigned int *)Reload_value_IWDG_ADDR;

难道不是像上面这样的,直接一行代码去读取FLASH中某个字节吗?
我就是这么操作的呀。
至少F1系列与L4系列是这么干的。

澜月亮 回答时间:2019-8-15 17:29:01
奏奏奏 发表于 2019-8-15 17:18
#define        Reload_value_IWDG_ADDR 0x0800C000
volatile uint8_t Start_DATA[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0 ...

我试试先
澜月亮 回答时间:2019-8-16 09:51:00
不是Flash 读取有问题,应该是HAL_FLASH_Write(uint32_t WriteAddr,uint32_t *pBuffer,uint32_t NumToWrite)函数写入数据异常导致下次读取数据有问题。现已将HAL_FLASH_Write(uint32_t WriteAddr,uint32_t *pBuffer,uint32_t NumToWrite)函数进行了调整。目前Flash访问正常
lyh04048 回答时间:2020-3-17 08:55:00
楼主,我也遇到你这样的问题了,请问你怎么解决的?麻烦指教一下。
lyh04048 回答时间:2020-3-17 09:07:52
楼主,你是怎么解决这问题的?

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版