2024-01-31
md
A PSA About CC2531 USB Zigbee Dongles
<-Adding an Ikea Trådfri Shortcut Button in Domoticz

After a recent purchase of discontinued IKEA Trådfri shortcut buttons, I wanted to get a Zigbee coordinator on which Zigbee2MQTT could be installed. With that it should be possible to upgrade the firmware on a single Trådfri button. Since this would be done mostly out of curiosity, I wished to minimize the outlay of funds. Numerous sellers on Aliexpress are flogging "Wireless Zigbee CC2531 USB Interface Dongle Capture Packet Modules". These appear to be knockoffs of the CC2531EMK CC2531 USB Evaluation Module Kit at a bit more than a 10th of the price of the real thing. I purchased one of the cheap dongles, but it was not what was expected. So consider this post as a PSA if you are contemplating buying one of these USB dongles for any purpose other than sniffing Zigbee packets.

Table of Content

  1. Why a CC2531 Based USB Dongle
  2. Public Service Announcement about CC2531 Based USB Dongles
  3. Getting the CC2531 Coordinator Firmware
  4. Flashing the CC2531 with a Raspberry Pi, or Not
    1. Install WiringPi
    2. Connecting the Pi and the USB Stick
    3. Installing flash_cc2531 on the Pi
    4. Saving the CC2531 Factory Installed Firwmare
    5. Failure to Flash the Coordinator Firmware
  5. What's Next?

Why a CC2531 Based USB Dongle toc

USB dongles with the Texas Instruments CC2531 chip are found in the Not recommended category on Zigbee2MQTT Supported Adapters. Here is the pertinent part of that document.

Not recommended

The adapters below are well-supported but use outdated chips.

The outdated CC251 adapters are well supported since Zigbee2MQTT provides coordinator firmware, router firmware, and instructions for flashing the firmware. Note that its Buy link is a search for "cc2531" on Aliexpress.

What's more, Zigbee2MQTT offers a number of alternative firmware flashing methods which do not require a CC debugger. One of these requires a Raspberry Pi which I had. Following the instructions, I was able to read and write to the CC2531 flash memory. However I could not upload the coordinator firmware nor the router firmware. The next section explains why.

Public Service Announcement about CC2531 Based USB Dongles toc

The CC2531 system-on-chip comes in two flavours: CC2531F128 and CC2531F256. The first has 128KB of flash memory and the second, you have guessed it, comes with 256KB of flash memory. The recommended coordinator firmware is about 240KB, so it will not fit in the available flash on the CC2531F128.The problem is that most sellers of cheap CC2531 dongles do not specify the actual chip on the module. I purchased the dongle from a vendor with the following offer on AliExpress.

seller's page for CC2531 with antenna on AlixExpress

Like other sellers, there is no mention of the actual chip in the "detailed" description, but the product picture does show a CC2531F256. I have rarely done this, but I rated my purchase and reviewed the product. It's the third review as of the Jan. 29, 2024 and the only one with pictures.

Two star review

Of course that should have been "bait and switch" and not the around way other, danm lexdysia!

The ethics of showing a picture that does not correspond to the product delivered is questionable even if many vendors do that. In all probability most vendors do not have the means to take decent photographs of every product in their store, but they could be more forthcoming in their descriptions. I still gave a 2-star rating because the product was delivered relatively quickly and it does enable one to sniff Zigbee packets with the help of something like WireShark. That could be of value, if you want to do that sort of thing, but I certainly don't.

The rest of this post will describe how I attempted to flash the coordinator firmware with a Raspberry Pi 1 and managed to restore the factory installed firmware after overwriting it trying to install the coordinator firmware. And therein is the second part of this PSA: do save the factory installed firmware on the CC2531's flash memory before attempting to write anything over it.

Finding the Dongle toc

Start to follow journal messages on the desktop and then plug in the CC2531 dongle to the desktop.

michel@hp:~$ journalctl -f jan 31 12:01:48 hp kernel: usb 3-13.3: new full-speed USB device number 16 using xhci_hcd jan 31 12:01:49 hp kernel: usb 3-13.3: New USB device found, idVendor=0451, idProduct=16ae, bcdDevice=35.72 jan 31 12:01:49 hp kernel: usb 3-13.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0 jan 31 12:01:49 hp kernel: usb 3-13.3: Product: CC2531 USB Dongle jan 31 12:01:49 hp kernel: usb 3-13.3: Manufacturer: Texas Instruments jan 31 12:01:49 hp mtp-probe[69211]: checking bus 3, device 16: "/sys/devices/pci0000:00/0000:00:14.0/usb3/3-13/3-13.3" jan 31 12:01:49 hp mtp-probe[69211]: bus: 3, device: 16 was not an MTP device jan 31 12:01:49 hp mtp-probe[69213]: checking bus 3, device 16: "/sys/devices/pci0000:00/0000:00:14.0/usb3/3-13/3-13.3" jan 31 12:01:49 hp mtp-probe[69213]: bus: 3, device: 16 was not an MTP device ...

The dongle is enumerated as a USB device. Here is detailed information about it

michel@hp:~$ sudo lsusb -v -d 0451: Bus 003 Device 016: ID 0451:16ae Texas Instruments, Inc. CC2531 Dongle Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 32 idVendor 0x0451 Texas Instruments, Inc. idProduct 0x16ae CC2531 Dongle bcdDevice 35.72 iManufacturer 1 Texas Instruments iProduct 2 CC2531 USB Dongle iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0019 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0x80 (Bus Powered) MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 5 Device Status: 0x0000 (Bus Powered)

