本帖最后由 huangxuejia-29212 于 2018-5-15 11:02 编辑
7 S& _% H9 v( m
2 s$ m! A- G' Q, a* w
今天开始移植uboot中的命令行功能到STM32上,使用的是MDK(KEIL)编译器。: ?6 n& W$ |, j! ^; Z
其实以前移植过一次,平台是K21+IAR。由于代码中有部分与编译器有关,折腾了半天才实现。特地记录。 UBOOT CMDUBOOT CMD的代码中,有一个比较特殊的定义。2 P) A& \; z1 P! r; m4 C, P) b
命令的定义通过一个宏声明一个结构体,这个结构体如下 - #define REGISTER_CMD(name,maxargs,rep,cmd,usage,help) \ __root const cmd_tbl_t strcmd_##name @ ".cmd" = {#name, maxargs, rep, cmd, usage,help}
复制代码
0 ~1 E, M/ K4 a7 t4 p我们先分析这个宏的功能
2 f" {1 v% g; k+ Q# `( J3 t# e2 u- __root:
! w T3 t" C. O1 R5 I被修饰的变量或者函数在用户程序里面没有显式调用情况下,也不会被优化掉。
# \4 m7 a6 `/ N- @1 x L7 W# |- const:
1 e' A+ y: K7 ` D: f1 M+ ]$ U& S* s这个大家应该常用,就是将变量定义为常量,保存在FLASH,不占用RAM。
3 K% `$ p! t% a7 b- cmd_tbl_t:: ]- N8 A" D3 ?! n
结构体定义
. X. `7 k5 b2 J: M- strcmd_##name:
! Q K4 q. _6 I. S7 M+ e宏名字,例如宏第一个参数是test,编译后得结构体名字就是strcmd__test
4 T0 K' P# s. {# D1 W" e' m8 r- @ ".cmd":: {- c- j* j% R8 h
定义的结构体保存在.cmd段,这个段是在IAR工程的.icf文件中定义。 剩下的就是赋值给结构体了。 这样定义的结果就是: 定义了一个放在.cmd段的结构体,就算这个结构体没有显式调用,也不会被程序优化。 MDK(KEIL)定义那么在MDK下要怎么定义呢?
3 J& D2 I8 L$ n" i9 o, Y% L/ k- 首先是如下,通过attribute 关键字将结构体放到cmd段中。 - #define REGISTER_CMD(name,maxargs,rep,cmd,usage,help) \ const cmd_tbl_t strcmd_##name __attribute__ ((section ("cmd"))) = {#name, maxargs, rep, cmd, usage,help}
复制代码 : j& P/ I% \/ @( J" O8 w
- 第二,就是要使用自定义的分散加载文件3 L* ]6 z6 A4 }6 m0 b

