Left or Right shift bits into another byte.

l have a 48 bit binary value that I need to handle 8 bits at a time in a for loop.
The loop handles the data the same way each time; starts at the 7th bit and goes down to the 0th bit.

I thought that I could do a sort of recursive action ==> byte << (x << 8 ) but I don’t think that would work!! I’ve seen it in other languages I think but I’m not sure.

Any suggestions??
Thanks,
pamam

store it as a 6 byte array?

How is it stored now?

Where is the data coming from? Are you reading it in from a serial port or something?

uint64_t n;

for (uint8_t b = 0; b < 48; b++)
{
  if (n & 0x800000000000) ....
  n <<= 1;
}
uint8_t n[6];


for (uint8_t b = 0; b < 48; b++)
{
  if (b[0] & 0x80) .....
  uint8_t c_in = 0;
  for (uint8_t  i = 0; i < 6; i++)
  {
    uint8_t c_out = n[i] & 0x80;
    n[i] <<= 1;
    if (c_in) n[i] |= 0x01;
    c_in = c_out;
  }
}
uint8_t n[6];

for (uint8_t b = 0; b < 48; b++)
{
  uint8_t i = b >> 3;
  uint8_t mask = 0x80 >> (b & 7);
  if (n[i] & mask) .....
}

etc…

Right now it is stored as a long long. It is the result of getting a value from the equation that calculates the 48 bity binary value to use as the data for the frequency

long long x = 50665495807918    // 48 binary value. all inttypes actually store number as  binary.

//I thought long and hard last night and came up with a way to handle the problem.

I just do a bitRead the first eight bits and assign them to the pins in my setData routine then before the 2nd time through my outside loop I do an x << 8.  This does not change the size of x, just the highest bits are replaced with the next highest, so I can use the same loop code every time. 

         void setFTW1( int Frequency1, int address) {
		/* calculate binary freq for the Frequency1 value */
		static long long freq = (Frequency1 * pow(2, 48))/(300 * pow(10, 6));
		for (int address = 5; address >= 0; address--) {
			setAddress(address);
			setData(freq): // see below
			freq << 8;
		}
}


 Where setData uses the freq value
	/* set the Data using bitRead and digitalWrite for one byte */
	void setData ( byte Data)  {
		int startPin = 24;
		/* 
		The data may be of any length up to a max of 48 b its 
		What we are doing is to always read the highest bit first
		then work our way down to the lowest bit.
		In the loop every bit from 7 through 0 or 47 through 40 will
		be added to the Digital Pins that feed the data to the DDS.
		If there are more than one byte in the Data such as the 48 bit
		Data of the FTW1 we repeat until all bytes are used etc.
		*/
		int startBitInData = length(Data) - 1;
		for (int n = startBitInData ; n >= startBitInData - 8 ; n--) {
			pinMode(startPin, OUTPUT);
			digitalWrite(startPin, bitRead(Data, n));
			startPin += 2;
		}
	}

I hope this makes sense the way I wrote it because it took a while for it to make sense to me. In essence each eight bit byte is set to an address. Do this 6 times and you get a 48 bit data specified by 6 Address with each holding a byte of the overall data. I think Analog Devices did this because the same buffers that receive this parallel has to work for serial data as well.
Thanks for the help

pinMode() should normally be run only once, in setup(). What does

setAddress(address);

this do? Are you indexing an array of bytes, as suggested in reply #1? Or serializing the bits for digital output as in setData? I think you can access a long long as a member of a union with bytes, which makes it easier to serialize.

I believe your float calculations could be done in scaled integer math and run much faster, if you need to.

example:
static long long freq = (Frequency1 <<48)/300000000L;Or something like that

This…

static long long freq = (Frequency1 * pow(2, 48))/(300 * pow(10, 6));

Seems highly unlikely to yield a 48 bit number. Firstly pow returns a double, so the calculation will be done in floating point. But if we ignore that for a moment, and assume you want it done using integer maths…

Frequency1 is 16 bits. Let’s represent by 0xnnnn
2^48 = 0x1000000000000
So Frequency1 * pow(2, 48)) is 0xnnnn000000000000 (16+48=64 bits)
And 300 * pow(10, 6) = 300000000
Or in hex 0x11E1A300 (29+ bits)

So overall 64 bit number divided by 29+ bit number can only yield 64-29=35 bits maximum.

Although as I said, because that expression is going to be evaluated using floating point, there will probably be significant loss of precision. So what you actually end up with is anyone’s guess.

And why is freq static? Ummm…