On DEVICE HUNT 0451:16AE is identified as a Texas Instruments CC2531 Dongle, while 0451:16A8 is identified as a Texas Instruments CC2531 ZigBee. From elsewhere I did find that the two variants are out there.

# lsusb Bus 001 Device 004: ID 0451:16a8 Texas Instruments, Inc. CC2531 ZigBee

In any case, the dongle is visible although it does not show up as a Linux serial device. Specific driver software is needed to talk to it.

Getting the CC2531 Firmware toc

No matter which method is used to program the CC2531, the desired firmware has to be obtained. There are three different types of firmware that can be uploaded to the dongle depending on what it needs to do.

Koen Kanters, the founder of Zigbee2MQTT, makes available quite a few versions of the software for various chips. He also published the following guide when it comes to a choice of coordinator firmware for the CC2531.

I'm using a CC2530 or CC2531, which firmware should I use? This depends:
  1. Zigbee 3.0 firmwares are not recommended for the CC2530 and CC2531 (since those are not powerful enough)
  2. If you have a network of 1 - 15 devices, the Z-Stack_Home_1.2 default firmware is recommended.
  3. If you have a network of 15+ devices, the Z-Stack_Home_1.2 source routing firmware is recommended.
  4. Note that the source routing firmware only supports 5 direct children, therefore you need to have routers in range of the coordinator.

In my case the choice is simple. I will download the Z-Stack_Home_1.2 default firmware for the CC2531 to the Raspberry Pi.

zigpi@zigpi:~ $ wget https://github.com/Koenkk/Z-Stack-firmware/raw/master/coordinator/Z-Stack_Home_1.2/bin/default/CC2531_DEFAULT_20211115.zip --2024-01-31 00:35:09-- https://github.com/Koenkk/Z-Stack-firmware/raw/master/coordinator/Z-Stack_Home_1.2/bin/default/CC2531_DEFAULT_20211115.zip Resolving github.com (github.com)... 140.82.113.3 Connecting to github.com (github.com)|140.82.113.3|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://raw.githubusercontent.com/Koenkk/Z-Stack-firmware/master/coordinator/Z-Stack_Home_1.2/bin/default/CC2531_DEFAULT_20211115.zip [following] --2024-01-31 00:35:10-- https://raw.githubusercontent.com/Koenkk/Z-Stack-firmware/master/coordinator/Z-Stack_Home_1.2/bin/default/CC2531_DEFAULT_20211115.zip Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ... Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 332844 (325K) [application/zip] Saving to: ‘CC2531_DEFAULT_20211115.zip’ CC2531_DEFAULT_20211115.zip 100%[===========================================>] 325.04K --.-KB/s in 0.1s 2024-01-31 00:35:10 (2.60 MB/s) - ‘CC2531_DEFAULT_20211115.zip’ saved [332844/332844]

Only the Intel Hex file within the archive is needed.

zigpi@zigpi:~ $ unzip -l CC2531_DEFAULT_20211115.zip Archive: CC2531_DEFAULT_20211115.zip Length Date Time Name --------- ---------- ----- ---- 697099 2021-11-15 17:47 CC2531ZNP-Prod.hex 239616 2021-11-15 17:48 CC2531ZNP-Prod.bin -------- ------- 936715 2 files

Right there, looking at the size of the binary file, I should have realized I was in trouble, but I did not know that the flash memory of the CC2531 was limited to 131072 bytes. So let's continue to see what happened anyway.

zigpi@zigpi:~ $ unzip CC2531_DEFAULT_20211115.zip CC2531ZNP-Prod.hex Archive: CC2531_DEFAULT_20211115.zip inflating: CC2531ZNP-Prod.hex

The hex file has now been extracted.

Flashing with a Raspberry Pi toc

The first method proposed by Zigbee2MQTT in Alternative firmware flashing methods uses a Raspberry Pi. Having an old Raspberry Pi 1 on hand, I decided to try that method. Basically, the Zigbee2MQTT instructions amount to "use flash_cc2531" by Jean Michault.

Install WiringPi on the Raspberry Pi toc

Unfortunately, flash_cc2531 uses WiringPi to access the GPIO pins of the Raspberry Pi. It's unfortunate because that library is no longer included in the Raspberry Pi OS repository.

zigpi@zigpi:~ $ apt-cache policy wiringpi wiringpi: Installed: (none) Candidate: (none) Version table:

The author of WiringPi, Gordon, announced the end of public releases in August 2019. There is an unofficial fork on GitHub which was archived at the end of November 2023 because "this project is going nowhere. It has been archived to more clearly indicate this status". By the end of 2023, Gordon closed his site. At this point, I know of only one way to install the library, which is to build it from the last available source from the unofficial fork. Let's start by getting the source code and extracting it from the downloaded archive.

