Particle compiler doesn't fully support initializing bit fields?

I have a short .c test program that compiles fine using my local gcc compiler but the (nearly) identical .ino file fails to compile using particle compile e ....

TL;DR

Compiling a const bit structure initialization under gcc works. Under particle compile..., I get the error message:

mini.ino:19:1: error: too many initializers for 'const gpio_port_config_t'

Is this because my gcc is more permissive? Is there a compiler switch I can use, or some other technique to get this to work?

The Gory Details

The C code

Here is the C program in its entirery:

#include <stdint.h>
#include <stdio.h>

typedef enum {
  kGpioModeInputAnalog,             //   0000 Input Mode, Analog
  kGpioModeOutput10MHzPushPull,     //   0001 Output 10MHz, Push-Pull
} gpio_mode_t;

typedef union {
  uint32_t cr;                  // the full register
  struct {
    gpio_mode_t pin00:4;        // lsb
    gpio_mode_t pin01:4;
    unsigned int unused:24;
  } __attribute__((__packed__));
} gpio_port_config_t;

const gpio_port_config_t g00 = { .pin00 = kGpioModeOutput10MHzPushPull,
                                 .pin01 = kGpioModeOutput10MHzPushPull
};

int main() {
  printf("%x\n", g00.cr);
  return 0;
}

The .ino version

Here is the corresponding .ino program. The only difference is in the call to setup() rather than main() and the lack of a #include <stdint.h>:

typedef enum {
  kGpioModeInputAnalog,             //   0000 Input Mode, Analog
  kGpioModeOutput10MHzPushPull,     //   0001 Output 10MHz, Push-Pull
} gpio_mode_t;

typedef union {
  uint32_t cr;                  // the full register
  struct {
    gpio_mode_t pin00:4;        // lsb
    gpio_mode_t pin01:4;
    unsigned int unused:24;
  } __attribute__((__packed__));
} gpio_port_config_t;

const gpio_port_config_t g00 = { .pin00 = kGpioModeOutput10MHzPushPull,
                                 .pin01 = kGpioModeOutput10MHzPushPull
};
void setup() {
}

Compiling in C works

Compiling with gcc on my Mac OS X (using the -v switch, so you can see the compiler settings) works fine:

$ gcc -v -Wall -o mini mini.c
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.12.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name mini.c -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu penryn -target-linker-version 278.4 -v -dwarf-column-info -debugger-tuning=lldb -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -Wall -fdebug-compilation-dir /Users/r/Projects/ParticleZen/sketches -ferror-limit 19 -fmessage-length 161 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.12.0 -fencode-extended-block-signature -fmax-type-align=16 -fdiagnostics-show-option -o /var/folders/7x/bsz1mn9d5ps8pzs886s71d9m0000gq/T/mini-cc2867.o -x c mini.c
clang -cc1 version 8.1.0 (clang-802.0.42) default target x86_64-apple-darwin16.6.0
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/local/include"
ignoring nonexistent directory "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include
 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks (framework directory)
End of search list.
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch x86_64 -macosx_version_min 10.12.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -o mini /var/folders/7x/bsz1mn9d5ps8pzs886s71d9m0000gq/T/mini-cc2867.o -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.1.0/lib/darwin/libclang_rt.osx.a

Compiling with particle compile... fails

Here's the result of compiling with particle compile...

$ particle compile e mini.ino

Compiling code for e

Including:
    mini.ino
