硬汉嵌入式论坛

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

[有问必答] stm32f10x内部flash为什么会被写两次

[复制链接]

23

主题

58

回帖

127

积分

初级会员

积分
127
发表于 2023-6-1 10:05:49 | 显示全部楼层 |阅读模式



[C] 纯文本查看 复制代码
u8 data_array[20]={0};

u16 STMFLASH_ReadHalfWord ( u32 faddr ) { /* 读取指定地址的半字(16位数据),参数faddr是读地址(此地址必须为2的倍数) */
    return * ( vu16 * ) faddr;
}

#if STM32_FLASH_WREN  /* 如果使能了写 */

/* 不检查的写入。参数WriteAddr是起始地址,pBuffer是数据指针,NumToWrite是半字(16位)的数量 */
void STMFLASH_Write_NoCheck ( u32 WriteAddr, u16 *pBuffer, u16 NumToWrite ) {
    u16 i;

    for ( i = 0; i < NumToWrite; i++ ) {
        FLASH_ProgramHalfWord ( WriteAddr, pBuffer[i] );
        WriteAddr += 2; /* 地址增加2 */
    }
}

#if STM32_FLASH_SIZE < 256
#define STM_SECTOR_SIZE 1024 /* 字节 */
#else
#define STM_SECTOR_SIZE 2048
#endif

u16 STMFLASH_BUF[STM_SECTOR_SIZE / 2]; /* 最多是2K字节 */

void STMFLASH_Write ( u32 WriteAddr, u16 *pBuffer, u16 NumToWrite ) { /* 从指定地址开始写入指定长度的数据 */
    u32 secpos; /* 扇区地址 */
    u16 secoff; /* 扇区内偏移地址(16位字计算) */
    u16 secremain; /* 扇区内剩余地址(16位字计算) */
    u16 i;
    u32 offaddr; /* 去掉0X08000000后的地址 */

    if ( WriteAddr < STM32_FLASH_BASE || ( WriteAddr >= ( STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE ) ) ) { /* 非法地址 */
        return;
    }

    FLASH_Unlock(); /* 解锁 */
    offaddr = WriteAddr - STM32_FLASH_BASE; /* 实际偏移地址 */
    secpos = offaddr / STM_SECTOR_SIZE; /* 扇区地址 */
    secoff = ( offaddr % STM_SECTOR_SIZE ) / 2; /* 在扇区内的偏移(2个字节为基本单位) */
    secremain = STM_SECTOR_SIZE / 2 - secoff; /* 扇区剩余空间大小 */

    if ( NumToWrite <= secremain ) { /* 不大于该扇区范围 */
        secremain = NumToWrite;
    }

    while ( 1 ) {
        STMFLASH_Read ( secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2 ); /* 读出整个扇区的内容 */

        for ( i = 0; i < secremain; i++ ) { /* 校验数据 */
            if ( STMFLASH_BUF[secoff + i] != 0XFFFF ) { /* 检验需要擦除 */
                break;
            }
        }

        if ( i < secremain ) { /* 如果需要擦除 */
            FLASH_ErasePage ( secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE ); /* 擦除这个扇区 */

            for ( i = 0; i < secremain; i++ ) { /* 复制 */
                STMFLASH_BUF[i + secoff] = pBuffer[i];
            }

            STMFLASH_Write_NoCheck ( secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2 ); /* 写入整个扇区 */
        } else {
            STMFLASH_Write_NoCheck ( WriteAddr, pBuffer, secremain );
        }

        if ( NumToWrite == secremain ) {
            break; /* 写入结束了 */
        } else { /* 写入未结束 */
            secpos++; /* 扇区地址增1 */
            secoff = 0; /* 偏移位置为0 */
            pBuffer += secremain; /* 指针偏移 */
            WriteAddr += secremain; /* 写地址偏移 */
            NumToWrite -= secremain; /* 字节(16位)数递减 */

            if ( NumToWrite > ( STM_SECTOR_SIZE / 2 ) ) {
                secremain = STM_SECTOR_SIZE / 2; /* 下一个扇区还是写不完 */
            } else {
                secremain = NumToWrite; /* 下一个扇区可以写完了 */
            }
        }
    };

    FLASH_Lock(); /* 上锁 */
}
#endif

