Masalah Endian pada STM32

11

Saya menggunakan arm gcc (CooCox) untuk memprogram penemuan STM32F4, dan saya sudah bergulat dengan masalah endian

Saya mengambil sampel dengan ADC 24 bit melalui SPI. Karena tiga byte datang, MSB pertama-tama saya punya ide memuat mereka ke dalam serikat untuk membuat mereka (saya berharap, bagaimanapun!) Sedikit lebih mudah digunakan.

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

Saya memuat data menggunakan spi yang dibaca dalam analogin0.spibytes [0] - [2], dengan [0] sebagai MSB, kemudian saya memuntahkannya melalui USART pada megabaud, 8 bit sekaligus. Tidak ada masalah.

Masalah dimulai ketika saya mencoba meneruskan data ke DAC 12 bit. SPI DAC ini membutuhkan 16 bit kata, yang terdiri dari awalan 4 bit mulai dari MSB, diikuti oleh 12 bit data.

Upaya awal adalah untuk mengkonversi dua-dua komplemen yang diberikan ADC saya untuk mengimbangi biner, dengan xor-ing analogin0.spihalfwords [0] dengan 0x8000, menggeser hasilnya ke 12 bit bagian bawah, dan kemudian menambahkan awalan pada aritmatika.

Sangat membuat frustrasi, sampai saya perhatikan bahwa untuk analogin0.spibytes [0] = 0xFF dan dan analogin0.spibytes [1] = 0xB5, analogin0.halfwords [0] sama dengan 0xB5FF dan bukan 0xFFB5 !!!!!

Setelah memperhatikan ini, saya berhenti menggunakan operasi aritmatika dan kata setengahnya, dan menempel pada logika bitwise dan byte

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)

... dan ini bekerja dengan baik. Ketika saya mengintip temp setelah baris kode pertama, 0xFFB5, dan bukan 0xB5FF, jadi semuanya baik-baik saja

Jadi, untuk pertanyaan ...

  • Cortex baru bagi saya. Saya tidak ingat PIC pernah bertukar byte di int16's, meskipun kedua platform sedikit endian. Apakah ini benar?

  • Apakah ada cara yang lebih elegan untuk menangani ini? Akan lebih bagus jika saya bisa memasukkan ARM7 ke mode big-endian. Saya melihat banyak referensi bahwa Cortex M4 adalah bi-endian, tetapi semua sumber tampaknya berhenti untuk memberi tahu saya caranya . Lebih khusus lagi, bagaimana cara menempatkan STM32f407 ke mode big-endian , bahkan lebih baik lagi jika itu dapat dilakukan dalam gcc. Apakah ini HANYA masalah pengaturan bit yang sesuai dalam register AIRCR? Apakah ada konsekuensi, seperti harus mengatur kompiler agar sesuai, atau matematika kemudian dikacaukan dengan pustaka yang tidak konsisten ??

Scott Seidman
sumber
2
"Sejak tiga byte masuk, MSB pertama" - itu big-endian, sedangkan CPU Anda adalah little-endian, jadi di situlah masalah Anda dimulai. Saya akan mencari fungsi compiler macro / library standar untuk melakukan swapping 16/32-bit, biasanya mereka diimplementasikan dengan cara yang paling efisien untuk platform CPU tertentu. Tentu saja, menggunakan bit-wise shifting / ANDing / ORing juga oke.
Laszlo Valko
Saya kira saya bisa memasukkan analog dalam 0. Urutan dalam urutan apa pun yang saya mau, tapi itu sepertinya sedikit curang juga, karena saya harus ingat urutan untuk melepaskannya agar dapat lulus melalui usart. Saya pikir format 3-byte membuat hal-hal sedikit tidak standar. Jika ini c ++, saya mungkin mempertimbangkan kelas.
Scott Seidman
3
CMSIS memiliki __REV()dan __REV16()untuk membalikkan byte.
Turbo J
3
Ini bukan cheat sama sekali - ketika Anda melakukan I / O pada level ini, Anda harus menyadari dan berurusan dengan hubungan antara urutan byte eksternal dan urutan byte internal. Preferensi saya sendiri adalah untuk mengubah representasi eksternal ke / dari representasi "asli" (internal) pada tingkat terendah dalam hierarki perangkat lunak yang masuk akal, dan membiarkan semua perangkat lunak tingkat yang lebih tinggi hanya berurusan dengan format asli.
Dave Tweed
Meskipun core yang dirancang oleh ARM Corp. dapat beroperasi dengan endianness, implementasi STM dari core ARM di STM32F407 hanya merupakan little-endian. Lihat Manual Referensi RM0090 halaman 64. AIRCR.ENDIANNESS adalah bit read-only.
Laszlo Valko

Jawaban:

6

Sistem tertanam akan selalu memiliki masalah big-endian / little-endian. Pendekatan pribadi saya adalah selalu menyandikan memori internal dengan endianiness asli dan membuat swap yang benar ketika data masuk atau pergi.

Saya memuat data menggunakan spi yang dibaca dalam analogin0.spibytes [0] - [2], dengan [0] sebagai MSB

Dengan memuat [0] sebagai MSB, Anda menyandikan nilainya sebagai big-endian.

analogin0.spibytes [0] = 0xFF dan dan analogin0.spibytes [1] = 0xB5, analogin0.halfwords [0] sama dengan 0xB5FF

Ini menunjukkan bahwa prosesornya adalah little-endian.

Jika sebaliknya, Anda memuat nilai pertama ke [2] dan bekerja kembali ke [0], maka Anda telah menyandikan angka yang masuk sebagai little-endian, yang pada dasarnya menjadikan swap saat nomor tersebut masuk. Setelah Anda bekerja dengan representasi asli, Anda dapat kembali ke pendekatan awal menggunakan operasi aritmatika. Pastikan untuk membalikkannya kembali ke big-endian ketika Anda mengirimkan nilainya.

DrRobotNinja
sumber
5

Mengenai karunia "Benar-benar ingin tahu tentang mode big endian srm32f4", tidak ada mode endian besar pada chip ini. STM32F4 melakukan semua akses memori di little endian.

Panduan pengguna http://www.st.com/web/en/resource/technical/document/programming_manual/DM00046982.pdf menyebutkan ini di halaman 25. Tetapi ada lebih banyak. Pada halaman 93 Anda dapat melihat ada instruksi bertukar endian. REV dan REVB untuk mundur dan mundur sedikit. REV akan mengubah endianess untuk 32 bit dan REV16 akan melakukannya untuk data 16 bit.

C. Towne Springer
sumber
3

Berikut ini adalah cuplikan kode untuk korteks M4, dikompilasi dengan gcc

/*
 * 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

Dari C, panggilan dapat:

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

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

Tidak tahu bagaimana melakukan lebih cepat dari ini :-)

Olivier Monnom
sumber
Anda dapat menggunakan fungsi makro atau inline untuk membuat kode ini lebih cepat
pro
bagaimana dengan data 24 bit?
pengemizt
1

Untuk CooCox STM32F429 ini tidak masalah:

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);
Argebir Laboratuvar
sumber