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
- Why a CC2531 Based USB Dongle
- Public Service Announcement about CC2531 Based USB Dongles
- Getting the CC2531 Coordinator Firmware
- Flashing the CC2531 with a Raspberry Pi, or Not
- Install WiringPi
- Connecting the Pi and the USB Stick
- Installing flash_cc2531 on the Pi
- Saving the CC2531 Factory Installed Firwmare
- Failure to Flash the Coordinator Firmware
- What's Next?
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.
- USB connected
- Texas Instruments CC2531
USB connected Zigbee adapter with PCB antenna
Warning 1: requires additional hardware to flash (CC debugger + download cable)
Warning 2: might not be powerful enough to handle networks of 20+ devices
Warning 3: this adapter has bad range
Coordinator firmware
Router firmware
Flashing instructions
Buy
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.
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.

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.

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.
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.
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.
- Coordinator: the dongle acts like a hub. Up to xx Zigbee devices can be paired with the dongle (xx depends on the installed firmware and version). The dongle acts as a radio transceiver between paired devices and the Zigbee2MQTT service running on the computer connected to the dongle with the USB port.
- Router: the dongle act like a repeater or bridge between xx Zigbee devices and a coordinator.
- Sniffer: the dongle exposes all Zigbee packets it receives to the device connected to its USB port. The CC2531 I purchased was sold as a sniffer and had the appropriate firmware loaded in its flash memory.
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:
- Zigbee 3.0 firmwares are not recommended for the CC2530 and CC2531 (since those are not powerful enough)
- If you have a network of 1 - 15 devices, the Z-Stack_Home_1.2 default firmware is recommended.
- If you have a network of 15+ devices, the Z-Stack_Home_1.2 source routing firmware is recommended.
- 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.
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.
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/
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 Pi | CC2531 Dongle |
40 pin Header | 26-pin Header | Debug |
PIN 39 | GND | | Pin 9 | GND | | GDN |
Pin 38 | GPIO 20 | wPi 28 | Pin 13 | GPIO 27 | wPi 2 | DD |
Pin 36 | GPIO 16 | wPi 27 | Pin 11 | GPIO 17 | wPi 0 | DC |
Pin 35 | GPIO 15 | wPi 24 | Pin 3 | GPIO 2 | wPi 8 | RESETn |
Pin 17 | 3v3 | | Pin 17 | 3v3 | | 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.


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.
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/
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.
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 ?
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 to do next? I see many possibilities right now.
- Follow Mat (notenoughtech)'s advice and Get CC2531 on the ITEAD store instead. I may need to flash newer firmware on it, but that's easy enough to do. Unfortunately, that dongle does not have an external antenna which might be useful for reaching Zigbee devices that are far away.
- Go back to AliExpress and try to find a vendor willing to vouch that the dongle comes with a CC2531F256 on a revision 2.4 board.
- Purchase a CC2531F256 and solder it in place of the chip on my board. Chances of success: 1%, cost of a chip about 14 $ before shipping and taxes.
- Purchase a CC2530 serial board on Aliexpress. But this one is even worse, being available with 32, 26, 128 or 256 KB of flash memory (see its datasheet and Flash CC2530).
- Purchase an ESP32-H2 or ESP32-C6 because these Risc-V microcontrollers support Zigbee natively. At this time, I have no idea which Zigbee stack would run on these boards and if they could be used to perform OTA which was the whole idea at the start of this project.
- Wait until the Tasmotized ZBBridge in place can no longer handle additional Zigbee devices slowly being added to the system. At that point getting a decent ZigBee coordinator and one or two routers might be warranted.
Time will tell.