Introduction

Introduction

This site is focused on my own notes relating to work on the nanoFramework.

The open-source documentation for nanoFramework created by volunteers can be found at docs.nanoFramework.net.

For more detailed information on the nanoFramework hardware and software architecture, see Understanding nanoFramework Architecture.

The nanoFramework

nanoFramework runs on many MCU devices and platforms with the smallest as low as 256kB of flash and 64kB of RAM. although this is constrained. I have opted to use MCU's with a larger Flash/RAM base.

Below is a quick list of some of the benefits

  • Embedded MCU programming with the C# language

  • Fast startup

  • Runs on a small Real Time Operating System

  • Supports common embedded peripherals and interconnects like GPIO, UART, SPI, I2C, USB, networking.

  • Multithreading support.

  • Support for energy-efficient operation such as devices running on batteries.

  • Support for Interop code allowing developers to easily write libraries that have both managed (C#) and native code (C/C++).

  • No manual memory management because of its simpler mark-and-sweep garbage collector.

  • Execution constrains catching device lockups and crashes.

  • Debug with breakpoints, single step, step into, step out, step over, pause and stop.

  • Support for a large range of inexpensive boards from several manufacturers.

  • Completely free and Open Source. From the core components to the utilities used for building, deploying, debugging and IDE components.

The nanoFramework sits on top of a Realtime operating System (RTOS), which includes FreeRTOS, ChibiOS and Azure RTOS, with an adaptation layer that marshals the data and events between the hardware and the C# classes.

The CLR is an agent that manages code at execution time, providing core services such as memory management, thread management, and remoting, while also enforcing strict type safety and other forms of code accuracy that promote application security and robustness. In fact, the concept of code management is a fundamental principle of the CLR. Code that targets the CLR is referred to as managed code, whereas code that does not target the CLR is known as unmanaged code.

In addition, the managed environment of the runtime eliminates many common software issues. For example, the runtime automatically handles object layout and manages references to objects, releasing them when they are no longer being used. This automatic memory management resolves the two most common application errors — memory leaks and invalid memory references.

The Class Library

The class library included with the nanoFramework is an object-oriented collection of reusable types you can use to develop embedded applications. Its classes are tightly integrated with the CLR and provide you with types you can employ to build functionality into your own managed code. For example, the nanoFramework collection classes implement a set of interfaces you can use to develop your own collection classes. Your collection classes will blend seamlessly with the classes in the .NET Framework.

To make the nanoFramework available with the smallest possible memory footprint, it is designed to contain only those pieces of the .NET Framework that are most relevant to small devices. These include the major portions of the System.Collections, System.Diagnostics, System.Globalization, System.IO, System.Reflection, System.Resources, System.Runtime, and System.Threading namespaces, among others.

Also, the class library contains specialized classes that are designed to give you access to the hardware features of your product's embedded system. For instance, your program can communicate across standard hardware interfaces, such as GPIO, I2C, and SPI. The powerful combination of standard .NET classes and hardware-specific objects can reduce the amount of time required to develop your embedded system.

The nanoFramework class library includes classes, interfaces, and value types that expedite and optimize the development process and provide access to system functionality. These types are the foundation on which you build your embedded applications and components. They provide a rich set of interfaces, as well as abstract and concrete (nonabstract) classes. You can either use the concrete classes as they are or, in many cases, derive your own classes from them. To use an interface's functionality, you can either create a class that implements the interface or derive a class from one of the nanoFramework classes that implements the interface.

Naming Conventions

The nanoFramework types use a dot syntax naming scheme that connotes a hierarchy. This technique groups related types into namespaces, making them easy to search and reference. The first part of the full name — up to the rightmost dot — is the namespace name. The last part of the name is the type name. For example, System.Collections.ArrayList represents the ArrayList type, which belongs to the System.Collections namespace. The types in System.Collections can be used to manipulate collections of objects.

This naming scheme makes it easy for library developers extending the nanoFramework to create hierarchical groups of types and name them in a consistent, informative manner. I

Compiling for the nanoFramework

In .NET, compilers, the C# compiler, transform the source code to DLL's or executables containing the common intermediate language and metadata for a self-describing code. The CLR then executes the managed code.

The nanoFramework uses a special intermediate language representation optimized for size. A global, shared string table for text and metadata such as type, method, and field names is used to reduce ROM and RAM usage on the devices.

Therefore, the nanoFramework metadata processor tool generates the optimized PE files to be deployed out of the managed .NET assemblies. Visual Studio and the nanoFramework Visual Studio Extensi

Is the nanoFramework right for you

Limitations

nanoFramework is not a real-time system. Although it is very fast and suitable for most applications, do not expect real-time deterministic behaviour.

A timer event may not be triggered exactly after the specified amount of time (varying by some milliseconds), or the runtime environment may take a few milliseconds to react to an interruption by calling the interrupt service routine. In addition, the garbage collector will run to free unused memory when memory gets low. Garbage collection might block all threads for a few milliseconds.

Executing managed code is a lot slower than executing native code. With the nanoFramework, all managed code will be interpreted. There is no just-in-time compiler that compiles managed code parts to native machine code on the first execution as there is for the full .NET Framework. These limitations are due to the small size of the microcontrollers that nanoframework is ported to run on.

To make the nanoFramework available with the smallest possible memory footprint, it is designed to contain only those pieces of the .NET Framework that are most relevant to small devices. These include the major portions of the System.Collections, System.Diagnostics, System.Globalization, System.IO, System.Reflection, System.Resources, System.Runtime, and System.Threading namespaces, among others.

But with these limitations you soon realize that additional naive C/C++ code can give you access to the underlying hardware at "native C compiled code" speed, for example the built in hardware for Pulse Width Modulation (PWM) can "toggle" a pin a high speed.

Flash and Ram Size

If you work with an MCU with the minimum Flash and Ram you can create small applications, but for a small additional cost I suggest you buy a device with larger Flash and Ram for development.

The .NET nanoFramework Base Class Library is provided in two flavours: with or without support for System.Reflection namespace. The reason for this is that the reflection API adds up a significant size to the DLL and image size. For targets with smaller flash this can be prohibitive.

Requirements

  • Developing with nanoFramework requires the following

  • Microsoft Visual Studio 2019 or 2022, any edition including the free community edition.

  • nanoFramework VS extension, a VSIX package available as a tool extension

  • A suitable 32-bit microcontroller board. I suggest a good starting point is an MCU with 192KB RAM and 256MB of flash memory.

  • The device also needs a serial, USB, or network interface to support downloading and debugging the applications.

The HAL and the PAL control the underlying system hardware. Both the HAL and the PAL are groups of C++ functions called by the CLR. The PAL functions are independent of the hardware and should not need to be ported. However, you must write your own version of the HAL for your hardware platform.

The bootstrap code is an additional piece of code that is associated with the HAL. The bootstrap code initializes the low-level hardware when the device is turned on. It then starts the CLR, which performs the higher-level initializations. The bootstrap code performs its tasks through calls to the HAL and assembly-language routines. Other than starting the CLR, it has no interaction with the code preceding it in the software architecture.