Skip to content

Commit

Permalink
Final(?) fixes for Oxcon board.
Browse files Browse the repository at this point in the history
- Add insomniac feature to suppress sleep at WFI because Humility
  doesn't know how to attach to an STM32G0 that is sleeping.

- Fix bug in user leds "blink on start" feature that failed to actually
  set up blink on start, because there are several pieces of data to
  update and I missed two of them. I've simplified it.

- Remap to make pins A9 and A10 available -- they're muxed away on G0 by
  default and need to be activated (see main). Extra fun because the
  relevant bits in the PAC are wrong.

- Fix I2C pin mapping for the actual fabbed board.

- Activate PLL and boost CPU to 64 MHz for bragging rights.

- Adjust I2C clock configuration to account for that.
  • Loading branch information
cbiffle committed Sep 20, 2023
1 parent e0b57eb commit cde51d0
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 31 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 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 = 11008, ram = 1296}
requires = {flash = 11104, ram = 1296}
stacksize = 640

[tasks.jefe]
Expand Down Expand Up @@ -42,17 +42,17 @@ config = { blink_at_start = [ "Led::Zero" ] }
[tasks.hiffy]
name = "task-hiffy"
priority = 4
max-sizes = {flash = 8192, ram = 2048}
max-sizes = {flash = 8192, ram = 4096}
start = true
task-slots = ["sys", "i2c_driver"]
stacksize = 912
features = ["stm32g0", "gpio", "i2c", "g030", "micro"]
features = ["stm32g0", "gpio", "i2c", "g030"]

[tasks.i2c_driver]
name = "drv-stm32xx-i2c-server"
features = ["g030"]
priority = 2
max-sizes = {flash = 16384, ram = 1024}
max-sizes = {flash = 4096, ram = 1024}
uses = ["i2c1"]
start = true
task-slots = ["sys"]
Expand All @@ -68,12 +68,13 @@ priority = 5
max-sizes = {flash = 128, ram = 64}
stacksize = 64
start = true
features = ["insomniac"]

[config]
[[config.i2c.controllers]]
controller = 1

[config.i2c.controllers.ports.A]
scl.pin = 11
scl.pin = 9
sda.pin = 10
af = 6
55 changes: 54 additions & 1 deletion app/oxcon2023g0/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,60 @@ use cortex_m_rt::entry;

#[entry]
fn main() -> ! {
const CYCLES_PER_MS: u32 = 16_000;
const CYCLES_PER_MS: u32 = 64_000;

let rcc = unsafe { &*stm32g0::stm32g030::RCC::PTR };
rcc.apbenr2.modify(|_, w| {
w.syscfgen().set_bit();
w
});
cortex_m::asm::dsb();

let flash = unsafe { &*stm32g0::stm32g030::FLASH::PTR };
flash.acr.modify(|_, w| unsafe { w.latency().bits(2) });

// PLL settings we want are:
// - SRC = 16 MHz oscillator
// - M = PLL input division = /1 (so VCO input = 16 MHz)
// - N = VCO multiplication factor = 8 (the lowest possible = 128 MHz)
// - R = Output R division = /2 (lowest possible = 64 MHz)
// - Output R goes to CPU
rcc.pllsyscfgr.write(|w| {
unsafe {
w.pllsrc().bits(0b10); // HSI16, I promise
w.pllm().bits(1 - 1);
w.plln().bits(8); // _not_ an n-1 field
w.pllr().bits(2 - 1);
}
w.pllren().set_bit();
w
});
// Turn on the PLL and wait for it to stabilize.
rcc.cr.modify(|_, w| {
w.pllon().set_bit();
w
});
while rcc.cr.read().pllrdy().bit_is_clear() {
// spin.
}
rcc.cfgr.modify(|_, w| {
unsafe {
w.sw().bits(0b010);
}
w
});
while rcc.cfgr.read().sws().bits() != 0b010 {
// spin.
}

let syscfg = unsafe { &*stm32g0::stm32g030::SYSCFG::PTR };
syscfg.cfgr1.modify(|r, w| {
// the PAC mapping of the PA9/PA10 remap bits is wrong. Do this by hand:
unsafe {
w.bits(r.bits() | 1 << 3 | 1 << 4);
}
w
});

unsafe { kern::startup::start_kernel(CYCLES_PER_MS) }
}
3 changes: 3 additions & 0 deletions drv/stm32xx-i2c/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ amd_erratum_1394 = []
test = false
doctest = false
bench = false

