03. January 2022 · Categories: .NET

As a C# programmer, Icon DLLs are a leftover from Windows XP days, but I recently needed to create one. The process is non obvious, but quite simple.

  1. Create a new DLL project for the icons, and remove the default class. To keep things portable, all icons should be in the project folder.

  2. Create a stand alone “Native Resource Template” with File | New | File

  3. Insert a dummy resource, then use File Save As, with the file type “Win32 Resource File”, to move the template to your project folder, and delete the dummy resource again.

    This is needed because the Save As refuses to save a template without any resources

  4. Right click to “Add Resource” and import all your existing icons

  5. In the project properties, tab “Application”, choose Resource file for resources, and select your .res file

  6. Add a reference to your icon and res files into the project to make them easier to open, with build action “None”.

08. November 2021 · Categories: Embedded

When using maths on a Cortex-M project, I ran into the problem that the linker would not find the pow function, which should be available. It turned out that the make files I was using were not correctly configured, and I got a basic lesson in diagnosing linker problems.

First is to get some diagnostics to figure out the problem. These are basically the --verbose option to get info about the libraries being loaded, and then --trace-symbol=mysym asks the linker to tell you when a symbol is introduced. Then you can use nm -gC lib.a to figure out whether the symbol is actually defined. If you use gcc to invoke the linker, remember that you need to forward linker options, e.g., -Wl,--verbose.

Now if the symbol is defined, but still not found, the culprit could be the link order. The linker keeps a table of defined elements, and required references. When an object file is found, all exported elements are added to its defined list. But when a library is found, only elements that are already a required reference are added, which is then repeated within the same library to resolve dependencies. This means that libraries must be always behind the object files, and if they have dependencies, must be ordered highest abstraction level first. You can use --start-group archives --end-group to group multiple archives so that dependencies between them are recursively resolved, but it costs performance. With --undefined= and --require-defined=, you can force including symbols from libraries. It would help with resolving dependencies in one pass, but it is brittle and should be avoided.

23. October 2021 · Categories: Apple

Rumors are that Apple will not provide an update for the iPhone 13 mini, because of disappointing sales. I believe this is because it is not mini enough. The standard size iPhone is just small enough to hold in one hand, and scroll through content, and the mini is already too large for typing one handed.

iPhone Sizes

The main culprit is the width. 64.2mm are 5.6mm more than the 5, and only 2.8mm less than the 6. It does not feel small in hand, it feels pretty close to a 6.

I believe Apple should recognize that the mini is a speciality phone, put it onto a triennial update schedule, and make it small:

  • 59 mm width would make it fit nicely into a hand again

  • 120g weight is the sweet point so that it does not feel too dense

  • 9mm depth would still be acceptable if needed.

For the small size, some compromises will be necessary. Important is to keep the battery life of the 13 mini, the full frontal screen with Face ID, and front and back cameras. With corona, adding Touch ID to the power button as well would be nice. I prefer having only one large back lens, similar to the normal on the 13 Pro, together with Lidar to provide some depth sensing. It does not need mmWave support, the standard 5G bands can provide 100 Mbit/s easily. It does not need a glass back, a combination of aluminium and carbon fibers can keep the weight down.

18. October 2021 · Categories: .NET

In WPF/XAML, you will very often create your custom templates for containers, and one of the issues is to properly adjust the template contents with its container.

The most common problem is making the template fill the container completely. This is done with the properties HorizontalContentAlignment and VerticalContentAlignment of the container, setting them to Stretch. You can then use the Margin of your top level template element for positioning.

When we need more precise control, we can do calculations with a converter based on the actual layout parameters of the container. You get that info with a RelativeSource binding in FindAncestor mode.

This requires you to add a simple converter to your project to do the calculation:

and include it in your application resources

17. October 2021 · Categories: Apple

My 45mm Watch has arrived, in a nice midnight blue.

Watch with black armband

Midnight Apple Watch 7 with black armband

The color is much darker than I was originally afraid of. It is very close to black, even closer than dark navy suits, and so can be easily combined with any color. I like it better than the space gray of my old watch.

It is quite large. If you wear long sleeves, it is most noticeable, as now a part of the watch will remain covered when casually raising it. Unlike the 38mm/42mm of the original, which registered as normal/small, 45mm/41mm should now be seen as large/normal. If you are in doubt about the size, get the 41mm.

First thing I was looking at was replacing my trusty old Modular face with the new Infograph Modular. I was in for a shock of ugliness.

Modular Face

Infograph Modular Face

