Skip to content

Welcome to blog.mbedded.ninja!

Use the links below or the sidebar (wide screens)/menu (mobile) to navigate through the different sections of the site.

Categories

Recent Updates

Happy New Year 2025

2024 saw 505k (505,000) page views for blog.mbedded.ninja! This was up from 436k last year, an increase of 69k or 16%. This is a placeholder for the reference: fig-stats-graphs shows the page views and other key stats per year.

Graphs of page views and content up to the end of 2024.

NinjaTerm went through 11 releases from v4.12.1 to v4.19.0. Some significant features were added, after it got turned into a PWA just before the start of 2024. It has 75 stars on GitHub and had 3.1k page views (as reported by Google Analytics).

NinjaCalc went through 2 releases from v3.5.2 to v3.5.4. These were minor releases which just fixed a broken URL and added the Umami analytics functionality. It has 30 stars on GitHub and had 52k page views (as reported by Google Analytics).

CppLinuxSerial went through 1 release from v2.8.1 to v2.8.2. This added changes to the CMake build system to allow add_subdirectory() to work correctly. It has 387 stars on GitHub.

Blog page views were based on a combination of Umami and Google Analytics. Umami was used were data was available due to it not being blocked by ad blockers, otherwise Google Analytics was used. Google Analytics values were adjusted to “Umami” values based on the average difference between the two. The average difference was calculated over all months that both were available. This is a placeholder for the reference: tbl-2024-page-views shows the page views for each month from the different analytics services. These were used to create This is a placeholder for the reference: fig-stats-graphs.

MonthUmamiGoogle AnalyticsUmami (interpolated)
Jan n/a 41k 54k
Feb n/a 42k 55k
Mar n/a 33k 43k
Apr 40k 30k 40k
May 40k 30k 40k
Jun 36k 32k 36k
Jul 39k 33k 39k
Aug n/a 28k 37k
Sep n/a 26k 34k
Oct 47k 30k 47k
Nov 44k 37k 44k
Dec 36k 24k 36k
Total n/a 386k 505k
The blog page views for each month from the different analytics services.

For all months in which data was available for both, Umami reported 282k views, and Google Analytics reported 216k views. Umami is 31% higher than Google Analytics.

This is a placeholder for the reference: fig-engagement-pages-and-screens shows the top 10 most popular pages, ranked by number of page views.

The top 10 most visited pages of 2024.

Blog Acquisition

This is a placeholder for the reference: fig-traffic-acquisition shows the top 7 sources of acquisition traffic in 2024. As usual, most of the traffic was from organic search (e.g. Google search engine).

Top 5 sources of acquisition traffic in 2024.

Blog Word, Page and Image Counts

At the end of 2024 the site had 704k words, up from 639k words last year (an increase of 65k). These words were spread over 1313 pages (up from 1221 pages last year), and included 3,222 images (an decrease of 1,296 from 4,518 images images last year). Even though many new images were added last year, the total dropped because I purged all of the redundant images that were still hanging around in the public/ directory from when the site was migrated away from Wordpress.

Achievements in 2024

  • The blog was migrated from Hugo to Astro.js. I’m really happy with the change, as Astro.js component syntax is much clearer than Hugo’s, and Astro.js lets me use React components if needed (I use React on a number of other projects).
  • I fully embraced the .webp image format (which has great compression size), and almost all new raster images are now in this format. .svg is still used for vector images.
  • Site-wide search was added to the blog. This became easier to implement after the migration to Astro.js.
  • Added a “cover image” feature to each page. Each page can now have a cover image assigned to it (a piece of metadata in the frontmatter). This cover image is used in the parent page’s “child pages” section to display beside the page description. It is also used for the social media preview image.
  • Added figure, table and equation numbering support (I had this in Hugo, but lost it when migrating to Astro.js).
  • NinjaTerm got heaps of new features added, after it got turned into a PWA just before the start of 2024.

Plans For The 2025 Year

  • Add more content to the blog (as always!).
  • Keep adding features to NinjaTerm.
  • Make sure CppLinuxSerial can work with CMake’s FetchContent feature (it’s an easy way to include external dependencies).

2025

Child Pages

December 2024 Updates

Add Relay Contact Forms Info

Added information about relay contact forms, e.g. Form A, Form B, Form C, Form D, and Form X.

Added a Page on Chip Carrier Packages

Added information about chip carrier packages, including PLCC, LCC, LCCC, and BCC.

Started a Page on Designing a HAL in C++

Added information about designing a HAL in C++.

Started a PCB Rework Guide

Started a page on PCB reworking.