[build-dependencies]
build-util = { path = "../../build/util" }
24 changes: 24 additions & 0 deletions drv/stm32xx-i2c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,11 @@ impl I2cController<'_> {
}

fn configure_timing(&self, i2c: &RegisterBlock) {
// TODO: this configuration mechanism is getting increasingly hairy. It
// generally assumes that a given processor runs at a given speed on all
// boards, which is not at all true. As of recently it's now doing a
// hybrid of "CPU model" and "board name" sensing. Should move to
// configuration!
cfg_if::cfg_if! {
if #[cfg(feature = "h7b3")] {
// We want to set our timing to achieve a 100kHz SCL. Given
Expand Down Expand Up @@ -304,6 +309,25 @@ impl I2cController<'_> {
.scldel().bits(scldel)
.sdadel().bits(0)
});
} else if #[cfg(target_board = "oxcon2023g0")] {
// This board runs at 64 MHz, yielding:
//
// - A PRESC of 4, yielding a t_presc of 62 ns
// - An SCLH of 61, yielding a t_sclh of 3844 ns
// - An SCLL of 91, yielding a t_scll of 5704 ns
//
// Taken together, this yields a t_scl of 9548 ns. Which,
// when added to our t_sync1 and t_sync2 will be close to our
// target of 10000 ns. Finally, we set SCLDEL to 3 and SDADEL
// to 0 -- values that come from the STM32CubeMX tool (as
// advised by 47.4.5).
i2c.timingr.write(|w| { w
.presc().bits(4)
.sclh().bits(61)
.scll().bits(91)
.scldel().bits(3)
.sdadel().bits(0)
});
} else if #[cfg(any(feature = "g031", feature = "g030"))] {
// On the G0, our APB peripheral clock is 16MHz, yielding:
//
Expand Down
48 changes: 23 additions & 25 deletions drv/user-leds/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ cfg_if::cfg_if! {

struct ServerImpl {
blinking: EnumMap<Led, bool>,
blink_state: bool,
}

impl idl::InOrderUserLedsImpl for ServerImpl {
Expand Down Expand Up @@ -144,11 +143,10 @@ impl idl::InOrderUserLedsImpl for ServerImpl {
index: usize,
) -> Result<(), RequestError<LedError>> {
let led = Led::from_usize(index).ok_or(LedError::NotPresent)?;
let already_blinking = self.blinking.values().any(|b| *b);
let any_blinking = self.blinking.values().any(|b| *b);
self.blinking[led] = true;
if !already_blinking {
led_on(led);
self.blink_state = false;

if !any_blinking {
sys_set_timer(
Some(sys_get_timer().now + BLINK_INTERVAL),
notifications::TIMER_MASK,
Expand All @@ -163,24 +161,21 @@ impl idol_runtime::NotificationHandler for ServerImpl {
notifications::TIMER_MASK
}

fn handle_notification(&mut self, _bits: u32) {
let mut any_blinking = false;
for (led, blinking) in &self.blinking {
if *blinking {
any_blinking = true;
if self.blink_state {
led_on(led);
} else {
led_off(led);
fn handle_notification(&mut self, bits: u32) {
if bits & notifications::TIMER_MASK != 0 {
let mut any_blinking = false;
for (led, blinking) in &self.blinking {
if *blinking {
any_blinking = true;
led_toggle(led);
}
}
}
self.blink_state = !self.blink_state;
if any_blinking {
sys_set_timer(
Some(sys_get_timer().now + BLINK_INTERVAL),
notifications::TIMER_MASK,
);
if any_blinking {
sys_set_timer(
Some(sys_get_timer().now + BLINK_INTERVAL),
notifications::TIMER_MASK,
);
}
}
}
}
Expand All @@ -196,11 +191,14 @@ fn main() -> ! {
for &led in config.blink_at_start {
blinking[led] = true;
}
if !config.blink_at_start.is_empty() {
sys_set_timer(
Some(sys_get_timer().now + BLINK_INTERVAL),
notifications::TIMER_MASK,
);
}
}
let mut server = ServerImpl {
blinking,
blink_state: false,
};
let mut server = ServerImpl { blinking };
loop {
idol_runtime::dispatch_n(&mut incoming, &mut server);
}
Expand Down

0 comments on commit cde51d0

Please sign in to comment.