Hi there, I am writing an app that communicates with a serial device. I am using RTIC and would like to leverage DMA for the writing and reading of values to/from the serial device. My program worked until I introduced DMA. I have initialized the stm32f3xx_hal::dma::dma1::Channels structure in the init function and would like to assign it to the LateResources structure so that it is available in my USART1_EXTI25 interrupt task. When I compile, I get these errors:
error[E0507]: cannot move out of `_dma1.ch4` which is behind a mutable reference
--> hanger-buddy/src/main.rs:124:41
|
124 | let (tx_channel, rx_channel) = (_dma1.ch4, _dma1.ch5);
| ^^^^^^^^^ move occurs because `_dma1.ch4` has type `stm32f3xx_hal::dma::dma1::C4`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `_dma1.ch5` which is behind a mutable reference
--> hanger-buddy/src/main.rs:124:52
|
124 | let (tx_channel, rx_channel) = (_dma1.ch4, _dma1.ch5);
| ^^^^^^^^^ move occurs because `_dma1.ch5` has type `stm32f3xx_hal::dma::dma1::C5`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `*tx` which is behind a mutable reference
--> hanger-buddy/src/main.rs:128:23
|
128 | let sending = tx.write_all(tx_buf, tx_channel);
| ^^ move occurs because `*tx` has type `Tx<USART1>`, which does not implement the `Copy` trait
error[E0507]: cannot move out of `*rx` which is behind a mutable reference
--> hanger-buddy/src/main.rs:131:25
|
131 | let receiving = rx.read_exact(rx_buf, rx_channel);
| ^^ move occurs because `*rx` has type `Rx<USART1>`, which does not implement the `Copy` trait
My code (still in proof of concept mode if you want to call it that):
//! main.rs
#![deny(unsafe_code)]
#![no_main]
#![no_std]
#[allow(unused_imports)]
use cortex_m_semihosting::{debug, hprintln};
use cortex_m::singleton;
use core::panic::PanicInfo;
use stm32f3xx_hal::prelude::*;
use stm32f3xx_hal::stm32;
use stm32f3xx_hal::interrupt;
use stm32f3xx_hal::serial;
use stm32f3xx_hal::serial::Event;
use stm32f3xx_hal::pac::DMA1;
use panic_semihosting as _;
#[rtic::app(device = stm32f3xx_hal::pac, peripherals = true)]
const APP: () = {
struct Resources {
usart1_tx: stm32f3xx_hal::serial::Tx<stm32f3xx_hal::pac::USART1>,
usart1_rx: stm32f3xx_hal::serial::Rx<stm32f3xx_hal::pac::USART1>,
dma1: stm32f3xx_hal::dma::dma1::Channels,
shared: u32,
}
#[init]
fn init(cx: init::Context) -> init::LateResources {
// Pends the UART1 interrupt but its handler won't run until *after*
// `init` returns because interrupts are disabled
rtic::pend(stm32f3xx_hal::interrupt::USART1_EXTI25); // equivalent to NVIC::pend
let peripherals: stm32f3xx_hal::pac::Peripherals = cx.device;
let mut rcc = peripherals.RCC.constrain();
let mut flash = peripherals.FLASH.constrain();
let clocks = rcc.cfgr.use_hse(8.mhz()).freeze(&mut flash.acr);
let mut gpioa = peripherals.GPIOA.split(&mut rcc.ahb);
let mut gpioc = peripherals.GPIOC.split(&mut rcc.ahb);
let dma1 = peripherals.DMA1.split(&mut rcc.ahb);
let tx = gpioc.pc4.into_af7(&mut gpioc.moder, &mut gpioc.afrl);
let rx = gpioc.pc5.into_af7(&mut gpioc.moder, &mut gpioc.afrl);
let mut usart1 = stm32f3xx_hal::serial::Serial::usart1(
peripherals.USART1,
(tx, rx),
9_600.bps(),
clocks,
&mut rcc.apb2,
);
usart1.listen(Event::Rxne);
let (usart1_tx, usart1_rx) = usart1.split();
let shared = 0;
init::LateResources {usart1_tx, usart1_rx, shared, dma1}
}
#[idle]
fn idle(_: idle::Context) -> ! {
static mut X: u32 = 0;
// Safe access to local `static mut` variable
let _x: &'static mut u32 = X;
debug::exit(debug::EXIT_SUCCESS);
loop {
cortex_m::asm::nop();
}
}
#[task(binds = USART1_EXTI25, resources = [usart1_tx, usart1_rx, dma1, shared])]
fn usart1(cx: usart1::Context) {
let tx: &mut stm32f3xx_hal::serial::Tx<stm32f3xx_hal::pac::USART1> = cx.resources.usart1_tx;
let rx: &mut stm32f3xx_hal::serial::Rx<stm32f3xx_hal::pac::USART1> = cx.resources.usart1_rx;
let _dma1: &mut stm32f3xx_hal::dma::dma1::Channels = cx.resources.dma1;
let shared_val: &mut u32 = cx.resources.shared;
// Safe access to local `static mut` variable, just testing
*shared_val += 1;
let tx_buf = singleton!(:[u8;8]=*b"hello321").unwrap();
let rx_buf = singleton!(:[u8;8]=[0;8]).unwrap();
let (tx_channel, rx_channel) = (_dma1.ch4, _dma1.ch5);
// tx, tx_buf, tx_channel will be moved here.
// The data will be sent here.
let sending = tx.write_all(tx_buf, tx_channel);
// The data will not be read here.
let receiving = rx.read_exact(rx_buf, rx_channel);
// tx, tx_buf, tx_channel are regenerated here.
// Method `wait` waits for the send operation complete.
let (_tx_buf, _tx_channel, _tx) = sending.wait();
// Wait for data to be received.
let (rx_buf, _rx_channel, _rx) = receiving.wait();
}
};
I'm still learning Rust which makes this probably more complex than it is. The good news is that I am able to communicate with the serial device and am feeling good momentum on my project.
Any ideas on how to get through this? Thanks in advance!