驅動中位域操作簡析

2021-05-17 11:49:44 字數 3005 閱讀 4818

在sm501的驅動中,暫存器非常多,每個暫存器位域的定義也特別多。 驅動採用了一套非常奇妙的巨集來操作暫存器的位域。覺得有必要總結一下。

1)相關定義

包括3 個方面:暫存器,暫存器位域,暫存器位域的可取值。

其中,暫存器位域的表示用以0為起始索引的 高位:低位 來表示。這點非常重要,因為後面的巨集定義就是利用了其中的冒號,來構造乙個條件操作符。

三種定義在識別符號安排上的關係:暫存器為r,則r中某位域f定義為r_f,則該位域某個值v定義為r_f_v.:

比如:

#define system_ctrl                                     0x000000

#define system_ctrl_dpms                                31:30

#define system_ctrl_dpms_vphp                           0

#define system_ctrl_dpms_vphn                           1

#define system_ctrl_dpms_vnhp                           2

#define system_ctrl_dpms_vnhn                           3

2)低層巨集操作

#define _f_start(f)             (0 ? f)

#define _f_end(f)               (1 ? f)

#define _f_size(f)              (1 + _f_end(f) - _f_start(f))

#define _f_mask(f)              (((1 << _f_size(f)) - 1) << _f_start(f))

#define _f_normalize(v, f)      (((v) & _f_mask(f)) >> _f_start(f))

#define _f_denormalize(v, f)    (((v) << _f_start(f)) & _f_mask(f))

其中f 表示位域,v表示位域的值。

_f_start(f) 表示取位域中的起始索引,即冒號右邊的值。展開就是乙個條件操作符。如 _f_start(system_ctrl_dpms) 展開就相當於

(0?31:30) 顯然值為30,正是表示起始索引。 其餘就比較好理解了。

_f_end(f) 表示 位域的結束索引位置。即位域冒號的左邊的值。

_f_size(f) 表示 位域的寬度,也就是包含幾位。

_f_mask(f)為位掩碼,在_f_start(f) 到 _f_end(f)的位為1,其餘為0。

_f_normalize(v, f) 以整數值的方式得到位域的值。位域右移到0開始的位置。

_f_denormalize(v, f)將以整數表示的值放到位域中去的表示。將值左移到位域的位置。

上面這些是底層巨集定義。

3)位域巨集操作:

實際上對位域的操作往往是獲取或設定某暫存器某位域的值。這些巨集定義如下

#define field_get(x, reg, field) /

( /

_f_normalize((x), reg ## _ ## field) /

)

#define field_set(x, reg, field, value) /

( /

(x & ~_f_mask(reg ## _ ## field)) /

| _f_denormalize(reg ## _ ## field ## _ ## value, reg ## _ ## field) /

)

#define field_clear(reg, field) /

( /

~ _f_mask(reg ## _ ## field) /

)

上述三個巨集只返回值,並不修改暫存器。上述巨集定義中,field,value都不是完整的巨集定義名稱,完整的巨集定義名稱是reg_field,reg_field_value。這就是為什麼3個定義要按照這種關係來寫的原因。好處是關係更清晰。**顯得短小。

一般的使用過程 是 使用 field_get獲取值,再使用field_set修改某個位域的值,最後用新值修改暫存器。典型的使用:

void panelplaneenable(void)

這樣做的好處是程式可以只使用暫存器,位域,位域值,和幾個巨集來進行操作。可讀性好,也簡化了程式設計!!

android lcd驅動簡析

對於lcd驅動的分析主要分為三部分 底層硬體結構 framebuffer mipi 底層硬體結構 1 要使一塊lcd正常的顯示文字或影象,不僅需要lcd驅動器,而且還需要相應的lcd控制器。在通常情況下,生產廠商把lcd驅動器與lcd玻璃基板製作在一起,而lcd控制器則是由外部的電路來實現 平台自帶...

位運算 簡析

位運算 在很多系統程式中常要求在位 bit 一級進行運算或處理,c語言提供了位運算的功能,使得c語言也能像組合語言一樣用來編寫系統程式,位運算共有 這六種。1.1.1按位與運算 按位與運算 是雙目運算子。按位運算通常用來對某些位清0 或者 保留某些位,如把a的高8位清0,保留低8位,與作 255運算...

TCP標誌位簡析

tcp標誌位簡析 tcp標誌位 urg 此標誌表示tcp包的緊急指標域 後面馬上就要說到 有效,用來保證tcp連線不被中斷,並且督促中間層裝置要盡快處理這些資料 ack 此標誌表示應答域有效,就是說前面所說的tcp應答號將會包含在tcp資料報中 有兩個取值 0和1,為1的時候表示應答域有效,反之為0...