The C programming language has dominated the embedded systems industry for half a century! C has been extraordinarily successful, but it is no longer meeting the needs of embedded software developers. In this chapter, we will begin to explore the programming language landscape for embedded systems and how Python, particularly MicroPython, is quickly becoming a good fit for a wide range of applications.
The following topics will be covered in this chapter:
- The embedded software language menagerie
- The case for MicroPython
- Use cases for MicroPython
- Evaluating whether MicroPython is right for you
- Selecting the right development platform
- MicroPython development processes and strategies
- Useful resources
In the history of the embedded software industries, for the most part, developers writing software for microcontroller-based systems have had very few software languages to choose from. At the dawn of the computer age, developers were stuck using low-level assembly language that forced them to learn the instruction set for each microcontroller device that they used. While highly effective and efficient, reading, maintaining, or even understanding assembly language was quite difficult and cumbersome.
Between 1969 and 1973, Dennis Ritchie developed the C programming language while working at Bell Labs and forever changed the way that software was developed. The C programming language caught on, and while general-purpose computing systems have moved on to other object-oriented languages, C has been the dominant language to use with microcontrollers for several different reasons. They include the following:
- It is a high-level programming language that doesn't require developers to understand target-specific assembly language.
- The ability to access low-level registers and hardware features.
- The capability to create high-level software abstractions.
- Cross-platform compilation (write the software once and deploy it to multiple targets).
- Software that is reusable and portable.
The C language is so popular and successful that it has dominated the embedded software industry as the language of choice for almost half a century. The popularity of C has remained despite major software design paradigm shifts, such as object-oriented design, and new languages being available, such as C++. C fills an important niche that allows developers to efficiently develop software that interacts at the bit and byte levels in the hardware.
While C has been extremely popular among developers, over the past several years, its popularity has been waning for several different reasons. Some of these reasons are listed as follows:
- First, the C language has several sticky spots in its specification that can result in developers either getting confused about what the code is doing or that results in different behavior when compiled for a different target. This has caused additional standards such as MISRA-C to be developed, which create a safe subset of C features that developers can use in their software.
- Second, the C language is no longer taught to university students in many parts of the world. In fact, even C++ is no longer taught at university! Students who want to learn a programming language are often presented with Java or Python as the language of choice, which means that any would-be embedded developers have to learn C on the job. When learning C on the job, the chances are that the developer will not be aware of the gotchas and issues with the C language, resulting in buggy, low-quality code that requires additional time and money to make production-ready.
- Next, C is a relatively low-level and verbose programming language. It is quite easy to cause incredibly hard-to-find bugs from memory leaks, buffer overflows, or accidentally accessing an array out-of-bounds. Most modern languages provide explicit protection against these issues with features such as memory management and managed pointers (if pointers exist at all!).
- Finally, most development teams use an object-oriented approach to software development when they develop their software architectures. While good software architecture is language agnostic, it can be much more difficult to write object-oriented code in a language such as C. It's often overlooked that C does provide perfect encapsulation and a mechanism for inheritance, but multiple inheritance and polymorphism are far more complicated and error-prone to pull off.
Because of these reasons, over the last few years, there has been a slow push to begin moving away from using C as the language of choice for embedded applications.
In fact, there has been a small explosion in the number of languages that can be used to develop embedded software. These range from the traditional compiled languages, such as Assembly or C, to C++ or Java, or to even more recent scripting languages such as Python or Squirrel. There are even visual programming languages that allow developers to generate high-level concepts and then generate low-level code such as MATLAB.
Every other year, ASPENCORE performs an embedded industry survey that polls a few thousand developers in the embedded systems industry. In the last survey, in 2019, it was found that only 56% of these projects were developed using the C programming language, while 22% of projects were developed using C++. The remaining 22% was a mix of several other languages, including Python. The complete breakdown can be seen in the following diagram. The menagerie of languages demonstrates how developers are desperately grasping at new languages and techniques that can be used to write their software in a more effective and modern manner. What's interesting is that if you compare these results to the 2017 results, the response for Python has doubled from 3% to 6%. Bear in mind, though, that the responses for C and C++ have stayed exactly the same, so while Python has grown more popular, it is not stealing any market share from C or C++.
The breakdown of programming languages used for embedded systems in 2019 is shown in the following image:
The preceding pie chart is from a survey done by https://www.embedded.com/. Note that this is for all embedded systems and includes application processors, not just microcontrollers (ASPENCORE Embedded Systems Survey, 2019, www.embedded.com).
As developers have started to look for alternative programming languages, the opportunity for Python to become a popular embedded language has dramatically risen. Python has several characteristics that make it an interesting choice for an embedded language. These include, but certainly aren't limited to, the following:
- It is taught at many universities around the world.
- It is easy to learn (I've seen elementary students write Python code).
- It is object-oriented.
- It is an interpreted scripting language that removes compilation.
- It is supported by a robust community, including many add-on libraries that minimize reinventing the wheel.
- It includes error handling (something that C didn't get the memo on).
- It is easily extensible.
Python has actually become the go-to language for developers working on popular application processors such as the Raspberry Pi board.
Python itself, though, has several challenges a developer must consider before using it on a microcontroller:
- First, microcontrollers are resource-constrained devices and, typically, don't have a lot of memory or processing power. This means that the Python interpreter would have to be rewritten so that it could easily fit on a microcontroller with a few hundred kilobytes of flash storage and be able to function in sub-200 MHz environments.
- Second, microcontrollers are used in real-time systems. This means that there needs to be a mechanism to handle interrupts, which doesn't directly exist in Python.
- Third, the Python interpreter would need to be ported to each microcontroller architecture and target in order to operate efficiently.
These three considerations could be quite challenging if a developer decided to undertake them alone. Thankfully, this effort has already been undertaken by the MicroPython community, as described by the project itself:
MicroPython aims to bring the best of the Python world to embedded systems and loosen our reliance on developing software in C (even though, under the hood, MicroPython is written in C!).
It's important to bear in mind that, just like any programming language, there are specific situations where MicroPython is best suited, and other situations where using MicroPython would be a disaster. In general, I have found that there are three different use cases where MicroPython really shines.
They include the following:
- Do-it-yourself (DIY) projects
- Rapid prototyping
- Low-volume production products
Let's examine each of these use cases in detail.
MicroPython is extremely well suited for developers who are looking to create a hobbyist or one-off project. As we discussed earlier, Python is a simple scripting language that is very easy to learn. This makes MicroPython extremely accessible to developers who are looking to experiment and create a DIY project such as a MIDI player, robot, drone, or home automation system. The possibilities for its use are really only limited by the imagination of the developer.
There are also, at least, a dozen different low-cost development boards that support MicroPython natively. Being low cost makes it extremely easy to just order a board and, when it arrives, fire it up and start programming with MicroPython. In Chapter 5, Customizing the MicroPython Kernel Start Up Code, we will show you how to customize the MicroPython kernel and deploy it on your own custom development board.
Finally, if you were to select your favorite search engine, you would find that not only are there a lot of examples on how to use MicroPython in different applications but there are also a lot of examples on how to use Python in general. These resources help to build up a great ecosystem around which a sole developer could create their own projects in the comfort of their own home. Throughout this book, we will also examine the most popular and useful resources, which you can also refer to at leisure.
The use of MicroPython is not limited to DIY engineers. MicroPython fits the bill quite nicely for engineering teams that are looking to develop a rapid prototype or proof of concept. The MicroPython kernel abstracts out the low-level microcontroller hardware, which allows developers to start developing application code or even test code from the first day of a development cycle. This makes it particularly well suited for prototyping.
In a prototyping environment, developers could assemble hardware components for their system and develop scripts to show that the end system that they want to create is actually viable. From the issues that they encounter when prototyping in MicroPython, they should then be able to extrapolate the potential issues they will encounter during development. This will then help them to get a handle on issues such as the following:
- Development costs
- Time to market
- Major engineering hurdles
- Resources that are required
With these types of activities worked out, the development of production code can go much smoother, and the schedule and project costs will be far more accurate.
In addition to proving that a product concept is viable, developers can also use MicroPython to interface with new sensors and devices that need to be understood for development. For example, if I need to write a C driver for an I2C I/O expander chip, I will often create or buy a development board for the chip and connect it to one of my MicroPython boards. I can then write simple Python scripts to interact with the chip, which allows me to do the following:
- Explore the chip registers.
- Exercise the device's peripherals.
- Monitor I2C bus communication to understand what good communication looks like.
Utilizing MicroPython in this manner provides us with an in-depth understanding of the device that we are interfacing with. The result is a better-written driver that is created faster because we can utilize a working example to compare our production driver with. Having that working example dramatically decreases the time spent on debugging.
MicroPython is still a relatively new programming language for microcontrollers compared to C or C++, which means that it does still carry some risk with it for use in production systems. For example, using MicroPython in mass production could result in issues such as the following:
- A longer programming production cycle
- More costly microcontrollers (to handle the larger MicroPython kernel)
- Difficulty in securing the application firmware properly
- Having to manage firmware updates
- Ensuring robust operation and recovery from failure modes
It's not impossible to use MicroPython for high-volume products, but these issues and several others can make such deployments more difficult, at least at the time of writing this book. However, for products that are going to be low volume – that is, maybe a few dozen a year or several hundred to a thousand units – MicroPython could be a really good fit.
MicroPython does allow a team to develop software much faster than if they were writing in C/C++ at a much lower layer of the software stack. Developers can make use of error-handling capabilities, which can help to decrease the time that is spent on debugging a system. Python is so easy to learn that hardware engineers can write basic Python scripts to monitor their hardware and speed up the development process. In general, MicroPython has the potential to help small businesses and low-volume manufacturers decrease costs and time to market.
There have been several real-world examples where MicroPython has been used in production systems. For example, with one of my clients that works in the space industry, developing small satellites for Earth-imaging applications, we used MicroPython to control the spacecraft's Electronic Power Supplies (EPS). MicroPython fit well because of the following factors:
- These systems were very low volume.
- The business was a start-up and didn't have a large budget for software engineers.
- The development time was short for the project.
- They had a small software team that was focused on other software priorities within the satellite system and mission.
- They could tolerate a greater level of product risk to offset costs and schedules.
Using MicroPython to develop the EPS software turned out to be more manageable for their team since most of the team understood and could write Python code even though they did not know C. The end results were extraordinarily successful.
Using MicroPython in space systems and other commercial products goes beyond just one company that I have personally encountered. The European Space Industry has been evaluating using MicroPython in their own satellite systems. I have also encountered several other start-ups and entrepreneurs using MicroPython to develop their consumer electronics products. This only helps to show that not only can MicroPython be used in such cases, but there is growing interest in using MicroPython in production systems.
So far, we have discussed several use cases for MicroPython and when using it could be a big problem. Even if a project we are working on falls within the sanctioned use cases, MicroPython may still not be the best fit. Just like with any project, we need to objectively evaluate whether MicroPython is the right language to use. Let's examine how we can evaluate whether MicroPython is right for us.
There are several steps that can be followed to evaluate whether a programming language meets the needs of a development team or developer:
- Identify the key language features needed
- Evaluate the team's programming skills
- Ascertain the business results the language might achieve
Let's discuss each of these in more detail.
First, it's important to identify the language features that are needed and will be utilized by the development team. For example, it would not be uncommon for a development team to want a language that is the following:
- Has built-in error handling
- Has free and available third-party libraries
- Has a strong ecosystem
- Prevalent examples of its use can be found on the internet
If a team required just these bullet points, MicroPython would already be a front runner as the preferred language choice along with C++.
Second, a team's programming skills really need to be evaluated to determine whether the language that is being used fits with the team. There are several skills that need to be reviewed, such as the following:
- The team's general understanding of programming principles and processes
- Language-specific skill level: beginner, intermediate, or expert
When a team is full of electrical engineers with no formal programming experience, using a language such as Python can be the right choice. We have already discussed that Python is easy to learn, but electrical engineers can use Python scripts to monitor their hardware and get the system working even if the code isn't intended for production. That code can then later be tossed to a software team that makes the software production-ready based on the working, functional examples.
Finally, the business ramifications for the language need to be examined. These could include items such as the following:
- Risk tolerance for security vulnerabilities
- Cost savings from needing fewer embedded developers
- Impact on time to market
- Overall system quality and customer reactions
Once all these factors have been reviewed, only then can a developer decide whether MicroPython is acceptable for them to use in their development cycle.
There are quite a few options available to developers who are interested in working with MicroPython. To date, MicroPython has been ported to approximately a dozen different microcontroller architectures. Each architecture then supports a range of development boards, putting the options for developers at nearly 50 different development boards. With so many different options, it can be a bit challenging to decide which one makes the most sense for your project.
While there are many different ways to go about selecting a development platform, we are going to walk through a simple process that includes this:
- Surveying the available architectures
- Identifying boards of interests within those architectures
- Creating a Kepner-Tregoe (KT) matrix to objectively evaluate the best board for the application
This simple process will ensure that you select a development platform that works best for what you want to do with MicroPython.
The easiest way to survey the available microcontroller architectures is to visit the MicroPython Git repository. The repository is located at https://github.com/micropython/micropython/tree/master/.
From the repository's root, navigate to the ports folder. The ports folder contains a list of all the available microcontroller architectures that run MicroPython and can be viewed as follows:
It's not a bad idea at this point to browse around the repository and see which microcontroller architectures are supported. At the end of the day, you'll want to choose an architecture that is well supported but also one that you are familiar with, in case you need to dive into the MicroPython kernel. For most developers interested in writing code at the Python level, diving into the MicroPython kernel is something they will probably rarely, if ever, do.
From the ports list, the architecture that is supported the most is the STM32 family. There are several reasons as to why STM32 is supported so well:
- STMicroelectronics provides a low-level driver framework that makes it easy to support multiple STM32 devices all using the same APIs.
- All the official MicroPython development boards, starting with the PYB1.0, were based on the STM32, which built up knowledge around these processors through early adopters.
- There is more support for MicroPython within the STM community than within other microcontroller architecture communities.
Developers will, therefore, find that there are quite a few options to choose from within the STM32 ports, in boards folder, as shown in the following two figures. Different STM32 development boards that are supported by MicroPython, including the Nucleo boards from STMicroelectronics, are shown in the following image:
Here are different STM32 development boards that are supported by MicroPython, including the discovery boards from STMicroelectronics and the flagship PY board (PYB) from the creators of MicroPython:
Take a few minutes to browse the MicroPython Git repository and look at the different architectures and the boards that are available in each architecture. Open up a web browser and use your favorite distributor, such as Adafruit, Arrow, Digikey, Mouser, or SparkFun, to see which boards are available and what some of their key features are. In fact, it can be useful to create a simple table with the parameters so that you can later go back and select the right board for your project. For example, you may want to track parameters like the following:
- Board name
- Processor used
- Processor speed (remember, higher clocks = more energy consumed)
- On-board features that are worth noting
I've put together my own table for several boards that I've found to be interesting and that could be used for the projects in this book, as listed in the following table. While you review this table, note the vast differences in available features and memory! MicroPython can be run on very resource-constrained devices with as little as 128 KB of flash (maybe less!). Following is a short list of interesting development boards that already support MicroPython:
Accelerometer, SD card, LEDs, and user and reset switches
Adafruit HUZZAH ESP8266
Accelerometer, Bluetooth LE, Magnetometer, and user switch
IoT Discovery Board
Accelerometer, barometer, Bluetooth, Gyroscope RF, microphone, Magnetometer, and humidity and temperature sensors
LED and user switch
LED and user switch
You have probably noticed that quite a few boards on my list are STM32 devices. The reason for this is that I am very familiar with the STM32 family and use it (and many other architectures) in my professional development efforts. While I work with a lot of different microcontroller vendors, the STM32 is the flagship for MicroPython, so it will have the most supported features and makes a really good choice.
In a later chapter, I will walk you through how to create your own custom board!
A KT matrix is one of my favorite decision-making tools. For nearly any engineering decision where I believe there could be team contention, or where I want to make an objective decision in which my personal biases are removed, I create a KT matrix.
A KT matrix is a decision-making technique that uses a decision matrix to force a ranking among possible alternative solutions (https://www.projectmanagement.com/wikis/233054/Forced-Ranking--A-K-A---Kepner-Tregoe--Decision-Matrix-). Developers can identify criteria that are used to make the decision and provide a weight on how important each criterion is. Each member of a team (even a one-man team) can then objectively rank how well an option meets that criteria. Once each criterion is ranked, the weights are calculated and a numeric value results. The option with the highest value is the objective choice that best fits the criteria.
Now, I know this sounds interesting, so let's apply this technique to help us choose a development board. When selecting a development board, there are going to be several different criteria that need to be considered. For example, we might want to consider the following:
- Development board cost (sadly, this is usually the first and only criteria most developers and teams consider, which is completely flawed)
- Board features
- Processor clock speed and memory
- Community support around the board
- Available board examples
- Existing libraries and features for devices that might be interfaced
- Easily expandable
As you can imagine, we can have as many, or as few, criteria as we so choose.
Once we identify which ones we do want to consider, we can put them in the first column of a spreadsheet. In the second column, we would list the weight of how important that criteria is. I personally like to use a ranking from 1 – 5, where 5 is can't live without and 1 is basically not important (like how an engineer feels about doing something). The remaining columns are then used to list the development board but also the responses from each person in the team.
If I were to build such a matrix for three development boards and a team of two members, the resulting matrix would look something like the upcoming table. In this example, the team is evaluating how well the boards compare when considering different aspects of cost, the ecosystem, board features, and the engineer.
Each aspect is broken up into small subtopics. For example, board features that are being evaluated can include the following:
- Temperature sensor
- Humidity sensor
- Arduino headers for shields
These may not all be important to be on board and could be external. The importance is adjusted using the weight. The KT matrix designed to evaluate which development board best fits a fictional application is shown as follows:
After each member of the team has had a chance to review the criteria and rate it, we can see that, in this fictional example, the IoT Discovery board wins out over the other boards. That's not because the IoT Discovery board is better, rather it was only better based on my requirements for my fictional application.
Developing embedded software using MicroPython can be quite a bit different than developing software using C/C++; however, at the same time, there are many tried and true development techniques and processes that still carry through. For example, when developing a MicroPython application, the software development life cycle doesn't change just because a different programming language is being used.
The Software Development Life Cycle, which is sometimes referred to as SDLC, defines best practices that developers should follow when developing software. These processes are usually grouped into five main categories:
There are two really good resources that you can review, which provide a great overview of how software should be developed. It can be found and downloaded for free by performing a simple web search. The first is the IEEE Software Engineering Body of Knowledge (SWEBOK). The SWEBOK is a free download from IEEE, which covers the best practices that engineers should be following when they develop software along with processes and strategies.
Second, Renesas offers a Synergy Software Quality Handbook that they developed when they were creating their Renesas Synergy™ Platform. Their quality guide describes the processes that they used to develop and validate their software. This document has several gems that both professional and novice software developers will find extremely interesting and worth implementing in their own software development processes.
As you go through this book and either follow along with the projects or leverage the materials for your own projects, there are several processes and strategies that you should be following. These include the following:
- Using revision control
- Clearly documenting the software
- Leveraging the Read-Eval-Print Loop (REPL) serial interface
- Understanding the firmware update process
Throughout this book, we will be demonstrating and discussing these topics further but let's take a moment to briefly discuss them now.
Before starting any project, it is highly recommended that you create a revision control repository for the project. This can be done using popular online repositories such as GitHub or Bitbucket. The reason we want to use a revision control system is that, as the software is developed, we want to be able to save snapshots of the code base that are in working order. If we break something in the code, accidentally delete it, or discover a bug, we can use the revision control system to revert our code back to a good known base or compare our code with a previous version to hunt down a bug.
There will potentially be two different types of projects that you will want to create a repository for: kernel code and application code. Managing kernel code can be tricky because we must pull from the MicroPython mainline and any changes we make will either need to be pushed back and approved to enter the kernel, or we will need to manage updates from the mainline back into our own version. As you might imagine, this can be messy; however, we will discuss best practices to manage this when we create our own MicroPython board.
As we work through our application code, we also want to make sure that we clearly document the software. Python is an easy language to read, but it's also easy to write code that is completely perplexing and difficult to understand. Make sure that as you develop your software you include code comments to help you understand what the code is doing. While you are writing the software, it will make sense, but come back a week, month, or year later and that code could easily make no sense to you.
Personally, I prefer to document all my Python code using comments that are compatible with Doxygen. Doxygen is a tool that can generate software documentation by parsing source files that are commented in very specific ways. Doxygen is beyond the scope of this book, but I would recommend that you check out the Doxygen website and review my Doxygen articles and free templates, which can be downloaded from www.beningo.com. You might also want to review my book, Reusable Firmware Development, Chapter 5, Documenting Firmware with Doxygen, for a full explanation on how to use Doxygen for embedded software development.
As you should already know, the REPL is an interactive MicroPython prompt that allows a developer to access and interact with their development board running MicroPython. A REPL example that shows the MicroPython prompt can be seen in the following screenshot. The REPL allows developers to work from the MicroPython prompt and test out APIs and functions or execute their application script so that the board can run autonomously. The REPL can also be used to transfer files and perform advanced functions. Throughout this book, we will be using the REPL in detail to test out our modules and perform ad hoc programming.
Mastering the REPL is beyond the scope of this book. If you are currently not familiar with it, I highly recommend that you review the MicroPython tutorials and documentation to fully understand everything that can be done through the REPL. The REPL provides developers with an interactive Python Terminal to interact with the kernel modules and scripts:
Finally, firmware updates for MicroPython applications are extremely simple. Python application code is stored in plain text format internally on flash or externally on an SD card or eMMC device. Updating the application simply requires that a developer copy their latest code to their development board. The general process that I use to update firmware is as follows:
- Stop any executing threads and applications.
- Copy the new files to the development board.
- Perform a soft reset using Ctrl + D.
At that point, the new firmware is installed, and the development board memory and peripheral have been set back to their default states. Commands can then be entered through the prompt or the application could be configured to start automatically. There are some ports that have USB, while others only have a serial interface. A few ports provide developers with over-the-air (Wi-Fi) update capabilities. We can even compile our application into the kernel code, which is often referred to as frozen. We can even convert our application modules into bytecode (mpy files) and place those on our filesystem. We will discuss all of these details throughout the book.
There are several resources that you will want to make sure that you have on hand to develop your MicroPython-based projects. In many instances, these are the same tools that you would want to have whether you are a hobbyist or a professional developer. At a minimum, I would recommend that you purchase or download the following:
- Male to female 6" jumpers (https://www.sparkfun.com/products/9140)
- Male to male 6" jumpers (https://www.sparkfun.com/products/8431)
- Female to female 6" jumpers (https://www.sparkfun.com/products/8430)
- A terminal application such as Tera Term, or PuTTY
- A high-speed micro SD card (if your development board supports one)
I would highly recommend that you also pick-up a logic analyzer such as an 8-channel Saleae Logic. I've also found that using an SPI/I2C bus tool such as a Total Phase Aardvark can be a major time-saver to test and understand different sensors and ICs that will be integrated with the microcontroller. Developers who are interested in MicroPython kernel development will also want to pick-up a good debugger such as a SEGGER J-Link or a Keil U-Link.
As far as development boards go, each project will describe the specific board that was used to create the project. These may vary from one project to the next, but the source code is fully available and can be modified to work with any available development board with a little extra effort. I enjoy working with and experimenting with different boards, so there will be several that we will use throughout the book. Part of this, undoubtedly, stems from my work as a consultant, where I am often evaluating and analyzing what's currently available in the industry and determining where the industry is going.
Python has taken the software world by storm due to its elegant simplicity, ease to learn, but also its ability to easily scale and adapt to changing industry conditions. Python has found its way into the resource-constrained environment of microcontroller applications through MicroPython. In the rest of this book, we will explore how we can learn and leverage MicroPython for DIY and product development projects through several hands-on projects.
The projects in this book vary in terms of the skill level required to complete and understand them. Whether you are new to programming or a skilled professional, I will walk you through the design process that's required to complete projects successfully. In order to make sure that no reader is left behind, I will periodically point out useful resources to get up to speed on topics that might otherwise be outside the scope of this book but that will be helpful in completing the projects.
In the next chapter, we will examine several techniques developers can use for real-time scheduling and design our own cooperative scheduler.
- What Python features make it a competing choice for use in embedded systems?
- What three use cases does MicroPython match well with?
- What business ramifications should be evaluated for using MicroPython?
- What microcontroller architecture is supported the most by MicroPython?
- What decision-making tool can be used to remove human bias?
- What five categories make up the SDLC?
- What key combination in the REPL will produce a soft reset?
- What workbench resources do you need to develop a MicroPython project? Are you currently missing any?
- ASPENCORE Embedded Systems Survey, 2017, www.embedded.com
- Know how to use a KT Matrix at https://www.projectmanagement.com/wikis/233054/Forced-Ranking--A-K-A---Kepner-Tregoe--Decision-Matrix-
- Reusable Firmware Development by Jacob Beningo
- MicroPython Tutorials, located at https://docs.micropython.org/en/latest/pyboard/tutorial/index.html