Safe mode after building system and app firmware from source

I wonder if someone can give me some guidance on a local build issue?

It’s the old breathing magenta (safe mode) issue but I have followed https://github.com/spark/firmware/blob/develop/docs/build.md in detail and looked at the common issues around this (normally due to mismatch between system and app firmware versions) but no solution yet.

To keep it simple, I have checked out the latest develop branch (as I wish to test against 0.4.5 changes). Here are the steps I have taken:

Switched to develop (or latest)
Pulled latest files for develop branch
Set environment variable PARTICLE_DEVELOP=1

[dfu mode set on Photon]
cd ~/firmware/modules
make PLATFORM=photon clean all program-dfu

[dfu mode set on Photon]
cd …/main
make PLATFORM=photon APP=blank program-dfu

[Photon connects WIFI, connects to Particle, sends normal online message then I get breathing magenta]

So, if my understanding is correct, the Photon is now running the latest dev system (part1/2) and the blank app compiled with the same source version as per docs.

After the above, If I build ‘blank’ app using particle compile photon … and push the bin using dfu-util to the Photon, all works fine (i.e. does not enter safe mode after checking in to Particle Cloud).

Following may be useful:

$ arm-none-eabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-none-eabi-gcc
COLLECT_LTO_WRAPPER=/opt/crosscompiler/gcc-arm-none-eabi-4_9-2015q2/bin/…/lib/gcc/arm-none-eabi/4.9.3/lto-wrapper
Target: arm-none-eabi
Configured with: /home/build/work/GCC-4-9-build/src/gcc/configure --target=arm-none-eabi --prefix=/home/build/work/GCC-4-9-build/install-native --libexecdir=/home/build/work/GCC-4-9-build/install-native/lib --infodir=/home/build/work/GCC-4-9-build/install-native/share/doc/gcc-arm-none-eabi/info --mandir=/home/build/work/GCC-4-9-build/install-native/share/doc/gcc-arm-none-eabi/man --htmldir=/home/build/work/GCC-4-9-build/install-native/share/doc/gcc-arm-none-eabi/html --pdfdir=/home/build/work/GCC-4-9-build/install-native/share/doc/gcc-arm-none-eabi/pdf --enable-languages=c,c++ --enable-plugins --disable-decimal-float --disable-libffi --disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-libstdcxx-pch --disable-nls --disable-shared --disable-threads --disable-tls --with-gnu-as --with-gnu-ld --with-newlib --with-headers=yes --with-python-dir=share/gcc-arm-none-eabi --with-sysroot=/home/build/work/GCC-4-9-build/install-native/arm-none-eabi --build=i686-linux-gnu --host=i686-linux-gnu --with-gmp=/home/build/work/GCC-4-9-build/build-native/host-libs/usr --with-mpfr=/home/build/work/GCC-4-9-build/build-native/host-libs/usr --with-mpc=/home/build/work/GCC-4-9-build/build-native/host-libs/usr --with-isl=/home/build/work/GCC-4-9-build/build-native/host-libs/usr --with-cloog=/home/build/work/GCC-4-9-build/build-native/host-libs/usr --with-libelf=/home/build/work/GCC-4-9-build/build-native/host-libs/usr --with-host-libstdcxx=’-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm’ --with-pkgversion=‘GNU Tools for ARM Embedded Processors’ --with-multilib-list=armv6-m,armv7-m,armv7e-m,cortex-m7,armv7-r
Thread model: single
gcc version 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 224288] (GNU Tools for ARM Embedded Processors)

Output of ‘s’ command from serial port (is this documented) - this after the local compile and NOT after the cloud compile of blank:

{“p”:6,“m”:[{“s”:16384,“l”:“m”,“vc”:30,“vv”:30,“f”:“b”,“n”:“0”,“v”:4,“d”:[]},{“s”:262144,“l”:“m”,“vc”:30,“vv”:28,“f”:“s”,“n”:“1”,“v”:6,“d”:[]},{“s”:262144,“l”:“m”,“vc”:30,“vv”:28,“f”:“s”,“n”:“2”,“v”:6,“d”:[{“f”:“s”,“n”:“1”,“v”:6,"":""}]},{“s”:131072,“l”:“m”,“vc”:30,“vv”:28,“u”:“EA5B50955411ED8A0231EBF467D3BF28909D8EDE1F5EDFE94E17478A74395128”,“f”:“u”,“n”:“1”,“v”:3,“d”:[{“f”:“s”,“n”:“2”,“v”:6,"":""}]},{“s”:131072,“l”:“f”,“vc”:30,“vv”:30,“u”:“FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF”,“f”:“u”,“n”:“1”,“v”:3,“d”:[{“f”:“s”,“n”:“2”,“v”:5,"_":""}]}]}