zigpi@zigpi:~ $ wget https://github.com/WiringPi/WiringPi/archive/master.zip --2024-01-27 22:09:39-- http://wget/ Resolving wget (wget)... failed: Name or service not known. wget: unable to resolve host address ‘wget’ --2024-01-27 22:09:39-- https://github.com/WiringPi/WiringPi/archive/master.zip Resolving github.com (github.com)... 140.82.114.4 Connecting to github.com (github.com)|140.82.114.4|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://codeload.github.com/WiringPi/WiringPi/zip/refs/heads/master [following] --2024-01-27 22:09:40-- https://codeload.github.com/WiringPi/WiringPi/zip/refs/heads/master Resolving codeload.github.com (codeload.github.com)... 140.82.112.10 Connecting to codeload.github.com (codeload.github.com)|140.82.112.10|:443... connected. HTTP request sent, awaiting response... 200 OK Length: unspecified [application/zip] Saving to: ‘master.zip’ master.zip [ <=> ] 279.84K 1.28MB/s in 0.2s 2024-01-27 22:09:41 (1.28 MB/s) - ‘master.zip’ saved [286554] FINISHED --2024-01-27 22:09:41-- Total wall clock time: 1.3s Downloaded: 1 files, 280K in 0.2s (1.28 MB/s) zigpi@zigpi:~ $ unzip master.zip Archive: master.zip 91284c42759d3268b09c185ba1d176d54ff59eea creating: WiringPi-master/ creating: WiringPi-master/.github/ creating: WiringPi-master/.github/workflows/ inflating: WiringPi-master/.github/workflows/build.yml inflating: WiringPi-master/.gitignore inflating: WiringPi-master/COPYING.LESSER inflating: WiringPi-master/INSTALL inflating: WiringPi-master/People inflating: WiringPi-master/README.md extracting: WiringPi-master/VERSION inflating: WiringPi-master/build creating: WiringPi-master/debian-template/ creating: WiringPi-master/debian-template/wiringPi/ creating: WiringPi-master/debian-template/wiringPi/DEBIAN/ inflating: WiringPi-master/debian-template/wiringPi/DEBIAN/control inflating: WiringPi-master/debian-template/wiringPi/DEBIAN/postinst inflating: WiringPi-master/debian-template/wiringPi/DEBIAN/postrm creating: WiringPi-master/debian/ inflating: WiringPi-master/debian/.gitignore inflating: WiringPi-master/debian/changelog extracting: WiringPi-master/debian/compat inflating: WiringPi-master/debian/control inflating: WiringPi-master/debian/copyright extracting: WiringPi-master/debian/libwiringpi-dev.dirs inflating: WiringPi-master/debian/libwiringpi-dev.install inflating: WiringPi-master/debian/libwiringpi2.install inflating: WiringPi-master/debian/libwiringpi2.shlibs inflating: WiringPi-master/debian/rules extracting: WiringPi-master/debian/wiringpi.dirs inflating: WiringPi-master/debian/wiringpi.install creating: WiringPi-master/devLib/ inflating: WiringPi-master/devLib/Makefile inflating: WiringPi-master/devLib/ds1302.c inflating: WiringPi-master/devLib/ds1302.h inflating: WiringPi-master/devLib/font.h inflating: WiringPi-master/devLib/gertboard.c inflating: WiringPi-master/devLib/gertboard.h inflating: WiringPi-master/devLib/lcd.c inflating: WiringPi-master/devLib/lcd.h inflating: WiringPi-master/devLib/lcd128x64.c inflating: WiringPi-master/devLib/lcd128x64.h inflating: WiringPi-master/devLib/maxdetect.c inflating: WiringPi-master/devLib/maxdetect.h inflating: WiringPi-master/devLib/piFace.c inflating: WiringPi-master/devLib/piFace.h inflating: WiringPi-master/devLib/piFaceOld.c inflating: WiringPi-master/devLib/piGlow.c inflating: WiringPi-master/devLib/piGlow.h inflating: WiringPi-master/devLib/piNes.c inflating: WiringPi-master/devLib/piNes.h inflating: WiringPi-master/devLib/scrollPhat.c inflating: WiringPi-master/devLib/scrollPhat.h inflating: WiringPi-master/devLib/scrollPhatFont.h creating: WiringPi-master/examples/ inflating: WiringPi-master/examples/COPYING.LESSER creating: WiringPi-master/examples/Gertboard/ inflating: WiringPi-master/examples/Gertboard/7segments.c inflating: WiringPi-master/examples/Gertboard/Makefile inflating: WiringPi-master/examples/Gertboard/buttons.c inflating: WiringPi-master/examples/Gertboard/gertboard.c inflating: WiringPi-master/examples/Gertboard/record.c inflating: WiringPi-master/examples/Gertboard/temperature.c inflating: WiringPi-master/examples/Gertboard/voltmeter.c inflating: WiringPi-master/examples/Gertboard/vumeter.c inflating: WiringPi-master/examples/Makefile creating: WiringPi-master/examples/PiFace/ inflating: WiringPi-master/examples/PiFace/Makefile inflating: WiringPi-master/examples/PiFace/blink.c inflating: WiringPi-master/examples/PiFace/buttons.c inflating: WiringPi-master/examples/PiFace/ladder.c inflating: WiringPi-master/examples/PiFace/metro.c inflating: WiringPi-master/examples/PiFace/motor.c inflating: WiringPi-master/examples/PiFace/reaction.c creating: WiringPi-master/examples/PiGlow/ inflating: WiringPi-master/examples/PiGlow/Makefile inflating: WiringPi-master/examples/PiGlow/piGlow0.c inflating: WiringPi-master/examples/PiGlow/piGlow1.c inflating: WiringPi-master/examples/PiGlow/piglow.c inflating: WiringPi-master/examples/README.TXT inflating: WiringPi-master/examples/blink-thread.c inflating: WiringPi-master/examples/blink.c inflating: WiringPi-master/examples/blink.rtb inflating: WiringPi-master/examples/blink.sh inflating: WiringPi-master/examples/blink12.c inflating: WiringPi-master/examples/blink12drcs.c inflating: WiringPi-master/examples/blink6drcs.c inflating: WiringPi-master/examples/blink8-drcn.c inflating: WiringPi-master/examples/blink8.c inflating: WiringPi-master/examples/clock.c inflating: WiringPi-master/examples/delayTest.c inflating: WiringPi-master/examples/ds1302.c inflating: WiringPi-master/examples/header.h inflating: WiringPi-master/examples/isr-osc.c inflating: WiringPi-master/examples/isr.c inflating: WiringPi-master/examples/lcd-adafruit.c inflating: WiringPi-master/examples/lcd.c inflating: WiringPi-master/examples/lowPower.c inflating: WiringPi-master/examples/max31855.c inflating: WiringPi-master/examples/nes.c inflating: WiringPi-master/examples/okLed.c inflating: WiringPi-master/examples/pwm.c creating: WiringPi-master/examples/q2w/ inflating: WiringPi-master/examples/q2w/Makefile inflating: WiringPi-master/examples/q2w/binary.c inflating: WiringPi-master/examples/q2w/blink-io.c inflating: WiringPi-master/examples/q2w/blink.c inflating: WiringPi-master/examples/q2w/blink.sh inflating: WiringPi-master/examples/q2w/bright.c inflating: WiringPi-master/examples/q2w/button.c inflating: WiringPi-master/examples/q2w/volts.c inflating: WiringPi-master/examples/rht03.c creating: WiringPi-master/examples/scrollPhat/ inflating: WiringPi-master/examples/scrollPhat/Makefile inflating: WiringPi-master/examples/scrollPhat/scphat.c inflating: WiringPi-master/examples/scrollPhat/test.c inflating: WiringPi-master/examples/serialRead.c inflating: WiringPi-master/examples/serialTest.c inflating: WiringPi-master/examples/servo.c inflating: WiringPi-master/examples/softPwm.c inflating: WiringPi-master/examples/softTone.c inflating: WiringPi-master/examples/speed.c inflating: WiringPi-master/examples/spiSpeed.c inflating: WiringPi-master/examples/wfi.c creating: WiringPi-master/gpio/ inflating: WiringPi-master/gpio/COPYING.LESSER inflating: WiringPi-master/gpio/Makefile inflating: WiringPi-master/gpio/gpio.1 inflating: WiringPi-master/gpio/gpio.c inflating: WiringPi-master/gpio/pintest inflating: WiringPi-master/gpio/readall.c inflating: WiringPi-master/gpio/test.sh inflating: WiringPi-master/newVersion creating: WiringPi-master/pins/ inflating: WiringPi-master/pins/Makefile inflating: WiringPi-master/pins/pins.pdf inflating: WiringPi-master/pins/pins.tex inflating: WiringPi-master/update inflating: WiringPi-master/version.h creating: WiringPi-master/wiringPi/ inflating: WiringPi-master/wiringPi/COPYING.LESSER inflating: WiringPi-master/wiringPi/Makefile inflating: WiringPi-master/wiringPi/ads1115.c inflating: WiringPi-master/wiringPi/ads1115.h inflating: WiringPi-master/wiringPi/bmp180.c inflating: WiringPi-master/wiringPi/bmp180.h inflating: WiringPi-master/wiringPi/drcNet.c inflating: WiringPi-master/wiringPi/drcNet.h inflating: WiringPi-master/wiringPi/drcSerial.c inflating: WiringPi-master/wiringPi/drcSerial.h inflating: WiringPi-master/wiringPi/ds18b20.c inflating: WiringPi-master/wiringPi/ds18b20.h inflating: WiringPi-master/wiringPi/htu21d.c inflating: WiringPi-master/wiringPi/htu21d.h inflating: WiringPi-master/wiringPi/max31855.c inflating: WiringPi-master/wiringPi/max31855.h inflating: WiringPi-master/wiringPi/max5322.c inflating: WiringPi-master/wiringPi/max5322.h inflating: WiringPi-master/wiringPi/mcp23008.c inflating: WiringPi-master/wiringPi/mcp23008.h inflating: WiringPi-master/wiringPi/mcp23016.c inflating: WiringPi-master/wiringPi/mcp23016.h inflating: WiringPi-master/wiringPi/mcp23016reg.h inflating: WiringPi-master/wiringPi/mcp23017.c inflating: WiringPi-master/wiringPi/mcp23017.h inflating: WiringPi-master/wiringPi/mcp23s08.c inflating: WiringPi-master/wiringPi/mcp23s08.h inflating: WiringPi-master/wiringPi/mcp23s17.c inflating: WiringPi-master/wiringPi/mcp23s17.h inflating: WiringPi-master/wiringPi/mcp23x08.h inflating: WiringPi-master/wiringPi/mcp23x0817.h inflating: WiringPi-master/wiringPi/mcp3002.c inflating: WiringPi-master/wiringPi/mcp3002.h inflating: WiringPi-master/wiringPi/mcp3004.c inflating: WiringPi-master/wiringPi/mcp3004.h inflating: WiringPi-master/wiringPi/mcp3422.c inflating: WiringPi-master/wiringPi/mcp3422.h inflating: WiringPi-master/wiringPi/mcp4802.c inflating: WiringPi-master/wiringPi/mcp4802.h inflating: WiringPi-master/wiringPi/noMoreStatic inflating: WiringPi-master/wiringPi/pcf8574.c inflating: WiringPi-master/wiringPi/pcf8574.h inflating: WiringPi-master/wiringPi/pcf8591.c inflating: WiringPi-master/wiringPi/pcf8591.h inflating: WiringPi-master/wiringPi/piHiPri.c inflating: WiringPi-master/wiringPi/piThread.c inflating: WiringPi-master/wiringPi/pseudoPins.c inflating: WiringPi-master/wiringPi/pseudoPins.h inflating: WiringPi-master/wiringPi/rht03.c inflating: WiringPi-master/wiringPi/rht03.h inflating: WiringPi-master/wiringPi/sn3218.c inflating: WiringPi-master/wiringPi/sn3218.h inflating: WiringPi-master/wiringPi/softPwm.c inflating: WiringPi-master/wiringPi/softPwm.h inflating: WiringPi-master/wiringPi/softServo.c inflating: WiringPi-master/wiringPi/softServo.h inflating: WiringPi-master/wiringPi/softTone.c inflating: WiringPi-master/wiringPi/softTone.h inflating: WiringPi-master/wiringPi/sr595.c inflating: WiringPi-master/wiringPi/sr595.h inflating: WiringPi-master/wiringPi/wiringPi.c inflating: WiringPi-master/wiringPi/wiringPi.h inflating: WiringPi-master/wiringPi/wiringPiI2C.c inflating: WiringPi-master/wiringPi/wiringPiI2C.h inflating: WiringPi-master/wiringPi/wiringPiSPI.c inflating: WiringPi-master/wiringPi/wiringPiSPI.h inflating: WiringPi-master/wiringPi/wiringSerial.c inflating: WiringPi-master/wiringPi/wiringSerial.h inflating: WiringPi-master/wiringPi/wiringShift.c inflating: WiringPi-master/wiringPi/wiringShift.h inflating: WiringPi-master/wiringPi/wpiExtensions.c inflating: WiringPi-master/wiringPi/wpiExtensions.h creating: WiringPi-master/wiringPiD/ inflating: WiringPi-master/wiringPiD/Makefile inflating: WiringPi-master/wiringPiD/daemonise.c inflating: WiringPi-master/wiringPiD/daemonise.h inflating: WiringPi-master/wiringPiD/drcNetCmd.h inflating: WiringPi-master/wiringPiD/network.c inflating: WiringPi-master/wiringPiD/network.h inflating: WiringPi-master/wiringPiD/runRemote.c inflating: WiringPi-master/wiringPiD/runRemote.h inflating: WiringPi-master/wiringPiD/wiringpid.c

