Skip to content

Commit

Permalink
Add rust binary for communication with clock chip
Browse files Browse the repository at this point in the history
  • Loading branch information
hiddemoll committed Dec 4, 2023
1 parent d53a4be commit c5aa123
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 28 deletions.
37 changes: 9 additions & 28 deletions firmware-binaries/examples/hello/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use ufmt::uwriteln;

use bittide_sys::i2c::I2C;
use bittide_sys::si534x::SI534X;
use bittide_sys::uart::Uart;

#[cfg(not(test))]
Expand All @@ -16,49 +17,29 @@ use riscv_rt::entry;
#[cfg_attr(not(test), entry)]
fn main() -> ! {
let mut uart = unsafe { Uart::new(0x8000_0000 as *mut u8) };
let mut i2c = unsafe { I2C::new(0xc000_0000 as *mut u8) };
let mut si534x = unsafe { SI534X::new(0xc000_0000 as *mut u8, 0x69) };

let names = ["Rust", "RISC-V", "Haskell"];
for name in names {
uwriteln!(uart, "Hello from {}!", name).unwrap();
}
uwriteln!(uart, "This can also do {} {:#x}", "debug prints", 42).unwrap();
_ = uart.receive();
uwriteln!(uart, "i2c device:\n{:?}", i2c).unwrap();

// Deasserting i2c reset
uwriteln!(uart, "Deasserting i2c statemachine reset").unwrap();
let mut flags = i2c.read_flags();
flags.statemachine_reset = false;
i2c.write_flags(flags);
uwriteln!(uart, "i2c flags:\n{:?}", flags).unwrap();

// Getting and setting clock divider
let mut clk_div = i2c.get_clock_divider();
let mut clk_div = si534x.get_clock_divider();
uwriteln!(uart, "i2c clk div:\n{:?}", clk_div).unwrap();
clk_div = 300;
uwriteln!(uart, "Changing i2c clk div to {}", clk_div).unwrap();
i2c.set_clock_divider(clk_div);
clk_div = i2c.get_clock_divider();
si534x.set_clock_divider(clk_div);
clk_div = si534x.get_clock_divider();
uwriteln!(uart, "i2c clk div:\n{:?}", clk_div).unwrap();

// Initiating i2c communication
uwriteln!(uart, "Claiming i2c bus").unwrap();
i2c.claim_bus().unwrap();
uwriteln!(uart, "Checking for success").unwrap();
let flags = i2c.read_flags();
uwriteln!(uart, "i2c bus claimed, status:\n{:?}", flags).unwrap();

let a = 0x69;
uwriteln!(uart, "Writing address").unwrap();
i2c.write_byte(a << 1).unwrap();
uwriteln!(uart, "Reading data").unwrap();
let d = i2c.read_byte().unwrap();
uwriteln!(uart, "Read {:X} from {:X}", d, a).unwrap();
for addr in 0..255 {
let data = si534x.read_byte(0x00, addr).unwrap();
uwriteln!(uart, "Read address {:X} with {:X}", addr, data).unwrap();
}

i2c.release_bus();
let flags = i2c.read_flags();
uwriteln!(uart, "i2c bus released, status: {:?}", flags).unwrap();
uwriteln!(uart, "Going in echo mode!").unwrap();
loop {
let c = uart.receive();
Expand Down
12 changes: 12 additions & 0 deletions firmware-support/bittide-sys/src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ impl I2C {
}
}

pub fn init(&mut self) {
let flags = I2CFlags {
bus_busy: false,
arbitration_lost: false,
acknowledge_incoming: false,
transaction_acknowledged: false,
bus_claimed: false,
statemachine_reset: false,
};
self.write_flags(flags);
}

pub fn claim_bus(&mut self) -> Result<(), ()> {
let mut flags = self.read_flags();
if flags.bus_busy && !flags.bus_claimed {
Expand Down
1 change: 1 addition & 0 deletions firmware-support/bittide-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod gather_unit;
pub mod i2c;
pub mod program_stream;
pub mod scatter_unit;
pub mod si534x;
pub mod uart;

pub(crate) mod utils;
Expand Down
85 changes: 85 additions & 0 deletions firmware-support/bittide-sys/src/si534x.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-FileCopyrightText: 2022 Google LLC
//
// SPDX-License-Identifier: Apache-2.0

use ufmt::derive::uDebug;

use crate::i2c::I2C;

#[derive(uDebug)]
pub struct SI534X {
i2c: I2C,
slave_addr: u8,
page: Option<u8>,
addr: Option<u8>,
}

impl SI534X {
/// Create a new [`SI534X`] instance given a base address and the slave
/// address of the SI534X chip.
///
/// # Safety
///
/// The `base_addr` pointer MUST BE a valid pointer that is backed
/// by either a memory mapped UART instance or at valid read-writable memory
/// (which will likely cause incorrect behaviour, but not break memory safety)
pub unsafe fn new(base_addr: *mut u8, slave_addr: u8) -> SI534X {
let mut si = SI534X {
i2c: I2C::new(base_addr),
slave_addr,
page: None,
addr: None,
};
si.i2c.init();
si
}

pub fn read_byte(&mut self, page: u8, addr: u8) -> Result<u8, ()> {
self.set_page(page)?;

self.i2c.claim_bus()?;
self.i2c.write_byte(self.slave_addr << 1)?;
self.addr = Some(addr);
self.i2c.release_bus();

self.i2c.claim_bus()?;
self.i2c.write_byte((self.slave_addr << 1) | 1)?;
let data = self.i2c.read_byte()?;
self.i2c.release_bus();

Ok(data)
}

pub fn write_byte(&mut self, page: u8, addr: u8, data: u8) -> Result<(), ()> {
self.set_page(page)?;

self.i2c.claim_bus()?;
self.i2c.write_byte(self.slave_addr << 1)?;
self.i2c.write_byte(addr)?;
self.addr = Some(addr);
self.i2c.write_byte(data)?;
self.i2c.release_bus();

Ok(())
}

fn set_page(&mut self, page: u8) -> Result<(), ()> {
if self.page != Some(page) {
self.i2c.claim_bus()?;
self.i2c.write_byte(self.slave_addr << 1)?;
self.i2c.write_byte(0x01)?;
self.i2c.write_byte(page)?;
self.page = Some(page);
self.i2c.release_bus();
}
Ok(())
}

pub fn get_clock_divider(&mut self) -> u16 {
self.i2c.get_clock_divider()
}

pub fn set_clock_divider(&mut self, clk_div: u16) {
self.i2c.set_clock_divider(clk_div)
}
}

0 comments on commit c5aa123

Please sign in to comment.