Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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:0x2001ffac

    QT 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!



  • molto strano...
    prima cosa, potresti cambiare char buffer_csv[6]; in char buffer_csv[sizeof(csv)]; e poi provare a stampare il valore di united_data.buffer_csv dal lato STM32?



  • 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:04000001114

    mentre 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:04000001114

    Non 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 00000011

    ma 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 su char[] 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]=0xFB

    Quindi 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


Log in to reply