attempting to compile firmware 
Compile failed. Exiting.
Processing  mini.ino
make -C ../modules/electron/user-part all
make[1]: Entering directory '/firmware/modules/electron/user-part'
make -C ../../../user 
make[2]: Entering directory '/firmware/user'
Building cpp file: mini.cpp
Invoking: ARM GCC CPP Compiler
mkdir -p ../build/target/user/platform-10-m
arm-none-eabi-gcc -DSTM32_DEVICE -DSTM32F2XX -DPLATFORM_THREADING=1 -DPLATFORM_ID=10 -DPLATFORM_NAME=electron -DUSBD_VID_SPARK=0x2B04 -DUSBD_PID_DFU=0xD00A -DUSBD_PID_CDC=0xC00A -DSPARK_PLATFORM -g3 -gdwarf-2 -Os -mcpu=cortex-m3 -mthumb -DINCLUDE_PLATFORM=1 -DPRODUCT_ID=10 -DPRODUCT_FIRMWARE_VERSION=65535 -DUSE_STDPERIPH_DRIVER -DDFU_BUILD_ENABLE -DSYSTEM_VERSION_STRING=0.6.2 -DRELEASE_BUILD -I./inc -I../wiring/inc -I../system/inc -I../services/inc -I../communication/src -I../hal/inc -I../hal/shared -I/rtos/FreeRTOSv8.2.2/FreeRTOS/Source/include -I/rtos/FreeRTOSv8.2.2/FreeRTOS/Source/portable/GCC/ARM_CM3 -I../hal/src/electron -I../hal/src/stm32f2xx -I../hal/src/stm32 -I../platform/shared/inc -I../platform/MCU/STM32F2xx/STM32_USB_Host_Driver/inc -I../platform/MCU/STM32F2xx/STM32_StdPeriph_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/inc -I../platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc -I../platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc -I../platform/MCU/shared/STM32/inc -I../platform/MCU/STM32F2xx/CMSIS/Include -I../platform/MCU/STM32F2xx/CMSIS/Device/ST/Include -I../dynalib/inc -I -I./libraries -I -I -I -I -I. -MD -MP -MF ../build/target/user/platform-10-mmini.o.d -ffunction-sections -fdata-sections -Wall -Wno-switch -Wno-error=deprecated-declarations -fmessage-length=0 -fno-strict-aliasing -DSPARK=1 -DPARTICLE=1 -DSTART_DFU_FLASHER_SERIAL_SPEED=14400 -DSTART_YMODEM_FLASHER_SERIAL_SPEED=28800 -DSPARK_PLATFORM_NET=UBLOXSARA -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc  -DLOG_INCLUDE_SOURCE_INFO=1 -DPARTICLE_USER_MODULE -DUSE_THREADING=0 -DUSE_SPI=SPI -DUSE_CS=A2 -DUSE_SPI=SPI -DUSE_CS=A2 -DUSE_THREADING=0 -DUSER_FIRMWARE_IMAGE_SIZE=0x20000 -DUSER_FIRMWARE_IMAGE_LOCATION=0x8080000 -DMODULAR_FIRMWARE=1 -DMODULE_VERSION=4 -DMODULE_FUNCTION=5 -DMODULE_INDEX=1 -DMODULE_DEPENDENCY=4,2,108 -D_WINSOCK_H -D_GNU_SOURCE -DLOG_MODULE_CATEGORY="\"app\""  -fno-exceptions -fno-rtti -fcheck-new -std=gnu++11 -c -o ../build/target/user/platform-10-mmini.o mini.cpp
mini.ino:19:1: error: too many initializers for 'const gpio_port_config_t'
 };
 ^
../build/module.mk:267: recipe for target '../build/target/user/platform-10-mmini.o' failed
make[2]: Leaving directory '/firmware/user'
make[2]: *** [../build/target/user/platform-10-mmini.o] Error 1
../../../build/recurse.mk:11: recipe for target 'user' failed
make[1]: Leaving directory '/firmware/modules/electron/user-part'
../build/recurse.mk:11: recipe for target 'modules/electron/user-part' failed

This builds tho’

typedef enum {
  kGpioModeInputAnalog,             //   0000 Input Mode, Analog
  kGpioModeOutput10MHzPushPull,     //   0001 Output 10MHz, Push-Pull
} gpio_mode_t;

typedef union {
  struct {
    gpio_mode_t pin00:4;        // lsb
    gpio_mode_t pin01:4;
    unsigned int unused:24;
  } __attribute__((__packed__));
  uint32_t cr;                  // the full register
} gpio_port_config_t;

const gpio_port_config_t g00 = { kGpioModeOutput10MHzPushPull, kGpioModeOutput10MHzPushPull };

void setup() {
}
1 Like

Ah – you have to move the uint32_t cr field to the end for this to work. I can live with that. And to keep it compatible with my C code base, I’ve added extra braces:

const gpio_port_config_t g00 = { { kGpioModeOutput10MHzPushPull, kGpioModeOutput10MHzPushPull } };

Thanks – that got me over the most recent hump!

2 Likes