Bit field definition like Borland C++ or codevision

In old Borland C++ we can define bit fileds in any size like following examples :slight_smile:
struct allinputs
{
unsigned Key01 : 1;
unsigned Key02 : 1;
unsigned Key03 : 1;
unsigned Key04 : 1;
unsigned Key05 : 1;
unsigned Key06 : 1;
unsigned Key07 : 1;
unsigned Key08 : 1;
unsigned LeftWise : 1;
unsigned RightWise : 1;
unsigned Start : 1;
unsigned Stop : 1;
unsigned Key12 : 1;
unsigned Key11 : 1;
unsigned Key10 : 1;
unsigned Key09 : 1;
}inputbits;

I test it in code viison and its work very nice the above example for input bits managing and following example for output bits managing :slight_smile:

struct allrelay
{
unsigned Relay11:1;
unsigned Relay10:1;
unsigned Relay09:1;
unsigned Left:1;
unsigned Relay15:1;
unsigned Relay14:1;
unsigned Relay13:1;
unsigned Relay12:1;

unsigned Group3LED7:1;
unsigned Group3LED6:1;
unsigned Group3LED5:1;
unsigned Group3LED4:1;
unsigned Group3LED3:1;
unsigned Group3LED2:1;
unsigned Group3LED1:1;
unsigned Group3LED0:1;

unsigned Group2LED0:1;
unsigned Group2LED1:1;
unsigned Group2LED2:1;
unsigned Group2LED3:1;
unsigned Group2LED4:1;
unsigned Group2LED5:1;
unsigned Group2LED6:1;
unsigned Group2LED7:1;

unsigned  Relay03:1;
unsigned  Relay02:1;
unsigned  Relay01:1;
unsigned  Relay00:1;
unsigned  Right:1;
unsigned  Pump:1;
unsigned  Relay05:1;
unsigned  Relay04:1;

unsigned char SevenSegment;

unsigned Group0LED0:1;
unsigned Group0LED1:1;
unsigned Group0LED2:1;
unsigned Group0LED3:1;
unsigned Group0LED4:1;
unsigned Group0LED5:1;
unsigned Group0LED6:1;
unsigned Group0LED7:1;


unsigned Group1LED7:1;
unsigned Group1LED6:1;
unsigned Group1LED5:1;
unsigned Group1LED4:1;
unsigned Group1LED3:1;
unsigned Group1LED2:1;
unsigned Group1LED1:1;
unsigned Group1LED0:1;

}relaybits;

When I want to transfer SPI bits simply using the following code :slight_smile:

  1. spi(peekb(&relaybits))
  2. spi(*((unsigned char *) &relaybits + 1))

It depends on the length of the structure information information.

But in the Arduino IDE this definition is not applicable.
The C - Bit Fields not applicable because this definition need more memory. I need only bits in one byte not each bits in another one byte.

Can any body help me to define this bit fields.

Can you post a minimal sketch that exhibits the problem, and the actual error message(s) it produces, please?

Each reference you create takes more memory overhead.

I try to keep those references as comments, as the example below.
This is a read-only situation, but a write could easily be done with an or.

Just my opinion but this is way to much complication for such a tiny device.

// Update a single digit to the display buffer
void digit_on(uint8_t digit_pixels[], uint8_t x_offset) {
  // 4 sets, 2 rows per, 8 rows total
  for (index = 0; index < 4; index++) {
    
    // Contains 2 rows, one per nibble
    // Upper row in MS nibble
    // Lower row in LS nibble
    // 0bUUUULLLL
    rows = digit_pixels[index]; 

    // Upper Row
    x = x_offset;       // adjust digit position on screen                  
    y = index + index;  //   2k, even row
    //         color shift        Modulo 8
    color_y = (y + color_shift) & 0b00000111;
    
    if (rows & 128)   leds[pos[y][x]] = font_color[color_y];  // check b2^7
    x++;
    if (rows & 64)    leds[pos[y][x]] = font_color[color_y];  // check b2^6 
    x++;
    if (rows & 32)    leds[pos[y][x]] = font_color[color_y];  // check b2^5 
    x++;
    if (rows & 16)    leds[pos[y][x]] = font_color[color_y];  // check b2^4

    // Lower Row
    x = x_offset; // reset x
    // 2k+1   Modulo 8
    y++;
    color_y = (y + color_shift) & 0b00000111;
    
    if (rows & 8)     leds[pos[y][x]] = font_color[color_y];   // check b2^3
    x++;
    if (rows & 4)     leds[pos[y][x]] = font_color[color_y];   // check b2^2
    x++;
    if (rows & 2)     leds[pos[y][x]] = font_color[color_y];   // check b2^1
    x++;
    if (rows & 1)     leds[pos[y][x]] = font_color[color_y];   // check b2^0
  }
}

