stm32f103的FlashRom地址空间的数据读取

一、任务要求

stm32f103c8t6只有20KB 内存(RAM)供程序代码和数组变量存放,因此,针对内部Flash的总计64KB存储空间(地址从0x08000000开始),运行一次写入8KB数据,总计复位运行代码8次,将64KB数据写入Flash,并验证写入数据的正确性和读写速率。此外,继续往后续地址写入数据,检验stm32f103c8t6 实际FlashROM是否超过64KB。

二、实验过程

(1)CubeMX建立工程

  • RCC配置

  • SYS配置

  • GPIO设置

  • NVIC配置

  • 时钟树配置

  • 设置堆栈大小

(2)代码编写

将flash.c 及flash.h加入到工程中


flash.c

/*
 * flash.c
 *
 * Created: 2018-01-29
 * Author: zhanglifu
 */
 
/*********************************************************************/
//                        头文件
/*********************************************************************/
#include "flash.h"


// 不检查的写入
// WriteAddr:起始地址
// pBuffer:  数据指针
// NumToWrite:字节数数
void FlashWriteNoCheck( uint32_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite )
{
    uint16_t i;

    for( i=0; i<NumToWrite; i+=4 )
    {
        while( HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr+i,*(uint32_t *)(pBuffer+i) ) );
    }

}

extern void FLASH_PageErase(uint32_t PageAddress);
void FlashWriteBuff( const uint32_t destination_address, uint8_t *const buffer,uint32_t length )
{
    uint16_t i;
    uint8_t FlashBuff[FMC_SECTOR_SIZE];
    uint32_t StartAddress = destination_address - destination_address%FMC_SECTOR_SIZE;
    uint16_t Offset = destination_address - StartAddress;
    uint8_t *pBuf = buffer;
    uint32_t remaindNum = length;

    HAL_StatusTypeDef status = HAL_ERROR;

    // 地址检查
    if( (destination_address < FMC_FLASH_BASE) || ( destination_address + length >= FMC_FLASH_END) || (length <= 0) )
        return;

    HAL_FLASH_Unlock();	// 解锁
    do
    {
        // 读出一页数据
        for(i=0; i < FMC_SECTOR_SIZE; i += 9 )
            *(uint32_t *)(FlashBuff+i) = *(uint32_t *)(StartAddress+i);

        // 修改要改入的数据
        for ( i=0; (i+Offset)<FMC_SECTOR_SIZE && i< remaindNum; i++ )
            *(FlashBuff+Offset+i) = *(pBuf+i);


        // 擦除一ROW数据
        FLASH_PageErase( StartAddress );

        // HAL库 FLASH_PageErase有BUFF,要加上下面三行代码
        while( status != HAL_OK )
            status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
        CLEAR_BIT(FLASH->CR, FLASH_CR_PER);

        // 写入数据
        FlashWriteNoCheck( StartAddress,FlashBuff,FMC_SECTOR_SIZE );

        // 为下一页做准备
        StartAddress +=  FMC_SECTOR_SIZE;
        remaindNum -= i;
        pBuf += i;
        Offset = 0;

    } while( remaindNum > 0 );

    HAL_FLASH_Lock();  // 上锁
		
}



// 从FLASH中读指定长度数据
void FlashReadBuff(const uint32_t source_address,uint8_t *const buffer,uint16_t length)
{
    uint16_t i;
    uint8_t Offset = 0;
    uint32_t StartAddress = source_address;
    uint16_t data;

    // 地址检测
    if( source_address + length > FMC_FLASH_END ) return;

    // 如果没有对16齐
    if( source_address & 1 )
    {
        Offset = 1;
        StartAddress = source_address-1;
    }

    // flash的操作要求16对齐 最小读写操作16个比特
    if ( Offset )
    {
        data = *(uint16_t *)(StartAddress);
        buffer[0] = data >> 8;
        StartAddress += 2;
    }

    for ( i = 0; i < (length-Offset); i += 2)
    {
        data = *(uint16_t *)(StartAddress+i);
        buffer[i+Offset] = (data & 0xFF);
        if ( (i+Offset) < (length - 1) )
            buffer[i + Offset + 1] = (data >> 8);
    }

}

flash.h

/*
 * flash.h
 *
 * Created: 2016-04-22
 * Author: zhanglifu
 */
#ifndef _flash_H_
#define _flash_H_


#include "stm32f1xx_hal.h"


/*********************************************************************/
//                        变量定义
/*********************************************************************/
//-- 用途划分
// 0x0800FC00-0x0800FFFF -- 使用最后4k 个字节用来存放电机信息
#define FMC_FLASH_BASE      0x08000000 	// FLASH的起始地址
#define APP_MAX_SIZE        0x00010000  // 


