STM32F1内部FLASH读写例程

1、环境

STM32F107RC核心板 + Atollic TrueStudio + Win8.1

2、STM32F1系列单片机分类

打开参考手册第三章,可以获知:不同储存容量的单片机有不同的FLASH分布,而主要分为以下几类。1、low-density,2、medium-density,3、high-density,4、connectivity line。我们需要根据使用的单片机容量,确认其FLASH分布。

下图中,Table 3是STM32F107RC规格书上的关于兼容性的描述。从这里以及规格书上文描述,我们可以知道:

STM32F107RC属于connectivity line。

 

 

STM32F1内部FLASH读写例程_第1张图片

 3、硬石STM32F1开源的源代码

3.1 stm32f107_flash.c

/**
  ******************************************************************************
  * 文件名程: stm_flash.c 
  * 作    者: 硬石嵌入式开发团队
  * 版    本: V1.0
  * 编写日期: 2015-10-04
  * 功    能: 内部Falsh读写实现
  ******************************************************************************
  * 说明:
  * 本例程配套硬石stm32开发板YS-F1Pro使用。
  * 
  * 淘宝:
  * 论坛:http://www.ing10bbs.com
  * 版权归硬石嵌入式开发团队所有,请勿商用。
  ******************************************************************************
  */
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f107_flash.h"

/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
#if STM32_FLASH_SIZE < 256
  #define STM_SECTOR_SIZE  1024 //字节
#else 
  #define STM_SECTOR_SIZE	 2048
#endif


/* 私有变量 ------------------------------------------------------------------*/
#if STM32_FLASH_WREN	//如果使能了写 
static uint16_t STMFLASH_BUF [ STM_SECTOR_SIZE / 2 ];//最多是2K字节
static FLASH_EraseInitTypeDef EraseInitStruct;
#endif

/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
  * 函数功能: 读取指定地址的半字(16位数据)
  * 输入参数: faddr:读地址(此地址必须为2的倍数!!)
  * 返 回 值: 返回值:对应数据.
  * 说    明:无
  */
uint16_t STMFLASH_ReadHalfWord ( uint32_t faddr )
{
	return *(__IO uint16_t*)faddr; 
}

#if STM32_FLASH_WREN	//如果使能了写   
/**
  * 函数功能: 不检查的写入
  * 输入参数: WriteAddr:起始地址
  *           pBuffer:数据指针
  *           NumToWrite:半字(16位)数
  * 返 回 值: 无
  * 说    明:无
  */
