From ebbe7d1847aa3b42b2e784620894239a92c56a94 Mon Sep 17 00:00:00 2001 From: Justin Beaurivage Date: Mon, 28 Oct 2024 00:43:59 -0400 Subject: [PATCH] examples: Add DMA examples for SPI, I2C, and UART to Tier 1 BSPs --- boards/atsame54_xpro/Cargo.toml | 7 ++ boards/feather_m0/Cargo.toml | 11 ++ boards/feather_m0/examples/i2c.rs | 29 ++--- boards/feather_m0/examples/spi.rs | 83 ++++++++++++++ boards/feather_m0/examples/uart.rs | 63 +++-------- .../feather_m0/examples/uart_dma_blocking.rs | 82 ++++++++++++++ .../examples/uart_dma_nonblocking.rs | 100 +++++++++++++++++ boards/feather_m4/Cargo.toml | 17 ++- boards/feather_m4/examples/i2c.rs | 29 ++--- boards/feather_m4/examples/spi.rs | 82 ++++++++++++++ boards/feather_m4/examples/uart.rs | 63 +++-------- .../feather_m4/examples/uart_dma_blocking.rs | 83 ++++++++++++++ .../examples/uart_dma_nonblocking.rs | 101 ++++++++++++++++++ boards/metro_m0/Cargo.toml | 4 + boards/metro_m0/examples/i2c.rs | 29 ++--- boards/metro_m0/examples/spi.rs | 83 ++++++++++++++ boards/metro_m4/Cargo.toml | 7 +- boards/metro_m4/examples/i2c.rs | 29 ++--- boards/metro_m4/examples/spi.rs | 75 +++++++++---- boards/samd11_bare/examples/i2c.rs | 29 ++--- 20 files changed, 788 insertions(+), 218 deletions(-) create mode 100644 boards/feather_m0/examples/spi.rs create mode 100644 boards/feather_m0/examples/uart_dma_blocking.rs create mode 100644 boards/feather_m0/examples/uart_dma_nonblocking.rs create mode 100644 boards/feather_m4/examples/spi.rs create mode 100644 boards/feather_m4/examples/uart_dma_blocking.rs create mode 100644 boards/feather_m4/examples/uart_dma_nonblocking.rs create mode 100644 boards/metro_m0/examples/spi.rs diff --git a/boards/atsame54_xpro/Cargo.toml b/boards/atsame54_xpro/Cargo.toml index 940c65f3a96..6c011af10b4 100644 --- a/boards/atsame54_xpro/Cargo.toml +++ b/boards/atsame54_xpro/Cargo.toml @@ -39,10 +39,17 @@ rtt-target = { version = "0.3", features = ["cortex-m"] } [features] default = ["rt", "atsamd-hal/same54p"] +dma = ["atsamd-hal/dma"] rt = ["cortex-m-rt", "atsamd-hal/same54p-rt"] usb = ["atsamd-hal/usb", "usb-device"] can = ["atsamd-hal/can"] +[[example]] +name = "blinky_basic" + +[[example]] +name = "blinky_rtic" + [[example]] name = "mcan" required-features = ["can"] diff --git a/boards/feather_m0/Cargo.toml b/boards/feather_m0/Cargo.toml index cce8bf7adaf..66d8eca1a9b 100644 --- a/boards/feather_m0/Cargo.toml +++ b/boards/feather_m0/Cargo.toml @@ -127,8 +127,19 @@ required-features = ["rtic"] [[example]] name = "uart" + +[[example]] +name = "uart_dma_nonblocking" +required-features = ["dma"] + +[[example]] +name = "uart_dma_blocking" required-features = ["dma"] [[example]] name = "i2c" required-features = ["dma"] + +[[example]] +name = "spi" +required-features = ["dma"] diff --git a/boards/feather_m0/examples/i2c.rs b/boards/feather_m0/examples/i2c.rs index 75f55f90365..02480426a84 100644 --- a/boards/feather_m0/examples/i2c.rs +++ b/boards/feather_m0/examples/i2c.rs @@ -1,4 +1,5 @@ -//! This example showcases the i2c module. +//! This example showcases the i2c module, and uses DMA to perform I2C +//! transactions. #![no_std] #![no_main] @@ -23,8 +24,9 @@ use hal::ehal::i2c::I2c; use hal::fugit::RateExtU32; use hal::sercom::i2c; -const LENGTH: usize = 1; -const ADDRESS: u8 = 0x77; +// This example is based on the BMP388 pressure sensor. Adjust the device and +// register addresses to your liking +const ADDRESS: u8 = 0x76; #[entry] fn main() -> ! { @@ -48,31 +50,18 @@ fn main() -> ! { let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); - let buf_src: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let buf_dest: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let gclk0 = clocks.gclk0(); let sercom3_clock = &clocks.sercom3_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.sercom3, pads, sercom3_clock.freq()) .baud(100.kHz()) - .enable(); + .enable() + .with_dma_channel(chan0); - let mut buffer = [0x00; 1]; + let mut received = [0x00; 1]; // Test writing then reading from an I2C chip - i2c.write_read(ADDRESS, &[0x00], &mut buffer).unwrap(); - - // Test writing then reading using DMA - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.send_with_dma(ADDRESS, init_token, buf_src, chan0, |_| {}); - let (chan0, _buf_src, mut i2c) = xfer.wait(); - - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.receive_with_dma(ADDRESS, init_token, buf_dest, chan0, |_| {}); - let (_chan0, _i2c, _buf_dest) = xfer.wait(); + i2c.write_read(ADDRESS, &[0x00; 8], &mut received).unwrap(); loop { // Go to sleep diff --git a/boards/feather_m0/examples/spi.rs b/boards/feather_m0/examples/spi.rs new file mode 100644 index 00000000000..43f8f9e395d --- /dev/null +++ b/boards/feather_m0/examples/spi.rs @@ -0,0 +1,83 @@ +//! This example showcases the spi module, and uses DMA to perform SPI +//! transactions. + +#![no_std] +#![no_main] + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use feather_m0 as bsp; + +use bsp::entry; +use bsp::hal; +use bsp::pac; + +use pac::Peripherals; + +use hal::clock::GenericClockController; +use hal::dmac::{DmaController, PriorityLevel}; +use hal::ehal::spi::SpiBus; +use hal::fugit::RateExtU32; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, + ); + + let mut pm = peripherals.pm; + let dmac = peripherals.dmac; + let pins = bsp::Pins::new(peripherals.port); + + // Take SPI pins + let (miso, mosi, sclk) = (pins.miso, pins.mosi, pins.sclk); + + // Setup DMA channels for later use + let mut dmac = DmaController::init(dmac, &mut pm); + let channels = dmac.split(); + let chan0 = channels.0.init(PriorityLevel::Lvl0); + let chan1 = channels.1.init(PriorityLevel::Lvl0); + + // Create a Spi with DMA enabled + let mut spi = bsp::spi_master( + &mut clocks, + 100.kHz(), + peripherals.sercom4, + &mut pm, + sclk, + mosi, + miso, + ) + .with_dma_channels(chan0, chan1); + + loop { + let mut source = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + let mut dest = [0xff; 16]; + + // Read words into a buffer. The words sent will be be NOP word + // (by default, 0x00). + spi.read(&mut dest).unwrap(); + + // Send words from a buffer + spi.write(&source).unwrap(); + + // Simultaneously read and write from different buffers. + // + // If the source is longer than the destination, the words read + // in excess will be discarded. + // + // If the destination is longer than the source, the excess words + // sent will be the NOP word (by default, 0x00). + spi.transfer(&mut dest, &source).unwrap(); + + // Simultaneously read and write from the same buffer + spi.transfer_in_place(&mut source).unwrap(); + } +} diff --git a/boards/feather_m0/examples/uart.rs b/boards/feather_m0/examples/uart.rs index d4492d8f14e..3bf5cb917f6 100644 --- a/boards/feather_m0/examples/uart.rs +++ b/boards/feather_m0/examples/uart.rs @@ -1,9 +1,9 @@ -//! This example showcases the uart module. +//! This example shows how to use the UART to perform transfers using the +//! embedded-hal-nb traits. #![no_std] #![no_main] -use cortex_m::asm; #[cfg(not(feature = "use_semihosting"))] use panic_halt as _; #[cfg(feature = "use_semihosting")] @@ -16,7 +16,6 @@ use hal::nb; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; -use hal::dmac::{DmaController, PriorityLevel}; use hal::ehal_nb::serial::{Read, Write}; use hal::fugit::RateExtU32; @@ -33,16 +32,8 @@ fn main() -> ! { ); let mut pm = peripherals.pm; - let dmac = peripherals.dmac; let pins = bsp::Pins::new(peripherals.port); - // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut pm); - let channels = dmac.split(); - - let chan0 = channels.0.init(PriorityLevel::Lvl0); - let chan1 = channels.1.init(PriorityLevel::Lvl0); - // Take peripheral and pins let uart_sercom = periph_alias!(peripherals.uart_sercom); let uart_rx = pin_alias!(pins.uart_rx); @@ -61,47 +52,27 @@ fn main() -> ! { // Split uart in rx + tx halves let (mut rx, mut tx) = uart.split(); - // Get a 50 byte buffer to store data to send/receive - const LENGTH: usize = 50; - let rx_buffer: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let tx_buffer: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); + // Make buffers to store data to send/receive + let mut rx_buffer = [0x00; 50]; + let mut tx_buffer = [0x00; 50]; // For fun, store numbers from 0 to 49 in buffer for (i, c) in tx_buffer.iter_mut().enumerate() { *c = i as u8; } - // Send data in a blocking way - for c in tx_buffer.iter() { - nb::block!(tx.write(*c)).unwrap(); - } - - // We'll now receive data in a blocking way - rx.flush_rx_buffer(); - for c in rx_buffer.iter_mut() { - *c = nb::block!(rx.read()).unwrap(); - } - - // Finally, we'll receive AND send data at the same time with DMA - - // Setup a DMA transfer to send our data asynchronously. - // We'll set the waker to be a no-op - let tx_dma = tx.send_with_dma(tx_buffer, chan0, |_| {}); - - // Setup a DMA transfer to receive our data asynchronously. - // Again, we'll set the waker to be a no-op - let rx_dma = rx.receive_with_dma(rx_buffer, chan1, |_| {}); - - // Wait for transmit DMA transfer to complete - let (_chan0, _tx_buffer, _tx) = tx_dma.wait(); - - // Wait for receive DMA transfer to complete - let (_chan1, _rx_buffer, _rx) = rx_dma.wait(); - loop { - // Go to sleep - asm::wfi(); + // Send data. We block on each byte, but we could also perform some tasks while + // waiting for the byte to finish sending. + for c in tx_buffer.iter() { + nb::block!(tx.write(*c)).unwrap(); + } + + // Receive data. We block on each byte, but we could also perform some tasks + // while waiting for the byte to finish sending. + rx.flush_rx_buffer(); + for c in rx_buffer.iter_mut() { + *c = nb::block!(rx.read()).unwrap(); + } } } diff --git a/boards/feather_m0/examples/uart_dma_blocking.rs b/boards/feather_m0/examples/uart_dma_blocking.rs new file mode 100644 index 00000000000..1c3c1a8d5d3 --- /dev/null +++ b/boards/feather_m0/examples/uart_dma_blocking.rs @@ -0,0 +1,82 @@ +//! This example shows how to use the UART to perform blocking transfers using +//! DMA and the embedded-io traits. + +#![no_std] +#![no_main] + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::hal; +use bsp::pac; +use feather_m0 as bsp; + +use bsp::{entry, periph_alias, pin_alias}; +use hal::clock::GenericClockController; +use hal::dmac::{DmaController, PriorityLevel}; +use hal::embedded_io::{Read, Write}; +use hal::fugit::RateExtU32; + +use pac::Peripherals; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, + ); + + let mut pm = peripherals.pm; + let dmac = peripherals.dmac; + let pins = bsp::Pins::new(peripherals.port); + + // Setup DMA channels for later use + let mut dmac = DmaController::init(dmac, &mut pm); + let channels = dmac.split(); + + let chan0 = channels.0.init(PriorityLevel::Lvl0); + let chan1 = channels.1.init(PriorityLevel::Lvl0); + + // Take peripheral and pins + let uart_sercom = periph_alias!(peripherals.uart_sercom); + let uart_rx = pin_alias!(pins.uart_rx); + let uart_tx = pin_alias!(pins.uart_tx); + + // Setup UART peripheral and attach DMA channels + let uart = bsp::uart( + &mut clocks, + 9600.Hz(), + uart_sercom, + &mut pm, + uart_rx, + uart_tx, + ) + .with_rx_channel(chan0) + .with_tx_channel(chan1); + + // Split uart in rx + tx halves + let (mut rx, mut tx) = uart.split(); + + loop { + // Make buffers to store data to send/receive + let mut rx_buffer = [0x00; 50]; + let mut tx_buffer = [0x00; 50]; + + // For fun, store numbers from 0 to 49 in buffer + for (i, c) in tx_buffer.iter_mut().enumerate() { + *c = i as u8; + } + + // Send data using DMA... + tx.write(&tx_buffer).unwrap(); + + //...and receive using DMA + rx.flush_rx_buffer(); + rx.read(&mut rx_buffer).unwrap(); + } +} diff --git a/boards/feather_m0/examples/uart_dma_nonblocking.rs b/boards/feather_m0/examples/uart_dma_nonblocking.rs new file mode 100644 index 00000000000..f42edf72fe3 --- /dev/null +++ b/boards/feather_m0/examples/uart_dma_nonblocking.rs @@ -0,0 +1,100 @@ +//! This example shows how to use the UART to perform non-blocking transfers +//! using DMA. + +#![no_std] +#![no_main] + +use cortex_m::asm; +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::hal; +use bsp::pac; +use feather_m0 as bsp; + +use bsp::{entry, periph_alias, pin_alias}; +use hal::clock::GenericClockController; +use hal::dmac::{DmaController, PriorityLevel}; +use hal::fugit::RateExtU32; + +use pac::Peripherals; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, + ); + + let mut pm = peripherals.pm; + let dmac = peripherals.dmac; + let pins = bsp::Pins::new(peripherals.port); + + // Setup DMA channels for later use + let mut dmac = DmaController::init(dmac, &mut pm); + let channels = dmac.split(); + + let chan0 = channels.0.init(PriorityLevel::Lvl0); + let chan1 = channels.1.init(PriorityLevel::Lvl0); + + // Take peripheral and pins + let uart_sercom = periph_alias!(peripherals.uart_sercom); + let uart_rx = pin_alias!(pins.uart_rx); + let uart_tx = pin_alias!(pins.uart_tx); + + // Setup UART peripheral. We shouldn't attach DMA channels to the UART; they + // instead must be passed to `send_with_dma` and `receive_with_dma`. + let uart = bsp::uart( + &mut clocks, + 9600.Hz(), + uart_sercom, + &mut pm, + uart_rx, + uart_tx, + ); + + // Split uart in rx + tx halves + let (mut rx, tx) = uart.split(); + + // Get a 50 byte buffer to store data to send/receive + const LENGTH: usize = 50; + let rx_buffer: &'static mut [u8; LENGTH] = + cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); + let tx_buffer: &'static mut [u8; LENGTH] = + cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); + + // For fun, store numbers from 0 to 49 in buffer + for (i, c) in tx_buffer.iter_mut().enumerate() { + *c = i as u8; + } + + //...and receive (blocking) using DMA + rx.flush_rx_buffer(); + + // Let's receive AND send data at the same time with DMA. Note that these + // transfers require static buffers + + // Setup a DMA transfer to send our data asynchronously. + // We'll set the waker to be a no-op + let tx_dma = tx.send_with_dma(tx_buffer, chan0, |_| {}); + + // Setup a DMA transfer to receive our data asynchronously. + // Again, we'll set the waker to be a no-op + let rx_dma = rx.receive_with_dma(rx_buffer, chan1, |_| {}); + + // Wait for transmit DMA transfer to complete + let (_chan0, _tx_buffer, _tx) = tx_dma.wait(); + + // Wait for receive DMA transfer to complete + let (_chan1, _rx_buffer, _rx) = rx_dma.wait(); + + loop { + // Go to sleep + asm::wfi(); + } +} diff --git a/boards/feather_m4/Cargo.toml b/boards/feather_m4/Cargo.toml index ef71fe198d2..7751846dc52 100644 --- a/boards/feather_m4/Cargo.toml +++ b/boards/feather_m4/Cargo.toml @@ -48,6 +48,7 @@ rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"] usb = ["atsamd-hal/usb", "usb-device"] dma = ["atsamd-hal/dma"] max-channels = ["dma", "atsamd-hal/dma"] +use_semihosting = [] [[example]] name = "pwm" @@ -62,6 +63,16 @@ required-features = ["dma"] [[example]] name = "uart" + +[[example]] +name = "uart_poll_echo" + +[[example]] +name = "uart_dma_nonblocking" +required-features = ["dma"] + +[[example]] +name = "uart_dma_blocking" required-features = ["dma"] [[example]] @@ -78,4 +89,8 @@ required-features = [ "usb"] [[example]] name = "i2c" -required-features = ["atsamd-hal/dma"] +required-features = ["dma"] + +[[example]] +name = "spi" +required-features = ["dma"] diff --git a/boards/feather_m4/examples/i2c.rs b/boards/feather_m4/examples/i2c.rs index dbf0a1a17e6..81073dade6e 100644 --- a/boards/feather_m4/examples/i2c.rs +++ b/boards/feather_m4/examples/i2c.rs @@ -1,4 +1,5 @@ -//! This example showcases the i2c module. +//! This example showcases the i2c module, and uses DMA to perform I2C +//! transactions. #![no_std] #![no_main] @@ -23,8 +24,9 @@ use hal::ehal::i2c::I2c; use hal::fugit::RateExtU32; use hal::sercom::i2c; -const LENGTH: usize = 1; -const ADDRESS: u8 = 0x77; +// This example is based on the BMP388 pressure sensor. Adjust the device and +// register addresses to your liking +const ADDRESS: u8 = 0x76; #[entry] fn main() -> ! { @@ -49,32 +51,19 @@ fn main() -> ! { let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); - let buf_src: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let buf_dest: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let gclk0 = clocks.gclk0(); let sercom2_clock = &clocks.sercom2_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let i2c_sercom = periph_alias!(peripherals.i2c_sercom); let mut i2c = i2c::Config::new(&mclk, i2c_sercom, pads, sercom2_clock.freq()) .baud(100.kHz()) - .enable(); + .enable() + .with_dma_channel(chan0); - let mut buffer = [0x00; 1]; + let mut received = [0x00; 1]; // Test writing then reading from an I2C chip - i2c.write_read(ADDRESS, &[0x00], &mut buffer).unwrap(); - - // Test writing then reading using DMA - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.send_with_dma(ADDRESS, init_token, buf_src, chan0, |_| {}); - let (chan0, _buf_src, mut i2c) = xfer.wait(); - - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.receive_with_dma(ADDRESS, init_token, buf_dest, chan0, |_| {}); - let (_chan0, _i2c, _buf_dest) = xfer.wait(); + i2c.write_read(ADDRESS, &[0x00; 8], &mut received).unwrap(); loop { // Go to sleep diff --git a/boards/feather_m4/examples/spi.rs b/boards/feather_m4/examples/spi.rs new file mode 100644 index 00000000000..1634b2ead2d --- /dev/null +++ b/boards/feather_m4/examples/spi.rs @@ -0,0 +1,82 @@ +//! This example showcases the spi module, and uses DMA to perform SPI +//! transactions. + +#![no_std] +#![no_main] + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use feather_m4 as bsp; + +use bsp::entry; +use bsp::hal; +use bsp::pac; + +use pac::Peripherals; + +use hal::clock::GenericClockController; +use hal::dmac::{DmaController, PriorityLevel}; +use hal::ehal::spi::SpiBus; +use hal::fugit::RateExtU32; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut clocks = GenericClockController::with_external_32kosc( + peripherals.gclk, + &mut peripherals.mclk, + &mut peripherals.osc32kctrl, + &mut peripherals.oscctrl, + &mut peripherals.nvmctrl, + ); + + let dmac = peripherals.dmac; + let pins = bsp::Pins::new(peripherals.port); + + // Take SPI pins + let (miso, mosi, sclk) = (pins.miso, pins.mosi, pins.sck); + + // Setup DMA channels for later use + let mut dmac = DmaController::init(dmac, &mut peripherals.pm); + let channels = dmac.split(); + let chan0 = channels.0.init(PriorityLevel::Lvl0); + let chan1 = channels.1.init(PriorityLevel::Lvl0); + + let mut spi = bsp::spi_master( + &mut clocks, + 100.kHz(), + peripherals.sercom1, + &mut peripherals.mclk, + sclk, + mosi, + miso, + ) + .with_dma_channels(chan0, chan1); + + loop { + let mut source = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + let mut dest = [0xff; 16]; + + // Read words into a buffer. The words sent will be be NOP word + // (by default, 0x00). + spi.read(&mut dest).unwrap(); + + // Send words from a buffer + spi.write(&source).unwrap(); + + // Simultaneously read and write from different buffers. + // + // If the source is longer than the destination, the words read + // in excess will be discarded. + // + // If the destination is longer than the source, the excess words + // sent will be the NOP word (by default, 0x00). + spi.transfer(&mut dest, &source).unwrap(); + + // Simultaneously read and write from the same buffer + spi.transfer_in_place(&mut source).unwrap(); + } +} diff --git a/boards/feather_m4/examples/uart.rs b/boards/feather_m4/examples/uart.rs index 96d53c992bb..3068709aa60 100644 --- a/boards/feather_m4/examples/uart.rs +++ b/boards/feather_m4/examples/uart.rs @@ -1,9 +1,9 @@ -//! This example showcases the uart::v2 module. +//! This example shows how to use the UART to perform transfers using the +//! embedded-hal-nb traits. #![no_std] #![no_main] -use cortex_m::asm; use panic_halt as _; use bsp::hal; @@ -12,7 +12,6 @@ use feather_m4 as bsp; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; -use hal::dmac::{DmaController, PriorityLevel}; use hal::ehal_nb::serial::{Read, Write}; use hal::fugit::RateExtU32; use hal::nb; @@ -31,20 +30,12 @@ fn main() -> ! { ); let mut mclk = peripherals.mclk; - let dmac = peripherals.dmac; let pins = bsp::Pins::new(peripherals.port); // Take RX and TX pins let uart_rx = pin_alias!(pins.uart_rx); let uart_tx = pin_alias!(pins.uart_tx); - // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut peripherals.pm); - let channels = dmac.split(); - - let chan0 = channels.0.init(PriorityLevel::Lvl0); - let chan1 = channels.1.init(PriorityLevel::Lvl0); - let uart_sercom = periph_alias!(peripherals.uart_sercom); // Setup UART peripheral @@ -60,47 +51,27 @@ fn main() -> ! { // Split uart in rx + tx halves let (mut rx, mut tx) = uart.split(); - // Get a 50 byte buffer to store data to send/receive - const LENGTH: usize = 50; - let rx_buffer: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let tx_buffer: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); + // Make buffers to store data to send/receive + let mut rx_buffer = [0x00; 50]; + let mut tx_buffer = [0x00; 50]; // For fun, store numbers from 0 to 49 in buffer for (i, c) in tx_buffer.iter_mut().enumerate() { *c = i as u8; } - // Send data in a blocking way - for c in tx_buffer.iter() { - nb::block!(tx.write(*c)).unwrap(); - } - - // We'll now receive data in a blocking way - rx.flush_rx_buffer(); - for c in rx_buffer.iter_mut() { - *c = nb::block!(rx.read()).unwrap(); - } - - // Finally, we'll receive AND send data at the same time with DMA - - // Setup a DMA transfer to send our data asynchronously. - // We'll set the waker to be a no-op - let tx_dma = tx.send_with_dma(tx_buffer, chan0, |_| {}); - - // Setup a DMA transfer to receive our data asynchronously. - // Again, we'll set the waker to be a no-op - let rx_dma = rx.receive_with_dma(rx_buffer, chan1, |_| {}); - - // Wait for transmit DMA transfer to complete - let (_chan0, _tx_buffer, _tx) = tx_dma.wait(); - - // Wait for receive DMA transfer to complete - let (_chan1, _rx_buffer, _rx) = rx_dma.wait(); - loop { - // Go to sleep - asm::wfi(); + // Send data. We block on each byte, but we could also perform some tasks while + // waiting for the byte to finish sending. + for c in tx_buffer.iter() { + nb::block!(tx.write(*c)).unwrap(); + } + + // Receive data. We block on each byte, but we could also perform some tasks + // while waiting for the byte to finish sending. + rx.flush_rx_buffer(); + for c in rx_buffer.iter_mut() { + *c = nb::block!(rx.read()).unwrap(); + } } } diff --git a/boards/feather_m4/examples/uart_dma_blocking.rs b/boards/feather_m4/examples/uart_dma_blocking.rs new file mode 100644 index 00000000000..3c0abf05141 --- /dev/null +++ b/boards/feather_m4/examples/uart_dma_blocking.rs @@ -0,0 +1,83 @@ +//! This example shows how to use the UART to perform blocking transfers using +//! DMA and the embedded-io traits. + +#![no_std] +#![no_main] + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::hal; +use bsp::pac; +use feather_m4 as bsp; + +use bsp::{entry, periph_alias, pin_alias}; +use hal::clock::GenericClockController; +use hal::dmac::{DmaController, PriorityLevel}; +use hal::embedded_io::{Read, Write}; +use hal::fugit::RateExtU32; + +use pac::Peripherals; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut clocks = GenericClockController::with_external_32kosc( + peripherals.gclk, + &mut peripherals.mclk, + &mut peripherals.osc32kctrl, + &mut peripherals.oscctrl, + &mut peripherals.nvmctrl, + ); + + let mut pm = peripherals.pm; + let dmac = peripherals.dmac; + let pins = bsp::Pins::new(peripherals.port); + + // Setup DMA channels for later use + let mut dmac = DmaController::init(dmac, &mut pm); + let channels = dmac.split(); + + let chan0 = channels.0.init(PriorityLevel::Lvl0); + let chan1 = channels.1.init(PriorityLevel::Lvl0); + + // Take peripheral and pins + let uart_sercom = periph_alias!(peripherals.uart_sercom); + let uart_rx = pin_alias!(pins.uart_rx); + let uart_tx = pin_alias!(pins.uart_tx); + + // Setup UART peripheral and attach DMA channels + let uart = bsp::uart( + &mut clocks, + 9600.Hz(), + uart_sercom, + &mut peripherals.mclk, + uart_rx, + uart_tx, + ) + .with_rx_channel(chan0) + .with_tx_channel(chan1); + + // Split uart in rx + tx halves + let (mut rx, mut tx) = uart.split(); + + loop { + // Make buffers to store data to send/receive + let mut rx_buffer = [0x00; 50]; + let mut tx_buffer = [0x00; 50]; + + // For fun, store numbers from 0 to 49 in buffer + for (i, c) in tx_buffer.iter_mut().enumerate() { + *c = i as u8; + } + + // Send data using DMA... + tx.write(&tx_buffer).unwrap(); + + //...and receive using DMA + rx.flush_rx_buffer(); + rx.read(&mut rx_buffer).unwrap(); + } +} diff --git a/boards/feather_m4/examples/uart_dma_nonblocking.rs b/boards/feather_m4/examples/uart_dma_nonblocking.rs new file mode 100644 index 00000000000..317293d9184 --- /dev/null +++ b/boards/feather_m4/examples/uart_dma_nonblocking.rs @@ -0,0 +1,101 @@ +//! This example shows how to use the UART to perform non-blocking transfers +//! using DMA. + +#![no_std] +#![no_main] + +use cortex_m::asm; +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::hal; +use bsp::pac; +use feather_m4 as bsp; + +use bsp::{entry, periph_alias, pin_alias}; +use hal::clock::GenericClockController; +use hal::dmac::{DmaController, PriorityLevel}; +use hal::fugit::RateExtU32; + +use pac::Peripherals; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut clocks = GenericClockController::with_external_32kosc( + peripherals.gclk, + &mut peripherals.mclk, + &mut peripherals.osc32kctrl, + &mut peripherals.oscctrl, + &mut peripherals.nvmctrl, + ); + + let mut pm = peripherals.pm; + let dmac = peripherals.dmac; + let pins = bsp::Pins::new(peripherals.port); + + // Setup DMA channels for later use + let mut dmac = DmaController::init(dmac, &mut pm); + let channels = dmac.split(); + + let chan0 = channels.0.init(PriorityLevel::Lvl0); + let chan1 = channels.1.init(PriorityLevel::Lvl0); + + // Take peripheral and pins + let uart_sercom = periph_alias!(peripherals.uart_sercom); + let uart_rx = pin_alias!(pins.uart_rx); + let uart_tx = pin_alias!(pins.uart_tx); + + // Setup UART peripheral. We shouldn't attach DMA channels to the UART; they + // instead must be passed to `send_with_dma` and `receive_with_dma`. + let uart = bsp::uart( + &mut clocks, + 9600.Hz(), + uart_sercom, + &mut peripherals.mclk, + uart_rx, + uart_tx, + ); + + // Split uart in rx + tx halves + let (mut rx, tx) = uart.split(); + + // Get a 50 byte buffer to store data to send/receive + const LENGTH: usize = 50; + let rx_buffer: &'static mut [u8; LENGTH] = + cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); + let tx_buffer: &'static mut [u8; LENGTH] = + cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); + + // For fun, store numbers from 0 to 49 in buffer + for (i, c) in tx_buffer.iter_mut().enumerate() { + *c = i as u8; + } + + //...and receive (blocking) using DMA + rx.flush_rx_buffer(); + + // Let's receive AND send data at the same time with DMA. Note that these + // transfers require static buffers + + // Setup a DMA transfer to send our data asynchronously. + // We'll set the waker to be a no-op + let tx_dma = tx.send_with_dma(tx_buffer, chan0, |_| {}); + + // Setup a DMA transfer to receive our data asynchronously. + // Again, we'll set the waker to be a no-op + let rx_dma = rx.receive_with_dma(rx_buffer, chan1, |_| {}); + + // Wait for transmit DMA transfer to complete + let (_chan0, _tx_buffer, _tx) = tx_dma.wait(); + + // Wait for receive DMA transfer to complete + let (_chan1, _rx_buffer, _rx) = rx_dma.wait(); + + loop { + // Go to sleep + asm::wfi(); + } +} diff --git a/boards/metro_m0/Cargo.toml b/boards/metro_m0/Cargo.toml index 3cc4aaf44c7..9c3ce63808d 100644 --- a/boards/metro_m0/Cargo.toml +++ b/boards/metro_m0/Cargo.toml @@ -63,3 +63,7 @@ name = "blinky_basic" [[example]] name = "i2c" required-features = ["dma"] + +[[example]] +name = "spi" +required-features = ["dma"] diff --git a/boards/metro_m0/examples/i2c.rs b/boards/metro_m0/examples/i2c.rs index 0001559f664..bb6abbcea70 100644 --- a/boards/metro_m0/examples/i2c.rs +++ b/boards/metro_m0/examples/i2c.rs @@ -1,4 +1,5 @@ -//! This example showcases the i2c module. +//! This example showcases the i2c module, and uses DMA to perform I2C +//! transactions. #![no_std] #![no_main] @@ -23,8 +24,9 @@ use hal::ehal::i2c::I2c; use hal::fugit::RateExtU32; use hal::sercom::i2c; -const LENGTH: usize = 1; -const ADDRESS: u8 = 0x77; +// This example is based on the BMP388 pressure sensor. Adjust the device and +// register addresses to your liking +const ADDRESS: u8 = 0x76; #[entry] fn main() -> ! { @@ -48,31 +50,18 @@ fn main() -> ! { let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); - let buf_src: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let buf_dest: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let gclk0 = clocks.gclk0(); let sercom3_clock = &clocks.sercom3_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.sercom3, pads, sercom3_clock.freq()) .baud(100.kHz()) - .enable(); + .enable() + .with_dma_channel(chan0); - let mut buffer = [0x00; 1]; + let mut received = [0x00; 1]; // Test writing then reading from an I2C chip - i2c.write_read(ADDRESS, &[0x00], &mut buffer).unwrap(); - - // Test writing then reading using DMA - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.send_with_dma(ADDRESS, init_token, buf_src, chan0, |_| {}); - let (chan0, _buf_src, mut i2c) = xfer.wait(); - - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.receive_with_dma(ADDRESS, init_token, buf_dest, chan0, |_| {}); - let (_chan0, _i2c, _buf_dest) = xfer.wait(); + i2c.write_read(ADDRESS, &[0x00; 8], &mut received).unwrap(); loop { // Go to sleep diff --git a/boards/metro_m0/examples/spi.rs b/boards/metro_m0/examples/spi.rs new file mode 100644 index 00000000000..46e417ff367 --- /dev/null +++ b/boards/metro_m0/examples/spi.rs @@ -0,0 +1,83 @@ +//! This example showcases the spi module, and uses DMA to perform I2C +//! transactions. + +#![no_std] +#![no_main] + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use metro_m0 as bsp; + +use bsp::entry; +use bsp::hal; +use bsp::pac; + +use pac::Peripherals; + +use hal::clock::GenericClockController; +use hal::dmac::{DmaController, PriorityLevel}; +use hal::ehal::spi::SpiBus; +use hal::fugit::RateExtU32; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.gclk, + &mut peripherals.pm, + &mut peripherals.sysctrl, + &mut peripherals.nvmctrl, + ); + + let mut pm = peripherals.pm; + let dmac = peripherals.dmac; + let pins = bsp::Pins::new(peripherals.port); + + // Take SPI pins + let (miso, mosi, sclk) = (pins.miso, pins.mosi, pins.sck); + + // Setup DMA channels for later use + let mut dmac = DmaController::init(dmac, &mut pm); + let channels = dmac.split(); + let chan0 = channels.0.init(PriorityLevel::Lvl0); + let chan1 = channels.1.init(PriorityLevel::Lvl0); + + // Create a Spi with DMA enabled + let mut spi = bsp::spi_master( + &mut clocks, + 100.kHz(), + peripherals.sercom4, + &mut pm, + sclk, + mosi, + miso, + ) + .with_dma_channels(chan0, chan1); + + loop { + let mut source = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + let mut dest = [0xff; 16]; + + // Read words into a buffer. The words sent will be be NOP word + // (by default, 0x00). + spi.read(&mut dest).unwrap(); + + // Send words from a buffer + spi.write(&source).unwrap(); + + // Simultaneously read and write from different buffers. + // + // If the source is longer than the destination, the words read + // in excess will be discarded. + // + // If the destination is longer than the source, the excess words + // sent will be the NOP word (by default, 0x00). + spi.transfer(&mut dest, &source).unwrap(); + + // Simultaneously read and write from the same buffer + spi.transfer_in_place(&mut source).unwrap(); + } +} diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index e16995dade1..e06294386e9 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -74,9 +74,6 @@ name = "pwm" [[example]] name = "serial" -[[example]] -name = "spi" - [[example]] name = "timer" @@ -93,3 +90,7 @@ required-features = ["usb"] [[example]] name = "i2c" required-features = ["dma"] + +[[example]] +name = "spi" +required-features = ["dma"] diff --git a/boards/metro_m4/examples/i2c.rs b/boards/metro_m4/examples/i2c.rs index 1d1b5b2c89e..31f511e8035 100644 --- a/boards/metro_m4/examples/i2c.rs +++ b/boards/metro_m4/examples/i2c.rs @@ -1,4 +1,5 @@ -//! This example showcases the i2c module. +//! This example showcases the i2c module, and uses DMA to perform I2C +//! transactions. #![no_std] #![no_main] @@ -23,8 +24,9 @@ use hal::ehal::i2c::I2c; use hal::fugit::RateExtU32; use hal::sercom::i2c; -const LENGTH: usize = 1; -const ADDRESS: u8 = 0x77; +// This example is based on the BMP388 pressure sensor. Adjust the device and +// register addresses to your liking +const ADDRESS: u8 = 0x76; #[entry] fn main() -> ! { @@ -49,32 +51,19 @@ fn main() -> ! { let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); - let buf_src: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let buf_dest: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let gclk0 = clocks.gclk0(); let sercom5_clock = &clocks.sercom5_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let i2c_sercom = periph_alias!(peripherals.i2c_sercom); let mut i2c = i2c::Config::new(&mclk, i2c_sercom, pads, sercom5_clock.freq()) .baud(100.kHz()) - .enable(); + .enable() + .with_dma_channel(chan0); - let mut buffer = [0x00; 1]; + let mut received = [0x00; 1]; // Test writing then reading from an I2C chip - i2c.write_read(ADDRESS, &[0x00], &mut buffer).unwrap(); - - // Test writing then reading using DMA - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.send_with_dma(ADDRESS, init_token, buf_src, chan0, |_| {}); - let (chan0, _buf_src, mut i2c) = xfer.wait(); - - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.receive_with_dma(ADDRESS, init_token, buf_dest, chan0, |_| {}); - let (_chan0, _i2c, _buf_dest) = xfer.wait(); + i2c.write_read(ADDRESS, &[0x00; 8], &mut received).unwrap(); loop { // Go to sleep diff --git a/boards/metro_m4/examples/spi.rs b/boards/metro_m4/examples/spi.rs index 7af19cf7533..1830b67a4d7 100644 --- a/boards/metro_m4/examples/spi.rs +++ b/boards/metro_m4/examples/spi.rs @@ -1,28 +1,30 @@ +//! This example showcases the spi module, and uses DMA to perform SPI +//! transactions. + #![no_std] #![no_main] -use metro_m4 as bsp; - -use bsp::hal; - #[cfg(not(feature = "use_semihosting"))] use panic_halt as _; #[cfg(feature = "use_semihosting")] use panic_semihosting as _; -use bsp::{entry, periph_alias}; +use metro_m4 as bsp; + +use bsp::entry; +use bsp::hal; +use bsp::pac; + +use pac::Peripherals; + use hal::clock::GenericClockController; -use hal::delay::Delay; -use hal::ehal::delay::DelayNs; -use hal::ehal_nb::spi::FullDuplex; +use hal::dmac::{DmaController, PriorityLevel}; +use hal::ehal::spi::SpiBus; use hal::fugit::RateExtU32; -use hal::nb; -use hal::pac::{CorePeripherals, Peripherals}; #[entry] fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); - let core = CorePeripherals::take().unwrap(); let mut clocks = GenericClockController::with_external_32kosc( peripherals.gclk, &mut peripherals.mclk, @@ -31,21 +33,50 @@ fn main() -> ! { &mut peripherals.nvmctrl, ); - let mut delay = Delay::new(core.SYST, &mut clocks); + let dmac = peripherals.dmac; let pins = bsp::Pins::new(peripherals.port); - let miso = pins.miso; - let mosi = pins.mosi; - let sclk = pins.sclk; - let spi_sercom = periph_alias!(peripherals.spi_sercom); - let mclk = &mut peripherals.mclk; + // Take SPI pins + let (miso, mosi, sclk) = (pins.miso, pins.mosi, pins.sclk); - let mut spi = bsp::spi_master(&mut clocks, 3.MHz(), spi_sercom, mclk, sclk, mosi, miso); + // Setup DMA channels for later use + let mut dmac = DmaController::init(dmac, &mut peripherals.pm); + let channels = dmac.split(); + let chan0 = channels.0.init(PriorityLevel::Lvl0); + let chan1 = channels.1.init(PriorityLevel::Lvl0); + + let mut spi = bsp::spi_master( + &mut clocks, + 100.kHz(), + peripherals.sercom2, + &mut peripherals.mclk, + sclk, + mosi, + miso, + ) + .with_dma_channels(chan0, chan1); loop { - for byte in b"Hello, world!" { - nb::block!(spi.write(*byte)).unwrap(); - } - delay.delay_ms(1000); + let mut source = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + let mut dest = [0xff; 16]; + + // Read words into a buffer. The words sent will be be NOP word + // (by default, 0x00). + spi.read(&mut dest).unwrap(); + + // Send words from a buffer + spi.write(&source).unwrap(); + + // Simultaneously read and write from different buffers. + // + // If the source is longer than the destination, the words read + // in excess will be discarded. + // + // If the destination is longer than the source, the excess words + // sent will be the NOP word (by default, 0x00). + spi.transfer(&mut dest, &source).unwrap(); + + // Simultaneously read and write from the same buffer + spi.transfer_in_place(&mut source).unwrap(); } } diff --git a/boards/samd11_bare/examples/i2c.rs b/boards/samd11_bare/examples/i2c.rs index 6aa33fb1f57..be321a5c117 100644 --- a/boards/samd11_bare/examples/i2c.rs +++ b/boards/samd11_bare/examples/i2c.rs @@ -1,4 +1,5 @@ -//! This example showcases the i2c::v2 module. +//! This example showcases the i2c module, and uses DMA to perform I2C +//! transactions. #![no_std] #![no_main] @@ -23,8 +24,9 @@ use hal::ehal::i2c::I2c; use hal::fugit::RateExtU32; use hal::sercom::i2c; -const LENGTH: usize = 1; -const ADDRESS: u8 = 0x77; +// This example is based on the BMP388 pressure sensor. Adjust the device and +// register addresses to your liking +const ADDRESS: u8 = 0x76; #[entry] fn main() -> ! { @@ -48,31 +50,18 @@ fn main() -> ! { let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); - let buf_src: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let buf_dest: &'static mut [u8; LENGTH] = - cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); - let gclk0 = clocks.gclk0(); let sercom0_clock = &clocks.sercom0_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.sercom0, pads, sercom0_clock.freq()) .baud(100.kHz()) - .enable(); + .enable() + .with_dma_channel(chan0); - let mut buffer = [0x00; 1]; + let mut received = [0x00; 1]; // Test writing then reading from an I2C chip - i2c.write_read(ADDRESS, &[0x00], &mut buffer).unwrap(); - - // Test writing then reading using DMA - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.send_with_dma(ADDRESS, init_token, buf_src, chan0, |_| {}); - let (chan0, _buf_src, mut i2c) = xfer.wait(); - - let init_token = i2c.init_dma_transfer().unwrap(); - let xfer = i2c.receive_with_dma(ADDRESS, init_token, buf_dest, chan0, |_| {}); - let (_chan0, _i2c, _buf_dest) = xfer.wait(); + i2c.write_read(ADDRESS, &[0x00; 8], &mut received).unwrap(); loop { // Go to sleep