2011-09-16 13 views
5

Programuję C w systemie wbudowanym. Architektura procesora ma 32 bity (sizeof(int) to 32 bity, sizeof(short) to 16 bitów). Istnieje 32-bitowa zmienna, która jest odwzorowanym w pamięci rejestrem kontrolnym (CTRL_REG), który jest określony jako tylko dolne 16 bitów, które są używane, i zawierają one 16-bitową liczbę całkowitą ze znakiem (zapisywanie do wyższych bitów nie daje żadnego efektu). Dostęp do pamięci musi być wyrównany do 32-bitów, więc nie mogę po prostu uderzyć wskaźnika przez kilka bajtów, a także nie mogę założyć endianness. Obawiam się, że automatyczna promocja typu będzie szaleć z tym, co przechowuję, przedłużając bit znaku na bit 31 zamiast pozostawiając go w bit 15, gdzie chcę. Jaki jest najlepszy sposób przechowywania czegoś w tej lokalizacji?przechowywanie podpisanego skrótu w niższych 16 bitach unsigned int

Tu był mój oryginalny kod, którego jestem prawie pewna jest źle:

#define CTRL_REG *((volatile unsigned int *)0x4000D008u) 
short calibrationValue; 

CTRL_REG = -2 * calibrationValue; 

Potem próbowałem, ale myślę, że nadal może podlegać całkowitych promocji w momencie cesji:

CTRL_REG = (short)(-2 * calibrationValue); 

wreszcie pomyślałem o tym:

CTRL_REG = (unsigned short)(short)(-2 * calibrationValue); 

nie mogę ocenić te opcje bardzo dobrze, ponieważ wszystkie działają w moich testach, ponieważ calibrationValue ma wartość ujemną (jest to parametr kalibracyjny charakterystyczny dla każdego urządzenia, a więc może być dodatni na niektórych urządzeniach), więc po pomnożeniu przez -2, kończę przechowywanie wartości dodatniej i w ten sposób nie napotkam problemu, którego oczekuję w testach.

Twoja pomoc jest bardzo doceniana, nawet jeśli chodzi o stwierdzenie "za dużo myślisz".

+0

Jeśli chcesz mieć pewność, że zmienna ma 32 bity, zamiast tego możesz użyć 'uint32_t', ze stdint.h. Zauważ, że 'int' [nie musi być 32-bitowe] (http://codinghorror.typepad.com/.a/6a0120a85dcdae970b0128776ff992970c-pi), nawet w systemach 32-bitowych. –

+1

@WTP: dziękuję za troskę. mamy nagłówek specyficzny dla kompilatora, który zawiera definicje typów, które gwarantują rozmiar. Nie są one standardowym uint32_t ani żadną nomenklaturą, więc zamiast mylić mój post z niestandardowymi typami, zdecydowałem się przekonwertować wszystko na typy, które każdy widział wcześniej. – rmeador

+1

Proponuję co najmniej jedną dodatkową parę nawiasów wokół makra: "(* ((volatile unsigned int *) 0x4000d008u))" – wildplasser

Odpowiedz

4

myśleć o tym, co -16 (na przykład) wygląda na 16 bit: '0xFFF0', aw 33 bitowe: '0xFFFFFFF0. Rozszerzanie znaków jest dokładnie tym, co chcesz, abyś miał bit znaku w odpowiednim miejscu. Ponieważ górna szesnastka nie dba o opiekę, dobrze jest wypełnić je 1sem.Więc utworzyć wartość podpisanej 32 bitową, a następnie wrzucił go do unsigned 32 umieścić w rejestrze:

Int32 calreg= -2L * calibrationValue; 
    CTRl_REG = (Uint32)calreg; 

Jeśli wolisz napisać 0s do wysokich bitów, maska ​​z 0xFFFF przed obsadą.

+0

Myślę, że odkryłeś wadę w moim rozumowaniu ... Myślałem, że bit znaku został przeniesiony, zamiast całej interweniującej liczby bitów wypełnionych 1s. Jeśli poprawnie podążam, nawet pośrednia zmienna i rzutowanie w twoim przykładzie są niepotrzebne, a mój oryginalny (najprostszy) kod zadziała, niezależnie od tego, jak kompilator może go rozszerzyć/wypromować. Czy to jest poprawne? – rmeador

+0

Tak, to prawda; oryginalny prosty kod zadziała dobrze. –

+0

Oryginalny kod powinien działać. Dodałbym jeszcze obsadę, aby uniknąć ostrzeżeń kompilatora i wyjaśnić, że zmiana typu jest zamierzona. Nie jestem pewien, "L" po 2 jest stanowczo potrzebne, ale wolałbym go włączyć zamiast dowiedzieć się, że nie dość poprawnie przewidzieć zasady promocji całkowitej: 'CTRL_REG = (Uint32) (- 2L * calibrationValue); ' – AShelly

0

Jeśli wartości zapisane na najważniejsze 16 bitów są ignorowane, myślę, że można bezpiecznie polegać na konwersji typu. Podsumowując, nie dbasz o wyższe bity.

#define CTRL_REG *((volatile signed int *)0x4000D008u) 
short calibrationValue; 

CTRL_REG = -2 * calibrationValue; 

Zauważ, że CTRL_REG jest zadeklarowana jako podpisał całkowitą teraz.

+0

Obawiam się, że nie mam możliwości ponownego zdefiniowania tego makra jako podpisanego. Myślę jednak, że nie ma to znaczenia, jak zauważyli inni. – rmeador

0
#define SS2L(sh,sl) (((sh) <<16) | ((sl) & 0xffff)) 

Łączenie dwóch 16-bitowych krótkich w jedną 32-bitową.

Najlepiej dla bitopsa zrobić przy użyciu niepodpisanych typów; awans do int może cię złapać. Możliwe, że dodasz dodatkowe rzuty również do tego samego makra.

3

Zamiast unsigned int, zdefiniuj połączenie unsigned int i 2 short signed ints.

W ten sposób radzę sobie z "zabawnymi rejestrami kontroli sprzętu" w moich systemach ARM, gdzie dość często nieparzyste bity są "nie obchodzi" lub "nie wolno im pisać 1".

Rgds, Martin

Powiązane problemy