void STMFLASH_Read ( u32 ReadAddr, u16 *pBuffer, u16 NumToRead ) { /* 从指定地址开始读出指定长度的数据 */
    u16 i;

    for ( i = 0; i < NumToRead; i++ ) {
        pBuffer[i] = STMFLASH_ReadHalfWord ( ReadAddr ); /* 读取2个字节 */
        ReadAddr += 2; /* 偏移2个字节 */
    }
}

void Test_Write ( u32 WriteAddr, u16 WriteData ) {
    STMFLASH_Write ( WriteAddr, &WriteData, 1 );
}
void test_aa(void)
{
	const u8 TEXT_Buffer[] = {"STM32 FLASH TEST"}; /* 要写入到STM32中FLASH的字符串数组 */
	#define SIZE sizeof(TEXT_Buffer) /* 数组长度 */
	u8 datatemp[SIZE] = {0};
	STMFLASH_Write ( FLASH_SAVE_ADDR, ( u16 * ) TEXT_Buffer, SIZE );
	STMFLASH_Read ( FLASH_SAVE_ADDR, ( u16 * ) datatemp, SIZE );
}

[C] 纯文本查看 复制代码
#if !defined(__data_store_)
#define __data_store_
#ifndef __STMFLASH_H__
#define __STMFLASH_H__
#include "sys.h"
extern u8 data_array[];
#define STM32_FLASH_SIZE 128 /* 所选STM32的FLASH容量大小(单位为K) */
#define STM32_FLASH_WREN 1 /* 使能FLASH写入(0为不使能,1为使能) */
#define STM32_FLASH_BASE 0x08000000 /* STM32的FLASH起始地址 */

#define SIZE sizeof(TEXT_Buffer) /* 数组长度 */
#define FLASH_SAVE_ADDR  0X0801f000 
typedef enum
{
	FLASHDATA_INT=0,
	FLASHDATA_WRITE,
	FLASHDATA_READ

}flash_e;



u16 STMFLASH_ReadHalfWord ( u32 faddr ); /* 读出半字 */
void STMFLASH_WriteLenByte ( u32 WriteAddr, u32 DataToWrite, u16 Len ); /* 指定地址开始写入指定长度的数据 */
u32 STMFLASH_ReadLenByte ( u32 ReadAddr, u16 Len ); /* 指定地址开始读取指定长度数据 */
void STMFLASH_Write ( u32 WriteAddr, u16 *pBuffer, u16 NumToWrite ); /* 从指定地址开始写入指定长度的数据 */
void STMFLASH_Read ( u32 ReadAddr, u16 *pBuffer, u16 NumToRead ); /* 从指定地址开始读出指定长度的数据 */
void Test_Write ( u32 WriteAddr, u16 WriteData ); /* 测试写入 */

void test_aa(void);
void data_store_fuc(flash_e a,int8_t *seror_num,int8_t *dtu_tti,uint8_t *dtu_uint);
#endif



#endif

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106575
QQ
发表于 2023-6-1 10:26:08 | 显示全部楼层
这个是我们的,供参考,没有这种问题。

