Saturday, 25 January 2025

RISC-V Bare Metal OS

Intro

I saw this article on hackaday and, as you can imagine, it set my heart racing.

Bare-metal programming isn't trivial, it typically requires intimate knowledge of hardware and a good understanding of assembly language programming.  The thought of writing a bare metal OS is pretty stunning - it isn't something I have contemplated previously.

I don't want to try learning a new assembly language but I am familiar with RISC-V assembler so I am not put off by it.
This project is built on QEMU so it avoids the need to purchase some new hardware.  In addition real-world hardware programming often has a tortuous method to load and test programs which it is good to avoid.

Preparation

There is an excellent online "book" which shows the code required at each step and clear instructions how to build and test it.

The installation instructions didn't work on Windows (always some complication with Windows) so I setup on PI41 linux where everything worked perfectly.

Code for the project is compiled using Clang (front-end) / LLVM (back-end).  Programs are written in C.  The small amount of assembly language required is incorporated using inline assembly instructions.  This closely integrates the C and assembly code so that they share data easily.

The only other software required in addition to QEMU, Clang and LLVM is openSBI.

QEMU includes a nice "generic" platform for RISC-V virtual machines called 'virt'.  The specification is shown on the right.  There is much more virtual hardware provided than we need.  In fact we just need an RV32 core, some memory and the UART console.  Later on we will add disk I/O for which we will attach a virtio device to the Virtual Machine.

Even though we are doing bare metal programming we need lower-level firmware SBI  (Supervisor Binary Interface, like BIOS/UEFI) to initialise the hardware prior to loading our programs.  Fortunately there is an openSBI implementation for our 'virt' machine.  This gives us everything we need.

First Boot

There is a lot of magic in our first step.

The memory layout is define in kernel.ld.  There are four sections text(the code), rodata (read-only data), data (variables), bss (zero-initialised variables).
Code and data are placed in memory starting at 32-bit address 80:20:00:00.  32 bit addresses provide 4GB storage.  "80" tells us that we are in the top half of storage (reserved for supervisor mode?) and "20" tells us that the start address is 2MB from the start.
The entry point will be the boot function address.

Our minimal first supervisor code is very short.  Luckily most of it can be written in C, in line assembly is used where C cannot cope.
The boot function, simply sets the stack pointer and jumps into the kernel_main program.  There are only two assembly instructions required, move and jump.
All the main program does is to initialise memory and  then loop for ever.  The important memory addresses (such as stack_top) are defined in kernel.ld and can then be referenced in kernel.c



The program is compiled to an ELF executable kernel.elf, we can look at the assembly using llvm-objdump, as shown above.  QEMU starts OpenSBI to initialise the hardware then loads and executes kernel.elf.  Our program doesnt do much, using the QEMU console we can see it loops at 80200050.

After our exercise we have a working environment, we have initialised our machine and loaded a minimal supervisor.  Excellent!

A Diversion: online compiler

The "book" mentions that Compiler Explorer is an online tool which enables you to see how a compiler translates C into assembly language.  This can be very useful when writing a mixture of C and assembler.  Code produced by compilers is very specific to the the compiler brand, its versions and switches used to invoke it.  For example Optimisation switches affect the code generated.  In our case we will be using riscv 32 bit clang as the variant.  The screenshot below shows how the compiler translates a simple square function.



Hello World!

We have now mastered our memory and CPU and we have compiled, loaded and executed our simplest kernel.  An OS which doesn't communicate with the outside world is useless and our next step is to print messages to our console.  Luckily OpenSBI has setup our virtual hardware console so we dont need to control the virtual serial UART directly to write to the console.  Instead we make an "ecall" to openSBI including the character we want to print within the parameters and let it work out the details.  The OpenSBI specification is available on github. 





To write a character to the console SBI provides a "putchar" function.   I dont quite understand the syntax but we set up risc-v registers a0-a7 as parameters to the sbi_call function, then we put the character to print ch in a0, and the putchar function id #0x01 in a7 and make the call.

The result is a "Hello World!" message on the virtual console.


Once we have a putchar function available in our C environment we can write our own printf function so that we can print formatted numbers, strings etc.



The printf function provided here is a simplified version which prints numbers and strings but is still very powerful allowing a list of variables and expressions to be printed.



C Standard Library

Previously we implemented a simplified version of the standard library functions printf to print a string to the console.  Looking at the code in printf we can see it is standard C, we don't need any environment specific coding.  There is a hint we could copy functions from the standard C library into our program, saving us a load of working and giving us many tools to help write our kernel.  However, in practice the C standard library is very complicated. I looked at vprintf.c which is the "Actual printf innards", it says in the header "This code is large and complicated".  The C header files and code are much more advanced than me and I dont want to make this project about learning a lot about C pointers.

