2

Without resorting to typedef union, is there working macro for Cortex-M0 in C where it copy byte data into word within 31 to 23.

I have recieved data from spi and need to copy this data into word.

The SRAM does not work with bit manipulation, so I use "How do you set, clear and toggle a single bit in C?" but what about the byte.

thanks

Riscy

Riscy
  • 843
  • 4
  • 13
  • 28

3 Answers3

2

Try this

word &= ~0xFF800000U; /* clear bits 23 - 31; thanks to Igor Skochinsky */
word |= ((byte << 23) & 0xFF800000U);

It shifts the (9-bit) byte value 23 bits and ors it with the value in word, making sure only bits 23-31 are affected.

pmg
  • 106,608
  • 13
  • 126
  • 198
  • 1
    While I'm all for defensive programming (and humor - I upvoted your 9-bit byte comment in the question) - won't a bitwise left shift bring zeroes into the low bits? Is the mask operation necessary? – Dan Jun 25 '11 at 14:49
  • @Dan: the thing is that "oring with 0 is a no-op": `X | 0` is always `X`. So no bits with a corresponding `0` change with the `|=` operation: only those in (the 9) positions 23 to 31. The mask is to guard against the initial byte having 10 or more bits :) – pmg Jun 25 '11 at 14:53
  • The compiler should optimize the mask away (I just checked that `gcc` does). – starblue Jun 25 '11 at 15:16
  • Ah! @starblue ... but your bytes are 8-bits long, and your words are 32-bits long. Try with `unsigned short` for byte and `unsigned long` for word :) – pmg Jun 25 '11 at 15:19
  • Actually both were `uint32_t`, but for your pleasure I've done it again for `byte` of type `uint16_t`, with essentially the same result. Shift and or are there, but there is no `and` opcode in the assembly. – starblue Jun 25 '11 at 22:24
  • With `uint32_t` the mask `0xFF800000U` is just enough for all bits and the compiler removes it. Try `uint64_t` (what I hoped `unsigned long` was) for the word – pmg Jun 25 '11 at 22:54
2

pmg's answer will only work in case the top 9 bits already zero. If there were some bits set, your data will get ORed with them. So, to be sure you need to clear those bits first:

#define POS   23          // position at which to insert data
#define MASK  ((1UL<<9)-1)  // mask of nine 1s

word = (word & ~(MASK<<POS)) | ((data9 & MASK) << POS));

The first part will shift the mask to the target position, then invert it, so you'll have zeroes at the target top bits and ones for the rest of the word, thus the AND operation will clear the top 9 bits and leave the low bits unchanged. The second part will make sure we have only 9 bits set, then shift them into the target position. Finally, the two parts will be combined with the OR operations, and because of the masking they will not interfere.

Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
  • Or you could simply write the mask as 0x01FFUL. Depending on the size of the default int type, there's somewhere between 9 and 12 implicit conversions going on in this single line of code. Fortunately, the Cortex is 32 bit, or you would have unleashed implicit conversion hell upon it with code like this. – Lundin Jun 27 '11 at 14:15
  • @Lundin: any modern compiler will evaluate preprocessor definitions before actual compilation. And the simplest optimization will evaluate the constant shifts in the expression as well. – Igor Skochinsky Jun 27 '11 at 15:43
  • It doesn't matter if it's the pre-processor or the compiler, neither is allowed to ignore C's type promotion rules. Neither is the optimizer. Code like this doing a lot of bit-wise operations can be dangerous because of it: especially the ~ and >> operators are vulnerable to accidental, implicit promotions. – Lundin Jun 28 '11 at 06:15
  • @Lundin `((1UL<<9)-1)` and `0x01FFUL` are equivalent in any compiler I know. We also know that the variable is 32-bit from the question, so I'm not sure what are you driving at. – Igor Skochinsky Jun 28 '11 at 10:17
0

Specifically for a byte, you can use the assembly instructions

  • UXTB to extract bits 0-7 from a register, followed by
  • LSLS to shift it left till where you want it.

Of course, you will need to do the load and store operations too. But you will already know that.

TSG
  • 877
  • 1
  • 6
  • 23