Compiling and installing the library is easily done.

zigpi@zigpi:~/WiringPi-master $./build wiringPi Build script ===================== WiringPi Library [UnInstall] [Compile] wiringSerial.c [Compile] wiringShift.c [Compile] piHiPri.c [Compile] wiringPi.c [Compile] piThread.c [Compile] wiringPiSPI.c [Compile] wiringPiI2C.c [Compile] softPwm.c [Compile] softTone.c [Compile] mcp23008.c [Compile] mcp23016.c [Compile] mcp23017.c [Compile] mcp23s08.c [Compile] mcp23s17.c [Compile] sr595.c [Compile] pcf8574.c [Compile] pcf8591.c [Compile] mcp3002.c [Compile] mcp3004.c [Compile] mcp4802.c [Compile] mcp3422.c [Compile] max31855.c [Compile] max5322.c [Compile] ads1115.c [Compile] sn3218.c [Compile] bmp180.c [Compile] htu21d.c [Compile] ds18b20.c [Compile] rht03.c [Compile] drcSerial.c [Compile] drcNet.c [Compile] pseudoPins.c [Compile] wpiExtensions.c [Link (Dynamic)] [Install Headers] [Install Dynamic Lib] WiringPi Devices Library [UnInstall] [Compile] ds1302.c [Compile] maxdetect.c [Compile] piNes.c [Compile] piFace.c [Compile] gertboard.c [Compile] lcd128x64.c [Compile] lcd.c [Compile] scrollPhat.c [Compile] piGlow.c [Link (Dynamic)] [Install Headers] [Install Dynamic Lib] GPIO Utility [Compile] gpio.c [Compile] readall.c [Link] [Install] chown: warning: '.' should be ':': ‘root.root’ All Done. NOTE: To compile programs with wiringPi, you need to add: -lwiringPi to your compile line(s) To use the Gertboard, MaxDetect, etc. code (the devLib), you need to also add: -lwiringPiDev to your compile line(s).

