STM32WB55xx 任意长度和任意地址写入的 Flash 驱动

本文深入探讨了STM32WB55xx系列微控制器的Flash编程细节,包括如何在不破坏蓝牙连接的情况下进行Flash操作,以及如何处理特定的Flash写入和擦除需求。文章提供了具体的代码实现,解释了为什么在尝试写入之前必须先擦除整个页面,即使页面内容已经是0xFF。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

wb这颗完蛋芯片的flash,即使整个page都是0xff也写不了必须擦除了才能写。
先在APP_BLE_Init() 中 添加两行

// 这一行防止flash操作导致断开链接
SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
void APP_BLE_Init( void )
{
...
/* Select which mechanism is used by CPU2 to protect its timing versus flash operation */
  SHCI_C2_SetFlashActivityControl(FLASH_ACTIVITY_CONTROL_SEM7);
  /**
   * The error flag shall be cleared before moving forward
   */
  __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
  /**
	* Initialize P2P Server Application
	*/
	P2PS_APP_Init();
	....
}
/**
 ******************************************************************************
 * File Name          : McuFlash.c
 * Description        : Flash driver for STM32WB55xx
 * @author            : zxk
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "app_common.h"

#include "flash_driver.h"
#include "shci.h"
#include "hw_conf.h"
#include "utilities_conf.h"

#include <stdio.h>
#include "cmsis_os.h"
#include "dbg_trace.h"
#include "McuFlash.h"
#include "main.h"

/* Private typedef -----------------------------------------------------------*/

/* Private defines -----------------------------------------------------------*/
#define FLASH_DBG			APP_DBG_MSG//PRINT_NO_MESG//

#define Rd64Bit(addr)       (*(uint64_t *)(addr))
#define USR_DATA_START		(ADDR_FLASH_PAGE_24)
#define USR_DATA_SIZE       (FLASH_PAGE_SIZE * 15)
#define USR_DATA_END		(USR_DATA_START + USR_DATA_SIZE - 1)
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint8_t pageBuff[FLASH_PAGE_SIZE];
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/

inline uint32_t GetPage(uint32_t Addr)
{
  return (Addr - FLASH_BASE) >> 12;
}

FlashWrRet McuFlashErase(uint32_t FirstPage, uint32_t NbOfPages)
{
	FLASH_EraseInitTypeDef EraseInitStruct;
	uint32_t PageError = 0;
	
	/* Fill EraseInit structure*/
	EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
	EraseInitStruct.Page        = FirstPage;
	EraseInitStruct.NbPages     = NbOfPages;
	/* Note: If an erase operation in Flash memory also concerns data in the data or instruction cache,
		you have to make sure that these data are rewritten before they are accessed during code
		execution. If this cannot be done safely, it is recommended to flush the caches by setting the
		DCRST and ICRST bits in the FLASH_CR register. */
	if (HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
	{
		FLASH_DBG("<0x%x>Erase once fail!\r\n",PageError);
		/* Try again. */
		if(HAL_FLASHEx_Erase(&EraseInitStruct, &PageError) != HAL_OK)
		{
			FLASH_DBG("<0x%x>Erase twice Error!\r\n",PageError);
			return 1;
		}
		/*Error occurred while  erase.user can call function 'HAL_FLASH_GetError()'*/
	}
	return 0;
}

FlashWrRet McuWriteNoChk(uint32_t addr, uint8_t * data, uint16_t len)
{
	Data64   tempData = {.buff = {0}};
	uint32_t tempAddr = 0;
	uint16_t tempLen  = 0;
	/* step.1 write head */
	if(addr & 0x07)
	{
		tempLen  = 8 - (addr & 0x07);
		tempLen  = (tempLen > len) ? len : tempLen;
		tempAddr = addr - (addr&0x07);
		memcpy(tempData.buff, (uint8_t *)tempAddr, 8);
		memcpy(&tempData.buff[addr & 0x07], data, tempLen);
		
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, tempAddr, tempData.num) != HAL_OK)
		{
			return 0x01;
		}
		len  -= tempLen;
		addr += tempLen;
		data += tempLen;
	}
	/* step.2 write body */
	while(len >= 8)
	{
		memcpy(tempData.buff, data, 8);
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, tempData.num) != HAL_OK)
		{
			return 0x02;
		}
		len  -= 8;
		addr += 8;
		data += 8;
	}
	/* step.3 write tail */
	if(len)
	{
		memcpy(tempData.buff, (uint8_t *)addr, 8);
		memcpy(tempData.buff, data, len);
		
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, tempData.num) != HAL_OK)
		{
			return 0x03;
		}
	}
	return 0;
}

