MyTetra Share
Делитесь знаниями!
Установка битовых флагов через удобный макрос
Время создания: 30.12.2021 12:14
Текстовые метки: stm32, программирование, макрос, битовый флаг,
Раздел: Компьютер - Аппаратное обеспечение - Микроконтроллеры ARM
Запись: xintrea/mytetra_syncro/master/base/1640855691zk8uvdd691/text.html на raw.github.com

В одном проекте, понадобилось много битовых флагов Выделять на каждый флаг по байту — это роскошь. Имея в STM32 bit-band, написал макрос, может кому то пригодится.



// Сама переменная, где будут наши флаги,можно заранее проинициализировать

unsigned int BitBandArray=0;


// SRAM_BASE начало памяти

// SRAM_BB_BASE  -  где начинается битбанд алиас памяти

// Объявлено тут stm32f10x.h

// Сам макрос  первый параметр - номер бита, второй  имя перемененной, где биты хранятся

#define BitBand(b,a)  (*((char *)SRAM_BB_BASE+(((int)&a)SRAM_BASE )*32+b*4))


// Сами флаги

#define AxelFlag  BitBand(0,BitBandArray)

#define PowerGood BitBand(1,BitBandArray)

#define BatFlag   BitBand(2,BitBandArray)

// И так 32 раза


////////////////

// Теперь можем к ним обращаться как к обычным переменным

////////////////


// Присвоение

AxelFlag =1;


// Чтение

if(PowerGood ==1)

{

}



Примечание 1


В приведенном макросе есть ошибка, должно быть:



#define BitBand(b, a)  (*((char *)SRAM_BB_BASE + (((unsigned)&a) - SRAM_BASE )*32+b*4))



Попробовал скомпилить, посмотрел, что вышло. Оказалось битовые поля даже быстрее, на такт. Компилятор почему-то не смог вычилить адрес во время компиляции, может LTO поможет, мне лень пробовать. Но он все равно не атомарны, в отличии от bit-band.



struct Foo

{

unsigned flag1:1;

unsigned flag2:1;

unsigned flag3:1;

unsigned flag4:1;

}foo;


unsigned int BitBandArray=0;


#define BitBand(b, a)  (*((char *)SRAM_BB_BASE + (((unsigned)&a)-SRAM_BASE )*32+b*4))

#define AxelFlag  BitBand(0,BitBandArray)

#define PowerGood BitBand(1,BitBandArray)

#define BatFlag   BitBand(2,BitBandArray)


void Bar()

{

AxelFlag = 1;

803e594: 4b05            ldr     r3, [pc, #20]   ; (803e5ac <Bar+0x18>)

803e596: 015b            lsls    r3, r3, #5

803e598:    f103 5308       add.w   r3, r3, #570425344      ; 0x22000000

803e59c: 2201            movs    r2, #1

803e59e: 701a            strb    r2, [r3, #0]

    foo.flag2 = 1;

803e5a0: 4b03            ldr     r3, [pc, #12]   ; (803e5b0 <Bar+0x1c>)

803e5a2: 781a            ldrb    r2, [r3, #0]

803e5a4:    f042 0202       orr.w   r2, r2, #2

803e5a8: 701a            strb    r2, [r3, #0]

803e5aa: 4770            bx      lr

803e5ac: 20000000 .word   0x20000000

803e5b0: 200008c8 .word   0x200008c8

}



В случае bit-band идет вычисление адреса и запись, с битовым полем — чтение, модификация, запись.


То есть, если нет потребности в атомарности, то битовые поля — норм? Ну, то есть других особых каких-то у них проблем нет? (я просто сам недавно о них узнал и начал применять, да и в Сях я очень новичок… А как увидел, подумал — «какая удобная штука!» Так что благодарю за информацию!)



Примечание 2


А так не проще?



#define     BIT_SET(var,mask)   { var |= (mask); }

#define     BIT_CLEAR(var,mask) { var &= ~(mask); }

#define     BIT_TOGGLE(var,mask) { var ^= (mask); }

#define     IS_BIT_SET(var,mask)      ( (var) & (mask) )

#define     IS_BIT_CLEARED(var,mask)  (!( (var) & (mask) ))



очень интересно, но стоит переписать так:



#define     BIT_SET(var,mask)   do{ var |= (mask); }while(0)

#define     BIT_CLEAR(var,mask) do{ var &= ~(mask); }while(0)

#define     BIT_TOGGLE(var,mask) do{ var ^= (mask); }while(0)



в этом случае не будет проблем в следующем построении:



if(cond)

    BIT_SET(var,mask);

else

    BIT_CLEAR(var,mask);



Так же в этом разделе:
 
MyTetra Share v.0.59
Яндекс индекс цитирования