That FFFFF… looks a bit suspicious I have to say :wink:
Oh, this is on Debian 7, not Ubuntu.
If you need anything else regarding environment please shout.

Many thanks

The build uses crc32 to compute checksums for the binary images. If the checksum isn’t valid then the system will not accept the image. So please check the build output and verify that is working.

The module format is documented here - https://github.com/spark/firmware/wiki/Module-descriptor-format.
The key is the vc (values checked) and vv (values verified). The verified flag 2 is not set. (28 instead of 30). Flag 2 is integrity check - so the crc isn’t correct, or hasn’t been correctly written to the file.

I hope that helps! :smile:

Thanks @mdma on the crc info and module descriptor format (extremely useful and sensible). Based on my original ‘s’ output, it looks like both system-part1, 2 and user image failed CRC checks on the Photon. Would I be correct in assuming that the system is running anyway but the user image is not.

I have checked the tail end of the compile, linker and file preparation but I see no errors in the processing (see below of the user-part linker).

However, on closer inspection I see that the checksum generated by arm-none-eabi-objcopy > *.pre_crc files ends in 7856 3412 which you mentioned in thread Photon and syncTime saying that the CRC has not been generated properly (presumably by …objcopy)

By the looks of things, my Debian install has the required crc32, shasum and stat all working. Any further thoughts. If you feel this is a Debian issue, I am happy to build the recommended Ubuntu box if really needed but AFAICS, this should compile fine on Debian.

Side issue: I am not sure of the purpose of the ‘test’ command in the Create Flash Image section as it’s presumably testing for a bad ‘magic checksum number’ but the results of the test do not appear to be used to raise an error if the test fails, perhaps leading to my situation.

Thanks
Gary

Building target: …/…/…/build/target/user-part/platform-6-m/user-part.elf
Invoking: ARM GCC C++ Linker
mkdir -p …/…/…/build/target/user-part/platform-6-m/
arm-none-eabi-g++ -DSTM32_DEVICE -DSTM32F2XX -DPLATFORM_THREADING=1 -DPLATFORM_ID=6 -DPLATFORM_NAME=photon -DUSBD_VID_SPARK=0x2B04 -DUSBD_PID_DFU=0xD006 -DUSBD_PID_CDC=0xC006 -DINCLUDE_PLATFORM=1 -fno-builtin -DUSE_STDPERIPH_DRIVER -DDFU_BUILD_ENABLE -DSYSTEM_VERSION_STRING=0.4.5-rc.2 -DRELEASE_BUILD -Werror -I./inc -I…/…/…/user/inc -I…/…/…/dynalib/inc -I…/…/…/services/inc -I…/…/…/hal/inc -I…/…/…/hal/shared -I…/…/…/hal/src/photon -I…/…/…/hal/src/stm32f2xx -I…/…/…/hal/src/stm32 -I…/…/…/hal/src/photon/api -I…/…/…/system/inc -I…/…/…/rt-dynalib/inc -I…/…/…/wiring/inc -I…/…/…/modules/photon/system-part1/inc -I…/…/…/platform/shared/inc -I…/…/…/platform/MCU/STM32F2xx/CMSIS/Include -I…/…/…/platform/MCU/STM32F2xx/CMSIS/Device/ST/Include -I…/…/…/platform/MCU/STM32F2xx/SPARK_Firmware_Driver/inc -I…/…/…/platform/MCU/shared/STM32/inc -I…/…/…/platform/MCU/STM32F2xx/STM32_StdPeriph_Driver/inc -I…/…/…/platform/MCU/STM32F2xx/STM32_USB_Device_Driver/inc -I…/…/…/platform/MCU/STM32F2xx/STM32_USB_Host_Driver/inc -I…/…/…/platform/MCU/STM32F2xx/STM32_USB_OTG_Driver/inc -I. -MD -MP -MF …/…/…/build/target/user-part/platform-6-m/user-part.elf.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 -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc -DUSER_FIRMWARE_IMAGE_SIZE=0x20000 -DUSER_FIRMWARE_IMAGE_LOCATION=0x80A0000 -DMODULAR_FIRMWARE=1 -DMODULE_VERSION=3 -DMODULE_FUNCTION=5 -DMODULE_INDEX=1 -DMODULE_DEPENDENCY=4,2,6 -g3 -gdwarf-2 -Os -mcpu=cortex-m3 -mthumb …/…/…/build/target/user-part/platform-6-m/src/module_info.o …/…/…/build/target/user-part/platform-6-m/src/user_export.o …/…/…/build/target/user-part/platform-6-m/src/user_module.o …/…/…/build/target/user-part/platform-6-m/src/newlib_stubs.o --output …/…/…/build/target/user-part/platform-6-m/user-part.elf -Wl,–whole-archive …/…/…/hal/src/photon/lib/STM32F2xx_Peripheral_Libraries.a -Wl,–no-whole-archive -L…/…/…/build/target/user/platform-6-m/src/ -L…/…/…/build/target/services-dynalib/arm/ -L…/…/…/build/target/hal-dynalib/platform-6-m/ -L…/…/…/build/target/system-dynalib/platform-6-m/ -L…/…/…/build/target/rt-dynalib/platform-6-m/ -L…/…/…/build/target/wiring/platform-6-m/ -L…/…/…/build/target/communication-dynalib/platform-6-m/ -L…/…/…/build/target/platform/platform-6-m/ -L…/…/…/hal/src/photon/lib/ -Wl,–whole-archive -luser -lhal-dynalib -lservices-dynalib -lsystem-dynalib -lrt-dynalib -lwiring -lcommunication-dynalib -lplatform -Wl,–no-whole-archive -L…/…/…/build/arm/linker -lnosys -L…/…/…/modules/photon/system-part2 -L…/…/…/modules/photon/system-part1 -L. -T./linker.ld -Wl,–defsym,USER_FIRMWARE_IMAGE_SIZE=0x20000 -Wl,–defsym,USER_FIRMWARE_IMAGE_LOCATION=0x80A0000 -Wl,-Map,…/…/…/build/target/user-part/platform-6-m/user-part.map -lstdc++_nano -lm -Wl,–start-group -lgcc -lg_nano -lc_nano -Wl,–end-group -Wl,–start-group -lgcc -lc_nano -Wl,–end-group -nostartfiles -Xlinker --gc-sections

