0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

為什么MISRA要求你不要使用位域-本文告訴你真相

嵌入式USB開發(fā) ? 來源:嵌入式Lee ? 作者:嵌入式Lee ? 2023-06-21 17:36 ? 次閱讀

本文轉(zhuǎn)自公眾號,歡迎關(guān)注

為什么MISRA要求你不要使用位域-本文告訴你真相 (qq.com)

一.前言

做過嵌入式開發(fā)的一般會看到一條編程規(guī)范:”不要使用位域”,一般都是知其然不其所以然,了解的多一點的可能知道位域是實現(xiàn)相關(guān)不具備可移植性,那么繼續(xù)追問哪些行為是實現(xiàn)相關(guān)哪些行為導(dǎo)致移植性問題? 或者還有人知道,存儲布局,對齊等行為是實現(xiàn)相關(guān)會導(dǎo)致不可移植性。如果再追問位域產(chǎn)生的匯編代碼是什么樣的,怎么進(jìn)行讀-修改-寫操作的?知道這些內(nèi)容的就更加少之又少了。 讀寫肯定不能讀指定位數(shù),只能字節(jié),或者16位,32位這種,那么編譯器到底讀寫用什么寬度? 這時基本大部分人都不知道了。

知其然知其所以然,尤其是嵌入式開發(fā)和硬件結(jié)合比較緊密,所以一定要了解細(xì)節(jié),我們這一篇從一個問題引出然后去分析查找原因,只有遇到問題然后去分析解決它才會有更深刻的映像。

二.問題分析過程

問題是驅(qū)動程序中一個寄存器的某個位域修改,導(dǎo)致其他位域的值被修改了。

關(guān)鍵代碼如下,

1.typedefunionnfc_ena_union{

2. uint32_tw;

3. struct{

4. /*spienable,oncethespitransiscompleted,thisbitwillbeclearedbyHWautomaticlly*/

5. uint32_tnfc_ena:1; //[0]

6. uint32_treserved_0:3; //[1,3]

7. /*swrequesttousedp*/

8. uint32_tnfc_dp_req:1; //[4]

9. uint32_treserved_1:3; //[5,7]

10. /*duetodelayinreceivingdata,nfcdelayonebeattorx*/

11. uint32_tnfc_rx_delay_en:1; //[8]

12. uint32_treserved_2:7; //[9,15]

13. /*spitransdatalength,unitisbyte,oncethespitransiscompleted,thisbitwillbeclearedbyHWautomaticlly*/

14. uint32_tnfc_data_len:16; //[16,31]

15.}_b;

16.}nfc_ena_u;

1./**

2.*fnintnfc_set_datalen(uint8_tid,uint16_tlen)

3.*param[in]idportid

4.*param[in]lendatalen

5.*retval0ok

6.*retval<0?param?err

7.*

8.*/

9.NFC_INLINEintnfc_set_datalen(uint8_tid,uint16_tlen)

10.{

11. if(id>=HW_NFC_PORT_MAX)

12.{

13. return-1;

14.}

15.nfc_base[id]->nfc_ena._b.nfc_data_len=len;

16. return0;

17.}

執(zhí)行之前該寄存器值為0x00020100

34b4c4c2-0f04-11ee-9c1d-dac502259ad0.png

nfc_base[id]->nfc_ena._b.nfc_data_len= len

匯編代碼被優(yōu)化為了寫高16位

34d22efe-0f04-11ee-9c1d-dac502259ad0.png

執(zhí)行完后寄存器低16位變?yōu)榱?

34f0fab4-0f04-11ee-9c1d-dac502259ad0.png

這是因為寄存器硬件上只支持32位的寫操作,所以寫高16位導(dǎo)致低16位清零了,這是硬件決定的。

二.驗證

一般想到的就是優(yōu)化相關(guān),加volatile等,我們分別驗證下。

3.1不使能編譯器優(yōu)化

編譯器優(yōu)化選項改為”-O0”

代碼不變

