Parsing with Union and variable types

Post Reply
FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

Parsing with Union and variable types

Post by FredCailloux » Wed Mar 02, 2016 4:43 pm

I am using the following part of sketch to extract a long type value (32 bits) from an array of 5 unsigned char type.
Using DSPI1 on a proMX7 board JE I connect an LS7366 chip via SPI communication. The chip transfer a 5 bytes chunk of data representing the Quadrature encoder counter value. Only the 4 last bytes are relevant, hence, only bytes array[1][2][3][4] must take part in "building" the long type value as a variable called lngEncoderValue.
My sketch will compile OK and upload to the board but when I run the encoder the only value I read on my display unit is from 0 to 255. It is obvious that the 3 most significant bytes from the extracted value are missing. The encoder chip is known to work fine after some previously successful less elegant codes. I am trying to render thing more swift and quick by using the Union C++ capability. Somehow I am missing something and just cant get to grasp what is going wrong here.

Code: Select all

// LS7366 Quadrature Encoder Test Sketch
union LSstructure { unsigned char Ob40[5]  ; struct { unsigned char Ob8      ;
                                                               long lngCount ; } LSmiso ;
    } LStransfer ;
unsigned char * pOb40 = LStransfer.Ob40    ; // pointer to Ob40 array 5 elements
void loop() { getEncoderValue ; delay(500) ; }

void	getEncoderValue() {
	myDSPI1.setSelect (             LOW ) ;
	myDSPI1.transfer  ( 5, pMOSI, pOb40 ) ;
	myDSPI1.setSelect (            HIGH ) ;
lngEncoderValue = LStransfer.LSmiso.lngCount ; 
myDisplay ( lngEncoderValue , , ) ; } // The display will only show value from 0 to 255 and go back to 0 and vice versa
Looking at how the Union is built I assume that whatever goes in the Ob40[] array will distribute throughout both variables of the structure Ob8 and lngCount. Somehow, the idea is working, but for some peculiar reason the long lngCount is not getting 3 out of 4 bytes from Ob40[].
Thank you for your hints and help on this one. I really am puzzled here :?
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

User avatar
majenko
Site Admin
Posts: 2165
Joined: Wed Nov 09, 2011 7:51 pm
Location: UK
Contact:

Re: Parsing with Union and variable types

Post by majenko » Wed Mar 02, 2016 4:55 pm

You most probably need to pack the union because you're not working with word-aligned data.

Code: Select all

union LSstructure { 
    unsigned char Ob40[5];
    struct { 
        unsigned char Ob8;
        long lngCount; 
    } __attribute__((packed)) LSmiso;
} __attribute__((packed)) LStransfer;
Personally I prefer an anonymous-struct-in-a-union-in-a-struct arrangement. It means you can then also add other values in there as well if you wish that aren't part of the union. Also by keeping the inner struct anonymous you can then just access myData.data or myData.value

Code: Select all

struct LSData {
    union {
        uint8_t data[5];
        struct {
            uint8_t unused;
            uint32_t value;
        } __attribute__((packed));
    } __attribute__((packed));
} __attribute__((packed));

struct LSData myData;
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".

FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

Re: Parsing with Union and variable types

Post by FredCailloux » Wed Mar 02, 2016 6:13 pm

Thank you Majenko, brilliant as usual :)

However, for some reason it doesn't work for my code. Don't know why? did some reading.
It sure does make sense in the actual situation, but no success. Although the behavior drastically changed. I changed my code to investigate what were the values in the 5 bytes array. I can see that all 4 bytes constituting the long union number lngCount, those 4 bytes are getting the proper values from the LS7366 reading. I can even calculate the final value of lngCount. I am getting the proper 4 bytes whether I use the __attribute__((packed)) option it make no difference, I get the 4 bytes properly. However, what I observe when I use the _attribute_ is that instead of my display showing only the value of 1 byte, now it display the "Error" word.
So, whatever this __attribute__((packed)) feature is doing to my code it actually messes up the LKM1638 display board.

Any hints :?:
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

User avatar
majenko
Site Admin
Posts: 2165
Joined: Wed Nov 09, 2011 7:51 pm
Location: UK
Contact:

Re: Parsing with Union and variable types

Post by majenko » Thu Mar 03, 2016 12:41 am

You might have a problem with endianness. Your 4 bytes might not be i the right order for a pic32 word.

Sent from my SM-T555 using Tapatalk
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".

FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

Re: Parsing with Union and variable types

Post by FredCailloux » Thu Mar 03, 2016 7:42 pm

After investigating each byte value I now can be assured that it is indeed an Endian problem. Thanks for the tip and for the never ending C++ education I am getting from you and this forum. Now the question is: How am I going to correct the situation?
Not that I am fishing for quick ready meal answer ( I am going to cook this myself ), the fact is I am contemplating two approaches here.
First, instead of using Structure and Union to parse the data I may just decide to go back to the original solution that was simply to use calculations based of 4 seperate bytes such as

Code: Select all

myLong    =    Byte1 * 2^24   +   Byte2 * 2^16   +   Byte3 * 2^8   +   Byte4 ;
This is a simple way of getting my number. But I like things that are fast, efficient and elegant so I am also contemplating the second approach which is the use of Structure and Union. For which I foresee the following approach for rearranging the bytes. It look like this:

Code: Select all

long RevEndian(uint8_t* i) { // i is a pointer to the array of 5 bytes
i++ ; pointer to the second of 5 elements
return (*i++&0xf)<<24 | (*i++&0xf)<<16 | (*i++&0xf)<<8 | (*i & 0xf ; }
I do not know what kind of burden that second approach will have on the μController. Is the processor going to use as many manipulation cycles as 24 + 16 + 8 = 48 shift cycles. It seems to me a lot of work for just getting one long number. Or is the processor going to work in bunches of 8bits, in such case this approach will necessitate only 6 shifts cycles.
If the choice is limited between 6 x 8bits shifts or a math calculation then I need to determine which of the two solutions will impose the least burden on the μController.
Can you please guide me here on how I can find which or the two approaches would be the most efficient ?
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

User avatar
majenko
Site Admin
Posts: 2165
Joined: Wed Nov 09, 2011 7:51 pm
Location: UK
Contact:

Re: Parsing with Union and variable types

Post by majenko » Thu Mar 03, 2016 10:37 pm

I don't know what the most efficient of those would be, but the method I usually use when I want to combine manually is:

Code: Select all

uint32_t out = (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
Of course, using whatever order you need to use to make the right value.

However, if you have a big-endian number stored in a 32-bit variable you can swap the whole thing round using the compiler's builtin bswap32 function:

Code: Select all

uint32_t swapped = __builtin_bswap32(bigendian);
So you could combine that with your union if you wanted.
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".

Post Reply