ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

union和bit field巧妙进行寄存器位操作

2021-04-22 21:33:11  阅读:311  来源: 互联网

标签:位操作 BA union field BLK 寄存器 bit bits REG


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的寄存器结构,typeof表示对该成员取数据结构类型,然后把该寄存器里的值读出来,最后返回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。

标签:位操作,BA,union,field,BLK,寄存器,bit,bits,REG
来源: https://www.cnblogs.com/fuzidage/p/14691578.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有