依然會按照16位訪問,導(dǎo)致低16位被清掉。

所以可以看到這個和編譯器行為有關(guān),編譯器顯然不是根據(jù)優(yōu)化等級決定位域的操作寬度,這里而是根據(jù)位域的寬度剛好是16位對齊,所以優(yōu)化為了16位操作指令。

3504cddc-0f04-11ee-9c1d-dac502259ad0.png351f3d70-0f04-11ee-9c1d-dac502259ad0.png

3.2使用volatile避免編譯器優(yōu)化

#ifndef__IOM

#define__IOM volatile

#endif

所有uint32_t替換為__IOM uint32_t

還是一樣的

353ad710-0f04-11ee-9c1d-dac502259ad0.png

顯然匯編代碼的訪問寬度也不受volatile影響。

3.3為什么指定了uint32_t和volatile還會優(yōu)化。

問題來了為什么告訴了編譯器是uint32_t和volatile,為什么其還要一意孤行,要優(yōu)化為16位訪問指令呢,答案就是因為是標(biāo)準(zhǔn)沒有規(guī)定,這是編譯器實現(xiàn)行為決定的,所以編譯器設(shè)計者決定的(當(dāng)然也會有一些現(xiàn)實考慮的),可能不同編譯器行為不同,這里以GCC為例。

GCC編譯器文檔中可以找到答案

GCC的文檔可以看到如下內(nèi)容,也給出了最好是不使用位域的原因

354f86f6-0f04-11ee-9c1d-dac502259ad0.png

35645612-0f04-11ee-9c1d-dac502259ad0.png

另外也介紹了位域哪些行為也是編譯器實現(xiàn)相關(guān)的,所以嵌入式可移植性考慮不要使用位域

3576ae5c-0f04-11ee-9c1d-dac502259ad0.png

那么有沒有辦法指定編譯按照一定大小訪問呢,GCC有編譯選項可以控制見下一節(jié)。

3.4使用編譯器選項-fstrict-volatile-bitfields

358c8eca-0f04-11ee-9c1d-dac502259ad0.png

可以看到改為了sw指令,按照32位進(jìn)行了操作

359dc4f6-0f04-11ee-9c1d-dac502259ad0.png

四.一些廠家做法

如下可見

4.1CMSIS

core_cmxx.h中定義

CMSIS中進(jìn)行了定義,寄存器個別使用位域

1./*IOdefinitions(accessrestrictionstoperipheralregisters)*/
2./**
3.defgroupCMSIS_glob_defsCMSISGlobalDefines
4.
5.IOTypeQualifiersareused
6.litospecifytheaccesstoperipheralvariables.
7.liforautomaticgenerationofperipheralregisterdebuginformation.
8.*/
9.#ifdef__cplusplus
10.#define__Ivolatile/*!

4.2ST