Added Info on the MFF2 (DFN-8) Package Used For eSIMs

Added information about the MFF2 (DFN-8) package used for eSIMs.

November 2024 Updates

Added New Page On Creating Digital and Analogue Delays

Added a new page on creating digital and analogue delays. This includes delays using RC/Schmitt triggers, 555 timers, long pieces of wire, delay line ICs, bucket brigade delay ICs, and microcontrollers.

Added New Page on Bucket Brigade Devices

Added a new page on Bucket Brigade Devices.

Added Info on Zephyr’s nsi_exit()

Added more info on Zephyr’s native_sim board to the Zephyr page.

Added Info on Zephyr’s State Machine Framework

Added info on Zephyr’s State Machine Framework (SMF).

Added Info on Dry Relay Contacts

Added info on what is meant by “dry” contacts in the context of relays to the Mechanical Relays page.

Added New Pages on SOD-57 and SOD-64 Component Packages

Added new pages on the SOD-57 and SOD-64 component packages.

Updated the Object-Orientated C Page

Updated the Object-Orientated C page with info on polymorphism and testing.

October 2024 Updates

IEEE 2030 Smart Grid Interoperability Communication Protocol

Added information about the IEEE 2030.5 Smart Grid communication protocol.

Makefiles

Added information on changing directory and detecting the operating system in a Makefile.

Cellular

Added information on LPWAN (cellular comm. protocols designed for embedded devices/IoT), including LTE Cat M and LTE Cat NB (NB-IoT).

Simple Network Management Protocol (SNMP)

Added information on the Simple Network Management Protocol (SNMP), including network hierarchy, versions, and traps.

Running GitLab Pipelines Locally

Added information on how to run GitLab pipelines locally using the gitlab-ci-local tool.

Added a Astro.js Table Component

To support data-rich tables in .mdx files, I created a Table component.

The Table component allows you to pass in the data as a Javascript object, and it will automatically create the headers and rows from this.

Using Dev Containers for Firmware Development

Added information on how to use dev containers for firmware development.

Add Info on ESP32 and ESP-IDF

Added info on ESP32 SoCs and ESP-IDF.

Added Equation Referencing Support

When moving from MathJac to Katex (as part of the move from Hugo to astro.js), I lost the ability to reference equations from within text as Katex does not support the \label and \ref commands with automatically numbered equations.

To get around this, I add \htmlId{}{} markers in the Katex and implement the reset of the logic for equation referencing in the client-side IRefClientScript.js script (which already does the figure and table referencing).

Added Resistor Node Analysis Info

Added a convoluted resistor network example to show how to analyse the nodes in a resistor network to determine whether resistors are in series or parallel.

Added Info on Kirchhoff’s Circuit Laws

Added a new page on Kirchhoff’s Circuit Laws.

Added Info on Google Cloud

Added a new page on Google Cloud, including info on Firebase and the Firebase CLI.

Fixed Missing Square Root Symbols

I discovered this month that square root symbols were not rendering in any equations across the site. After much digging, I found at that this was because some Starlight CSS was messing with the svg used to render the square root symbol.

The offending CSS from Starlight was:

.sl-markdown-content :is(img, picture, video, canvas, svg, iframe):not(:where(.not-content *)) {
display: block;
max-width: 100%;
height: auto;
}

Specifically, it is the height: auto; which selects svg. Katex uses an svg to draw the square root symbol in equations (many other parts of the equation are not svg, which is why you may not notice anything is amiss!). I added the following CSS to custom.css to fix this:

custom.css
/**
This CSS fixes issue where \sqrt{} was not being rendered in Katex, due to a Starlight Css svg height rule
*/
.katex-html svg {
height: inherit;
}

Split the RF Info Into It’s Own Page

The RF connector info on the Connectors page was brought out onto it’s own child page. Info on reverse-thread SMA connectors was added.

September 2024 Updates

Split Battery Page

The Lithium Thionyl Chloride and Zinc-Air info have been split from the main Batteries page into their own pages. This was done to match the other battery chemistries.

Embedded Template Library (ETL)

Added info on the C++ Embedded Template Library (ETL).

nRF Connect for VS Code

Added info on nRF Connect for VS Code.

I2S Communication Protocol

Added info on the I2S Communication Protocol.

Cover Images

Added cover images to many pages, especially those in the Communication Protocols section.

Added Ability To Add Page Aliases

I added the ability for document pages to specify aliases. Aliases are great when you are moving pages around and the existing page is linked (and has a significant amount of traffic) from external sites. These aliases are added to each .mdx documents front matter like so:

