Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UART v2 #443

Merged
merged 54 commits into from
Jul 31, 2021
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
c314c3d
Begin implementing v2 UART driver
jbeaurivage May 19, 2021
5091949
Refactor to new Pads API (#434)
jbeaurivage May 21, 2021
367ffab
Split UART into Rx and Tx halves
jbeaurivage May 26, 2021
82bcd3c
Baudrate configuration, bugfixes
jbeaurivage May 28, 2021
6c15a81
Begin thumbv7em support
jbeaurivage May 28, 2021
7b610f8
Module-level documentation
jbeaurivage May 28, 2021
d0c93cb
Finish thumbv7em implementation
jbeaurivage Jun 9, 2021
499d2a6
Internal clock mode bugfix, add IrDA support
jbeaurivage Jun 11, 2021
512e269
Rename 'ready_to_send' to 'rts' and 'clear_to_send' to 'cts'
jbeaurivage Jun 11, 2021
3173f11
DMA transfers; Change way of splitting Uart rx and tx.
jbeaurivage Jun 11, 2021
f2424c1
Kitchen sink of jelly-bean changes:
jbeaurivage Jun 11, 2021
a7a8bf6
Add Tx/Rx trait bounds to UartTx and UartRx
jbeaurivage Jun 11, 2021
1df5109
Separate uart/spi DMA implementations in sercom::v2::dma.rs
jbeaurivage Jun 16, 2021
cc58bed
Remove the sercom::v2::Pad type
bradleyharden May 28, 2021
1add44a
Refactor to 'bradleyharden/remove_v2_pad_type'
jbeaurivage Jun 16, 2021
b490c75
UartRx error handling; UartRx::flush
jbeaurivage Jun 16, 2021
1f9fa33
Asynchronous fractional baud mode
jbeaurivage Jun 16, 2021
9b43f65
Make default bit order LSB-first and clarify docs
jbeaurivage Jun 17, 2021
37fbc1a
Clear all errors on UartRx::flush
jbeaurivage Jun 17, 2021
1b22ec6
Major refactor of splitting UartRx and UartTx
jbeaurivage Jun 18, 2021
500b94e
Remove DMAC payload in sercom::dma.rs
jbeaurivage Jun 21, 2021
017fba6
Merge 'bradleyharden/remove_v2_pad_type' and refactor accordingly
jbeaurivage Jun 21, 2021
cc23fd6
Finish IrDA encoding, doc fixes
jbeaurivage Jun 21, 2021
fc04ba8
Complete refactor of handling split Tx/Rx.
jbeaurivage Jun 22, 2021
ac03bd3
Remove the sercom::v2::Pad type (#451)
bradleyharden Jun 21, 2021
8673208
Add `pub use nb;` to HAL prelude
ianrrees Jun 22, 2021
a144482
Merge branch 'master' into uart-v2
jbeaurivage Jun 25, 2021
9bf98ac
Change 'uart' to 'spi' in deprecation notices
jbeaurivage Jun 25, 2021
1120fd4
Various typo and doc fixes
jbeaurivage Jun 28, 2021
fde8dac
Merge thumbv6m and thumbv7em implementations
jbeaurivage Jun 28, 2021
82b959d
Fix spi::Length issue in sercom::dma.rs
jbeaurivage Jun 28, 2021
e5ada81
Add examples and update BSP
jbeaurivage Jun 28, 2021
112894e
Move ALL register accesses to the Registers struct
jbeaurivage Jun 30, 2021
dd53693
Make CTS operation possible only when CTS pad is specified
jbeaurivage Jun 30, 2021
3822686
Clear TXC flag when flushing
jbeaurivage Jun 30, 2021
ed81ff6
Change stop_bit to stop_bits, add Parity::None variant
jbeaurivage Jul 1, 2021
bc3fca2
Remove deprecation warnings
jbeaurivage Jul 1, 2021
856117f
Add DynCharSize
jbeaurivage Jul 2, 2021
145b8f1
Add ReadConfig trait
jbeaurivage Jul 2, 2021
9f43201
Rename setters as set_* in Registers impl
jbeaurivage Jul 2, 2021
ccd4e5d
Add setter methods
jbeaurivage Jul 2, 2021
827dfe5
Fix unused warnings, add inline hints
jbeaurivage Jul 2, 2021
71ced79
Implement AsRef<Config> for Uart, reconfigure takes SpecificConfig<C>
jbeaurivage Jul 2, 2021
a456ed3
Fix bugs related to parity handling
jbeaurivage Jul 7, 2021
b0baf11
unsafe impl Sync for Registers
jbeaurivage Jul 7, 2021
4b45804
Reorganize code into modules
jbeaurivage Jul 7, 2021
13bf4cf
Dynamically change character size
jbeaurivage Jul 7, 2021
332b9b8
Fix TXPO SVD error for thumbv7em
jbeaurivage Jul 8, 2021
f695821
Merge branch 'master' of https://github.com/atsamd-rs/atsamd into uar…
jbeaurivage Jul 21, 2021
a0c747e
Merge branch 'master' of https://github.com/atsamd-rs/atsamd into uar…
jbeaurivage Jul 28, 2021
368044c
Minor refactoring
jbeaurivage Jul 28, 2021
5b03193
Only enable CTRLA.{RXEN|TXEN} if necessary
jbeaurivage Jul 29, 2021
f9654ec
Merge branch 'master' of https://github.com/atsamd-rs/atsamd into uar…
jbeaurivage Jul 29, 2021
0eac8bb
Move BITS constant from CharSize to FixedCharSize
jbeaurivage Jul 30, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions boards/feather_m0/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,7 @@ required-features = ["adalogger", "usb", "sdmmc", "unproven"]
[[example]]
name = "blinky_rtic"
required-features = ["rtic", "unproven"]

[[example]]
name = "uart"
required-features = ["dma"]
100 changes: 100 additions & 0 deletions boards/feather_m0/examples/uart.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//! This example showcases the uart::v2 module.

#![no_std]
#![no_main]

use cortex_m::asm;
use panic_halt as _;

use bsp::hal;
use bsp::pac;
use feather_m0 as bsp;

use bsp::entry;
use hal::clock::GenericClockController;
use hal::dmac::{DmaController, PriorityLevel};
use hal::prelude::*;

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);

// Take RX and TX pins
let (rx_pin, tx_pin) = (pins.d0, pins.d1);

// 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);

// Setup UART peripheral
let uart = bsp::uart(
&mut clocks,
9600.hz(),
peripherals.SERCOM0,
&mut pm,
rx_pin,
tx_pin,
);

// 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();

// 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();
}
}
20 changes: 15 additions & 5 deletions boards/feather_m0/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ pub use embedded_hal as ehal;
pub use hal::pac;

