zoukankan      html  css  js  c++  java
  • 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
    ",
            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)container_of根据结构体成员找到该结构体

     该函数实现位于include/linux/kernel.h, 源码如下:

    #define container_of(ptr, type, member) ({            
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    
        (type *)( (char *)__mptr - offsetof(type,member) );})

      1. 定义一个结构体成员指针mptr指向该成员,

      2.用该成员指针减去该成员在结构体中的偏移量,不就是该结构体的起始地址

    比如:

    struct student stu={.name="robin", .age=18, .id=123456, .sex='M'}, *pstu;
    pstu = container_of(&stu.sex, struct student, sex);

    (3)读取寄存器

    #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。

     (4)写寄存器

    #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。

    (5)位读取

    #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]。

    (6) 位写入

    #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。

  • 相关阅读:
    nginx windows could not build server_names_hash, you should increase server_names_hash_bucket_size: 32
    两个spring boot项目war部署到tomcat 其中一个无法正常启动
    spring boot 集成axis1.4 java.lang.NoClassDefFoundError: Could not initialize class org.apache.axis.client.AxisClient
    springmvc 控制器 读取properties文件
    EntityFramework+EntityFramework.SqlServerCompact部署网站
    Dapper+SqlServerCe部署
    swagger.net 使用nginx 代理时出现端口号导致出错
    vs2017 EFCore 迁移数据库命令
    itextsharp html转成pdf 特殊符号异常处理
    java web项目部署到tomcat 8.5 此驱动程序不支持 Java Runtime Environment (JRE) 1.8 版。请使用支持 JDBC 4.0 的 sqljdbc4.jar 类库
  • 原文地址:https://www.cnblogs.com/fuzidage/p/14691578.html
Copyright © 2011-2022 走看看