void STMFLASH_Write_NoCheck ( uint32_t WriteAddr, uint16_t * pBuffer, uint16_t NumToWrite )   
{ 			 		 
  uint16_t i;
	
  for(i=0;i=(FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
	
  HAL_FLASH_Unlock();						//解锁
	
  offaddr=WriteAddr-FLASH_BASE;		//实际偏移地址.
  secpos=offaddr/STM_SECTOR_SIZE;			//扇区地址  0~127 for STM32F103RBT6
  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+FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
	for(i=0;i(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
      else secremain=NumToWrite;//下一个扇区可以写完了
    }
  };
  HAL_FLASH_Lock();//上锁
}



#endif

/**
  * 函数功能: 从指定地址开始读出指定长度的数据
  * 输入参数: ReadAddr:起始地址
  *           pBuffer:数据指针
  *           NumToRead:半字(16位)数
  * 返 回 值: 无
  * 说    明:无
  */
void STMFLASH_Read ( uint32_t ReadAddr, uint16_t *pBuffer, uint16_t NumToRead )   	
{
  uint16_t i;

  for(i=0;i

3.2 stm32f107_flash.h

#ifndef __STMFLASH_H__
#define __STMFLASH_H__

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f1xx_hal.h"

/* 类型定义 ------------------------------------------------------------------*/
/* 宏定义 --------------------------------------------------------------------*/
/************************** STM32 内部 FLASH 配置 *****************************/
#define STM32_FLASH_SIZE        256  // 所选STM32的FLASH容量大小(单位为K)
#define STM32_FLASH_WREN        1    // stm32芯片内容FLASH 写入使能(0,禁用;1,使能)

typedef enum
{
  FAILED = 0,
  PASSED = !FAILED
}TestStatus;

#define  FLASH_WriteAddress     0x0803F800            // 写在靠后位置,防止破坏程序
#define  FLASH_ReadAddress      FLASH_WriteAddress
#define  FLASH_TESTSIZE         512                 //实际是512*2=1024字节


/* 扩展变量 ------------------------------------------------------------------*/
/* 函数声明 ------------------------------------------------------------------*/
uint16_t STMFLASH_ReadHalfWord(uint32_t faddr);		  //读出半字

void STMFLASH_WriteLenByte(uint32_t WriteAddr, uint32_t DataToWrite, uint16_t Len );	      //指定地址开始写入指定长度的数据
uint32_t STMFLASH_ReadLenByte(uint32_t ReadAddr, uint16_t Len );					                    	//指定地址开始读取指定长度数据
void STMFLASH_Write( uint32_t WriteAddr, uint16_t * pBuffer, uint16_t NumToWrite );		//从指定地址开始写入指定长度的数据
void STMFLASH_Read( uint32_t ReadAddr, uint16_t * pBuffer, uint16_t NumToRead );   	//从指定地址开始读出指定长度的数据
//static TestStatus Buffercmp(uint16_t* pBuffer1, uint16_t* pBuffer2, uint16_t BufferLength);
TestStatus Buffercmp(uint16_t* pBuffer1, uint16_t* pBuffer2, uint16_t BufferLength);

#endif /* __STMFLASH_H__ */

/******************* (C) COPYRIGHT 2015-2020 硬石嵌入式开发团队 *****END OF FILE****/

3.3 main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * 

© Copyright (c) 2019 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "can.h" #include "dma.h" #include "lwip.h" #include "usart.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "string.h" #include "tcp_echoclient.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__))) /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ uint32_t counter_10ms, counter_50ms, counter_100ms, counter_200ms, counter_500ms, counter_1000ms, counter_2000ms, counter_5000ms, counter_10s; uint8_t flag_1ms, flag_10ms, flag_50ms, flag_100ms, flag_200ms, flag_500ms, flag_1000ms, flag_2000ms, flag_5000ms, flag_10s; uint8_t b_KeyNumber; uint8_t a_DtuInBuffer[100]; uint16_t b_DtuInBufferRxCnt; uint8_t a_DtuOutBuffer[100]; uint16_t b_DtuOutBufferRxCnt; struct netif gnetif; extern struct tcp_pcb *echoclient_pcb; uint32_t status_TCPProc; uint8_t a_SocketConfig[7]; uint8_t a_SocketHeartBeat[60]; uint8_t a_SocketHeartBeatInterval[2]; uint8_t a_SocketRegister[60]; uint8_t a_DtuInOutConfig[2]; uint8_t b_WifiMode; uint8_t a_RouterSsid[20]; uint8_t a_RouterPswd[20]; uint8_t a_Rs485Config[5]; uint8_t a_CanConfig[5]; uint8_t flag_DtuConfigUpdate; uint8_t flag_DtuEthReady = 0; uint32_t b_HeartBeatPackageCnt = 0; uint32_t b_232STM32ParamConfigBusyCnt = 0; //尝试通过串口和STM32交互时候,会让出相应时间,优先处理 /* 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 */ void Task_HeartBeatPackSent(void) { uint16_t b_interval; b_interval = (a_SocketHeartBeatInterval[0]<<8) + a_SocketHeartBeatInterval[1]; b_HeartBeatPackageCnt++; if(b_HeartBeatPackageCnt>=b_interval) { b_HeartBeatPackageCnt = 0; if(a_DtuInOutConfig[1]==1) { if(flag_8266DTUReady==1) { HAL_UART_Transmit(&huart3, a_SocketHeartBeat, strlen((char*)a_SocketHeartBeat), 100); printf("\r\n"); printf("\r\nA heart beat package is sent.\r\n "); } } else if(a_DtuInOutConfig[1]==2) { if(status_TCPProc>=2) { tcp_senddata(1); printf("\r\n"); printf("\r\nA heart beat package is sent.\r\n "); } } } } void cleanDtuInBuffer(void) { uint32_t i; for(i=0;i0) { printf("\r\n"); printf("\r\nData sent to Wifi: "); HAL_UART_Transmit(&huart3, (uint8_t*)a_DtuInBuffer, b_DtuInBufferRxCnt, 100); HAL_UART_Transmit(&huart1, (uint8_t*)a_DtuInBuffer, b_DtuInBufferRxCnt, 100); //debug cleanDtuInBuffer(); } } } else if(a_DtuInOutConfig[1]==2) { if(status_TCPProc>=2) { if(status_TCPProc == 2) { tcp_senddata(0); //专门发送注册包 } if(b_DtuInBufferRxCnt>0) { if(status_TCPProc <= 3) { tcp_senddata(0); } else { status_TCPProc = 0; } cleanDtuInBuffer(); } } } //把数据输出到RS232,RS485或者CAN if(a_DtuInOutConfig[0]==1) { if(b_DtuOutBufferRxCnt>0) { HAL_UART_Transmit(&huart1, (uint8_t*)a_DtuOutBuffer, b_DtuOutBufferRxCnt, 100); cleanDtuOutBuffer(); } } else if(a_DtuInOutConfig[0]==2) { if(b_DtuOutBufferRxCnt>0) { printf("\r\n"); printf("\r\nData sent to RS485: "); HAL_UART_Transmit(&huart1, (uint8_t*)a_DtuOutBuffer, b_DtuOutBufferRxCnt, 100);//debug RS485_TX_MODE(); HAL_UART_Transmit(&huart5, (uint8_t*)a_DtuOutBuffer, b_DtuOutBufferRxCnt, 100); HAL_Delay(1); RS485_RX_MODE(); cleanDtuOutBuffer(); } } else if(a_DtuInOutConfig[0]==3) { if(b_DtuOutBufferRxCnt>0) { k = 0; if(b_DtuOutBufferRxCnt>8) { for(i=0; i<8; i++) { Can_TxData[i] = a_DtuOutBuffer[i]; k += Can_TxData[i]; } } else { for(i=0; i0) { if(b_DtuOutBufferRxCnt>8) { Can_TxMessage(0, Can_TxHeader.StdId, 8, Can_TxData); } else { Can_TxMessage(0, Can_TxHeader.StdId, b_DtuOutBufferRxCnt, Can_TxData); } ArrayLeftShift8bits(a_DtuOutBuffer, &b_DtuOutBufferRxCnt); } else { b_DtuOutBufferRxCnt = 0; } } } } void Task_DtuRedoConfig(void) { if(flag_DtuConfigUpdate==0) return; HAL_Delay(10); printf("Re-initialize ETH, WIFI module, RS485... "); //ETH: if(status_TCPProc >= 2) { tcp_echoclient_disconnect(); status_TCPProc = 0; } //ESP8266: if(Status_NodeMCU>=6) { sprintf((char *)a_8266TxBuffer, "+++"); //esp8266 接收到这个+++会停止透传模式 HAL_UART_Transmit(&huart3, (uint8_t *)a_8266TxBuffer, strlen((char *)a_8266TxBuffer), 100); Status_NodeMCU = 0; HAL_Delay(100); } //485 //MX_RS485_Reconfigure(); printf("Completed.\r\n"); // flag_DtuConfigUpdate = 0; HAL_UART_Receive_IT(&huart1, &b_232RxByte, 1); } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* 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 */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_USART1_UART_Init(); MX_USART3_UART_Init(); MX_CAN1_Init(); MX_UART5_Init(); MX_LWIP_Init(); /* USER CODE BEGIN 2 */ RS232Interact_Init(); printf("Hello. STM32F107_DTU project: DTU. All in one.\n"); HAL_UART_Receive_IT(&huart1, &b_232RxByte, 1); HAL_UART_Receive_IT(&huart5, &b_485RxByte, 1); sprintf((char *)a_8266TxBuffer, "+++"); //esp8266 接收到这个+++会停止透传模式 HAL_UART_Transmit(&huart3, (uint8_t *)a_8266TxBuffer, strlen((char *)a_8266TxBuffer), 100); Status_NodeMCU = 0; status_TCPProc = 0; RS485_RX_MODE(); CAN_Config_User(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { if(a_DtuInOutConfig[1]==2) { MX_LWIP_Process(); } if(flag_1ms ==1) { flag_1ms = 0; Task_232PC_Interact(); if(flag_DtuConfigUpdate ==1) { Task_DtuRedoConfig(); } if(b_232STM32ParamConfigBusyCnt>6) { Task_DirectTransfer(); } } if(flag_10ms==1) { flag_10ms=0; } if(flag_50ms==1) { flag_50ms=0; } if(flag_100ms==1) { if(b_232STM32ParamConfigBusyCnt>6) { if(a_DtuInOutConfig[1]==1) { if((flag_ProcNodeMCUActive ==1)&&(status_232PC<12)) { Proc_NodeMCU(); } } } flag_100ms=0; } if(flag_200ms==1) { flag_200ms=0; } if(flag_500ms==1) { flag_500ms=0; } if(flag_1000ms==1) { flag_1000ms=0; HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); if(b_232STM32ParamConfigBusyCnt>6) { if(a_DtuInOutConfig[1]==2) { if(status_TCPProc<=1) { printf("connecting to TCP Server...\r\n"); tcp_echoclient_connect(); } } Task_HeartBeatPackSent(); } if(flag_ProcNodeMCUActive ==0) { flag_ProcNodeMCUActive = 1; } if(b_232STM32ParamConfigBusyCnt<80) { b_232STM32ParamConfigBusyCnt++; } } if(flag_2000ms==1) { flag_2000ms=0; } if(flag_5000ms==1) { flag_5000ms=0; } if(flag_10s==1) { flag_10s=0; } /* 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_DIV5; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.Prediv1Source = RCC_PREDIV1_SOURCE_PLL2; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; RCC_OscInitStruct.PLL2.PLL2State = RCC_PLL2_ON; RCC_OscInitStruct.PLL2.PLL2MUL = RCC_PLL2_MUL10; RCC_OscInitStruct.PLL2.HSEPrediv2Value = RCC_HSE_PREDIV2_DIV2; 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(); } /** Enables the Clock Security System */ HAL_RCC_EnableCSS(); /** Configure the Systick interrupt time */ __HAL_RCC_PLLI2S_ENABLE(); } /* USER CODE BEGIN 4 */ /** * @brief HAL_SYSTICK_Callback() * SW timer triggered every 1ms. */ void HAL_SYSTICK_Callback(void) { flag_1ms = 1; /*update counters*/ if(counter_10ms<9) { counter_10ms++; } else { counter_10ms = 0; flag_10ms = 1; } if(counter_50ms<49) { counter_50ms++; } else { counter_50ms = 0; flag_50ms = 1; } if(counter_100ms<99) { counter_100ms++; } else { counter_100ms = 0; flag_100ms = 1; if(counter_200ms<1) { counter_200ms++; } else { counter_200ms = 0; flag_200ms = 1; } if(counter_500ms<4) { counter_500ms++; } else { counter_500ms = 0; flag_500ms = 1; } if(counter_1000ms<9) { counter_1000ms++; } else { counter_1000ms = 0; flag_1000ms = 1; } if(counter_2000ms<19) { counter_2000ms++; } else { counter_2000ms = 0; flag_2000ms = 1; } if(counter_5000ms<49) { counter_5000ms++; } else { counter_5000ms = 0; flag_5000ms = 1; } if(counter_10s<99) { counter_10s++; } else { counter_10s = 0; flag_10s = 1; } } } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin ==GPIO_PIN_13) { b_KeyNumber++; if(b_KeyNumber>=2) { b_KeyNumber = 0; } sprintf((char *)a_DtuInBuffer, "a simple package\r\n"); b_DtuInBufferRxCnt = strlen((char *)a_DtuInBuffer); } } /* 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****/

4 试验结果

开发板上面的指示灯亮了,同时使用仿真器观察接收数组的内容:

STM32F1内部FLASH读写例程_第2张图片

 参考资料:

1、STM32F107规格书,https://www.st.com/resource/en/datasheet/stm32f107rc.pdf

2、STM32F107参考手册,https://www.st.com/resource/en/reference_manual/cd00171190.pdf

3、硬石YS-F1Pro开发板资料,http://www.ing10bbs.com/forum.php?mod=viewthread&tid=1458&extra=page%3D1

你可能感兴趣的:(单片机)