Projects

Engineered and validated in real-world conditions, our products go beyond lab testing to ensure durability, practicality, and reliable performance under actual operating environments.

Heterogeneous sensor integration into an RTOS-based application.

In this project, we use a mix of sensors: one (1) SPI-based sensor, one (1) ADC-based sensor, three (3) I²C sensors sharing a common bus, and three (3) GPIO-based sensors. Instead of starting from scratch, we reuse our existing driver framework, which has been proven in real projects. This ensures consistent implementation, easier integration, and reliable performance across different microcontroller platforms and hardware configurations.

 

Most effort goes into properly developing and validating the drivers. We ensure correct operation over SPI, I²C, ADC, and GPIO, covering timing, data handling, conversion, calibration, and error management. Each module is tested and well documented to keep the design clear and maintainable. This helps reduce confusion during updates and makes the system easier to support and extend over time.

 

With a stable hardware and operating system abstraction layer, integrating these sensors into a new project is typically fast, often under 30 minutes. The same drivers work in both bare-metal and RTOS environments without major changes. Under RTOS, shared peripherals like I²C and SPI are managed safely, allowing multiple tasks to access resources without conflicts or integration issues.

 

Using pre-developed drivers greatly reduces development time. Instead of focusing on low-level integration and debugging, we can concentrate on application-level features that deliver real value, such as control logic, data processing, and system behavior. Since the drivers are already validated in real use cases, technical risk is lower. This approach enables faster, more efficient delivery of robust embedded systems.

STM32G491, CAN-FD, FreeRTOS, SEGGER J-Link, I²C, SPI, ADC

RTOS, embedded software profiling with SEGGER SystemView.

The behavior of embedded software can be erratic under certain conditions. Sometimes such behavior begins with the software’s interrupt service routine (ISR) taking slightly more or slightly less time than usual. This situation can be caused by interrupt priority, priority inversion, and unforeseen events that may occur intermittently.
 

SEGGER SystemView is one of the tools we used to quantify and measure the performance of our software under specific load conditions in order to cover at least most, if not all, worst-case scenarios. This amazing tool helps measure every interrupt and the time consumption of RTOS events. All of this can be collected as evidence to present to our customers and strengthen their confidence in the software package to be delivered.

 

Referring to the image on the left, the orange block shows when CAN-FD interrupt was triggered for a new message. Interestingly, this takes about 60 µs in the debug version, while it takes significantly less time with compiler optimization, namely about 35 µs. Without this tool, there is no way to measure the time required by the ISR so accurately without causing delays in the system.

 

In addition to measuring interrupt and RTOS events, this tool can also measure CPU utilization in percent, real-time stack and heap utilization, and other debugging messages, helping to reduce software development time, build confidence, and detect serious errors earlier. It goes without saying that RTOS development benefits most from such a tool.

STM32G491, CAN-FD, FreeRTOS, SEGGER SystemView

High-speed, low-latency data acquisition via CAN-FD.

The STM32G491 provides two CAN-FD channels, supporting data rates up to 8 Mbit/s, significantly higher than classic CAN at 1 Mbit/s. In this project, multiple CAN nodes are used, each transmitting at 5.5 ksps with 16-byte payloads. This results in a total data throughput requirement of approximately 2.8 MB/s, which must be handled reliably by the system.
 
To meet this requirement, we designed a robust system architecture supported by careful implementation and validation. Extensive measurement and testing were carried out to ensure reliable communication under load. The system successfully achieved more than 40 ksps overall throughput, exceeding the minimum requirement, with an average of 5.7 ksps per node, while continuously logging data to an SD card.

 

The software implementation reuses our existing BSPs, drivers, and supporting libraries, which have already been proven in other projects. This significantly reduces development effort and allows us to focus on application-level features that provide real value to customers. By leveraging validated components, we also improve reliability and reduce integration risks across different subsystems and communication interfaces.

 

The system architecture supports both FreeRTOS-based and bare-metal modules, depending on functional requirements. Despite this mixed approach, both environments share the same BSP, sensor drivers, and communication libraries. This ensures consistency across the entire project, simplifies maintenance, and allows flexible deployment strategies while maintaining predictable behavior and performance across all CAN-FD nodes and data logging operations.

STM32G491, CAN-FD, FreeRTOS, DAQ

IMU performance comparison under same platform.

Evaluating IMU performance is an important step before selecting a sensor for any project. In most cases, we aim for higher accuracy, lower latency, and minimal jitter. To support this decision-making process, we conducted an experiment comparing the TDK ICM-42688 and the TDK MPU-9250, with the goal of demonstrating which sensor provides better stability and measurement quality.
 
The comparison was carried out under controlled conditions, where both sensors were placed at rest in the same environment and room temperature. Both devices used the same software framework and configuration to ensure a fair comparison without external influence. This setup allows the observed differences in output signals to be attributed directly to the sensor performance itself.

 

From the recorded data, we observed that the MPU-9250 exhibits noticeably higher jitter, especially on the Y-axis, with fluctuations of around 1 deg/s. In contrast, the ICM-42688 shows much lower noise levels of approximately 0.1 deg/s. This represents about a tenfold improvement in signal stability, indicating significantly better performance in terms of measurement consistency and noise suppression.

 

Based on these results, the ICM-42688 is a more suitable choice for high-precision applications where stability and low noise are critical. Although it may come at a higher BOM cost compared to the MPU-9250, the improvement in performance justifies its selection. This evaluation provides clear, data-driven support for making informed sensor selection decisions in future system designs.

TDK MPU-9250, TDK ICM-42688, IMU, Grafana

Path Tracking with u-blox NEO-6 GPS.

The u-blox NEO-6 is a GPS receiver based on the u-blox 6 positioning engine. Driver development started with defining core and alternative use cases, along with API design for parsing NMEA messages. A sample project was also created using CMake, GCC, and the NXP LPC54114 platform to ensure early validation and a structured development workflow from the beginning.
 
Development was built on our stable HAL and BSP for the NXP LPC54114 (v0.5.0). In the early phase, we simulated NMEA messages including cold start, valid, and invalid cases to cover edge scenarios defined in the requirements. Unit tests were also created to verify expected behavior, ensuring that the implementation is robust and behaves correctly under different input conditions.

 

The driver supports key NMEA sentence parsers including RMC, VTG, GGA, GSA, GSV, and GLL. By default, these messages are enabled on the NEO-6 module using a UART baud rate of 9600. Development continued with real hardware testing to validate accuracy and reliability, ensuring that parsed outputs matched actual GPS behavior under real operating conditions.

 

The system was validated through real-world testing, where GPS receivers were mounted on a vehicle and data was recorded while driving through a residential area. Coordinates were captured using Python scripts and visualized with Google Earth to confirm route accuracy. This end-to-end validation helped ensure that the driver performs reliably in practical use cases, not only in simulation environments.

u-blox NEO-6, GPS, NXP LPC54114, Google Earth

Sensor driver development for TDK MPU9250, an IMU sensor.

The TDK MPU-9250 is an IMU that integrates an accelerometer, gyroscope, magnetometer, and internal temperature sensor. The driver development began with clearly defined use cases supported by design artifacts such as use case diagrams, class diagrams, and sequence diagrams. This structured approach ensured a clear understanding of functionality before implementation, improving design clarity and reducing development ambiguity.
 
The driver was developed and tested using the NXP LPCXpresso54114 development board, leveraging our existing BSP for the LPC54114. This BSP provides stable I²C peripheral support, which significantly accelerates development. By relying on the established hardware abstraction layer, we were able to focus primarily on implementing and validating the sensor driver logic rather than low-level hardware configuration.

The driver exposes 15 functions covering the most commonly used sensor features. During initialization, the user specifies the I²C channel connected to the sensor, along with configuration parameters such as low-pass filter settings and measurement scale factors. This flexible setup allows the driver to be easily adapted to different application requirements while maintaining consistent and predictable sensor behavior.

 

The project documentation is automatically generated using Doxygen, providing clear and structured API references. From the class diagram, it is evident that the driver depends only on the HAL I²C interface, ensuring hardware independence. The app_config.h file is used to store user-defined I²C configuration settings, allowing easy customization without modifying the core driver implementation.

TDK MPU-9250, IMU, NXP LPC54114

Generic bootloader program for firmware update.

A bootloader is a small program responsible for loading and starting the main application firmware. A well-designed bootloader is essential for reliable field updates without requiring a debugger. It enables end users to update software through communication interfaces such as UART, SPI, or CAN, making maintenance easier and reducing the need for direct engineering support during deployment.
 
In this project, we designed, implemented, and tested a generic bootloader that serves as a reusable component across different applications. It supports firmware updates via UART and is structured for portability and reuse. To simplify the update process, we also developed a Python-based tool that allows end users to perform firmware upgrades with minimal supervision or technical knowledge.

 

The bootloader is optimized for a small footprint, with a code size of approximately 4.8 kB. This leaves sufficient space for user-specific routines, as typical bootloader memory allocation is around 8 kB. On the Microchip PIC32MK platform used in this project, 16 kB is reserved, providing additional flexibility while still maintaining a compact and efficient bootloader design.

 

This implementation improves long-term product maintainability by enabling safe and straightforward firmware updates in the field. By reducing dependency on external debugging tools, it simplifies deployment and support workflows. The combination of a lightweight bootloader and an easy-to-use update script ensures that system upgrades can be performed reliably, helping extend product lifecycle and reduce operational maintenance costs.

Bootloader, Microchip PIC32MK

Newly support OSAL FreeRTOS for Microchip PIC32MK.

The Microchip PIC32MK offers a wide range of on-board peripherals, including CAN (6 channels), I²C (4 channels), SPI (6 channels), and UART (6 channels), along with additional features such as a Memory Protection Unit (MPU) and configurable pin multiplexing. It is also designed with safety-oriented capabilities that support development toward standards such as ISO 26262.
 
To fully utilize these peripherals efficiently, an RTOS is recommended to manage concurrency and ensure low latency, responsiveness, and deterministic behavior. In our implementation, FreeRTOS integrates seamlessly with our proprietary Board Support Package (BSP), which provides HAL drivers for easy configuration and use of all available peripherals. This combination simplifies system design while maintaining predictable real-time performance.

 

The FreeRTOS version used is based on kernel v11.0, with only minimal modifications specific to PIC32MK configuration. No core kernel logic was altered, ensuring compatibility and stability. This approach allows us to maintain a standard RTOS foundation while adapting it to the hardware platform. It also simplifies maintenance and future upgrades to newer FreeRTOS versions.

 

In our sample implementation, all available BSP modules were successfully used simultaneously across multiple peripherals without blocking system operation. This demonstrates that the architecture can handle high peripheral load while maintaining responsiveness. It also confirms that the combination of PIC32MK, BSP, HAL, and FreeRTOS provides a stable and scalable foundation for complex embedded applications requiring multiple concurrent communication channels.

OSAL, FreeRTOS, Microchip PIC32MK, ISO26262

Finite State Machine with event driven capabilites.

A common issue with existing embedded FSM frameworks is poor documentation, untested code, and overly complex interfaces. We addressed these problems by delivering a fully tested solution with 100% line and branch coverage. The framework also complies with C coding standards and MISRA C:2012, ensuring high code quality, reliability, and suitability for safety-conscious embedded development environments.
 
The framework is supported by clear and practical documentation, including usage examples, sequence diagrams, and class diagrams. These materials help visualize internal behavior and simplify understanding of state transitions and use cases. This structured documentation approach makes it easier for developers to adopt the framework quickly and apply it consistently across both simple and complex embedded system projects.

 

The FSM is fully platform agnostic, meaning it does not depend on any specific HAL, BSP, OSAL, or microcontroller. It can be easily integrated into different systems with minimal effort. The implementation is lightweight and requires fewer than 50 lines of code for basic usage, making it highly accessible while still supporting scalable designs for more advanced applications.

 

To enhance reliability, the FSM includes built-in safety mechanisms that strictly control state transitions based on user-defined rules. It also supports state recovery, allowing the system to handle failures during state entry gracefully. With only two public APIs, the interface remains simple while still providing essential FSM functionality, making it well-suited for robust and maintainable embedded software design.

Event Driven, Finite State Machine, FSM, MISRA, CERT, CWE

Newly support Board Support Package for Microchip PIC32MK.

Developing a reusable Hardware Abstraction Layer (HAL) and Board Support Package (BSP) is a challenging but effective approach for simplifying microcontroller migration and driver development. This architecture allows software to be reused across projects with minimal changes. As a result, it helps reduce development effort, improves consistency, and provides long-term value for companies working on multiple embedded systems.
 
We provide a complete BSP implementation for the Microchip PIC32MK1024MCM100 microcontroller, covering all major peripheral interfaces. This includes UART, I²C, SPI, can, GPIO, timers, ADC, DAC, PWM, real-time clock and calendar, watchdog, and other core functions. The implementation is designed to be production-ready, with a focus on reliability, maintainability, and ease of integration into new embedded projects.

All developed code is thoroughly tested and aligned with industry standards such as MISRA C, CERT, and CWE guidelines. This ensures that the software meets high levels of quality, safety, and reliability. By following these standards, we reduce potential bugs and risks early in development, resulting in more stable firmware that is suitable for production environments and long-term deployment.

 

The BSP package also includes example projects designed to validate all peripheral functions on the Microchip PIC32MK MCM Curiosity Pro development board. These examples help verify correct hardware operation and provide a practical starting point for new development. They also simplify onboarding, allowing engineers to quickly understand and use the BSP effectively in real application scenarios.

BSP, HAL, Microchip PIC32MK

Drive-by-wire software development for vehicle motion control.

In this project, we designed and deployed a drive-by-wire system for gas-powered vehicles for a research institute in Malaysia. The system uses both UART and CAN bus communication to receive velocity and steering commands from an onboard autonomous control computer. This dual-communication setup ensures reliable data exchange between the vehicle control system and the higher-level autonomy module.
 
The software was developed in C and C++, built on our reusable Hardware Abstraction Layer (HAL) and Board Support Package (BSP) designed for Atmel microcontrollers. With FreeRTOS as the operating system, the system supports concurrent control tasks while maintaining strict timing requirements. This structure ensures that critical vehicle control functions run reliably alongside other non-critical system operations.

To support system safety and maintainability, we delivered complete documentation, including user manuals, Software Detailed Design (SDD), troubleshooting notes, and Hazard Analysis and Risk Assessment (HARA). These materials help ensure clear understanding between stakeholders and development teams. They also provide structured guidance for system operation, maintenance, and future enhancements, reducing ambiguity during deployment and long-term support phases.

 

We used UML as a standardized approach to define the system architecture and detailed software design before implementation. This provided a clear blueprint for firmware development and improved communication between stakeholders. By structuring the system design upfront, we reduced development risks and ensured alignment with requirements, resulting in a more robust, traceable, and maintainable drive-by-wire software solution.

Atmel, C++, FreeRTOS, Drive by Wire, HARA, Risk Assessments

Newly support OSAL FreeRTOS for ESP32.

In this project, we developed a flexible Operating System Abstraction Layer (OSAL) with RTOS support using FreeRTOS, along with a generic Hardware Abstraction Layer (HAL) tailored for the ESP32 chipset. These interfaces are designed to be reusable and portable across projects. This helps reduce development effort and simplifies adaptation when working with different microcontroller platforms and customer requirements.
 
The main benefit of this architecture is the reduction in migration effort. When moving from ESP32 to another MCU, such as an NXP platform, most of the application and middleware code remains unchanged. Only the HAL layer needs to be adapted. This significantly reduces redevelopment time and helps maintain consistency across different hardware targets without affecting higher-level software components.

The OSAL is designed to isolate the application layer from the underlying RTOS implementation. This allows the system to switch between different real-time operating systems without major code changes. Supported options include FreeRTOS, SAFERTOS, MicriumOS, and others. This flexibility ensures that projects can meet different safety, performance, or licensing requirements while keeping the application logic stable and reusable.

 

Overall, this layered architecture improves software portability, maintainability, and long-term scalability. By standardizing both HAL and OSAL interfaces, we minimize dependency on specific hardware and RTOS choices. This reduces integration risk and development cost while enabling faster project delivery. It also ensures that core application features remain intact even when underlying hardware or operating system components are changed.

OSAL, FreeRTOS, C, C++, ESP32

Newly support Board Support Package for NXP LPC54114.

In this project, we developed a comprehensive Hardware Abstraction Layer (HAL) for NXP LPC microcontrollers. It covers key peripherals such as GPIO, I²C, SPI, ADC, PWM, and timers. The interface is designed to be flexible and reusable across different projects. This approach improves development efficiency and provides clear long-term value, especially when adapting to varying customer requirements and system constraints.
 
The BSP implementation demonstrates smooth portability between different MCU platforms. We successfully migrated from the LPC845 to the LPC54114, which provides higher memory capacity for application use. Importantly, this transition required no changes to the application layer, HAL, OSAL, or middleware. This highlights the strength of the abstraction design and its ability to isolate hardware differences effectively.
 

The LPC54114 BSP was integrated as a direct replacement for the LPC845 BSP without impacting existing software components. This seamless swap confirms that the system architecture is well-structured and hardware-independent at higher layers. It also reduces migration effort in future projects, allowing faster scaling to new hardware while maintaining consistent behaviour across different NXP LPC microcontroller variants.

 

Overall, this abstraction-driven design significantly reduces development effort when supporting new hardware platforms. By standardizing peripheral access through HAL and BSP layers, application code remains unchanged across MCU upgrades. This improves maintainability, reduces integration risks, and ensures better reuse of software assets. It also delivers clear return-on-investment by minimizing redevelopment effort for future embedded system projects.

BSP, HAL, NXP LPC845, NXP LPC54114

Customized object recognition with YOLOv4.

This project is developed using Python and relies on TCP and UDP communication for remote drone control. It also integrates a YOLOv4-based object recognition framework to detect and track pre-trained objects. In addition, gesture recognition is used to support intuitive drone operation, allowing more flexible and interactive control of the system during real-time flight scenarios.
 
Since the system uses multiple UDP ports for sensor data, camera frame capture, and command transmission, careful multi-threading management is required. To keep this manageable, the overall logic is structured using a Finite State Machine (FSM). This helps clearly define drone behaviour, coordinate concurrent tasks, and ensure that system responses remain predictable under different operating conditions.
 

The FSM also simplifies control flow by separating system states such as idle, tracking, and command execution. This makes the system easier to extend and debug, especially when handling asynchronous data streams. By organizing logic in a structured way, we reduce complexity in thread coordination and improve overall system stability during real-time drone operation and communication handling.

 

All application code, including the FSM framework, is validated using Python’s unittest framework. Unit tests are run regularly to ensure functional correctness and detect issues early during development. This process helps maintain code quality, especially during refactoring or feature updates. It also reduces the risk of unexpected bugs, ensuring more stable and reliable behaviour throughout the development lifecycle.

Python, State Machine, Object Recognition, AI, Machine Learning

Quality gates with CI/CD in Bitbucket pipeline.

We have the capability to automatically build the software, run unit tests, check code coverage, and perform static analysis for every Pull Request, as well as for commits to the Master or Release branches. This ensures that each change is verified early and consistently, maintaining a stable codebase and enforcing the required quality standards before integration or release.

 

This automated workflow helps us detect issues quickly, including functional bugs, regression problems, and coding standard violations. By running these checks on every change, we reduce the risk of defects reaching later stages of development. It also improves code reliability and gives developers immediate feedback, making it easier to maintain a high-quality and stable embedded software baseline over time.

 

Our CI/CD pipeline is built using Docker-based environments to ensure consistent and reproducible builds across all stages. The infrastructure is integrated with Atlassian tools such as Bitbucket and Pipelines, providing smooth version control and automation support. This setup allows us to standardize the build process, simplify environment management, and ensure that all builds run in controlled and predictable conditions.

 

We are also able to support and guide CI/CD implementation for your projects, helping establish automated build, test, and deployment workflows. This includes improving internal development processes and software delivery efficiency. With our experience, we can help align your pipeline with best practices, ensuring better scalability, higher code quality, and faster release cycles for embedded and software systems.

CI/CD, BitBucket, Gitlab, Docker, Unit Test, Code Coverage