Hardware FPU, VPU, NEON, and SIMD: How They Supercharge CPU Performance in Embedded Systems
When selecting a microcontroller or processor, you’ll often see specs like “hardware FPU”, “NEON support”, or “SIMD instructions”. These features can provide 10x to 100x performance improvements for certain workloads—but only if you understand what they do and when to use them.
This guide demystifies these performance accelerators with clear examples and real benchmarks.
What Are We Talking About?
FPU (Floating Point Unit)
Hardware dedicated to floating-point math operations (float, double).
Without FPU: CPU emulates floating-point math in software (slow).
With FPU: Dedicated silicon handles float operations in 1-2 cycles (fast).
VPU (Vector Processing Unit) / SIMD (Single Instruction, Multiple Data)
Hardware that processes multiple data elements with a single instruction.
Example: Add 4 numbers in parallel instead of 4 separate add operations.
NEON
ARM’s implementation of SIMD for Cortex-A and some Cortex-R processors. Processes 64-bit or 128-bit vectors.
DSP Extensions
Specialized instructions for signal processing (MAC, saturating arithmetic, etc.). Found in Cortex-M4/M7.
Real Performance Impact: The Numbers
Example 1: Sine Wave Calculation (Hardware FPU)
Scenario: Calculate 10,000 sine values for audio synthesis.
// Simple sine calculation
for (int i = 0; i < 10000; i++) {
output[i] = sinf(i * 0.001f);
}
Performance on STM32F4 (Cortex-M4 @ 168MHz):
| Configuration | Execution Time | Speedup |
|---|---|---|
| Software FP (Cortex-M3) | 142 ms | 1x (baseline) |
| Hardware FPU (Cortex-M4) | 18 ms | 7.9x faster |
Why? Hardware FPU executes sin(), cos(), multiply, divide in dedicated silicon instead of hundreds of integer instructions.
Example 2: Image Brightness Adjustment (NEON SIMD)
Scenario: Increase brightness of 1920×1080 image (2,073,600 pixels).
// Without SIMD: Process one pixel at a time
for (int i = 0; i < num_pixels; i++) {
pixels[i] = pixels[i] + 50; // Add brightness
}
// With NEON: Process 16 pixels simultaneously
for (int i = 0; i < num_pixels; i += 16) {
uint8x16_t vec = vld1q_u8(&pixels[i]);
vec = vaddq_u8(vec, vdupq_n_u8(50));
vst1q_u8(&pixels[i], vec);
}
Performance on ARM Cortex-A53 @ 1.2GHz:
| Method | Processing Time | Speedup |
|---|---|---|
| Scalar (no SIMD) | 45 ms | 1x |
| NEON SIMD | 3.2 ms | 14x faster |
Why? NEON processes 16 bytes in parallel with a single instruction.
Example 3: Audio FIR Filter (DSP + FPU)
Scenario: Apply a 64-tap FIR filter to 48kHz audio stream.
// Standard implementation
float fir_filter(float *samples, float *coefficients, int taps) {
float result = 0.0f;
for (int i = 0; i < taps; i++) {
result += samples[i] * coefficients[i]; // MAC operation
}
return result;
}
Performance on different ARM Cortex-M processors @ 100MHz:
| Processor | Features | Processing Time (per sample) | Real-time Capability |
|---|---|---|---|
| Cortex-M0+ | None | 42 µs | Cannot handle 48kHz |
| Cortex-M4 | FPU only | 8.5 µs | Marginal |
| Cortex-M4 | FPU + DSP | 2.1 µs | Easy (4.8µs available) |
| Cortex-M7 | FPU + DSP + Cache | 0.8 µs | Headroom for more |
Why? DSP instructions include MAC (Multiply-Accumulate) that does result += a * b in a single cycle.
When Do These Features Matter?
Hardware FPU is Critical For:
✅ Audio/DSP: Real-time filters, effects, synthesis
✅ Motor Control: Field-oriented control, PID loops with float
✅ Sensor Fusion: Kalman filters, IMU quaternion math
✅ Graphics: 3D transformations, lighting calculations
✅ Physics: Game engines, simulations
✅ Scientific Computing: Any algorithm using float/double
Cost: Minimal. Many modern MCUs include FPU (STM32F4, ESP32, most Cortex-M4/M7).
NEON/SIMD is Critical For:
✅ Image Processing: Filters, format conversion, scaling
✅ Video Encoding/Decoding: H.264, VP9, AV1
✅ Machine Learning: Matrix operations, convolutions
✅ Cryptography: AES, SHA acceleration
✅ Signal Processing: FFT, correlation, filtering
✅ Data Compression: DEFLATE, LZ4, Zstd
Availability:
- ARM Cortex-A (A5, A7, A8, A9, A53, A72, etc.): Includes NEON
- ARM Cortex-M: No NEON (except M55 with Helium—ARM’s M-profile vector extension)
- RISC-V: V extension (vector processing)
- x86: SSE, AVX, AVX-512
DSP Extensions Matter For:
✅ Audio Processing: Low-latency filters, codecs
✅ Motor Control: Fast current control loops
✅ Signal Analysis: Correlation, FFT
✅ Saturation Math: Prevent overflow in control algorithms
Availability:
- Cortex-M4/M7: DSP instructions
- Cortex-M3/M0/M0+: No DSP
Practical Decision Tree
“Should I enable hardware FPU?”
YES if:
- Your code uses
floatordoublein performance-critical paths - You do any trigonometry, exponentials, or transcendental functions
- Real-time processing with floating-point math
NO if:
- Purely integer workloads (GPIO, basic I/O)
- Code size is extreme constraint (FPU adds ~2KB)
- Never use floating-point
Example: STM32F4 with FPU disabled still includes the hardware—you’re just forcing slow software emulation.
“Do I need a processor with NEON?”
YES if:
- Image/video processing (even simple operations)
- Machine learning inference
- Heavy data processing (>1000 elements)
- Cryptography without hardware accelerators
NO if:
- Simple control tasks
- Low data throughput
- Cost-sensitive design (Cortex-M vs Cortex-A price difference)
Reality Check: If you’re processing camera images, NEON is non-negotiable for acceptable performance.
“Does DSP extension matter on Cortex-M?”
YES if:
- Audio I/O with real-time filtering
- Motor control with fast loops (>10kHz)
- Signal processing on sensor data
NO if:
- Infrequent calculations
- Background processing (low real-time demands)
Cost: Negligible. Cortex-M4 with DSP vs M3 is minimal price difference.
Code Examples: Before and After
FPU Example: PID Controller
Without FPU awareness (slow):
double pid_calculate(double error) {
integral += error; // Compiler uses software FP
double derivative = error - prev_error;
prev_error = error;
return Kp * error + Ki * integral + Kd * derivative;
}
With FPU optimization (fast):
// Use float for hardware FPU (single-precision)
float pid_calculate(float error) {
integral += error;
float derivative = error - prev_error;
prev_error = error;
return Kp * error + Ki * integral + Kd * derivative;
}
Performance: float on Cortex-M4 FPU is 5-10x faster than double (which uses software emulation even with FPU).
NEON Example: Array Sum
Scalar version:
int sum_array(int *data, int count) {
int sum = 0;
for (int i = 0; i < count; i++) {
sum += data[i];
}
return sum;
}
NEON version (ARM):
int sum_array_neon(int *data, int count) {
int32x4_t sum_vec = vdupq_n_s32(0); // Vector of 4 zeros
for (int i = 0; i < count; i += 4) {
int32x4_t data_vec = vld1q_s32(&data[i]);
sum_vec = vaddq_s32(sum_vec, data_vec); // Add 4 at once
}
// Horizontal sum
int32x2_t sum_half = vadd_s32(vget_low_s32(sum_vec),
vget_high_s32(sum_vec));
return vget_lane_s32(vpadd_s32(sum_half, sum_half), 0);
}
Performance on 10,000 elements: 4x faster (theoretical, often 3-4x in practice due to memory bandwidth).
Common Mistakes
Mistake 1: Using double when you have single-precision FPU
double angle = 3.14159265359; // ❌ Slow on most embedded FPUs
float angle = 3.14159265359f; // ✅ Fast
Most embedded FPUs are single-precision only. Using double forces software emulation.
Mistake 2: Not compiling with FPU flags
# ❌ Wrong: FPU not used even though hardware exists
arm-none-eabi-gcc -mcpu=cortex-m4 main.c
# ✅ Correct: Enable hardware FPU
arm-none-eabi-gcc -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard main.c
Without -mfpu and -mfloat-abi=hard, the compiler won’t use hardware FPU.
Mistake 3: Expecting SIMD auto-vectorization
Most compilers don’t auto-vectorize well. You need:
- Intrinsics (ARM NEON intrinsics, SSE intrinsics)
- Hand-written assembly
- Specialized libraries (Arm Compute Library, CMSIS-DSP)
Real-World Use Case: ESP32 Audio Processing
Scenario: ESP32-S3 (Xtensa LX7 with vector extensions) processing audio effects.
Implementation:
- Sample rate: 48 kHz (20.8 µs per sample)
- Effect: Reverb with 4-tap delay + mixing
Performance:
| Implementation | Processing Time | Result |
|---|---|---|
| Scalar float (no optimization) | 38 µs | ❌ Drops samples |
| Compiler optimization (-O3) | 24 µs | ❌ Still drops |
| Hand-written vector ops | 12 µs | ✅ Real-time |
| + Assembly tuning | 7 µs | ✅ Plenty of headroom |
Takeaway: Vector processing (SIMD) made the impossible possible.
Benchmarking Your Code
Quick FPU Test
#include <math.h>
#include <time.h>
void benchmark_fpu() {
volatile float result = 0;
clock_t start = clock();
for (int i = 0; i < 100000; i++) {
result += sinf(i * 0.001f) * cosf(i * 0.002f);
}
clock_t end = clock();
printf("Time: %ld ms\n", (end - start) * 1000 / CLOCKS_PER_SEC);
}
Run this on your target. If it’s slow, check FPU configuration.
Summary Table
| Feature | What It Does | Speedup | Found In | When to Use |
|---|---|---|---|---|
| Hardware FPU | Fast float math | 5-20x | Cortex-M4/M7, Cortex-A, ESP32 | Any float-heavy code |
| NEON/SIMD | Parallel data ops | 4-16x | Cortex-A, x86 SSE/AVX | Image, video, ML, DSP |
| DSP Extensions | MAC, saturation | 2-4x | Cortex-M4/M7/M33 | Audio, motor control |
| Vector Ext (Helium) | M-profile SIMD | 4-8x | Cortex-M55/M85 | Future M-series SIMD |
Key Takeaways
- Hardware FPU is nearly free on modern MCUs—always enable it if using
float. - Use
float, notdoubleon embedded systems (unless you have double-precision FPU). - NEON/SIMD is mandatory for image/video processing, ML inference, heavy DSP.
- Compiler flags matter—wrong flags = hardware sits idle while software emulates.
- Measure, don’t guess—profile your code to see if FPU/SIMD helps.
- DSP instructions give “free” performance on Cortex-M4/M7 for filters and control loops.
Recommended Reading
- ARM NEON Programmer’s Guide
- CMSIS-DSP Library (optimized DSP functions)
- Cortex-M4 Generic User Guide (FPU and DSP usage)
- ARM Compute Library (optimized NEON kernels)
Bottom Line: These hardware accelerators aren’t just marketing buzzwords—they’re the difference between “real-time” and “too slow”. Choose your processor and configure your compiler accordingly.