How To: Basic firmware update with Linux / Raspberry Pi without particle-cli

Summary:
This is a set of scripts I wrote to update P1 system software (part 1&2), bootloader, and application firmware. They can serve as an example for a method to do this without installing particle-cli tools.

I’m writing some of this stuff down because I haven’t found any material like it, and what I have is working. It should be considered pretty ‘quick and dirty’, but can serve as a decent guide to setting up end of line programming or test processes on a Raspberry Pi if you’re so inclined.

Little attempt is made at error handling here, and it relies on an attentive user watching for problems. Retry and fail sequences could be added pretty easily to the main script and the application firmware loads could easily be changed from YMODEM transfers to dfu-util commands if that floats your boat. (Note: bootloader must be written using YMODEM!)

DISCLAIMER: YMMV, use at your own risk, no warranty implied

First: Find the connected device name

  • This script is called “listp1” and only works for P1 devices.
  • It returns a list of all connected P1 devices.
  • For other device types, substitute the proper PID.

Listing:

#!/bin/bash

# Basic idea shamelessly stolen from
# https://unix.stackexchange.com/questions/144029/

# This file scans the USB system for the VID and PID of the Particle P1 module
# and returns the device path of any connected devices.

for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do
 (
   syspath="${sysdevpath%/dev}"
   devname="$(udevadm info -q name -p $syspath)"
   [[ "$devname" == "bus/"* ]] && continue
   eval "$(udevadm info -q property --export -p $syspath)"
   [[ "$ID_MODEL_ID" != "c008" && "$ID_VENDOR_ID" != "2b04" ]] && continue
   #echo "/dev/$devname - $ID_SERIAL $ID_MODEL_ID $ID_VENDOR_ID"
   echo "/dev/$devname"
  )
done

(BUG: I just noticed that this script may have a bug that accepts devices with the same PID from other vendors. Something to look out for!)

Second: Update system firmware

  • This script is called “paupdate”
  • It loads the system part 1 and part 2 firmwares to a device in DFU mode

Listing:

#!/bin/bash

# This script runs commands to update the P1 to 0.7.0 system firmware

dfu-util -d 2b04:d008 -a 0 -s 0x8020000 -D system-part1-0.7.0-p1.bin
dfu-util -d 2b04:d008 -a 0 -s 0x8060000:leave -D system-part2-0.7.0-p1.bin

Third: Put it all together

  • This program is called “paautoupdate”
  • It uses the previous scripts and @nrobinson2000 's custom_baud utility
  • Quick and dirty process to load
    • System firmware part 1 (via dfu-util)
    • System firmware part 2 (via dfu-util)
    • Bootloader firmware (via YMODEM)
    • A custom test firmware (which is then run and interacted with via cu)
      • This program starts in Listening mode and waits for a device button press.
      • This program resets the device when complete, which releases the cu session.
    • Final application firmware

Listing:

#!/bin/bash

# This program tests PupAlert Model 1 units and loads production firmware onto them.


function bailout {
  echo "Quitting: $1"
  exit
}

function find_p1 {
P1COUNT=0

for p1 in $(./listp1)
do
  P1COUNT=$((P1COUNT+1))
  #echo "Item $P1COUNT $p1"
done

[[ P1COUNT -eq 0 ]] && bailout "No devices found!"
[[ P1COUNT -gt 1 ]] && bailout "More than one device found!"

echo $p1
}

p1=$(find_p1)

# At this point there is one and only one device connected.

echo "Using $p1"

./custom-baud $p1 14400

sleep 5

./paupdate

echo "System firmware update complete"
sleep 5


p1=$(find_p1)
echo "Writing bootloader..."
echo f > $p1

sb -vv bootloader-0.7.0-p1.bin < $p1 > $p1

echo "Bootloader written!"

sleep 5

p1=$(find_p1)
# Send signal to receive firmware file
echo f > $p1

# Send firmware file 
sb -vv testfw18.bin < $p1 > $p1

echo "Waiting for reset..."
sleep 5
echo "Press power button on PupAlert to continue test."


p1=$(find_p1)
# Connect to PupAlert serial terminal for interactive test
cu -s 115200 -l $p1
sleep 5

# Need to ask user if test passed

# Test is done, write application firmware
echo "Writing application firmware..."

p1=$(find_p1)
# Send signal to receive firmware file
echo f > $p1

# Send firmware file
sb -vv beta2.bin < $p1 > $p1

H/T @ScruffR for the formatting help!

1 Like

Does this tutorial have a github repo associated with it? It think that would help.

EDIT:

I just remembered that I recently forked one of @jenschr’s projects into this.

1 Like

I will probably clean it up and add it at some point, but until then I thought this could help some people out.

listp1 can be copied whole-cloth and be quite useful, while the others mostly serve as a functioning example of two different ways to load firmware without relying on particle-cli (and npm).

They're obviously not especially helpful in this exact form!

1 Like