use hal::clock::GenericClockController;
use hal::sercom::v2::{spi, Sercom4};
use hal::sercom::{I2CMaster3, UART0};
use hal::sercom::{
v2::{
spi,
uart::{self, BaudMode, Oversampling},
Sercom0, Sercom4,
},
I2CMaster3,
};
use hal::time::Hertz;

#[cfg(feature = "usb")]
Expand Down Expand Up @@ -259,8 +265,10 @@ pub fn i2c_master(
I2CMaster3::new(clock, baud, sercom3, pm, sda, scl)
}

pub type UartPads = uart::Pads<Sercom0, UartRx, UartTx>;

/// UART device for the labelled RX & TX pins
pub type Uart = UART0<UartRx, UartTx, (), ()>;
pub type Uart = uart::Uart<uart::Config<UartPads>, uart::Duplex>;

/// Convenience for setting up the labelled RX, TX pins to
/// operate as a UART device running at the specified baud.
Expand All @@ -275,8 +283,10 @@ pub fn uart(
let gclk0 = clocks.gclk0();
let clock = &clocks.sercom0_core(&gclk0).unwrap();
let baud = baud.into();
let pads = (uart_rx.into(), uart_tx.into());
UART0::new(clock, baud, sercom0, pm, pads)
let pads = uart::Pads::default().rx(uart_rx.into()).tx(uart_tx.into());
uart::Config::new(pm, sercom0, pads, clock.freq())
.baud(baud, BaudMode::Fractional(Oversampling::Bits16))
.enable()
}

#[cfg(feature = "usb")]
Expand Down
4 changes: 4 additions & 0 deletions boards/feather_m4/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,7 @@ name = "sleeping_timer_rtc"
[[example]]
name = "dmac"
required-features = ["dma"]

[[example]]
name = "uart"
required-features = ["dma"]
101 changes: 101 additions & 0 deletions boards/feather_m4/examples/uart.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! This example showcases the uart::v2 module.

#![no_std]
#![no_main]

use cortex_m::asm;
use panic_halt as _;

use bsp::hal;
use bsp::pac;
use feather_m4 as bsp;

use bsp::entry;
use hal::clock::GenericClockController;
use hal::dmac::{DmaController, PriorityLevel};
use hal::prelude::*;

use pac::Peripherals;

#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let mut clocks = GenericClockController::with_internal_32kosc(
peripherals.GCLK,
&mut peripherals.MCLK,
&mut peripherals.OSC32KCTRL,
&mut peripherals.OSCCTRL,
&mut peripherals.NVMCTRL,
);

let mut mclk = peripherals.MCLK;
let dmac = peripherals.DMAC;
let pins = bsp::Pins::new(peripherals.PORT);

// Take RX and TX pins
let (rx_pin, tx_pin) = (pins.d0, pins.d1);

// 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);

// Setup UART peripheral
let uart = bsp::uart(
&mut clocks,
9600.hz(),
peripherals.SERCOM5,
&mut mclk,
rx_pin,
tx_pin,
);

// 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();

// 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();
}
}
58 changes: 34 additions & 24 deletions boards/feather_m4/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#![no_std]
#![recursion_limit = "1024"]

