通常我们喜欢将一个外设的寄存器定义成一个结构体的形式来访问,但有些外设寄存器比较庞大,同时寄存器地址不连续,跨度也比较大,这样我们在定义头文件的时候就比较麻烦了,编写完成后一定要检查一遍,避免以后捅娄子。今天分享一个较为方便的检查方法。
uart_hw.h
#ifndef _UART_HW_H_ #define _UART_HW_H_ typedef volatile unsigned int _RW; typedef volatile unsigned int _W; typedef volatile const unsigned int _R; typedef const unsigned int _NU; #define BASE_UART_ADDR 0x40000000 typedef struct { union { _R RXH; /* Offset 0x00 */ _W TXH; /* Offset 0x00*/ }; _RW BAUD; /* Offset 0x04*/ _RW CON; /* Reserved 0x04*/ _NU RESERVED0[1]; /* Reserved 0x04*/ _RW SR; /* Reserved 0x10*/ _NU RESERVED1[3]; /* Reserved 0x0C*/ _RW IE; /* Reserved 0x20*/ } UART_Struct; #define UART ((UART_Struct *)BASE_UART_ADDR) #endif /* _UART_HW_H_ */
此处使用Linux,我直接写个PC的程序来打印各个寄存器成员的实际地址。
main.c
#include "uart_hw.h" #define AA(x,y) volatile uint32_t *addr##x = (uint32_t *)y int main(int argc, char *argv[]) { (void)argc; (void)argv; /* 此处仅仅是引用uart_hw.h文件中的内容,目的是编译时 * 让gcc将uart_hw.h中的信息包含进来 。若有多个IP,则 * 可以继续定义AA(1, SPI)等等。该数字仅仅是保证定义的 * 变量不重复,无它用。 */ AA(0, UART); while(1); }
编译运行
$ gcc -g3 main.c -Idrivers/include(此处`-I`后面为uart_hw.h的相对/绝对路径) $ gdb a.out (gdb) r 此处会退出将gdb切到后台,需要CTRL+D退出shell回到gdb,在CTRL+C,让程序停下来。 (gdb) source uart_hw.gdb (gdb) uart ========== UART ========== 0x40000000 RXH 0x40000000 TXH 0x40000004 BAUD 0x40000008 CON 0x40000010 SR 0x40000020 IE (gdb) q $
这里我们就可以比较直观的对比各个寄存器成员的实际地址与手册上的差异了。下面我们需要来编写uart_hw.gdb
。需要使用vim编辑器,因为它支持块编辑。
- 拷贝uart_hw.h为uart_hw.gdb:
cp uart_hw.h uart_hw.gdb
- 使用vi打开uart_hw.gdb:
vi uart_hw.gdb
- 以下在vi中操作,定位到文件头:
gg
- 删除前11行,删除
union {
及以前的内容:d11d
- 定位到
UART_Struct
行,删除至结尾:dG
- 删除包含
RESERVED
的行::g/RESERVED/d
- 删除
;
至行尾::%s/;.*$//g
- 定位到
_R RXH
这两行,删除行首空白将其与下面的成员对齐:x
- 定位并删除
}
这一行:dd
当前处理结果如下:
uart_hw.gdb
_R RXH _W TXH _RW BAUD _RW CON _RW SR _RW IE
- 定位到
_R RXH
中第一个R
块选中至_RW IE
中的W
:CTRL+v
- 删除选中块:
x
- 块选中
RTBCSR
:CTRL+v
- 块前插入:
I
- 输入:
see UART-> (此处有个空格)
- 退出块编辑:
ESC
当前处理结果如下:
uart_hw.gdb
see UART-> RXH see UART-> TXH see UART-> BAUD see UART-> CON see UART-> SR see UART-> IE
- 继续编辑结果如下,
see
是自己定义的指令用来格式化打印。
uart_hw.gdb
define see printf "0x%08X $arg1\n", &$arg0$arg1 end define uart echo ========== UART ========== \n see UART-> RXH see UART-> TXH see UART-> BAUD see UART-> CON see UART-> SR see UART-> IE end