0

(I've seen these questions (Convert Bytes to Int / uint in C and Converting Byte Array To Int24) but they seem more complicated than what I am trying to do, so I thought I would ask.)

I'm doing some LED matrix programming in Arduino/Wiring. For reasons probably not relevant here I have a byte array representing a "bit state" of a LED row, which I use to buffer the result of other operations. To actually set the LEDs (I'm using the Maxim 7219 chip), I need to derive an integer from the byte array.

Using the Arduino/Wiring bitWrite method, my little stripped down example routine below works but I am wondering if there is a C method which would be faster than looping.

 byte dog[8] = {0,0,1,1,1,1,1,0};
 byte cat;

 for (int i = 0; i < 8; i++){
  bitWrite(cat, i, dog[7-i]);
 }
Community
  • 1
  • 1
spring
  • 18,009
  • 15
  • 80
  • 160
  • 1
    You have an array; you have to iterate/step over it. – this Mar 02 '14 at 15:04
  • What sort of processor does your Arduino have? – James Mar 02 '14 at 15:19
  • If you are wanting it to go faster we would have to exploit some feature of the processor, like if it's a 32-bit processor, perhaps look at expressions that process bytes 4 at a time. And what's the problem you are trying to solve; running too slow? If so how much faster does it need to go? – James Mar 02 '14 at 15:27

2 Answers2

4

You could unroll the loop:

bitWrite(cat, 0, dog[7]);
bitWrite(cat, 1, dog[6]);
bitWrite(cat, 2, dog[5]);
bitWrite(cat, 3, dog[4]);
bitWrite(cat, 4, dog[3]);
bitWrite(cat, 5, dog[2]);
bitWrite(cat, 6, dog[1]);
bitWrite(cat, 7, dog[0]);

Or set the bits without a library function (only works if the bytes are guaranteed to be either 0 or 1):

cat = (dog[7] << 0) |
      (dog[6] << 1) |
      (dog[5] << 2) |
      (dog[4] << 3) |
      (dog[3] << 4) |
      (dog[2] << 5) |
      (dog[1] << 6) |
      (dog[0] << 7);

But there's nothing built into C to do this with a single command so it probably won't get much faster than that.

EDIT: With some bit-twiddling tricks this can be (probably) sped up a little. Something like the following should work on a little-endian 32-bit processor:

uint32_t int_dog = (uint32_t*)dog;
uint32_t t0, t1;

t0 = int_dog[0];   // .......3.......2.......1.......0
t0 |= t0 << 9;     // ......23......12......01.......0
t0 |= t0 << 18;    // ....0123.....012......01.......0
t1 = int_dog[1];   // .......7.......6.......5.......4
t1 |= t1 << 9;     // ......67......56......45.......4
t1 |= t1 << 18;    // ....4567.....456......45.......4
cat = (t0 >> 20) | (t1 >> 24);
nwellnhof
  • 32,319
  • 7
  • 89
  • 113
  • Depending on the processor this might not go faster. The loop is less code and might be cached more efficiently. – James Mar 02 '14 at 15:32
  • Thanks - couple of question: why might unrolling the loop be faster? And in your second example, can you explain a little what it is doing? I understand that it is bitshifting each bit of 'dog' by the inverse of the bit position but I am confused by the bit OR - and yes, the bytes will be 1 or 0. fwiw - it's an ATmega168 chip (http://www.atmel.com/devices/atmega168.aspx) – spring Mar 02 '14 at 23:36
-2

It's pretty trashy, but you can do that with goto labels:

byte dog[8] = {0,0,1,1,1,1,1,0};
byte cat;
int i = 0;

BitWriteBeginning:    
bitWrite(cat, i, dog[7-i]);
i++
if (i < 8)
   goto BitWriteBeginning;

But even, i'm not sure it will be more efficient. It still a condition to evaluate, and the compiler probably can't optimize that (for instance put i in ecx).

So you can do even more ugly (:D), with putting register label before int i = 0; .

Antoine C.
  • 3,730
  • 5
  • 32
  • 56