1./**
2.*@briefUniversalSerialBusFullSpeedDevice
3.*/
4.
5.typedefstruct
6.{
7.__IOuint16_tEP0R;/*!

4.3瑞薩

__I,__O__ROM也是core_cmxx.h中定義,大量使用位域

1.#ifndef__IM/*!

五.總結(jié)

結(jié)論就是正如很多嵌入式編程規(guī)范所描述的(比如MISRA),一般不建議使用位域,因為涉及到位域的訪問,存儲等行為都是實現(xiàn)定義的,不具備可移植性。

嵌入式領(lǐng)域寄存器的定義也最好不要使用位域,到寄存器級別以寄存器操作為單位即可,每個寄存器都要使用__IM,__OM,__IOM描述。

如果一定要使用位域可以使用-fstrict-volatile-bitfields選項,使用GCC測試可以保證按照固定指定大小訪問,但是不保證其他編譯器也支持該選項,最好能不使用就不使用位域。


審核編輯黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5082

    文章

    19126

    瀏覽量

    305198
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5343

    瀏覽量

    120365
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1634

    瀏覽量

    49132
  • MISRA
    +關(guān)注

    關(guān)注

    0

    文章

    21

    瀏覽量

    6969
  • 嵌入式編程
    +關(guān)注

    關(guān)注

    0

    文章

    27

    瀏覽量

    10314
收藏 人收藏

    評論

    相關(guān)推薦

    IC設(shè)計:ram的應(yīng)用-異步時鐘寬轉(zhuǎn)換

    在進(jìn)行模塊設(shè)計時,我們經(jīng)常需要進(jìn)行數(shù)據(jù)寬的轉(zhuǎn)換,常見的兩種轉(zhuǎn)換場景有同步時鐘寬轉(zhuǎn)換和異步時鐘寬轉(zhuǎn)換。
    的頭像 發(fā)表于 11-23 16:41 ?869次閱讀
    IC設(shè)計:ram的應(yīng)用-異步時鐘<b class='flag-5'>域</b><b class='flag-5'>位</b>寬轉(zhuǎn)換

    使用問題

    在支持操作的單片機(jī)中,如C51,使用定義變量或者寄存器,操作方便并且節(jié)約空間。 問題1:但是很多單片機(jī)不支持操作,仍然使用
    發(fā)表于 09-16 22:25

    MISRA C編程規(guī)范標(biāo)準(zhǔn)有什么規(guī)則要求

    如何衡量代碼是否滿足某些標(biāo)準(zhǔn)?MISRA C編程規(guī)范標(biāo)準(zhǔn)有什么規(guī)則要求
    發(fā)表于 04-19 07:20

    所不知道的關(guān)于iPhone7的幾個真相,看完讓所有人震驚!

    Phone7發(fā)布這么久了,用的還好嗎?希望你的iPhone不要出現(xiàn)掉漆等不好的現(xiàn)象。你們在使用的過程中有沒有發(fā)現(xiàn)iPhone7什么不為人知的秘密呢?如果沒發(fā)現(xiàn)的話,下面我就來告訴大家關(guān)于iPhone7的一些
    發(fā)表于 02-23 09:40 ?3442次閱讀

    什么是分層架構(gòu)的依據(jù)與原則?本文告訴答案!

    分層架構(gòu)是運用最為廣泛的架構(gòu)模式,幾乎每個軟件系統(tǒng)都需要通過層(Layer)來隔離不同的關(guān)注點(Concern Point),以此應(yīng)對不同需求的變化,使得這種變化可以獨立進(jìn)行;此外,分層架構(gòu)模式還是隔離業(yè)務(wù)復(fù)雜度與技術(shù)復(fù)雜度的利器,《領(lǐng)域驅(qū)動設(shè)計模式、原理與實踐》寫道:
    發(fā)表于 07-27 14:16 ?7472次閱讀
    什么是分層架構(gòu)的依據(jù)與原則?<b class='flag-5'>本文告訴</b><b class='flag-5'>你</b>答案!

    如何區(qū)分FPGA與CPLD?本文告訴答案!

    如何區(qū)分CPLD或FPGA和哪一個更適合自己?這是一個老生常談的問題,尤其是學(xué)生和初學(xué)者。如果您也在這個問題上很迷茫,那么就請聽小編為您區(qū)分FPGA與CPLD。
    發(fā)表于 09-04 14:16 ?2222次閱讀
    如何區(qū)分FPGA與CPLD?<b class='flag-5'>本文告訴</b><b class='flag-5'>你</b>答案!

    智能音箱究竟有哪些用處?本文告訴答案!

    在許多人心中一直以來都有個困惑,智能音箱到底有什么作用?無可否認(rèn),智能音箱能夠讓我們解放雙手,只通過語音就能夠進(jìn)行操作。智能音箱也能夠打通許多智能家居通道,消費者能夠舒服的躺在沙發(fā)上控制家中燈光、電視、空調(diào)等電器是多么愜意的一件事。但這里有一個問題,能用智能音箱辦到的事情,使用智能手機(jī)也一樣可以做到,兩者似乎在這一點上有很多功能重合。
    發(fā)表于 09-20 16:46 ?2380次閱讀

    怎么分辨機(jī)器人種類 本文告訴答案

    自20世紀(jì)中期出現(xiàn)的第一臺現(xiàn)代機(jī)器人后,隨著相關(guān)技術(shù)的快速演進(jìn),時至今日,機(jī)器人已廣泛地被應(yīng)用在許多不同的領(lǐng)域,來協(xié)助或取代人類完成各式各樣的工作。依照不同的需求,將機(jī)器人做出不同的分類,以達(dá)到有效區(qū)分或辨識他們的目的。
    發(fā)表于 01-14 15:41 ?5001次閱讀

    2018的量子計算是怎么跟AI一起兩開花的 本文告訴答案

    回首剛剛過去的2018,如果讓我回答一個“科技產(chǎn)業(yè)怎么看”的問題。那答案應(yīng)該是這樣的:上看AI,下看IoT,近看5G,遠(yuǎn)看量子計算,千萬不要看區(qū)塊鏈,因為太亂,看了容易上頭。
    發(fā)表于 01-15 10:16 ?857次閱讀

    怎么放置洗衣機(jī)最好 本文告訴答案

    洗衣機(jī)可以說是家里很重要的一種電器了,沒有洗衣機(jī)的時候,人們只能辛辛苦苦的用手來洗衣服,不僅傷手而且效率還很低,但是自從有了洗衣機(jī),我們的生活的確是方便了很多。不過,通常人們喜歡把洗衣機(jī)放在陽臺上,但是小編不建議大家這樣做,最好還是放在衛(wèi)生間。
    發(fā)表于 02-15 11:40 ?780次閱讀

    智慧城市該如何建設(shè) 本文告訴答案

    智慧城市建設(shè)興起于歐美地區(qū),世界各國都將發(fā)展智慧城市定為未來幾年的目標(biāo)。我國雖起步較晚,但在政府的支持和企業(yè)的參與下,智慧城市建設(shè)也取得階段性進(jìn)展,在我國目前已有超過500個城市開展了相關(guān)建設(shè)。隨著人工智能、云計算、大數(shù)據(jù)等技術(shù)成熟,我國智慧城市發(fā)展將逐步向數(shù)據(jù)共享、萬物互聯(lián)、生態(tài)共贏邁進(jìn)。
    發(fā)表于 05-29 08:53 ?1305次閱讀
    智慧城市該如何建設(shè) <b class='flag-5'>本文告訴</b><b class='flag-5'>你</b>答案

    文告訴單相電機(jī)運轉(zhuǎn)無力該如何檢測

    本文小編告訴大家單相電機(jī)運轉(zhuǎn)無力的3個檢測方法。
    的頭像 發(fā)表于 12-14 21:28 ?1953次閱讀

    文告訴為什么電機(jī)過載保護(hù)元件常用熱繼電器?

    小編告訴大家電機(jī)過載保護(hù)元件常用的是熱繼電器,因為它能滿足一些要求。
    的頭像 發(fā)表于 12-14 22:09 ?2695次閱讀

    文告訴什么是電機(jī)短時運行?

    本文小編告訴大家什么是電機(jī)短時運行。
    的頭像 發(fā)表于 12-14 22:12 ?3252次閱讀

    服務(wù)器ups運行時間,圖文告訴關(guān)于UPS電源的一些基礎(chǔ)知識

    原標(biāo)題:圖文告訴關(guān)于UPS電源的一些基礎(chǔ)知識UPS - Uninterrupted Power System利用電池化學(xué)能作為后備能量,在市電斷電等電網(wǎng)故障時,不間斷地為用戶設(shè)備提供(交流)電能
    發(fā)表于 11-08 19:21 ?8次下載
    服務(wù)器ups運行時間,圖<b class='flag-5'>文告訴</b><b class='flag-5'>你</b>關(guān)于UPS電源的一些基礎(chǔ)知識