Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Cortex-M3 - bit band w pamięci SRAM

Freddie Chopin 31 Mar 2009 10:06 6195 30
Computer Controls
  • #1
    Freddie Chopin
    MCUs specialist
    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:

    
    #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!!
  • Computer Controls
  • #2
    User removed account
    User removed account  
  • Computer Controls
  • #4
    User removed account
    User removed account  
  • #5
    Freddie Chopin
    MCUs specialist
    No tak, to jest jasne, niemniej jednak szukam najlepszego sposobu ominięcia tego problemu (;

    Zwróć też uwagę, że wartość którą dostaje kod:

    80004c4: 01100028 .word 0x01100028

    jest jednak częściowo zoptymalizowana, ponieważ adresy pamięci SRAM zaczynają się od 0x20000000. Optymalizacja jaka się dokonała nie jest też 'tępa' typu 'minus cośtam', bo wartośc ta jest w pewnym sensie połączeniem kilku operacji - tych które zaznaczyłem pogrubieniem:

    (BITBAND_SRAM_BASE+(((unsigned long)address)-BITBAND_SRAM_REF)*32+(bit)*4)

    przy czym do całości jest jeszcze częsciowo włączone mnożenie przez 32 (a w zasadzie podzielenie przez 32 wartości BITBAND_SRAM_BASE).

    Wstawki assemblerowe niczego nie rozwiążą, bo chodzi o takie zdefiniowanie całości, aby ilością instrukcji zejść do absolutnego minimum, czyli załadowania konkretnego adresu, wartości 0 lub 1 i wysłania wartości pod adres. Zadklarowanie zmiennej jako register też nic nie zmieni, bo rejestry w Cortexie nie są zmapowane w pamięci SRAM.

    4\/3!!
  • #6
    User removed account
    User removed account  
  • #7
    Freddie Chopin
    MCUs specialist
    No ja wiem o tym, tylko zastanawiam się czemu linker nie może jeszcze jej pomnozyć przez 32 i dodać do niej 16 [;

    Co do deklaracji jak rejestr - wymagane byłoby ręczne pozycjonowanie zmiennych w pamięci, a tego chciałbym uniknąć );

    4\/3!!
  • #8
    User removed account
    User removed account  
  • #9
    michalko12
    MCUs specialist
    Nie używałem jeszcze bit bandingu na SRAMie i nie śledziłem poczynań kompilatora w tym kierunku, ale spróbuj może makr od LM

    //*****************************************************************************
    //
    // Macros for hardware access, both direct and via the bit-band region.
    //
    //*****************************************************************************
    #define HWREG(x)                                                              \
            (*((volatile unsigned long *)(x)))
    #define HWREGH(x)                                                             \
            (*((volatile unsigned short *)(x)))
    #define HWREGB(x)                                                             \
            (*((volatile unsigned char *)(x)))
    #define HWREGBITW(x, b)                                                       \
            HWREG(((unsigned long)(x) & 0xF0000000) | 0x02000000 |                \
                  (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))
    #define HWREGBITH(x, b)                                                       \
            HWREGH(((unsigned long)(x) & 0xF0000000) | 0x02000000 |               \
                   (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))
    #define HWREGBITB(x, b)                                                       \
            HWREGB(((unsigned long)(x) & 0xF0000000) | 0x02000000 |               \
                   (((unsigned long)(x) & 0x000FFFFF) << 5) | ((b) << 2))


    Sprawdziłem...
    Heh, jeszcze większa głupota w przypadku globalnych:

    
    
    unsigned long test_bb;
    
    
    
    	HWREGBITW(&test_bb,8)=1;
         b4c:	4b80      	ldr	r3, [pc, #512]	(d50 <.text+0x550>)
         b4e:	f003 4270 	and.w	r2, r3, #4026531840	; 0xf0000000
         b52:	4b7f      	ldr	r3, [pc, #508]	(d50 <.text+0x550>)
         b54:	f023 437f 	bic.w	r3, r3, #4278190080	; 0xff000000
         b58:	f423 0370 	bic.w	r3, r3, #15728640	; 0xf00000
         b5c:	ea4f 1343 	mov.w	r3, r3, lsl #5
         b60:	ea42 0303 	orr.w	r3, r2, r3
         b64:	f043 7300 	orr.w	r3, r3, #33554432	; 0x2000000
         b68:	f043 0320 	orr.w	r3, r3, #32	; 0x20
         b6c:	461a      	mov	r2, r3
         b6e:	f04f 0301 	mov.w	r3, #1	; 0x1
         b72:	6013      	str	r3, [r2, #0]
    	
    	HWREGBITW(NVIC_PRI11,8)=1;
         b74:	4a77      	ldr	r2, [pc, #476]	(d54 <.text+0x554>)
         b76:	f04f 0301 	mov.w	r3, #1	; 0x1
         b7a:	6013      	str	r3, [r2, #0]
    
    ...
    
         d50:	200092b8 	.word	0x200092b8
         d54:	e21c85a0 	.word	0xe21c85a0
    
    	
    
  • Helpful post
    #11
    User removed account
    User removed account  
  • #12
    Freddie Chopin
    MCUs specialist
    Da się - wiem o tym. Tylko zwróć uwagę 2 sprawy:

    1. Przy tym rozwiązaniu musisz cały czas pamiętać o tym, żeby sekcja miała odpowiedni rozmiar, żeby zmniejszyć .data i .bss, żeby wszystko było stosownie wyrównane, itd. jesli zechcesz użyć 10 takich zmiennych, to musisz poprawiać skrypt linkera. Jeśli potem wystarczą ci jednak 3, to znów zmiana.

    2. Tracisz możliwość dostępu do zmiennej w sposób 'klasyczny'.

    4\/3!!
  • #13
    User removed account
    User removed account  
  • #14
    michalko12
    MCUs specialist
    Freddie Chopin wrote:

    Swoją drogą widzę, że kompilowałeś swój przykład dla innej architektury (widzę instrukcje trybu ARM), ale to nic nie zmienia.


    Dla Cortexa-M3, które według Ciebie są tylko dla ARMa?
  • #16
    Svavo
    Level 23  
    Czy wie ktoś czy uC NXP serii LPC11xxx (Cortex-M0) mają bit-banding? W opisie rdzenia jest informacja, że jest to funkcja opcjonalna.
    Pozdro.
  • #18
    maniek1818
    Level 22  
    Męczę bitbanding u Atmela SAM3S4C.
    Code: c
    Log in, to see the code

    Wszystko działa, ale mam problem z wyłuskaniem adresu rejestru PIOA_ODSR. W tej chwili chamsko szukam w RM tego adresu i go wklepuję.
    Chciałem zrobić to jak na wstępie tego tematu przedstawił kol. freddie, czyli w takiej formie:
    Code: c
    Log in, to see the code

    Lecz kompilator (Atmel Studio) wywala błąd: invalid operands to binary * (have 'volatile long unsigned int *' and 'int').
  • #20
    Freddie Chopin
    MCUs specialist
    Wszystko spoko, tylko żeby pobrać ADRES to musisz... pobrać adres (;

    #define PIOA_ODSR PIOA->PIO_ODSR

    Po tej operacji Twoje makro jest swoistym "aliasem" na wskazywaną wartość, ale NIE JEST adresem. Powinno być:

    #define PIOA_ODSR &PIOA->PIO_ODSR

    Jak już przy tym jesteśmy to wrzucam nowszą rewizję mojego nagłówka hdr_bitband.h

    Code: text
    Log in, to see the code


    Przykład użycia:

    Code: text
    Log in, to see the code


    (definicje są w kilku "etapach" aby było łatwiej coś zmienić, bo tylko w jednym miejscu trzeba wtedy (pamiętamy - D-R-Y!).

    Sposób rajszyma też fajny, bo zunifikował bitband w SRAM i w obszarze rejestrów peryferyjnych (;

    4\/3!!
  • #21
    BlueDraco
    MCUs specialist
    Freddie: pierwsze pytanie tutaj to: czy konsolidator obsługuje taki rodzaj relokacji, jaki jest potrzebny dla bitband RAM. Przy peryferialach adres jest stały, więc konsolidator nie ma nic do roboty. Przy RAM konsolidator musiałby umieć obsługiwać relokację "razy 32", a potem jeszcze ktoś (asembler) musiałby wygenerować w pliku pośrednim takie relokacje. Nie śledzę postępów w GCC i LD, ale to chyba jeszcze długa droga.
  • #22
    Freddie Chopin
    MCUs specialist
    Dla bitbandingu w SRAM trzeba tego wszystkiego użyć nieco inaczej niestety (; Mianowicie adres niestety musi być wyliczony w czasie działania programu, a potem można sobie go np przypisać do wskaźnika.

    Niemniej jednak jeśli ktoś ma fantazję korzystać z BB w SRAM to lepszą opcją jest stworzenie sobie w skrypcie linkera specjalnej sekcji pamięci BB, zmniejszenie "normalnego" RAMu o te kilka pozycji, a następnie tworzenie w programie zmiennych typu "32-bitowy bool" (32-bitowość uzyskując np. poprzez align(4)), które umieszczone będą w tej sekcji i od razu będą BB. Jeśli ktoś chce mieć i dostęp zwykły i BB, to niestety tylko w run-time obecnie.

    4\/3!!
  • #24
    Freddie Chopin
    MCUs specialist
    Czyli nic nowego nie prezentuje - jak ktoś preferuje "alokację" pamięci poprzez ręczny wybór adresu to w GCC też tak można zrobić (;

    Bitband w RAM wg tego linka:
    Code: text
    Log in, to see the code


    (;

    4\/3!!
  • #25
    maniek1818
    Level 22  
    Electix wrote:
    ARM, całe zagadnienie prezentuje w ten sposób:

    ARM nie stosuje przypisania adresu peryferii jak kol. Freddie, tylko wpisują ręcznie. Wieczorem sprawdzę, czy pójdzie mi taki zapis:
    Freddie Chopin wrote:
    #define PIOA_ODSR &PIOA->PIO_ODSR
  • #26
    rajszym
    Level 20  
    Przykład dla komercyjnego RealView Development Suite (RVDS):
    Code: c
    Log in, to see the code


    Po kompilacji:
    Code: armasm
    Log in, to see the code

    Czyli armcc pięknie obsługuje bitbanding! Taka przyjemność kosztuje niestety kilka tysięcy euro.
  • #27
    Freddie Chopin
    MCUs specialist
    Ale właśnie prawie to samo da się zrobić w GCC za pomocą skryptu linkera. Jest tylko jedna niedogodność - trzeba "ręcznie" zadbać o rozmiary sekcji - w sensie jak zabraknie miejsca na kolejną zmienną w sekcji bitband, to trzeba sobie ją powiększyć (a normalną pamięć zmniejszyć).

    4\/3!!
  • #28
    Svavo
    Level 23  
    W RVMDK generowane jest coś takiego (STM32F4):

    Code: armasm
    Log in, to see the code


    Z dodaną opcją kompilatora --bitbang. Bez dodawania atrybutów do (każdej) struktury.
  • #29
    maniek1818
    Level 22  
    Ok, poradziłem sobie. Z znakiem adresu - & to w wyniku późnej pory zwyczajnie o nim zapomniałem. W tej chwili wszystko pięknie hula, a powodem "nie działania" był brak rzutowania (uint32_t)a adresu rejestru PIOA->PIO_ODSR.
    Code: c
    Log in, to see the code

    Obczaiłem plik .lss a w nim wygląda to tak:
    Code: armasm
    Log in, to see the code

    Pozdrawiam
  • #30
    Svavo
    Level 23  
    Poprawcie mnie jeśli się mylę - czy bitbanding działa tak, że przy zapisie np. pod adres 0x40000000 (czyli robi to układ peryferyjny) "coś" zapisuje również pod adres 0x42000000? Chodzi mi o kwestię opóźnień przy dostępnie do obu obszarów pamięci - mam wrażenie, że są to 2 cykle (chyba, gdzieś nawet o tym czytałem...).