Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ rp2040-boot2 = "0.2.1"
defmt-brtt = { version = "0.1.0", default-features = false }
# We don't need bbqueue directly, but we need to activate the
# thumbv6 feature on it so it will compile.
bbqueue = { version = "0.5", features = ["thumbv6"], optional = true }
bbqueue = { version = "0.5", features = ["thumbv6"] }

[features]
default = [ "defmt-brtt/rtt", "gnddetect" ]
defmt-bbq = ["defmt-brtt/bbq", "dep:bbqueue"]
defmt-bbq = ["defmt-brtt/bbq"]
gnddetect = []
usb-serial-reboot = []

Expand Down
113 changes: 110 additions & 3 deletions src/bin/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,65 @@ mod app {
use rp2040_hal::usb::UsbBus;
use usb_device::class_prelude::*;

use rtic_monotonics::rp2040::{ExtU64, Timer};
use rtic_monotonics::rp2040::{fugit::RateExtU32, ExtU64, Timer};

struct UsbUartState {
data_rate: u32,
data_bits: u8,
stop_bits: usbd_serial::StopBits,
parity_type: usbd_serial::ParityType,
}

impl PartialEq<usbd_serial::LineCoding> for UsbUartState {
fn eq(&self, other: &usbd_serial::LineCoding) -> bool {
self.data_bits == other.data_bits() &&
self.data_rate == other.data_rate() &&
self.parity_type == other.parity_type() &&
self.stop_bits == other.stop_bits()
}
}

impl UsbUartState {
pub fn new(line_coding: &usbd_serial::LineCoding) -> Self {
Self {
data_rate: line_coding.data_rate(),
data_bits: line_coding.data_bits(),
stop_bits: line_coding.stop_bits(),
parity_type: line_coding.parity_type(),
}
}

pub fn try_get_uart_config(&self) -> Option<rp2040_hal::uart::UartConfig> {
let data_bits = match self.data_bits {
5 => Some(rp2040_hal::uart::DataBits::Five),
6 => Some(rp2040_hal::uart::DataBits::Six),
7 => Some(rp2040_hal::uart::DataBits::Seven),
8 => Some(rp2040_hal::uart::DataBits::Eight),
_ => None,
}?;
let parity = match self.parity_type {
// "Event" is probably a typo
usbd_serial::ParityType::Event => Some(Some(rp2040_hal::uart::Parity::Even)),
usbd_serial::ParityType::Odd => Some(Some(rp2040_hal::uart::Parity::Odd)),
usbd_serial::ParityType::None => Some(None),
_ => None,
}?;
let stop_bits = match self.stop_bits {
usbd_serial::StopBits::One => Some(rp2040_hal::uart::StopBits::One),
usbd_serial::StopBits::Two => Some(rp2040_hal::uart::StopBits::Two),
_ => None
}?;

Some(rp2040_hal::uart::UartConfig::new(
self.data_rate.Hz(),
data_bits, parity, stop_bits))
}
}

#[shared]
struct Shared {
probe_usb: pico_probe::usb::ProbeUsb,
uart: Uart,
}

#[local]
Expand All @@ -28,6 +82,7 @@ mod app {
translator_power: TranslatorPower,
target_power: TargetPower,
target_physically_connected: TargetPhysicallyConnected,
uart_state: Option<UsbUartState>,
}

#[init(local = [
Expand All @@ -38,6 +93,7 @@ mod app {
let (
leds,
probe_usb,
uart,
dap_handler,
target_vcc,
translator_power,
Expand All @@ -53,13 +109,14 @@ mod app {
led_driver::spawn(leds).ok();

(
Shared { probe_usb },
Shared { probe_usb, uart },
Local {
dap_handler,
target_vcc,
translator_power,
target_power,
target_physically_connected,
uart_state: None,
},
)
}
Expand Down Expand Up @@ -115,11 +172,13 @@ mod app {
}
}

#[task(binds = USBCTRL_IRQ, priority = 2, shared = [ probe_usb ], local = [dap_handler, resp_buf: [u8; 64] = [0; 64]])]
#[task(binds = USBCTRL_IRQ, priority = 2, shared = [ probe_usb, uart ], local = [dap_handler, uart_state, resp_buf: [u8; 64] = [0; 64]])]
fn on_usb(ctx: on_usb::Context) {
let mut probe_usb = ctx.shared.probe_usb;
let mut uart = ctx.shared.uart;
let dap = ctx.local.dap_handler;
let resp_buf = ctx.local.resp_buf;
let uart_state = ctx.local.uart_state;

probe_usb.lock(|probe_usb| {
if let Some(request) = probe_usb.interrupt() {
Expand All @@ -146,6 +205,54 @@ mod app {
}
}
}

let uart_state_changed = uart_state.as_ref().map_or(true, |uart_state| !uart_state.eq(probe_usb.serial_line_coding()));
uart.lock(|uart| {
if uart_state_changed {
*uart_state = Some(UsbUartState::new(probe_usb.serial_line_coding()));
if let Some(uart_config) = uart_state.as_ref().unwrap().try_get_uart_config() {
uart.configure(uart_config);
}
}

if buffer_uart_tx_data(probe_usb, uart) > 0 {
uart.flush_write_buffer();
}
});
});
}

#[task(binds = UART1_IRQ, priority = 3, shared = [probe_usb, uart])]
fn on_uart(ctx: on_uart::Context) {
let mut probe_usb = ctx.shared.probe_usb;
let mut uart = ctx.shared.uart;

uart.lock(|uart| {
let mut uart_buf = [0u8; 32];
let read_size = uart.read(&mut uart_buf);
probe_usb.lock(|probe_usb| {
if read_size > 0 {
probe_usb.serial_write(&uart_buf[..read_size]);
}

buffer_uart_tx_data(probe_usb, uart);
});

uart.flush_write_buffer();
});
}

fn buffer_uart_tx_data(probe_usb: &mut pico_probe::usb::ProbeUsb, uart: &mut Uart) -> usize {
if let Some(mut grant) = uart.try_grant_write(64) {
let used = probe_usb.serial_read(&mut grant);
#[cfg(feature = "usb-serial-reboot")]
if grant.len() >= 4 && &grant[..used] == &0xDABAD000u32.to_be_bytes() {
rp2040_hal::rom_data::reset_to_usb_boot(0, 0);
}
grant.commit(used);
used
} else {
0
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod leds;
pub mod pio;
pub mod setup;
pub mod systick_delay;
pub mod uart;
pub mod usb;

defmt::timestamp! {"{=u64:us}", {
Expand Down
15 changes: 11 additions & 4 deletions src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub type DapHandler = dap_rs::dap::Dap<'static, Context, HostStatusToken, Wait,
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;

type UartPins = (Pin<Gpio20, rp2040_hal::gpio::FunctionUart>, Pin<Gpio21, rp2040_hal::gpio::FunctionUart>);
pub type Uart = crate::uart::Uart<pac::UART1, UartPins>;

#[inline(always)]
pub fn setup(
pac: pac::Peripherals,
Expand All @@ -42,6 +45,7 @@ pub fn setup(
) -> (
LedManager,
ProbeUsb,
Uart,
DapHandler,
TargetVccReader,
TranslatorPower,
Expand Down Expand Up @@ -95,6 +99,10 @@ pub fn setup(
let sio = Sio::new(pac.SIO);
let pins = Pins::new(pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut resets);

let uart = Uart::new(pac.UART1, (pins.gpio20.into_mode(), pins.gpio21.into_mode()), clocks.peripheral_clock.freq(), &mut resets);
let _dir_vcp_rx = pins.gpio25.into_push_pull_output_in_state(false.into());
let _dir_vcp_tx = pins.gpio24.into_push_pull_output_in_state(true.into());

let mut led_green = pins.gpio27.into_push_pull_output();
led_green.set_high().ok();
let mut led_red = pins.gpio28.into_push_pull_output();
Expand Down Expand Up @@ -158,10 +166,8 @@ pub fn setup(
let _tdi = pins.gpio17;
let _dir_tdi = pins.gpio23;

let _vcp_rx = pins.gpio21;
let _vcp_tx = pins.gpio20;
let _dir_vcp_rx = pins.gpio25;
let _dir_vcp_tx = pins.gpio24;
// let _vcp_rx = pins.gpio21;
// let _vcp_tx = pins.gpio20;

// High speed IO
io.set_drive_strength(OutputDriveStrength::TwelveMilliAmps);
Expand Down Expand Up @@ -199,6 +205,7 @@ pub fn setup(
(
led_manager,
probe_usb,
uart,
dap_hander,
adc,
translator_power,
Expand Down
78 changes: 78 additions & 0 deletions src/uart.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use rp2040_hal::uart;
use rtic_monotonics::rp2040::fugit::HertzU32;

enum Device<D: uart::UartDevice, P: uart::ValidUartPinout<D>> {
Disabled(uart::UartPeripheral<uart::Disabled, D, P>),
Enabled(uart::UartPeripheral<uart::Enabled, D, P>)
}

pub use uart::UartConfig as Config;

const WRITE_BUFFER_SIZE: usize = 256;
static WRITE_BUFFER: bbqueue::BBBuffer<WRITE_BUFFER_SIZE> = bbqueue::BBBuffer::new();

pub struct Uart<D: uart::UartDevice, P: uart::ValidUartPinout<D>> {
device: Option<Device<D, P>>,
peripheral_freq: HertzU32,
write_buffer_consumer: bbqueue::Consumer<'static, WRITE_BUFFER_SIZE>,
write_buffer_producer: bbqueue::Producer<'static, WRITE_BUFFER_SIZE>,
}

impl<D: uart::UartDevice, P: uart::ValidUartPinout<D>> Uart<D, P> {
pub fn new(device: D, pinout: P, peripheral_freq: HertzU32, resets: &mut rp2040_hal::pac::RESETS) -> Self {
let (producer, consumer) = WRITE_BUFFER.try_split().unwrap();
let device = uart::UartPeripheral::new(device, pinout, resets);
Self {
device: Some(Device::Disabled(device)),
peripheral_freq,
write_buffer_consumer: consumer,
write_buffer_producer: producer,
}
}

pub fn configure(&mut self, config: Config) {
let disabled_device = match self.device.take().unwrap() {
Device::Disabled(device) => device,
Device::Enabled(device) => device.disable(),
};

defmt::info!("configure uart: {}bps", config.baudrate.raw());

let mut device = disabled_device.enable(config, self.peripheral_freq).expect("failed to enable the uart peripheral");
device.set_fifos(true);
device.enable_rx_interrupt();
self.device = Some(Device::Enabled(device));
}

pub fn read(&self, data: &mut[u8]) -> usize {
if let Some(Device::Enabled(uart)) = self.device.as_ref() {
uart.read_raw(data).unwrap_or(0)
} else {
0
}
}

pub fn try_grant_write(&mut self, max_size: usize) -> Option<bbqueue::GrantW<'static, WRITE_BUFFER_SIZE>> {
self.write_buffer_producer.grant_max_remaining(max_size).ok()
}

pub fn flush_write_buffer(&mut self) {
if let Some(Device::Enabled(uart)) = self.device.as_mut() {
if let Ok(grant) = self.write_buffer_consumer.split_read() {
let unused = uart.write_raw(grant.bufs().0).unwrap_or(grant.bufs().0);
let mut used = grant.bufs().0.len() - unused.len();
if unused.len() == 0 {
let unused = uart.write_raw(grant.bufs().1).unwrap_or(grant.bufs().1);
used += grant.bufs().1.len() - unused.len();
}

if used < grant.combined_len() {
uart.enable_tx_interrupt();
} else {
uart.disable_tx_interrupt();
}
grant.release(used);
}
}
}
}
27 changes: 16 additions & 11 deletions src/usb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@ impl ProbeUsb {
}
}

pub fn serial_write(&mut self, data: &[u8]) -> usize {
if self.device.state() == UsbDeviceState::Configured && self.serial.dtr() {
self.serial.write(data).unwrap_or(0)
} else {
0
}
}

pub fn serial_read(&mut self, data: &mut [u8]) -> usize {
self.serial.read(data).unwrap_or(0)
}

pub fn serial_line_coding(&self) -> &usbd_serial::LineCoding {
self.serial.line_coding()
}

pub fn flush_logs(&mut self) {
#[cfg(feature = "defmt-bbq")]
{
Expand Down Expand Up @@ -86,17 +102,6 @@ impl ProbeUsb {
return Some(Request::Suspend);
}

// Discard data from the serial interface
let mut buf = [0; 64 as usize];
let _read_data = self.serial.read(&mut buf);

#[cfg(feature = "usb-serial-reboot")]
if let Ok(read_data) = _read_data {
if &buf[..read_data] == &0xDABAD000u32.to_be_bytes() {
rp2040_hal::rom_data::reset_to_usb_boot(0, 0);
}
}

let r = self.dap_v1.process();
if r.is_some() {
return r;
Expand Down
Loading