Regardless, let’s assume that is all correct and you somehow have the 48 bit number you want in long long (64 bit) variable freq.

Then just shift it like you would any other integer number. I already provided the code for that…

uint64_t n;

for (uint8_t b = 0; b < 48; b++)
{
  if (n & 0x800000000000) ....
  n <<= 1;
}

This all seems like one hell of a huge X/Y problem to me. Please specify exactly what you want to do, not how you think you want to do it.

Is your Analog Devices device is yielding a 6 byte number a byte at a time, and you wish to convert that to/from a 64 bit integer type (long long) so that it contains the 48 bit quantity represented by those 6 bytes?

Is that correct?
Is that all the above code is trying to do?
So there’s no “secret sauce” in Frequency1 * pow(2, 48))/(300 * pow(10, 6)), which quite frankly still has me baffled.

A datasheet and reference to tge AD product in question wouldn’t go amiss either. But in the absence of that information, how are the 6 bytes arriving? As whole bytes or bits?

//as bits, MSB arrives first...
uint64_t n = 0;
for (uint8_t i = 0; i < 48; i++) {
  n <<= 1;
  if (bit in is 1) n |= 1;
}

//as bytes, MSB arrives first...
uint64_t n = 0;
for (uint8_t i = 0; i < 48; i+=8) {
  n <<= 8;
  uint8_t b = byte in;
  n |= (uint64_t)b;
}

In this case it might be needed to use pinMode in a function. if the data goes on a bi-directional data bus, one will have to switch between input and output.

@pamam, it's always advisable to post complete code. This can either be your full code if it's not too big or a proof-of-concept code.

I further don't quite understand the problem, possibly because there isn't a complete code. Do you have 48 bits that you want to put on a (parallel?) bus 8 bits at a time?

I hope this makes things clearer. It makes things clearer for me to do this. However I did not
mean for this to get this involved since my question was quiet limited in scope. being is there a way to make
x << 8 end up in a different variable such as:
byte data = x << 8; apparently not.

Here goes

I have two tuning words for the final frequencies (freq)

per Analog Devices
Type Name PA SA Description Data Bits Hex Default value

int FTW1 04:09 02 Frequency Tuning Word 1 Bits 47:0 00
int FTW2 0A:0F 03 Frequency Tuning Word 2 Bits 47:0 00

The binary frequency has to be calculated using this formula

int freq = desired frequency * 2^48/ System Clock

in my case that is for a required frequency of 60,000,000

Frequency Binary Data Calc Binary Representation Size Byte
60000000 56294995342131 10111111001001011000101111110010010110001100 44 48

10111111001001011000101111110010010110001100 this is the binary contained in the number below.

Binary Data Calc
56294995342131

if I assign this number to a long long it takes up 48 bits including the leading zeros

I used in my test sketch like this

