In the era of big data, how do embedded systems cope with massive data streams?
In embedded system development, we often face the dilemma:interrupt service routines need to quickly process input data, whileapplications need to reliably and stably consume this data. The mismatch in speed between the two often leads to data loss or system stalling.
Today, we will delve into a classic solution to this problem—double buffering technology, and share a practical implementation tested in RT-Thread.
1. What is Double Buffering?
Double buffering is adata exchange technique that uses two identical buffers to alternate read and write operations. When one buffer is used for writing data, the other buffer is used for reading data, thus achieving separation of read and write operations.
Core Advantages:
-
Read-write separation, reducing contention
-
Increased data throughput
-
Ensures data integrity
-
Suitable for high-speed data flow scenarios
2. Typical Application Scenarios of Double Buffering
1. Data Acquisition Systems
// Sensor data acquisitionvoid ADC_IRQHandler(void){ // Quickly write to buffer in interrupt DoubleBuffer_Write_ISR(adc_buffer, sample_data, SAMPLE_SIZE);}
2. Communication Protocol Processing
-
UART serial data reception
-
Ethernet packet buffering
-
Wireless communication module data exchange
3. Real-time Audio and Video Processing
-
Audio PCM data buffering
-
Camera frame data acquisition
-
Display refresh data preparation
3. Detailed Implementation of Double Buffering
Based on RT-Thread’s double buffering implementation, we designed the following core structure:
Data Structure Design
typedef struct{ uint8_t* buffer; // Data buffer uint16_t bufferSize; // Buffer size uint16_t datalen; // Current data length} Sub_buffer;
typedef struct{ struct rt_mutex ReadLock; // Read lock struct rt_mutex WriteLock; // Write lock Sub_buffer* SubBuffers[2]; // Double buffer uint8_t ReadIndex; // Read index uint8_t WriteIndex; // Write index} Double_buffer;
Key Technical Highlights
1. Thread-safe Design
// Regular thread write (with timeout waiting)uint16_t DoubleBuffer_Write(DoubleBufferHandle handle, uint8_t* buffer, uint16_t datalen, rt_int32_t timeout);
// Interrupt-safe write (non-blocking)uint16_t DoubleBuffer_Write_ISR(DoubleBufferHandle handle, uint8_t* buffer, uint16_t datalen);
2. Intelligent Buffer Switching
When the read buffer data is empty, the system automatically swaps the read and write buffers:
// Swap read and write buffersuint8_t tmpIndex = DoubleBuffer->WriteIndex;DoubleBuffer->WriteIndex = DoubleBuffer->ReadIndex;DoubleBuffer->ReadIndex = tmpIndex;
3. Packet Format Optimization
Usinglength-prefixed packet format to ensure data integrity:
[Length High][Length Low][Data Content...]
4. Performance Testing and Comparison
We conducted performance testing on the STM32F407 platform:
Testing Environment
-
MCU: STM32F407 @168MHz
-
RTOS: RT-Thread Nano 3.1.5
-
Buffer Size: 2KB × 2
Performance Data
| Scenario | Data Throughput | CPU Usage | Data Loss Rate |
|---|---|---|---|
| Single Buffer | 850KB/s | 65% | 2.3% |
| Double Buffer | 1.2MB/s | 45% | 0% |
Practical Application Effects
In an industrial sensor project, after adopting double buffering:
-
Data loss rate dropped from 5% to 0%
-
System response time decreased from 15ms to 3ms
-
CPU usage reduced by 20%
5. Best Practices and Optimization Suggestions
1. Buffer Size Selection
// Choose appropriate size based on application scenario#define BUFFER_SIZE_512B 512 // Small data packets#define BUFFER_SIZE_2KB 2048 // Medium data#define BUFFER_SIZE_8KB 8192 // Large data volume
2. Error Handling Strategy
// Check write return valueuint16_t written = DoubleBuffer_Write(handle, data, len, timeout);if (written != len) { // Handle write failure rt_kprintf("Buffer full\n");}
3. Performance Monitoring
It is recommended to add statistical functions to monitor buffer usage in real-time:
typedef struct { uint32_t total_writes; uint32_t total_reads; uint32_t buffer_full_errors; uint32_t buffer_switches;} Buffer_Stats;
6. Advanced Optimization Directions
1. Multi-level Buffering
For particularly high-speed data flows, consider a multi-level buffering design:
Acquisition → Level 1 Buffer → Level 2 Buffer → Processing
2. Dynamic Buffer Adjustment
Adjust buffer size dynamically based on data flow to optimize memory usage efficiency.
3. DMA Cooperation
Use in conjunction with DMA controllers to achieve zero-copy data transfer, further enhancing performance.。
4. Issues with rt_memmove
Modify to a circular buffer to reduce memory copying
7. Conclusion
Double buffering technology is an effective solution for embedded systemsto cope with high-speed data flows. Through the implementation scheme introduced in this article, developers can:
✅ Easily handle data exchange between interrupts and threads✅ Significantly reduce data loss rates✅ Improve overall system throughput✅ Ensure real-time performance and reliability
In practical projects, double buffering has become a standard technology in scenarios such asdata acquisition, communication processing, and audio-video streaming. Mastering this technology will add significant weight to your embedded development skills.
Original Statement: This article was originally published by [Embedded Xiao Jin], and sharing is welcome. For reprints, please contact for authorization.
Author / Editor: Xiao Jin