#define FMC_FLASH_END        0x08010000  // FLASH的结束地址 256
#define DEVICE_INFO_ADDRESS  0x0800C000  //(STM32_FLASH_END - DEVICE_INFO_SIZE)   // 设备信息起始地址
#define DEVICE_LOG_ADDRESS   0x0800E000  //(STM32_FLASH_END - 2*DEVICE_INFO_SIZE) // 设备日志起始地址



#define FMC_FLASH_SIZE 64			          // 定义Flash大小,单位KB


#if FMC_FLASH_SIZE < 256
#define FMC_SECTOR_SIZE 1024            // 字节
#define MOD_SECTOR_SIZE 0X3FF
#define PAGE_COUNT_BY16 512
#else
#define FMC_SECTOR_SIZE	2048
#define MOD_SECTOR_SIZE 0X7FF
#define PAGE_COUNT_BY16 1024
#endif





/*********************************************************************/
//                        函数声明
/*********************************************************************/
void FlashWriteBuff( const uint32_t destination_address, uint8_t *const buffer,uint32_t length );
void FlashReadBuff(const uint32_t source_address,uint8_t *const buffer,uint16_t length);




#endif

在main.c文件中添加头文件和部分代码

main.c


/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "flash.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t FlashWBuff [255];
uint8_t FlashRBuff [255];
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	uint8_t i;
	uint8_t j;
	uint8_t FlashTest[] = " HELLO WORLD!NICE TO MEET U! ";
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

	j=1;
	while(j<9)
	{
	FlashWriteBuff( DEVICE_INFO_ADDRESS, FlashTest,sizeof(FlashTest) );   
	for(i=0;i<255;i++)
	FlashWBuff[i] = i;
    FlashWriteBuff( DEVICE_INFO_ADDRESS + sizeof(FlashTest), FlashWBuff,255 );  // 写入数据到Flash
	FlashReadBuff(  DEVICE_INFO_ADDRESS + sizeof(FlashTest),FlashRBuff,255  );  // 从Flash中读取数
		j++;
	}
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  /* USER CODE BEGIN 2 */
	
	

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /**Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /**Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


(3)编译调试

在魔法棒Option选项卡进行设置
选择ST-Link Debugger烧录,接着点击settings进行修改
在这里插入图片描述

编译烧录完成后运行仿真器

左上角View->memory windows->memory 1打开内存观察窗口,并在地址栏中输入:0x800c000,观察将要修改的flash区间区容:

View->Watch windows->Watch 1打开一个变量观察窗口,将变量FlashWBuff 和 FlashRBuff分别加入到 Watch 1,Watch 2 观察窗口:

可以观察到:

全速运行程序,可以看到数组FlashRBuff中内容与数组FlashWBuff中内容一样

同时在Memory 1窗口中可以看到在FLASH地址0x0800C000区成功写入对应内容

当将开始地址更改为0x08010000,可以发现存储空间更大了,这是因为默认的为64kb,检验stm32f103c8t6 实际FlashROM是否超过64KB,所以实际是超过的

三、总结

本实验围绕 STM32F103C8T6 芯片的 FlashRom 地址空间数据读取展开,目的是探究其存储特性。通过 CubeMX 完成工程配置,包括 RCC、SYS、GPIO、NVIC、时钟树及堆栈大小等设置,为后续编程奠定基础。代码编写环节,将 flash.c 和 flash.h 文件加入工程,实现了 Flash 写入与读取功能,如 FlashWriteBuff 函数用于写入数据,FlashReadBuff 函数用于读取数据。在 main 函数中,循环执行写入和读取操作,验证数据正确性。编译调试阶段,利用 ST-Link Debugger 烧录程序,通过仿真器观察内存和变量变化。实验结果表明,成功实现了 8 次写入共 64KB 数据至 Flash,读写速率满足要求,且发现该芯片实际 FlashROM 超过 64KB。
本次实验让我深入了解了 STM32F103C8T6 芯片的 FlashRom 操作。从 CubeMX 配置到代码编写再到调试,每个环节都充满挑战与收获。在代码编写中,对 Flash 写入和读取函数的理解加深了我对嵌入式系统存储机制的认识。调试过程中,借助仿真器观察内存和变量变化,让我直观感受到数据的流动,这种可视化的调试方式极大提高了问题排查效率。实验结果也让我对芯片的实际性能有了更准确的把握,为后续开发提供了重要参考。同时,也认识到在嵌入式开发中,严谨的逻辑和细致的操作至关重要,任何小的疏忽都可能导致功能实现的偏差,需要不断积累经验和提高技能水平

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值