Skip to content

Commit

Permalink
add bufered uart
Browse files Browse the repository at this point in the history
  • Loading branch information
huseinmsft committed Feb 14, 2025
1 parent 3667499 commit eaa1c7a
Show file tree
Hide file tree
Showing 4 changed files with 393 additions and 28 deletions.
96 changes: 76 additions & 20 deletions src/dma/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,24 +124,6 @@ impl<'d> Channel<'d> {
let xfercount = (mem_len / xferwidth) - 1;
let channel = self.info.ch_num;

// Configure the channel descriptor
// NOTE: the DMA controller expects the memory buffer end address but peripheral address is actual
// SAFETY: unsafe due to use of a mutable static (DESCRIPTORS.list)
unsafe {
DESCRIPTORS.list[channel].reserved = 0;
if dir == Direction::MemoryToPeripheral {
DESCRIPTORS.list[channel].dst_data_end_addr = dstbase as u32;
} else {
DESCRIPTORS.list[channel].dst_data_end_addr = dstbase as u32 + (xfercount * xferwidth) as u32;
}
if dir == Direction::PeripheralToMemory {
DESCRIPTORS.list[channel].src_data_end_addr = srcbase as u32;
} else {
DESCRIPTORS.list[channel].src_data_end_addr = srcbase as u32 + (xfercount * xferwidth) as u32;
}
DESCRIPTORS.list[channel].nxt_desc_link_addr = 0;
}

// Configure for transfer type, no hardware triggering (we'll trigger via software), high priority
// SAFETY: unsafe due to .bits usage
self.info.regs.channel(channel).cfg().write(|w| unsafe {
Expand All @@ -164,8 +146,19 @@ impl<'d> Channel<'d> {
// SAFETY: unsafe due to .bits usage
self.info.regs.channel(channel).xfercfg().write(|w| unsafe {
w.cfgvalid().set_bit();
w.clrtrig().set_bit();
w.reload().clear_bit();

if options.is_continuous {
w.reload().enabled();
w.clrtrig().clear_bit();
} else {
w.reload().disabled();
w.clrtrig().set_bit();
}
if options.is_sw_trig {
w.swtrig().set_bit();
} else {
w.swtrig().clear_bit();
}
w.setinta().set_bit();
w.width().bits(options.width.into());
if dir == Direction::PeripheralToMemory {
Expand All @@ -180,6 +173,35 @@ impl<'d> Channel<'d> {
}
w.xfercount().bits(xfercount as u16)
});

// Configure the channel descriptor
// NOTE: the DMA controller expects the memory buffer end address but peripheral address is actual
// SAFETY: unsafe due to use of a mutable static (DESCRIPTORS.list)
unsafe {
if options.is_continuous {
let xfer_cfg = self.info.regs.channel(channel).xfercfg().read();
DESCRIPTORS.list[channel].reserved_reloadcfg = xfer_cfg.bits();
} else {
DESCRIPTORS.list[channel].reserved_reloadcfg = 0;
}

if dir == Direction::MemoryToPeripheral {
DESCRIPTORS.list[channel].dst_data_end_addr = dstbase as u32;
} else {
DESCRIPTORS.list[channel].dst_data_end_addr = dstbase as u32 + (xfercount * xferwidth) as u32;
}

if dir == Direction::PeripheralToMemory {
DESCRIPTORS.list[channel].src_data_end_addr = srcbase as u32;
} else {
DESCRIPTORS.list[channel].src_data_end_addr = srcbase as u32 + (xfercount * xferwidth) as u32;
}
if options.is_continuous {
DESCRIPTORS.list[channel].nxt_desc_link_addr = &DESCRIPTORS.list[channel] as *const _ as u32;
} else {
DESCRIPTORS.list[channel].nxt_desc_link_addr = 0;
}
}
}

/// Enable the DMA channel (only after configuring)
Expand All @@ -192,6 +214,40 @@ impl<'d> Channel<'d> {
.modify(|_, w| unsafe { w.ena().bits(1 << channel) });
}

#[cfg(feature = "defmt")]
/// Log the DMA channel transfer configuration
pub fn log_channel(&self) {
// Log DMA Channel Config Register
let channel = self.info.ch_num;
let dma_channel_cfg = self.info.regs.channel(channel).cfg().read();
defmt::info!(
"DMA Channel {} Config Register: 0x{=u32:x}",
channel,
dma_channel_cfg.bits()
);
// Log Interrupt Enable Set Register
let intenset0 = self.info.regs.intenset0().read();
defmt::info!("Interrupt Enable Set Register: 0x{=u32:x}", intenset0.bits());

// Log DMA Xfer Config Register
let xfer_cfg = self.info.regs.channel(channel).xfercfg().read();
defmt::info!(
"DMA Channel {} Xfer Config Register: 0x{=u32:x}",
channel,
xfer_cfg.bits()
);
// Log DMA Enable Set Register after enabling
let enableset0 = self.info.regs.enableset0().read();
defmt::info!("DMA Enable Set Register:0x{=u32:x}", enableset0.bits());
// Log DMA Xfer Config Register after triggering
let xfer_cfg_after = self.info.regs.channel(channel).xfercfg().read();
defmt::info!(
"DMA Channel {} Xfer Config Register (After Trigger): 0x{=u32:x}",
channel,
xfer_cfg_after.bits()
);
}

/// Disable the DMA channel
pub fn disable_channel(&self) {
let channel = self.info.ch_num;
Expand Down
4 changes: 2 additions & 2 deletions src/dma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const DMA_CHANNEL_COUNT: usize = 33;
#[derive(Copy, Clone, Debug)]
#[repr(C)]
struct ChannelDescriptor {
reserved: u32,
reserved_reloadcfg: u32,
src_data_end_addr: u32,
dst_data_end_addr: u32,
nxt_desc_link_addr: u32,
Expand All @@ -42,7 +42,7 @@ struct DescriptorBlock {
/// DMA channel descriptor list
static mut DESCRIPTORS: DescriptorBlock = DescriptorBlock {
list: [ChannelDescriptor {
reserved: 0,
reserved_reloadcfg: 0,
src_data_end_addr: 0,
dst_data_end_addr: 0,
nxt_desc_link_addr: 0,
Expand Down
8 changes: 8 additions & 0 deletions src/dma/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@ pub struct TransferOptions {

/// Transfer priority level
pub priority: Priority,

/// Transfer is intended to be done continuously, such as for a circular buffer
pub is_continuous: bool,

/// Transfer is software triggerred
pub is_sw_trig: bool,
}

impl Default for TransferOptions {
fn default() -> Self {
Self {
width: Width::Bit8,
priority: Priority::Priority0,
is_continuous: false,
is_sw_trig: false,
}
}
}
Expand Down
Loading

0 comments on commit eaa1c7a

Please sign in to comment.