long long x;
void loop() {
  x = 938249922369;
  Serial.print(x);

  for (int n = 47; n >= 0; n--)
  {
    result = bitRead(x, n);
    Serial.print(result);
   }
   Serial.println();

This pints out

1010110111110001001
12:18:27.434 → 000000001101101001110100000011011010011101000001
12:18:27.536 → 000000001101101001110100000011011010011101000001
12:18:27.604 → 000000001101101001110100000011011010011101000001
12:18:27.671 → 000000001101101001110100000011011010011101000001
12:18:27.772 → 000000001101101001110100000011011010011101000001
12:18:27.840 → 000000001101101001110100000011011010011101000001
12:18:27.908 → 000000001101101001110100000011011010011101000001
12:18:27.976 → 000000001101101001110100000011011010011101000001

They are all 48 bits long. ( of course because they are the same umber over and over again)

Now I have the 6 address that each have to take a data byte out of this string of binary numbers.
However this is not a string or a real number as shown since I printed it one bit at a time. If you copy the binary number and paste it into excel you get a weird decimal number.
But when I do a bitRead(x, bitNum) I do get the actual bit value either 0 or 1,
that is because the long long does store the number in binary format yet it’s value
is shown as 938249922369. Think about it, computers only store stuff in binary, they can’t store 152 as 152 but as binary

Addresses 04:09 is used for FTW1 that is 6 bytes at 6 consecutive addresses of 04:09 hex

Now what I have to do in code is.

	void setData ( long long Data)  {
		int startPin = 24;
		int startBitsInData = length(Data) - 1;
		for (int n = startBitsInData ; n >= startBitsInData - 8 ; n--) {
			pinMode(startPin, OUTPUT);
			digitalWrite(startPin, bitRead(Data, n));
			startPin += 2;
		}
	}

Here: Data is the value of x above,
startPin is the first pin of the D7:D0
Since I want this variable for other data sizes I’m using this
startBitsInData = length(Data)-1 this I have not verified yet
but it should work since the length of the actual number 938249922369 makes no sense at all.

So I loop through the data one byte section at a time assembling the address ( different code)
o4:09 in this case

so we do 04 in this iteration and setup 8 pins with the bit values in first byte one bit at time .
incrementing the pin number by 2 then repeat until 8 bits and pins are set. This data is stored at address 04
With the address I use a similar setup.

so for
setFTW1( address, data)
{
for each address and data I do this in a loop.
{
setAddress(address);
setData(Data);
pulse write pin (pseudo)
data << 8
}
}

It’s not that hard just complex enough to need lots of focus, and when your dog tries to get you to play every hour or so it is easy to loose your place.
Thanks all for being so patient,
pamam

mean for this to get this involved since my question was quiet limited in scope. being is there a way to make
x << 8 end up in a different variable such as:
byte data = x << 8; apparently not.

No, or at least not unless data is a member of a union and larger type than a byte.
Which it obviously isn’t when expressed like that.

If you want bits to shift into higher order bytes, it seems obvious to user a larger type that byte, and have the compiler/cpu do this for you.
Which begs the question, why aren’t you?

Here I shift 2 32 bits into 8 bit buckets:

  if (!PassTwo)
        {
          rx_frame.FIR.B.FF = CAN_frame_std;
          rx_frame.MsgID = 1;
          rx_frame.FIR.B.DLC = 8;
          rx_frame.data.u8[0] = *item & 0xFF;
          rx_frame.data.u8[1] = (*item >> 8) & 0xFF;
          rx_frame.data.u8[2] = (*item >> 16) & 0xFF;
          rx_frame.data.u8[3] = (*item >> 24) & 0xFF;
          PassTwo = true;
        } else {
          rx_frame.data.u8[4] = *item & 0xFF;;
          rx_frame.data.u8[5] = (*item >> 8) & 0xFF;
          rx_frame.data.u8[6] = (*item >> 16) & 0xFF;
          rx_frame.data.u8[7] = (*item >> 24) & 0xFF;
          ESP32Can.CANWriteFrame(&rx_frame); // send items over CAN buss
          PassTwo = false;
        }

The union was already mention by @pcbbc. And I think that that is what you’re looking for.

union DATA64
{
  uint64_t value;
  uint8_t bytes[8];
};

DATA64 theData;


void setup()
{
  theData.value = 0x0123456789AB;

  Serial.begin(57600);
  for (uint8_t cnt = 0; cnt < 6; cnt++)
  {
    Serial.println(theData.bytes[cnt], HEX);
  }
}

@sterretje: using a union will set off a row with the C/C++ clerics! They strongly disapprove.

Since the OP’s number is 48 bits, the following works too. (I showed something like this to the OP in the previous thread on this topic).

void setup() {
  Serial.begin(9600);
  long long x = 938249922369LL;
  char bytes[6];

  for (char i = 0; i < 6; i++)  {
    bytes[i] = (byte) (x & 0x0FF);
    x= x >> 8;
    Serial.println(bytes[i]&0xFF, HEX);  //&0xFF avoids the serial.print bug
  }

}
void loop() {}

Thanks to all your help the problem has been resolved. All the input combined generated and spawned some ideas that i got to work. Also the "Arduino Internals" book helped in some performance issues: I highly recommend it even though it's a little pricey.

Thanks again.
pamam

This post is now closed.
Thanks to all who responded.
pamam

pamam:
This post is now closed.
Thanks to all who responded.
pamam

Under your opening post is a link "more". You can use "more" -> "modify" to modify the post and put e.g. [solved] in front of the title.

jremington,

this is what I came up with and it works fine.

#include <Arduino.h>

void NotWritePulse()
{
  /* 
   *Pin 37 of the board is the NotWrite bit. The boards Read and NotWrite did not align
   *with the DDS pinout that's why it was generated separately.
   *PC0 is Pin D37 which matches /WR on DDS
    */
  bitClear(DDRC, 0);
  bitSet(DDRC, 0);
  delayMicroseconds(10);
  bitClear(DDRC, 0);
}

void setAdddressAndData(uint64_t Address, uint64_t Data, int Length)
{
  /* 
   *Data is the binary data in uint64_t format generated by the 
   *Control Panel on the Laptop and sent to the 2560 board.
    */

   /* 
    *Since the data will never get more than 6 bytes we can ignore the
    *top MSBytes, 8 and 7, since there are only 6 bytes of address and 6
    *bytes of Data dataa.
      */
  int addLength = sizeof(Address)*Length;
  int dataLength = sizeof(Data)*Length;
  //TBR
  Serial.print( " sizeof Address = "); Serial.print(sizeof(Address));
  Serial.print("  addLength = "); Serial.print(addLength);
  Serial.print(" Sizeof Data = ");Serial.println(sizeof(Data));
  Serial.print("  dataLength = "); Serial.print(dataLength);
  
  /*
   * since if there are 6 addresses there will also be 6 data segments. The
   * length of the address will be equal to the the sizeof the Address. 
   * The number of bytes in an address will equal the size of the Address 
    */

  /* numBytes is same for Data as for Address */
  int numBytes = addLength / 8;

  /*
   * The code will be setting the pin direction to output. then for each bit
   * in the address or Data; we will set the pin value to either 0 or 1
   * depending on the pin losition in the Data or Address. I did not use 
   * the DDR's directly for this operation since the pins were located on 
   * different ports which would have made iteration a nightmare and in the 
   * end waste even more memory.
    */
  for ( numBytes; numBytes >= 1; numBytes--)
  {
    /* 
     * Step 1. Generate the Addresses 
     * The startPin values come from the board Arduiono 2560 from the parallel
     * port consisting of bits 20 - 55 of which we use 22 - 41. 23 - 33 all odd
     * are the address bits.
      */
    Serial.print(" ==> numBytes = ");Serial.println(numBytes);
    int startPin = 23;

    /* 
     * Main loop for the Address setup 
     */

     /* addLength - 3 since we want to start with the 6th bit per byte
      * hence 48 - 1 to get actual bit position - 2 since that there are
      * only 6 bits in each address hextuplt. i.e, Instead of starting at
      * bit 47, 45 is the start point and it ends at 40. 45 to 40 inclusive are 
      * 6 bits.
       */
    for ( int bit = addLength - 3; bit >= addLength - 8; bit--) {
      pinMode(startPin, OUTPUT);
      digitalWrite(startPin, (bitRead(Address, bit)));
      Serial.print(" ==> startPin = "); Serial.print(startPin);Serial.print(" bit = ");Serial.print(bit );
      int value = bitRead(Address, bit);
      Serial.print(" ==> The read bit value = "); Serial.print(value); Serial.println();
      startPin += 2;
    }

    /* Step 2. Generate the Data segments 
      The startPin values come from the board Arduiono 2560 from the parallel
      port consisting of bits 20 - 55 of which we use 22 - 41. 24 - 38 are the 
      data bits.  37 is the NotWrite bits. The boards Read and NotWrite did not align
      with the DDS pin out that's why it was generated separately.
     */
     
    // TBR
    Serial.print(" ==> numBytes = ");Serial.println(numBytes);

    /* 
     * Main loop for the Data setup 
     */

    /* Data - 1 since we want to start with 47th byte hence 48 - 1 to get the 
    * actual bit position since there are 8 bits in each Data byte. i.e, 
    * Starting at bit 47, it ends at 40. 47 to 40 inclusive are 8 bits.
      */

    startPin = 24;
    for ( int bit = dataLength - 1; bit >= dataLength - 8; bit--) {
        pinMode(startPin, OUTPUT);
        //Serial.print(dataLength - 1);
        digitalWrite(startPin, (bitRead(Data, bit)));
       // TBR
        int value = bitRead(Data, bit);
       Serial.print(" ==> startPin = "); Serial.print(startPin);Serial.print(" bit = ");Serial.print(bit);
       Serial.print(" ==> The read bit value = ");Serial.print(value); Serial.println();
       
       startPin += 2;
    }

    //  Step 3. Generate NotWrite signal.
    NotWritePulse();

    /*  Step 4. Setup for next Address byte, Data byte, and Write Command. */
    Address = Address << 8;
    Data = Data << 8;
  }
}


void setup() {
  Serial.begin(9600);
  delay(200);
  /* FTWAddress number generated by controll panel. */
  uint64_t Address = 4419622471689;
  /* Frequency number for 54000000 HJz.*/
  uint64_t Data = 63331869759898;

  int Length = 6;
  /* Call the function */
  setAdddressAndData(Address, Data, Length);
}
void loop() {


}

Run it as is the attachment could not be uploaded.