Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The MB2 Speaker

Your MB2 has a built-in speaker — the large black square device labeled "SPEAKER" in the middle of the back of the board.

The speaker works by moving air in response to a GPIO pin: when the speaker pin is high (3.3V) a diaphragm inside — the "speaker cone" — is pushed all the way out; when the speaker pin is low (GND) it is pulled all the way back in. As air is pushed out and sucked back in, it flows in and out of the tiny rectangular hole — the "speaker port" — on the side of the device. Do this fast enough, and the pressure changes will make a sound.

With the right hardware driving it, this speaker cone could actually be moved to any position in its range with an appropriate current. This would allow fairly good reproduction of any sound, like a "normal" speaker. Unfortunately, limitations in the MB2 hardware controlling the speaker mean that only the full-in and full-out positions are readily available.

Let's push the speaker cone out and then in 220 times per second. This will produce a "square" 220-cycles-per-second pressure wave. The unit "cycles-per-second" is Hertz; we will be producing a 220Hz tone (a musical "A3"), which is not unpleasant on this shrill speaker.

We'll make our tone play for five seconds and then stop. It is important to remember that our program lives in flash on the MB2 — the tone will start up again each time we reset or even power on the MB2. If we let the tone run forever, this behavior can rapidly become quite annoying.

Here's the code (examples/square-wave.rs).

#![no_main]
#![no_std]

use cortex_m::asm;
use cortex_m_rt::entry;
use embedded_hal::{delay::DelayNs, digital::OutputPin};
use panic_rtt_target as _;
use rtt_target::rtt_init_print;

use microbit::{
    Board,
    hal::{gpio, timer},
};

/// The "period" is the time per cycle. It is
/// 1/f where f is the frequency in Hz. In this
/// case we measure time in milliseconds.
const PERIOD: u32 = 1000 / 220;

/// Number of cycles for 5 seconds of output.
const CYCLES: u32 = 5000 / PERIOD;

#[entry]
fn main() -> ! {
    rtt_init_print!();
    let board = Board::take().unwrap();
    let mut speaker_pin = board.speaker_pin.into_push_pull_output(gpio::Level::Low);
    let mut timer = timer::Timer::new(board.TIMER0);

    for _ in 0..CYCLES {
        speaker_pin.set_high().unwrap();
        timer.delay_ms(PERIOD / 2);
        speaker_pin.set_low().unwrap();
        timer.delay_ms(PERIOD / 2);
    }
    
    loop {
        asm::wfi();
    }
}