SmartRC CC1101 rewrites a radio driver around registers instead of RAM
This driver library can be used for many libraries that use a simple RF ASK module, with the advantages of the cc1101 module. It offers many direct setting options as in SmartRF Studio and calculates settings such as MHz directly.
At a glance
- What is it?
- SmartRC CC1101 is an Arduino, ESP8266 and ESP32 driver for the CC1101 radio that was re-engineered for version 3 around read-modify-write register access, datasheet formulas and a per-instance object model. It keeps old sketches working through a wrapper, and it ships a calibration tool for cheap modules with drifting crystals.
- Who is it for?
- SmartRC CC1101 fits a maker building a 433 or 868 MHz link on an Arduino or an ESP32 who wants the register values derived from the datasheet rather than copied from someone else's defaults, and who is willing to calibrate a module whose crystal is off.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 158 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A fork that replaced copied constants with datasheet formulas
SmartRC CC1101 is a driver library for the CC1101 radio, and its own description is about the arithmetic: it offers many direct setting options as in SmartRF Studio and calculates settings such as the frequency in MHz directly.
The project is the official evolution of the SmartRC CC1101 library, and the readme frames version 3.0.2 as a re-engineering for 2026 after years of community use of versions up to 2.5.7. The change is described as fundamental: the older versions relied on experimental values and global variables, while version 3 follows the physical formulas in the Texas Instruments CC1101 datasheet and uses a modern, object-oriented design.
That lineage matters for provenance. The library was originally based on the Elechouse CC1101 Library by Wilson Shen, and the readme thanks Wilson and the Elechouse team for permission to modify and evolve the code, with the original work at www.elechouse.com.
The platform target is unchanged in spirit and stated on the badge: Arduino, ESP8266 and ESP32, with the licence MIT and the author recorded as Little Satan of SmartRC, revision April 2026.
Read-modify-write removes the RAM mirror of chip state
The first technical improvement listed is the one with the clearest engineering consequence: instead of mirroring chip states in the microcontroller's RAM, the driver operates bit-precisely directly on the hardware registers.
The reasoning is about small targets. On an Arduino Nano or Uno, every byte of RAM counts, and a driver that keeps a copy of the chip's registers in RAM is spending scarce memory on a duplicate of state the chip already holds. The read-modify-write approach reads the register, changes the bits you care about, and writes it back, so the configuration lives in one place.
The second improvement is mathematical precision, and the claim attached to it is link stability. Frequencies, data rates and bandwidths are now calculated with exact logarithmic formulas rather than round numbers copied from a reference, and the readme attributes a drastic increase in link stability to that change. Whether it is drastic on your bench is worth measuring, but the direction is the right one: a frequency offset of a few kilohertz is enough to lose a narrowband link entirely, which is exactly the subject of the calibration section further down.
The third improvement is hardware feedback, and it is the one that changes how you debug. The new plain-text getters, getMHZ() and getDRate() among them, let you read back the actual internal settings of the chip. On a driver that computed its values for you, that was the missing half of the loop: you could set a frequency but not confirm what the chip ended up with.
One object per module, and four functions that no longer exist
The object-oriented redesign is not cosmetic, and the readme is explicit about what it cost.
Multi-module setups are now handled by class instantiation, with the example of a dual-band gateway running 433 and 868 MHz as the case in mind. Two objects, radio1 and radio2, each with their own configuration.
The price is the removal of the old multi-module workaround functions. setModul(), addSpiPin(), addGDO() and addGDO0() are gone, and the readme states the reason plainly: to keep the library clean and professional. The new approach is to instantiate multiple objects instead.
The transition for existing code is handled by a built-in wrapper, and the readme says most legacy sketches using ELECHOUSE_CC1101 will compile and run out of the box. The compatibility is therefore partial by design: sketches that only use the driver to talk to one radio keep working, while sketches that used the removed functions have to be rewritten.
That is a reasonable trade for a driver that had accumulated global state, but it does mean an upgrade is not a version bump for everyone. The repository keeps the old source file name ELECHOUSE_CC1101_SRC_DRV.h alongside the new SmartRC_CC1101.cpp and SmartRC_CC1101.h, which is the shape you would expect from a wrapper that keeps the legacy include path alive.
Custom SPI pins work on ESP32 and not on an Uno
The wiring section is specific enough to be useful, and it is where the platform differences bite.
Power is 3.3V only, and the table gives the rest for Arduino Uno and Nano against the ESP32 defaults: SCK on pin 13 or GPIO 18, MISO on pin 12 or GPIO 19, MOSI on pin 11 or GPIO 23, CSN or SS on pin 10 or GPIO 5, and GDO0 on pin 2 or GPIO 2, with ground on ground in both cases.
If you need different pins, setSpiPin() reconfigures the bus, and there is a hard ordering rule: you must call setSpiPin() before calling radio.Init(). The example makes that sequence explicit.
// Example for setting custom SPI pins
radio.setSpiPin(SCK_PIN, MISO_PIN, MOSI_PIN, SS_PIN);
radio.Init();The platform notes explain why this is not uniform. On the ESP32, ESP32-S2 and ESP32-S3 the internal GPIO matrix lets you map the SPI bus to almost any available GPIO, and using this function is mandatory on the newer variants because their default hardware SPI pins differ significantly from the classic ESP32. On classic 8-bit Arduinos and most ARM boards the hardware SPI lines are hardwired into the silicon and cannot be changed, so you can only change the SS or CS pin, and passing different values for SCK, MISO or MOSI there is ignored, or the driver falls back to the hardware defaults.
That is a hardware constraint rather than a library choice, and it is the kind of thing that decides which library suits your board.
Init, setMHZ, SetRx, then poll CheckReceiveFlag
The quick start is a complete sketch, and it is worth reading as the API in miniature.
#include "SmartRC_CC1101.h"
// Create an instance
SmartRC_CC1101 radio;
void setup() {
Serial.begin(115200);
radio.Init();
radio.setMHZ(433.92);
radio.SetRx();
if(radio.getCC1101()) {
Serial.println("Hardware found and ready!");
}
}The order is Init, then the frequency in MHz, then receive mode, then the presence check through getCC1101(). That last call is the one to keep, because Init returning without throwing is not the same as the radio being there.
The receive side is a poll in the loop.
void loop() {
if (radio.CheckReceiveFlag()) {
byte buffer[64];
byte len = radio.ReceiveData(buffer);
// Process data...
}
}CheckReceiveFlag() tells you a packet is waiting, and ReceiveData(buffer) copies it into a buffer you supply, with the length returned. The buffer in the example is 64 bytes, which is also close to the default maximum packet length of the CC1101 itself, so a larger payload needs a different configuration as well as a larger array.
The examples directory in the repository goes further, with folders for the default CC1101 examples, ESPiLight, NewRemoteSwitch, Rc-Switch, RemoteSensor and the SmartRC-CC1101 examples, and library.json and library.properties at the root mark it as an installable library for the Arduino and PlatformIO ecosystems.
Cheap crystals drift, and the calibration tool corrects them
The hardware calibration section is the most practically useful part of the readme, and it addresses a problem that has nothing to do with code.
Inexpensive CC1101 modules often have a severe deviation in the integrated 26 MHz crystal oscillator, often plus or minus 20 to 30 ppm. The consequence is that the module transmits slightly off centre, for example at 433.911 MHz instead of 433.920 MHz, and that costs a lot of range when the receiver is narrowband.
The fix is in the examples folder as a Band Calibration Tool, and it needs an SDR and the serial monitor. The guided script measures the upper and lower limits of an entire frequency band, such as the 433 MHz band, then calculates the FSCTRL0 register offsets and outputs ready-to-use C++ code, in the form myRadio.setClb(...), that permanently tunes that specific module.
This reframes what the driver is doing. The register-level access and the formula-based calculations are what make a correction possible at all: the tool has to write a specific offset into a specific register and then confirm the resulting frequency, which is exactly the combination of write capability and read-back feedback that version 3 added.
It also explains the emphasis on getMHZ() in the feature list. With a cheap module, the number you configured and the number the radio is actually using are different, and only one of them is the truth.
MIT licensed, a fresh issue backlog, and a v3 in the wild
The licence is MIT, released under that licence with the author and revision date recorded in the readme, and the lineage from the Elechouse library is acknowledged, which matters if you are choosing between the two.
The version history shows how new the current line is. Version 3.0.0 landed in April 2026 as a major release with a new object-oriented architecture and mathematical precision, 3.0.1 followed in late April with a registry fix, and 3.0.2 in May 2026 with improvements and fixes for the ESP32. The repository is not archived and the last push was on 2026-05-18.
The issue policy is worth reading before you file anything. With the version 3.0.0 release, all issues reported before April 2026 were closed and moved to a Legacy V1.x and V2.x milestone, because they refer to an architecture that is no longer maintained. A bug with the new version means a new issue, and the readme asks you to confirm you are on the object-oriented structure and can reproduce the problem with the current release first.
That is a clean reset, and it is also a signal about the library's maturity. A driver that computes its own register values from datasheet formulas, offers read-back verification and includes a calibration workflow is a serious piece of work, but it is a few months old, its issue tracker starts empty, and anyone building on it should expect the API to settle further.
Editorial conclusion
SmartRC CC1101 fits a maker building a 433 or 868 MHz link on an Arduino or an ESP32 who wants the register values derived from the datasheet rather than copied from someone else's defaults, and who is willing to calibrate a module whose crystal is off. It is the wrong choice if you need the old multi-module workaround functions, if your board is a classic AVR where the SPI pins cannot be moved, or if you want a driver with a settled API, since the version 3 rewrite closed the entire legacy issue backlog in April 2026. Check first that the removed functions are not in your code, that setSpiPin is called before Init(), and that your module's crystal error is within what the Band Calibration Tool can correct.
Frequently asked questions
Which boards does the SmartRC CC1101 library support?
The readme lists Arduino, ESP8266 and ESP32, and the wiring table gives defaults for the Arduino Uno and Nano and for the ESP32. The module is powered at 3.3V only.
How do I set custom SPI pins on an ESP32?
Call radio.setSpiPin(SCK_PIN, MISO_PIN, MOSI_PIN, SS_PIN) before radio.Init(). On classic 8-bit Arduinos and most ARM boards the SPI lines are hardwired, so only the SS or CS pin can be changed and other values are ignored.
Why does my cheap CC1101 module transmit off frequency?
Inexpensive modules often have a 26 MHz crystal oscillator deviating by plus or minus 20 to 30 ppm, so they transmit slightly off centre and lose range with narrowband receivers. The examples folder has a Band Calibration Tool that measures a band with an SDR and outputs setClb offsets for that module.
Will my old ELECHOUSE_CC1101 sketch still compile with version 3?
Most legacy sketches will, through a built-in wrapper. However setModul, addSpiPin, addGDO and addGDO0 were removed, and multiple modules are now handled by instantiating several objects instead of the old workaround functions.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/lsatan-smartrc-cc1101-driver-lib)Was this useful?