diff --git a/src/ble.rs b/src/ble.rs
index 94be06c7afc0514e2ca9394699d270495244c215..81effee4a89fd87cc05081633378a7c7b2cb3c45 100644
--- a/src/ble.rs
+++ b/src/ble.rs
@@ -44,15 +44,6 @@ static mut BLE_BUFFERS: BleBuffers = BleBuffers {
     rx_queue: SimpleQueue::new(),
 };
 
-pub struct Ble {
-    pub radio: BleRadio,
-    pub ble_ll: LinkLayer<AppConfig>,
-    // pub ble_r: Responder<AppConfig>,
-    // pub beacon: Beacon,
-
-}
-static BLE: Mutex<OnceCell<Ble>> = Mutex::new(OnceCell::uninitialized());
-
 pub enum AppConfig {}
 
 impl Config for AppConfig {
@@ -62,132 +53,114 @@ impl Config for AppConfig {
     type PacketQueue = &'static mut SimpleQueue;
 }
 
+struct Ble {
+    radio: BleRadio,
+    ble_ll: LinkLayer<AppConfig>,
+    ble_r: Responder<AppConfig>,
+}
+
+static BLE: Mutex<OnceCell<Ble>> = Mutex::new(OnceCell::uninitialized());
+
 pub(crate) fn initialize(radio: RADIO, ficr: &FICR, timer: TIMER0, clock: CLOCK, nvic: &mut NVIC) {
+    // On reset, the internal high frequency clock is already used, but we
+    // also need to switch to the external HF oscillator. This is needed
+    // for Bluetooth to work.
     let _clocks = Clocks::new(clock).enable_ext_hfosc();
+    let ble_timer = BleTimer::init(timer);
 
     let buffers: &'static mut BleBuffers = unsafe { &mut BLE_BUFFERS };
+
+    // Determine device address
     let device_address = get_device_address();
 
-    let ble_timer = BleTimer::init(timer);
+    // Rubble currently requires an RX buffer even though the radio is only used as a TX-only beacon.
     let mut radio = BleRadio::new(
         radio,
-        &ficr,
+        ficr,
         &mut buffers.ble_tx_buf,
         &mut buffers.ble_rx_buf,
     );
 
+
+    // Create TX/RX queues
+    let (tx, tx_cons) = buffers.tx_queue.split();
+    let (rx_prod, rx) = buffers.rx_queue.split();
+
+    // Create the actual BLE stack objects
     let mut ble_ll = LinkLayer::<AppConfig>::new(device_address, ble_timer);
 
-    // let (tx, tx_cons) = buffers.tx_queue.split();
-    // let (rx_prod, rx) = buffers.rx_queue.split();
-    // let ble_r: Responder<AppConfig> = Responder::new(
-    //     tx,
-    //     rx,
-    //     L2CAPState::new(BleChannelMap::with_attributes(DemoAttrs::new())),
-    // );
+    let ble_r = Responder::new(
+        tx,
+        rx,
+        L2CAPState::new(BleChannelMap::with_attributes(DemoAttrs::new())),
+    );
 
     // Send advertisement and set up regular interrupt
-    // let next_update = ble_ll
-    //     .start_advertise(
-    //         Duration::from_millis(200),
-    //         &[AdStructure::CompleteLocalName("RUSTY TRANSMITTER")],
-    //         &mut radio,
-    //         tx_cons,
-    //         rx_prod,
-    //     )
-    //     .unwrap();
-    // ble_ll.timer().configure_interrupt(next_update);
-
-    // let beacon = Beacon::new(device_address, &[AdStructure::CompleteLocalName("RUSTY TRANSMITTER")]).unwrap();
-
-    BLE.lock().initialize(Ble {
+    let next_update = ble_ll
+        .start_advertise(
+            Duration::from_millis(100),
+            &[AdStructure::CompleteLocalName("Rusty Transmitter")],
+            &mut radio,
+            tx_cons,
+            rx_prod,
+        )
+        .unwrap();
+
+    ble_ll.timer().configure_interrupt(next_update);
+
+    unsafe {
+        NVIC::unpend(Interrupt::RADIO);
+        NVIC::unpend(Interrupt::TIMER0);
+        nvic.set_priority(Interrupt::RADIO, 3);
+        nvic.set_priority(Interrupt::TIMER0, 3);
+        NVIC::unmask(Interrupt::RADIO);
+        NVIC::unmask(Interrupt::TIMER0);
+    }
+
+    BLE.modify(|ble| ble.initialize(Ble {
         radio,
-        // beacon
         ble_ll,
-        // ble_r
-    });
+        ble_r
+    }))
+}
 
-    //Enable interrupts
-    unsafe {
-    //     nvic.set_priority(Interrupt::TIMER0, 3);
-    //     NVIC::unpend(Interrupt::TIMER0);
-    //     NVIC::unmask(Interrupt::TIMER0);
-    //     nvic.set_priority(Interrupt::RADIO, 3);
-    //     NVIC::unpend(Interrupt::RADIO);
-    //     NVIC::unmask(Interrupt::RADIO);
+#[interrupt]
+fn RADIO() {
+    let ble: &mut Ble = unsafe { BLE.no_critical_section_lock_mut() };
+    if let Some(cmd) = ble
+        .radio
+        .recv_interrupt(ble.ble_ll.timer().now(), &mut ble.ble_ll) {
+        ble.radio.configure_receiver(cmd.radio);
+        ble.ble_ll.timer().configure_interrupt(cmd.next_update);
     }
 }
 
-pub fn update_ble() {
-    let ble = &mut **BLE.lock();
-    // let _ = ble.ble_ll.update_timer(&mut ble.radio);
+#[interrupt]
+fn TIMER0() {
+    let ble: &mut Ble = unsafe { BLE.no_critical_section_lock_mut() };
 
-    let addr = get_device_address();
-    let data = &[AdStructure::CompleteLocalName("RUSTY TRANSMITTER")];
-    let tx = &mut ble.radio;
+    let timer = ble.ble_ll.timer();
+    if !timer.is_interrupt_pending() {
+        return;
+    }
+    timer.clear_interrupt();
 
-    // let pdu = PduBuf::beacon(addr, data).unwrap();
-    let pdu = PduBuf::discoverable(addr, data).unwrap();
-    let payload = pdu.payload();
-    let buf = tx.tx_payload_buf();
-    buf[..payload.len()].copy_from_slice(payload);
+    let cmd = ble.ble_ll.update_timer(&mut ble.radio);
+    ble.radio.configure_receiver(cmd.radio);
 
-    for channel in AdvertisingChannel::iter_all() {
-        tx.transmit_advertising(pdu.header(), channel);
-    }
+    ble
+        .ble_ll
+        .timer()
+        .configure_interrupt(cmd.next_update);
+}
 
-    // ble.beacon.broadcast(&mut ble.radio);
+pub fn update_ble() {
+    BLE.modify(|ble: &mut OnceCell<Ble> | {
+        while ble.ble_r.has_work() {
+            ble.ble_r.process_one().unwrap();
+        }
+
+        Green.set(ble.ble_ll.is_connected());
+    });
 }
 
-// #[interrupt]
-// fn RADIO() {
-    // let ble = &mut **BLE.lock();
-    // Green.toggle();
-
-    // let ble_ll: &mut LinkLayer<AppConfig> = &mut ble.ble_ll;
-    // if let Some(cmd) = ble
-    //     .radio
-    //     .recv_interrupt(ble_ll.timer().now(), ble_ll)
-    // {
-    //     ble.radio.configure_receiver(cmd.radio);
-    //     ble_ll.timer().configure_interrupt(cmd.next_update);
-    //
-    //     if cmd.queued_work {
-    //         while ble.ble_r.has_work() {
-    //             ble.ble_r.process_one().unwrap();
-    //         }
-    //     }
-    // }
-// }
-
-// #[interrupt]
-// fn TIMER0() {
-//     let ble = &mut **BLE.lock();
-//     let ble_ll: &mut LinkLayer<AppConfig> = &mut ble.ble_ll;
-//
-//     let timer = ble_ll.timer();
-//     if !timer.is_interrupt_pending() {
-//         return;
-//     }
-//     timer.clear_interrupt();
-//
-//     let cmd = ble.ble_ll.update_timer(&mut ble.radio);
-//     ble.radio.configure_receiver(cmd.radio);
-//
-//     if ble.ble_ll.is_advertising() {
-//         Green.toggle();
-//     }
-//
-//     ble
-//         .ble_ll
-//         .timer()
-//         .configure_interrupt(cmd.next_update);
-//
-//
-//
-//     if cmd.queued_work {
-//         while ble.ble_r.has_work() {
-//             ble.ble_r.process_one().unwrap();
-//         }
-//     }
-// }
\ No newline at end of file
diff --git a/src/initialize.rs b/src/initialize.rs
index cb4b5e2f4b3d65a31547732d6680891ac2a53ea7..e60139ea7c539b93983207f9e49fc5906caad03a 100644
--- a/src/initialize.rs
+++ b/src/initialize.rs
@@ -115,7 +115,7 @@ pub fn initialize(heap_memory: &'static mut [MaybeUninit<u8>], debug: bool) {
         &mut cortex_m_peripherals.NVIC,
     );
     if debug {
-        send_bytes(b"BLE driver initialized\n");
+        let _ = send_bytes(b"BLE driver initialized\n");
     }
 
     // done with initialization sequence
diff --git a/src/lib.rs b/src/lib.rs
index 568adad735cabf286b9d0ced2da64fefa0a7dff2..95b003aca306045c9e7ea0d6ed209aef5fe1338d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,9 +1,9 @@
 #![no_std]
 #![feature(strict_provenance)]
-#![deny(missing_docs)]
+// #![deny(missing_docs)]
 // #![deny(warnings)]
-#![deny(unused_import_braces)]
-#![deny(unused_results)]
+// #![deny(unused_import_braces)]
+// #![deny(unused_results)]
 // #![deny(trivial_casts)]
 // #![deny(trivial_numeric_casts)]
 // #![deny(unused_qualifications)]
@@ -84,6 +84,8 @@ pub mod time;
 
 /// Utilities to read from and write to UART
 pub mod uart;
+
+/// Utilities to read and write using BLE
 pub mod ble;
 
 /// Internal utilities to read out TWI (I2C) devices