Arduino is using bitfields left right an center for register mapping

Last time I checked, bit fields in structs worked as expected on an Arduino.

Thank you for every body

I read all responses and now I solve the problem for our project like following code , in this code I can access each bits in 64 bit memory location and let the compiler manage bits postion changing , only need to send spi data to the bus, if the code any mistake please help me to upgrade it

typedef struct {
unsigned long a1:3;
unsigned long a2:1;
unsigned long a3:1;
unsigned long a4:3;
unsigned long b:8;
unsigned long c:8;
unsigned long d:8;
unsigned long e:4;
unsigned long f:6;
}spi_bit_fields;

union data{
unsigned long long bits_holder;
spi_bit_fields control_bits;
};

void setup(){
union data x;
unsigned long long test_bits = 0xefaabbcc6d;

Serial.begin(115200);

printf("sizeof x is %dbytes\n",sizeof(x));

/* write to the union treating it as a single integer */
x.bits_holder = test_bits;

/* read from the union treating it as a bitfields structure */
printf("%x %x %x %x %x %x %x %x %x\n",
x.control_bits.a1,
x.control_bits.a2,
x.control_bits.a3,
x.control_bits.a4,
x.control_bits.b,
x.control_bits.c,
x.control_bits.d,
x.control_bits.e,
x.control_bits.f);

/* read from the union treating it as an integer /
/
Now we can send out each byte of data to spi bus */
printf("0 0x%x\n", *((unsigned char *) &x.bits_holder + 0));
printf("1 0x%x\n", *((unsigned char *) &x.bits_holder + 1));
printf("2 0x%x\n", *((unsigned char *) &x.bits_holder + 2));
printf("3 0x%x\n", *((unsigned char *) &x.bits_holder + 3));
printf("4 0x%x\n", *((unsigned char *) &x.bits_holder + 4));
printf("5 0x%x\n", *((unsigned char *) &x.bits_holder + 5));
printf("6 0x%x\n", *((unsigned char *) &x.bits_holder + 6));
}

void loop()
{

}

thanks a lot

Are you sure your struct won’t be padded? I think the only sure way to set your bit fields is to make a method to set them individually

Dear killzone_kid

Thank you for interesting but I test the following code in ESp32 without any crash or error :

#include "driver/spi_master.h"

#define PIN_NUM_MISO 25
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 19
#define PIN_NUM_CS 22

esp_err_t ret;
spi_device_handle_t spi;
gpio_config_t io_conf;
spi_bus_config_t buscfg;
spi_device_interface_config_t devcfg;
TaskHandle_t xHandleSlaveTask = NULL;

typedef struct {
unsigned long a1:3;
unsigned long a2:1;
unsigned long a3:1;
unsigned long a4:3;
unsigned long b:8;
unsigned long c:8;
unsigned long d:8;
unsigned long e:4;
unsigned long f:6;
}bitfields;

union data{
unsigned long long i;
bitfields bf;
};

union data x;

void spi_pre_transfer_callback(spi_transaction_t *t)
{
Serial.println("CB");
}

void spi_post_transfer_callback(spi_transaction_t *t)
{
Serial.println("PB");
}

void send_spi_data_packet(void * pvParameters)
{
spi_transaction_t t;
static spi_transaction_t trans;
memset(&t, 0, sizeof(t));
memset(&trans, 0, sizeof(spi_transaction_t));
trans.length=8;
trans.user=(void*)0;
trans.flags=SPI_TRANS_USE_TXDATA;
trans.tx_data[0]=0x2A; //Column Address Set
// while(1)
// {
// ret=spi_device_queue_trans(spi, &trans, portMAX_DELAY);
// assert(ret==ESP_OK);
// vTaskDelay(5 / portTICK_RATE_MS);
// }
//while(1)
{
t.length = 64;
t.tx_buffer = &x.i;
t.user=(void*)0;
ret=spi_device_transmit(spi, &t);
assert(ret==ESP_OK);
vTaskDelay(5 / portTICK_RATE_MS);

}
}

