Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
MicroPython Projects
MicroPython Projects

MicroPython Projects: A do-it-yourself guide for embedded developers to build a range of applications using Python

eBook
Mex$504.99 Mex$721.99
Paperback
Mex$902.99
Subscription
Free Trial

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing
Table of content icon View table of contents Preview book icon Preview Book

MicroPython Projects

Managing Real-Time Tasks

Embedded systems need a way to schedule activities and respond to events in an efficient and deterministic manner. MicroPython offers developers several methods to achieve task scheduling.

In this chapter, we will review the methods that are most commonly used by developers and how to use uasyncio to schedule our own real-time tasks.

The following topics will be covered in this chapter:

  • The need for real-time scheduling
  • MicroPython scheduling techniques
  • Writing a scheduling loop with uasyncio

Technical requirements

The example code for this chapter can be found in this book's GitHub repository: https://github.com/PacktPublishing/MicroPython-Projects/tree/master/Chapter02

In order to run the examples, you will require the following hardware and software:

  • Pyboard Revision 1.0 or 1.1
  • Pyboard Series-D
  • Terminal application (such as PuTTy, RealTerm, or a Terminal)
  • A text editor (such as VS Code or PyCharm)

The need for real-time scheduling

A real-time embedded system is a system with a dedicated purpose. The real-time system may operate standalone or it may be a component or subsystem of a larger device. Real-time systems are often event-driven and must produce the same output and timing when given the same initial conditions. A real-time system might be built using a microcontroller system that uses a bare-metal scheduler or a real-time operating system (RTOS) to schedule all of its system tasks. Alternatively, it could be built using a System on Chip (SoC) or Field Programming Gate Array (FPGA).

Every embedded system is not necessarily a real-time system. An application processor such as Raspberry Pi using Raspbian or Linux would not be a real-time system because, for a given set of inputs, while the system may give the same output, the time taken can vary wildly due to the multitasking nature of the system. General-purpose operating systems often interrupt tasks to handle OS-related functions, which results in the computing time being variable and non-deterministic.

There are several characteristics that can be used to identify a real-time embedded system:

  • They're event-driven as they do not poll inputs.
  • They're deterministic because when given the same initial conditions, they produce the same outputs in the same time frame.
  • They're resource-constrained in some manner; for example, clock speed, memory, or energy consumption.
  • They use a dedicated microcontroller-based processor.
  • They may use an RTOS to manage system tasks.

Real-time system types

Real-time systems can be subdivided into two categories: soft real-time and hard real-time systems. Both types require that the system executes in a deterministic and predictable manner. However, they differ in what happens if a deadline is missed. A soft real-time system that misses a deadline is considered to be annoying to its users. It's undesirable for the deadline to be missed and may decrease the usefulness of the system after the deadline, but it's not critical. A hard real-time system, on the other hand, will dramatically decrease its usefulness after a deadline and results in a fatal system fault.

An example of a soft real-time system is a Human Machine Interface (HMI) with a touch controller that is controlling a home furnace. There may be a deadline where the system needs to respond to user input within 1 second of the screen being touched. If a user goes and touches the screen but the system doesn't respond for 3 or 4 seconds, the result is not world ending, but it may make the user complain about how slow the system is.

A hard real-time system could be an electronic braking system that needs to respond to a user pressing the brake pedal within 30 milliseconds. If a user were to press the brake and it took 2 seconds for the brakes to respond, the outcome could be critical. The system's failure to respond could result in injury to the user and dramatically decreases the usefulness of the embedded system.

It is possible to have an embedded system that has a mix of hard and soft requirements. The software in an embedded system is often subdivided into separate tasks based on function and timing requirements. We might find that the user interface on a system is considered to have soft real-time requirements, while the actuator control task must have hard real-time requirements. The type of system that is being built will often factor in the type of scheduler that is used in the solution.

Now, let's explore the different scheduling architectures that can be used with MicroPython to achieve real-time performance.

MicroPython scheduling techniques

When it comes to real-time scheduling using MicroPython, there are five common techniques that developers can employ. These techniques are as follows:

  • Round-robin scheduling
  • Periodic scheduling using timers
  • Event-driven scheduling
  • Cooperative scheduling
  • MicroPython threads

We'll discuss them in detail in the subsequent sections. In the rest of this chapter, we will build example projects to explore several of these scheduling paradigms. We will also give special treatment to the uasyncio library at the end of this chapter, which is a powerful library for scheduling in MicroPython.

Round-robin scheduling

Round-robin scheduling is nothing more than an infinite loop that is created with a while loop. Inside the loop, developers add their task code and each task is executed sequentially, one after the other. While round-robin is the easiest and simplest scheduling paradigm to implement, there are several problems that developers will encounter when using it. First, getting the application tasks to run at the right rates can be difficult. Any code that is added or removed from the application will result in changes to the loop timing. The reason for this is that there is now more or less code to execute per loop. Second, each task has to be designed to recognize that there are other tasks, which means that they cannot block or wait for an event. They must check and then move on so that the other code has the opportunity to use the processor.

Round-robin scheduling can also be used with interrupts to handle any real-time events that might be occurring in the system. The loop handles all the soft real-time tasks, and then the hard real-time tasks are allocated to interrupt handlers. This helps to provide a balance that ensures each type is executed within a reasonable period of time. Round-robin is a good technique for beginners who are just trying to get a simple application up and running.

As we discussed earlier, adding or removing code affects the loop time, which can affect how the system performs. Round-robin schedulers can handle soft real-time tasks. Any events or hard real-time requirements need to be handled using interrupts. I often refer to this as round-robin scheduling with interrupts. A flowchart showing round-robin scheduling with interrupts can be seen in the following diagram:

The main round-robin loop is often referred to as the background loop. This loop constantly executes in the background when there are no interrupts executing. The interrupts themselves are referred to as the foreground and handle any hard real-time events that need to be handled by the system. These functions trump background tasks and run immediately. It's also important to note that MicroPython handles clearing the interrupt flags for developers, so while they are shown in the preceding diagram, this detail is abstracted and handled by the MicroPython kernel.

In C, an application that uses round-robin scheduling might look something like the following:

int main (void)
{
// Initialize the Microcontroller Unit (MCU) peripherals
System_Init();

while(1)
{
Task1();

Task2();

Task3();
}
// The application should never exit. Return 1 if
// we do reach this point!

return 1;
}

In this example, the code enters into the main function, initializes the microcontroller, and then enters into an infinite while loop that calls each task in order. This is a design pattern that every embedded software developer will have seen early in their career and should be quite familiar with.

