window.search = {"doc_urls":["index.html#microrust","index.html#approach","index.html#scope","index.html#non-goals","index.html#reporting-problems","background/index.html#background","background/index.html#what-is-a-microcontroller","background/index.html#what-can-you-do-with-a-microcontroller","background/index.html#when-should-i-use-a-microcontroller","background/index.html#when-should-i--not--use-a-microcontroller","background/index.html#development-on-the-microbit","background/index.html#why-use-rust-and-not-c","background/index.html#why-should-i-not-use-rust","requirements/index.html#requirements","requirements/index.html#knowledge","requirements/index.html#hardware","hardware/index.html#meet-your-hardware","hardware/index.html#bbc-microbit-the-microbit","hardware/index.html#micro-usb-cable","hardware/index.html#external-battery-pack","hardware/index.html#plugging-it-in","setup/index.html#development-environment-setup","setup/index.html#documentation","setup/index.html#tools","setup/index.html#rustc---cargo","setup/index.html#os-specific-instructions","setup/LINUX.html#linux","setup/LINUX.html#required-packages","setup/LINUX.html#udev-rules","setup/WINDOWS.html#windows","setup/WINDOWS.html#arm-none-eabi-","setup/WINDOWS.html#openocd","setup/WINDOWS.html#putty","setup/MACOS.html#macos","setup/VERIFY.html#verify-the-installation","setup/VERIFY.html#linux-only","setup/VERIFY.html#verify-permissions","setup/VERIFY.html#all","setup/VERIFY.html#first-openocd-connection","getting-started/00.00.README.html#getting-started","getting-started/01.00.BUILD.html#new-project","getting-started/01.00.BUILD.html#targets","getting-started/01.00.BUILD.html#build-1","getting-started/01.00.BUILD.html#no_std","getting-started/01.00.BUILD.html#build-2","getting-started/01.00.BUILD.html#build-3","getting-started/01.00.BUILD.html#panic_impl","getting-started/01.00.BUILD.html#build-4","getting-started/01.00.BUILD.html#no_main","getting-started/01.00.BUILD.html#microbit-crate","getting-started/01.00.BUILD.html#embedded-hal","getting-started/01.00.BUILD.html#cortex-m-rt","getting-started/01.00.BUILD.html#cargo-config","getting-started/01.00.BUILD.html#cargoconfig","getting-started/01.00.BUILD.html#arm-none-eabi-gdb","getting-started/01.00.BUILD.html#build-target","getting-started/01.00.BUILD.html#build-5","getting-started/01.00.BUILD.html#cargotoml","getting-started/01.00.BUILD.html#srcmainrs","getting-started/01.00.BUILD.html#a--return-type","getting-started/01.00.BUILD.html#srcmainrs","getting-started/01.00.BUILD.html#build-6","getting-started/01.00.BUILD.html#build-complete","getting-started/02.00.FLASH.html#flashing","getting-started/02.00.FLASH.html#gdbinit","getting-started/03.00.DEBUG.html#debugging","getting-started/03.00.DEBUG.html#setup","getting-started/03.00.DEBUG.html#gdb-session","getting-started/03.00.DEBUG.html#what-next","getting-started/04.00.SOLUTION.html#solution","getting-started/04.00.SOLUTION.html#cargotoml","getting-started/04.00.SOLUTION.html#rust","getting-started/04.00.SOLUTION.html#cargoconfig","getting-started/04.00.SOLUTION.html#gdbinit","hello-world/00.00.README.html#hello-world","hello-world/01.00.SEMIHOSTING.html#semihosting","hello-world/01.00.SEMIHOSTING.html#semihosting-is-slow","hello-world/01.00.SEMIHOSTING.html#gdb","hello-world/01.00.SEMIHOSTING.html#openocd","hello-world/01.00.SEMIHOSTING.html#panic","hello-world/01.00.SEMIHOSTING.html#stdout","hello-world/02.00.UART.html#serial-communication","hello-world/02.00.UART.html#usb","hello-world/02.00.UART.html#tooling","hello-world/02.00.UART.html#code","hello-world/02.01.NIX.html#nix-tooling","hello-world/02.01.NIX.html#minicom","hello-world/02.01.NIX.html#minicom--commands","hello-world/02.02.WINDOWS.html#windows-tooling","hello-world/03.00.LED.html#gpio-and-leds","hello-world/03.00.LED.html#gpio","hello-world/03.00.LED.html#led","hello-world/03.01.SOLUTION.html#solution","choice/00.00.README.html#choose-your-own-adventure","microbit/00.00.README.html#microbit-hal","microbit/01.00.BUTTONS.html#buttons","microbit/01.00.BUTTONS.html#user-buttons","microbit/02.00.DELAY.html#delays","microbit/03.00.DISPLAY.html#display","microbit/03.00.DISPLAY.html#blocking-binary-image-display","serial/00.00.README.html#wip---uart-serial-server","serial/00.00.README.html#input-and-output","serial/01.00.ECHO.html#echo-server","serial/01.00.ECHO.html#flow","serial/01.01.THEORY.html#serial-theory","serial/01.01.THEORY.html#writeln--and-carriage-return","serial/01.01.THEORY.html#control-characters","serial/01.01.THEORY.html#writeln--macro","serial/01.01.THEORY.html#minicom","serial/01.01.THEORY.html#putty","serial/01.01.THEORY.html#blocking","serial/01.01.THEORY.html#block","serial/01.01.THEORY.html#tx----embedded_halserialwrite--or--corefmtwrite","serial/01.02.ECHO.html#echo-solution","serial/02.00.html#exercises","serial/02.01.html#reverse-echo","serial/02.01.html#flow","serial/02.01.html#useful-crates","serial/02.01.SOLUTION.html#solution","serial/02.02.html#countdown","serial/02.02.html#useful-crates","serial/02.02.SOLUTION.html#solution","serial/02.04.html#quiz","serial/02.04.SOLUTION.html#solution","display/00.00.README.html#wip---led-display","display/01.00.THEORY.html#theory","display/01.00.THEORY.html#led-dot-matrix-display","display/01.00.THEORY.html#persistence-of-vision","display/01.00.THEORY.html#multiplexing","display/01.00.THEORY.html#method","display/02.00.PROBLEM.html#problem-statement","display/02.01.LAYOUT.html#led-layout","display/02.01.LAYOUT.html#schematics","display/02.01.LAYOUT.html#reference-design","display/02.02.DELAY.html#delays","display/02.02.DELAY.html#for-loop","display/02.02.DELAY.html#timers","display/02.02.DELAY.html#microbit","display/02.03.MULT.html#multiplexing","display/02.03.MULT.html#pseudocode","display/03.00.SOLUTION.html#solution","display/03.01.LAYOUT.html#layout","display/03.02.MULT.html#multiplexing","display/03.03.FULL.html#full-solution","sensors/00.00.README.html#wip---sensors-and-i²c","nb/00.00.README.html#wip---interrupts","nb/00.00.README.html#wip---interrupts","rtfm/00.00.README.html#wip---real-time","hal/00.00.README.html#wip---creating-a-hal","appendix/explore.html#whats-left-for-you-to-explore","appendix/explore.html#multitasking","appendix/explore.html#direct-memory-access-dma","appendix/explore.html#sleeping","appendix/explore.html#pulse-width-modulation-pwm","appendix/explore.html#digital-input","appendix/explore.html#sensor-fusion","appendix/explore.html#analog-to-digital-converters-adc","appendix/explore.html#digital-to-analog-converters-dac","appendix/explore.html#real-time-clock-rtc","appendix/explore.html#other-communication-protocols","appendix/gdb.html#gdb-cheatsheet","appendix/troubleshooting.html#general-troubleshooting","appendix/troubleshooting.html#openocd-problems","appendix/troubleshooting.html#cant-connect-to-openocd---error-open-failed","appendix/troubleshooting.html#cant-connect-to-openocd---polling-again-in-x00ms","appendix/troubleshooting.html#openocd-connection-lost---polling-again-in-x00ms","appendix/troubleshooting.html#cargo-problems","appendix/troubleshooting.html#cant-find-crate-for--core-","appendix/troubleshooting.html#build-problems","appendix/troubleshooting.html#error-language-item-required-but-not-found-eh_personality","appendix/troubleshooting.html#error-ld-cannot-open-linker-script-file-memoryx-no-such-file-or-directory"],"index":{"documentStore":{"docInfo":{"0":{"body":23,"breadcrumbs":1,"title":1},"1":{"body":55,"breadcrumbs":1,"title":1},"10":{"body":37,"breadcrumbs":2,"title":2},"100":{"body":17,"breadcrumbs":4,"title":4},"101":{"body":18,"breadcrumbs":2,"title":2},"102":{"body":29,"breadcrumbs":5,"title":2},"103":{"body":45,"breadcrumbs":4,"title":1},"104":{"body":11,"breadcrumbs":7,"title":2},"105":{"body":60,"breadcrumbs":8,"title":3},"106":{"body":27,"breadcrumbs":7,"title":2},"107":{"body":18,"breadcrumbs":7,"title":2},"108":{"body":13,"breadcrumbs":6,"title":1},"109":{"body":9,"breadcrumbs":6,"title":1},"11":{"body":51,"breadcrumbs":3,"title":3},"110":{"body":28,"breadcrumbs":6,"title":1},"111":{"body":12,"breadcrumbs":6,"title":1},"112":{"body":20,"breadcrumbs":8,"title":3},"113":{"body":72,"breadcrumbs":7,"title":2},"114":{"body":10,"breadcrumbs":4,"title":1},"115":{"body":26,"breadcrumbs":6,"title":2},"116":{"body":30,"breadcrumbs":5,"title":1},"117":{"body":1,"breadcrumbs":6,"title":2},"118":{"body":141,"breadcrumbs":7,"title":1},"119":{"body":20,"breadcrumbs":5,"title":1},"12":{"body":67,"breadcrumbs":2,"title":2},"120":{"body":1,"breadcrumbs":6,"title":2},"121":{"body":138,"breadcrumbs":6,"title":1},"122":{"body":0,"breadcrumbs":5,"title":1},"123":{"body":0,"breadcrumbs":6,"title":1},"124":{"body":41,"breadcrumbs":3,"title":3},"125":{"body":0,"breadcrumbs":3,"title":1},"126":{"body":30,"breadcrumbs":6,"title":4},"127":{"body":22,"breadcrumbs":4,"title":2},"128":{"body":16,"breadcrumbs":3,"title":1},"129":{"body":18,"breadcrumbs":3,"title":1},"13":{"body":0,"breadcrumbs":1,"title":1},"130":{"body":67,"breadcrumbs":4,"title":2},"131":{"body":8,"breadcrumbs":5,"title":2},"132":{"body":29,"breadcrumbs":4,"title":1},"133":{"body":93,"breadcrumbs":5,"title":2},"134":{"body":26,"breadcrumbs":4,"title":1},"135":{"body":52,"breadcrumbs":4,"title":1},"136":{"body":30,"breadcrumbs":4,"title":1},"137":{"body":14,"breadcrumbs":4,"title":1},"138":{"body":16,"breadcrumbs":4,"title":1},"139":{"body":54,"breadcrumbs":4,"title":1},"14":{"body":19,"breadcrumbs":1,"title":1},"140":{"body":5,"breadcrumbs":3,"title":1},"141":{"body":116,"breadcrumbs":4,"title":1},"142":{"body":100,"breadcrumbs":4,"title":1},"143":{"body":495,"breadcrumbs":5,"title":2},"144":{"body":0,"breadcrumbs":3,"title":3},"145":{"body":0,"breadcrumbs":2,"title":2},"146":{"body":0,"breadcrumbs":2,"title":2},"147":{"body":0,"breadcrumbs":3,"title":3},"148":{"body":0,"breadcrumbs":3,"title":3},"149":{"body":8,"breadcrumbs":3,"title":3},"15":{"body":108,"breadcrumbs":1,"title":1},"150":{"body":99,"breadcrumbs":1,"title":1},"151":{"body":45,"breadcrumbs":4,"title":4},"152":{"body":52,"breadcrumbs":1,"title":1},"153":{"body":87,"breadcrumbs":4,"title":4},"154":{"body":30,"breadcrumbs":2,"title":2},"155":{"body":43,"breadcrumbs":2,"title":2},"156":{"body":37,"breadcrumbs":4,"title":4},"157":{"body":37,"breadcrumbs":4,"title":4},"158":{"body":27,"breadcrumbs":4,"title":4},"159":{"body":159,"breadcrumbs":2,"title":2},"16":{"body":5,"breadcrumbs":2,"title":2},"160":{"body":81,"breadcrumbs":2,"title":2},"161":{"body":0,"breadcrumbs":2,"title":2},"162":{"body":0,"breadcrumbs":2,"title":2},"163":{"body":52,"breadcrumbs":6,"title":6},"164":{"body":99,"breadcrumbs":6,"title":6},"165":{"body":81,"breadcrumbs":6,"title":6},"166":{"body":0,"breadcrumbs":2,"title":2},"167":{"body":93,"breadcrumbs":4,"title":4},"168":{"body":0,"breadcrumbs":2,"title":2},"169":{"body":23,"breadcrumbs":6,"title":6},"17":{"body":106,"breadcrumbs":3,"title":3},"170":{"body":20,"breadcrumbs":10,"title":10},"18":{"body":8,"breadcrumbs":3,"title":3},"19":{"body":18,"breadcrumbs":3,"title":3},"2":{"body":33,"breadcrumbs":1,"title":1},"20":{"body":35,"breadcrumbs":1,"title":1},"21":{"body":16,"breadcrumbs":3,"title":3},"22":{"body":25,"breadcrumbs":1,"title":1},"23":{"body":57,"breadcrumbs":1,"title":1},"24":{"body":38,"breadcrumbs":2,"title":2},"25":{"body":9,"breadcrumbs":3,"title":3},"26":{"body":6,"breadcrumbs":4,"title":1},"27":{"body":107,"breadcrumbs":5,"title":2},"28":{"body":135,"breadcrumbs":5,"title":2},"29":{"body":0,"breadcrumbs":4,"title":1},"3":{"body":48,"breadcrumbs":2,"title":2},"30":{"body":33,"breadcrumbs":6,"title":3},"31":{"body":43,"breadcrumbs":4,"title":1},"32":{"body":11,"breadcrumbs":4,"title":1},"33":{"body":40,"breadcrumbs":4,"title":1},"34":{"body":5,"breadcrumbs":5,"title":2},"35":{"body":0,"breadcrumbs":4,"title":1},"36":{"body":72,"breadcrumbs":5,"title":2},"37":{"body":0,"breadcrumbs":3,"title":0},"38":{"body":168,"breadcrumbs":6,"title":3},"39":{"body":25,"breadcrumbs":2,"title":2},"4":{"body":14,"breadcrumbs":2,"title":2},"40":{"body":29,"breadcrumbs":4,"title":2},"41":{"body":58,"breadcrumbs":3,"title":1},"42":{"body":72,"breadcrumbs":4,"title":2},"43":{"body":19,"breadcrumbs":3,"title":1},"44":{"body":27,"breadcrumbs":4,"title":2},"45":{"body":17,"breadcrumbs":4,"title":2},"46":{"body":40,"breadcrumbs":3,"title":1},"47":{"body":10,"breadcrumbs":4,"title":2},"48":{"body":88,"breadcrumbs":3,"title":1},"49":{"body":15,"breadcrumbs":4,"title":2},"5":{"body":0,"breadcrumbs":1,"title":1},"50":{"body":35,"breadcrumbs":4,"title":2},"51":{"body":56,"breadcrumbs":5,"title":3},"52":{"body":15,"breadcrumbs":4,"title":2},"53":{"body":53,"breadcrumbs":3,"title":1},"54":{"body":16,"breadcrumbs":6,"title":4},"55":{"body":12,"breadcrumbs":4,"title":2},"56":{"body":0,"breadcrumbs":4,"title":2},"57":{"body":8,"breadcrumbs":3,"title":1},"58":{"body":26,"breadcrumbs":3,"title":1},"59":{"body":18,"breadcrumbs":4,"title":2},"6":{"body":32,"breadcrumbs":1,"title":1},"60":{"body":11,"breadcrumbs":3,"title":1},"61":{"body":14,"breadcrumbs":4,"title":2},"62":{"body":32,"breadcrumbs":4,"title":2},"63":{"body":569,"breadcrumbs":3,"title":1},"64":{"body":56,"breadcrumbs":3,"title":1},"65":{"body":0,"breadcrumbs":3,"title":1},"66":{"body":16,"breadcrumbs":3,"title":1},"67":{"body":687,"breadcrumbs":4,"title":2},"68":{"body":12,"breadcrumbs":3,"title":1},"69":{"body":3,"breadcrumbs":3,"title":1},"7":{"body":77,"breadcrumbs":1,"title":1},"70":{"body":13,"breadcrumbs":3,"title":1},"71":{"body":22,"breadcrumbs":3,"title":1},"72":{"body":53,"breadcrumbs":3,"title":1},"73":{"body":31,"breadcrumbs":3,"title":1},"74":{"body":19,"breadcrumbs":2,"title":2},"75":{"body":20,"breadcrumbs":3,"title":1},"76":{"body":29,"breadcrumbs":4,"title":2},"77":{"body":20,"breadcrumbs":3,"title":1},"78":{"body":37,"breadcrumbs":3,"title":1},"79":{"body":37,"breadcrumbs":3,"title":1},"8":{"body":115,"breadcrumbs":2,"title":2},"80":{"body":21,"breadcrumbs":3,"title":1},"81":{"body":56,"breadcrumbs":4,"title":2},"82":{"body":10,"breadcrumbs":3,"title":1},"83":{"body":10,"breadcrumbs":3,"title":1},"84":{"body":63,"breadcrumbs":3,"title":1},"85":{"body":78,"breadcrumbs":6,"title":2},"86":{"body":185,"breadcrumbs":5,"title":1},"87":{"body":43,"breadcrumbs":6,"title":2},"88":{"body":139,"breadcrumbs":6,"title":2},"89":{"body":0,"breadcrumbs":4,"title":2},"9":{"body":34,"breadcrumbs":2,"title":2},"90":{"body":58,"breadcrumbs":3,"title":1},"91":{"body":190,"breadcrumbs":3,"title":1},"92":{"body":133,"breadcrumbs":5,"title":1},"93":{"body":45,"breadcrumbs":2,"title":2},"94":{"body":26,"breadcrumbs":2,"title":2},"95":{"body":9,"breadcrumbs":4,"title":1},"96":{"body":120,"breadcrumbs":5,"title":2},"97":{"body":15,"breadcrumbs":4,"title":1},"98":{"body":24,"breadcrumbs":4,"title":1},"99":{"body":204,"breadcrumbs":7,"title":4}},"docs":{"0":{"body":"Discover the world of microcontrollers through Rust on the BBC micro:bit ! This book is an introductory course on microcontroller-based embedded systems that uses Rust as the teaching language (rather than the usual C/C++), and the micro:bit as the target system.","breadcrumbs":"MicroRust","id":"0","title":"MicroRust"},"1":{"body":"Beginner friendly. No previous experience with microcontrollers or embedded systems is required. Hands on. You will be doing most of the work here. When possible, pages will end on a problem for you to solve, with the solution on the next page. There are plenty of exercises to put the theory into practice. Standard. We'll make plenty use of standard tooling and processes to ease development so you can apply the skills learnt to any Rust embedded project. Fixing compiler errors, debugging with GDB, and logging will be introduced early on. Using LEDs as a debugging mechanism has no place here.","breadcrumbs":"Approach","id":"1","title":"Approach"},"10":{"body":"The micro:bit website offers several very simple ways of programming a microbit, aimed at teaching school children how to program. This is a very good introduction to the world of microcontollers and programming, but falls short of teaching true embedded development. From there you would usually move to C to develop skills useful in industry, developing performant embedded software.","breadcrumbs":"Development on the micro:bit","id":"10","title":"Development on the micro:bit"},"100":{"body":"In the first section of this book we saw how to do a simple debug print using serial. This is useful for logging and debugging, but does not cover the full potential of the UART peripheral.","breadcrumbs":"WIP - UART serial server","id":"100","title":"WIP - UART serial server"},"101":{"body":"The simultaneous input and output capabilities of the UART allow for both your computer and the micro:bit to act as a server. They can receive a transmission, process it, perform some action, and send a response.","breadcrumbs":"Input and output","id":"101","title":"Input and output"},"102":{"body":"An echo server, is probably the simplest server we could make. It should receive a message, and echo it back to the sender. We earlier said that minicom/PuTTY would transmit any keystrokes we send, and display and data received, so the end result should be the familiar experience of typing and seeing the letters typed appear as expected.","breadcrumbs":"Serial UART - Blocking » Echo Server","id":"102","title":"Echo Server"},"103":{"body":"The character a is typed minicom/PuTTY encodes the a character's unicode code point ( 097 in decimal) as a word in a serial frame The frame is transmitted to the micro:bit over USB The micro:bit software decodes the frame to get the word The microbit software re-encodes the word to get a (new but identical) frame The frame is transmitted to the computer over USB minicom/PuTTY decodes the frame's word as a unicode code point The letter a is displayed","breadcrumbs":"Serial UART - Blocking » Flow","id":"103","title":"Flow"},"104":{"body":"The micro:bit core crate implements the embedded_hal::serial::Write and embedded_hal::serial::Read traits for the tx and rx pins respectively.","breadcrumbs":"Serial UART - Blocking » Echo Server » Serial Theory","id":"104","title":"Serial Theory"},"105":{"body":"In the introduction page on serial communication, I brushed over this: // Write string with newline and carriage return\nlet _ = write!(tx, \"serial test\\r\\n\"); A naïve assumption would be to try the seemingly more correct writeln! macro: // Write string with newline and carriage return\nlet _ = 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 .","breadcrumbs":"Serial UART - Blocking » Echo Server » writeln! and Carriage Return","id":"105","title":"writeln! and Carriage Return"},"106":{"body":"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.","breadcrumbs":"Serial UART - Blocking » Echo Server » Control Characters","id":"106","title":"Control Characters"},"107":{"body":"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).","breadcrumbs":"Serial UART - Blocking » Echo Server » writeln! macro","id":"107","title":"writeln! macro"},"108":{"body":"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","breadcrumbs":"Serial UART - Blocking » Echo Server » minicom","id":"108","title":"minicom"},"109":{"body":"In PuTTY, you can enable enable Implicit LF in every CR under Terminal options.","breadcrumbs":"Serial UART - Blocking » Echo Server » PuTTY","id":"109","title":"PuTTY"},"11":{"body":"Hopefully I don't need to convince you here as you are probably familiar with the language differences between Rust and C. One point I do want to bring up is package management. C lacks an official, widely accepted package management solution whereas Rust has Cargo. This makes development much easier. And, IMO, easy package management encourages code reuse because libraries can be easily integrated into an application which is also a good thing as libraries get more \"battle testing\".","breadcrumbs":"Why use Rust and not C?","id":"11","title":"Why use Rust and not C?"},"110":{"body":"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.","breadcrumbs":"Serial UART - Blocking » Echo Server » Blocking","id":"110","title":"Blocking"},"111":{"body":"The block! macro provided by the crate continuously calls the expression contained until it no longer returns Error::WouldBlock.","breadcrumbs":"Serial UART - Blocking » Echo Server » block!","id":"111","title":"block!"},"112":{"body":"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')) .","breadcrumbs":"Serial UART - Blocking » Echo Server » Tx - embedded_hal::serial::Write or core::fmt::Write","id":"112","title":"Tx - embedded_hal::serial::Write or core::fmt::Write"},"113":{"body":"#![no_std]\n#![no_main] extern crate panic_semihosting;\nextern crate cortex_m_rt as rt;\nextern crate cortex_m_semihosting as sh;\nextern crate microbit; use core::fmt::Write;\nuse rt::entry;\nuse sh::hio; use microbit::hal::prelude::*;\nuse microbit::hal::serial;\nuse microbit::hal::serial::BAUD115200;\nuse microbit::nb::block; #[entry]\nfn main() -> ! { let mut stdout = hio::hstdout().unwrap(); writeln!(stdout, \"Start\").unwrap(); if let Some(p) = microbit::Peripherals::take() { // Split GPIO let mut gpio = p.GPIO.split(); // Configure RX and TX pins accordingly let tx = gpio.pin24.into_push_pull_output().downgrade(); let rx = gpio.pin25.into_floating_input().downgrade(); // Configure serial communication let (mut tx, mut rx) = serial::Serial::uart0(p.UART0, tx, rx, BAUD115200).split(); writeln!(tx, \"Start\"); loop { let val = block!(rx.read()).unwrap(); block!(tx.write(val)); } } panic!(\"End\");\n}","breadcrumbs":"Serial UART - Blocking » Echo Server » Echo Solution","id":"113","title":"Echo Solution"},"114":{"body":"Reverse echo a line of input Numerical countdown Display echo Quiz game","breadcrumbs":"Serial UART - Blocking » Exercises","id":"114","title":"Exercises"},"115":{"body":"The micro:bit should buffer characters it receives until \\n or \\r is received (the enter key is pressed on the host computer). The characters should then be printed back in reverse order to the host computer. The characters may also be echoed like earlier to see what is being typed.","breadcrumbs":"Serial UART - Blocking » Exercises » Reverse Echo","id":"115","title":"Reverse Echo"},"116":{"body":"Letter a is typed and transmitted to the micro:bit (optional) The micro:bit retransmits the letter a (echo) Letter b is typed and transmitted to the micro:bit (optional) The micro:bit retransmits the letter b (echo) Enter key is pressed and \\r is transmitted to the micro:bit Letters ba are transmitted from the micro:bit","breadcrumbs":"Serial UART - Blocking » Exercises » Flow","id":"116","title":"Flow"},"117":{"body":"Heapless","breadcrumbs":"Serial UART - Blocking » Exercises » Useful crates","id":"117","title":"Useful crates"},"118":{"body":"#![no_std]\n#![no_main] extern crate panic_semihosting;\nextern crate cortex_m_rt as rt;\nextern crate cortex_m_semihosting as sh;\nextern crate heapless;\nextern crate microbit; use core::fmt::Write;\nuse rt::entry;\nuse sh::hio;\nuse heapless::{consts, Vec}; use microbit::hal::prelude::*;\nuse microbit::hal::delay::Delay;\nuse microbit::hal::serial;\nuse microbit::hal::serial::BAUD115200; #[entry]\nfn main() -> ! { let mut stdout = hio::hstdout().unwrap(); writeln!(stdout, \"Start\").unwrap(); if let Some(p) = microbit::Peripherals::take() { // Split GPIO let mut gpio = p.GPIO.split(); // Create delay provider let mut delay = Delay::new(p.TIMER0); // Configure RX and TX pins accordingly let tx = gpio.pin24.into_push_pull_output().downgrade(); let rx = gpio.pin25.into_floating_input().downgrade(); // Configure serial communication let (mut tx, mut rx) = serial::Serial::uart0(p.UART0, tx, rx, BAUD115200).split(); // A buffer with 32 bytes of capacity let mut buffer: Vec = Vec::new(); writeln!(tx, \"Start\"); loop { loop { // Read let byte = block!(rx.read()).unwrap(); // Echo block!(tx.write(byte)); // Carriage return if byte == b'\\r' { break; } // Push to buffer if buffer.push(byte).is_err() { // Buffer full writeln!(tx, \"\\r\\nWarning: buffer full, dumping buffer\"); break; } } // Uncomment to not overwrite input string //writeln!(tx, \"\"); // Respond for b in buffer.iter().rev() { block!(tx.write(*b)); } writeln!(tx, \"\"); buffer.clear(); } } panic!(\"End\");\n} I have used an implementation of a vector on the stack, provided by the heapless crate. After 32 characters (a char is a u8 byte) the heapless vector is full, and an error is shown.","breadcrumbs":"Serial UART - Blocking » Exercises » Reverse echo » Solution","id":"118","title":"Solution"},"119":{"body":"You should be able to type a number greater than 0, press enter, and the micro:bit will return a countdown. 5\n4\n3\n2\n1 Feel free to add your own surprise at the end of the countdown","breadcrumbs":"Serial UART - Blocking » Exercises » Countdown","id":"119","title":"Countdown"},"12":{"body":"Or why should I prefer C over Rust? The C ecosystem is way more mature. Off the shelf solution for several problems already exist. If you need to control a time sensitive process, you can grab one of the existing commercial Real Time Operating Systems (RTOS) out there and solve your problem. There are no commercial, production-grade RTOSes in Rust yet so you would have to either create one yourself or try one of the ones that are in development. If you are looking to develop your skills to find a job, it is currently unlikely that a company doing embedded software development will be using Rust, and so your time would be better spent learning normal embedded development using C.","breadcrumbs":"Why should I not use Rust?","id":"12","title":"Why should I not use Rust?"},"120":{"body":"Heapless","breadcrumbs":"Serial UART - Blocking » Exercises » Useful crates","id":"120","title":"Useful crates"},"121":{"body":"#![no_std]\n#![no_main] extern crate panic_semihosting;\nextern crate cortex_m_rt as rt;\nextern crate cortex_m_semihosting as sh;\nextern crate heapless;\nextern crate microbit; use core::fmt::Write;\nuse rt::entry;\nuse sh::hio;\nuse heapless::{consts, Vec, String}; use microbit::hal::prelude::*;\nuse microbit::hal::delay::Delay;\nuse microbit::hal::serial;\nuse microbit::hal::serial::BAUD115200; #[entry]\nfn main() -> ! { let mut stdout = hio::hstdout().unwrap(); writeln!(stdout, \"Start\").unwrap(); if let Some(p) = microbit::Peripherals::take() { // Split GPIO let mut gpio = p.GPIO.split(); // Create delay provider let mut delay = Delay::new(p.TIMER0); // Configure RX and TX pins accordingly let tx = gpio.pin24.into_push_pull_output().downgrade(); let rx = gpio.pin25.into_floating_input().downgrade(); // Configure serial communication let (mut tx, mut rx) = serial::Serial::uart0(p.UART0, tx, rx, BAUD115200).split(); writeln!(tx, \"Start\"); loop { // A buffer with 32 bytes of capacity let mut buffer: Vec = Vec::new(); loop { // Read let byte = block!(rx.read()).unwrap(); // Echo block!(tx.write(byte)); // Carriage return if byte == b'\\r' { break; } // Push to buffer if buffer.push(byte).is_err() { // Buffer full writeln!(tx, \"\\r\\nWarning: buffer full, dumping buffer\"); break; } } // Buffer to string let buf_str = String::from_utf8(buffer).unwrap(); writeln!(tx, \"\"); match buf_str.parse() { // Transmit countdown Ok(buf_int) => { for i in (1..buf_int).rev() { delay.delay_ms(1000_u32); writeln!(tx, \"{}\", i); } // Add post countdown effects here }, // Transmit parse error Err(e) => writeln!(tx, \"{:?}\", e).unwrap(), } } } panic!(\"End\");\n}","breadcrumbs":"Serial UART - Blocking » Exercises » Countdown » Solution","id":"121","title":"Solution"},"122":{"body":"","breadcrumbs":"Serial UART - Blocking » Exercises » Quiz","id":"122","title":"Quiz"},"123":{"body":"","breadcrumbs":"Serial UART - Blocking » Exercises » Quiz » Solution","id":"123","title":"Solution"},"124":{"body":"This chapters follows on from the basic LED example from getting started. The LEDs are wired up in a matrix, as described in these schematics . Only a small proportion of images can be displayed at once with this layout; it is impossible for example to turn on both LED1 and LED11 without also having LED2 and LED10 turning on. In this chapter we will be talking through how to achieve the impossible, displaying any chosen image, and even adjusting the brightness!","breadcrumbs":"WIP - LED display","id":"124","title":"WIP - LED display"},"125":{"body":"","breadcrumbs":"LED display » Theory","id":"125","title":"Theory"},"126":{"body":"A dot matrix display is a display containing a two dimensional array of points, used to represent characters, symbols, or images. All displays today are dot matrix displays, but vector displays also used to exist, examples include radar displays and 1980s arcade games.","breadcrumbs":"LED display » LED dot matrix display","id":"126","title":"LED dot matrix display"},"127":{"body":"In order to achieve full control of all LEDs we need to use an optical illusion called the persistence of vision . This effect causes light which has ceased entering the eye to still be seen for a little while after it has disappeared.","breadcrumbs":"LED display » Persistence of vision","id":"127","title":"Persistence of vision"},"128":{"body":"Multiplexing is the combination of multiple signals over shared medium. In this case, we will be using human vision to multiplex time and space divided signals","breadcrumbs":"LED display » Multiplexing","id":"128","title":"Multiplexing"},"129":{"body":"We are able to fully control one (circuit) row of LEDs at a time, so by quickly looping through the rows lof LEDs, we can let the brain blur them together into a complete image.","breadcrumbs":"LED display » Method","id":"129","title":"Method"},"13":{"body":"","breadcrumbs":"Requirements","id":"13","title":"Requirements"},"130":{"body":"Display any given image on the micro:bit display. The image will be a 5x5 array, where 0 will represent off and 1 will represent on. The following, for example, should display a heart: let heart = [ [0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [1, 0, 0, 0, 1], [0, 1, 0, 1, 0], [0, 0, 1, 0, 0],\n]; At this point, you may know enough to solve the problem yourself. If you want to jump straight to the solution, you can go to the end of the next section in this chapter. This section will continue formally breaking this problem down into smaller and more tractable pieces.","breadcrumbs":"LED display » Problem statement","id":"130","title":"Problem statement"},"131":{"body":"Convert a 5x5 array into a 3x9 array to match the display's circuitry.","breadcrumbs":"LED display » Problem » LED layout","id":"131","title":"LED layout"},"132":{"body":"The schem1 discussed earlier describe the electrical layout of the LEDs, but they do not describe how it relates to the visual layout. It would be a mistake to assume that the numbers 1 to 25 have any correlation to the visual layout of the LEDs on the micro:bit as they do NOT . It just happened to be that ROW0 and COL0 intersect at an LED in the top left corner.","breadcrumbs":"LED display » Problem » Schematics","id":"132","title":"Schematics"},"133":{"body":"To find the relationship between the electrical array and visual array, we need to look at the reference design for the micro:bit. This can be found through a link at the bottom of the micro:bit hardware page By navigating to the github page > PDF > Schematic Print, you can find a detailed electrical schematic for the micro:bit . In the top right, you will see an array which can be defined in Rust as follows: const LED_LAYOUT: [[(usize, usize); 5]; 5] = [ [(0, 0), (1, 3), (0, 1), (1, 4), (0, 2)], [(2, 3), (2, 4), (2, 5), (2, 6), (2, 7)], [(1, 1), (0, 8), (1, 2), (2, 8), (1, 0)], [(0, 7), (0, 6), (0, 5), (0, 4), (0, 3)], [(2, 2), (1, 6), (2, 0), (1, 5), (2, 1)],\n];","breadcrumbs":"LED display » Problem » Reference design","id":"133","title":"Reference design"},"134":{"body":"Create a time delay. Another piece of information you will need is how to create a time delay before moving to the next row. we want the time spent switching LED lines on and off to be much shorter than the time spent waiting with LEDs on.","breadcrumbs":"LED display » Problem » Delays","id":"134","title":"Delays"},"135":{"body":"A first attempt to implement the delay function without using any peripherals is to implement it as a for loop delay: fn delay(ms: u16) { const K: u16 = 16_000; // 16MHz microprocessor, needs to be tweaked for _ in 0..(K*ms) {}\n} When compiled in release mode however, this is optimized away. To solve this we could explicitly add an operation inside the loop. The perfect candidate is the NOP . fn delay(ms: u16) { const K: u16 = 16_000; // 16MHz microprocessor, needs to be tweaked for _ in 0..(K*ms) { cortex_m::asm::nop(); }\n}","breadcrumbs":"LED display » Problem » For loop","id":"135","title":"For loop"},"136":{"body":"A better way of implementing delays is by using timers. A one-shot timer (also called one pulse mode) works like an alarm clock. You set it once with the amount of time you want, and then wait until it goes off. Fortuinately for us, HAL crates usually have already solved this for us.","breadcrumbs":"LED display » Problem » Timers","id":"136","title":"Timers"},"137":{"body":"The microbit has 3 timers, we will use the first: TIMER0. To use it, do the following: if let Some(p) = microbit::Peripherals::take() { let mut delay = Delay::new(p.TIMER0); delay.delay_ms(1000_u32);\n}","breadcrumbs":"LED display » Problem » Microbit","id":"137","title":"Microbit"},"138":{"body":"Multiplex the rows of the matrix The final task is to multiplex the rows of electrical matrix into a full image. We will be doing this by scanning through the rows in the display.","breadcrumbs":"LED display » Problem » Multiplexing","id":"138","title":"Multiplexing"},"139":{"body":"In order to light up an LED, the row needs to be set high and the column needs to be set low. We will assume that at the start of a refresh cycle, that all the rows are set low and all the columns are set high. The order of operations during a refresh cycle is then, for each row: set the row high for each column set low if the LED associated with that row-column pair should be on sleep for a known duration, you should find 2ms is sufficient for each column set high set the row low","breadcrumbs":"LED display » Problem » Pseudocode","id":"139","title":"Pseudocode"},"14":{"body":"The only knowledge requirement to read this book is to know some Rust. It's hard to quantify some but a good benchmark is having read and understood the first 14 chapters of the Rust book .","breadcrumbs":"Knowledge","id":"14","title":"Knowledge"},"140":{"body":"This solution describes a blocking display driver.","breadcrumbs":"LED display » Solution","id":"140","title":"Solution"},"141":{"body":"Convert a 5x5 array into a 3x9 array to match the display's circuitry. const LED_LAYOUT: [[(usize, usize); 5]; 5] = [ [(0, 0), (1, 3), (0, 1), (1, 4), (0, 2)], [(2, 3), (2, 4), (2, 5), (2, 6), (2, 7)], [(1, 1), (0, 8), (1, 2), (2, 8), (1, 0)], [(0, 7), (0, 6), (0, 5), (0, 4), (0, 3)], [(2, 2), (1, 6), (2, 0), (1, 5), (2, 1)],\n]; /// Convert 5x5 display image to 3x9 matrix image\npub fn display2matrix(led_display: [[u8; 5]; 5]) -> [[u8; 9]; 3] { // Create 3x9 array let mut led_matrix: [[u8; 9]; 3] = [[0; 9]; 3]; // Iterate through zip of input array and layout array for (led_display_row, layout_row) in led_display.iter().zip(LED_LAYOUT.iter()) { // Continue iterating through rows for (led_display_val, layout_loc) in led_display_row.iter().zip(layout_row) { // Assign dereferenced val to array led_matrix[layout_loc.0][layout_loc.1] = *led_display_val; } } return led_matrix;\n}","breadcrumbs":"LED display » Solution » Layout","id":"141","title":"Layout"},"142":{"body":"Multiplex the rows of the matrix /// Display 3x9 matrix image for a given duration.\npub fn display_pre(&mut self, delay: &mut Delay, led_matrix: [[u8; 9]; 3], duration_ms: u32) { // TODO // These need to be populated with PINs, e.g.: let rows = [PIN; 3]; let cols = [PIN; 9]; // Set refresh rate. let delay_ms = 2; // Calculate number of loops. let loops = duration_ms / (rows.len() as u32 * delay_ms); for _ in 0..loops { for (row_line, led_matrix_row) in rows.iter_mut().zip(led_matrix.iter()) { // Set the row high. row_line.set_high(); // Set the correct pins low (on) // This could lead to very small differences in execution time, // but this is not worth correcting for, as it is << 2ms. for (col_line, led_matrix_val) in cols.iter_mut().zip(led_matrix_row.iter()) { // We ignore any brightness setting, just use 0 and 1. if *led_matrix_val > 0 { col_line.set_low(); } } delay.delay_ms(delay_ms); // It is not worth the logic to check which pins need resetting, // so set all the pins back high. for col_line in &mut cols { col_line.set_high(); } // Set the row back low. row_line.set_low(); } }\n}","breadcrumbs":"LED display » Solution » Multiplexing","id":"142","title":"Multiplexing"},"143":{"body":"For the most modern implementations, please look at the code in the micro:bit crate . #![no_std]\n#![no_main] extern crate panic_semihosting;\nextern crate cortex_m_rt as rt;\nextern crate cortex_m_semihosting as sh;\nextern crate microbit; use core::fmt::Write;\nuse rt::entry;\nuse sh::hio; use microbit::hal::delay::Delay;\nuse microbit::hal::gpio::gpio::PIN;\nuse microbit::hal::gpio::gpio::{PIN4, PIN5, PIN6, PIN7, PIN8, PIN9, PIN10, PIN11, PIN12, PIN13, PIN14, PIN15};\nuse microbit::hal::gpio::{Output, PushPull};\nuse microbit::hal::serial;\nuse microbit::hal::serial::BAUD115200;\nuse microbit::hal::prelude::*; type LED = PIN