P1 hangs (led frozen cyan)


i have a p1 which starts up fine, it waits a while, logs some stuff and then communicates with an atmega by spi. it will read its firmware version and when it is old it will flash the atmega also through spi (like a normal programmer would do). this works fine.

the last step is checking the flashed code. this is where at some point it hangs. led frozen cyan. not always at the same point (i added lots of log.info). there are not conditional whiles or anything that can block. just plain spi reading/writing like a programmer would do

i have added delays, particle.connects - does nothing seem to have an effect. always only at the verification stage, never during programming (which is more-or-less the same)

edit: just tried to put a long 10s delay between programming and verifying: no hang!

anyone any idea how to get a frozen cyan led? something in device-os blocking… but what?



  • wifi connected before programming
  • spi is my own bit-banging using digitalWrites and delayMicroseconds
  • spi using miso = micro_spi1_miso (A4), mosi = micro_spi1_mosi (A5), clk = micro_api1_sck (A3), reset = micro-gpio5 (A1)
  • device os = 1.5.2

How come you didn’t go with HW SPI?

Without knowing the code that may cause the deadlock it’s hard to advise.

hi scruffr,

i am using the hw spi for regular p1 - atmega communication. just had this programming code lying around which does not. i might migrate… do you think it matters in this case?

is the observation that adding a “delay(10000)” between programming and verifying a clue? i looks like it is time related. just programming works fine as it is fast enough? programming and verifying takes too long for some system something? adding the delay gives device-os time to do something?

i do not mind sharing code (first attempt below) but it is spread over multiple files. seems more time related as code related? stops/hangs at different places


starting from low to hi:

// low level spi transfer
unsigned char spi_transfer(unsigned char b) {
    unsigned char i;
    for (i = 0; i < 8; ++i) {
        digitalWrite(SPI_PIN_MOSI, (b & 0x80) ? HIGH : LOW);
        digitalWrite(SPI_PIN_SCK, HIGH);
        delayMicroseconds(2 * SPI_QUARTER_CYCLE_DURATION_US);
        b = (b << 1) | digitalRead(SPI_PIN_MISO);
        digitalWrite(SPI_PIN_SCK, LOW);
    return b;

// while in reset, programmer instruction
unsigned char programmer_process_instruction_extended(unsigned short instruction, unsigned char orByte2, unsigned char orByte3, unsigned char orByte4) {
    spi_transfer(LSB(instruction) | orByte2);
    return (spi_transfer(orByte4));

// hex is pointer to hex file
unsigned char programmer_flash_hex_verify(char *hex, unsigned int length) {
    unsigned char **ptr;
    unsigned char *end_ptr;
    unsigned char block_length;
    unsigned int address;
    unsigned int address_from_hex;
    unsigned char type_from_hex;
    unsigned char cs_from_hex;
    unsigned int i;
    unsigned char high_byte, low_byte;

    ptr = (unsigned char **) (&hex);
    end_ptr = (*ptr) + length;
    Log.info("verifying %d bytes", length);
    while ((*ptr) < end_ptr) {
        if (hex_start_code(ptr)) {
            block_length = hex_get_byte(ptr);
            address_from_hex = hex_get_word(ptr);
            type_from_hex = hex_get_byte(ptr);
            address = address_from_hex >> 1;
            for (i = 0; i < block_length; i += 2) {
                low_byte = hex_get_byte(ptr);
                high_byte = hex_get_byte(ptr);
                if (type_from_hex == 0) {
                    // check                   
                    if(high_byte != programmer_process_instruction_extended(INSTRUCTION_READ_PROGRAM_MEMORY_HIGH_BYTE, MSB(address), LSB(address), 0x00)) {                      
                    if(low_byte != programmer_process_instruction_extended(INSTRUCTION_READ_PROGRAM_MEMORY_LOW_BYTE, MSB(address), LSB(address), 0x00)) {

            cs_from_hex = hex_get_byte(ptr);
        } else {
            Log.info("! wrong start code @ %x",address);
    Log.info("ALL GOOD");

Deadlocks often are and a frozen RGB LED on a Photon has a good chance to suggest a deadlock.
With HW SPI you can facilitate the DMA capabilities of the STM32 controler to keep your code (and the system) running while performing the transfer - so it might help your deadlock issue.

If you are bitbanging you may also want to use digitalWriteFast() (or even pinSetFast() & pinResetFast()) instead of digitalWrite() (and pinReadFast() instead of digitalRead()) to speed up the process and cut out some internal sanity checks that may also contribute to the issue at hand.

1 Like