Implementing round-robin in MicroPython is very similar:

  1. First, it's important to recall that the application entry for MicroPython is located within main.py. To access any peripherals, the pyb library needs to be imported into the application (or the machine library for code that can be ported across MicroPython ports).
  2. Second, any initialization and task functions need to be defined above the main loop. This ensures that they are defined before they are called by the Python interpreter.
  3. Finally, an infinite loop is created using a while True statement. Each defined task is entered into this loop. The loop's timing can be controlled and tuned using pyb.delay().

Building a task manager using round-robin scheduling

Let's look at an example application that generates an LED railroad lights pattern. From a hardware perspective, this requires the use of two LEDs on the pyboard, such as the blue and yellow LEDs (on the pyboard series-D, you might use the green and blue LEDs). I prefer to use these because when we save new code to the pyboard, the red LED is used to show that the filesystem is being written to, and we don't want to interfere with that indicator. If we want one LED to be on while the other is off and then toggle them back and forth, we will need to initialize the blue LED to be on and the yellow to be off. We can then create two separate tasks, one to control the yellow LED and the other to control the blue LED. The Python code for this is as follows:

import pyb   # For uPython MCU features
import time

# define LED color constants
LED_RED = 1
LED_GREEN = 2
LED_BLUE = 3

LED_YELLOW = 4

def task1():
pyb.LED(LED_BLUE).toggle()

def task2():
pyb.LED(LED_GREEN).toggle()

However, the application is not complete until we initialize the LEDs and schedule the tasks to run. The following code shows the LED railroad application's initialization and task execution being written using round-robin scheduling. The main loop is delayed by 150 milliseconds, as well as each loop using the sleep_ms method from the time module. Importing time actually imports the utime module, but importing time can make porting code a little bit easier:

# Setup the MCU and application code to starting conditions
# The blue LED will start on, the yellow LED will be off
pyb.LED(LED_BLUE).on()
pyb.LED(LED_GREEN).off()

# Main application loop
while True:
# Run the first task
task1()

# Run the second task
task2()

# Delay 150 ms
pyb.delay(150)

These two code blocks, when combined, provide us with our first MicroPython application. Running the application on the pyboard can be done by copying the main.py script onto the development board. This can be done either directly, through a Python IDE such as PyCharm, or manually using the following steps:

  1. Connect the pyboard to your computer with a USB cable.
  2. Open your Terminal application and connect to the pyboard (refer to the MicroPython documentation | Quick reference for the pyboard | MicroPython tutorial for the pyboard | 3. Getting a MicroPython REPL prompt, for details).
  3. In the serial Terminal, press Ctrl + C to interrupt any currently running scripts.
  4. Copy the script to the pyboard USB drive. While the copy is in progress, the red LED will be lit up.
  5. Once the red light has gone off, the pyboard flash system will be updated.
  6. In the Terminal, press Ctrl + D to perform a soft reset.
For additional methods regarding how to deploy the application and develop within the PyCharm environment, refer to the Appendix, Downloading and Running MicroPython Code.

Now, you should see the blue and green LEDs toggling back and forth.

Periodic scheduling using timers

There may be applications where every task that needs to be executed is periodic, such as a push button that needs to be sampled every 10 milliseconds; a display that needs to be updated 60 times per second; or a sensor that is sampled at 10 Hz or interrupts when a value has gone out of range. In purely periodic systems, developers can architect their software to use periodic timers to execute tasks. Each timer can be set up to represent a single task that is executed at the desired rate. When the timer interrupt fires, the task executes.

When using periodic timers for task scheduling, it's important to keep in mind that the task code will be executed from an interrupt handler. Developers should follow best practices for using interrupts, such as the following:

  • Keep ISRs short and fast.
  • Perform measurements to understand interrupt timing and latency.
  • Use interrupt priority settings to emulate pre-emption.
  • Make sure that task variables are declared as volatile.
  • Avoid calling multiple functions from an ISR.
  • Disable interrupts as little as possible.
  • Use micropython.schedule() to schedule a function to execute as soon as the MicroPython scheduler is able to.

When using periodic timers to schedule tasks, some of these best practices can be bent slightly. However, if the developer carefully monitors their task timing, bending the rules shouldn't be an issue. If it is, then any hard real-time activity can be handled by the interrupt task and then a round-robin loop can be notified to finish processing the task at a later time.

Timers guarantee that the task will be executed at a regular interval, no matter what is being executed, assuming that a higher-priority interrupt is not executing. The key thing to remember is that these tasks are executed within an interrupt, so the tasks need to be kept short and fast! Developers who use this method should handle any high-priority activity in the task and then offload the rest of the task to the background. For example, a task that handles an incoming byte over a Universal Asynchronous Receiver/Transmitter (UART) device can process the incoming byte by storing it in a circular buffer and then allowing a background task to later process the circular buffer. This keeps the interrupt task short and sweet while allowing the lower-priority processing to be done in the background.

Interrupts within MicroPython are also special in that they are garbage collector (gc) locked. What this means to a developer is that you cannot allocate memory in an ISR. All memory, classes, and so on need to be allocated before being used by the ISR. This has an interesting side effect in that if something goes wrong while executing an ISR, the developer has no way of knowing what went wrong! To get traceback information in situations where memory can't be allocated, such as in ISRs, developers can use the MicroPython emergency exception buffer. This is done by adding the following line of code to either the top of main.py or boot.py:

micropython.alloc_emergency_exception_buf(100) 

This line of code is used to allocate 100 bytes to store the traceback information for ISRs and any other tracebacks that occur in areas where memory cannot be allocated. If an exception occurs, the Python traceback information is saved to this buffer and then printed to the REPL. This allows a developer to then figure out what they did wrong and correct it. The value of 100 is recommended as the buffer size by the MicroPython documentation.

When considering using timers for tasks, it's also important to recognize that each time an interrupt fires on an Arm Cortex®-M processor, there is a 12–15 clock cycle overhead to switch from the main code to the interrupt and then again to switch back. The reason for this overhead is that the processor needs to save and restore context information for the application when switching into and out of the interrupts. The nice thing is that these transitions, while they consume clock cycles, are deterministic!

Building a task manager using periodic scheduling

Setting up a timer to behave as a periodic task is exactly the same as setting up a timer in MicroPython for any other purpose. We can create an application very similar to our round-robin scheduler using timers by initializing a timer for each task in the application. The first timer will control the blue LED, while the second will control the green LED. Each timer will use a callback function to the task code that will be executed when the timer expires.