The instructions provided actually give us a small set of subroutines which we will need to help us.  The ones we have available are memset (initialise a range of memory), memcpy (copy a range of memory), strcpy (copy a string), strcmp (compare two strings).


Intermission

We are making wonderful progress with our kernel.  We have been able to use openSBI to setup our RISC-V VM and we are able to write C programs which communicate with the SBI API to utilise our virtual hardware, in particular to print messages on the virtual console.


Wednesday, 15 January 2025

Virgin TV Automation

 Intro

In September 2024 it was time to participate in the annual Virgin vs Sky renewal debate.  Virgin come up with a deal each year to make it too much hassle for me to change over to Sky.  This year the deal required a mandatory upgrade from Tivo to Virgin TV Go 360.  Our set top box remains the same but the Tivo software has been replaced by Horizon from Liberty Global, Virgins parent company.  The new software looks more up-to-date / standard and has a few more features, for example personal profiles and voice control through the remote.

In addition to watching recordings on the TV from the  Virgin set-top box we also watch downloaded films / series from our home server.  Fiddling around with multiple remote controls is becoming more of a pain, particularly when the programme maybe on the Tivo, available via catchup or downloaded onto the local network.  I felt it was time to come up with a better solution based on a browser application.

Approach

Home Assistant (HA) can be used to control a wide variety of electronic devices.  As well as integrating with most vendors IoT apps, the open source community has added many more "integrations" for a myriad of devices.

In my scenario I would like a HA running on an iPad or phone to provide all the functions I currently use on the Samsung TV, Virgin V6 set-top-box and Yamaha Soundbar with remote controls.

Samsung TV has its own HA integration and also an IoT app called Smart Things which HA can utilise.
Virgin has its TV Go app which is closely integrated with the V6 box but isn't incorporated into HA.
The Yamaha soundbar only has an infra-red remote control interface so any automation would need to be integrated using a Broadlink IR sender.

Solution

My intention was to combine Samsung, Tivo and Soundbar(Broadlink) functions into a single web browser based HA dashboard.  The project seems to be never-ending so I will outline the solution as it currently stands and, maybe, provide more technical detail and describe enhancements later.  The screen layout changes, depending on whether you are using Samsung TV or Virgin Tivo functions and the two layouts are shown below.


In the top part of the app there are buttons to turn equipment on/off, choose a source to display on the TV and control volume.  The bottom half of the screen contains all necessary buttons "copied" from the Virgin (red) or Samsung (blue) remote controls.

The power button switches TV, Tivo and Soundbar on/off at the same time.  The green sound buttons allow you to change the soundbar volume or mute it.

The TV source is usually Virgin Tivo so the set of red buttons is displayed allowing you to change channels, obtain program info, look at the TV guide etc.  Lots of the virgin channels are password protected during the day and earlier evening so I added a "code" button which inserts the password for you.  I also added some preset channels which may be of use when channel hopping.
There is a single button to access the Tivo recording screen, you can then navigate and choose the recording you want using the red arrow and OK keys in the normal way.

The downloads button takes you to the top level menu for films and programs downloaded from the internet.  Again you use keys and ENTER as usual, this time using the blue buttons, to choose and play your recording.  During playback there are also fast forward, rewind and pause buttons.

There are also buttons for Netflix and Amazon so that their programs can be selected using the app.
We dont currently make use of them but I have included Youtube and Internet browser buttons to access the built in functions which Samsung provide.

Although we dont watch it much there are lots of programs, including a wide selection of filsm on Samsung TVPlus.  The blue buttons allow you to choose channels, and I have set up a number of presents - although, irritatingly, channel numbers appear to change regularly.

Conclusion

TheVirgin TV Remote project seemed to be quite straightforward to start off with but there are many functions which need to be implemented.  Each time I look at it I think of enhancements which could be made.  We are just starting to use the version which has been outlined above and it will need some "rough edges" smoothed out before going much further.

The current system is excellent in a number of ways, so it is meeting expectations already.  In particular:
  • All devices are powered on/off by a single button instead of using three different remotes.
  • Most days, the app is all we need, the remotes aren't required.
  • All viewing sources are grouped together making it easier to find/choose the one you need.
  • A single button press is required to access Virgin recordings - instead of about 6
  • A single button press is required to access download folders - instead of about 6
  • Presets are available for favorite Tivo channels as necessary
  • Parental codes can be entered with a single button
There is a lot more that can be added but I should be content with what we have for the moment.










Samsung TV

