|
|
View previous topic :: View next topic |
Author |
Message |
Frozen01
Joined: 23 Apr 2009 Posts: 32
|
Constructing a 32-bit word |
Posted: Wed Aug 24, 2016 9:31 am |
|
|
I need to build up a 32-bit word to be sent out via SPI, and I am looking for the best way to do it.
It needs to be built up via several pieces, an 8-bit label, 2-bit identifier, 19-bit value, 2-bit status, and 1 bit parity.
I am by far no expert programmer, and this seems like it should be easy, like maybe just shifting the values in to a variable or something like that...
So would this work?
word32 = (label<<23) | (ident<<21) | (value<<3) | (status<<1) | parity |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Wed Aug 24, 2016 12:33 pm |
|
|
try 'struct'... !
from the CCS manual
For example:
Code: | struct data_record {
int a[2];
int b : 2; /*2 bits */
int c : 3; /*3 bits*/
int d;
} data_var; //data_record is a structure type |
//data _var is a variable
If you press F11 while your project is open, the manual 'magically' appears ! search for struct... and it's in the 'data definitions' area...
Though not a great example, you can probably figure it out, just remember the ORDER you store the stuff !!
Hay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Aug 24, 2016 1:56 pm |
|
|
temtronic wrote: | try 'struct'... ! |
He wants a 19-bit wide bitfield. The compiler won't accept it.
It gives this error:
Quote: | Number of bits is out of range |
Therefore your proposed method won't work. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Wed Aug 24, 2016 2:12 pm |
|
|
well thats just 'silly'... maybe split the 19 into 16 and 3 ?
there HAS to be a way .....
I'm just too beat from changing a tractor tire in 90*F heat..
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu Aug 25, 2016 4:20 am |
|
|
It depends what you actually want to do.
You can assemble the 32bit word as you show with rotations. Only 'caveats', make sure that you are limiting the values involved to their actual maximum sizes 'first', or you risk extra bits in 'value' for example, interfering with the ident etc..
However if you want to read the data 'back' or do other manipulations with them, and alternative may be worthwhile. Everything except 'value', can be done with a structure, and then a union with this, gives access to these parts very easily. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Thu Aug 25, 2016 7:08 am |
|
|
If you insist on sending it as a one 32 bit word then yes, your suggested technique will work, with some mods for practicality.
The union and bit field methods both have limitations and restrictions relating to the PIC hardware. There is no guaranty that arbitrarily complex data formats can be mapped by C code on the PIC. Sometimes it works, sometimes it can't. In this case it's the 19 bit value field that's causing trouble :-(
Personally, I tend to treat all SPI data as 8 bit, and send 32 bits as four bytes. In any case, that's what #use_spi() and xfer_spi() will do for you with a hardware SPI as the native mode of the hardware is bytes. The way I'd tread this is to send four bytes, the first is the label. The second is the ID shifted into the top bits, with the upper six bits of the value or'ed in. Then comes the mid eight bits of the value. The last byte is the lower bits of the value, the status and the parity. Yes, it can get unweildy, but that's the way I tend to play it, having been burnt by both unions (which suffer from alignment issues) and bit fields (which suffer from alignment and field size restrictions.
I use the same method for formatting CAN messages. Instead of sending the bytes directly, I put them in to the data bytes of a CAN message structure ready for sending.
Code: |
// Byte by byte method.
output_low(DEVICE_CS);
// This assumes the data is sent in the order in the original post. This can easily be altered for other byte orders.
spi_xfer(label)
spi_xfer((value & 0x03F800)>> 11);
spi_xfer((value & 0x0007F8)>> 3);
spi_xfer((value & 0x000007) << 5 | (status & 0x03) << 1 | (parity & 0x01));
output_high(DEVICE_CS);
|
You can use your code with a little modification. You need to a) limit the values to sensible ranges and b) cast some of the values so that they can shift correctly. Casting is required in the label as, presumably, its an int8. If so, when you shift it more than seven bits ithe result will be zero. It needs to be cast to the final size, int32, before shifting:
Code: |
// More practical shift version, with masking, casting and corrected shifts. Assuming label, ident and status are int8, parity is int1.
word32 = ((int32)label<<24) | ((int32)(ident & 0x03)<<22) | (value<<3) | ((status & 0x02)<<1) | parity;
|
Parity doesn't get shifted, so there's no problem there, and the status stays within a int8 after shifting, so also has no problem. The value has to be int32 already. Its the label and ident that need to be cast. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|