Invoking: ARM GNU Create Flash Image
arm-none-eabi-objcopy -O binary …/…/…/build/target/user-part/platform-6-m/user-part.elf …/…/…/build/target/user-part/platform-6-m/user-part.bin.pre_crc
if [ -s …/…/…/build/target/user-part/platform-6-m/user-part.bin.pre_crc ]; then
head -c $((stat -c %s ../../../build/target/user-part/platform-6-m/user-part.bin.pre_crc - 38)) …/…/…/build/target/user-part/platform-6-m/user-part.bin.pre_crc > …/…/…/build/target/user-part/platform-6-m/user-part.bin.no_crc &&
tail -c 38 …/…/…/build/target/user-part/platform-6-m/user-part.bin.pre_crc > …/…/…/build/target/user-part/platform-6-m/user-part.bin.crc_block &&
test “0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20280078563412” = xxd -p -c 500 ../../../build/target/user-part/platform-6-m/user-part.bin.crc_block &&
shasum -a 256 …/…/…/build/target/user-part/platform-6-m/user-part.bin.no_crc | cut -c 1-65 | xxd -r -p | dd bs=1 of=…/…/…/build/target/user-part/platform-6-m/user-part.bin.pre_crc seek=$((stat -c %s ../../../build/target/user-part/platform-6-m/user-part.bin.pre_crc - 38)) conv=notrunc &&
head -c $((stat -c %s ../../../build/target/user-part/platform-6-m/user-part.bin.pre_crc - 4)) …/…/…/build/target/user-part/platform-6-m/user-part.bin.pre_crc > …/…/…/build/target/user-part/platform-6-m/user-part.bin.no_crc &&
crc32 …/…/…/build/target/user-part/platform-6-m/user-part.bin.no_crc | cut -c 1-10 | xxd -r -p | dd bs=1 of=…/…/…/build/target/user-part/platform-6-m/user-part.bin.pre_crc seek=$((stat -c %s ../../../build/target/user-part/platform-6-m/user-part.bin.pre_crc - 4)) conv=notrunc ;
fi
32+0 records in
32+0 records out
32 bytes (32 B) copied, 0.0147744 s, 2.2 kB/s
5+0 records in
5+0 records out
5 bytes (5 B) copied, 0.000497399 s, 10.1 kB/s
[ ! -f …/…/…/build/target/user-part/platform-6-m/user-part.bin ] || rm …/…/…/build/target/user-part/platform-6-m/user-part.bin
mv …/…/…/build/target/user-part/platform-6-m/user-part.bin.pre_crc …/…/…/build/target/user-part/platform-6-m/user-part.bin

arm-none-eabi-objcopy -O ihex …/…/…/build/target/user-part/platform-6-m/user-part.elf …/…/…/build/target/user-part/platform-6-m/user-part.hex
arm-none-eabi-size --format=berkeley …/…/…/build/target/user-part/platform-6-m/user-part.elf
text data bss dec hex filename
4292 152 304 4748 128c …/…/…/build/target/user-part/platform-6-m/user-part.elf
arm-none-eabi-objdump -h -S …/…/…/build/target/user-part/platform-6-m/user-part.elf > …/…/…/build/target/user-part/platform-6-m/user-part.lst