We can use the exact same format for our code that we used previously. We will initialize the blue LED as on, and the green LED as off. This allows us to let the timers free-run and generate the railroad pattern that we saw earlier. It's important to note that if we let the timer free-run, even if we stop the application in the REPL, the timers will continue to execute! The reason for this is that the timers are hardware peripherals that will run until the peripheral is disabled, even if we exit our application and return to the REPL. I mention this because any print statements you add to your callback functions will continue to populate the REPL, even after you halt the program, which can make it difficult to work or determine the state of the application.

When using timers to set up tasks, there is no need for an infinite while loop like we saw with the round-robin applications. The timers will just free-run. If the infinite loop is not added to main.py, background processing will fall back to the system REPL and sit there instead. I personally still like to include the while loop and some status information so that I know whether the MicroPython interpreter is executing code. In this example, we will put a sleep delay in the main loop and then calculate how long the application has been running.

The Python code for our tasks is identical to the round-robin example, except for the addition of the emergency exception buffer, as shown here:

import micropython # For emergency exception buffer
import pyb # For uPython MCU
import time

micropython.alloc_emergency_exception_buf(100)

LED_RED = 1
LED_GREEN = 2
LED_BLUE = 3
LED_YELLOW = 4

def task1(timer):
pyb.LED(LED_BLUE).toggle()

return

def task2(timer):
pyb.LED(LED_GREEN).toggle()

return

Instead of calling the task code directly, we set up two timers time 1, and timer 2 with a frequency of 5 Hz (period of 200 milliseconds) and set up the callback function to call the tasks. The code to accomplish this is as follows:

pyb.LED(LED_BLUE).on()
pyb.LED(LED_GREEN).off()

# Create task timer for Blue LED
TimerBlueLed = pyb.Timer(1)
TimerBlueLed.init(freq=5)
TimerBlueLed.callback(task1)
print("Task 1 - Blue LED Toggle initialized ...")

# Create task timer for Green LED
TimerGreenLed = pyb.Timer(2)
TimerGreenLed.init(freq=5)
TimerGreenLed.callback(task2)
print("Task 2 - Green LED Toggle initialized ...")

The only code that's necessary for this example is the code for the main loop, which will do nothing more than print out how long our application has been running. To accomplish this, we need to sample the application start time using the time module's ticks_ms method and store it in TimeStart. We can then use time.ticks_diff to calculate the elapsed time between the current tick and the application start tick. The final piece of code is as follows:

TimeStart = time.ticks_ms()

while True:
time.sleep_ms(5000)
SecondsLive = time.ticks_diff(time.ticks_ms(), TimeStart) / 1000
print("Executing for ", SecondsLive, " seconds")

Once the code is on the pyboard and executing, the REPL should display the information shown in the following screenshot. It shows timer-based task scheduling, which prints the current execution time in the REPL and toggles between the blue and green LEDs at 5 Hz. At this point, you know how to use timers to schedule periodic tasks:

At this point, we are ready to examine some additional scheduling paradigms that are not completely mainstream within MicroPython, such as thread support.

MicroPython thread mechanism

The last scheduling paradigm that developers can use to schedule tasks is the MicroPython thread mechanism. In a microcontroller-based system, a thread is essentially a synonym for a task. There are some minor differences, but they are beyond the scope of this book. Developers can create threads that will contain task code. Each task could then use several different mechanisms to execute their task code, such as the following:

  • Waiting on a queue
  • Waiting on time using a delay
  • Periodically monitoring for a polled event

The thread mechanism has been implemented directly from Python 3.x and provides developers with an easy method for creating separate tasks in their application. It is important to recognize that the Python thread mechanism is NOT deterministic. This means that it will not be useful for developing software that has a hard real-time requirement. The MicroPython thread mechanism is also currently experimental! Threads are not supported in all MicroPython ports and for the ones that are, a developer usually needs to enable threads and recompile the kernel in order to have access to the capability on offer.

For additional information on threads and their behavior, please refer to the Further reading section at the end of this chapter.

Starting with MicroPython version 1.8.2, there is support for an experimental threads module that developers can use to create separate threads. Using the threads module is not recommended for developers who are just getting started with MicroPython for several reasons. First, by default, threading is not enabled in the MicroPython kernel. Developers need to enable threading and then recompile and deploy the kernel. Second, since the threading module is experimental, it has not been ported to every MicroPython port yet.

If threads aren't officially supported and not recommended, why are we even talking about them? Well, if we want to understand the different scheduling mechanisms available to us with MicroPython, we need to include the mechanisms that are even experimental. So, let's dive in and talk about threading with MicroPython (even though you may not be able to run a threading application until you have learned how to recompile the kernel, which you will do in Chapter 5, Customizing the MicroPython Kernel Start Up Code).

When a developer creates a thread, they are creating a semi-independent program. If you think back to what a typical program looks like, it starts with an initialization section and then enters into an infinite loop. Every thread has this structure! There is a section to initialize the thread and its variables, followed by an independent loop. The loop itself can be periodic by using time.sleep_ms() or it can block an event, such as an interrupt.

Advantages of using threads in MicroPython

From an organizational standpoint, threads can be a good choice for many MicroPython applications, although similar behavior can be achieved using the asyncio library (which we will talk about shortly). There are several advantages that threads provide, such as the following:

  • They allow a developer to easily break up their program into smaller constituents that can be assigned to individual developers.
  • They help us improve the code so that it's scalable and reusable.
  • They provide us with a small opportunity to decrease bugs in an application by breaking the application up into smaller, less complex pieces. However, as we mentioned previously, more bugs can be created by developers who are unfamiliar with how to use threads properly.

Considerations when using threads in MicroPython

