union和bit field巧妙进行寄存器位操作
1. 用union结构区分大小端
#define read_bits(stc, field)({stc.raw = 0x12345678; stc.bits.field;}) union a{ unsigned int raw; struct { unsigned int bit_a : 8; unsigned int bit_b : 8; unsigned int bit_c : 5; unsigned int bit_d : 3; unsigned int bit_e : 1; }bits; }; int main(void) { union a num; printf("%#x, %#x, %#x, %#x, %#x\n", read_bits(num, bit_a), read_bits(num, bit_b), read_bits(num, bit_c), read_bits(num, bit_d), read_bits(num, bit_e)); return 0; }
最终结果如下:
这样的结果,原理如下图:
那么从这里可以看出,低地址对应低字节, 因此我们的运行机器是Little Endian。
那么bit_a=0x78; bit_b=0x56; bit_c等于0x34取低5位,也就是0x14; bit_d 等于0x34取高3位,也就是0x1; bit_e等于0x12取最低位,也就是0。
由于这里的num是union结构,因此对.raw进行操作,那么也就等于对.bits也进行了操作,那么返回bit field是不是和寄存器的位操作很类似。下面详细介绍如何用union和bit field巧妙进行寄存器位操作。
2. 进行寄存器的位操作
下面以具体的例子来展示是如何巧妙的用union进行寄存器位的读写操作的。
这是mipi-rx DPHY的寄存器的部分截取:
那么我们可以对该module进行结构定义如下:
这里对该module的每个寄存器都定义成union。
(1) offsetof获取结构体成员的偏移量
#define offsetof(struct_t,member) ( (int)&((struct_t *)0)->member )
(struct_t *)0),可以看到这里把一个0地址转换成一个指针,它表示一个结构体指针变量,并且是值=0的指针, 那么访问它的成员,成员的地址自然就会往后递增,因此该成员的地址那么就等于该成员的偏移量。
Eg:
struct student{ unsigned char name[100]; int age; int id; unsigned char sex; }
那么offsetof(struct student, id)就为100 + 4=104,同理.name的offsetof为0,.age的offsetof为100,.sex的offsetof为108。
(2)读取寄存器
#define _reg_read(addr) readl((void __iomem *)addr) #define DPHY_BA_ADDR (0x0300b000) #define _OFST(_BLK_T, _REG) ((uint64_t)&(((struct _BLK_T *)0)->_REG))//this is same with offsetof #define RD_REG(_BA, _BLK_T, _REG) \ (_reg_read(_BA+_OFST(_BLK_T, _REG)))
调用如下函数,
RD_REG(DPHY_BA_ADDR, REG_CSI_DPHY_4LANE_WRAP_T, REG_08);
这样就表示对该module的REG_08的寄存器进行了read。
(3)写寄存器
#define _reg_write(addr, data) writel(data, (void __iomem *)addr) #define WR_REG(_BA, _BLK_T, _REG, _V) \ (_reg_write((_BA+_OFST(_BLK_T, _REG)), _V))
调用如下函数,
WR_REG(DPHY_BA_ADDR, REG_CSI_DPHY_4LANE_WRAP_T, REG_08, 0x3333ffff);
这样就表示对该module的REG_08的寄存器进行了write, write的数据为0x3333ffff。
(4)位读取
#define RD_BITS(_BA, _BLK_T, _REG, _FLD) \ ({\ typeof(((struct _BLK_T *)0)->_REG) _r;\ _r.raw = RD_REG(_BA, _BLK_T, _REG);\ _r.bits._FLD;\ })
调用如下函数,
RD_BITS(DPHY_BA_ADDR, REG_CSI_DPHY_4LANE_WRAP_T, REG_08, MIPIRX_TEST_BIST1);
这里首先是定义了一个module的REG_08的寄存器结构,然后把该寄存器里的值读出来,最后返回bit[31:16]。
(5) 位写入
#define WR_BITS(_BA, _BLK_T, _REG, _FLD, _V) \ do {\ typeof(((struct _BLK_T *)0)->_REG) _r;\ _r.raw = RD_REG(_BA, _BLK_T, _REG);\ _r.bits._FLD = _V;\ _reg_write((_BA+_OFST(_BLK_T, _REG)), _r.raw);\ } while (0) WR_BITS(DPHY_BA_ADDR, REG_CSI_DPHY_4LANE_WRAP_T, REG_08, MIPIRX_TEST_BIST1, 0x1111);
这里首先是定义了一个module的REG_08的寄存器结构,然后把该寄存器里的值读出来, 再把该寄存器的bit[31:16]写入0x1111。
原文地址:https://www.cnblogs.com/fuzidage/p/14691578.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 在ubuntu16.04上创建matlab的快捷方式(实现方法)
- CentOS 7.6 Telnet服务搭建过程(Openssh升级之战 第一任务备用运输线搭建)
- Ubuntu18.04下安装MySQL(图文教程)
- 基于 ffmpeg+Webassembly 实现视频帧提取
- Ubuntu14.04 opencv2.4.8和opencv3.3.1多版本共存的实现方法
- 解决Unixbench安装报错信息的问题
- 关于安装LNMP集成包后上传图片报500错误的解决方法
- linux下SVN配置实现项目目录自动更新以及源码安装的操作方法
- linux安装redis和mysql的实例讲解
- tomcat服务器如何配置字符集为utf-8彻底解决中文乱码的问题详解
- Linux下Android开发环境搭建的操作方法
- liunx 时间函数与时间格式与字符串之间的转化方法
- 详解linux下的.net/mvc/cms程序结构
- Azure给ubuntu虚拟机挂载数据盘的详细步骤
- 详解SSH 远程执行任务的方法