The purple face now has a dominant color of white. I understand that on a small display you will want white for the best constrast when the text is small, and this is done correctly in the temperature range, but what is the point of changing the color when it only changes a small accent? You can also see that the 60% text is not properly aligned.

Interestingly, other faces use an inverted color scheme for the complications, as the new Contour face.

Contour Face


And both are not appropriate. For readability we want all tiny text in white, no point of adding information if you cannot read it. You also want enough contrast in the dial, not one color where you have trouble seeing the important detail.

Instead, I would use the colors differently to ensure both pretty good readability, and to keep our color the dominant element in the interface:

Modular Redesign

10. September 2021 · Categories: Software

Adding a lot of files, spread across multiple directories, to a SeggerStudio project is annoying, so I was looking for a faster way. Fortunately the project file is simple XML, so I can use unix tools to automate this a bit. The find tool is extremely powerful, and allow me to generate all the references in one go:

find .. \( -name *.c -o -name *.h \) -printf ' <file file_name="%p" />\n'

  • the group with the two -name patterns allows me to select all C header and source files. It must be grouped so that the printf applies to everything found.
  • the -printf then prints them out in exactly the form to paste them into the emProject file
26. April 2021 · Categories: Software

Sometimes it is very useful to attach a debugger to an already running target. With the STM32CubeIDE, the ability exists but is a bit convoluted to activate. This turns out to work:

  • start with your existing debug configuration, under Run|Debug Configurations…

  • Duplicate it and rename it to “Attach”

  • In Main, disable auto build

  • In Debugger, uncheck “Verify flash download”, and set the reset behavior to “None”.

  • In Startup, edit all the load images to no longer download

The option Debugger|Reset behaviour tells GDB what to do after it attaches:

  • Connect Under Reset will put the device in reset, then connect

  • Software System Reset will connect, then trigger a software reset

  • None will keep the device running

26. April 2021 · Categories: Software

freeRTOS has the ability to collect run time statistics when you activate the configuration configGENERATE_RUN_TIME_STATS. You still need to implement the timer yourself, though. On the Cortex-M processors, a pretty generic way is to use the system timer, so I adapted it to provide timing information with a 1µs resolution. Because freeRTOS uses 32bit numbers to store the counter, it will overflow after 70 minutes. For most performance checks that should be ample, but you can always change runTimeCountsPerSecond below to match your needs.

The code avoids costly divisions by first calculating the inverse, and scaling it with a shift to achieve a good compromise between speed and accuracy. This optimization is because the counter will be retrieved with every context switch, and so slightly distort the measurements.

Erich Styger shows a few alternatives. There I also learned that the tick counter must be atomic (portTICK_TYPE_IS_ATOMIC), which is always the case on Cortex-M, but could trip you on other CPUs.

26. April 2021 · Categories: Software

Typically, freeRTOS uses preemptive multitasking, which can lead you to needing to guard anything shared between the tasks. That is prone to mistakes, and thus I prefer to use cooperative multitasking instead.

There is an option, configUSE_TIME_SLICING, that can disable time slicing, but it only prevents the scheduler from interrupting the current task with another task of the same priority. The kernel still switches to another task of the same priority when a higher priority tasks interrupts, and then returns to another task. So the option does not provide protection from getting interrupted, it just removes some overhead. A better implementation would allow to set the number of ticks per time slice, in case you want high precision in the timers, but also avoid the overhead of very short slices.

We can provide correct cooperative multitasking in the following ways:

  • Timers: They all run in one task, but then a long task could block.

  • Event task: You have one central event queue, and the main program just processes these events. This is also recommended for timers, use the timer tasks to post to the event queue, and so prevent blocking from longer processing.

  • Global Mutex: a mutex protects the main data structures, and all tasks just take it when doing work. You then must yield regularly to allow the other tasks to proceed. That would be a sequence of xSemaphoreGive( xLock); vTaskDelay( 0); xSemaphoreTake( xLock, portMAX_DELAY);

To reduce time slicing, add an option configTICKS_PER_TIMESLICE that defaults to 1, and the following code to tasks.c. I modified version 10.4.3.

11. March 2021 · Categories: .NET

I recently was adding binding support to a custom WPF control in .NET, and was checking how you can integrate information from the bindings Binding.UpdateSourceTrigger setting. But you do not need to implement anything. If you just post an update on every change, the binding system itself will prevent the updates from being forwarded if you use a different mode than UpdateSourceTrigger.PropertyChanged. It might be useful to look at BindingOperations.GetBindingBase to retrieve the Binding, and determine when you need to post updates, but that is a performance optimization, not needed to get correct behavior.