SIMD-accelerated computer vision on a $2 microcontroller

Hacker News Top Tools

Summary

作者为 2 美元的 ESP32-S3 微控制器编写了利用 128 位 SIMD 指令加速的 FAST 特征检测器,性能约为参考实现的两倍,处理 QVGA 帧约需 6ms,并顺带开发了自用的寄存器分配器 basm。

No content available
Original Article
View Cached Full Text

Cached at: 10/27/26, 02:07 AM

# SIMD-accelerated computer vision on a $2 microcontroller — shraiwi Source: [https://shraiwi.com/blog/simd-fast-esp32s3/](https://shraiwi.com/blog/simd-fast-esp32s3/) > I wrote an accelerated FAST feature detector for the ESP32\-S3 that leverages its 128\-bit SIMD instructions\. It achieves roughly double the performance of the reference implementation, and takes around ~6ms to process a QVGA \(320x240\) frame\. You can find the source code[here](https://github.com/shraiwi/simd-fast-esp32s3)\. For its price, the ESP32\-S3 is a powerhouse of a microcontroller\. Within its unassuming plastic package lies a dual\-core CPU running at a maximum of 240MHz with a slew of peripherals, including WiFi and Bluetooth Low Energy radios\. While digging through its[technical reference manual](https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf)I discovered that the chip supports a limited set of SIMD instructions\. For silicon that’s cheaper than the average coffee, that’s pretty cool\. Let’s see what exciting things we can do with it\! In the process of writing a SIMD\-accelerated FAST corner detector, I learned the basics of assembly on the ESP32\-S3, worked around its eccentric limitations, and ended up writing my own basic register allocator,`basm`\. --- After some more web browsing, I realized that these instructions weren’t exactly[secret](https://bitbanksoftware.blogspot.com/2024/01/surprise-esp32-s3-has-few-simd.html), but rather relatively unknown\. I wanted to experiment with them myself and write more advanced code than what I could find online\. As I’ve been really interested in computer vision lately, I decided on writing a SIMD\-accelerated implementation of the[FAST feature detector](https://en.wikipedia.org/wiki/Features_from_accelerated_segment_test)for the ESP32\-S3\. I started by looking for example code that uses SIMD instructions\. At the time of writing, I could only find three sources: 1. [Larry Bank’s blog](https://bitbanksoftware.blogspot.com/), where he explores the feature and provides a[minimal example](https://bitbanksoftware.blogspot.com/2024/01/esp32-s3-simd-minimal-example.html) 2. Espressif’s[`esp\-dsp`](https://github.com/espressif/esp-dsp)library, used for DSP\-esque features \(convolutions, FFT, etc\.\) 3. Espressif’s[`esp\-dl`](https://github.com/espressif/esp-dl)library, used for on\-chip AI acceleration\. After perusing through them, I was relieved to find that assembly on the ESP32\-S3 isn’t that bad\. I settled on this general structure: ``` .section .rodata # read-only data here     .section .text     .align 4     .global add     .type   add,@function # a simple function that adds two numbers # int32_t add(int32_t a, int32_t b) add: entry           sp, 48 # sp (stack pointer) is an alias for a1     #define r_a a2     #define r_b a3 # code here     add a2, r_a, r_b # a2 = a + b     retw.n # return, with a2 containing the return value. ``` From there, I started writing a SIMD\-accelerated version of the FAST corner pre\-test\. Essentially, it samples one pixel in each cardinal direction and checks if there are at least three “extreme” pixels\. In this case, an extreme pixel is one whose absolute difference from the center pixel is above a certain threshold\. I decided on a function that would calculate the extrema count of sixteen pixels at a time, since each vector register can store sixteen eight\-bit values\. This would be achieved by sampling four “chunks” of pixels in each cardinal direction and comparing them to their respective center pixels\. However, this is where I ran into my first limitation\- the ISA doesn’t allow for direct misaligned reads\. Under the assumption that the center pixel would be aligned, the east and west blocks would be misaligned: centereastwestnorthsouthThankfully, the chip has aninstructionthat allows for extracting a slice of two concatenated registers into another one\. Using this functionality, I was able to extract the east and west blocks by reading and extracting slices from the two blocks adjacent to the center block\. Okay, so now I have the pixel data\. Time to do some comparisons, right? Wrong\. Turns out the ESP32\-S3’s only implements comparisons for signed eight\-bit numbers\. This made processing a little more difficult, because all my pixel data was stored as unsigned eight\-bit numbers\. If you just reinterpreted the unsigned data as signed data, you get some weird results: ``` >>> np.int8(np.uint8(range(0, 256, 8))) array([ 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, -128, -120, -112, -104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8], dtype=int8) ``` The range`\[128 255\]`gets nonlinearly mapped to`\[\-128 \-1\]`, breaking all compare operations\. To make this work, I needed to shift the range of the values from`\[0, 255\]`to`\[\-128 127\]`\. This should’ve been a simple subtraction, but the instruction set got in the way again: on the ESP32\-S3, all the SIMD arithmetic operations are saturating, which meant that all pixel values above 127 would end up being clamped at \-128 instead of underflowing to their appropriate values\. To overcome this problem, I had to somehow subtract 128 from each number in parallel without using the subtraction instruction\. This seemed like a daunting task to me at first, but I eventually arrived at a solution\. Let’s assume that`x`is theminuend\. Here is its digits’ place values: ``` -128 64 32 16 8 4 2 1 ``` Notice anything interesting? Subtraction is the same as addition by \-128, so to compute`x \- 128`, we can just “increment” the number by \-128 by adding one to`x`’s most significant digit, whose place value is \-128\. We can compute this by simply flipping the highest bit of`x`\. Since XORing any bit with one is the same as taking the bitwise NOT, we can selectively flip the highest bit of`x`by XORing it with the bit mask`0b10000000`, which equal to`0x80`\. Therefore,`x \- 128 == x ^ 0x80`\. Now, whenever unsigned eight\-bit values are loaded in, they are XOR’d with`0x80`to convert them an appropriate \(linear\) range where the arithmetic and comparisons make sense again\. With those two tricks, I was able to circumvent the limitations of the ESP32\-S3 and write the SIMD\-accelerated FAST corner pre\-test\. I also wrote a SIMD\-accelerated scoring function using a similar set of operations but I won’t be writing about that here\. In the end, I was able to improve the throughput of the FAST feature detector by about 220%, from 5\.1MP/s to 11\.2MP/s in my testing\. This is well within the acceptable range of performance for realtime computer vision tasks, enabling the ESP32\-S3 to easily process a 30fps VGA stream\. Not bad for $2\!

