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

STM32 I2C size improvements, STM32G030 support #1540

Merged
merged 7 commits into from
Sep 19, 2023
Merged
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
27 changes: 25 additions & 2 deletions app/oxcon2023g0/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ board = "oxcon2023g0"

[kernel]
name = "oxcon2023g0"
requires = {flash = 10752, ram = 1200}
requires = {flash = 11008, ram = 1296}
stacksize = 640

[tasks.jefe]
Expand All @@ -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"]

Expand All @@ -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
1 change: 1 addition & 0 deletions build/i2c/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ h743 = []
h753 = []
h7b3 = []
g031 = []
g030 = []
4 changes: 3 additions & 1 deletion build/i2c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;"##
)?;
}

Expand Down
11 changes: 6 additions & 5 deletions drv/stm32xx-i2c-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand All @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions drv/stm32xx-i2c-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drv/stm32xx-i2c/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
55 changes: 31 additions & 24 deletions drv/stm32xx-i2c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()));

Expand All @@ -454,42 +466,37 @@ 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
// amount of time we would expect the controller to be busy...
//
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
Expand Down
2 changes: 1 addition & 1 deletion lib/fixedmap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl<K: Copy + PartialEq, V: Copy, const N: usize> FixedMap<K, V, { N }> {
}
}

panic!("FixedMap overflow");
panic!();
}

///
Expand Down
32 changes: 21 additions & 11 deletions sys/userlib/src/hl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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, &[]);
Expand Down Expand Up @@ -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)
}
7 changes: 2 additions & 5 deletions sys/userlib/src/task_slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@ pub struct TaskSlot(VolatileConst<u16>);
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)
Expand Down