版主
![Rank: 7](static/image/common/star_level3.gif) ![Rank: 7](static/image/common/star_level2.gif) ![Rank: 7](static/image/common/star_level1.gif)
主题
帖子
积分10609
阅读权限200
注册时间2008-11-22
最后登录1970-1-1
在线时间 小时
|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2013-10-12 14:30
|
显示全部楼层
C8051F MCU应 用 笔 记& X, \- X: ^1 J' }
$ C% g+ [8 J2 nAN009 — 从应用程序写 FLASH ) p8 ]5 W6 N/ ^1 @0 r; U
( @" k) V; S4 l$ F
相关器件 " S6 C& e% r7 i, `
本应用笔记适用于下列器件:
: Q: t6 S3 G( A) L- {/ R( D+ h# Y& g. mC8051F000、C8051F001、C8051F002、C8051F005、C8051F006、C8051F007、C8051F010、
7 y" ?2 P& V! E# x K: Y7 I1 M2 TC8051F011 和 C8051F012。 & U/ h2 @; ^0 B# { g, H
引言 / n( F0 S( A$ T7 F
本应用笔记的目的是说明如何从应用程序写FLASH。在应用编程允许将FLASH用于非易失性* h- d8 @4 r/ Y, X$ q9 c2 b
信息的存储(例如配置参数),还可以允许采用JTAG接口之外的另一种接口(例如UART)进行在
9 D4 ^: T: Q6 W; D$ t系统引导装载。本笔记的最后给出了如何读和写FLASH的‘C’代码。 & ?+ _( E& t+ h" i% t2 N9 \
关键点
. p- d0 L, ]- I' Y 在应用编程允许将FLASH用于非易失性信息的存储,这一点与EEPROM类似。
$ o- `* X) v* X7 r5 Y7 R$ Q FLASH写/擦除寿命在 – 40 ~ + 85℃的工业温度范围内保证在 10000 次以上。
# l% Y( S7 K2 n* U( S- M6 u FLASH存储器用 MOVC指令读取(MOVC a, @A+DPTR)。 , v: _/ c! ?$ P# S0 h7 N
FLASH存储器用 MOVX 指令写入(MOVX @A+DPTR, a)。
: w" D; z! f$ x( K* w5 N FLASH页以 512 字节分界(0200h, 0400h, 依此类推)。 4 Z6 @* c) w. E P
FLASH写操作只能写入 0。因此在写一个 FLASH字节之前,包含该字节的页必须首先被擦除
/ L/ k( ~& y2 W3 S4 h# i(使该页中的所有位都为 1)。 # b8 t) [$ V. V' s* M
在进行 FLASH写或擦除之前,必须根据当前的系统时钟设置 FLSCL 中的 FLASCL 位。
) `2 t) t2 K/ [, V 在进行 FLASH写之前,必须将 PSWE 置 1。
0 k2 ?$ A4 ]4 P+ n; x4 h 在进行 FLASH擦除之前,必须将 PSWE 和 PSEE 置 1。
" z5 K5 l, O4 L( w7 _7 q FLASH页的擦除操作是将PSWE和PSEE置1并向该页512字节中的任一字节进行写操作。 : t! }% V2 f6 y( U M( U, Z
含有读锁定字节和写/擦除锁定字节的 FLASH页不能由用户软件擦除(但是,该页可以由用户
0 S1 y }# Q' H" p- g! r软件写入)。该页只能通过 JTAG 接口擦除。
: w6 x1 `4 _7 I! w; t过程
: R5 Y- F" o4 w4 f0 TFLASH 是按一系列 512 字节的页组织的。另外还有一个 128 字节的页,该页位于 FLASH 的
: F& }/ F- A! D) F4 _! {顶部,起始地址为 0x8000。由于写一个 FLASH字节只能对各位写入 0,因此在写一个 FLASH字" F5 R8 P+ R7 L5 _2 w. X9 q
节之前,该字节必须被初始化为 0xFF。一个 FLASH擦除操作将一页内的所有字节初始化为 0xFF。
( R6 T2 c' b" H2 u/ [( D擦除一个 FLASH 页
) T; U( T% {! x4 q( u一个 FLASH 页可以通过下述过程擦除: / E4 d5 v" H V6 W- [& h% I$ p+ v4 [
1.根据当前系统时钟频率值按 C8051F000 数据表的说明设置 FLSCL(当使用缺省的 2MHz
; u0 t# Z0 M/ I2 l内部振荡器时,FLSCL=0x86)。 1 U5 f/ i- N. a5 g0 `" [7 b
/ i+ e# j( v# o' _Silicon Laboratories Inc. 新华龙电子有限公司
5 ?/ `8 L* e: y1 p# O- b# X+ R4635 Boston Lane 深圳市福田区华强北路现代之窗大厦A座13F C室(518013) 3 @$ v D6 e" A" L
Austin, TX 78735 电话:0755-83645240 83645242 83645244 83645251 7 h! o; ^+ v6 ]' r' f% g
Email: mcuinfo@silabs.com (版权所有) 电邮:shenzhen@xhl.com.cn
' e: Q5 a7 ~+ F' J9 ^- Y0 K# YInternet: www.silabs.com 网址:www.xhl.com.cn
5 h1 m3 ~& G$ @& l2 g/ i& w2 _6 ^' F) H3 ~; ]2 k
& J e X) y1 @4 kAN009 — 从应用程序写 FLASH 8 }: a$ K3 F& I5 x3 Q: I7 K
8 j9 b- U) }2 {6 ?: w8 y
2. 通过向 PSCTL写入 03h 使 PSWE 和 PSEE 置 1。
: X' K9 a& _$ T8 a, g# e3. 向待擦除页内的任一字节写入任意值:
% w1 j# Y, ~+ d; R. Q. F( K% p ; 初始化 DPTR,使其指向待擦除页内的地址 x6 ` T; `* v9 k
mov DPTR, #address . k6 X0 {% x+ `' U; C0 f
; 启动擦除过程
6 ~. G$ r! J/ v6 L3 X, |& a movx @DPTR, a 2 i' k8 M Q. J' m$ ]: Q9 l5 z
4.如果不再进行擦除操作,将 PSEE 设置为‘0’。
H9 U' V+ D3 f, J G; X) K擦除每个页需要 10到 20ms 的时间。注意:CPU内核在 FLASH擦除过程中停止工作,但外
; [) N; Y! a0 |1 `( J# F# X设(象 ADC、UART、SMBus 和定时器)仍然工作。在擦除过程中产生的任何中断都将被挂起,2 H- |# s; L' N# q
直到该过程结束。在写一个 FLASH字节期间 CPU的工作情况与此相同。
8 \! \' b' q4 E& k- k: P写一个 FLASH 字节 5 ?( v- j3 ~/ p3 D5 g. `+ }
下述过程用于写一个 FLASH字节:
* Q5 n- \" U3 p A, _3 F7 d1. 根据当前系统时钟频率值按 C8051F000 数据表的说明设置 FLSCL(当使用缺省的 2MHz1 k) X2 P3 Q& c0 K; z/ o- q
内部振荡器时,FLSCL=0x86)。
" \# t8 ^! h5 m! V2. 通过向 PSCTL写入 01h 使 PSWE 置 1(PSEE 必须为‘0’)。 ; h' y4 {; u5 {% r
3. 写入字节数据。 % ]% L. A; w" M) }" o
; 初始化 DPTR,使其指向待写字节的地址 " [) G& e6 k/ `
mov DPTR, #address
( V5 D: A/ G+ ?5 S ; 将待写字节装入 acc
* r3 c3 @1 A( g mov a, #value 1 R" E4 w# f- f' w! q
; 启动写操作
( U0 j5 D# y0 P5 \3 |7 o: ~7 H7 C movx @DPTR, a 9 _* f" j: N7 J2 y9 x
4. 如果不再进行写操作,将 PSWE 设置为‘0’。 - r- T4 o/ _' X$ ?$ Q
每个 FLASH字节的写操作需要 20到 40μs 的时间。
( M* J/ |) B; D$ ?! X l6 T& a) K更新 FLASH中的数据
0 `9 G) ]/ q9 k: [$ Q当保存一组配置信息时,经常需要在一组字节中单独改变某个字节的数值。单独更新某个字节
( f! i- i# q2 n; J3 V7 L- j1 m(或字节子集)的一般过程如下: ) ~" D% P$ @' Y% E* B5 |0 i
1. 将 FLASH页拷贝到一个临时存储区(RAM 或一个已被擦除的‘临时’FLASH页)。
3 g2 v7 K/ Q; s1 {( H0 r, L2. 擦除 FLASH页的数据。
0 i; @7 [& a7 G3. 将前面存储在临时存储区的内容复制到 FLASH页中。 2 t- p: ^1 S" ~8 N8 h+ g; x$ P# h2 g
用‘C’代码访问 FLASH
7 ?9 {/ x/ _5 Y* V' d6 B! E: p所附的示例代码说明了如何用‘C’程序擦除、写和读 FLASH 内容。由于 FLASH 读操作是
( _: W% |9 F/ K1 x! {% T用 MOVC 指令实现的,因此用于读操作的 FLASH 指针必须是 CODE 类型。由于 FLASH 写操作 D7 A! {* F) ^' p! R+ l6 d
是用 MOVX 指令实现的,所以用于写(或擦除)操作的 FLASH指针必须是 XDATA 类型。
9 u# B0 ]5 O" h. e u# e- F# T! l7 l! V
2 AN009-1.0 JAN01
$ `8 ]* ^2 U' \+ J! ~8 i! \, r* O- t/ i+ a+ N- Y: O% N
# l8 b) c5 |) \ Q+ C; J- Y$ U. C
6 l" k/ i$ U x) Z; _) `8 JAN009 — 从应用程序写 FLASH
2 A$ f) g4 l, }! S" d
! q- b: l7 L7 s6 F9 z软件示例 5 S; n5 M/ o% f* k* M5 h
//-----------------------------------------------------------------------------------------------------------------------
; F/ }3 m3 i. `) }2 A$ H, A9 U2 h// FLASH_1.c
# [0 `8 a% {3 H: |! q& r//-----------------------------------------------------------------------------------------------------------------------
( v) x5 b1 y: y0 j, ~//
p5 A! |6 |5 w+ l7 _. t& X1 T// 作者:BW
# X( v# |8 v' A7 w5 F//
) {' q4 z8 N! X// 本示例程序给出了用‘C’程序擦除、写和读 FLASH存储器的例子。 7 h5 i; i1 A) p- K3 w3 U' W1 y
//
3 b# G+ K+ m( J @0 X// 目标器件:C8051F000 或 C8051F010 / X6 C! a% u2 i
// 开发工具:KEIL C51 % l% Y# a3 H9 y. X, U* k6 `! J# K
// 7 C8 N7 O8 D; F3 s8 d
+ O& T/ [! y$ ^8 e5 F- I
//----------------------------------------------------------------------------- 9 Z% M$ k6 Z' U+ K# v% t1 Y1 t/ c
// 包含文件
; p" u c3 U7 \) U9 I3 o//-----------------------------------------------------------------------------
0 i4 Y# b) d: R! P8 i$ o7 P, {8 u. u
#include <c8051f000.h> // SFR 声明
@2 u1 V$ j" p2 b5 z5 r#include <stdio.h> 4 ?! d, ]9 H+ ?3 ]2 k- J+ [
0 q2 \! ?8 l" p
//-----------------------------------------------------------------------------
" L6 o I+ R! ]/ O+ ^// Function PROTOTYPES u; e$ e0 F; k
//-----------------------------------------------------------------------------
) k, M4 U# Y, |2 Q4 M: a' ~! ^# _9 h' |: e4 G
void main (void); 8 J+ x u3 v4 I P+ t; ]' B; ?# W/ I) J
# W# o. \5 b& Y# m" M# f//-----------------------------------------------------------------------------
, t. M1 z; e* y7 A// MAIN Routine 8 G1 n# u% b+ {
//----------------------------------------------------------------------------- ) n3 q3 ?: R: g! ~* r) `% z
/ M& j5 H% Q3 ?0 _8 C. c- d, @% pvoid main (void) { $ s5 ^) p7 T+ N/ C3 M& _ f' E
) P0 ^0 P0 s( ~2 N unsigned char test_string[ ] = "Howdy!"; // 将被拷贝到 FLASH中的字符串 ; `8 C3 N; \2 l
1 v, a& ~7 j# C4 n3 {, T
unsigned char xdata *pwrite; // 程序存储器空间的指针(FLASH),指向待写地址
0 P$ P/ \4 s- Z* Y" I, ]8 j unsigned char code *pread; // 程序存储器空间的指针(FLASH),指向待读地址 ) S% C0 K6 j' i3 N" e
unsigned char *pgen; // 一般指针
) n- o9 l, H$ t7 P char test; // 测试字符
9 r3 x8 O* d" P* R7 U4 M$ Y8 Y& [5 a3 L9 z7 B1 j0 C1 u; q
AN009-1.0 JAN01 3 # Q' G/ S& z% u9 m# X
: M/ v( m8 r }& p% D {$ a5 r, O) e
! z1 L7 ?: q0 b; h, G# v1 M: v: P& qAN009 — 从应用程序写 FLASH ) D( {: ^ `: T2 J
$ i/ O6 E& L+ C0 v( I
// 禁止看门狗定时器 , T" [% X, F" [; n8 ^
WDTCN = 0xde; ; n% ?9 I) P, R Z7 D" |6 }# O
WDTCN = 0xad;
: t3 C, \: c8 E# F( k# \ // 擦除 128 字节的信息页(位于 0x8000)
* C. c$ I" o# i' X% R$ O FLSCL = 0x86; // 设置 FLASH标度寄存器(对 2MHz 系统时钟)
+ C& t$ {( Q% e% [ PSCTL = 0x03; // 将 PSWE 和 PSEE 置‘1’(MOVX 指令对应
* b4 G' R: [6 |: X // 的 FLASH页 & s# p7 a5 j5 W! C; o7 n3 s
pwrite = 0x8000; // 将指针指向待擦除页
( t# \' Z/ _+ z" Z& G *pwrite = 0; // 启动擦除过程
1 u Z3 V$ T* n5 L2 | M+ | PSCTL = 0x01; // 清除 PSEE,PSWE 仍然置 1
. q! ]4 L& r2 w6 F" ^8 U // MOVX 指令将写到对应的地址
# ^& i4 a% M; J: z' w
7 c) C) M' R4 [5 s // 现在我们要拷贝字符串 <test_string> 的内容到 FLASH页,从地址 0x8000 开始。
* L" g3 T* X, `9 M1 N& u
2 e8 `- M6 `, R) h% V; o- ^6 { pgen = test_string; // pgen 指向源字符串
' s+ o, _) |7 [ M# S! v C: G do {
: E1 `, d7 ~/ U! u# z *pwrite++ = *pgen++; // 拷贝字节
! q1 R5 H$ G. V2 U } while (*pgen != '\0'); // 直到 NULL 结束符
$ M" H# a/ D4 h9 b* M
5 o% C, C& |! h; h* B *pwrite = NULL; // 用 NULL 结束目的字符串 8 u D7 y& O* p/ y( c# y5 f
' g4 l+ E* c' S) J, e! a
PSCTL = 0; // 禁止 FLASH写
; x0 S7 |. O( l w FLSCL = 0x8f; // 禁止 FLASH写
) Y5 l5 {( c: }, S* u3 F5 y! a. A! W4 ^8 b$ ^
// 现在我们读写入的字符串
" u3 t2 x% Q7 e' X3 k, Z
% Y2 M. ]6 @6 O pread = 0x8000; // 初始化 CODE 读指针为字符串起始地址 - P6 A' c" k( ~! a8 f* J9 V% u
1 ]6 o8 w) T5 U, S" Z9 `) s
test = 0x5a;
% a+ C: y$ A5 L& G; a do { 2 Q' s y* U$ b: q/ b
test = *pread++; ' j: f9 d6 S4 b% g
} while (test != '\0');
$ F1 V. B1 h3 W; [3 h2 g8 Q( V, }
while (1) { // 原地循环
+ y' z6 }& K8 u6 _( d8 d% D } J( V M: w+ Z
} 5 [% ?* C' |* W/ P# @
x' }6 }8 O. z: ^ r: ~2 N7 ^4 AN03 d% r, R1 Q; a$ ]: @
; d$ \ u0 Z8 k
|
|