We can test that the library is installed.

zigpi@zigpi:~ $ gpio readall +-----+-----+---------+------+---+-Model B1-+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+ | | | 3.3v | | | 1 || 2 | | | 5v | | | | 2 | 8 | SDA.1 | IN | 1 | 3 || 4 | | | 5v | | | | 3 | 9 | SCL.1 | IN | 1 | 5 || 6 | | | 0v | | | | 4 | 7 | GPIO. 7 | IN | 1 | 7 || 8 | 1 | ALT0 | TxD | 15 | 14 | | | | 0v | | | 9 || 10 | 1 | ALT0 | RxD | 16 | 15 | | 17 | 0 | GPIO. 0 | IN | 0 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 | | 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | | | 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 0 | IN | GPIO. 4 | 4 | 23 | | | | 3.3v | | | 17 || 18 | 0 | IN | GPIO. 5 | 5 | 24 | | 10 | 12 | MOSI | IN | 0 | 19 || 20 | | | 0v | | | | 9 | 13 | MISO | IN | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 | | 11 | 14 | SCLK | IN | 0 | 23 || 24 | 1 | IN | CE0 | 10 | 8 | | | | 0v | | | 25 || 26 | 1 | IN | CE1 | 11 | 7 | +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+---------+------+---+-Model B1-+---+------+---------+-----+-----+