src/content/pages/my-page.mdx
---
aliases: [/my-old-page/]
authors: [gbmhunter]
date: 2024-09-11
lastUpdated: 2024-09-11
tags: [my tag]
title: My Page
type: page
---
This is my page!

This field is specified in the content collection so it becomes available in the .data object when inside the getStaticPaths() function. To specify it in the collection’s schema, add the following to the src/content/config.ts file:

src/content/config.ts
const pagesCollection = defineCollection({
type: 'content',
schema: ({image}) => z.object({
aliases: z.array(z.string()).optional(), // Used to setup dynamic redirects. This is done in [...slug].astro
authors: z.array(z.string()),
date: z.date(),
description: z.string().optional(),
draft: z.boolean().default(false),
image: image().optional(),
lastUpdated: z.date(),
tags: z.array(z.string()).optional(),
title: z.string(),
}),
});

Then, in the [...slug].astro file which contains the getStaticPaths() function which determines the routes for the site, I check if the page has aliases and if so, add them to the static paths array. Alias paths are passed a aliasTo prop which is used to redirect to the correct page:

src/pages/[...slug].astro
---
export async function getStaticPaths() {
const combinedCollection = await getAllCollections();
const routablePages = getRoutablePages(combinedCollection);
const sidebarData = getSidebarData(combinedCollection);
let staticPaths = [];
for (let pageRoute of routablePages) {
//...
// Need to create additional paths if the page contains aliases in it's front matter
const aliases = pageRoute.data.aliases;
if (aliases) {
for (let alias of aliases) {
staticPaths.push({
params: { slug: alias },
props: {
aliasTo: pageRoute.slug,
// Nothing more is needed for the alias page
frontmatter: undefined,
render: undefined,
sidebarData: undefined,
},
});
}
}
staticPaths.push({
params: { slug: pageRoute.slug },
props: {
aliasTo: undefined,
frontmatter: pageRoute.data,
render: pageRoute.render,
sidebarData: sidebarData,
},
});
}
return staticPaths;
}
const { aliasTo, frontmatter, render, sidebarData } = Astro.props;
// Check if this page is an alias, and if so, redirect before attempting to render page
if (aliasTo) {
return Astro.redirect(`/${aliasTo}/`);
}
---

Created a Programming > Design Section

I decided that the Programming > General section was somewhat mis-labeled (what is “General” mean anyway?). Some of the pages under this section seemed to fit a “Design” section, so I created a new section called Programming > Design. As a start, the pages on state machines have been moved across.

Added Info on GNU Linker Scripts

Added info on GNU Linker Scripts.

Added New Optocoupler Schematic Symbols

Added new schematic symbols for bidirectional phototransistor optocouplers.

Moved the EEPROM Info to it’s Own Page

The EEPROM info has been moved from the Memory page to it’s own EEPROM page.

Added Code To Convert From Year/Month/Day To Day Of The Week

Added code to calculate the day of the week from the year, month and day in the Real Time Clock (RTC) ICs page.

Google Analytics vs. Umami

Umami has now been running long enough to do a useful comparison with Google Analytics. Below are the results for this blog, NinjaCalc and NinjaTerm. The time periods are slightly different for each site (due to different dates on which the data was valid).

Blog

Time range: 1st April 2024 - 30th June 2024 (3 months)

MetricGoogle AnalyticsUmami
Views92k116k
Visitors (Users)45k66.9k

NinjaCalc

Time range: 1st May 2024 - 31st August 2024 (4 months)

MetricGoogle AnalyticsUmami
Views13k4.32k
Visitors (Users)1.1k1.57k

NinjaTerm

Time range: 1st April 2024 - 31st August 2024 (5 months)

MetricGoogle AnalyticsUmami
Views1.5k3.21k
Visitors (Users)5901.18k

Added Info on the Memfault CLI

Added info on the Memfault CLI.

Updated Menu Styling

The default Starlight menu styling provided different font size and weights to sections and links. Given the arbitrarily nested nature of this site’s menu hierarchy, this did not look that great. I decided to make all the menu items look the same. To this I add to add some more selective CSS that would override the default Starlight styling.

A comparison of the old and new menu styling.

Info on Phototransistors

Added info on phototransistors, including the schematic symbol and a basic circuit.

Added Figure/Table Numbering and References

I wanted to be able to refer to figures and tables within page text using syntax like “Figure 1”, “Table 2” e.t.c, rather than “see the figure below”. Unfortunately this feature is not supported by .mdx out-of-the-box.

I figured I had two options to implement this:

  1. Write a remark/rehype plugin that runs during the build process.
  2. Write a Typescript script that runs on the client’s browser.

