以前一直使用STM32F1系列的MCU做产品,去年参加了ST无锡研讨会,了解到STM32cubeMX,回来后就下载了,发现功能还是比较强大。正好一款产品需要改版,所以就选择了STM32F030,正好也偿试一下STM32cubeMX的强大功能。( A# }" p+ r" W+ U: w 打开软件,选择MCU,配置IO,配置外设,配置时钟,配置功能,一气呵成。不得不说,图形化的界面真的很直观,每个IO的复用功能,每个外设的时钟频率,等等一目了然。最后,可以直接生成IAR工程文件(当然也可以生成其他工程文件),再也不要为建工程而烦恼了。。。# S! x8 [$ u2 t) w& A* a9 `# F 接着,打开IAR,打开刚刚生成的工程文件,开始写应用程序(此过程省略)。) ]* A# o% f. W2 S5 b 由于有标定值需要储存,没几个字节,就打算存在内部FLASH中,因为之前也是这样做的。等到调试的时候,发现每次读出的值都是0xff,很明显是没有写进FLASH,于是就开始找原因 & ?' p! ^5 o* H* C- mvoid WriteRevise(void)2 f' [4 G% l" r0 E {9 V" p- h" b { & i5 s c/ r" M HAL_FLASH_Unlock(); ! o0 C8 b+ s" P6 e0 ^# s FLASH_PageErase(0x8003c00); & @8 R" j8 S& o# @2 ?, _ HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, 0x8003c00, RealFlow);4 U; c1 t! p' k" ^: |" H HAL_FLASH_Lock(); ' _' Z' M3 b7 i; V$ u}9 Z6 b8 ~9 X$ Y" Z' ~* j; |; D+ ? & }4 R2 m2 `5 I void GetRevise(void) " w6 b9 ^ b' X* c4 \. {- C{ ( n8 {8 v" }, M* d D$ C8 Y RealFlow = *(__IO uint32_t*)(0x8003c00); & Z3 } o% H6 I , i( w( z: J# i5 a) \2 {) T3 D3 a if(RealFlow == 0xffff)// > 8000 || RealFlow < 500)% b- h6 J- y5 p6 w { . B* [: s6 k" C+ o4 _ RealFlow = 2060;7 ?% y! C" L4 a" G" `7 r: B- Y. A3 j WriteRevise();8 S. f# b [( ]( `: @, V! D* D }! j) C# ]3 O. M' K# n$ y } / u5 h& e& }' G. N6 c0 Z" w, u& R5 x& S! Q$ [7 |$ Q8 a' H 读写函数都很简单,看不出问题。 ; T( x! S2 m+ A- O于是重写测试程序,单步跟踪,先来 读-加1-写-再读 操作,发现结果正确,接着,再来 读-加1-写-再读-擦除-再读 操作,发现结果也正确;这时候我有郁闷了,读,写,擦除操作都没问题,为什么程序里有不行呢? / L( O, c. M) N1 I! U8 r 没找到根本原因,就在原写函数中,每一步操作后加了一个读操作,也就是,解锁-读-擦除-读-写-读……发现写完之后再读就是0xff了,中间各种测试,延时、去掉擦除操作等等,最终,单独的写操作或者是擦除操作都是没有问题的,连起来就是不行。 / A" G) p5 y h5 J0 H在无技可施的时候,就去看看库函数里的实现方法,在看到擦除函数的时候发现: / S; O: R1 H* n" V( h/** % B+ j k% @3 b2 W * @brief Erase the specified FLASH memory page 8 ]! h5 \' M: N& ~7 i * @param PageAddress: FLASH page to erase 9 i( W% z! W" v" \ * The value of this parameter depend on device used within the same series 9 u, Z1 X6 ]3 X& K * T( G v+ v, `" Y8 G" j3 w y& i2 D$ T5 ^# V * @retval None * L' y) c& ?. f# p, P! J: V- l1 {; j */4 b. l- y; N8 m7 Q" z$ |" X3 I: R void FLASH_PageErase(uint32_t PageAddress) 8 W, `! U% O' }& \3 l' v& Z. h{ {; Z6 }6 @: I7 i0 @& X /* Clear pending flags (if any) */ : v4 L$ G" B& F$ e2 e __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); 8 C( \0 }8 [/ h& ]; c ! _$ Y) @6 D# f& z+ Q /* Proceed to erase the page */ ' i* S3 x) n6 O SET_BIT(FLASH->CR, FLASH_CR_PER); m/ Y7 V7 I- e. q: h6 c, y WRITE_REG(FLASH->AR, PageAddress);9 V' @1 @$ X( X SET_BIT(FLASH->CR, FLASH_CR_STRT); ) C& S5 J8 k' a& u; g! U} , P1 `, x8 C$ E3 n: s. B$ l9 ?% x* p2 U: Y$ k8 x 该函数中,只是置位了FLASH_CR_PER,然后写地址,开始擦除,而完成之后并没有清除该位。问题就出现在这儿,只要调用了擦除函数后,该位就一直为高,所以导致数据无法写入,而不调用擦除函数时,写正常。于是对该函数修改,如下: . P \3 j3 p7 \void FLASH_PageErase(uint32_t PageAddress)9 t+ }7 v' S1 S/ G1 ^4 Z( o1 v { ; z/ L6 i4 q* a6 S% n /* Clear pending flags (if any) */ ( i( _1 o6 `& t" r& K0 i2 e __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); $ v1 B, H! C# W1 u( f6 P " T. Q$ D3 O1 o2 M- _ /* Proceed to erase the page */: v6 ?( s J2 y( }: g SET_BIT(FLASH->CR, FLASH_CR_PER);, ], c# P+ v0 V1 w" ?/ s WRITE_REG(FLASH->AR, PageAddress);/ I3 s4 z) F/ I* _ SET_BIT(FLASH->CR, FLASH_CR_STRT);* |5 d2 _+ M6 [$ y9 n% J: e % |. _3 x; @- p FLASH_WaitForLastOperation((uint32_t)HAL_FLASH_TIMEOUT_VALUE);. n0 l7 x- _" \ CLEAR_BIT(FLASH->CR, FLASH_CR_PER);2 P8 E+ I* H j) Q7 o } , |/ I2 A8 x: F/ J8 p5 Y T: V- K% v/ e% E- m" u$ Y/ H# J 增加等待操作完成,清除FLASH_CR_PER,至此,读写FLASH正常。 2 ^+ b8 g! O* }8 B/ `( i* {4 G0 S# Y& ]- f , r9 U6 O* x ^. R& P1 l3 a G ======================================================================================== # F+ ]- x- k8 A) ^以上是我在第一次使用STM32cubeMX中遇到的一点问题,应该是ST在设计过程中出现的BUG,我也看了之前的F1库函数,在擦除后是需要清的。6 R6 N) T' P8 `# [( ? 希望ST的工作人员看到之后能对此优化,也希望各位工程师能避免此问题。5 y$ T7 y0 J8 S; k8 L9 H ; J1 [ X( Y( z/ y. x, ^ STM32cubeMX也刚出来不久,使用确实比较方便,但也难免有些BUG,不知道现在有多少人在用,什么地方可以交流? - Z8 b C) R6 }3 p; i/ l" }* x! g' H
cubeMX确实好,特别是配IO脚、外设、时钟、中断,生成的项目模板也好用。