Remember, I am using a Raspbery Pi 1 with a GPIO header containing only 26 pins. The newer models have a 40-pin GPIO connector. Now that WiringPi is installed, it was time to clean up. By that I mean to keep the source archive in a downloads directory and to delete everything created just for building the library which was installed in /usr/local/lib and usr/local/include.

zigpi@zigpi:~ $ mkdir downloads zigpi@zigpi:~ $ mv master.zip downloads/WiringPi.zip zigpi@zigpi:~ $ rm -r WiringPi-master/

Connecting the Pi and the USB Stick toc

USB stick pinout The following table displays the flash_cc2531 default connection between the Raspberry Pi's with 40 pin headers and the Pi and the CC2531 dongle debug header and the suggested connection between older Pi's with a 26-pin header and the debug header of the dongle.

Raspberry PiCC2531 Dongle
40 pin Header26-pin HeaderDebug
PIN 39 GND Pin 9 GND GDN
Pin 38 GPIO 20wPi 28Pin 13GPIO 27wPi 2DD
Pin 36 GPIO 16wPi 27Pin 11GPIO 17wPi 0DC
Pin 35 GPIO 15wPi 24Pin 3 GPIO 2 wPi 8RESETn
Pin 17 3v3 Pin 173v3 VCC*

(*) The dongle needs to be powered while it is being flashed. The easiest way to do this is to connect the dongle to a USB 5V power source. I used a free USB port on the desktop machine, but perhaps a USB port on the Pi would also work. I have read on the Web where some have used the connection shown above in the table to feed 3.3 volts to the dongle via the debug connector. Presumably, that means that a required "R2" resistor is mounted on the dongle. See page 11 of CC2531 USB Hardware User’s Guide.

The biggest problem with making these connections is the small size of the debug header. As far as I can tell, pins are 1.27 mm apart instead of the 2.54 mm breadboard standard. A special cable can be purchased (see the AliExpress vendors that sell the dongle), but I did not want to wait for that. Some solder Dupont wires directly to the header pins often bending these outward at different angles for better access. I happened to have a flat ribbon cable of the correct size with female IDC connectors at both ends purchased for use with an unusual sensor. I jury rigged the following with it.

Connection to dongle headerDupont test clip

Solid copper strands from CAT5 Ethernet cable fit perfectly into the IDC sockets. Four short lengths of that wire were inserted into the IDC connector. Very flexible silicone Dupont test clips completed the connections to the correct pins on the Raspberry Pi. It may not look very solid, but it nevertheless worked for numerous attempts at programming the dongle. Note how the pin layout of the free IDC connector is mirrored because the ribbon cable was bent back onto itself. Be careful when connecting the wires. You may want to measure continuity between the metal casing of the USB connectors of the Pi and the dongle with a VOM. Make sure nothing is powered when checking this.

 

Installing flash_cc2531 on the Pi toc

Jean Michault has written a collection of programs that can be used to read and write the flash memory of the CC231 connected with a simple USB cable to a Linux computer such as the Raspberry Pi. We only need to download the repository.

zigpi@zigpi:~ $ https://github.com/jmichault/flash_cc2531/archive/master.zip --2024-01-28 01:13:44-- https://github.com/jmichault/flash_cc2531/archive/master.zip Resolving github.com (github.com)... 140.82.114.3 Connecting to github.com (github.com)|140.82.114.3|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://codeload.github.com/jmichault/flash_cc2531/zip/refs/heads/master [following] --2024-01-28 01:13:45-- https://codeload.github.com/jmichault/flash_cc2531/zip/refs/heads/master Resolving codeload.github.com (codeload.github.com)... 140.82.112.10 Connecting to codeload.github.com (codeload.github.com)|140.82.112.10|:443... connected. HTTP request sent, awaiting response... 200 OK Length: unspecified [application/zip] Saving to: ‘master.zip’ master.zip [ <=> ] 72.32K --.-KB/s in 0.08s 2024-01-28 01:13:45 (942 KB/s) - ‘master.zip’ saved [74060]

Let's extract the content of the archive which will create a directory named flash_cc253-master by default.