FlashWrRet McuFlashWrie(uint32_t addr, uint8_t * data, uint16_t lenToWr)
{
	uint16_t pageOff    		= addr & 0x0FFF;
	uint16_t pageRemain 		= FLASH_PAGE_SIZE - pageOff;
	uint32_t pageAddr			= addr - pageOff;
	
	/* Check the input parameter.*/
	if((addr < USR_DATA_START) 	  || \
		(NULL == data)			  || \
		(lenToWr > USR_DATA_SIZE) || (0 == lenToWr))
		return 0x01;
	
	/* Unlock the Flash to enable the flash control register access *************/
	HAL_FLASH_Unlock();
	do{
		/* Updata the number of data to be written in this page. */
		pageRemain = (pageRemain > lenToWr) ? lenToWr : pageRemain;
		/* Copy the old data of this page before erase it. */
		memcpy(pageBuff, (uint8_t *)pageAddr, FLASH_PAGE_SIZE);
		/* Refresh the buff of this page. */
		memcpy(pageBuff+pageOff, data, pageRemain);
		/* Refresh flash data. */
		if(0 != McuFlashErase(GetPage(pageAddr), 1))
		{
			HAL_FLASH_Lock();
			FLASH_DBG("-<Err> McuFlashErase... 0x02.\n");
			return 0x02;
		}
		if(0 != McuWriteNoChk(pageAddr, pageBuff, FLASH_PAGE_SIZE))
		{
			HAL_FLASH_Lock();
			FLASH_DBG("-<Err> McuWriteNoChk... 0x03.\n");
			return 0x03;
		}
		/* Updata addr and length. */
		data 		+= pageRemain;
		lenToWr 	-= pageRemain;
		pageAddr 	+= FLASH_PAGE_SIZE;
		pageOff 	= 0;
		pageRemain 	= FLASH_PAGE_SIZE;		
	}while(lenToWr);
	/* Lock the Flash to disable the flash control register access (recommended
     to protect the FLASH memory against possible unwanted operation) *********/
	HAL_FLASH_Lock();
	
	return 0;
}

验证待写入的page全为0xff也不能直接写,这一页最近一个flash动作必须是被擦除。

static void DbgFlash(const char * str,uint32_t addr, short len)
{
	if(str != NULL)
	{
		MAIN_DBG("%s addr[0x%x]-%d\r\n",str,addr,uwTick);osDelay(1);
	}
	while(len--)
	{
		MAIN_DBG("0x%02x, ",*(uint8_t *)addr);
		addr++;
	}//osDelay(4);
	MAIN_DBG("\n\n\n"); osDelay(1);
}
void test_flash(void)
{
	uint32_t addr = FLASH_USER_START_ADDR;
	
	osDelay(64);
	
	DbgFlash("Before test operation:", addr, 16);

	HAL_FLASH_Unlock();
	
	McuFlashErase(GetPage(addr), 1);
	DbgFlash("-1-erase.", addr, 16);
	
	if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, 0xFFFFFFFFFFFFffFF) != HAL_OK)
	{
		MAIN_DBG("--<Err> ... HAL_FLASH_Program 0xff.\n");osDelay(2);
	}
	DbgFlash("after write 0xff.", addr, 16);
	
	if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr, 0xFFFFFFFFFFFF07FF) != HAL_OK)
	{
		MAIN_DBG("--<Err> ... HAL_FLASH_Program 0x07.\n");osDelay(2);
	}
	DbgFlash("after write 0x07.", addr, 16);
	HAL_FLASH_Lock();
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值