Używam arm gcc (CooCox) do programowania odkrycia STM32F4 i walczyłem z problemem endian
Próbuję z 24-bitowym ADC przez SPI. Ponieważ nadchodzą trzy bajty, MSB najpierw wpadłem na pomysł załadowania ich do unii, aby uczynić je (w każdym razie mam nadzieję!) Nieco łatwiejszymi w użyciu.
typedef union
{
int32_t spilong;
uint8_t spibytes [4];
uint16_t spihalfwords [2];} spidata;
spidata analogin0;
Ładuję dane przy użyciu odczytów SPI do analogin0.spibytes [0] - [2], z [0] jako MSB, a następnie wypluwam je za pośrednictwem USART z megabudem, 8 bitów na raz. Bez problemów.
Problemy zaczęły się, gdy próbowałem przekazać dane do 12-bitowego przetwornika cyfrowo-analogowego. Ten SPI DAC chce 16-bitowych słów, które składają się z 4-bitowego przedrostka rozpoczynającego się od MSB, po którym następuje 12 bitów danych.
Początkowe próby polegały na przekształceniu dwójki uzupełnień, które ADC dał mi, aby skompensować dane binarne, poprzez xor-analogię0. Słowa-klucze [0] z 0x8000, przesunięcie wyniku do dolnych 12 bitów, a następnie dodanie przedrostka arytmetycznie.
Niesamowicie frustrujące, dopóki nie zauważę, że dla analogin0.spibytes [0] = 0xFF i i analogin0.spibytes [1] = 0xB5, analogin0.halfwords [0] było równe 0xB5FF, a nie 0xFFB5 !!!!!
Po zauważeniu tego przestałem używać operacji arytmetycznych i półsłówka, i utknąłem w logice bitowej i bajtach
uint16_t temp=0;
.
.
.
// work on top 16 bits
temp= (uint16_t)(analogin0.spibytes[0])<<8|(uint16_t)(analogin0.spibytes[1]);
temp=temp^0x8000; // convert twos complement to offset binary
temp=(temp>>4) | 0x3000; // shift and prepend with bits to send top 12 bits to DAC A
SPI_I2S_SendData(SPI3,temp); //send to DACa (16 bit SPI words)
... i to działało dobrze. Kiedy zerkam w temp po pierwszym wierszu kodu, to 0xFFB5, a nie 0xB5FF, więc wszystko jest dobrze
W przypadku pytań ...
Kora jest dla mnie nowa. Nie pamiętam, żeby PIC zamieniał bajty w int16, mimo że obie platformy są małymi endianami. Czy to jest poprawne?
Czy istnieje bardziej elegancki sposób, aby sobie z tym poradzić? Byłoby wspaniale, gdybym mógł po prostu ustawić ARM7 w tryb big-endian. Widzę wiele odniesień do tego, że Cortex M4 jest bi-endianem, ale wszystkie źródła wydają się przestać mówić o tym, jak to zrobić . Mówiąc dokładniej, jak ustawić STM32f407 w trybie big-endian , nawet lepiej, jeśli można to zrobić w gcc. Czy to po prostu kwestia ustawienia odpowiedniego bitu w rejestrze AIRCR? Czy są jakieś konsekwencje, takie jak konieczność ustawienia kompilatora w celu dopasowania lub matematyczne błędy później z niespójnymi bibliotekami?
__REV()
i__REV16()
do cofania bajtów.Odpowiedzi:
W systemach wbudowanych zawsze występuje problem big-endian / little-endian. Moim osobistym podejściem było zawsze kodowanie pamięci wewnętrznej z natywnym endianizmem i dokonywanie wszelkich wymian w momencie, gdy dane wchodzą lub wychodzą.
Ładując [0] jako MSB, kodujesz wartość jako big-endian.
Oznacza to, że procesor jest little-endian.
Jeśli zamiast tego załadujesz pierwszą wartość do [2] i wrócisz do [0], to zakodowałeś przychodzącą liczbę jako little-endian, zasadniczo wykonując zamianę przy wprowadzaniu liczby. Po pracy z natywną reprezentacją możesz powrócić do pierwotnego podejścia do korzystania z operacji arytmetycznych. Po prostu przekaż wartość z powrotem do big-endian.
źródło
Jeśli chodzi o nagrodę „Naprawdę chcesz wiedzieć o trybie srm32f4 big endian”, nie ma w tym układzie dużego trybu endian. STM32F4 ma dostęp do całej pamięci w małym endianie.
Instrukcja obsługi http://www.st.com/web/en/resource/technical/document/programming_manual/DM00046982.pdf wspomina o tym na stronie 25. Ale jest więcej. Na stronie 93 można zobaczyć instrukcje wymiany Endian. REV i REVB dla bitów do tyłu i do tyłu. REV zmieni endianessę dla 32 bitów, a REV16 zrobi to dla danych 16-bitowych.
źródło
Oto fragment kodu dla kory M4, skompilowany z gcc
Od C połączenie może być:
Nie wiem, jak to zrobić szybciej :-)
źródło
W przypadku CooCox STM32F429 jest to prawidłowe:
...
źródło