zigpi@zigpi:~ $ unzip master.zip Archive: master.zip 005054e5ff062128591e2a68b9977ab38856e807 creating: flash_cc2531-master/ creating: flash_cc2531-master/.github/ extracting: flash_cc2531-master/.github/FUNDING.yml inflating: flash_cc2531-master/.github/stale.yml extracting: flash_cc2531-master/.gitignore inflating: flash_cc2531-master/CCDebugger.c inflating: flash_cc2531-master/CCDebugger.h inflating: flash_cc2531-master/LICENSE inflating: flash_cc2531-master/Makefile inflating: flash_cc2531-master/README.md inflating: flash_cc2531-master/cc_chipid inflating: flash_cc2531-master/cc_chipid.c inflating: flash_cc2531-master/cc_erase inflating: flash_cc2531-master/cc_erase.c inflating: flash_cc2531-master/cc_read inflating: flash_cc2531-master/cc_read.c inflating: flash_cc2531-master/cc_write inflating: flash_cc2531-master/cc_write.c

The files cc_chipid, cc_erase, cc_read, and cc_write are all exectable, so there is no need to build anything. Again, its not a bad idea to rename the directory created by unzip and then cleanup a bit.

zigpi@zigpi:~ $ mv flash_cc2531-master flash_cc2531 zigpi@zigpi:~ $ rm -r flash_cc2531/.github zigpi@zigpi:~ $ mv master.zip downloads/flash_cc2531.zip

To quote Jean Michault, now one can read the CC2531 ID, save, erase and write its flash memory with the following commands.

./cc_chipid -r 8 -c 0 -d 2 ./cc_read -r 8 -c 0 -d 2 save.hex ./cc_erase -r 8 -c 0 -d 2 ./cc_write -r 8 -c 0 -d 2 CC2531ZNP-Prod.hex

Of course if the default wiring was used, then the wPi pin parameters should not be used and the commands would simply be as follows.

./cc_chipid ./cc_read save.hex ./cc_erase ./cc_write CC2531ZNP-Prod.hex

In preparation for the programming step, I copied the Zigbee coordinator hex file into the flash_cc2531 directory.

zigpi@zigpi:~ $ cp CC2531ZNP-Prod.hex flash_cc2531/

Saving the CC2531 Factory Installed Firmware toc

I followed the instructions give above to identify the chip and to download the installed firmware.

zigpi@zigpi:~ $ cd flash_cc2531 zigpi@zigpi:~/flash_cc2531 $ ./cc_chipid -r 8 -c 0 -d 2 ID = b522. zigpi@zigpi:~/flash_cc2531 $ ./cc_read -r 8 -c 0 -d 2 save.hex ID = b522. reading 256k/256k

And then; being paranoid, I did this a second time. After I peeked at the content of the saved hex files and checked that they were identical.

zigpi@zigpi:~/flash_cc2531 $ ./cc_chipid -r 8 -c 0 -d 2 ID = b522. zigpi@zigpi:~/flash_cc2531 $ ./cc_read -r 8 -c 0 -d 2 factory_sniffer.hex ID = b522. reading 256k/256k zigpi@zigpi:~/flash_cc2531 $ ls -l *hex -rw-r--r-- 1 zigpi zigpi 697099 Jan 29 03:47 CC2531ZNP-Prod.hex -rw-r--r-- 1 zigpi zigpi 23572 Jan 28 01:19 factory_sniffer.hex -rw-r--r-- 1 zigpi zigpi 23572 Jan 28 01:18 save.hex zigpi@zigpi:~/flash_cc2531 $ head save.hex :020000040000FA :100000000200E1020674FFFFFFFFFFFFFFFFFFFF9B :10003000FFFFFF021229FFFFFFFFFFFFFFFFFFFF90 :10004000FFFFFF021129FFFFFFFFFF020767FFFF0E :10005000FFFFFF0207C5FFFFFFFFFFFFFFFFFFFFDF :10008000FFFFFF0205D400000080FB1200F0B90062 :10009000030200DBE479217816B800028004F70936 :1000A000D8FCE4900200789B79028002F0A3D8FC8F :1000B000D9FA90039AAA82AB839000F3781F790152 :1000C0008015E493A3AC82AD838A828B83F0A3AACC zigpi@zigpi:~/flash_cc2531 $ head factory_sniffer.hex :020000040000FA :100000000200E1020674FFFFFFFFFFFFFFFFFFFF9B :10003000FFFFFF021229FFFFFFFFFFFFFFFFFFFF90 :10004000FFFFFF021129FFFFFFFFFF020767FFFF0E :10005000FFFFFF0207C5FFFFFFFFFFFFFFFFFFFFDF :10008000FFFFFF0205D400000080FB1200F0B90062 :10009000030200DBE479217816B800028004F70936 :1000A000D8FCE4900200789B79028002F0A3D8FC8F :1000B000D9FA90039AAA82AB839000F3781F790152 :1000C0008015E493A3AC82AD838A828B83F0A3AACC zigpi@zigpi:~/flash_cc2531 $ diff -s save.hex factory_sniffer.hex Files save.hex and factory_sniffer.hex are identical

Of course I was still in the dark about the real size of the flash memory. In retrospect, how could cc_read report reading 256 KB from the flash memory? The saved hex file is considerably smaller than the coordinator hex file. So it was a bit surprising to find that factory_sniffer.hex contained 4 32-bit segment addresses just like CC2531ZNP-Prod.hex.

