Skip to content
Snippets Groups Projects
Commit e2e024a6 authored by Stephen D's avatar Stephen D
Browse files

DMA wip. not working

parent 27001441
Branches master
No related tags found
No related merge requests found
Pipeline #2057 failed
......@@ -11,21 +11,34 @@ mod packet;
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true)]
mod app {
use hal::block;
use hal::gpio;
use hal::pac::{SPI1, TIM5, USART1};
use hal::prelude::*;
use hal::serial::{Config, Event, Serial};
use hal::spi::{Mode, Phase, Polarity, Spi};
use hal::timer::Delay;
use rf4463::config::RADIO_CONFIG_500_2;
use rf4463::Rf4463;
use hal::{
block,
dma::{
config::DmaConfig,
traits::{Stream, StreamISR},
PeripheralToMemory, Stream2, StreamsTuple, Transfer,
},
gpio,
pac::{DMA2, SPI1, TIM5, USART1},
prelude::*,
serial::{self, Config, Rx, Serial, Tx},
spi::{Mode, Phase, Polarity, Spi},
timer::Delay,
};
use rf4463::{config::RADIO_CONFIG_500_2, Rf4463};
use ringbuffer::{ConstGenericRingBuffer, RingBuffer, RingBufferRead, RingBufferWrite};
use rtic::Mutex;
use crate::packet::Packet;
// in # packets
const BUFFER_LEN: usize = 50;
// # bytes
// if we make this too big, the interrupt may take too long to process them all
// and we could drop packets!
// ideally we would use the rf4463 interrupt (higher priority)
// to keep the transceiver fed
const DMA_BUFFER_LEN: usize = 128;
const MODE: Mode = Mode {
polarity: Polarity::IdleLow,
......@@ -39,6 +52,14 @@ mod app {
Delay<TIM5, 1000000>,
>;
type RxTransfer = Transfer<
Stream2<DMA2>,
4,
Rx<USART1>,
PeripheralToMemory,
&'static mut [u8; DMA_BUFFER_LEN],
>;
#[derive(Debug)]
enum SlaveCmd {
BufferStatus,
......@@ -67,13 +88,24 @@ mod app {
struct Shared {
radio_temp: f32,
tx_buf: ConstGenericRingBuffer<Packet, BUFFER_LEN>,
// Can use lock free for any resources that are only shared between tasks of the same priority
#[lock_free]
state: SlaveState,
#[lock_free]
tx: Tx<USART1>,
#[lock_free]
rx_transfer: RxTransfer,
#[lock_free]
rx_buffer: Option<&'static mut [u8; DMA_BUFFER_LEN]>,
}
#[local]
struct Local {
radio: Radio,
usart: Serial<USART1>,
state: SlaveState,
}
#[init]
......@@ -110,26 +142,53 @@ mod app {
let tx = gpioa.pa9;
let rx = gpioa.pa10;
let mut usart = Serial::new(
let usart = Serial::new(
ctx.device.USART1,
(tx, rx),
Config::default().baudrate(921_600.bps()),
Config::default()
.baudrate(921_600.bps())
.dma(serial::config::DmaConfig::Rx),
&clocks,
)
.unwrap();
usart.listen(Event::Rxne);
let (tx, mut rx) = usart.split();
rx.listen_idle();
let dma2 = StreamsTuple::new(ctx.device.DMA2);
let rx_buffer1 =
cortex_m::singleton!(: [u8; DMA_BUFFER_LEN] = [0; DMA_BUFFER_LEN]).unwrap();
let rx_buffer2 =
cortex_m::singleton!(: [u8; DMA_BUFFER_LEN] = [0; DMA_BUFFER_LEN]).unwrap();
// todo figure out double buffering
let mut rx_transfer = Transfer::init_peripheral_to_memory(
dma2.2,
rx,
rx_buffer1,
None,
DmaConfig::default()
.memory_increment(true)
.fifo_enable(true)
.fifo_error_interrupt(true)
.transfer_complete_interrupt(true),
);
rx_transfer.start(|_rx| {});
(
Shared {
radio_temp: 0.0,
tx_buf: ConstGenericRingBuffer::new(),
},
Local {
radio,
usart,
tx,
state: SlaveState::Idle,
rx_transfer,
rx_buffer: Some(rx_buffer2),
},
Local { radio },
init::Monotonics(),
)
}
......@@ -144,7 +203,7 @@ mod app {
i += 1;
// get temp every 500 packets, or whenever when idle TODO
// get temp every 500 packets, or whenever when idle
if i >= 500 {
i = 0;
......@@ -155,52 +214,105 @@ mod app {
}
}
#[task(binds = USART1, priority=1, local = [state, usart], shared = [tx_buf, radio_temp])]
#[task(binds = USART1, priority=1, shared = [state, tx_buf, tx,radio_temp, rx_transfer, rx_buffer])]
fn usart1(mut ctx: usart1::Context) {
let state = ctx.local.state;
let usart = ctx.local.usart;
let mut buf = ctx.shared.tx_buf;
let x = block!(usart.read()).unwrap();
match state {
SlaveState::Idle => {
if let Some(cmd) = SlaveCmd::from_u8(x) {
match cmd {
SlaveCmd::BufferStatus => {
if buf.lock(|b| b.is_full()) {
block!(usart.write(0x01)).unwrap(); // not enough space for a new packet
} else {
block!(usart.write(0x02)).unwrap(); // safe to send a packet
}
}
let transfer = &mut ctx.shared.rx_transfer;
if transfer.is_idle() {
let byte_count =
DMA_BUFFER_LEN - usize::from(Stream2::<DMA2>::get_number_of_transfers());
let new_buf = ctx.shared.rx_buffer.take().unwrap();
let (buffer, _) = transfer.next_transfer(new_buf).unwrap();
let bytes = &buffer[..byte_count];
handle_bytes(
ctx.shared.state,
ctx.shared.tx_buf,
ctx.shared.tx,
ctx.shared.radio_temp,
bytes,
);
*ctx.shared.rx_buffer = Some(buffer);
}
}
// Must be same priority as USART1
#[task(binds = DMA2_STREAM2, priority=1, shared = [state, tx_buf, tx, radio_temp, rx_transfer, rx_buffer])]
fn dma2_stream2(mut ctx: dma2_stream2::Context) {
let transfer = &mut ctx.shared.rx_transfer;
if Stream2::<DMA2>::get_fifo_error_flag() {
transfer.clear_fifo_error_interrupt();
}
if Stream2::<DMA2>::get_transfer_complete_flag() {
transfer.clear_transfer_complete_interrupt();
let new_buf = ctx.shared.rx_buffer.take().unwrap();
let (buffer, _) = transfer.next_transfer(new_buf).unwrap();
handle_bytes(
ctx.shared.state,
ctx.shared.tx_buf,
ctx.shared.tx,
ctx.shared.radio_temp,
buffer,
);
*ctx.shared.rx_buffer = Some(buffer);
}
}
SlaveCmd::SendPacket => {
if buf.lock(|b| b.len() >= b.capacity() - 1) {
block!(usart.write(0x01)).unwrap(); // not enough space for a new packet
} else {
block!(usart.write(0x02)).unwrap(); // safe to send a packet
fn handle_bytes<
B: Mutex<T = ConstGenericRingBuffer<Packet, BUFFER_LEN>>,
RT: Mutex<T = f32>,
>(
state: &mut SlaveState,
mut buf: B,
tx: &mut Tx<USART1>,
mut radio_temp: RT,
bytes: &[u8],
) {
for &x in bytes {
match state {
SlaveState::Idle => {
if let Some(cmd) = SlaveCmd::from_u8(x) {
match cmd {
SlaveCmd::BufferStatus => {
if buf.lock(|b| b.is_full()) {
block!(tx.write(0x01)).unwrap(); // not enough space for a new packet
} else {
block!(tx.write(0x02)).unwrap(); // safe to send a packet
}
}
*state = SlaveState::RecvPacket(Packet::default());
}
SlaveCmd::SendPacket => {
if buf.lock(|b| b.len() >= b.capacity() - 1) {
block!(tx.write(0x01)).unwrap(); // not enough space for a new packet
} else {
block!(tx.write(0x02)).unwrap(); // safe to send a packet
}
SlaveCmd::GetTemp => {
let temp = ctx.shared.radio_temp.lock(|x| *x);
usart.bwrite_all(&temp.to_le_bytes()).unwrap();
*state = SlaveState::RecvPacket(Packet::default());
}
SlaveCmd::GetTemp => {
let temp = radio_temp.lock(|x| *x);
tx.bwrite_all(&temp.to_le_bytes()).unwrap();
}
}
}
}
}
SlaveState::RecvPacket(pkt) => {
pkt.push(x);
if pkt.is_complete() {
buf.lock(|b| b.enqueue(pkt.clone()));
SlaveState::RecvPacket(pkt) => {
pkt.push(x);
if pkt.is_complete() {
buf.lock(|b| b.enqueue(pkt.clone()));
*state = SlaveState::Idle;
*state = SlaveState::Idle;
}
}
}
};
};
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment