Introduction
JSON is everywhere - from web services to IoT. But here’s the catch: most popular JSON libraries were written with desktops and servers in mind, where nobody cares about a few extra megabytes. On microcontrollers, especially Cortex-M devices, every byte and every millisecond counts.
Sure, you can push raw C structs around and even write them directly to a config file. It works, but debugging turns into a painful quest.
At some point I got tired of wrestling with JSON on STM32: writing endless boilerplate to walk through cJSON trees, hunting memory leaks, and guessing where malloc would betray me next. That’s when JsonX was born - a lightweight, minimalistic wrapper around cJSON, designed specifically for MCUs and RTOS.
What JsonX Brings to the Table
Automatic mapping JSON <> C structures via a flat
JX_ELEMENT[]
description.Memory control: no heap required (baremetal) or use your RTOS allocators (ThreadX/FreeRTOS).
Straightforward configuration via jx_config.h.
Less boilerplate when reading/writing configs and reports.
Why not just use cJSON?
Good question. JsonX doesn’t replace cJSON - it complements it. Inside, cJSON still does the parsing and builds its object tree. JsonX adds what’s usually missing in embedded projects:
Mapping instead of manual walking: describe your schema once, JsonX takes care of the rest.
Centralized memory management: all allocations go through a pool or a custom allocator, so you control fragmentation and leaks.
RTOS-friendly integration: ThreadX, FreeRTOS, baremetal with static buffers, or even POSIX with custom allocators.
In short: you keep the ecosystem of cJSON, but without the pain of raw malloc/free on MCUs and without hundreds of lines of repetitive glue code.
Example:
Config structure
typedef struct
{
char device_name[32];
uint32_t baudrate;
bool debug;
} config_t;
static config_t config;
Mapping description
JX_ELEMENT config_desc[] =
{
JX_ELEMENT_STR ("device_name", config.device_name),
JX_ELEMENT_NUM ("baudrate", config.baudrate),
JX_ELEMENT_BOOL("debug", config.debug),
JX_ELEMENT_END()
};
Parsing JSON
jx_json_to_struct(json_str, config_desc);
Generating JSON
char buffer[256];
jx_struct_to_json(config_desc, buffer, sizeof(buffer), JX_FORMAT_PRETTY);
Limitations:
- Numbers are currently doubles (like in cJSON). A strict int mode is planned. -Max property name length is fixed via JX_PROPERTY_MAX_SIZE.
- No auto-expansion of element arrays — you define the limit at compile time.
Where to Get It
GitHub: embedmind/JsonX
STM32 usage example: src/example.c
Roadmap
Right now JsonX relies on cJSON for parsing and generation. But I’m considering a move towards a custom parser that would:
- Work directly with memory pools (ThreadX block pool, FreeRTOS safe allocator).
- Operate fully without malloc/free.
- Reduce overhead and improve predictability in constrained systems.
Whether this happens depends on how much demand JsonX gets from the embedded community.
Conclusion
JsonX is a way to use cJSON on microcontrollers without unpredictable allocations and endless glue code. It’s especially useful in projects where every byte and millisecond matters — but you still want JSON to be as easy to work with as on a PC.
Top comments (0)