diff --git a/app/oxcon2023g0/app.toml b/app/oxcon2023g0/app.toml index 53e338e42..78bfbb0ab 100644 --- a/app/oxcon2023g0/app.toml +++ b/app/oxcon2023g0/app.toml @@ -6,7 +6,7 @@ board = "oxcon2023g0" [kernel] name = "oxcon2023g0" -requires = {flash = 10752, ram = 1200} +requires = {flash = 11008, ram = 1296} stacksize = 640 [tasks.jefe] @@ -24,7 +24,7 @@ priority = 1 max-sizes = {flash = 2048, ram = 256} uses = ["rcc", "gpio", "system_flash"] start = true -features = ["g031"] +features = ["g030"] stacksize = 256 task-slots = ["jefe"] @@ -48,9 +48,32 @@ task-slots = ["sys"] stacksize = 912 features = ["stm32g0", "gpio", "micro"] +[tasks.i2c_driver] +name = "drv-stm32xx-i2c-server" +features = ["g030"] +priority = 2 +max-sizes = {flash = 16384, ram = 1024} +uses = ["i2c1"] +start = true +task-slots = ["sys"] +stacksize = 896 +notifications = ["i2c1-irq"] + +[tasks.i2c_driver.interrupts] +"i2c1.irq" = "i2c1-irq" + [tasks.idle] name = "task-idle" priority = 5 max-sizes = {flash = 128, ram = 64} stacksize = 64 start = true + +[config] +[[config.i2c.controllers]] +controller = 1 + +[config.i2c.controllers.ports.A] +scl.pin = 11 +sda.pin = 10 +af = 6 diff --git a/build/i2c/Cargo.toml b/build/i2c/Cargo.toml index d6c94cd06..941b80a74 100644 --- a/build/i2c/Cargo.toml +++ b/build/i2c/Cargo.toml @@ -18,3 +18,4 @@ h743 = [] h753 = [] h7b3 = [] g031 = [] +g030 = [] diff --git a/build/i2c/src/lib.rs b/build/i2c/src/lib.rs index e5225bb82..ed601b244 100644 --- a/build/i2c/src/lib.rs +++ b/build/i2c/src/lib.rs @@ -650,7 +650,9 @@ impl ConfigGenerator { use stm32h7::stm32h7b3 as device; #[cfg(feature = "g031")] - use stm32g0::stm32g031 as device;"## + use stm32g0::stm32g031 as device; + #[cfg(feature = "g030")] + use stm32g0::stm32g030 as device;"## )?; } diff --git a/drv/stm32xx-i2c-server/Cargo.toml b/drv/stm32xx-i2c-server/Cargo.toml index 91b703899..48dbb2892 100644 --- a/drv/stm32xx-i2c-server/Cargo.toml +++ b/drv/stm32xx-i2c-server/Cargo.toml @@ -15,7 +15,7 @@ drv-stm32xx-i2c = { path = "../stm32xx-i2c" } drv-stm32xx-sys-api = { path = "../stm32xx-sys-api" } fixedmap = { path = "../../lib/fixedmap" } ringbuf = { path = "../../lib/ringbuf" } -userlib = { path = "../../sys/userlib", features = ["panic-messages"] } +userlib = { path = "../../sys/userlib" } [build-dependencies] anyhow = { workspace = true } @@ -25,10 +25,11 @@ build-util = { path = "../../build/util" } build-i2c = { path = "../../build/i2c" } [features] -h743 = ["stm32h7/stm32h743", "drv-stm32xx-i2c/h743", "drv-stm32xx-sys-api/h743", "build-i2c/h743"] -h753 = ["stm32h7/stm32h753", "drv-stm32xx-i2c/h753", "drv-stm32xx-sys-api/h753", "build-i2c/h753"] -g031 = ["stm32g0/stm32g031", "drv-stm32xx-i2c/g031", "drv-stm32xx-sys-api/g031", -"build-i2c/g031", "ringbuf/disabled"] +h743 = ["stm32h7/stm32h743", "drv-stm32xx-i2c/h743", "drv-stm32xx-sys-api/h743", "build-i2c/h743", "panic-messages"] +h753 = ["stm32h7/stm32h753", "drv-stm32xx-i2c/h753", "drv-stm32xx-sys-api/h753", "build-i2c/h753", "panic-messages"] +g031 = ["stm32g0/stm32g031", "drv-stm32xx-i2c/g031", "drv-stm32xx-sys-api/g031", "build-i2c/g031", "ringbuf/disabled", "panic-messages"] +g030 = ["stm32g0/stm32g030", "drv-stm32xx-i2c/g030", "drv-stm32xx-sys-api/g030", "build-i2c/g030", "ringbuf/disabled"] +panic-messages = ["userlib/panic-messages"] # This section is here to discourage RLS/rust-analyzer from doing test builds, # since test builds don't work for cross compilation. diff --git a/drv/stm32xx-i2c-server/src/main.rs b/drv/stm32xx-i2c-server/src/main.rs index 437b522c7..3dba253d0 100644 --- a/drv/stm32xx-i2c-server/src/main.rs +++ b/drv/stm32xx-i2c-server/src/main.rs @@ -585,7 +585,7 @@ fn configure_port( /// [0] Analog Devices. AN-686: Implementing an I2C Reset. 2003. /// fn wiggle_scl(sys: &Sys, scl: PinSet, sda: PinSet) { - let mut wiggles = 0; + let mut wiggles = 0_u8; sys.gpio_set(scl); sys.gpio_configure_output( @@ -618,7 +618,7 @@ fn wiggle_scl(sys: &Sys, scl: PinSet, sda: PinSet) { // sys.gpio_reset(scl); sys.gpio_set(scl); - wiggles += 1; + wiggles = wiggles.wrapping_add(1); } else { // // SDA is high. We're going to flip it back to an output, pull the diff --git a/drv/stm32xx-i2c/Cargo.toml b/drv/stm32xx-i2c/Cargo.toml index 022bb4a1f..a41788da9 100644 --- a/drv/stm32xx-i2c/Cargo.toml +++ b/drv/stm32xx-i2c/Cargo.toml @@ -20,6 +20,7 @@ userlib = { path = "../../sys/userlib" } h743 = ["stm32h7/stm32h743", "drv-stm32xx-sys-api/h743"] h753 = ["stm32h7/stm32h753", "drv-stm32xx-sys-api/h753"] g031 = ["stm32g0/stm32g031", "drv-stm32xx-sys-api/g031"] +g030 = ["stm32g0/stm32g030", "drv-stm32xx-sys-api/g030"] amd_erratum_1394 = [] # This section is here to discourage RLS/rust-analyzer from doing test builds, diff --git a/drv/stm32xx-i2c/src/lib.rs b/drv/stm32xx-i2c/src/lib.rs index 2a821d7ea..6fae96bf0 100644 --- a/drv/stm32xx-i2c/src/lib.rs +++ b/drv/stm32xx-i2c/src/lib.rs @@ -25,10 +25,23 @@ pub type Isr = device::i2c3::isr::R; #[cfg(feature = "g031")] use stm32g0::stm32g031 as device; -#[cfg(any(feature = "h743", feature = "h753", feature = "g031"))] +#[cfg(feature = "g030")] +use stm32g0::stm32g030 as device; + +#[cfg(any( + feature = "h743", + feature = "h753", + feature = "g031", + feature = "g030" +))] pub type RegisterBlock = device::i2c1::RegisterBlock; -#[cfg(any(feature = "h743", feature = "h753", feature = "g031"))] +#[cfg(any( + feature = "h743", + feature = "h753", + feature = "g031", + feature = "g030" +))] pub type Isr = device::i2c1::isr::R; pub mod ltc4306; @@ -291,7 +304,7 @@ impl I2cController<'_> { .scldel().bits(scldel) .sdadel().bits(0) }); - } else if #[cfg(feature = "g031")] { + } else if #[cfg(any(feature = "g031", feature = "g030"))] { // On the G0, our APB peripheral clock is 16MHz, yielding: // // - A PRESC of 0, yielding a t_presc of 62 ns @@ -339,7 +352,7 @@ impl I2cController<'_> { .timeouta().bits(3417) // Timeout value .tidle().clear_bit() // Want SCL, not IDLE }); - } else if #[cfg(feature = "g031")] { + } else if #[cfg(any(feature = "g030", feature = "g031"))] { i2c.timeoutr.write(|w| { w .timouten().set_bit() // Enable SCL timeout .timeouta().bits(196) // Timeout value @@ -441,9 +454,8 @@ impl I2cController<'_> { // failure mode for a condition expected to be unusual.) // const BUSY_SLEEP_THRESHOLD: u32 = 300; - let mut laps = 0; - loop { + for lap in 0..=BUSY_SLEEP_THRESHOLD + 1 { let isr = i2c.isr.read(); ringbuf_entry!(Trace::WaitISR(isr.bits())); @@ -454,20 +466,17 @@ impl I2cController<'_> { // up to the controller, the timeout flag is set, we clear it and // ignore it -- we know that it's spurious. // - if laps == 0 && isr.timeout().is_timeout() { + if lap == 0 && isr.timeout().is_timeout() { i2c.icr.write(|w| w.timoutcf().set_bit()); } if !isr.busy().is_busy() { - break; + return Ok(()); } self.check_errors(&isr)?; - laps += 1; - - #[allow(clippy::comparison_chain)] // clippy misfire - if laps == BUSY_SLEEP_THRESHOLD { + if lap == BUSY_SLEEP_THRESHOLD { // // If we have taken BUSY_SLEEP_THRESHOLD laps, we are going to // sleep for two ticks -- which should be far greater than the @@ -475,21 +484,19 @@ impl I2cController<'_> { // ringbuf_entry!(Trace::BusySleep); hl::sleep_for(2); - } else if laps > BUSY_SLEEP_THRESHOLD { - // - // We have already taken BUSY_SLEEP_THRESHOLD laps AND a two - // tick sleep -- and the busy bit is still set. At this point, - // we need to return an error indicating that we need to reset - // the controller. We return a disjoint error code here to - // be able to know that we hit this condition rather than our - // more expected conditions on bus lockup (namely, a timeout - // or arbitration lost). - // - return Err(drv_i2c_api::ResponseCode::ControllerBusy); } + // On lap == BUSY_SLEEP_THRESHOLD + 1 we'll fall out. } - Ok(()) + // + // We have already taken BUSY_SLEEP_THRESHOLD laps AND a two tick sleep + // -- and the busy bit is still set. At this point, we need to return + // an error indicating that we need to reset the controller. We return + // a disjoint error code here to be able to know that we hit this + // condition rather than our more expected conditions on bus lockup + // (namely, a timeout or arbitration lost). + // + Err(drv_i2c_api::ResponseCode::ControllerBusy) } /// Perform a write to and then a read from the specified device. Either diff --git a/lib/fixedmap/src/lib.rs b/lib/fixedmap/src/lib.rs index c1e4402bc..497302958 100644 --- a/lib/fixedmap/src/lib.rs +++ b/lib/fixedmap/src/lib.rs @@ -75,7 +75,7 @@ impl FixedMap { } } - panic!("FixedMap overflow"); + panic!(); } /// diff --git a/sys/userlib/src/hl.rs b/sys/userlib/src/hl.rs index bee304682..00e7be98f 100644 --- a/sys/userlib/src/hl.rs +++ b/sys/userlib/src/hl.rs @@ -9,12 +9,13 @@ use abi::TaskId; use core::marker::PhantomData; +use unwrap_lite::UnwrapLite; use zerocopy::{AsBytes, FromBytes, LayoutVerified}; use crate::{ sys_borrow_info, sys_borrow_read, sys_borrow_write, sys_get_timer, - sys_recv, sys_recv_closed, sys_recv_open, sys_reply, sys_set_timer, - BorrowInfo, ClosedRecvError, FromPrimitive, + sys_recv, sys_recv_closed, sys_recv_open, sys_reply, sys_reply_fault, + sys_set_timer, BorrowInfo, ClosedRecvError, FromPrimitive, }; const INTERNAL_TIMER_NOTIFICATION: u32 = 1 << 31; @@ -94,14 +95,18 @@ pub fn recv<'a, O, E, S>( if rm.sender == TaskId::KERNEL { notify(state, rm.operation); } else if let Some(op) = O::from_u32(rm.operation) { - let m = Message { - buffer: &buffer[..rm.message_len], - sender: rm.sender, - response_capacity: rm.response_capacity, - lease_count: rm.lease_count, - }; - if let Err(e) = msg(state, op, m) { - sys_reply(sender, e.into(), &[]); + if let Some(buffer) = buffer.get(..rm.message_len) { + let m = Message { + buffer, + sender: rm.sender, + response_capacity: rm.response_capacity, + lease_count: rm.lease_count, + }; + if let Err(e) = msg(state, op, m) { + sys_reply(sender, e.into(), &[]); + } + } else { + sys_reply_fault(sender, abi::ReplyFaultReason::BadMessageSize); } } else { sys_reply(sender, 1, &[]); @@ -460,5 +465,10 @@ pub fn sleep_for(ticks: u64) { // `sleep_for(x)` will sleep for at least `x` full ticks. Note that the task // calling `sleep_for` may get woken arbitrarily later if preempted by // higher priority tasks, so at-least is generally the best we can do. - sleep_until(sys_get_timer().now + ticks + 1) + let deadline = sys_get_timer() + .now + .checked_add(ticks) + .and_then(|t| t.checked_add(1)) + .unwrap_lite(); + sleep_until(deadline) } diff --git a/sys/userlib/src/task_slot.rs b/sys/userlib/src/task_slot.rs index 9ecbaede8..4c30d6f48 100644 --- a/sys/userlib/src/task_slot.rs +++ b/sys/userlib/src/task_slot.rs @@ -20,16 +20,13 @@ pub struct TaskSlot(VolatileConst); impl TaskSlot { /// A TaskSlot that has not been resolved by a later processing step. /// - /// Calling get_task_id() on an unbound TaskSlot will panic. + /// Calling get_task_id() on an unbound TaskSlot will cause a fault from the + /// kernel. pub const UNBOUND: Self = Self(VolatileConst::new(TaskId::UNBOUND.0)); pub fn get_task_id(&self) -> TaskId { let task_index = self.get_task_index(); - if task_index == TaskId::UNBOUND.0 { - panic!("Attempted to get task id of unbound TaskSlot"); - } - let prototype = TaskId::for_index_and_gen(task_index.into(), Generation::default()); crate::sys_refresh_task_id(prototype)