Jak zapewne niektórym wiadomo - Cortex posiada możliwość (pośredniego) dostępu bitowego do pamięci SRAM i rejestrów sterujących peryferiami.
Mam więc takie makra makra:
Następnie gdy korzystam z makra dla dowolnego rejestru peryferyjnego:
to w efekcie dostaję w assemblerze to o co chodzi (czyli minimalną ilość instrukcji:
Natomiast gdy zaastosuję tę metodę do dowolnej zmiennej globalnej w pamięci SRAM:
to już niestety kompilator nie robi tego o co mi chodzi:
Widać więc, że kompilator jedynie częściowo wyliczył stosowny adres, nie wiedzieć czemu nie policzył dalszej części... Rejestry peryferiów zapewne działają, ponieważ adres stosownych miejsc w pamięci podany jest wprost, bo rozwinięcie makra ENA_0_bb=1:
Natomiast makro flag_4_bb:
Niemniej jednak - kompilator (lub linker) są w stanie przeliczyć adres zmiennej choć częściowo, więc czemu nie do końca?
(optymalizacja ustawiona na -Os)
Jak można rozwiązać sprawę dostępu bitband do zmiennych w gcc? Ręczne pozycjonowanie zmiennych? Może konieczne jest zdefiniowanie dodatkowej zmiennej? Możliwość jest, tylko jak z niej skorzystac?
4\/3!!
Mam więc takie makra makra:
#define BITBAND_SRAM_REF 0x20000000
#define BITBAND_SRAM_BASE 0x22000000
#define BITBAND_PERIPH_REF 0x40000000
#define BITBAND_PERIPH_BASE 0x42000000
[...]
#define bitband_t *(volatile unsigned long*)
[...]
#define m_BITBAND_SRAM(address,bit) (BITBAND_SRAM_BASE+(((unsigned long)address)-BITBAND_SRAM_REF)*32+(bit)*4)
#define m_BITBAND_PERIPH(address,bit) (BITBAND_PERIPH_BASE+(((unsigned long)address)-BITBAND_PERIPH_REF)*32+(bit)*4)
Następnie gdy korzystam z makra dla dowolnego rejestru peryferyjnego:
#define ENA_ODR GPIOC->ODR
#define ENA_0_pin 8
[...]
#define ENA_0_bb bitband_t m_BITBAND_PERIPH(&ENA_ODR,ENA_0_pin)
[...]
ENA_0_bb=1;
to w efekcie dostaję w assemblerze to o co chodzi (czyli minimalną ilość instrukcji:
80002d4: 2401 movs r4, #1
[...]
80002e0: 4b1b ldr r3, [pc, #108] (8000350 <l9942_init+0x80>)
[...]
80002e6: 601c str r4, [r3, #0]
[...]
8000350: 422201a0 .word 0x422201a0
Natomiast gdy zaastosuję tę metodę do dowolnej zmiennej globalnej w pamięci SRAM:
uint32_t flag;
#define flag_4_bb bitband_t m_BITBAND_SRAM(&flag,4)
[...]
flag_4_bb=1;
to już niestety kompilator nie robi tego o co mi chodzi:
8000428: 4b26 ldr r3, [pc, #152] (80004c4 <main+0x9c>)
800042a: 2201 movs r2, #1
800042c: 015b lsls r3, r3, #5
800042e: 3310 adds r3, #16
[...]
8000434: 601a str r2, [r3, #0]
[...]
80004c4: 01100028 .word 0x01100028
Widać więc, że kompilator jedynie częściowo wyliczył stosowny adres, nie wiedzieć czemu nie policzył dalszej części... Rejestry peryferiów zapewne działają, ponieważ adres stosownych miejsc w pamięci podany jest wprost, bo rozwinięcie makra ENA_0_bb=1:
*(volatile unsigned long*) (0x42000000+(((unsigned long)&((GPIO_TypeDef *) ((((u32)0x40000000) + 0x10000) + 0x1000))->ODR)-0x40000000)*32+(8)*4)
Natomiast makro flag_4_bb:
*(volatile unsigned long*) (0x22000000+(((unsigned long)&flag)-0x20000000)*32+(4)*4)
Niemniej jednak - kompilator (lub linker) są w stanie przeliczyć adres zmiennej choć częściowo, więc czemu nie do końca?
(optymalizacja ustawiona na -Os)
Jak można rozwiązać sprawę dostępu bitband do zmiennych w gcc? Ręczne pozycjonowanie zmiennych? Może konieczne jest zdefiniowanie dodatkowej zmiennej? Możliwość jest, tylko jak z niej skorzystac?
4\/3!!