For a Python programmer, before using threads in a MicroPython application, it makes a lot of sense to consider the potential consequences before immediately jumping to threads. There are a few important considerations that a developer needs to contemplate:

  • Threads are not deterministic. When a Python thread is ready to execute, there is no mechanism in place for one thread to be executed before another.
  • There is no real mechanism for controlling time slicing. Time slicing is when the CPU is shared between multiple threads that are currently ready to execute.
  • To pass data around the application, developers may need to add additional complexities to their design, such as the use of queues.
  • Developers who are not familiar with designing and implementing multi-threaded applications will find that inter-thread communication and syncing is full of pitfalls and traps. More time will be spent debugging and new developers will find that the other methods we've discussed are more appropriate for their applications.
  • Support for threading is currently experimental in MicroPython (see https://docs.micropython.org/en/latest/library/_thread.html).
  • Threads are not supported on all MicroPython ports, so the applications may be less portable than expected.
  • Threads will use more resources than the other techniques we've discussed in this chapter.

Building a task manager using threads

Despite a few drawbacks to using threads, they can be a very powerful tool for developers who understand how to use them in the context of a real-time embedded system. Let's take a look at how we can implement our railroad blinky LED application using threads. The first step to developing the application is to create our threads, just like how we created our tasks in the previous examples. In this case, though, there are several key modifications that are worth noting.

First, we need to import the threading module (_thread). Second, we need to define a thread as a regular function declaration. The difference here is that we treat each function like a separate application where we insert a while True statement. If the thread were to exit the infinite loop, the thread would cease operating and not use any more CPU time.

In this example, we're controlling the LED toggling time by using the time.sleep_ms function and setting our thread loop time to 150 milliseconds, just like we did in the previous examples. Our code now looks as follows:

import micropython # For emergency exception buffer
import pyb # For uPython MCU features
import time # For time features
import _thread # For thread support

micropython.alloc_emergency_exception_buf(100)

LED_RED = 1
LED_GREEN = 2
LED_BLUE = 3
LED_YELLOW = 4

def task1():
while True:
pyb.LED(LED_BLUE).toggle()
time.sleep_ms(15
0)

def task2():
while True:
pyb.LED(LED_GREEN).toggle()
time.sleep_ms(25
0)

We can initialize the system the exact same way that we did before by initializing the blue LED to on and the green LED to off. The difference in our thread application is that we want to write some code that will spawn off our two threads. This can be done with the following code:

pyb.LED(LED_BLUE).on()
pyb.LED(LED_GREEN).off()

_thread.start_new_thread(task1, ())
_thread.start_new_thread(task2, ())

As you can see, we're using the _thread.start_new_thread method here. This method requires two parameters. The first is the function that should be called when the thread is ready to run. In this case, these are our Led_BlueToggle and Led_YellowToggle functions. The second parameter is a tuple that needs to be passed to our threads. In this case, we have no parameters to pass, so we just pass an empty tuple.

Before running this code, it's useful to note that the rest of the script is the same as the code in our timer example. We create an infinite loop for the script and then report how long the application has been running for. As a reminder, the code for this is as follows:

TimeStart = time.ticks_ms()

while True:
time.sleep_ms(5000)
SecondsLive = time.ticks_diff(time.ticks_ms(), TimeStart) / 1000
print("Executing for ", SecondsLive, " seconds")

An interesting question to ask yourself as you run the threaded code is, How long will it take before these LEDs are no longer blinking in an alternating pattern? Since the threads are not deterministic, over time, there is the potential for these threads to get out of sync and for the application to no longer behave the way that we expect it to. If you are going to run the code, let it run for a while, over several hours, a day, or even a week, and observe the application's behavior.

Event-driven scheduling

Event-driven scheduling can be an extremely convenient technique for developers whose systems are driven by events that are happening on the system. For example, the system may need to respond to a user button press, an incoming data packet, or a limit switch being reached by an actuator.

In event-driven systems, there may be no need to have a periodic background timer; instead, the system can just respond to the event using interrupts. Event-driven scheduling may have our common infinite while loop, but that loop will do nothing or put the system into a low-power state until an event occurs. Developers who are using event-driven systems can follow the interrupt best practices that we discussed earlier and should also read the MicroPython documentation on ISR rules, which can be found at https://docs.micropython.org/en/latest/reference/isr_rules.html. It's important to note that when you do use interrupts, MicroPython automatically clears the interrupt flag for the developer so that using interrupts is simplified.

Cooperative scheduling

Cooperative scheduling is a technique that developers can leverage to achieve task periodicity without using a timer for every task. Cooperative schedulers are one of the most widely used schedulers throughout embedded system history. A quick look at any of the embedded.com embedded systems surveys will easily show that.

A cooperative scheduler often uses a single timer to create a system tick that the scheduler then uses to determine whether the task code should be executed. The cooperative scheduler provides a perfect balance for developers who need periodicity, simplicity, flexibility, and scalability. They are also a stepping stone toward an RTOS.

So far, we have examined the methods that developers can use in MicroPython to schedule activities. In the next section, we will discuss how we can use the asyncio library to cooperatively schedule tasks. This method is perhaps the most commonly used method by MicroPython developers due to its flexibility and precise timing beyond the methods that we have already examined.

Cooperative multitasking using asyncio

So far, we have examined how we can schedule tasks in a MicroPython-based system using round-robin, timers, and threads. While threads may be the most powerful scheduling option available, they aren't deterministic schedulers and don't fit the bill for most MicroPython applications. There is another scheduling algorithm that developers can leverage to schedule tasks within their systems: cooperative scheduling.

A cooperative scheduler, also known as cooperative multitasking, is basically a round-robin scheduling loop that includes several mechanisms to allow a task to yield the CPU to other tasks that may need to use it. The developer can fine-tune the way that their application behaves, and their tasks execute without adding the complexity that is required for a pre-emptive scheduler, like those included in an RTOS. Developers who decide that a cooperative scheduler fits their application best will need to make sure that each task they create can complete before any other task needs to execute, hence the name cooperative. The tasks cooperate to ensure that all the tasks are able to execute their code within their requirements but are not held to their timing by any mechanism.

Developers can develop their own cooperative schedulers, but MicroPython currently provides the asyncio library, which can be used to create cooperatively scheduled tasks and to handle asynchronous events in an efficient manner. In the rest of this chapter, we will examine asyncio and how we can use it for task scheduling within our embedded applications.

Introducing asyncio

The asyncio module was added to Python starting in version 3.4 and has been steadily evolving ever since. The purpose of asyncio is to handle asynchronous events that occur in Python applications, such as access to input/output devices, a network, or even a database. Rather than allowing a function to block the application, asyncio added the functionality for us to use coroutines that can yield the CPU while they wait for responses from asynchronous devices.

MicroPython has supported asyncio in the kernel since version 1.11 through the uasyncio library. Prior versions still supported asyncio, but the libraries had to be added manually. This could be done through several means, such as the following:

  • Copying the usyncio library to your application folder
  • Using micropip.py to download the usyncio library
  • Using upip if there is a network connection

If you are unsure whether your MicroPython port supports asyncio, all you need to do is type the following into the REPL:

import usyncio

If you receive an import error, then you know that you need to install the library before continuing. Peter Hinch has put together an excellent guide regarding asyncio with instructions for installing the library that you can find at https://github.com/peterhinch/micropython-async/blob/master/TUTORIAL.md#0-introduction.

It's important to note that the support for asyncio in MicroPython is for the features that were introduced in Python 3.4. Very few features from the Python 3.5 or above asyncio library have been ported to MicroPython, so if you happen to do more in-depth research into asyncio, please keep this in mind to avoid hours of debugging.

The main purpose of asyncio is to provide developers with a technique for handling asynchronous operations in an efficient manner that doesn't block the CPU. This is done through the use of coroutines, which are sometimes referred to as coros. A coroutine is a specialized version of a Python generator function that can suspend its execution before reaching a return and indirectly passes control to another coroutine. Coroutines are a technique that provides concurrency to a Python application. Concurrency basically means that we can have multiple functions that appear to be executing at the same time but are actually running one at a time in a cooperative manner. This is not parallel processing but cooperative multitasking, which can dramatically improve the scalability and performance of a Python application compared to other synchronous methods.

The general idea behind asyncio is that a developer creates several coroutines that will operate asynchronously with each other. Each coroutine is then called using a task from an event loop that schedules the tasks. This makes the coroutines and tasks nearly synonymous. The event loop will execute a task until it yields execution back to the event loop or to another coroutine. The coroutine may block waiting for an I/O operation or it may simply sleep if the coroutine wants to execute at a periodic interval. It's important to note, however, that if a coroutine is meant to be periodic, there may be jitter in the period, depending on the timing for the other tasks and when the event loop can schedule it to run again.

The general behavior for how coroutines work can be seen in the following diagram, which represents an overview of using coroutines with the asyncio library. This diagram is a modified version of the one presented by Matt Trentini at Pycon AU in 2019 during his talk on asyncio in MicroPython:

As shown in the preceding diagram, the Event Loop schedules a task to be executed that has 100% of the CPU until it reaches a yield point. A yield point is a point in the coroutine where a blocking operation (asynchronous operation) will occur and the coroutine is then willing to give up the CPU until the operation is completed. At this point, the event loop will then schedule other coroutines to run. When the asynchronous event occurs, a callback is used to notify the Event Loop that the event has occurred. The Event Loop will then mark the original coroutine as ready to run and will schedule it to resume when other coroutines have yielded the CPU. At that point, the coroutine can resume operation, but as we mentioned earlier, there could be some time that elapses between the receipt of the callback and the coroutine resuming execution, and this is by no means deterministic.

Now, let's examine how we can use asyncio to rewrite our blinky LED application using cooperative multitasking.

A cooperative multitasking blinky LED example

The first step in creating a railroad blinky LED example is to import the asyncio library. In MicroPython, there is not an asyncio library exactly, but a uasyncio library. To improve portability, many developers will import uasyncio as if it were the asyncio library by importing it at the top of their application, as follows:

import uasyncio as asyncio

Next, we can define our LEDs, just like we did in all our other examples, using the following code:

LED_RED = 1
LED_GREEN = 2
LED_BLUE = 3
LED_YELLOW = 4

If you look back at our example of writing a thread-based application, you'll recall that our task1 code looked as follows:

def task1():
while True:
pyb.LED(LED_BLUE).toggle()
time.sleep_ms(150)

def task2():
while True:
pyb.LED(LED_GREEN).toggle()
time.sleep_ms(150)

This is important to review because creating a coroutine will follow a similar structure! In fact, to tell the Python interpreter that our tasks are asynchronous coroutines, we need to add the async keyword before each of our task definitions, as shown in the following code:

async def task1():
while True:
pyb.LED(LED_BLUE).toggle()
time.sleep_ms(150)
async def task2():
while True:
pyb.LED(LED_GREEN).toggle()
time.sleep_ms(150)

The functions are now coroutines, but they are missing something very important: a yield point! If you examine each of our tasks, you can tell that we really want our coroutine to yield once we have toggled our LED and are going to wait 150 milliseconds. The problem with these functions as they are currently written is that they are making a blocking call to time.sleep_ms. We want to update this with a call to asyncio.sleep_ms and we want to let the interpreter know that we want to relinquish the CPU at this point. In order to do that, we are going to use the await keyword.

The await keyword, when reached by the coroutine, tells the event loop that it has reached a point in its execution where it will be waiting for an event to occur and it is willing to give up the CPU to another task. At this point, control is handed back to the event loop and the event loop can decide what task should be executed next. Using this syntax, our task code for the railroad blinky LED applications would be updated to the following:

async def task1():
while True:
pyb.LED(LED_BLUE).toggle()
await asyncio.sleep_ms(150)
async def task2():
while True:
pyb.LED(LED_GREEN).toggle()
await asyncio.sleep_ms(150)

For the most part, the general structure of our coroutine/task functions remains the same. The difference is that we define the function as async and then use await where we expect the asynchronous function call to be made.

At this point, we just initialize the LEDs using the following code:

pyb.LED(LED_BLUE).on()
pyb.LED(LED_GREEN).off()

Then, we create our event loop.

Creating the event loop for this application requires just four lines of code. The first line will assign the asyncio event loop to a loop variable. The next two lines create tasks that assign our coroutines to the event loop. Finally, we tell the event loop to run forever and our coroutines to execute. These four lines of code look as follows:

loop = asyncio.get_event_loop()
loop.create_task(task1())
loop.create_task(task2())
loop.run_forever()

As you can see, we can create any number of tasks and pass the desired coroutine to the create_task method in order to get them into the event loop. At this point, you could run this example and see that you have an efficiently running railroad blinky LED program that uses cooperative multitasking.

Going further with asyncio

Unfortunately, there just isn't enough time to discuss all the cool capabilities that are offered by asyncio in MicroPython applications. However, as we progress through this book, we will use asyncio and its additional capabilities as we develop our various projects. For those of you who want to dig deeper right now, I would highly recommend checking out Peter Hinch's asyncio tutorial, which also covers how you can coordinate tasks, use queues, and more, with asyncio. You can find the tutorial and some example code at https://github.com/peterhinch/micropython-async/blob/master/TUTORIAL.md#0-introduction.

Summary

In this chapter, we explored several different types of real-time scheduling techniques that can be used with a MicroPython project. We found that there are many different techniques that a MicroPython developer can leverage to schedule activities in their application. We found that each of these techniques has its place and varies based on the level of complexity a developer wants to include in their scheduler. For example, MicroPython threads can be used, but they are not fully supported in every MicroPython port and should be considered an in-development feature.

After looking at several techniques, we saw that the asyncio library may be the best choice for developers looking to get started with MicroPython. Python developers are already familiar with it and asyncio provides developers with cooperative scheduling capabilities that can provide them with the ability to handle asynchronous events in an efficient, non-blocking manner. This allows developers to get more out of their applications while wasting fewer cycles.

In the next chapter, we will explore how we can write drivers for a simple application that uses a push button to control the state of its RGB LEDs.

Questions

  1. What characteristics define a real-time embedded system?
  2. What four scheduling algorithms are commonly used with MicroPython?
  3. What best practices should a developer follow when using callbacks in MicroPython?
  4. What process should be followed to load new code onto a MicroPython board?
  5. Why would a developer place micropython.alloc_emergency_exception_buf(100) in their application?
  6. What reasons might deter a developer from using the _thread library?
  7. What keywords indicate that a function is being defined as a coroutine?
Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Delve into MicroPython Kernel and learn to make modifications that will enhance your embedded applications
  • Design and implement drivers to interact with a variety of sensors and devices
  • Build low-cost projects such as DIY automation and object detection with machine learning

Description

With the increasing complexity of embedded systems seen over the past few years, developers are looking for ways to manage them easily by solving problems without spending a lot of time on finding supported peripherals. MicroPython is an efficient and lean implementation of the Python 3 programming language, which is optimized to run on microcontrollers. MicroPython Projects will guide you in building and managing your embedded systems with ease. This book is a comprehensive project-based guide that will help you build a wide range of projects and give you the confidence to design complex projects spanning new areas of technology such as electronic applications, automation devices, and IoT applications. While building seven engaging projects, you'll learn how to enable devices to communicate with each other, access and control devices over a TCP/IP socket, and store and retrieve data. The complexity will increase progressively as you work on different projects, covering areas such as driver design, sensor interfacing, and MicroPython kernel customization. By the end of this MicroPython book, you'll be able to develop industry-standard embedded systems and keep up with the evolution of the Internet of Things.

Who is this book for?

If you are an embedded developer or hobbyist looking to build interesting projects using MicroPython, this book is for you. A basic understanding of electronics and Python is required while some MicroPython experience will be helpful.

What you will learn

  • Develop embedded systems using MicroPython
  • Build a custom debugging tool to visualize sensor data in real-time
  • Detect objects using machine learning and MicroPython
  • Discover how to minimize project costs and reduce development time
  • Get to grips with gesture operations and parsing gesture data
  • Learn how to customize and deploy the MicroPython kernel
  • Explore the techniques for scheduling application tasks and activities

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Apr 17, 2020
Length: 294 pages
Edition : 1st
Language : English
ISBN-13 : 9781789958034
Category :
Languages :

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing

Product Details

Publication date : Apr 17, 2020
Length: 294 pages
Edition : 1st
Language : English
ISBN-13 : 9781789958034
Category :
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just Mex$85 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just Mex$85 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total Mex$ 2,872.97
MicroPython Projects
Mex$902.99
Practical Python Programming for IoT
Mex$1066.99
MicroPython Cookbook
Mex$902.99
Total Mex$ 2,872.97 Stars icon

Table of Contents

13 Chapters
Down the Rabbit Hole with MicroPython Chevron down icon Chevron up icon
Managing Real-Time Tasks Chevron down icon Chevron up icon
Writing a MicroPython Driver for an I/O Expander Chevron down icon Chevron up icon
Developing an Application Test Harness Chevron down icon Chevron up icon
Customizing the MicroPython Kernel Start Up Code Chevron down icon Chevron up icon
A Custom Debugging Tool to Visualize Sensor Data Chevron down icon Chevron up icon
Device Control Using Gestures Chevron down icon Chevron up icon
Automation and Control Using Android Chevron down icon Chevron up icon
Building an Object Detection Application Using Machine Learning Chevron down icon Chevron up icon
The Future of MicroPython Chevron down icon Chevron up icon
Downloading and Running MicroPython Code Chevron down icon Chevron up icon
Assessments Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.4
(10 Ratings)
5 star 70%
4 star 20%
3 star 0%
2 star 0%
1 star 10%
Filter icon Filter
Top Reviews

Filter reviews by




Subramaniam Ganesan May 21, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
OverviewThis book is for anyone interested in learning Micropython and doing projects with Arduino and similar microprocessor boards.What I likedThis book is very clearly written with a lot of example codes, steps to download Micropython, the board and Camera information. I liked the Chapter 2 on real time scheduling, and description of the “asyncio” module for connecting input and output. As a computer engineer with many decades of experience, I really enjoyed reading the whole book without keeping it down. I learnt new techniques and the new language Micropython.What I didn’t likeChapter 9 describes well the STM32 board and the OpenMV camera, Machine Learning program to detect objects. This chapter may give more examples and more description of the codes. A fresh engineer may find some parts difficult to understand. Chapter 10 describes the future of Micropython and I wish to see more depth in this topic. More description at the student level will be good in the later chapters.SummaryIt is an excellent book. Embedded System engineers will certainly find this book interesting and good for learning new techniques. I recommend this book for EE, CE, CS students and working engineers.
Amazon Verified review Amazon
jerzy wilder Feb 22, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Thanks
Amazon Verified review Amazon
Brad Stewart May 26, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This is one of the most interesting books I've discovered for MicroPython. It's clearly written, the examples are comprehensive, and most important of all—I gained new insights and knowledge. The author has created a series of very useful projects and a design methodology that I am adopting for my own needs. The chapter on managing real-time tasks alone is worth the admission price.I'm an electrical engineer and I've been programming embedded systems for about 40 years. I've used many different languages, debuggers, middleware, and IDEs. A couple of years ago, I discovered MicroPython that runs on a STM32F405 MCU. Since then, I've developed several products from automotive to industrial applications that utilize the MicroPython environment. And unless I really need to program in C, I'm sticking with MicroPython. It's that good.One thing I must mention first. This is not a book for beginners. It helps if you have some Python experience, but you should really have some hands-on experience with MicroPython. There are excellent sources on the web and other books such as Programming with MicroPython: Embedded Programming with Microcontrollers and Python by Nicholas Tollervey. But when you're ready to take the next step, then MicroPython Projects should be on your list of must reads.The first chapter makes the case for MicroPython. Although the author makes it clear of the advantages of using MicroPython, I would go even further and make the bold statement that MicroPython will become the dominant embedded programming language in the foreseeable future. My main justification is that Python is the world most popular computer language. Even embedded projects that utilize the Raspberry Pi use Python. Furthermore, those knowledgeable in embedded C are becoming a scarce resource, especially in the U.S.The second chapter is my favorite. It's about managing real time tasks. Yes, it's possible with MicroPython which makes it different from regular Python. The author explains standard methods familiar with RTOS programmers. This includes round-robin scheduling, periodic scheduling using timers, event-driven scheduling, cooperative scheduling, and even using the nascent (and too early to use) MicroPython thread mechanism. Of these, the “asyncio” library has the ability to do cooperative multitasking,and a simple example is provided. Brilliant. My only comment is that not all versions of MicroPython (e.g. CircuitPython) can use these techniques and perhaps this could have been pointed out.The third chapter goes into details on hooking up some hardware to a PyBoard and writing the drivers to support it. The author details the design methodology including flow diagrams, building a series of “test cases,” and creating class objects to drive the hardware. My only comment is that one of the libraries was written as a class object, where as the second example is not. However, a glance at the git repository where the example code is available shows everything tied together as class libraries and invoked with a “main.py” module.The fourth chapter introduces the concept of “test harnesses.” These are used to test the MicroPython modules and application code. A simple example is used to convey the general idea.The fifth chapter is also very useful. It explains how you can customize the MicroPython kernel. This is important if you need to port to another MCU or if you want to develop custom libraries that can be included in the kernel. I've had to do this in the past to overcome some MCU peripheral limitations and functionality, as well as “freezing” libraries into the kernel as I started to run out of SRAM. Although the procedures for doing the modifications can be found on the internet, this is the first time I've seen it clearly presented in a book form.Chapter Six discusses ways to visualize data which is very useful during code development such as plotting data from a sensor in real-time (or near real-time) on your PC. In a typical C development, this is a bit of a challenge. The REPL prompt of MicroPython (and PC Python) is a very powerful feature which can be leveraged to send data to a PC over USB and displaying the data graphically using the Python mathplotlib (or Tkinter) libraries.To round out the rest of the book, Chapter Seven goes through a gesture recognizer that uses IR emitters and detectors, Chapter Eight explains how to use Android and the web to communicate with a ESP32 MicroPython board, Chapter Nine has examples for machine learning, and Chapter Ten provides a glimpse into the near future of MicroPython.So what's not to like about MicroPython Projects? I found the mix of examples using class objects and regular code to cause some temporary confusion. But my main complaint is the quality of some of the pictures and diagrams. For $40, I would expect higher print quality. But that is really the fault of the publisher.Although this book has a lot of useful information, more is needed. By it's nature, MicroPython can be slow and memory hungry. But it doesn't have to be as there are many ways to speed it up and optimize memory. Perhaps this can be covered in a second volume.All in all, an excellent read and I highly recommend it.
Amazon Verified review Amazon
Clive (Max) Maxfield May 18, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Let’s commence with the full disclosure “weasel words” (remember that eagles may soar, but weasels rarely get sucked into jet engines). First, I’m a friend of the author; second, the publisher gave me a free copy of the book to peruse, ponder, and review.OK, so I’ll start by saying that this book is not for everyone. It’s intended for a specific audience and for that audience it’s a fantastic book, but it’s not intended for beginners.The high-level blurb for the book says: “A basic understanding of electronics and Python is required while some MicroPython experience will be helpful.” When you start reading the book, it becomes a little more specific by saying: “This book assumes that the reader has a basic understanding of Python and that they have at least built a few embedded systems projects previously.”I think the key point here is the fact that the book is targeting readers who have already created a couple of embedded systems, so they understand concepts like hardware abstraction layers (HALs) and they are familiar with using GitHub and suchlike.I’m a hardware design engineer by trade. I can read and write software (predominantly C with a hint of a sniff of Python), but you wouldn’t want to use my hobbyist-level code for anything serious. Also, I’ve found it difficult in the past to meander my way around GitHub and download and install libraries and make sense of other peoples’ implementations, which is something professional embedded systems developers appear to have no problems with at all.So, assuming that you already have a clue what you are doing with regard to microcontroller development boards and embedded systems, and aren’t afraid when you hear the term “Python,” then this book provides an awesome introduction to MicroPython, which is an efficient and lean implementation of the Python 3 programming language optimized to run on microcontrollers.The book starts by setting the scene -- talking about the advantages and disadvantages of languages like C/C++ and Python and MicroPython. Next, we look at different ways to manage real-time tasks in MicroPython, using blinking a couple of unicolor LEDs as examples. This leads us into creating a simple application to read a pushbutton and use it to cycle through a series of colors on a tricolor (RGB) LED.From here, the author keeps building things up layer-by-layer, developing an application test harness, customizing the MicroPython Kernel start-up-code for your own boards, and creating a visualizer tool to display sensor data. By the end of the book, we are using MicroPython, computer vision, and machine learning (ML) to build an object detection system using the OpenMV Camera.I know many embedded systems developers who are devoted to C, but although C is incredibly powerful, it also provides you with a lot of ways to mess up (I found most of them on my own). I also know developers who started off by dipping their toes in the MicroPython waters and who subsequently became ardent users, especially for things like sensor evaluation and rapid prototyping.If you are an embedded systems developer, then the worst-case scenario is that reading this book could give you “another string to your bow” -- but beware, because you may find yourself sliding down the slippery slope to becoming a MicroPython advocate.
Amazon Verified review Amazon
Brick Sep 16, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Summary:This is not a book of elevated discussions about the choice of a programming language for embedded systems development. Rather, it is a compendium of detailed information about creating embedded systems with MicroPython as the software programming language.The sub-title, “A do-it-yourself guide for embedded developers to build a range of applications using Python”, is apt. And the book gives a more complete description of the development process than is true of most, yet is not too deep for the less experienced to enjoy.***** *****My impressions?Cons:Let me get the “cons” out of the way first, because they are few and no doubt mostly picky.I found the changing fonts distracting. This grabbed my attention as I paged through the book for the first time--perhaps because in many technical publications differing fonts express meaning, which is not the case here.In addition, some of the color images seemed indistinct. The effect was small but noticeable.And there were some places that my pseudo-English major’s brain wanted to challenge for grammar or style. But not content. That’s pretty much it. My list of “pros” is much more pertinent.Pros:The thing I like most about this book is that it is so complete in describing the topic at hand, and yet concise. This author was not “paid by the word”, as Mom used to say.I liked the introductory project, which lays the groundwork for a consistent, evolving path through the book. This begins in Chapter 3 following introductory information about the development environment.Another 'pro' for me is the choice and sequence of chapter topics. Though having different targets, they build on the previous work, progressing to the most complex and challenging projects in digestible steps.Subjectively and last on my list is the book’s aptness for those with experience in embedded systems development, but with little or no experience in using Python as the implementation language. Given the continuing rise of Python in surveys of programming languages, and its reputed productivity in terms of net code creation per programmer-hour, it’s a natural move to find a way to use it in embedded systems.Making me glad I read the book. It has been worth every minute. There’s more to say below.***** *****Recommendation:The book is packed with well thought-out information. There is much more detail in these chapters than in most such books I have read. And in very understandable form. So my recommendation is that if you want a practical manual for implementing an embedded system programmed in Python, this is an excellent choice.I believe an experienced developer or sufficiently interested person will be able to create the work described in the successively more advanced projects. It is a challenging book for those with little experience, but not beyond them. [NB--I am testing this assertion. Update forthcoming]***** *****Comments on Chapters:There are some huge additional contributions beyond the example projects themselves, including:Chapter 2 has a succinct discussion of alternative ways to manage real-time tasks, noting their pros and cons.Chapter 3 is a meat-and-potatoes exposition of a real, viable project—attaching an external I/O port-expander to the system and creating the necessary driver in MicroPython. Exactly why most will pick up the book.Later chapters (7, 8, 9) describe in equally thorough terms more challenging projects:“Device Control Using Gestures”, “Automation and Control Using Android”, and “Building an Object Detection Application Using Machine Learning”In addition to the project details there is more to be had in these chapters:Chapter 4 “Developing an Application Test Harness” gives relatively brief but well-described and usable info on a test/debug tool which I personally knew little about; so, I learned a great deal.Chapter 5 “Customizing the MicroPython Kernel Start Up Code” goes places I wish I would never go. At least yet. A good description of how to go about customizing the kernel’s start up code should you need to, and suggestions of things that might lead you there.Chapter 6 “A Custom Debugging Tool to Visualize Sensor Data” is, for me, the unexpected jewel of the book. So often I have struggled to make an embedded system yield enough information to help me find and fix what is not working. You know?It's like the software debugger’s equivalent of a hardware engineer’s oscilloscope. A quote from the chapter’s summary: “***transport sensor and debugging information*** from our device to a computer that ***then visualizes what is happening*** on our system. This can be critical to monitoring key variables, debug statements, or just creating a sensor dashboard.” [*** emphasis mine] What a valuable tool to have at hand during bring-up and debug!Chapter 10 “The Future of MicroPython”, concludes the book with thoughts about the advance of MicroPython, current real-world implementations, the pyboard D-series as a MicroPython platform, and conjecture about MicroPython’s future.Lastly, Appendix A “Downloading and Running MicroPython Code” explains in good detail how to do that, assuming you’re using the same or compatible µC board (“pyboard”--there is a link to a MicroPython tutorial for it).I also valued the extensive links and references to external resource materials throughout the body of the book and at the end of each chapter.And lastly, Chapter 1 titled “Down the Rabbit Hole …” is a bit like that literary adventure in “Alice’s Adventures in Wonderland”. By which I mean it first seemingly wanders from idea to idea, but ultimately segues to topics related to the book’s title including other programming languages, use cases for MicroPython and evaluation of whether to use it, and selecting a development platform.***** *****External resources:This quote from Chapter 10 is representative of the frequently cited external resources which enrich the reader:“There are two really good resources that you can review, which provide a great overview ofhow software should be developed. It can be found and downloaded for free by performinga 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.”***** *****Final thoughts:These projects, suggestions, references, and pointers to them found in “MicroPython Projects” have expanded my understanding and skills in a domain that is new to me and very promising. If that's your goal too, I believe you'd benefit from reading it.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is included in a Packt subscription? Chevron down icon Chevron up icon

A subscription provides you with full access to view all Packt and licnesed content online, this includes exclusive access to Early Access titles. Depending on the tier chosen you can also earn credits and discounts to use for owning content

How can I cancel my subscription? Chevron down icon Chevron up icon

To cancel your subscription with us simply go to the account page - found in the top right of the page or at https://subscription.packtpub.com/my-account/subscription - From here you will see the ‘cancel subscription’ button in the grey box with your subscription information in.

What are credits? Chevron down icon Chevron up icon

Credits can be earned from reading 40 section of any title within the payment cycle - a month starting from the day of subscription payment. You also earn a Credit every month if you subscribe to our annual or 18 month plans. Credits can be used to buy books DRM free, the same way that you would pay for a book. Your credits can be found in the subscription homepage - subscription.packtpub.com - clicking on ‘the my’ library dropdown and selecting ‘credits’.

What happens if an Early Access Course is cancelled? Chevron down icon Chevron up icon

Projects are rarely cancelled, but sometimes it's unavoidable. If an Early Access course is cancelled or excessively delayed, you can exchange your purchase for another course. For further details, please contact us here.

Where can I send feedback about an Early Access title? Chevron down icon Chevron up icon

If you have any feedback about the product you're reading, or Early Access in general, then please fill out a contact form here and we'll make sure the feedback gets to the right team. 

Can I download the code files for Early Access titles? Chevron down icon Chevron up icon

We try to ensure that all books in Early Access have code available to use, download, and fork on GitHub. This helps us be more agile in the development of the book, and helps keep the often changing code base of new versions and new technologies as up to date as possible. Unfortunately, however, there will be rare cases when it is not possible for us to have downloadable code samples available until publication.

When we publish the book, the code files will also be available to download from the Packt website.

How accurate is the publication date? Chevron down icon Chevron up icon

The publication date is as accurate as we can be at any point in the project. Unfortunately, delays can happen. Often those delays are out of our control, such as changes to the technology code base or delays in the tech release. We do our best to give you an accurate estimate of the publication date at any given time, and as more chapters are delivered, the more accurate the delivery date will become.

How will I know when new chapters are ready? Chevron down icon Chevron up icon

We'll let you know every time there has been an update to a course that you've bought in Early Access. You'll get an email to let you know there has been a new chapter, or a change to a previous chapter. The new chapters are automatically added to your account, so you can also check back there any time you're ready and download or read them online.

I am a Packt subscriber, do I get Early Access? Chevron down icon Chevron up icon

Yes, all Early Access content is fully available through your subscription. You will need to have a paid for or active trial subscription in order to access all titles.

How is Early Access delivered? Chevron down icon Chevron up icon

Early Access is currently only available as a PDF or through our online reader. As we make changes or add new chapters, the files in your Packt account will be updated so you can download them again or view them online immediately.

How do I buy Early Access content? Chevron down icon Chevron up icon

Early Access is a way of us getting our content to you quicker, but the method of buying the Early Access course is still the same. Just find the course you want to buy, go through the check-out steps, and you’ll get a confirmation email from us with information and a link to the relevant Early Access courses.

What is Early Access? Chevron down icon Chevron up icon

Keeping up to date with the latest technology is difficult; new versions, new frameworks, new techniques. This feature gives you a head-start to our content, as it's being created. With Early Access you'll receive each chapter as it's written, and get regular updates throughout the product's development, as well as the final course as soon as it's ready.We created Early Access as a means of giving you the information you need, as soon as it's available. As we go through the process of developing a course, 99% of it can be ready but we can't publish until that last 1% falls in to place. Early Access helps to unlock the potential of our content early, to help you start your learning when you need it most. You not only get access to every chapter as it's delivered, edited, and updated, but you'll also get the finalized, DRM-free product to download in any format you want when it's published. As a member of Packt, you'll also be eligible for our exclusive offers, including a free course every day, and discounts on new and popular titles.