[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*
*	模块名称 : cpu内部falsh操作模块
*	文件名称 : bsp_cpu_flash.c
*	版    本 : V1.0
*	说    明 : 提供读写CPU内部Flash的函数
*	修改记录 :
*		版本号  日期        作者     说明
*		V1.0    2013-02-01 armfly  正式发布
*
*	Copyright (C), 2013-2014, 安富莱电子 [url]www.armfly.com[/url]
*
*********************************************************************************************************
*/

#include "bsp.h"

#define SECTOR_MASK			0xFFFFF800

/*
*********************************************************************************************************
*	函 数 名: bsp_GetSector
*	功能说明: 根据地址计算扇区首地址
*	形    参:无
*	返 回 值: 扇区首地址
*********************************************************************************************************
*/
uint32_t bsp_GetSector(uint32_t _ulWrAddr)
{
	uint32_t sector = 0;

	sector = _ulWrAddr & SECTOR_MASK;

	return sector;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_ReadCpuFlash
*	功能说明: 读取CPU Flash的内容
*	形    参:_ucpDst : 目标缓冲区
*			 _ulFlashAddr : 起始地址
*			 _ulSize : 数据大小(单位是字节)
*	返 回 值: 0=成功,1=失败
*********************************************************************************************************
*/
uint8_t bsp_ReadCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpDst, uint32_t _ulSize)
{
	uint32_t i;

	/* 如果偏移地址超过芯片容量,则不改写输出缓冲区 */
	if (_ulFlashAddr + _ulSize > FLASH_BASE_ADDR + FLASH_SIZE)
	{
		return 1;
	}

	/* 长度为0时不继续操作,否则起始地址为奇地址会出错 */
	if (_ulSize == 0)
	{
		return 1;
	}

	for (i = 0; i < _ulSize; i++)
	{
		*_ucpDst++ = *(uint8_t *)_ulFlashAddr++;
	}

	return 0;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_CmpCpuFlash
*	功能说明: 比较Flash指定地址的数据.
*	形    参: _ulFlashAddr : Flash地址
*			 _ucpBuf : 数据缓冲区
*			 _ulSize : 数据大小(单位是字节)
*	返 回 值:
*			FLASH_IS_EQU		0   Flash内容和待写入的数据相等,不需要擦除和写操作
*			FLASH_REQ_WRITE		1	Flash不需要擦除,直接写
*			FLASH_REQ_ERASE		2	Flash需要先擦除,再写
*			FLASH_PARAM_ERR		3	函数参数错误
*********************************************************************************************************
*/
uint8_t bsp_CmpCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpBuf, uint32_t _ulSize)
{
	uint32_t i;
	uint8_t ucIsEqu;	/* 相等标志 */
	uint8_t ucByte;

	/* 如果偏移地址超过芯片容量,则不改写输出缓冲区 */
	if (_ulFlashAddr + _ulSize > FLASH_BASE_ADDR + FLASH_SIZE)
	{
		return FLASH_PARAM_ERR;		/* 函数参数错误 */
	}

	/* 长度为0时返回正确 */
	if (_ulSize == 0)
	{
		return FLASH_IS_EQU;		/* Flash内容和待写入的数据相等 */
	}

	ucIsEqu = 1;			/* 先假设所有字节和待写入的数据相等,如果遇到任何一个不相等,则设置为 0 */
	for (i = 0; i < _ulSize; i++)
	{
		ucByte = *(uint8_t *)_ulFlashAddr;

		if (ucByte != *_ucpBuf)
		{
			if (ucByte != 0xFF)
			{
				return FLASH_REQ_ERASE;		/* 需要擦除后再写 */
			}
			else
			{
				ucIsEqu = 0;	/* 不相等,需要写 */
			}
		}

		_ulFlashAddr++;
		_ucpBuf++;
	}

	if (ucIsEqu == 1)
	{
		return FLASH_IS_EQU;	/* Flash内容和待写入的数据相等,不需要擦除和写操作 */
	}
	else
	{
		return FLASH_REQ_WRITE;	/* Flash不需要擦除,直接写 */
	}
}

/*
*********************************************************************************************************
*	函 数 名: bsp_WriteCpuFlash
*	功能说明: 写数据到CPU 内部Flash。
*	形    参: _ulFlashAddr : Flash地址
*			 _ucpSrc : 数据缓冲区
*			 _ulSize : 数据大小(单位是字节)
*	返 回 值: 0-成功,1-数据长度或地址溢出,2-写Flash出错(估计Flash寿命到)
*********************************************************************************************************
*/
uint8_t bsp_WriteCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpSrc, uint32_t _ulSize)
{
	uint32_t i;
	uint8_t ucRet;
	uint16_t usTemp;
	FLASH_Status status = FLASH_COMPLETE;

	/* 如果偏移地址超过芯片容量,则不改写输出缓冲区 */
	if (_ulFlashAddr + _ulSize > FLASH_BASE_ADDR + FLASH_SIZE)
	{
		return 1;
	}

	/* 长度为0 时不继续操作  */
	if (_ulSize == 0)
	{
		return 0;
	}

	/* 长度为奇数时不继续操作  */
	if ((_ulSize % 2) != 0)
	{
		return 1;
	}	

	ucRet = bsp_CmpCpuFlash(_ulFlashAddr, _ucpSrc, _ulSize);

	if (ucRet == FLASH_IS_EQU)
	{
		return 0;
	}

	__set_PRIMASK(1);  		/* 关中断 */

	/* FLASH 解锁 */
	FLASH_Unlock();

  	/* Clear pending flags (if any) */
	FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);	

	/* 需要擦除 */
	if (ucRet == FLASH_REQ_ERASE)
	{
		status = FLASH_ErasePage(bsp_GetSector(_ulFlashAddr));
		if (status != FLASH_COMPLETE)
		{
			return 2;
		}		
	}

	/* 按字节模式编程(为提高效率,可以按字编程,一次写入4字节) */
	for (i = 0; i < _ulSize / 2; i++)
	{
		//FLASH_ProgramByte(_ulFlashAddr++, *_ucpSrc++);		
		usTemp = _ucpSrc[2 * i];
		usTemp |= (_ucpSrc[2 * i + 1] << 8);
		status = FLASH_ProgramHalfWord(_ulFlashAddr, usTemp);
		if (status != FLASH_COMPLETE)
		{
			break;
		}
		
		_ulFlashAddr += 2;
	}

  	/* Flash 加锁,禁止写Flash控制寄存器 */
  	FLASH_Lock();

  	__set_PRIMASK(0);  		/* 开中断 */

	if (status == FLASH_COMPLETE)
	{
		return 0;
	}
	return 2;
}

