STM32f030f4p6 内部flash 打包读写
最近做到的项目在运行需要把一组uint8_t(unsigned char)的数据进行掉电储存,想到单片机STM32f030f4p6内部flash可以直接由程序操作,写了以下代码用于uint8_t数据打包保存和读取。 ? 1、程序清单 与 测试结果本程序包含5个文件,分别是: 1、Flash.c:内部flash读取储存相关函数 2、Flash.h:flash头文件 3、USART1.c:STM32F030F4P6的串口驱动,串口仅用于打印数据观察。 4、USART1.h:串口头文件 5、main.c:防止程序主入口 ? 1、Flash.c #include "Flash.h" #include "USART1.h" /******************************************************************************* * Function Name : doseFlashHasPackedMessage * Description : Does flash has packed messages * Input : None * Output : * Return : ture/false *******************************************************************************/ bool doseFlashHasPackedMessage(void) { uint16_t length; uint16_t getHead; /*Is head matched*/ getHead = (uint16_t)(*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR )); if( EEPPROM_PACKAGEHEAD != getHead ) { return false; } /*Is length zero*/ length = (*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+2)); if( 0 == length) { return false; } return true; } /******************************************************************************* * Function Name : getValuablePackedMessageLengthofFlash * Description : Get valuable packed message length of flash * Input : None * Output : * Return : valuable length *******************************************************************************/ uint16_t getValuablePackedMessageLengthofFlash( void ) { uint16_t length; /*Is head matched*/ if( EEPPROM_PACKAGEHEAD != (*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR )) ) { return 0; } /*Get length*/ length = (uint16_t)(*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+2)); return length; } /******************************************************************************* * Function Name : readPackedMessageFromFlash * Description : Read packed message form flash * Input : buff:point to first location of received buffer.length:Maxmum length of reception * Output : * Return : reception length *******************************************************************************/ uint16_t readPackedMessageFromFlash( uint8_t *buff,uint16_t length) { int i; uint16_t getLength; if( !doseFlashHasPackedMessage() ) return 0; /*Get valuable length*/ getLength = getValuablePackedMessageLengthofFlash(); /*Read out message*/ for(i=0;i<MIN(getLength,length);i++) { buff[i]= *(uint8_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+4+i); } return MIN(getLength,length); } /******************************************************************************* * Function Name : isItOddNumber * Description : is input data an odd number? * Input : number:input data * Output : * Return : true/false *******************************************************************************/ bool isItOddNumber(uint16_t number) { if(0 != number%2) { return true; } return false; } /******************************************************************************* * Function Name : Flash_eeprom_WriteWithPacked * Description : Write a group of datas to flash. * Input : buff:pointer of first data,length: write length * Output : * Return : true/false *******************************************************************************/ bool writeMessageToFlash( uint8_t *buff,uint16_t length) { uint16_t temp; int i; /*Protection*/ if( (length+4) > STM32F0xx_PAGE_SIZE ) { return false; } FLASH_Unlock( ); /*Clear all flags*/ FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR ); /*Erase first . Do not rember.*/ if(FLASH_COMPLETE != FLASH_ErasePage(STM32F0xx_FLASH_PAGE15_STARTADDR))//°üo?á?μè′ybusy { return false; } /*Write head*/ FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR,EEPPROM_PACKAGEHEAD ); /*Write length*/ FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR+2,length ); /*Write datas*/ for(i=0 ;i<length/2 ;i++) { temp = buff[2*i]|(uint16_t)buff[2*i+1]<<8; FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR+4+2*i,temp); } if( isItOddNumber(length) )//Write one more if length is odd number. { temp = (uint16_t)buff[length-1]; FLASH_ProgramHalfWord( STM32F0xx_FLASH_PAGE15_STARTADDR+4+(length-1),temp); } /*Read out and check*/ for(i=0 ;i<length ;i++) { if( *(uint8_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+4+i) != buff[i] ) { FLASH_Lock(); return false; } } FLASH_Lock(); return true; } /******************************************************************************* * Function Name : flashReadWriteTest * Description : Flash read write test. * Input : None * Output : None * Return : None *******************************************************************************/ void flashReadWriteTest( void ) { #define testReadWriteNumber 200 uint8_t buff_write[testReadWriteNumber]={0}; uint8_t buff_read[testReadWriteNumber]={0}; uint16_t length; int i; for( i=0;i<testReadWriteNumber;i++) { buff_write[i]=i; } writeMessageToFlash( buff_write,testReadWriteNumber); length = readPackedMessageFromFlash( buff_read,testReadWriteNumber); printf("length=%drn",length); for(i=0;i<length;i++) { printf("read[%d]=%drn",i,buff_read[i]); } while(1); } 2、Flash.h #ifndef __FLASH_H #define __FLASH_H #include "stm32f0xx.h" #include <stdbool.h> //Message head #define EEPPROM_PACKAGEHEAD 0xAA55// //Flash page head #define STM32F0xx_PAGE_SIZE 0x400 #define STM32F0xx_FLASH_PAGE0_STARTADDR 0x8000000 #define STM32F0xx_FLASH_PAGE1_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE2_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+2*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE3_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+3*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE4_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+4*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE5_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+5*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE6_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+6*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE7_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+7*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE8_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+8*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE9_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+9*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE10_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+10*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE11_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+11*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE12_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+12*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE13_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+13*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE14_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+14*STM32F0xx_PAGE_SIZE) #define STM32F0xx_FLASH_PAGE15_STARTADDR (STM32F0xx_FLASH_PAGE0_STARTADDR+15*STM32F0xx_PAGE_SIZE) #define MIN(A,B) (A<B?A:B) void flashReadWriteTest( void ) ; #endif 3、USART1.c #include "USART1.h" void USART1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1); GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA,&GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx; USART_Init(USART1,&USART_InitStructure); USART_Cmd(USART1,ENABLE); } void USART1_IRQHandler(void) { } /** * @brief Retargets the C library printf function to the USART. * @param None * @retval None */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the USART */ USART_SendData(USART1,(uint8_t) ch); /* Loop until the end of transmission */ while (USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET) {} return ch; } 4、USART1.h #ifndef __BSP_USART1_H #define __BSP_USART1_H #include "stm32f0xx.h" #include <stdio.h> #ifdef __GNUC__ /* With GCC/RAISONANCE,small printf (option LD Linker->Libraries->Small printf set to ‘Yes‘) calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f) #endif /* __GNUC__ */ void USART1_Init(void); #endif 5、main.c #include "stm32f0xx.h" #include "USART1.h" #include "Flash.h" int main(void) { USART1_Init(); flashReadWriteTest(); while(1) { } } ?测试结果:第54-199省略.. ? ? 2、程序详解2.1、内存结构:STM32F0xx的flash结构如下:最多具有64页,每页1KByte大小。 我使用的STM32F030F4P6 flash区域有16K,所以实际上只有0-15页,本程序中把需要保存的数据数据存放在最后一页(第15页)中。 ? 2.2、定义数据包结构为了保证储存和读出flash的数据是正确的,本程序将写入flash数据分为3个区域
? 2.3、写操作写操作有如下步骤:
/******************************************************************************* * Function Name : Flash_eeprom_WriteWithPacked * Description : Write a group of datas to flash. * Input : buff:pointer of first data,temp); } /*Read out and check*/ for(i=0 ;i<length ;i++) { if( *(uint8_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+4+i) != buff[i] ) { FLASH_Lock(); return false; } } FLASH_Lock(); return true; } ? 2.3.1、解锁操作:用户手册描述如下: 在(芯片)重置过后,为了防止多余的擦写操作flash会被保护。除了OBL_LAUNCH位用于重载option bit,FLASH_CR寄存器的其他部分都不可以访问。 需要把以下两个解锁序列写入FLASH_KEY寄存器,才能访问FLASH_CR:
检索官方库定位FLASH_Unlock()这个函数,它的底层实现与文档描述相符,另外增加了防止重复解锁的操作,直接使用FLASH_Unlock()这个函数即可以完成解锁。 ? ? 2.3.2、页擦除用户手册描述如下: ? 1、通过检查FLASH_SR寄存器的BSY位来确认flash没有使用 2、把FLASH_CR寄存器的PER位置SET 3、通过编写FLASH_AR寄存器来确认要擦除的页 4、将FLASH_CR寄存器的STRT位置SET 5、等待BSY位rst 6、检查FLASH_SR寄存器中的EOP标记(成功会置SET)(流程图没有、库函数没检查) 7、清除EOP标记(流程图没有、库函数没清除) ? 检索官方库定位到FLASH_ErasePage(uint32_t Page_Address)这个函数,它的底层实现与文档流程图描述相符,值得注意的是,手册描述中6、7步并没有出现在手册的流程图和库函数中(库版本V1.2.0)。但在使用中没有出现问题,这里先记录看以后使用中会不会出现问题 ? ? ? 2.3.3、往flash中写入数据用户手册描述如下 1、通过检查FLASH_SR寄存器的BSY位来确认flash没有使用 2、设置FLASH_CR寄存器的PG位 3、在目标地址上写入半个word的数据 4、等BSY位reset 5、检查FLASH_SR寄存器的EOP标记(SET表示成功)(流程图没有出现、库函数中没检查) ?检索官方库定位到FLASH_ErasePage(uint32_t Page_Address)这个函数,它的底层实现与文档流程图描述相符,同样地,库函数没有检查第五步的EOP标记 ? ? 2.3.4、上锁操作根据手册提示,定位到库函数void FLASH_Lock(void)。只要置位LOCK位就上锁了。 ? ? ? ? ? 2.4、读操作 ?程序如下 /******************************************************************************* * Function Name : readPackedMessageFromFlash * Description : Read packed message form flash * Input : buff:point to first location of received buffer.length:Maxmum length of reception * Output : * Return : reception length *******************************************************************************/ uint16_t readPackedMessageFromFlash( uint8_t *buff,length); } ? 根据用户手册提示,读操作是可以直接取址的,所以读操作实际只有如下一句只要用uint8_t类型取出目标地址再取值就可以了。 ? 但是,我们的数据是打包的(详见2.2),所以还需要: 1、根据报头判断是不是有效数据 2、根据长度判断要读取多少数据 3、最后才是读出数据 ? 2.4.1、判断数据有效性:我们通过报头来判断数据是不是自己写入的。 也就是判断flash第15页的第1、2个字节是不是0xaa55,如果不是,那这段数据是无效的。 另外再判断一下长度字段,如果长度等于0,也就是后面没有数据,那这段数据也是无效的。 ? /******************************************************************************* * Function Name : doseFlashHasPackedMessage * Description : Does flash has packed messages * Input : None * Output : * Return : ture/false *******************************************************************************/ bool doseFlashHasPackedMessage(void) { uint16_t length; uint16_t getHead; /*Is head matched*/ getHead = (uint16_t)(*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR )); if( EEPPROM_PACKAGEHEAD != getHead ) { return false; } /*Is length zero*/ length = (*(uint16_t*)(STM32F0xx_FLASH_PAGE15_STARTADDR+2)); if( 0 == length) { return false; } return true; } ?2.4.2、根据长度读出数据:? 在读Flash程序中,getLength是从flash中读出的长度,length是我们指定的最大读取长度。如果getLength大于我们指定读取长度,很可能会造成溢出,所以两者取小的一个防止溢出。 ? ? 到此为止程序写完了,要是有什么错误或不足的地方还望各位大佬指出,要是使用中出现什么BUG也希望大家回来反馈一下,十分感谢 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |