Episode 12: Burkhard on Qt Embedded Systems
View this email in your browser
Welcome to Episode 12 of my newsletter on Qt Embedded Systems!
I can’t believe it! This is the 1st anniversary of my newsletter 🎉 Episode 1 had 6 readers. Episode 12 has 254 readers. I hope that you have as much fun reading my newsletters as I have writing them. I learn a lot while writing them 😉🙏
Here is a preview of the posts I am planning to write in the next months:
Migrating the terminal application of “my” sugar beet harvester from Qt 5 to Qt 6.
Getting my Internet radio working on the Yocto Dunfell - using kas.
Getting a real-life QML application under test using approval tests.
Determining the architecture of a Qt embedded system - mimicking the discussion at the start of my customer projects.
Let me know your ideas both for blog posts and newsletter posts.
Enjoy reading and stay safe - Burkhard 💜
My Blog Posts
Cross-Compiling Qt Embedded Applications with QtCreator and CMake
When we develop Qt embedded applications, we want QtCreator to cross-compile the application for the embedded device, deploy it to the device and run it on the device - all with a single click of the Run button in QtCreator. The crucial factor is to set up a QtCreator kit with CMake configuration and toolchain files correctly. Doing this manually is a tedious and error-prone process.
A fairly unknown script, configure-qtcreator.sh from the meta-boot2qt layer comes to the rescue. It generates the QtCreator kit automatically. This easily saves you a couple of hours in convincing QtCreator, CMake and Yocto to work together properly.
My Thoughts on Tom Hirst’s Book “Pricing Freelance Projects”
Don’t skip this section, if you are not a freelancer. As a freelancer, my customers are machine manufacturers or makers of medical devices. As employees of my (potential) customers, you have customers as well: farmers, hospitals, patients or consumers. Our job is the same: to provide higher value to our customers by making existing things easier, faster or more fun to do, or by making new things possible.
This post is half review of Tom Hirst’s excellent book Pricing Freelance Projects and half description of my pricing experiences as a freelancer. I wish Tom’s book would have been available when I started freelancing in 2013. It would have saved me from a lot of mistakes. Tom’s book is equally well suited for new freelancers and “old” freelancers. His advice helped me to sharpen my understandig of pricing and to define my next steps in ditching hourly billing.
Value For Clients
The core sentence of Tom's book comes from the section Bought Time: “The most valuable asset in life is time.” Alan Weiss, the godfather of value-based pricing, gives the reason: “You can always make another dollar, but you can’t make another minute.”
Tom continues: “Clients hire freelancers […] [to buy] themselves their own time back and to free [themselves] up to do the things that only they can."
While negotiating with prospects, you as a freelancer must find an answer to this question: How much time can you buy your clients? The more time you buy your clients, the more value you provide to them and the higher is your fee.
In Tom’s words (emphasis mine): “People with a value mindset spend their time more carefully than they spend their money. [Clients will] pay a premium for a freelancer who offers peace of mind that their time will not be compromised, outside of what they expect, due to this engagement.”
Giving clients peace of mind is invaluable and an excellent differentiator from your freelancing competition. For example, I have brought several high-quality products to the market quickly and enabled my clients to do so themselves in the future. Prospects can be pretty sure that I can do it again - with less resources.
Value For Freelancers
Increasing Baseline Value. Clients gauge your baseline value by how much peace of mind you can give them. How confident are clients that you do your part of the project successfully without much help? You increase your baseline value by honing your primary skill, which is developing Qt embedded systems for me.
Continue to study your skill. For me, it was learning QML, touch user interaction, C++11/14/17 and Yocto. Now, it’s Qt 6.
Show proof of successful work. That’s my project portfolio with two harvester terminals, two infotainment systems and more.
Self-initiate relevant side projects. I started building a simple Internet radio on a Raspberry Pi. So far, it’s a two-part series how to build a Linux image and an SDK with Yocto - with more to come. The series has already caught the eyes of some prospects.
Present your expertise, process and workings publicly. I write blog posts and give talks about technical problems I solved for clients. Prospects can easily find out that I prefer agile processes like Scrum, XP and Kanban and that I am a big fan of TDD, automated builds and tests, and that I prefer value-based pricing.
And Tom is right: “Raising [my] baseline value is […] attached to something [I] enjoy.”
Increasing Differential Value. Passing the baseline-value filter gets you on the shortlist of prospects. They will contact you to discuss a project in more detail - with a handful of competitors. Then, “clients make their selection decision by performing a differential value assessment”. Offering the lowest price is not the way to go: “Being the lowest priced freelancer is certainly a differentiator, but it won’t do anything short-term or long-term to increase your differential value.”
Tom lists a dozen of possible differentiators including:
A specialism in service offering. Most of my competitors happily develop Qt applications for mobile, desktop and embedded. I don’t. I have niched down to embedded Qt applications.
A particular type of client served. My ideal customers are medium-sized businesses who develop a Qt embedded system themselves for the first time to have control over their own fate.
A unique style of delivery. My delivery style is characterised by using Kanban or Scrum for project management, TDD for programming, automated tests, automated builds and frequent releases.
Cross-over and supplementary skills to your core competency. This can be as simple as knowing how to cross-build Qt applications with CMake and how to integrate QtCreator with such cross-builds (see this post). Only few Qt consultants have this expertise.
Having a blog full of articles relevant to your client’s problems. I seem to get better at this, as I can refer my clients to my own articles more often. But way to go for me.
Your differential value will significantly increase your chances to close projects.
Providing Added Value. You don’t add value by giving a discount on your fees. You add value by “[including] items that aren’t of the same unit as those in your initial proposition. Items with their own separate and unrelated value. Preferably, items that don’t take you much time, if any time at all, to create, execute and deliver on an individual client basis.”
You could give your customers access to your knowledge database or an e-book about the service or product, in which they are investing. The marginal cost for you is minimal: granting access to a GitHub repository or sending an email with the e-book takes a minute or two. This is an area where I must certainly improve.
Pricing Methodologies For Freelancers
For each of the five pricing methodologies, Tom provides detailed sections How It Works, Example Scenario, Pros, Cons and How To Use Value. After reading these sections, you should have a good understanding of each pricing methodology. I’ll add my experience to each billing method.
Hourly Billing.
“Use [value] to set your rate”. For example, my rate for building a Qt embedded system (my niche) would be much higher than for building a mobile Qt app (little experience).
“Regularly raise your rate as you become more valuable over time”. I suggest to keep projects short, at most three months, which is just enough to demonstrate your true value. This gives you regular points, where you can raise your rate, switch to another pricing method or walk away from an awful project.
Daily Billing. When you equate a day with, say, 8 hours, daily billing is nothing else but hourly billing. Daily billing differs from hourly billing if you give the estimates in days and not hours. I think that you’d face annoying discussions, when you finish a task in 4 hours and take the rest of the day off.
Fixed-Pricing. Fixed pricing means that “that a body of work will be completed in its entirety for a set price. No matter how long it takes.”
It’s important that a fixed-price project has a very well-defined scope. You should be able to specify objective acceptance criteria, better even acceptance tests. Don’t use fixed-pricing if the scope is not crystal clear. Otherwise, you will lose out big time!
Productised services are well-suited for fixed pricing. They are a repitition of what you have done before with some small changes. Building a Linux image and SDK for known SoCs is a good example. If you have done the heavy lifting once, you can do the next repetitions with little effort.
I’d suggest to keep fixed-priced projects short, to 1-3 months. The bigger the scope the less accurate your estimate and the higher risk. Building a minimum viable product (MVP) in 1-3 months could be a good fit.
If you can attach good value to a fixed-price project, you’ll end up with a value-based project.
Value-Based Pricing. The value of a project is measured as the return a client gets from investing in your services. The value can be something tangible like selling 10% more machines per year or something intangible like improving the standing of a manager in a company. Value-based pricing is fixed-pricing on steroids.
Again, the project scope should be well-defined. And, you should agree on measurable outcomes with your client.
The price for a value-based project is considerably higher than for a fixed-price project. So, you can be slightly more relaxed with changing or expanding requirements. Ideally, you can replace an existing with a new requirement.
I think that small projects like a proof of concept, a minimum viable project and an architecture definition work best.
Retainers. An advisory retainer is a weekly, monthly or quarterly subscription to your brain (knowledge) or to your hands (labour). “A fixed-price is given by a freelancer to a client for their guaranteed availability through a period of professional time.”
“You might deliver more value in a 30 minute phone call during an emergency than in 40 hours worth of regular work. […] When you provide peace of mind and risk reduction, you can attach an appropriately high level of compensation to the retainer, without having all of your time specifically allocated.”
As the client and you can cancel the retainer at the end of each subscription period (e.g., a month), the financial risk for the client and you is small and manageable.
You may start a project on an hourly basis and help the customer to get up to speed, say, with an MVP. At some point, customers don’t need your services 8 hours per day, but they still want you to be available as an insurance. A retainer may be the right choice.
Pricing Preferences
"[Pricing] preferences are a personal set of rules that you aim to follow when pricing freelance projects”. These preferences shall prevent you from doing stupid things when pricing projects. For example, it would be stupid to use fixed-pricing for a project with unclear scope.
The table in this chapter gives Tom’s pricing preferences, which he worked out over 11 years of freelancing. The columns state, when he will use a methodology, which requirements and circumstances must hold and which supplementary assets (e.g., deposit, in-advance payment, pre-project, proposal) he must provide. This chapter alone is worth the price of the book.
It is important to understand that different freelancers have different pricing preferences. “A freelancer who is just starting their journey may conclude different pricing preferences from someone further down the line and there’s nothing wrong with that.”
When you start freelancing, it’s perfectly OK to use hourly billing. You can build up your value and a financial safety net. It’s a lot easier to say “No!” to a prospect, if your business account keeps you and your family afloat for another two years. Tom started with hourly billing and so did I. And, I am still doing it, although I try to wean myself off it.
Over time, you may feel the disadvantages of hourly billing. I did about two years ago. That’s when I started reading the books of Alan Weiss about value-based pricing and found my way to Jonathan Stark’s Ditching Hourly.
I failed with my first value-priced projects. Some proposals were not accepted, because customers didn’t see my value and regarded my prices as too high. One didn’t have a clear enough scope and my actual hourly rate was 30% under my usual hourly rate. My remarks above about fixed-pricing and value-pricing reflect my experience and will go in my pricing preferences.
Thanks to my blog posts, talks and this newsletter, I see the demand for several productised services. I’ll finalise these services over the next weeks. I am two months into my first advisory retainer. Both my client and I love it. Retainers seem to be a good way to get paid for my expertise. So, I’ll try more of them.
Reading
Patterns and Anti-Patterns for Easy and Fast Layout of Complex Desktop Applications (video) by Franck Arrecot (KDAB) and Philippe Hermite (Adobe)
For the past year, I have been overhauling an embedded Qt application using QWidgets. It was my first QWidgets application after 12 years. Layouting QML items is so much easier than QWidgets. Especially anchor layouts are sorely missing for QWidgets.
I had re-learned basic layouting with QHBoxLayout, QVBoxLayout, QGridLayout and QStackedLayout. There was one thing that caused me (even more) grey hair: dynamic resizing. Unfortunately, the talk doesn’t cover this complex topic. Franck just suggests to use QSizePolicy.
Franck explains the basic use of Qt layouts on a well-chosen example and uncovers performance issues with the different solutions. The example displays the properties of a QObject in a table. Each row has the three columns: the property name, the property value and an option edit button for integer-typed properties.
The first solution is to put each row into a QHBoxLayout and all the rows into a QVBoxLayout. Rows without an edit button position the property name at 0% and the value at 50%, whereas rows with an edit button position the name, value and edit button at 0%, 33.3% and 66.6%, respectively. The second solution uses a QGridLayout with three columns and with a variable number of rows. Names, value and edit buttons are properly aligned.
Franck tries out two approaches to change the value of integer-typed properties. Both approaches toggle between a QLabel for displaying the value and a QSpinBox for changing the value. Both QLabel and QSpinBox have their own layout. The first approach toggles the visibility of the two widgets, which leads to heavy flickering. The second approach uses a QStackedLayout to toggle between the two widgets. The flickering is gone.
Performance benchmarking of the QGridLayout solution with 10 and 100 rows reveals some interesting facts. For 10 rows, rendering of Editor in QStackedLayout is 2.3 slower than Editor in QBoxLayout. For 100 rows, it’s even 10.2 times slower. This allows only one conclusion: Do not use QGridLayout with QStackLayouts when you must display dozens, let alone hundreds of widgets. Use QListView, QTableView and QTreeView instead. They scale well for hundreds and thousands of widgets.
Using containers on embedded Linux by Sergio Prado
Sergio weighs the pros and cons of using Docker containers on embedded systems. The best known and most advanced container solution is Torizon from Toradex. I think that container solutions for embedded systems are missing from Gartner’s Hype Cycle for Embedded Software and Systems, 2020 (see ). It would be a technology on the rise, in the first phase of the hype cycle.
Pros:
Packaging your application in a Docker container and running the container on a ready-made Linux distribution (e.g., Debian for ARMv7 or ARMv8) is a lot simpler and faster than building a Linux distribution yourself with Yocto or Buildroot.
You can assemble your system from different containers like UI application, web server, window manager and network tools. Some of these containers are ready-made components whereas others are custom developments.
You get a “robust, fast and fail-safe update system” for free.
“Containers facilitate the partitioning of the system’s hardware resources” like the “application’s use of CPU, memory and I/O”. They also let you control the communication between containers.
Cons:
Containers consume much more RAM, persistent storage and CPU. Just think of a system with five Qt applications. Each application is package into a container, with its own set of Qt and other libraries. The applications cannot share the libraries - neither in persistent storage nor in RAM, as containers are isolated execution environments.
Cross-compiling applications and their libraries for, say, an ARMv7 container is more complicated than cross-compiling applications against a Yocto-built SDK. It took me a day to figure out how to build a Torizon container on the command line. Toradex provides a VS Code plugin to take the pain out of this step. Tool support for the command line is also a must-have, as we need it for automated application and container builds.
Updating the containers on a system becomes tricky, when they depend on each other and when they only work with certain versions of other containers. Yocto takes care of dependencies at build time and package managers at run time. Container-based systems don’t provide a solution yet.
Sergio concludes that he “[doesn’t] really know [whether] containers [are] the future of embedded Linux systems”. Containers may be good for rapid prototyping and for execution environments with contradicting dependencies. They are not ideal for small and medium-sized embedded systems, as they are too resource-hungry. “Only time - and the market - will tell. ;-)”
I’d like to add a warning. Containers are one of the most hyped technologies of the last years. However, they are not a silver bullet for every domain and every product. You should weigh carefully whether containers are the best solution for your Qt embedded system. They could be the preferred solution,
if you have a single custom-developed HMI application with a few off-the-shelf headless services,
if your time to market is very short, or
if you have to minimise your development costs.
OpenEmbedded and Yocto Project best practices (video) by Alexandre Belloni (Bootlin)
Alexandre gave this talk at the Embedded Linux Conference Europe 2020. He works for Bootlin, which provides excellent services and trainings how to build Linux systems with Yocto and BuildRoot. I found the parts about configuration files, release management and network access most interesting.
Configuration files. Alexandre explains which information goes into which configuration file: local.conf, site.conf, machine.conf and distro.conf. In local.conf, you define the characteristics of your build machine (e.g., number of cores and processes used in parallel). For releases, you never define parts of your image, distro or machine in local.conf - despite what numerous posts will tell you. Sometimes it may be useful to do that temporarily to try something out. But never for releases!
In machine.conf, you define the preferred providers of the kernel and bootloader. As the kernel depends on the bootloader and the bootloader on the machine, you add the bootloader and kernel with IMAGE_INSTALL_append in machine.conf. Note that IMAGE_INSTAL += doesn’t work in configuration files. You also specify IMAGE_FSTYPES, because the type of the image (e.g., *.wic.bz, *.tar.bz) often depends on the machine and not just the distro.
site.conf contains proxies, mirrors and sstate-cache shared by all members of a development team.
Release Management comprises the tagging of sources and images for a release and the generation of bblayers.conf and layer.conf at project setup. So far, Alexandre has been using the repo tool and a setup script. You specify in the manifest file, which layer repositories at which revisions the repo tool shall download. You pass the machine configuration, distro configuration and some other information to the setup script, which creates the bblayers.conf and layer.conf. I use the same approach in my post Building a Linux Image with Yocto.
Alexandre will give up the repo approach in favour of kas. With kas, you specify everything (layers, machine, distro, image, etc.) in a single YAML file instead of doing some bits in the manifest file and some other bits through the setup script. Kas then launches a Yocto build environment and builds a Linux image with bitbake. It sounds like kas gets your first Linux build rolling a lot quicker than the repo approach. I’ll definitely have a look at it soon and blog about it.
Network Access. When you release your product, you should make sure that you can build your complete Linux system without network access. When you must fix some issues in five years, you are guaranteed to work with the exact same sources as at release. Here is a quick guide:
Replace all AUTOREVs in recipes by a specific revision. The line SRCREV = ${AUTOREV} tells bitbake to download the latest version from a repository. This changes the source code from build to build.
Use BB_GENERATE_MIRROR_TARBALLS = "1" to generate tarballs of all git repositories in the download directory DL_DIR. Without this setting, bitbake clones the git repository into the package directory below build/tmp/work.
Archive DL_DIR and make tarballs available internally through pre-mirrors.
Set BB_NO_NETWORK = “1” to check for missing tarballs and overooked AUTOREVs.
Point bitbake to internal mirrors using PREMIRRORS and run a release build from scratch with BB_FETCH_PREMIRRORONLY = "1".
Optimizing Power Consumption in Battery-Powered Devices by Silard Gal
Silard does a fantastic job in explaining how to reduce the power consumption of embedded devices. Although I have a fairly limited understanding of electronics, I could follow Silard’s explanations easily. I might soon apply my newly acquired knowledge on a battery-powered bespoke tablet.
A power system consists of three parts: regulator, load and battery.
The regulator adjusts the voltage to the level required by the device and keeps the voltage stable. It’s important to choose a regulator with an efficiency of at least 90% and with a quiescent current between 5 and 15 uA.
The load comprises all the power-consuming parts like microcontroller, sensors and peripherals.
The battery provides power to the device. You choose the battery capacity once you have an estimate of the average power consumption and the required lifetime. If, for example, your device has an average power consumption of 57 uA and an expected lifetime of 1 year, your battery needs a capacity of 1 y * 57 uA = 8760 h * 0.057 mA = 499.32 mAh.
Silad provides 8 tips to improve battery life.
Create a battery budget. Estimate or measure the average power consumption for the different power modes (e.g., active, sleep and deep-sleep mode) and estimate how long the device is in each power mode per hour or day. You can calculate the battery life with this formula: Battery[mAh] / AverageConsumption[mA] = BatteryLife[h].
Set I/O to Low Power. Put the GPIOs of the MCU into low-power mode to prevent current from leaking in or out of the device.
Use Processor Power Modes. MCUs and MPUs come with different power modes (e.g., active, sleep and deep-sleep mode). When the screen of your phone goes black after 15 seconds, the phone goes into sleep mode. It may switch off the high-performance cores and wait for a wake-up trigger on a single low-performance and low-power core.
Turn Off Unused Processor Peripherals at boot time and disable peripherals when they are not used.
Control External Peripheral Power. When you turn off, say, the RS232 port of the MCU, you should also turn off the sensor connected to it. Of course, the sensor must have a power pin or a sleep mode.
Optimise Program Flow. The application should spend as little time as possible in the active power mode. You can simplify the calculations of the application or use more power-efficient communication protocols. You should give up regular polling for an interrupt-driven or event-driven design.
Increase Clock Speed to Finish Processing Faster. Depending on the power consumption per MHz, executing a function faster (at a higher clock speed) may turn out to be less power-consuming. Power consumption per MHz is where Apple silicon is several years ahead of its competition.
Use a Buck Converter or LDO. This is the one tip I don’t understand. If you, dear reader, can explain it to me, please hit the Reply button.
Copyright (C) *|CURRENT_YEAR|* *|LIST:COMPANY|*. All rights reserved.
*|IFNOT:ARCHIVE_PAGE|**|LIST:DESCRIPTION|**|END:IF|*
*|IFNOT:ARCHIVE_PAGE|**|HTML:LIST_ADDRESS_HTML|**|END:IF|*
Update Preferences | Unsubscribe
*|IF:REWARDS|* *|HTML:REWARDS|* *|END:IF|*