/***************************** 安富莱电子 [url]www.armfly.com[/url] (END OF FILE) *********************************/


[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*
*	模块名称 : cpu内部falsh操作模块
*	文件名称 : bsp_cpu_flash.h
*	版    本 : V1.0
*
*	Copyright (C), 2013-2014, 安富莱电子 [url]www.armfly.com[/url]
*
*********************************************************************************************************
*/

#ifndef _BSP_CPU_FLASH_H_
#define _BSP_CPU_FLASH_H_

#define FLASH_BASE_ADDR	0x08000000			/* Flash基地址 */
#define	FLASH_SIZE		(1*1024*1024)		/* Flash 容量 */

/* Base address of the Flash sectors */
#define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */
#define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */
#define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */
#define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */
#define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */
#define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */
#define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */
#define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */
#define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes */

#define FLASH_IS_EQU		0   /* Flash内容和待写入的数据相等,不需要擦除和写操作 */
#define FLASH_REQ_WRITE		1	/* Flash不需要擦除,直接写 */
#define FLASH_REQ_ERASE		2	/* Flash需要先擦除,再写 */
#define FLASH_PARAM_ERR		3	/* 函数参数错误 */

uint8_t bsp_ReadCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpDst, uint32_t _ulSize);
uint8_t bsp_WriteCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpSrc, uint32_t _ulSize);
uint8_t bsp_CmpCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpBuf, uint32_t _ulSize);

#endif


/***************************** 安富莱电子 [url]www.armfly.com[/url] (END OF FILE) *********************************/


回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-25 09:51 , Processed in 0.229710 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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