以前一直使用STM32F1系列的MCU做产品,去年参加了ST无锡研讨会,了解到STM32cubeMX,回来后就下载了,发现功能还是比较强大。正好一款产品需要改版,所以就选择了STM32F030,正好也偿试一下STM32cubeMX的强大功能。# ?9 _$ N& D5 t6 J- w/ a 打开软件,选择MCU,配置IO,配置外设,配置时钟,配置功能,一气呵成。不得不说,图形化的界面真的很直观,每个IO的复用功能,每个外设的时钟频率,等等一目了然。最后,可以直接生成IAR工程文件(当然也可以生成其他工程文件),再也不要为建工程而烦恼了。。。) [3 c8 Y) L2 o% n ^* e 接着,打开IAR,打开刚刚生成的工程文件,开始写应用程序(此过程省略)。( r* R Y T7 \8 Z( X, t+ q 由于有标定值需要储存,没几个字节,就打算存在内部FLASH中,因为之前也是这样做的。等到调试的时候,发现每次读出的值都是0xff,很明显是没有写进FLASH,于是就开始找原因% k& L3 X% s. ?/ S) b void WriteRevise(void)" j0 n n' h$ ? { ( T+ N8 K. B$ K" f6 N HAL_FLASH_Unlock();- L) I6 P: [2 K% u FLASH_PageErase(0x8003c00); ( J& i$ s. `( [& K! {3 D0 z HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, 0x8003c00, RealFlow);% `& O. W1 j% C4 w/ x+ M5 i HAL_FLASH_Lock(); 1 B" |4 i+ U4 i: B} : J8 ]# ~, v$ F9 {. j* ~0 y' ~ $ u* K0 s. R2 n- ~$ o! Ovoid GetRevise(void)2 s' h, a5 k0 j4 q V { N3 J; }- [) l" W9 [9 S RealFlow = *(__IO uint32_t*)(0x8003c00);* M& ~5 O- E0 R0 n0 @8 T ' ]* L% q0 v6 b; _% c; U1 U2 K- { if(RealFlow == 0xffff)// > 8000 || RealFlow < 500)% s9 Y6 ?4 t! P7 y, Q g { 4 `2 R. j) `6 U4 ] RealFlow = 2060; 2 Q$ j9 x d$ L* m WriteRevise();3 v. E7 y( \7 T. n5 C8 D% m } - T Q. k& U2 G% G* N3 e} - [7 {7 i" d' o/ e6 C+ f) P6 f, W9 c 读写函数都很简单,看不出问题。& R: H m6 A# T s. K4 D 于是重写测试程序,单步跟踪,先来 读-加1-写-再读 操作,发现结果正确,接着,再来 读-加1-写-再读-擦除-再读 操作,发现结果也正确;这时候我有郁闷了,读,写,擦除操作都没问题,为什么程序里有不行呢? ! o3 _1 c$ o. _0 v3 `& N+ s& ? 没找到根本原因,就在原写函数中,每一步操作后加了一个读操作,也就是,解锁-读-擦除-读-写-读……发现写完之后再读就是0xff了,中间各种测试,延时、去掉擦除操作等等,最终,单独的写操作或者是擦除操作都是没有问题的,连起来就是不行。/ p" k4 V+ I/ Y. H& h2 }. H# x7 O, X$ \ 在无技可施的时候,就去看看库函数里的实现方法,在看到擦除函数的时候发现: T$ f# g6 ?/ l: R. @& c /** : R- I. W) a1 [4 B: o * @brief Erase the specified FLASH memory page* D6 f! r+ [$ t8 U9 p% }- } * @param PageAddress: FLASH page to erase0 b+ T5 C% u6 P2 F * The value of this parameter depend on device used within the same series * a' b5 g% `0 `" T0 O * - C9 Q0 K6 T* K* ?# d3 {* T * @retval None: i% ^2 C% y+ i( F* } */ $ o/ @6 s& [# c a2 A' ?; fvoid FLASH_PageErase(uint32_t PageAddress) ' _3 ?: F! l/ V$ i& e4 }/ c{ # M4 p; |4 v0 H5 |7 Z p /* Clear pending flags (if any) */ " K1 ^& Q: A& l+ c* _5 U$ c( e( W __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); ) z* \9 f5 P) ~9 }5 ]1 L" r * p" {) s; t, m /* Proceed to erase the page */ % k! E$ p) b2 ~) q SET_BIT(FLASH->CR, FLASH_CR_PER); 8 u% }' O M& Q, N. A0 O WRITE_REG(FLASH->AR, PageAddress);$ y: d( D: Q' T( C0 J+ E w+ Q SET_BIT(FLASH->CR, FLASH_CR_STRT); 7 Q' C) ]1 k; E6 k2 V} 8 j: b8 X' @ _8 S v* w" y2 v- R2 d$ ^& h4 M 该函数中,只是置位了FLASH_CR_PER,然后写地址,开始擦除,而完成之后并没有清除该位。问题就出现在这儿,只要调用了擦除函数后,该位就一直为高,所以导致数据无法写入,而不调用擦除函数时,写正常。于是对该函数修改,如下: & H& X9 c/ _* H3 ]' N) lvoid FLASH_PageErase(uint32_t PageAddress) 0 C/ k% c7 }7 ^$ ^) U9 M+ @ Q{ 3 Z) ^/ ?4 A P6 f, ` /* Clear pending flags (if any) */ 7 J Z1 I$ [) Y# a7 [( r' e, P$ b __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); % T H# | ^$ X3 N , @# L: d1 y' g- W& u /* Proceed to erase the page */0 Y! @! O% z$ ^& ]1 L7 ] k2 b SET_BIT(FLASH->CR, FLASH_CR_PER); 7 V# E" g+ F) s4 g$ E* | WRITE_REG(FLASH->AR, PageAddress); + Y8 O' e6 b; s9 N1 s& } SET_BIT(FLASH->CR, FLASH_CR_STRT); # O) {6 V# @- Y' r1 j. Y/ M! J . T# v9 i# q& T- ]9 [2 T/ Y I FLASH_WaitForLastOperation((uint32_t)HAL_FLASH_TIMEOUT_VALUE);6 u) @4 V3 g1 H% v1 R% Q CLEAR_BIT(FLASH->CR, FLASH_CR_PER); % i+ V3 X. i7 A}4 D1 C- a4 u1 u7 d# d- l 3 o4 l, N% j4 S h 增加等待操作完成,清除FLASH_CR_PER,至此,读写FLASH正常。$ j! h7 F$ b* F: }" e/ R5 c$ X1 u, T- m- S , N' l/ o4 O W) U" c6 ` + u1 p* U8 Y: R9 m8 w) q========================================================================================2 a$ `6 l& \1 [- ]/ q' ` 以上是我在第一次使用STM32cubeMX中遇到的一点问题,应该是ST在设计过程中出现的BUG,我也看了之前的F1库函数,在擦除后是需要清的。* K5 v8 E( A8 x7 r) \1 b& g: o5 a 希望ST的工作人员看到之后能对此优化,也希望各位工程师能避免此问题。 0 {/ C: g) E; ]9 F % a. `+ Z; {* w S% o7 M0 j" z, OSTM32cubeMX也刚出来不久,使用确实比较方便,但也难免有些BUG,不知道现在有多少人在用,什么地方可以交流? 1 O/ k# y5 H$ s: G1 I. x3 g1 f& Z
cubeMX确实好,特别是配IO脚、外设、时钟、中断,生成的项目模板也好用。