Even though the remark/rehype plug-in would of have been the best for load speeds, I decided to go with the Typescript route as it would be easier to implement (I have no experience with remark/rehype).

I decided to call this feature “Item References” to distinguish them from the references already used to cite sources. I made a <IRef /> Astro component that can be used to reference items. This allows page authors to write this:

src/content/pages/my-page.mdx
<IRef iref="my-figure" /> shows my picture I made. Yay!
<Image iref="my-figure" src={import('./_assets/my-figure.webp')}>A picture!</Image>

The user will see <IRef ... /> replaced with the text Figure 1, and the figure will have Figure 1 prefixed to the caption text.

So far only images and tables can be referenced, but I plan on adding support for equations and code snippets soon. The entire client-side script can be shown below.

The client-side script source code
src/js/IRefClientScript.ts
/**
* This script is run in the user's browser and adds "Item Reference" (IRef) functionality.
* Item references are used to link to specific elements in the page, such as figures, tables, equations, e.t.c. They
* are different from "references" which are used to cite sources.
* It prefixes figure captions with "Figure 1", "Figure 2", etc.
* It also looks for <IRef /> components and replaces the text and link to the corresponding item.
*/
/**
* Represents a reference destination in the page.
*/
class RefDestination {
type: string;
index: number;
ref_name: string;
constructor(type: string, index: number, ref_name: string) {
this.type = type;
this.index = index;
this.ref_name = ref_name;
}
}
function create_ref_links() {
let found_iref_destinations: { [key: string]: RefDestination } = {};
const markdownContentDiv = document.querySelector('.sl-markdown-content');
if (!markdownContentDiv) {
console.error('markdownContentDiv not found');
return;
}
// Find all figures.
// 1) Prefix figcaptions with "Figure X: "
// 2) Add figure to found_ref_destinations if ref present
const figures = markdownContentDiv.querySelectorAll('.figure');
console.log('figures', figures);
figures.forEach((figure, index) => {
const figcaption = figure.querySelector('figcaption');
if (figcaption) {
figcaption.textContent = `Figure ${index + 1}: ` + figcaption.textContent;
}
// If figure has an id, add it to the found_ref_destinations array
const iref = figure.getAttribute('data-iref');
if (iref) {
found_iref_destinations[iref] = new RefDestination('figure', index, `Figure ${index + 1}`);
}
});
// Find all tables under the markdown content div
// 1) Prefix table captions with "Table X: "
// 2) Add table to found_ref_destinations if iref present
const tables = markdownContentDiv.querySelectorAll('table');
console.log('tables', tables);
tables.forEach((table, index) => {
console.log('table', table);
const tableCaption = table.querySelector('caption');
if (tableCaption) {
tableCaption.textContent = `Table ${index + 1}: ` + tableCaption.textContent;
}
// If table has an iref, add it to the found_ref_destinations array
const iref = table.getAttribute('data-iref');
if (iref) {
found_iref_destinations[iref] = new RefDestination('table', index, `Table ${index + 1}`);
// Add id to table so we can link to it
table.id = iref;
}
});
console.log('found_ref_destinations', found_iref_destinations);
// Find all ref-source elements and link them to the corresponding item ref in the page
const refSources = document.querySelectorAll('.ref-source');
console.log('refSources', refSources);
refSources.forEach((refSource) => {
const ref = refSource.getAttribute('data-iref');
console.log('ref', ref);
// Check if ref is in found_ref_destinations
if (!ref) {
console.error('ref not found in refSource', refSource);
return;
}
if (found_iref_destinations[ref]) {
refSource.textContent = `${found_iref_destinations[ref].ref_name}`;
} else {
// This is an error, it means there is an <IRef /> component in the markdown
// that does not have a corresponding figure, table, etc.
console.error('ref not found in found_ref_destinations', ref);
}
});
}
// Create ref links on page load (e.g. navigating to the site from a different site)
create_ref_links()
// Re-link figures after swapping pages (i.e. navigating between pages on this site)
// We need to do this because page transitions do not reload the entire page and
// trigger this script file to be reparsed.
// Using after-swap is better than page-load because it is before the page is rendered
document.addEventListener("astro:after-swap", create_ref_links)

August 2024 Updates

Load Dumps

Added info on TVS diodes used in automotive applications to protect against alternator “load dumps”.

Inline Imports

Converted the separate “import then Image component” style images in MDX pages to inline imports.

Child Page Images

Added images to the child page links shown on parent pages.

Astro Content Collections

Moves all updates into their own Astro content “collection”, rather than being mixed in with the pages collection.

Recent Updates to Home Page

Added the most recent 12 updates to the home page underneath the main content links:

