J'utilise arm gcc (CooCox) pour programmer une découverte STM32F4, et j'ai lutté avec un problème endian
J'échantillonne avec un ADC 24 bits via SPI. Puisque trois octets arrivent, MSB a d'abord eu l'idée de les charger dans une union pour les rendre (j'espérais quand même!) Un peu plus faciles à utiliser.
typedef union
{
int32_t spilong;
uint8_t spibytes [4];
uint16_t spihalfwords [2];} spidata;
spidata analogin0;
Je charge les données en utilisant des lectures spi dans analogin0.spibytes [0] - [2], avec [0] comme MSB, puis je les recrache via USART à un mégabaud, 8 bits à la fois. Pas de problème.
Les problèmes ont commencé lorsque j'ai essayé de transmettre les données à un DAC 12 bits. Ce DAC SPI veut des mots de 16 bits, qui consistent en un préfixe de 4 bits commençant au MSB, suivi de 12 bits de données.
Les premières tentatives ont consisté à convertir le complément à deux que l'ADC m'a donné pour compenser le binaire, en xorant analogin0.spihalfwords [0] avec 0x8000, en décalant le résultat sur les 12 derniers bits, puis en ajoutant le préfixe arithmétiquement.
Incroyablement frustrant, jusqu'à ce que je remarque que pour analogin0.spibytes [0] = 0xFF et et analogin0.spibytes [1] = 0xB5, analogin0.halfwords [0] était égal à 0xB5FF et non 0xFFB5 !!!!!
Après avoir remarqué cela, j'ai arrêté d'utiliser les opérations arithmétiques et le demi-mot, et je suis resté fidèle à la logique au niveau du bit et aux octets
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)
... et cela a bien fonctionné. Quand je jette un œil à temp après la première ligne de code, son 0xFFB5, et non 0xB5FF, donc tout va bien
Donc, pour les questions ...
Le cortex est nouveau pour moi. Je ne me souviens pas que PIC ait jamais échangé des octets en int16, même si les deux plates-formes sont peu endiennes. Est-ce correct?
Existe-t-il une manière plus élégante de gérer cela? Ce serait formidable si je pouvais simplement mettre l'ARM7 en mode big-endian. Je vois de nombreuses références au Cortex M4 étant bi-endian, mais toutes les sources semblent s'arrêter de me dire comment . Plus précisément, comment placer le STM32f407 en mode big-endian , encore mieux s'il peut être fait en gcc. Est-ce juste une question de réglage du bit approprié dans le registre AIRCR? Y a-t-il des ramifications, telles que la nécessité de définir le compilateur pour qu'il corresponde, ou des erreurs mathématiques plus tard avec des bibliothèques incohérentes ??
__REV()
et__REV16()
pour inverser les octets.Réponses:
Les systèmes embarqués auront toujours le problème big-endian / little-endian. Mon approche personnelle a été de toujours encoder la mémoire interne avec l'endianité native et de faire les échanges nécessaires lorsque les données entrent ou sortent.
En chargeant [0] comme MSB, vous encodez la valeur en big-endian.
Cela indique que le processeur est peu endian.
Si au lieu de cela, vous chargez la première valeur dans [2] et revenez à [0], alors vous avez encodé le numéro entrant en petit-boutien, effectuant essentiellement le swap lorsque le nombre entre. Une fois que vous travaillez avec la représentation native, vous pouvez revenir à votre approche originale d'utilisation des opérations arithmétiques. Assurez-vous simplement de le retourner en big-endian lorsque vous transmettez la valeur.
la source
Concernant la prime "Je veux vraiment savoir sur le mode big endian srm32f4", il n'y a pas de mode big endian sur cette puce. STM32F4 fait tous les accès mémoire en petit endian.
Le manuel d'utilisation http://www.st.com/web/en/resource/technical/document/programming_manual/DM00046982.pdf le mentionne à la page 25. Mais il y a plus. À la page 93, vous pouvez voir qu'il y a des instructions de permutation endienne. REV et REVB pour inverser et inverser bit. REV changera l'endianess pour 32 bits et REV16 le fera pour les données 16 bits.
la source
Voici un extrait de code pour un cortex M4, compilé avec gcc
Depuis C, l'appel peut être:
Je ne sais pas comment faire plus vite que ça :-)
la source
Pour CooCox STM32F429, c'est OK:
...
la source