/ ]% e# c0 _. r) l" [把左上角的use memory layout from target Dialog前面的勾去掉。( {2 d) _ q& O
然后点击右边中间的Edit按钮,关掉窗口,就可以编辑.sct文件了。8 E" h& k( @( K9 H' W
# }1 a% ]( M- T6 p+ Y- LR_IROM1 0x08000000 0x00100000 { ; load region size_region
- T/ z9 J: m* h0 F - ER_IROM1 0x08000000 0x000ff000 { ; load address = execution address
: t& H' E1 q; B - *.o (RESET, +First) w+ l6 W0 p( a/ f/ [* ]/ s% i
- *(InRoot$Sections)
6 v9 ?% k+ E4 b, ]) M7 u9 { - .ANY (+RO)+ O0 p! o: l! X9 u/ W/ b/ |5 }
- }
0 ]# K! c0 ~' j' {: l5 C
! p! L$ k$ p% z6 P! R- a- cmdreg +0" H2 w4 Z* f; _/ S* y
- {
# [6 D2 ^" l( z- L$ d# z - .ANY(cmd)
& n- x: h4 P' I$ Z - }# n5 D1 |" |! b: X2 _" t" h
- RW_IRAM1 0x20000000 0x00020000 { ; RW data
/ n# L* {) }, V' o% Y+ t! j - .ANY (+RW +ZI)
. f% j" B3 h9 ]& p - }( z# \3 n8 \" \3 Y, p x
- }
复制代码 $ q+ ^* C9 n5 f; e. s
: v7 W& v. N. D$ _( l# v4 m& _
中间一段就是增加的
, p9 Z. j: L$ g1 Kcmdreg区域名字。( q. @/ r3 x+ V8 d1 N- _3 t. ^, m( ~
+0的意思是紧跟着其他代码段。
# g# A, A- h; m! H* m" h.ANY(cmd) 这个比较关键,跟代码中的(section ("cmd"))对应。 也可以指定这个段的起始地址跟长度. b, A8 G8 e; Y0 z4 n5 E; G
cmdreg 0x080ff000 0x1000
4 Y9 q9 l4 o( ^- D z0 g6 a: r{4 Z* j/ b7 U* }" x
.ANY(cmd)9 K( K: C- P3 K
}
- 第三,就是要防止这些变量被优化
& D: t: C) |0 s; }8 ^, _# a% F在option中设置0 n8 n/ o% a0 _; ]" |

; P1 D# W, @; O0 {4 H( J看下面,Misc controls中,添加一个宏“--keep=strcmd_*”,意思是所有strcmd_开头的变量跟函数,都不会被优化。7 D j* c1 J3 M( W
确认结果编译后,查看.map文件(通常在工程下的Listings文件夹下) - Execution Region cmdreg (Exec base: 0x08048efc, Load base: 0x08048efc, Size: 0x000000a8, Max: 0xffffffff, ABSOLUTE)
. v' D& Y9 P; S4 J+ v4 a6 y5 B8 l
# h! r: X8 n6 ]% [ p+ H3 r$ F- Exec Addr Load Addr Size Type Attr Idx E Section Name Object
- C9 A% H9 O$ K. W' S2 s; q, ]
0 c4 H0 P' q+ |$ r+ A+ K- 0x08048efc 0x08048efc 0x0000001c Data RO 16605 cmd cmd_sys.o0 Z o. r! s d* e5 J2 z
- 0x08048f18 0x08048f18 0x0000001c Data RO 16606 cmd cmd_sys.o- i" U1 u9 W& h# q8 `0 v& S
- 0x08048f34 0x08048f34 0x0000001c Data RO 16607 cmd cmd_sys.o
' b8 c& H- W, s8 f - 0x08048f50 0x08048f50 0x0000001c Data RO 16608 cmd cmd_sys.o% C/ Y& ?: c0 B) {% r
- 0x08048f6c 0x08048f6c 0x0000001c Data RO 16685 cmd commnad.o
- l, h8 t1 \8 |/ i0 Y2 O# l - 0x08048f88 0x08048f88 0x0000001c Data RO 16686 cmd commnad.o
复制代码 # t7 Q; C7 B! W
从中也可以看到我们前面定义的意思+ G: @6 A8 F5 Q! [+ t
cmdreg是Execution Region名字2 B0 K8 m w% M& M" Q
Base: 0x080ff000, Size: 0x000000a8, Max: 0x00001000+ N F4 _/ O0 _5 P, u: s
我们现在只用了0x000000a8字节/ f1 G7 ^2 W/ ~ F0 y8 f
cmd 是E Section Name 代码中使用段地址跟长度好的,前面我们已经定义了一个命令段,那代码中怎么用这个段呢?
% a2 A# ?/ N: |, i像下面这样使用即可。 - extern unsigned char Load$cmdreg$Base[];) r( @( e7 _ }8 n4 u) y
- extern unsigned char Load$cmdreg$Length[];
) J0 a: u6 J0 t3 y5 K
/ A. Q# z2 Z2 k# n4 i- unsigned long add = (unsigned long)Load$cmdreg$Base;
/ i3 J; `( m2 I Y& p m) p9 W. u - unsigned long len = (unsigned long)Load$cmdreg$Length;% b+ c4 L' j" R3 A5 P
. U4 H5 P( C; a, W9 r8 p2 h; ?- uart_printf("cmd addr:%08x, limit:%08x\r\n", add, len);
复制代码 9 ~$ i8 P4 c4 Q! p1 |) d. b
问题--keep是在MDK设置中定义,能不能直接在代码中定义?" I& n) I0 \" X5 X, e, F
--keep=cmd_*会有匹问题,如果以后其他模块定义类似的变量或者函数,就同样不会被优化了。
2 E. e1 v( r& E# Y* @能不能在代码中直接指定不优化的内容?不使用通配符。: }% y2 U2 y0 C- D/ s6 O# g0 P
不管了,暂时能用先。 通过shell交互安装Xshell 5软件,配置一个串口链接。8 P: c$ i( Y% E# G, S. j
# W7 P! h4 Y% c C* ]& }; G6 A
系统启动后,敲下回车,出现命令行,输入help,查看有多少命令。
0 o% h* H2 N/ `: P! M( }5 `输入命令systeminfo,查看系统信息。 增加命令可以随意添加命令,按照下面的个是注册命令就可以了, REGISTER_CMD( systeminfo,2,1,do_system_info, "systeminfo", "\t display system info ");说明- 1- ~$ \ t P! e0 j
本次测试命令行基于freertos。
0 l7 B% U$ q# H$ H+ j# y; o A- K因为命令行程序内部是while(1)死循环,如果没有操作系统任务调度,很难实现。
$ N, G3 \0 }0 ]除非只有命令行功能,并且其他功能全部通过命令行调用或者是中断。 - 24 |' r7 ]; |( U& `+ w- C6 o) m: n% D9 p
代码托管在github:http://github.com/wujique/stm32f407/tree/sw_arch" D9 A& n' _$ s5 Q
总结本文档指说明了移植过在MDK的细节,对于UBOOT命令行的具体实现,有兴趣自行研究。
& y# i8 G6 ]2 F8 a |
http://github.com/wujique/stm32f407