Serial Theory

The micro:bit core crate implements the embedded_hal::serial::Write and embedded_hal::serial::Read traits for the tx and rx pins respectively.

writeln! and Carriage Return

In the introduction page on serial communication, I brushed over this:


# #![allow(unused_variables)]
#fn main() {
// Write string with newline and carriage return
let _ = write!(tx, "serial test\r\n");
#}

A naïve assumption would be to try the seemingly more correct writeln! macro:


# #![allow(unused_variables)]
#fn main() {
// Write string with newline and carriage return
let _ = writeln!(tx, "serial test");
#}

This will usually fail to do what is intended, as multiple writes will only print one line in PuTTY, and produce the following in minicom:

serial test
           serial test
                      serial test
                                 serial test

Your choices are to either configure minicom and PuTTY appropriately or use write! with \r\n.

Control Characters

The control characters operate based on a print head, as used in teleprinters.

\r - Carriage Return - The print head is moves left to the start of the line. \n - Line Feed - The print head moves down once to a new line.

writeln! macro

The writeln! macro should append a new line, but he documentation for core::writeln says:

On all platforms, the newline is the LINE FEED character (\n/U+000A) alone (no additional CARRIAGE RETURN (\r/U+000D).

minicom

CTRL-A + Z will tell you that CTRL-A + U will add a carriage return. This will add a carriage return to a received \n

PuTTY

In PuTTY, you can enable enable Implicit LF in every CR under Terminal options.

Blocking

Behind the scenes, embedded_hal::serial uses the nb crate to allow for blocking and non-blocking operation. This is implemented in embedded_hal crates by returning nb::Error::WouldBlock when a read or write action cannot be performed immediately. In this chapter, we will only be using read and write as simple blocking calls.

block!

The block! macro provided by the crate continuously calls the expression contained until it no longer returns Error::WouldBlock.

Tx - embedded_hal::serial::Write or core::fmt::Write

The write! and writeln! macros call write_str of the core::fmt::Write trait which is implemented for Tx. write_str is implemented as a blocking call to write of the embedded_hal::serial::Write trait.

This means write!(tx, "a") is equivalent to block!(tx.write(b'a')).