void setup(){
unsigned long long v = 0xefaabbcc6d;
unsigned char y;
BaseType_t xReturned;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 0b11111;
gpio_config(&io_conf);
buscfg.miso_io_num=PIN_NUM_MISO;
buscfg.mosi_io_num=PIN_NUM_MOSI;
buscfg.sclk_io_num=PIN_NUM_CLK;
buscfg.quadwp_io_num=-1;
buscfg.quadhd_io_num=-1;
devcfg.clock_speed_hz=10000;
devcfg.mode=0;
devcfg.spics_io_num=PIN_NUM_CS;
devcfg.queue_size=7;
devcfg.pre_cb = spi_pre_transfer_callback;
devcfg.post_cb = spi_post_transfer_callback;
x.i = v;
Serial.begin(115200);
printf("sizeof x is %dbytes\n",sizeof(x));
printf("%x %x %x %x %x %x %x %x %x\n", x.bf.a1,x.bf.a2,x.bf.a3,x.bf.a4, x.bf.b, x.bf.c, x.bf.d, x.bf.e, x.bf.f);
printf("0 0x%x\n", *((unsigned char *) &x.i + 0));
printf("1 0x%x\n", *((unsigned char *) &x.i + 1));
printf("2 0x%x\n", *((unsigned char *) &x.i + 2));
printf("3 0x%x\n", *((unsigned char *) &x.i + 3));
printf("4 0x%x\n", *((unsigned char *) &x.i + 4));
printf("5 0x%x\n", *((unsigned char *) &x.i + 5));
printf("6 0x%x\n", *((unsigned char *) &x.i + 6));
//Initialize the SPI bus
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
assert(ret==ESP_OK);
ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
assert(ret==ESP_OK);
while(1)
{
send_spi_data_packet(spi);
x.bf.c++;
x.bf.a4--;
printf("%x %x %x %x %x %x %x %x %x %p\n", x.bf.a1,x.bf.a2,x.bf.a3,x.bf.a4, x.bf.b, x.bf.c, x.bf.d, x.bf.e, x.bf.f,&x.i);
}
xReturned = xTaskCreate(&send_spi_data_packet, "send_spi_data_packet", 5 * configMINIMAL_STACK_SIZE, NULL, 5, &xHandleSlaveTask);
if( xReturned != pdPASS )
{
ESP_LOGE ("xTaskCreate", "send_spi_data_packet: %d", xReturned);
}
}

void loop() {

}

Can you please mark the topic "solved"?

Please remember to use code tags when posting code

What you do is not supported by the c++ standard, reading from non active union member is undefined behaviour. So if you write in i then read from bf, it is UB. However some compilers may allow this via extensions. On top, compilers are free to pad the structs so unless you specifically tell the compiler not to pad, you can end up with a surprise.

What you can do is get rid of union and add helper methods to struct to initialise bitfields from different data

Dear Killzone_kid
The padding of data after compiling the code As far as I know it is always fixed.
In this code I need only 64 bit (8 byte) if need more data after changing the size of structure and compiling, the size of structure in assmbeled code I don't think change.

I do not know how to use the helper for this purpose, please give me an example or a link. I need only setup the bits of shift registers outputs or reading shift registers inputs without any bitwise operation and or bit position calculation.
Thanks alot
Best regards

What I meant was:

/*
 Name:		bitfields.ino
 Created:	10/19/2021 8:55:35 AM
 Author:	KK
*/

struct ChessPieceMove
{
	uint16_t side : 1;
	uint16_t piece : 3;
	uint16_t fromX : 3;
	uint16_t fromY : 3;
	uint16_t toX : 3;
	uint16_t toY : 3;

	ChessPieceMove() = delete;

	ChessPieceMove(uint16_t move)
	{
		uint16ToMove(move);
	}

	void uint16ToMove(uint16_t move)
	{
		toY = move & 0b111;
		toX = (move >> 3) & 0b111;
		fromY = (move >> 6) & 0b111;
		fromX = (move >> 9) & 0b111;
		piece = (move >> 12) & 0b111;
		side = (move >> 15) & 0b1;
	}
};

void PrintMove(const ChessPieceMove &move)
{
	static const char *pieces[] = { "Pawn", "Rook", "Knight", "Bishop", "Queen", "King" };

	if (move.piece > 5)
	{
		Serial.println("Invalid Chess piece");
		return;
	}

	Serial.print(move.side ? "White " : "Black ");
	Serial.print(pieces[move.piece]);
	Serial.print(" From ");
	Serial.print(char(move.fromY + 65));
	Serial.print(move.fromX + 1);
	Serial.print(" To ");
	Serial.print(char(move.toY + 65));
	Serial.println(move.toX + 1);
}

// the setup function runs once when you press reset or power the board
void setup() 
{
	Serial.begin(9600);
}

// the loop function runs over and over again until power down or reset
void loop() 
{
	ChessPieceMove myMove(random(0u, 65535u));
	PrintMove(myMove);
	delay(1000);
}