STM32のエンディアンの問題


11

arm gcc(CooCox)を使用してSTM32F4discoveryをプログラムしていますが、エンディアンの問題と格闘しています。

SPIを介して24ビットADCでサンプリングしています。3バイトが入ってくるので、MSBを最初に、それらを共用体にロードして、少しでも使いやすくすることを考えました(とにかく希望!)。

typedef union
{
int32_t spilong;
uint8_t spibytes [4];
uint16_t spihalfwords [2];} spidata;
spidata analogin0;

spi読み取りを使用してデータをanalogin0.spibytes [0]-[2]にロードし、[0]をMSBにしてから、USARTを介して8ビットずつメガボーで吐き出します。問題はありません。

問題は、データを12ビットDACに渡そうとしたときに始まりました。このSPI DACは、MSBで始まる4ビットのプレフィックスとそれに続く12ビットのデータで構成される16ビットワードを必要とします。

最初の試みは、ADCから与えられた2の補数を変換して、analogin0.spihalfwords [0]を0x8000とxor-ingし、結果を下位12ビットにシフトし、算術的にプレフィックスを追加することでした。

analogin0.spibytes [0] = 0xFFおよびanalogin0.spibytes [1] = 0xB5の場合、analogin0.halfwords [0]は0xFFB5ではなく0xB5FFに等しかったことに気付くまで、非常にイライラします。

これに気づいた後、算術演算とハーフワードの使用を停止し、ビット単位のロジックとバイトに固執しました

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)

...そしてこれはうまくいきました。コードの最初の行、0xB5FFではなく、0xFFB5の後にtempで覗くと、すべてがうまくいきます

だから、質問のために...

  • 皮質は私にとって新しいです。両方のプラットフォームがリトルエンディアンであっても、int16でのPICのバイトスワッピングは思い出せません。これは正しいです?

  • これを処理するよりエレガントな方法はありますか?ARM7をビッグエンディアンモードにすればいいと思います。Cortex M4がバイエンディアンであるという多くの言及がありますが、すべての情報源は実際にどのように私に言うのを止めているようです。より具体的には、STM32f407をビッグエンディアンモードにするにはどうすればよいですか(gccで実行できる場合)。これは、AIRCRレジスタの適切なビットを設定するだけの問題ですか?コンパイラを一致するように設定する必要がある、または後で矛盾したライブラリと数学のねじ込みをするなどの影響はありますか?


2
「3バイトが入ってくるので、MSBが最初です」 -それはビッグエンディアンですが、CPUはリトルエンディアンなので、そこから問題が始まります。16/32ビットのバイトスワッピングを行うコンパイラマクロ/標準ライブラリ関数を探します。通常、これらは特定のCPUプラットフォームに対して最も効率的な方法で実装されます。もちろん、ビット単位のシフト/ AND / ORを使用しても問題ありません。
ラスロヴァルコ14年

analogin0.spibytesを好きな順序で詰めることができると思いますが、usart経由で渡すためにそれを詰める順序を覚えておく必要があるので、それはちょっとした詐欺のようにも思えます。3バイトのフォーマットは、物事を少し非標準的にすると思います。これがc ++であれば、クラスを検討するかもしれません。
スコットサイド

3
CMSISに__REV()__REV16()バイトを反転するためのバイトがあります。
ターボJ 14年

3
これはチートではありません。このレベルでI / Oを実行しているときは、外部バイト順序と内部バイト順序の関係を認識して対処する必要あります。私自身の好みは、理にかなっているソフトウェア階層の最下位レベルで外部表現を「ネイティブ」(内部)表現に変換したり、すべての高レベルソフトウェアがネイティブ形式だけを処理できるようにすることです。
デイブツイード

ARM Corp.が設計したコアはどちらのエンディアンでも動作できますが、STM32F407でのSTMのARMコアの実装はリトルエンディアンのみです。リファレンスマニュアルRM0090の64ページを参照してください。AIRCR.ENDIANNESSは読み取り専用ビットです。
ラスロヴァルコ

回答:


6

組み込みシステムには、常にビッグエンディアン/リトルエンディアンの問題があります。私の個人的なアプローチは、常にネイティブエンディアンで内部メモリをエンコードし、データが出入りするときにスワップを行うことです。

spi読み取りを使用してデータをanalogin0.spibytes [0]-[2]に読み込み、[0]をMSBとして

[0]をMSBとしてロードすることにより、値をビッグエンディアンとしてエンコードしています。

analogin0.spibytes [0] = 0xFFおよびanalogin0.spibytes [1] = 0xB5、analogin0.halfwords [0]は0xB5FFでした

これは、プロセッサがリトルエンディアンであることを示しています。

代わりに、最初の値を[2]にロードして[0]に戻ると、着信番号をリトルエンディアンとしてエンコードし、番号が入力されると基本的にスワップが行われます。ネイティブ表現で作業したら、算術演算を使用する元のアプローチに戻ることができます。値を送信するときは、必ずビッグエンディアンに戻してください。


5

「本当にsrm32f4ビッグエンディアンモードについて知りたい」という賞金に関して、このチップにはビッグエンディアンモードはありません。STM32F4は、すべてのメモリアクセスをリトルエンディアンで行います。

ユーザーマニュアルhttp://www.st.com/web/en/resource/technical/document/programming_manual/DM00046982.pdfには、25ページでこれが記載されています。しかし、もっとあります。93ページに、エンディアンスワッピングの手順があります。REVおよびREVBは、リバースおよびリバースビット用です。REVは32ビットのエンディアンネスを変更し、REV16は16ビットデータのエンディアンネスを変更します。


3

これは、gccでコンパイルされた皮質M4のコードスニペットです。

/*
 * asmLib.s
 *
 *  Created on: 13 mai 2016
 */
    .syntax unified
    .cpu cortex-m4
    .thumb
    .align
    .global big2little32
    .global big2little16
    .thumb
    .thumb_func
 big2little32:
    rev r0, r0
    bx  lr
 big2little16:
    rev16   r0, r0
    bx  lr

Cからの呼び出しは次のとおりです。

 extern uint32_t big2little32(uint32_t x);
 extern uint16_t big2little16(uint16_t x);

 myVar32bit = big2little32( myVar32bit );
 myVar16bit = big2little16( myVar16bit );

これより速くする方法がわからない:-)


あなたは、このコードを迅速にするために、マクロまたはインライン関数を使うことができます
プロ

24ビットデータはどうですか?
pengemizt

1

CooCox STM32F429の場合、これは問題ありません。

typedef union {
  uint8_t  c[4];
  uint16_t   i[2];
  uint32_t  l[1];
}adc;

adc     adcx[8];

...

// first channel ...
    adcx[0].c[3] = 0;
    adcx[0].c[2] = UB_SPI1_SendByte(0x00);
    adcx[0].c[1] = UB_SPI1_SendByte(0x00);
    adcx[0].c[0] = UB_SPI1_SendByte(0x00);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.