extern crate atsamd_hal as hal;
pub use atsamd_hal as hal;

#[cfg(feature = "rt")]
extern crate cortex_m_rt;
use cortex_m_rt;
#[cfg(feature = "rt")]
pub use cortex_m_rt::entry;

Expand All @@ -15,13 +15,21 @@ pub use hal::common::*;
pub use hal::samd51::*;
pub use hal::target_device as pac;

use gpio::{Floating, Input, PfC, Port};
use gpio::{Floating, Input, Port};
use hal::clock::GenericClockController;
use hal::sercom::{I2CMaster2, PadPin, SPIMaster1, UART5};
use hal::sercom::{
v2::{
uart::{self, BaudMode, Oversampling},
IoSet1, Sercom5,
},
I2CMaster2, PadPin, SPIMaster1,
};
use hal::time::Hertz;

use gpio::v2::{AlternateC, AnyPin, Pin, C, PB16, PB17};

#[cfg(feature = "usb")]
use gpio::v2::{AnyPin, PA24, PA25};
use gpio::v2::{PA24, PA25};
#[cfg(feature = "usb")]
use hal::usb::usb_device::bus::UsbBusAllocator;
#[cfg(feature = "usb")]
Expand Down Expand Up @@ -148,31 +156,33 @@ pub fn i2c_master<F: Into<Hertz>>(
)
}

pub type UartRx = Pin<PB17, AlternateC>;
pub type UartTx = Pin<PB16, AlternateC>;
pub type UartPads = uart::Pads<Sercom5, IoSet1, UartRx, UartTx>;

/// UART device for the labelled RX & TX pins
pub type Uart = uart::Uart<uart::Config<UartPads>, uart::Duplex>;

/// Convenience for setting up the labelled RX, TX pins to
/// operate as a UART device running at the specified baud.
pub fn uart<F: Into<Hertz>>(
pub fn uart(
clocks: &mut GenericClockController,
baud: F,
sercom5: pac::SERCOM5,
baud: impl Into<Hertz>,
sercom5: Sercom5,
mclk: &mut pac::MCLK,
d0: gpio::Pb17<Input<Floating>>,
d1: gpio::Pb16<Input<Floating>>,
port: &mut Port,
) -> UART5<
hal::sercom::Sercom5Pad1<gpio::Pb17<PfC>>,
hal::sercom::Sercom5Pad0<gpio::Pb16<PfC>>,
(),
(),
> {
rx: impl AnyPin<Id = PB17>,
tx: impl AnyPin<Id = PB16>,
) -> Uart {
let gclk0 = clocks.gclk0();

UART5::new(
&clocks.sercom5_core(&gclk0).unwrap(),
baud.into(),
sercom5,
mclk,
(d0.into_pad(port), d1.into_pad(port)),
)
let clock = &clocks.sercom5_core(&gclk0).unwrap();
let baud = baud.into();
let pads = uart::Pads::default()
.rx(rx.into().into_alternate::<C>())
.tx(tx.into().into_alternate::<C>());
uart::Config::new(mclk, sercom5, pads, clock.freq())
.baud(baud, BaudMode::Fractional(Oversampling::Bits16))
.enable()
}

#[cfg(feature = "usb")]
Expand Down
1 change: 1 addition & 0 deletions hal/src/dmac/channel/reg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ reg_proxy!(swtrigctrl, bit, rw);
/// Acts as a proxy to the PAC DMAC object. Only registers and bits
/// within registers that should be readable/writable by specific
/// [`Channel`]s are exposed.
#[allow(dead_code)]
pub(super) struct RegisterBlock<Id: ChId> {
bradleyharden marked this conversation as resolved.
Show resolved Hide resolved
pub chctrla: ChctrlaProxy<Id, CHCTRLA>,
pub chctrlb: ChctrlbProxy<Id, CHCTRLB>,
Expand Down
7 changes: 4 additions & 3 deletions hal/src/sercom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@
//! The [v2] module will eventually replace [v1]. New users are encouraged to
//! use [v2] instead of [v1].
//!
//! The new [`v2::spi`] module is substantially more configurable and safe than
//! the existing, [`v1::spi`] module. To assist in migration, the
//! [`v2::spi::Pads`] struct accepts both [`v1::Pin`]s and [`v2::Pin`]s.
//! The new [`v2::spi`] and [`v2::uart`] modules are substantially more
//! configurable and safe than the existing, [`v1::spi`] and [`v1::uart`]
//! modules. To assist in migration, the [`v2::spi::Pads`] and
//! [`v2::uart::Pads`] structs accept both [`v1::Pin`]s and [`v2::Pin`]s.
//!
//! [`Pad`]: v2::pads::Pad
//! [`v1::Pin`]: crate::gpio::v1::Pin
Expand Down
4 changes: 4 additions & 0 deletions hal/src/sercom/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ pub mod pad;
pub use pad::*;

pub mod spi_future;
pub mod uart;

#[cfg(feature = "dma")]
pub mod dma;

//==============================================================================
// Sercom
Expand Down