Streaming int32_t tramite union struct tra QT e STM32F4
-
Ho un problema con l'invio di dati tra QT e un micro STM32.
Ho creato in QT ( e nel programma che correrà sul micro) una struttura:typedef struct { char start_char[1]; //1 uint8_t test; //1 int32_t time_x; //4 } csv; union assembl { csv csv_array; char buffer_csv[6]; } united_data;
A scopo di debug, ho inserito delle costanti nei campi della struttura che il micro invierà al pc :
strcpy(united_data.csv_array.start_char,"q"); //only for testing united_data.csv_array.test=6; //only for testing united_data.csv_array.time_x =3; //only for testing
e inviato i dati tramite la USART dell'STM:
HAL_UART_Transmit(&huart2, (uint8_t*)united_data.buffer_csv, 6, 0xffff);
I dati vengono correttamente ricevuti dal PC, ma per quanto riguarda la variabile int32_t non riesco ad avere un'interpretazione corretta.
Sul fronte del controllore ho:Expression---------------------------Type---------Value united_data.buffer_csv---------------char[6] united_data.buffer_csv[0]------------char--------113'q' united_data.buffer_csv[1]------------char--------6'\006\ united_data.buffer_csv[2]------------char--------0'\0' united_data.buffer_csv[3]------------char--------0'\0' united_data.buffer_csv[4]------------char--------3'\003' united_data.buffer_csv[5]------------char--------0'\0'
e il tutto viene letto correttamente da QT:
Expression-------------------------Type --------------- Value united_data.buffer_csv-------------char[6] [0]--------------------------------char---------------'q' 113 0x71 [1]--------------------------------char--------------- 6 0x06 [2]--------------------------------char--------------- 0'\0' [3]--------------------------------char--------------- 0'\0' [4]--------------------------------char--------------- 3'\003' [5]--------------------------------char--------------- 0'\0'
Il problema è che gli ultimi 32bit (united_data.buffer_csv[2...5] vengono interpretati in modo non corretto (o, meglio, non come vorrei io...):
Details:"\0\0\003"
Default:0x2001ffac
Decimal:537001900
Hex:0x2001ffacQT legge il valore int32_t di csv_array.time_x come "537001900" al posto di "3".
Il fatto è che non ho ben capito come viene archiviata la variabile int32_t, non mi sembra LittleEndian e nemmeno BigEndian.
Ho provato a modificare l'ordine ma senza risultato:... [2]-------------------------------- char ---------------- 0'\0' [3]-------------------------------- char ---------------- 0'\0' [4]-------------------------------- char ---------------- 0'\0' [5]-------------------------------- char ---------------- 3'\003'
Penso sia meglio "riorganizzare" i dati -ammesso che questa sia la strategia giusta - da PC ma forse mi sto perdendo in un bicchiere d'acqua...
Grazie mille a tutti! -
Ciao e grazie per la risposta.
Inizialmente avevo definito la dimensione del buffer proprio con un sizeof e in QT continuo a seguire questa strada. Il problema con atollic (quindi sul micro) è che non riesco a fargli "digerire" il #pragma pack(), quindi mi ritrovo con un valore per la lunghezza pari a 8byte (contro i 6byte risultanti da due variabili 8 bit e una 32bit->48bit=6byte).
Leggendo il valore della variabile (fissando la lunghezza del buffer pari a 8 byte-64bit-) avevo -sul micro-:Expression---------------------------Type---------Value united_data.buffer_csv---------------char[6] united_data.buffer_csv[0]------------char--------113'q' united_data.buffer_csv[1]------------char--------6'\006\ united_data.buffer_csv[2]------------char--------0'\0' united_data.buffer_csv[3]------------char--------0'\0' united_data.buffer_csv[4]------------char--------3'\003' united_data.buffer_csv[5]------------char--------0'\0' united_data.buffer_csv[6]------------char--------0'\0' united_data.buffer_csv[7]------------char--------0'\0'
Name : united_data.buffer_csv
Details:"q\006\0\0\003\0\0"
Default:0x2000024c <united_data>
Decimal:536871500
Hex:0x2000024c
Binary:100000000000000000001001001100
Octal:04000001114mentre ora, con la lunghezza fissata a 6 -48 bit-, ho il risultato (sempre sul micro) troncato al valore [5]:
Name : united_data.buffer_csv
Details:"q\006\0\0\003"
Default:0x2000024c <united_data>
Decimal:536871500
Hex:0x2000024c
Binary:100000000000000000001001001100
Octal:04000001114Non capisco perché i valori siano 3.75 byte in entrambi i casi (30bit)!
Sinceramente mi sarei aspettato un binario del tipo|---113---|----6-----|----------------------3-------------------|
01110001 00000110 00000000 00000000 00000000 00000011ma evidentemente sbaglio io visto che QT legge i primi due dati da 8 bit correttamente.
Ho come l'impressione che l'allineamento sulla struttura lasci dentro dei "pad " un po' a caso, ma si tratta di un'impressione, appunto. Chissà che lavorando sul #pragma pack() potrei chiarirmi il dubbio ma forse sono su una strada sbagliata...
Buona giornata a tutti e a presto! -
@lagodolio said in Streaming int32_t tramite union struct tra QT e STM32F4:
non riesco a fargli "digerire" il #pragma pack(),
Questo e' il problema. Non e' che modificando la dimensione del buffer l'allineamento si risolva magicamente.
Rimuovi la
union
completamente e salva i dati suchar[]
manualmente:typedef struct { char start_char[1]; //1 uint8_t test; //1 int32_t time_x; //4 } csv; csv data; data.start_char[0]='q'; data.test=6; data.time_x =3; uint8_t buffer_csv[6]; memcpy(buffer_csv,data.start_char,1); memcpy(buffer_csv+1,&data.test,1); memcpy(buffer_csv+2,&data.time_x,4); HAL_UART_Transmit(&huart2, buffer_csv, 6, 0xffff);
Dovresti pero' anche assicurarti che
data.time_x
sia trasmesso sempre in big endian visto che e' la convenzione usata da quasi tutti i protocolli di comunicazione -
Ho provato a modificare il tipo di variabili.
Premessa, STM32 TrueSTUDIO (Atollic) usa la codifica LittleEndian.
Ho provato a impostare l'ultima variabile come uint16_t, ho definito il suo valore pari a 30000 (quindi >8bit) e QT non ha fatto una piega, riportando il valore corretto. Idem con int16_t e "-30000".
Ho poi provato con uint32_t ( e 130000 come valore) e qui sono cominciati i dolori.
I valori registrati in united_data.buffer_csv[2...5] sono:
united_data.buffer_csv[2]=0x00
united_data.buffer_csv[3]=0x00
united_data.buffer_csv[4]=0xD0
united_data.buffer_csv[5]=0xFBQuindi un valore di 32bit sarà:
0x0000FBD0 =64464
dovrei avere,invece
0x0001FBD0=130000!
-
RISOLTO!
Alla fine il problema era proprio nel #pragma !
E' stato sufficiente inserire :#pragma pack(1) typedef struct { char start_char[1]; //1 uint8_t test; //1 int32_t time_x; //4 } csv; union assembl { csv csv_array; char buffer_csv[sizeof(csv)]; } united_data;
Il mio problema era che , per errore, avevo messo il #pragma dopo la struttura (avevo visto così in un esempio e avevo pensato che atollic volesse questa istruzione DOPO la struttura da allineare) e prima della union: quindi non allineava niente!
Adesso ho:
united_data.buffer_csv[2]=0xD0
united_data.buffer_csv[3]=0xFB
united_data.buffer_csv[4]=0x01
united_data.buffer_csv[5]=0x0.Sembra che QT "capisca" che stiamo trattando LittleEndian (gli ARM dovrebbero usare questa convenzione, o almeno gli STM32 lo fanno) e riporta i dati correttamente!!
Grazie mille , in effetti mi hai convinto sul fatto che con un allineamento "non allineato" non potevo andare lontano...
Buona Giornata e grazie ancora! -
@lagodolio said in Streaming int32_t tramite union struct tra QT e STM32F4:
Sembra che QT "capisca" che stiamo trattando LittleEndian
Dipende da cosa usi per leggere. Se usi
QDataStream
devi manualmente impostarlo su little endian, se leggi i dati grezzi usano la convenzione imposta dalla macchina su cui esegui il programma