What you can try is to fetch an existing binary, such as tinker from the github releases page. Then remove the last 4 bytes and compute the crc of that file. It should match the crc that was the last 4 bytes removed. My suspicion is that your crc32 is using a different algorithm, and arriving at a different crc value.

The purpose of the “test” command was to check that a crc was indeed appended and not left at the default. Here, it seems some kind of crc is added, but possibly not the right one.

1 Like

Hi @mdma,

Finally found some time to look at this issue. You were 100% correct of course - it was a simple CRC issue.
All working now, thanks for your insight.

If it helps someone else, the issue is described below:

This issue applied to Debian 7. The Debian crc32 program installed reported the CRC in a decimal format rather than hex which was not processed correctly by the make process.

For example:
DebianBox$ crc32 hello
3015617425 6 hello

UbuntuBox$ crc32 hello
363a3020

I tried to figure out a conversion between the two but failed.
In the end I found a crc32 source that gave the same format as Ubuntu, compiled it and replaced the debian crc32 with the resultant binary.
Job done :smile:

Steps:

  • Save code below as crc.c

  • Compile using
    gcc -lz -o crc32 crc.c

  • Determine which crc32 is on the path
    which crc32

  • Backup that file and replace with the new binary

    /*******************************************************************************
    crc32.c by elektron

    Compile: 
             
      # gcc -lz -o crc32 crc32.c
             
    Usage:   
      # ./crc32 -h
             
      crc32 by elektron
        crc32 [-h] file1 [fileN...]
             
             
    Notes:   
      This is a hack from someone elses code :
       http://www.linuxquestions.org/questi...hreadid=199640   
             
      Find the most current version of this application at:
           http://kremlor.net/projects/crc32
    

    *******************************************************************************/

    #include <errno.h>
    #include <stdio.h>
    #include <zlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <libgen.h>
    #include <stdlib.h>

    #define _GNU_SOURCE
    #include <getopt.h>

    int usage( char *progname )
    {
    printf( “%s by elektron\n”, progname);
    printf( " %s [-h] file1 [fileN…]\n\n", progname );
    }

    unsigned long getFileSize( char *filename )
    {
    FILE *input_file;
    unsigned long file_size;

    input_file = fopen( filename, "r" );
    if( input_file == NULL )
    { 
      printf( "Could not open %s for reading.\n", filename );
      return 0;
    }
    
    fseek( input_file, 0, SEEK_END );
    file_size = ftell( input_file );
    rewind( input_file);
    
    fclose( input_file );
    return file_size;
    

    }

    unsigned long computeCRC32( char *filename )
    {
    int input_fd;
    char *file_buffer;
    unsigned long file_size;
    unsigned long chunk_size=1024;
    unsigned long bytes_read;
    unsigned long crc=0L;

    file_size = getFileSize( filename );
    
    if( file_size == 0 )
    { 
      printf( "File size is calculated to be 0. Cannot calculate CRC\n" );
      return 0;
    }
    
    file_buffer = (char *)malloc( chunk_size );
    if( file_buffer == NULL )
    { 
      printf( "Unable to reserve enough memory for file buffer.\n" );
      return 0;
    }
    crc = crc32( 0L, Z_NULL, 0 );
    
    input_fd = open( filename, O_RDONLY );
    if( input_fd == -1 )
    { 
      printf( "Could not open %s for reading.\n", filename );
      return 0;
    }
    while( 1 ){
    
     bytes_read = read( input_fd, file_buffer, chunk_size );
    
     if (bytes_read == 0 ) {
          break;
     }
     if (bytes_read == -1 ) {
          perror("read");
          break;
     }
     
     crc = crc32( crc, file_buffer, bytes_read );
    
    }
    
    free( file_buffer );
    
    close( input_fd );
    
    return crc;
    

    }

    int main( int argc, char *argv[] )
    {
    unsigned long crc=0L;
    extern char *optarg;
    extern int optind, opterr, optopt;
    int i;

    while ( getopt( argc, argv, "h" ) != -1 ) {
    //    printf("optarg = %s, optind = %d, opterr = %d, optopt = %d\n",
    //            optarg, optind, opterr, optopt);
          if ( strncmp( argv[optind-1], "-h", 2 ) == 0 ) {
                  usage( basename(argv[0]) );
                  return 0;
          }
    }
    

    //printf(“optarg = %s, optind = %d, opterr = %d, optopt = %d, argc = %d\n”,
    // optarg, optind, opterr, optopt, argc);

    if( argc < optind+1 )
    { 
      printf( "I need at least one filename to calculate crc on\n" );
      return 1;
    }
    for ( i=optind; i<argc; i++){
      crc = computeCRC32(argv[i] );
    
      printf("%08x\n",crc );
    }
    

    }

1 Like