Similar Articles

@grapeot: A complete machine vision project, from collecting image data from scratch, labeling, neural network training, quantization, building a system on a microcontroller (ESP32), firmware flashing and deployment. After deployment, the results turned out poor, so I retrained from scratch, then optimized performance and energy consumption, and finally deployed. If a senior scientist were to do it, it would take...

X AI KOLs Timeline

The author used GPT-5.6 to complete a garage door recognition project on ESP32-CAM within 10 hours, covering data collection, labeling, training, quantization, and deployment, demonstrating AI's autonomous capabilities in hardware development, and sharing insights on human-machine collaboration.

Home made GPU escalated quickly [video]

Hacker News Top

The author built a DIY GPU-like parallel computing cluster using 65536 low-cost RISC-V microcontrollers (CH570), achieving QVGA resolution rendering, and solved engineering challenges such as power supply, heat dissipation, and programming automation.

ESP32 as counter-surveillance platform

Lobsters Hottest

This article introduces how to use low-cost ESP32 microcontrollers to build a counter-surveillance platform, employing open-source tools to detect and counter surveillance technologies such as license plate recognition and police cameras, thereby enabling accessible privacy protection.

GameBoy on E-Paper ESP32 at 30FPS [video]

Hacker News Top

The author wrote a custom display driver for an ESP32 e-paper development board with a dedicated display controller. By shortening waveforms, budgeting drive time per pixel, and calibrating grayscale, they boosted the Game Boy emulator from under 2 FPS to around 30 FPS and achieved true four-level grayscale output without relying on dithering.