Trivial File Transfer Protocol (TFTP)

Added information on the Trivial File Transfer Protocol (TFTP).

Cover Image Aspect Ratios

Experimented with different image aspect ratios for page cover images. The main aspect ratios I tested were 4:3 (old TV), 16:9 (HD), and 1.91:1 (recommended by Facebook for sharing). Eventually I settled on using the 16:9 aspect ratio with a resolution of 1280x720px.

On/Off Controller ICs

Added info on on/off controller ICs.

chown

Added info on chown.

July 2024 Updates

Migration from Hugo to Docusaurus then Astro.js

This month I migrated this site from Hugo to Docusaurus and then finally to Hugo. The first attempt was to migrate to Docusaurus. The main reason for this was to take advantage of the more modern React-based framework that Docusaurus provides, as well as the ability to use MDX for content pages. MDX allows you to embed React components within it when you want to add functionality to page above and beyond what standard markdown provides. Over the last 5 years I had found Hugo’s shortcode syntax to be a bit clunky and difficult to work with, and I was looking for a more modern solution. Given I am already familiar with React due to the NinjaTerm and NinjaCalc projects, Docusaurus seemed like a good fit. It also has a built in theme which suited this site well, reducing development time.

The Docusaurus theme should have much better responsive design than my self-written Hugo theme.

A screenshot of this website before migrating to Docusaurus.
A screenshot of this website after migrating to Docusaurus.

Unfortunately, I encountered some serious issues with Docusaurus late in the migration process. The biggest issues were build time and memory usage. The build process was taking over 10 minutes and using approx. 5-7GB of RAM when running on my Windows laptop. The build was failing in the Netlify pipeline due to it exceeding the pipeline limits (8GB is promised, so presumably the total system usage was exceeding this).

So I decided to migrate to astro.js instead, leveraging the Starlight theme (which is designed for documentation). Luckily, astro.js supports MDX much in the same way Docusaurus does, so not as much per-page porting was required. I had to add some imports to each .mdx file (I couldn’t work out how to add global imports to all .mdx files), and I had to replace my inline require() statements in the <Image> component’s src with a separate import statement above it.

Added New Info on MAHD

Added new info on the MAHD (Modified Agile for Hardware Development) project management methodology.

June 2024 Updates

I added the ability to change basic port settings in NinjaTerm from the right-hand drawer. This was a feature request by a user.

You now have the ability in NinjaTerm to send a break signal at the end of every line in a hex macro. This was another feature request by a user.

I added a page to this blog on how to choose serial numbers for embedded devices. It shows the way to calculate the mathematical probability of a collision when using random numbers for serial numbers.

I added a page to this blog on ANSI escape codes.

April 2024 Updates

NinjaTerm got four releases this May! Given all the time I spent on NinjaTerm there were no updates to this blog.

NinjaTerm can now display numerical data types such as hex, uint8, uint16, float32, e.t.c.:

You can now send a 200ms break signal by pressing Ctrl-Shift-B when the terminal is focused and the serial port open.

You can now specify a custom baud rate, and updated the default baud rates to include more common options.

A circular progress modal is shown while the port is being opened.

NinjaTerm has a new macros feature which lets you send pre-defined ASCII or HEX sequences out the serial port:

You now have the ability to select the flow-control method (none or hardware) when opening a serial port:

NinjaTerm has a new profiles feature which lets you save and load different serial port configurations.

April 2024 Updates

Added links in the top navbar to NinjaTerm and NinjaCalc.

New page on the PowerPC e200 CPU architecture.

New page on controlling a LED using PWM.

Added a new page with info on system basis chips (SBCs).

Improved the consistency and look of a number of component package pages by removing the old table design and adding more references.

Add more component package pages for the packages in the DO-204 family.

Added more info on EMA filters.

Added a new page on the SMF (DO-219AB) component package.

Added info on bitter coatings added to coin cells.

Started a new page on Optimizing BLE for Low Power.

March 2024 Updates

Released a new version of NinjaTerm, v4.13.0 which adds smart copy/paste support with Ctrl-Shift-C/V.

Started using Umami Analytics for analytics alongside Google Analytics. Umami is self-hosted on a Amazon Lightsail instance. The subdomain umami.mbedded.ninja points to the IPv6 only instance. If Umami works well (it’s privacy focused and is unlikely to be blocked by ad blockers), Google Analytics will be removed in the following months.

Added a new page on how to setup Umami Analytics on Amazon Lightsail.

Added info on C compile-time asserts().

Added a new page with a small amount of info on Infineon 32-bit AURIX TriCore MCUs.