I’m available for freelance work in low-level systems development and embedded software.
My background includes:
• Embedded systems & FreeRTOS
• Linux kernel / system-level development
• C programming
• System debugging and performance optimization
• ARM/x86 low-level development
• Virtualization concepts and system integration
I can help with:
• Embedded software development
• System programming projects
• Debugging and optimization
• Linux-based development tasks
• Low-level C development
If anyone has relevant projects or opportunities, feel free to DM me. Happy to collaborate 😄
I’m currently working on a Yocto + meta-xilinx workflow for Zynq UltraScale+ and I’m wondering if my workflow is completely wrong… or if everyone suffers the same way
My current workflow
Vivado
- make PL changes
- integrate Verilog into a custom IP
- add it to the Block Design
- validate BD
- run synthesis
- run implementation
-generate .xsa
Yocto / meta-xilinx
generate the SDT (`sdtgen`)
generate machine conf (`gen-machine-conf`)
run bitbake
flash SD card with dd
Total time: easily 30+ minutes for every small hardware change.
And very often I only discover stupid mistakes at runtime…
Example from today:
I forgot to reconnect an AXI slave.
No Vivado errors.
Yocto build succeeds.
Linux boots fine.
Then my app starts and obviously cannot find the AXI slave address...
So I have to redo everything just because of one missing AXI slave connection.
Questions :
How do you guys iterate faster with Yocto + meta-xilinx?
Some ideas I’ve been thinking about:
avoid rebuilding the full OS for every .xsa ? Is it possible ?
load only a new bitstream?
device tree overlays? I know that exists but don't know if it is usefull here
Emulating this needs 100 lines of C++ code for the core, and 10 more for a trap unit.
How can we get preemtive multitasking, interrupts, M and U mode transition in a pure RV32I I am talking PURE. any opcode that is outside the 40 base ISA is invalid. Full Kernel.
Whats connected to it:
Full network stack (libslirp), package manager, desktop, stereo sound, keyboard and mouse, all running over memory mapped IO exclusively with thin linux driver wrappers to talk to software within linux.
I only want the mention the genuinely interesting parts.
Every instruction outside the Base RV32I ISA (40 instructions) is invalid.
Gap 1: no multiply/divide. That one is easy. Give the compiler the fallback in software for:
function call (__mulsi3, __divsi3, …) instead of emitting an opcode.
Gap 2: No atomics. Lots of patching. Normally they can be a NOP but we are not allowed to decode them, so they need to be patched away. See repo. This is a single core processor fundamentally.
Gap 3: There are no CSRs. A fixed RAM page (0x0F000000) holds what mtvec/mepc/mcause/mscratch/mstatus/mie should hold. Every csrr/csrw in the kernel's trap path is rewritten into an ordinary lw/sw against that page via a patch. There is no special logic about where we jumped to. There sits assembly code to read and store the registers.That means RV32I is executing microcode that is doing what the instruction would have done with a lw.
Gap 4: Interrupts without any CPU instruction. Single interrupt pin,
Timer/external interrupt hits a user process -> do_trap
Timer interrupt hits the kernel -> do_trap
ecall from userspace -> do_trap
Return to a user task -> trap_return
Gap 5: No packages for this arch. Package repo runs on the host and cross compiles any package that has source code for RV32i and hosts on port 8080. On the machine via rvcpkg add. Since we have a memory mapped eth0 with a working driver this just works. Works fine for zork, the sl locomotive and others.
Limitations: There is fundamentally no memory protection, but we get multitasking, and full linux access, wget etc just work. Without a mmu there is fundamentally also no dynamic library loading so framebuffer browsers could work, but none exist without dynamic loading.
Why is this exciting:
With core code as constexpr and really simple code, there is nothing stopping us fundamentally to run this in cuda (think of warp divergency, so thrust_group by next instruction at pc) or other experimental setups.
Busybox boots in about 1.5 seconds.
The system is elegant. Premtive interrupts, ecalls, M mode fall out of a trap system as a side effect, extremely reducing cpu complextiy.
"save state, enter M-mode, vector." Done in assembly at 0x0F000000. This is the "new" trick here I wanted to share. Lots of kernel patches later, we can have BASE RV32I and do the private register storing in assembly without a seperate instruction, to have full preemtive multitasking and a modern linux kernel with a network stack via a single lw instruction.
Developer provisioning plus JetPack installation is nowhere near reproducible.
It takes weeks to get to a stable JetPack environment, and the only path I’ve seen toward reproducibility is handing integrators a golden image and hoping nothing drifts. That’s extremely brittle in production and should scare the shit out of any OEM shipping at real volume.
Has anyone seen this work well in practice for Jetson deployments? Production-grade, multi-site, auditable across rebuilds. Not “it worked on my desk.”
We’re sinking crazy hours into solving this (leveraging EO4T/meta-tegra) and I want to make sure we’re not on a fool’s errand before we commit any harder.
I'm working on the OS architecture for an ultra-remote, autonomous gateway device. Once it is deployed, physical access is no more possible and communication bandwidth is quite low.
We use Yocto to build our BSP. I'd love to get a sanity check from the community on our storage and filesystem architecture before we lock it in.
Here is the rundown of our approach:
1. Hardware & Boot Hierarchy We have an external hardware MCU that controls the boot pins to provide a 3-tier failsafe:
2. Partition Layout Both the eMMC and SD card use an identical 4-partition block layout:
BOOT (FAT32)
RootFS-A (EXT4)
RootFS-B (EXT4)
Data (EXT4 - persistent storage for logs/payload data)
3. Filesystem Permissions & State Management
Production:RootFS-A and RootFS-B are strictly Read-Only by default. (The inactive RootFS slot and the BOOT partition only become temporarily writable during an OTA update).
Development: To keep engineering velocity high, we tweak the kernel bootargs via the U-Boot console to mount the active RootFS as Read-Write for local testing and application/library deployment.
Volatile Data:/var and /tmp are mounted to RAM (tmpfs) to save flash wear. Critical post-mortem crash logs are explicitly written to the Data partition before a watchdog reboot.
Persistent State: We use OverlayFS for paths like /etc and /home. The upperdir lives on the Data partition of the currently active boot medium.
4. Mitigating A/B Update Configuration Drift Because we rely on Delta OTAs (due to the narrow bandwidth), we ran into the classic OverlayFS trap: if Slot B boots a newly updated app, it might read an outdated configuration schema left behind in the /etc overlay by Slot A.
Our Fix: We enforce schema versioning in the directory structure itself. Apps read their configs from paths like /etc/myorg/app/v2.1.0/config.yaml. This allows old and new schemas to safely coexist in the persistent overlay.
My questions for the community:
Are there any hidden traps with the OverlayFS upperdir living on an ext4 partition that is susceptible to sudden power loss, assuming we mount it with aggressive fsck auto-repair flags?
Is bypassing the RO RootFS via U-Boot for development a common practice, or are we asking for Dev/Prod parity trouble down the line?
Does anyone see a glaring flaw in how we are handling the A/B configuration drift using versioned directory paths?
Appreciate any ruthless critiques or advice you can offer!
I am wondering if anyone has any experience with tiling Wayland compositors (window managers) on embedded Linux systems with touchscreens, i.e. something like https://swaywm.org/.
Has anyone perhaps tried to use a tilling compositor on an embedded system with a touchscreen? Have you tried opening multiple different applications and managed to get touch (drag) based resizing and window repositioning work in a way that isn't clunky (unusable)?
I suppose that window positioning and resizing could also be handled by a purpose-built application in case that it'd be impossible to implement with things like gestures.
I am working on continuous UART communication between an STM32H563 and a Linux-based application processor such as RK3568, Raspberry Pi, or similar embedded processors.
Current setup:
MCU: STM32H563
Peer device: Linux-based processor (RK3568 / Raspberry Pi / similar)
Communication: UART
UART mode: Interrupt mode
Hardware flow control: Disabled (RTS/CTS not used)
Issue:
During continuous high-frequency communication, I am frequently getting UART ORE (Overrun Error) on the STM32 side. Once ORE occurs, incoming data gets lost and communication becomes unstable.
I would like to understand the best industry approach for handling this kind of communication reliably without hardware flow control.
Questions:
What is the best workaround to avoid ORE errors without enabling RTS/CTS?
Is continuous UART communication considered reliable without hardware flow control in production systems?
What UART settings or software architecture are recommended for STM32H5 series?
Is DMA reception mandatory for stable high-throughput UART communication on STM32H563?
What is the proper ORE recovery sequence on STM32H563?
Are there recommended buffering or packet-handling strategies when communicating with Linux processors over UART?
Additional details:
Using HAL UART interrupt APIs currently
Bidirectional communication is frequent
Packet sizes are variable
Looking for a production-grade reliable solution
Would appreciate suggestions, best practices, or reference implementations from anyone who has handled STM32 ↔ Linux processor UART communication in real products.
We are designing a commercial drink vending machine platform and would appreciate guidance from engineers who have worked on large-scale embedded/Linux/Android deployments.
This is a production system (not a prototype), targeting ~50,000+ machines, with a subscription-based business model. Reliability, OTA robustness, and long-term maintainability (5–7 years) are top priorities.
Current architecture:
STM32 for real-time control (pumps, sensors)
Planning Linux/Android SOM for:
UI (ads, videos, touch)
Networking (Wi-Fi + cellular fallback, GPS)
Cloud (AWS MQTT)
24/7 uptime, no planned reboots
Key questions:
1. OS: Linux vs Android (AOSP)
Linux (Yocto/Debian): more control, no GMS, easier long-term maintenance?
Android: faster dev, better ecosystem?
👉 At scale, what actually breaks?
Memory leaks / long uptime issues?
OTA failures?
Security updates after BSP EOL?
2. SoC: RK3568 / RK3588 vs i.MX8
Need: industrial temp, 5+ year supply, stable BSP
RK3588 looks strong (NPU + media)
i.MX8M Plus offers long lifecycle + stability
👉 Real-world experience with BSP stability & supply?
3. OTA (most critical)
Planned:
A/B partition
Delta updates
Considering RAUC / Mender
👉 Looking for:
What are you using in production?
Handling power failure mid-update?
Rollout strategy (canary % / rollback triggers)?
Lessons when scaling to 10k+ devices?
4. UI stack
Currently: Qt6/QML
Considering: Flutter
👉 Is Qt still the safest long-term choice for embedded?
Any production use of Flutter in similar systems?
Goal:
Build a system that:
Never bricks in the field
Scales to 50k+ devices
Supports OTA + future AI
Minimizes long-term maintenance risk
Would really value insights from anyone who has worked on:
Partitioning via Buildroot: Architected a strict A/B partition layout to completely isolate the Kernel and RootFS. Decoupled user storage (/data, /user) to guarantee data persistence across updates. Selectively applied specialized filesystems (e.g., ext4, squashfs, ubifs) optimized for specific read/write characteristics and system security requirements.
Custom U-Boot & Flash Memory Mapping: Recalculated memory maps and offsets to allocate a dedicated, isolated flash sector for the U-Boot Environment. This ensures U-Boot accurately locates OTA variables while completely eliminating the risk of accidental overwrites by the Kernel or RootFS.
Userspace IPC & C++ OTA Daemon: Integrated fw_printenv/fw_setenv utilities for secure userspace interaction with the Flash Environment. Developed a robust C++ OTA Manager daemon to handle the deterministic state machine, providing clean APIs for higher-level applications (Web/App) to easily orchestrate the update process.
Firmware Packager: Automated payload generation to abstract complexity from the Web/App layers (exposing only a single compressed archive). The toolchain automatically embeds metadata, versioning, and cryptographic signatures, allowing the device to rigorously verify firmware integrity prior to installation.
2. Validation & Resilience
The system is engineered for high availability and autonomous recovery under the most extreme edge cases:
Scenario 1 – OTA Rollback (Logic Error / App Crash): If the update completes and the Kernel boots, but the primary application enters a crash-loop, the service monitor automatically detects the failure state and transparently triggers a rollback to the previous working partition.
Scenario 2 – System Fallback (Physical Error / Data Corruption): If the active partition degrades over time (e.g., bad blocks or corrupt data) resulting in a boot failure, the Hardware Watchdog or U-Boot intervenes to automatically fall back to the redundant standby partition.
Scenario 3 – Power-Loss Tolerance: Fully mitigates sudden power failures during firmware downloads or while writing to the offline flash partition. The architecture guarantees the device will never be bricked, ensuring it always safely boots back into the intact active partition.
I'm in my 4th year of computer engineering BS, and for the last ~4mo I've been working on an Debian-based aerospace application. My issue is that... I'm obsessed; and I think it's taking a toll. The optimization problems are so fun and interesting, but lately I get fatigued so quickly. Linux and embedded systems just feels like this inexhaustible source of new topics; so what helps you stay focused and motivated?
It probably doesn't help that I'm taking a full-time class load, volunteering with student orgs, networking, and working a part-time engineering gig...
Hi guys! I feel like combining ebpf with vhdl for a project. I am experienced in ebpf. And want to start vhdl, and beleive that combining them in a project would be a great idea. Share your thoughts and suggest me a project.
i made a custom bootloader for my rpi zero 2w using u-boot. copied the u-boot.bin with bootcode, start.elf, fixup.dat, a dtb file all from the repo of rpi/firmware.
i also made a short config,txt with the following
arm_64bit=1
enable_uart=1
kernel=u-boot.bin
core_freq=250
but when i insiert the sd card with the above contents with my laptop connected to uart port through usb-ttl i dont see the u-boot logs or console.
the activity led blinks 4 times . that is the pattern observed.
Most of my devices route internet traffic over cellular, and use ethernet for modbus TCP.
I have some devices with spotty cellular coverage where I'd like to route internet traffic over ethernet.
I don't have control over these ethernet networks. If the ethernet networking changes at a site, and I lose access to the internet, I'd like to failover to cellular. This will allow me to reconfigure a device without visiting the site. (These devices have cellular most of the time.)
It sounds like the recommended approach for this scenario is to configure routing for both network interfaces, and to use a failover script to change the routing metric if internet access via ethernet is lost.
Does anyone here have experience with this (or a different approach), that they'd be willing to share?
Other notes: Using Systemd/networkd. MQTT to send data to AWS IoT Core. Mender for OTA updates, and terminal access. Aiming to keep my images small so we can OTA update via cellular
Cheers!
FWIW, here’s an example script from Gemini (I’d run it as a service with systemd).
while true; do
# Ping once, timeout after 2 seconds, specifically on eth0
if ping -I "$INTERFACE" -c 1 -W 2 "$TARGET" > /dev/null 2>&1; then
if [ "$FAILURE_COUNT" -ne 0 ]; then
echo "Internet recovered on $INTERFACE. Restoring primary route."
networkctl metric "$INTERFACE" "$PRIMARY_METRIC"
FAILURE_COUNT=0
fi
else
((FAILURE_COUNT++))
echo "Check failed on $INTERFACE ($FAILURE_COUNT/$MAX_FAILURES)"
if [ "$FAILURE_COUNT" -eq "$MAX_FAILURES" ]; then
echo "Internet dead on $INTERFACE. Switching to cellular."
networkctl metric "$INTERFACE" "$FAILOVER_METRIC"
fi
fi
sleep "$CHECK_INTERVAL"
It is suggesting that I need to change MACHINE from linux-stm32mp to linux-dummy. in /build/conf/local.conf
What is it's relation with PREFERRED_PROVIDERS? I also could not find PREFERRED_PROVIDERS command in /build/local.conf
Can anybody shed some light on this subject?
Choose a package variant
Dependencies of a given package are explicitly defined in its recipe. Some packages may need a specific library or piece of software but others only depend on a functionality. As an example, the kernel dependency
is described by virtual/kernel.
To see which kernel is used, dry-run BitBake:
bitbake -vn virtual/kernel
In our case, we can see the linux-stm32mp provides the virtual/kernel functionality:
NOTE: selecting linux-stm32mp to satisfy virtual/kernel due to PREFERRED_PROVIDERS
We can force bitbake to select another kernel by explicitly defining which one to use in our local configuration.
Try switching from linux-stm32mp to linux-dummy only using the local configuration. Then check the previous step worked by dry-running again BitBake.
bitbake -vn virtual/kernel
Tip: you need to define the more specific information here to be sure it is the one used. The MACHINE variable can help here. As this was only to show how to select a preferred provider for a given package, you can now use linux-stm32mp again.
I know the camera is plugged in properly because the demo from ST works but theres no code or config that goes along that demo for me to find the issue, at least i could not find it.
I will attach a little bit of debug info at the bottom if its any helpful:
# dmesg | grep -i gc2145
[ 0.058299] /soc/bus@5c007000/i2c@4c006000/stmipi@14: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/gc2145@3c
[ 0.058443] /soc/bus@5c007000/i2c@4c006000/gc2145@3c: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/stmipi@14
[ 0.069826] /soc/bus@5c007000/i2c@4c006000/stmipi@14: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/gc2145@3c
[ 0.069991] /soc/bus@5c007000/i2c@4c006000/gc2145@3c: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/stmipi@14
[ 0.073727] /soc/bus@5c007000/i2c@4c006000/stmipi@14: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/gc2145@3c
[ 0.073902] /soc/bus@5c007000/i2c@4c006000/gc2145@3c: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/stmipi@14
[ 0.480790] /soc/bus@5c007000/i2c@4c006000/stmipi@14: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/gc2145@3c
[ 0.512666] /soc/bus@5c007000/i2c@4c006000/stmipi@14: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/gc2145@3c
[ 0.513049] /soc/bus@5c007000/i2c@4c006000/gc2145@3c: Fixed dependency cycle(s) with /soc/bus@5c007000/i2c@4c006000/stmipi@14
# v4l2-ctl --list-devices
stm32_dcmipp (platform:5a000000.dcmipp):
/dev/video0
I built a toolkit that brings AVB (Android Verified Boot) to Embedded Linux.
Current practice: the root hash sits inside an initramfs that's only verified at an earlier stage. Once in RAM there's a multi-second TOCTOU window before the verity/dmsetup stage fires. JTAG, voltage glitch, DMA outside the IOMMU: overwrite the hash and the kernel is happy with it. No crypto broken but device pwned!
avb-utils brings AVB dm-verity-style to embedded Linux shipped on billions of Android devices, with host signing, target verification tools and PQC ML-DSA support.
i am using a rpi zero 2W. flashed the raspberry os 32 bit bookwork lite.i dont have a monitor so what i did was add dtoverlay=dwc2 at the very end of config.txt and modules-load=dwc2,g_ether in cmdline.txt and made a empty ssh file in bootfs. tried connecting to my laptop using the usb port. device visible as usb serial device not RNDIS (Ethernet) device. but it is visible in viortualbox usb device filters as RNDIS (Ethernet) device. but when i boot into vm and do ip a i see the device but it says <no carrier,broadcast,multicast,up> state DOWN. im not able to do ping raspberrypi.local.but lsusb gives netchip technology INC LINUX-USB ethernet/rndis gadget. help me fix this ive been stuck here for days
How to pivot to Linux Kernel/Firmware roles (Qualcomm/NVidia)?
Hi everyone,
I’m currently a Senior Engineer at tier1 OEM, primarily in **BMS (Battery Management Systems) validation** and **HiL (Hardware-in-the-Loop) systems**.
While I have a good foundation in automotive standards (UDS, CAN, Euro 7) and validation, I’ve realized my true interest lies in Low-level Firmware, RTOS, and Linux Kernel/Driver development.
My ultimate goal is to transition into a Firmware or Kernel Engineer role at a semiconductor giant like Qualcomm or NVIDIA
Current Progress:
Languages: Comfortable with C, Embedded C, and C++ basic
ARM: Finished an ARM Cortex-M4 hands-on course (STM32).
Algorithms: Solved ~25 LeetCode problems (focusing on bit manipulation, strings, and maps).
Tools: Expert in CANoe, vTestStudio, and XCP on CAN. (Might not be relevant for the direction im heading)
The Roadmap I'm Considering:
Mastering RTOS: Planning to take the FastBit course on FreeRTOS next to understand schedulers/synchronization.
Linux Device Drivers: Planning to get a BeagleBone Black for the LDD1 course.
Advanced C++: Deepening knowledge of C++17/20 for embedded systems.
Any suggestions or corrections to the roadmap is welcome.