The HA Samsung integration can select between TV+ and HDMI sources, change channels and simulate pressing buttons on the remote control.  An improved integration is available on a github repository by ollo69. It has some extra features


In particular, it can use the SmartThings API to obtain better information about channels/sources and has more remote controller key-press capabilities.

Our main interest for the remote control is to set the "source", this is to choose what is displayed on the TV screen.  Most of the time we use the Virgin Set top box and the source is set to "Virgin".  However Youtube, Amazon, Netflix can also be used.
Our basic script to send one or more key presses uses the standard SamsungTV remote HA entity to send a command to the living room tv.  "{{ key_sequence}}" is an argument providing the key definitions.
For TV+ and Virgin, keys are KEY_TV and KEY_HDMI (as Virgin box is connected to HDMI1).

For YouTube and Internet we use the ollo69 Samsung media.player entity to play an application.
The Youtube app is "111299001912" and the Internet browser is "org.tizen.browser"

For Netflix and Amazon I couldn't get the apps to work, so I had to use a sequence of remote control keys.

The sequence of keys shown on the left: HOME, followed by right-arrow three times then Enter starts Amazon.

We can use the SmartThings Key ST_VD:RouterShare as a key_sequence for  the ollo69 entity media_player.samsungtv55 to select the RouterShare source.  Unfortunately, although there are other sources and Apps available in SmartThings I haven't had much luck in accessing them (yet).  In particular I have failed to access USB sticks.  As the source order changes if a USB stick is removed/inserted we cant use "arrow" keys automatically to select them.



3D Printer

 


My main Christmas present, bought jointly for me by the family (organised by Alex) was an Elegoo Neptune 4 Pro 3D printer.  This introduces me to an indispensible tool of the maker world.

There is a fair amount of careful assembly work required.  Luckily a video and instructions provide clear details for each step.  Assembling it myself also provides a basic understanding of the parts and mechanism.  There are three axes controlled by stepper motors which are accurate to 0.01mm.  An extruder heats up filament so that it is soft and comes out of a nozzle where it is built up in thin layers (maybe 0.04mm) into shapes.

The base plate needs to be carefully levelled.  The method makes the level accurate to less than the thickness of a piece of paper over the base.


My first test print, provided on an Elegoo USB stick was a buddha about 2cm high.  The level of detail and surface smoothness achieved was excellent.  The print took about 30 minutes, which seemed slow but is much faster than earlier printers.

The next couple of experiments were a tetrahedron and a "gyro" keyring both of which came out brilliantly, perhaps as good as you would expect from shop bought items. 

My first proper build is a collapsing pirate sword for Harry jnr, it is amazing.  I saw it on a great turoial from Everything STEM.  You print it in situ on the printer and when you pick it up it telescopes into a full-length sword.






Tuesday, 14 January 2025

Mathematics

Polyhedra

I have become interested in polyhedra recently.
I have some small platonic crystals, some lovely solid stone cuboctohedrons and an obsidian tetrahedron.

Solid Starred Rhombicosidodecahedron

This interest reminded me of an idea I had when I was about nine years old.  At home there was a Time-Life book of Mathematics which included many subjects I found fascinating.  In particular there was a picture of a complex polyhedron which I decided I could make.  I knew about simple nets to make tetrahedra, cubes etc and after much time/thought I worked out the net for a Rhomibicosidodecahedron.  I purchased some cartridge paper (from Crawfords paint/art shop), drew out the net and glued it together.  The final stage was to make some three, four and five-sided pyramids which were glued on to the surface.

The resulting object was about 18" in diameter and looked very impressive.  I was proud of the result and kept it for a few years, although unfortunately no pictures of it remain.

Time-Life

The Time-Life Mathematics book was very accessible, easy to read with plenty of informative illustrations.  It inspired my interest in Mathematics and of late I have become obsessed with finding a copy.  Although I recalled its title was "Mathematics" I didn't have much recollection of what it was but eventually found it was a "Time-Life" book (I had imagined it was from Readers Digest).

In December I discovered its author is David Bergamini and found a copy on the Internet Archive which I could look through.  There were numerous pages, particularly pictures that I clearly remembered I decided I must obtain a copy.

The book was first published in 1963 with a later edition in 1969.  In 1963 I was six so it must have been that edition that my family owned which I remember.  There was a copy on sale on ebay in America and luckily as Harry and Leah were in California at the time they were able to buy it for me and bring it back with them.

Memories

Here is a selection of pages I remember very clearly from all those years ago.






PS

Now I have a 3D printer I can actually print out the smaller rhombicosidodecahedron.  The version I made was covered with 3,4,5 sided pyramid making it a solid starred rhombicosidodecahedron.

This is the net