An async Embassy driver for the CC1101 sub-1 GHz RF transceiver, built on embedded-hal 1.0 and embedded-hal-async 1.0.
Early development — RX and TX are implemented, RSSI scanning works. Tested on RP2040 (Raspberry Pi Pico) with Ebyte E07-M1101D 433 MHz modules.
use cc1101_embassy::{Cc1101, Modulation, RadioConfig, TxPower};
let config = RadioConfig::new()
.frequency_hz(433_920_000) // 433.920 MHz EU ISM centre
.baud_rate(38_400)
.modulation(Modulation::Gfsk)
.tx_power(TxPower::Dbm0);
let mut radio = Cc1101::new(spi, gdo0, gdo2).await?;
radio.configure(&config).await?;
// Transmit
radio.transmit(b"hello").await?;
// Receive
let mut buf = [0u8; 64];
let packet = radio.receive(&mut buf).await?;
defmt::info!("rssi: {} dBm lqi: {}", packet.rssi_dbm, packet.lqi);This library has been tested with the E07-M1101D modules from Ebyte connected to a RP2040 board using SPI0 — adjust pin numbers to match your wiring.
| CC1101 pin | Pico GPIO | Notes |
|---|---|---|
| VCC | 3.3 V | 1.8–3.6 V supply |
| GND | GND | |
| CSn | GP5 | Active low — idle high |
| SCLK | GP2 | SPI0 clock |
| MOSI (SI) | GP3 | SPI0 TX |
| MISO (SO) | GP4 | SPI0 RX (shared with GDO1) |
| GDO0 | GP6 | Packet sync interrupt — required |
| GDO2 | GP7 | RX FIFO threshold — wire up, reserved for future use |
Note: Make sue you fit an appropriate antenna before testing.
The examples/rp2040/ directory contains working examples for the Raspberry Pi Pico.
If you have a new board I'd recommend starting with the rssi_scan example
which can be used to check the SPI connection and a simple wiring check. This is
RX only, so can be used with a single board.
Flash with probe-rs:
DEFMT_LOG=debug cargo run -p cc1101-embassy-rp2040-examples --bin rssi_scanIf you have a 433 MHz signal near (like an RF doorbell) by you might see the signal strength indicator change in response. If not, it might be a frequency mismatch or mode mismatch (maybe try OOK instead)? Still having trouble? I'd suggest buying or borrowing an SDR dongle which will allow you to see the signal on a waterfall; you can then visually see the frequency and sometimes work out the mode if you can get enough resolution.
I was able to get the Received Signal Strength Indicator (RSSI) to change by holding and letting go of the antenna, and moving the device around the room. While this is not picking up a meaningful signal it still shows that the SPI connection to the board is working and communication with the CC1101 has been established.
Expected output:
INFO CC1101 found OK
INFO CC1101 configured: 433.920 MHz GFSK 38.4 kbps
INFO RX active. Press your doorbell to see RSSI jump!
INFO RSSI: -103 dBm []
INFO RSSI: -101 dBm []
INFO RSSI: -68 dBm [=====] <- doorbell pressed
INFO RSSI: -71 dBm [=====]
INFO RSSI: -104 dBm []
There is also a complimentary TX and RX example if you flash both examples to different boards then you should get an PING message sent and received. This is useful for checking the wiring before moving on to more complicated setup.
First flash the TX demo.
DEFMT_LOG=debug cargo run -p cc1101-embassy-rp2040-examples --bin txYou should see something like this if you have a defmt capable SWD probe:
0.004087 [INFO ] CC1101 TX starting (tx src/bin/tx.rs:47)
0.007718 [INFO ] CC1101 OK (tx src/bin/tx.rs:65)
0.017342 [INFO ] Configured. Sending PING every second... (tx src/bin/tx.rs:77)
4.260004 [INFO ] TX PING #0 (tx src/bin/tx.rs:86)
9.503073 [INFO ] TX PING #1 (tx src/bin/tx.rs:86)
14.746071 [INFO ] TX PING #2 (tx src/bin/tx.rs:86)
19.989067 [INFO ] TX PING #3 (tx src/bin/tx.rs:86)
25.232080 [INFO ] TX PING #4 (tx src/bin/tx.rs:86)
30.475101 [INFO ] TX PING #5 (tx src/bin/tx.rs:86)
35.718125 [INFO ] TX PING #6 (tx src/bin/tx.rs:86)
40.961113 [INFO ] TX PING #7 (tx src/bin/tx.rs:86)
Then on a second board flash the RX demo.
DEFMT_LOG=debug cargo run -p cc1101-embassy-rp2040-examples --bin rxNOTE: the antennas that came with my CC1101 boards were turned to 400 MHz and had an SWR of about 3.3:1 in free space, worse on my desk (6:1). With an SWR this bad it was actually receiving better without the antenna connected on the RX board! As a temporary solution I've cut the end off the antenna and straightened out the coil. Then using my nanoVNA, trimmed until the SWR was down to about 1.12:1
let config = RadioConfig::new() // Carrier frequency — must be in a supported CC1101 band
.frequency_hz(433_920_000) // 433.920 MHz (EU ISM)
// .frequency_hz(868_000_000) // 868 MHz (EU SRD)
// Data rate
.baud_rate(38_400) // 38.4 kbps (also try 4_800, 9_600, 115_200)
// Modulation
.modulation(Modulation::Gfsk) // GFSK recommended for new designs
// .modulation(Modulation::Ook) // For receiving OOK doorbells etc.
// Sync word — both ends must match; avoid 0x0000 and 0xFFFF
.sync_word(0xD391)
// Packet length
.packet_length(PacketLength::Variable(61)) // up to 61 bytes
// .packet_length(PacketLength::Fixed(16)) // fixed 16 bytes
// TX power (433 MHz)
.tx_power(TxPower::Dbm0) // 1 mW — safe for bench testing
// .tx_power(TxPower::Dbm10) // 10 mW — ISM band max for unlicensed UK/EU use ;The 433.050–434.790 MHz band is an ISM (licence-exempt) band in the UK and EU. Key limits for unlicensed use:
- Maximum ERP: 10 mW (
TxPower::Dbm10) - Duty cycle: ≤ 10% in most sub-bands
As a licensed radio amateur you may operate on the 70 cm amateur allocation (430–440 MHz) with higher power and without duty cycle restrictions, subject to your licence conditions.
The library's unit tests run on the host (no hardware needed) and cover the register calculation maths:
bash cargo test -p cc1101-embassy
Issues and PRs welcome. The most useful next contributions would be:
- Testing on hardware other than RP2040
- STM32 or nRF52 example crates
- Channel hopping support
Licensed under either of Apache License 2.0.