zigpi@zigpi:~/flash_cc2531 $ grep :02 factory_sniffer.hex :020000040000FA :020000040001F9 :020000040002F8 :020000040003F7

It turns out that none of these were needed.

zigpi@zigpi:~/flash_cc2531 $ tail -10 factory_sniffer.hex :10214000007400720075006D0065006E007400730D :1021500000240343004300320035003300310020E7 :1021600000550053004200200044006F006E0067DD :10217000006C006500120330003000300030003089 :10218000003000300037000C03430045004200419E :10219000004C0019210000 FF FF FF FF FF FF FF FF FFC2 :020000040001F9 :020000040002F8 :020000040003F7 :00000001FF

Because the last 16-byte record was written at address 0x2190, the next record would be at 0x21A0 = 8,608. Since the trailing 0xFF bytes look like padding, the actual size of the binary file might be only 8,599 bytes in size. So a 128KB flash memory is big enough for the packet sniffing firmware. But again this is all in retrospect.

Failure to Flash the Coordinator Firmware toc

The device ID was unusual, b522 instead of the b524 shown in most guides. I am not too sure why that would be, but it is something I have observed with other "cloned" USB devices. In any case, it was time to upload the coordinator firmware.

zigpi@zigpi:~/flash_cc2531 $ ./cc_erase -r 8 -c 0 -d 2 ID = b522. erase result = 00a2. zigpi@zigpi:~/flash_cc2531 $ ./cc_write -r 8 -c 0 -d 2 CC2531ZNP-Prod.hex ID = 0000. reading line 15490. file loaded (15497 lines read). writing page 1/128.

That erase result was what I expected from reading others' posts. However, the session froze while writing page 1. I used CtrlC to exit. After powering the dongle off and then back on, I tried again but with a timing change.

zigpi@zigpi:~/flash_cc2531 $ ./cc_erase -r 8 -c 0 -d 2 -m 100 ID = b522. erase result = 00a2. zigpi@zigpi:~/flash_cc2531 $ ./cc_write -r 8 -c 0 -d 2 -m 100 CC2531ZNP-Prod.hex ID = b522. reading line 15490. writing page 65/128. flash error... Have you erased before write ?

This is an improvement. I tried different values for the time base parameter m, but could never get beyond page 65, even if the error message changed.

zigpi@zigpi:~/flash_cc2531 $ ./cc_write -r 8 -c 0 -d 2 -m 300 CC2531ZNP-Prod.hex ID = b522. reading line 15490. file loaded (15497 lines read). writing page 65/128.verification error... Have you erased before write ?

I started to get suspicious that precisely half of the pages had been written. Consequently, I tried writing smaller older firmware and the router firmware but I would get no further.

zigpi@zigpi:~/flash_cc2531-master $ ./cc_write -r 8 -c 0 -d 2 -m 300 router-cc2531-std.hex ID = b522. reading line 12070. file loaded (12073 lines read). writing page 65/ 95.verification error... Have you erased before write ?

CC2531 F 128 chip That's when the penny dropped. Sure enough on searching I discovered that there were two versions of the CC2531 chip one of which only has 128 KB of memory. On checking the chip on my dongle, I confirmed that this what it had. Click on the thumbnail at the right and the F 128 will be visible on the bigger image.

Just to make sure that the problem had nothing to do with the flashing software, I read back what was flashed onto the CC2531 and compared it with the original firmware saved initially.

zigpi@zigpi:~/flash_cc2531 $ ./cc_read -r 8 -c 0 -d 2 -m 300 broken.hex ID = b522. reading 50k/256k^C (stopped because 50 k is more enough to check) zigpi@zigpi:~/flash_cc2531 $ diff broken.hex factory_sniffer.hex -y :020000040000FA :020000040000FA :10000000000412000002E792AF22E4002000A3F0F7 | :100000000200E1020674FFFFFFFFFFFFFFFFFFFF9B :1000100022A312000003F0227F0C02000000F5086A | :10003000FFFFFF021229FFFFFFFFFFFFFFFFFFFF90 :10002000E4F5090000210B227401F0000020E064D7 | :10004000FFFFFF021129FFFFFFFFFF020767FFFF0E :100030000F2274000023227F040228002023E024E2 | :10005000FFFFFF0207C5FFFFFFFFFFFFFFFFFFFFDF :10004000F5C394022000058412AB8C02004B002201 | :10008000FFFFFF0205D400000080FB1200F0B90062 :10005000C082C00200130C7440F0A3000050A374CF | :10009000030200DBE479217816B800028004F70936 :1000600052F0A3000060901B10742800206046F03E | :1000A000D8FCE4900200789B79028002F0A3D8FC8F :10007000A3742200207046F0A3745E00207046F046 | :1000B000D9FA90039AAA82AB839000F3781F790152 ...

So new firmware had been written to the flash memory. The good news is that flash_cc2531 had no problem restoring the original firmware.

zigpi@zigpi:~/flash_cc2531 $ ./cc_erase -r 8 -c 0 -d 2 -m 300 ID = b522. erase result = 00a2. zigpi@zigpi:~/flash_cc2531 $ ./cc_write -r 8 -c 0 -d 2 -m 300 factory_sniffer.hex ID = b522. reading line 530. file loaded (539 lines read). writing page 5/ 5. flash OK.

What's Next? toc

What to do next? I see many possibilities right now.

Time will tell.